Skip to content

Commit f7e041a

Browse files
committed
fix(xai): handle optional tool call fields with explicit fallbacks
Make name, arguments, input, and call_id fields optional in toolCallSchema to match xAI API behavior during in_progress states. Add explicit ?? '' fallbacks in language model code for clear, maintainable handling of missing fields. Add custom_tool_call handling in both doGenerate and doStream methods, using the input field (instead of arguments) for custom tool calls per the API specification.
1 parent 67dcfb5 commit f7e041a

File tree

1 file changed

+25
-11
lines changed

1 file changed

+25
-11
lines changed

packages/xai/src/responses/xai-responses-language-model.ts

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -198,22 +198,29 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
198198
part.type === 'code_interpreter_call' ||
199199
part.type === 'code_execution_call' ||
200200
part.type === 'view_image_call' ||
201-
part.type === 'view_x_video_call'
201+
part.type === 'view_x_video_call' ||
202+
part.type === 'custom_tool_call'
202203
) {
203-
let toolName = part.name;
204-
if (webSearchSubTools.includes(part.name)) {
204+
let toolName = part.name ?? '';
205+
if (webSearchSubTools.includes(part.name ?? '')) {
205206
toolName = webSearchToolName ?? 'web_search';
206-
} else if (xSearchSubTools.includes(part.name)) {
207+
} else if (xSearchSubTools.includes(part.name ?? '')) {
207208
toolName = xSearchToolName ?? 'x_search';
208209
} else if (part.name === 'code_execution') {
209210
toolName = codeExecutionToolName ?? 'code_execution';
210211
}
211212

213+
// custom_tool_call uses 'input' field, others use 'arguments'
214+
const toolInput =
215+
part.type === 'custom_tool_call'
216+
? (part.input ?? '')
217+
: (part.arguments ?? '');
218+
212219
content.push({
213220
type: 'tool-call',
214221
toolCallId: part.id,
215222
toolName,
216-
input: part.arguments,
223+
input: toolInput,
217224
providerExecuted: true,
218225
});
219226

@@ -476,7 +483,8 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
476483
part.type === 'code_interpreter_call' ||
477484
part.type === 'code_execution_call' ||
478485
part.type === 'view_image_call' ||
479-
part.type === 'view_x_video_call'
486+
part.type === 'view_x_video_call' ||
487+
part.type === 'custom_tool_call'
480488
) {
481489
if (!seenToolCalls.has(part.id)) {
482490
seenToolCalls.add(part.id);
@@ -493,15 +501,21 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
493501
'x_thread_fetch',
494502
];
495503

496-
let toolName = part.name;
497-
if (webSearchSubTools.includes(part.name)) {
504+
let toolName = part.name ?? '';
505+
if (webSearchSubTools.includes(part.name ?? '')) {
498506
toolName = webSearchToolName ?? 'web_search';
499-
} else if (xSearchSubTools.includes(part.name)) {
507+
} else if (xSearchSubTools.includes(part.name ?? '')) {
500508
toolName = xSearchToolName ?? 'x_search';
501509
} else if (part.name === 'code_execution') {
502510
toolName = codeExecutionToolName ?? 'code_execution';
503511
}
504512

513+
// custom_tool_call uses 'input' field, others use 'arguments'
514+
const toolInput =
515+
part.type === 'custom_tool_call'
516+
? (part.input ?? '')
517+
: (part.arguments ?? '');
518+
505519
controller.enqueue({
506520
type: 'tool-input-start',
507521
id: part.id,
@@ -511,7 +525,7 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
511525
controller.enqueue({
512526
type: 'tool-input-delta',
513527
id: part.id,
514-
delta: part.arguments,
528+
delta: toolInput,
515529
});
516530

517531
controller.enqueue({
@@ -523,7 +537,7 @@ export class XaiResponsesLanguageModel implements LanguageModelV3 {
523537
type: 'tool-call',
524538
toolCallId: part.id,
525539
toolName,
526-
input: part.arguments,
540+
input: toolInput,
527541
providerExecuted: true,
528542
});
529543
}

0 commit comments

Comments
 (0)