Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ declare global {
name: string;
arguments: string;
};
responsesOutputItemId?: string;
}

export interface ToolCallDelta {
Expand All @@ -311,6 +312,7 @@ declare global {
name?: string;
arguments?: string;
};
responsesOutputItemId?: string;
}

export interface ToolResultChatMessage {
Expand Down
2 changes: 2 additions & 0 deletions core/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ export interface ToolCall {
name: string;
arguments: string;
};
responsesOutputItemId?: string;
}

export interface ToolCallDelta {
Expand All @@ -357,6 +358,7 @@ export interface ToolCallDelta {
name?: string;
arguments?: string;
};
responsesOutputItemId?: string;
}

export interface ToolResultChatMessage {
Expand Down
41 changes: 27 additions & 14 deletions core/llm/openaiTypeConverters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,7 @@ function toResponseInputContentList(
return list;
}

// eslint-disable-next-line complexity
export function toResponsesInput(messages: ChatMessage[]): ResponseInput {
const input: ResponseInput = [];

Expand Down Expand Up @@ -816,22 +817,34 @@ export function toResponsesInput(messages: ChatMessage[]): ResponseInput {
const respId = msg.metadata?.responsesOutputItemId as
| string
| undefined;

const toolCalls = msg.toolCalls as ToolCallDelta[] | undefined;

if (respId && Array.isArray(toolCalls) && toolCalls.length > 0) {
// Emit full function_call output item
const tc = toolCalls[0];
const name = tc?.function?.name as string | undefined;
const args = tc?.function?.arguments as string | undefined;
const call_id = tc?.id as string | undefined;
const functionCallItem: ResponseFunctionToolCall = {
id: respId,
type: "function_call",
name: name || "",
arguments: typeof args === "string" ? args : "{}",
call_id: call_id || respId,
};
input.push(functionCallItem);
if (Array.isArray(toolCalls) && toolCalls.length > 0) {
// Emit one function_call item per recorded tool call,
// prefer per-tool responsesOutputItemId when available
for (const tc of toolCalls) {
const name = tc?.function?.name as string | undefined;
const args = tc?.function?.arguments as string | undefined;
const tcRespId = (tc as any).responsesOutputItemId as
| string
| undefined;
const callId = tc?.id as string | undefined;
const rawItemId = tcRespId || respId || callId;
const itemId = rawItemId
? rawItemId.startsWith("fc")
? rawItemId
: `fc_${rawItemId}`
: undefined;
const functionCallItem: ResponseFunctionToolCall = {
id: itemId,
type: "function_call",
name: name || "",
arguments: typeof args === "string" ? args : "{}",
call_id: callId || tcRespId || respId || "",
};
input.push(functionCallItem);
}
} else if (respId) {
// Emit full assistant output message item
const outputMessageItem: ResponseOutputMessage = {
Expand Down
17 changes: 13 additions & 4 deletions gui/src/redux/slices/sessionSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,12 @@ export function handleToolCallsInMessage(

// Initialize tool call states for each filtered tool call in the message
// Each tool call gets its own state to track generation/execution progress
lastItem.toolCallStates = filteredToolCalls.map((toolCallDelta) =>
addToolCallDeltaToState(toolCallDelta, undefined),
);
lastItem.toolCallStates = filteredToolCalls.map((toolCallDelta) => {
const state = addToolCallDeltaToState(toolCallDelta, undefined);
state.toolCall.responsesOutputItemId =
(message.metadata?.responsesOutputItemId as string) ?? undefined;
return state;
});

// Update the message's toolCalls array to reflect the processed tool calls
// We can safely cast because we verified the role above
Expand All @@ -116,6 +119,7 @@ export function handleToolCallsInMessage(
function applyToolCallDelta(
toolCallDelta: ToolCallDelta,
toolCallStates: ToolCallState[],
responsesOutputItemId: string,
): void {
// Find existing state by matching toolCallId - this ensures we update
// the correct tool call even when multiple tool calls are being streamed
Expand Down Expand Up @@ -150,6 +154,7 @@ function applyToolCallDelta(
toolCallStates[existingStateIndex] = updatedState;
} else {
// Add new tool call state for a newly discovered tool call
updatedState.toolCall.responsesOutputItemId = responsesOutputItemId;
toolCallStates.push(updatedState);
}
}
Expand Down Expand Up @@ -181,7 +186,11 @@ export function handleStreamingToolCallUpdates(

// Process each filtered tool call delta, matching by ID to update the correct state
filteredToolCalls.forEach((toolCallDelta) => {
applyToolCallDelta(toolCallDelta, updatedToolCallStates);
applyToolCallDelta(
toolCallDelta,
updatedToolCallStates,
message.metadata?.responsesOutputItemId as string,
);
});

// Replace the entire tool call states array with the updated version
Expand Down
1 change: 1 addition & 0 deletions gui/src/util/toolCallState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export function addToolCallDeltaToState(
name: mergedName,
arguments: mergedArgs,
},
responsesOutputItemId: currentCall?.responsesOutputItemId,
},
toolCallId: callId,
parsedArgs,
Expand Down
Loading