@zhivex-ai/openai 0.9.6 → 0.10.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.
- package/README.md +10 -3
- package/dist/capabilities.d.ts +13 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +178 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +296 -249
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { toJSONSchema, z } from "zod";
|
|
2
2
|
import { createOpenAIImageGenerationModel, normalizeOpenAIImageGenerationCall, normalizeOpenAIImageGenerationPartialImage } from "./image-generation.js";
|
|
3
|
-
import {
|
|
3
|
+
import { capabilities, groundedCapabilities, inferOpenAIRealtimeMode, isOpenAIGpt56Model, modelCapabilities, openAIRealtimeSupportsImageInput, realtimeCapabilities, speechCapabilities, supportsOpenAIApplyPatchAndSkills, supportsOpenAIShell, transcriptionCapabilities, } from "./capabilities.js";
|
|
4
|
+
import { CallbackRealtimeSession, ConfigurationError, ProviderHTTPError, ProviderResponseTooLargeError, ProviderToolCallError, assertTrustedEndpoint, decodeBase64WithLimit, readBodyWithLimit, readErrorBodyWithLimit, readJsonWithLimit, resolveAudioResponseLimits, openWebSocketConnection, hostedTool, providerDataPart, UnsupportedFeatureError, createProviderAdapter, encodeAudioFrame, encodeMediaFrame, isCallableToolDefinition, isHostedToolDefinition, normalizeFinishReason, streamSSE, toToolSet, toolResultPayload, withRetry, withTimeoutSignal } from "@zhivex-ai/core";
|
|
4
5
|
const MIB = 1024 * 1024;
|
|
5
6
|
const DEFAULT_HOSTED_IMAGE_EVENT_BYTES = 32 * MIB;
|
|
6
7
|
const DEFAULT_HOSTED_IMAGE_TOTAL_BYTES = 128 * MIB;
|
|
8
|
+
const DEFAULT_TOOL_CALL_ARGUMENT_CHARS = MIB;
|
|
7
9
|
const HOSTED_IMAGE_EVENT_JSON_OVERHEAD_CHARS = MIB;
|
|
10
|
+
export const OPENAI_RESPONSES_TOOL_CALL_ERROR_CODE = "OPENAI_RESPONSES_TOOL_CALL_INVALID";
|
|
8
11
|
const normalizeOpenAIResponseLimit = (value, fallback, name) => {
|
|
9
12
|
const resolved = value ?? fallback;
|
|
10
13
|
if (!Number.isSafeInteger(resolved) || resolved <= 0) {
|
|
@@ -15,7 +18,16 @@ const normalizeOpenAIResponseLimit = (value, fallback, name) => {
|
|
|
15
18
|
const resolveOpenAIResponseLimits = (limits = {}) => ({
|
|
16
19
|
...resolveAudioResponseLimits(limits),
|
|
17
20
|
hostedImageEventBytes: normalizeOpenAIResponseLimit(limits.hostedImageEventBytes, DEFAULT_HOSTED_IMAGE_EVENT_BYTES, "hostedImageEventBytes"),
|
|
18
|
-
hostedImageTotalBytes: normalizeOpenAIResponseLimit(limits.hostedImageTotalBytes, DEFAULT_HOSTED_IMAGE_TOTAL_BYTES, "hostedImageTotalBytes")
|
|
21
|
+
hostedImageTotalBytes: normalizeOpenAIResponseLimit(limits.hostedImageTotalBytes, DEFAULT_HOSTED_IMAGE_TOTAL_BYTES, "hostedImageTotalBytes"),
|
|
22
|
+
toolCallArgumentChars: normalizeOpenAIResponseLimit(limits.toolCallArgumentChars, DEFAULT_TOOL_CALL_ARGUMENT_CHARS, "toolCallArgumentChars")
|
|
23
|
+
});
|
|
24
|
+
const openAIResponsesToolCallError = (reason, effectsPossible = false) => new ProviderToolCallError({
|
|
25
|
+
provider: "openai",
|
|
26
|
+
transport: "responses",
|
|
27
|
+
diagnosticCode: OPENAI_RESPONSES_TOOL_CALL_ERROR_CODE,
|
|
28
|
+
reason,
|
|
29
|
+
retryable: !effectsPossible,
|
|
30
|
+
effectsPossible
|
|
19
31
|
});
|
|
20
32
|
const openAIResponsesToolMetadataKey = "openai.responses_tool_type";
|
|
21
33
|
const openAIResponsesFunctionConfigMetadataKey = "openai.responses_function_config";
|
|
@@ -45,174 +57,6 @@ const assertOpenAIToolPathInsideRoot = async (rootDir, targetPath, label) => {
|
|
|
45
57
|
return target;
|
|
46
58
|
};
|
|
47
59
|
export const openAIRealtimeMcpMetadataKey = "openai.realtime_mcp";
|
|
48
|
-
const capabilities = {
|
|
49
|
-
streaming: true,
|
|
50
|
-
tools: true,
|
|
51
|
-
structuredOutput: true,
|
|
52
|
-
jsonMode: true,
|
|
53
|
-
toolChoice: true,
|
|
54
|
-
parallelToolCalls: true,
|
|
55
|
-
vision: true,
|
|
56
|
-
files: false,
|
|
57
|
-
audioInput: false,
|
|
58
|
-
audioOutput: false,
|
|
59
|
-
embeddings: true,
|
|
60
|
-
reasoning: true,
|
|
61
|
-
webSearch: true,
|
|
62
|
-
agentCapabilities: {
|
|
63
|
-
supportTier: "tier-a",
|
|
64
|
-
toolChoiceNone: true,
|
|
65
|
-
approvalRequests: true,
|
|
66
|
-
hostedWebSearch: true,
|
|
67
|
-
hostedFileSearch: true,
|
|
68
|
-
remoteMcp: true,
|
|
69
|
-
computerUse: true,
|
|
70
|
-
codeExecution: true,
|
|
71
|
-
shell: true,
|
|
72
|
-
applyPatch: true,
|
|
73
|
-
toolSearch: true,
|
|
74
|
-
skills: true,
|
|
75
|
-
toolsets: false
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
const normalizeModelId = (modelId) => modelId.trim().toLowerCase();
|
|
79
|
-
const isOpenAIGpt56Model = (modelId) => /^gpt-5\.6(?:$|-(?:sol|terra|luna)(?:-|$)|-\d{4}-\d{2}-\d{2})/.test(normalizeModelId(modelId));
|
|
80
|
-
const isOpenAIGpt55BaseModel = (modelId) => /^gpt-5\.5(?:$|-\d{4}-\d{2}-\d{2})/.test(normalizeModelId(modelId));
|
|
81
|
-
const isOpenAIGpt55ProModel = (modelId) => /^gpt-5\.5-pro(?:$|-\d{4}-\d{2}-\d{2})/.test(normalizeModelId(modelId));
|
|
82
|
-
const isOpenAIGpt54BaseModel = (modelId) => /^gpt-5\.4(?:$|-\d{4}-\d{2}-\d{2})/.test(normalizeModelId(modelId));
|
|
83
|
-
const isOpenAIGpt54MiniModel = (modelId) => /^gpt-5\.4-mini(?:$|-\d{4}-\d{2}-\d{2})/.test(normalizeModelId(modelId));
|
|
84
|
-
const isOpenAIGpt54NanoModel = (modelId) => /^gpt-5\.4-nano(?:$|-\d{4}-\d{2}-\d{2})/.test(normalizeModelId(modelId));
|
|
85
|
-
const isOpenAIGpt54ProModel = (modelId) => /^gpt-5\.4-pro(?:$|-\d{4}-\d{2}-\d{2})/.test(normalizeModelId(modelId));
|
|
86
|
-
const supportsOpenAIToolSearch = (modelId) => isOpenAIGpt56Model(modelId) || isOpenAIGpt55BaseModel(modelId) || isOpenAIGpt54BaseModel(modelId) || isOpenAIGpt54MiniModel(modelId);
|
|
87
|
-
const supportsOpenAIComputerUse = (modelId) => isOpenAIGpt56Model(modelId) || isOpenAIGpt55BaseModel(modelId) || isOpenAIGpt54BaseModel(modelId) || isOpenAIGpt54MiniModel(modelId);
|
|
88
|
-
const supportsOpenAIShell = (modelId) => isOpenAIGpt56Model(modelId) ||
|
|
89
|
-
isOpenAIGpt55BaseModel(modelId) ||
|
|
90
|
-
isOpenAIGpt55ProModel(modelId) ||
|
|
91
|
-
isOpenAIGpt54BaseModel(modelId) ||
|
|
92
|
-
isOpenAIGpt54MiniModel(modelId) ||
|
|
93
|
-
isOpenAIGpt54NanoModel(modelId) ||
|
|
94
|
-
isOpenAIGpt54ProModel(modelId);
|
|
95
|
-
const supportsOpenAIApplyPatchAndSkills = (modelId) => isOpenAIGpt56Model(modelId) ||
|
|
96
|
-
isOpenAIGpt55BaseModel(modelId) ||
|
|
97
|
-
isOpenAIGpt54BaseModel(modelId) ||
|
|
98
|
-
isOpenAIGpt54MiniModel(modelId) ||
|
|
99
|
-
isOpenAIGpt54NanoModel(modelId);
|
|
100
|
-
const supportsOpenAIChatAudio = (modelId) => {
|
|
101
|
-
const normalized = normalizeModelId(modelId);
|
|
102
|
-
return /^(?:gpt-audio(?:-|$)|gpt-4o(?:-mini)?-audio-preview(?:-|$))/.test(normalized);
|
|
103
|
-
};
|
|
104
|
-
const modelCapabilities = (modelId) => ({
|
|
105
|
-
...capabilities,
|
|
106
|
-
explicitPromptCaching: isOpenAIGpt56Model(modelId),
|
|
107
|
-
files: isOpenAIGpt56Model(modelId),
|
|
108
|
-
reasoningEfforts: isOpenAIGpt56Model(modelId)
|
|
109
|
-
? ["none", "low", "medium", "high", "xhigh", "max"]
|
|
110
|
-
: undefined,
|
|
111
|
-
reasoningModes: isOpenAIGpt56Model(modelId) ? ["standard", "pro"] : undefined,
|
|
112
|
-
reasoningContexts: isOpenAIGpt56Model(modelId) ? ["auto", "current_turn", "all_turns"] : undefined,
|
|
113
|
-
audioInput: supportsOpenAIChatAudio(modelId),
|
|
114
|
-
audioOutput: supportsOpenAIChatAudio(modelId),
|
|
115
|
-
agentCapabilities: {
|
|
116
|
-
...capabilities.agentCapabilities,
|
|
117
|
-
computerUse: supportsOpenAIComputerUse(modelId),
|
|
118
|
-
shell: supportsOpenAIShell(modelId),
|
|
119
|
-
applyPatch: supportsOpenAIApplyPatchAndSkills(modelId),
|
|
120
|
-
skills: supportsOpenAIApplyPatchAndSkills(modelId),
|
|
121
|
-
toolSearch: supportsOpenAIToolSearch(modelId),
|
|
122
|
-
programmaticToolCalling: isOpenAIGpt56Model(modelId),
|
|
123
|
-
multiAgent: isOpenAIGpt56Model(modelId)
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
const transcriptionCapabilities = {
|
|
127
|
-
...capabilities,
|
|
128
|
-
streaming: false,
|
|
129
|
-
tools: false,
|
|
130
|
-
structuredOutput: false,
|
|
131
|
-
jsonMode: false,
|
|
132
|
-
toolChoice: false,
|
|
133
|
-
parallelToolCalls: false,
|
|
134
|
-
vision: false,
|
|
135
|
-
audioInput: true,
|
|
136
|
-
audioOutput: false,
|
|
137
|
-
embeddings: false,
|
|
138
|
-
reasoning: false,
|
|
139
|
-
webSearch: false,
|
|
140
|
-
agentCapabilities: {
|
|
141
|
-
supportTier: "tier-c",
|
|
142
|
-
toolChoiceNone: false,
|
|
143
|
-
approvalRequests: false,
|
|
144
|
-
hostedWebSearch: false,
|
|
145
|
-
hostedFileSearch: false,
|
|
146
|
-
remoteMcp: false,
|
|
147
|
-
computerUse: false,
|
|
148
|
-
codeExecution: false,
|
|
149
|
-
toolsets: false
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
const speechCapabilities = {
|
|
153
|
-
...transcriptionCapabilities,
|
|
154
|
-
audioInput: false,
|
|
155
|
-
audioOutput: true
|
|
156
|
-
};
|
|
157
|
-
const groundedCapabilities = {
|
|
158
|
-
...capabilities,
|
|
159
|
-
webSearch: true
|
|
160
|
-
};
|
|
161
|
-
const isOpenAIRealtimeTranslationModel = (modelId) => /^gpt-realtime-translate(?:[-@]|$)/.test(modelId);
|
|
162
|
-
const isOpenAIRealtimeTranscriptionModel = (modelId) => /^gpt-realtime-whisper(?:[-@]|$)/.test(modelId);
|
|
163
|
-
const inferOpenAIRealtimeMode = (modelId, mode) => {
|
|
164
|
-
if (mode) {
|
|
165
|
-
return mode;
|
|
166
|
-
}
|
|
167
|
-
if (isOpenAIRealtimeTranslationModel(modelId)) {
|
|
168
|
-
return "translation";
|
|
169
|
-
}
|
|
170
|
-
if (isOpenAIRealtimeTranscriptionModel(modelId)) {
|
|
171
|
-
return "transcription";
|
|
172
|
-
}
|
|
173
|
-
return "conversation";
|
|
174
|
-
};
|
|
175
|
-
const isOpenAIRealtimeReasoningModel = (modelId) => /^gpt-realtime-2(?:\.1(?:-mini)?)?(?:-\d{4}-\d{2}-\d{2}|@.*)?$/.test(modelId);
|
|
176
|
-
const openAIRealtimeSupportsImageInput = (modelId) => /^(?:gpt-realtime|gpt-realtime-mini|gpt-realtime-1\.5|gpt-realtime-2(?:\.1(?:-mini)?)?)(?:-\d{4}-\d{2}-\d{2}|@.*)?$/.test(modelId);
|
|
177
|
-
const realtimeCapabilities = (modelId) => ({
|
|
178
|
-
...capabilities,
|
|
179
|
-
streaming: false,
|
|
180
|
-
structuredOutput: false,
|
|
181
|
-
jsonMode: false,
|
|
182
|
-
embeddings: false,
|
|
183
|
-
audioInput: true,
|
|
184
|
-
audioOutput: !isOpenAIRealtimeTranscriptionModel(modelId),
|
|
185
|
-
tools: !isOpenAIRealtimeTranslationModel(modelId) && !isOpenAIRealtimeTranscriptionModel(modelId),
|
|
186
|
-
toolChoice: !isOpenAIRealtimeTranslationModel(modelId) && !isOpenAIRealtimeTranscriptionModel(modelId),
|
|
187
|
-
parallelToolCalls: !isOpenAIRealtimeTranslationModel(modelId) && !isOpenAIRealtimeTranscriptionModel(modelId),
|
|
188
|
-
vision: openAIRealtimeSupportsImageInput(modelId),
|
|
189
|
-
reasoning: isOpenAIRealtimeReasoningModel(modelId),
|
|
190
|
-
webSearch: false,
|
|
191
|
-
agentCapabilities: {
|
|
192
|
-
...capabilities.agentCapabilities,
|
|
193
|
-
supportTier: isOpenAIRealtimeTranslationModel(modelId) || isOpenAIRealtimeTranscriptionModel(modelId) ? "tier-c" : "tier-a",
|
|
194
|
-
toolChoiceNone: !isOpenAIRealtimeTranslationModel(modelId) && !isOpenAIRealtimeTranscriptionModel(modelId),
|
|
195
|
-
approvalRequests: !isOpenAIRealtimeTranslationModel(modelId) && !isOpenAIRealtimeTranscriptionModel(modelId),
|
|
196
|
-
hostedWebSearch: false,
|
|
197
|
-
hostedFileSearch: false,
|
|
198
|
-
remoteMcp: !isOpenAIRealtimeTranslationModel(modelId) && !isOpenAIRealtimeTranscriptionModel(modelId),
|
|
199
|
-
computerUse: false,
|
|
200
|
-
codeExecution: false,
|
|
201
|
-
shell: false,
|
|
202
|
-
applyPatch: false,
|
|
203
|
-
toolSearch: false,
|
|
204
|
-
skills: false,
|
|
205
|
-
toolsets: false
|
|
206
|
-
},
|
|
207
|
-
realtime: {
|
|
208
|
-
sessions: true,
|
|
209
|
-
audioInput: true,
|
|
210
|
-
audioOutput: !isOpenAIRealtimeTranscriptionModel(modelId),
|
|
211
|
-
imageInput: openAIRealtimeSupportsImageInput(modelId),
|
|
212
|
-
tools: !isOpenAIRealtimeTranslationModel(modelId) && !isOpenAIRealtimeTranscriptionModel(modelId),
|
|
213
|
-
browserTokens: true
|
|
214
|
-
}
|
|
215
|
-
});
|
|
216
60
|
const jsonHeaders = (apiKey) => ({
|
|
217
61
|
"content-type": "application/json",
|
|
218
62
|
authorization: `Bearer ${apiKey}`
|
|
@@ -1220,6 +1064,23 @@ const parseAssistantMessage = (message) => ({
|
|
|
1220
1064
|
})) ?? [])
|
|
1221
1065
|
]
|
|
1222
1066
|
});
|
|
1067
|
+
const parseOpenAIResponsesToolArguments = (rawArguments, maxChars, effectsPossible = false) => {
|
|
1068
|
+
if (typeof rawArguments !== "string") {
|
|
1069
|
+
throw openAIResponsesToolCallError("incomplete_arguments", effectsPossible);
|
|
1070
|
+
}
|
|
1071
|
+
if (rawArguments.trim().length === 0) {
|
|
1072
|
+
throw openAIResponsesToolCallError("empty_arguments", effectsPossible);
|
|
1073
|
+
}
|
|
1074
|
+
if (rawArguments.length > maxChars) {
|
|
1075
|
+
throw openAIResponsesToolCallError("arguments_too_large", effectsPossible);
|
|
1076
|
+
}
|
|
1077
|
+
try {
|
|
1078
|
+
return JSON.parse(rawArguments);
|
|
1079
|
+
}
|
|
1080
|
+
catch {
|
|
1081
|
+
throw openAIResponsesToolCallError("invalid_json", effectsPossible);
|
|
1082
|
+
}
|
|
1083
|
+
};
|
|
1223
1084
|
const extractAudioOutputs = (message) => message.parts
|
|
1224
1085
|
.filter((part) => part.type === "audio")
|
|
1225
1086
|
.map((part) => ({
|
|
@@ -1301,9 +1162,29 @@ const toResponsesInput = (messages) => {
|
|
|
1301
1162
|
}
|
|
1302
1163
|
return input;
|
|
1303
1164
|
};
|
|
1304
|
-
const parseResponsesAssistantMessage = (json, multiAgentEnabled = false, localTools = new Map()) => {
|
|
1165
|
+
const parseResponsesAssistantMessage = (json, multiAgentEnabled = false, localTools = new Map(), toolCallArgumentChars = DEFAULT_TOOL_CALL_ARGUMENT_CHARS) => {
|
|
1305
1166
|
const parts = [];
|
|
1306
|
-
|
|
1167
|
+
const output = Array.isArray(json.output) ? json.output : [];
|
|
1168
|
+
const responseStatus = typeof json.status === "string" ? json.status : undefined;
|
|
1169
|
+
const isExecutableToolOutput = (item) => item?.type === "function_call" ||
|
|
1170
|
+
(item?.type === "shell_call" && localTools.has("shell")) ||
|
|
1171
|
+
(item?.type === "apply_patch_call" && localTools.has("apply_patch")) ||
|
|
1172
|
+
(item?.type === "computer_call" && localTools.has("computer"));
|
|
1173
|
+
const hasExecutableToolOutput = output.some(isExecutableToolOutput);
|
|
1174
|
+
if (hasExecutableToolOutput && responseStatus !== "completed") {
|
|
1175
|
+
throw openAIResponsesToolCallError(responseStatus === "failed"
|
|
1176
|
+
? "response_failed"
|
|
1177
|
+
: responseStatus === "incomplete"
|
|
1178
|
+
? "response_incomplete"
|
|
1179
|
+
: "inconsistent_metadata");
|
|
1180
|
+
}
|
|
1181
|
+
const nonCompletedToolOutput = output.find((item) => isExecutableToolOutput(item) &&
|
|
1182
|
+
typeof item.status === "string" &&
|
|
1183
|
+
item.status !== "completed");
|
|
1184
|
+
if (nonCompletedToolOutput) {
|
|
1185
|
+
throw openAIResponsesToolCallError(nonCompletedToolOutput.status === "failed" ? "response_failed" : "incomplete_arguments");
|
|
1186
|
+
}
|
|
1187
|
+
for (const [index, item] of output.entries()) {
|
|
1307
1188
|
if (item?.type === "message") {
|
|
1308
1189
|
if (multiAgentEnabled && (item.agent?.agent_name !== "/root" || item.phase !== "final_answer")) {
|
|
1309
1190
|
continue;
|
|
@@ -1319,13 +1200,21 @@ const parseResponsesAssistantMessage = (json, multiAgentEnabled = false, localTo
|
|
|
1319
1200
|
continue;
|
|
1320
1201
|
}
|
|
1321
1202
|
if (item?.type === "function_call") {
|
|
1322
|
-
|
|
1203
|
+
if (typeof item.call_id !== "string" ||
|
|
1204
|
+
item.call_id.length === 0 ||
|
|
1205
|
+
typeof item.name !== "string" ||
|
|
1206
|
+
item.name.length === 0) {
|
|
1207
|
+
throw openAIResponsesToolCallError("inconsistent_metadata");
|
|
1208
|
+
}
|
|
1209
|
+
if (item.status === "incomplete" || item.status === "failed") {
|
|
1210
|
+
throw openAIResponsesToolCallError(item.status === "failed" ? "response_failed" : "incomplete_arguments");
|
|
1211
|
+
}
|
|
1323
1212
|
parts.push({
|
|
1324
1213
|
type: "tool-call",
|
|
1325
1214
|
toolCall: {
|
|
1326
|
-
id:
|
|
1215
|
+
id: item.call_id,
|
|
1327
1216
|
name: item.name,
|
|
1328
|
-
input:
|
|
1217
|
+
input: parseOpenAIResponsesToolArguments(item.arguments, toolCallArgumentChars),
|
|
1329
1218
|
...(item.caller && typeof item.caller === "object"
|
|
1330
1219
|
? { providerMetadata: { caller: item.caller } }
|
|
1331
1220
|
: {})
|
|
@@ -1404,6 +1293,9 @@ const extractResponsesImageOutputs = (response, outputFormat = "png") => (Array.
|
|
|
1404
1293
|
return normalized?.image ? [normalized.image] : [];
|
|
1405
1294
|
});
|
|
1406
1295
|
const normalizeResponsesFinishReason = (status, hasToolCalls, hasRefusal = false) => {
|
|
1296
|
+
if (status === "failed") {
|
|
1297
|
+
return "error";
|
|
1298
|
+
}
|
|
1407
1299
|
if (hasToolCalls) {
|
|
1408
1300
|
return "tool-calls";
|
|
1409
1301
|
}
|
|
@@ -1413,9 +1305,6 @@ const normalizeResponsesFinishReason = (status, hasToolCalls, hasRefusal = false
|
|
|
1413
1305
|
if (status === "completed") {
|
|
1414
1306
|
return "stop";
|
|
1415
1307
|
}
|
|
1416
|
-
if (status === "failed") {
|
|
1417
|
-
return "error";
|
|
1418
|
-
}
|
|
1419
1308
|
return normalizeFinishReason(status);
|
|
1420
1309
|
};
|
|
1421
1310
|
const mapResponsesUsage = (usage) => usage
|
|
@@ -1453,14 +1342,19 @@ const addTokenUsage = (left, right) => {
|
|
|
1453
1342
|
totalTokens: sum(left.totalTokens, right.totalTokens)
|
|
1454
1343
|
};
|
|
1455
1344
|
};
|
|
1456
|
-
const streamResponses = async function* (response, multiAgentEnabled = false, localTools = new Map(), imageGeneration) {
|
|
1345
|
+
const streamResponses = async function* (response, multiAgentEnabled = false, localTools = new Map(), imageGeneration, toolCallArgumentChars = DEFAULT_TOOL_CALL_ARGUMENT_CHARS) {
|
|
1457
1346
|
const toolBuffers = new Map();
|
|
1347
|
+
const toolBuffersByOutputIndex = new Map();
|
|
1348
|
+
const pendingExecutableEvents = [];
|
|
1349
|
+
const pendingExecutableProviderEvents = [];
|
|
1458
1350
|
const outputAgents = new Map();
|
|
1459
1351
|
const hostedImageEventMaxBytes = imageGeneration?.eventMaxBytes ?? DEFAULT_HOSTED_IMAGE_EVENT_BYTES;
|
|
1460
1352
|
const hostedImageTotalMaxBytes = imageGeneration?.totalMaxBytes ?? DEFAULT_HOSTED_IMAGE_TOTAL_BYTES;
|
|
1461
1353
|
let hostedImageBytes = 0;
|
|
1462
1354
|
let sawToolCalls = false;
|
|
1463
1355
|
let sawRefusal = false;
|
|
1356
|
+
let sawTerminalResponse = false;
|
|
1357
|
+
let nextToolOrder = 0;
|
|
1464
1358
|
const recordHostedImageBytes = (image) => {
|
|
1465
1359
|
const receivedBytes = hostedImageBytes + (image.data?.byteLength ?? 0);
|
|
1466
1360
|
if (receivedBytes > hostedImageTotalMaxBytes) {
|
|
@@ -1473,32 +1367,155 @@ const streamResponses = async function* (response, multiAgentEnabled = false, lo
|
|
|
1473
1367
|
}
|
|
1474
1368
|
hostedImageBytes = receivedBytes;
|
|
1475
1369
|
};
|
|
1476
|
-
const
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
return undefined;
|
|
1370
|
+
const toolBufferKey = (itemId, outputIndex) => {
|
|
1371
|
+
if (typeof itemId === "string" && itemId.length > 0) {
|
|
1372
|
+
return `item:${itemId}`;
|
|
1480
1373
|
}
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1374
|
+
if (typeof outputIndex === "number" && Number.isSafeInteger(outputIndex) && outputIndex >= 0) {
|
|
1375
|
+
return `output:${outputIndex}`;
|
|
1376
|
+
}
|
|
1377
|
+
throw openAIResponsesToolCallError("inconsistent_metadata", sawToolCalls);
|
|
1378
|
+
};
|
|
1379
|
+
const getToolBuffer = (key, itemId, outputIndex) => {
|
|
1380
|
+
const canonicalItemId = typeof itemId === "string" && itemId.length > 0 ? itemId : undefined;
|
|
1381
|
+
const canonicalOutputIndex = typeof outputIndex === "number" && Number.isSafeInteger(outputIndex) && outputIndex >= 0
|
|
1382
|
+
? outputIndex
|
|
1383
|
+
: undefined;
|
|
1384
|
+
const bindItemId = (toolCall) => {
|
|
1385
|
+
if (canonicalItemId !== undefined &&
|
|
1386
|
+
toolCall.itemId !== undefined &&
|
|
1387
|
+
toolCall.itemId !== canonicalItemId) {
|
|
1388
|
+
throw openAIResponsesToolCallError("inconsistent_metadata", sawToolCalls);
|
|
1389
|
+
}
|
|
1390
|
+
if (canonicalItemId !== undefined) {
|
|
1391
|
+
toolCall.itemId = canonicalItemId;
|
|
1490
1392
|
}
|
|
1491
1393
|
};
|
|
1394
|
+
const bindOutputIndex = (toolCall) => {
|
|
1395
|
+
if (canonicalOutputIndex === undefined) {
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
if (toolCall.outputIndex !== undefined && toolCall.outputIndex !== canonicalOutputIndex) {
|
|
1399
|
+
throw openAIResponsesToolCallError("inconsistent_metadata", sawToolCalls);
|
|
1400
|
+
}
|
|
1401
|
+
const indexed = toolBuffersByOutputIndex.get(canonicalOutputIndex);
|
|
1402
|
+
if (indexed && indexed !== toolCall) {
|
|
1403
|
+
throw openAIResponsesToolCallError("inconsistent_metadata", sawToolCalls);
|
|
1404
|
+
}
|
|
1405
|
+
toolCall.outputIndex = canonicalOutputIndex;
|
|
1406
|
+
toolBuffersByOutputIndex.set(canonicalOutputIndex, toolCall);
|
|
1407
|
+
};
|
|
1408
|
+
const existing = toolBuffers.get(key);
|
|
1409
|
+
if (existing) {
|
|
1410
|
+
bindItemId(existing);
|
|
1411
|
+
bindOutputIndex(existing);
|
|
1412
|
+
return existing;
|
|
1413
|
+
}
|
|
1414
|
+
if (canonicalOutputIndex !== undefined) {
|
|
1415
|
+
const indexed = toolBuffersByOutputIndex.get(canonicalOutputIndex);
|
|
1416
|
+
if (indexed) {
|
|
1417
|
+
bindItemId(indexed);
|
|
1418
|
+
toolBuffers.set(key, indexed);
|
|
1419
|
+
return indexed;
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
const created = {
|
|
1423
|
+
...(canonicalItemId !== undefined ? { itemId: canonicalItemId } : {}),
|
|
1424
|
+
deltaArguments: "",
|
|
1425
|
+
argumentsDone: false,
|
|
1426
|
+
outputItemDone: false,
|
|
1427
|
+
emitted: false,
|
|
1428
|
+
order: nextToolOrder++,
|
|
1429
|
+
...(canonicalOutputIndex !== undefined ? { outputIndex: canonicalOutputIndex } : {})
|
|
1430
|
+
};
|
|
1431
|
+
toolBuffers.set(key, created);
|
|
1432
|
+
if (created.outputIndex !== undefined) {
|
|
1433
|
+
toolBuffersByOutputIndex.set(created.outputIndex, created);
|
|
1434
|
+
}
|
|
1435
|
+
return created;
|
|
1436
|
+
};
|
|
1437
|
+
const mergeToolString = (toolCall, field, value) => {
|
|
1438
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
1439
|
+
return;
|
|
1440
|
+
}
|
|
1441
|
+
if (toolCall[field] !== undefined && toolCall[field] !== value) {
|
|
1442
|
+
throw openAIResponsesToolCallError("inconsistent_metadata", sawToolCalls);
|
|
1443
|
+
}
|
|
1444
|
+
toolCall[field] = value;
|
|
1445
|
+
};
|
|
1446
|
+
const ensureArgumentLimit = (argumentsValue) => {
|
|
1447
|
+
if (argumentsValue.length > toolCallArgumentChars) {
|
|
1448
|
+
throw openAIResponsesToolCallError("arguments_too_large", sawToolCalls);
|
|
1449
|
+
}
|
|
1450
|
+
};
|
|
1451
|
+
const setFinalArguments = (toolCall, argumentsValue) => {
|
|
1452
|
+
if (typeof argumentsValue !== "string") {
|
|
1453
|
+
return;
|
|
1454
|
+
}
|
|
1455
|
+
ensureArgumentLimit(argumentsValue);
|
|
1456
|
+
if (toolCall.finalArguments !== undefined && toolCall.finalArguments !== argumentsValue) {
|
|
1457
|
+
throw openAIResponsesToolCallError("inconsistent_metadata", sawToolCalls);
|
|
1458
|
+
}
|
|
1459
|
+
if (toolCall.deltaArguments.length > 0 && toolCall.deltaArguments !== argumentsValue) {
|
|
1460
|
+
throw openAIResponsesToolCallError("inconsistent_metadata", sawToolCalls);
|
|
1461
|
+
}
|
|
1462
|
+
toolCall.finalArguments = argumentsValue;
|
|
1463
|
+
};
|
|
1464
|
+
const materializeToolCalls = () => {
|
|
1465
|
+
const pending = [...new Set(toolBuffers.values())]
|
|
1466
|
+
.filter((toolCall) => !toolCall.emitted)
|
|
1467
|
+
.sort((left, right) => (left.outputIndex ?? Number.MAX_SAFE_INTEGER) - (right.outputIndex ?? Number.MAX_SAFE_INTEGER) ||
|
|
1468
|
+
left.order - right.order);
|
|
1469
|
+
const events = pending.map((toolCall) => {
|
|
1470
|
+
if (!toolCall.callId ||
|
|
1471
|
+
!toolCall.name ||
|
|
1472
|
+
(!toolCall.argumentsDone && !toolCall.outputItemDone)) {
|
|
1473
|
+
throw openAIResponsesToolCallError("incomplete_arguments", sawToolCalls);
|
|
1474
|
+
}
|
|
1475
|
+
if (toolCall.itemStatus === "failed" || toolCall.itemStatus === "incomplete") {
|
|
1476
|
+
throw openAIResponsesToolCallError(toolCall.itemStatus === "failed" ? "response_failed" : "incomplete_arguments", sawToolCalls);
|
|
1477
|
+
}
|
|
1478
|
+
const rawArguments = toolCall.finalArguments ?? toolCall.deltaArguments;
|
|
1479
|
+
const input = parseOpenAIResponsesToolArguments(rawArguments, toolCallArgumentChars, sawToolCalls);
|
|
1480
|
+
return {
|
|
1481
|
+
type: "tool-call",
|
|
1482
|
+
toolCall: {
|
|
1483
|
+
id: toolCall.callId,
|
|
1484
|
+
name: toolCall.name,
|
|
1485
|
+
input,
|
|
1486
|
+
...(toolCall.caller !== undefined ? { providerMetadata: { caller: toolCall.caller } } : {})
|
|
1487
|
+
}
|
|
1488
|
+
};
|
|
1489
|
+
});
|
|
1490
|
+
for (const toolCall of pending) {
|
|
1491
|
+
toolCall.emitted = true;
|
|
1492
|
+
}
|
|
1493
|
+
if (events.length > 0) {
|
|
1494
|
+
sawToolCalls = true;
|
|
1495
|
+
}
|
|
1496
|
+
return events;
|
|
1492
1497
|
};
|
|
1493
1498
|
const maxHostedImageEventChars = Math.min(Number.MAX_SAFE_INTEGER, 4 * Math.ceil(hostedImageEventMaxBytes / 3) + HOSTED_IMAGE_EVENT_JSON_OVERHEAD_CHARS);
|
|
1494
1499
|
for await (const event of streamSSE(response, imageGeneration
|
|
1495
1500
|
? { maxEventChars: maxHostedImageEventChars, maxBufferChars: maxHostedImageEventChars }
|
|
1496
1501
|
: undefined)) {
|
|
1497
1502
|
if (event.data === "[DONE]") {
|
|
1498
|
-
|
|
1503
|
+
break;
|
|
1504
|
+
}
|
|
1505
|
+
let json;
|
|
1506
|
+
try {
|
|
1507
|
+
json = JSON.parse(event.data);
|
|
1508
|
+
}
|
|
1509
|
+
catch (error) {
|
|
1510
|
+
if (toolBuffers.size > 0 || sawToolCalls) {
|
|
1511
|
+
throw openAIResponsesToolCallError("stream_truncated", sawToolCalls);
|
|
1512
|
+
}
|
|
1513
|
+
throw error;
|
|
1499
1514
|
}
|
|
1500
|
-
const json = JSON.parse(event.data);
|
|
1501
1515
|
const type = json.type;
|
|
1516
|
+
if (sawTerminalResponse) {
|
|
1517
|
+
continue;
|
|
1518
|
+
}
|
|
1502
1519
|
if (type === "response.image_generation_call.partial_image") {
|
|
1503
1520
|
const normalized = normalizeOpenAIImageGenerationPartialImage(json, imageGeneration?.outputFormat ?? "png", hostedImageEventMaxBytes);
|
|
1504
1521
|
if (normalized) {
|
|
@@ -1516,6 +1533,9 @@ const streamResponses = async function* (response, multiAgentEnabled = false, lo
|
|
|
1516
1533
|
continue;
|
|
1517
1534
|
}
|
|
1518
1535
|
if (type === "error") {
|
|
1536
|
+
if (toolBuffers.size > 0 || pendingExecutableEvents.length > 0 || sawToolCalls) {
|
|
1537
|
+
throw openAIResponsesToolCallError("response_failed", sawToolCalls);
|
|
1538
|
+
}
|
|
1519
1539
|
throw new ProviderHTTPError(`OpenAI Responses stream failed: ${json.error?.message ?? json.message ?? "unknown error"}`, 500, { responseBody: JSON.stringify(json) });
|
|
1520
1540
|
}
|
|
1521
1541
|
if (type === "response.output_text.delta" &&
|
|
@@ -1536,6 +1556,16 @@ const streamResponses = async function* (response, multiAgentEnabled = false, lo
|
|
|
1536
1556
|
if (type === "response.output_item.added" || type === "response.output_item.done") {
|
|
1537
1557
|
const item = json.item;
|
|
1538
1558
|
let handledLocalToolCall = false;
|
|
1559
|
+
const isLocalExecutableItem = item?.type === "function_call" ||
|
|
1560
|
+
(item?.type === "shell_call" && localTools.has("shell")) ||
|
|
1561
|
+
(item?.type === "apply_patch_call" && localTools.has("apply_patch")) ||
|
|
1562
|
+
(item?.type === "computer_call" && localTools.has("computer"));
|
|
1563
|
+
if (type === "response.output_item.done" &&
|
|
1564
|
+
isLocalExecutableItem &&
|
|
1565
|
+
typeof item.status === "string" &&
|
|
1566
|
+
item.status !== "completed") {
|
|
1567
|
+
throw openAIResponsesToolCallError(item.status === "failed" ? "response_failed" : "incomplete_arguments", sawToolCalls);
|
|
1568
|
+
}
|
|
1539
1569
|
if (item?.type === "image_generation_call" && type === "response.output_item.done") {
|
|
1540
1570
|
const normalized = normalizeOpenAIImageGenerationCall(item, imageGeneration?.outputFormat ?? "png", hostedImageEventMaxBytes);
|
|
1541
1571
|
if (normalized?.image) {
|
|
@@ -1556,31 +1586,26 @@ const streamResponses = async function* (response, multiAgentEnabled = false, lo
|
|
|
1556
1586
|
});
|
|
1557
1587
|
}
|
|
1558
1588
|
if (item?.type === "function_call") {
|
|
1559
|
-
const
|
|
1560
|
-
const
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
emitted: false
|
|
1565
|
-
};
|
|
1566
|
-
existing.callId = item.call_id ?? existing.callId;
|
|
1567
|
-
existing.name ||= item.name ?? "";
|
|
1589
|
+
const itemId = item.id ?? json.item_id;
|
|
1590
|
+
const key = toolBufferKey(itemId, json.output_index);
|
|
1591
|
+
const existing = getToolBuffer(key, itemId, json.output_index);
|
|
1592
|
+
mergeToolString(existing, "callId", item.call_id);
|
|
1593
|
+
mergeToolString(existing, "name", item.name);
|
|
1568
1594
|
if (item.caller && typeof item.caller === "object") {
|
|
1569
1595
|
existing.caller = item.caller;
|
|
1570
1596
|
}
|
|
1571
|
-
if (typeof item.arguments === "string") {
|
|
1572
|
-
existing.args = item.arguments;
|
|
1573
|
-
}
|
|
1574
|
-
toolBuffers.set(key, existing);
|
|
1575
1597
|
if (type === "response.output_item.done") {
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1598
|
+
existing.outputItemDone = true;
|
|
1599
|
+
existing.itemStatus = typeof item.status === "string" ? item.status : existing.itemStatus;
|
|
1600
|
+
setFinalArguments(existing, item.arguments);
|
|
1601
|
+
}
|
|
1602
|
+
else if (typeof item.arguments === "string" && item.arguments.length > 0) {
|
|
1603
|
+
ensureArgumentLimit(item.arguments);
|
|
1604
|
+
existing.deltaArguments = item.arguments;
|
|
1580
1605
|
}
|
|
1581
1606
|
}
|
|
1582
1607
|
if (item?.type === "shell_call" && type === "response.output_item.done" && localTools.has("shell")) {
|
|
1583
|
-
|
|
1608
|
+
pendingExecutableEvents.push({
|
|
1584
1609
|
type: "tool-call",
|
|
1585
1610
|
toolCall: {
|
|
1586
1611
|
id: item.call_id ?? item.id ?? `${json.output_index ?? "shell"}`,
|
|
@@ -1588,12 +1613,11 @@ const streamResponses = async function* (response, multiAgentEnabled = false, lo
|
|
|
1588
1613
|
input: parseShellCallInput(item),
|
|
1589
1614
|
providerMetadata: { responsesToolType: "shell" }
|
|
1590
1615
|
}
|
|
1591
|
-
};
|
|
1592
|
-
sawToolCalls = true;
|
|
1616
|
+
});
|
|
1593
1617
|
handledLocalToolCall = true;
|
|
1594
1618
|
}
|
|
1595
1619
|
if (item?.type === "apply_patch_call" && type === "response.output_item.done" && localTools.has("apply_patch")) {
|
|
1596
|
-
|
|
1620
|
+
pendingExecutableEvents.push({
|
|
1597
1621
|
type: "tool-call",
|
|
1598
1622
|
toolCall: {
|
|
1599
1623
|
id: item.call_id ?? item.id ?? `${json.output_index ?? "apply_patch"}`,
|
|
@@ -1601,12 +1625,11 @@ const streamResponses = async function* (response, multiAgentEnabled = false, lo
|
|
|
1601
1625
|
input: parseApplyPatchCallInput(item),
|
|
1602
1626
|
providerMetadata: { responsesToolType: "apply_patch" }
|
|
1603
1627
|
}
|
|
1604
|
-
};
|
|
1605
|
-
sawToolCalls = true;
|
|
1628
|
+
});
|
|
1606
1629
|
handledLocalToolCall = true;
|
|
1607
1630
|
}
|
|
1608
1631
|
if (item?.type === "computer_call" && type === "response.output_item.done" && localTools.has("computer")) {
|
|
1609
|
-
|
|
1632
|
+
pendingExecutableEvents.push({
|
|
1610
1633
|
type: "tool-call",
|
|
1611
1634
|
toolCall: {
|
|
1612
1635
|
id: item.call_id ?? item.id ?? `${json.output_index ?? "computer"}`,
|
|
@@ -1616,8 +1639,7 @@ const streamResponses = async function* (response, multiAgentEnabled = false, lo
|
|
|
1616
1639
|
},
|
|
1617
1640
|
providerMetadata: { responsesToolType: "computer" }
|
|
1618
1641
|
}
|
|
1619
|
-
};
|
|
1620
|
-
sawToolCalls = true;
|
|
1642
|
+
});
|
|
1621
1643
|
handledLocalToolCall = true;
|
|
1622
1644
|
}
|
|
1623
1645
|
const providerData = parseResponsesProviderData(item);
|
|
@@ -1629,7 +1651,7 @@ const streamResponses = async function* (response, multiAgentEnabled = false, lo
|
|
|
1629
1651
|
};
|
|
1630
1652
|
}
|
|
1631
1653
|
if (item && type === "response.output_item.done") {
|
|
1632
|
-
|
|
1654
|
+
const outputEvent = {
|
|
1633
1655
|
type: "provider-data",
|
|
1634
1656
|
provider: "openai",
|
|
1635
1657
|
data: {
|
|
@@ -1637,41 +1659,60 @@ const streamResponses = async function* (response, multiAgentEnabled = false, lo
|
|
|
1637
1659
|
items: [item]
|
|
1638
1660
|
}
|
|
1639
1661
|
};
|
|
1662
|
+
if (item.type === "function_call" || handledLocalToolCall) {
|
|
1663
|
+
pendingExecutableProviderEvents.push(outputEvent);
|
|
1664
|
+
}
|
|
1665
|
+
else {
|
|
1666
|
+
yield outputEvent;
|
|
1667
|
+
}
|
|
1640
1668
|
}
|
|
1641
1669
|
continue;
|
|
1642
1670
|
}
|
|
1643
1671
|
if (type === "response.function_call_arguments.delta") {
|
|
1644
|
-
const key = json.item_id
|
|
1645
|
-
const existing =
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1672
|
+
const key = toolBufferKey(json.item_id, json.output_index);
|
|
1673
|
+
const existing = getToolBuffer(key, json.item_id, json.output_index);
|
|
1674
|
+
mergeToolString(existing, "callId", json.call_id);
|
|
1675
|
+
mergeToolString(existing, "name", json.name);
|
|
1676
|
+
if (typeof json.delta === "string") {
|
|
1677
|
+
const nextArguments = existing.deltaArguments + json.delta;
|
|
1678
|
+
ensureArgumentLimit(nextArguments);
|
|
1679
|
+
existing.deltaArguments = nextArguments;
|
|
1680
|
+
}
|
|
1653
1681
|
continue;
|
|
1654
1682
|
}
|
|
1655
1683
|
if (type === "response.function_call_arguments.done") {
|
|
1656
|
-
const key = json.item_id
|
|
1657
|
-
const existing =
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
};
|
|
1663
|
-
if (typeof json.arguments === "string") {
|
|
1664
|
-
existing.args = json.arguments;
|
|
1665
|
-
}
|
|
1666
|
-
toolBuffers.set(key, existing);
|
|
1667
|
-
const emitted = emitToolCall(key);
|
|
1668
|
-
if (emitted) {
|
|
1669
|
-
yield emitted;
|
|
1670
|
-
}
|
|
1684
|
+
const key = toolBufferKey(json.item_id, json.output_index);
|
|
1685
|
+
const existing = getToolBuffer(key, json.item_id, json.output_index);
|
|
1686
|
+
mergeToolString(existing, "callId", json.call_id);
|
|
1687
|
+
mergeToolString(existing, "name", json.name);
|
|
1688
|
+
existing.argumentsDone = true;
|
|
1689
|
+
setFinalArguments(existing, json.arguments);
|
|
1671
1690
|
continue;
|
|
1672
1691
|
}
|
|
1673
1692
|
if (type === "response.completed" || type === "response.failed" || type === "response.incomplete") {
|
|
1674
1693
|
const responseData = json.response ?? {};
|
|
1694
|
+
const responseStatus = typeof responseData.status === "string"
|
|
1695
|
+
? responseData.status
|
|
1696
|
+
: type.slice("response.".length);
|
|
1697
|
+
sawTerminalResponse = true;
|
|
1698
|
+
if (responseStatus === "completed") {
|
|
1699
|
+
for (const toolCallEvent of materializeToolCalls()) {
|
|
1700
|
+
yield toolCallEvent;
|
|
1701
|
+
}
|
|
1702
|
+
if (pendingExecutableEvents.length > 0) {
|
|
1703
|
+
sawToolCalls = true;
|
|
1704
|
+
for (const toolCallEvent of pendingExecutableEvents) {
|
|
1705
|
+
yield toolCallEvent;
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
for (const providerEvent of pendingExecutableProviderEvents) {
|
|
1709
|
+
yield providerEvent;
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
else if ((responseStatus === "failed" || responseStatus === "incomplete") &&
|
|
1713
|
+
(toolBuffers.size > 0 || pendingExecutableEvents.length > 0 || sawToolCalls)) {
|
|
1714
|
+
throw openAIResponsesToolCallError(responseStatus === "failed" ? "response_failed" : "response_incomplete", sawToolCalls);
|
|
1715
|
+
}
|
|
1675
1716
|
if (typeof responseData.id === "string") {
|
|
1676
1717
|
yield {
|
|
1677
1718
|
type: "provider-data",
|
|
@@ -1681,12 +1722,17 @@ const streamResponses = async function* (response, multiAgentEnabled = false, lo
|
|
|
1681
1722
|
}
|
|
1682
1723
|
yield {
|
|
1683
1724
|
type: "finish",
|
|
1684
|
-
finishReason: normalizeResponsesFinishReason(
|
|
1685
|
-
providerFinishReason:
|
|
1725
|
+
finishReason: normalizeResponsesFinishReason(responseStatus, sawToolCalls, sawRefusal),
|
|
1726
|
+
providerFinishReason: responseStatus,
|
|
1686
1727
|
usage: mapResponsesUsage(responseData.usage)
|
|
1687
1728
|
};
|
|
1729
|
+
continue;
|
|
1688
1730
|
}
|
|
1689
1731
|
}
|
|
1732
|
+
if (!sawTerminalResponse &&
|
|
1733
|
+
(toolBuffers.size > 0 || pendingExecutableEvents.length > 0 || sawToolCalls)) {
|
|
1734
|
+
throw openAIResponsesToolCallError("stream_truncated", sawToolCalls);
|
|
1735
|
+
}
|
|
1690
1736
|
};
|
|
1691
1737
|
const streamGenerateResult = async function* (result) {
|
|
1692
1738
|
for (const message of result.messages ?? (result.message ? [result.message] : [])) {
|
|
@@ -1805,7 +1851,7 @@ class OpenAILanguageModel {
|
|
|
1805
1851
|
}), input);
|
|
1806
1852
|
const json = await parseJson(response);
|
|
1807
1853
|
accumulatedUsage = addTokenUsage(accumulatedUsage, mapResponsesUsage(json.usage));
|
|
1808
|
-
const assistantMessage = parseResponsesAssistantMessage(json, options.multiAgentEnabled, localResponsesTools(input.tools));
|
|
1854
|
+
const assistantMessage = parseResponsesAssistantMessage(json, options.multiAgentEnabled, localResponsesTools(input.tools), this.responseLimits.toolCallArgumentChars);
|
|
1809
1855
|
const currentOutput = Array.isArray(json.output)
|
|
1810
1856
|
? json.output
|
|
1811
1857
|
: [];
|
|
@@ -1937,9 +1983,10 @@ class OpenAILanguageModel {
|
|
|
1937
1983
|
})
|
|
1938
1984
|
}), input);
|
|
1939
1985
|
const imageGeneration = responsesImageGenerationConfig(input.tools, this.responseLimits);
|
|
1986
|
+
const toolCallArgumentChars = this.responseLimits.toolCallArgumentChars;
|
|
1940
1987
|
return (async function* () {
|
|
1941
1988
|
try {
|
|
1942
|
-
yield* streamResponses(response, options.multiAgentEnabled, localResponsesTools(input.tools), imageGeneration);
|
|
1989
|
+
yield* streamResponses(response, options.multiAgentEnabled, localResponsesTools(input.tools), imageGeneration, toolCallArgumentChars);
|
|
1943
1990
|
}
|
|
1944
1991
|
finally {
|
|
1945
1992
|
cleanup();
|