@openclaw/ai 2026.7.2-beta.5 → 2026.7.2-beta.7
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/dist/{anthropic-CQVj3le6.mjs → anthropic-CH4UUnZr.mjs} +14 -463
- package/dist/anthropic-usage-DWU-x8MI.mjs +459 -0
- package/dist/{azure-openai-responses-DIYgsqFM.mjs → azure-openai-responses-CImcwB83.mjs} +4 -3
- package/dist/azure-openai-responses-client-compat-C7K7QfUE.mjs +62 -0
- package/dist/cache-retention-0x979a5V.mjs +12 -0
- package/dist/deferred-event-buffer-DAvyP7qA.mjs +19 -0
- package/dist/github-copilot-headers-NCJtz9i0.mjs +37 -0
- package/dist/{google-f-A8xrae.mjs → google-CtSg0iTS.mjs} +3 -3
- package/dist/{google-shared-J6qvYINH.mjs → google-shared-DNBz5rcD.mjs} +5 -3
- package/dist/{google-vertex-D3yMVXIY.mjs → google-vertex-31f1uS9L.mjs} +3 -3
- package/dist/host-Dog2WQiR.mjs +369 -0
- package/dist/index.mjs +1 -1
- package/dist/internal/anthropic.d.mts +3 -53
- package/dist/internal/anthropic.mjs +3 -2
- package/dist/internal/openai.d.mts +259 -2
- package/dist/internal/openai.mjs +8 -4
- package/dist/internal/runtime.mjs +6 -4
- package/dist/internal/shared.d.mts +1 -1
- package/dist/internal/shared.mjs +5 -1
- package/dist/{llm-request-activity-CehVkZP-.mjs → llm-request-activity-BjtkplhG.mjs} +1 -19
- package/dist/{mistral-CKV-TOQj.mjs → mistral-CWmpvWYh.mjs} +5 -3
- package/dist/{openai-chatgpt-responses-CedIj0hk.mjs → openai-chatgpt-responses-B84Ibtrd.mjs} +18 -13
- package/dist/openai-completions-DsOxhOD1.mjs +630 -0
- package/dist/openai-completions-compat-DBWjXoMZ.d.mts +43 -0
- package/dist/openai-reasoning-compat-YgeLncHw.mjs +396 -0
- package/dist/openai-responses-BT7A3sLu.mjs +138 -0
- package/dist/openai-responses-shared-pXl6Wd8S.mjs +392 -0
- package/dist/{openai-D3PD6PE-.mjs → openai-responses-stream-internal-Cw5txaGW.mjs} +1409 -1863
- package/dist/openai-tool-projection-OhX64DoP.mjs +215 -0
- package/dist/{provider-error-apVOZI6G.mjs → provider-error-CAEvRjry.mjs} +1 -1
- package/dist/provider-options-D8bB3z9b.d.mts +144 -0
- package/dist/providers.mjs +8 -8
- package/dist/{stream-first-event-timeout-C3OgBjIk.mjs → reasoning-tag-text-partitioner-CGDyLWUR.mjs} +1 -86
- package/dist/simple-options-9lhRrN73.mjs +50 -0
- package/dist/stream-first-event-timeout-BBys9hSb.mjs +86 -0
- package/dist/tls-certificate-errors-DXSpluKI.mjs +93 -0
- package/dist/tool-result-text-CTpIRbYd.mjs +225 -0
- package/dist/{github-copilot-headers-BCoBNmL7.mjs → tool-schema-json-projection-BwNu3nDi.mjs} +1 -48
- package/dist/transform-messages-C8mBqZxF.mjs +2 -0
- package/dist/{transport-stream-shared-BbMELSI4.mjs → transport-stream-shared-D81p90xq.mjs} +4 -4
- package/dist/transports.d.mts +13 -33
- package/dist/transports.mjs +75 -34
- package/package.json +4 -4
- package/dist/host-XYGZcgO8.mjs +0 -98
- package/dist/openai-BPor_3WI.d.mts +0 -358
- package/dist/openai-completions-CiSutyu0.mjs +0 -1223
- package/dist/shared-CdjNZd35.mjs +0 -634
|
@@ -1,19 +1,13 @@
|
|
|
1
|
-
import { n as
|
|
2
|
-
import { t as AssistantMessageEventStream } from "./event-stream-D8n2uFee.mjs";
|
|
3
|
-
import { n as getAiTransportHost } from "./host-XYGZcgO8.mjs";
|
|
1
|
+
import { g as isRecord, m as normalizeOptionalString, n as getAiTransportHost, p as normalizeLowercaseStringOrEmpty } from "./host-Dog2WQiR.mjs";
|
|
4
2
|
import { n as clampOpenAIPromptCacheKey } from "./openai-prompt-cache-mZTCdRPo.mjs";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { c as calculateCost, l as clampThinkingLevel } from "./number-coercion-DvG7SNMg.mjs";
|
|
9
|
-
import { b as redactIdentifier, d as transportAbortError, l as sanitizeNonEmptyTransportPayloadText, u as sanitizeTransportPayloadText, x as redactSensitiveText } from "./transport-stream-shared-BbMELSI4.mjs";
|
|
10
|
-
import { t as headersToRecord } from "./headers-B_e4-1J0.mjs";
|
|
3
|
+
import { a as isImageWithMediaPayload, d as stripSystemPromptCacheBoundary, o as truncateUtf16Safe, r as extractToolResultText, t as describeToolResultMediaPlaceholder } from "./tool-result-text-CTpIRbYd.mjs";
|
|
4
|
+
import { u as transformTransportMessages } from "./openai-tool-projection-OhX64DoP.mjs";
|
|
5
|
+
import { c as calculateCost } from "./number-coercion-DvG7SNMg.mjs";
|
|
11
6
|
import { n as parseStreamingJson } from "./json-parse-BvXNt1-7.mjs";
|
|
12
|
-
import {
|
|
7
|
+
import { b as redactIdentifier, d as transportAbortError, l as sanitizeNonEmptyTransportPayloadText, u as sanitizeTransportPayloadText, x as redactSensitiveText } from "./transport-stream-shared-D81p90xq.mjs";
|
|
8
|
+
import { a as withFirstStreamEventTimeout } from "./stream-first-event-timeout-BBys9hSb.mjs";
|
|
13
9
|
import { t as shortHash } from "./hash-CHgqbJmD.mjs";
|
|
14
|
-
import {
|
|
15
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
16
|
-
import OpenAI from "openai";
|
|
10
|
+
import { randomUUID } from "node:crypto";
|
|
17
11
|
//#region packages/ai/src/transports/model-transport-debug.ts
|
|
18
12
|
function normalizeEnv(value) {
|
|
19
13
|
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
@@ -66,6 +60,159 @@ function uniqueStrings(values) {
|
|
|
66
60
|
return uniqueValues(values);
|
|
67
61
|
}
|
|
68
62
|
//#endregion
|
|
63
|
+
//#region packages/ai/src/providers/openai-reasoning-effort.ts
|
|
64
|
+
/**
|
|
65
|
+
* OpenAI-compatible reasoning-effort normalization. Different GPT families
|
|
66
|
+
* expose different accepted effort enums, so callers map requested values here
|
|
67
|
+
* before constructing provider payloads.
|
|
68
|
+
*/
|
|
69
|
+
const GPT_5_REASONING_EFFORTS = [
|
|
70
|
+
"minimal",
|
|
71
|
+
"low",
|
|
72
|
+
"medium",
|
|
73
|
+
"high"
|
|
74
|
+
];
|
|
75
|
+
const GPT_51_REASONING_EFFORTS = [
|
|
76
|
+
"none",
|
|
77
|
+
"low",
|
|
78
|
+
"medium",
|
|
79
|
+
"high"
|
|
80
|
+
];
|
|
81
|
+
const GPT_52_REASONING_EFFORTS = [
|
|
82
|
+
"none",
|
|
83
|
+
"low",
|
|
84
|
+
"medium",
|
|
85
|
+
"high",
|
|
86
|
+
"xhigh"
|
|
87
|
+
];
|
|
88
|
+
const GPT_56_REASONING_EFFORTS = [
|
|
89
|
+
"none",
|
|
90
|
+
"low",
|
|
91
|
+
"medium",
|
|
92
|
+
"high",
|
|
93
|
+
"xhigh",
|
|
94
|
+
"max"
|
|
95
|
+
];
|
|
96
|
+
const GPT_CODEX_REASONING_EFFORTS = [
|
|
97
|
+
"low",
|
|
98
|
+
"medium",
|
|
99
|
+
"high",
|
|
100
|
+
"xhigh"
|
|
101
|
+
];
|
|
102
|
+
const GPT_PRO_REASONING_EFFORTS = [
|
|
103
|
+
"medium",
|
|
104
|
+
"high",
|
|
105
|
+
"xhigh"
|
|
106
|
+
];
|
|
107
|
+
const GPT_5_PRO_REASONING_EFFORTS = ["high"];
|
|
108
|
+
const GPT_51_CODEX_MAX_REASONING_EFFORTS = [
|
|
109
|
+
"none",
|
|
110
|
+
"medium",
|
|
111
|
+
"high",
|
|
112
|
+
"xhigh"
|
|
113
|
+
];
|
|
114
|
+
const GPT_51_CODEX_MINI_REASONING_EFFORTS = ["medium"];
|
|
115
|
+
const GENERIC_REASONING_EFFORTS = [
|
|
116
|
+
"low",
|
|
117
|
+
"medium",
|
|
118
|
+
"high"
|
|
119
|
+
];
|
|
120
|
+
const CANONICAL_REASONING_EFFORTS = /* @__PURE__ */ new Set([
|
|
121
|
+
"none",
|
|
122
|
+
"minimal",
|
|
123
|
+
"low",
|
|
124
|
+
"medium",
|
|
125
|
+
"high",
|
|
126
|
+
"xhigh",
|
|
127
|
+
"max",
|
|
128
|
+
"off"
|
|
129
|
+
]);
|
|
130
|
+
function normalizeModelId(id) {
|
|
131
|
+
return normalizeLowercaseStringOrEmpty(id ?? "").replace(/-\d{4}-\d{2}-\d{2}$/u, "");
|
|
132
|
+
}
|
|
133
|
+
/** Return whether a model is the GPT-5.4 mini family. */
|
|
134
|
+
function isOpenAIGpt54MiniModel(model) {
|
|
135
|
+
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
136
|
+
return /^gpt-5\.4-mini(?:-|$)/u.test(id);
|
|
137
|
+
}
|
|
138
|
+
/** Return whether a model is the GPT-5.5 family. */
|
|
139
|
+
function isOpenAIGpt55Model(model) {
|
|
140
|
+
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
141
|
+
const name = normalizeModelId(typeof model.name === "string" ? model.name : void 0);
|
|
142
|
+
return /^gpt-5\.5(?:-|$)/u.test(id) || /^gpt-5\.5(?:\s|\(|-|$)/u.test(name);
|
|
143
|
+
}
|
|
144
|
+
/** Return whether a model is the GPT-5.6 family. */
|
|
145
|
+
function isOpenAIGpt56Model(model) {
|
|
146
|
+
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
147
|
+
const name = normalizeModelId(typeof model.name === "string" ? model.name : void 0);
|
|
148
|
+
return /^gpt-5\.6(?:-|$)/u.test(id) || /^gpt-5\.6(?:\s|\(|-|$)/u.test(name);
|
|
149
|
+
}
|
|
150
|
+
/** Normalize user-facing reasoning effort names to API effort names. */
|
|
151
|
+
function normalizeOpenAIReasoningEffort(effort) {
|
|
152
|
+
const trimmed = effort.trim();
|
|
153
|
+
const folded = trimmed.toLowerCase();
|
|
154
|
+
return CANONICAL_REASONING_EFFORTS.has(folded) ? folded : trimmed;
|
|
155
|
+
}
|
|
156
|
+
function readCompatReasoningEfforts(compat) {
|
|
157
|
+
if (!compat || typeof compat !== "object") return;
|
|
158
|
+
if (compat.supportsReasoningEffort === false) return [];
|
|
159
|
+
const raw = compat.supportedReasoningEfforts;
|
|
160
|
+
if (!Array.isArray(raw)) return;
|
|
161
|
+
const supported = uniqueStrings(normalizeStringEntries(raw.filter((value) => typeof value === "string")));
|
|
162
|
+
return supported.length > 0 ? supported : void 0;
|
|
163
|
+
}
|
|
164
|
+
function isDisabledReasoningEffort(effort) {
|
|
165
|
+
return effort === "none" || effort === "off";
|
|
166
|
+
}
|
|
167
|
+
/** Resolve the reasoning efforts accepted by a specific OpenAI-compatible model. */
|
|
168
|
+
function resolveOpenAISupportedReasoningEfforts(model) {
|
|
169
|
+
const compatEfforts = readCompatReasoningEfforts(model.compat);
|
|
170
|
+
if (compatEfforts) return compatEfforts;
|
|
171
|
+
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
172
|
+
if (/^gpt-5\.6(?:-|$)/u.test(id)) return GPT_56_REASONING_EFFORTS;
|
|
173
|
+
if (id === "gpt-5.1-codex-mini") return GPT_51_CODEX_MINI_REASONING_EFFORTS;
|
|
174
|
+
if (id === "gpt-5.1-codex-max") return GPT_51_CODEX_MAX_REASONING_EFFORTS;
|
|
175
|
+
if (/^gpt-5(?:\.\d+)?-codex(?:-|$)/u.test(id)) return GPT_CODEX_REASONING_EFFORTS;
|
|
176
|
+
if (id === "gpt-5-pro") return GPT_5_PRO_REASONING_EFFORTS;
|
|
177
|
+
if (/^gpt-5\.[2-9](?:\.\d+)?-pro(?:-|$)/u.test(id)) return GPT_PRO_REASONING_EFFORTS;
|
|
178
|
+
if (/^gpt-5\.[2-9](?:\.\d+)?(?:-|$)/u.test(id)) return GPT_52_REASONING_EFFORTS;
|
|
179
|
+
if (/^gpt-5\.1(?:-|$)/u.test(id)) return GPT_51_REASONING_EFFORTS;
|
|
180
|
+
if (/^gpt-5(?:-|$)/u.test(id)) return GPT_5_REASONING_EFFORTS;
|
|
181
|
+
return GENERIC_REASONING_EFFORTS;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Return whether a model accepts the temperature parameter. The GPT-5.6
|
|
185
|
+
* family rejects it with a 400; catalog compat can override per model.
|
|
186
|
+
*/
|
|
187
|
+
function supportsOpenAITemperature(model) {
|
|
188
|
+
const compat = model.compat;
|
|
189
|
+
if (compat && typeof compat === "object") {
|
|
190
|
+
const declared = compat.supportsTemperature;
|
|
191
|
+
if (typeof declared === "boolean") return declared;
|
|
192
|
+
}
|
|
193
|
+
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
194
|
+
return !/^gpt-5\.6(?:-|$)/u.test(id);
|
|
195
|
+
}
|
|
196
|
+
/** Return whether a model accepts a requested reasoning effort. */
|
|
197
|
+
function supportsOpenAIReasoningEffort(model, effort) {
|
|
198
|
+
return resolveOpenAISupportedReasoningEfforts(model).includes(normalizeOpenAIReasoningEffort(effort));
|
|
199
|
+
}
|
|
200
|
+
/** Resolve a requested reasoning effort to the closest value supported by the model. */
|
|
201
|
+
function resolveOpenAIReasoningEffortForModel(params) {
|
|
202
|
+
const requested = normalizeOpenAIReasoningEffort(params.effort);
|
|
203
|
+
const mapped = params.fallbackMap?.[requested] ?? (params.fallbackMap && CANONICAL_REASONING_EFFORTS.has(requested) ? Object.entries(params.fallbackMap).find(([effort]) => normalizeOpenAIReasoningEffort(effort) === requested)?.[1] : void 0);
|
|
204
|
+
const normalized = mapped === void 0 ? requested : mapped.trim();
|
|
205
|
+
const supported = resolveOpenAISupportedReasoningEfforts(params.model);
|
|
206
|
+
if (supported.includes(normalized)) return normalized;
|
|
207
|
+
if (requested === "off" && supported.includes("none")) return "none";
|
|
208
|
+
if (isDisabledReasoningEffort(requested) || isDisabledReasoningEffort(normalized)) return;
|
|
209
|
+
if (requested === "minimal" && supported.includes("low")) return "low";
|
|
210
|
+
if ((requested === "minimal" || requested === "low") && supported.includes("medium")) return "medium";
|
|
211
|
+
if (requested === "xhigh" && supported.includes("high")) return "high";
|
|
212
|
+
if (requested === "max" && supported.includes("xhigh")) return "xhigh";
|
|
213
|
+
return supported.find((effort) => !isDisabledReasoningEffort(normalizeOpenAIReasoningEffort(effort)));
|
|
214
|
+
}
|
|
215
|
+
//#endregion
|
|
69
216
|
//#region packages/ai/src/providers/clean-for-gemini.ts
|
|
70
217
|
const GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
|
|
71
218
|
"patternProperties",
|
|
@@ -337,7 +484,127 @@ function cleanSchemaForGemini(schema) {
|
|
|
337
484
|
return cleanSchemaForGeminiWithDefs(schema, extendSchemaDefs$1(void 0, schema), void 0);
|
|
338
485
|
}
|
|
339
486
|
//#endregion
|
|
487
|
+
//#region packages/ai/src/providers/clean-for-llamacpp-gbnf.ts
|
|
488
|
+
/** llama.cpp rejects grammar repetitions whose expanded rule count reaches 2000. */
|
|
489
|
+
const LLAMACPP_GBNF_MAX_REPETITION_THRESHOLD = 2e3;
|
|
490
|
+
const SCHEMA_MAP_KEYS$2 = /* @__PURE__ */ new Set([
|
|
491
|
+
"$defs",
|
|
492
|
+
"definitions",
|
|
493
|
+
"dependentSchemas",
|
|
494
|
+
"patternProperties",
|
|
495
|
+
"properties"
|
|
496
|
+
]);
|
|
497
|
+
const SCHEMA_CHILD_KEYS = /* @__PURE__ */ new Set([
|
|
498
|
+
"additionalItems",
|
|
499
|
+
"additionalProperties",
|
|
500
|
+
"allOf",
|
|
501
|
+
"anyOf",
|
|
502
|
+
"contains",
|
|
503
|
+
"else",
|
|
504
|
+
"if",
|
|
505
|
+
"items",
|
|
506
|
+
"not",
|
|
507
|
+
"oneOf",
|
|
508
|
+
"prefixItems",
|
|
509
|
+
"propertyNames",
|
|
510
|
+
"then",
|
|
511
|
+
"unevaluatedItems",
|
|
512
|
+
"unevaluatedProperties"
|
|
513
|
+
]);
|
|
514
|
+
function isSchemaRecord(value) {
|
|
515
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
516
|
+
}
|
|
517
|
+
function cleanSchemaNode(node) {
|
|
518
|
+
if (Array.isArray(node)) {
|
|
519
|
+
let changed = false;
|
|
520
|
+
const entries = node.map((entry) => {
|
|
521
|
+
const next = cleanSchemaNode(entry);
|
|
522
|
+
changed ||= next !== entry;
|
|
523
|
+
return next;
|
|
524
|
+
});
|
|
525
|
+
return changed ? entries : node;
|
|
526
|
+
}
|
|
527
|
+
if (!isSchemaRecord(node)) return node;
|
|
528
|
+
let changed = false;
|
|
529
|
+
const cleaned = {};
|
|
530
|
+
for (const [key, value] of Object.entries(node)) {
|
|
531
|
+
if (key === "pattern") {
|
|
532
|
+
changed = true;
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
if (key === "maxLength" && typeof value === "number" && value >= 2e3) {
|
|
536
|
+
changed = true;
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
539
|
+
let next = value;
|
|
540
|
+
if (SCHEMA_MAP_KEYS$2.has(key) && isSchemaRecord(value)) {
|
|
541
|
+
let mapChanged = false;
|
|
542
|
+
next = Object.fromEntries(Object.entries(value).map(([childKey, childValue]) => {
|
|
543
|
+
const cleanedChild = cleanSchemaNode(childValue);
|
|
544
|
+
mapChanged ||= cleanedChild !== childValue;
|
|
545
|
+
return [childKey, cleanedChild];
|
|
546
|
+
}));
|
|
547
|
+
if (!mapChanged) next = value;
|
|
548
|
+
} else if (SCHEMA_CHILD_KEYS.has(key)) next = cleanSchemaNode(value);
|
|
549
|
+
cleaned[key] = next;
|
|
550
|
+
changed ||= next !== value;
|
|
551
|
+
}
|
|
552
|
+
return changed ? cleaned : node;
|
|
553
|
+
}
|
|
554
|
+
function collectSchemaViolations(node, path, violations) {
|
|
555
|
+
if (Array.isArray(node)) {
|
|
556
|
+
node.forEach((entry, index) => collectSchemaViolations(entry, `${path}[${index}]`, violations));
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
if (!isSchemaRecord(node)) return;
|
|
560
|
+
if ("pattern" in node) violations.push(`${path}.pattern`);
|
|
561
|
+
if (typeof node.maxLength === "number" && node.maxLength >= 2e3) violations.push(`${path}.maxLength`);
|
|
562
|
+
for (const [key, value] of Object.entries(node)) if (SCHEMA_MAP_KEYS$2.has(key) && isSchemaRecord(value)) for (const [childKey, childValue] of Object.entries(value)) collectSchemaViolations(childValue, `${path}.${key}.${childKey}`, violations);
|
|
563
|
+
else if (SCHEMA_CHILD_KEYS.has(key)) collectSchemaViolations(value, `${path}.${key}`, violations);
|
|
564
|
+
}
|
|
565
|
+
/** Removes JSON Schema constraints that llama.cpp cannot compile into GBNF. */
|
|
566
|
+
function cleanSchemaForLlamacppGbnf(schema) {
|
|
567
|
+
return cleanSchemaNode(schema);
|
|
568
|
+
}
|
|
569
|
+
/** Reports schema paths that llama.cpp cannot compile into GBNF. */
|
|
570
|
+
function findLlamacppGbnfSchemaViolations(schema, path) {
|
|
571
|
+
const violations = [];
|
|
572
|
+
collectSchemaViolations(schema, path, violations);
|
|
573
|
+
return violations;
|
|
574
|
+
}
|
|
575
|
+
//#endregion
|
|
340
576
|
//#region packages/ai/src/providers/schema-keyword-strip.ts
|
|
577
|
+
const SCHEMA_MAP_KEYS$1 = /* @__PURE__ */ new Set([
|
|
578
|
+
"$defs",
|
|
579
|
+
"definitions",
|
|
580
|
+
"dependentSchemas",
|
|
581
|
+
"dependencies",
|
|
582
|
+
"patternProperties",
|
|
583
|
+
"properties"
|
|
584
|
+
]);
|
|
585
|
+
/** Containers whose value is a single nested schema. */
|
|
586
|
+
const SCHEMA_OBJECT_KEYS$1 = /* @__PURE__ */ new Set([
|
|
587
|
+
"additionalItems",
|
|
588
|
+
"additionalProperties",
|
|
589
|
+
"contains",
|
|
590
|
+
"contentSchema",
|
|
591
|
+
"else",
|
|
592
|
+
"if",
|
|
593
|
+
"items",
|
|
594
|
+
"not",
|
|
595
|
+
"propertyNames",
|
|
596
|
+
"then",
|
|
597
|
+
"unevaluatedItems",
|
|
598
|
+
"unevaluatedProperties"
|
|
599
|
+
]);
|
|
600
|
+
/** Containers whose value is a list of nested schemas. */
|
|
601
|
+
const SCHEMA_ARRAY_KEYS$1 = /* @__PURE__ */ new Set([
|
|
602
|
+
"allOf",
|
|
603
|
+
"anyOf",
|
|
604
|
+
"items",
|
|
605
|
+
"oneOf",
|
|
606
|
+
"prefixItems"
|
|
607
|
+
]);
|
|
341
608
|
/** Recursively remove schema keywords unsupported by a target provider/tool surface. */
|
|
342
609
|
function stripUnsupportedSchemaKeywords(schema, unsupportedKeywords) {
|
|
343
610
|
if (!schema || typeof schema !== "object") return schema;
|
|
@@ -346,16 +613,16 @@ function stripUnsupportedSchemaKeywords(schema, unsupportedKeywords) {
|
|
|
346
613
|
const cleaned = {};
|
|
347
614
|
for (const [key, value] of Object.entries(obj)) {
|
|
348
615
|
if (unsupportedKeywords.has(key)) continue;
|
|
349
|
-
if (key
|
|
616
|
+
if (SCHEMA_MAP_KEYS$1.has(key) && value && typeof value === "object" && !Array.isArray(value)) {
|
|
350
617
|
cleaned[key] = Object.fromEntries(Object.entries(value).map(([childKey, childValue]) => [childKey, stripUnsupportedSchemaKeywords(childValue, unsupportedKeywords)]));
|
|
351
618
|
continue;
|
|
352
619
|
}
|
|
353
|
-
if (key
|
|
354
|
-
cleaned[key] =
|
|
620
|
+
if (SCHEMA_ARRAY_KEYS$1.has(key) && Array.isArray(value)) {
|
|
621
|
+
cleaned[key] = value.map((entry) => stripUnsupportedSchemaKeywords(entry, unsupportedKeywords));
|
|
355
622
|
continue;
|
|
356
623
|
}
|
|
357
|
-
if ((key
|
|
358
|
-
cleaned[key] =
|
|
624
|
+
if (SCHEMA_OBJECT_KEYS$1.has(key) && value && typeof value === "object") {
|
|
625
|
+
cleaned[key] = stripUnsupportedSchemaKeywords(value, unsupportedKeywords);
|
|
359
626
|
continue;
|
|
360
627
|
}
|
|
361
628
|
cleaned[key] = value;
|
|
@@ -867,9 +1134,11 @@ function normalizeToolParameterSchemaUncached(schema, options) {
|
|
|
867
1134
|
const isAnthropicProvider = normalizedProvider.includes("anthropic");
|
|
868
1135
|
const unsupportedToolSchemaKeywords = resolveUnsupportedToolSchemaKeywords(options?.modelCompat);
|
|
869
1136
|
const omitEmptyArrayItems = shouldOmitEmptyArrayItems(options?.modelCompat);
|
|
1137
|
+
const isLlamacppGbnfProfile = normalizedToolSchemaProfile === "llamacpp";
|
|
870
1138
|
function applyProviderCleaning(s) {
|
|
871
1139
|
const normalizedSchema = normalizeArraySchemasMissingItems(s);
|
|
872
|
-
|
|
1140
|
+
let arrayItemsCompatibleSchema = omitEmptyArrayItems ? stripEmptyArrayItemsFromArraySchemas(normalizedSchema) : normalizedSchema;
|
|
1141
|
+
if (isLlamacppGbnfProfile) arrayItemsCompatibleSchema = cleanSchemaForLlamacppGbnf(arrayItemsCompatibleSchema);
|
|
873
1142
|
if (isGeminiProvider && !isAnthropicProvider) {
|
|
874
1143
|
const geminiCompatibleSchema = cleanSchemaForGemini(arrayItemsCompatibleSchema);
|
|
875
1144
|
return unsupportedToolSchemaKeywords.size > 0 ? stripUnsupportedSchemaKeywords(geminiCompatibleSchema, unsupportedToolSchemaKeywords) : geminiCompatibleSchema;
|
|
@@ -940,327 +1209,276 @@ function normalizeToolParameterSchema(schema, options) {
|
|
|
940
1209
|
return rememberCachedToolParameterSchema(schema, cacheKey, normalizeToolParameterSchemaUncached(schema, options));
|
|
941
1210
|
}
|
|
942
1211
|
//#endregion
|
|
943
|
-
//#region packages/ai/src/providers/
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
const separator = trimmed.indexOf("=");
|
|
952
|
-
if (separator <= 0) continue;
|
|
953
|
-
const modelId = trimmed.slice(0, separator).trim();
|
|
954
|
-
const deploymentName = trimmed.slice(separator + 1).trim();
|
|
955
|
-
if (!modelId || !deploymentName) continue;
|
|
956
|
-
map.set(modelId, deploymentName);
|
|
957
|
-
}
|
|
958
|
-
return map;
|
|
959
|
-
}
|
|
960
|
-
let cachedDeploymentLookup;
|
|
961
|
-
function getDeploymentLookup(source) {
|
|
962
|
-
const cached = cachedDeploymentLookup;
|
|
963
|
-
if (cached && cached.source === source) return cached;
|
|
964
|
-
const exact = parseAzureDeploymentNameMap(source);
|
|
965
|
-
const folded = /* @__PURE__ */ new Map();
|
|
966
|
-
for (const [modelId, deploymentName] of exact) folded.set(modelId.toLowerCase(), deploymentName);
|
|
967
|
-
cachedDeploymentLookup = {
|
|
968
|
-
source,
|
|
969
|
-
exact,
|
|
970
|
-
folded
|
|
971
|
-
};
|
|
972
|
-
return cachedDeploymentLookup;
|
|
973
|
-
}
|
|
974
|
-
/**
|
|
975
|
-
* Resolves the Azure deployment name for a model id, falling back to the model id.
|
|
976
|
-
*
|
|
977
|
-
* An exact-case match always wins, so configs that intentionally distinguish keys by
|
|
978
|
-
* case keep their exact mappings; a case-insensitive match is only used as a fallback
|
|
979
|
-
* (e.g. `GPT-4o` against a `gpt-4o=...` map) to avoid 404s from casing differences.
|
|
980
|
-
*/
|
|
981
|
-
function resolveAzureDeploymentNameFromMap(params) {
|
|
982
|
-
const { exact, folded } = getDeploymentLookup(params.deploymentMap);
|
|
983
|
-
return exact.get(params.modelId) ?? folded.get(params.modelId.toLowerCase()) ?? params.modelId;
|
|
984
|
-
}
|
|
985
|
-
//#endregion
|
|
986
|
-
//#region packages/ai/src/providers/azure-openai-responses-client-compat.ts
|
|
987
|
-
function isTraditionalAzureOpenAIHost(hostname) {
|
|
988
|
-
return hostname.endsWith(".openai.azure.com") || hostname.endsWith(".cognitiveservices.azure.com");
|
|
989
|
-
}
|
|
990
|
-
function isOpenAICompatibleAzureResponsesBaseUrl(baseUrl) {
|
|
991
|
-
let url;
|
|
992
|
-
try {
|
|
993
|
-
url = new URL(baseUrl);
|
|
994
|
-
} catch {
|
|
995
|
-
return false;
|
|
996
|
-
}
|
|
997
|
-
if (isTraditionalAzureOpenAIHost(url.hostname)) return false;
|
|
998
|
-
const hostname = url.hostname.toLowerCase();
|
|
999
|
-
if (!(hostname.endsWith(".services.ai.azure.com") || hostname.endsWith(".api.cognitive.microsoft.com"))) return false;
|
|
1000
|
-
const normalizedPath = url.pathname.replace(/\/+$/, "");
|
|
1001
|
-
return normalizedPath === "/openai/v1" || normalizedPath.endsWith("/openai/v1");
|
|
1002
|
-
}
|
|
1003
|
-
//#endregion
|
|
1004
|
-
//#region packages/ai/src/providers/openai-reasoning-effort.ts
|
|
1005
|
-
/**
|
|
1006
|
-
* OpenAI-compatible reasoning-effort normalization. Different GPT families
|
|
1007
|
-
* expose different accepted effort enums, so callers map requested values here
|
|
1008
|
-
* before constructing provider payloads.
|
|
1009
|
-
*/
|
|
1010
|
-
const GPT_5_REASONING_EFFORTS = [
|
|
1011
|
-
"minimal",
|
|
1012
|
-
"low",
|
|
1013
|
-
"medium",
|
|
1014
|
-
"high"
|
|
1015
|
-
];
|
|
1016
|
-
const GPT_51_REASONING_EFFORTS = [
|
|
1017
|
-
"none",
|
|
1018
|
-
"low",
|
|
1019
|
-
"medium",
|
|
1020
|
-
"high"
|
|
1021
|
-
];
|
|
1022
|
-
const GPT_52_REASONING_EFFORTS = [
|
|
1023
|
-
"none",
|
|
1024
|
-
"low",
|
|
1025
|
-
"medium",
|
|
1026
|
-
"high",
|
|
1027
|
-
"xhigh"
|
|
1028
|
-
];
|
|
1029
|
-
const GPT_56_REASONING_EFFORTS = [
|
|
1030
|
-
"none",
|
|
1031
|
-
"low",
|
|
1032
|
-
"medium",
|
|
1033
|
-
"high",
|
|
1034
|
-
"xhigh",
|
|
1035
|
-
"max"
|
|
1036
|
-
];
|
|
1037
|
-
const GPT_CODEX_REASONING_EFFORTS = [
|
|
1038
|
-
"low",
|
|
1039
|
-
"medium",
|
|
1040
|
-
"high",
|
|
1041
|
-
"xhigh"
|
|
1042
|
-
];
|
|
1043
|
-
const GPT_PRO_REASONING_EFFORTS = [
|
|
1044
|
-
"medium",
|
|
1045
|
-
"high",
|
|
1046
|
-
"xhigh"
|
|
1047
|
-
];
|
|
1048
|
-
const GPT_5_PRO_REASONING_EFFORTS = ["high"];
|
|
1049
|
-
const GPT_51_CODEX_MAX_REASONING_EFFORTS = [
|
|
1050
|
-
"none",
|
|
1051
|
-
"medium",
|
|
1052
|
-
"high",
|
|
1053
|
-
"xhigh"
|
|
1054
|
-
];
|
|
1055
|
-
const GPT_51_CODEX_MINI_REASONING_EFFORTS = ["medium"];
|
|
1056
|
-
const GENERIC_REASONING_EFFORTS = [
|
|
1057
|
-
"low",
|
|
1058
|
-
"medium",
|
|
1059
|
-
"high"
|
|
1060
|
-
];
|
|
1061
|
-
const CANONICAL_REASONING_EFFORTS = /* @__PURE__ */ new Set([
|
|
1062
|
-
"none",
|
|
1063
|
-
"minimal",
|
|
1064
|
-
"low",
|
|
1065
|
-
"medium",
|
|
1066
|
-
"high",
|
|
1067
|
-
"xhigh",
|
|
1068
|
-
"max",
|
|
1069
|
-
"off"
|
|
1212
|
+
//#region packages/ai/src/providers/openai-tool-schema-compat.ts
|
|
1213
|
+
const OPENAI_STRICT_COMPAT_SCHEMA_MAP_KEYS = /* @__PURE__ */ new Set([
|
|
1214
|
+
"$defs",
|
|
1215
|
+
"definitions",
|
|
1216
|
+
"dependentSchemas",
|
|
1217
|
+
"dependencies",
|
|
1218
|
+
"patternProperties",
|
|
1219
|
+
"properties"
|
|
1070
1220
|
]);
|
|
1071
|
-
|
|
1072
|
-
|
|
1221
|
+
const OPENAI_NULLABLE_ANNOTATION_KEYS = /* @__PURE__ */ new Set([
|
|
1222
|
+
"default",
|
|
1223
|
+
"description",
|
|
1224
|
+
"examples",
|
|
1225
|
+
"format",
|
|
1226
|
+
"title"
|
|
1227
|
+
]);
|
|
1228
|
+
const OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS = /* @__PURE__ */ new Set([
|
|
1229
|
+
"additionalItems",
|
|
1230
|
+
"additionalProperties",
|
|
1231
|
+
"allOf",
|
|
1232
|
+
"anyOf",
|
|
1233
|
+
"contains",
|
|
1234
|
+
"contentSchema",
|
|
1235
|
+
"else",
|
|
1236
|
+
"if",
|
|
1237
|
+
"items",
|
|
1238
|
+
"not",
|
|
1239
|
+
"oneOf",
|
|
1240
|
+
"prefixItems",
|
|
1241
|
+
"propertyNames",
|
|
1242
|
+
"then",
|
|
1243
|
+
"unevaluatedItems",
|
|
1244
|
+
"unevaluatedProperties"
|
|
1245
|
+
]);
|
|
1246
|
+
function normalizeOpenAIStrictCompatSchemaMap(schema) {
|
|
1247
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema)) return schema;
|
|
1248
|
+
let changed = false;
|
|
1249
|
+
const normalized = {};
|
|
1250
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
1251
|
+
const next = normalizeOpenAIStrictCompatSchemaRecursive(value, { promoteEmptyObject: false });
|
|
1252
|
+
normalized[key] = next;
|
|
1253
|
+
changed ||= next !== value;
|
|
1254
|
+
}
|
|
1255
|
+
return changed ? normalized : schema;
|
|
1073
1256
|
}
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1257
|
+
function normalizeOpenAIStrictCompatSchemaRecursive(schema, options) {
|
|
1258
|
+
if (Array.isArray(schema)) {
|
|
1259
|
+
let changed = false;
|
|
1260
|
+
const normalized = schema.map((entry) => {
|
|
1261
|
+
const next = normalizeOpenAIStrictCompatSchemaRecursive(entry, { promoteEmptyObject: false });
|
|
1262
|
+
changed ||= next !== entry;
|
|
1263
|
+
return next;
|
|
1264
|
+
});
|
|
1265
|
+
return changed ? normalized : schema;
|
|
1266
|
+
}
|
|
1267
|
+
if (!schema || typeof schema !== "object") return schema;
|
|
1268
|
+
const record = schema;
|
|
1269
|
+
let changed = false;
|
|
1270
|
+
let hadNullType = false;
|
|
1271
|
+
const normalized = {};
|
|
1272
|
+
for (const [key, value] of Object.entries(record)) {
|
|
1273
|
+
if (value === null && OPENAI_NULLABLE_ANNOTATION_KEYS.has(key)) {
|
|
1274
|
+
changed = true;
|
|
1275
|
+
continue;
|
|
1276
|
+
}
|
|
1277
|
+
if (value === null && key === "type") {
|
|
1278
|
+
hadNullType = true;
|
|
1279
|
+
changed = true;
|
|
1280
|
+
continue;
|
|
1281
|
+
}
|
|
1282
|
+
const next = OPENAI_STRICT_COMPAT_SCHEMA_MAP_KEYS.has(key) ? normalizeOpenAIStrictCompatSchemaMap(value) : OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS.has(key) ? normalizeOpenAIStrictCompatSchemaRecursive(value, { promoteEmptyObject: false }) : value;
|
|
1283
|
+
normalized[key] = next;
|
|
1284
|
+
changed ||= next !== value;
|
|
1285
|
+
}
|
|
1286
|
+
if (Object.keys(normalized).length === 0) {
|
|
1287
|
+
if (!options.promoteEmptyObject) return schema;
|
|
1288
|
+
return {
|
|
1289
|
+
type: "object",
|
|
1290
|
+
properties: {},
|
|
1291
|
+
required: [],
|
|
1292
|
+
additionalProperties: false
|
|
1293
|
+
};
|
|
1294
|
+
}
|
|
1295
|
+
const hasObjectShapeHints = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) || Array.isArray(normalized.required);
|
|
1296
|
+
const hasArrayShapeHints = "items" in normalized;
|
|
1297
|
+
if (!("type" in normalized) && hasObjectShapeHints !== hasArrayShapeHints) {
|
|
1298
|
+
normalized.type = hasObjectShapeHints ? "object" : "array";
|
|
1299
|
+
changed = true;
|
|
1300
|
+
} else if (hadNullType && !("type" in normalized)) normalized.type = null;
|
|
1301
|
+
if (normalized.type === "object" && !("properties" in normalized)) {
|
|
1302
|
+
normalized.properties = {};
|
|
1303
|
+
changed = true;
|
|
1304
|
+
}
|
|
1305
|
+
const hasEmptyProperties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) && Object.keys(normalized.properties).length === 0;
|
|
1306
|
+
if (normalized.type === "object" && !Array.isArray(normalized.required) && hasEmptyProperties) {
|
|
1307
|
+
normalized.required = [];
|
|
1308
|
+
changed = true;
|
|
1309
|
+
}
|
|
1310
|
+
if (normalized.type === "object" && hasEmptyProperties && !("additionalProperties" in normalized)) {
|
|
1311
|
+
normalized.additionalProperties = false;
|
|
1312
|
+
changed = true;
|
|
1313
|
+
}
|
|
1314
|
+
return changed ? normalized : schema;
|
|
1078
1315
|
}
|
|
1079
|
-
/**
|
|
1080
|
-
function
|
|
1081
|
-
|
|
1082
|
-
const name = normalizeModelId(typeof model.name === "string" ? model.name : void 0);
|
|
1083
|
-
return /^gpt-5\.5(?:-|$)/u.test(id) || /^gpt-5\.5(?:\s|\(|-|$)/u.test(name);
|
|
1316
|
+
/** Repairs recoverable OpenAI tool-schema shapes before canonical normalization. */
|
|
1317
|
+
function normalizeOpenAIStrictCompatSchema(schema) {
|
|
1318
|
+
return normalizeOpenAIStrictCompatSchemaRecursive(schema, { promoteEmptyObject: true });
|
|
1084
1319
|
}
|
|
1085
|
-
/**
|
|
1086
|
-
function
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1320
|
+
/** Finds schema paths that violate OpenAI strict tool-schema requirements. */
|
|
1321
|
+
function findOpenAIStrictSchemaViolations(schema, path, options) {
|
|
1322
|
+
if (Array.isArray(schema)) {
|
|
1323
|
+
if (options?.requireObjectRoot) return [`${path}.type`];
|
|
1324
|
+
return schema.flatMap((item, index) => findOpenAIStrictSchemaViolations(item, `${path}[${index}]`));
|
|
1325
|
+
}
|
|
1326
|
+
if (!schema || typeof schema !== "object") return options?.requireObjectRoot ? [`${path}.type`] : [];
|
|
1327
|
+
const record = schema;
|
|
1328
|
+
const violations = [];
|
|
1329
|
+
for (const key of [
|
|
1330
|
+
"anyOf",
|
|
1331
|
+
"oneOf",
|
|
1332
|
+
"allOf"
|
|
1333
|
+
]) if (key in record) violations.push(`${path}.${key}`);
|
|
1334
|
+
if (Array.isArray(record.type)) violations.push(`${path}.type`);
|
|
1335
|
+
const properties = record.properties && typeof record.properties === "object" && !Array.isArray(record.properties) ? record.properties : void 0;
|
|
1336
|
+
if (record.type === "object") {
|
|
1337
|
+
if (record.additionalProperties !== false) violations.push(`${path}.additionalProperties`);
|
|
1338
|
+
const required = Array.isArray(record.required) ? record.required.filter((entry) => typeof entry === "string") : void 0;
|
|
1339
|
+
if (!required) violations.push(`${path}.required`);
|
|
1340
|
+
else if (properties) {
|
|
1341
|
+
const requiredSet = new Set(required);
|
|
1342
|
+
for (const key of Object.keys(properties)) if (!requiredSet.has(key)) violations.push(`${path}.required.${key}`);
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
for (const key of OPENAI_STRICT_COMPAT_SCHEMA_MAP_KEYS) {
|
|
1346
|
+
const schemaMap = record[key];
|
|
1347
|
+
if (!schemaMap || typeof schemaMap !== "object" || Array.isArray(schemaMap)) continue;
|
|
1348
|
+
for (const [entryKey, value] of Object.entries(schemaMap)) violations.push(...findOpenAIStrictSchemaViolations(value, `${path}.${key}.${entryKey}`));
|
|
1349
|
+
}
|
|
1350
|
+
for (const key of OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS) {
|
|
1351
|
+
const value = record[key];
|
|
1352
|
+
if (value && typeof value === "object") violations.push(...findOpenAIStrictSchemaViolations(value, `${path}.${key}`));
|
|
1353
|
+
}
|
|
1354
|
+
return violations;
|
|
1090
1355
|
}
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1356
|
+
//#endregion
|
|
1357
|
+
//#region packages/ai/src/providers/openai-tool-schema.ts
|
|
1358
|
+
/**
|
|
1359
|
+
* OpenAI strict JSON-schema normalization for tool inventories and request payloads.
|
|
1360
|
+
*
|
|
1361
|
+
* Caches normalized object inputs by provider compatibility so repeated inventory builds preserve identity.
|
|
1362
|
+
*/
|
|
1363
|
+
const MAX_STRICT_SCHEMA_CACHE_ENTRIES_PER_SCHEMA = 8;
|
|
1364
|
+
let strictOpenAISchemaCache = /* @__PURE__ */ new WeakMap();
|
|
1365
|
+
function resolveToolSchemaModelCompat(compat) {
|
|
1366
|
+
if (!compat) return;
|
|
1367
|
+
const unsupportedToolSchemaKeywords = Array.isArray(compat.unsupportedToolSchemaKeywords) ? compat.unsupportedToolSchemaKeywords.filter((keyword) => typeof keyword === "string") : [];
|
|
1368
|
+
if (unsupportedToolSchemaKeywords.length === 0 && compat.omitEmptyArrayItems !== true) return;
|
|
1369
|
+
return {
|
|
1370
|
+
...unsupportedToolSchemaKeywords.length > 0 ? { unsupportedToolSchemaKeywords } : {},
|
|
1371
|
+
...compat.omitEmptyArrayItems === true ? { omitEmptyArrayItems: true } : {}
|
|
1372
|
+
};
|
|
1096
1373
|
}
|
|
1097
|
-
function
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
const raw = compat.supportedReasoningEfforts;
|
|
1101
|
-
if (!Array.isArray(raw)) return;
|
|
1102
|
-
const supported = uniqueStrings(normalizeStringEntries(raw.filter((value) => typeof value === "string")));
|
|
1103
|
-
return supported.length > 0 ? supported : void 0;
|
|
1374
|
+
function resolveStrictOpenAISchemaCacheKey(modelCompat) {
|
|
1375
|
+
const compat = resolveToolSchemaModelCompat(modelCompat);
|
|
1376
|
+
return JSON.stringify([[...compat?.unsupportedToolSchemaKeywords ?? []].toSorted(), shouldOmitEmptyArrayItems(compat)]);
|
|
1104
1377
|
}
|
|
1105
|
-
function
|
|
1106
|
-
return
|
|
1378
|
+
function readCachedStrictOpenAISchema(schema, key) {
|
|
1379
|
+
return strictOpenAISchemaCache.get(schema)?.find((entry) => entry.key === key)?.value;
|
|
1107
1380
|
}
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
if (id === "gpt-5.1-codex-max") return GPT_51_CODEX_MAX_REASONING_EFFORTS;
|
|
1116
|
-
if (/^gpt-5(?:\.\d+)?-codex(?:-|$)/u.test(id)) return GPT_CODEX_REASONING_EFFORTS;
|
|
1117
|
-
if (id === "gpt-5-pro") return GPT_5_PRO_REASONING_EFFORTS;
|
|
1118
|
-
if (/^gpt-5\.[2-9](?:\.\d+)?-pro(?:-|$)/u.test(id)) return GPT_PRO_REASONING_EFFORTS;
|
|
1119
|
-
if (/^gpt-5\.[2-9](?:\.\d+)?(?:-|$)/u.test(id)) return GPT_52_REASONING_EFFORTS;
|
|
1120
|
-
if (/^gpt-5\.1(?:-|$)/u.test(id)) return GPT_51_REASONING_EFFORTS;
|
|
1121
|
-
if (/^gpt-5(?:-|$)/u.test(id)) return GPT_5_REASONING_EFFORTS;
|
|
1122
|
-
return GENERIC_REASONING_EFFORTS;
|
|
1123
|
-
}
|
|
1124
|
-
/**
|
|
1125
|
-
* Return whether a model accepts the temperature parameter. The GPT-5.6
|
|
1126
|
-
* family rejects it with a 400; catalog compat can override per model.
|
|
1127
|
-
*/
|
|
1128
|
-
function supportsOpenAITemperature(model) {
|
|
1129
|
-
const compat = model.compat;
|
|
1130
|
-
if (compat && typeof compat === "object") {
|
|
1131
|
-
const declared = compat.supportsTemperature;
|
|
1132
|
-
if (typeof declared === "boolean") return declared;
|
|
1133
|
-
}
|
|
1134
|
-
const id = normalizeModelId(typeof model.id === "string" ? model.id : void 0);
|
|
1135
|
-
return !/^gpt-5\.6(?:-|$)/u.test(id);
|
|
1136
|
-
}
|
|
1137
|
-
/** Return whether a model accepts a requested reasoning effort. */
|
|
1138
|
-
function supportsOpenAIReasoningEffort(model, effort) {
|
|
1139
|
-
return resolveOpenAISupportedReasoningEfforts(model).includes(normalizeOpenAIReasoningEffort(effort));
|
|
1140
|
-
}
|
|
1141
|
-
/** Resolve a requested reasoning effort to the closest value supported by the model. */
|
|
1142
|
-
function resolveOpenAIReasoningEffortForModel(params) {
|
|
1143
|
-
const requested = normalizeOpenAIReasoningEffort(params.effort);
|
|
1144
|
-
const mapped = params.fallbackMap?.[requested] ?? (params.fallbackMap && CANONICAL_REASONING_EFFORTS.has(requested) ? Object.entries(params.fallbackMap).find(([effort]) => normalizeOpenAIReasoningEffort(effort) === requested)?.[1] : void 0);
|
|
1145
|
-
const normalized = mapped === void 0 ? requested : mapped.trim();
|
|
1146
|
-
const supported = resolveOpenAISupportedReasoningEfforts(params.model);
|
|
1147
|
-
if (supported.includes(normalized)) return normalized;
|
|
1148
|
-
if (requested === "off" && supported.includes("none")) return "none";
|
|
1149
|
-
if (isDisabledReasoningEffort(requested) || isDisabledReasoningEffort(normalized)) return;
|
|
1150
|
-
if (requested === "minimal" && supported.includes("low")) return "low";
|
|
1151
|
-
if ((requested === "minimal" || requested === "low") && supported.includes("medium")) return "medium";
|
|
1152
|
-
if (requested === "xhigh" && supported.includes("high")) return "high";
|
|
1153
|
-
if (requested === "max" && supported.includes("xhigh")) return "xhigh";
|
|
1154
|
-
return supported.find((effort) => !isDisabledReasoningEffort(normalizeOpenAIReasoningEffort(effort)));
|
|
1155
|
-
}
|
|
1156
|
-
//#endregion
|
|
1157
|
-
//#region packages/ai/src/providers/openai-responses-stream-compat.ts
|
|
1158
|
-
const OPENAI_RESPONSES_OUTPUT_TEXT_CONTENT_PART_TYPE = "output_text";
|
|
1159
|
-
const AZURE_RESPONSES_TEXT_CONTENT_PART_TYPE = "text";
|
|
1160
|
-
const OPENAI_RESPONSES_OUTPUT_TEXT_DELTA_EVENT_TYPE = "response.output_text.delta";
|
|
1161
|
-
const AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE = "response.text.delta";
|
|
1162
|
-
function isResponsesTextContentPartType(type) {
|
|
1163
|
-
return type === "output_text" || type === "text";
|
|
1164
|
-
}
|
|
1165
|
-
function isResponsesTextDeltaEventType(type) {
|
|
1166
|
-
return type === "response.output_text.delta" || type === "response.text.delta";
|
|
1381
|
+
function rememberStrictOpenAISchema(schema, key, value) {
|
|
1382
|
+
const entries = strictOpenAISchemaCache.get(schema) ?? [];
|
|
1383
|
+
strictOpenAISchemaCache.set(schema, [{
|
|
1384
|
+
key,
|
|
1385
|
+
value
|
|
1386
|
+
}, ...entries.filter((entry) => entry.key !== key)].slice(0, MAX_STRICT_SCHEMA_CACHE_ENTRIES_PER_SCHEMA));
|
|
1387
|
+
return value;
|
|
1167
1388
|
}
|
|
1168
|
-
function
|
|
1169
|
-
|
|
1389
|
+
function clearOpenAIToolSchemaCacheForTest() {
|
|
1390
|
+
strictOpenAISchemaCache = /* @__PURE__ */ new WeakMap();
|
|
1170
1391
|
}
|
|
1171
|
-
|
|
1172
|
-
|
|
1392
|
+
/** Normalizes a tool parameter schema into the OpenAI strict JSON-schema subset. */
|
|
1393
|
+
function normalizeStrictOpenAIJsonSchema(schema, modelCompat) {
|
|
1394
|
+
const schemaInput = schema ?? {};
|
|
1395
|
+
if (!schemaInput || typeof schemaInput !== "object") return normalizeStrictOpenAIJsonSchemaRecursive(normalizeToolParameterSchema(schemaInput, { modelCompat: resolveToolSchemaModelCompat(modelCompat) }), 0);
|
|
1396
|
+
const cacheKey = resolveStrictOpenAISchemaCacheKey(modelCompat);
|
|
1397
|
+
const cached = readCachedStrictOpenAISchema(schemaInput, cacheKey);
|
|
1398
|
+
if (cached !== void 0) return cached;
|
|
1399
|
+
return rememberStrictOpenAISchema(schemaInput, cacheKey, normalizeStrictOpenAIJsonSchemaRecursive(normalizeToolParameterSchema(schemaInput, { modelCompat: resolveToolSchemaModelCompat(modelCompat) }), 0));
|
|
1173
1400
|
}
|
|
1174
|
-
function
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1401
|
+
function normalizeStrictOpenAIJsonSchemaRecursive(schema, depth) {
|
|
1402
|
+
if (Array.isArray(schema)) {
|
|
1403
|
+
let changed = false;
|
|
1404
|
+
const normalized = schema.map((entry) => {
|
|
1405
|
+
const next = normalizeStrictOpenAIJsonSchemaRecursive(entry, depth);
|
|
1406
|
+
changed ||= next !== entry;
|
|
1407
|
+
return next;
|
|
1408
|
+
});
|
|
1409
|
+
return changed ? normalized : schema;
|
|
1410
|
+
}
|
|
1411
|
+
if (!schema || typeof schema !== "object") return schema;
|
|
1412
|
+
const record = schema;
|
|
1413
|
+
let changed = false;
|
|
1414
|
+
const normalized = {};
|
|
1415
|
+
for (const [key, value] of Object.entries(record)) {
|
|
1416
|
+
const next = normalizeStrictOpenAIJsonSchemaRecursive(value, key === "properties" ? depth : depth + 1);
|
|
1417
|
+
normalized[key] = next;
|
|
1418
|
+
changed ||= next !== value;
|
|
1419
|
+
}
|
|
1420
|
+
if (normalized.type === "object") {
|
|
1421
|
+
const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : void 0;
|
|
1422
|
+
if (properties && Object.keys(properties).length === 0 && !Array.isArray(normalized.required)) {
|
|
1423
|
+
normalized.required = [];
|
|
1424
|
+
changed = true;
|
|
1425
|
+
}
|
|
1426
|
+
if (depth === 0 && !("additionalProperties" in normalized)) {
|
|
1427
|
+
normalized.additionalProperties = false;
|
|
1428
|
+
changed = true;
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
return changed ? normalized : schema;
|
|
1182
1432
|
}
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1433
|
+
/** Normalizes tool parameters using strict OpenAI rules only when strict mode is active. */
|
|
1434
|
+
function normalizeOpenAIStrictToolParameters(schema, strict, modelCompat) {
|
|
1435
|
+
const toolSchemaCompat = resolveToolSchemaModelCompat(modelCompat);
|
|
1436
|
+
if (!strict) return normalizeToolParameterSchema(schema ?? {}, { modelCompat: toolSchemaCompat });
|
|
1437
|
+
return normalizeStrictOpenAIJsonSchema(schema, toolSchemaCompat);
|
|
1187
1438
|
}
|
|
1188
|
-
|
|
1189
|
-
|
|
1439
|
+
/** Returns whether a schema already satisfies OpenAI strict tool-schema constraints. */
|
|
1440
|
+
function isStrictOpenAIJsonSchemaCompatible(schema) {
|
|
1441
|
+
return isStrictOpenAIJsonSchemaCompatibleRecursive(normalizeStrictOpenAIJsonSchema(schema));
|
|
1190
1442
|
}
|
|
1191
|
-
|
|
1192
|
-
|
|
1443
|
+
/** Returns strict-schema diagnostics for an already materialized OpenAI tool projection. */
|
|
1444
|
+
function findOpenAIStrictToolProjectionDiagnostics(projection) {
|
|
1445
|
+
return [...projection.diagnostics.map((diagnostic) => ({
|
|
1446
|
+
toolIndex: diagnostic.toolIndex,
|
|
1447
|
+
...diagnostic.toolName ? { toolName: diagnostic.toolName } : {},
|
|
1448
|
+
violations: [...diagnostic.violations]
|
|
1449
|
+
})), ...projection.tools.flatMap((tool) => {
|
|
1450
|
+
const violations = findOpenAIStrictSchemaViolations(normalizeStrictOpenAIJsonSchema(tool.parameters), `${tool.name}.parameters`);
|
|
1451
|
+
return violations.length > 0 ? [{
|
|
1452
|
+
toolIndex: tool.toolIndex,
|
|
1453
|
+
toolName: tool.name,
|
|
1454
|
+
violations
|
|
1455
|
+
}] : [];
|
|
1456
|
+
})];
|
|
1193
1457
|
}
|
|
1194
|
-
function
|
|
1195
|
-
return
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1458
|
+
function isStrictOpenAIJsonSchemaCompatibleRecursive(schema) {
|
|
1459
|
+
if (Array.isArray(schema)) return schema.every((entry) => isStrictOpenAIJsonSchemaCompatibleRecursive(entry));
|
|
1460
|
+
if (!schema || typeof schema !== "object") return true;
|
|
1461
|
+
const record = schema;
|
|
1462
|
+
if ("anyOf" in record || "oneOf" in record || "allOf" in record) return false;
|
|
1463
|
+
if (Array.isArray(record.type)) return false;
|
|
1464
|
+
if (record.type === "object" && record.additionalProperties !== false) return false;
|
|
1465
|
+
if (record.type === "object") {
|
|
1466
|
+
const properties = record.properties && typeof record.properties === "object" && !Array.isArray(record.properties) ? record.properties : {};
|
|
1467
|
+
const required = Array.isArray(record.required) ? record.required.filter((entry) => typeof entry === "string") : void 0;
|
|
1468
|
+
if (!required) return false;
|
|
1469
|
+
const requiredSet = new Set(required);
|
|
1470
|
+
if (Object.keys(properties).some((key) => !requiredSet.has(key))) return false;
|
|
1471
|
+
}
|
|
1472
|
+
return Object.entries(record).every(([key, entry]) => {
|
|
1473
|
+
if (key === "properties" && entry && typeof entry === "object" && !Array.isArray(entry)) return Object.values(entry).every((value) => isStrictOpenAIJsonSchemaCompatibleRecursive(value));
|
|
1474
|
+
return isStrictOpenAIJsonSchemaCompatibleRecursive(entry);
|
|
1475
|
+
});
|
|
1199
1476
|
}
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
const sharesIdentity = (state, identity) => Boolean(state.itemId && identity.itemId && state.itemId === identity.itemId || state.callId && identity.callId && state.callId === identity.callId);
|
|
1205
|
-
const adoptIdentity = (state, identity) => {
|
|
1206
|
-
state.itemId ??= identity.itemId;
|
|
1207
|
-
state.callId ??= identity.callId;
|
|
1208
|
-
return state;
|
|
1209
|
-
};
|
|
1210
|
-
const resolveCompatible = (candidates, identity) => {
|
|
1211
|
-
const uniqueCandidates = [...new Set(candidates)];
|
|
1212
|
-
if (!identity.itemId && !identity.callId) return uniqueCandidates.length === 1 ? uniqueCandidates.at(0) : void 0;
|
|
1213
|
-
const compatible = uniqueCandidates.filter((state) => !identitiesConflict(state, identity));
|
|
1214
|
-
const matches = compatible.filter((state) => sharesIdentity(state, identity));
|
|
1215
|
-
const matched = matches.length === 1 ? matches.at(0) : void 0;
|
|
1216
|
-
if (matched) return adoptIdentity(matched, identity);
|
|
1217
|
-
const soleCompatible = uniqueCandidates.length === 1 && compatible.length === 1 && matches.length === 0 ? compatible.at(0) : void 0;
|
|
1218
|
-
return soleCompatible ? adoptIdentity(soleCompatible, identity) : void 0;
|
|
1219
|
-
};
|
|
1220
|
-
return {
|
|
1221
|
-
register(event, state) {
|
|
1222
|
-
const outputIndex = readOutputIndex(event);
|
|
1223
|
-
if (outputIndex === void 0) {
|
|
1224
|
-
unindexedCalls.add(state);
|
|
1225
|
-
return;
|
|
1226
|
-
}
|
|
1227
|
-
if (indexedCalls.has(outputIndex)) throw new Error(`Responses stream reused active tool-call output index ${outputIndex}`);
|
|
1228
|
-
indexedCalls.set(outputIndex, state);
|
|
1229
|
-
},
|
|
1230
|
-
resolve(event, identity = readEventIdentity(event)) {
|
|
1231
|
-
const outputIndex = readOutputIndex(event);
|
|
1232
|
-
if (outputIndex !== void 0) {
|
|
1233
|
-
const indexed = indexedCalls.get(outputIndex);
|
|
1234
|
-
if (indexed) {
|
|
1235
|
-
if (indexed.callId && identity.callId && indexed.callId !== identity.callId) return;
|
|
1236
|
-
return adoptIdentity(indexed, identity);
|
|
1237
|
-
}
|
|
1238
|
-
const unindexed = resolveCompatible(unindexedCalls, identity);
|
|
1239
|
-
if (unindexed) {
|
|
1240
|
-
unindexedCalls.delete(unindexed);
|
|
1241
|
-
indexedCalls.set(outputIndex, unindexed);
|
|
1242
|
-
}
|
|
1243
|
-
return unindexed;
|
|
1244
|
-
}
|
|
1245
|
-
return resolveCompatible([...indexedCalls.values(), ...unindexedCalls], identity);
|
|
1246
|
-
},
|
|
1247
|
-
forget(toolCall) {
|
|
1248
|
-
for (const [outputIndex, tracked] of indexedCalls) if (tracked === toolCall) indexedCalls.delete(outputIndex);
|
|
1249
|
-
unindexedCalls.delete(toolCall);
|
|
1250
|
-
},
|
|
1251
|
-
markArgumentsUnreliable() {
|
|
1252
|
-
for (const toolCall of /* @__PURE__ */ new Set([...indexedCalls.values(), ...unindexedCalls])) toolCall.argumentStreamReliable = false;
|
|
1253
|
-
},
|
|
1254
|
-
hasActive() {
|
|
1255
|
-
return indexedCalls.size > 0 || unindexedCalls.size > 0;
|
|
1256
|
-
}
|
|
1257
|
-
};
|
|
1477
|
+
/** Resolves strict mode for the projected tools that will be emitted in the request payload. */
|
|
1478
|
+
function resolveOpenAIProjectedToolsStrictToolFlag(projection, strict) {
|
|
1479
|
+
if (strict !== true) return strict === false ? false : void 0;
|
|
1480
|
+
return projection.tools.every((tool) => isStrictOpenAIJsonSchemaCompatible(tool.parameters));
|
|
1258
1481
|
}
|
|
1259
|
-
const OPENAI_CODEX_RESPONSES_DEFAULT_INSTRUCTIONS = "Follow the user request.";
|
|
1260
|
-
const AZURE_RESPONSES_FIRST_EVENT_TIMEOUT_MS = 3e4;
|
|
1261
|
-
const RESPONSE_FAILED_NO_DETAILS_MESSAGE = "Unknown error (no error details in response)";
|
|
1262
|
-
const OPENAI_RESPONSES_REASONING_REPLAY_META_KEY = "__openclaw_replay";
|
|
1263
|
-
const OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY = "openclawReasoningReplay";
|
|
1264
1482
|
//#endregion
|
|
1265
1483
|
//#region packages/ai/src/transports/openai-transport-shared.ts
|
|
1266
1484
|
/** Shared options, usage shape, cache identity, ordering, and stream scheduling for OpenAI APIs. */
|
|
@@ -1300,31 +1518,39 @@ function createModelStreamCooperativeScheduler(signal) {
|
|
|
1300
1518
|
throwIfModelStreamAborted(signal);
|
|
1301
1519
|
} };
|
|
1302
1520
|
}
|
|
1303
|
-
function resolveCacheRetention(cacheRetention) {
|
|
1304
|
-
if (cacheRetention === "short" || cacheRetention === "long" || cacheRetention === "none") return cacheRetention;
|
|
1305
|
-
if (typeof process !== "undefined" && process.env.OPENCLAW_CACHE_RETENTION === "long") return "long";
|
|
1306
|
-
return "short";
|
|
1307
|
-
}
|
|
1308
1521
|
function resolvePromptCacheKey(options, cacheRetention) {
|
|
1309
1522
|
if (cacheRetention === "none") return;
|
|
1310
1523
|
return clampOpenAIPromptCacheKey(options?.promptCacheKey ?? options?.sessionId);
|
|
1311
1524
|
}
|
|
1312
1525
|
//#endregion
|
|
1526
|
+
//#region packages/ai/src/transports/openai-responses-replay.ts
|
|
1527
|
+
/** Resolves the assistant message id that can be replayed to OpenAI Responses. */
|
|
1528
|
+
function resolveReplayableResponsesMessageId(params) {
|
|
1529
|
+
if (!params.replayResponsesItemIds) return;
|
|
1530
|
+
if (!params.textSignatureId) return params.fallbackOrdinal === 0 ? params.fallbackId : `${params.fallbackId}_${params.fallbackOrdinal}`;
|
|
1531
|
+
return params.previousReplayItemWasReasoning ? params.textSignatureId : void 0;
|
|
1532
|
+
}
|
|
1533
|
+
const OPENAI_CODEX_RESPONSES_DEFAULT_INSTRUCTIONS = "Follow the user request.";
|
|
1534
|
+
const AZURE_RESPONSES_FIRST_EVENT_TIMEOUT_MS = 3e4;
|
|
1535
|
+
const RESPONSE_FAILED_NO_DETAILS_MESSAGE = "Unknown error (no error details in response)";
|
|
1536
|
+
const OPENAI_RESPONSES_REASONING_REPLAY_META_KEY = "__openclaw_replay";
|
|
1537
|
+
const OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY = "openclawReasoningReplay";
|
|
1538
|
+
//#endregion
|
|
1313
1539
|
//#region packages/ai/src/transports/openai-responses-debug.ts
|
|
1314
1540
|
function stringifyUnknown(value, fallback = "") {
|
|
1315
1541
|
if (typeof value === "string") return value;
|
|
1316
1542
|
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
1317
1543
|
return fallback;
|
|
1318
1544
|
}
|
|
1319
|
-
function getServiceTierCostMultiplier
|
|
1545
|
+
function getServiceTierCostMultiplier(serviceTier) {
|
|
1320
1546
|
switch (serviceTier) {
|
|
1321
1547
|
case "flex": return .5;
|
|
1322
1548
|
case "priority": return 2;
|
|
1323
1549
|
default: return 1;
|
|
1324
1550
|
}
|
|
1325
1551
|
}
|
|
1326
|
-
function applyServiceTierPricing
|
|
1327
|
-
const multiplier = getServiceTierCostMultiplier
|
|
1552
|
+
function applyServiceTierPricing(usage, serviceTier) {
|
|
1553
|
+
const multiplier = getServiceTierCostMultiplier(serviceTier);
|
|
1328
1554
|
if (multiplier === 1) return;
|
|
1329
1555
|
usage.cost.input *= multiplier;
|
|
1330
1556
|
usage.cost.output *= multiplier;
|
|
@@ -1584,14 +1810,6 @@ function summarizeOpenAITransportError(error) {
|
|
|
1584
1810
|
].join(" ");
|
|
1585
1811
|
}
|
|
1586
1812
|
//#endregion
|
|
1587
|
-
//#region packages/ai/src/transports/openai-responses-replay.ts
|
|
1588
|
-
/** Resolves the assistant message id that can be replayed to OpenAI Responses. */
|
|
1589
|
-
function resolveReplayableResponsesMessageId$1(params) {
|
|
1590
|
-
if (!params.replayResponsesItemIds) return;
|
|
1591
|
-
if (!params.textSignatureId) return params.fallbackOrdinal === 0 ? params.fallbackId : `${params.fallbackId}_${params.fallbackOrdinal}`;
|
|
1592
|
-
return params.previousReplayItemWasReasoning ? params.textSignatureId : void 0;
|
|
1593
|
-
}
|
|
1594
|
-
//#endregion
|
|
1595
1813
|
//#region packages/ai/src/transports/openai-responses-replay-internal.ts
|
|
1596
1814
|
function isInvalidEncryptedContentError(error) {
|
|
1597
1815
|
if (!error || typeof error !== "object") return false;
|
|
@@ -1730,7 +1948,7 @@ function encodeTextSignatureV1(id, phase) {
|
|
|
1730
1948
|
...phase ? { phase } : {}
|
|
1731
1949
|
});
|
|
1732
1950
|
}
|
|
1733
|
-
function parseTextSignature
|
|
1951
|
+
function parseTextSignature(signature) {
|
|
1734
1952
|
if (!signature) return;
|
|
1735
1953
|
if (signature.startsWith("{")) try {
|
|
1736
1954
|
const parsed = JSON.parse(signature);
|
|
@@ -1753,7 +1971,7 @@ function buildResponsesInputMessage(role, content) {
|
|
|
1753
1971
|
content
|
|
1754
1972
|
};
|
|
1755
1973
|
}
|
|
1756
|
-
function convertResponsesMessages
|
|
1974
|
+
function convertResponsesMessages(model, context, allowedToolCallProviders, options) {
|
|
1757
1975
|
const messages = [];
|
|
1758
1976
|
const shouldReplayReasoningItems = options?.replayReasoningItems ?? true;
|
|
1759
1977
|
const shouldReplayResponsesItemIds = options?.replayResponsesItemIds ?? true;
|
|
@@ -1823,8 +2041,8 @@ function convertResponsesMessages$1(model, context, allowedToolCallProviders, op
|
|
|
1823
2041
|
previousReplayItemWasReasoning = true;
|
|
1824
2042
|
}
|
|
1825
2043
|
} else if (block.type === "text") {
|
|
1826
|
-
const textSignature = parseTextSignature
|
|
1827
|
-
let msgId = resolveReplayableResponsesMessageId
|
|
2044
|
+
const textSignature = parseTextSignature(block.textSignature);
|
|
2045
|
+
let msgId = resolveReplayableResponsesMessageId({
|
|
1828
2046
|
replayResponsesItemIds: shouldReplayResponsesItemIds,
|
|
1829
2047
|
textSignatureId: textSignature?.id,
|
|
1830
2048
|
fallbackId: `msg_${msgIndex}`,
|
|
@@ -1842,1577 +2060,905 @@ function convertResponsesMessages$1(model, context, allowedToolCallProviders, op
|
|
|
1842
2060
|
annotations: []
|
|
1843
2061
|
}],
|
|
1844
2062
|
status: "completed",
|
|
1845
|
-
...msgId ? { id: msgId } : {},
|
|
1846
|
-
phase: textSignature?.phase
|
|
1847
|
-
};
|
|
1848
|
-
output.push(messageItem);
|
|
1849
|
-
previousReplayItemWasReasoning = false;
|
|
1850
|
-
} else if (block.type === "toolCall") {
|
|
1851
|
-
const separatorIndex = block.id.indexOf("|");
|
|
1852
|
-
const callId = separatorIndex === -1 ? block.id : block.id.slice(0, separatorIndex);
|
|
1853
|
-
const itemIdRaw = separatorIndex === -1 ? void 0 : block.id.slice(separatorIndex + 1);
|
|
1854
|
-
const itemId = shouldReplayResponsesItemIds && !(isDifferentModel && itemIdRaw?.startsWith("fc_")) ? itemIdRaw : void 0;
|
|
1855
|
-
output.push({
|
|
1856
|
-
type: "function_call",
|
|
1857
|
-
...itemId ? { id: itemId } : {},
|
|
1858
|
-
call_id: callId,
|
|
1859
|
-
name: block.name,
|
|
1860
|
-
arguments: typeof block.arguments === "string" ? block.arguments : JSON.stringify(block.arguments ?? {})
|
|
1861
|
-
});
|
|
1862
|
-
previousReplayItemWasReasoning = false;
|
|
1863
|
-
}
|
|
1864
|
-
if (output.length > 0) messages.push(...output);
|
|
1865
|
-
} else if (msg.role === "toolResult") {
|
|
1866
|
-
const textResult = extractToolResultText(msg.content);
|
|
1867
|
-
const sanitizedTextResult = sanitizeTransportPayloadText(textResult);
|
|
1868
|
-
const hasText = sanitizedTextResult.trim().length > 0;
|
|
1869
|
-
const mediaPlaceholder = describeToolResultMediaPlaceholder(msg.content);
|
|
1870
|
-
const hasImages = msg.content.some(isImageWithMediaPayload);
|
|
1871
|
-
const separatorIndex = msg.toolCallId.indexOf("|");
|
|
1872
|
-
const callId = separatorIndex === -1 ? msg.toolCallId : msg.toolCallId.slice(0, separatorIndex);
|
|
1873
|
-
messages.push({
|
|
1874
|
-
type: "function_call_output",
|
|
1875
|
-
call_id: callId,
|
|
1876
|
-
output: hasImages && model.input.includes("image") ? [...hasText ? [{
|
|
1877
|
-
type: "input_text",
|
|
1878
|
-
text: sanitizedTextResult
|
|
1879
|
-
}] : mediaPlaceholder === "(see attached media)" ? [{
|
|
1880
|
-
type: "input_text",
|
|
1881
|
-
text: mediaPlaceholder
|
|
1882
|
-
}] : [], ...msg.content.filter(isImageWithMediaPayload).map((item) => ({
|
|
1883
|
-
type: "input_image",
|
|
1884
|
-
detail: "auto",
|
|
1885
|
-
image_url: `data:${item.mimeType};base64,${item.data}`
|
|
1886
|
-
}))] : sanitizeNonEmptyTransportPayloadText(textResult, mediaPlaceholder ?? "(no output)")
|
|
1887
|
-
});
|
|
1888
|
-
}
|
|
1889
|
-
msgIndex += 1;
|
|
1890
|
-
}
|
|
1891
|
-
return messages;
|
|
1892
|
-
}
|
|
1893
|
-
//#endregion
|
|
1894
|
-
//#region packages/ai/src/transports/openai-responses-stream-observer-internal.ts
|
|
1895
|
-
const STRING_DELTA_EVENTS = /* @__PURE__ */ new Set([
|
|
1896
|
-
"response.function_call_arguments.delta",
|
|
1897
|
-
"response.output_text.delta",
|
|
1898
|
-
"response.reasoning_summary_text.delta",
|
|
1899
|
-
"response.reasoning_text.delta",
|
|
1900
|
-
"response.refusal.delta",
|
|
1901
|
-
"response.text.delta"
|
|
1902
|
-
]);
|
|
1903
|
-
async function* adaptResponsesStream(stream, signal) {
|
|
1904
|
-
const scheduler = createModelStreamCooperativeScheduler(signal);
|
|
1905
|
-
for await (const event of stream) {
|
|
1906
|
-
if (signal?.aborted) throw transportAbortError(signal);
|
|
1907
|
-
if (!isRecord(event) || typeof event.type !== "string") throw new Error("Responses stream delivered a malformed event without a string type");
|
|
1908
|
-
if (STRING_DELTA_EVENTS.has(event.type) && typeof event.delta !== "string") throw new Error(`Responses stream delivered malformed ${event.type} delta`);
|
|
1909
|
-
if ((event.type === "response.output_item.added" || event.type === "response.output_item.done") && !isRecord(event.item)) throw new Error(`Responses stream delivered malformed ${event.type} item`);
|
|
1910
|
-
if ((event.type === "response.created" || event.type === "response.completed" || event.type === "response.incomplete" || event.type === "response.failed") && !isRecord(event.response)) throw new Error(`Responses stream delivered malformed ${event.type} response`);
|
|
1911
|
-
yield event;
|
|
1912
|
-
await scheduler.afterEvent();
|
|
1913
|
-
}
|
|
1914
|
-
}
|
|
1915
|
-
async function* observeResponsesStream(stream, model) {
|
|
1916
|
-
const startedAt = Date.now();
|
|
1917
|
-
const eventTypes = /* @__PURE__ */ new Map();
|
|
1918
|
-
const debugMode = resolveModelSseDebugMode();
|
|
1919
|
-
let eventCount = 0;
|
|
1920
|
-
try {
|
|
1921
|
-
for await (const event of stream) {
|
|
1922
|
-
const type = isRecord(event) && typeof event.type === "string" ? event.type : "unknown";
|
|
1923
|
-
eventCount += 1;
|
|
1924
|
-
eventTypes.set(type, (eventTypes.get(type) ?? 0) + 1);
|
|
1925
|
-
if (eventCount === 1) emitModelTransportDebug(log, `[responses] first_event provider=${model.provider} api=${model.api} model=${model.id} elapsedMs=${Date.now() - startedAt} type=${type}`);
|
|
1926
|
-
if (debugMode === "peek" && eventCount <= 5) emitModelTransportDebug(log, `[responses] event_peek provider=${model.provider} api=${model.api} model=${model.id} index=${eventCount} type=${type} event=${stringifyRedactedEvent(event)}`);
|
|
1927
|
-
yield event;
|
|
1928
|
-
}
|
|
1929
|
-
} finally {
|
|
1930
|
-
const types = [...eventTypes].map(([type, count]) => `${type}:${count}`).join(",");
|
|
1931
|
-
emitModelTransportDebug(log, `[responses] stream_done provider=${model.provider} api=${model.api} model=${model.id} elapsedMs=${Date.now() - startedAt} events=${eventCount} types=${types}`);
|
|
1932
|
-
}
|
|
1933
|
-
}
|
|
1934
|
-
//#endregion
|
|
1935
|
-
//#region packages/ai/src/transports/openai-responses-stream-slots-internal.ts
|
|
1936
|
-
function readResponsesOutputIndex(event) {
|
|
1937
|
-
const outputIndex = event.output_index;
|
|
1938
|
-
return typeof outputIndex === "number" && Number.isInteger(outputIndex) && outputIndex >= 0 ? outputIndex : void 0;
|
|
1939
|
-
}
|
|
1940
|
-
function createResponsesOutputSlotTracker() {
|
|
1941
|
-
const indexed = /* @__PURE__ */ new Map();
|
|
1942
|
-
let unindexed;
|
|
1943
|
-
return {
|
|
1944
|
-
register(event, slot) {
|
|
1945
|
-
const outputIndex = readResponsesOutputIndex(event);
|
|
1946
|
-
if (outputIndex === void 0) {
|
|
1947
|
-
if (unindexed) throw new Error("Responses stream added overlapping unindexed output items");
|
|
1948
|
-
unindexed = slot;
|
|
1949
|
-
return;
|
|
1950
|
-
}
|
|
1951
|
-
if (indexed.has(outputIndex)) throw new Error(`Responses stream reused active output index ${outputIndex}`);
|
|
1952
|
-
indexed.set(outputIndex, slot);
|
|
1953
|
-
},
|
|
1954
|
-
resolve(event, type) {
|
|
1955
|
-
const outputIndex = readResponsesOutputIndex(event);
|
|
1956
|
-
let slot = outputIndex === void 0 ? unindexed : indexed.get(outputIndex);
|
|
1957
|
-
if (outputIndex === void 0 && !slot) {
|
|
1958
|
-
const matches = [...indexed.values()].filter((candidate) => candidate.type === type);
|
|
1959
|
-
slot = matches.length === 1 ? matches[0] : void 0;
|
|
1960
|
-
}
|
|
1961
|
-
return slot?.type === type ? slot : void 0;
|
|
1962
|
-
},
|
|
1963
|
-
get(event) {
|
|
1964
|
-
const outputIndex = readResponsesOutputIndex(event);
|
|
1965
|
-
return outputIndex === void 0 ? unindexed : indexed.get(outputIndex);
|
|
1966
|
-
},
|
|
1967
|
-
values() {
|
|
1968
|
-
return [.../* @__PURE__ */ new Set([...indexed.values(), ...unindexed ? [unindexed] : []])];
|
|
1969
|
-
},
|
|
1970
|
-
forget(slot) {
|
|
1971
|
-
if (unindexed === slot) unindexed = void 0;
|
|
1972
|
-
for (const [outputIndex, candidate] of indexed) if (candidate === slot) indexed.delete(outputIndex);
|
|
1973
|
-
}
|
|
1974
|
-
};
|
|
1975
|
-
}
|
|
1976
|
-
//#endregion
|
|
1977
|
-
//#region packages/ai/src/providers/openai-responses-terminal-usage.ts
|
|
1978
|
-
function readCount(value) {
|
|
1979
|
-
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
1980
|
-
}
|
|
1981
|
-
/**
|
|
1982
|
-
* Split a terminal usage payload into the priced buckets.
|
|
1983
|
-
*
|
|
1984
|
-
* OpenAI includes cache reads and writes in `input_tokens`, so both are subtracted out of the
|
|
1985
|
-
* billable input bucket. `total_tokens` comes from the payload, but never below the sum of the
|
|
1986
|
-
* split buckets: proxies routinely omit it (reporting 0 would understate the turn), and a payload
|
|
1987
|
-
* whose `cached_tokens` exceeds `input_tokens` clamps the input bucket, leaving the reported total
|
|
1988
|
-
* short of what the buckets actually price.
|
|
1989
|
-
*/
|
|
1990
|
-
function mapResponsesTerminalUsage(usage) {
|
|
1991
|
-
if (!usage) return;
|
|
1992
|
-
const cacheRead = readCount(usage.input_tokens_details?.cached_tokens);
|
|
1993
|
-
const cacheWrite = readCount(usage.input_tokens_details?.cache_write_tokens);
|
|
1994
|
-
const input = Math.max(0, readCount(usage.input_tokens) - cacheRead - cacheWrite);
|
|
1995
|
-
const output = readCount(usage.output_tokens);
|
|
1996
|
-
const bucketTotal = input + output + cacheRead + cacheWrite;
|
|
1997
|
-
return {
|
|
1998
|
-
input,
|
|
1999
|
-
output,
|
|
2000
|
-
cacheRead,
|
|
2001
|
-
cacheWrite,
|
|
2002
|
-
totalTokens: Math.max(bucketTotal, readCount(usage.total_tokens))
|
|
2003
|
-
};
|
|
2004
|
-
}
|
|
2005
|
-
/** Reasoning tokens are reported by the agent path only; the package path does not track them. */
|
|
2006
|
-
function readResponsesReasoningTokens(usage) {
|
|
2007
|
-
const reasoningTokens = usage?.output_tokens_details?.reasoning_tokens;
|
|
2008
|
-
return typeof reasoningTokens === "number" && Number.isFinite(reasoningTokens) ? reasoningTokens : void 0;
|
|
2009
|
-
}
|
|
2010
|
-
function mapResponsesTerminalStopReason(status) {
|
|
2011
|
-
if (!status) return "stop";
|
|
2012
|
-
switch (status) {
|
|
2013
|
-
case "completed": return "stop";
|
|
2014
|
-
case "incomplete": return "length";
|
|
2015
|
-
case "failed":
|
|
2016
|
-
case "cancelled": return "error";
|
|
2017
|
-
case "in_progress":
|
|
2018
|
-
case "queued": return "stop";
|
|
2019
|
-
default: throw new Error(`Unhandled stop reason: ${String(status)}`);
|
|
2020
|
-
}
|
|
2021
|
-
}
|
|
2022
|
-
/**
|
|
2023
|
-
* Resolve the terminal stop reason, including the two overrides every Responses path shares: a
|
|
2024
|
-
* content-filtered turn is a provider error rather than a truncated answer, and a turn that
|
|
2025
|
-
* produced tool calls reports `toolUse` instead of a plain stop.
|
|
2026
|
-
*/
|
|
2027
|
-
function resolveResponsesTerminalStopReason(params) {
|
|
2028
|
-
if (params.status === "incomplete" && params.incompleteReason === "content_filter") return {
|
|
2029
|
-
stopReason: "error",
|
|
2030
|
-
errorMessage: "Provider incomplete_reason: content_filter"
|
|
2031
|
-
};
|
|
2032
|
-
const stopReason = mapResponsesTerminalStopReason(params.status);
|
|
2033
|
-
if (stopReason === "stop" && params.hasToolCall) return { stopReason: "toolUse" };
|
|
2034
|
-
return { stopReason };
|
|
2035
|
-
}
|
|
2036
|
-
//#endregion
|
|
2037
|
-
//#region packages/ai/src/transports/openai-responses-stream-terminal-internal.ts
|
|
2038
|
-
function splitToolCallId(id) {
|
|
2039
|
-
const separator = id.indexOf("|");
|
|
2040
|
-
return separator === -1 ? [id, void 0] : [id.slice(0, separator), id.slice(separator + 1)];
|
|
2041
|
-
}
|
|
2042
|
-
function resolveResponsesToolCallId(item, fallbackId) {
|
|
2043
|
-
const callId = typeof item.call_id === "string" ? item.call_id.trim() : "";
|
|
2044
|
-
const itemId = typeof item.id === "string" ? item.id.trim() : "";
|
|
2045
|
-
const [fallbackCallId, fallbackItemId = ""] = splitToolCallId(fallbackId ?? "");
|
|
2046
|
-
const resolvedCallId = callId || fallbackCallId;
|
|
2047
|
-
const resolvedItemId = itemId || fallbackItemId;
|
|
2048
|
-
if (resolvedCallId) return resolvedItemId ? `${resolvedCallId}|${resolvedItemId}` : resolvedCallId;
|
|
2049
|
-
const generated = `call_${randomUUID().replaceAll("-", "").slice(0, 24)}`;
|
|
2050
|
-
return resolvedItemId ? `${generated}|${resolvedItemId}` : generated;
|
|
2051
|
-
}
|
|
2052
|
-
function resolveCompletedToolCallName(toolCall, value) {
|
|
2053
|
-
const streamedName = toolCall?.block.name.trim() || void 0;
|
|
2054
|
-
const completedName = typeof value === "string" ? value.trim() || void 0 : void 0;
|
|
2055
|
-
if (streamedName && completedName && streamedName !== completedName) throw new Error(`Responses stream changed tool-call function name from ${streamedName} to ${completedName}`);
|
|
2056
|
-
const name = completedName ?? streamedName;
|
|
2057
|
-
if (!name) throw new Error("Responses stream completed tool call without a function name");
|
|
2058
|
-
return name;
|
|
2059
|
-
}
|
|
2060
|
-
function createResponsesTerminalController(params) {
|
|
2061
|
-
const { output, stream, model, options } = params;
|
|
2062
|
-
const blocks = output.content;
|
|
2063
|
-
const backfillReasoning = (items) => {
|
|
2064
|
-
for (const item of items) {
|
|
2065
|
-
if (item.type !== "reasoning" || !item.encrypted_content) continue;
|
|
2066
|
-
const block = params.reasoningBlocksById.get(item.id);
|
|
2067
|
-
if (!block?.thinkingSignature) continue;
|
|
2068
|
-
const stored = JSON.parse(block.thinkingSignature);
|
|
2069
|
-
if (!stored.encrypted_content) block.thinkingSignature = JSON.stringify({
|
|
2070
|
-
...stored,
|
|
2071
|
-
encrypted_content: item.encrypted_content
|
|
2072
|
-
});
|
|
2073
|
-
if (options?.reasoningReplayMetadata) block[OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY] = options.reasoningReplayMetadata;
|
|
2074
|
-
}
|
|
2075
|
-
};
|
|
2076
|
-
const appendText = (item) => {
|
|
2077
|
-
const text = (Array.isArray(item.content) ? item.content : []).map((part) => {
|
|
2078
|
-
const content = part;
|
|
2079
|
-
return content.type === "output_text" || content.type === "text" ? content.text ?? "" : content.refusal ?? "";
|
|
2080
|
-
}).join("");
|
|
2081
|
-
if (!text) return;
|
|
2082
|
-
const phase = item.phase ?? void 0;
|
|
2083
|
-
const previous = params.getLastTextBlock();
|
|
2084
|
-
const collapse = resolveResponsesMessageSnapshotCollapse({
|
|
2085
|
-
prior: previous && {
|
|
2086
|
-
text: previous.block.text,
|
|
2087
|
-
phase: previous.phase
|
|
2088
|
-
},
|
|
2089
|
-
nextText: text,
|
|
2090
|
-
nextPhase: phase
|
|
2091
|
-
});
|
|
2092
|
-
if (collapse.kind === "extend" && previous) {
|
|
2093
|
-
previous.block.text = collapse.text;
|
|
2094
|
-
previous.block.textSignature = encodeTextSignatureV1(item.id, phase);
|
|
2095
|
-
stream.push({
|
|
2096
|
-
type: "text_end",
|
|
2097
|
-
contentIndex: previous.index,
|
|
2098
|
-
content: collapse.text,
|
|
2099
|
-
partial: output
|
|
2100
|
-
});
|
|
2101
|
-
return;
|
|
2102
|
-
}
|
|
2103
|
-
const block = {
|
|
2104
|
-
type: "text",
|
|
2105
|
-
text,
|
|
2106
|
-
textSignature: encodeTextSignatureV1(item.id, phase)
|
|
2107
|
-
};
|
|
2108
|
-
blocks.push(block);
|
|
2109
|
-
const index = blocks.length - 1;
|
|
2110
|
-
params.setLastTextBlock({
|
|
2111
|
-
block,
|
|
2112
|
-
index,
|
|
2113
|
-
phase
|
|
2114
|
-
});
|
|
2115
|
-
stream.push({
|
|
2116
|
-
type: "text_start",
|
|
2117
|
-
contentIndex: index,
|
|
2118
|
-
partial: output
|
|
2119
|
-
});
|
|
2120
|
-
stream.push({
|
|
2121
|
-
type: "text_end",
|
|
2122
|
-
contentIndex: index,
|
|
2123
|
-
content: text,
|
|
2124
|
-
partial: output
|
|
2125
|
-
});
|
|
2126
|
-
};
|
|
2127
|
-
const appendToolCall = (item) => {
|
|
2128
|
-
const toolCall = {
|
|
2129
|
-
type: "toolCall",
|
|
2130
|
-
id: resolveResponsesToolCallId(item),
|
|
2131
|
-
name: resolveCompletedToolCallName(void 0, item.name),
|
|
2132
|
-
arguments: parseStreamingJson(item.arguments || "{}")
|
|
2133
|
-
};
|
|
2134
|
-
blocks.push(toolCall);
|
|
2135
|
-
const contentIndex = blocks.length - 1;
|
|
2136
|
-
stream.push({
|
|
2137
|
-
type: "toolcall_start",
|
|
2138
|
-
contentIndex,
|
|
2139
|
-
partial: output
|
|
2140
|
-
});
|
|
2141
|
-
stream.push({
|
|
2142
|
-
type: "toolcall_end",
|
|
2143
|
-
contentIndex,
|
|
2144
|
-
toolCall,
|
|
2145
|
-
partial: output
|
|
2146
|
-
});
|
|
2147
|
-
};
|
|
2148
|
-
const recoverTerminalOutput = (items, includeToolCalls) => {
|
|
2149
|
-
if (blocks.length > 0) return;
|
|
2150
|
-
for (const item of items) if (item.type === "message") appendText(item);
|
|
2151
|
-
else {
|
|
2152
|
-
params.setLastTextBlock(null);
|
|
2153
|
-
if (includeToolCalls && item.type === "function_call") appendToolCall(item);
|
|
2154
|
-
}
|
|
2155
|
-
};
|
|
2156
|
-
const finalizeResponse = (response) => {
|
|
2157
|
-
params.markFinalized();
|
|
2158
|
-
backfillReasoning(response.output ?? []);
|
|
2159
|
-
output.responseId = response.id || output.responseId;
|
|
2160
|
-
const usage = mapResponsesTerminalUsage(response.usage);
|
|
2161
|
-
const reasoningTokens = readResponsesReasoningTokens(response.usage);
|
|
2162
|
-
if (usage) output.usage = {
|
|
2163
|
-
...usage,
|
|
2164
|
-
...reasoningTokens === void 0 ? {} : { reasoningTokens },
|
|
2165
|
-
cost: {
|
|
2166
|
-
input: 0,
|
|
2167
|
-
output: 0,
|
|
2168
|
-
cacheRead: 0,
|
|
2169
|
-
cacheWrite: 0,
|
|
2170
|
-
total: 0
|
|
2171
|
-
}
|
|
2172
|
-
};
|
|
2173
|
-
calculateCost(model, output.usage);
|
|
2174
|
-
if (options?.applyServiceTierPricing) {
|
|
2175
|
-
const tier = options.resolveServiceTier ? options.resolveServiceTier(response.service_tier, options.serviceTier) : response.service_tier ?? options.serviceTier;
|
|
2176
|
-
options.applyServiceTierPricing(output.usage, tier);
|
|
2177
|
-
}
|
|
2178
|
-
const terminal = resolveResponsesTerminalStopReason({
|
|
2179
|
-
status: response.status,
|
|
2180
|
-
incompleteReason: response.incomplete_details?.reason,
|
|
2181
|
-
hasToolCall: blocks.some((block) => block.type === "toolCall")
|
|
2182
|
-
});
|
|
2183
|
-
output.stopReason = terminal.stopReason;
|
|
2184
|
-
output.errorMessage = terminal.errorMessage;
|
|
2185
|
-
};
|
|
2186
|
-
return {
|
|
2187
|
-
finalizeResponse,
|
|
2188
|
-
recoverTerminalOutput
|
|
2189
|
-
};
|
|
2190
|
-
}
|
|
2191
|
-
//#endregion
|
|
2192
|
-
//#region packages/ai/src/transports/openai-responses-stream-internal.ts
|
|
2193
|
-
var ResponsesStreamFailure = class extends Error {
|
|
2194
|
-
constructor(failure, response) {
|
|
2195
|
-
super(failure.message);
|
|
2196
|
-
this.name = "ResponsesStreamFailure";
|
|
2197
|
-
this.responseId = failure.responseId;
|
|
2198
|
-
this.response = response;
|
|
2199
|
-
this.observation = failure.observation;
|
|
2200
|
-
}
|
|
2201
|
-
};
|
|
2202
|
-
async function processResponsesStream(openaiStream, output, stream, model, options) {
|
|
2203
|
-
const streamingToolCalls = createResponsesToolCallTracker();
|
|
2204
|
-
const outputSlots = createResponsesOutputSlotTracker();
|
|
2205
|
-
const reasoningBlocksById = /* @__PURE__ */ new Map();
|
|
2206
|
-
let terminalResponseEvent;
|
|
2207
|
-
let lastTextBlock = null;
|
|
2208
|
-
const blocks = output.content;
|
|
2209
|
-
const blockIndex = () => blocks.length - 1;
|
|
2210
|
-
const createOutputSlot = (event, item) => {
|
|
2211
|
-
if (item.type === "reasoning") {
|
|
2212
|
-
const block = {
|
|
2213
|
-
type: "thinking",
|
|
2214
|
-
thinking: ""
|
|
2215
|
-
};
|
|
2216
|
-
const slot = {
|
|
2217
|
-
type: "thinking",
|
|
2218
|
-
item,
|
|
2219
|
-
block,
|
|
2220
|
-
contentIndex: blocks.length
|
|
2221
|
-
};
|
|
2222
|
-
blocks.push(block);
|
|
2223
|
-
outputSlots.register(event, slot);
|
|
2224
|
-
stream.push({
|
|
2225
|
-
type: "thinking_start",
|
|
2226
|
-
contentIndex: slot.contentIndex,
|
|
2227
|
-
partial: output
|
|
2228
|
-
});
|
|
2229
|
-
return slot;
|
|
2230
|
-
}
|
|
2231
|
-
if (item.type === "message") {
|
|
2232
|
-
const messageItem = item;
|
|
2233
|
-
const collapseCandidate = lastTextBlock;
|
|
2234
|
-
const block = collapseCandidate ? null : {
|
|
2235
|
-
type: "text",
|
|
2236
|
-
text: "",
|
|
2237
|
-
...messageItem.phase ? { textSignature: encodeTextSignatureV1(messageItem.id, messageItem.phase) } : {}
|
|
2238
|
-
};
|
|
2239
|
-
const slot = {
|
|
2240
|
-
type: "text",
|
|
2241
|
-
item: messageItem,
|
|
2242
|
-
block,
|
|
2243
|
-
contentIndex: block ? blocks.length : void 0,
|
|
2244
|
-
pendingText: collapseCandidate ? "" : null,
|
|
2245
|
-
collapseCandidate
|
|
2246
|
-
};
|
|
2247
|
-
if (block) blocks.push(block);
|
|
2248
|
-
outputSlots.register(event, slot);
|
|
2249
|
-
if (slot.contentIndex !== void 0) stream.push({
|
|
2250
|
-
type: "text_start",
|
|
2251
|
-
contentIndex: slot.contentIndex,
|
|
2252
|
-
partial: output
|
|
2253
|
-
});
|
|
2254
|
-
return slot;
|
|
2255
|
-
}
|
|
2256
|
-
};
|
|
2257
|
-
const resolveOutputItemSlot = (event, item) => {
|
|
2258
|
-
if (item.type === "reasoning") return outputSlots.resolve(event, "thinking");
|
|
2259
|
-
if (item.type === "message") return outputSlots.resolve(event, "text");
|
|
2260
|
-
return readResponsesOutputIndex(event) === void 0 ? void 0 : outputSlots.get(event);
|
|
2261
|
-
};
|
|
2262
|
-
const getOrCreateOutputSlot = (event, item) => {
|
|
2263
|
-
return resolveOutputItemSlot(event, item) ?? createOutputSlot(event, item);
|
|
2264
|
-
};
|
|
2265
|
-
const materializeDeferredTextSlot = (slot) => {
|
|
2266
|
-
if (slot.block || slot.pendingText === null) return;
|
|
2267
|
-
const text = slot.pendingText;
|
|
2268
|
-
slot.block = {
|
|
2269
|
-
type: "text",
|
|
2270
|
-
text,
|
|
2271
|
-
...slot.item.phase ? { textSignature: encodeTextSignatureV1(slot.item.id, slot.item.phase) } : {}
|
|
2272
|
-
};
|
|
2273
|
-
blocks.push(slot.block);
|
|
2274
|
-
slot.contentIndex = blockIndex();
|
|
2275
|
-
stream.push({
|
|
2276
|
-
type: "text_start",
|
|
2277
|
-
contentIndex: slot.contentIndex,
|
|
2278
|
-
partial: output
|
|
2279
|
-
});
|
|
2280
|
-
if (text) stream.push({
|
|
2281
|
-
type: "text_delta",
|
|
2282
|
-
contentIndex: slot.contentIndex,
|
|
2283
|
-
delta: text
|
|
2284
|
-
});
|
|
2285
|
-
if (lastTextBlock === slot.collapseCandidate) lastTextBlock = null;
|
|
2286
|
-
slot.pendingText = null;
|
|
2287
|
-
slot.collapseCandidate = null;
|
|
2288
|
-
};
|
|
2289
|
-
const materializeDeferredTextSlots = (except) => {
|
|
2290
|
-
for (const slot of outputSlots.values()) if (slot !== except && slot.type === "text") materializeDeferredTextSlot(slot);
|
|
2291
|
-
};
|
|
2292
|
-
const appendPendingMessageDelta = (slot, delta) => {
|
|
2293
|
-
slot.pendingText = `${slot.pendingText ?? ""}${delta}`;
|
|
2294
|
-
const priorText = slot.collapseCandidate?.block.text ?? "";
|
|
2295
|
-
if (priorText.startsWith(slot.pendingText) || slot.pendingText.startsWith(priorText)) return;
|
|
2296
|
-
materializeDeferredTextSlot(slot);
|
|
2297
|
-
};
|
|
2298
|
-
const { finalizeResponse, recoverTerminalOutput } = createResponsesTerminalController({
|
|
2299
|
-
output,
|
|
2300
|
-
stream,
|
|
2301
|
-
model,
|
|
2302
|
-
options,
|
|
2303
|
-
reasoningBlocksById,
|
|
2304
|
-
getLastTextBlock: () => lastTextBlock,
|
|
2305
|
-
setLastTextBlock: (block) => {
|
|
2306
|
-
lastTextBlock = block;
|
|
2307
|
-
},
|
|
2308
|
-
markFinalized: () => {
|
|
2309
|
-
terminalResponseEvent = "finalized";
|
|
2310
|
-
}
|
|
2311
|
-
});
|
|
2312
|
-
const guardedStream = adaptResponsesStream(withFirstStreamEventTimeout(openaiStream, {
|
|
2313
|
-
provider: model.provider,
|
|
2314
|
-
api: model.api,
|
|
2315
|
-
model: model.id,
|
|
2316
|
-
timeoutMs: options?.firstEventTimeoutMs ?? 0,
|
|
2317
|
-
stage: "responses",
|
|
2318
|
-
abort: options?.abortFirstEventStream,
|
|
2319
|
-
onTimeout: options?.onFirstEventTimeout,
|
|
2320
|
-
hint: "The provider may be stalled while parsing the tool payload; retry with a smaller tool surface or enable OPENCLAW_DEBUG_MODEL_PAYLOAD=tools to inspect exposed tools."
|
|
2321
|
-
}), options?.signal);
|
|
2322
|
-
try {
|
|
2323
|
-
for await (const event of guardedStream) if (event.type === "response.created") output.responseId = event.response.id;
|
|
2324
|
-
else if (event.type === "response.output_item.added") {
|
|
2325
|
-
materializeDeferredTextSlots();
|
|
2326
|
-
const item = event.item;
|
|
2327
|
-
if (item.type !== "message") lastTextBlock = null;
|
|
2328
|
-
if (item.type === "reasoning" || item.type === "message") createOutputSlot(event, item);
|
|
2329
|
-
else if (item.type === "function_call") {
|
|
2330
|
-
const toolCallBlock = {
|
|
2331
|
-
type: "toolCall",
|
|
2332
|
-
id: resolveResponsesToolCallId(item),
|
|
2333
|
-
name: typeof item.name === "string" ? item.name.trim() : "",
|
|
2334
|
-
arguments: {},
|
|
2335
|
-
partialJson: item.arguments || ""
|
|
2336
|
-
};
|
|
2337
|
-
const contentIndex = output.content.length;
|
|
2338
|
-
const toolCallState = {
|
|
2339
|
-
block: toolCallBlock,
|
|
2340
|
-
contentIndex,
|
|
2341
|
-
argumentStreamReliable: true,
|
|
2342
|
-
...readResponsesToolCallItemIdentity(item)
|
|
2343
|
-
};
|
|
2344
|
-
streamingToolCalls.register(event, toolCallState);
|
|
2345
|
-
if (readResponsesOutputIndex(event) !== void 0) outputSlots.register(event, {
|
|
2346
|
-
type: "toolCall",
|
|
2347
|
-
toolCall: toolCallState
|
|
2348
|
-
});
|
|
2349
|
-
output.content.push(toolCallBlock);
|
|
2350
|
-
stream.push({
|
|
2351
|
-
type: "toolcall_start",
|
|
2352
|
-
contentIndex,
|
|
2353
|
-
partial: output
|
|
2354
|
-
});
|
|
2355
|
-
}
|
|
2356
|
-
} else if (event.type === "response.reasoning_summary_part.added") {
|
|
2357
|
-
const slot = outputSlots.resolve(event, "thinking");
|
|
2358
|
-
if (!slot) continue;
|
|
2359
|
-
slot.item.summary = slot.item.summary || [];
|
|
2360
|
-
slot.item.summary.push(event.part);
|
|
2361
|
-
} else if (event.type === "response.reasoning_summary_text.delta") {
|
|
2362
|
-
const slot = outputSlots.resolve(event, "thinking");
|
|
2363
|
-
if (!slot) continue;
|
|
2364
|
-
slot.item.summary = slot.item.summary || [];
|
|
2365
|
-
const lastPart = slot.item.summary[slot.item.summary.length - 1];
|
|
2366
|
-
if (!lastPart) continue;
|
|
2367
|
-
slot.block.thinking += event.delta;
|
|
2368
|
-
lastPart.text += event.delta;
|
|
2369
|
-
stream.push({
|
|
2370
|
-
type: "thinking_delta",
|
|
2371
|
-
contentIndex: slot.contentIndex,
|
|
2372
|
-
delta: event.delta,
|
|
2373
|
-
partial: output
|
|
2374
|
-
});
|
|
2375
|
-
} else if (event.type === "response.reasoning_summary_part.done") {
|
|
2376
|
-
const slot = outputSlots.resolve(event, "thinking");
|
|
2377
|
-
if (!slot) continue;
|
|
2378
|
-
slot.item.summary = slot.item.summary || [];
|
|
2379
|
-
const lastPart = slot.item.summary[slot.item.summary.length - 1];
|
|
2380
|
-
if (!lastPart) continue;
|
|
2381
|
-
slot.block.thinking += "\n\n";
|
|
2382
|
-
lastPart.text += "\n\n";
|
|
2383
|
-
stream.push({
|
|
2384
|
-
type: "thinking_delta",
|
|
2385
|
-
contentIndex: slot.contentIndex,
|
|
2386
|
-
delta: "\n\n",
|
|
2387
|
-
partial: output
|
|
2388
|
-
});
|
|
2389
|
-
} else if (event.type === "response.reasoning_text.delta") {
|
|
2390
|
-
const slot = outputSlots.resolve(event, "thinking");
|
|
2391
|
-
if (!slot) continue;
|
|
2392
|
-
slot.block.thinking += event.delta;
|
|
2393
|
-
stream.push({
|
|
2394
|
-
type: "thinking_delta",
|
|
2395
|
-
contentIndex: slot.contentIndex,
|
|
2396
|
-
delta: event.delta,
|
|
2397
|
-
partial: output
|
|
2398
|
-
});
|
|
2399
|
-
} else if (event.type === "response.content_part.added") {
|
|
2400
|
-
const slot = outputSlots.resolve(event, "text");
|
|
2401
|
-
if (!slot) continue;
|
|
2402
|
-
slot.item.content = slot.item.content || [];
|
|
2403
|
-
if (event.part.type === "output_text" || event.part.type === "text" || event.part.type === "refusal") slot.item.content.push(event.part);
|
|
2404
|
-
} else if (event.type === "response.output_text.delta") {
|
|
2405
|
-
const slot = outputSlots.resolve(event, "text");
|
|
2406
|
-
if (!slot) continue;
|
|
2407
|
-
slot.item.content ||= [];
|
|
2408
|
-
let lastPart = slot.item.content[slot.item.content.length - 1];
|
|
2409
|
-
if (!isResponsesTextContentPartType(lastPart?.type)) {
|
|
2410
|
-
lastPart = {
|
|
2411
|
-
type: "output_text",
|
|
2412
|
-
text: "",
|
|
2413
|
-
annotations: []
|
|
2414
|
-
};
|
|
2415
|
-
slot.item.content.push(lastPart);
|
|
2416
|
-
}
|
|
2417
|
-
lastPart.text += event.delta;
|
|
2418
|
-
if (slot.pendingText !== null) appendPendingMessageDelta(slot, event.delta);
|
|
2419
|
-
else if (slot.block && slot.contentIndex !== void 0) {
|
|
2420
|
-
slot.block.text += event.delta;
|
|
2421
|
-
stream.push({
|
|
2422
|
-
type: "text_delta",
|
|
2423
|
-
contentIndex: slot.contentIndex,
|
|
2424
|
-
delta: event.delta
|
|
2425
|
-
});
|
|
2426
|
-
}
|
|
2427
|
-
} else if (isAzureResponsesTextDeltaEvent(event)) {
|
|
2428
|
-
const slot = outputSlots.resolve(event, "text");
|
|
2429
|
-
if (!slot) continue;
|
|
2430
|
-
slot.item.content = slot.item.content || [];
|
|
2431
|
-
let lastPart = slot.item.content[slot.item.content.length - 1];
|
|
2432
|
-
if (lastPart?.type !== "text") {
|
|
2433
|
-
lastPart = {
|
|
2434
|
-
type: "text",
|
|
2435
|
-
text: ""
|
|
2436
|
-
};
|
|
2437
|
-
slot.item.content.push(lastPart);
|
|
2438
|
-
}
|
|
2439
|
-
lastPart.text += event.delta;
|
|
2440
|
-
if (slot.pendingText !== null) appendPendingMessageDelta(slot, event.delta);
|
|
2441
|
-
else if (slot.block && slot.contentIndex !== void 0) {
|
|
2442
|
-
slot.block.text += event.delta;
|
|
2443
|
-
stream.push({
|
|
2444
|
-
type: "text_delta",
|
|
2445
|
-
contentIndex: slot.contentIndex,
|
|
2446
|
-
delta: event.delta
|
|
2447
|
-
});
|
|
2448
|
-
}
|
|
2449
|
-
} else if (event.type === "response.refusal.delta") {
|
|
2450
|
-
const slot = outputSlots.resolve(event, "text");
|
|
2451
|
-
if (!slot) continue;
|
|
2452
|
-
slot.item.content ||= [];
|
|
2453
|
-
let lastPart = slot.item.content[slot.item.content.length - 1];
|
|
2454
|
-
if (lastPart?.type !== "refusal") {
|
|
2455
|
-
lastPart = {
|
|
2456
|
-
type: "refusal",
|
|
2457
|
-
refusal: ""
|
|
2458
|
-
};
|
|
2459
|
-
slot.item.content.push(lastPart);
|
|
2460
|
-
}
|
|
2461
|
-
lastPart.refusal += event.delta;
|
|
2462
|
-
if (slot.pendingText !== null) appendPendingMessageDelta(slot, event.delta);
|
|
2463
|
-
else if (slot.block && slot.contentIndex !== void 0) {
|
|
2464
|
-
slot.block.text += event.delta;
|
|
2465
|
-
stream.push({
|
|
2466
|
-
type: "text_delta",
|
|
2467
|
-
contentIndex: slot.contentIndex,
|
|
2468
|
-
delta: event.delta
|
|
2469
|
-
});
|
|
2470
|
-
}
|
|
2471
|
-
} else if (event.type === "response.function_call_arguments.delta") {
|
|
2472
|
-
const toolCall = streamingToolCalls.resolve(event);
|
|
2473
|
-
if (toolCall) {
|
|
2474
|
-
toolCall.block.partialJson += event.delta;
|
|
2475
|
-
toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
|
|
2476
|
-
stream.push({
|
|
2477
|
-
type: "toolcall_delta",
|
|
2478
|
-
contentIndex: toolCall.contentIndex,
|
|
2479
|
-
delta: event.delta,
|
|
2480
|
-
partial: output
|
|
2481
|
-
});
|
|
2482
|
-
} else if (streamingToolCalls.hasActive()) streamingToolCalls.markArgumentsUnreliable();
|
|
2483
|
-
} else if (event.type === "response.function_call_arguments.done") {
|
|
2484
|
-
const toolCall = streamingToolCalls.resolve(event);
|
|
2485
|
-
if (toolCall) {
|
|
2486
|
-
const previousPartialJson = toolCall.block.partialJson;
|
|
2487
|
-
const doneArguments = typeof event.arguments === "string" ? event.arguments : void 0;
|
|
2488
|
-
if (doneArguments !== void 0 && (doneArguments.length > 0 || previousPartialJson === "")) {
|
|
2489
|
-
toolCall.block.partialJson = doneArguments;
|
|
2490
|
-
toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
|
|
2491
|
-
toolCall.argumentStreamReliable = true;
|
|
2492
|
-
}
|
|
2493
|
-
if (doneArguments?.startsWith(previousPartialJson)) {
|
|
2494
|
-
const delta = doneArguments.slice(previousPartialJson.length);
|
|
2495
|
-
if (delta.length > 0) stream.push({
|
|
2496
|
-
type: "toolcall_delta",
|
|
2497
|
-
contentIndex: toolCall.contentIndex,
|
|
2498
|
-
delta,
|
|
2499
|
-
partial: output
|
|
2500
|
-
});
|
|
2501
|
-
}
|
|
2502
|
-
} else if (streamingToolCalls.hasActive()) streamingToolCalls.markArgumentsUnreliable();
|
|
2503
|
-
} else if (event.type === "response.output_item.done") {
|
|
2504
|
-
const item = event.item;
|
|
2505
|
-
if (item.type !== "message") lastTextBlock = null;
|
|
2506
|
-
const existingOutputSlot = resolveOutputItemSlot(event, item);
|
|
2507
|
-
materializeDeferredTextSlots(existingOutputSlot);
|
|
2508
|
-
const outputSlot = existingOutputSlot ?? getOrCreateOutputSlot(event, item);
|
|
2509
|
-
if (item.type === "reasoning" && outputSlot?.type === "thinking") {
|
|
2510
|
-
const summaryText = item.summary?.map((s) => s.text).join("\n\n") || "";
|
|
2511
|
-
const contentText = item.content?.map((c) => c.text).join("\n\n") || "";
|
|
2512
|
-
outputSlot.block.thinking = summaryText || contentText || outputSlot.block.thinking;
|
|
2513
|
-
outputSlot.block.thinkingSignature = JSON.stringify(item);
|
|
2514
|
-
if (item.encrypted_content && options?.reasoningReplayMetadata) outputSlot.block[OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY] = options.reasoningReplayMetadata;
|
|
2515
|
-
if (typeof item.id === "string") reasoningBlocksById.set(item.id, outputSlot.block);
|
|
2516
|
-
stream.push({
|
|
2517
|
-
type: "thinking_end",
|
|
2518
|
-
contentIndex: outputSlot.contentIndex,
|
|
2519
|
-
content: outputSlot.block.thinking,
|
|
2520
|
-
partial: output
|
|
2521
|
-
});
|
|
2522
|
-
outputSlots.forget(outputSlot);
|
|
2523
|
-
} else if (item.type === "message" && outputSlot?.type === "text" && (outputSlot.block || outputSlot.pendingText !== null)) {
|
|
2524
|
-
const streamedText = outputSlot.pendingText ?? outputSlot.block?.text ?? "";
|
|
2525
|
-
const finalText = item.content == null ? streamedText : item.content.map((c) => c.type === "output_text" || c.type === "text" ? c.text : c.refusal).join("");
|
|
2526
|
-
const phase = item.phase ?? void 0;
|
|
2527
|
-
const collapse = outputSlot.pendingText !== null ? resolveResponsesMessageSnapshotCollapse({
|
|
2528
|
-
prior: outputSlot.collapseCandidate && {
|
|
2529
|
-
text: outputSlot.collapseCandidate.block.text,
|
|
2530
|
-
phase: outputSlot.collapseCandidate.phase
|
|
2531
|
-
},
|
|
2532
|
-
nextText: finalText,
|
|
2533
|
-
nextPhase: phase
|
|
2534
|
-
}) : { kind: "keep" };
|
|
2535
|
-
outputSlot.pendingText = null;
|
|
2536
|
-
if (collapse.kind === "extend" && outputSlot.collapseCandidate) {
|
|
2537
|
-
outputSlot.collapseCandidate.block.text = collapse.text;
|
|
2538
|
-
outputSlot.collapseCandidate.block.textSignature = encodeTextSignatureV1(item.id, phase);
|
|
2539
|
-
stream.push({
|
|
2540
|
-
type: "text_end",
|
|
2541
|
-
contentIndex: outputSlot.collapseCandidate.index,
|
|
2542
|
-
content: collapse.text,
|
|
2543
|
-
partial: output
|
|
2544
|
-
});
|
|
2545
|
-
lastTextBlock = outputSlot.collapseCandidate;
|
|
2546
|
-
} else {
|
|
2547
|
-
if (!outputSlot.block) {
|
|
2548
|
-
outputSlot.block = {
|
|
2549
|
-
type: "text",
|
|
2550
|
-
text: "",
|
|
2551
|
-
...phase ? { textSignature: encodeTextSignatureV1(item.id, phase) } : {}
|
|
2552
|
-
};
|
|
2553
|
-
blocks.push(outputSlot.block);
|
|
2554
|
-
outputSlot.contentIndex = blockIndex();
|
|
2555
|
-
stream.push({
|
|
2556
|
-
type: "text_start",
|
|
2557
|
-
contentIndex: outputSlot.contentIndex,
|
|
2558
|
-
partial: output
|
|
2559
|
-
});
|
|
2560
|
-
}
|
|
2561
|
-
outputSlot.block.text = finalText;
|
|
2562
|
-
outputSlot.block.textSignature = encodeTextSignatureV1(item.id, phase);
|
|
2563
|
-
const contentIndex = outputSlot.contentIndex;
|
|
2564
|
-
if (contentIndex === void 0) throw new Error("Responses stream finalized text without a content index");
|
|
2565
|
-
lastTextBlock = {
|
|
2566
|
-
block: outputSlot.block,
|
|
2567
|
-
index: contentIndex,
|
|
2568
|
-
phase
|
|
2569
|
-
};
|
|
2570
|
-
stream.push({
|
|
2571
|
-
type: "text_end",
|
|
2572
|
-
contentIndex,
|
|
2573
|
-
content: outputSlot.block.text,
|
|
2574
|
-
partial: output
|
|
2575
|
-
});
|
|
2576
|
-
}
|
|
2577
|
-
outputSlots.forget(outputSlot);
|
|
2578
|
-
} else if (item.type === "function_call") {
|
|
2579
|
-
const streamingToolCall = streamingToolCalls.resolve(event, readResponsesToolCallItemIdentity(item));
|
|
2580
|
-
if (!streamingToolCall && streamingToolCalls.hasActive()) continue;
|
|
2581
|
-
const completedName = resolveCompletedToolCallName(streamingToolCall, item.name);
|
|
2582
|
-
const streamedArguments = streamingToolCall?.block.partialJson ?? "";
|
|
2583
|
-
const completedArguments = typeof item.arguments === "string" ? item.arguments : void 0;
|
|
2584
|
-
if (streamingToolCall && !streamingToolCall.argumentStreamReliable && !completedArguments) continue;
|
|
2585
|
-
const args = parseStreamingJson(completedArguments !== void 0 && (completedArguments.length > 0 || !streamedArguments) ? completedArguments : streamedArguments || "{}");
|
|
2586
|
-
let toolCall;
|
|
2587
|
-
let contentIndex;
|
|
2588
|
-
if (streamingToolCall) {
|
|
2589
|
-
const block = streamingToolCall.block;
|
|
2590
|
-
block.id = resolveResponsesToolCallId(item, block.id);
|
|
2591
|
-
block.name = completedName;
|
|
2592
|
-
block.arguments = args;
|
|
2593
|
-
delete block.partialJson;
|
|
2594
|
-
toolCall = block;
|
|
2595
|
-
contentIndex = streamingToolCall.contentIndex;
|
|
2596
|
-
} else {
|
|
2597
|
-
toolCall = {
|
|
2598
|
-
type: "toolCall",
|
|
2599
|
-
id: resolveResponsesToolCallId(item),
|
|
2600
|
-
name: completedName,
|
|
2601
|
-
arguments: args
|
|
2602
|
-
};
|
|
2603
|
-
blocks.push(toolCall);
|
|
2604
|
-
contentIndex = blockIndex();
|
|
2605
|
-
stream.push({
|
|
2606
|
-
type: "toolcall_start",
|
|
2607
|
-
contentIndex,
|
|
2608
|
-
partial: output
|
|
2609
|
-
});
|
|
2610
|
-
}
|
|
2611
|
-
if (streamingToolCall) {
|
|
2612
|
-
streamingToolCalls.forget(streamingToolCall);
|
|
2613
|
-
for (const slot of outputSlots.values()) if (slot.type === "toolCall" && slot.toolCall === streamingToolCall) outputSlots.forget(slot);
|
|
2614
|
-
}
|
|
2615
|
-
stream.push({
|
|
2616
|
-
type: "toolcall_end",
|
|
2617
|
-
contentIndex,
|
|
2618
|
-
toolCall,
|
|
2619
|
-
partial: output
|
|
2063
|
+
...msgId ? { id: msgId } : {},
|
|
2064
|
+
phase: textSignature?.phase
|
|
2065
|
+
};
|
|
2066
|
+
output.push(messageItem);
|
|
2067
|
+
previousReplayItemWasReasoning = false;
|
|
2068
|
+
} else if (block.type === "toolCall") {
|
|
2069
|
+
const separatorIndex = block.id.indexOf("|");
|
|
2070
|
+
const callId = separatorIndex === -1 ? block.id : block.id.slice(0, separatorIndex);
|
|
2071
|
+
const itemIdRaw = separatorIndex === -1 ? void 0 : block.id.slice(separatorIndex + 1);
|
|
2072
|
+
const itemId = shouldReplayResponsesItemIds && !(isDifferentModel && itemIdRaw?.startsWith("fc_")) ? itemIdRaw : void 0;
|
|
2073
|
+
output.push({
|
|
2074
|
+
type: "function_call",
|
|
2075
|
+
...itemId ? { id: itemId } : {},
|
|
2076
|
+
call_id: callId,
|
|
2077
|
+
name: block.name,
|
|
2078
|
+
arguments: typeof block.arguments === "string" ? block.arguments : JSON.stringify(block.arguments ?? {})
|
|
2620
2079
|
});
|
|
2080
|
+
previousReplayItemWasReasoning = false;
|
|
2621
2081
|
}
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
const
|
|
2631
|
-
|
|
2632
|
-
|
|
2082
|
+
if (output.length > 0) messages.push(...output);
|
|
2083
|
+
} else if (msg.role === "toolResult") {
|
|
2084
|
+
const textResult = extractToolResultText(msg.content);
|
|
2085
|
+
const sanitizedTextResult = sanitizeTransportPayloadText(textResult);
|
|
2086
|
+
const hasText = sanitizedTextResult.trim().length > 0;
|
|
2087
|
+
const mediaPlaceholder = describeToolResultMediaPlaceholder(msg.content);
|
|
2088
|
+
const hasImages = msg.content.some(isImageWithMediaPayload);
|
|
2089
|
+
const separatorIndex = msg.toolCallId.indexOf("|");
|
|
2090
|
+
const callId = separatorIndex === -1 ? msg.toolCallId : msg.toolCallId.slice(0, separatorIndex);
|
|
2091
|
+
messages.push({
|
|
2092
|
+
type: "function_call_output",
|
|
2093
|
+
call_id: callId,
|
|
2094
|
+
output: hasImages && model.input.includes("image") ? [...hasText ? [{
|
|
2095
|
+
type: "input_text",
|
|
2096
|
+
text: sanitizedTextResult
|
|
2097
|
+
}] : mediaPlaceholder === "(see attached media)" ? [{
|
|
2098
|
+
type: "input_text",
|
|
2099
|
+
text: mediaPlaceholder
|
|
2100
|
+
}] : [], ...msg.content.filter(isImageWithMediaPayload).map((item) => ({
|
|
2101
|
+
type: "input_image",
|
|
2102
|
+
detail: "auto",
|
|
2103
|
+
image_url: `data:${item.mimeType};base64,${item.data}`
|
|
2104
|
+
}))] : sanitizeNonEmptyTransportPayloadText(textResult, mediaPlaceholder ?? "(no output)")
|
|
2105
|
+
});
|
|
2633
2106
|
}
|
|
2634
|
-
|
|
2635
|
-
if (!terminalResponseEvent) throw new Error("OpenAI Responses stream ended before a terminal response event");
|
|
2636
|
-
} finally {
|
|
2637
|
-
for (const block of output.content) delete block.partialJson;
|
|
2107
|
+
msgIndex += 1;
|
|
2638
2108
|
}
|
|
2109
|
+
return messages;
|
|
2639
2110
|
}
|
|
2640
2111
|
//#endregion
|
|
2641
|
-
//#region packages/ai/src/providers/openai-
|
|
2642
|
-
const
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
"
|
|
2648
|
-
"properties"
|
|
2649
|
-
]);
|
|
2650
|
-
const OPENAI_NULLABLE_ANNOTATION_KEYS = /* @__PURE__ */ new Set([
|
|
2651
|
-
"default",
|
|
2652
|
-
"description",
|
|
2653
|
-
"examples",
|
|
2654
|
-
"format",
|
|
2655
|
-
"title"
|
|
2656
|
-
]);
|
|
2657
|
-
const OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS = /* @__PURE__ */ new Set([
|
|
2658
|
-
"additionalItems",
|
|
2659
|
-
"additionalProperties",
|
|
2660
|
-
"allOf",
|
|
2661
|
-
"anyOf",
|
|
2662
|
-
"contains",
|
|
2663
|
-
"contentSchema",
|
|
2664
|
-
"else",
|
|
2665
|
-
"if",
|
|
2666
|
-
"items",
|
|
2667
|
-
"not",
|
|
2668
|
-
"oneOf",
|
|
2669
|
-
"prefixItems",
|
|
2670
|
-
"propertyNames",
|
|
2671
|
-
"then",
|
|
2672
|
-
"unevaluatedItems",
|
|
2673
|
-
"unevaluatedProperties"
|
|
2674
|
-
]);
|
|
2675
|
-
function normalizeOpenAIStrictCompatSchemaMap(schema) {
|
|
2676
|
-
if (!schema || typeof schema !== "object" || Array.isArray(schema)) return schema;
|
|
2677
|
-
let changed = false;
|
|
2678
|
-
const normalized = {};
|
|
2679
|
-
for (const [key, value] of Object.entries(schema)) {
|
|
2680
|
-
const next = normalizeOpenAIStrictCompatSchemaRecursive(value, { promoteEmptyObject: false });
|
|
2681
|
-
normalized[key] = next;
|
|
2682
|
-
changed ||= next !== value;
|
|
2683
|
-
}
|
|
2684
|
-
return changed ? normalized : schema;
|
|
2112
|
+
//#region packages/ai/src/providers/openai-responses-stream-compat.ts
|
|
2113
|
+
const OPENAI_RESPONSES_OUTPUT_TEXT_CONTENT_PART_TYPE = "output_text";
|
|
2114
|
+
const AZURE_RESPONSES_TEXT_CONTENT_PART_TYPE = "text";
|
|
2115
|
+
const OPENAI_RESPONSES_OUTPUT_TEXT_DELTA_EVENT_TYPE = "response.output_text.delta";
|
|
2116
|
+
const AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE = "response.text.delta";
|
|
2117
|
+
function isResponsesTextContentPartType(type) {
|
|
2118
|
+
return type === "output_text" || type === "text";
|
|
2685
2119
|
}
|
|
2686
|
-
function
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2120
|
+
function isResponsesTextDeltaEventType(type) {
|
|
2121
|
+
return type === "response.output_text.delta" || type === "response.text.delta";
|
|
2122
|
+
}
|
|
2123
|
+
function isAzureResponsesTextDeltaEventType(type) {
|
|
2124
|
+
return type === AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE;
|
|
2125
|
+
}
|
|
2126
|
+
function isAzureResponsesTextDeltaEvent(event) {
|
|
2127
|
+
return isAzureResponsesTextDeltaEventType(event.type) && typeof event.delta === "string";
|
|
2128
|
+
}
|
|
2129
|
+
function resolveResponsesMessageSnapshotCollapse(params) {
|
|
2130
|
+
const { prior, nextText } = params;
|
|
2131
|
+
if (!prior?.text || !nextText || prior.phase !== params.nextPhase) return { kind: "keep" };
|
|
2132
|
+
if (nextText.length > prior.text.length && nextText.startsWith(prior.text)) return {
|
|
2133
|
+
kind: "extend",
|
|
2134
|
+
text: nextText
|
|
2135
|
+
};
|
|
2136
|
+
return { kind: "keep" };
|
|
2137
|
+
}
|
|
2138
|
+
//#endregion
|
|
2139
|
+
//#region packages/ai/src/providers/openai-responses-tool-call-tracker.ts
|
|
2140
|
+
function readIdentityValue(value) {
|
|
2141
|
+
return (typeof value === "string" ? value.trim() : "") || void 0;
|
|
2142
|
+
}
|
|
2143
|
+
function readOutputIndex(event) {
|
|
2144
|
+
return typeof event.output_index === "number" && Number.isInteger(event.output_index) && event.output_index >= 0 ? event.output_index : void 0;
|
|
2145
|
+
}
|
|
2146
|
+
function readEventIdentity(event) {
|
|
2147
|
+
return { itemId: readIdentityValue(event.item_id) };
|
|
2148
|
+
}
|
|
2149
|
+
function readResponsesToolCallItemIdentity(item) {
|
|
2150
|
+
return {
|
|
2151
|
+
itemId: readIdentityValue(item.id),
|
|
2152
|
+
callId: readIdentityValue(item.call_id)
|
|
2153
|
+
};
|
|
2154
|
+
}
|
|
2155
|
+
function createResponsesToolCallTracker() {
|
|
2156
|
+
const indexedCalls = /* @__PURE__ */ new Map();
|
|
2157
|
+
const unindexedCalls = /* @__PURE__ */ new Set();
|
|
2158
|
+
const identitiesConflict = (state, identity) => Boolean(state.itemId && identity.itemId && state.itemId !== identity.itemId || state.callId && identity.callId && state.callId !== identity.callId);
|
|
2159
|
+
const sharesIdentity = (state, identity) => Boolean(state.itemId && identity.itemId && state.itemId === identity.itemId || state.callId && identity.callId && state.callId === identity.callId);
|
|
2160
|
+
const adoptIdentity = (state, identity) => {
|
|
2161
|
+
state.itemId ??= identity.itemId;
|
|
2162
|
+
state.callId ??= identity.callId;
|
|
2163
|
+
return state;
|
|
2164
|
+
};
|
|
2165
|
+
const resolveCompatible = (candidates, identity) => {
|
|
2166
|
+
const uniqueCandidates = [...new Set(candidates)];
|
|
2167
|
+
if (!identity.itemId && !identity.callId) return uniqueCandidates.length === 1 ? uniqueCandidates.at(0) : void 0;
|
|
2168
|
+
const compatible = uniqueCandidates.filter((state) => !identitiesConflict(state, identity));
|
|
2169
|
+
const matches = compatible.filter((state) => sharesIdentity(state, identity));
|
|
2170
|
+
const matched = matches.length === 1 ? matches.at(0) : void 0;
|
|
2171
|
+
if (matched) return adoptIdentity(matched, identity);
|
|
2172
|
+
const soleCompatible = uniqueCandidates.length === 1 && compatible.length === 1 && matches.length === 0 ? compatible.at(0) : void 0;
|
|
2173
|
+
return soleCompatible ? adoptIdentity(soleCompatible, identity) : void 0;
|
|
2174
|
+
};
|
|
2175
|
+
return {
|
|
2176
|
+
register(event, state) {
|
|
2177
|
+
const outputIndex = readOutputIndex(event);
|
|
2178
|
+
if (outputIndex === void 0) {
|
|
2179
|
+
unindexedCalls.add(state);
|
|
2180
|
+
return;
|
|
2181
|
+
}
|
|
2182
|
+
if (indexedCalls.has(outputIndex)) throw new Error(`Responses stream reused active tool-call output index ${outputIndex}`);
|
|
2183
|
+
indexedCalls.set(outputIndex, state);
|
|
2184
|
+
},
|
|
2185
|
+
resolve(event, identity = readEventIdentity(event)) {
|
|
2186
|
+
const outputIndex = readOutputIndex(event);
|
|
2187
|
+
if (outputIndex !== void 0) {
|
|
2188
|
+
const indexed = indexedCalls.get(outputIndex);
|
|
2189
|
+
if (indexed) {
|
|
2190
|
+
if (indexed.callId && identity.callId && indexed.callId !== identity.callId) return;
|
|
2191
|
+
return adoptIdentity(indexed, identity);
|
|
2192
|
+
}
|
|
2193
|
+
const unindexed = resolveCompatible(unindexedCalls, identity);
|
|
2194
|
+
if (unindexed) {
|
|
2195
|
+
unindexedCalls.delete(unindexed);
|
|
2196
|
+
indexedCalls.set(outputIndex, unindexed);
|
|
2197
|
+
}
|
|
2198
|
+
return unindexed;
|
|
2199
|
+
}
|
|
2200
|
+
return resolveCompatible([...indexedCalls.values(), ...unindexedCalls], identity);
|
|
2201
|
+
},
|
|
2202
|
+
forget(toolCall) {
|
|
2203
|
+
for (const [outputIndex, tracked] of indexedCalls) if (tracked === toolCall) indexedCalls.delete(outputIndex);
|
|
2204
|
+
unindexedCalls.delete(toolCall);
|
|
2205
|
+
},
|
|
2206
|
+
markArgumentsUnreliable() {
|
|
2207
|
+
for (const toolCall of /* @__PURE__ */ new Set([...indexedCalls.values(), ...unindexedCalls])) toolCall.argumentStreamReliable = false;
|
|
2208
|
+
},
|
|
2209
|
+
hasActive() {
|
|
2210
|
+
return indexedCalls.size > 0 || unindexedCalls.size > 0;
|
|
2710
2211
|
}
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
const
|
|
2725
|
-
const
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
}
|
|
2734
|
-
const hasEmptyProperties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) && Object.keys(normalized.properties).length === 0;
|
|
2735
|
-
if (normalized.type === "object" && !Array.isArray(normalized.required) && hasEmptyProperties) {
|
|
2736
|
-
normalized.required = [];
|
|
2737
|
-
changed = true;
|
|
2212
|
+
};
|
|
2213
|
+
}
|
|
2214
|
+
//#endregion
|
|
2215
|
+
//#region packages/ai/src/transports/openai-responses-stream-observer-internal.ts
|
|
2216
|
+
const STRING_DELTA_EVENTS = /* @__PURE__ */ new Set([
|
|
2217
|
+
"response.function_call_arguments.delta",
|
|
2218
|
+
"response.output_text.delta",
|
|
2219
|
+
"response.reasoning_summary_text.delta",
|
|
2220
|
+
"response.reasoning_text.delta",
|
|
2221
|
+
"response.refusal.delta",
|
|
2222
|
+
"response.text.delta"
|
|
2223
|
+
]);
|
|
2224
|
+
async function* adaptResponsesStream(stream, signal) {
|
|
2225
|
+
const scheduler = createModelStreamCooperativeScheduler(signal);
|
|
2226
|
+
for await (const event of stream) {
|
|
2227
|
+
if (signal?.aborted) throw transportAbortError(signal);
|
|
2228
|
+
if (!isRecord(event) || typeof event.type !== "string") throw new Error("Responses stream delivered a malformed event without a string type");
|
|
2229
|
+
if (STRING_DELTA_EVENTS.has(event.type) && typeof event.delta !== "string") throw new Error(`Responses stream delivered malformed ${event.type} delta`);
|
|
2230
|
+
if ((event.type === "response.output_item.added" || event.type === "response.output_item.done") && !isRecord(event.item)) throw new Error(`Responses stream delivered malformed ${event.type} item`);
|
|
2231
|
+
if ((event.type === "response.created" || event.type === "response.completed" || event.type === "response.incomplete" || event.type === "response.failed") && !isRecord(event.response)) throw new Error(`Responses stream delivered malformed ${event.type} response`);
|
|
2232
|
+
yield event;
|
|
2233
|
+
await scheduler.afterEvent();
|
|
2738
2234
|
}
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2235
|
+
}
|
|
2236
|
+
async function* observeResponsesStream(stream, model) {
|
|
2237
|
+
const startedAt = Date.now();
|
|
2238
|
+
const eventTypes = /* @__PURE__ */ new Map();
|
|
2239
|
+
const debugMode = resolveModelSseDebugMode();
|
|
2240
|
+
let eventCount = 0;
|
|
2241
|
+
try {
|
|
2242
|
+
for await (const event of stream) {
|
|
2243
|
+
const type = isRecord(event) && typeof event.type === "string" ? event.type : "unknown";
|
|
2244
|
+
eventCount += 1;
|
|
2245
|
+
eventTypes.set(type, (eventTypes.get(type) ?? 0) + 1);
|
|
2246
|
+
if (eventCount === 1) emitModelTransportDebug(log, `[responses] first_event provider=${model.provider} api=${model.api} model=${model.id} elapsedMs=${Date.now() - startedAt} type=${type}`);
|
|
2247
|
+
if (debugMode === "peek" && eventCount <= 5) emitModelTransportDebug(log, `[responses] event_peek provider=${model.provider} api=${model.api} model=${model.id} index=${eventCount} type=${type} event=${stringifyRedactedEvent(event)}`);
|
|
2248
|
+
yield event;
|
|
2249
|
+
}
|
|
2250
|
+
} finally {
|
|
2251
|
+
const types = [...eventTypes].map(([type, count]) => `${type}:${count}`).join(",");
|
|
2252
|
+
emitModelTransportDebug(log, `[responses] stream_done provider=${model.provider} api=${model.api} model=${model.id} elapsedMs=${Date.now() - startedAt} events=${eventCount} types=${types}`);
|
|
2742
2253
|
}
|
|
2743
|
-
return changed ? normalized : schema;
|
|
2744
2254
|
}
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2255
|
+
//#endregion
|
|
2256
|
+
//#region packages/ai/src/transports/openai-responses-stream-slots-internal.ts
|
|
2257
|
+
function readResponsesOutputIndex(event) {
|
|
2258
|
+
const outputIndex = event.output_index;
|
|
2259
|
+
return typeof outputIndex === "number" && Number.isInteger(outputIndex) && outputIndex >= 0 ? outputIndex : void 0;
|
|
2748
2260
|
}
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2261
|
+
function createResponsesOutputSlotTracker() {
|
|
2262
|
+
const indexed = /* @__PURE__ */ new Map();
|
|
2263
|
+
let unindexed;
|
|
2264
|
+
return {
|
|
2265
|
+
register(event, slot) {
|
|
2266
|
+
const outputIndex = readResponsesOutputIndex(event);
|
|
2267
|
+
if (outputIndex === void 0) {
|
|
2268
|
+
if (unindexed) throw new Error("Responses stream added overlapping unindexed output items");
|
|
2269
|
+
unindexed = slot;
|
|
2270
|
+
return;
|
|
2271
|
+
}
|
|
2272
|
+
if (indexed.has(outputIndex)) throw new Error(`Responses stream reused active output index ${outputIndex}`);
|
|
2273
|
+
indexed.set(outputIndex, slot);
|
|
2274
|
+
},
|
|
2275
|
+
resolve(event, type) {
|
|
2276
|
+
const outputIndex = readResponsesOutputIndex(event);
|
|
2277
|
+
let slot = outputIndex === void 0 ? unindexed : indexed.get(outputIndex);
|
|
2278
|
+
if (outputIndex === void 0 && !slot) {
|
|
2279
|
+
const matches = [...indexed.values()].filter((candidate) => candidate.type === type);
|
|
2280
|
+
slot = matches.length === 1 ? matches[0] : void 0;
|
|
2281
|
+
}
|
|
2282
|
+
return slot?.type === type ? slot : void 0;
|
|
2283
|
+
},
|
|
2284
|
+
get(event) {
|
|
2285
|
+
const outputIndex = readResponsesOutputIndex(event);
|
|
2286
|
+
return outputIndex === void 0 ? unindexed : indexed.get(outputIndex);
|
|
2287
|
+
},
|
|
2288
|
+
values() {
|
|
2289
|
+
return [.../* @__PURE__ */ new Set([...indexed.values(), ...unindexed ? [unindexed] : []])];
|
|
2290
|
+
},
|
|
2291
|
+
forget(slot) {
|
|
2292
|
+
if (unindexed === slot) unindexed = void 0;
|
|
2293
|
+
for (const [outputIndex, candidate] of indexed) if (candidate === slot) indexed.delete(outputIndex);
|
|
2772
2294
|
}
|
|
2773
|
-
}
|
|
2774
|
-
for (const key of OPENAI_STRICT_COMPAT_SCHEMA_MAP_KEYS) {
|
|
2775
|
-
const schemaMap = record[key];
|
|
2776
|
-
if (!schemaMap || typeof schemaMap !== "object" || Array.isArray(schemaMap)) continue;
|
|
2777
|
-
for (const [entryKey, value] of Object.entries(schemaMap)) violations.push(...findOpenAIStrictSchemaViolations(value, `${path}.${key}.${entryKey}`));
|
|
2778
|
-
}
|
|
2779
|
-
for (const key of OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS) {
|
|
2780
|
-
const value = record[key];
|
|
2781
|
-
if (value && typeof value === "object") violations.push(...findOpenAIStrictSchemaViolations(value, `${path}.${key}`));
|
|
2782
|
-
}
|
|
2783
|
-
return violations;
|
|
2295
|
+
};
|
|
2784
2296
|
}
|
|
2785
2297
|
//#endregion
|
|
2786
|
-
//#region packages/ai/src/providers/openai-
|
|
2298
|
+
//#region packages/ai/src/providers/openai-responses-terminal-usage.ts
|
|
2299
|
+
function readCount(value) {
|
|
2300
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
2301
|
+
}
|
|
2787
2302
|
/**
|
|
2788
|
-
*
|
|
2303
|
+
* Split a terminal usage payload into the priced buckets.
|
|
2789
2304
|
*
|
|
2790
|
-
*
|
|
2305
|
+
* OpenAI includes cache reads and writes in `input_tokens`, so both are subtracted out of the
|
|
2306
|
+
* billable input bucket. `total_tokens` comes from the payload, but never below the sum of the
|
|
2307
|
+
* split buckets: proxies routinely omit it (reporting 0 would understate the turn), and a payload
|
|
2308
|
+
* whose `cached_tokens` exceeds `input_tokens` clamps the input bucket, leaving the reported total
|
|
2309
|
+
* short of what the buckets actually price.
|
|
2791
2310
|
*/
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
const
|
|
2797
|
-
|
|
2311
|
+
function mapResponsesTerminalUsage(usage) {
|
|
2312
|
+
if (!usage) return;
|
|
2313
|
+
const cacheRead = readCount(usage.input_tokens_details?.cached_tokens);
|
|
2314
|
+
const cacheWrite = readCount(usage.input_tokens_details?.cache_write_tokens);
|
|
2315
|
+
const input = Math.max(0, readCount(usage.input_tokens) - cacheRead - cacheWrite);
|
|
2316
|
+
const output = readCount(usage.output_tokens);
|
|
2317
|
+
const bucketTotal = input + output + cacheRead + cacheWrite;
|
|
2798
2318
|
return {
|
|
2799
|
-
|
|
2800
|
-
|
|
2319
|
+
input,
|
|
2320
|
+
output,
|
|
2321
|
+
cacheRead,
|
|
2322
|
+
cacheWrite,
|
|
2323
|
+
totalTokens: Math.max(bucketTotal, readCount(usage.total_tokens))
|
|
2801
2324
|
};
|
|
2802
2325
|
}
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
function readCachedStrictOpenAISchema(schema, key) {
|
|
2808
|
-
return strictOpenAISchemaCache.get(schema)?.find((entry) => entry.key === key)?.value;
|
|
2809
|
-
}
|
|
2810
|
-
function rememberStrictOpenAISchema(schema, key, value) {
|
|
2811
|
-
const entries = strictOpenAISchemaCache.get(schema) ?? [];
|
|
2812
|
-
strictOpenAISchemaCache.set(schema, [{
|
|
2813
|
-
key,
|
|
2814
|
-
value
|
|
2815
|
-
}, ...entries.filter((entry) => entry.key !== key)].slice(0, MAX_STRICT_SCHEMA_CACHE_ENTRIES_PER_SCHEMA));
|
|
2816
|
-
return value;
|
|
2817
|
-
}
|
|
2818
|
-
function clearOpenAIToolSchemaCacheForTest() {
|
|
2819
|
-
strictOpenAISchemaCache = /* @__PURE__ */ new WeakMap();
|
|
2820
|
-
}
|
|
2821
|
-
/** Normalizes a tool parameter schema into the OpenAI strict JSON-schema subset. */
|
|
2822
|
-
function normalizeStrictOpenAIJsonSchema(schema, modelCompat) {
|
|
2823
|
-
const schemaInput = schema ?? {};
|
|
2824
|
-
if (!schemaInput || typeof schemaInput !== "object") return normalizeStrictOpenAIJsonSchemaRecursive(normalizeToolParameterSchema(schemaInput, { modelCompat: resolveToolSchemaModelCompat(modelCompat) }), 0);
|
|
2825
|
-
const cacheKey = resolveStrictOpenAISchemaCacheKey(modelCompat);
|
|
2826
|
-
const cached = readCachedStrictOpenAISchema(schemaInput, cacheKey);
|
|
2827
|
-
if (cached !== void 0) return cached;
|
|
2828
|
-
return rememberStrictOpenAISchema(schemaInput, cacheKey, normalizeStrictOpenAIJsonSchemaRecursive(normalizeToolParameterSchema(schemaInput, { modelCompat: resolveToolSchemaModelCompat(modelCompat) }), 0));
|
|
2829
|
-
}
|
|
2830
|
-
function normalizeStrictOpenAIJsonSchemaRecursive(schema, depth) {
|
|
2831
|
-
if (Array.isArray(schema)) {
|
|
2832
|
-
let changed = false;
|
|
2833
|
-
const normalized = schema.map((entry) => {
|
|
2834
|
-
const next = normalizeStrictOpenAIJsonSchemaRecursive(entry, depth);
|
|
2835
|
-
changed ||= next !== entry;
|
|
2836
|
-
return next;
|
|
2837
|
-
});
|
|
2838
|
-
return changed ? normalized : schema;
|
|
2839
|
-
}
|
|
2840
|
-
if (!schema || typeof schema !== "object") return schema;
|
|
2841
|
-
const record = schema;
|
|
2842
|
-
let changed = false;
|
|
2843
|
-
const normalized = {};
|
|
2844
|
-
for (const [key, value] of Object.entries(record)) {
|
|
2845
|
-
const next = normalizeStrictOpenAIJsonSchemaRecursive(value, key === "properties" ? depth : depth + 1);
|
|
2846
|
-
normalized[key] = next;
|
|
2847
|
-
changed ||= next !== value;
|
|
2848
|
-
}
|
|
2849
|
-
if (normalized.type === "object") {
|
|
2850
|
-
const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : void 0;
|
|
2851
|
-
if (properties && Object.keys(properties).length === 0 && !Array.isArray(normalized.required)) {
|
|
2852
|
-
normalized.required = [];
|
|
2853
|
-
changed = true;
|
|
2854
|
-
}
|
|
2855
|
-
if (depth === 0 && !("additionalProperties" in normalized)) {
|
|
2856
|
-
normalized.additionalProperties = false;
|
|
2857
|
-
changed = true;
|
|
2858
|
-
}
|
|
2859
|
-
}
|
|
2860
|
-
return changed ? normalized : schema;
|
|
2861
|
-
}
|
|
2862
|
-
/** Normalizes tool parameters using strict OpenAI rules only when strict mode is active. */
|
|
2863
|
-
function normalizeOpenAIStrictToolParameters(schema, strict, modelCompat) {
|
|
2864
|
-
const toolSchemaCompat = resolveToolSchemaModelCompat(modelCompat);
|
|
2865
|
-
if (!strict) return normalizeToolParameterSchema(schema ?? {}, { modelCompat: toolSchemaCompat });
|
|
2866
|
-
return normalizeStrictOpenAIJsonSchema(schema, toolSchemaCompat);
|
|
2867
|
-
}
|
|
2868
|
-
/** Returns whether a schema already satisfies OpenAI strict tool-schema constraints. */
|
|
2869
|
-
function isStrictOpenAIJsonSchemaCompatible(schema) {
|
|
2870
|
-
return isStrictOpenAIJsonSchemaCompatibleRecursive(normalizeStrictOpenAIJsonSchema(schema));
|
|
2871
|
-
}
|
|
2872
|
-
/** Returns strict-schema diagnostics for an already materialized OpenAI tool projection. */
|
|
2873
|
-
function findOpenAIStrictToolProjectionDiagnostics(projection) {
|
|
2874
|
-
return [...projection.diagnostics.map((diagnostic) => ({
|
|
2875
|
-
toolIndex: diagnostic.toolIndex,
|
|
2876
|
-
...diagnostic.toolName ? { toolName: diagnostic.toolName } : {},
|
|
2877
|
-
violations: [...diagnostic.violations]
|
|
2878
|
-
})), ...projection.tools.flatMap((tool) => {
|
|
2879
|
-
const violations = findOpenAIStrictSchemaViolations(normalizeStrictOpenAIJsonSchema(tool.parameters), `${tool.name}.parameters`);
|
|
2880
|
-
return violations.length > 0 ? [{
|
|
2881
|
-
toolIndex: tool.toolIndex,
|
|
2882
|
-
toolName: tool.name,
|
|
2883
|
-
violations
|
|
2884
|
-
}] : [];
|
|
2885
|
-
})];
|
|
2326
|
+
/** Reasoning tokens are reported by the agent path only; the package path does not track them. */
|
|
2327
|
+
function readResponsesReasoningTokens(usage) {
|
|
2328
|
+
const reasoningTokens = usage?.output_tokens_details?.reasoning_tokens;
|
|
2329
|
+
return typeof reasoningTokens === "number" && Number.isFinite(reasoningTokens) ? reasoningTokens : void 0;
|
|
2886
2330
|
}
|
|
2887
|
-
function
|
|
2888
|
-
if (
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
if (!required) return false;
|
|
2898
|
-
const requiredSet = new Set(required);
|
|
2899
|
-
if (Object.keys(properties).some((key) => !requiredSet.has(key))) return false;
|
|
2331
|
+
function mapResponsesTerminalStopReason(status) {
|
|
2332
|
+
if (!status) return "stop";
|
|
2333
|
+
switch (status) {
|
|
2334
|
+
case "completed": return "stop";
|
|
2335
|
+
case "incomplete": return "length";
|
|
2336
|
+
case "failed":
|
|
2337
|
+
case "cancelled": return "error";
|
|
2338
|
+
case "in_progress":
|
|
2339
|
+
case "queued": return "stop";
|
|
2340
|
+
default: throw new Error(`Unhandled stop reason: ${String(status)}`);
|
|
2900
2341
|
}
|
|
2901
|
-
return Object.entries(record).every(([key, entry]) => {
|
|
2902
|
-
if (key === "properties" && entry && typeof entry === "object" && !Array.isArray(entry)) return Object.values(entry).every((value) => isStrictOpenAIJsonSchemaCompatibleRecursive(value));
|
|
2903
|
-
return isStrictOpenAIJsonSchemaCompatibleRecursive(entry);
|
|
2904
|
-
});
|
|
2905
2342
|
}
|
|
2906
|
-
/**
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2343
|
+
/**
|
|
2344
|
+
* Resolve the terminal stop reason, including the two overrides every Responses path shares: a
|
|
2345
|
+
* content-filtered turn is a provider error rather than a truncated answer, and a turn that
|
|
2346
|
+
* produced tool calls reports `toolUse` instead of a plain stop.
|
|
2347
|
+
*/
|
|
2348
|
+
function resolveResponsesTerminalStopReason(params) {
|
|
2349
|
+
const status = params.status ?? (params.terminalEventType === "response.incomplete" ? "incomplete" : void 0);
|
|
2350
|
+
if (status === "incomplete" && params.incompleteReason === "content_filter") return {
|
|
2351
|
+
stopReason: "error",
|
|
2352
|
+
errorMessage: "Provider incomplete_reason: content_filter"
|
|
2353
|
+
};
|
|
2354
|
+
const stopReason = mapResponsesTerminalStopReason(status);
|
|
2355
|
+
if (stopReason === "stop" && params.hasToolCall) return { stopReason: "toolUse" };
|
|
2356
|
+
return { stopReason };
|
|
2910
2357
|
}
|
|
2911
2358
|
//#endregion
|
|
2912
|
-
//#region packages/ai/src/
|
|
2913
|
-
|
|
2914
|
-
const
|
|
2915
|
-
|
|
2916
|
-
/** Converts and returns the projection used to reconcile tool choices. */
|
|
2917
|
-
function convertResponsesToolPayload(tools, options) {
|
|
2918
|
-
const projection = projectOpenAITools(tools);
|
|
2919
|
-
const strict = resolveResponsesStrictToolFlag(projection, resolveResponsesStrictToolSetting(options), options?.model);
|
|
2920
|
-
return {
|
|
2921
|
-
projection,
|
|
2922
|
-
tools: sortPromptCacheToolsByName(projection.tools).map((tool) => {
|
|
2923
|
-
const result = {
|
|
2924
|
-
type: "function",
|
|
2925
|
-
name: tool.name,
|
|
2926
|
-
description: tool.description,
|
|
2927
|
-
parameters: normalizeOpenAIStrictToolParameters(tool.parameters, strict === true, options?.model?.compat)
|
|
2928
|
-
};
|
|
2929
|
-
if (strict !== void 0) result.strict = strict;
|
|
2930
|
-
return result;
|
|
2931
|
-
})
|
|
2932
|
-
};
|
|
2359
|
+
//#region packages/ai/src/transports/openai-responses-stream-terminal-internal.ts
|
|
2360
|
+
function splitToolCallId(id) {
|
|
2361
|
+
const separator = id.indexOf("|");
|
|
2362
|
+
return separator === -1 ? [id, void 0] : [id.slice(0, separator), id.slice(separator + 1)];
|
|
2933
2363
|
}
|
|
2934
|
-
function
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
return
|
|
2364
|
+
function resolveResponsesToolCallId(item, fallbackId) {
|
|
2365
|
+
const callId = typeof item.call_id === "string" ? item.call_id.trim() : "";
|
|
2366
|
+
const itemId = typeof item.id === "string" ? item.id.trim() : "";
|
|
2367
|
+
const [fallbackCallId, fallbackItemId = ""] = splitToolCallId(fallbackId ?? "");
|
|
2368
|
+
const resolvedCallId = callId || fallbackCallId;
|
|
2369
|
+
const resolvedItemId = itemId || fallbackItemId;
|
|
2370
|
+
if (resolvedCallId) return resolvedItemId ? `${resolvedCallId}|${resolvedItemId}` : resolvedCallId;
|
|
2371
|
+
const generated = `call_${randomUUID().replaceAll("-", "").slice(0, 24)}`;
|
|
2372
|
+
return resolvedItemId ? `${generated}|${resolvedItemId}` : generated;
|
|
2941
2373
|
}
|
|
2942
|
-
function
|
|
2943
|
-
const
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2374
|
+
function resolveCompletedToolCallName(toolCall, value) {
|
|
2375
|
+
const streamedName = toolCall?.block.name.trim() || void 0;
|
|
2376
|
+
const completedName = typeof value === "string" ? value.trim() || void 0 : void 0;
|
|
2377
|
+
if (streamedName && completedName && streamedName !== completedName) throw new Error(`Responses stream changed tool-call function name from ${streamedName} to ${completedName}`);
|
|
2378
|
+
const name = completedName ?? streamedName;
|
|
2379
|
+
if (!name) throw new Error("Responses stream completed tool call without a function name");
|
|
2380
|
+
return name;
|
|
2381
|
+
}
|
|
2382
|
+
function createResponsesTerminalController(params) {
|
|
2383
|
+
const { output, stream, model, options } = params;
|
|
2384
|
+
const blocks = output.content;
|
|
2385
|
+
const backfillReasoning = (items) => {
|
|
2386
|
+
for (const item of items) {
|
|
2387
|
+
if (item.type !== "reasoning" || !item.encrypted_content) continue;
|
|
2388
|
+
const block = params.reasoningBlocksById.get(item.id);
|
|
2389
|
+
if (!block?.thinkingSignature) continue;
|
|
2390
|
+
const stored = JSON.parse(block.thinkingSignature);
|
|
2391
|
+
if (!stored.encrypted_content) block.thinkingSignature = JSON.stringify({
|
|
2392
|
+
...stored,
|
|
2393
|
+
encrypted_content: item.encrypted_content
|
|
2394
|
+
});
|
|
2395
|
+
if (options?.reasoningReplayMetadata) block[OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY] = options.reasoningReplayMetadata;
|
|
2396
|
+
}
|
|
2397
|
+
};
|
|
2398
|
+
const appendText = (item) => {
|
|
2399
|
+
const text = (Array.isArray(item.content) ? item.content : []).map((part) => {
|
|
2400
|
+
const content = part;
|
|
2401
|
+
return content.type === "output_text" || content.type === "text" ? content.text ?? "" : content.refusal ?? "";
|
|
2402
|
+
}).join("");
|
|
2403
|
+
if (!text) return;
|
|
2404
|
+
const phase = item.phase ?? void 0;
|
|
2405
|
+
const previous = params.getLastTextBlock();
|
|
2406
|
+
const collapse = resolveResponsesMessageSnapshotCollapse({
|
|
2407
|
+
prior: previous && {
|
|
2408
|
+
text: previous.block.text,
|
|
2409
|
+
phase: previous.phase
|
|
2410
|
+
},
|
|
2411
|
+
nextText: text,
|
|
2412
|
+
nextPhase: phase
|
|
2413
|
+
});
|
|
2414
|
+
if (collapse.kind === "extend" && previous) {
|
|
2415
|
+
previous.block.text = collapse.text;
|
|
2416
|
+
previous.block.textSignature = encodeTextSignatureV1(item.id, phase);
|
|
2417
|
+
stream.push({
|
|
2418
|
+
type: "text_end",
|
|
2419
|
+
contentIndex: previous.index,
|
|
2420
|
+
content: collapse.text,
|
|
2421
|
+
partial: output
|
|
2422
|
+
});
|
|
2423
|
+
return;
|
|
2424
|
+
}
|
|
2425
|
+
const block = {
|
|
2426
|
+
type: "text",
|
|
2427
|
+
text,
|
|
2428
|
+
textSignature: encodeTextSignatureV1(item.id, phase)
|
|
2429
|
+
};
|
|
2430
|
+
blocks.push(block);
|
|
2431
|
+
const index = blocks.length - 1;
|
|
2432
|
+
params.setLastTextBlock({
|
|
2433
|
+
block,
|
|
2434
|
+
index,
|
|
2435
|
+
phase
|
|
2436
|
+
});
|
|
2437
|
+
stream.push({
|
|
2438
|
+
type: "text_start",
|
|
2439
|
+
contentIndex: index,
|
|
2440
|
+
partial: output
|
|
2441
|
+
});
|
|
2442
|
+
stream.push({
|
|
2443
|
+
type: "text_end",
|
|
2444
|
+
contentIndex: index,
|
|
2445
|
+
content: text,
|
|
2446
|
+
partial: output
|
|
2447
|
+
});
|
|
2448
|
+
};
|
|
2449
|
+
const appendToolCall = (item) => {
|
|
2450
|
+
const toolCall = {
|
|
2451
|
+
type: "toolCall",
|
|
2452
|
+
id: resolveResponsesToolCallId(item),
|
|
2453
|
+
name: resolveCompletedToolCallName(void 0, item.name),
|
|
2454
|
+
arguments: parseStreamingJson(item.arguments || "{}")
|
|
2455
|
+
};
|
|
2456
|
+
blocks.push(toolCall);
|
|
2457
|
+
const contentIndex = blocks.length - 1;
|
|
2458
|
+
stream.push({
|
|
2459
|
+
type: "toolcall_start",
|
|
2460
|
+
contentIndex,
|
|
2461
|
+
partial: output
|
|
2462
|
+
});
|
|
2463
|
+
stream.push({
|
|
2464
|
+
type: "toolcall_end",
|
|
2465
|
+
contentIndex,
|
|
2466
|
+
toolCall,
|
|
2467
|
+
partial: output
|
|
2468
|
+
});
|
|
2469
|
+
};
|
|
2470
|
+
const recoverTerminalOutput = (items, includeToolCalls) => {
|
|
2471
|
+
if (blocks.some((block) => block.type !== "thinking")) return;
|
|
2472
|
+
for (const item of items) if (item.type === "message") appendText(item);
|
|
2473
|
+
else {
|
|
2474
|
+
params.setLastTextBlock(null);
|
|
2475
|
+
if (includeToolCalls && item.type === "function_call") appendToolCall(item);
|
|
2476
|
+
}
|
|
2477
|
+
};
|
|
2478
|
+
const finalizeResponse = (response, terminalEventType) => {
|
|
2479
|
+
params.markFinalized();
|
|
2480
|
+
backfillReasoning(response.output ?? []);
|
|
2481
|
+
output.responseId = response.id || output.responseId;
|
|
2482
|
+
const usage = mapResponsesTerminalUsage(response.usage);
|
|
2483
|
+
const reasoningTokens = readResponsesReasoningTokens(response.usage);
|
|
2484
|
+
if (usage) output.usage = {
|
|
2485
|
+
...usage,
|
|
2486
|
+
...reasoningTokens === void 0 ? {} : { reasoningTokens },
|
|
2487
|
+
cost: {
|
|
2488
|
+
input: 0,
|
|
2489
|
+
output: 0,
|
|
2490
|
+
cacheRead: 0,
|
|
2491
|
+
cacheWrite: 0,
|
|
2492
|
+
total: 0
|
|
2958
2493
|
}
|
|
2959
2494
|
};
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2495
|
+
calculateCost(model, output.usage);
|
|
2496
|
+
if (options?.applyServiceTierPricing) {
|
|
2497
|
+
const tier = options.resolveServiceTier ? options.resolveServiceTier(response.service_tier, options.serviceTier) : response.service_tier ?? options.serviceTier;
|
|
2498
|
+
options.applyServiceTierPricing(output.usage, tier);
|
|
2499
|
+
}
|
|
2500
|
+
const terminal = resolveResponsesTerminalStopReason({
|
|
2501
|
+
status: response.status,
|
|
2502
|
+
terminalEventType,
|
|
2503
|
+
incompleteReason: response.incomplete_details?.reason,
|
|
2504
|
+
hasToolCall: blocks.some((block) => block.type === "toolCall")
|
|
2505
|
+
});
|
|
2506
|
+
output.stopReason = terminal.stopReason;
|
|
2507
|
+
output.errorMessage = terminal.errorMessage;
|
|
2508
|
+
};
|
|
2509
|
+
return {
|
|
2510
|
+
finalizeResponse,
|
|
2511
|
+
recoverTerminalOutput
|
|
2512
|
+
};
|
|
2977
2513
|
}
|
|
2978
2514
|
//#endregion
|
|
2979
|
-
//#region packages/ai/src/
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
}
|
|
2989
|
-
function
|
|
2990
|
-
const
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
if (id !== void 0 || phase !== void 0) return {
|
|
3003
|
-
id,
|
|
3004
|
-
phase
|
|
2515
|
+
//#region packages/ai/src/transports/openai-responses-stream-internal.ts
|
|
2516
|
+
var ResponsesStreamFailure = class extends Error {
|
|
2517
|
+
constructor(failure, response) {
|
|
2518
|
+
super(failure.message);
|
|
2519
|
+
this.name = "ResponsesStreamFailure";
|
|
2520
|
+
this.responseId = failure.responseId;
|
|
2521
|
+
this.response = response;
|
|
2522
|
+
this.observation = failure.observation;
|
|
2523
|
+
}
|
|
2524
|
+
};
|
|
2525
|
+
async function processResponsesStream(openaiStream, output, stream, model, options) {
|
|
2526
|
+
const streamingToolCalls = createResponsesToolCallTracker();
|
|
2527
|
+
const outputSlots = createResponsesOutputSlotTracker();
|
|
2528
|
+
const reasoningBlocksById = /* @__PURE__ */ new Map();
|
|
2529
|
+
let terminalResponseEvent;
|
|
2530
|
+
let lastTextBlock = null;
|
|
2531
|
+
const blocks = output.content;
|
|
2532
|
+
const blockIndex = () => blocks.length - 1;
|
|
2533
|
+
const createOutputSlot = (event, item) => {
|
|
2534
|
+
if (item.type === "reasoning") {
|
|
2535
|
+
const block = {
|
|
2536
|
+
type: "thinking",
|
|
2537
|
+
thinking: ""
|
|
3005
2538
|
};
|
|
3006
|
-
|
|
2539
|
+
const slot = {
|
|
2540
|
+
type: "thinking",
|
|
2541
|
+
item,
|
|
2542
|
+
block,
|
|
2543
|
+
contentIndex: blocks.length
|
|
2544
|
+
};
|
|
2545
|
+
blocks.push(block);
|
|
2546
|
+
outputSlots.register(event, slot);
|
|
2547
|
+
stream.push({
|
|
2548
|
+
type: "thinking_start",
|
|
2549
|
+
contentIndex: slot.contentIndex,
|
|
2550
|
+
partial: output
|
|
2551
|
+
});
|
|
2552
|
+
return slot;
|
|
2553
|
+
}
|
|
2554
|
+
if (item.type === "message") {
|
|
2555
|
+
const messageItem = item;
|
|
2556
|
+
const collapseCandidate = lastTextBlock;
|
|
2557
|
+
const block = collapseCandidate ? null : {
|
|
2558
|
+
type: "text",
|
|
2559
|
+
text: "",
|
|
2560
|
+
...messageItem.phase ? { textSignature: encodeTextSignatureV1(messageItem.id, messageItem.phase) } : {}
|
|
2561
|
+
};
|
|
2562
|
+
const slot = {
|
|
2563
|
+
type: "text",
|
|
2564
|
+
item: messageItem,
|
|
2565
|
+
block,
|
|
2566
|
+
contentIndex: block ? blocks.length : void 0,
|
|
2567
|
+
pendingText: collapseCandidate ? "" : null,
|
|
2568
|
+
collapseCandidate
|
|
2569
|
+
};
|
|
2570
|
+
if (block) blocks.push(block);
|
|
2571
|
+
outputSlots.register(event, slot);
|
|
2572
|
+
if (slot.contentIndex !== void 0) stream.push({
|
|
2573
|
+
type: "text_start",
|
|
2574
|
+
contentIndex: slot.contentIndex,
|
|
2575
|
+
partial: output
|
|
2576
|
+
});
|
|
2577
|
+
return slot;
|
|
3007
2578
|
}
|
|
3008
|
-
} catch {}
|
|
3009
|
-
return { id: signature };
|
|
3010
|
-
}
|
|
3011
|
-
function resolveReplayableResponsesMessageId(params) {
|
|
3012
|
-
if (!params.textSignatureId) return params.fallbackOrdinal === 0 ? params.fallbackId : `${params.fallbackId}_${params.fallbackOrdinal}`;
|
|
3013
|
-
return params.previousReplayItemWasReasoning ? params.textSignatureId : void 0;
|
|
3014
|
-
}
|
|
3015
|
-
function isResponsesReasoningEffort(effort) {
|
|
3016
|
-
return effort === "minimal" || effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh" || effort === "max";
|
|
3017
|
-
}
|
|
3018
|
-
function convertResponsesMessages(model, context, allowedToolCallProviders, options) {
|
|
3019
|
-
const messages = [];
|
|
3020
|
-
const shouldReplayResponsesItemIds = options?.replayResponsesItemIds ?? true;
|
|
3021
|
-
const normalizeIdPart = (part) => {
|
|
3022
|
-
const sanitized = part.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
3023
|
-
return (sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized).replace(/_+$/, "");
|
|
3024
2579
|
};
|
|
3025
|
-
const
|
|
3026
|
-
|
|
3027
|
-
|
|
2580
|
+
const resolveOutputItemSlot = (event, item) => {
|
|
2581
|
+
if (item.type === "reasoning") return outputSlots.resolve(event, "thinking");
|
|
2582
|
+
if (item.type === "message") return outputSlots.resolve(event, "text");
|
|
2583
|
+
return readResponsesOutputIndex(event) === void 0 ? void 0 : outputSlots.get(event);
|
|
3028
2584
|
};
|
|
3029
|
-
const
|
|
3030
|
-
|
|
3031
|
-
if (!id.includes("|")) return normalizeIdPart(id);
|
|
3032
|
-
const [callId, itemId = ""] = splitResponsesToolCallId(id);
|
|
3033
|
-
const normalizedCallId = normalizeIdPart(callId);
|
|
3034
|
-
let normalizedItemId = source.provider !== model.provider || source.api !== model.api ? buildForeignResponsesItemId(itemId) : normalizeIdPart(itemId);
|
|
3035
|
-
if (!normalizedItemId.startsWith("fc_")) normalizedItemId = normalizeIdPart(`fc_${normalizedItemId}`);
|
|
3036
|
-
return `${normalizedCallId}|${normalizedItemId}`;
|
|
2585
|
+
const getOrCreateOutputSlot = (event, item) => {
|
|
2586
|
+
return resolveOutputItemSlot(event, item) ?? createOutputSlot(event, item);
|
|
3037
2587
|
};
|
|
3038
|
-
const
|
|
3039
|
-
|
|
3040
|
-
const
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
2588
|
+
const materializeDeferredTextSlot = (slot) => {
|
|
2589
|
+
if (slot.block || slot.pendingText === null) return;
|
|
2590
|
+
const text = slot.pendingText;
|
|
2591
|
+
slot.block = {
|
|
2592
|
+
type: "text",
|
|
2593
|
+
text,
|
|
2594
|
+
...slot.item.phase ? { textSignature: encodeTextSignatureV1(slot.item.id, slot.item.phase) } : {}
|
|
2595
|
+
};
|
|
2596
|
+
blocks.push(slot.block);
|
|
2597
|
+
slot.contentIndex = blockIndex();
|
|
2598
|
+
stream.push({
|
|
2599
|
+
type: "text_start",
|
|
2600
|
+
contentIndex: slot.contentIndex,
|
|
2601
|
+
partial: output
|
|
3049
2602
|
});
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
type: "message",
|
|
3055
|
-
role: "user",
|
|
3056
|
-
content: [{
|
|
3057
|
-
type: "input_text",
|
|
3058
|
-
text: sanitizeSurrogates(msg.content)
|
|
3059
|
-
}]
|
|
2603
|
+
if (text) stream.push({
|
|
2604
|
+
type: "text_delta",
|
|
2605
|
+
contentIndex: slot.contentIndex,
|
|
2606
|
+
delta: text
|
|
3060
2607
|
});
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
2608
|
+
if (lastTextBlock === slot.collapseCandidate) lastTextBlock = null;
|
|
2609
|
+
slot.pendingText = null;
|
|
2610
|
+
slot.collapseCandidate = null;
|
|
2611
|
+
};
|
|
2612
|
+
const materializeDeferredTextSlots = (except) => {
|
|
2613
|
+
for (const slot of outputSlots.values()) if (slot !== except && slot.type === "text") materializeDeferredTextSlot(slot);
|
|
2614
|
+
};
|
|
2615
|
+
const appendPendingMessageDelta = (slot, delta) => {
|
|
2616
|
+
slot.pendingText = `${slot.pendingText ?? ""}${delta}`;
|
|
2617
|
+
const priorText = slot.collapseCandidate?.block.text ?? "";
|
|
2618
|
+
if (priorText.startsWith(slot.pendingText) || slot.pendingText.startsWith(priorText)) return;
|
|
2619
|
+
materializeDeferredTextSlot(slot);
|
|
2620
|
+
};
|
|
2621
|
+
const { finalizeResponse, recoverTerminalOutput } = createResponsesTerminalController({
|
|
2622
|
+
output,
|
|
2623
|
+
stream,
|
|
2624
|
+
model,
|
|
2625
|
+
options,
|
|
2626
|
+
reasoningBlocksById,
|
|
2627
|
+
getLastTextBlock: () => lastTextBlock,
|
|
2628
|
+
setLastTextBlock: (block) => {
|
|
2629
|
+
lastTextBlock = block;
|
|
2630
|
+
},
|
|
2631
|
+
markFinalized: () => {
|
|
2632
|
+
terminalResponseEvent = "finalized";
|
|
2633
|
+
}
|
|
2634
|
+
});
|
|
2635
|
+
const guardedStream = adaptResponsesStream(withFirstStreamEventTimeout(openaiStream, {
|
|
2636
|
+
provider: model.provider,
|
|
2637
|
+
api: model.api,
|
|
2638
|
+
model: model.id,
|
|
2639
|
+
timeoutMs: options?.firstEventTimeoutMs ?? 0,
|
|
2640
|
+
stage: "responses",
|
|
2641
|
+
abort: options?.abortFirstEventStream,
|
|
2642
|
+
onTimeout: options?.onFirstEventTimeout,
|
|
2643
|
+
hint: "The provider may be stalled while parsing the tool payload; retry with a smaller tool surface or enable OPENCLAW_DEBUG_MODEL_PAYLOAD=tools to inspect exposed tools."
|
|
2644
|
+
}), options?.signal);
|
|
2645
|
+
try {
|
|
2646
|
+
for await (const event of guardedStream) if (event.type === "response.created") output.responseId = event.response.id;
|
|
2647
|
+
else if (event.type === "response.output_item.added") {
|
|
2648
|
+
materializeDeferredTextSlots();
|
|
2649
|
+
const item = event.item;
|
|
2650
|
+
if (item.type !== "message") lastTextBlock = null;
|
|
2651
|
+
if (item.type === "reasoning" || item.type === "message") createOutputSlot(event, item);
|
|
2652
|
+
else if (item.type === "function_call") {
|
|
2653
|
+
const toolCallBlock = {
|
|
2654
|
+
type: "toolCall",
|
|
2655
|
+
id: resolveResponsesToolCallId(item),
|
|
2656
|
+
name: typeof item.name === "string" ? item.name.trim() : "",
|
|
2657
|
+
arguments: {},
|
|
2658
|
+
partialJson: item.arguments || ""
|
|
3066
2659
|
};
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
2660
|
+
const contentIndex = output.content.length;
|
|
2661
|
+
const toolCallState = {
|
|
2662
|
+
block: toolCallBlock,
|
|
2663
|
+
contentIndex,
|
|
2664
|
+
argumentStreamReliable: true,
|
|
2665
|
+
...readResponsesToolCallItemIdentity(item)
|
|
3071
2666
|
};
|
|
2667
|
+
streamingToolCalls.register(event, toolCallState);
|
|
2668
|
+
if (readResponsesOutputIndex(event) !== void 0) outputSlots.register(event, {
|
|
2669
|
+
type: "toolCall",
|
|
2670
|
+
toolCall: toolCallState
|
|
2671
|
+
});
|
|
2672
|
+
output.content.push(toolCallBlock);
|
|
2673
|
+
stream.push({
|
|
2674
|
+
type: "toolcall_start",
|
|
2675
|
+
contentIndex,
|
|
2676
|
+
partial: output
|
|
2677
|
+
});
|
|
2678
|
+
}
|
|
2679
|
+
} else if (event.type === "response.reasoning_summary_part.added") {
|
|
2680
|
+
const slot = outputSlots.resolve(event, "thinking");
|
|
2681
|
+
if (!slot) continue;
|
|
2682
|
+
slot.item.summary = slot.item.summary || [];
|
|
2683
|
+
slot.item.summary.push(event.part);
|
|
2684
|
+
} else if (event.type === "response.reasoning_summary_text.delta") {
|
|
2685
|
+
const slot = outputSlots.resolve(event, "thinking");
|
|
2686
|
+
if (!slot) continue;
|
|
2687
|
+
slot.item.summary = slot.item.summary || [];
|
|
2688
|
+
const lastPart = slot.item.summary[slot.item.summary.length - 1];
|
|
2689
|
+
if (!lastPart) continue;
|
|
2690
|
+
slot.block.thinking += event.delta;
|
|
2691
|
+
lastPart.text += event.delta;
|
|
2692
|
+
stream.push({
|
|
2693
|
+
type: "thinking_delta",
|
|
2694
|
+
contentIndex: slot.contentIndex,
|
|
2695
|
+
delta: event.delta,
|
|
2696
|
+
partial: output
|
|
3072
2697
|
});
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
2698
|
+
} else if (event.type === "response.reasoning_summary_part.done") {
|
|
2699
|
+
const slot = outputSlots.resolve(event, "thinking");
|
|
2700
|
+
if (!slot) continue;
|
|
2701
|
+
slot.item.summary = slot.item.summary || [];
|
|
2702
|
+
const lastPart = slot.item.summary[slot.item.summary.length - 1];
|
|
2703
|
+
if (!lastPart) continue;
|
|
2704
|
+
slot.block.thinking += "\n\n";
|
|
2705
|
+
lastPart.text += "\n\n";
|
|
2706
|
+
stream.push({
|
|
2707
|
+
type: "thinking_delta",
|
|
2708
|
+
contentIndex: slot.contentIndex,
|
|
2709
|
+
delta: "\n\n",
|
|
2710
|
+
partial: output
|
|
3078
2711
|
});
|
|
3079
|
-
}
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
if (!parsedSignature?.id) textFallbackOrdinal += 1;
|
|
3105
|
-
if (msgId && msgId.length > 64) msgId = `msg_${shortHash(msgId)}`;
|
|
3106
|
-
const messageItem = {
|
|
3107
|
-
type: "message",
|
|
3108
|
-
role: "assistant",
|
|
3109
|
-
content: [{
|
|
3110
|
-
type: "output_text",
|
|
3111
|
-
text: sanitizeSurrogates(textBlock.text),
|
|
3112
|
-
annotations: []
|
|
3113
|
-
}],
|
|
3114
|
-
status: "completed",
|
|
3115
|
-
...msgId ? { id: msgId } : {},
|
|
3116
|
-
phase: parsedSignature?.phase
|
|
2712
|
+
} else if (event.type === "response.reasoning_text.delta") {
|
|
2713
|
+
const slot = outputSlots.resolve(event, "thinking");
|
|
2714
|
+
if (!slot) continue;
|
|
2715
|
+
slot.block.thinking += event.delta;
|
|
2716
|
+
stream.push({
|
|
2717
|
+
type: "thinking_delta",
|
|
2718
|
+
contentIndex: slot.contentIndex,
|
|
2719
|
+
delta: event.delta,
|
|
2720
|
+
partial: output
|
|
2721
|
+
});
|
|
2722
|
+
} else if (event.type === "response.content_part.added") {
|
|
2723
|
+
const slot = outputSlots.resolve(event, "text");
|
|
2724
|
+
if (!slot) continue;
|
|
2725
|
+
slot.item.content = slot.item.content || [];
|
|
2726
|
+
if (event.part.type === "output_text" || event.part.type === "text" || event.part.type === "refusal") slot.item.content.push(event.part);
|
|
2727
|
+
} else if (event.type === "response.output_text.delta") {
|
|
2728
|
+
const slot = outputSlots.resolve(event, "text");
|
|
2729
|
+
if (!slot) continue;
|
|
2730
|
+
slot.item.content ||= [];
|
|
2731
|
+
let lastPart = slot.item.content[slot.item.content.length - 1];
|
|
2732
|
+
if (!isResponsesTextContentPartType(lastPart?.type)) {
|
|
2733
|
+
lastPart = {
|
|
2734
|
+
type: "output_text",
|
|
2735
|
+
text: "",
|
|
2736
|
+
annotations: []
|
|
3117
2737
|
};
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
2738
|
+
slot.item.content.push(lastPart);
|
|
2739
|
+
}
|
|
2740
|
+
lastPart.text += event.delta;
|
|
2741
|
+
if (slot.pendingText !== null) appendPendingMessageDelta(slot, event.delta);
|
|
2742
|
+
else if (slot.block && slot.contentIndex !== void 0) {
|
|
2743
|
+
slot.block.text += event.delta;
|
|
2744
|
+
stream.push({
|
|
2745
|
+
type: "text_delta",
|
|
2746
|
+
contentIndex: slot.contentIndex,
|
|
2747
|
+
delta: event.delta
|
|
2748
|
+
});
|
|
2749
|
+
}
|
|
2750
|
+
} else if (isAzureResponsesTextDeltaEvent(event)) {
|
|
2751
|
+
const slot = outputSlots.resolve(event, "text");
|
|
2752
|
+
if (!slot) continue;
|
|
2753
|
+
slot.item.content = slot.item.content || [];
|
|
2754
|
+
let lastPart = slot.item.content[slot.item.content.length - 1];
|
|
2755
|
+
if (lastPart?.type !== "text") {
|
|
2756
|
+
lastPart = {
|
|
2757
|
+
type: "text",
|
|
2758
|
+
text: ""
|
|
2759
|
+
};
|
|
2760
|
+
slot.item.content.push(lastPart);
|
|
2761
|
+
}
|
|
2762
|
+
lastPart.text += event.delta;
|
|
2763
|
+
if (slot.pendingText !== null) appendPendingMessageDelta(slot, event.delta);
|
|
2764
|
+
else if (slot.block && slot.contentIndex !== void 0) {
|
|
2765
|
+
slot.block.text += event.delta;
|
|
2766
|
+
stream.push({
|
|
2767
|
+
type: "text_delta",
|
|
2768
|
+
contentIndex: slot.contentIndex,
|
|
2769
|
+
delta: event.delta
|
|
2770
|
+
});
|
|
2771
|
+
}
|
|
2772
|
+
} else if (event.type === "response.refusal.delta") {
|
|
2773
|
+
const slot = outputSlots.resolve(event, "text");
|
|
2774
|
+
if (!slot) continue;
|
|
2775
|
+
slot.item.content ||= [];
|
|
2776
|
+
let lastPart = slot.item.content[slot.item.content.length - 1];
|
|
2777
|
+
if (lastPart?.type !== "refusal") {
|
|
2778
|
+
lastPart = {
|
|
2779
|
+
type: "refusal",
|
|
2780
|
+
refusal: ""
|
|
2781
|
+
};
|
|
2782
|
+
slot.item.content.push(lastPart);
|
|
2783
|
+
}
|
|
2784
|
+
lastPart.refusal += event.delta;
|
|
2785
|
+
if (slot.pendingText !== null) appendPendingMessageDelta(slot, event.delta);
|
|
2786
|
+
else if (slot.block && slot.contentIndex !== void 0) {
|
|
2787
|
+
slot.block.text += event.delta;
|
|
2788
|
+
stream.push({
|
|
2789
|
+
type: "text_delta",
|
|
2790
|
+
contentIndex: slot.contentIndex,
|
|
2791
|
+
delta: event.delta
|
|
3131
2792
|
});
|
|
3132
|
-
previousReplayItemWasReasoning = false;
|
|
3133
2793
|
}
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
if (hasImages && model.input.includes("image")) {
|
|
3145
|
-
const contentParts = [];
|
|
3146
|
-
if (hasText) contentParts.push({
|
|
3147
|
-
type: "input_text",
|
|
3148
|
-
text: sanitizedTextResult
|
|
2794
|
+
} else if (event.type === "response.function_call_arguments.delta") {
|
|
2795
|
+
const toolCall = streamingToolCalls.resolve(event);
|
|
2796
|
+
if (toolCall) {
|
|
2797
|
+
toolCall.block.partialJson += event.delta;
|
|
2798
|
+
toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
|
|
2799
|
+
stream.push({
|
|
2800
|
+
type: "toolcall_delta",
|
|
2801
|
+
contentIndex: toolCall.contentIndex,
|
|
2802
|
+
delta: event.delta,
|
|
2803
|
+
partial: output
|
|
3149
2804
|
});
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
2805
|
+
} else if (streamingToolCalls.hasActive()) streamingToolCalls.markArgumentsUnreliable();
|
|
2806
|
+
} else if (event.type === "response.function_call_arguments.done") {
|
|
2807
|
+
const toolCall = streamingToolCalls.resolve(event);
|
|
2808
|
+
if (toolCall) {
|
|
2809
|
+
const previousPartialJson = toolCall.block.partialJson;
|
|
2810
|
+
const doneArguments = typeof event.arguments === "string" ? event.arguments : void 0;
|
|
2811
|
+
if (doneArguments !== void 0 && (doneArguments.length > 0 || previousPartialJson === "")) {
|
|
2812
|
+
toolCall.block.partialJson = doneArguments;
|
|
2813
|
+
toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
|
|
2814
|
+
toolCall.argumentStreamReliable = true;
|
|
2815
|
+
}
|
|
2816
|
+
if (doneArguments?.startsWith(previousPartialJson)) {
|
|
2817
|
+
const delta = doneArguments.slice(previousPartialJson.length);
|
|
2818
|
+
if (delta.length > 0) stream.push({
|
|
2819
|
+
type: "toolcall_delta",
|
|
2820
|
+
contentIndex: toolCall.contentIndex,
|
|
2821
|
+
delta,
|
|
2822
|
+
partial: output
|
|
2823
|
+
});
|
|
2824
|
+
}
|
|
2825
|
+
} else if (streamingToolCalls.hasActive()) streamingToolCalls.markArgumentsUnreliable();
|
|
2826
|
+
} else if (event.type === "response.output_item.done") {
|
|
2827
|
+
const item = event.item;
|
|
2828
|
+
if (item.type !== "message") lastTextBlock = null;
|
|
2829
|
+
const existingOutputSlot = resolveOutputItemSlot(event, item);
|
|
2830
|
+
materializeDeferredTextSlots(existingOutputSlot);
|
|
2831
|
+
const outputSlot = existingOutputSlot ?? getOrCreateOutputSlot(event, item);
|
|
2832
|
+
if (item.type === "reasoning" && outputSlot?.type === "thinking") {
|
|
2833
|
+
const summaryText = item.summary?.map((s) => s.text).join("\n\n") || "";
|
|
2834
|
+
const contentText = item.content?.map((c) => c.text).join("\n\n") || "";
|
|
2835
|
+
outputSlot.block.thinking = summaryText || contentText || outputSlot.block.thinking;
|
|
2836
|
+
outputSlot.block.thinkingSignature = JSON.stringify(item);
|
|
2837
|
+
if (item.encrypted_content && options?.reasoningReplayMetadata) outputSlot.block[OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY] = options.reasoningReplayMetadata;
|
|
2838
|
+
if (typeof item.id === "string") reasoningBlocksById.set(item.id, outputSlot.block);
|
|
2839
|
+
stream.push({
|
|
2840
|
+
type: "thinking_end",
|
|
2841
|
+
contentIndex: outputSlot.contentIndex,
|
|
2842
|
+
content: outputSlot.block.thinking,
|
|
2843
|
+
partial: output
|
|
3153
2844
|
});
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
2845
|
+
outputSlots.forget(outputSlot);
|
|
2846
|
+
} else if (item.type === "message" && outputSlot?.type === "text" && (outputSlot.block || outputSlot.pendingText !== null)) {
|
|
2847
|
+
const streamedText = outputSlot.pendingText ?? outputSlot.block?.text ?? "";
|
|
2848
|
+
const finalText = item.content == null ? streamedText : item.content.map((c) => c.type === "output_text" || c.type === "text" ? c.text : c.refusal).join("");
|
|
2849
|
+
const phase = item.phase ?? void 0;
|
|
2850
|
+
const collapse = outputSlot.pendingText !== null ? resolveResponsesMessageSnapshotCollapse({
|
|
2851
|
+
prior: outputSlot.collapseCandidate && {
|
|
2852
|
+
text: outputSlot.collapseCandidate.block.text,
|
|
2853
|
+
phase: outputSlot.collapseCandidate.phase
|
|
2854
|
+
},
|
|
2855
|
+
nextText: finalText,
|
|
2856
|
+
nextPhase: phase
|
|
2857
|
+
}) : { kind: "keep" };
|
|
2858
|
+
outputSlot.pendingText = null;
|
|
2859
|
+
if (collapse.kind === "extend" && outputSlot.collapseCandidate) {
|
|
2860
|
+
outputSlot.collapseCandidate.block.text = collapse.text;
|
|
2861
|
+
outputSlot.collapseCandidate.block.textSignature = encodeTextSignatureV1(item.id, phase);
|
|
2862
|
+
stream.push({
|
|
2863
|
+
type: "text_end",
|
|
2864
|
+
contentIndex: outputSlot.collapseCandidate.index,
|
|
2865
|
+
content: collapse.text,
|
|
2866
|
+
partial: output
|
|
2867
|
+
});
|
|
2868
|
+
lastTextBlock = outputSlot.collapseCandidate;
|
|
2869
|
+
} else {
|
|
2870
|
+
if (!outputSlot.block) {
|
|
2871
|
+
outputSlot.block = {
|
|
2872
|
+
type: "text",
|
|
2873
|
+
text: "",
|
|
2874
|
+
...phase ? { textSignature: encodeTextSignatureV1(item.id, phase) } : {}
|
|
2875
|
+
};
|
|
2876
|
+
blocks.push(outputSlot.block);
|
|
2877
|
+
outputSlot.contentIndex = blockIndex();
|
|
2878
|
+
stream.push({
|
|
2879
|
+
type: "text_start",
|
|
2880
|
+
contentIndex: outputSlot.contentIndex,
|
|
2881
|
+
partial: output
|
|
2882
|
+
});
|
|
2883
|
+
}
|
|
2884
|
+
outputSlot.block.text = finalText;
|
|
2885
|
+
outputSlot.block.textSignature = encodeTextSignatureV1(item.id, phase);
|
|
2886
|
+
const contentIndex = outputSlot.contentIndex;
|
|
2887
|
+
if (contentIndex === void 0) throw new Error("Responses stream finalized text without a content index");
|
|
2888
|
+
lastTextBlock = {
|
|
2889
|
+
block: outputSlot.block,
|
|
2890
|
+
index: contentIndex,
|
|
2891
|
+
phase
|
|
2892
|
+
};
|
|
2893
|
+
stream.push({
|
|
2894
|
+
type: "text_end",
|
|
2895
|
+
contentIndex,
|
|
2896
|
+
content: outputSlot.block.text,
|
|
2897
|
+
partial: output
|
|
2898
|
+
});
|
|
2899
|
+
}
|
|
2900
|
+
outputSlots.forget(outputSlot);
|
|
2901
|
+
} else if (item.type === "function_call") {
|
|
2902
|
+
const streamingToolCall = streamingToolCalls.resolve(event, readResponsesToolCallItemIdentity(item));
|
|
2903
|
+
if (!streamingToolCall && streamingToolCalls.hasActive()) continue;
|
|
2904
|
+
const completedName = resolveCompletedToolCallName(streamingToolCall, item.name);
|
|
2905
|
+
const streamedArguments = streamingToolCall?.block.partialJson ?? "";
|
|
2906
|
+
const completedArguments = typeof item.arguments === "string" ? item.arguments : void 0;
|
|
2907
|
+
if (streamingToolCall && !streamingToolCall.argumentStreamReliable && !completedArguments) continue;
|
|
2908
|
+
const args = parseStreamingJson(completedArguments !== void 0 && (completedArguments.length > 0 || !streamedArguments) ? completedArguments : streamedArguments || "{}");
|
|
2909
|
+
let toolCall;
|
|
2910
|
+
let contentIndex;
|
|
2911
|
+
if (streamingToolCall) {
|
|
2912
|
+
const block = streamingToolCall.block;
|
|
2913
|
+
block.id = resolveResponsesToolCallId(item, block.id);
|
|
2914
|
+
block.name = completedName;
|
|
2915
|
+
block.arguments = args;
|
|
2916
|
+
delete block.partialJson;
|
|
2917
|
+
toolCall = block;
|
|
2918
|
+
contentIndex = streamingToolCall.contentIndex;
|
|
2919
|
+
} else {
|
|
2920
|
+
toolCall = {
|
|
2921
|
+
type: "toolCall",
|
|
2922
|
+
id: resolveResponsesToolCallId(item),
|
|
2923
|
+
name: completedName,
|
|
2924
|
+
arguments: args
|
|
2925
|
+
};
|
|
2926
|
+
blocks.push(toolCall);
|
|
2927
|
+
contentIndex = blockIndex();
|
|
2928
|
+
stream.push({
|
|
2929
|
+
type: "toolcall_start",
|
|
2930
|
+
contentIndex,
|
|
2931
|
+
partial: output
|
|
2932
|
+
});
|
|
2933
|
+
}
|
|
2934
|
+
if (streamingToolCall) {
|
|
2935
|
+
streamingToolCalls.forget(streamingToolCall);
|
|
2936
|
+
for (const slot of outputSlots.values()) if (slot.type === "toolCall" && slot.toolCall === streamingToolCall) outputSlots.forget(slot);
|
|
2937
|
+
}
|
|
2938
|
+
stream.push({
|
|
2939
|
+
type: "toolcall_end",
|
|
2940
|
+
contentIndex,
|
|
2941
|
+
toolCall,
|
|
2942
|
+
partial: output
|
|
3158
2943
|
});
|
|
3159
|
-
output = contentParts;
|
|
3160
|
-
} else output = sanitizeToolResultText(textResult, mediaPlaceholder ?? EMPTY_TOOL_RESULT_TEXT);
|
|
3161
|
-
messages.push({
|
|
3162
|
-
type: "function_call_output",
|
|
3163
|
-
call_id: callId,
|
|
3164
|
-
output
|
|
3165
|
-
});
|
|
3166
|
-
}
|
|
3167
|
-
msgIndex++;
|
|
3168
|
-
}
|
|
3169
|
-
return messages;
|
|
3170
|
-
}
|
|
3171
|
-
function createResponsesAssistantOutput(model, api = model.api) {
|
|
3172
|
-
return {
|
|
3173
|
-
role: "assistant",
|
|
3174
|
-
content: [],
|
|
3175
|
-
api,
|
|
3176
|
-
provider: model.provider,
|
|
3177
|
-
model: model.id,
|
|
3178
|
-
usage: {
|
|
3179
|
-
input: 0,
|
|
3180
|
-
output: 0,
|
|
3181
|
-
cacheRead: 0,
|
|
3182
|
-
cacheWrite: 0,
|
|
3183
|
-
totalTokens: 0,
|
|
3184
|
-
cost: {
|
|
3185
|
-
input: 0,
|
|
3186
|
-
output: 0,
|
|
3187
|
-
cacheRead: 0,
|
|
3188
|
-
cacheWrite: 0,
|
|
3189
|
-
total: 0
|
|
3190
2944
|
}
|
|
3191
|
-
}
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
return isResponsesReasoningEffort(effort) ? effort : void 0;
|
|
3206
|
-
}
|
|
3207
|
-
return clampedReasoning;
|
|
3208
|
-
}
|
|
3209
|
-
function applyCommonResponsesParams(params, model, context, options, config) {
|
|
3210
|
-
if (options?.maxTokens) params.max_output_tokens = Math.max(options.maxTokens, 16);
|
|
3211
|
-
if (options?.temperature !== void 0 && supportsOpenAITemperature(model)) params.temperature = options.temperature;
|
|
3212
|
-
if (context.tools) {
|
|
3213
|
-
const converted = convertResponsesToolPayload(context.tools, { model });
|
|
3214
|
-
if (converted.tools.length > 0) params.tools = converted.tools;
|
|
3215
|
-
}
|
|
3216
|
-
if (!model.reasoning) return;
|
|
3217
|
-
if (options?.reasoningEffort || options?.reasoningSummary) {
|
|
3218
|
-
params.reasoning = {
|
|
3219
|
-
effort: options?.reasoningEffort ? model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort : "medium",
|
|
3220
|
-
summary: options?.reasoningSummary || "auto"
|
|
3221
|
-
};
|
|
3222
|
-
params.include = ["reasoning.encrypted_content"];
|
|
3223
|
-
} else if ((config?.setDefaultReasoningOff ?? true) && model.thinkingLevelMap?.off !== null) params.reasoning = { effort: model.thinkingLevelMap?.off ?? "none" };
|
|
3224
|
-
}
|
|
3225
|
-
function buildResponsesRequestOptions(options) {
|
|
3226
|
-
return {
|
|
3227
|
-
...options?.signal ? { signal: options.signal } : {},
|
|
3228
|
-
...options?.timeoutMs !== void 0 ? { timeout: options.timeoutMs } : {},
|
|
3229
|
-
maxRetries: options?.maxRetries ?? 0
|
|
3230
|
-
};
|
|
3231
|
-
}
|
|
3232
|
-
function cleanStreamingScratchBuffers(output) {
|
|
3233
|
-
for (const block of output.content) {
|
|
3234
|
-
delete block.index;
|
|
3235
|
-
delete block.partialJson;
|
|
3236
|
-
}
|
|
3237
|
-
}
|
|
3238
|
-
async function runResponsesStreamLifecycle(params) {
|
|
3239
|
-
const { stream, model, output, options } = params;
|
|
3240
|
-
let firstEventAbort;
|
|
3241
|
-
try {
|
|
3242
|
-
const client = params.createClient();
|
|
3243
|
-
let requestParams = params.buildParams();
|
|
3244
|
-
const nextParams = await options?.onPayload?.(requestParams, model);
|
|
3245
|
-
if (nextParams !== void 0) requestParams = nextParams;
|
|
3246
|
-
firstEventAbort = createFirstStreamEventAbortController(options?.signal);
|
|
3247
|
-
const { data: openaiStream, response } = await client.responses.create(requestParams, {
|
|
3248
|
-
...buildResponsesRequestOptions(options),
|
|
3249
|
-
signal: firstEventAbort.signal
|
|
3250
|
-
}).withResponse();
|
|
3251
|
-
await options?.onResponse?.({
|
|
3252
|
-
status: response.status,
|
|
3253
|
-
headers: headersToRecord(response.headers)
|
|
3254
|
-
}, model);
|
|
3255
|
-
stream.push({
|
|
3256
|
-
type: "start",
|
|
3257
|
-
partial: output
|
|
3258
|
-
});
|
|
3259
|
-
const firstEventTimeoutMs = getFirstStreamEventTimeoutMs(options);
|
|
3260
|
-
const onFirstEventTimeout = getFirstStreamEventTimeoutHandler(options);
|
|
3261
|
-
await processResponsesStream(openaiStream, output, stream, model, params.processStreamOptions || firstEventTimeoutMs !== void 0 || onFirstEventTimeout !== void 0 ? {
|
|
3262
|
-
...params.processStreamOptions,
|
|
3263
|
-
firstEventTimeoutMs: params.processStreamOptions?.firstEventTimeoutMs ?? firstEventTimeoutMs,
|
|
3264
|
-
abortFirstEventStream: params.processStreamOptions?.abortFirstEventStream ?? firstEventAbort.abort,
|
|
3265
|
-
onFirstEventTimeout: params.processStreamOptions?.onFirstEventTimeout ?? onFirstEventTimeout,
|
|
3266
|
-
signal: params.processStreamOptions?.signal ?? options?.signal
|
|
3267
|
-
} : void 0);
|
|
3268
|
-
if (options?.signal?.aborted) throw transportAbortError(options.signal);
|
|
3269
|
-
if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error(output.errorMessage ?? "An unknown error occurred");
|
|
3270
|
-
stream.push({
|
|
3271
|
-
type: "done",
|
|
3272
|
-
reason: output.stopReason,
|
|
3273
|
-
message: output
|
|
3274
|
-
});
|
|
3275
|
-
stream.end();
|
|
3276
|
-
} catch (error) {
|
|
3277
|
-
cleanStreamingScratchBuffers(output);
|
|
3278
|
-
output.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
|
3279
|
-
output.errorMessage = params.formatError(error);
|
|
3280
|
-
stream.push({
|
|
3281
|
-
type: "error",
|
|
3282
|
-
reason: output.stopReason,
|
|
3283
|
-
error: output
|
|
3284
|
-
});
|
|
3285
|
-
stream.end();
|
|
2945
|
+
} else if (event.type === "response.completed" || event.type === "response.incomplete") {
|
|
2946
|
+
if (streamingToolCalls.hasActive()) throw new Error("Responses stream completed with unresolved tool calls");
|
|
2947
|
+
finalizeResponse(event.response, event.type);
|
|
2948
|
+
if (event.type === "response.completed" || output.stopReason === "length") recoverTerminalOutput(event.response.output ?? [], event.type === "response.completed");
|
|
2949
|
+
if (output.stopReason === "stop" && output.content.some((block) => block.type === "toolCall")) output.stopReason = "toolUse";
|
|
2950
|
+
break;
|
|
2951
|
+
} else if (event.type === "error") throw new Error(event.message ? `Error Code ${event.code}: ${event.message}` : "Unknown error");
|
|
2952
|
+
else if (event.type === "response.failed") {
|
|
2953
|
+
const failure = normalizeResponsesFailedEvent(event, model);
|
|
2954
|
+
if (failure.responseId) output.responseId = failure.responseId;
|
|
2955
|
+
throw new ResponsesStreamFailure(failure, event.response);
|
|
2956
|
+
}
|
|
2957
|
+
if (streamingToolCalls.hasActive()) throw new Error("Responses stream ended with unresolved tool calls");
|
|
2958
|
+
if (!terminalResponseEvent) throw new Error("OpenAI Responses stream ended before a terminal response event");
|
|
3286
2959
|
} finally {
|
|
3287
|
-
|
|
3288
|
-
}
|
|
3289
|
-
}
|
|
3290
|
-
//#endregion
|
|
3291
|
-
//#region packages/ai/src/providers/openai-responses.ts
|
|
3292
|
-
var openai_responses_exports = /* @__PURE__ */ __exportAll({
|
|
3293
|
-
streamOpenAIResponses: () => streamOpenAIResponses,
|
|
3294
|
-
streamSimpleOpenAIResponses: () => streamSimpleOpenAIResponses
|
|
3295
|
-
});
|
|
3296
|
-
const OPENAI_TOOL_CALL_PROVIDERS = /* @__PURE__ */ new Set(["openai", "opencode"]);
|
|
3297
|
-
function getCompat(model) {
|
|
3298
|
-
return {
|
|
3299
|
-
sendSessionIdHeader: model.compat?.sendSessionIdHeader ?? true,
|
|
3300
|
-
supportsLongCacheRetention: model.compat?.supportsLongCacheRetention ?? true
|
|
3301
|
-
};
|
|
3302
|
-
}
|
|
3303
|
-
function getPromptCacheRetention(compat, cacheRetention) {
|
|
3304
|
-
return cacheRetention === "long" && compat.supportsLongCacheRetention ? "24h" : void 0;
|
|
3305
|
-
}
|
|
3306
|
-
function formatOpenAIResponsesError(error) {
|
|
3307
|
-
if (error instanceof Error) {
|
|
3308
|
-
const status = error.status;
|
|
3309
|
-
const statusCode = typeof status === "number" ? status : void 0;
|
|
3310
|
-
if (statusCode !== void 0) return `OpenAI API error (${statusCode}): ${error.message}`;
|
|
3311
|
-
return error.message;
|
|
3312
|
-
}
|
|
3313
|
-
try {
|
|
3314
|
-
return JSON.stringify(error);
|
|
3315
|
-
} catch {
|
|
3316
|
-
return String(error);
|
|
3317
|
-
}
|
|
3318
|
-
}
|
|
3319
|
-
/**
|
|
3320
|
-
* Generate function for OpenAI Responses API
|
|
3321
|
-
*/
|
|
3322
|
-
const streamOpenAIResponses = (model, context, options) => {
|
|
3323
|
-
const stream = new AssistantMessageEventStream();
|
|
3324
|
-
runResponsesStreamLifecycle({
|
|
3325
|
-
stream,
|
|
3326
|
-
model,
|
|
3327
|
-
output: createResponsesAssistantOutput(model),
|
|
3328
|
-
options,
|
|
3329
|
-
createClient: () => {
|
|
3330
|
-
const apiKey = options?.apiKey || getEnvApiKey(model.provider) || "";
|
|
3331
|
-
const cacheSessionId = resolveCacheRetention$1(options?.cacheRetention) === "none" ? void 0 : options?.sessionId;
|
|
3332
|
-
return createClient(model, context, apiKey, options?.headers, cacheSessionId);
|
|
3333
|
-
},
|
|
3334
|
-
buildParams: () => buildParams(model, context, options),
|
|
3335
|
-
processStreamOptions: {
|
|
3336
|
-
serviceTier: options?.serviceTier,
|
|
3337
|
-
applyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model)
|
|
3338
|
-
},
|
|
3339
|
-
formatError: formatOpenAIResponsesError
|
|
3340
|
-
});
|
|
3341
|
-
return stream;
|
|
3342
|
-
};
|
|
3343
|
-
const streamSimpleOpenAIResponses = (model, context, options) => {
|
|
3344
|
-
const apiKey = options?.apiKey || getEnvApiKey(model.provider);
|
|
3345
|
-
if (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);
|
|
3346
|
-
const base = buildBaseOptions(model, options, apiKey);
|
|
3347
|
-
return streamOpenAIResponses(model, context, {
|
|
3348
|
-
...base,
|
|
3349
|
-
reasoningEffort: resolveResponsesReasoningEffort(model, options?.reasoning),
|
|
3350
|
-
replayResponsesItemIds: options?.replayResponsesItemIds
|
|
3351
|
-
});
|
|
3352
|
-
};
|
|
3353
|
-
function createClient(model, context, apiKey, optionsHeaders, sessionId) {
|
|
3354
|
-
if (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);
|
|
3355
|
-
const compat = getCompat(model);
|
|
3356
|
-
const headers = { ...model.headers };
|
|
3357
|
-
if (model.provider === "github-copilot") {
|
|
3358
|
-
const hasImages = hasCopilotVisionInput(context.messages);
|
|
3359
|
-
const copilotHeaders = buildCopilotDynamicHeaders({
|
|
3360
|
-
messages: context.messages,
|
|
3361
|
-
hasImages
|
|
3362
|
-
});
|
|
3363
|
-
Object.assign(headers, copilotHeaders);
|
|
3364
|
-
}
|
|
3365
|
-
if (sessionId) {
|
|
3366
|
-
if (compat.sendSessionIdHeader) headers.session_id = sessionId;
|
|
3367
|
-
headers["x-client-request-id"] = sessionId;
|
|
3368
|
-
}
|
|
3369
|
-
if (optionsHeaders) Object.assign(headers, optionsHeaders);
|
|
3370
|
-
const defaultHeaders = model.provider === "cloudflare-ai-gateway" ? {
|
|
3371
|
-
...headers,
|
|
3372
|
-
Authorization: headers.Authorization ?? null,
|
|
3373
|
-
"cf-aig-authorization": `Bearer ${apiKey}`
|
|
3374
|
-
} : headers;
|
|
3375
|
-
return new OpenAI({
|
|
3376
|
-
apiKey,
|
|
3377
|
-
baseURL: isCloudflareProvider(model.provider) ? resolveCloudflareBaseUrl(model) : model.baseUrl,
|
|
3378
|
-
dangerouslyAllowBrowser: true,
|
|
3379
|
-
defaultHeaders,
|
|
3380
|
-
fetch: getAiTransportHost().buildModelFetch(model)
|
|
3381
|
-
});
|
|
3382
|
-
}
|
|
3383
|
-
function buildParams(model, context, options) {
|
|
3384
|
-
const messages = convertResponsesMessages(model, context, OPENAI_TOOL_CALL_PROVIDERS, { replayResponsesItemIds: options?.replayResponsesItemIds ?? false });
|
|
3385
|
-
const cacheRetention = resolveCacheRetention$1(options?.cacheRetention);
|
|
3386
|
-
const compat = getCompat(model);
|
|
3387
|
-
const params = {
|
|
3388
|
-
model: model.id,
|
|
3389
|
-
input: messages,
|
|
3390
|
-
stream: true,
|
|
3391
|
-
prompt_cache_key: cacheRetention === "none" ? void 0 : clampOpenAIPromptCacheKey(options?.promptCacheKey ?? options?.sessionId),
|
|
3392
|
-
prompt_cache_retention: getPromptCacheRetention(compat, cacheRetention),
|
|
3393
|
-
store: false
|
|
3394
|
-
};
|
|
3395
|
-
if (options?.maxTokens) params.max_output_tokens = options?.maxTokens;
|
|
3396
|
-
if (options?.temperature !== void 0 && supportsOpenAITemperature(model)) params.temperature = options?.temperature;
|
|
3397
|
-
if (options?.serviceTier !== void 0) params.service_tier = options.serviceTier;
|
|
3398
|
-
applyCommonResponsesParams(params, model, context, options, { setDefaultReasoningOff: model.provider !== "github-copilot" });
|
|
3399
|
-
return params;
|
|
3400
|
-
}
|
|
3401
|
-
function getServiceTierCostMultiplier(model, serviceTier) {
|
|
3402
|
-
switch (serviceTier) {
|
|
3403
|
-
case "flex": return .5;
|
|
3404
|
-
case "priority": return model.id === "gpt-5.5" ? 2.5 : 2;
|
|
3405
|
-
default: return 1;
|
|
2960
|
+
for (const block of output.content) delete block.partialJson;
|
|
3406
2961
|
}
|
|
3407
2962
|
}
|
|
3408
|
-
function applyServiceTierPricing(usage, serviceTier, model) {
|
|
3409
|
-
const multiplier = getServiceTierCostMultiplier(model, serviceTier);
|
|
3410
|
-
if (multiplier === 1) return;
|
|
3411
|
-
usage.cost.input *= multiplier;
|
|
3412
|
-
usage.cost.output *= multiplier;
|
|
3413
|
-
usage.cost.cacheRead *= multiplier;
|
|
3414
|
-
usage.cost.cacheWrite *= multiplier;
|
|
3415
|
-
usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
|
|
3416
|
-
}
|
|
3417
2963
|
//#endregion
|
|
3418
|
-
export {
|
|
2964
|
+
export { normalizeOpenAIStrictCompatSchema as $, normalizeResponsesFailedEvent as A, resolveReplayableResponsesMessageId as B, prepareOpenAIResponsesReasoningItemForReplay as C, applyServiceTierPricing as D, tagOpenAIResponsesReasoningReplayItem as E, summarizeResponsesFailedNoDetailsObservation as F, throwIfModelStreamAborted as G, createModelStreamCooperativeScheduler as H, summarizeResponsesPayload as I, isStrictOpenAIJsonSchemaCompatible as J, clearOpenAIToolSchemaCacheForTest as K, summarizeResponsesTools as L, stringifyRedactedEvent as M, stringifyRedactedPayload as N, buildResponsesFailedNoDetailsObservation as O, summarizeOpenAITransportError as P, findOpenAIStrictSchemaViolations as Q, AZURE_RESPONSES_FIRST_EVENT_TIMEOUT_MS as R, isInvalidEncryptedContentError as S, stripResponsesRequestEncryptedContent as T, log as U, GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP as V, resolvePromptCacheKey as W, normalizeStrictOpenAIJsonSchema as X, normalizeOpenAIStrictToolParameters as Y, resolveOpenAIProjectedToolsStrictToolFlag as Z, resolveResponsesMessageSnapshotCollapse as _, supportsOpenAITemperature as _t, resolveResponsesTerminalStopReason as a, LLAMACPP_GBNF_MAX_REPETITION_THRESHOLD as at, convertResponsesMessages as b, resolveModelPayloadDebugMode as bt, readResponsesToolCallItemIdentity as c, GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS as ct, OPENAI_RESPONSES_OUTPUT_TEXT_CONTENT_PART_TYPE as d, isOpenAIGpt55Model as dt, extractToolSchemaModelCompat as et, OPENAI_RESPONSES_OUTPUT_TEXT_DELTA_EVENT_TYPE as f, isOpenAIGpt56Model as ft, isResponsesTextDeltaEventType as g, supportsOpenAIReasoningEffort as gt, isResponsesTextContentPartType as h, resolveOpenAISupportedReasoningEfforts as ht, readResponsesReasoningTokens as i, stripUnsupportedSchemaKeywords as it, safeDebugValue as j, logResponsesFailedNoDetails as k, AZURE_RESPONSES_TEXT_CONTENT_PART_TYPE as l, cleanSchemaForGemini as lt, isAzureResponsesTextDeltaEventType as m, resolveOpenAIReasoningEffortForModel as mt, processResponsesStream as n, resolveUnsupportedToolSchemaKeywords as nt, observeResponsesStream as o, cleanSchemaForLlamacppGbnf as ot, isAzureResponsesTextDeltaEvent as p, normalizeOpenAIReasoningEffort as pt, findOpenAIStrictToolProjectionDiagnostics as q, mapResponsesTerminalUsage as r, shouldOmitEmptyArrayItems as rt, createResponsesToolCallTracker as s, findLlamacppGbnfSchemaViolations as st, ResponsesStreamFailure as t, normalizeToolParameterSchema as tt, AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE as u, isOpenAIGpt54MiniModel as ut, buildOpenAIResponsesReasoningReplayMetadata as v, uniqueStrings as vt, resolveAzureOpenAIApiVersion as w, createResponsesStreamWithEncryptedContentRetry as x, resolveModelSseDebugMode as xt, buildResponsesInputMessage as y, emitModelTransportDebug as yt, OPENAI_CODEX_RESPONSES_DEFAULT_INSTRUCTIONS as z };
|