@openrouter/sdk 0.3.15 → 0.4.0

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.
Files changed (43) hide show
  1. package/esm/funcs/modelsListForUser.d.ts +5 -2
  2. package/esm/funcs/modelsListForUser.js +6 -3
  3. package/esm/index.d.ts +3 -2
  4. package/esm/index.js +1 -1
  5. package/esm/lib/config.d.ts +2 -2
  6. package/esm/lib/config.js +2 -2
  7. package/esm/lib/model-result.d.ts +25 -3
  8. package/esm/lib/model-result.js +93 -21
  9. package/esm/lib/stream-transformers.d.ts +12 -0
  10. package/esm/lib/stream-transformers.js +206 -0
  11. package/esm/lib/tool-executor.js +37 -13
  12. package/esm/lib/tool-types.d.ts +28 -2
  13. package/esm/lib/tool-types.js +6 -0
  14. package/esm/models/chatgenerationparams.d.ts +22 -22
  15. package/esm/models/chatgenerationparams.js +24 -21
  16. package/esm/models/index.d.ts +0 -5
  17. package/esm/models/index.js +0 -5
  18. package/esm/models/outputmodality.d.ts +1 -0
  19. package/esm/models/outputmodality.js +1 -0
  20. package/esm/models/publicendpoint.d.ts +8 -0
  21. package/esm/models/publicendpoint.js +4 -0
  22. package/esm/models/publicpricing.d.ts +4 -0
  23. package/esm/models/publicpricing.js +2 -0
  24. package/esm/sdk/models.d.ts +4 -1
  25. package/esm/sdk/models.js +4 -1
  26. package/esm/sdk/sdk.d.ts +0 -3
  27. package/esm/sdk/sdk.js +0 -4
  28. package/jsr.json +1 -1
  29. package/package.json +12 -12
  30. package/esm/funcs/completionsGenerate.d.ts +0 -18
  31. package/esm/funcs/completionsGenerate.js +0 -83
  32. package/esm/models/completionchoice.d.ts +0 -25
  33. package/esm/models/completionchoice.js +0 -34
  34. package/esm/models/completioncreateparams.d.ts +0 -120
  35. package/esm/models/completioncreateparams.js +0 -118
  36. package/esm/models/completionlogprobs.d.ts +0 -15
  37. package/esm/models/completionlogprobs.js +0 -24
  38. package/esm/models/completionresponse.d.ts +0 -19
  39. package/esm/models/completionresponse.js +0 -28
  40. package/esm/models/completionusage.d.ts +0 -12
  41. package/esm/models/completionusage.js +0 -23
  42. package/esm/sdk/completions.d.ts +0 -12
  43. package/esm/sdk/completions.js +0 -19
@@ -10,7 +10,10 @@ import * as operations from "../models/operations/index.js";
10
10
  import { APIPromise } from "../types/async.js";
11
11
  import { Result } from "../types/fp.js";
12
12
  /**
13
- * List models filtered by user provider preferences
13
+ * List models filtered by user provider preferences, privacy settings, and guardrails
14
+ *
15
+ * @remarks
16
+ * List models filtered by user provider preferences, [privacy settings](https://openrouter.ai/docs/guides/privacy/logging), and [guardrails](https://openrouter.ai/docs/guides/features/guardrails). If requesting through `eu.openrouter.ai/api/v1/...` the results will be filtered to models that satisfy [EU in-region routing](https://openrouter.ai/docs/guides/privacy/logging#enterprise-eu-in-region-routing).
14
17
  */
15
- export declare function modelsListForUser(client: OpenRouterCore, security: operations.ListModelsUserSecurity, options?: RequestOptions): APIPromise<Result<models.ModelsListResponse, errors.UnauthorizedResponseError | errors.InternalServerResponseError | OpenRouterError | ResponseValidationError | ConnectionError | RequestAbortedError | RequestTimeoutError | InvalidRequestError | UnexpectedClientError | SDKValidationError>>;
18
+ export declare function modelsListForUser(client: OpenRouterCore, security: operations.ListModelsUserSecurity, options?: RequestOptions): APIPromise<Result<models.ModelsListResponse, errors.UnauthorizedResponseError | errors.NotFoundResponseError | errors.InternalServerResponseError | OpenRouterError | ResponseValidationError | ConnectionError | RequestAbortedError | RequestTimeoutError | InvalidRequestError | UnexpectedClientError | SDKValidationError>>;
16
19
  //# sourceMappingURL=modelsListForUser.d.ts.map
@@ -10,7 +10,10 @@ import * as errors from "../models/errors/index.js";
10
10
  import * as models from "../models/index.js";
11
11
  import { APIPromise } from "../types/async.js";
12
12
  /**
13
- * List models filtered by user provider preferences
13
+ * List models filtered by user provider preferences, privacy settings, and guardrails
14
+ *
15
+ * @remarks
16
+ * List models filtered by user provider preferences, [privacy settings](https://openrouter.ai/docs/guides/privacy/logging), and [guardrails](https://openrouter.ai/docs/guides/features/guardrails). If requesting through `eu.openrouter.ai/api/v1/...` the results will be filtered to models that satisfy [EU in-region routing](https://openrouter.ai/docs/guides/privacy/logging#enterprise-eu-in-region-routing).
14
17
  */
15
18
  export function modelsListForUser(client, security, options) {
16
19
  return new APIPromise($do(client, security, options));
@@ -54,7 +57,7 @@ async function $do(client, security, options) {
54
57
  const req = requestRes.value;
55
58
  const doResult = await client._do(req, {
56
59
  context,
57
- errorCodes: ["401", "4XX", "500", "5XX"],
60
+ errorCodes: ["401", "404", "4XX", "500", "5XX"],
58
61
  retryConfig: context.retryConfig,
59
62
  retryCodes: context.retryCodes,
60
63
  });
@@ -65,7 +68,7 @@ async function $do(client, security, options) {
65
68
  const responseFields = {
66
69
  HttpMeta: { Response: response, Request: req },
67
70
  };
68
- const [result] = await M.match(M.json(200, models.ModelsListResponse$inboundSchema), M.jsonErr(401, errors.UnauthorizedResponseError$inboundSchema), M.jsonErr(500, errors.InternalServerResponseError$inboundSchema), M.fail("4XX"), M.fail("5XX"))(response, req, { extraFields: responseFields });
71
+ const [result] = await M.match(M.json(200, models.ModelsListResponse$inboundSchema), M.jsonErr(401, errors.UnauthorizedResponseError$inboundSchema), M.jsonErr(404, errors.NotFoundResponseError$inboundSchema), M.jsonErr(500, errors.InternalServerResponseError$inboundSchema), M.fail("4XX"), M.fail("5XX"))(response, req, { extraFields: responseFields });
69
72
  if (!result.ok) {
70
73
  return [result, { status: "complete", request: req, response }];
71
74
  }
package/esm/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export type { CallModelInput, CallModelInputWithState, FieldOrAsyncFunction, ResolvedCallModelInput, } from './lib/async-params.js';
2
2
  export type { Fetcher, HTTPClientOptions } from './lib/http.js';
3
- export type { ChatStreamEvent, ConversationState, ConversationStatus, ResponseStreamEvent as EnhancedResponseStreamEvent, HasApprovalTools, InferToolEvent, InferToolEventsUnion, InferToolInput, InferToolOutput, ManualTool, NextTurnParamsContext, NextTurnParamsFunctions, ParsedToolCall, PartialResponse, StateAccessor, StepResult, StopCondition, StopWhen, Tool, ToolApprovalCheck, ToolExecutionResult, ToolExecutionResultUnion, ToolHasApproval, ToolPreliminaryResultEvent, ToolStreamEvent, ToolWithExecute, ToolWithGenerator, TurnContext, TypedToolCall, TypedToolCallUnion, UnsentToolResult, Warning, } from './lib/tool-types.js';
3
+ export type { ChatStreamEvent, ConversationState, ConversationStatus, ResponseStreamEvent as EnhancedResponseStreamEvent, HasApprovalTools, InferToolEvent, InferToolEventsUnion, InferToolInput, InferToolOutput, InferToolOutputsUnion, ManualTool, NextTurnParamsContext, NextTurnParamsFunctions, ParsedToolCall, PartialResponse, StateAccessor, StepResult, StopCondition, StopWhen, Tool, ToolApprovalCheck, ToolExecutionResult, ToolExecutionResultUnion, ToolHasApproval, ToolPreliminaryResultEvent, ToolResultEvent, ToolStreamEvent, ToolWithExecute, ToolWithGenerator, TurnContext, TypedToolCall, TypedToolCallUnion, UnsentToolResult, Warning, } from './lib/tool-types.js';
4
4
  export type { BuildTurnContextOptions } from './lib/turn-context.js';
5
5
  export type { ClaudeBase64ImageSource, ClaudeCacheControl, ClaudeCitationCharLocation, ClaudeCitationContentBlockLocation, ClaudeCitationPageLocation, ClaudeCitationSearchResultLocation, ClaudeCitationWebSearchResultLocation, ClaudeContentBlock, ClaudeContentBlockParam, ClaudeImageBlockParam, ClaudeMessage, ClaudeMessageParam, ClaudeRedactedThinkingBlock, ClaudeServerToolUseBlock, ClaudeStopReason, ClaudeTextBlock, ClaudeTextBlockParam, ClaudeTextCitation, ClaudeThinkingBlock, ClaudeToolResultBlockParam, ClaudeToolUseBlock, ClaudeToolUseBlockParam, ClaudeURLImageSource, ClaudeUsage, } from './models/claude-message.js';
6
6
  export { fromClaudeMessages, toClaudeMessage } from './lib/anthropic-compat.js';
@@ -14,8 +14,9 @@ export { HTTPClient } from './lib/http.js';
14
14
  export { applyNextTurnParamsToRequest, buildNextTurnParamsContext, executeNextTurnParamsFunctions, } from './lib/next-turn-params.js';
15
15
  export { finishReasonIs, hasToolCall, isStopConditionMet, maxCost, maxTokensUsed, stepCountIs, } from './lib/stop-conditions.js';
16
16
  export { extractUnsupportedContent, getUnsupportedContentSummary, hasUnsupportedContent, } from './lib/stream-transformers.js';
17
+ export type { StreamableOutputItem } from './lib/stream-transformers.js';
17
18
  export { tool } from './lib/tool.js';
18
- export { hasApprovalRequiredTools, hasExecuteFunction, isGeneratorTool, isRegularExecuteTool, isToolPreliminaryResultEvent, toolHasApprovalConfigured, ToolType, } from './lib/tool-types.js';
19
+ export { hasApprovalRequiredTools, hasExecuteFunction, isGeneratorTool, isRegularExecuteTool, isToolPreliminaryResultEvent, isToolResultEvent, toolHasApprovalConfigured, ToolType, } from './lib/tool-types.js';
19
20
  export { buildTurnContext, normalizeInputToArray } from './lib/turn-context.js';
20
21
  export { appendToMessages, createInitialState, createRejectedResult, createUnsentResult, generateConversationId, partitionToolCalls, toolRequiresApproval, updateState, } from './lib/conversation-state.js';
21
22
  export { ToolEventBroadcaster } from './lib/tool-event-broadcaster.js';
package/esm/index.js CHANGED
@@ -18,7 +18,7 @@ export { finishReasonIs, hasToolCall, isStopConditionMet, maxCost, maxTokensUsed
18
18
  export { extractUnsupportedContent, getUnsupportedContentSummary, hasUnsupportedContent, } from './lib/stream-transformers.js';
19
19
  // Tool creation helpers
20
20
  export { tool } from './lib/tool.js';
21
- export { hasApprovalRequiredTools, hasExecuteFunction, isGeneratorTool, isRegularExecuteTool, isToolPreliminaryResultEvent, toolHasApprovalConfigured, ToolType, } from './lib/tool-types.js';
21
+ export { hasApprovalRequiredTools, hasExecuteFunction, isGeneratorTool, isRegularExecuteTool, isToolPreliminaryResultEvent, isToolResultEvent, toolHasApprovalConfigured, ToolType, } from './lib/tool-types.js';
22
22
  // Turn context helpers
23
23
  export { buildTurnContext, normalizeInputToArray } from './lib/turn-context.js';
24
24
  // Conversation state helpers
@@ -45,8 +45,8 @@ export declare function serverURLFromOptions(options: SDKOptions): URL | null;
45
45
  export declare const SDK_METADATA: {
46
46
  readonly language: "typescript";
47
47
  readonly openapiDocVersion: "1.0.0";
48
- readonly sdkVersion: "0.3.15";
48
+ readonly sdkVersion: "0.4.0";
49
49
  readonly genVersion: "2.788.4";
50
- readonly userAgent: "speakeasy-sdk/typescript 0.3.15 2.788.4 1.0.0 @openrouter/sdk";
50
+ readonly userAgent: "speakeasy-sdk/typescript 0.4.0 2.788.4 1.0.0 @openrouter/sdk";
51
51
  };
52
52
  //# sourceMappingURL=config.d.ts.map
package/esm/lib/config.js CHANGED
@@ -26,8 +26,8 @@ export function serverURLFromOptions(options) {
26
26
  export const SDK_METADATA = {
27
27
  language: "typescript",
28
28
  openapiDocVersion: "1.0.0",
29
- sdkVersion: "0.3.15",
29
+ sdkVersion: "0.4.0",
30
30
  genVersion: "2.788.4",
31
- userAgent: "speakeasy-sdk/typescript 0.3.15 2.788.4 1.0.0 @openrouter/sdk",
31
+ userAgent: "speakeasy-sdk/typescript 0.4.0 2.788.4 1.0.0 @openrouter/sdk",
32
32
  };
33
33
  //# sourceMappingURL=config.js.map
@@ -2,7 +2,8 @@ import type { OpenRouterCore } from '../core.js';
2
2
  import type * as models from '../models/index.js';
3
3
  import type { CallModelInput } from './async-params.js';
4
4
  import type { RequestOptions } from './sdks.js';
5
- import type { ConversationState, ResponseStreamEvent, InferToolEventsUnion, ParsedToolCall, StateAccessor, StopWhen, Tool, ToolStreamEvent, TurnContext } from './tool-types.js';
5
+ import type { ConversationState, ResponseStreamEvent, InferToolEventsUnion, InferToolOutputsUnion, ParsedToolCall, StateAccessor, StopWhen, Tool, ToolStreamEvent, TurnContext } from './tool-types.js';
6
+ import { type StreamableOutputItem } from './stream-transformers.js';
6
7
  export interface GetResponseOptions<TTools extends readonly Tool[]> {
7
8
  request: CallModelInput<TTools>;
8
9
  client: OpenRouterCore;
@@ -57,6 +58,7 @@ export declare class ModelResult<TTools extends readonly Tool[]> {
57
58
  /**
58
59
  * Get or create the tool event broadcaster (lazy initialization).
59
60
  * Ensures only one broadcaster exists for the lifetime of this ModelResult.
61
+ * Broadcasts both preliminary results and final tool results.
60
62
  */
61
63
  private ensureBroadcaster;
62
64
  /**
@@ -139,6 +141,7 @@ export declare class ModelResult<TTools extends readonly Tool[]> {
139
141
  /**
140
142
  * Execute all tools in a single round.
141
143
  * Runs each tool call sequentially and collects results for API submission.
144
+ * Emits tool.result events after each tool execution completes.
142
145
  *
143
146
  * @param toolCalls - The tool calls to execute
144
147
  * @param turnContext - The current turn context
@@ -234,15 +237,34 @@ export declare class ModelResult<TTools extends readonly Tool[]> {
234
237
  /**
235
238
  * Stream all response events as they arrive.
236
239
  * Multiple consumers can iterate over this stream concurrently.
237
- * Preliminary tool results are streamed in REAL-TIME as generator tools yield.
240
+ * Preliminary tool results and tool results are streamed in REAL-TIME as generator tools yield.
238
241
  */
239
- getFullResponsesStream(): AsyncIterableIterator<ResponseStreamEvent<InferToolEventsUnion<TTools>>>;
242
+ getFullResponsesStream(): AsyncIterableIterator<ResponseStreamEvent<InferToolEventsUnion<TTools>, InferToolOutputsUnion<TTools>>>;
240
243
  /**
241
244
  * Stream only text deltas as they arrive.
242
245
  * This filters the full event stream to only yield text content.
243
246
  */
244
247
  getTextStream(): AsyncIterableIterator<string>;
245
248
  /**
249
+ * Stream all output items cumulatively as they arrive.
250
+ * Items are emitted with the same ID but progressively updated content as streaming progresses.
251
+ * Also yields tool results (function_call_output) after tool execution completes.
252
+ *
253
+ * Item types include:
254
+ * - message: Assistant text responses (emitted cumulatively as text streams)
255
+ * - function_call: Tool calls (emitted cumulatively as arguments stream)
256
+ * - reasoning: Model reasoning (emitted cumulatively as thinking streams)
257
+ * - web_search_call: Web search operations
258
+ * - file_search_call: File search operations
259
+ * - image_generation_call: Image generation operations
260
+ * - function_call_output: Results from executed tools
261
+ */
262
+ getItemsStream(): AsyncIterableIterator<StreamableOutputItem>;
263
+ /**
264
+ * @deprecated Use `getItemsStream()` instead. This method only streams messages,
265
+ * while `getItemsStream()` streams all output item types (messages, function_calls,
266
+ * reasoning, etc.) with cumulative updates.
267
+ *
246
268
  * Stream incremental message updates as content is added in responses format.
247
269
  * Each iteration yields an updated version of the message with new content.
248
270
  * Also yields OpenResponsesFunctionCallOutput after tool execution completes.
@@ -3,11 +3,12 @@ import { betaResponsesSend } from '../funcs/betaResponsesSend.js';
3
3
  import { hasAsyncFunctions, resolveAsyncFunctions, } from './async-params.js';
4
4
  import { appendToMessages, createInitialState, createRejectedResult, createUnsentResult, extractTextFromResponse as extractTextFromResponseState, partitionToolCalls, unsentResultsToAPIFormat, updateState, } from './conversation-state.js';
5
5
  import { ReusableReadableStream } from './reusable-stream.js';
6
- import { buildResponsesMessageStream, buildToolCallStream, consumeStreamForCompletion, extractReasoningDeltas, extractResponsesMessageFromResponse, extractTextDeltas, extractTextFromResponse, extractToolCallsFromResponse, extractToolDeltas, } from './stream-transformers.js';
6
+ import { buildItemsStream, buildResponsesMessageStream, buildToolCallStream, consumeStreamForCompletion, extractReasoningDeltas, extractResponsesMessageFromResponse, extractTextDeltas, extractTextFromResponse, extractToolCallsFromResponse, extractToolDeltas, } from './stream-transformers.js';
7
7
  import { executeTool } from './tool-executor.js';
8
8
  import { executeNextTurnParamsFunctions, applyNextTurnParamsToRequest } from './next-turn-params.js';
9
9
  import { hasExecuteFunction } from './tool-types.js';
10
10
  import { isStopConditionMet, stepCountIs } from './stop-conditions.js';
11
+ import { isOutputMessage, isFunctionCallOutputItem, isReasoningOutputItem, isWebSearchCallOutputItem, isFileSearchCallOutputItem, isImageGenerationCallOutputItem, hasTypeProperty, } from './stream-type-guards.js';
11
12
  /**
12
13
  * Default maximum number of tool execution steps if no stopWhen is specified.
13
14
  * This prevents infinite loops in tool execution.
@@ -30,15 +31,6 @@ function isEventStream(value) {
30
31
  const maybeStream = value;
31
32
  return typeof maybeStream.toReadableStream === 'function';
32
33
  }
33
- /**
34
- * Type guard for output items with a type property
35
- */
36
- function hasTypeProperty(item) {
37
- return (typeof item === 'object' &&
38
- item !== null &&
39
- 'type' in item &&
40
- typeof item.type === 'string');
41
- }
42
34
  /**
43
35
  * A wrapper around a streaming response that provides multiple consumption patterns.
44
36
  *
@@ -93,6 +85,7 @@ export class ModelResult {
93
85
  /**
94
86
  * Get or create the tool event broadcaster (lazy initialization).
95
87
  * Ensures only one broadcaster exists for the lifetime of this ModelResult.
88
+ * Broadcasts both preliminary results and final tool results.
96
89
  */
97
90
  ensureBroadcaster() {
98
91
  if (!this.toolEventBroadcaster) {
@@ -300,6 +293,7 @@ export class ModelResult {
300
293
  /**
301
294
  * Execute all tools in a single round.
302
295
  * Runs each tool call sequentially and collects results for API submission.
296
+ * Emits tool.result events after each tool execution completes.
303
297
  *
304
298
  * @param toolCalls - The tool calls to execute
305
299
  * @param turnContext - The current turn context
@@ -311,17 +305,33 @@ export class ModelResult {
311
305
  const tool = this.options.tools?.find((t) => t.function.name === toolCall.name);
312
306
  if (!tool || !hasExecuteFunction(tool))
313
307
  continue;
308
+ // Track preliminary results for this specific tool call
309
+ const preliminaryResultsForCall = [];
314
310
  // Create callback for real-time preliminary results
315
311
  const onPreliminaryResult = this.toolEventBroadcaster
316
312
  ? (callId, resultValue) => {
313
+ // Track preliminary results for the tool.result event
314
+ const typedResult = resultValue;
315
+ preliminaryResultsForCall.push(typedResult);
316
+ // Emit preliminary result event
317
317
  this.toolEventBroadcaster?.push({
318
318
  type: 'preliminary_result',
319
319
  toolCallId: callId,
320
- result: resultValue,
320
+ result: typedResult,
321
321
  });
322
322
  }
323
323
  : undefined;
324
324
  const result = await executeTool(tool, toolCall, turnContext, onPreliminaryResult);
325
+ // Emit tool.result event with final result and any preliminary results
326
+ if (this.toolEventBroadcaster) {
327
+ const toolResultEvent = {
328
+ type: 'tool_result',
329
+ toolCallId: toolCall.id,
330
+ result: (result.error ? { error: result.error.message } : result.result),
331
+ ...(preliminaryResultsForCall.length > 0 && { preliminaryResults: preliminaryResultsForCall }),
332
+ };
333
+ this.toolEventBroadcaster.push(toolResultEvent);
334
+ }
325
335
  toolResults.push({
326
336
  type: 'function_call_output',
327
337
  id: `output_${toolCall.id}`,
@@ -799,7 +809,7 @@ export class ModelResult {
799
809
  /**
800
810
  * Stream all response events as they arrive.
801
811
  * Multiple consumers can iterate over this stream concurrently.
802
- * Preliminary tool results are streamed in REAL-TIME as generator tools yield.
812
+ * Preliminary tool results and tool results are streamed in REAL-TIME as generator tools yield.
803
813
  */
804
814
  getFullResponsesStream() {
805
815
  return async function* () {
@@ -819,14 +829,25 @@ export class ModelResult {
819
829
  for await (const event of consumer) {
820
830
  yield event;
821
831
  }
822
- // Yield tool preliminary results as they arrive (real-time!)
832
+ // Yield tool events as they arrive (real-time!)
823
833
  for await (const event of toolEventConsumer) {
824
- yield {
825
- type: 'tool.preliminary_result',
826
- toolCallId: event.toolCallId,
827
- result: event.result,
828
- timestamp: Date.now(),
829
- };
834
+ if (event.type === 'preliminary_result') {
835
+ yield {
836
+ type: 'tool.preliminary_result',
837
+ toolCallId: event.toolCallId,
838
+ result: event.result,
839
+ timestamp: Date.now(),
840
+ };
841
+ }
842
+ else if (event.type === 'tool_result') {
843
+ yield {
844
+ type: 'tool.result',
845
+ toolCallId: event.toolCallId,
846
+ result: event.result,
847
+ timestamp: Date.now(),
848
+ ...(event.preliminaryResults && { preliminaryResults: event.preliminaryResults }),
849
+ };
850
+ }
830
851
  }
831
852
  // Ensure execution completed (handles errors)
832
853
  await executionPromise;
@@ -846,6 +867,55 @@ export class ModelResult {
846
867
  }.call(this);
847
868
  }
848
869
  /**
870
+ * Stream all output items cumulatively as they arrive.
871
+ * Items are emitted with the same ID but progressively updated content as streaming progresses.
872
+ * Also yields tool results (function_call_output) after tool execution completes.
873
+ *
874
+ * Item types include:
875
+ * - message: Assistant text responses (emitted cumulatively as text streams)
876
+ * - function_call: Tool calls (emitted cumulatively as arguments stream)
877
+ * - reasoning: Model reasoning (emitted cumulatively as thinking streams)
878
+ * - web_search_call: Web search operations
879
+ * - file_search_call: File search operations
880
+ * - image_generation_call: Image generation operations
881
+ * - function_call_output: Results from executed tools
882
+ */
883
+ getItemsStream() {
884
+ return async function* () {
885
+ await this.initStream();
886
+ if (!this.reusableStream) {
887
+ throw new Error('Stream not initialized');
888
+ }
889
+ // Stream all items from the API response cumulatively
890
+ yield* buildItemsStream(this.reusableStream);
891
+ // Execute tools if needed
892
+ await this.executeToolsIfNeeded();
893
+ // Yield function call outputs for each executed tool
894
+ for (const round of this.allToolExecutionRounds) {
895
+ for (const toolResult of round.toolResults) {
896
+ yield toolResult;
897
+ }
898
+ }
899
+ // If tools were executed, yield all items from the final response
900
+ if (this.finalResponse && this.allToolExecutionRounds.length > 0) {
901
+ for (const item of this.finalResponse.output) {
902
+ if (isOutputMessage(item) ||
903
+ isFunctionCallOutputItem(item) ||
904
+ isReasoningOutputItem(item) ||
905
+ isWebSearchCallOutputItem(item) ||
906
+ isFileSearchCallOutputItem(item) ||
907
+ isImageGenerationCallOutputItem(item)) {
908
+ yield item;
909
+ }
910
+ }
911
+ }
912
+ }.call(this);
913
+ }
914
+ /**
915
+ * @deprecated Use `getItemsStream()` instead. This method only streams messages,
916
+ * while `getItemsStream()` streams all output item types (messages, function_calls,
917
+ * reasoning, etc.) with cumulative updates.
918
+ *
849
919
  * Stream incremental message updates as content is added in responses format.
850
920
  * Each iteration yields an updated version of the message with new content.
851
921
  * Also yields OpenResponsesFunctionCallOutput after tool execution completes.
@@ -916,9 +986,11 @@ export class ModelResult {
916
986
  content: delta,
917
987
  };
918
988
  }
919
- // Yield tool events as they arrive (real-time!)
989
+ // Yield only preliminary_result events (filter out tool_result events)
920
990
  for await (const event of toolEventConsumer) {
921
- yield event;
991
+ if (event.type === 'preliminary_result') {
992
+ yield event;
993
+ }
922
994
  }
923
995
  // Ensure execution completed (handles errors)
924
996
  await executionPromise;
@@ -18,6 +18,18 @@ export declare function extractToolDeltas(stream: ReusableReadableStream<models.
18
18
  * Returns ResponsesOutputMessage (assistant/responses format)
19
19
  */
20
20
  export declare function buildResponsesMessageStream(stream: ReusableReadableStream<models.OpenResponsesStreamEvent>): AsyncIterableIterator<models.ResponsesOutputMessage>;
21
+ /**
22
+ * Output item types that can be streamed from a response.
23
+ * This is the union of all item types that appear in response output,
24
+ * plus function_call_output for tool results.
25
+ */
26
+ export type StreamableOutputItem = models.ResponsesOutputMessage | models.ResponsesOutputItemFunctionCall | models.ResponsesOutputItemReasoning | models.ResponsesWebSearchCallOutput | models.ResponsesOutputItemFileSearchCall | models.ResponsesImageGenerationCall | models.OpenResponsesFunctionCallOutput;
27
+ /**
28
+ * Build incremental output item updates from responses stream events.
29
+ * Yields all item types cumulatively - same item may be emitted multiple times
30
+ * with the same ID but progressively updated content as streaming progresses.
31
+ */
32
+ export declare function buildItemsStream(stream: ReusableReadableStream<models.OpenResponsesStreamEvent>): AsyncIterableIterator<StreamableOutputItem>;
21
33
  /**
22
34
  * Build incremental message updates from responses stream events
23
35
  * Returns AssistantMessage (chat format) instead of ResponsesOutputMessage
@@ -127,6 +127,212 @@ export async function* buildResponsesMessageStream(stream) {
127
127
  }
128
128
  }
129
129
  }
130
+ /**
131
+ * Handle output_item.added event - Initialize tracking for new items
132
+ */
133
+ function handleOutputItemAdded(event, itemsInProgress) {
134
+ if (!isOutputItemAddedEvent(event) || !event.item) {
135
+ return undefined;
136
+ }
137
+ const item = event.item;
138
+ if (isOutputMessage(item)) {
139
+ itemsInProgress.set(item.id, {
140
+ type: 'message',
141
+ id: item.id,
142
+ textContent: '',
143
+ });
144
+ return {
145
+ id: item.id,
146
+ type: 'message',
147
+ role: 'assistant',
148
+ status: 'in_progress',
149
+ content: [],
150
+ };
151
+ }
152
+ if (isFunctionCallOutputItem(item)) {
153
+ // Use item.id if available (matches itemId in delta events), fall back to callId
154
+ const itemKey = item.id ?? item.callId;
155
+ itemsInProgress.set(itemKey, {
156
+ type: 'function_call',
157
+ id: itemKey,
158
+ name: item.name,
159
+ callId: item.callId,
160
+ argumentsAccumulated: '',
161
+ });
162
+ return {
163
+ type: 'function_call',
164
+ id: item.id,
165
+ callId: item.callId,
166
+ name: item.name,
167
+ arguments: '',
168
+ status: 'in_progress',
169
+ };
170
+ }
171
+ if (isReasoningOutputItem(item)) {
172
+ itemsInProgress.set(item.id, {
173
+ type: 'reasoning',
174
+ id: item.id,
175
+ reasoningContent: '',
176
+ });
177
+ return {
178
+ type: 'reasoning',
179
+ id: item.id,
180
+ status: 'in_progress',
181
+ summary: [],
182
+ };
183
+ }
184
+ if (isWebSearchCallOutputItem(item)) {
185
+ return item;
186
+ }
187
+ if (isFileSearchCallOutputItem(item)) {
188
+ return item;
189
+ }
190
+ if (isImageGenerationCallOutputItem(item)) {
191
+ return item;
192
+ }
193
+ return undefined;
194
+ }
195
+ /**
196
+ * Handle text delta event for messages
197
+ */
198
+ function handleTextDelta(event, itemsInProgress) {
199
+ if (!isOutputTextDeltaEvent(event) || !event.delta) {
200
+ return undefined;
201
+ }
202
+ const item = itemsInProgress.get(event.itemId);
203
+ if (item?.type === 'message') {
204
+ item.textContent += event.delta;
205
+ return {
206
+ id: item.id,
207
+ type: 'message',
208
+ role: 'assistant',
209
+ status: 'in_progress',
210
+ content: [
211
+ {
212
+ type: 'output_text',
213
+ text: item.textContent,
214
+ annotations: [],
215
+ },
216
+ ],
217
+ };
218
+ }
219
+ return undefined;
220
+ }
221
+ /**
222
+ * Handle function call argument delta event
223
+ */
224
+ function handleFunctionCallDelta(event, itemsInProgress) {
225
+ if (!isFunctionCallArgumentsDeltaEvent(event) || !event.delta) {
226
+ return undefined;
227
+ }
228
+ const item = itemsInProgress.get(event.itemId);
229
+ if (item?.type === 'function_call') {
230
+ item.argumentsAccumulated += event.delta;
231
+ return {
232
+ type: 'function_call',
233
+ // Include id if it differs from callId (means API provided an id)
234
+ id: item.id !== item.callId ? item.id : undefined,
235
+ callId: item.callId,
236
+ name: item.name,
237
+ arguments: item.argumentsAccumulated,
238
+ status: 'in_progress',
239
+ };
240
+ }
241
+ return undefined;
242
+ }
243
+ /**
244
+ * Handle reasoning text delta event
245
+ */
246
+ function handleReasoningDelta(event, itemsInProgress) {
247
+ if (!isReasoningDeltaEvent(event) || !event.delta) {
248
+ return undefined;
249
+ }
250
+ const item = itemsInProgress.get(event.itemId);
251
+ if (item?.type === 'reasoning') {
252
+ item.reasoningContent += event.delta;
253
+ return {
254
+ type: 'reasoning',
255
+ id: item.id,
256
+ status: 'in_progress',
257
+ summary: [
258
+ {
259
+ type: 'summary_text',
260
+ text: item.reasoningContent,
261
+ },
262
+ ],
263
+ };
264
+ }
265
+ return undefined;
266
+ }
267
+ /**
268
+ * Handle output_item.done event - Yield final complete item
269
+ */
270
+ function handleOutputItemDone(event, itemsInProgress) {
271
+ if (!isOutputItemDoneEvent(event) || !event.item) {
272
+ return undefined;
273
+ }
274
+ const item = event.item;
275
+ if (isOutputMessage(item)) {
276
+ itemsInProgress.delete(item.id);
277
+ return item;
278
+ }
279
+ if (isFunctionCallOutputItem(item)) {
280
+ // Use item.id if available (matches itemId in delta events), fall back to callId
281
+ itemsInProgress.delete(item.id ?? item.callId);
282
+ return item;
283
+ }
284
+ if (isReasoningOutputItem(item)) {
285
+ itemsInProgress.delete(item.id);
286
+ return item;
287
+ }
288
+ if (isWebSearchCallOutputItem(item)) {
289
+ return item;
290
+ }
291
+ if (isFileSearchCallOutputItem(item)) {
292
+ return item;
293
+ }
294
+ if (isImageGenerationCallOutputItem(item)) {
295
+ return item;
296
+ }
297
+ return undefined;
298
+ }
299
+ const itemsStreamHandlers = {
300
+ 'response.output_item.added': handleOutputItemAdded,
301
+ 'response.output_text.delta': handleTextDelta,
302
+ 'response.function_call_arguments.delta': handleFunctionCallDelta,
303
+ 'response.reasoning_text.delta': handleReasoningDelta,
304
+ 'response.output_item.done': handleOutputItemDone,
305
+ };
306
+ const streamTerminationEvents = new Set([
307
+ 'response.completed',
308
+ 'response.failed',
309
+ 'response.incomplete',
310
+ ]);
311
+ //#endregion
312
+ /**
313
+ * Build incremental output item updates from responses stream events.
314
+ * Yields all item types cumulatively - same item may be emitted multiple times
315
+ * with the same ID but progressively updated content as streaming progresses.
316
+ */
317
+ export async function* buildItemsStream(stream) {
318
+ const consumer = stream.createConsumer();
319
+ const itemsInProgress = new Map();
320
+ for await (const event of consumer) {
321
+ if (!('type' in event)) {
322
+ continue;
323
+ }
324
+ if (streamTerminationEvents.has(event.type)) {
325
+ return;
326
+ }
327
+ const handler = itemsStreamHandlers[event.type];
328
+ if (handler) {
329
+ const result = handler(event, itemsInProgress);
330
+ if (result) {
331
+ yield result;
332
+ }
333
+ }
334
+ }
335
+ }
130
336
  /**
131
337
  * Build incremental message updates from responses stream events
132
338
  * Returns AssistantMessage (chat format) instead of ResponsesOutputMessage