@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.
- package/README.md +1 -1
- package/dist/{anthropic-C4Qu4H0Z.mjs → anthropic-DZQ_7gD1.mjs} +37 -38
- package/dist/{anthropic-payload-policy-BZ8umAbk.d.mts → anthropic-payload-policy-DyfwikYJ.d.mts} +4 -4
- package/dist/{anthropic-stream-reducer-CILWF7JD.mjs → anthropic-stream-reducer-D6ZI1wwj.mjs} +70 -50
- package/dist/{api-registry-ByUwIR0e.d.mts → api-registry-C2T3lTV7.d.mts} +2 -2
- package/dist/{assistant-output-tLt4H-iQ.mjs → assistant-output-DM1JBNs1.mjs} +1 -1
- package/dist/{azure-openai-responses-BAlqlKKc.mjs → azure-openai-responses-DS86GYzq.mjs} +6 -9
- package/dist/{base64-D-su8YVo.mjs → base64-CPmadnUf.mjs} +12 -12
- package/dist/credential-redaction-BKv49aiv.d.mts +24 -0
- package/dist/{diagnostics-QuErwCIl.mjs → diagnostics-CH8j2wIG.mjs} +139 -7
- package/dist/{diagnostics-CPeq9F7y.mjs → diagnostics-DzrF1h4J.mjs} +18 -1
- package/dist/diagnostics.d.mts +11 -24
- package/dist/diagnostics.mjs +4 -4
- package/dist/event-stream-C0nsgbj2.d.mts +1 -0
- package/dist/{event-stream-Bt5Y4Pav.d.mts → event-stream-CjnIZZst.d.mts} +1 -1
- package/dist/event-stream.d.mts +2 -2
- package/dist/expect-lbe3Hgrh.mjs +8 -0
- package/dist/{google-DPBAOaOW.mjs → google-BZJFjhuC.mjs} +6 -9
- package/dist/{google-messages-6JkpHrhJ.mjs → google-messages-DB7GKkDk.mjs} +3 -3
- package/dist/{google-shared-BvBeW9aq.mjs → google-shared-Bok4I6zB.mjs} +13 -13
- package/dist/{google-vertex-k-TMCAYD.mjs → google-vertex-3eVNR2qW.mjs} +5 -8
- package/dist/{host-4atIX-2V.d.mts → host-DH-Z-LDb.d.mts} +5 -3
- package/dist/{host-policy-Zcg_cNz8.mjs → host-policy-DZO3oPPk.mjs} +1 -1
- package/dist/{host-B8YfDGd4.mjs → host-yTvBrYM2.mjs} +63 -31
- package/dist/{index-DdD3qerf.d.mts → index-C25RT6bP.d.mts} +37 -14
- package/dist/index.d.mts +7 -8
- package/dist/index.mjs +5 -6
- package/dist/internal/anthropic.d.mts +13 -10
- package/dist/internal/anthropic.mjs +5 -5
- package/dist/internal/openai-completions-compat.d.mts +2 -0
- package/dist/internal/openai-completions-compat.mjs +2 -0
- package/dist/internal/openai-responses-payload-policy.d.mts +2 -2
- package/dist/internal/openai-responses-payload-policy.mjs +2 -2
- package/dist/internal/openai.d.mts +24 -53
- package/dist/internal/openai.mjs +12 -9
- package/dist/internal/runtime.d.mts +6 -8
- package/dist/internal/runtime.mjs +6 -10
- package/dist/internal/shared.d.mts +7 -5
- package/dist/internal/shared.mjs +4 -3
- package/dist/internal/tool-schema.d.mts +4 -4
- package/dist/internal/tool-schema.mjs +2 -2
- package/dist/{mistral-CxUZ1jUb.mjs → mistral-C_13dVBn.mjs} +9 -13
- package/dist/{model-transport-url-DKocrEsb.d.mts → model-transport-url-C5f59L3Y.d.mts} +1 -1
- package/dist/{openai-chatgpt-responses-CgO6kZfo.mjs → openai-chatgpt-responses-sTxPl4zM.mjs} +150 -83
- package/dist/{openai-completions-yJuk7eis.mjs → openai-completions-BO6D_hrB.mjs} +11 -12
- package/dist/{openai-prompt-cache-Bds-n_9Q.mjs → openai-completions-compat-CUollwl6.mjs} +5 -50
- package/dist/{openai-completions-compat-eHgh5UPE.d.mts → openai-completions-compat-DfJG1wSO.d.mts} +4 -4
- package/dist/{openai-completions-stream-Da2vvl-S.mjs → openai-completions-stream-BpuJ0ZOA.mjs} +117 -106
- package/dist/{openai-prompt-cache-B4eYo2-I.d.mts → openai-prompt-cache-C4RHdN4n.d.mts} +2 -2
- package/dist/openai-prompt-cache-CjV_2IRI.mjs +46 -0
- package/dist/{openai-provider-client-S2gCrM2Z.mjs → openai-provider-client-BP8J1aeg.mjs} +2 -2
- package/dist/openai-reasoning-effort-ash8dPrd.mjs +243 -0
- package/dist/{openai-responses-DaYwH05E.mjs → openai-responses-BJ_IEoMU.mjs} +8 -12
- package/dist/{openai-responses-compaction-window-CIhBAkkq.mjs → openai-responses-compaction-window-BiNCT0bS.mjs} +20 -62
- package/dist/{openai-responses-contracts-BjBAqAg_.d.mts → openai-responses-contracts-B1ENJFpI.d.mts} +9 -5
- package/dist/openai-responses-contracts-DWrfMODE.mjs +81 -0
- package/dist/{openai-responses-payload-policy-rLRPsSmB.d.mts → openai-responses-payload-policy-C7GsA1y0.d.mts} +5 -3
- package/dist/openai-responses-prompt-observer-internal-DPHWgbBH.mjs +198 -0
- package/dist/openai-responses-request-lifecycle-DFuyO1pQ.mjs +36 -0
- package/dist/{openai-responses-shared-B8RdBPCv.mjs → openai-responses-shared-DvSqtJ6_.mjs} +859 -581
- package/dist/openai-responses-terminal-usage-BNFbvY9f.d.mts +47 -0
- package/dist/{openai-tool-schema-CzjyYXun.mjs → openai-tool-schema-D4BMcj2D.mjs} +262 -162
- package/dist/{openai-transport-params-9aPuV5YY.mjs → openai-transport-params-DZKOTSfH.mjs} +157 -47
- package/dist/{positive-integer-41zhOdcV.mjs → positive-integer-BiUxrd71.mjs} +1 -1
- package/dist/{provider-error-BA-v_tKd.mjs → provider-error-CRhW7lkJ.mjs} +139 -44
- package/dist/{provider-error-CzNw4BWX.d.mts → provider-error-xumb1V3F.d.mts} +3 -1
- package/dist/{provider-options-Ceqv1OKk.d.mts → provider-options-DZYq53lj.d.mts} +12 -7
- package/dist/{provider-replay-context-CJ_YvcEW.mjs → provider-replay-context-DPr3w20a.mjs} +1 -1
- package/dist/{provider-transcript-transform-V5YzU9zh.mjs → provider-transcript-transform-BTocjCRs.mjs} +1 -1
- package/dist/{provider-transport-turn-state-D5EXOFL2.mjs → provider-transport-turn-state-lrXEFkYr.mjs} +1 -1
- package/dist/{provider-types-CVjKjsuq.d.mts → provider-types-w1rEqrGP.d.mts} +3 -3
- package/dist/provider-types.d.mts +6 -7
- package/dist/providers.d.mts +2 -2
- package/dist/providers.mjs +10 -10
- package/dist/{reasoning-tag-text-partitioner-BcR5pztD.mjs → reasoning-tag-text-partitioner-Di38crhI.mjs} +167 -40
- package/dist/{simple-options-BQbb4yQL.mjs → simple-options-np1XPuhm.mjs} +5 -3
- package/dist/{usage-cost-BNWbbXav.mjs → src-DwGYYyZp.mjs} +18 -11
- package/dist/{stream-first-event-timeout-2hfrquuz.mjs → stream-first-event-timeout-BeptfRL6.mjs} +1 -1
- package/dist/{string-normalization-CmLIasuf.mjs → string-normalization-J9ZiLfGO.mjs} +13 -1
- package/dist/tool-schema-json-projection-CD9c_fK8.mjs +134 -0
- package/dist/{transport-stream-shared-zHll9BxO.mjs → transport-stream-shared-B5RioB_Q.mjs} +16 -24
- package/dist/{transport-stream-shared-DNvmoWnv.d.mts → transport-stream-shared-B7Z9oCYg.d.mts} +5 -5
- package/dist/{transport-utils-zrYjICLZ.mjs → transport-utils-03Qi0CN2.mjs} +3 -3
- package/dist/transports.d.mts +27 -13
- package/dist/transports.mjs +168 -462
- package/dist/types-DTvddOfm.d.mts +1 -0
- package/dist/{types-Ntv5z2g2.d.mts → types-qZFbaDbK.d.mts} +49 -3
- package/dist/types.d.mts +6 -7
- package/dist/types.mjs +4 -5
- package/dist/{validation-B0t_G2H6.d.mts → validation-DhQhmt6t.d.mts} +1 -1
- package/dist/{validation-BDzVDnTs.mjs → validation-Dw7cb6BV.mjs} +1 -0
- package/dist/validation.d.mts +1 -1
- package/dist/validation.mjs +1 -1
- package/package.json +11 -6
- package/dist/diagnostics-DnPnOui6.d.mts +0 -29
- package/dist/event-stream-C3WGFsum.d.mts +0 -1
- package/dist/openai-responses-contracts-DDOHA62Y.mjs +0 -245
- package/dist/openai-responses-prompt-observer-internal-f8J7wpsk.mjs +0 -32
- package/dist/src-DDmEryvj.mjs +0 -2
- package/dist/tool-schema-json-projection-ClptDdAO.mjs +0 -82
- 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 {
|
|
7
|
-
import { a as resolveModelSseDebugMode, i as resolveModelPayloadDebugMode, r as emitModelTransportDebug } from "./diagnostics-
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { s as transformTransportMessages } from "./host-policy-
|
|
11
|
-
import { m as stripSystemPromptCacheBoundary, v as sortPromptCacheToolsByName } from "./simple-options-
|
|
12
|
-
import {
|
|
13
|
-
import { E as parseStreamingJson, _ as sanitizeTransportPayloadText, b as withProviderResponseHook, g as sanitizeNonEmptyTransportPayloadText, h as parseTerminalToolCallArguments,
|
|
14
|
-
import { n as providerReplayContextMatches, t as buildProviderReplayContext } from "./provider-replay-context-
|
|
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-
|
|
17
|
-
import { t as transformProviderMessages } from "./provider-transcript-transform-
|
|
18
|
-
import {
|
|
19
|
-
import { a as
|
|
20
|
-
import { n as isOpenAIResponsesCompactionOutput, r as readOpenAIResponsesCompactionWindow } from "./openai-responses-compaction-window-
|
|
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-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
const
|
|
617
|
-
return
|
|
618
|
-
}
|
|
619
|
-
function
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
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
|
-
|
|
637
|
-
|
|
638
|
-
const
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
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
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
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
|
-
|
|
674
|
-
|
|
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
|
|
753
|
-
return
|
|
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/
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
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
|
|
768
|
-
|
|
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
|
|
771
|
-
|
|
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
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
}
|
|
780
|
-
return
|
|
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
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
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
|
|
788
|
-
return
|
|
922
|
+
function hashOpaqueResponsesValue(value) {
|
|
923
|
+
return createHash("sha256").update(value).digest("hex");
|
|
789
924
|
}
|
|
790
|
-
function
|
|
791
|
-
return
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
const
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
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
|
|
1061
|
-
|
|
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
|
|
1067
|
-
|
|
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
|
|
1094
|
-
const
|
|
1095
|
-
|
|
1096
|
-
|
|
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
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
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
|
-
|
|
1112
|
-
|
|
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
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
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
|
|
1152
|
-
|
|
1153
|
-
const
|
|
1154
|
-
const
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
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
|
|
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,
|
|
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 =
|
|
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:
|
|
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")
|
|
2040
|
-
|
|
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
|
|
2059
|
-
}
|
|
2060
|
-
/**
|
|
2061
|
-
function
|
|
2062
|
-
const
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
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 :
|
|
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 }) =>
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
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 {
|
|
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 };
|