@openrouter/sdk 0.3.7 → 0.3.10
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.
- package/.zed/settings.json +10 -0
- package/_speakeasy/.github/action-inputs-config.json +53 -0
- package/_speakeasy/.github/action-security-config.json +88 -0
- package/esm/funcs/call-model.d.ts +94 -9
- package/esm/funcs/call-model.js +102 -120
- package/esm/index.d.ts +20 -8
- package/esm/index.js +20 -7
- package/esm/lib/anthropic-compat.d.ts +6 -2
- package/esm/lib/anthropic-compat.js +117 -98
- package/esm/lib/async-params.d.ts +53 -0
- package/esm/lib/async-params.js +76 -0
- package/esm/lib/chat-compat.js +4 -0
- package/esm/lib/claude-constants.d.ts +22 -0
- package/esm/lib/claude-constants.js +20 -0
- package/esm/lib/claude-type-guards.d.ts +10 -0
- package/esm/lib/claude-type-guards.js +70 -0
- package/esm/lib/config.d.ts +2 -2
- package/esm/lib/config.js +2 -2
- package/esm/lib/model-result.d.ts +18 -25
- package/esm/lib/model-result.js +137 -176
- package/esm/lib/next-turn-params.d.ts +30 -0
- package/esm/lib/next-turn-params.js +129 -0
- package/esm/lib/reusable-stream.js +10 -10
- package/esm/lib/stop-conditions.d.ts +80 -0
- package/esm/lib/stop-conditions.js +104 -0
- package/esm/lib/stream-transformers.d.ts +3 -3
- package/esm/lib/stream-transformers.js +311 -260
- package/esm/lib/stream-type-guards.d.ts +29 -0
- package/esm/lib/stream-type-guards.js +109 -0
- package/esm/lib/tool-executor.d.ts +7 -6
- package/esm/lib/tool-executor.js +4 -0
- package/esm/lib/tool-orchestrator.d.ts +7 -7
- package/esm/lib/tool-orchestrator.js +38 -10
- package/esm/lib/tool-types.d.ts +162 -28
- package/esm/lib/tool-types.js +6 -0
- package/esm/lib/tool.d.ts +99 -0
- package/esm/lib/tool.js +71 -0
- package/esm/lib/turn-context.d.ts +50 -0
- package/esm/lib/turn-context.js +59 -0
- package/esm/sdk/sdk.d.ts +3 -9
- package/jsr.json +1 -1
- package/package.json +6 -3
package/esm/lib/model-result.js
CHANGED
|
@@ -1,38 +1,28 @@
|
|
|
1
|
-
import { betaResponsesSend } from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { betaResponsesSend } from '../funcs/betaResponsesSend.js';
|
|
2
|
+
import { hasAsyncFunctions, resolveAsyncFunctions, } from './async-params.js';
|
|
3
|
+
import { ReusableReadableStream } from './reusable-stream.js';
|
|
4
|
+
import { buildResponsesMessageStream, buildToolCallStream, consumeStreamForCompletion, extractReasoningDeltas, extractResponsesMessageFromResponse, extractTextDeltas, extractTextFromResponse, extractToolCallsFromResponse, extractToolDeltas, } from './stream-transformers.js';
|
|
5
|
+
import { executeTool } from './tool-executor.js';
|
|
6
|
+
import { executeNextTurnParamsFunctions, applyNextTurnParamsToRequest } from './next-turn-params.js';
|
|
7
|
+
import { hasExecuteFunction } from './tool-types.js';
|
|
8
|
+
import { isStopConditionMet } from './stop-conditions.js';
|
|
6
9
|
/**
|
|
7
10
|
* Type guard for stream event with toReadableStream method
|
|
8
11
|
*/
|
|
9
12
|
function isEventStream(value) {
|
|
10
13
|
return (value !== null &&
|
|
11
|
-
typeof value ===
|
|
12
|
-
|
|
13
|
-
typeof value.toReadableStream ===
|
|
14
|
-
"function");
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Type guard for response.output_text.delta events
|
|
18
|
-
*/
|
|
19
|
-
function isOutputTextDeltaEvent(event) {
|
|
20
|
-
return "type" in event && event.type === "response.output_text.delta";
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Type guard for response.completed events
|
|
24
|
-
*/
|
|
25
|
-
function isResponseCompletedEvent(event) {
|
|
26
|
-
return "type" in event && event.type === "response.completed";
|
|
14
|
+
typeof value === 'object' &&
|
|
15
|
+
'toReadableStream' in value &&
|
|
16
|
+
typeof value.toReadableStream === 'function');
|
|
27
17
|
}
|
|
28
18
|
/**
|
|
29
19
|
* Type guard for output items with a type property
|
|
30
20
|
*/
|
|
31
21
|
function hasTypeProperty(item) {
|
|
32
|
-
return (typeof item ===
|
|
22
|
+
return (typeof item === 'object' &&
|
|
33
23
|
item !== null &&
|
|
34
|
-
|
|
35
|
-
typeof item.type ===
|
|
24
|
+
'type' in item &&
|
|
25
|
+
typeof item.type === 'string');
|
|
36
26
|
}
|
|
37
27
|
/**
|
|
38
28
|
* A wrapper around a streaming response that provides multiple consumption patterns.
|
|
@@ -50,6 +40,8 @@ function hasTypeProperty(item) {
|
|
|
50
40
|
*
|
|
51
41
|
* All consumption patterns can be used concurrently thanks to the underlying
|
|
52
42
|
* ReusableReadableStream implementation.
|
|
43
|
+
*
|
|
44
|
+
* @template TTools - The tools array type to enable typed tool calls and results
|
|
53
45
|
*/
|
|
54
46
|
export class ModelResult {
|
|
55
47
|
constructor(options) {
|
|
@@ -61,6 +53,8 @@ export class ModelResult {
|
|
|
61
53
|
this.finalResponse = null;
|
|
62
54
|
this.preliminaryResults = new Map();
|
|
63
55
|
this.allToolExecutionRounds = [];
|
|
56
|
+
// Track resolved request after async function resolution
|
|
57
|
+
this.resolvedRequest = null;
|
|
64
58
|
this.options = options;
|
|
65
59
|
}
|
|
66
60
|
/**
|
|
@@ -68,11 +62,11 @@ export class ModelResult {
|
|
|
68
62
|
*/
|
|
69
63
|
isNonStreamingResponse(value) {
|
|
70
64
|
return (value !== null &&
|
|
71
|
-
typeof value ===
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
!(
|
|
65
|
+
typeof value === 'object' &&
|
|
66
|
+
'id' in value &&
|
|
67
|
+
'object' in value &&
|
|
68
|
+
'output' in value &&
|
|
69
|
+
!('toReadableStream' in value));
|
|
76
70
|
}
|
|
77
71
|
/**
|
|
78
72
|
* Initialize the stream if not already started
|
|
@@ -83,16 +77,40 @@ export class ModelResult {
|
|
|
83
77
|
return this.initPromise;
|
|
84
78
|
}
|
|
85
79
|
this.initPromise = (async () => {
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
80
|
+
// Resolve async functions before initial request
|
|
81
|
+
// Build initial turn context (turn 0 for initial request)
|
|
82
|
+
const initialContext = {
|
|
83
|
+
numberOfTurns: 0,
|
|
84
|
+
};
|
|
85
|
+
// Resolve any async functions first
|
|
86
|
+
let baseRequest;
|
|
87
|
+
if (hasAsyncFunctions(this.options.request)) {
|
|
88
|
+
baseRequest = await resolveAsyncFunctions(this.options.request, initialContext);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// Already resolved, extract non-function fields
|
|
92
|
+
// Since request is CallModelInput, we need to filter out stopWhen
|
|
93
|
+
// Note: tools are already in API format at this point (converted in callModel())
|
|
94
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
95
|
+
const { stopWhen, ...rest } = this.options.request;
|
|
96
|
+
// Cast to ResolvedCallModelInput - we know it's resolved if hasAsyncFunctions returned false
|
|
97
|
+
baseRequest = rest;
|
|
98
|
+
}
|
|
99
|
+
// Store resolved request with stream mode
|
|
100
|
+
this.resolvedRequest = {
|
|
101
|
+
...baseRequest,
|
|
89
102
|
stream: true,
|
|
90
103
|
};
|
|
104
|
+
// Force stream mode for initial request
|
|
105
|
+
const request = this.resolvedRequest;
|
|
91
106
|
// Create the stream promise
|
|
92
107
|
this.streamPromise = betaResponsesSend(this.options.client, request, this.options.options).then((result) => {
|
|
93
108
|
if (!result.ok) {
|
|
94
109
|
throw result.error;
|
|
95
110
|
}
|
|
111
|
+
// When stream: true, the API returns EventStream
|
|
112
|
+
// TypeScript can't narrow the union type based on runtime parameter values,
|
|
113
|
+
// so we assert the type here based on our knowledge that stream=true
|
|
96
114
|
return result.value;
|
|
97
115
|
});
|
|
98
116
|
// Wait for the stream and create the reusable stream
|
|
@@ -112,14 +130,15 @@ export class ModelResult {
|
|
|
112
130
|
this.toolExecutionPromise = (async () => {
|
|
113
131
|
await this.initStream();
|
|
114
132
|
if (!this.reusableStream) {
|
|
115
|
-
throw new Error(
|
|
133
|
+
throw new Error('Stream not initialized');
|
|
116
134
|
}
|
|
135
|
+
// Note: Async functions already resolved in initStream()
|
|
117
136
|
// Get the initial response
|
|
118
137
|
const initialResponse = await consumeStreamForCompletion(this.reusableStream);
|
|
119
138
|
// Check if we have tools and if auto-execution is enabled
|
|
120
139
|
const shouldAutoExecute = this.options.tools &&
|
|
121
140
|
this.options.tools.length > 0 &&
|
|
122
|
-
initialResponse.output.some((item) => hasTypeProperty(item) && item.type ===
|
|
141
|
+
initialResponse.output.some((item) => hasTypeProperty(item) && item.type === 'function_call');
|
|
123
142
|
if (!shouldAutoExecute) {
|
|
124
143
|
// No tools to execute, use initial response
|
|
125
144
|
this.finalResponse = initialResponse;
|
|
@@ -137,12 +156,34 @@ export class ModelResult {
|
|
|
137
156
|
this.finalResponse = initialResponse;
|
|
138
157
|
return;
|
|
139
158
|
}
|
|
140
|
-
// Get maxToolRounds configuration
|
|
141
|
-
const maxToolRounds = this.options.maxToolRounds ?? 5;
|
|
142
159
|
let currentResponse = initialResponse;
|
|
143
160
|
let currentRound = 0;
|
|
144
|
-
let currentInput = this.options.request.input || [];
|
|
145
161
|
while (true) {
|
|
162
|
+
// Check stopWhen conditions
|
|
163
|
+
if (this.options.stopWhen) {
|
|
164
|
+
const stopConditions = Array.isArray(this.options.stopWhen)
|
|
165
|
+
? this.options.stopWhen
|
|
166
|
+
: [this.options.stopWhen];
|
|
167
|
+
const shouldStop = await isStopConditionMet({
|
|
168
|
+
stopConditions,
|
|
169
|
+
steps: this.allToolExecutionRounds.map((round) => ({
|
|
170
|
+
stepType: 'continue',
|
|
171
|
+
text: extractTextFromResponse(round.response),
|
|
172
|
+
toolCalls: round.toolCalls,
|
|
173
|
+
toolResults: round.toolResults.map((tr) => ({
|
|
174
|
+
toolCallId: tr.callId,
|
|
175
|
+
toolName: round.toolCalls.find((tc) => tc.id === tr.callId)?.name ?? '',
|
|
176
|
+
result: JSON.parse(tr.output),
|
|
177
|
+
})),
|
|
178
|
+
response: round.response,
|
|
179
|
+
usage: round.response.usage,
|
|
180
|
+
finishReason: undefined, // OpenResponsesNonStreamingResponse doesn't have finishReason
|
|
181
|
+
})),
|
|
182
|
+
});
|
|
183
|
+
if (shouldStop) {
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
146
187
|
const currentToolCalls = extractToolCallsFromResponse(currentResponse);
|
|
147
188
|
if (currentToolCalls.length === 0) {
|
|
148
189
|
break;
|
|
@@ -154,46 +195,19 @@ export class ModelResult {
|
|
|
154
195
|
if (!hasExecutable) {
|
|
155
196
|
break;
|
|
156
197
|
}
|
|
157
|
-
//
|
|
158
|
-
if (typeof maxToolRounds === "number") {
|
|
159
|
-
if (currentRound >= maxToolRounds) {
|
|
160
|
-
break;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
else if (typeof maxToolRounds === "function") {
|
|
164
|
-
// Function signature: (context: TurnContext) => boolean
|
|
165
|
-
const turnContext = {
|
|
166
|
-
numberOfTurns: currentRound + 1,
|
|
167
|
-
messageHistory: currentInput,
|
|
168
|
-
...(this.options.request.model && {
|
|
169
|
-
model: this.options.request.model,
|
|
170
|
-
}),
|
|
171
|
-
...(this.options.request.models && {
|
|
172
|
-
models: this.options.request.models,
|
|
173
|
-
}),
|
|
174
|
-
};
|
|
175
|
-
const shouldContinue = maxToolRounds(turnContext);
|
|
176
|
-
if (!shouldContinue) {
|
|
177
|
-
break;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
// Store execution round info
|
|
181
|
-
this.allToolExecutionRounds.push({
|
|
182
|
-
round: currentRound,
|
|
183
|
-
toolCalls: currentToolCalls,
|
|
184
|
-
response: currentResponse,
|
|
185
|
-
});
|
|
186
|
-
// Build turn context for tool execution
|
|
198
|
+
// Build turn context for this round (for async parameter resolution only)
|
|
187
199
|
const turnContext = {
|
|
188
200
|
numberOfTurns: currentRound + 1, // 1-indexed
|
|
189
|
-
messageHistory: currentInput,
|
|
190
|
-
...(this.options.request.model && {
|
|
191
|
-
model: this.options.request.model,
|
|
192
|
-
}),
|
|
193
|
-
...(this.options.request.models && {
|
|
194
|
-
models: this.options.request.models,
|
|
195
|
-
}),
|
|
196
201
|
};
|
|
202
|
+
// Resolve async functions for this turn
|
|
203
|
+
if (hasAsyncFunctions(this.options.request)) {
|
|
204
|
+
const resolved = await resolveAsyncFunctions(this.options.request, turnContext);
|
|
205
|
+
// Update resolved request with new values
|
|
206
|
+
this.resolvedRequest = {
|
|
207
|
+
...resolved,
|
|
208
|
+
stream: false, // Tool execution turns don't need streaming
|
|
209
|
+
};
|
|
210
|
+
}
|
|
197
211
|
// Execute all tool calls
|
|
198
212
|
const toolResults = [];
|
|
199
213
|
for (const toolCall of currentToolCalls) {
|
|
@@ -203,12 +217,11 @@ export class ModelResult {
|
|
|
203
217
|
}
|
|
204
218
|
const result = await executeTool(tool, toolCall, turnContext);
|
|
205
219
|
// Store preliminary results
|
|
206
|
-
if (result.preliminaryResults &&
|
|
207
|
-
result.preliminaryResults.length > 0) {
|
|
220
|
+
if (result.preliminaryResults && result.preliminaryResults.length > 0) {
|
|
208
221
|
this.preliminaryResults.set(toolCall.id, result.preliminaryResults);
|
|
209
222
|
}
|
|
210
223
|
toolResults.push({
|
|
211
|
-
type:
|
|
224
|
+
type: 'function_call_output',
|
|
212
225
|
id: `output_${toolCall.id}`,
|
|
213
226
|
callId: toolCall.id,
|
|
214
227
|
output: result.error
|
|
@@ -218,19 +231,40 @@ export class ModelResult {
|
|
|
218
231
|
: JSON.stringify(result.result),
|
|
219
232
|
});
|
|
220
233
|
}
|
|
234
|
+
// Store execution round info including tool results
|
|
235
|
+
this.allToolExecutionRounds.push({
|
|
236
|
+
round: currentRound,
|
|
237
|
+
toolCalls: currentToolCalls,
|
|
238
|
+
response: currentResponse,
|
|
239
|
+
toolResults,
|
|
240
|
+
});
|
|
241
|
+
// Execute nextTurnParams functions for tools that were called
|
|
242
|
+
if (this.options.tools && currentToolCalls.length > 0) {
|
|
243
|
+
if (!this.resolvedRequest) {
|
|
244
|
+
throw new Error('Request not initialized');
|
|
245
|
+
}
|
|
246
|
+
const computedParams = await executeNextTurnParamsFunctions(currentToolCalls, this.options.tools, this.resolvedRequest);
|
|
247
|
+
// Apply computed parameters to the resolved request for next turn
|
|
248
|
+
if (Object.keys(computedParams).length > 0) {
|
|
249
|
+
this.resolvedRequest = applyNextTurnParamsToRequest(this.resolvedRequest, computedParams);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
221
252
|
// Build new input with tool results
|
|
222
253
|
// For the Responses API, we need to include the tool results in the input
|
|
223
254
|
const newInput = [
|
|
224
255
|
...(Array.isArray(currentResponse.output)
|
|
225
256
|
? currentResponse.output
|
|
226
|
-
: [
|
|
257
|
+
: [
|
|
258
|
+
currentResponse.output,
|
|
259
|
+
]),
|
|
227
260
|
...toolResults,
|
|
228
261
|
];
|
|
229
|
-
// Update current input for next iteration
|
|
230
|
-
currentInput = newInput;
|
|
231
262
|
// Make new request with tool results
|
|
263
|
+
if (!this.resolvedRequest) {
|
|
264
|
+
throw new Error('Request not initialized');
|
|
265
|
+
}
|
|
232
266
|
const newRequest = {
|
|
233
|
-
...this.
|
|
267
|
+
...this.resolvedRequest,
|
|
234
268
|
input: newInput,
|
|
235
269
|
stream: false,
|
|
236
270
|
};
|
|
@@ -249,18 +283,17 @@ export class ModelResult {
|
|
|
249
283
|
currentResponse = value;
|
|
250
284
|
}
|
|
251
285
|
else {
|
|
252
|
-
throw new Error(
|
|
286
|
+
throw new Error('Unexpected response type from API');
|
|
253
287
|
}
|
|
254
288
|
currentRound++;
|
|
255
289
|
}
|
|
256
290
|
// Validate the final response has required fields
|
|
257
291
|
if (!currentResponse || !currentResponse.id || !currentResponse.output) {
|
|
258
|
-
throw new Error(
|
|
292
|
+
throw new Error('Invalid final response: missing required fields');
|
|
259
293
|
}
|
|
260
294
|
// Ensure the response is in a completed state (has output content)
|
|
261
|
-
if (!Array.isArray(currentResponse.output) ||
|
|
262
|
-
|
|
263
|
-
throw new Error("Invalid final response: empty or invalid output");
|
|
295
|
+
if (!Array.isArray(currentResponse.output) || currentResponse.output.length === 0) {
|
|
296
|
+
throw new Error('Invalid final response: empty or invalid output');
|
|
264
297
|
}
|
|
265
298
|
this.finalResponse = currentResponse;
|
|
266
299
|
})();
|
|
@@ -272,7 +305,7 @@ export class ModelResult {
|
|
|
272
305
|
async getTextInternal() {
|
|
273
306
|
await this.executeToolsIfNeeded();
|
|
274
307
|
if (!this.finalResponse) {
|
|
275
|
-
throw new Error(
|
|
308
|
+
throw new Error('Response not available');
|
|
276
309
|
}
|
|
277
310
|
return extractTextFromResponse(this.finalResponse);
|
|
278
311
|
}
|
|
@@ -295,7 +328,7 @@ export class ModelResult {
|
|
|
295
328
|
async getResponse() {
|
|
296
329
|
await this.executeToolsIfNeeded();
|
|
297
330
|
if (!this.finalResponse) {
|
|
298
|
-
throw new Error(
|
|
331
|
+
throw new Error('Response not available');
|
|
299
332
|
}
|
|
300
333
|
return this.finalResponse;
|
|
301
334
|
}
|
|
@@ -308,7 +341,7 @@ export class ModelResult {
|
|
|
308
341
|
return async function* () {
|
|
309
342
|
await this.initStream();
|
|
310
343
|
if (!this.reusableStream) {
|
|
311
|
-
throw new Error(
|
|
344
|
+
throw new Error('Stream not initialized');
|
|
312
345
|
}
|
|
313
346
|
const consumer = this.reusableStream.createConsumer();
|
|
314
347
|
// Yield original events directly
|
|
@@ -321,9 +354,9 @@ export class ModelResult {
|
|
|
321
354
|
for (const [toolCallId, results] of this.preliminaryResults) {
|
|
322
355
|
for (const result of results) {
|
|
323
356
|
yield {
|
|
324
|
-
type:
|
|
357
|
+
type: 'tool.preliminary_result',
|
|
325
358
|
toolCallId,
|
|
326
|
-
result,
|
|
359
|
+
result: result,
|
|
327
360
|
timestamp: Date.now(),
|
|
328
361
|
};
|
|
329
362
|
}
|
|
@@ -338,7 +371,7 @@ export class ModelResult {
|
|
|
338
371
|
return async function* () {
|
|
339
372
|
await this.initStream();
|
|
340
373
|
if (!this.reusableStream) {
|
|
341
|
-
throw new Error(
|
|
374
|
+
throw new Error('Stream not initialized');
|
|
342
375
|
}
|
|
343
376
|
yield* extractTextDeltas(this.reusableStream);
|
|
344
377
|
}.call(this);
|
|
@@ -353,38 +386,22 @@ export class ModelResult {
|
|
|
353
386
|
return async function* () {
|
|
354
387
|
await this.initStream();
|
|
355
388
|
if (!this.reusableStream) {
|
|
356
|
-
throw new Error(
|
|
389
|
+
throw new Error('Stream not initialized');
|
|
357
390
|
}
|
|
358
391
|
// First yield messages from the stream in responses format
|
|
359
392
|
yield* buildResponsesMessageStream(this.reusableStream);
|
|
360
393
|
// Execute tools if needed
|
|
361
394
|
await this.executeToolsIfNeeded();
|
|
362
|
-
// Yield function call
|
|
395
|
+
// Yield function call outputs for each executed tool
|
|
363
396
|
for (const round of this.allToolExecutionRounds) {
|
|
364
|
-
for (const
|
|
365
|
-
|
|
366
|
-
const tool = this.options.tools?.find((t) => t.function.name === toolCall.name);
|
|
367
|
-
if (!tool || !hasExecuteFunction(tool)) {
|
|
368
|
-
continue;
|
|
369
|
-
}
|
|
370
|
-
// Get the result from preliminary results or construct from the response
|
|
371
|
-
const prelimResults = this.preliminaryResults.get(toolCall.id);
|
|
372
|
-
const result = prelimResults && prelimResults.length > 0
|
|
373
|
-
? prelimResults[prelimResults.length - 1] // Last result is the final output
|
|
374
|
-
: undefined;
|
|
375
|
-
// Yield function call output in responses format
|
|
376
|
-
yield {
|
|
377
|
-
type: "function_call_output",
|
|
378
|
-
id: `output_${toolCall.id}`,
|
|
379
|
-
callId: toolCall.id,
|
|
380
|
-
output: result !== undefined ? JSON.stringify(result) : "",
|
|
381
|
-
};
|
|
397
|
+
for (const toolResult of round.toolResults) {
|
|
398
|
+
yield toolResult;
|
|
382
399
|
}
|
|
383
400
|
}
|
|
384
401
|
// If tools were executed, yield the final message (if there is one)
|
|
385
402
|
if (this.finalResponse && this.allToolExecutionRounds.length > 0) {
|
|
386
403
|
// Check if the final response contains a message
|
|
387
|
-
const hasMessage = this.finalResponse.output.some((item) => hasTypeProperty(item) && item.type ===
|
|
404
|
+
const hasMessage = this.finalResponse.output.some((item) => hasTypeProperty(item) && item.type === 'message');
|
|
388
405
|
if (hasMessage) {
|
|
389
406
|
yield extractResponsesMessageFromResponse(this.finalResponse);
|
|
390
407
|
}
|
|
@@ -399,7 +416,7 @@ export class ModelResult {
|
|
|
399
416
|
return async function* () {
|
|
400
417
|
await this.initStream();
|
|
401
418
|
if (!this.reusableStream) {
|
|
402
|
-
throw new Error(
|
|
419
|
+
throw new Error('Stream not initialized');
|
|
403
420
|
}
|
|
404
421
|
yield* extractReasoningDeltas(this.reusableStream);
|
|
405
422
|
}.call(this);
|
|
@@ -414,12 +431,12 @@ export class ModelResult {
|
|
|
414
431
|
return async function* () {
|
|
415
432
|
await this.initStream();
|
|
416
433
|
if (!this.reusableStream) {
|
|
417
|
-
throw new Error(
|
|
434
|
+
throw new Error('Stream not initialized');
|
|
418
435
|
}
|
|
419
436
|
// Yield tool deltas as structured events
|
|
420
437
|
for await (const delta of extractToolDeltas(this.reusableStream)) {
|
|
421
438
|
yield {
|
|
422
|
-
type:
|
|
439
|
+
type: 'delta',
|
|
423
440
|
content: delta,
|
|
424
441
|
};
|
|
425
442
|
}
|
|
@@ -429,65 +446,9 @@ export class ModelResult {
|
|
|
429
446
|
for (const [toolCallId, results] of this.preliminaryResults) {
|
|
430
447
|
for (const result of results) {
|
|
431
448
|
yield {
|
|
432
|
-
type:
|
|
433
|
-
toolCallId,
|
|
434
|
-
result,
|
|
435
|
-
};
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
}.call(this);
|
|
439
|
-
}
|
|
440
|
-
/**
|
|
441
|
-
* Stream events in chat format (compatibility layer).
|
|
442
|
-
* Note: This transforms responses API events into a chat-like format.
|
|
443
|
-
* Includes preliminary tool result events after tool execution.
|
|
444
|
-
*
|
|
445
|
-
* @remarks
|
|
446
|
-
* This is a compatibility method that attempts to transform the responses API
|
|
447
|
-
* stream into a format similar to the chat API. Due to differences in the APIs,
|
|
448
|
-
* this may not be a perfect mapping.
|
|
449
|
-
*/
|
|
450
|
-
getFullChatStream() {
|
|
451
|
-
return async function* () {
|
|
452
|
-
await this.initStream();
|
|
453
|
-
if (!this.reusableStream) {
|
|
454
|
-
throw new Error("Stream not initialized");
|
|
455
|
-
}
|
|
456
|
-
const consumer = this.reusableStream.createConsumer();
|
|
457
|
-
for await (const event of consumer) {
|
|
458
|
-
if (!("type" in event)) {
|
|
459
|
-
continue;
|
|
460
|
-
}
|
|
461
|
-
// Transform responses events to chat-like format using type guards
|
|
462
|
-
if (isOutputTextDeltaEvent(event)) {
|
|
463
|
-
yield {
|
|
464
|
-
type: "content.delta",
|
|
465
|
-
delta: event.delta,
|
|
466
|
-
};
|
|
467
|
-
}
|
|
468
|
-
else if (isResponseCompletedEvent(event)) {
|
|
469
|
-
yield {
|
|
470
|
-
type: "message.complete",
|
|
471
|
-
response: event.response,
|
|
472
|
-
};
|
|
473
|
-
}
|
|
474
|
-
else {
|
|
475
|
-
// Pass through other events
|
|
476
|
-
yield {
|
|
477
|
-
type: event.type,
|
|
478
|
-
event,
|
|
479
|
-
};
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
// After stream completes, check if tools were executed and emit preliminary results
|
|
483
|
-
await this.executeToolsIfNeeded();
|
|
484
|
-
// Emit all preliminary results
|
|
485
|
-
for (const [toolCallId, results] of this.preliminaryResults) {
|
|
486
|
-
for (const result of results) {
|
|
487
|
-
yield {
|
|
488
|
-
type: "tool.preliminary_result",
|
|
449
|
+
type: 'preliminary_result',
|
|
489
450
|
toolCallId,
|
|
490
|
-
result,
|
|
451
|
+
result: result,
|
|
491
452
|
};
|
|
492
453
|
}
|
|
493
454
|
}
|
|
@@ -502,7 +463,7 @@ export class ModelResult {
|
|
|
502
463
|
async getToolCalls() {
|
|
503
464
|
await this.initStream();
|
|
504
465
|
if (!this.reusableStream) {
|
|
505
|
-
throw new Error(
|
|
466
|
+
throw new Error('Stream not initialized');
|
|
506
467
|
}
|
|
507
468
|
const completedResponse = await consumeStreamForCompletion(this.reusableStream);
|
|
508
469
|
return extractToolCallsFromResponse(completedResponse);
|
|
@@ -515,7 +476,7 @@ export class ModelResult {
|
|
|
515
476
|
return async function* () {
|
|
516
477
|
await this.initStream();
|
|
517
478
|
if (!this.reusableStream) {
|
|
518
|
-
throw new Error(
|
|
479
|
+
throw new Error('Stream not initialized');
|
|
519
480
|
}
|
|
520
481
|
yield* buildToolCallStream(this.reusableStream);
|
|
521
482
|
}.call(this);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type * as models from '../models/index.js';
|
|
2
|
+
import type { NextTurnParamsContext, ParsedToolCall, Tool } from './tool-types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Build a NextTurnParamsContext from the current request
|
|
5
|
+
* Extracts relevant fields that can be modified by nextTurnParams functions
|
|
6
|
+
*
|
|
7
|
+
* @param request - The current OpenResponsesRequest
|
|
8
|
+
* @returns Context object with current parameter values
|
|
9
|
+
*/
|
|
10
|
+
export declare function buildNextTurnParamsContext(request: models.OpenResponsesRequest): NextTurnParamsContext;
|
|
11
|
+
/**
|
|
12
|
+
* Execute nextTurnParams functions for all called tools
|
|
13
|
+
* Composes functions when multiple tools modify the same parameter
|
|
14
|
+
*
|
|
15
|
+
* @param toolCalls - Tool calls that were executed in this turn
|
|
16
|
+
* @param tools - All available tools
|
|
17
|
+
* @param currentRequest - The current request
|
|
18
|
+
* @returns Object with computed parameter values
|
|
19
|
+
*/
|
|
20
|
+
export declare function executeNextTurnParamsFunctions(toolCalls: ParsedToolCall<Tool>[], tools: readonly Tool[], currentRequest: models.OpenResponsesRequest): Promise<Partial<NextTurnParamsContext>>;
|
|
21
|
+
/**
|
|
22
|
+
* Apply computed nextTurnParams to the current request
|
|
23
|
+
* Returns a new request object with updated parameters
|
|
24
|
+
*
|
|
25
|
+
* @param request - The current request
|
|
26
|
+
* @param computedParams - Computed parameter values from nextTurnParams functions
|
|
27
|
+
* @returns New request with updated parameters
|
|
28
|
+
*/
|
|
29
|
+
export declare function applyNextTurnParamsToRequest(request: models.OpenResponsesRequest, computedParams: Partial<NextTurnParamsContext>): models.OpenResponsesRequest;
|
|
30
|
+
//# sourceMappingURL=next-turn-params.d.ts.map
|