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
46 changes: 46 additions & 0 deletions src/llm/openai/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,27 @@ export class ChatOpenAI extends OriginalChatOpenAI<t.ChatOpenAICallOptions> {
chunk.additional_kwargs.provider_specific_fields =
delta.provider_specific_fields;
}
// Capture provider_specific_fields from individual tool calls (e.g., Gemini thought_signature)
if (delta.tool_calls) {
const toolCallProviderFields =
(chunk.additional_kwargs._tool_call_provider_fields as Record<
string,
unknown
>) ?? {};
for (const tc of delta.tool_calls as Array<
(typeof delta.tool_calls)[number] & {
provider_specific_fields?: Record<string, unknown>;
}
>) {
if (tc.provider_specific_fields && tc.id) {
toolCallProviderFields[tc.id] = tc.provider_specific_fields;
}
}
if (Object.keys(toolCallProviderFields).length > 0) {
chunk.additional_kwargs._tool_call_provider_fields =
toolCallProviderFields;
}
}
defaultRole = delta.role ?? defaultRole;
const newTokenIndices = {
prompt: options.promptIndex ?? 0,
Expand Down Expand Up @@ -776,6 +797,31 @@ export class ChatXAI extends OriginalChatXAI {
if ('reasoning_content' in delta) {
chunk.additional_kwargs.reasoning_content = delta.reasoning_content;
}
if ('provider_specific_fields' in delta) {
chunk.additional_kwargs.provider_specific_fields =
delta.provider_specific_fields;
}
// Capture provider_specific_fields from individual tool calls (e.g., Gemini thought_signature)
if (delta.tool_calls) {
const toolCallProviderFields =
(chunk.additional_kwargs._tool_call_provider_fields as Record<
string,
unknown
>) ?? {};
for (const tc of delta.tool_calls as Array<
(typeof delta.tool_calls)[number] & {
provider_specific_fields?: Record<string, unknown>;
}
>) {
if (tc.provider_specific_fields && tc.id) {
toolCallProviderFields[tc.id] = tc.provider_specific_fields;
}
}
if (Object.keys(toolCallProviderFields).length > 0) {
chunk.additional_kwargs._tool_call_provider_fields =
toolCallProviderFields;
}
}
defaultRole = delta.role ?? defaultRole;
const newTokenIndices = {
prompt: (options as OpenAIChatCallOptions).promptIndex ?? 0,
Expand Down
51 changes: 37 additions & 14 deletions src/llm/openai/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,9 +329,17 @@ export function _convertMessagesToOpenAIParams(
completionParam.content = '';
}
if (isAIMessage(message) && !!message.tool_calls?.length) {
completionParam.tool_calls = message.tool_calls.map(
convertLangChainToolCallToOpenAI
);
const toolCallProviderFields = message.additional_kwargs
._tool_call_provider_fields as
| Record<string, Record<string, unknown>>
| undefined;
completionParam.tool_calls = message.tool_calls.map((tc) => {
const providerFields = toolCallProviderFields?.[tc.id!];
return {
...convertLangChainToolCallToOpenAI(tc),
...(providerFields && { provider_specific_fields: providerFields }),
};
});
completionParam.content = hasAnthropicThinkingBlock ? content : '';
} else {
if (message.additional_kwargs.tool_calls != null) {
Expand Down Expand Up @@ -402,6 +410,7 @@ export function _convertMessagesToOpenAIResponsesParams(
const additional_kwargs =
lcMsg.additional_kwargs as BaseMessageFields['additional_kwargs'] & {
[_FUNCTION_CALL_IDS_MAP_KEY]?: Record<string, string>;
_tool_call_provider_fields?: Record<string, unknown>;
reasoning?: OpenAIClient.Responses.ResponseReasoningItem;
type?: string;
refusal?: string;
Expand Down Expand Up @@ -534,29 +543,43 @@ export function _convertMessagesToOpenAIResponsesParams(
});

const functionCallIds = additional_kwargs[_FUNCTION_CALL_IDS_MAP_KEY];
const toolCallProviderFields =
additional_kwargs._tool_call_provider_fields as
| Record<string, Record<string, unknown>>
| undefined;

if (isAIMessage(lcMsg) && !!lcMsg.tool_calls?.length) {
input.push(
...lcMsg.tool_calls.map(
(toolCall): ResponsesInputItem => ({
...lcMsg.tool_calls.map((toolCall): ResponsesInputItem => {
const providerFields = toolCallProviderFields?.[toolCall.id!];
return {
type: 'function_call',
name: toolCall.name,
arguments: JSON.stringify(toolCall.args),
call_id: toolCall.id!,
...(zdrEnabled ? { id: functionCallIds?.[toolCall.id!] } : {}),
})
)
...(providerFields && {
provider_specific_fields: providerFields,
}),
};
})
);
} else if (additional_kwargs.tool_calls) {
input.push(
...additional_kwargs.tool_calls.map(
(toolCall): ResponsesInputItem => ({
type: 'function_call',
name: toolCall.function.name,
call_id: toolCall.id,
arguments: toolCall.function.arguments,
...(zdrEnabled ? { id: functionCallIds?.[toolCall.id] } : {}),
})
(toolCall): ResponsesInputItem => {
const providerFields = toolCallProviderFields?.[toolCall.id];
return {
type: 'function_call',
name: toolCall.function.name,
call_id: toolCall.id,
arguments: toolCall.function.arguments,
...(zdrEnabled ? { id: functionCallIds?.[toolCall.id] } : {}),
...(providerFields && {
provider_specific_fields: providerFields,
}),
};
}
)
);
}
Expand Down