@jaypie/llm 1.2.16 → 1.2.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26,6 +26,12 @@ export declare class OpenAiAdapter extends BaseProviderAdapter {
26
26
  responseToHistoryItems(response: unknown): LlmHistory;
27
27
  classifyError(error: unknown): ClassifiedError;
28
28
  isComplete(response: unknown): boolean;
29
+ /**
30
+ * Sanitize history items for the OpenAI Responses API.
31
+ * Strips fields not accepted by specific item types (e.g., `name` on
32
+ * function_call_output items) to prevent 400 "Unknown parameter" errors.
33
+ */
34
+ private sanitizeInputItems;
29
35
  private hasToolCalls;
30
36
  private extractContent;
31
37
  }
@@ -16,6 +16,8 @@ export interface LlmStreamChunkToolCall {
16
16
  id: string;
17
17
  name: string;
18
18
  arguments: string;
19
+ /** Provider-specific metadata preserved through tool-call roundtrip */
20
+ metadata?: Record<string, unknown>;
19
21
  };
20
22
  }
21
23
  export interface LlmStreamChunkToolResult {
package/dist/esm/index.js CHANGED
@@ -1679,6 +1679,11 @@ class GeminiAdapter extends BaseProviderAdapter {
1679
1679
  name: functionCall.name || "",
1680
1680
  arguments: functionCall.args || {},
1681
1681
  };
1682
+ // Preserve thoughtSignature for Gemini 3 models
1683
+ // Required to maintain tool call context between turns
1684
+ const metadata = part.thoughtSignature
1685
+ ? { thoughtSignature: part.thoughtSignature }
1686
+ : undefined;
1682
1687
  // Emit the function call immediately
1683
1688
  yield {
1684
1689
  type: LlmStreamChunkType.ToolCall,
@@ -1686,6 +1691,7 @@ class GeminiAdapter extends BaseProviderAdapter {
1686
1691
  id: currentFunctionCall.id,
1687
1692
  name: currentFunctionCall.name,
1688
1693
  arguments: JSON.stringify(currentFunctionCall.arguments),
1694
+ metadata,
1689
1695
  },
1690
1696
  };
1691
1697
  currentFunctionCall = null;
@@ -2221,7 +2227,7 @@ class OpenAiAdapter extends BaseProviderAdapter {
2221
2227
  const model = request.model || this.defaultModel;
2222
2228
  const openaiRequest = {
2223
2229
  model,
2224
- input: request.messages,
2230
+ input: this.sanitizeInputItems(request.messages),
2225
2231
  };
2226
2232
  if (request.user) {
2227
2233
  openaiRequest.user = request.user;
@@ -2372,6 +2378,9 @@ class OpenAiAdapter extends BaseProviderAdapter {
2372
2378
  id: currentFunctionCall.callId,
2373
2379
  name: currentFunctionCall.name,
2374
2380
  arguments: currentFunctionCall.arguments,
2381
+ // Preserve the item ID (fc_...) separately from call_id (call_...)
2382
+ // OpenAI Responses API requires both with correct prefixes
2383
+ metadata: { itemId: currentFunctionCall.id },
2375
2384
  },
2376
2385
  };
2377
2386
  currentFunctionCall = null;
@@ -2566,6 +2575,31 @@ class OpenAiAdapter extends BaseProviderAdapter {
2566
2575
  //
2567
2576
  // Private Helpers
2568
2577
  //
2578
+ /**
2579
+ * Sanitize history items for the OpenAI Responses API.
2580
+ * Strips fields not accepted by specific item types (e.g., `name` on
2581
+ * function_call_output items) to prevent 400 "Unknown parameter" errors.
2582
+ */
2583
+ sanitizeInputItems(messages) {
2584
+ return messages.map((item) => {
2585
+ const typedItem = item;
2586
+ // function_call_output only accepts: type, call_id, output, id, status
2587
+ if (typedItem.type === LlmMessageType.FunctionCallOutput) {
2588
+ const sanitized = {
2589
+ type: typedItem.type,
2590
+ call_id: typedItem.call_id,
2591
+ output: typedItem.output,
2592
+ };
2593
+ if (typedItem.id)
2594
+ sanitized.id = typedItem.id;
2595
+ if (typedItem.status)
2596
+ sanitized.status = typedItem.status;
2597
+ return sanitized;
2598
+ }
2599
+ // All other items pass through as-is
2600
+ return item;
2601
+ });
2602
+ }
2569
2603
  hasToolCalls(response) {
2570
2604
  if (!response.output || !Array.isArray(response.output)) {
2571
2605
  return false;
@@ -4791,13 +4825,22 @@ class StreamLoop {
4791
4825
  if (collectedToolCalls.length > 0 && state.toolkit && state.maxTurns > 1) {
4792
4826
  // Add tool calls to history
4793
4827
  for (const toolCall of collectedToolCalls) {
4794
- state.currentInput.push({
4828
+ // Extract provider-specific metadata from the stream chunk
4829
+ const metadata = toolCall.raw?.metadata;
4830
+ const historyItem = {
4795
4831
  type: LlmMessageType.FunctionCall,
4796
4832
  name: toolCall.name,
4797
4833
  arguments: toolCall.arguments,
4798
4834
  call_id: toolCall.callId,
4799
- id: toolCall.callId,
4800
- });
4835
+ // Use provider item ID if available (e.g., OpenAI fc_... prefix),
4836
+ // otherwise fall back to callId
4837
+ id: metadata?.itemId || toolCall.callId,
4838
+ };
4839
+ // Preserve provider-specific fields (e.g., Gemini thoughtSignature)
4840
+ if (metadata?.thoughtSignature) {
4841
+ historyItem.thoughtSignature = metadata.thoughtSignature;
4842
+ }
4843
+ state.currentInput.push(historyItem);
4801
4844
  }
4802
4845
  return { shouldContinue: true, toolCalls: collectedToolCalls };
4803
4846
  }