@openclaw/ai 2026.9.4 → 2026.9.6

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 (101) hide show
  1. package/README.md +1 -1
  2. package/dist/{anthropic-C4Qu4H0Z.mjs → anthropic-DZQ_7gD1.mjs} +37 -38
  3. package/dist/{anthropic-payload-policy-BZ8umAbk.d.mts → anthropic-payload-policy-DyfwikYJ.d.mts} +4 -4
  4. package/dist/{anthropic-stream-reducer-CILWF7JD.mjs → anthropic-stream-reducer-D6ZI1wwj.mjs} +70 -50
  5. package/dist/{api-registry-ByUwIR0e.d.mts → api-registry-C2T3lTV7.d.mts} +2 -2
  6. package/dist/{assistant-output-tLt4H-iQ.mjs → assistant-output-DM1JBNs1.mjs} +1 -1
  7. package/dist/{azure-openai-responses-BAlqlKKc.mjs → azure-openai-responses-DS86GYzq.mjs} +6 -9
  8. package/dist/{base64-D-su8YVo.mjs → base64-CPmadnUf.mjs} +12 -12
  9. package/dist/credential-redaction-BKv49aiv.d.mts +24 -0
  10. package/dist/{diagnostics-QuErwCIl.mjs → diagnostics-CH8j2wIG.mjs} +139 -7
  11. package/dist/{diagnostics-CPeq9F7y.mjs → diagnostics-DzrF1h4J.mjs} +18 -1
  12. package/dist/diagnostics.d.mts +11 -24
  13. package/dist/diagnostics.mjs +4 -4
  14. package/dist/event-stream-C0nsgbj2.d.mts +1 -0
  15. package/dist/{event-stream-Bt5Y4Pav.d.mts → event-stream-CjnIZZst.d.mts} +1 -1
  16. package/dist/event-stream.d.mts +2 -2
  17. package/dist/expect-lbe3Hgrh.mjs +8 -0
  18. package/dist/{google-DPBAOaOW.mjs → google-BZJFjhuC.mjs} +6 -9
  19. package/dist/{google-messages-6JkpHrhJ.mjs → google-messages-DB7GKkDk.mjs} +3 -3
  20. package/dist/{google-shared-BvBeW9aq.mjs → google-shared-Bok4I6zB.mjs} +13 -13
  21. package/dist/{google-vertex-k-TMCAYD.mjs → google-vertex-3eVNR2qW.mjs} +5 -8
  22. package/dist/{host-4atIX-2V.d.mts → host-DH-Z-LDb.d.mts} +5 -3
  23. package/dist/{host-policy-Zcg_cNz8.mjs → host-policy-DZO3oPPk.mjs} +1 -1
  24. package/dist/{host-B8YfDGd4.mjs → host-yTvBrYM2.mjs} +63 -31
  25. package/dist/{index-DdD3qerf.d.mts → index-C25RT6bP.d.mts} +37 -14
  26. package/dist/index.d.mts +7 -8
  27. package/dist/index.mjs +5 -6
  28. package/dist/internal/anthropic.d.mts +13 -10
  29. package/dist/internal/anthropic.mjs +5 -5
  30. package/dist/internal/openai-completions-compat.d.mts +2 -0
  31. package/dist/internal/openai-completions-compat.mjs +2 -0
  32. package/dist/internal/openai-responses-payload-policy.d.mts +2 -2
  33. package/dist/internal/openai-responses-payload-policy.mjs +2 -2
  34. package/dist/internal/openai.d.mts +24 -53
  35. package/dist/internal/openai.mjs +12 -9
  36. package/dist/internal/runtime.d.mts +6 -8
  37. package/dist/internal/runtime.mjs +6 -10
  38. package/dist/internal/shared.d.mts +7 -5
  39. package/dist/internal/shared.mjs +4 -3
  40. package/dist/internal/tool-schema.d.mts +4 -4
  41. package/dist/internal/tool-schema.mjs +2 -2
  42. package/dist/{mistral-CxUZ1jUb.mjs → mistral-C_13dVBn.mjs} +9 -13
  43. package/dist/{model-transport-url-DKocrEsb.d.mts → model-transport-url-C5f59L3Y.d.mts} +1 -1
  44. package/dist/{openai-chatgpt-responses-CgO6kZfo.mjs → openai-chatgpt-responses-sTxPl4zM.mjs} +150 -83
  45. package/dist/{openai-completions-yJuk7eis.mjs → openai-completions-BO6D_hrB.mjs} +11 -12
  46. package/dist/{openai-prompt-cache-Bds-n_9Q.mjs → openai-completions-compat-CUollwl6.mjs} +5 -50
  47. package/dist/{openai-completions-compat-eHgh5UPE.d.mts → openai-completions-compat-DfJG1wSO.d.mts} +4 -4
  48. package/dist/{openai-completions-stream-Da2vvl-S.mjs → openai-completions-stream-BpuJ0ZOA.mjs} +117 -106
  49. package/dist/{openai-prompt-cache-B4eYo2-I.d.mts → openai-prompt-cache-C4RHdN4n.d.mts} +2 -2
  50. package/dist/openai-prompt-cache-CjV_2IRI.mjs +46 -0
  51. package/dist/{openai-provider-client-S2gCrM2Z.mjs → openai-provider-client-BP8J1aeg.mjs} +2 -2
  52. package/dist/openai-reasoning-effort-ash8dPrd.mjs +243 -0
  53. package/dist/{openai-responses-DaYwH05E.mjs → openai-responses-BJ_IEoMU.mjs} +8 -12
  54. package/dist/{openai-responses-compaction-window-CIhBAkkq.mjs → openai-responses-compaction-window-BiNCT0bS.mjs} +20 -62
  55. package/dist/{openai-responses-contracts-BjBAqAg_.d.mts → openai-responses-contracts-B1ENJFpI.d.mts} +9 -5
  56. package/dist/openai-responses-contracts-DWrfMODE.mjs +81 -0
  57. package/dist/{openai-responses-payload-policy-rLRPsSmB.d.mts → openai-responses-payload-policy-C7GsA1y0.d.mts} +5 -3
  58. package/dist/openai-responses-prompt-observer-internal-DPHWgbBH.mjs +198 -0
  59. package/dist/openai-responses-request-lifecycle-DFuyO1pQ.mjs +36 -0
  60. package/dist/{openai-responses-shared-B8RdBPCv.mjs → openai-responses-shared-DvSqtJ6_.mjs} +859 -581
  61. package/dist/openai-responses-terminal-usage-BNFbvY9f.d.mts +47 -0
  62. package/dist/{openai-tool-schema-CzjyYXun.mjs → openai-tool-schema-D4BMcj2D.mjs} +262 -162
  63. package/dist/{openai-transport-params-9aPuV5YY.mjs → openai-transport-params-DZKOTSfH.mjs} +157 -47
  64. package/dist/{positive-integer-41zhOdcV.mjs → positive-integer-BiUxrd71.mjs} +1 -1
  65. package/dist/{provider-error-BA-v_tKd.mjs → provider-error-CRhW7lkJ.mjs} +139 -44
  66. package/dist/{provider-error-CzNw4BWX.d.mts → provider-error-xumb1V3F.d.mts} +3 -1
  67. package/dist/{provider-options-Ceqv1OKk.d.mts → provider-options-DZYq53lj.d.mts} +12 -7
  68. package/dist/{provider-replay-context-CJ_YvcEW.mjs → provider-replay-context-DPr3w20a.mjs} +1 -1
  69. package/dist/{provider-transcript-transform-V5YzU9zh.mjs → provider-transcript-transform-BTocjCRs.mjs} +1 -1
  70. package/dist/{provider-transport-turn-state-D5EXOFL2.mjs → provider-transport-turn-state-lrXEFkYr.mjs} +1 -1
  71. package/dist/{provider-types-CVjKjsuq.d.mts → provider-types-w1rEqrGP.d.mts} +3 -3
  72. package/dist/provider-types.d.mts +6 -7
  73. package/dist/providers.d.mts +2 -2
  74. package/dist/providers.mjs +10 -10
  75. package/dist/{reasoning-tag-text-partitioner-BcR5pztD.mjs → reasoning-tag-text-partitioner-Di38crhI.mjs} +167 -40
  76. package/dist/{simple-options-BQbb4yQL.mjs → simple-options-np1XPuhm.mjs} +5 -3
  77. package/dist/{usage-cost-BNWbbXav.mjs → src-DwGYYyZp.mjs} +18 -11
  78. package/dist/{stream-first-event-timeout-2hfrquuz.mjs → stream-first-event-timeout-BeptfRL6.mjs} +1 -1
  79. package/dist/{string-normalization-CmLIasuf.mjs → string-normalization-J9ZiLfGO.mjs} +13 -1
  80. package/dist/tool-schema-json-projection-CD9c_fK8.mjs +134 -0
  81. package/dist/{transport-stream-shared-zHll9BxO.mjs → transport-stream-shared-B5RioB_Q.mjs} +16 -24
  82. package/dist/{transport-stream-shared-DNvmoWnv.d.mts → transport-stream-shared-B7Z9oCYg.d.mts} +5 -5
  83. package/dist/{transport-utils-zrYjICLZ.mjs → transport-utils-03Qi0CN2.mjs} +3 -3
  84. package/dist/transports.d.mts +27 -13
  85. package/dist/transports.mjs +168 -462
  86. package/dist/types-DTvddOfm.d.mts +1 -0
  87. package/dist/{types-Ntv5z2g2.d.mts → types-qZFbaDbK.d.mts} +49 -3
  88. package/dist/types.d.mts +6 -7
  89. package/dist/types.mjs +4 -5
  90. package/dist/{validation-B0t_G2H6.d.mts → validation-DhQhmt6t.d.mts} +1 -1
  91. package/dist/{validation-BDzVDnTs.mjs → validation-Dw7cb6BV.mjs} +1 -0
  92. package/dist/validation.d.mts +1 -1
  93. package/dist/validation.mjs +1 -1
  94. package/package.json +11 -6
  95. package/dist/diagnostics-DnPnOui6.d.mts +0 -29
  96. package/dist/event-stream-C3WGFsum.d.mts +0 -1
  97. package/dist/openai-responses-contracts-DDOHA62Y.mjs +0 -245
  98. package/dist/openai-responses-prompt-observer-internal-f8J7wpsk.mjs +0 -32
  99. package/dist/src-DDmEryvj.mjs +0 -2
  100. package/dist/tool-schema-json-projection-ClptDdAO.mjs +0 -82
  101. package/dist/types-DlfwzH3T.d.mts +0 -1
@@ -1,23 +1,26 @@
1
+ import { o as readProviderRefusalReview, t as appendAssistantMessageDiagnostic } from "./diagnostics-DzrF1h4J.mjs";
1
2
  import { r as appendAssistantThinking } from "./event-stream-D8PARQfL.mjs";
2
- import { a as normalizeOptionalString } from "./string-coerce-fsri9iCu.mjs";
3
- import { M as clampThinkingLevel, _ as isImageWithMediaPayload, d as describeToolResultMediaPlaceholder, j as calculateCost, m as extractToolResultText, n as getAiTransportHost } from "./host-B8YfDGd4.mjs";
3
+ import { a as normalizeOptionalString, o as normalizeStringifiedOptionalString, s as readStringValue } from "./string-coerce-fsri9iCu.mjs";
4
4
  import { o as isRecord } from "./record-coerce-DwRYMj3t.mjs";
5
+ import { d as supportsOpenAITemperature } from "./openai-reasoning-effort-ash8dPrd.mjs";
6
+ import { M as calculateCost, _ as isImageWithMediaPayload, d as describeToolResultMediaPlaceholder, m as extractToolResultText, n as getAiTransportHost, r as resolveAiTransportHeaderSentinels } from "./host-yTvBrYM2.mjs";
5
7
  import { t as truncateUtf16Safe } from "./utf16-slice-CvGodqok.mjs";
6
- import { i as stableStringify } from "./provider-error-BA-v_tKd.mjs";
7
- import { a as resolveModelSseDebugMode, i as resolveModelPayloadDebugMode, r as emitModelTransportDebug } from "./diagnostics-QuErwCIl.mjs";
8
- import { r as asFiniteNumber } from "./base64-D-su8YVo.mjs";
9
- import { o as redactSensitiveText } from "./transport-utils-zrYjICLZ.mjs";
10
- import { s as transformTransportMessages } from "./host-policy-Zcg_cNz8.mjs";
11
- import { m as stripSystemPromptCacheBoundary, v as sortPromptCacheToolsByName } from "./simple-options-BQbb4yQL.mjs";
12
- import { O as redactIdentifier, _ as createOpenAIProviderAcceptanceHook, b as log, f as projectOpenAITools, g as createModelStreamCooperativeScheduler, k as sha256Hex, u as resolveOpenAIStrictToolFlagWithDiagnostics } from "./openai-transport-params-9aPuV5YY.mjs";
13
- import { E as parseStreamingJson, _ as sanitizeTransportPayloadText, b as withProviderResponseHook, g as sanitizeNonEmptyTransportPayloadText, h as parseTerminalToolCallArguments, k as shortHash, l as finalizeTransportStream, s as failTransportStream, t as IncompleteToolCallError, v as transportAbortError, w as createToolArgumentPreviewSchedule } from "./transport-stream-shared-zHll9BxO.mjs";
14
- import { n as providerReplayContextMatches, t as buildProviderReplayContext } from "./provider-replay-context-CJ_YvcEW.mjs";
8
+ import { o as stableStringify } from "./provider-error-CRhW7lkJ.mjs";
9
+ import { a as resolveModelSseDebugMode, d as isResponsesProviderTool, g as resolveResponsesTerminalStopReason, h as readResponsesReasoningTokens, i as resolveModelPayloadDebugMode, l as ResponsesOutputIdentityError, m as mapResponsesTerminalUsage, r as emitModelTransportDebug, u as hasOnlyResponsesFunctionTools } from "./diagnostics-CH8j2wIG.mjs";
10
+ import { o as redactSensitiveText } from "./transport-utils-03Qi0CN2.mjs";
11
+ import { i as resolveOpenAICompletionsCompat } from "./openai-completions-compat-CUollwl6.mjs";
12
+ import { s as transformTransportMessages } from "./host-policy-DZO3oPPk.mjs";
13
+ import { m as stripSystemPromptCacheBoundary, v as sortPromptCacheToolsByName } from "./simple-options-np1XPuhm.mjs";
14
+ import { M as redactIdentifier, N as sha256Hex, b as createOpenAIProviderAcceptanceHook, d as prepareOpenAITools, h as resolveOpenAIRequestReasoning, u as resolveOpenAIStrictToolFlagWithDiagnostics, w as log, y as createModelStreamCooperativeScheduler } from "./openai-transport-params-DZKOTSfH.mjs";
15
+ import { E as parseStreamingJson, O as shortHash, _ as sanitizeTransportPayloadText, b as withProviderResponseHook, g as sanitizeNonEmptyTransportPayloadText, h as parseTerminalToolCallArguments, l as finalizeTransportStream, s as failTransportStream, t as IncompleteToolCallError, v as transportAbortError, w as createToolArgumentPreviewSchedule, x as parseJsonObjectPreservingUnsafeIntegers } from "./transport-stream-shared-B5RioB_Q.mjs";
16
+ import { n as providerReplayContextMatches, t as buildProviderReplayContext } from "./provider-replay-context-DPr3w20a.mjs";
15
17
  import { t as notifyLlmRequestActivity } from "./llm-request-activity-BjtkplhG.mjs";
16
- import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-2hfrquuz.mjs";
17
- import { t as transformProviderMessages } from "./provider-transcript-transform-V5YzU9zh.mjs";
18
- import { C as supportsOpenAITemperature, a as OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE, b as resolveOpenAIReasoningEffortForModel, c as OPENAI_RESPONSES_RETAINED_COMPACTION_REPLAY_TYPE, f as RESPONSE_FAILED_NO_DETAILS_MESSAGE, o as OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY, s as OPENAI_RESPONSES_REASONING_REPLAY_META_KEY, y as resolveOpenAIModelReasoningEfforts } from "./openai-responses-contracts-DDOHA62Y.mjs";
19
- import { a as resolveOpenAIProjectedToolsStrictToolFlag, r as normalizeOpenAIStrictToolParameters } from "./openai-tool-schema-CzjyYXun.mjs";
20
- import { n as isOpenAIResponsesCompactionOutput, r as readOpenAIResponsesCompactionWindow } from "./openai-responses-compaction-window-CIhBAkkq.mjs";
18
+ import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-BeptfRL6.mjs";
19
+ import { t as transformProviderMessages } from "./provider-transcript-transform-BTocjCRs.mjs";
20
+ import { a as resolveOpenAIProjectedToolsStrictToolFlag, f as withPreparedToolSchemaNormalization, r as normalizeOpenAIStrictToolParameters } from "./openai-tool-schema-D4BMcj2D.mjs";
21
+ import { a as OPENAI_RESPONSES_COMPACTION_REPLAY_TYPE, c as OPENAI_RESPONSES_RETAINED_COMPACTION_REPLAY_TYPE, f as RESPONSE_FAILED_NO_DETAILS_MESSAGE, o as OPENAI_RESPONSES_REASONING_REPLAY_BLOCK_META_KEY, p as isPreviousResponseRejection, s as OPENAI_RESPONSES_REASONING_REPLAY_META_KEY } from "./openai-responses-contracts-DWrfMODE.mjs";
22
+ import { n as isOpenAIResponsesCompactionOutput, r as readOpenAIResponsesCompactionWindow } from "./openai-responses-compaction-window-BiNCT0bS.mjs";
23
+ import { n as registerSessionResourceCleanup } from "./session-resources-CkR4WWy1.mjs";
21
24
  import { createHash, randomUUID } from "node:crypto";
22
25
  //#region packages/ai/src/transports/openai-responses-replay.ts
23
26
  /** Resolves the assistant message id that can be replayed to OpenAI Responses. */
@@ -187,6 +190,199 @@ function buildOpenAIResponsesReasoningReplayMetadata(model, options) {
187
190
  };
188
191
  }
189
192
  //#endregion
193
+ //#region packages/ai/src/transports/openai-responses-reasoning-update.ts
194
+ function isConfigurationUpdate(value) {
195
+ return isRecord(value) && value.type === "configuration_update" && isRecord(value.reasoning) && typeof value.reasoning.effort === "string";
196
+ }
197
+ function isResponsesReasoningUpdateCompatible(request) {
198
+ const mode = isRecord(request.reasoning) ? request.reasoning.mode : void 0;
199
+ return request.model === "gpt-6-astra" && (mode === void 0 || mode === "standard") && (!isRecord(request.multi_agent) || request.multi_agent.enabled !== true) && request.truncation !== "auto" && (!Array.isArray(request.context_management) || !request.context_management.some((item) => isRecord(item) && item.type === "compaction"));
200
+ }
201
+ function supportsResponsesReasoningUpdate(request) {
202
+ return isResponsesReasoningUpdateCompatible(request) && isRecord(request.reasoning) && typeof request.reasoning.effort === "string";
203
+ }
204
+ function canReferenceResponsesReasoningHistory(previous, request) {
205
+ return !previous.input?.some(isConfigurationUpdate) || isResponsesReasoningUpdateCompatible(request);
206
+ }
207
+ /** Rehydrate input controls only provisionally; continuation must validate the full prefix. */
208
+ function replayResponsesReasoningUpdates(previous, request, previousOutputLength, steering) {
209
+ if (steering !== "required-input" && (!supportsResponsesReasoningUpdate(previous) || !supportsResponsesReasoningUpdate(request)) || !Array.isArray(previous.input) || !Array.isArray(request.input) || request.input.some(isConfigurationUpdate)) return request;
210
+ const input = [...request.input];
211
+ let activeEffort = isRecord(previous.reasoning) ? previous.reasoning.effort : void 0;
212
+ for (const [index, item] of previous.input.entries()) if (isConfigurationUpdate(item)) {
213
+ input.splice(index, 0, item);
214
+ activeEffort = item.reasoning.effort;
215
+ }
216
+ if (steering === "required-input") return input.length === request.input.length ? request : {
217
+ ...request,
218
+ input
219
+ };
220
+ if (!isRecord(previous.reasoning) || !isRecord(request.reasoning) || typeof request.reasoning.effort !== "string") return request;
221
+ if (activeEffort !== request.reasoning.effort && steering !== "automatic") {
222
+ const baselineLength = previous.input.length + previousOutputLength;
223
+ const nextUser = input.findIndex((item, index) => index >= baselineLength && "role" in item && item.role === "user");
224
+ if (nextUser === -1) return request;
225
+ input.splice(nextUser, 0, {
226
+ type: "configuration_update",
227
+ reasoning: { effort: request.reasoning.effort }
228
+ });
229
+ }
230
+ if (input.length === request.input.length && activeEffort === request.reasoning.effort) return request;
231
+ return {
232
+ ...request,
233
+ reasoning: {
234
+ ...request.reasoning,
235
+ effort: previous.reasoning.effort
236
+ },
237
+ input
238
+ };
239
+ }
240
+ //#endregion
241
+ //#region packages/ai/src/transports/openai-responses-continuation.ts
242
+ const HTTP_CONTINUATION_IDLE_TTL_MS = 3e5;
243
+ const TURN_HEADERS = /* @__PURE__ */ new Set([
244
+ "traceparent",
245
+ "x-openclaw-turn-id",
246
+ "x-openclaw-turn-attempt"
247
+ ]);
248
+ function jsonValuesEqual(left, right) {
249
+ const leftJson = JSON.stringify(left);
250
+ const normalizedLeft = stableStringify(JSON.parse(leftJson));
251
+ const rightJson = JSON.stringify(right);
252
+ return leftJson === rightJson || normalizedLeft === stableStringify(JSON.parse(rightJson));
253
+ }
254
+ function requestWithoutInput(request) {
255
+ const { input: _input, previous_response_id: _previousResponseId, instructions: _instructions, tools: _tools, ...rest } = request;
256
+ if (!isRecord(rest.metadata)) return rest;
257
+ const metadata = Object.fromEntries(Object.entries(rest.metadata).filter(([key]) => key !== "openclaw_turn_id" && key !== "openclaw_turn_attempt"));
258
+ return {
259
+ ...rest,
260
+ metadata
261
+ };
262
+ }
263
+ function normalizeAssistantReplayInput(input, fromResponse = false) {
264
+ return input.map((item) => {
265
+ if (!isRecord(item)) return item;
266
+ if (item.type === "reasoning") return { type: "reasoning" };
267
+ if (item.type !== "function_call" && !(item.type === "message" && item.role === "assistant")) return item;
268
+ const { id: _id, status: _status, ...stableItem } = item;
269
+ if (fromResponse && item.type === "function_call") {
270
+ const args = parseJsonObjectPreservingUnsafeIntegers(stableItem.arguments);
271
+ stableItem.arguments = args ? JSON.stringify(args) : stableItem.arguments;
272
+ }
273
+ if (item.type === "message" && Array.isArray(stableItem.content)) stableItem.content = stableItem.content.map((part) => {
274
+ if (!isRecord(part) || part.type !== "output_text") return part;
275
+ const { annotations: _annotations, logprobs: _logprobs, ...stablePart } = part;
276
+ return stablePart;
277
+ });
278
+ return stableItem;
279
+ });
280
+ }
281
+ function responsesContinuationRequestFingerprint(request) {
282
+ const serialized = JSON.stringify(requestWithoutInput(request));
283
+ return sha256Hex(stableStringify(JSON.parse(serialized)));
284
+ }
285
+ function responsesContinuationPrefixFingerprint(input, output = []) {
286
+ const serialized = JSON.stringify([...normalizeAssistantReplayInput(input), ...normalizeAssistantReplayInput(output, true)]);
287
+ return sha256Hex(stableStringify(JSON.parse(serialized)));
288
+ }
289
+ function resolveResponsesContinuationRequest(continuation, request, steering) {
290
+ if (!continuation) return {
291
+ request,
292
+ continuationStatus: "no_previous_response"
293
+ };
294
+ if (request.previous_response_id) return {
295
+ request,
296
+ continuationStatus: "explicit_previous_response_id"
297
+ };
298
+ if (!canReferenceResponsesReasoningHistory(continuation.lastRequest, request)) return {
299
+ request,
300
+ continuationStatus: "request_changed"
301
+ };
302
+ const prepared = replayResponsesReasoningUpdates(continuation.lastRequest, request, continuation.lastResponseItems.length, steering);
303
+ if (steering !== "required-input" && !jsonValuesEqual(requestWithoutInput(prepared), requestWithoutInput(continuation.lastRequest))) return {
304
+ request,
305
+ continuationStatus: "request_changed"
306
+ };
307
+ const currentInput = prepared.input ?? [];
308
+ const previousInput = continuation.lastRequest.input ?? [];
309
+ const baselineLength = previousInput.length + continuation.lastResponseItems.length;
310
+ if (currentInput.length < baselineLength) return {
311
+ request,
312
+ continuationStatus: "history_shorter"
313
+ };
314
+ if (!jsonValuesEqual(normalizeAssistantReplayInput(currentInput.slice(0, previousInput.length)), normalizeAssistantReplayInput(previousInput)) || !jsonValuesEqual(normalizeAssistantReplayInput(currentInput.slice(previousInput.length, baselineLength)), normalizeAssistantReplayInput(continuation.lastResponseItems, true))) return {
315
+ request,
316
+ continuationStatus: "history_changed"
317
+ };
318
+ return {
319
+ request: {
320
+ ...prepared,
321
+ previous_response_id: continuation.lastResponseId,
322
+ input: currentInput.slice(baselineLength)
323
+ },
324
+ ...prepared !== request ? { fullRequest: prepared } : {},
325
+ continuationStatus: "continued"
326
+ };
327
+ }
328
+ const httpContinuationEntries = /* @__PURE__ */ new Map();
329
+ function deleteHttpContinuationIfOwned(key, entry) {
330
+ if (httpContinuationEntries.get(key) === entry) httpContinuationEntries.delete(key);
331
+ }
332
+ function connectionIdentity(params) {
333
+ const headers = Object.entries(resolveAiTransportHeaderSentinels(params.headers) ?? {}).map(([name, value]) => [name.toLowerCase(), value]).filter(([name]) => !TURN_HEADERS.has(name)).toSorted(([a], [b]) => a.localeCompare(b));
334
+ return sha256Hex(JSON.stringify([
335
+ getAiTransportHost().resolveSecretSentinel(params.apiKey),
336
+ params.baseUrl,
337
+ headers
338
+ ]));
339
+ }
340
+ function claimOpenAIResponsesHttpContinuation(params) {
341
+ const key = `${params.sessionId}\0${connectionIdentity(params)}`;
342
+ const previous = httpContinuationEntries.get(key);
343
+ if (previous?.kind === "claimed") return;
344
+ if (previous?.kind === "ready") clearTimeout(previous.idleTimer);
345
+ const claimed = {
346
+ kind: "claimed",
347
+ sessionId: params.sessionId
348
+ };
349
+ httpContinuationEntries.set(key, claimed);
350
+ try {
351
+ const request = previous?.kind === "ready" ? params.request : params.restoreRequest?.() ?? params.request;
352
+ const resolved = resolveResponsesContinuationRequest(previous?.kind === "ready" ? previous.state : void 0, request);
353
+ const fullRequest = resolved.fullRequest ?? request;
354
+ return {
355
+ request: params.request.store === false ? fullRequest : resolved.request,
356
+ fullRequest,
357
+ commit: (effectiveRequest, response) => {
358
+ if (httpContinuationEntries.get(key) !== claimed) return;
359
+ const ready = {
360
+ ...claimed,
361
+ kind: "ready",
362
+ state: {
363
+ lastRequest: effectiveRequest,
364
+ lastResponseId: response.id,
365
+ lastResponseItems: response.output
366
+ },
367
+ idleTimer: setTimeout(() => deleteHttpContinuationIfOwned(key, ready), HTTP_CONTINUATION_IDLE_TTL_MS)
368
+ };
369
+ ready.idleTimer.unref?.();
370
+ httpContinuationEntries.set(key, ready);
371
+ },
372
+ release: () => deleteHttpContinuationIfOwned(key, claimed)
373
+ };
374
+ } catch (error) {
375
+ deleteHttpContinuationIfOwned(key, claimed);
376
+ throw error;
377
+ }
378
+ }
379
+ registerSessionResourceCleanup((sessionId) => {
380
+ for (const [key, entry] of httpContinuationEntries) if (!sessionId || entry.sessionId === sessionId) {
381
+ if (entry.kind === "ready") clearTimeout(entry.idleTimer);
382
+ httpContinuationEntries.delete(key);
383
+ }
384
+ });
385
+ //#endregion
190
386
  //#region packages/ai/src/transports/openai-responses-input-replay.ts
191
387
  function recordResponsesInputReplay(message, replay) {
192
388
  if (replay) Object.assign(message, { openclawResponsesInputReplay: replay });
@@ -605,325 +801,148 @@ function convertProviderResponsesMessages(model, context, allowedToolCallProvide
605
801
  return convertResponsesMessagesWithStyle(model, context, allowedToolCallProviders, options, "provider");
606
802
  }
607
803
  //#endregion
608
- //#region packages/ai/src/transports/openai-responses-replay-internal.ts
609
- function isAsyncIterable(value) {
610
- return (typeof value === "object" && value !== null || typeof value === "function") && Symbol.asyncIterator in value;
611
- }
612
- function isInvalidEncryptedContentError(error) {
613
- if (!error || typeof error !== "object") return false;
614
- const record = error;
615
- if (record.code === "invalid_encrypted_content" || record.code === "thinking_signature_invalid") return true;
616
- const message = typeof record.message === "string" ? record.message.toLowerCase() : "";
617
- return message.includes("invalid_encrypted_content") || message.includes("thinking_signature_invalid") || (record.status === 400 || record.status == null && /(?:^|[\s(])400(?:[\s):]|$)/.test(message)) && (message.includes("could not decrypt the provided encrypted_content") || message.includes("encrypted content") && (message.includes("could not be verified") || message.includes("could not be decrypted or parsed")));
618
- }
619
- function isOrphanedFunctionCallOutputError(error) {
620
- if (!error || typeof error !== "object") return false;
621
- const record = error;
622
- const message = typeof record.message === "string" ? record.message : "";
623
- return /No tool call found for function call output with call_id [A-Za-z0-9_-]+/.test(message);
624
- }
625
- function commitResponsesEncryptedContentAttempt(attempt, commit) {
626
- if (attempt.kind === "compaction-stripped") commit(attempt.rejectedCompaction);
627
- }
628
- function stripResponsesRequestEncryptedReasoning(request) {
629
- const stripped = stripEncryptedReasoningContentFields(request.input);
630
- if (!stripped.changed) return request;
631
- return {
632
- ...request,
633
- input: stripped.value
634
- };
804
+ //#region packages/ai/src/transports/openai-responses-context-usage.ts
805
+ const TOOL_CALL_PROVIDERS = /* @__PURE__ */ new Set([
806
+ "openai",
807
+ "opencode",
808
+ "azure-openai-responses",
809
+ "github-copilot"
810
+ ]);
811
+ function inputReplay(message) {
812
+ const value = "openclawResponsesInputReplay" in message ? message.openclawResponsesInputReplay : void 0;
813
+ return isRecord(value) ? value : void 0;
814
+ }
815
+ function contextFingerprint(input, output = []) {
816
+ const reasoning = [...input, ...output].flatMap((item) => {
817
+ if (!isRecord(item) || item.type !== "reasoning") return [];
818
+ const { id: _id, status: _status, ...content } = item;
819
+ return [content];
820
+ });
821
+ return sha256Hex(stableStringify({
822
+ prefix: responsesContinuationPrefixFingerprint(input, output),
823
+ reasoning
824
+ }));
635
825
  }
636
- function stripResponsesRequestCompaction(request) {
637
- if (!Array.isArray(request.input)) return request;
638
- const input = request.input.filter((item) => !(item !== null && typeof item === "object" && item.type === "compaction"));
639
- return input.length === request.input.length ? request : {
640
- ...request,
641
- input
826
+ /** Bind measured usage to the admitted replay prefix, without copying its content. */
827
+ function recordResponsesContextUsage(message, model, identity, request, output, projection) {
828
+ const usage = message.usage.contextUsage;
829
+ if (usage?.state !== "available" || !Number.isSafeInteger(usage.totalTokens) || usage.totalTokens <= 0 || message.stopReason === "error" || message.stopReason === "aborted" || message.providerReplay || request.previous_response_id || !Array.isArray(request.input) || !request.input.some((item) => isRecord(item) && item.type === "compaction") || !Array.isArray(output) || output.some((item) => isRecord(item) && item.type === "compaction")) return;
830
+ const replayOutput = (projection === "transport" ? convertResponsesMessages$1 : convertProviderResponsesMessages)(model, { messages: [message] }, TOOL_CALL_PROVIDERS, {
831
+ ...identity,
832
+ includeSystemPrompt: false
833
+ }).filter((item) => item.type !== "function_call_output");
834
+ const firstInput = request.input[0];
835
+ const contextUsage = {
836
+ ...buildProviderReplayContext(model, identity),
837
+ projection,
838
+ includeSystemPrompt: request.instructions === void 0 && firstInput?.type === "message" && (firstInput.role === "developer" || firstInput.role === "system"),
839
+ prefixHash: contextFingerprint(request.input, replayOutput),
840
+ prefixLength: request.input.length + replayOutput.length,
841
+ promptTokens: usage.promptTokens,
842
+ totalTokens: usage.totalTokens
642
843
  };
844
+ Object.assign(message, { openclawResponsesInputReplay: {
845
+ ...inputReplay(message),
846
+ contextUsage
847
+ } });
643
848
  }
644
- function readOpenAIResponsesCompactionRejection(request) {
645
- if (!Array.isArray(request.input)) return;
646
- const item = request.input.find((candidate) => candidate !== null && typeof candidate === "object" && candidate.type === "compaction" && typeof candidate.encrypted_content === "string");
647
- return item ? {
648
- data: item.encrypted_content,
649
- ...typeof item.id === "string" ? { id: item.id } : {}
650
- } : void 0;
651
- }
652
- async function resolveNextResponsesEncryptedContentAttempt(attempt, error, options) {
653
- const orphanedFunctionOutput = isOrphanedFunctionCallOutputError(error);
654
- if (!isInvalidEncryptedContentError(error) && !orphanedFunctionOutput || attempt.kind === "compaction-stripped") return;
655
- if (!orphanedFunctionOutput && (attempt.kind === "initial" || attempt.kind === "continuation-rejected")) {
656
- const reasoningStripped = stripResponsesRequestEncryptedReasoning(attempt.request);
657
- if (reasoningStripped !== attempt.request) return {
658
- kind: "reasoning-stripped",
659
- request: reasoningStripped
849
+ /** Only matching provider input may replace the conservative local pressure estimate. */
850
+ function resolveResponsesContextUsageBoundary(messages, model, identity, systemPrompt) {
851
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
852
+ const message = messages[index];
853
+ if (!message || !isAssistant(message)) continue;
854
+ const state = inputReplay(message)?.contextUsage;
855
+ const usage = message.usage.contextUsage;
856
+ if (!isRecord(state) || usage?.state !== "available") continue;
857
+ const { projection, prefixHash, prefixLength, promptTokens, totalTokens, includeSystemPrompt } = state;
858
+ if (!isOpenAIResponsesReplayContext(state) || !providerReplayContextMatches(state, buildProviderReplayContext(model, identity)) || message.provider !== model.provider || message.api !== model.api || message.model !== model.id || projection !== "transport" && projection !== "provider" || typeof prefixHash !== "string" || typeof prefixLength !== "number" || !Number.isSafeInteger(prefixLength) || prefixLength <= 0 || promptTokens !== usage.promptTokens || totalTokens !== usage.totalTokens || !Number.isSafeInteger(usage.totalTokens) || usage.totalTokens <= 0) return;
859
+ const input = (projection === "transport" ? convertResponsesMessages$1 : convertProviderResponsesMessages)(model, {
860
+ messages: messages.filter(isProviderMessage),
861
+ systemPrompt
862
+ }, TOOL_CALL_PROVIDERS, {
863
+ ...identity,
864
+ includeSystemPrompt: includeSystemPrompt === true
865
+ });
866
+ if (input.length < prefixLength || contextFingerprint(input.slice(0, prefixLength)) !== prefixHash) return;
867
+ return {
868
+ index,
869
+ totalTokens: usage.totalTokens,
870
+ suffix: input.slice(prefixLength)
660
871
  };
661
872
  }
662
- const locallyStripped = stripResponsesRequestCompaction(attempt.request);
663
- if (locallyStripped === attempt.request) return;
664
- let compactionStripped = options?.buildFullHistoryRequest ? await options.buildFullHistoryRequest() : locallyStripped;
665
- compactionStripped = stripResponsesRequestCompaction(compactionStripped);
666
- if (attempt.kind === "reasoning-stripped") compactionStripped = stripResponsesRequestEncryptedReasoning(compactionStripped);
667
- return {
668
- kind: "compaction-stripped",
669
- request: compactionStripped,
670
- rejectedCompaction: readOpenAIResponsesCompactionRejection(attempt.request)
671
- };
672
873
  }
673
- async function createResponsesStreamWithEncryptedContentRetry(params) {
674
- const send = async (initialAttempt) => {
675
- let attempt = initialAttempt;
676
- for (;;) {
677
- params.observePrompt?.(attempt.request, {
678
- egress: "responses-sdk",
679
- payloadVariant: attempt.kind
680
- });
681
- try {
682
- const { data, response } = await params.client.responses.create(attempt.request, params.requestOptions).withResponse();
683
- commitResponsesEncryptedContentAttempt(attempt, (checkpoint) => {
684
- if (checkpoint) params.onCompactionRejected?.(checkpoint);
685
- });
686
- if (!isAsyncIterable(data)) throw new Error("OpenAI Responses streaming request returned a non-stream response");
687
- return {
688
- stream: data,
689
- response,
690
- attempt
691
- };
692
- } catch (error) {
693
- let nextAttempt = await resolveNextResponsesEncryptedContentAttempt(attempt, error, { buildFullHistoryRequest: params.buildFullHistoryRequest });
694
- if (!nextAttempt && attempt.request.previous_response_id && error && typeof error === "object" && typeof error.status === "number" && error.code === "previous_response_not_found") {
695
- const request = { ...params.buildFullHistoryRequest ? await params.buildFullHistoryRequest() : attempt.request };
696
- delete request.previous_response_id;
697
- nextAttempt = {
698
- kind: "continuation-rejected",
699
- request
700
- };
701
- }
702
- if (!nextAttempt) throw error;
703
- const retryDescription = nextAttempt.kind === "reasoning-stripped" ? "without encrypted reasoning content" : nextAttempt.kind === "compaction-stripped" ? "without encrypted compaction content" : "full history after rejected previous_response_id";
704
- log.warn(`[responses] retrying ${retryDescription} provider=${params.model.provider} api=${params.model.api} model=${params.model.id}`);
705
- attempt = nextAttempt;
706
- }
707
- }
708
- };
709
- const result = await send({
710
- kind: params.initialAttemptKind ?? "initial",
711
- request: params.request,
712
- ...params.initialRejectedCompaction ? { rejectedCompaction: params.initialRejectedCompaction } : {}
713
- });
714
- return {
715
- ...result,
716
- stream: { async *[Symbol.asyncIterator]() {
717
- let current = result;
718
- for (;;) {
719
- let rejectedEvent;
720
- try {
721
- for await (const event of params.wrapStream?.(current) ?? current.stream) {
722
- if (isRecord(event)) {
723
- const failure = event.type === "response.failed" && isRecord(event.response) ? event.response.error : event.type === "error" ? event.error ?? event : void 0;
724
- if (isRecord(failure) && params.canRetryStream?.() === true && isInvalidEncryptedContentError(failure)) {
725
- rejectedEvent = event;
726
- const message = typeof failure.message === "string" ? failure.message : "";
727
- throw Object.assign(new Error(message), {
728
- code: failure.code,
729
- status: failure.status
730
- });
731
- }
732
- }
733
- yield event;
734
- }
735
- return;
736
- } catch (error) {
737
- const nextAttempt = params.canRetryStream?.() === true && !params.requestOptions?.signal?.aborted ? await resolveNextResponsesEncryptedContentAttempt(current.attempt, error, { buildFullHistoryRequest: params.buildFullHistoryRequest }) : void 0;
738
- if (!nextAttempt) {
739
- if (rejectedEvent !== void 0) {
740
- yield rejectedEvent;
741
- return;
742
- }
743
- throw error;
744
- }
745
- log.warn(`[responses] retrying streamed encrypted content provider=${params.model.provider} api=${params.model.api} model=${params.model.id}`);
746
- current = await send(nextAttempt);
747
- }
748
- }
749
- } }
750
- };
874
+ function isAssistant(message) {
875
+ return message.role === "assistant";
751
876
  }
752
- function resolveAzureOpenAIApiVersion(env = process.env) {
753
- return env.AZURE_OPENAI_API_VERSION?.trim() || "preview";
877
+ function isProviderMessage(message) {
878
+ return message.role === "user" || message.role === "assistant" || message.role === "toolResult";
754
879
  }
755
880
  //#endregion
756
- //#region packages/ai/src/providers/openai-responses-stream-compat.ts
757
- const OPENAI_RESPONSES_OUTPUT_TEXT_CONTENT_PART_TYPE = "output_text";
758
- const AZURE_RESPONSES_TEXT_CONTENT_PART_TYPE = "text";
759
- const OPENAI_RESPONSES_OUTPUT_TEXT_DELTA_EVENT_TYPE = "response.output_text.delta";
760
- const AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE = "response.text.delta";
761
- function isResponsesTextContentPartType(type) {
762
- return type === "output_text" || type === "text";
763
- }
764
- function isResponsesTextDeltaEventType(type) {
765
- return type === "response.output_text.delta" || type === "response.text.delta";
881
+ //#region packages/ai/src/transports/openai-responses-debug.ts
882
+ function stringifyUnknown(value, fallback = "") {
883
+ if (typeof value === "string") return value;
884
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
885
+ return fallback;
766
886
  }
767
- function isAzureResponsesTextDeltaEventType(type) {
768
- return type === AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE;
887
+ function safeDebugValue(value) {
888
+ if (typeof value === "string") return value;
889
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
890
+ if (value === null) return "null";
891
+ if (value === void 0) return "undefined";
892
+ return Array.isArray(value) ? "array" : typeof value;
769
893
  }
770
- function isAzureResponsesTextDeltaEvent(event) {
771
- return isAzureResponsesTextDeltaEventType(event.type) && typeof event.delta === "string";
894
+ function responseInputTextChars(input) {
895
+ if (typeof input === "string") return input.length;
896
+ if (Array.isArray(input)) return input.reduce((total, item) => total + responseInputTextChars(item), 0);
897
+ if (!input || typeof input !== "object") return 0;
898
+ const record = input;
899
+ let total = 0;
900
+ if (typeof record.text === "string") total += record.text.length;
901
+ if (typeof record.content === "string") total += record.content.length;
902
+ else if (Array.isArray(record.content)) total += responseInputTextChars(record.content);
903
+ return total;
772
904
  }
773
- function resolveResponsesMessageSnapshotCollapse(params) {
774
- const { prior, nextText } = params;
775
- if (!prior?.text || !nextText || prior.phase !== params.nextPhase) return { kind: "keep" };
776
- if (nextText.length > prior.text.length && nextText.startsWith(prior.text)) return {
777
- kind: "extend",
778
- text: nextText
779
- };
780
- return { kind: "keep" };
905
+ function responseInputRoles(input) {
906
+ if (!Array.isArray(input)) return "";
907
+ const roles = /* @__PURE__ */ new Set();
908
+ for (const item of input) if (item && typeof item === "object") {
909
+ const role = item.role;
910
+ if (typeof role === "string" && role.trim()) roles.add(role.trim());
911
+ }
912
+ return [...roles].toSorted().join(",");
781
913
  }
782
- //#endregion
783
- //#region packages/ai/src/providers/openai-responses-tool-call-tracker.ts
784
- function readOutputIndex(event) {
785
- return typeof event.output_index === "number" && Number.isInteger(event.output_index) && event.output_index >= 0 ? event.output_index : void 0;
914
+ function responseInputItemShape(input) {
915
+ if (!Array.isArray(input)) return "none";
916
+ return input.map((item) => {
917
+ if (!isRecord(item) || typeof item.type !== "string") return "unknown";
918
+ if (item.type === "message" && typeof item.role === "string") return `message:${item.role}`;
919
+ return item.type;
920
+ }).join(",") || "none";
786
921
  }
787
- function readEventIdentity(event) {
788
- return { itemId: normalizeOptionalString(event.item_id) };
922
+ function hashOpaqueResponsesValue(value) {
923
+ return createHash("sha256").update(value).digest("hex");
789
924
  }
790
- function readResponsesToolCallItemIdentity(item) {
791
- return {
792
- itemId: normalizeOptionalString(item.id),
793
- callId: normalizeOptionalString(item.call_id)
794
- };
795
- }
796
- function createResponsesToolCallTracker() {
797
- const indexedCalls = /* @__PURE__ */ new Map();
798
- const unindexedCalls = /* @__PURE__ */ new Set();
799
- const identitiesConflict = (state, identity) => Boolean(state.itemId && identity.itemId && state.itemId !== identity.itemId || state.callId && identity.callId && state.callId !== identity.callId);
800
- const sharesIdentity = (state, identity) => Boolean(state.itemId && identity.itemId && state.itemId === identity.itemId || state.callId && identity.callId && state.callId === identity.callId);
801
- const adoptIdentity = (state, identity) => {
802
- state.itemId ??= identity.itemId;
803
- state.callId ??= identity.callId;
804
- return state;
805
- };
806
- const resolveCompatible = (candidates, identity, allowUnmatchedIdentity) => {
807
- const uniqueCandidates = [...new Set(candidates)];
808
- if (!identity.itemId && !identity.callId) return allowUnmatchedIdentity && uniqueCandidates.length === 1 ? uniqueCandidates.at(0) : void 0;
809
- const compatible = uniqueCandidates.filter((state) => !identitiesConflict(state, identity));
810
- const matches = compatible.filter((state) => sharesIdentity(state, identity));
811
- const matched = matches.length === 1 ? matches.at(0) : void 0;
812
- if (matched) return adoptIdentity(matched, identity);
813
- const soleCompatible = allowUnmatchedIdentity && uniqueCandidates.length === 1 && compatible.length === 1 && matches.length === 0 ? compatible.at(0) : void 0;
814
- return soleCompatible ? adoptIdentity(soleCompatible, identity) : void 0;
815
- };
816
- return {
817
- register(event, state) {
818
- const outputIndex = readOutputIndex(event);
819
- if (outputIndex === void 0) {
820
- unindexedCalls.add(state);
821
- return;
822
- }
823
- if (indexedCalls.has(outputIndex)) throw new Error(`Responses stream reused active tool-call output index ${outputIndex}`);
824
- state.outputIndex = outputIndex;
825
- indexedCalls.set(outputIndex, state);
826
- },
827
- resolve(event, identity = readEventIdentity(event), allowUnmatchedIdentity = true) {
828
- const outputIndex = readOutputIndex(event);
829
- if (outputIndex !== void 0) {
830
- const indexed = indexedCalls.get(outputIndex);
831
- if (indexed) {
832
- if (indexed.callId && identity.callId && indexed.callId !== identity.callId) return;
833
- return adoptIdentity(indexed, identity);
834
- }
835
- const unindexed = resolveCompatible(unindexedCalls, identity, allowUnmatchedIdentity);
836
- if (unindexed) {
837
- unindexedCalls.delete(unindexed);
838
- unindexed.outputIndex = outputIndex;
839
- indexedCalls.set(outputIndex, unindexed);
840
- }
841
- return unindexed;
842
- }
843
- return resolveCompatible([...indexedCalls.values(), ...unindexedCalls], identity, allowUnmatchedIdentity);
844
- },
845
- forget(toolCall) {
846
- for (const [outputIndex, tracked] of indexedCalls) if (tracked === toolCall) indexedCalls.delete(outputIndex);
847
- unindexedCalls.delete(toolCall);
848
- },
849
- markArgumentsUnreliable() {
850
- for (const toolCall of /* @__PURE__ */ new Set([...indexedCalls.values(), ...unindexedCalls])) toolCall.argumentStreamReliable = false;
851
- },
852
- hasActive() {
853
- return indexedCalls.size > 0 || unindexedCalls.size > 0;
854
- },
855
- hasExactlyActive(expected) {
856
- const active = /* @__PURE__ */ new Set([...indexedCalls.values(), ...unindexedCalls]);
857
- return active.size === expected.length && expected.every((state) => active.has(state));
858
- }
859
- };
860
- }
861
- //#endregion
862
- //#region packages/ai/src/transports/openai-responses-debug.ts
863
- function stringifyUnknown(value, fallback = "") {
864
- if (typeof value === "string") return value;
865
- if (typeof value === "number" || typeof value === "boolean") return String(value);
866
- return fallback;
867
- }
868
- function safeDebugValue(value) {
869
- if (typeof value === "string") return value;
870
- if (typeof value === "number" || typeof value === "boolean") return String(value);
871
- if (value === null) return "null";
872
- if (value === void 0) return "undefined";
873
- return Array.isArray(value) ? "array" : typeof value;
874
- }
875
- function responseInputTextChars(input) {
876
- if (typeof input === "string") return input.length;
877
- if (Array.isArray(input)) return input.reduce((total, item) => total + responseInputTextChars(item), 0);
878
- if (!input || typeof input !== "object") return 0;
879
- const record = input;
880
- let total = 0;
881
- if (typeof record.text === "string") total += record.text.length;
882
- if (typeof record.content === "string") total += record.content.length;
883
- else if (Array.isArray(record.content)) total += responseInputTextChars(record.content);
884
- return total;
885
- }
886
- function responseInputRoles(input) {
887
- if (!Array.isArray(input)) return "";
888
- const roles = /* @__PURE__ */ new Set();
889
- for (const item of input) if (item && typeof item === "object") {
890
- const role = item.role;
891
- if (typeof role === "string" && role.trim()) roles.add(role.trim());
892
- }
893
- return [...roles].toSorted().join(",");
894
- }
895
- function responseInputItemShape(input) {
896
- if (!Array.isArray(input)) return "none";
897
- return input.map((item) => {
898
- if (!isRecord(item) || typeof item.type !== "string") return "unknown";
899
- if (item.type === "message" && typeof item.role === "string") return `message:${item.role}`;
900
- return item.type;
901
- }).join(",") || "none";
902
- }
903
- function hashOpaqueResponsesValue(value) {
904
- return createHash("sha256").update(value).digest("hex");
905
- }
906
- function summarizeResponsesCompactionItems(input) {
907
- if (!Array.isArray(input)) return [
908
- "compactionItems=0",
909
- "compactionIdHashes=none",
910
- "compactionPayloadHashes=none",
911
- "compactionInputIndexes=none"
912
- ];
913
- const compactions = input.flatMap((item, inputIndex) => {
914
- if (!isRecord(item) || item.type !== "compaction") return [];
915
- return [{
916
- idHash: typeof item.id === "string" ? hashOpaqueResponsesValue(item.id) : void 0,
917
- inputIndex,
918
- payloadHash: typeof item.encrypted_content === "string" ? hashOpaqueResponsesValue(item.encrypted_content) : void 0
919
- }];
920
- });
921
- return [
922
- `compactionItems=${compactions.length}`,
923
- `compactionIdHashes=${compactions.flatMap((item) => item.idHash ?? []).join(",") || "none"}`,
924
- `compactionPayloadHashes=${compactions.flatMap((item) => item.payloadHash ?? []).join(",") || "none"}`,
925
- `compactionInputIndexes=${compactions.map((item) => item.inputIndex).join(",") || "none"}`
926
- ];
925
+ function summarizeResponsesCompactionItems(input) {
926
+ if (!Array.isArray(input)) return [
927
+ "compactionItems=0",
928
+ "compactionIdHashes=none",
929
+ "compactionPayloadHashes=none",
930
+ "compactionInputIndexes=none"
931
+ ];
932
+ const compactions = input.flatMap((item, inputIndex) => {
933
+ if (!isRecord(item) || item.type !== "compaction") return [];
934
+ return [{
935
+ idHash: typeof item.id === "string" ? hashOpaqueResponsesValue(item.id) : void 0,
936
+ inputIndex,
937
+ payloadHash: typeof item.encrypted_content === "string" ? hashOpaqueResponsesValue(item.encrypted_content) : void 0
938
+ }];
939
+ });
940
+ return [
941
+ `compactionItems=${compactions.length}`,
942
+ `compactionIdHashes=${compactions.flatMap((item) => item.idHash ?? []).join(",") || "none"}`,
943
+ `compactionPayloadHashes=${compactions.flatMap((item) => item.payloadHash ?? []).join(",") || "none"}`,
944
+ `compactionInputIndexes=${compactions.map((item) => item.inputIndex).join(",") || "none"}`
945
+ ];
927
946
  }
928
947
  function readToolPayloadField(record, field) {
929
948
  try {
@@ -1036,131 +1055,382 @@ function collectResponseFailedIdentifierHashes(value, opts = {}) {
1036
1055
  }
1037
1056
  return out;
1038
1057
  }
1039
- function redactResponseFailedDiagnosticValue(value, opts = {}) {
1040
- const key = opts.key ?? "";
1041
- const depth = opts.depth ?? 0;
1042
- if (typeof value === "string" || typeof value === "number") return key && isResponseFailedIdentifierKey(key) ? redactIdentifier(String(value), { len: 12 }) : value;
1043
- if (depth > 6 || !value || typeof value !== "object") return value;
1044
- const seen = opts.seen ?? /* @__PURE__ */ new WeakSet();
1045
- if (seen.has(value)) return "<circular>";
1046
- seen.add(value);
1047
- if (Array.isArray(value)) return value.slice(0, 16).map((item) => redactResponseFailedDiagnosticValue(item, {
1048
- key,
1049
- depth: depth + 1,
1050
- seen
1051
- }));
1052
- const out = {};
1053
- for (const [childKey, child] of Object.entries(value)) out[childKey] = redactResponseFailedDiagnosticValue(child, {
1054
- key: childKey,
1055
- depth: depth + 1,
1056
- seen
1057
- });
1058
- return out;
1058
+ function redactResponseFailedDiagnosticValue(value, opts = {}) {
1059
+ const key = opts.key ?? "";
1060
+ const depth = opts.depth ?? 0;
1061
+ if (typeof value === "string" || typeof value === "number") return key && isResponseFailedIdentifierKey(key) ? redactIdentifier(String(value), { len: 12 }) : value;
1062
+ if (depth > 6 || !value || typeof value !== "object") return value;
1063
+ const seen = opts.seen ?? /* @__PURE__ */ new WeakSet();
1064
+ if (seen.has(value)) return "<circular>";
1065
+ seen.add(value);
1066
+ if (Array.isArray(value)) return value.slice(0, 16).map((item) => redactResponseFailedDiagnosticValue(item, {
1067
+ key,
1068
+ depth: depth + 1,
1069
+ seen
1070
+ }));
1071
+ const out = {};
1072
+ for (const [childKey, child] of Object.entries(value)) out[childKey] = redactResponseFailedDiagnosticValue(child, {
1073
+ key: childKey,
1074
+ depth: depth + 1,
1075
+ seen
1076
+ });
1077
+ return out;
1078
+ }
1079
+ function buildResponsesFailedFailureFields(response) {
1080
+ if (!response) return {};
1081
+ const fields = {};
1082
+ for (const key of RESPONSE_FAILED_FAILURE_FIELD_KEYS) if (response[key] !== void 0 && response[key] !== null) fields[key] = response[key];
1083
+ return fields;
1084
+ }
1085
+ function buildResponsesFailedNoDetailsObservation(event, model, response = isRecord(event.response) ? event.response : void 0) {
1086
+ const failureFields = redactResponseFailedDiagnosticValue(buildResponsesFailedFailureFields(response));
1087
+ const metadataKeys = isRecord(response?.metadata) ? Object.keys(response.metadata).toSorted() : [];
1088
+ const responsePreview = {
1089
+ id: readResponseFailedString(response, "id"),
1090
+ status: readResponseFailedString(response, "status"),
1091
+ model: readResponseFailedString(response, "model"),
1092
+ object: readResponseFailedString(response, "object"),
1093
+ failureFields,
1094
+ metadataKeys
1095
+ };
1096
+ return {
1097
+ event: "openai_responses_response_failed_without_details",
1098
+ provider: model.provider,
1099
+ api: model.api,
1100
+ transportModel: model.id,
1101
+ providerRuntimeFailureKind: "no_error_details",
1102
+ responseId: responsePreview.id,
1103
+ responseStatus: responsePreview.status,
1104
+ responseModel: responsePreview.model,
1105
+ responseObject: responsePreview.object,
1106
+ metadataKeys,
1107
+ requestIdHashes: collectResponseFailedIdentifierHashes(event),
1108
+ failureFieldsPreview: stringifyRedactedEvent(failureFields),
1109
+ responsePreview: stringifyRedactedEvent(responsePreview)
1110
+ };
1111
+ }
1112
+ function summarizeResponsesFailedNoDetailsObservation(observation) {
1113
+ const requestIds = observation.requestIdHashes.join(",");
1114
+ const metadataKeys = observation.metadataKeys.join(",");
1115
+ return `responseId=${safeDebugValue(observation.responseId || void 0)} responseStatus=${safeDebugValue(observation.responseStatus || void 0)} responseModel=${safeDebugValue(observation.responseModel || void 0)} requestIds=${requestIds || "none"} metadataKeys=${metadataKeys || "none"} failureFields=${observation.failureFieldsPreview}`;
1116
+ }
1117
+ function normalizeResponsesFailedEvent(event, model) {
1118
+ const response = isRecord(event.response) ? event.response : void 0;
1119
+ const responseId = readResponseFailedString(response, "id") || void 0;
1120
+ const error = isRecord(response?.error) ? response.error : void 0;
1121
+ if (error) {
1122
+ const code = readResponseFailedString(error, "code").trim();
1123
+ const message = readResponseFailedString(error, "message").trim();
1124
+ if (code || message) return buildResponsesFailedEventSummary(`${code || "unknown"}: ${message || "no message"}`, responseId, code || void 0);
1125
+ }
1126
+ const incompleteReason = readResponseFailedString(isRecord(response?.incomplete_details) ? response.incomplete_details : void 0, "reason");
1127
+ if (incompleteReason) return buildResponsesFailedEventSummary(`incomplete: ${incompleteReason}`, responseId);
1128
+ return buildResponsesFailedEventSummary(RESPONSE_FAILED_NO_DETAILS_MESSAGE, responseId, void 0, buildResponsesFailedNoDetailsObservation(event, model, response));
1129
+ }
1130
+ var ResponsesStreamFailure = class extends Error {
1131
+ constructor(failure, response) {
1132
+ super(failure.message);
1133
+ this.name = "ResponsesStreamFailure";
1134
+ this.responseId = failure.responseId;
1135
+ this.response = response;
1136
+ this.code = failure.code;
1137
+ this.observation = failure.observation;
1138
+ }
1139
+ };
1140
+ function logResponsesFailedNoDetails(observation) {
1141
+ log.warn(`[responses] response.failed missing error details provider=${observation.provider} api=${observation.api} model=${observation.transportModel} ` + summarizeResponsesFailedNoDetailsObservation(observation), observation);
1142
+ }
1143
+ function summarizeResponsesPayload(params) {
1144
+ if (!params || typeof params !== "object") return "payload=non-object";
1145
+ const record = params;
1146
+ const input = record.input;
1147
+ const reasoning = record.reasoning && typeof record.reasoning === "object" ? record.reasoning : void 0;
1148
+ const text = record.text && typeof record.text === "object" ? record.text : void 0;
1149
+ const parts = [
1150
+ `fields=${Object.keys(record).toSorted().join(",")}`,
1151
+ `model=${safeDebugValue(record.model)}`,
1152
+ `stream=${safeDebugValue(record.stream)}`,
1153
+ `inputItems=${Array.isArray(input) ? input.length : typeof input}`,
1154
+ `inputItemShape=${responseInputItemShape(input)}`,
1155
+ `inputRoles=${responseInputRoles(input) || "none"}`,
1156
+ `inputTextChars=${responseInputTextChars(input)}`,
1157
+ `tools=${summarizeResponsesTools(record.tools)}`,
1158
+ `reasoningEffort=${safeDebugValue(reasoning?.effort)}`,
1159
+ `reasoningSummary=${safeDebugValue(reasoning?.summary)}`,
1160
+ `textVerbosity=${safeDebugValue(text?.verbosity)}`,
1161
+ `serviceTier=${safeDebugValue(record.service_tier)}`,
1162
+ ...summarizeResponsesCompactionItems(input),
1163
+ `store=${safeDebugValue(record.store)}`,
1164
+ `promptCacheKey=${record.prompt_cache_key === void 0 ? "absent" : "present"}`,
1165
+ `metadataKeys=${record.metadata && typeof record.metadata === "object" ? Object.keys(record.metadata).toSorted().join(",") : "none"}`
1166
+ ];
1167
+ if (resolveModelPayloadDebugMode() === "full-redacted") parts.push(`payload=${stringifyRedactedPayload(record)}`);
1168
+ return parts.join(" ");
1169
+ }
1170
+ function summarizeOpenAITransportError(error) {
1171
+ if (!error || typeof error !== "object") return `type=${typeof error} message=${safeDebugValue(error)}`;
1172
+ const record = error;
1173
+ const cause = record.cause && typeof record.cause === "object" ? record.cause : void 0;
1174
+ return [
1175
+ `name=${safeDebugValue(record.name)}`,
1176
+ `status=${safeDebugValue(record.status)}`,
1177
+ `code=${safeDebugValue(record.code)}`,
1178
+ `type=${safeDebugValue(record.type)}`,
1179
+ `causeName=${safeDebugValue(cause?.name)}`,
1180
+ `causeCode=${safeDebugValue(cause?.code)}`,
1181
+ `message=${error instanceof Error ? error.message : safeDebugValue(error)}`
1182
+ ].join(" ");
1183
+ }
1184
+ //#endregion
1185
+ //#region packages/ai/src/transports/openai-responses-replay-internal.ts
1186
+ function isAsyncIterable(value) {
1187
+ return (typeof value === "object" && value !== null || typeof value === "function") && Symbol.asyncIterator in value;
1188
+ }
1189
+ function isInvalidEncryptedContentError(error) {
1190
+ if (!error || typeof error !== "object") return false;
1191
+ const record = error;
1192
+ if (record.code === "invalid_encrypted_content" || record.code === "thinking_signature_invalid") return true;
1193
+ const message = typeof record.message === "string" ? record.message.toLowerCase() : "";
1194
+ return message.includes("invalid_encrypted_content") || message.includes("thinking_signature_invalid") || (record.status === 400 || record.status == null && /(?:^|[\s(])400(?:[\s):]|$)/.test(message)) && (message.includes("could not decrypt the provided encrypted_content") || message.includes("encrypted content") && (message.includes("could not be verified") || message.includes("could not be decrypted or parsed")));
1195
+ }
1196
+ function isOrphanedFunctionCallOutputError(error) {
1197
+ if (!error || typeof error !== "object") return false;
1198
+ const record = error;
1199
+ const message = typeof record.message === "string" ? record.message : "";
1200
+ return /No tool call found for function call output with call_id [A-Za-z0-9_-]+/.test(message);
1201
+ }
1202
+ function commitResponsesEncryptedContentAttempt(attempt, commit) {
1203
+ if (attempt.kind === "compaction-stripped") commit(attempt.rejectedCompaction);
1204
+ }
1205
+ function stripResponsesRequestEncryptedReasoning(request) {
1206
+ const stripped = stripEncryptedReasoningContentFields(request.input);
1207
+ if (!stripped.changed) return request;
1208
+ return {
1209
+ ...request,
1210
+ input: stripped.value
1211
+ };
1212
+ }
1213
+ function stripResponsesRequestCompaction(request) {
1214
+ if (!Array.isArray(request.input)) return request;
1215
+ const input = request.input.filter((item) => !(item !== null && typeof item === "object" && item.type === "compaction"));
1216
+ return input.length === request.input.length ? request : {
1217
+ ...request,
1218
+ input
1219
+ };
1220
+ }
1221
+ function readOpenAIResponsesCompactionRejection(request) {
1222
+ if (!Array.isArray(request.input)) return;
1223
+ const item = request.input.find((candidate) => candidate !== null && typeof candidate === "object" && candidate.type === "compaction" && typeof candidate.encrypted_content === "string");
1224
+ return item ? {
1225
+ data: item.encrypted_content,
1226
+ ...typeof item.id === "string" ? { id: item.id } : {}
1227
+ } : void 0;
1228
+ }
1229
+ async function resolveNextResponsesEncryptedContentAttempt(attempt, error, options) {
1230
+ const orphanedFunctionOutput = isOrphanedFunctionCallOutputError(error);
1231
+ if (!isInvalidEncryptedContentError(error) && !orphanedFunctionOutput || attempt.kind === "compaction-stripped") return;
1232
+ if (!orphanedFunctionOutput && (attempt.kind === "initial" || attempt.kind === "continuation-rejected")) {
1233
+ const reasoningStripped = stripResponsesRequestEncryptedReasoning(attempt.request);
1234
+ if (reasoningStripped !== attempt.request) return {
1235
+ kind: "reasoning-stripped",
1236
+ request: reasoningStripped
1237
+ };
1238
+ }
1239
+ const locallyStripped = stripResponsesRequestCompaction(attempt.request);
1240
+ if (locallyStripped === attempt.request) return;
1241
+ let compactionStripped = options?.buildFullHistoryRequest ? await options.buildFullHistoryRequest() : locallyStripped;
1242
+ compactionStripped = stripResponsesRequestCompaction(compactionStripped);
1243
+ if (attempt.kind === "reasoning-stripped") compactionStripped = stripResponsesRequestEncryptedReasoning(compactionStripped);
1244
+ return {
1245
+ kind: "compaction-stripped",
1246
+ request: compactionStripped,
1247
+ rejectedCompaction: readOpenAIResponsesCompactionRejection(attempt.request)
1248
+ };
1249
+ }
1250
+ async function createResponsesStreamWithEncryptedContentRetry(params) {
1251
+ const send = async (initialAttempt) => {
1252
+ let attempt = initialAttempt;
1253
+ for (;;) {
1254
+ params.observePrompt?.(attempt.request, {
1255
+ egress: "responses-sdk",
1256
+ payloadVariant: attempt.kind
1257
+ });
1258
+ try {
1259
+ const { data, response } = await params.client.responses.create(attempt.request, params.requestOptions).withResponse();
1260
+ commitResponsesEncryptedContentAttempt(attempt, (checkpoint) => {
1261
+ if (checkpoint) params.onCompactionRejected?.(checkpoint);
1262
+ });
1263
+ if (!isAsyncIterable(data)) throw new Error("OpenAI Responses streaming request returned a non-stream response");
1264
+ return {
1265
+ stream: data,
1266
+ response,
1267
+ attempt
1268
+ };
1269
+ } catch (error) {
1270
+ let nextAttempt = await resolveNextResponsesEncryptedContentAttempt(attempt, error, { buildFullHistoryRequest: params.buildFullHistoryRequest });
1271
+ if (!nextAttempt && attempt.request.previous_response_id && error && typeof error === "object" && typeof error.status === "number" && isPreviousResponseRejection(error)) {
1272
+ const request = { ...params.buildFullHistoryRequest ? await params.buildFullHistoryRequest() : attempt.request };
1273
+ delete request.previous_response_id;
1274
+ nextAttempt = {
1275
+ kind: "continuation-rejected",
1276
+ request
1277
+ };
1278
+ }
1279
+ if (!nextAttempt) throw error;
1280
+ const retryDescription = nextAttempt.kind === "reasoning-stripped" ? "without encrypted reasoning content" : nextAttempt.kind === "compaction-stripped" ? "without encrypted compaction content" : "full history after rejected previous_response_id";
1281
+ log.warn(`[responses] retrying ${retryDescription} provider=${params.model.provider} api=${params.model.api} model=${params.model.id}`);
1282
+ attempt = nextAttempt;
1283
+ }
1284
+ }
1285
+ };
1286
+ const result = await send({
1287
+ kind: params.initialAttemptKind ?? "initial",
1288
+ request: params.request,
1289
+ ...params.initialRejectedCompaction ? { rejectedCompaction: params.initialRejectedCompaction } : {}
1290
+ });
1291
+ return { stream: { async *[Symbol.asyncIterator]() {
1292
+ let current = result;
1293
+ for (;;) {
1294
+ let rejectedEvent;
1295
+ try {
1296
+ for await (const event of params.wrapStream?.(current) ?? current.stream) {
1297
+ if (isRecord(event)) {
1298
+ const failure = event.type === "response.failed" && isRecord(event.response) ? event.response.error : event.type === "error" ? event.error ?? event : void 0;
1299
+ if (isRecord(failure) && params.canRetryStream?.() === true && isInvalidEncryptedContentError(failure)) {
1300
+ rejectedEvent = event;
1301
+ const message = typeof failure.message === "string" ? failure.message : "";
1302
+ throw Object.assign(new Error(message), {
1303
+ code: failure.code,
1304
+ status: failure.status
1305
+ });
1306
+ }
1307
+ }
1308
+ yield event;
1309
+ }
1310
+ return;
1311
+ } catch (error) {
1312
+ const nextAttempt = params.canRetryStream?.() === true && !params.requestOptions?.signal?.aborted ? await resolveNextResponsesEncryptedContentAttempt(current.attempt, error, { buildFullHistoryRequest: params.buildFullHistoryRequest }) : void 0;
1313
+ if (!nextAttempt) {
1314
+ if (rejectedEvent !== void 0) {
1315
+ yield rejectedEvent;
1316
+ return;
1317
+ }
1318
+ throw error;
1319
+ }
1320
+ log.warn(`[responses] retrying streamed encrypted content provider=${params.model.provider} api=${params.model.api} model=${params.model.id}`);
1321
+ current = await send(nextAttempt);
1322
+ }
1323
+ }
1324
+ } } };
1325
+ }
1326
+ function resolveAzureOpenAIApiVersion(env = process.env) {
1327
+ return env.AZURE_OPENAI_API_VERSION?.trim() || "preview";
1328
+ }
1329
+ //#endregion
1330
+ //#region packages/ai/src/providers/openai-responses-stream-compat.ts
1331
+ const OPENAI_RESPONSES_OUTPUT_TEXT_CONTENT_PART_TYPE = "output_text";
1332
+ const AZURE_RESPONSES_TEXT_CONTENT_PART_TYPE = "text";
1333
+ const OPENAI_RESPONSES_OUTPUT_TEXT_DELTA_EVENT_TYPE = "response.output_text.delta";
1334
+ const AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE = "response.text.delta";
1335
+ function isResponsesTextContentPartType(type) {
1336
+ return type === "output_text" || type === "text";
1337
+ }
1338
+ function isResponsesTextDeltaEventType(type) {
1339
+ return type === "response.output_text.delta" || type === "response.text.delta";
1059
1340
  }
1060
- function buildResponsesFailedFailureFields(response) {
1061
- if (!response) return {};
1062
- const fields = {};
1063
- for (const key of RESPONSE_FAILED_FAILURE_FIELD_KEYS) if (response[key] !== void 0 && response[key] !== null) fields[key] = response[key];
1064
- return fields;
1341
+ function isAzureResponsesTextDeltaEventType(type) {
1342
+ return type === AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE;
1065
1343
  }
1066
- function buildResponsesFailedNoDetailsObservation(event, model, response = isRecord(event.response) ? event.response : void 0) {
1067
- const failureFields = redactResponseFailedDiagnosticValue(buildResponsesFailedFailureFields(response));
1068
- const metadataKeys = isRecord(response?.metadata) ? Object.keys(response.metadata).toSorted() : [];
1069
- const responsePreview = {
1070
- id: readResponseFailedString(response, "id"),
1071
- status: readResponseFailedString(response, "status"),
1072
- model: readResponseFailedString(response, "model"),
1073
- object: readResponseFailedString(response, "object"),
1074
- failureFields,
1075
- metadataKeys
1076
- };
1077
- return {
1078
- event: "openai_responses_response_failed_without_details",
1079
- provider: model.provider,
1080
- api: model.api,
1081
- transportModel: model.id,
1082
- providerRuntimeFailureKind: "no_error_details",
1083
- responseId: responsePreview.id,
1084
- responseStatus: responsePreview.status,
1085
- responseModel: responsePreview.model,
1086
- responseObject: responsePreview.object,
1087
- metadataKeys,
1088
- requestIdHashes: collectResponseFailedIdentifierHashes(event),
1089
- failureFieldsPreview: stringifyRedactedEvent(failureFields),
1090
- responsePreview: stringifyRedactedEvent(responsePreview)
1091
- };
1344
+ function isAzureResponsesTextDeltaEvent(event) {
1345
+ return isAzureResponsesTextDeltaEventType(event.type) && typeof event.delta === "string";
1092
1346
  }
1093
- function summarizeResponsesFailedNoDetailsObservation(observation) {
1094
- const requestIds = observation.requestIdHashes.join(",");
1095
- const metadataKeys = observation.metadataKeys.join(",");
1096
- return `responseId=${safeDebugValue(observation.responseId || void 0)} responseStatus=${safeDebugValue(observation.responseStatus || void 0)} responseModel=${safeDebugValue(observation.responseModel || void 0)} requestIds=${requestIds || "none"} metadataKeys=${metadataKeys || "none"} failureFields=${observation.failureFieldsPreview}`;
1347
+ function resolveResponsesMessageSnapshotCollapse(params) {
1348
+ const { prior, nextText } = params;
1349
+ if (!prior?.text || !nextText || prior.phase !== params.nextPhase) return { kind: "keep" };
1350
+ if (nextText.length > prior.text.length && nextText.startsWith(prior.text)) return {
1351
+ kind: "extend",
1352
+ text: nextText
1353
+ };
1354
+ return { kind: "keep" };
1097
1355
  }
1098
- function normalizeResponsesFailedEvent(event, model) {
1099
- const response = isRecord(event.response) ? event.response : void 0;
1100
- const responseId = readResponseFailedString(response, "id") || void 0;
1101
- const error = isRecord(response?.error) ? response.error : void 0;
1102
- if (error) {
1103
- const code = readResponseFailedString(error, "code").trim();
1104
- const message = readResponseFailedString(error, "message").trim();
1105
- if (code || message) return buildResponsesFailedEventSummary(`${code || "unknown"}: ${message || "no message"}`, responseId, code || void 0);
1106
- }
1107
- const incompleteReason = readResponseFailedString(isRecord(response?.incomplete_details) ? response.incomplete_details : void 0, "reason");
1108
- if (incompleteReason) return buildResponsesFailedEventSummary(`incomplete: ${incompleteReason}`, responseId);
1109
- return buildResponsesFailedEventSummary(RESPONSE_FAILED_NO_DETAILS_MESSAGE, responseId, void 0, buildResponsesFailedNoDetailsObservation(event, model, response));
1356
+ //#endregion
1357
+ //#region packages/ai/src/providers/openai-responses-tool-call-tracker.ts
1358
+ function readOutputIndex(event) {
1359
+ return typeof event.output_index === "number" && Number.isInteger(event.output_index) && event.output_index >= 0 ? event.output_index : void 0;
1110
1360
  }
1111
- var ResponsesStreamFailure = class extends Error {
1112
- constructor(failure, response) {
1113
- super(failure.message);
1114
- this.name = "ResponsesStreamFailure";
1115
- this.responseId = failure.responseId;
1116
- this.response = response;
1117
- this.code = failure.code;
1118
- this.observation = failure.observation;
1119
- }
1120
- };
1121
- function logResponsesFailedNoDetails(observation) {
1122
- log.warn(`[responses] response.failed missing error details provider=${observation.provider} api=${observation.api} model=${observation.transportModel} ` + summarizeResponsesFailedNoDetailsObservation(observation), observation);
1361
+ function readEventIdentity(event) {
1362
+ return { itemId: normalizeOptionalString(event.item_id) };
1123
1363
  }
1124
- function summarizeResponsesPayload(params) {
1125
- if (!params || typeof params !== "object") return "payload=non-object";
1126
- const record = params;
1127
- const input = record.input;
1128
- const reasoning = record.reasoning && typeof record.reasoning === "object" ? record.reasoning : void 0;
1129
- const text = record.text && typeof record.text === "object" ? record.text : void 0;
1130
- const parts = [
1131
- `fields=${Object.keys(record).toSorted().join(",")}`,
1132
- `model=${safeDebugValue(record.model)}`,
1133
- `stream=${safeDebugValue(record.stream)}`,
1134
- `inputItems=${Array.isArray(input) ? input.length : typeof input}`,
1135
- `inputItemShape=${responseInputItemShape(input)}`,
1136
- `inputRoles=${responseInputRoles(input) || "none"}`,
1137
- `inputTextChars=${responseInputTextChars(input)}`,
1138
- `tools=${summarizeResponsesTools(record.tools)}`,
1139
- `reasoningEffort=${safeDebugValue(reasoning?.effort)}`,
1140
- `reasoningSummary=${safeDebugValue(reasoning?.summary)}`,
1141
- `textVerbosity=${safeDebugValue(text?.verbosity)}`,
1142
- `serviceTier=${safeDebugValue(record.service_tier)}`,
1143
- ...summarizeResponsesCompactionItems(input),
1144
- `store=${safeDebugValue(record.store)}`,
1145
- `promptCacheKey=${record.prompt_cache_key === void 0 ? "absent" : "present"}`,
1146
- `metadataKeys=${record.metadata && typeof record.metadata === "object" ? Object.keys(record.metadata).toSorted().join(",") : "none"}`
1147
- ];
1148
- if (resolveModelPayloadDebugMode() === "full-redacted") parts.push(`payload=${stringifyRedactedPayload(record)}`);
1149
- return parts.join(" ");
1364
+ function readResponsesToolCallItemIdentity(item) {
1365
+ return {
1366
+ itemId: normalizeOptionalString(item.id),
1367
+ callId: normalizeOptionalString(item.call_id)
1368
+ };
1150
1369
  }
1151
- function summarizeOpenAITransportError(error) {
1152
- if (!error || typeof error !== "object") return `type=${typeof error} message=${safeDebugValue(error)}`;
1153
- const record = error;
1154
- const cause = record.cause && typeof record.cause === "object" ? record.cause : void 0;
1155
- return [
1156
- `name=${safeDebugValue(record.name)}`,
1157
- `status=${safeDebugValue(record.status)}`,
1158
- `code=${safeDebugValue(record.code)}`,
1159
- `type=${safeDebugValue(record.type)}`,
1160
- `causeName=${safeDebugValue(cause?.name)}`,
1161
- `causeCode=${safeDebugValue(cause?.code)}`,
1162
- `message=${error instanceof Error ? error.message : safeDebugValue(error)}`
1163
- ].join(" ");
1370
+ function createResponsesToolCallTracker() {
1371
+ const indexedCalls = /* @__PURE__ */ new Map();
1372
+ const unindexedCalls = /* @__PURE__ */ new Set();
1373
+ const identitiesConflict = (state, identity) => Boolean(state.itemId && identity.itemId && state.itemId !== identity.itemId || state.callId && identity.callId && state.callId !== identity.callId);
1374
+ const sharesIdentity = (state, identity) => Boolean(state.itemId && identity.itemId && state.itemId === identity.itemId || state.callId && identity.callId && state.callId === identity.callId);
1375
+ const adoptIdentity = (state, identity) => {
1376
+ state.itemId ??= identity.itemId;
1377
+ state.callId ??= identity.callId;
1378
+ return state;
1379
+ };
1380
+ const resolveCompatible = (candidates, identity, allowUnmatchedIdentity) => {
1381
+ const uniqueCandidates = [...new Set(candidates)];
1382
+ if (!identity.itemId && !identity.callId) return allowUnmatchedIdentity && uniqueCandidates.length === 1 ? uniqueCandidates.at(0) : void 0;
1383
+ const compatible = uniqueCandidates.filter((state) => !identitiesConflict(state, identity));
1384
+ const matches = compatible.filter((state) => sharesIdentity(state, identity));
1385
+ const matched = matches.length === 1 ? matches.at(0) : void 0;
1386
+ if (matched) return adoptIdentity(matched, identity);
1387
+ const soleCompatible = allowUnmatchedIdentity && uniqueCandidates.length === 1 && compatible.length === 1 && matches.length === 0 ? compatible.at(0) : void 0;
1388
+ return soleCompatible ? adoptIdentity(soleCompatible, identity) : void 0;
1389
+ };
1390
+ return {
1391
+ register(event, state) {
1392
+ const outputIndex = readOutputIndex(event);
1393
+ if (outputIndex === void 0) {
1394
+ unindexedCalls.add(state);
1395
+ return;
1396
+ }
1397
+ if (indexedCalls.has(outputIndex)) throw new Error(`Responses stream reused active tool-call output index ${outputIndex}`);
1398
+ state.outputIndex = outputIndex;
1399
+ indexedCalls.set(outputIndex, state);
1400
+ },
1401
+ resolve(event, identity = readEventIdentity(event), allowUnmatchedIdentity = true) {
1402
+ const outputIndex = readOutputIndex(event);
1403
+ if (outputIndex !== void 0) {
1404
+ const indexed = indexedCalls.get(outputIndex);
1405
+ if (indexed) {
1406
+ if (indexed.callId && identity.callId && indexed.callId !== identity.callId) return;
1407
+ return adoptIdentity(indexed, identity);
1408
+ }
1409
+ const unindexed = resolveCompatible(unindexedCalls, identity, allowUnmatchedIdentity);
1410
+ if (unindexed) {
1411
+ unindexedCalls.delete(unindexed);
1412
+ unindexed.outputIndex = outputIndex;
1413
+ indexedCalls.set(outputIndex, unindexed);
1414
+ }
1415
+ return unindexed;
1416
+ }
1417
+ return resolveCompatible([...indexedCalls.values(), ...unindexedCalls], identity, allowUnmatchedIdentity);
1418
+ },
1419
+ forget(toolCall) {
1420
+ for (const [outputIndex, tracked] of indexedCalls) if (tracked === toolCall) indexedCalls.delete(outputIndex);
1421
+ unindexedCalls.delete(toolCall);
1422
+ },
1423
+ markArgumentsUnreliable() {
1424
+ for (const toolCall of /* @__PURE__ */ new Set([...indexedCalls.values(), ...unindexedCalls])) toolCall.argumentStreamReliable = false;
1425
+ },
1426
+ hasActive() {
1427
+ return indexedCalls.size > 0 || unindexedCalls.size > 0;
1428
+ },
1429
+ hasExactlyActive(expected) {
1430
+ const active = /* @__PURE__ */ new Set([...indexedCalls.values(), ...unindexedCalls]);
1431
+ return active.size === expected.length && expected.every((state) => active.has(state));
1432
+ }
1433
+ };
1164
1434
  }
1165
1435
  //#endregion
1166
1436
  //#region packages/ai/src/transports/openai-responses-stream-observer-internal.ts
@@ -1205,8 +1475,12 @@ async function* observeResponsesStream(stream, model, requestStartedAt) {
1205
1475
  }
1206
1476
  //#endregion
1207
1477
  //#region packages/ai/src/transports/openai-responses-stream-slots-internal.ts
1208
- function createResponsesOutputTracker() {
1478
+ function createResponsesOutputTracker(params) {
1209
1479
  const outputs = /* @__PURE__ */ new Map();
1480
+ let currentEventType = "unknown";
1481
+ let providerToolObserved = false;
1482
+ let visibleTextEmitted = false;
1483
+ let terminalAllowsRetry = false;
1210
1484
  const identity = (item) => {
1211
1485
  if ((item.type === "reasoning" || item.type === "message") && item.id) return `${item.type}:${item.id}`;
1212
1486
  const callId = item.call_id ?? item.id;
@@ -1216,10 +1490,37 @@ function createResponsesOutputTracker() {
1216
1490
  const key = identity(item);
1217
1491
  const output = (outputIndex === void 0 ? void 0 : outputs.get(outputIndex)) ?? (key === void 0 ? void 0 : outputs.get(key));
1218
1492
  if (!output || outputIndex !== void 0 && output.outputIndex !== void 0 && output.outputIndex !== outputIndex) return;
1219
- if (output.type !== item.type || output.callId && item.call_id && output.callId !== item.call_id) throw new Error("Responses stream changed output item identity");
1493
+ if (output.type !== item.type || output.callId && item.call_id && output.callId !== item.call_id) throw new ResponsesOutputIdentityError({
1494
+ outputIndex,
1495
+ expectedType: output.type,
1496
+ actualType: item.type,
1497
+ completed: output.completed,
1498
+ completedToolCall: [...outputs.values()].some((candidate) => candidate.type === "function_call" && candidate.completed),
1499
+ eventType: currentEventType,
1500
+ retrySafe: params.canRetryIdentityConflict?.() === true && !providerToolObserved && !visibleTextEmitted && terminalAllowsRetry && !params.output.content.some((block) => block.type === "text" && block.text.length > 0)
1501
+ });
1220
1502
  return output;
1221
1503
  };
1222
1504
  return {
1505
+ trackStream(sink) {
1506
+ return { push(event) {
1507
+ visibleTextEmitted ||= event.type === "text_delta" && event.delta.length > 0 || event.type === "text_end" && event.content.length > 0;
1508
+ sink.push(event);
1509
+ } };
1510
+ },
1511
+ observeEvent(event) {
1512
+ currentEventType = event.type;
1513
+ terminalAllowsRetry = false;
1514
+ if (event.type === "response.output_item.added" || event.type === "response.output_item.done") providerToolObserved ||= isResponsesProviderTool(event.item);
1515
+ else if (event.type === "response.completed" || event.type === "response.incomplete") {
1516
+ let terminalHasRefusal = false;
1517
+ for (const item of event.response.output ?? []) {
1518
+ providerToolObserved ||= isResponsesProviderTool(item);
1519
+ terminalHasRefusal ||= item.type === "message" && (item.content ?? []).some((part) => part.type === "refusal");
1520
+ }
1521
+ terminalAllowsRetry = event.type === "response.completed" && event.response.status === "completed" && event.response.error == null && event.response.incomplete_details == null && !terminalHasRefusal;
1522
+ }
1523
+ },
1223
1524
  get,
1224
1525
  set(item, contentIndex, outputIndex, completed = false) {
1225
1526
  const output = get(item, outputIndex) ?? {
@@ -1278,6 +1579,11 @@ function createResponsesOutputSlotTracker() {
1278
1579
  const outputIndex = readResponsesOutputIndex(event);
1279
1580
  return outputIndex === void 0 ? unindexed : indexed.get(outputIndex);
1280
1581
  },
1582
+ resolveOutputItem(event, item) {
1583
+ if (item.type === "reasoning") return this.resolve(event, "thinking");
1584
+ if (item.type === "message") return this.resolve(event, "text");
1585
+ return readResponsesOutputIndex(event) === void 0 ? void 0 : this.get(event);
1586
+ },
1281
1587
  values() {
1282
1588
  return [.../* @__PURE__ */ new Set([...indexed.values(), ...unindexed ? [unindexed] : []])];
1283
1589
  },
@@ -1288,86 +1594,6 @@ function createResponsesOutputSlotTracker() {
1288
1594
  };
1289
1595
  }
1290
1596
  //#endregion
1291
- //#region packages/ai/src/providers/openai-responses-terminal-usage.ts
1292
- /**
1293
- * Canonical mapping for terminal OpenAI Responses events.
1294
- *
1295
- * `response.completed`, `response.incomplete`, and `response.failed` are terminal and can carry
1296
- * usage, so every Responses path finalizes through the helpers here. Keeping one owner prevents
1297
- * package and managed transports from drifting on token buckets, service-tier pricing, or future
1298
- * terminal-event semantics.
1299
- */
1300
- function readReportedCount(value) {
1301
- return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
1302
- }
1303
- function readCount(value) {
1304
- return readReportedCount(value) ?? 0;
1305
- }
1306
- /**
1307
- * Split a terminal usage payload into the priced buckets.
1308
- *
1309
- * OpenAI includes cache reads and writes in `input_tokens`, so both are subtracted out of the
1310
- * billable input bucket. `total_tokens` comes from the payload, but never below the sum of the
1311
- * split buckets: proxies routinely omit it (reporting 0 would understate the turn), and a payload
1312
- * whose `cached_tokens` exceeds `input_tokens` clamps the input bucket, leaving the reported total
1313
- * short of what the buckets actually price.
1314
- */
1315
- function mapResponsesTerminalUsage(usage) {
1316
- if (!usage) return;
1317
- const cacheRead = readCount(usage.input_tokens_details?.cached_tokens);
1318
- const cacheWrite = readCount(usage.input_tokens_details?.cache_write_tokens);
1319
- const input = Math.max(0, readCount(usage.input_tokens) - cacheRead - cacheWrite);
1320
- const output = readCount(usage.output_tokens);
1321
- const bucketTotal = input + output + cacheRead + cacheWrite;
1322
- const totalTokens = Math.max(bucketTotal, readCount(usage.total_tokens));
1323
- const reportedInput = readReportedCount(usage.input_tokens);
1324
- const reportedOutput = readReportedCount(usage.output_tokens);
1325
- const reportedTotal = readReportedCount(usage.total_tokens);
1326
- return {
1327
- input,
1328
- output,
1329
- cacheRead,
1330
- cacheWrite,
1331
- contextUsage: reportedInput !== void 0 && (reportedOutput !== void 0 || reportedTotal !== void 0 && reportedTotal >= reportedInput) && cacheRead + cacheWrite <= reportedInput ? {
1332
- state: "available",
1333
- promptTokens: reportedInput,
1334
- totalTokens: Math.max(totalTokens, reportedInput + (reportedOutput ?? 0))
1335
- } : { state: "unavailable" },
1336
- totalTokens
1337
- };
1338
- }
1339
- /** Reasoning tokens are reported by the agent path only; the package path does not track them. */
1340
- function readResponsesReasoningTokens(usage) {
1341
- return asFiniteNumber(usage?.output_tokens_details?.reasoning_tokens);
1342
- }
1343
- function mapResponsesTerminalStopReason(status) {
1344
- if (!status) return "stop";
1345
- switch (status) {
1346
- case "completed": return "stop";
1347
- case "incomplete": return "length";
1348
- case "failed":
1349
- case "cancelled": return "error";
1350
- case "in_progress":
1351
- case "queued": return "stop";
1352
- default: throw new Error(`Unhandled stop reason: ${String(status)}`);
1353
- }
1354
- }
1355
- /**
1356
- * Resolve the terminal stop reason, including the two overrides every Responses path shares: a
1357
- * content-filtered turn is a provider error rather than a truncated answer, and a turn that
1358
- * produced tool calls reports `toolUse` instead of a plain stop.
1359
- */
1360
- function resolveResponsesTerminalStopReason(params) {
1361
- const status = params.status ?? (params.terminalEventType === "response.incomplete" ? "incomplete" : void 0);
1362
- if (status === "incomplete" && params.incompleteReason === "content_filter") return {
1363
- stopReason: "error",
1364
- errorMessage: "Provider incomplete_reason: content_filter"
1365
- };
1366
- const stopReason = mapResponsesTerminalStopReason(status);
1367
- if (stopReason === "stop" && params.hasToolCall) return { stopReason: "toolUse" };
1368
- return { stopReason };
1369
- }
1370
- //#endregion
1371
1597
  //#region packages/ai/src/transports/openai-responses-stream-terminal-internal.ts
1372
1598
  function splitToolCallId(id) {
1373
1599
  const separator = id.indexOf("|");
@@ -1561,7 +1787,7 @@ function createResponsesTerminalController(params) {
1561
1787
  };
1562
1788
  const finalizeTerminalFacts = (response, responseId = response.id) => {
1563
1789
  output.responseId = responseId || output.responseId;
1564
- output.responseModel = response.model?.trim() || void 0;
1790
+ output.responseModel = options?.resolveResponseModel ? options.resolveResponseModel()?.trim() || void 0 : response.model?.trim() || void 0;
1565
1791
  const usage = mapResponsesTerminalUsage(response.usage);
1566
1792
  const reasoningTokens = readResponsesReasoningTokens(response.usage);
1567
1793
  if (usage) output.usage = {
@@ -1592,6 +1818,18 @@ function createResponsesTerminalController(params) {
1592
1818
  });
1593
1819
  output.stopReason = terminal.stopReason;
1594
1820
  output.errorMessage = terminal.errorMessage;
1821
+ if (terminalEventType === "response.completed" && typeof response.end_turn === "boolean") output.endTurn = response.end_turn;
1822
+ const incompleteReason = response.incomplete_details?.reason;
1823
+ appendAssistantMessageDiagnostic(output, {
1824
+ type: "openai_responses_terminal",
1825
+ timestamp: Date.now(),
1826
+ details: {
1827
+ eventType: terminalEventType,
1828
+ stopReason: terminal.stopReason,
1829
+ ...terminalEventType === "response.incomplete" ? { incompleteReason: incompleteReason === "max_output_tokens" || incompleteReason === "max_messages" || incompleteReason === "content_filter" || incompleteReason === "steered" ? incompleteReason : "unknown" } : {},
1830
+ endTurn: typeof response.end_turn === "boolean" ? response.end_turn : response.end_turn === void 0 ? "absent" : "invalid"
1831
+ }
1832
+ });
1595
1833
  };
1596
1834
  return {
1597
1835
  finalizeResponse,
@@ -1602,10 +1840,14 @@ function createResponsesTerminalController(params) {
1602
1840
  }
1603
1841
  //#endregion
1604
1842
  //#region packages/ai/src/transports/openai-responses-stream-internal.ts
1605
- async function processResponsesStream(openaiStream, output, stream, model, options) {
1843
+ async function processResponsesStream(openaiStream, output, sink, model, options) {
1606
1844
  const streamingToolCalls = createResponsesToolCallTracker();
1607
1845
  const outputSlots = createResponsesOutputSlotTracker();
1608
- const outputs = createResponsesOutputTracker();
1846
+ const outputs = createResponsesOutputTracker({
1847
+ output,
1848
+ canRetryIdentityConflict: options?.canRetryIdentityConflict
1849
+ });
1850
+ const stream = outputs.trackStream(sink);
1609
1851
  let terminalResponse;
1610
1852
  let incompleteToolCall;
1611
1853
  let lastTextBlock = null;
@@ -1664,11 +1906,6 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1664
1906
  return slot;
1665
1907
  }
1666
1908
  };
1667
- const resolveOutputItemSlot = (event, item) => {
1668
- if (item.type === "reasoning") return outputSlots.resolve(event, "thinking");
1669
- if (item.type === "message") return outputSlots.resolve(event, "text");
1670
- return readResponsesOutputIndex(event) === void 0 ? void 0 : outputSlots.get(event);
1671
- };
1672
1909
  const materializeDeferredTextSlot = (slot) => {
1673
1910
  if (slot.block || slot.pendingText === null) return;
1674
1911
  const text = slot.pendingText;
@@ -1784,6 +2021,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1784
2021
  }), options?.signal);
1785
2022
  try {
1786
2023
  for await (const event of guardedStream) {
2024
+ outputs.observeEvent(event);
1787
2025
  notifyLlmRequestActivity(options?.signal);
1788
2026
  if (event.type === "response.output_item.done" && event.item.type === "function_call" && event.item.status === "incomplete") incompleteToolCall ??= event.item;
1789
2027
  if (incompleteToolCall && event.type !== "response.completed" && event.type !== "response.incomplete" && event.type !== "response.failed" && event.type !== "error") continue;
@@ -1807,6 +2045,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1807
2045
  block: toolCallBlock,
1808
2046
  contentIndex,
1809
2047
  argumentStreamReliable: true,
2048
+ argumentsStreamed: false,
1810
2049
  previewSchedule: createToolArgumentPreviewSchedule(),
1811
2050
  ...readResponsesToolCallItemIdentity(item)
1812
2051
  };
@@ -1900,6 +2139,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1900
2139
  const toolCall = streamingToolCalls.resolve(event);
1901
2140
  if (toolCall) {
1902
2141
  toolCall.block.partialJson += event.delta;
2142
+ toolCall.argumentsStreamed = true;
1903
2143
  if (toolCall.previewSchedule(toolCall.block.partialJson.length)) toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
1904
2144
  stream.push({
1905
2145
  type: "toolcall_delta",
@@ -1917,6 +2157,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1917
2157
  toolCall.block.partialJson = doneArguments;
1918
2158
  toolCall.block.arguments = parseStreamingJson(toolCall.block.partialJson);
1919
2159
  toolCall.argumentStreamReliable = true;
2160
+ toolCall.argumentsStreamed = true;
1920
2161
  }
1921
2162
  if (doneArguments?.startsWith(previousPartialJson)) {
1922
2163
  const delta = doneArguments.slice(previousPartialJson.length);
@@ -1931,7 +2172,7 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1931
2172
  } else if (event.type === "response.output_item.done") {
1932
2173
  const item = event.item;
1933
2174
  if (item.type !== "message") lastTextBlock = null;
1934
- const existingOutputSlot = resolveOutputItemSlot(event, item);
2175
+ const existingOutputSlot = outputSlots.resolveOutputItem(event, item);
1935
2176
  materializeDeferredTextSlots(existingOutputSlot);
1936
2177
  const outputSlot = existingOutputSlot ?? createOutputSlot(event, item);
1937
2178
  compactionTracker.completed(item, blocks.length);
@@ -2012,9 +2253,11 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2012
2253
  if (!streamingToolCall && streamingToolCalls.hasActive()) continue;
2013
2254
  const completedArguments = typeof item.arguments === "string" ? item.arguments : void 0;
2014
2255
  if (streamingToolCall && !streamingToolCall.argumentStreamReliable && !completedArguments) continue;
2256
+ const streamedArguments = streamingToolCall?.block.partialJson || "";
2257
+ const parsedStreamedArguments = streamingToolCall?.argumentStreamReliable && streamingToolCall?.argumentsStreamed && streamedArguments.length > 0 && completedArguments !== void 0 && streamedArguments !== completedArguments ? parseJsonObjectPreservingUnsafeIntegers(streamedArguments) : null;
2015
2258
  const validated = resolveCompletedResponsesToolCall(item, {
2016
2259
  name: streamingToolCall?.block.name,
2017
- arguments: completedArguments || streamingToolCall?.block.partialJson || ""
2260
+ arguments: parsedStreamedArguments ?? (completedArguments || streamedArguments)
2018
2261
  });
2019
2262
  finalizeToolCall(item, readResponsesOutputIndex(event), streamingToolCall, validated);
2020
2263
  }
@@ -2036,8 +2279,15 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2036
2279
  terminalResponse = event.type === "response.completed" ? event.response : null;
2037
2280
  if (output.stopReason === "stop" && output.content.some((block) => block.type === "toolCall")) output.stopReason = "toolUse";
2038
2281
  break;
2039
- } else if (event.type === "error") throw new Error(event.message ? `Error Code ${event.code}: ${event.message}` : "Unknown error");
2040
- else if (event.type === "response.failed") {
2282
+ } else if (event.type === "error") {
2283
+ const details = isRecord(event) && isRecord(event.error) ? event.error : event;
2284
+ const message = readStringValue(details.message);
2285
+ const code = normalizeStringifiedOptionalString(details.code);
2286
+ throw Object.assign(new Error(message ? code ? `Error Code ${code}: ${message}` : message : "Unknown error"), {
2287
+ code: details.code,
2288
+ error: details
2289
+ });
2290
+ } else if (event.type === "response.failed") {
2041
2291
  const failure = normalizeResponsesFailedEvent(isRecord(event) ? event : {}, model);
2042
2292
  terminal.finalizeFailedResponse(event.response, failure.responseId);
2043
2293
  throw new ResponsesStreamFailure(failure, event.response);
@@ -2052,33 +2302,54 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2052
2302
  }
2053
2303
  }
2054
2304
  //#endregion
2305
+ //#region packages/ai/src/providers/openai-provider-refusal.ts
2306
+ /** Responses uses snake_case; the ChatGPT app-server error envelope uses camelCase. */
2307
+ function readOpenAIMisalignmentReview(value, continuationSupported) {
2308
+ if (!isRecord(value)) return;
2309
+ return readProviderRefusalReview({
2310
+ explanation: value.detailed_explanation ?? value.detailedExplanation,
2311
+ errorType: value.error_type ?? value.errorType,
2312
+ ...continuationSupported ? { continuation: value.steer } : {}
2313
+ });
2314
+ }
2315
+ //#endregion
2055
2316
  //#region packages/ai/src/providers/openai-responses-tools.ts
2056
2317
  /** Projects direct provider descriptors before resolving their strict policy. */
2057
2318
  function convertResponsesToolPayload(tools, options) {
2058
- return convertProjectedResponsesTools(projectOpenAITools(tools), resolveResponsesStrictToolSetting(options), options?.model);
2059
- }
2060
- /** Uses caller-prepared facts without rereading descriptors or resolving host policy again. */
2061
- function convertProjectedResponsesTools(projection, strictSetting, model) {
2062
- const strict = model ? resolveOpenAIStrictToolFlagWithDiagnostics(projection, strictSetting, {
2063
- transport: "responses",
2064
- model
2065
- }) : resolveOpenAIProjectedToolsStrictToolFlag(projection, strictSetting);
2066
- return sortPromptCacheToolsByName(projection.tools).map((tool) => {
2067
- const result = {
2068
- type: "function",
2069
- name: tool.name,
2070
- description: tool.description,
2071
- parameters: normalizeOpenAIStrictToolParameters(tool.parameters, strict === true, model?.compat)
2072
- };
2073
- if (strict !== void 0) result.strict = strict;
2074
- return result;
2319
+ return convertPreparedResponsesTools(prepareOpenAITools(tools), resolveResponsesStrictToolSetting(options), options?.model);
2320
+ }
2321
+ /** The transport has already resolved policy before descriptor projection. */
2322
+ function prepareResponsesTools(tools, strictSetting, model) {
2323
+ const prepared = prepareOpenAITools(tools);
2324
+ return {
2325
+ projection: prepared.projection,
2326
+ tools: convertPreparedResponsesTools(prepared, strictSetting, model)
2327
+ };
2328
+ }
2329
+ function convertPreparedResponsesTools(prepared, strictSetting, model) {
2330
+ const { projection, schemas } = prepared;
2331
+ return withPreparedToolSchemaNormalization(schemas, () => {
2332
+ const strict = model ? resolveOpenAIStrictToolFlagWithDiagnostics(projection, strictSetting, {
2333
+ transport: "responses",
2334
+ model
2335
+ }) : resolveOpenAIProjectedToolsStrictToolFlag(projection, strictSetting);
2336
+ return sortPromptCacheToolsByName(projection.tools).map((tool) => {
2337
+ const result = {
2338
+ type: "function",
2339
+ name: tool.name,
2340
+ description: tool.description,
2341
+ parameters: normalizeOpenAIStrictToolParameters(tool.parameters, strict === true, model?.compat)
2342
+ };
2343
+ if (strict !== void 0) result.strict = strict;
2344
+ return result;
2345
+ });
2075
2346
  });
2076
2347
  }
2077
2348
  function resolveResponsesStrictToolSetting(options) {
2078
2349
  if (options?.strict !== void 0) return options.strict;
2079
2350
  if (options?.model) return getAiTransportHost().resolveOpenAIStrictToolSetting(options.model, {
2080
2351
  transport: "stream",
2081
- supportsStrictMode: options.supportsStrictMode
2352
+ supportsStrictMode: options.supportsStrictMode ?? resolveOpenAICompletionsCompat(options.model).supportsStrictMode
2082
2353
  });
2083
2354
  return false;
2084
2355
  }
@@ -2099,19 +2370,6 @@ function applyResponsesServiceTierPricing(usage, serviceTier, model) {
2099
2370
  usage.cost.cacheWrite *= multiplier;
2100
2371
  usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
2101
2372
  }
2102
- function resolveResponsesReasoningEffort(model, reasoning) {
2103
- if (!reasoning) return;
2104
- const clampedReasoning = model.reasoning && model.thinkingLevelMap?.[reasoning] === void 0 && resolveOpenAIModelReasoningEfforts(model)?.includes(reasoning) ? reasoning : clampThinkingLevel(model, reasoning);
2105
- return clampedReasoning === "off" ? void 0 : clampedReasoning;
2106
- }
2107
- function resolveResponsesRequestReasoningEffort(model, reasoning) {
2108
- const mapped = model.thinkingLevelMap?.[reasoning === "none" ? "off" : reasoning];
2109
- if (mapped !== void 0) return mapped ?? void 0;
2110
- return resolveOpenAIModelReasoningEfforts(model) === void 0 ? reasoning === "off" ? "none" : reasoning : resolveOpenAIReasoningEffortForModel({
2111
- model,
2112
- effort: reasoning
2113
- });
2114
- }
2115
2373
  function applyCommonResponsesParams(params, model, context, options, config) {
2116
2374
  if (options?.maxTokens) params.max_output_tokens = Math.max(options.maxTokens, 16);
2117
2375
  if (options?.temperature !== void 0 && supportsOpenAITemperature(model)) params.temperature = options.temperature;
@@ -2121,10 +2379,10 @@ function applyCommonResponsesParams(params, model, context, options, config) {
2121
2379
  }
2122
2380
  if (!model.reasoning) return;
2123
2381
  const requestedEffort = options?.reasoningEffort ?? (options?.reasoningSummary ? "medium" : config?.setDefaultReasoningOff ?? true ? "off" : void 0);
2124
- const effort = requestedEffort === void 0 ? void 0 : resolveResponsesRequestReasoningEffort(model, requestedEffort);
2382
+ const effort = requestedEffort === void 0 ? void 0 : resolveOpenAIRequestReasoning(model, requestedEffort).effort;
2125
2383
  if (effort === void 0) return;
2126
2384
  params.reasoning = { effort };
2127
- if (options?.reasoningEffort || options?.reasoningSummary) {
2385
+ if (effort !== "none" && (options?.reasoningEffort || options?.reasoningSummary)) {
2128
2386
  params.reasoning.summary = options?.reasoningSummary || "auto";
2129
2387
  params.include = ["reasoning.encrypted_content"];
2130
2388
  }
@@ -2158,6 +2416,7 @@ async function runResponsesStreamLifecycle(params) {
2158
2416
  const firstEvent = createFirstStreamEventAbortController(options?.signal);
2159
2417
  firstEventAbort = firstEvent;
2160
2418
  let started = false;
2419
+ let admittedRequest;
2161
2420
  const { stream: hookedOpenAIStream } = await createResponsesStreamWithEncryptedContentRetry({
2162
2421
  client,
2163
2422
  request: requestParams,
@@ -2169,25 +2428,28 @@ async function runResponsesStreamLifecycle(params) {
2169
2428
  buildFullHistoryRequest: () => buildRequest("full-history"),
2170
2429
  onCompactionRejected: (checkpoint) => suppressOpenAIResponsesCompaction(output, model, options, checkpoint),
2171
2430
  canRetryStream: () => output.content.length === 0,
2172
- wrapStream: ({ stream: openaiStream, response }) => withProviderResponseHook({
2173
- stream: openaiStream,
2174
- signal: firstEvent.signal,
2175
- abort: firstEvent.abort,
2176
- hook: createOpenAIProviderAcceptanceHook(options, response, model),
2177
- onReady: () => {
2178
- if (!started) {
2179
- started = true;
2180
- stream.push({
2181
- type: "start",
2182
- partial: output
2183
- });
2431
+ wrapStream: ({ stream: openaiStream, response, attempt }) => {
2432
+ admittedRequest = attempt.kind === "initial" ? attempt.request : void 0;
2433
+ return withProviderResponseHook({
2434
+ stream: openaiStream,
2435
+ signal: firstEvent.signal,
2436
+ abort: firstEvent.abort,
2437
+ hook: createOpenAIProviderAcceptanceHook(options, response, model),
2438
+ onReady: () => {
2439
+ if (!started) {
2440
+ started = true;
2441
+ stream.push({
2442
+ type: "start",
2443
+ partial: output
2444
+ });
2445
+ }
2184
2446
  }
2185
- }
2186
- })
2447
+ });
2448
+ }
2187
2449
  });
2188
2450
  const firstEventTimeoutMs = getFirstStreamEventTimeoutMs(options);
2189
2451
  const onFirstEventTimeout = getFirstStreamEventTimeoutHandler(options);
2190
- await processResponsesStream(hookedOpenAIStream, output, stream, model, {
2452
+ const terminal = await processResponsesStream(hookedOpenAIStream, output, stream, model, {
2191
2453
  ...params.processStreamOptions || firstEventTimeoutMs !== void 0 || onFirstEventTimeout !== void 0 ? {
2192
2454
  ...params.processStreamOptions,
2193
2455
  firstEventTimeoutMs: params.processStreamOptions?.firstEventTimeoutMs ?? firstEventTimeoutMs,
@@ -2195,17 +2457,33 @@ async function runResponsesStreamLifecycle(params) {
2195
2457
  onFirstEventTimeout: params.processStreamOptions?.onFirstEventTimeout ?? onFirstEventTimeout,
2196
2458
  signal: params.processStreamOptions?.signal ?? options?.signal
2197
2459
  } : void 0,
2460
+ canRetryIdentityConflict: () => hasOnlyResponsesFunctionTools(admittedRequest),
2198
2461
  reasoningReplayMetadata: buildOpenAIResponsesReasoningReplayMetadata(model, {
2199
2462
  sessionId: options?.sessionId,
2200
2463
  authProfileId: options?.authProfileId
2201
2464
  })
2202
2465
  });
2466
+ if (terminal && admittedRequest && !options?.signal?.aborted) recordResponsesContextUsage(output, model, options, admittedRequest, terminal.output, "provider");
2203
2467
  finalizeTransportStream({
2204
2468
  stream,
2205
2469
  output,
2206
2470
  signal: options?.signal
2207
2471
  });
2208
2472
  } catch (error) {
2473
+ const response = error instanceof ResponsesStreamFailure ? error.response : error;
2474
+ const rawError = isRecord(response) && isRecord(response.error) ? response.error : response;
2475
+ if (params.model.provider === "openai" && params.model.api === "openai-responses" && isRecord(rawError) && rawError.code === "misalignment_policy_violation") {
2476
+ const review = readOpenAIMisalignmentReview(rawError.misalignment, false);
2477
+ appendAssistantMessageDiagnostic(output, {
2478
+ type: "provider_refusal",
2479
+ timestamp: Date.now(),
2480
+ details: {
2481
+ provider: "openai",
2482
+ category: "misalignment",
2483
+ ...review ? { review } : {}
2484
+ }
2485
+ });
2486
+ }
2209
2487
  failTransportStream({
2210
2488
  stream,
2211
2489
  output,
@@ -2218,4 +2496,4 @@ async function runResponsesStreamLifecycle(params) {
2218
2496
  }
2219
2497
  }
2220
2498
  //#endregion
2221
- export { resolveResponsesMessageSnapshotCollapse as A, responsesInputFingerprint as B, AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE as C, isAzureResponsesTextDeltaEventType as D, isAzureResponsesTextDeltaEvent as E, resolveNextResponsesEncryptedContentAttempt as F, resolveNewestOpenAIResponsesCompactionReplay as G, buildOpenAIResponsesReasoningReplayMetadata as H, buildResponsesInputMessage as I, suppressOpenAIResponsesCompaction as K, convertResponsesMessages$1 as L, createResponsesStreamWithEncryptedContentRetry as M, isInvalidEncryptedContentError as N, isResponsesTextContentPartType as O, resolveAzureOpenAIApiVersion as P, createOpenAIResponsesAssistantOutput as R, AZURE_RESPONSES_TEXT_CONTENT_PART_TYPE as S, OPENAI_RESPONSES_OUTPUT_TEXT_DELTA_EVENT_TYPE as T, captureOpenAIResponsesCompaction as U, CompactionReplayRefreshRequiredError as V, isOpenAIResponsesReplayContext as W, safeDebugValue as _, resolveResponsesReasoningEffort as a, createResponsesToolCallTracker as b, convertProjectedResponsesTools as c, mapResponsesTerminalUsage as d, readResponsesReasoningTokens as f, logResponsesFailedNoDetails as g, ResponsesStreamFailure as h, createResponsesAssistantOutput as i, commitResponsesEncryptedContentAttempt as j, isResponsesTextDeltaEventType as k, convertResponsesToolPayload as l, observeResponsesStream as m, applyResponsesServiceTierPricing as n, resolveResponsesRequestReasoningEffort as o, resolveResponsesTerminalStopReason as p, resolveReplayableResponsesMessageId as q, convertResponsesMessages as r, runResponsesStreamLifecycle as s, applyCommonResponsesParams as t, processResponsesStream as u, summarizeOpenAITransportError as v, OPENAI_RESPONSES_OUTPUT_TEXT_CONTENT_PART_TYPE as w, readResponsesToolCallItemIdentity as x, summarizeResponsesPayload as y, recordResponsesInputReplay as z };
2499
+ export { summarizeOpenAITransportError as A, resolveResponsesContinuationRequest as B, createResponsesStreamWithEncryptedContentRetry as C, ResponsesStreamFailure as D, resolveNextResponsesEncryptedContentAttempt as E, convertResponsesMessages$1 as F, supportsResponsesReasoningUpdate as G, responsesContinuationRequestFingerprint as H, createOpenAIResponsesAssistantOutput as I, captureOpenAIResponsesCompaction as J, CompactionReplayRefreshRequiredError as K, recordResponsesInputReplay as L, recordResponsesContextUsage as M, resolveResponsesContextUsageBoundary as N, logResponsesFailedNoDetails as O, buildResponsesInputMessage as P, resolveReplayableResponsesMessageId as Q, responsesInputFingerprint as R, commitResponsesEncryptedContentAttempt as S, resolveAzureOpenAIApiVersion as T, isConfigurationUpdate as U, responsesContinuationPrefixFingerprint as V, replayResponsesReasoningUpdates as W, resolveNewestOpenAIResponsesCompactionReplay as X, isOpenAIResponsesReplayContext as Y, suppressOpenAIResponsesCompaction as Z, isAzureResponsesTextDeltaEvent as _, runResponsesStreamLifecycle as a, isResponsesTextDeltaEventType as b, readOpenAIMisalignmentReview as c, createResponsesToolCallTracker as d, readResponsesToolCallItemIdentity as f, OPENAI_RESPONSES_OUTPUT_TEXT_DELTA_EVENT_TYPE as g, OPENAI_RESPONSES_OUTPUT_TEXT_CONTENT_PART_TYPE as h, createResponsesAssistantOutput as i, summarizeResponsesPayload as j, safeDebugValue as k, processResponsesStream as l, AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE as m, applyResponsesServiceTierPricing as n, convertResponsesToolPayload as o, AZURE_RESPONSES_TEXT_CONTENT_PART_TYPE as p, buildOpenAIResponsesReasoningReplayMetadata as q, convertResponsesMessages as r, prepareResponsesTools as s, applyCommonResponsesParams as t, observeResponsesStream as u, isAzureResponsesTextDeltaEventType as v, isInvalidEncryptedContentError as w, resolveResponsesMessageSnapshotCollapse as x, isResponsesTextContentPartType as y, claimOpenAIResponsesHttpContinuation as z };