@openclaw/ai 2026.7.2-beta.2 → 2026.7.2-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +6 -5
  2. package/dist/{anthropic-BIRSg5x9.mjs → anthropic-CrUDIBpM.mjs} +173 -47
  3. package/dist/{api-registry-Byvoz8Ha.d.mts → api-registry-BMphkFf1.d.mts} +1 -2
  4. package/dist/{azure-openai-responses-CHi7Wo4A.mjs → azure-openai-responses-CbrpVeEv.mjs} +9 -11
  5. package/dist/{env-api-keys-DnhYpc27.mjs → env-api-keys-DrgeBuva.mjs} +1 -1
  6. package/dist/{event-stream-uQspnL8S.d.mts → event-stream-Douf9dob.d.mts} +1 -1
  7. package/dist/event-stream.d.mts +1 -1
  8. package/dist/{google-BmsqsNwR.mjs → google-Cs62KA7t.mjs} +4 -4
  9. package/dist/{google-shared-Dx2aba47.mjs → google-shared-CMLI-tCZ.mjs} +4 -3
  10. package/dist/{google-vertex-HZ_0rTwS.mjs → google-vertex-B4SD3U0f.mjs} +3 -3
  11. package/dist/host-WvWBo4h8.d.mts +173 -0
  12. package/dist/host-XYGZcgO8.mjs +98 -0
  13. package/dist/index-BVVgDSdq.d.mts +1 -0
  14. package/dist/index.d.mts +7 -50
  15. package/dist/index.mjs +1 -1
  16. package/dist/internal/anthropic.d.mts +9 -3
  17. package/dist/internal/anthropic.mjs +3 -3
  18. package/dist/internal/openai.d.mts +2 -279
  19. package/dist/internal/openai.mjs +5 -5
  20. package/dist/internal/runtime.d.mts +8 -5
  21. package/dist/internal/runtime.mjs +22 -12
  22. package/dist/internal/shared.d.mts +4 -2
  23. package/dist/internal/shared.mjs +2 -2
  24. package/dist/{mistral-DxMPt9q9.mjs → mistral-D5Ps7Led.mjs} +26 -10
  25. package/dist/{model-utils-Q1LSRIdo.mjs → model-utils-1GiZ2_rr.mjs} +3 -1
  26. package/dist/openai-CoGicoDt.d.mts +332 -0
  27. package/dist/{openai-chatgpt-responses-BuH2NvsR.mjs → openai-chatgpt-responses-h0o5yV8Y.mjs} +47 -48
  28. package/dist/{openai-completions-DPR_O2RW.mjs → openai-completions-exO8NFQf.mjs} +342 -102
  29. package/dist/{openai-responses-Cov-Vdc2.mjs → openai-responses-BHpmtUKo.mjs} +5 -5
  30. package/dist/{openai-responses-shared-Befb4D6R.mjs → openai-responses-shared-CzCurmY1.mjs} +527 -268
  31. package/dist/{openai-tool-projection-CFqm42J2.mjs → openai-tool-projection-ITOU9bG1.mjs} +1 -1
  32. package/dist/provider-error-C4VvV_3t.mjs +41 -0
  33. package/dist/providers.d.mts +1 -1
  34. package/dist/providers.mjs +8 -8
  35. package/dist/{stream-first-event-timeout-RjWszj8c.mjs → stream-first-event-timeout-DP4xEyBY.mjs} +45 -1
  36. package/dist/{transform-messages-BmS70CP5.mjs → system-prompt-cache-boundary-CbHeV4_l.mjs} +171 -161
  37. package/dist/transports.d.mts +590 -0
  38. package/dist/transports.mjs +5701 -0
  39. package/dist/{types-Cx2zJtyz.d.mts → types-AFwwWium.d.mts} +7 -0
  40. package/dist/types.d.mts +4 -4
  41. package/dist/{validation-Cej7htKc.d.mts → validation-sxvxC8J-.d.mts} +1 -1
  42. package/dist/validation.d.mts +1 -1
  43. package/npm-shrinkwrap.json +43 -50
  44. package/package.json +36 -10
  45. package/dist/host-4t713IeR.mjs +0 -37
  46. /package/dist/{index-BoTnz8cv.d.mts → anthropic-BoTnz8cv.d.mts} +0 -0
@@ -1,12 +1,12 @@
1
- import { n as getAiTransportHost } from "./host-4t713IeR.mjs";
2
- import { n as calculateCost, r as clampThinkingLevel } from "./model-utils-Q1LSRIdo.mjs";
1
+ import { n as getAiTransportHost } from "./host-XYGZcgO8.mjs";
2
+ import { C as isImageWithMediaPayload, T as isRecord, _ as normalizeOptionalString, a as stripSystemPromptCacheBoundary, c as transformMessages, g as normalizeLowercaseStringOrEmpty, x as extractToolResultText, y as describeToolResultMediaPlaceholder } from "./system-prompt-cache-boundary-CbHeV4_l.mjs";
3
+ import { t as sanitizeSurrogates } from "./sanitize-unicode-DT5o51ur.mjs";
4
+ import { n as calculateCost, r as clampThinkingLevel } from "./model-utils-1GiZ2_rr.mjs";
3
5
  import { t as headersToRecord } from "./headers-B_e4-1J0.mjs";
4
6
  import { n as parseStreamingJson } from "./json-parse-BvXNt1-7.mjs";
5
- import { t as sanitizeSurrogates } from "./sanitize-unicode-DT5o51ur.mjs";
6
- import { C as stripSystemPromptCacheBoundary, D as normalizeOptionalString, E as normalizeLowercaseStringOrEmpty, d as isRecord, i as extractToolResultText, n as describeToolResultMediaPlaceholder, o as isImageWithMediaPayload, t as transformMessages } from "./transform-messages-BmS70CP5.mjs";
7
- import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-RjWszj8c.mjs";
8
- import { t as projectOpenAITools } from "./openai-tool-projection-CFqm42J2.mjs";
9
7
  import { t as shortHash } from "./hash-CHgqbJmD.mjs";
8
+ import { a as withFirstStreamEventTimeout, i as getFirstStreamEventTimeoutMs, r as getFirstStreamEventTimeoutHandler, t as createFirstStreamEventAbortController } from "./stream-first-event-timeout-DP4xEyBY.mjs";
9
+ import { t as projectOpenAITools } from "./openai-tool-projection-ITOU9bG1.mjs";
10
10
  import { createHash, randomUUID } from "node:crypto";
11
11
  //#region packages/normalization-core/src/string-normalization.ts
12
12
  /** Coerces entries to strings, trims them, and drops empty results. */
@@ -1076,6 +1076,66 @@ function resolveResponsesMessageSnapshotCollapse(params) {
1076
1076
  return { kind: "keep" };
1077
1077
  }
1078
1078
  //#endregion
1079
+ //#region packages/ai/src/providers/openai-responses-terminal-usage.ts
1080
+ function readCount(value) {
1081
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
1082
+ }
1083
+ /**
1084
+ * Split a terminal usage payload into the priced buckets.
1085
+ *
1086
+ * OpenAI includes cache reads and writes in `input_tokens`, so both are subtracted out of the
1087
+ * billable input bucket. `total_tokens` comes from the payload, but never below the sum of the
1088
+ * split buckets: proxies routinely omit it (reporting 0 would understate the turn), and a payload
1089
+ * whose `cached_tokens` exceeds `input_tokens` clamps the input bucket, leaving the reported total
1090
+ * short of what the buckets actually price.
1091
+ */
1092
+ function mapResponsesTerminalUsage(usage) {
1093
+ if (!usage) return;
1094
+ const cacheRead = readCount(usage.input_tokens_details?.cached_tokens);
1095
+ const cacheWrite = readCount(usage.input_tokens_details?.cache_write_tokens);
1096
+ const input = Math.max(0, readCount(usage.input_tokens) - cacheRead - cacheWrite);
1097
+ const output = readCount(usage.output_tokens);
1098
+ const bucketTotal = input + output + cacheRead + cacheWrite;
1099
+ return {
1100
+ input,
1101
+ output,
1102
+ cacheRead,
1103
+ cacheWrite,
1104
+ totalTokens: Math.max(bucketTotal, readCount(usage.total_tokens))
1105
+ };
1106
+ }
1107
+ /** Reasoning tokens are reported by the agent path only; the package path does not track them. */
1108
+ function readResponsesReasoningTokens(usage) {
1109
+ const reasoningTokens = usage?.output_tokens_details?.reasoning_tokens;
1110
+ return typeof reasoningTokens === "number" && Number.isFinite(reasoningTokens) ? reasoningTokens : void 0;
1111
+ }
1112
+ function mapResponsesTerminalStopReason(status) {
1113
+ if (!status) return "stop";
1114
+ switch (status) {
1115
+ case "completed": return "stop";
1116
+ case "incomplete": return "length";
1117
+ case "failed":
1118
+ case "cancelled": return "error";
1119
+ case "in_progress":
1120
+ case "queued": return "stop";
1121
+ default: throw new Error(`Unhandled stop reason: ${String(status)}`);
1122
+ }
1123
+ }
1124
+ /**
1125
+ * Resolve the terminal stop reason, including the two overrides every Responses path shares: a
1126
+ * content-filtered turn is a provider error rather than a truncated answer, and a turn that
1127
+ * produced tool calls reports `toolUse` instead of a plain stop.
1128
+ */
1129
+ function resolveResponsesTerminalStopReason(params) {
1130
+ if (params.status === "incomplete" && params.incompleteReason === "content_filter") return {
1131
+ stopReason: "error",
1132
+ errorMessage: "Provider incomplete_reason: content_filter"
1133
+ };
1134
+ const stopReason = mapResponsesTerminalStopReason(params.status);
1135
+ if (stopReason === "stop" && params.hasToolCall) return { stopReason: "toolUse" };
1136
+ return { stopReason };
1137
+ }
1138
+ //#endregion
1079
1139
  //#region packages/ai/src/providers/openai-responses-tool-call-tracker.ts
1080
1140
  function readIdentityValue(value) {
1081
1141
  return (typeof value === "string" ? value.trim() : "") || void 0;
@@ -1152,6 +1212,151 @@ function createResponsesToolCallTracker() {
1152
1212
  };
1153
1213
  }
1154
1214
  //#endregion
1215
+ //#region packages/ai/src/providers/openai-tool-schema-compat.ts
1216
+ const OPENAI_STRICT_COMPAT_SCHEMA_MAP_KEYS = /* @__PURE__ */ new Set([
1217
+ "$defs",
1218
+ "definitions",
1219
+ "dependentSchemas",
1220
+ "dependencies",
1221
+ "patternProperties",
1222
+ "properties"
1223
+ ]);
1224
+ const OPENAI_NULLABLE_ANNOTATION_KEYS = /* @__PURE__ */ new Set([
1225
+ "default",
1226
+ "description",
1227
+ "examples",
1228
+ "format",
1229
+ "title"
1230
+ ]);
1231
+ const OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS = /* @__PURE__ */ new Set([
1232
+ "additionalItems",
1233
+ "additionalProperties",
1234
+ "allOf",
1235
+ "anyOf",
1236
+ "contains",
1237
+ "contentSchema",
1238
+ "else",
1239
+ "if",
1240
+ "items",
1241
+ "not",
1242
+ "oneOf",
1243
+ "prefixItems",
1244
+ "propertyNames",
1245
+ "then",
1246
+ "unevaluatedItems",
1247
+ "unevaluatedProperties"
1248
+ ]);
1249
+ function normalizeOpenAIStrictCompatSchemaMap(schema) {
1250
+ if (!schema || typeof schema !== "object" || Array.isArray(schema)) return schema;
1251
+ let changed = false;
1252
+ const normalized = {};
1253
+ for (const [key, value] of Object.entries(schema)) {
1254
+ const next = normalizeOpenAIStrictCompatSchemaRecursive(value, { promoteEmptyObject: false });
1255
+ normalized[key] = next;
1256
+ changed ||= next !== value;
1257
+ }
1258
+ return changed ? normalized : schema;
1259
+ }
1260
+ function normalizeOpenAIStrictCompatSchemaRecursive(schema, options) {
1261
+ if (Array.isArray(schema)) {
1262
+ let changed = false;
1263
+ const normalized = schema.map((entry) => {
1264
+ const next = normalizeOpenAIStrictCompatSchemaRecursive(entry, { promoteEmptyObject: false });
1265
+ changed ||= next !== entry;
1266
+ return next;
1267
+ });
1268
+ return changed ? normalized : schema;
1269
+ }
1270
+ if (!schema || typeof schema !== "object") return schema;
1271
+ const record = schema;
1272
+ let changed = false;
1273
+ let hadNullType = false;
1274
+ const normalized = {};
1275
+ for (const [key, value] of Object.entries(record)) {
1276
+ if (value === null && OPENAI_NULLABLE_ANNOTATION_KEYS.has(key)) {
1277
+ changed = true;
1278
+ continue;
1279
+ }
1280
+ if (value === null && key === "type") {
1281
+ hadNullType = true;
1282
+ changed = true;
1283
+ continue;
1284
+ }
1285
+ const next = OPENAI_STRICT_COMPAT_SCHEMA_MAP_KEYS.has(key) ? normalizeOpenAIStrictCompatSchemaMap(value) : OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS.has(key) ? normalizeOpenAIStrictCompatSchemaRecursive(value, { promoteEmptyObject: false }) : value;
1286
+ normalized[key] = next;
1287
+ changed ||= next !== value;
1288
+ }
1289
+ if (Object.keys(normalized).length === 0) {
1290
+ if (!options.promoteEmptyObject) return schema;
1291
+ return {
1292
+ type: "object",
1293
+ properties: {},
1294
+ required: [],
1295
+ additionalProperties: false
1296
+ };
1297
+ }
1298
+ const hasObjectShapeHints = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) || Array.isArray(normalized.required);
1299
+ const hasArrayShapeHints = "items" in normalized;
1300
+ if (!("type" in normalized) && hasObjectShapeHints !== hasArrayShapeHints) {
1301
+ normalized.type = hasObjectShapeHints ? "object" : "array";
1302
+ changed = true;
1303
+ } else if (hadNullType && !("type" in normalized)) normalized.type = null;
1304
+ if (normalized.type === "object" && !("properties" in normalized)) {
1305
+ normalized.properties = {};
1306
+ changed = true;
1307
+ }
1308
+ const hasEmptyProperties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) && Object.keys(normalized.properties).length === 0;
1309
+ if (normalized.type === "object" && !Array.isArray(normalized.required) && hasEmptyProperties) {
1310
+ normalized.required = [];
1311
+ changed = true;
1312
+ }
1313
+ if (normalized.type === "object" && hasEmptyProperties && !("additionalProperties" in normalized)) {
1314
+ normalized.additionalProperties = false;
1315
+ changed = true;
1316
+ }
1317
+ return changed ? normalized : schema;
1318
+ }
1319
+ /** Repairs recoverable OpenAI tool-schema shapes before canonical normalization. */
1320
+ function normalizeOpenAIStrictCompatSchema(schema) {
1321
+ return normalizeOpenAIStrictCompatSchemaRecursive(schema, { promoteEmptyObject: true });
1322
+ }
1323
+ /** Finds schema paths that violate OpenAI strict tool-schema requirements. */
1324
+ function findOpenAIStrictSchemaViolations(schema, path, options) {
1325
+ if (Array.isArray(schema)) {
1326
+ if (options?.requireObjectRoot) return [`${path}.type`];
1327
+ return schema.flatMap((item, index) => findOpenAIStrictSchemaViolations(item, `${path}[${index}]`));
1328
+ }
1329
+ if (!schema || typeof schema !== "object") return options?.requireObjectRoot ? [`${path}.type`] : [];
1330
+ const record = schema;
1331
+ const violations = [];
1332
+ for (const key of [
1333
+ "anyOf",
1334
+ "oneOf",
1335
+ "allOf"
1336
+ ]) if (key in record) violations.push(`${path}.${key}`);
1337
+ if (Array.isArray(record.type)) violations.push(`${path}.type`);
1338
+ const properties = record.properties && typeof record.properties === "object" && !Array.isArray(record.properties) ? record.properties : void 0;
1339
+ if (record.type === "object") {
1340
+ if (record.additionalProperties !== false) violations.push(`${path}.additionalProperties`);
1341
+ const required = Array.isArray(record.required) ? record.required.filter((entry) => typeof entry === "string") : void 0;
1342
+ if (!required) violations.push(`${path}.required`);
1343
+ else if (properties) {
1344
+ const requiredSet = new Set(required);
1345
+ for (const key of Object.keys(properties)) if (!requiredSet.has(key)) violations.push(`${path}.required.${key}`);
1346
+ }
1347
+ }
1348
+ for (const key of OPENAI_STRICT_COMPAT_SCHEMA_MAP_KEYS) {
1349
+ const schemaMap = record[key];
1350
+ if (!schemaMap || typeof schemaMap !== "object" || Array.isArray(schemaMap)) continue;
1351
+ for (const [entryKey, value] of Object.entries(schemaMap)) violations.push(...findOpenAIStrictSchemaViolations(value, `${path}.${key}.${entryKey}`));
1352
+ }
1353
+ for (const key of OPENAI_STRICT_COMPAT_SCHEMA_NESTED_KEYS) {
1354
+ const value = record[key];
1355
+ if (value && typeof value === "object") violations.push(...findOpenAIStrictSchemaViolations(value, `${path}.${key}`));
1356
+ }
1357
+ return violations;
1358
+ }
1359
+ //#endregion
1155
1360
  //#region packages/ai/src/providers/openai-tool-schema.ts
1156
1361
  /**
1157
1362
  * OpenAI strict JSON-schema normalization for tool inventories and request payloads.
@@ -1245,7 +1450,7 @@ function findOpenAIStrictToolProjectionDiagnostics(projection) {
1245
1450
  ...diagnostic.toolName ? { toolName: diagnostic.toolName } : {},
1246
1451
  violations: [...diagnostic.violations]
1247
1452
  })), ...projection.tools.flatMap((tool) => {
1248
- const violations = findStrictOpenAIJsonSchemaViolations(normalizeStrictOpenAIJsonSchema(tool.parameters), `${tool.name}.parameters`);
1453
+ const violations = findOpenAIStrictSchemaViolations(normalizeStrictOpenAIJsonSchema(tool.parameters), `${tool.name}.parameters`);
1249
1454
  return violations.length > 0 ? [{
1250
1455
  toolIndex: tool.toolIndex,
1251
1456
  toolName: tool.name,
@@ -1272,34 +1477,6 @@ function isStrictOpenAIJsonSchemaCompatibleRecursive(schema) {
1272
1477
  return isStrictOpenAIJsonSchemaCompatibleRecursive(entry);
1273
1478
  });
1274
1479
  }
1275
- function findStrictOpenAIJsonSchemaViolations(schema, path) {
1276
- if (Array.isArray(schema)) return schema.flatMap((entry, index) => findStrictOpenAIJsonSchemaViolations(entry, `${path}[${index}]`));
1277
- if (!schema || typeof schema !== "object") return [];
1278
- const record = schema;
1279
- const violations = [];
1280
- for (const key of [
1281
- "anyOf",
1282
- "oneOf",
1283
- "allOf"
1284
- ]) if (key in record) violations.push(`${path}.${key}`);
1285
- if (Array.isArray(record.type)) violations.push(`${path}.type`);
1286
- if (record.type === "object") {
1287
- if (record.additionalProperties !== false) violations.push(`${path}.additionalProperties`);
1288
- const properties = record.properties && typeof record.properties === "object" && !Array.isArray(record.properties) ? record.properties : {};
1289
- const required = Array.isArray(record.required) ? record.required.filter((entry) => typeof entry === "string") : void 0;
1290
- if (!required) violations.push(`${path}.required`);
1291
- else {
1292
- const requiredSet = new Set(required);
1293
- for (const key of Object.keys(properties)) if (!requiredSet.has(key)) violations.push(`${path}.required.${key}`);
1294
- }
1295
- }
1296
- if (record.properties && typeof record.properties === "object" && !Array.isArray(record.properties)) for (const [key, value] of Object.entries(record.properties)) violations.push(...findStrictOpenAIJsonSchemaViolations(value, `${path}.properties.${key}`));
1297
- for (const [key, value] of Object.entries(record)) {
1298
- if (key === "properties") continue;
1299
- if (value && typeof value === "object") violations.push(...findStrictOpenAIJsonSchemaViolations(value, `${path}.${key}`));
1300
- }
1301
- return violations;
1302
- }
1303
1480
  /** Resolves strict mode for the projected tools that will be emitted in the request payload. */
1304
1481
  function resolveOpenAIProjectedToolsStrictToolFlag(projection, strict) {
1305
1482
  if (strict !== true) return strict === false ? false : void 0;
@@ -1462,7 +1639,8 @@ function convertResponsesMessages(model, context, allowedToolCallProviders, opti
1462
1639
  };
1463
1640
  const transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);
1464
1641
  if ((options?.includeSystemPrompt ?? true) && context.systemPrompt) {
1465
- const role = model.reasoning ? "developer" : "system";
1642
+ const compat = model.compat;
1643
+ const role = model.reasoning && compat?.supportsDeveloperRole !== false ? "developer" : "system";
1466
1644
  messages.push({
1467
1645
  type: "message",
1468
1646
  role,
@@ -1631,7 +1809,7 @@ function resolveResponsesReasoningEffort(model, reasoning) {
1631
1809
  return clampedReasoning;
1632
1810
  }
1633
1811
  function applyCommonResponsesParams(params, model, context, options, config) {
1634
- if (options?.maxTokens) params.max_output_tokens = options.maxTokens;
1812
+ if (options?.maxTokens) params.max_output_tokens = Math.max(options.maxTokens, 16);
1635
1813
  if (options?.temperature !== void 0 && supportsOpenAITemperature(model)) params.temperature = options.temperature;
1636
1814
  if (context.tools) {
1637
1815
  const converted = convertResponsesToolPayload(context.tools, { model });
@@ -1650,7 +1828,7 @@ function buildResponsesRequestOptions(options) {
1650
1828
  return {
1651
1829
  ...options?.signal ? { signal: options.signal } : {},
1652
1830
  ...options?.timeoutMs !== void 0 ? { timeout: options.timeoutMs } : {},
1653
- ...options?.maxRetries !== void 0 ? { maxRetries: options.maxRetries } : {}
1831
+ maxRetries: options?.maxRetries ?? 0
1654
1832
  };
1655
1833
  }
1656
1834
  function cleanStreamingScratchBuffers(output) {
@@ -1689,7 +1867,7 @@ async function runResponsesStreamLifecycle(params) {
1689
1867
  onFirstEventTimeout: params.processStreamOptions?.onFirstEventTimeout ?? onFirstEventTimeout
1690
1868
  } : void 0);
1691
1869
  if (options?.signal?.aborted) throw new Error("Request was aborted");
1692
- if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error("An unknown error occurred");
1870
+ if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error(output.errorMessage ?? "An unknown error occurred");
1693
1871
  stream.push({
1694
1872
  type: "done",
1695
1873
  reason: output.stopReason,
@@ -1711,13 +1889,49 @@ async function runResponsesStreamLifecycle(params) {
1711
1889
  }
1712
1890
  }
1713
1891
  async function processResponsesStream(openaiStream, output, stream, model, options) {
1714
- let currentItem = null;
1715
- let currentBlock = null;
1716
1892
  const streamingToolCalls = createResponsesToolCallTracker();
1893
+ const outputSlots = /* @__PURE__ */ new Map();
1894
+ const reasoningBlocksById = /* @__PURE__ */ new Map();
1895
+ let unindexedOutputSlot;
1896
+ let terminalResponseEvent;
1717
1897
  let lastTextBlock = null;
1718
- let pendingMessageText = null;
1719
1898
  const blocks = output.content;
1720
1899
  const blockIndex = () => blocks.length - 1;
1900
+ const readOutputIndex = (event) => {
1901
+ const outputIndex = event.output_index;
1902
+ return typeof outputIndex === "number" && Number.isInteger(outputIndex) && outputIndex >= 0 ? outputIndex : void 0;
1903
+ };
1904
+ const registerOutputSlot = (event, slot) => {
1905
+ const outputIndex = readOutputIndex(event);
1906
+ if (outputIndex === void 0) {
1907
+ if (unindexedOutputSlot) throw new Error("Responses stream added overlapping unindexed output items");
1908
+ unindexedOutputSlot = slot;
1909
+ return;
1910
+ }
1911
+ if (outputSlots.has(outputIndex)) throw new Error(`Responses stream reused active output index ${outputIndex}`);
1912
+ outputSlots.set(outputIndex, slot);
1913
+ };
1914
+ const resolveOutputSlot = (event, type) => {
1915
+ const outputIndex = readOutputIndex(event);
1916
+ let slot = outputIndex === void 0 ? unindexedOutputSlot : outputSlots.get(outputIndex);
1917
+ if (outputIndex === void 0 && !slot) {
1918
+ const matchingSlots = [...outputSlots.values()].filter((candidate) => candidate.type === type);
1919
+ slot = matchingSlots.length === 1 ? matchingSlots[0] : void 0;
1920
+ }
1921
+ return slot?.type === type ? slot : void 0;
1922
+ };
1923
+ const forgetOutputSlot = (event, slot) => {
1924
+ const outputIndex = readOutputIndex(event);
1925
+ if (outputIndex === void 0) {
1926
+ if (unindexedOutputSlot === slot) unindexedOutputSlot = void 0;
1927
+ else for (const [indexedOutput, indexedSlot] of outputSlots) if (indexedSlot === slot) outputSlots.delete(indexedOutput);
1928
+ return;
1929
+ }
1930
+ if (outputSlots.get(outputIndex) === slot) outputSlots.delete(outputIndex);
1931
+ };
1932
+ const forgetToolCallOutputSlot = (toolCall) => {
1933
+ for (const [outputIndex, slot] of outputSlots) if (slot.type === "toolCall" && slot.toolCall === toolCall) outputSlots.delete(outputIndex);
1934
+ };
1721
1935
  const readIdentityValue = (value) => {
1722
1936
  return (typeof value === "string" ? value.trim() : "") || void 0;
1723
1937
  };
@@ -1729,28 +1943,137 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1729
1943
  if (!name) throw new Error("Responses stream completed tool call without a function name");
1730
1944
  return name;
1731
1945
  };
1732
- const appendPendingMessageDelta = (delta) => {
1733
- pendingMessageText = `${pendingMessageText ?? ""}${delta}`;
1734
- const priorText = lastTextBlock?.block.text ?? "";
1735
- if (priorText.startsWith(pendingMessageText) || pendingMessageText.startsWith(priorText)) return;
1736
- currentBlock = {
1946
+ const createOutputSlot = (event, item) => {
1947
+ if (item.type === "reasoning") {
1948
+ const block = {
1949
+ type: "thinking",
1950
+ thinking: ""
1951
+ };
1952
+ const slot = {
1953
+ type: "thinking",
1954
+ item,
1955
+ block,
1956
+ contentIndex: blocks.length
1957
+ };
1958
+ blocks.push(block);
1959
+ registerOutputSlot(event, slot);
1960
+ stream.push({
1961
+ type: "thinking_start",
1962
+ contentIndex: slot.contentIndex,
1963
+ partial: output
1964
+ });
1965
+ return slot;
1966
+ }
1967
+ if (item.type === "message") {
1968
+ const messageItem = item;
1969
+ const collapseCandidate = lastTextBlock;
1970
+ const block = collapseCandidate ? null : {
1971
+ type: "text",
1972
+ text: "",
1973
+ ...messageItem.phase ? { textSignature: encodeTextSignatureV1(messageItem.id, messageItem.phase) } : {}
1974
+ };
1975
+ const slot = {
1976
+ type: "text",
1977
+ item: messageItem,
1978
+ block,
1979
+ contentIndex: block ? blocks.length : void 0,
1980
+ pendingText: collapseCandidate ? "" : null,
1981
+ collapseCandidate
1982
+ };
1983
+ if (block) blocks.push(block);
1984
+ registerOutputSlot(event, slot);
1985
+ if (slot.contentIndex !== void 0) stream.push({
1986
+ type: "text_start",
1987
+ contentIndex: slot.contentIndex,
1988
+ partial: output
1989
+ });
1990
+ return slot;
1991
+ }
1992
+ };
1993
+ const resolveOutputItemSlot = (event, item) => {
1994
+ if (item.type === "reasoning") return resolveOutputSlot(event, "thinking");
1995
+ if (item.type === "message") return resolveOutputSlot(event, "text");
1996
+ const outputIndex = readOutputIndex(event);
1997
+ return outputIndex === void 0 ? void 0 : outputSlots.get(outputIndex);
1998
+ };
1999
+ const getOrCreateOutputSlot = (event, item) => {
2000
+ return resolveOutputItemSlot(event, item) ?? createOutputSlot(event, item);
2001
+ };
2002
+ const materializeDeferredTextSlot = (slot) => {
2003
+ if (slot.block || slot.pendingText === null) return;
2004
+ const text = slot.pendingText;
2005
+ slot.block = {
1737
2006
  type: "text",
1738
- text: pendingMessageText,
1739
- ...currentItem?.type === "message" && currentItem.phase ? { textSignature: encodeTextSignatureV1(currentItem.id, currentItem.phase ?? void 0) } : {}
2007
+ text,
2008
+ ...slot.item.phase ? { textSignature: encodeTextSignatureV1(slot.item.id, slot.item.phase) } : {}
1740
2009
  };
1741
- blocks.push(currentBlock);
2010
+ blocks.push(slot.block);
2011
+ slot.contentIndex = blockIndex();
1742
2012
  stream.push({
1743
2013
  type: "text_start",
1744
- contentIndex: blockIndex(),
2014
+ contentIndex: slot.contentIndex,
1745
2015
  partial: output
1746
2016
  });
1747
- stream.push({
2017
+ if (text) stream.push({
1748
2018
  type: "text_delta",
1749
- contentIndex: blockIndex(),
1750
- delta: pendingMessageText,
2019
+ contentIndex: slot.contentIndex,
2020
+ delta: text,
1751
2021
  partial: output
1752
2022
  });
1753
- pendingMessageText = null;
2023
+ if (lastTextBlock === slot.collapseCandidate) lastTextBlock = null;
2024
+ slot.pendingText = null;
2025
+ slot.collapseCandidate = null;
2026
+ };
2027
+ const materializeDeferredTextSlots = (except) => {
2028
+ for (const slot of outputSlots.values()) if (slot !== except && slot.type === "text") materializeDeferredTextSlot(slot);
2029
+ if (unindexedOutputSlot !== except && unindexedOutputSlot?.type === "text") materializeDeferredTextSlot(unindexedOutputSlot);
2030
+ };
2031
+ const appendPendingMessageDelta = (slot, delta) => {
2032
+ slot.pendingText = `${slot.pendingText ?? ""}${delta}`;
2033
+ const priorText = slot.collapseCandidate?.block.text ?? "";
2034
+ if (priorText.startsWith(slot.pendingText) || slot.pendingText.startsWith(priorText)) return;
2035
+ materializeDeferredTextSlot(slot);
2036
+ };
2037
+ const backfillReasoningSignatures = (responseOutput) => {
2038
+ for (const item of responseOutput) {
2039
+ if (item.type !== "reasoning" || !item.encrypted_content) continue;
2040
+ const block = reasoningBlocksById.get(item.id);
2041
+ if (!block?.thinkingSignature) continue;
2042
+ const storedItem = JSON.parse(block.thinkingSignature);
2043
+ if (storedItem.encrypted_content) continue;
2044
+ block.thinkingSignature = JSON.stringify({
2045
+ ...storedItem,
2046
+ encrypted_content: item.encrypted_content
2047
+ });
2048
+ }
2049
+ };
2050
+ const finalizeResponse = (response) => {
2051
+ terminalResponseEvent = "finalized";
2052
+ backfillReasoningSignatures(response.output ?? []);
2053
+ if (response.id) output.responseId = response.id;
2054
+ const mappedUsage = mapResponsesTerminalUsage(response.usage);
2055
+ if (mappedUsage) output.usage = {
2056
+ ...mappedUsage,
2057
+ cost: {
2058
+ input: 0,
2059
+ output: 0,
2060
+ cacheRead: 0,
2061
+ cacheWrite: 0,
2062
+ total: 0
2063
+ }
2064
+ };
2065
+ calculateCost(model, output.usage);
2066
+ if (options?.applyServiceTierPricing) {
2067
+ const serviceTier = options.resolveServiceTier ? options.resolveServiceTier(response.service_tier, options.serviceTier) : response.service_tier ?? options.serviceTier;
2068
+ options.applyServiceTierPricing(output.usage, serviceTier);
2069
+ }
2070
+ const terminal = resolveResponsesTerminalStopReason({
2071
+ status: response.status,
2072
+ incompleteReason: response.incomplete_details?.reason,
2073
+ hasToolCall: output.content.some((block) => block.type === "toolCall")
2074
+ });
2075
+ output.stopReason = terminal.stopReason;
2076
+ if (terminal.errorMessage) output.errorMessage = terminal.errorMessage;
1754
2077
  };
1755
2078
  const guardedStream = withFirstStreamEventTimeout(openaiStream, {
1756
2079
  provider: model.provider,
@@ -1764,42 +2087,11 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1764
2087
  });
1765
2088
  for await (const event of guardedStream) if (event.type === "response.created") output.responseId = event.response.id;
1766
2089
  else if (event.type === "response.output_item.added") {
2090
+ materializeDeferredTextSlots();
1767
2091
  const item = event.item;
1768
- if (item.type !== "message") {
1769
- lastTextBlock = null;
1770
- pendingMessageText = null;
1771
- }
1772
- if (item.type === "reasoning") {
1773
- currentItem = item;
1774
- currentBlock = {
1775
- type: "thinking",
1776
- thinking: ""
1777
- };
1778
- output.content.push(currentBlock);
1779
- stream.push({
1780
- type: "thinking_start",
1781
- contentIndex: blockIndex(),
1782
- partial: output
1783
- });
1784
- } else if (item.type === "message") {
1785
- currentItem = item;
1786
- if (lastTextBlock) {
1787
- currentBlock = null;
1788
- pendingMessageText = "";
1789
- } else {
1790
- currentBlock = {
1791
- type: "text",
1792
- text: "",
1793
- ...item.phase ? { textSignature: encodeTextSignatureV1(item.id, item.phase) } : {}
1794
- };
1795
- output.content.push(currentBlock);
1796
- stream.push({
1797
- type: "text_start",
1798
- contentIndex: blockIndex(),
1799
- partial: output
1800
- });
1801
- }
1802
- } else if (item.type === "function_call") {
2092
+ if (item.type !== "message") lastTextBlock = null;
2093
+ if (item.type === "reasoning" || item.type === "message") createOutputSlot(event, item);
2094
+ else if (item.type === "function_call") {
1803
2095
  const toolCallBlock = {
1804
2096
  type: "toolCall",
1805
2097
  id: resolveResponsesToolCallId(item),
@@ -1815,8 +2107,10 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1815
2107
  ...readResponsesToolCallItemIdentity(item)
1816
2108
  };
1817
2109
  streamingToolCalls.register(event, toolCallState);
1818
- currentItem = item;
1819
- currentBlock = toolCallBlock;
2110
+ if (readOutputIndex(event) !== void 0) registerOutputSlot(event, {
2111
+ type: "toolCall",
2112
+ toolCall: toolCallState
2113
+ });
1820
2114
  output.content.push(toolCallBlock);
1821
2115
  stream.push({
1822
2116
  type: "toolcall_start",
@@ -1825,113 +2119,107 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1825
2119
  });
1826
2120
  }
1827
2121
  } else if (event.type === "response.reasoning_summary_part.added") {
1828
- if (currentItem && currentItem.type === "reasoning") {
1829
- currentItem.summary = currentItem.summary || [];
1830
- currentItem.summary.push(event.part);
1831
- }
2122
+ const slot = resolveOutputSlot(event, "thinking");
2123
+ if (!slot) continue;
2124
+ slot.item.summary = slot.item.summary || [];
2125
+ slot.item.summary.push(event.part);
1832
2126
  } else if (event.type === "response.reasoning_summary_text.delta") {
1833
- if (currentItem?.type === "reasoning" && currentBlock?.type === "thinking") {
1834
- currentItem.summary = currentItem.summary || [];
1835
- const lastPart = currentItem.summary[currentItem.summary.length - 1];
1836
- if (lastPart) {
1837
- currentBlock.thinking += event.delta;
1838
- lastPart.text += event.delta;
1839
- stream.push({
1840
- type: "thinking_delta",
1841
- contentIndex: blockIndex(),
1842
- delta: event.delta,
1843
- partial: output
1844
- });
1845
- }
1846
- }
2127
+ const slot = resolveOutputSlot(event, "thinking");
2128
+ if (!slot) continue;
2129
+ slot.item.summary = slot.item.summary || [];
2130
+ const lastPart = slot.item.summary[slot.item.summary.length - 1];
2131
+ if (!lastPart) continue;
2132
+ slot.block.thinking += event.delta;
2133
+ lastPart.text += event.delta;
2134
+ stream.push({
2135
+ type: "thinking_delta",
2136
+ contentIndex: slot.contentIndex,
2137
+ delta: event.delta,
2138
+ partial: output
2139
+ });
1847
2140
  } else if (event.type === "response.reasoning_summary_part.done") {
1848
- if (currentItem?.type === "reasoning" && currentBlock?.type === "thinking") {
1849
- currentItem.summary = currentItem.summary || [];
1850
- const lastPart = currentItem.summary[currentItem.summary.length - 1];
1851
- if (lastPart) {
1852
- currentBlock.thinking += "\n\n";
1853
- lastPart.text += "\n\n";
1854
- stream.push({
1855
- type: "thinking_delta",
1856
- contentIndex: blockIndex(),
1857
- delta: "\n\n",
1858
- partial: output
1859
- });
1860
- }
1861
- }
2141
+ const slot = resolveOutputSlot(event, "thinking");
2142
+ if (!slot) continue;
2143
+ slot.item.summary = slot.item.summary || [];
2144
+ const lastPart = slot.item.summary[slot.item.summary.length - 1];
2145
+ if (!lastPart) continue;
2146
+ slot.block.thinking += "\n\n";
2147
+ lastPart.text += "\n\n";
2148
+ stream.push({
2149
+ type: "thinking_delta",
2150
+ contentIndex: slot.contentIndex,
2151
+ delta: "\n\n",
2152
+ partial: output
2153
+ });
1862
2154
  } else if (event.type === "response.reasoning_text.delta") {
1863
- if (currentItem?.type === "reasoning" && currentBlock?.type === "thinking") {
1864
- currentBlock.thinking += event.delta;
2155
+ const slot = resolveOutputSlot(event, "thinking");
2156
+ if (!slot) continue;
2157
+ slot.block.thinking += event.delta;
2158
+ stream.push({
2159
+ type: "thinking_delta",
2160
+ contentIndex: slot.contentIndex,
2161
+ delta: event.delta,
2162
+ partial: output
2163
+ });
2164
+ } else if (event.type === "response.content_part.added") {
2165
+ const slot = resolveOutputSlot(event, "text");
2166
+ if (!slot) continue;
2167
+ slot.item.content = slot.item.content || [];
2168
+ if (event.part.type === "output_text" || event.part.type === "text" || event.part.type === "refusal") slot.item.content.push(event.part);
2169
+ } else if (event.type === "response.output_text.delta") {
2170
+ const slot = resolveOutputSlot(event, "text");
2171
+ if (!slot?.item.content || slot.item.content.length === 0) continue;
2172
+ const lastPart = slot.item.content[slot.item.content.length - 1];
2173
+ if (!isResponsesTextContentPartType(lastPart?.type)) continue;
2174
+ lastPart.text += event.delta;
2175
+ if (slot.pendingText !== null) appendPendingMessageDelta(slot, event.delta);
2176
+ else if (slot.block && slot.contentIndex !== void 0) {
2177
+ slot.block.text += event.delta;
1865
2178
  stream.push({
1866
- type: "thinking_delta",
1867
- contentIndex: blockIndex(),
2179
+ type: "text_delta",
2180
+ contentIndex: slot.contentIndex,
1868
2181
  delta: event.delta,
1869
2182
  partial: output
1870
2183
  });
1871
2184
  }
1872
- } else if (event.type === "response.content_part.added") {
1873
- if (currentItem?.type === "message") {
1874
- currentItem.content = currentItem.content || [];
1875
- if (event.part.type === "output_text" || event.part.type === "text" || event.part.type === "refusal") currentItem.content.push(event.part);
1876
- }
1877
- } else if (event.type === "response.output_text.delta") {
1878
- if (currentItem?.type === "message") {
1879
- if (!currentItem.content || currentItem.content.length === 0) continue;
1880
- const lastPart = currentItem.content[currentItem.content.length - 1];
1881
- if (isResponsesTextContentPartType(lastPart?.type)) {
1882
- lastPart.text += event.delta;
1883
- if (pendingMessageText !== null) appendPendingMessageDelta(event.delta);
1884
- else if (currentBlock?.type === "text") {
1885
- currentBlock.text += event.delta;
1886
- stream.push({
1887
- type: "text_delta",
1888
- contentIndex: blockIndex(),
1889
- delta: event.delta,
1890
- partial: output
1891
- });
1892
- }
1893
- }
1894
- }
1895
2185
  } else if (isAzureResponsesTextDeltaEvent(event)) {
1896
- if (currentItem?.type === "message") {
1897
- currentItem.content = currentItem.content || [];
1898
- let lastPart = currentItem.content[currentItem.content.length - 1];
1899
- if (lastPart?.type !== "text") {
1900
- lastPart = {
1901
- type: "text",
1902
- text: ""
1903
- };
1904
- currentItem.content.push(lastPart);
1905
- }
1906
- lastPart.text += event.delta;
1907
- if (pendingMessageText !== null) appendPendingMessageDelta(event.delta);
1908
- else if (currentBlock?.type === "text") {
1909
- currentBlock.text += event.delta;
1910
- stream.push({
1911
- type: "text_delta",
1912
- contentIndex: blockIndex(),
1913
- delta: event.delta,
1914
- partial: output
1915
- });
1916
- }
2186
+ const slot = resolveOutputSlot(event, "text");
2187
+ if (!slot) continue;
2188
+ slot.item.content = slot.item.content || [];
2189
+ let lastPart = slot.item.content[slot.item.content.length - 1];
2190
+ if (lastPart?.type !== "text") {
2191
+ lastPart = {
2192
+ type: "text",
2193
+ text: ""
2194
+ };
2195
+ slot.item.content.push(lastPart);
2196
+ }
2197
+ lastPart.text += event.delta;
2198
+ if (slot.pendingText !== null) appendPendingMessageDelta(slot, event.delta);
2199
+ else if (slot.block && slot.contentIndex !== void 0) {
2200
+ slot.block.text += event.delta;
2201
+ stream.push({
2202
+ type: "text_delta",
2203
+ contentIndex: slot.contentIndex,
2204
+ delta: event.delta,
2205
+ partial: output
2206
+ });
1917
2207
  }
1918
2208
  } else if (event.type === "response.refusal.delta") {
1919
- if (currentItem?.type === "message") {
1920
- if (!currentItem.content || currentItem.content.length === 0) continue;
1921
- const lastPart = currentItem.content[currentItem.content.length - 1];
1922
- if (lastPart?.type === "refusal") {
1923
- lastPart.refusal += event.delta;
1924
- if (pendingMessageText !== null) appendPendingMessageDelta(event.delta);
1925
- else if (currentBlock?.type === "text") {
1926
- currentBlock.text += event.delta;
1927
- stream.push({
1928
- type: "text_delta",
1929
- contentIndex: blockIndex(),
1930
- delta: event.delta,
1931
- partial: output
1932
- });
1933
- }
1934
- }
2209
+ const slot = resolveOutputSlot(event, "text");
2210
+ if (!slot?.item.content || slot.item.content.length === 0) continue;
2211
+ const lastPart = slot.item.content[slot.item.content.length - 1];
2212
+ if (lastPart?.type !== "refusal") continue;
2213
+ lastPart.refusal += event.delta;
2214
+ if (slot.pendingText !== null) appendPendingMessageDelta(slot, event.delta);
2215
+ else if (slot.block && slot.contentIndex !== void 0) {
2216
+ slot.block.text += event.delta;
2217
+ stream.push({
2218
+ type: "text_delta",
2219
+ contentIndex: slot.contentIndex,
2220
+ delta: event.delta,
2221
+ partial: output
2222
+ });
1935
2223
  }
1936
2224
  } else if (event.type === "response.function_call_arguments.delta") {
1937
2225
  const toolCall = streamingToolCalls.resolve(event);
@@ -1967,72 +2255,78 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
1967
2255
  } else if (streamingToolCalls.hasActive()) streamingToolCalls.markArgumentsUnreliable();
1968
2256
  } else if (event.type === "response.output_item.done") {
1969
2257
  const item = event.item;
1970
- if (item.type !== "message") {
1971
- lastTextBlock = null;
1972
- pendingMessageText = null;
1973
- }
1974
- if (item.type === "reasoning" && currentBlock?.type === "thinking") {
2258
+ if (item.type !== "message") lastTextBlock = null;
2259
+ const existingOutputSlot = resolveOutputItemSlot(event, item);
2260
+ materializeDeferredTextSlots(existingOutputSlot);
2261
+ const outputSlot = existingOutputSlot ?? getOrCreateOutputSlot(event, item);
2262
+ if (item.type === "reasoning" && outputSlot?.type === "thinking") {
1975
2263
  const summaryText = item.summary?.map((s) => s.text).join("\n\n") || "";
1976
2264
  const contentText = item.content?.map((c) => c.text).join("\n\n") || "";
1977
- currentBlock.thinking = summaryText || contentText || currentBlock.thinking;
1978
- currentBlock.thinkingSignature = JSON.stringify(item);
2265
+ outputSlot.block.thinking = summaryText || contentText || outputSlot.block.thinking;
2266
+ outputSlot.block.thinkingSignature = JSON.stringify(item);
2267
+ if (typeof item.id === "string") reasoningBlocksById.set(item.id, outputSlot.block);
1979
2268
  stream.push({
1980
2269
  type: "thinking_end",
1981
- contentIndex: blockIndex(),
1982
- content: currentBlock.thinking,
2270
+ contentIndex: outputSlot.contentIndex,
2271
+ content: outputSlot.block.thinking,
1983
2272
  partial: output
1984
2273
  });
1985
- currentBlock = null;
1986
- } else if (item.type === "message" && (currentBlock?.type === "text" || pendingMessageText !== null)) {
1987
- const finalText = item.content.map((c) => c.type === "output_text" || c.type === "text" ? c.text : c.refusal).join("");
2274
+ forgetOutputSlot(event, outputSlot);
2275
+ } else if (item.type === "message" && outputSlot?.type === "text" && (outputSlot.block || outputSlot.pendingText !== null)) {
2276
+ const streamedText = outputSlot.pendingText ?? outputSlot.block?.text ?? "";
2277
+ const finalText = item.content == null ? streamedText : item.content.map((c) => c.type === "output_text" || c.type === "text" ? c.text : c.refusal).join("");
1988
2278
  const phase = item.phase ?? void 0;
1989
- const collapse = pendingMessageText !== null ? resolveResponsesMessageSnapshotCollapse({
1990
- prior: lastTextBlock && {
1991
- text: lastTextBlock.block.text,
1992
- phase: lastTextBlock.phase
2279
+ const collapse = outputSlot.pendingText !== null ? resolveResponsesMessageSnapshotCollapse({
2280
+ prior: outputSlot.collapseCandidate && {
2281
+ text: outputSlot.collapseCandidate.block.text,
2282
+ phase: outputSlot.collapseCandidate.phase
1993
2283
  },
1994
2284
  nextText: finalText,
1995
2285
  nextPhase: phase
1996
2286
  }) : { kind: "keep" };
1997
- pendingMessageText = null;
1998
- if (collapse.kind === "extend" && lastTextBlock) {
1999
- lastTextBlock.block.text = collapse.text;
2000
- lastTextBlock.block.textSignature = encodeTextSignatureV1(item.id, phase);
2287
+ outputSlot.pendingText = null;
2288
+ if (collapse.kind === "extend" && outputSlot.collapseCandidate) {
2289
+ outputSlot.collapseCandidate.block.text = collapse.text;
2290
+ outputSlot.collapseCandidate.block.textSignature = encodeTextSignatureV1(item.id, phase);
2001
2291
  stream.push({
2002
2292
  type: "text_end",
2003
- contentIndex: lastTextBlock.index,
2293
+ contentIndex: outputSlot.collapseCandidate.index,
2004
2294
  content: collapse.text,
2005
2295
  partial: output
2006
2296
  });
2297
+ lastTextBlock = outputSlot.collapseCandidate;
2007
2298
  } else {
2008
- if (currentBlock?.type !== "text") {
2009
- currentBlock = {
2299
+ if (!outputSlot.block) {
2300
+ outputSlot.block = {
2010
2301
  type: "text",
2011
2302
  text: "",
2012
2303
  ...phase ? { textSignature: encodeTextSignatureV1(item.id, phase) } : {}
2013
2304
  };
2014
- blocks.push(currentBlock);
2305
+ blocks.push(outputSlot.block);
2306
+ outputSlot.contentIndex = blockIndex();
2015
2307
  stream.push({
2016
2308
  type: "text_start",
2017
- contentIndex: blockIndex(),
2309
+ contentIndex: outputSlot.contentIndex,
2018
2310
  partial: output
2019
2311
  });
2020
2312
  }
2021
- currentBlock.text = finalText;
2022
- currentBlock.textSignature = encodeTextSignatureV1(item.id, phase);
2313
+ outputSlot.block.text = finalText;
2314
+ outputSlot.block.textSignature = encodeTextSignatureV1(item.id, phase);
2315
+ const contentIndex = outputSlot.contentIndex;
2316
+ if (contentIndex === void 0) throw new Error("Responses stream finalized text without a content index");
2023
2317
  lastTextBlock = {
2024
- block: currentBlock,
2025
- index: blockIndex(),
2318
+ block: outputSlot.block,
2319
+ index: contentIndex,
2026
2320
  phase
2027
2321
  };
2028
2322
  stream.push({
2029
2323
  type: "text_end",
2030
- contentIndex: blockIndex(),
2031
- content: currentBlock.text,
2324
+ contentIndex,
2325
+ content: outputSlot.block.text,
2032
2326
  partial: output
2033
2327
  });
2034
2328
  }
2035
- currentBlock = null;
2329
+ forgetOutputSlot(event, outputSlot);
2036
2330
  } else if (item.type === "function_call") {
2037
2331
  const streamingToolCall = streamingToolCalls.resolve(event, readResponsesToolCallItemIdentity(item));
2038
2332
  if (!streamingToolCall && streamingToolCalls.hasActive()) continue;
@@ -2066,10 +2360,9 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2066
2360
  partial: output
2067
2361
  });
2068
2362
  }
2069
- if (streamingToolCall) streamingToolCalls.forget(streamingToolCall);
2070
- if (currentBlock === toolCall) {
2071
- currentBlock = null;
2072
- currentItem = null;
2363
+ if (streamingToolCall) {
2364
+ streamingToolCalls.forget(streamingToolCall);
2365
+ forgetToolCallOutputSlot(streamingToolCall);
2073
2366
  }
2074
2367
  stream.push({
2075
2368
  type: "toolcall_end",
@@ -2078,56 +2371,22 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
2078
2371
  partial: output
2079
2372
  });
2080
2373
  }
2081
- } else if (event.type === "response.completed") {
2374
+ } else if (event.type === "response.completed" || event.type === "response.incomplete") {
2082
2375
  if (streamingToolCalls.hasActive()) throw new Error("Responses stream completed with unresolved tool calls");
2083
- const response = event.response;
2084
- if (response?.id) output.responseId = response.id;
2085
- if (response?.usage) {
2086
- const inputTokenDetails = response.usage.input_tokens_details;
2087
- const cachedTokens = inputTokenDetails?.cached_tokens || 0;
2088
- const cacheWriteTokens = inputTokenDetails?.cache_write_tokens || 0;
2089
- output.usage = {
2090
- input: Math.max(0, (response.usage.input_tokens || 0) - cachedTokens - cacheWriteTokens),
2091
- output: response.usage.output_tokens || 0,
2092
- cacheRead: cachedTokens,
2093
- cacheWrite: cacheWriteTokens,
2094
- totalTokens: response.usage.total_tokens || 0,
2095
- cost: {
2096
- input: 0,
2097
- output: 0,
2098
- cacheRead: 0,
2099
- cacheWrite: 0,
2100
- total: 0
2101
- }
2102
- };
2103
- }
2104
- calculateCost(model, output.usage);
2105
- if (options?.applyServiceTierPricing) {
2106
- const serviceTier = options.resolveServiceTier ? options.resolveServiceTier(response?.service_tier, options.serviceTier) : response?.service_tier ?? options.serviceTier;
2107
- options.applyServiceTierPricing(output.usage, serviceTier);
2108
- }
2109
- output.stopReason = mapStopReason(response?.status);
2110
- if (output.content.some((b) => b.type === "toolCall") && output.stopReason === "stop") output.stopReason = "toolUse";
2376
+ finalizeResponse(event.response);
2111
2377
  } else if (event.type === "error") throw new Error(event.message ? `Error Code ${event.code}: ${event.message}` : "Unknown error");
2112
2378
  else if (event.type === "response.failed") {
2113
2379
  const error = event.response?.error;
2114
2380
  const details = event.response?.incomplete_details;
2115
- const msg = error ? `${error.code || "unknown"}: ${error.message || "no message"}` : details?.reason ? `incomplete: ${details.reason}` : "Unknown error (no error details in response)";
2116
- throw new Error(msg);
2381
+ output.responseId = event.response.id;
2382
+ output.stopReason = "error";
2383
+ output.errorMessage = error ? `${error.code || "unknown"}: ${error.message || "no message"}` : details?.reason ? `incomplete: ${details.reason}` : "Unknown error (no error details in response)";
2384
+ terminalResponseEvent = "failed";
2385
+ break;
2117
2386
  }
2387
+ if (terminalResponseEvent === "failed") return;
2118
2388
  if (streamingToolCalls.hasActive()) throw new Error("Responses stream ended with unresolved tool calls");
2119
- }
2120
- function mapStopReason(status) {
2121
- if (!status) return "stop";
2122
- switch (status) {
2123
- case "completed": return "stop";
2124
- case "incomplete": return "length";
2125
- case "failed":
2126
- case "cancelled": return "error";
2127
- case "in_progress":
2128
- case "queued": return "stop";
2129
- default: throw new Error(`Unhandled stop reason: ${String(status)}`);
2130
- }
2389
+ if (!terminalResponseEvent) throw new Error("OpenAI Responses stream ended before a terminal response event");
2131
2390
  }
2132
2391
  //#endregion
2133
- export { resolveOpenAISupportedReasoningEfforts as A, isResponsesTextDeltaEventType as C, isOpenAIGpt56Model as D, isOpenAIGpt55Model as E, resolveUnsupportedToolSchemaKeywords as F, shouldOmitEmptyArrayItems as I, stripUnsupportedSchemaKeywords as L, supportsOpenAITemperature as M, extractToolSchemaModelCompat as N, normalizeOpenAIReasoningEffort as O, normalizeToolParameterSchema as P, GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS as R, isResponsesTextContentPartType as S, isOpenAIGpt54MiniModel as T, AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE as _, resolveResponsesReasoningEffort as a, isAzureResponsesTextDeltaEvent as b, clearOpenAIToolSchemaCacheForTest as c, normalizeOpenAIStrictToolParameters as d, normalizeStrictOpenAIJsonSchema as f, AZURE_RESPONSES_TEXT_CONTENT_PART_TYPE as g, readResponsesToolCallItemIdentity as h, processResponsesStream as i, supportsOpenAIReasoningEffort as j, resolveOpenAIReasoningEffortForModel as k, findOpenAIStrictToolProjectionDiagnostics as l, createResponsesToolCallTracker as m, convertResponsesMessages as n, runResponsesStreamLifecycle as o, resolveOpenAIProjectedToolsStrictToolFlag as p, createResponsesAssistantOutput as r, convertResponsesToolPayload as s, applyCommonResponsesParams as t, isStrictOpenAIJsonSchemaCompatible as u, OPENAI_RESPONSES_OUTPUT_TEXT_CONTENT_PART_TYPE as v, resolveResponsesMessageSnapshotCollapse as w, isAzureResponsesTextDeltaEventType as x, OPENAI_RESPONSES_OUTPUT_TEXT_DELTA_EVENT_TYPE as y, cleanSchemaForGemini as z };
2392
+ export { isOpenAIGpt54MiniModel as A, resolveUnsupportedToolSchemaKeywords as B, OPENAI_RESPONSES_OUTPUT_TEXT_CONTENT_PART_TYPE as C, isResponsesTextContentPartType as D, isAzureResponsesTextDeltaEventType as E, resolveOpenAISupportedReasoningEfforts as F, uniqueStrings as G, stripUnsupportedSchemaKeywords as H, supportsOpenAIReasoningEffort as I, supportsOpenAITemperature as L, isOpenAIGpt56Model as M, normalizeOpenAIReasoningEffort as N, isResponsesTextDeltaEventType as O, resolveOpenAIReasoningEffortForModel as P, extractToolSchemaModelCompat as R, AZURE_RESPONSES_TEXT_DELTA_EVENT_TYPE as S, isAzureResponsesTextDeltaEvent as T, GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS as U, shouldOmitEmptyArrayItems as V, cleanSchemaForGemini as W, readResponsesToolCallItemIdentity as _, resolveResponsesReasoningEffort as a, resolveResponsesTerminalStopReason as b, clearOpenAIToolSchemaCacheForTest as c, normalizeOpenAIStrictToolParameters as d, normalizeStrictOpenAIJsonSchema as f, createResponsesToolCallTracker as g, normalizeOpenAIStrictCompatSchema as h, processResponsesStream as i, isOpenAIGpt55Model as j, resolveResponsesMessageSnapshotCollapse as k, findOpenAIStrictToolProjectionDiagnostics as l, findOpenAIStrictSchemaViolations as m, convertResponsesMessages as n, runResponsesStreamLifecycle as o, resolveOpenAIProjectedToolsStrictToolFlag as p, createResponsesAssistantOutput as r, convertResponsesToolPayload as s, applyCommonResponsesParams as t, isStrictOpenAIJsonSchemaCompatible as u, mapResponsesTerminalUsage as v, OPENAI_RESPONSES_OUTPUT_TEXT_DELTA_EVENT_TYPE as w, AZURE_RESPONSES_TEXT_CONTENT_PART_TYPE as x, readResponsesReasoningTokens as y, normalizeToolParameterSchema as z };