@openclaw/ai 2026.8.1-beta.3 → 2026.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/dist/{anthropic-B8KwTtlb.mjs → anthropic-DTGZ4VMY.mjs} +25 -23
  2. package/dist/{anthropic-compaction-replay-4Zx7-aCr.mjs → anthropic-compaction-replay-CKCDrZJv.mjs} +34 -35
  3. package/dist/{anthropic-payload-policy-CSx7MoKH.d.mts → anthropic-payload-policy-BTzmNC14.d.mts} +3 -2
  4. package/dist/{api-registry-DFxSnFqG.d.mts → api-registry-BbUHEKER.d.mts} +2 -1
  5. package/dist/{azure-openai-responses-Aa4mVcYG.mjs → azure-openai-responses-BmqaDXM1.mjs} +6 -5
  6. package/dist/{number-coercion-H9qHik3g.mjs → base64-CEFBpSkN.mjs} +73 -1
  7. package/dist/diagnostics.d.mts +2 -3
  8. package/dist/diagnostics.mjs +1 -1
  9. package/dist/{env-api-keys-DrgeBuva.mjs → env-api-keys-bktO00EJ.mjs} +2 -15
  10. package/dist/{event-stream-D91-ohD_.d.mts → event-stream-DcvAPSBe.d.mts} +1 -2
  11. package/dist/event-stream-pXT3FI6X.d.mts +1 -0
  12. package/dist/event-stream.d.mts +2 -1
  13. package/dist/{google-yDRnipeq.mjs → google-CqjVZMwo.mjs} +8 -6
  14. package/dist/{google-shared-M1dl64nz.mjs → google-shared-Bnqni5j3.mjs} +34 -25
  15. package/dist/{google-vertex-DCJHM_a5.mjs → google-vertex-D_WREEJi.mjs} +8 -6
  16. package/dist/{host-DF_yxOsA.mjs → host-BIaiBURL.mjs} +4 -8
  17. package/dist/{host-DJq_FGcz.d.mts → host-DKFUAmCn.d.mts} +3 -3
  18. package/dist/index-CefaUGSS.d.mts +111 -0
  19. package/dist/index.d.mts +9 -10
  20. package/dist/index.mjs +4 -5
  21. package/dist/internal/anthropic.d.mts +51 -49
  22. package/dist/internal/anthropic.mjs +5 -5
  23. package/dist/internal/openai-responses-payload-policy.d.mts +3 -3
  24. package/dist/internal/openai-responses-payload-policy.mjs +2 -3
  25. package/dist/internal/openai.d.mts +65 -63
  26. package/dist/internal/openai.mjs +10 -9
  27. package/dist/internal/retry-after.d.mts +2 -3
  28. package/dist/internal/runtime.d.mts +51 -40
  29. package/dist/internal/runtime.mjs +9 -9
  30. package/dist/internal/shared.d.mts +25 -25
  31. package/dist/internal/shared.mjs +3 -3
  32. package/dist/{json-parse-CDnesDM_.mjs → json-parse-BuAJEbdW.mjs} +18 -2
  33. package/dist/{mistral-D6hRXI7A.mjs → mistral-C24jVd6f.mjs} +34 -32
  34. package/dist/{openai-chatgpt-responses-C339VIfT.mjs → openai-chatgpt-responses-Czum0oXz.mjs} +38 -20
  35. package/dist/openai-completions-BfFwac6f.mjs +404 -0
  36. package/dist/{openai-completions-compat-B0KTleXp.d.mts → openai-completions-compat-SZhi0Lf4.d.mts} +3 -3
  37. package/dist/openai-completions-stream-DGOvau4J.mjs +1625 -0
  38. package/dist/{openai-responses-BXEcr-Tp.mjs → openai-responses-BAryVEJM.mjs} +11 -7
  39. package/dist/openai-responses-compaction-window-DO7yV7az.mjs +686 -0
  40. package/dist/{openai-responses-contracts-CD75pQ0m.d.mts → openai-responses-contracts-BthRXano.d.mts} +14 -5
  41. package/dist/{openai-responses-payload-policy-CNGFT9zr.d.mts → openai-responses-payload-policy-rLRPsSmB.d.mts} +1 -0
  42. package/dist/{openai-responses-prompt-observer-internal-BG-1AsBI.mjs → openai-responses-prompt-observer-internal--R0kZLOZ.mjs} +3 -2
  43. package/dist/{openai-responses-shared-Cvt5MgEm.mjs → openai-responses-shared-CxgdGBvm.mjs} +332 -1484
  44. package/dist/openai-stop-reason-Drnn_6Qj.mjs +28 -0
  45. package/dist/openai-tool-schema-CSMh5e9O.mjs +1697 -0
  46. package/dist/{provider-error-C8mBRJDl.mjs → provider-error-BI8kIViN.mjs} +14 -88
  47. package/dist/{provider-options-Cc5ZQ6Aa.d.mts → provider-options-DJd_9euj.d.mts} +13 -4
  48. package/dist/{provider-transcript-transform--gtf0ZbR.mjs → provider-transcript-transform-WvJmFUAf.mjs} +1 -1
  49. package/dist/provider-types.d.mts +18 -17
  50. package/dist/providers.d.mts +5 -6
  51. package/dist/providers.mjs +9 -9
  52. package/dist/{reasoning-tag-text-partitioner-5ygO2rZc.mjs → reasoning-tag-text-partitioner-BsUX44Tq.mjs} +30 -20
  53. package/dist/rolldown-runtime-BhDjJH2R.mjs +15 -0
  54. package/dist/{sanitize-unicode-BP7HLLZn.mjs → sanitize-unicode-S6binQG-.mjs} +2 -9
  55. package/dist/simple-options-rdOPzr7Z.mjs +155 -0
  56. package/dist/{anthropic-BQXQudmA.mjs → src-C8U7lkoa.mjs} +75 -1
  57. package/dist/{stream-first-event-timeout-MK28puvq.mjs → stream-first-event-timeout-DcNjoFQE.mjs} +1 -1
  58. package/dist/{streaming-byte-guard-BrbkbwUu.mjs → streaming-byte-guard-CC-HMn_u.mjs} +5 -6
  59. package/dist/string-normalization--fwJ4S2q.mjs +16 -0
  60. package/dist/{tool-schema-json-projection-FEr-jOoZ.mjs → tool-schema-json-projection-BtZiml7r.mjs} +22 -32
  61. package/dist/transport-stream-shared-BbG7PThh.d.mts +138 -0
  62. package/dist/{simple-options-oqsXB6U3.mjs → transport-stream-shared-D8nQWCUo.mjs} +10 -118
  63. package/dist/{transport-utils-Bv0FHkd0.mjs → transport-utils-CtuS1Upe.mjs} +10 -10
  64. package/dist/transports.d.mts +130 -189
  65. package/dist/transports.mjs +227 -1249
  66. package/dist/{types-DTAP49HF.d.mts → types-Beemor2E.d.mts} +58 -24
  67. package/dist/types-COdhCX0U.d.mts +1 -0
  68. package/dist/types.d.mts +6 -5
  69. package/dist/types.mjs +3 -4
  70. package/dist/utf16-slice-qz3nsy87.mjs +84 -0
  71. package/dist/{validation-DYNNrU9u.d.mts → validation-CC6s7Smp.d.mts} +1 -2
  72. package/dist/{validation-B61OhAio.mjs → validation-CJZtym2g.mjs} +7 -5
  73. package/dist/validation.d.mts +1 -1
  74. package/dist/validation.mjs +1 -1
  75. package/package.json +6 -6
  76. package/dist/anthropic-BECQCNdF.d.mts +0 -98
  77. package/dist/event-stream-BVVgDSdq.d.mts +0 -1
  78. package/dist/headers-B_e4-1J0.mjs +0 -9
  79. package/dist/index-BVVgDSdq.d.mts +0 -1
  80. package/dist/openai-completions-D88orSJ9.mjs +0 -632
  81. package/dist/openai-responses-contracts-DvILoqBk.mjs +0 -247
  82. package/dist/openai-responses-payload-policy-BDo8CQsx.mjs +0 -208
  83. package/dist/openai-stop-reason-9OONKyAm.mjs +0 -579
  84. package/dist/openai-tool-projection-CHGLt03m.mjs +0 -426
  85. package/dist/provider-options-AvldWZt8.mjs +0 -21
  86. package/dist/record-coerce-DdXsgUd_.mjs +0 -23
  87. package/dist/src-D2H6yKkH.mjs +0 -2
  88. package/dist/stream-first-event-timeout-DvDeSucC.d.mts +0 -29
  89. package/dist/string-coerce-fsri9iCu.mjs +0 -34
  90. package/dist/types-BVVgDSdq.d.mts +0 -1
  91. package/dist/utf16-slice-CvGodqok.mjs +0 -29
@@ -0,0 +1,1625 @@
1
+ import { c as normalizeLowercaseStringOrEmpty, i as asOptionalObjectRecord, o as isRecord, t as truncateUtf16Safe } from "./utf16-slice-qz3nsy87.mjs";
2
+ import { t as sanitizeSurrogates } from "./sanitize-unicode-S6binQG-.mjs";
3
+ import { a as describeToolResultMediaPlaceholder, c as extractToolResultText, d as isImageWithMediaPayload, n as getAiTransportHost } from "./host-BIaiBURL.mjs";
4
+ import { n as clampOpenAIPromptCacheKey } from "./openai-prompt-cache-mZTCdRPo.mjs";
5
+ import { d as stripSystemPromptCacheBoundary } from "./simple-options-rdOPzr7Z.mjs";
6
+ import { o as resolveProviderRequestCapabilities, r as resolveModelRequestTimeoutMs, s as resolveProviderRequestPolicyConfig } from "./tool-schema-json-projection-BtZiml7r.mjs";
7
+ import { i as isCodeModeModelVisibleToolName, p as sha256Hex } from "./transport-utils-CtuS1Upe.mjs";
8
+ import { s as finalizeTerminalToolCallArguments } from "./transport-stream-shared-D8nQWCUo.mjs";
9
+ import { r as parseStreamingJson, t as createToolArgumentPreviewSchedule } from "./json-parse-BuAJEbdW.mjs";
10
+ import { t as notifyLlmRequestActivity } from "./llm-request-activity-BjtkplhG.mjs";
11
+ import { A as readOpenAICompletionsReasoningBatch, D as measureUtf8AppendBytes, N as throwIfModelStreamAborted, O as parseOpenAICompletionsUsage, S as createModelStreamCooperativeScheduler, T as isOpenAICompletionsThinkingEnabled, a as resolveOpenAIProjectedToolsStrictToolFlag, k as readOpenAICompletionsContentDeltas, t as findOpenAIStrictToolProjectionDiagnostics } from "./openai-tool-schema-CSMh5e9O.mjs";
12
+ import { a as withFirstStreamEventTimeout } from "./stream-first-event-timeout-DcNjoFQE.mjs";
13
+ import { t as transformProviderMessages } from "./provider-transcript-transform-WvJmFUAf.mjs";
14
+ import { t as mapOpenAIStopReason } from "./openai-stop-reason-Drnn_6Qj.mjs";
15
+ import { t as createReasoningTagTextPartitioner } from "./reasoning-tag-text-partitioner-BsUX44Tq.mjs";
16
+ import { randomUUID } from "node:crypto";
17
+ //#region packages/ai/src/utils/assistant-text-phase.ts
18
+ const EMPTY_ASSISTANT_TEXT_BLOCK_SET = /* @__PURE__ */ new Set();
19
+ function isAssistantTextPhaseBlock(block) {
20
+ if (!block || typeof block !== "object") return false;
21
+ const record = block;
22
+ return record.type === "text" && typeof record.text === "string";
23
+ }
24
+ function encodeAssistantTextSignatureV1(id, phase) {
25
+ return JSON.stringify({
26
+ v: 1,
27
+ id,
28
+ ...phase ? { phase } : {}
29
+ });
30
+ }
31
+ function tagUnphasedText(content, phase, idPrefix) {
32
+ const textBlocks = content.filter(isAssistantTextPhaseBlock);
33
+ let phaseIndex = textBlocks.filter((block) => block.textSignature !== void 0).length;
34
+ const tagged = /* @__PURE__ */ new Map();
35
+ for (const block of textBlocks) {
36
+ if (block.text.trim().length === 0 || block.textSignature !== void 0) continue;
37
+ const signature = encodeAssistantTextSignatureV1(`${idPrefix}-${phaseIndex}`, phase);
38
+ block.textSignature = signature;
39
+ tagged.set(block, signature);
40
+ phaseIndex += 1;
41
+ }
42
+ return tagged;
43
+ }
44
+ /** Tags unphased narration before a tool-call event becomes consumer-visible. */
45
+ function tagPendingCommentaryText(content) {
46
+ return tagUnphasedText(content, "commentary", "commentary");
47
+ }
48
+ /** Records the confirmed final-answer boundary after reasoning resumes. */
49
+ function tagInterruptedTextPhases(content, interruptedText, preservedVisibleText = EMPTY_ASSISTANT_TEXT_BLOCK_SET) {
50
+ const interruptedTextIndex = content.indexOf(interruptedText);
51
+ if (interruptedTextIndex === -1) return;
52
+ const finalAnswerIndex = content.findIndex((block, index) => index > interruptedTextIndex && isAssistantTextPhaseBlock(block) && block.text.trim().length > 0);
53
+ if (finalAnswerIndex === -1) return;
54
+ tagUnphasedText(content.slice(0, finalAnswerIndex).filter((block) => !preservedVisibleText.has(block)), "commentary", "commentary");
55
+ tagUnphasedText(content.filter((block, index) => index >= finalAnswerIndex || preservedVisibleText.has(block)), "final_answer", "final-answer");
56
+ }
57
+ /** Prevents unresolved completion text from becoming a fallback answer after stream failure. */
58
+ function tagUnresolvedTextAsCommentary(message) {
59
+ if (message.openclawDelivery?.textPhaseRequiresTerminal) tagUnphasedText(message.content, "commentary", "commentary");
60
+ }
61
+ /** Rolls back only the exact provisional signatures created by this transport turn. */
62
+ function clearPendingCommentaryText(tags) {
63
+ for (const [block, signature] of tags) if (block.textSignature === signature) delete block.textSignature;
64
+ tags.clear();
65
+ }
66
+ function rememberPendingCommentaryTags(target, tagged) {
67
+ for (const [block, signature] of tagged) target.set(block, signature);
68
+ }
69
+ //#endregion
70
+ //#region packages/ai/src/transports/deepseek-dsml-grammar.ts
71
+ const DEEPSEEK_DSML_MARKERS = [
72
+ "|",
73
+ "|",
74
+ "||"
75
+ ].map((bar) => `${bar}DSML${bar}`);
76
+ const DEEPSEEK_DSML_MARKER_PATTERN = `(${DEEPSEEK_DSML_MARKERS.map((marker) => marker.replaceAll("|", "\\|")).join("|")})`;
77
+ //#endregion
78
+ //#region packages/ai/src/transports/deepseek-text-filter.ts
79
+ /**
80
+ * DeepSeek DSML streaming text filter.
81
+ * Removes provider-emitted DSML tool markup while buffering split tag prefixes
82
+ * across streamed chunks.
83
+ */
84
+ const DSML_KINDS = [
85
+ "tool_use_error",
86
+ "tool_calls",
87
+ "tool_call",
88
+ "function_calls"
89
+ ];
90
+ const DSML_OPEN_TOKENS = DEEPSEEK_DSML_MARKERS.flatMap((marker) => DSML_KINDS.map((kind) => `<${marker}${kind}>`));
91
+ const MAX_OPEN_TOKEN_LEN = Math.max(...DSML_OPEN_TOKENS.map((token) => token.length));
92
+ /** Create an incremental text filter that strips DeepSeek DSML tool blocks. */
93
+ function createDeepSeekTextFilter() {
94
+ let buffer = "";
95
+ let closeToken;
96
+ const consume = (final) => {
97
+ const output = [];
98
+ const emit = (text) => {
99
+ if (text) output.push(text);
100
+ };
101
+ while (buffer) {
102
+ if (closeToken) {
103
+ const closeIndex = buffer.indexOf(closeToken);
104
+ if (closeIndex !== -1) {
105
+ buffer = buffer.slice(closeIndex + closeToken.length);
106
+ closeToken = void 0;
107
+ continue;
108
+ }
109
+ const keep = final ? 0 : Math.min(buffer.length, closeToken.length - 1);
110
+ buffer = buffer.slice(buffer.length - keep);
111
+ if (final) closeToken = void 0;
112
+ return output;
113
+ }
114
+ const open = findEarliestToken(buffer, DSML_OPEN_TOKENS);
115
+ if (open) {
116
+ emit(buffer.slice(0, open.index));
117
+ buffer = buffer.slice(open.index + open.token.length);
118
+ closeToken = open.token.replace("<", "</");
119
+ continue;
120
+ }
121
+ if (final) {
122
+ emit(buffer);
123
+ buffer = "";
124
+ return output;
125
+ }
126
+ const keep = longestDsmlOpenPrefixSuffixLength(buffer);
127
+ const emitLength = buffer.length - keep;
128
+ if (emitLength <= 0) return output;
129
+ emit(buffer.slice(0, emitLength));
130
+ buffer = buffer.slice(emitLength);
131
+ return output;
132
+ }
133
+ return output;
134
+ };
135
+ return {
136
+ push(chunk) {
137
+ buffer += chunk;
138
+ return consume(false);
139
+ },
140
+ flush() {
141
+ return consume(true);
142
+ }
143
+ };
144
+ }
145
+ function findEarliestToken(text, tokens) {
146
+ let best = null;
147
+ for (const token of tokens) {
148
+ const index = text.indexOf(token);
149
+ if (index !== -1 && (!best || index < best.index)) best = {
150
+ index,
151
+ token
152
+ };
153
+ }
154
+ return best;
155
+ }
156
+ function longestDsmlOpenPrefixSuffixLength(text) {
157
+ const maxLength = Math.min(text.length, MAX_OPEN_TOKEN_LEN - 1);
158
+ for (let length = maxLength; length > 0; length--) {
159
+ const suffix = text.slice(text.length - length);
160
+ if (DSML_OPEN_TOKENS.some((token) => token.startsWith(suffix))) return length;
161
+ }
162
+ return 0;
163
+ }
164
+ //#endregion
165
+ //#region packages/ai/src/providers/openai-response-format.ts
166
+ const JSON_SCHEMA_RESPONSE_FORMAT_NAME = "openclaw_response";
167
+ const OLLAMA_CLOUD_ORIGIN = "https://ollama.com";
168
+ function isKnownOpenAIJsonSchemaModelId(modelId) {
169
+ if (typeof modelId !== "string") return false;
170
+ if (/^gpt-5(?:[.-]|$)/i.test(modelId) || /^gpt-4\.1(?:-|$)/i.test(modelId)) return true;
171
+ const gpt4o = /^gpt-4o(-mini)?(?:-(\d{4}-\d{2}-\d{2}))?$/i.exec(modelId);
172
+ if (gpt4o) {
173
+ const snapshot = gpt4o[2];
174
+ return !snapshot || snapshot >= (gpt4o[1] ? "2024-07-18" : "2024-08-06");
175
+ }
176
+ return /^(?:o1|o3(?:-mini|-pro)?|o4-mini)(?:-\d{4}-\d{2}-\d{2})?$/i.test(modelId);
177
+ }
178
+ function shouldOmitOllamaCompatResponseFormat(params) {
179
+ if (!params.provider.includes("ollama")) return false;
180
+ if (params.hasTools()) return true;
181
+ try {
182
+ return new URL(params.baseUrl).origin === OLLAMA_CLOUD_ORIGIN;
183
+ } catch {
184
+ return false;
185
+ }
186
+ }
187
+ /**
188
+ * Maps the shared JSON Schema option to Chat Completions while preserving the
189
+ * older provider-shaped json_object/json_schema inputs accepted by model params.
190
+ */
191
+ function resolveOpenAICompletionsResponseFormat(responseFormat, supportsJsonSchemaResponseFormat) {
192
+ if (!responseFormat) return;
193
+ if (responseFormat.type === "json_object") return responseFormat;
194
+ if (responseFormat.type === "text") return responseFormat;
195
+ if (responseFormat.type === "json_schema" && isRecord(responseFormat.json_schema)) return responseFormat;
196
+ if (!supportsJsonSchemaResponseFormat) return;
197
+ return {
198
+ type: "json_schema",
199
+ json_schema: {
200
+ name: JSON_SCHEMA_RESPONSE_FORMAT_NAME,
201
+ schema: responseFormat
202
+ }
203
+ };
204
+ }
205
+ //#endregion
206
+ //#region packages/ai/src/transports/openai-completions-compat.ts
207
+ function isDefaultRouteProvider(provider, ...ids) {
208
+ return provider !== void 0 && ids.includes(provider);
209
+ }
210
+ /** Resolves default request flags for an OpenAI-compatible completions endpoint. */
211
+ function resolveOpenAICompletionsCompatDefaults(input) {
212
+ const { provider, modelId, endpointClass, knownProviderFamily, supportsNativeStreamingUsageCompat = false, supportsOpenAICompletionsStreamingUsageCompat = false, usesExplicitProxyLikeEndpoint = false } = input;
213
+ const isDefaultRoute = endpointClass === "default";
214
+ const usesConfiguredNonOpenAIEndpoint = endpointClass !== "default" && endpointClass !== "openai-public";
215
+ const isMoonshot = knownProviderFamily === "moonshot" || endpointClass === "moonshot-native";
216
+ const isMoonshotLike = isMoonshot || knownProviderFamily === "modelstudio" || endpointClass === "modelstudio-native";
217
+ const isModelStudioLike = knownProviderFamily === "modelstudio" || endpointClass === "modelstudio-native" || isDefaultRoute && isDefaultRouteProvider(provider, "dashscope", "modelstudio", "qwen");
218
+ const isZai = endpointClass === "zai-native" || isDefaultRoute && isDefaultRouteProvider(input.provider, "zai");
219
+ const isDeepSeek = endpointClass === "deepseek-native" || isDefaultRoute && isDefaultRouteProvider(input.provider, "deepseek");
220
+ const isTogether = knownProviderFamily === "together" || input.baseUrl?.includes("api.together.ai") === true || input.baseUrl?.includes("api.together.xyz") === true || isDefaultRoute && isDefaultRouteProvider(input.provider, "together");
221
+ const isCloudflareAiGateway = provider === "cloudflare-ai-gateway" || input.baseUrl?.includes("gateway.ai.cloudflare.com") === true;
222
+ const isXiaomi = endpointClass === "xiaomi-native" || isDefaultRoute && isDefaultRouteProvider(input.provider, "xiaomi");
223
+ const isNonStandard = endpointClass === "cerebras-native" || endpointClass === "chutes-native" || endpointClass === "deepseek-native" || endpointClass === "mistral-public" || endpointClass === "opencode-native" || endpointClass === "xai-native" || isXiaomi || isZai || isDefaultRoute && isDefaultRouteProvider(input.provider, "cerebras", "chutes", "deepseek", "opencode", "xai");
224
+ const isOpenRouterLike = input.provider === "openrouter" || endpointClass === "openrouter";
225
+ const isLocalEndpoint = endpointClass === "local";
226
+ const usesMaxTokens = endpointClass === "chutes-native" || endpointClass === "mistral-public" || knownProviderFamily === "mistral" || isMoonshot || isCloudflareAiGateway || isZai || isTogether || isDefaultRoute && isDefaultRouteProvider(provider, "chutes");
227
+ return {
228
+ supportsStore: !isNonStandard && knownProviderFamily !== "mistral" && !usesExplicitProxyLikeEndpoint,
229
+ supportsDeveloperRole: !isNonStandard && !isMoonshotLike && !usesConfiguredNonOpenAIEndpoint,
230
+ supportsReasoningEffort: !isZai && !isTogether && knownProviderFamily !== "mistral" && endpointClass !== "xai-native" && !usesExplicitProxyLikeEndpoint,
231
+ supportsUsageInStreaming: supportsOpenAICompletionsStreamingUsageCompat || !isNonStandard && (isLocalEndpoint || !usesConfiguredNonOpenAIEndpoint || supportsNativeStreamingUsageCompat),
232
+ maxTokensField: usesMaxTokens ? "max_tokens" : "max_completion_tokens",
233
+ thinkingFormat: isDeepSeek || isXiaomi ? "deepseek" : isZai ? "zai" : isTogether ? "together" : isOpenRouterLike ? "openrouter" : "openai",
234
+ visibleReasoningDetailTypes: isOpenRouterLike ? ["response.output_text", "response.text"] : [],
235
+ supportsStrictMode: !isZai && !usesConfiguredNonOpenAIEndpoint,
236
+ supportsJsonSchemaResponseFormat: (endpointClass === "openai-public" || isDefaultRoute && isDefaultRouteProvider(provider, "openai")) && isKnownOpenAIJsonSchemaModelId(modelId),
237
+ requiresReasoningContentOnAssistantMessages: isDeepSeek || isXiaomi,
238
+ requiresNonEmptyUserOrAssistantMessage: isModelStudioLike,
239
+ cacheControlFormat: provider === "openrouter" && modelId?.startsWith("anthropic/") === true ? "anthropic" : void 0,
240
+ sessionAffinityFormat: isOpenRouterLike ? "openrouter" : "openai",
241
+ supportsLongCacheRetention: provider !== "cloudflare-workers-ai" && provider !== "cloudflare-ai-gateway" && knownProviderFamily !== "together" && !input.baseUrl?.includes("api.cloudflare.com") && !input.baseUrl?.includes("gateway.ai.cloudflare.com") && !input.baseUrl?.includes("api.together.ai") && !input.baseUrl?.includes("api.together.xyz")
242
+ };
243
+ }
244
+ function resolveOpenAICompletionsCompatDefaultsFromCapabilities(input) {
245
+ return resolveOpenAICompletionsCompatDefaults(input);
246
+ }
247
+ /** Detects endpoint capabilities and defaults for an OpenAI-completions model. */
248
+ function detectOpenAICompletionsCompat(model, resolveCapabilities) {
249
+ const capabilities = (resolveCapabilities ?? ((input) => resolveProviderRequestCapabilities(input, model)))({
250
+ provider: model.provider,
251
+ api: "openai-completions",
252
+ baseUrl: model.baseUrl,
253
+ capability: "llm",
254
+ transport: "stream",
255
+ modelId: model.id,
256
+ compat: model.compat && typeof model.compat === "object" ? model.compat : void 0
257
+ });
258
+ return {
259
+ capabilities,
260
+ defaults: resolveOpenAICompletionsCompatDefaultsFromCapabilities({
261
+ provider: model.provider,
262
+ modelId: model.id,
263
+ baseUrl: model.baseUrl,
264
+ ...capabilities
265
+ })
266
+ };
267
+ }
268
+ function resolveSessionAffinity(model, detectedFormat) {
269
+ if (model.compat?.sendSessionAffinityHeaders !== true) return "none";
270
+ if (detectedFormat === "openrouter" || model.compat.thinkingFormat === "openrouter" || model.compat.openRouterRouting !== void 0) return "openrouter";
271
+ return "openai";
272
+ }
273
+ /** Applies explicit model overrides once on top of the canonical transport defaults. */
274
+ function resolveOpenAICompletionsCompat(model, resolveCapabilities) {
275
+ const { defaults } = detectOpenAICompletionsCompat(model, resolveCapabilities);
276
+ const configured = model.compat;
277
+ return {
278
+ supportsStore: configured?.supportsStore ?? defaults.supportsStore,
279
+ supportsDeveloperRole: configured?.supportsDeveloperRole ?? defaults.supportsDeveloperRole,
280
+ supportsReasoningEffort: configured?.supportsReasoningEffort ?? defaults.supportsReasoningEffort,
281
+ supportsUsageInStreaming: configured?.supportsUsageInStreaming ?? defaults.supportsUsageInStreaming,
282
+ maxTokensField: configured?.maxTokensField ?? defaults.maxTokensField,
283
+ requiresToolResultName: configured?.requiresToolResultName ?? false,
284
+ requiresAssistantAfterToolResult: configured?.requiresAssistantAfterToolResult ?? false,
285
+ requiresThinkingAsText: configured?.requiresThinkingAsText ?? false,
286
+ requiresReasoningContentOnAssistantMessages: configured?.requiresReasoningContentOnAssistantMessages ?? defaults.requiresReasoningContentOnAssistantMessages,
287
+ thinkingFormat: configured?.thinkingFormat ?? defaults.thinkingFormat,
288
+ openRouterRouting: configured?.openRouterRouting,
289
+ vercelGatewayRouting: configured?.vercelGatewayRouting ?? {},
290
+ zaiToolStream: configured?.zaiToolStream ?? false,
291
+ supportsStrictMode: configured?.supportsStrictMode ?? defaults.supportsStrictMode,
292
+ supportsJsonSchemaResponseFormat: configured?.supportsJsonSchemaResponseFormat ?? defaults.supportsJsonSchemaResponseFormat,
293
+ cacheControlFormat: configured?.cacheControlFormat ?? defaults.cacheControlFormat,
294
+ sessionAffinity: resolveSessionAffinity(model, defaults.sessionAffinityFormat),
295
+ supportsPromptCacheKey: configured?.supportsPromptCacheKey ?? false,
296
+ supportsLongCacheRetention: configured?.supportsLongCacheRetention ?? defaults.supportsLongCacheRetention,
297
+ visibleReasoningDetailTypes: configured && "visibleReasoningDetailTypes" in configured ? configured.visibleReasoningDetailTypes ?? defaults.visibleReasoningDetailTypes : defaults.visibleReasoningDetailTypes,
298
+ requiresNonEmptyUserOrAssistantMessage: defaults.requiresNonEmptyUserOrAssistantMessage
299
+ };
300
+ }
301
+ //#endregion
302
+ //#region packages/ai/src/providers/openai-completions-tool-calls.ts
303
+ const MAX_BUFFERED_TOOL_CALL_ARGUMENT_BYTES = 256e3;
304
+ const MAX_BUFFERED_LEGACY_FOLLOWING_DELTA_BYTES = 256e3;
305
+ const MAX_BUFFERED_LEGACY_FOLLOWING_DELTAS = 1024;
306
+ /** Keep encrypted provider reasoning attached to the first matching tool call. */
307
+ function createOpenAIEncryptedToolCallReasoningTracker() {
308
+ const firstBlocks = /* @__PURE__ */ new Map();
309
+ const pendingDetails = /* @__PURE__ */ new Map();
310
+ return {
311
+ rememberToolCall(id, block) {
312
+ if (!id || firstBlocks.has(id)) return;
313
+ firstBlocks.set(id, block);
314
+ const pendingDetail = pendingDetails.get(id);
315
+ if (pendingDetail) {
316
+ block.thoughtSignature = pendingDetail;
317
+ pendingDetails.delete(id);
318
+ }
319
+ },
320
+ consumeDetails(details) {
321
+ if (!Array.isArray(details)) return;
322
+ for (const detail of details) {
323
+ if (!isRecord(detail) || detail.type !== "reasoning.encrypted" || typeof detail.id !== "string" || detail.id.length === 0 || typeof detail.data !== "string" || detail.data.length === 0) continue;
324
+ const serializedDetail = JSON.stringify(detail);
325
+ const matchingBlock = firstBlocks.get(detail.id);
326
+ if (matchingBlock) matchingBlock.thoughtSignature = serializedDetail;
327
+ else pendingDetails.set(detail.id, serializedDetail);
328
+ }
329
+ }
330
+ };
331
+ }
332
+ /** Normalize the SDK's legacy single-function lane into its modern tool-call shape. */
333
+ function createOpenAICompletionsToolCallDeltaNormalizer() {
334
+ let sawModernToolCall = false;
335
+ let pendingLegacyArgumentBytes = 0;
336
+ let pendingFollowingDeltaBytes = 0;
337
+ let pendingLegacyToolCall;
338
+ const modernArguments = /* @__PURE__ */ new Map();
339
+ const pendingFollowingDeltas = [];
340
+ const takePendingFollowingDeltas = () => {
341
+ pendingFollowingDeltaBytes = 0;
342
+ return pendingFollowingDeltas.splice(0).map((delta) => ({
343
+ delta,
344
+ toolCalls: []
345
+ }));
346
+ };
347
+ const bufferFollowingDelta = (delta) => {
348
+ const nextDeltaBytes = Buffer.byteLength(JSON.stringify(delta), "utf8");
349
+ if (pendingFollowingDeltaBytes + nextDeltaBytes > MAX_BUFFERED_LEGACY_FOLLOWING_DELTA_BYTES || pendingFollowingDeltas.length >= MAX_BUFFERED_LEGACY_FOLLOWING_DELTAS) throw new Error("Exceeded legacy tool-call content buffer limit");
350
+ pendingFollowingDeltaBytes += nextDeltaBytes;
351
+ pendingFollowingDeltas.push(delta);
352
+ };
353
+ const withoutToolCalls = (delta) => {
354
+ const ordinaryDelta = { ...delta };
355
+ delete ordinaryDelta.function_call;
356
+ delete ordinaryDelta.tool_calls;
357
+ return ordinaryDelta;
358
+ };
359
+ const hasObservableContent = (value) => {
360
+ if (typeof value === "string") return value.length > 0;
361
+ if (Array.isArray(value)) return value.some(hasObservableContent);
362
+ if (isRecord(value)) return Object.entries(value).some(([field, nestedValue]) => field !== "type" && field !== "id" && field !== "index" && hasObservableContent(nestedValue));
363
+ return false;
364
+ };
365
+ const hasOrdinaryContent = (delta) => Object.entries(delta).some(([field, value]) => field !== "role" && hasObservableContent(value));
366
+ return (delta, finishReason) => {
367
+ const ordinaryDelta = withoutToolCalls(delta);
368
+ if (delta.tool_calls && delta.tool_calls.length > 0) {
369
+ for (const toolCall of delta.tool_calls) {
370
+ const index = typeof toolCall.index === "number" ? toolCall.index : void 0;
371
+ const state = (index === void 0 ? void 0 : modernArguments.get(index)) ?? (toolCall.id ? modernArguments.get(toolCall.id) : void 0) ?? {
372
+ bytes: 0,
373
+ pendingHighSurrogate: false
374
+ };
375
+ if (index !== void 0) modernArguments.set(index, state);
376
+ if (toolCall.id) modernArguments.set(toolCall.id, state);
377
+ const argumentDelta = toolCall.function?.arguments ?? "";
378
+ const append = measureUtf8AppendBytes(state.pendingHighSurrogate, argumentDelta);
379
+ state.bytes += append.bytes;
380
+ if (state.bytes > MAX_BUFFERED_TOOL_CALL_ARGUMENT_BYTES) throw new Error("Exceeded tool-call argument buffer limit");
381
+ state.pendingHighSurrogate = append.endsWithHighSurrogate;
382
+ }
383
+ const precedingDeltas = takePendingFollowingDeltas();
384
+ sawModernToolCall = true;
385
+ pendingLegacyArgumentBytes = 0;
386
+ pendingLegacyToolCall = void 0;
387
+ return [...precedingDeltas, {
388
+ delta: ordinaryDelta,
389
+ toolCalls: delta.tool_calls
390
+ }];
391
+ }
392
+ const functionCall = delta.function_call;
393
+ if (sawModernToolCall) return [{
394
+ delta: ordinaryDelta,
395
+ toolCalls: []
396
+ }];
397
+ const hadPendingLegacyCall = pendingLegacyToolCall !== void 0;
398
+ const leadingDeltas = [];
399
+ if (hasOrdinaryContent(ordinaryDelta)) {
400
+ if (hadPendingLegacyCall) bufferFollowingDelta(ordinaryDelta);
401
+ else leadingDeltas.push({
402
+ delta: ordinaryDelta,
403
+ toolCalls: []
404
+ });
405
+ }
406
+ if (functionCall && (functionCall.name || functionCall.arguments)) {
407
+ const nextFunctionName = pendingLegacyToolCall?.function?.name ? void 0 : functionCall.name;
408
+ const nextArgumentBytes = Buffer.byteLength(functionCall.arguments ?? "", "utf8") + Buffer.byteLength(nextFunctionName ?? "", "utf8");
409
+ if (pendingLegacyArgumentBytes + nextArgumentBytes > MAX_BUFFERED_TOOL_CALL_ARGUMENT_BYTES) throw new Error("Exceeded tool-call argument buffer limit");
410
+ pendingLegacyArgumentBytes += nextArgumentBytes;
411
+ pendingLegacyToolCall ??= {
412
+ index: 0,
413
+ id: `call_${randomUUID().replaceAll("-", "").slice(0, 24)}`,
414
+ type: "function",
415
+ function: {}
416
+ };
417
+ const pendingFunction = pendingLegacyToolCall.function ??= {};
418
+ if (nextFunctionName) pendingFunction.name = nextFunctionName;
419
+ if (functionCall.arguments) pendingFunction.arguments = (pendingFunction.arguments ?? "") + functionCall.arguments;
420
+ }
421
+ if (!pendingLegacyToolCall) return leadingDeltas.length > 0 ? leadingDeltas : [{
422
+ delta: ordinaryDelta,
423
+ toolCalls: []
424
+ }];
425
+ if (finishReason === "function_call") {
426
+ const confirmedLegacyToolCall = pendingLegacyToolCall;
427
+ pendingLegacyToolCall = void 0;
428
+ pendingLegacyArgumentBytes = 0;
429
+ return [
430
+ ...leadingDeltas,
431
+ {
432
+ delta: {},
433
+ toolCalls: [confirmedLegacyToolCall]
434
+ },
435
+ ...takePendingFollowingDeltas()
436
+ ];
437
+ }
438
+ if (finishReason) {
439
+ pendingLegacyArgumentBytes = 0;
440
+ pendingLegacyToolCall = void 0;
441
+ return [...leadingDeltas, ...takePendingFollowingDeltas()];
442
+ }
443
+ return leadingDeltas;
444
+ };
445
+ }
446
+ /** Publish only executable calls; streaming scratch state never belongs in replay. */
447
+ function finalizeOpenAICompletionsToolCalls(output, options = {}) {
448
+ const isToolCall = (block) => block.type === "toolCall";
449
+ const hasToolCalls = output.content.some(isToolCall);
450
+ if (output.stopReason === "toolUse" && !hasToolCalls) output.stopReason = "stop";
451
+ if (output.stopReason === "stop" && hasToolCalls && options.allowSilentToolCallPromotion !== false && !output.content.some((block) => {
452
+ const candidate = block;
453
+ return candidate.type === "text" && typeof candidate.text === "string" && candidate.text.trim().length > 0;
454
+ })) output.stopReason = "toolUse";
455
+ if (output.stopReason !== "toolUse") {
456
+ if (hasToolCalls) output.content = output.content.filter((block) => !isToolCall(block));
457
+ return;
458
+ }
459
+ const toolCalls = output.content.filter(isToolCall);
460
+ const rejectToolCalls = () => {
461
+ output.stopReason = "error";
462
+ output.errorMessage = "Provider returned an incomplete or malformed tool call";
463
+ output.content = output.content.filter((candidate) => !isToolCall(candidate));
464
+ };
465
+ if (toolCalls.some((call) => typeof call.name !== "string" || call.name.trim().length === 0 || typeof call.partialArgs !== "string" || call.partialArgs.trim().length === 0)) {
466
+ rejectToolCalls();
467
+ return;
468
+ }
469
+ try {
470
+ finalizeTerminalToolCallArguments(toolCalls, (call) => call.partialArgs);
471
+ } catch {
472
+ rejectToolCalls();
473
+ return;
474
+ }
475
+ for (let contentIndex = 0; contentIndex < output.content.length; contentIndex += 1) {
476
+ const block = output.content[contentIndex];
477
+ if (!block || !isToolCall(block)) continue;
478
+ delete block.partialArgs;
479
+ delete block.streamIndex;
480
+ options.onConfirmedToolCall?.(block, contentIndex);
481
+ }
482
+ }
483
+ //#endregion
484
+ //#region packages/ai/src/openai-completions-messages.ts
485
+ const EMPTY_TOOL_RESULT_TEXT = "(no output)";
486
+ function isTextContentBlock(block) {
487
+ return block.type === "text";
488
+ }
489
+ function isThinkingContentBlock(block) {
490
+ return block.type === "thinking";
491
+ }
492
+ function isToolCallBlock(block) {
493
+ return block.type === "toolCall";
494
+ }
495
+ function sanitizeToolResultText(text, fallback) {
496
+ const sanitized = sanitizeSurrogates(text);
497
+ return sanitized.trim().length > 0 ? sanitized : fallback;
498
+ }
499
+ /** Whether replayed messages require a tools marker for proxy compatibility. */
500
+ function hasToolCallHistory(messages) {
501
+ return messages.some((message) => message.role === "toolResult" || message.role === "assistant" && Array.isArray(message.content) && message.content.some((block) => block.type === "toolCall"));
502
+ }
503
+ /** Convert a normalized transcript to OpenAI Chat Completions messages. */
504
+ function convertMessages(model, context, compat, options = {}) {
505
+ const params = [];
506
+ const normalizeToolCallId = (id) => {
507
+ if (id.includes("|")) return id.slice(0, id.indexOf("|")).replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 40);
508
+ if (model.provider === "openai") return id.length > 40 ? truncateUtf16Safe(id, 40) : id;
509
+ return id;
510
+ };
511
+ const transformedMessages = transformProviderMessages(context.messages, model, (id) => normalizeToolCallId(id));
512
+ if (context.systemPrompt) {
513
+ const role = model.reasoning && compat.supportsDeveloperRole ? "developer" : "system";
514
+ const systemPrompt = options.preserveSystemPromptCacheBoundary ? context.systemPrompt : stripSystemPromptCacheBoundary(context.systemPrompt);
515
+ params.push({
516
+ role,
517
+ content: sanitizeSurrogates(systemPrompt)
518
+ });
519
+ }
520
+ let lastRole = null;
521
+ for (let i = 0; i < transformedMessages.length; i++) {
522
+ const msg = transformedMessages[i];
523
+ if (!msg) continue;
524
+ if (compat.requiresAssistantAfterToolResult && lastRole === "toolResult" && msg.role === "user") params.push({
525
+ role: "assistant",
526
+ content: "I have processed the tool results."
527
+ });
528
+ if (msg.role === "user") {
529
+ const isRuntimeContextCarrier = msg.runtimeContextCarrier === true;
530
+ if (typeof msg.content === "string") {
531
+ const userParam = {
532
+ role: "user",
533
+ content: sanitizeSurrogates(msg.content)
534
+ };
535
+ if (isRuntimeContextCarrier) options.cacheOptOutIndexes?.add(params.length);
536
+ params.push(userParam);
537
+ } else {
538
+ const content = msg.content.map((item) => {
539
+ if (item.type === "text") return {
540
+ type: "text",
541
+ text: sanitizeSurrogates(item.text)
542
+ };
543
+ if (item.type === "video") return {
544
+ type: "video_url",
545
+ video_url: { url: `data:${item.mimeType};base64,${item.data}` }
546
+ };
547
+ return {
548
+ type: "image_url",
549
+ image_url: { url: `data:${item.mimeType};base64,${item.data}` }
550
+ };
551
+ });
552
+ if (content.length === 0) continue;
553
+ const userParam = {
554
+ role: "user",
555
+ content
556
+ };
557
+ if (isRuntimeContextCarrier) options.cacheOptOutIndexes?.add(params.length);
558
+ params.push(userParam);
559
+ }
560
+ } else if (msg.role === "assistant") {
561
+ const assistantMsg = {
562
+ role: "assistant",
563
+ content: compat.requiresAssistantAfterToolResult ? "" : null
564
+ };
565
+ const assistantTextParts = msg.content.filter(isTextContentBlock).filter((block) => block.text.trim().length > 0).map((block) => ({
566
+ type: "text",
567
+ text: sanitizeSurrogates(block.text)
568
+ }));
569
+ const assistantText = assistantTextParts.map((part) => part.text).join("\n");
570
+ const nonEmptyThinkingBlocks = msg.content.filter(isThinkingContentBlock).filter((block) => block.thinking.trim().length > 0);
571
+ if (nonEmptyThinkingBlocks.length > 0) {
572
+ if (compat.requiresThinkingAsText) assistantMsg.content = [{
573
+ type: "text",
574
+ text: nonEmptyThinkingBlocks.map((block) => sanitizeSurrogates(block.thinking)).join("\n\n")
575
+ }, ...assistantTextParts];
576
+ else {
577
+ if (assistantText.length > 0) assistantMsg.content = assistantText;
578
+ let signature = nonEmptyThinkingBlocks.at(0)?.thinkingSignature;
579
+ if (model.provider === "opencode-go" && signature === "reasoning") signature = "reasoning_content";
580
+ if (signature && signature.length > 0) assistantMsg[signature] = nonEmptyThinkingBlocks.map((block) => block.thinking).join("\n");
581
+ }
582
+ } else if (assistantText.length > 0) assistantMsg.content = assistantText;
583
+ const toolCalls = msg.content.filter(isToolCallBlock);
584
+ if (toolCalls.length > 0) {
585
+ assistantMsg.tool_calls = toolCalls.map((toolCall) => ({
586
+ id: toolCall.id,
587
+ type: "function",
588
+ function: {
589
+ name: toolCall.name,
590
+ arguments: JSON.stringify(toolCall.arguments)
591
+ }
592
+ }));
593
+ const reasoningDetails = toolCalls.flatMap((toolCall) => {
594
+ const signature = toolCall.thoughtSignature;
595
+ if (!signature) return [];
596
+ try {
597
+ const parsed = JSON.parse(signature);
598
+ return parsed ? [parsed] : [];
599
+ } catch {
600
+ return [];
601
+ }
602
+ });
603
+ if (reasoningDetails.length > 0) assistantMsg.reasoning_details = reasoningDetails;
604
+ }
605
+ if (compat.requiresReasoningContentOnAssistantMessages && model.reasoning && assistantMsg.reasoning_content === void 0) assistantMsg.reasoning_content = "";
606
+ const content = assistantMsg.content;
607
+ if (!(content !== null && content !== void 0 && (typeof content === "string" ? content.length > 0 : content.length > 0)) && !assistantMsg.tool_calls) continue;
608
+ params.push(assistantMsg);
609
+ } else if (msg.role === "toolResult") {
610
+ const imageBlocks = [];
611
+ let j = i;
612
+ while (j < transformedMessages.length) {
613
+ const toolMsg = transformedMessages.at(j);
614
+ if (toolMsg?.role !== "toolResult") break;
615
+ const textResult = extractToolResultText(toolMsg.content);
616
+ const mediaPlaceholder = describeToolResultMediaPlaceholder(toolMsg.content);
617
+ const hasImages = toolMsg.content.some(isImageWithMediaPayload);
618
+ const toolResultMsg = {
619
+ role: "tool",
620
+ content: sanitizeToolResultText(textResult, mediaPlaceholder ?? EMPTY_TOOL_RESULT_TEXT),
621
+ tool_call_id: toolMsg.toolCallId
622
+ };
623
+ if (compat.requiresToolResultName && toolMsg.toolName) toolResultMsg.name = toolMsg.toolName;
624
+ params.push(toolResultMsg);
625
+ if (hasImages && model.input.includes("image")) {
626
+ for (const block of toolMsg.content) if (isImageWithMediaPayload(block)) imageBlocks.push({
627
+ type: "image_url",
628
+ image_url: { url: `data:${block.mimeType};base64,${block.data}` }
629
+ });
630
+ }
631
+ j += 1;
632
+ }
633
+ i = j - 1;
634
+ if (imageBlocks.length > 0) {
635
+ if (compat.requiresAssistantAfterToolResult) params.push({
636
+ role: "assistant",
637
+ content: "I have processed the tool results."
638
+ });
639
+ params.push({
640
+ role: "user",
641
+ content: [{
642
+ type: "text",
643
+ text: "Attached image(s) from tool result:"
644
+ }, ...imageBlocks]
645
+ });
646
+ lastRole = "user";
647
+ } else lastRole = "toolResult";
648
+ continue;
649
+ }
650
+ lastRole = msg.role;
651
+ }
652
+ return params;
653
+ }
654
+ //#endregion
655
+ //#region packages/ai/src/transports/openai-reasoning-compat.ts
656
+ /**
657
+ * OpenAI reasoning-effort compatibility helpers.
658
+ *
659
+ * Keeps provider metadata and built-in model exceptions on one path before request payloads are built.
660
+ */
661
+ const OPENAI_MEDIUM_ONLY_REASONING_MODEL_IDS = /* @__PURE__ */ new Set(["gpt-5.1-codex-mini"]);
662
+ function readCompatReasoningEffortMap(compat) {
663
+ const rawMap = asOptionalObjectRecord(asOptionalObjectRecord(compat)?.reasoningEffortMap);
664
+ if (!rawMap) return {};
665
+ return Object.fromEntries(Object.entries(rawMap).filter((entry) => typeof entry[0] === "string" && typeof entry[1] === "string"));
666
+ }
667
+ /** Resolves the reasoning effort remap for an OpenAI-compatible model. */
668
+ function resolveOpenAIReasoningEffortMap(model, fallbackMap = {}) {
669
+ const provider = normalizeLowercaseStringOrEmpty(model.provider ?? "");
670
+ const id = normalizeLowercaseStringOrEmpty(model.id ?? "");
671
+ const builtinMap = provider === "openai" && OPENAI_MEDIUM_ONLY_REASONING_MODEL_IDS.has(id) ? {
672
+ minimal: "medium",
673
+ low: "medium"
674
+ } : {};
675
+ return {
676
+ ...fallbackMap,
677
+ ...builtinMap,
678
+ ...readCompatReasoningEffortMap(model.compat)
679
+ };
680
+ }
681
+ //#endregion
682
+ //#region packages/ai/src/transports/openai-transport-params.ts
683
+ const MAX_OPENAI_STRICT_TOOL_DOWNGRADE_DIAGNOSTIC_KEYS = 256;
684
+ const OPENAI_CODEX_RESPONSES_PROVIDERS = /* @__PURE__ */ new Set(["openai"]);
685
+ const loggedOpenAIStrictToolDowngradeDiagnosticKeys = /* @__PURE__ */ new Set();
686
+ function readToolPayloadField(record, field) {
687
+ try {
688
+ return Object.hasOwn(record, field) ? record[field] : void 0;
689
+ } catch {
690
+ return;
691
+ }
692
+ }
693
+ function readCodeModePayloadToolName(tool) {
694
+ if (!isRecord(tool)) return;
695
+ const name = readToolPayloadField(tool, "name");
696
+ if (typeof name === "string") return name;
697
+ const fn = readToolPayloadField(tool, "function");
698
+ if (!isRecord(fn)) return;
699
+ const fnName = readToolPayloadField(fn, "name");
700
+ return typeof fnName === "string" ? fnName : void 0;
701
+ }
702
+ function readCodeModePayloadToolIdentity(tool, visibleToolNames, allowedHostedToolTypes) {
703
+ if (!isRecord(tool)) return;
704
+ const type = readToolPayloadField(tool, "type");
705
+ if (typeof type === "string" && allowedHostedToolTypes?.has(type)) {
706
+ try {
707
+ if (Object.hasOwn(tool, "name") || Object.hasOwn(tool, "function") || Object.hasOwn(tool, "functionDeclarations") || Object.hasOwn(tool, "function_declarations")) return false;
708
+ } catch {
709
+ return false;
710
+ }
711
+ return `hosted:${type}`;
712
+ }
713
+ const name = readCodeModePayloadToolName(tool);
714
+ return typeof name === "string" && isCodeModeModelVisibleToolName(name, visibleToolNames) ? `client:${name}` : void 0;
715
+ }
716
+ function readCodeModePayloadToolIdentities(payload) {
717
+ if (!isRecord(payload)) return [];
718
+ const tools = readToolPayloadField(payload, "tools");
719
+ if (!Array.isArray(tools)) return [];
720
+ return tools.flatMap((tool) => {
721
+ if (!isRecord(tool)) return [];
722
+ const identities = [];
723
+ const name = readCodeModePayloadToolName(tool);
724
+ if (name) identities.push(`client:${name}`);
725
+ for (const key of ["functionDeclarations", "function_declarations"]) {
726
+ const declarations = readToolPayloadField(tool, key);
727
+ if (!Array.isArray(declarations)) continue;
728
+ for (const declaration of declarations) {
729
+ const declarationName = readCodeModePayloadToolName(declaration);
730
+ if (declarationName) identities.push(`client:${declarationName}`);
731
+ }
732
+ }
733
+ const type = readToolPayloadField(tool, "type");
734
+ if (typeof type === "string" && type !== "function") identities.push(`hosted:${type}`);
735
+ return identities;
736
+ });
737
+ }
738
+ function filterCodeModePayloadTools(payload, visibleToolNames, allowedHostedToolTypes, observer) {
739
+ if (!isRecord(payload)) return;
740
+ const tools = readToolPayloadField(payload, "tools");
741
+ if (!Array.isArray(tools)) return;
742
+ const beforeToolIdentities = observer ? readCodeModePayloadToolIdentities(payload) : void 0;
743
+ payload.tools = tools.flatMap((tool) => {
744
+ const identity = readCodeModePayloadToolIdentity(tool, visibleToolNames, allowedHostedToolTypes);
745
+ if (identity) return [tool];
746
+ if (identity === false) return [];
747
+ if (!isRecord(tool)) return [];
748
+ const filteredGroups = {};
749
+ for (const key of ["functionDeclarations", "function_declarations"]) {
750
+ const declarations = readToolPayloadField(tool, key);
751
+ if (!Array.isArray(declarations)) continue;
752
+ const filtered = declarations.filter((declaration) => {
753
+ const declarationName = readCodeModePayloadToolName(declaration);
754
+ return typeof declarationName === "string" && isCodeModeModelVisibleToolName(declarationName, visibleToolNames);
755
+ });
756
+ if (filtered.length > 0) filteredGroups[key] = filtered;
757
+ }
758
+ return Object.keys(filteredGroups).length > 0 ? [filteredGroups] : [];
759
+ });
760
+ if (beforeToolIdentities) observer?.({
761
+ beforeToolIdentities,
762
+ afterToolIdentities: readCodeModePayloadToolIdentities(payload)
763
+ });
764
+ }
765
+ function resolveCodeModeResponsesVisibleToolNames(context) {
766
+ return new Set((context.tools ?? []).map(readCodeModePayloadToolName).filter((name) => typeof name === "string"));
767
+ }
768
+ function enforceCodeModeResponsesToolSurface(payload, visibleToolNames, allowedHostedToolTypes, observer) {
769
+ if (!isRecord(payload)) return;
770
+ const tools = readToolPayloadField(payload, "tools");
771
+ if (!Array.isArray(tools)) return;
772
+ const beforeToolIdentities = observer ? readCodeModePayloadToolIdentities(payload) : void 0;
773
+ payload.tools = tools.filter((tool) => Boolean(readCodeModePayloadToolIdentity(tool, visibleToolNames, allowedHostedToolTypes)));
774
+ if (beforeToolIdentities) observer?.({
775
+ beforeToolIdentities,
776
+ afterToolIdentities: readCodeModePayloadToolIdentities(payload)
777
+ });
778
+ }
779
+ function assertCodeModeResponsesToolSurface(payload, visibleToolNames, allowedHostedToolTypes) {
780
+ const tools = isRecord(payload) ? readToolPayloadField(payload, "tools") : void 0;
781
+ if (!Array.isArray(tools)) throw new Error("Code mode payload tool surface violation: expected exec,wait; got no tools");
782
+ const identities = tools.map((tool) => readCodeModePayloadToolIdentity(tool, visibleToolNames, allowedHostedToolTypes));
783
+ const names = identities.flatMap((identity) => typeof identity === "string" && identity.startsWith("client:") ? [identity.slice(7)] : []).toSorted((left, right) => left.localeCompare(right));
784
+ if (names.length >= 2 && identities.every((identity) => typeof identity === "string") && new Set(identities).size === identities.length && names.includes("exec") && names.includes("wait")) return;
785
+ throw new Error(`Code mode payload tool surface violation: expected exec,wait plus direct-only tools; got ${names.length > 0 ? names.join(",") : "none"}`);
786
+ }
787
+ function buildOpenAIStrictToolDowngradeDiagnosticKey(diagnostics, context) {
788
+ return sha256Hex(JSON.stringify({
789
+ transport: context.transport,
790
+ provider: context.model.provider ?? null,
791
+ model: context.model.id ?? null,
792
+ diagnostics: diagnostics.map((entry) => ({
793
+ toolIndex: entry.toolIndex,
794
+ toolName: entry.toolName ?? null,
795
+ violations: entry.violations
796
+ }))
797
+ }));
798
+ }
799
+ function shouldLogOpenAIStrictToolDowngradeDiagnostic(diagnostics, context) {
800
+ const key = buildOpenAIStrictToolDowngradeDiagnosticKey(diagnostics, context);
801
+ if (loggedOpenAIStrictToolDowngradeDiagnosticKeys.has(key)) return false;
802
+ if (loggedOpenAIStrictToolDowngradeDiagnosticKeys.size >= MAX_OPENAI_STRICT_TOOL_DOWNGRADE_DIAGNOSTIC_KEYS) loggedOpenAIStrictToolDowngradeDiagnosticKeys.clear();
803
+ loggedOpenAIStrictToolDowngradeDiagnosticKeys.add(key);
804
+ return true;
805
+ }
806
+ function resolveOpenAIStrictToolFlagWithDiagnostics(projection, strictSetting, context) {
807
+ const strict = resolveOpenAIProjectedToolsStrictToolFlag(projection, strictSetting);
808
+ if (strictSetting === true && strict === false) {
809
+ const diagnostics = findOpenAIStrictToolProjectionDiagnostics(projection);
810
+ getAiTransportHost().logDebug("openai-transport", () => {
811
+ if (!shouldLogOpenAIStrictToolDowngradeDiagnostic(diagnostics, context)) return null;
812
+ const sample = diagnostics.slice(0, 5).map((entry) => ({
813
+ tool: entry.toolName ?? `tool[${entry.toolIndex}]`,
814
+ violations: entry.violations.slice(0, 8)
815
+ }));
816
+ return {
817
+ message: `OpenAI ${context.transport} tool schema strict mode downgraded to strict=false for ${context.model.provider ?? "unknown"}/${context.model.id ?? "unknown"} because ${diagnostics.length} tool schema(s) are not strict-compatible`,
818
+ data: {
819
+ transport: context.transport,
820
+ provider: context.model.provider,
821
+ model: context.model.id,
822
+ incompatibleToolCount: diagnostics.length,
823
+ sample
824
+ }
825
+ };
826
+ });
827
+ }
828
+ return strict;
829
+ }
830
+ function isOpenAICodexResponsesModel(model) {
831
+ return OPENAI_CODEX_RESPONSES_PROVIDERS.has(model.provider) && (model.api === "openai-chatgpt-responses" || model.api === "openclaw-openai-chatgpt-responses-transport");
832
+ }
833
+ function isNativeOpenAICodexResponsesBaseUrl(baseUrl) {
834
+ const trimmed = typeof baseUrl === "string" ? baseUrl.trim() : "";
835
+ if (!trimmed) return false;
836
+ try {
837
+ const url = new URL(trimmed);
838
+ if (url.protocol !== "http:" && url.protocol !== "https:") return false;
839
+ if (url.hostname.toLowerCase() !== "chatgpt.com") return false;
840
+ const pathname = url.pathname.replace(/\/+$/u, "").toLowerCase();
841
+ return [
842
+ "/backend-api",
843
+ "/backend-api/v1",
844
+ "/backend-api/codex",
845
+ "/backend-api/codex/v1"
846
+ ].includes(pathname);
847
+ } catch {
848
+ return false;
849
+ }
850
+ }
851
+ function usesNativeOpenAICodexResponsesBackend(model) {
852
+ return isOpenAICodexResponsesModel(model) && isNativeOpenAICodexResponsesBaseUrl(model.baseUrl);
853
+ }
854
+ function buildOpenAIClientHeaders(model, context, optionHeaders, turnHeaders, sessionId) {
855
+ const providerHeaders = { ...model.headers };
856
+ if (model.provider === "github-copilot") Object.assign(providerHeaders, getAiTransportHost().buildCopilotDynamicHeaders(context.messages));
857
+ const callerHeaders = {
858
+ ...optionHeaders,
859
+ ...turnHeaders
860
+ };
861
+ const resolvedHeaders = resolveProviderRequestPolicyConfig(model, {
862
+ provider: model.provider,
863
+ api: model.api,
864
+ baseUrl: model.baseUrl,
865
+ capability: "llm",
866
+ transport: "stream",
867
+ providerHeaders,
868
+ callerHeaders: Object.keys(callerHeaders).length > 0 ? callerHeaders : void 0,
869
+ precedence: "caller-wins"
870
+ }).headers ?? {};
871
+ if (sessionId && !Object.keys(resolvedHeaders).some((key) => normalizeLowercaseStringOrEmpty(key) === "session_id") && usesNativeOpenAICodexResponsesBackend(model)) resolvedHeaders.session_id = clampOpenAIPromptCacheKey(sessionId) ?? sessionId;
872
+ return resolvedHeaders;
873
+ }
874
+ function resolveOpenAISdkTimeoutMs(model, timeoutMs) {
875
+ return resolveModelRequestTimeoutMs(model, timeoutMs);
876
+ }
877
+ function buildOpenAISdkClientOptions(model) {
878
+ const timeout = resolveOpenAISdkTimeoutMs(model);
879
+ return timeout === void 0 ? {} : { timeout };
880
+ }
881
+ function buildOpenAISdkRequestOptions(model, signal, options) {
882
+ const timeout = resolveOpenAISdkTimeoutMs(model, options?.timeoutMs);
883
+ const headers = options?.stream === true && usesNativeOpenAICodexResponsesBackend(model) ? { Accept: "text/event-stream" } : void 0;
884
+ if (timeout === void 0 && options?.maxRetries === void 0 && !signal && !headers) return;
885
+ return {
886
+ ...headers ? { headers } : {},
887
+ ...signal ? { signal } : {},
888
+ ...timeout !== void 0 ? { timeout } : {},
889
+ ...options?.maxRetries !== void 0 ? { maxRetries: options.maxRetries } : {}
890
+ };
891
+ }
892
+ function getCompat(model) {
893
+ const resolved = resolveOpenAICompletionsCompat(model);
894
+ const compat = model.compat ?? {};
895
+ return {
896
+ ...resolved,
897
+ cacheControlFormat: resolved.cacheControlFormat,
898
+ reasoningEffortMap: resolveOpenAIReasoningEffortMap(model, {}),
899
+ openRouterRouting: resolved.openRouterRouting ?? {},
900
+ vercelGatewayRouting: resolved.vercelGatewayRouting,
901
+ requiresStringContent: compat.requiresStringContent ?? false,
902
+ strictMessageKeys: compat.strictMessageKeys === true
903
+ };
904
+ }
905
+ //#endregion
906
+ //#region packages/ai/src/transports/openai-completions-dsml.ts
907
+ const DEEPSEEK_DSML_TOOL_KINDS = [
908
+ "tool_calls",
909
+ "tool_call",
910
+ "function_calls"
911
+ ];
912
+ const DEEPSEEK_DSML_TOOL_OPEN_TOKENS = DEEPSEEK_DSML_MARKERS.flatMap((marker) => DEEPSEEK_DSML_TOOL_KINDS.map((kind) => `<${marker}${kind}>`));
913
+ const DEEPSEEK_DSML_INVOKE_OPEN_PREFIXES = DEEPSEEK_DSML_MARKERS.map((marker) => `<${marker}invoke`);
914
+ const DEEPSEEK_DSML_INVOKE_OPEN_TAG = new RegExp(`^<${DEEPSEEK_DSML_MARKER_PATTERN}invoke\\b[^<>]*>$`);
915
+ const DEEPSEEK_DSML_TOOL_MAX_OPEN_TOKEN_LEN = Math.max(...DEEPSEEK_DSML_TOOL_OPEN_TOKENS.map((token) => token.length));
916
+ const DEEPSEEK_DSML_RECOVERY_MAX_BOUNDARY_LEN = Math.max(...DEEPSEEK_DSML_TOOL_OPEN_TOKENS.map((token) => token.length + 1), ...DEEPSEEK_DSML_INVOKE_OPEN_PREFIXES.map((token) => token.length + 2));
917
+ const MAX_DSML_RECOVERY_BUFFER_BYTES = 256e3;
918
+ const DEEPSEEK_DSML_SCAN_BATCH_CHARS = 65536;
919
+ function createDsmlRecoverer() {
920
+ let buffer = "";
921
+ let bufferBytes = 0;
922
+ let bufferEndsWithHighSurrogate = false;
923
+ let pendingScanChars = 0;
924
+ let activeOpenToken = null;
925
+ let blockScanState = { offset: 0 };
926
+ const resetBlockScan = () => {
927
+ activeOpenToken = null;
928
+ pendingScanChars = 0;
929
+ blockScanState = { offset: 0 };
930
+ };
931
+ const consume = (final) => {
932
+ const output = [];
933
+ while (buffer) {
934
+ const open = activeOpenToken ? {
935
+ index: 0,
936
+ token: activeOpenToken
937
+ } : findEarliestStringToken(buffer, DEEPSEEK_DSML_TOOL_OPEN_TOKENS);
938
+ if (!open) {
939
+ resetBlockScan();
940
+ if (final) {
941
+ output.push({
942
+ kind: "text",
943
+ text: buffer
944
+ });
945
+ buffer = "";
946
+ bufferBytes = 0;
947
+ bufferEndsWithHighSurrogate = false;
948
+ return output;
949
+ }
950
+ const keep = longestDeepSeekDsmlToolOpenPrefixSuffixLength(buffer);
951
+ const emitLength = buffer.length - keep;
952
+ if (emitLength > 0) {
953
+ const emitted = buffer.slice(0, emitLength);
954
+ output.push({
955
+ kind: "text",
956
+ text: emitted
957
+ });
958
+ bufferBytes -= Buffer.byteLength(emitted, "utf8");
959
+ buffer = buffer.slice(emitted.length);
960
+ if (!buffer) bufferEndsWithHighSurrogate = false;
961
+ }
962
+ return output;
963
+ }
964
+ if (open.index > 0) {
965
+ const prefix = buffer.slice(0, open.index);
966
+ output.push({
967
+ kind: "text",
968
+ text: prefix
969
+ });
970
+ bufferBytes -= Buffer.byteLength(prefix, "utf8");
971
+ buffer = buffer.slice(prefix.length);
972
+ resetBlockScan();
973
+ }
974
+ activeOpenToken = open.token;
975
+ if (blockScanState.offset === 0) blockScanState.offset = open.token.length;
976
+ const blockScan = scanDeepSeekDsmlToolBlock(buffer, open.token.replace("<", "</"), open.token.length, blockScanState);
977
+ if (blockScan.kind === "nested-open") throw new Error("Nested DeepSeek DSML recovery wrappers are not supported");
978
+ const close = blockScan.kind === "close" ? blockScan : null;
979
+ if (!close) {
980
+ if (final) {
981
+ output.push({
982
+ kind: "text",
983
+ text: buffer
984
+ });
985
+ buffer = "";
986
+ bufferBytes = 0;
987
+ bufferEndsWithHighSurrogate = false;
988
+ return output;
989
+ }
990
+ if (bufferBytes > MAX_DSML_RECOVERY_BUFFER_BYTES) throw new Error("Exceeded DeepSeek DSML recovery buffer limit");
991
+ return output;
992
+ }
993
+ resetBlockScan();
994
+ const body = buffer.slice(open.token.length, close.index);
995
+ const blockText = buffer.slice(0, close.index + close.token.length);
996
+ if (Buffer.byteLength(blockText, "utf8") > MAX_DSML_RECOVERY_BUFFER_BYTES) throw new Error("Exceeded DeepSeek DSML recovery buffer limit");
997
+ const recoveredToolCalls = parseDeepSeekDsmlToolCallBlock(body);
998
+ if (recoveredToolCalls.length > 0) output.push(...recoveredToolCalls);
999
+ else output.push({
1000
+ kind: "text",
1001
+ text: blockText
1002
+ });
1003
+ bufferBytes -= Buffer.byteLength(blockText, "utf8");
1004
+ buffer = buffer.slice(blockText.length);
1005
+ if (!buffer) bufferEndsWithHighSurrogate = false;
1006
+ }
1007
+ return output;
1008
+ };
1009
+ return {
1010
+ push(chunk) {
1011
+ const append = measureUtf8AppendBytes(bufferEndsWithHighSurrogate, chunk);
1012
+ bufferBytes += append.bytes;
1013
+ bufferEndsWithHighSurrogate = append.endsWithHighSurrogate;
1014
+ buffer += chunk;
1015
+ pendingScanChars += chunk.length;
1016
+ if (activeOpenToken && pendingScanChars < DEEPSEEK_DSML_SCAN_BATCH_CHARS && !chunk.includes("<") && !chunk.includes(">") && bufferBytes <= MAX_DSML_RECOVERY_BUFFER_BYTES) return [];
1017
+ pendingScanChars = 0;
1018
+ return consume(false);
1019
+ },
1020
+ flush() {
1021
+ return consume(true);
1022
+ }
1023
+ };
1024
+ }
1025
+ function parseDeepSeekDsmlToolCallBlock(body) {
1026
+ const toolCalls = [];
1027
+ const invokeOpenRegex = new RegExp(`<${DEEPSEEK_DSML_MARKER_PATTERN}invoke\\b([^<>]*)>`, "g");
1028
+ let openMatch;
1029
+ while ((openMatch = invokeOpenRegex.exec(body)) !== null) {
1030
+ const invokeBodyStart = openMatch.index + openMatch[0].length;
1031
+ const invokeCloseToken = `</${openMatch[1]}invoke>`;
1032
+ const invokeCloseIndex = body.indexOf(invokeCloseToken, invokeBodyStart);
1033
+ if (invokeCloseIndex === -1) break;
1034
+ const invokeBody = body.slice(invokeBodyStart, invokeCloseIndex);
1035
+ invokeOpenRegex.lastIndex = invokeCloseIndex + invokeCloseToken.length;
1036
+ const invokeName = parseXmlAttribute(openMatch[2] ?? "", "name");
1037
+ if (!invokeName) continue;
1038
+ const parsedArguments = parseDeepSeekDsmlInvokeArguments(invokeBody);
1039
+ if (!parsedArguments) continue;
1040
+ toolCalls.push({
1041
+ kind: "toolCall",
1042
+ name: invokeName,
1043
+ arguments: parsedArguments,
1044
+ partialArgs: JSON.stringify(parsedArguments)
1045
+ });
1046
+ }
1047
+ return toolCalls;
1048
+ }
1049
+ function parseDeepSeekDsmlInvokeArguments(body) {
1050
+ const args = {};
1051
+ const parameterRegex = new RegExp(`<${DEEPSEEK_DSML_MARKER_PATTERN}parameter\\b([^>]*)>([\\s\\S]*?)</\\1parameter>`, "g");
1052
+ let parameterMatch;
1053
+ while ((parameterMatch = parameterRegex.exec(body)) !== null) {
1054
+ const name = parseXmlAttribute(parameterMatch[2] ?? "", "name");
1055
+ if (!name) continue;
1056
+ const rawValue = parameterMatch[3] ?? "";
1057
+ if (rawValue.length === 0) continue;
1058
+ args[name] = decodeDeepSeekDsmlText(rawValue);
1059
+ }
1060
+ if (Object.keys(args).length > 0) return args;
1061
+ const trimmed = body.trim();
1062
+ if (!trimmed.startsWith("{")) return null;
1063
+ try {
1064
+ const parsed = JSON.parse(trimmed);
1065
+ if (isRecord(parsed) && Object.keys(parsed).length > 0) return parsed;
1066
+ } catch {
1067
+ return null;
1068
+ }
1069
+ return null;
1070
+ }
1071
+ const xmlAttributeRegexCache = /* @__PURE__ */ new Map();
1072
+ function xmlAttributeRegex(name) {
1073
+ const cached = xmlAttributeRegexCache.get(name);
1074
+ if (cached) return cached;
1075
+ const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1076
+ const pattern = new RegExp(`\\b${escaped}=("([^"]*)"|'([^']*)'|([^\\s>]+))`);
1077
+ xmlAttributeRegexCache.set(name, pattern);
1078
+ return pattern;
1079
+ }
1080
+ function parseXmlAttribute(attributes, name) {
1081
+ const match = xmlAttributeRegex(name).exec(attributes);
1082
+ const value = match?.[2] ?? match?.[3] ?? match?.[4];
1083
+ return value ? decodeDeepSeekDsmlText(value) : null;
1084
+ }
1085
+ function decodeDeepSeekDsmlText(value) {
1086
+ return value.replaceAll("&quot;", "\"").replaceAll("&apos;", "'").replaceAll("&lt;", "<").replaceAll("&gt;", ">").replaceAll("&amp;", "&");
1087
+ }
1088
+ function findEarliestStringToken(text, tokens, fromIndex = 0) {
1089
+ let best = null;
1090
+ for (const token of tokens) {
1091
+ const index = text.indexOf(token, fromIndex);
1092
+ if (index !== -1 && (!best || index < best.index)) best = {
1093
+ index,
1094
+ token
1095
+ };
1096
+ }
1097
+ return best;
1098
+ }
1099
+ function scanDeepSeekDsmlToolBlock(text, closeToken, contentStartIndex, state) {
1100
+ while (state.offset < text.length) {
1101
+ if (state.invoke?.kind === "open") {
1102
+ const nextOpen = text.indexOf("<", state.offset);
1103
+ const nextClose = text.indexOf(">", state.offset);
1104
+ if (nextClose === -1 && nextOpen === -1) {
1105
+ state.offset = text.length;
1106
+ return { kind: "incomplete" };
1107
+ }
1108
+ if (nextOpen !== -1 && (nextClose === -1 || nextOpen < nextClose)) {
1109
+ state.invoke = void 0;
1110
+ state.offset = nextOpen;
1111
+ continue;
1112
+ }
1113
+ const invokeOpenTag = text.slice(state.invoke.start, nextClose + 1);
1114
+ const open = DEEPSEEK_DSML_INVOKE_OPEN_TAG.exec(invokeOpenTag);
1115
+ if (!open) {
1116
+ state.offset = state.invoke.start + 1;
1117
+ state.invoke = void 0;
1118
+ continue;
1119
+ }
1120
+ state.invoke = {
1121
+ kind: "body",
1122
+ closeToken: `</${open[1]}invoke>`
1123
+ };
1124
+ state.offset = nextClose + 1;
1125
+ continue;
1126
+ }
1127
+ if (state.invoke?.kind === "body") {
1128
+ const invokeCloseIndex = text.indexOf(state.invoke.closeToken, state.offset);
1129
+ if (invokeCloseIndex === -1) {
1130
+ state.offset = Math.max(0, text.length - DEEPSEEK_DSML_RECOVERY_MAX_BOUNDARY_LEN + 1);
1131
+ return { kind: "incomplete" };
1132
+ }
1133
+ state.offset = invokeCloseIndex + state.invoke.closeToken.length;
1134
+ state.invoke = void 0;
1135
+ continue;
1136
+ }
1137
+ const toolOpen = findEarliestStringToken(text, DEEPSEEK_DSML_TOOL_OPEN_TOKENS, state.offset);
1138
+ const toolCloseIndex = text.indexOf(closeToken, state.offset);
1139
+ const invokeOpen = findEarliestStringToken(text, DEEPSEEK_DSML_INVOKE_OPEN_PREFIXES, state.offset);
1140
+ const next = [
1141
+ toolOpen ? {
1142
+ kind: "nested-open",
1143
+ ...toolOpen
1144
+ } : null,
1145
+ toolCloseIndex === -1 ? null : {
1146
+ kind: "close",
1147
+ index: toolCloseIndex,
1148
+ token: closeToken
1149
+ },
1150
+ invokeOpen ? {
1151
+ kind: "invoke-open",
1152
+ ...invokeOpen
1153
+ } : null
1154
+ ].filter((candidate) => candidate !== null).toSorted((left, right) => left.index - right.index)[0];
1155
+ if (!next) {
1156
+ state.offset = Math.max(contentStartIndex, text.length - DEEPSEEK_DSML_RECOVERY_MAX_BOUNDARY_LEN + 1);
1157
+ return { kind: "incomplete" };
1158
+ }
1159
+ if (next.kind === "invoke-open") {
1160
+ state.invoke = {
1161
+ kind: "open",
1162
+ start: next.index
1163
+ };
1164
+ state.offset = next.index + next.token.length;
1165
+ continue;
1166
+ }
1167
+ return next;
1168
+ }
1169
+ return { kind: "incomplete" };
1170
+ }
1171
+ function longestDeepSeekDsmlToolOpenPrefixSuffixLength(text) {
1172
+ const maxLength = Math.min(text.length, DEEPSEEK_DSML_TOOL_MAX_OPEN_TOKEN_LEN - 1);
1173
+ for (let length = maxLength; length > 0; length -= 1) {
1174
+ const suffix = text.slice(text.length - length);
1175
+ if (DEEPSEEK_DSML_TOOL_OPEN_TOKENS.some((token) => token.startsWith(suffix))) return length;
1176
+ }
1177
+ return 0;
1178
+ }
1179
+ //#endregion
1180
+ //#region packages/ai/src/transports/openai-completions-stream.ts
1181
+ function extractToolCallThoughtSignature(toolCall) {
1182
+ const tc = toolCall;
1183
+ if (!tc) return;
1184
+ const fromExtra = (tc.extra_content?.google)?.thought_signature;
1185
+ if (typeof fromExtra === "string" && fromExtra.length > 0) return fromExtra;
1186
+ const fromFunction = tc.function?.thought_signature;
1187
+ if (typeof fromFunction === "string" && fromFunction.length > 0) return fromFunction;
1188
+ const fromToolCall = tc.thought_signature;
1189
+ return typeof fromToolCall === "string" && fromToolCall.length > 0 ? fromToolCall : void 0;
1190
+ }
1191
+ async function processCompletionsStream(responseStream, output, model, stream, options) {
1192
+ const MAX_POST_TOOL_CALL_BUFFER_BYTES = 256e3;
1193
+ const directMode = options?.mode === "direct";
1194
+ const emitReasoning = options?.emitReasoning ?? true;
1195
+ const compat = getCompat(model);
1196
+ const visibleReasoningDetailTypes = new Set(compat.visibleReasoningDetailTypes);
1197
+ const shouldFilterDeepSeekDsmlText = !directMode && compat.thinkingFormat === "deepseek";
1198
+ const deepSeekTextFilter = shouldFilterDeepSeekDsmlText ? createDeepSeekTextFilter() : null;
1199
+ const deepSeekToolCallRecoverer = shouldFilterDeepSeekDsmlText ? createDsmlRecoverer() : null;
1200
+ const reasoningTagTextPartitioner = createReasoningTagTextPartitioner();
1201
+ if (options?.strictReasoningTags) reasoningTagTextPartitioner.markStrict();
1202
+ let currentBlock = null;
1203
+ let directTextBlock = null;
1204
+ let directThinkingBlock = null;
1205
+ let currentTextSource;
1206
+ let pendingInterruptedTextBlock = null;
1207
+ let confirmedInterruptedTextBlock = null;
1208
+ let pendingPostToolCallDeltas = [];
1209
+ let pendingPostToolCallBytes = 0;
1210
+ let isFlushingPendingPostToolCallDeltas = false;
1211
+ const toolCallBlocksByIndex = /* @__PURE__ */ new Map();
1212
+ const toolCallBlocksById = /* @__PURE__ */ new Map();
1213
+ const encryptedReasoning = directMode ? createOpenAIEncryptedToolCallReasoningTracker() : void 0;
1214
+ const toolArgumentPreviewSchedules = /* @__PURE__ */ new WeakMap();
1215
+ const provisionalCommentaryTags = directMode ? options.provisionalCommentaryTags : /* @__PURE__ */ new Map();
1216
+ const contentBlockIndices = /* @__PURE__ */ new WeakMap();
1217
+ const toolCallBlockIndices = /* @__PURE__ */ new WeakMap();
1218
+ let explicitVisibleTextBlocks;
1219
+ const normalizeToolCallDeltas = createOpenAICompletionsToolCallDeltaNormalizer();
1220
+ let finishReason;
1221
+ let sawNativeToolCallDelta = false;
1222
+ const blockIndex = () => directMode && currentBlock && currentBlock.type !== "toolCall" ? contentBlockIndices.get(currentBlock) ?? output.content.length - 1 : output.content.length - 1;
1223
+ const measureUtf8Bytes = (text) => Buffer.byteLength(text, "utf8");
1224
+ let chunkPushedEvent = false;
1225
+ const pushStreamEvent = (event) => {
1226
+ chunkPushedEvent = true;
1227
+ stream.push(event);
1228
+ };
1229
+ const queuePostToolCallDelta = (next) => {
1230
+ const nextBytes = measureUtf8Bytes(next.text);
1231
+ if (pendingPostToolCallBytes + nextBytes > MAX_POST_TOOL_CALL_BUFFER_BYTES) throw new Error("Exceeded post-tool-call delta buffer limit");
1232
+ pendingPostToolCallBytes += nextBytes;
1233
+ const previous = pendingPostToolCallDeltas[pendingPostToolCallDeltas.length - 1];
1234
+ if (!previous || previous.kind !== next.kind || previous.kind === "text" && next.kind === "text" && previous.source !== next.source) {
1235
+ pendingPostToolCallDeltas.push(next);
1236
+ return;
1237
+ }
1238
+ if (next.kind === "thinking" && previous.kind === "thinking") {
1239
+ if (previous.signature !== next.signature) {
1240
+ pendingPostToolCallDeltas.push(next);
1241
+ return;
1242
+ }
1243
+ previous.text += next.text;
1244
+ return;
1245
+ }
1246
+ previous.text += next.text;
1247
+ };
1248
+ const appendThinkingDeltaInternal = (reasoningDelta) => {
1249
+ if (directMode && directThinkingBlock) currentBlock = directThinkingBlock;
1250
+ if (!currentBlock || currentBlock.type !== "thinking") {
1251
+ options?.beforeContentBlock?.("thinking");
1252
+ const thinkingSignature = reasoningDelta.signature;
1253
+ currentBlock = {
1254
+ type: "thinking",
1255
+ thinking: "",
1256
+ ...thinkingSignature ? { thinkingSignature } : {}
1257
+ };
1258
+ if (directMode) {
1259
+ directTextBlock = null;
1260
+ directThinkingBlock = currentBlock;
1261
+ }
1262
+ output.content.push(currentBlock);
1263
+ contentBlockIndices.set(currentBlock, output.content.length - 1);
1264
+ pushStreamEvent({
1265
+ type: "thinking_start",
1266
+ contentIndex: blockIndex(),
1267
+ partial: output
1268
+ });
1269
+ }
1270
+ currentBlock.thinking += reasoningDelta.text;
1271
+ pushStreamEvent({
1272
+ type: "thinking_delta",
1273
+ contentIndex: blockIndex(),
1274
+ delta: reasoningDelta.text,
1275
+ partial: output
1276
+ });
1277
+ };
1278
+ const appendTextDeltaInternal = (text, source) => {
1279
+ if (directMode && directTextBlock) currentBlock = directTextBlock;
1280
+ if (currentBlock?.type === "text" && currentTextSource !== source) currentBlock = null;
1281
+ if (!currentBlock || currentBlock.type !== "text") {
1282
+ options?.beforeContentBlock?.("text");
1283
+ currentBlock = {
1284
+ type: "text",
1285
+ text: ""
1286
+ };
1287
+ currentTextSource = source;
1288
+ if (directMode) {
1289
+ directTextBlock = currentBlock;
1290
+ directThinkingBlock = null;
1291
+ }
1292
+ if (source === "reasoning_detail") (explicitVisibleTextBlocks ??= /* @__PURE__ */ new Set()).add(currentBlock);
1293
+ output.content.push(currentBlock);
1294
+ contentBlockIndices.set(currentBlock, output.content.length - 1);
1295
+ pushStreamEvent({
1296
+ type: "text_start",
1297
+ contentIndex: blockIndex(),
1298
+ partial: output
1299
+ });
1300
+ }
1301
+ currentBlock.text += text;
1302
+ if (pendingInterruptedTextBlock && text.trim()) {
1303
+ confirmedInterruptedTextBlock = pendingInterruptedTextBlock;
1304
+ pendingInterruptedTextBlock = null;
1305
+ }
1306
+ pushStreamEvent({
1307
+ type: "text_delta",
1308
+ contentIndex: blockIndex(),
1309
+ delta: text,
1310
+ ...directMode ? { partial: output } : {}
1311
+ });
1312
+ };
1313
+ const flushPendingPostToolCallDeltas = () => {
1314
+ if (isFlushingPendingPostToolCallDeltas || currentBlock?.type === "toolCall" || pendingPostToolCallDeltas.length === 0) return;
1315
+ isFlushingPendingPostToolCallDeltas = true;
1316
+ const bufferedDeltas = pendingPostToolCallDeltas;
1317
+ pendingPostToolCallDeltas = [];
1318
+ pendingPostToolCallBytes = 0;
1319
+ for (const delta of bufferedDeltas) if (delta.kind === "text") appendTextDeltaInternal(delta.text, delta.source);
1320
+ else if (emitReasoning) appendThinkingDeltaInternal(delta);
1321
+ isFlushingPendingPostToolCallDeltas = false;
1322
+ };
1323
+ const appendThinkingDelta = (reasoningDelta) => {
1324
+ flushPendingPostToolCallDeltas();
1325
+ appendThinkingDeltaInternal(reasoningDelta);
1326
+ };
1327
+ const appendTextDelta = (text, source) => {
1328
+ flushPendingPostToolCallDeltas();
1329
+ appendTextDeltaInternal(text, source);
1330
+ };
1331
+ const appendVisibleTextDelta = (text) => {
1332
+ if (!text) return;
1333
+ if (currentBlock?.type === "toolCall" && !directMode) queuePostToolCallDelta({
1334
+ kind: "text",
1335
+ text
1336
+ });
1337
+ else appendTextDelta(text);
1338
+ };
1339
+ const appendReasoningDeltas = (reasoningDeltas) => {
1340
+ for (const reasoningDelta of reasoningDeltas) {
1341
+ if (reasoningDelta.kind === "thinking" && !emitReasoning) continue;
1342
+ if (currentBlock?.type === "toolCall" && !directMode) {
1343
+ queuePostToolCallDelta({ ...reasoningDelta });
1344
+ continue;
1345
+ }
1346
+ if (reasoningDelta.kind === "text") appendTextDelta(reasoningDelta.text, reasoningDelta.source);
1347
+ else if (emitReasoning) appendThinkingDelta(directMode && model.provider === "opencode-go" && reasoningDelta.signature === "reasoning" ? {
1348
+ ...reasoningDelta,
1349
+ signature: "reasoning_content"
1350
+ } : reasoningDelta);
1351
+ }
1352
+ };
1353
+ const appendRecoveredToolCall = (toolCall) => {
1354
+ if (currentBlock?.type === "toolCall") {
1355
+ currentBlock = null;
1356
+ flushPendingPostToolCallDeltas();
1357
+ }
1358
+ rememberPendingCommentaryTags(provisionalCommentaryTags, tagPendingCommentaryText(output.content));
1359
+ const block = {
1360
+ type: "toolCall",
1361
+ id: `call_${randomUUID().replaceAll("-", "").slice(0, 24)}`,
1362
+ name: toolCall.name,
1363
+ arguments: toolCall.arguments,
1364
+ partialArgs: toolCall.partialArgs
1365
+ };
1366
+ toolArgumentPreviewSchedules.set(block, createToolArgumentPreviewSchedule());
1367
+ currentBlock = block;
1368
+ output.content.push(block);
1369
+ toolCallBlockIndices.set(block, output.content.length - 1);
1370
+ pushStreamEvent({
1371
+ type: "toolcall_start",
1372
+ contentIndex: toolCallBlockIndices.get(block) ?? -1,
1373
+ partial: output
1374
+ });
1375
+ pushStreamEvent({
1376
+ type: "toolcall_delta",
1377
+ contentIndex: toolCallBlockIndices.get(block) ?? -1,
1378
+ delta: toolCall.partialArgs,
1379
+ partial: output
1380
+ });
1381
+ };
1382
+ const appendFilteredVisibleTextDelta = (text) => {
1383
+ const recoveredParts = deepSeekToolCallRecoverer?.push(text) ?? [{
1384
+ kind: "text",
1385
+ text
1386
+ }];
1387
+ for (const recoveredPart of recoveredParts) {
1388
+ if (recoveredPart.kind === "toolCall") {
1389
+ appendRecoveredToolCall(recoveredPart);
1390
+ continue;
1391
+ }
1392
+ const parts = deepSeekTextFilter?.push(recoveredPart.text) ?? [recoveredPart.text];
1393
+ for (const part of parts) appendVisibleTextDelta(part);
1394
+ }
1395
+ };
1396
+ const flushDeepSeekToolCallRecovererAtEnd = () => {
1397
+ const recoveredParts = deepSeekToolCallRecoverer?.flush();
1398
+ if (!recoveredParts) return;
1399
+ for (const recoveredPart of recoveredParts) {
1400
+ if (recoveredPart.kind === "toolCall") {
1401
+ appendRecoveredToolCall(recoveredPart);
1402
+ continue;
1403
+ }
1404
+ const parts = deepSeekTextFilter?.push(recoveredPart.text) ?? [recoveredPart.text];
1405
+ for (const part of parts) appendVisibleTextDelta(part);
1406
+ }
1407
+ };
1408
+ const flushDeepSeekTextFilterAtEnd = () => {
1409
+ const parts = deepSeekTextFilter?.flush();
1410
+ if (!parts) return;
1411
+ for (const part of parts) appendVisibleTextDelta(part);
1412
+ };
1413
+ const appendRoutedContentDelta = (delta) => {
1414
+ if (delta.kind === "text") {
1415
+ appendFilteredVisibleTextDelta(delta.text);
1416
+ return;
1417
+ }
1418
+ if (!emitReasoning) return;
1419
+ if (currentBlock?.type === "toolCall" && !directMode) queuePostToolCallDelta(delta);
1420
+ else appendThinkingDelta(delta);
1421
+ };
1422
+ const appendPartitionedVisibleDelta = (delta) => {
1423
+ if (delta.kind === "text") appendFilteredVisibleTextDelta(delta.text);
1424
+ };
1425
+ const emitReasoningUsageActivity = (hasReasoningUsageActivity) => {
1426
+ if (directMode || !hasReasoningUsageActivity || chunkPushedEvent || !emitReasoning) return;
1427
+ const latestBlock = output.content[output.content.length - 1];
1428
+ if (currentBlock?.type === "text" || currentBlock?.type === "toolCall") return;
1429
+ if (latestBlock?.type === "text" || latestBlock?.type === "toolCall") return;
1430
+ appendThinkingDelta({ text: "" });
1431
+ };
1432
+ const flushReasoningTagTextPartitioner = () => {
1433
+ for (const delta of reasoningTagTextPartitioner.flush()) appendPartitionedVisibleDelta(delta);
1434
+ };
1435
+ const sealTextBeforeReasoning = () => {
1436
+ if (currentBlock?.type !== "text" && !reasoningTagTextPartitioner.hasPending()) return;
1437
+ flushReasoningTagTextPartitioner();
1438
+ if (currentBlock?.type !== "text") return;
1439
+ if (currentTextSource !== "reasoning_detail" && currentBlock.text.trim()) pendingInterruptedTextBlock = currentBlock;
1440
+ currentBlock = null;
1441
+ if (directMode) directTextBlock = null;
1442
+ currentTextSource = void 0;
1443
+ };
1444
+ const beginReasoning = (hasFollowingVisibleText, forceStrict = false) => {
1445
+ if (!output.openclawDelivery?.textPhaseRequiresTerminal) output.openclawDelivery = {
1446
+ ...output.openclawDelivery,
1447
+ textPhaseRequiresTerminal: true
1448
+ };
1449
+ if (forceStrict || reasoningTagTextPartitioner.hasPending()) reasoningTagTextPartitioner.markStrict();
1450
+ if (!hasFollowingVisibleText || !reasoningTagTextPartitioner.hasPendingSyntax()) sealTextBeforeReasoning();
1451
+ };
1452
+ const cooperativeScheduler = directMode ? void 0 : createModelStreamCooperativeScheduler(options?.signal);
1453
+ const guardedStream = withFirstStreamEventTimeout(responseStream, {
1454
+ provider: model.provider,
1455
+ api: model.api,
1456
+ model: model.id,
1457
+ timeoutMs: options?.firstEventTimeoutMs ?? 0,
1458
+ stage: "completions",
1459
+ abort: options?.abortFirstEventStream,
1460
+ onTimeout: options?.onFirstEventTimeout,
1461
+ 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."
1462
+ });
1463
+ for await (const rawChunk of guardedStream) {
1464
+ throwIfModelStreamAborted(options?.signal);
1465
+ chunkPushedEvent = false;
1466
+ if (!rawChunk || typeof rawChunk !== "object") {
1467
+ if (cooperativeScheduler) await cooperativeScheduler.afterEvent();
1468
+ continue;
1469
+ }
1470
+ notifyLlmRequestActivity(options?.signal);
1471
+ const chunk = rawChunk;
1472
+ output.responseId ||= chunk.id;
1473
+ if (typeof chunk.model === "string" && chunk.model.length > 0 && chunk.model !== model.id) output.responseModel ||= chunk.model;
1474
+ let hasReasoningUsageActivity = false;
1475
+ if (chunk.usage) {
1476
+ output.usage = parseOpenAICompletionsUsage(chunk.usage, model, { includeReasoningTokens: !directMode });
1477
+ hasReasoningUsageActivity = hasOpenAICompletionsReasoningUsageActivity(chunk.usage);
1478
+ }
1479
+ const choice = Array.isArray(chunk.choices) ? chunk.choices[0] : void 0;
1480
+ if (!choice) {
1481
+ emitReasoningUsageActivity(hasReasoningUsageActivity);
1482
+ if (cooperativeScheduler) await cooperativeScheduler.afterEvent();
1483
+ continue;
1484
+ }
1485
+ const choiceUsage = choice.usage;
1486
+ if (!chunk.usage && choiceUsage) {
1487
+ output.usage = parseOpenAICompletionsUsage(choiceUsage, model, { includeReasoningTokens: !directMode });
1488
+ hasReasoningUsageActivity = hasOpenAICompletionsReasoningUsageActivity(choiceUsage);
1489
+ }
1490
+ if (choice.finish_reason) {
1491
+ const finishReasonResult = mapOpenAIStopReason(choice.finish_reason, { allowSingularToolCall: true });
1492
+ output.stopReason = finishReasonResult.stopReason;
1493
+ finishReason = finishReasonResult.stopReason;
1494
+ if (finishReasonResult.errorMessage) output.errorMessage = finishReasonResult.errorMessage;
1495
+ }
1496
+ const rawChoiceDelta = choice.delta ?? choice.message;
1497
+ if (!rawChoiceDelta) {
1498
+ emitReasoningUsageActivity(hasReasoningUsageActivity);
1499
+ if (cooperativeScheduler) await cooperativeScheduler.afterEvent();
1500
+ continue;
1501
+ }
1502
+ for (const normalizedDelta of normalizeToolCallDeltas(rawChoiceDelta, choice.finish_reason)) {
1503
+ const choiceDelta = normalizedDelta.delta;
1504
+ const deltaFields = choiceDelta;
1505
+ const reasoningBatch = readOpenAICompletionsReasoningBatch(deltaFields, visibleReasoningDetailTypes);
1506
+ const reasoningDeltas = reasoningBatch.deltas;
1507
+ const hasReasoningThinking = reasoningBatch.hasThinking;
1508
+ const contentDeltas = readOpenAICompletionsContentDeltas(choiceDelta.content, choiceDelta.refusal, reasoningBatch.mirroredThinking);
1509
+ const lastVisibleTextIndex = contentDeltas.findLastIndex((delta) => delta.kind === "text");
1510
+ const hasSameChunkVisibleText = reasoningBatch.hasVisibleText || lastVisibleTextIndex !== -1;
1511
+ if (hasReasoningThinking) {
1512
+ beginReasoning(hasSameChunkVisibleText, true);
1513
+ appendReasoningDeltas(reasoningDeltas);
1514
+ }
1515
+ for (const [contentDeltaIndex, contentDelta] of contentDeltas.entries()) if (contentDelta.kind === "text") {
1516
+ const routedDeltas = hasReasoningThinking ? reasoningTagTextPartitioner.push(contentDelta.text) : reasoningTagTextPartitioner.pushVisible(contentDelta.text);
1517
+ for (const routedDelta of routedDeltas) appendPartitionedVisibleDelta(routedDelta);
1518
+ } else {
1519
+ beginReasoning(contentDeltaIndex < lastVisibleTextIndex);
1520
+ appendRoutedContentDelta(contentDelta);
1521
+ }
1522
+ if (!hasReasoningThinking) appendReasoningDeltas(reasoningDeltas);
1523
+ const toolCallDeltas = normalizedDelta.toolCalls;
1524
+ if (toolCallDeltas.length > 0) {
1525
+ sawNativeToolCallDelta = true;
1526
+ flushReasoningTagTextPartitioner();
1527
+ rememberPendingCommentaryTags(provisionalCommentaryTags, tagPendingCommentaryText(output.content));
1528
+ for (const toolCall of toolCallDeltas) {
1529
+ const streamIndex = typeof toolCall.index === "number" ? toolCall.index : void 0;
1530
+ let block = streamIndex !== void 0 ? toolCallBlocksByIndex.get(streamIndex) : void 0;
1531
+ if (!block && toolCall.id) block = toolCallBlocksById.get(toolCall.id);
1532
+ if (!block) {
1533
+ if (currentBlock?.type === "toolCall") {
1534
+ currentBlock = null;
1535
+ flushPendingPostToolCallDeltas();
1536
+ }
1537
+ const initialSig = directMode ? void 0 : extractToolCallThoughtSignature(toolCall);
1538
+ options?.beforeContentBlock?.("toolCall");
1539
+ if (directMode) directThinkingBlock = null;
1540
+ block = {
1541
+ type: "toolCall",
1542
+ id: toolCall.id || "",
1543
+ name: toolCall.function?.name || "",
1544
+ arguments: {},
1545
+ partialArgs: "",
1546
+ ...initialSig ? { thoughtSignature: initialSig } : {}
1547
+ };
1548
+ encryptedReasoning?.rememberToolCall(block.id, block);
1549
+ toolArgumentPreviewSchedules.set(block, createToolArgumentPreviewSchedule());
1550
+ output.content.push(block);
1551
+ toolCallBlockIndices.set(block, output.content.length - 1);
1552
+ pushStreamEvent({
1553
+ type: "toolcall_start",
1554
+ contentIndex: toolCallBlockIndices.get(block) ?? -1,
1555
+ partial: output
1556
+ });
1557
+ }
1558
+ if (streamIndex !== void 0 && !toolCallBlocksByIndex.has(streamIndex)) toolCallBlocksByIndex.set(streamIndex, block);
1559
+ if (toolCall.id) {
1560
+ if (!directMode || !block.id) block.id = toolCall.id;
1561
+ toolCallBlocksById.set(toolCall.id, block);
1562
+ if (block.id === toolCall.id) encryptedReasoning?.rememberToolCall(toolCall.id, block);
1563
+ }
1564
+ currentBlock = block;
1565
+ const conflictingId = directMode && block.id && toolCall.id && block.id !== toolCall.id;
1566
+ if (toolCall.function?.name && !conflictingId) block.name = toolCall.function.name;
1567
+ const deltaSig = directMode ? void 0 : extractToolCallThoughtSignature(toolCall);
1568
+ if (deltaSig) block.thoughtSignature = deltaSig;
1569
+ const toolArgumentsDelta = toolCall.function?.arguments;
1570
+ if (toolArgumentsDelta) {
1571
+ block.partialArgs += toolArgumentsDelta;
1572
+ if (toolArgumentPreviewSchedules.get(block)?.(block.partialArgs.length)) block.arguments = parseStreamingJson(block.partialArgs);
1573
+ }
1574
+ if (toolArgumentsDelta || directMode) pushStreamEvent({
1575
+ type: "toolcall_delta",
1576
+ contentIndex: toolCallBlockIndices.get(block) ?? -1,
1577
+ delta: toolArgumentsDelta ?? "",
1578
+ partial: output
1579
+ });
1580
+ }
1581
+ }
1582
+ encryptedReasoning?.consumeDetails(deltaFields.reasoning_details);
1583
+ }
1584
+ flushPendingPostToolCallDeltas();
1585
+ emitReasoningUsageActivity(hasReasoningUsageActivity);
1586
+ if (cooperativeScheduler) await cooperativeScheduler.afterEvent();
1587
+ }
1588
+ if (!finishReason && (directMode || options?.sawStreamDONE?.() === false)) throw new Error("Stream ended without finish_reason");
1589
+ flushReasoningTagTextPartitioner();
1590
+ flushDeepSeekToolCallRecovererAtEnd();
1591
+ flushDeepSeekTextFilterAtEnd();
1592
+ currentBlock = null;
1593
+ flushPendingPostToolCallDeltas();
1594
+ finalizeOpenAICompletionsToolCalls(output, {
1595
+ allowSilentToolCallPromotion: finishReason === "stop" || sawNativeToolCallDelta && (options?.sawStreamDONE?.() ?? false),
1596
+ onConfirmedToolCall(block, contentIndex) {
1597
+ if (directMode || block.type !== "toolCall") return;
1598
+ pushStreamEvent({
1599
+ type: "toolcall_end",
1600
+ contentIndex,
1601
+ toolCall: block,
1602
+ partial: output
1603
+ });
1604
+ }
1605
+ });
1606
+ if (confirmedInterruptedTextBlock && output.stopReason !== "toolUse" && output.stopReason !== "error" && output.stopReason !== "aborted") tagInterruptedTextPhases(output.content, confirmedInterruptedTextBlock, explicitVisibleTextBlocks);
1607
+ if (output.stopReason !== "toolUse") clearPendingCommentaryText(provisionalCommentaryTags);
1608
+ if (output.stopReason === "error" || output.stopReason === "aborted") tagUnresolvedTextAsCommentary(output);
1609
+ if (output.stopReason === "toolUse") tagPendingCommentaryText(output.content);
1610
+ }
1611
+ function resolveOpenAICompletionsReasoningEffort(options) {
1612
+ return options?.reasoningEffort ?? options?.reasoning ?? "high";
1613
+ }
1614
+ function shouldEmitOpenAICompletionsReasoning(model, options) {
1615
+ if (!model.reasoning) return false;
1616
+ const effort = resolveOpenAICompletionsReasoningEffort(options);
1617
+ if (!effort || !isOpenAICompletionsThinkingEnabled(effort)) return false;
1618
+ return true;
1619
+ }
1620
+ function hasOpenAICompletionsReasoningUsageActivity(rawUsage) {
1621
+ const reasoningTokens = rawUsage.completion_tokens_details?.reasoning_tokens;
1622
+ return typeof reasoningTokens === "number" && Number.isFinite(reasoningTokens) && reasoningTokens > 0;
1623
+ }
1624
+ //#endregion
1625
+ export { createDeepSeekTextFilter as C, tagUnresolvedTextAsCommentary as E, shouldOmitOllamaCompatResponseFormat as S, tagPendingCommentaryText as T, hasToolCallHistory as _, buildOpenAISdkClientOptions as a, resolveOpenAICompletionsCompat as b, filterCodeModePayloadTools as c, readCodeModePayloadToolName as d, resolveCodeModeResponsesVisibleToolNames as f, convertMessages as g, resolveOpenAIReasoningEffortMap as h, buildOpenAIClientHeaders as i, getCompat as l, usesNativeOpenAICodexResponsesBackend as m, shouldEmitOpenAICompletionsReasoning as n, buildOpenAISdkRequestOptions as o, resolveOpenAIStrictToolFlagWithDiagnostics as p, assertCodeModeResponsesToolSurface as r, enforceCodeModeResponsesToolSurface as s, processCompletionsStream as t, isOpenAICodexResponsesModel as u, finalizeOpenAICompletionsToolCalls as v, clearPendingCommentaryText as w, resolveOpenAICompletionsResponseFormat as x, detectOpenAICompletionsCompat as y };