@xiaoso/dsh-tool-plus 0.1.6 → 0.1.7-beta.0

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 (119) hide show
  1. package/THIRD_PARTY_NOTICES.md +9 -3
  2. package/lib/{abort-Cwwm4Err.mjs → abort-Caqff3M6.mjs} +2 -2
  3. package/lib/alibaba-coding-plan-DTupMiAi.mjs +73 -0
  4. package/lib/alibaba-token-plan-CHGyWOfX.mjs +46 -0
  5. package/lib/alibaba-token-plan-Dj3OZhEE.mjs +82 -0
  6. package/lib/{amazon-bedrock-TVMpUTRG.mjs → amazon-bedrock-DbFSYXfJ.mjs} +117 -38
  7. package/lib/{anthropic-BL6LFDQS.mjs → anthropic-CTJ3IQVa.mjs} +675 -166
  8. package/lib/anthropic-CXfWlp-x.mjs +105 -0
  9. package/lib/{aws-credentials-B20dliS7.mjs → anthropic-wire-CKuhDwZ1.mjs} +74 -14
  10. package/lib/{api-key-login-CIDnXeYd.mjs → api-key-validation-CGCJFbFr.mjs} +27 -68
  11. package/lib/{azure-openai-responses-BkhsLmN3.mjs → azure-openai-responses-ChFbWaGj.mjs} +27 -16
  12. package/lib/{browser-render-CmgvSNte.mjs → browser-render-9o0Rknop.mjs} +4 -4
  13. package/lib/bun-shim.mjs +71 -2
  14. package/lib/{bundled-references-ChZSPDFw.mjs → bundled-references-DY3EJxZV.mjs} +6 -5
  15. package/lib/cline-pass-Bwg3esu9.mjs +44 -0
  16. package/lib/cloudflare-ai-gateway-BupNXyKK.mjs +35 -0
  17. package/lib/cloudflare-ai-gateway-EWo0VkP5.mjs +44 -0
  18. package/lib/collapse-DOR8sOGf.mjs +2304 -0
  19. package/lib/coreweave-C82HrLpb.mjs +31 -0
  20. package/lib/coreweave-Ct8cF-da.mjs +14 -0
  21. package/lib/{cursor-B6HcmplF.mjs → cursor-B95LzVWV.mjs} +11 -3
  22. package/lib/{cursor-CRpLpaZ3.mjs → cursor-DJV_dcgB.mjs} +887 -1784
  23. package/lib/{cursor-B8m6SqAH.mjs → cursor-LKGjucn2.mjs} +48 -38
  24. package/lib/cursor-proto-B8Wj8bv9.mjs +10513 -0
  25. package/lib/{deterministic-id-D-yIV_eI.mjs → deterministic-id-CUEIMSqR.mjs} +1 -1
  26. package/lib/devin-BMTdx_hx.mjs +316 -0
  27. package/lib/{devin-DUAfvBsW.mjs → devin-DSp0Rw_E.mjs} +172 -86
  28. package/lib/devin-ExGIghmx.mjs +69 -0
  29. package/lib/devin-proto-Br8fdyNl.mjs +2888 -0
  30. package/lib/{dom-CawWi8fa.mjs → dom-DG3sPESc.mjs} +8 -8
  31. package/lib/effort-BdtQMN-_.mjs +23 -0
  32. package/lib/{error-C-f_Wnw4.mjs → error-CORgGg5a.mjs} +275 -154
  33. package/lib/{event-stream-Dh2guZxS.mjs → event-stream-ulcDenZD.mjs} +20 -4
  34. package/lib/{gemini-headers-DKUShltF.mjs → gemini-headers-Co9cVvex.mjs} +2 -2
  35. package/lib/{github-copilot-suDymKrx.mjs → github-copilot-Dstq1D3s.mjs} +69 -29
  36. package/lib/github-copilot-headers-DOh1gt_w.mjs +312 -0
  37. package/lib/gitlab-duo-DSCMrU0m.mjs +11 -0
  38. package/lib/google-CtsKkOQK.mjs +38 -0
  39. package/lib/google-antigravity-z-5KsEci.mjs +252 -0
  40. package/lib/{google-auth-DYJLM792.mjs → google-auth-ieLBaneO.mjs} +4 -4
  41. package/lib/{google-gemini-cli-8BT513Ul.mjs → google-gemini-cli-C6NE5mWz.mjs} +28 -54
  42. package/lib/{google-gemini-cli-D6cSmfvB.mjs → google-gemini-cli-CAIPSl7e.mjs} +23 -29
  43. package/lib/google-oauth-shared-DhMllAkt.mjs +53 -0
  44. package/lib/{google-shared-CVbHK5vZ.mjs → google-shared-B0aNCYEH.mjs} +140 -44
  45. package/lib/{google-validation-Cgbn3tWJ.mjs → google-validation-BEkNs-Bx.mjs} +1 -1
  46. package/lib/{google-vertex-Bui-ypAe.mjs → google-vertex-Bbd1tYNc.mjs} +8 -8
  47. package/lib/hosts-00rjRzUD.mjs +203 -0
  48. package/lib/id-AL5obQzR.mjs +71 -0
  49. package/lib/{idle-iterator-CYAxUkSD.mjs → idle-iterator-DlUkEfzW.mjs} +3 -3
  50. package/lib/index.mjs +587 -5266
  51. package/lib/kilo-ChJL54wq.mjs +81 -0
  52. package/lib/kimi-C2c_Zq8A.mjs +67 -0
  53. package/lib/{launch-BmgEUycu.mjs → launch-DKDH71En.mjs} +1 -1
  54. package/lib/markit-CmRfm4E2.mjs +9885 -0
  55. package/lib/models-DnXMYGcJ.mjs +381604 -0
  56. package/lib/muse-code-Di1VZmB1.mjs +143 -0
  57. package/lib/{ollama-Df9ce-Cp.mjs → ollama-B8ic3sEp.mjs} +15 -30
  58. package/lib/{openai-codex-CAVI3Me-.mjs → openai-codex-DuJNC99x.mjs} +29 -99
  59. package/lib/{openai-codex-responses-BcnOotRB.mjs → openai-codex-responses-BL29nh9K.mjs} +204 -116
  60. package/lib/{openai-completions-Bq4WT47M.mjs → openai-completions-BK2f2dBv.mjs} +152 -82
  61. package/lib/openai-configuration-update-xMYUjaK_.mjs +150 -0
  62. package/lib/{openai-reasoning-fallback-DXsfiSXO.mjs → openai-reasoning-fallback-BdB3RCbj.mjs} +106 -12
  63. package/lib/{openai-responses-Mq_-PjvE.mjs → openai-responses-CGQPlIIy.mjs} +76 -82
  64. package/lib/{perplexity-XgLF73E7.mjs → perplexity-TBjz3VMB.mjs} +52 -9
  65. package/lib/{pkce-BlQikGPu.mjs → pkce-BYjmugmw.mjs} +1 -1
  66. package/lib/protobuf-aab1UGVn.mjs +717 -0
  67. package/lib/{provider-response-C6vcbQyO.mjs → provider-response-SqKSkkUc.mjs} +1 -1
  68. package/lib/{proxy-D9lm7ONA.mjs → proxy-5nWqRL1f.mjs} +45 -5
  69. package/lib/{readability-Cpm-ocau.mjs → readability-uGhqb4GC.mjs} +2 -2
  70. package/lib/reference-CtvM4zLU.mjs +114 -0
  71. package/lib/{request-debug-HJMoJncL.mjs → request-debug-NQN0BjHH.mjs} +1 -1
  72. package/lib/{sanitize-text-CfcXzw5X.mjs → sanitize-text-BCf5KmCf.mjs} +1 -1
  73. package/lib/{scrapers-Cg5w77td.mjs → scrapers-D8oWspgW.mjs} +12 -12
  74. package/lib/{src-BcD0_rQR.mjs → src-BwW51vA5.mjs} +979 -388
  75. package/lib/{sse-debug-CYdjOC96.mjs → sse-debug-B-tkLCPW.mjs} +1 -1
  76. package/lib/{stream-Bjq8wjfr.mjs → stream-B_7qN-bA.mjs} +3802 -2623
  77. package/lib/stream-markup-healing-DKT1lnkW.mjs +267 -0
  78. package/lib/{strict-tool-validation-imVLUcbI.mjs → strict-tool-validation-CBTz1dAA.mjs} +2 -2
  79. package/lib/taxonomy-DSIM99rS.mjs +15392 -0
  80. package/lib/{stream-markup-healing-DZ6bVDxH.mjs → thinking-CiLa2LFB.mjs} +31 -186
  81. package/lib/{turndown-DN7ByzEI.mjs → turndown-DrX1M4WG.mjs} +4 -4
  82. package/lib/{type-guards-B9VVjRDK.mjs → type-guards-CttAANEx.mjs} +1 -1
  83. package/lib/{types-DX_bvuus.mjs → types-PVueGi9S.mjs} +2 -2
  84. package/lib/{utils-C-dSORPa.mjs → utils-CCfhUQen.mjs} +2364 -2676
  85. package/lib/{utils-Cp2Mxf_U.mjs → utils-CUPhpw9A.mjs} +413 -134
  86. package/lib/{utils-CQHPEQ3W.mjs → utils-DeWqNWV8.mjs} +2 -2
  87. package/lib/{vision-guard-mBmtAHx0.mjs → vision-guard-_XwsL1DF.mjs} +14 -29
  88. package/lib/xai-oauth-CXhnz0gO.mjs +210 -0
  89. package/lib/{xiaomi-7mE345KX.mjs → xiaomi-psoUItal.mjs} +8 -37
  90. package/lib/{zai-CeNpMV3W.mjs → zai-ApJ8HBgT.mjs} +8 -71
  91. package/lib/{zip-BK7UHCwX.mjs → zip-Kd602XNe.mjs} +1 -1
  92. package/package.json +11 -11
  93. package/presets/package.json +1 -1
  94. package/presets/tool-plus-ptc/agent.cordis.yml +1 -1
  95. package/presets/tool-plus-standard/agent.cordis.yml +1 -1
  96. package/lib/agent_pb-Rizyt9Zg.mjs +0 -805
  97. package/lib/anthropic-CDmj476p.mjs +0 -262
  98. package/lib/api_server_pb-CDZgLMta.mjs +0 -252
  99. package/lib/callback-server-CFJK-jvK.mjs +0 -398
  100. package/lib/codex-P1dGpX7G.mjs +0 -54
  101. package/lib/device-code-CuXTWYwY.mjs +0 -51
  102. package/lib/devin-BcQwht1W.mjs +0 -114
  103. package/lib/devin-BvMfGevz.mjs +0 -95
  104. package/lib/github-copilot-B3kQl0g0.mjs +0 -104
  105. package/lib/gitlab-duo-BriUTP8k.mjs +0 -155
  106. package/lib/gitlab-duo-workflow-wK5Ljzmc.mjs +0 -91
  107. package/lib/google-CE5tFDod.mjs +0 -30
  108. package/lib/google-antigravity-C1jgNljz.mjs +0 -198
  109. package/lib/google-oauth-shared-BLVTvokk.mjs +0 -147
  110. package/lib/grammar-D-NqNUxQ.mjs +0 -49
  111. package/lib/identity-HNO1Oe9B.mjs +0 -219
  112. package/lib/kimi-DgcUpPtK.mjs +0 -236
  113. package/lib/markit-DtGoRE6M.mjs +0 -1417
  114. package/lib/minimax-code-Y3h5li9N.mjs +0 -53
  115. package/lib/models-DRA2c_8U.mjs +0 -104660
  116. package/lib/opencode-BsVw9rCD.mjs +0 -38
  117. package/lib/to-binary-B1BEBIPC.mjs +0 -6002
  118. package/lib/wafer-BlhWLweO.mjs +0 -17
  119. package/lib/xai-oauth-5pORHUrg.mjs +0 -446
@@ -1,24 +1,24 @@
1
1
  import { installBunShim as __installBunShim } from "./bun-shim.mjs";
2
2
  __installBunShim();
3
3
  import { r as __exportAll } from "./fs-promises-shim-Bx0fpxuk.mjs";
4
- import { B as USER_AGENT, C as error, I as $flag, P as $env, S as debug, g as parseStreamingJson, o as readSseJson, q as getInstallId, t as structuredCloneJSON, w as time } from "./src-BcD0_rQR.mjs";
5
- import { G as fetchWithRetry, V as ProviderHttpError, g as MissingApiKeyError, l as finalize, v as AbortError } from "./error-C-f_Wnw4.mjs";
6
- import { A as NO_STRICT, C as kStreamingPartialJson, L as sanitizeSchemaForOpenAIResponses, a as normalizeSystemPrompts, c as sanitizeOpenAIResponsesAssistantFallbackItemsForReplay, d as stripOpenAIResponsesComputerLinkedReasoningIdsForReplay, h as clearStreamingPartialJson, j as adaptSchemaForStrict, k as toolWireSchema, l as sanitizeOpenAIResponsesAssistantHistoryItemsForReplay, m as transformMessages, n as getOpenAIResponsesHistoryItems, p as redactSensitiveInObject, r as getOpenAIResponsesHistoryPayload, t as createOpenAIResponsesHistoryPayload } from "./utils-Cp2Mxf_U.mjs";
7
- import { t as asRecord } from "./type-guards-B9VVjRDK.mjs";
8
- import { A as computerCallMetadata, B as finalizeCustomToolCallInputDone, E as buildResponsesDeltaInput, F as createSequentialCutoffSummaryState, H as finalizePendingResponsesToolCalls, K as getOpenAIPromptCacheKey, L as encodeResponsesToolCallId, M as convertResponsesInputContent, Q as isOpenAIResponsesProgressEvent, R as encodeTextSignatureV1, U as finalizeReasoningThinking, V as finalizeMessageText, W as finalizeToolCallArgumentsDone, X as hasExecutableIncompleteResponsesToolCalls, a as accumulateCustomToolCallInputDelta, at as populateResponsesUsageFromResponse, bt as escapeHarmonyControlTokens, c as appendMessageTextDelta, d as appendReasoningSummaryTextDelta, f as appendResponsesImageResult, j as convertResponsesAssistantMessage, l as appendReasoningSummaryPart, n as getEnvApiKey, nt as mapOpenAIResponsesStopReason, o as accumulateToolCallArgumentsDelta, p as appendResponsesToolResultMessages, r as isOfficialCodexApiUrl, rt as normalizeOpenAIPromptCacheKey, s as appendMessageContentPart, st as promoteResponsesToolUseStopReason, tt as mapOpenAIReasoningEffort, u as appendReasoningSummaryPartDone, x as applyReasoningSummaryDone, xt as isHarmonyDialectModel, y as applyOpenAIServiceTier, z as escapeReplayedControlTokens } from "./stream-Bjq8wjfr.mjs";
9
- import { r as getProxyForUrl } from "./proxy-D9lm7ONA.mjs";
10
- import { E as supportsCodexReasoningSummary, T as supportsAllTurnsReasoningContext, s as requireSupportedEffort, t as calculateCost } from "./models-DRA2c_8U.mjs";
11
- import { a as toNumber } from "./utils-CQHPEQ3W.mjs";
12
- import "./identity-HNO1Oe9B.mjs";
13
- import { t as AssistantMessageEventStream } from "./event-stream-Dh2guZxS.mjs";
14
- import { a as getCodexAccountId, i as OPENAI_HEADER_VALUES, n as CODEX_CLIENT_VERSION, r as OPENAI_HEADERS, t as CODEX_BASE_URL } from "./codex-P1dGpX7G.mjs";
15
- import { n as getOpenAIStreamFirstEventTimeoutMs, o as iterateWithIdleTimeout, r as getOpenAIStreamIdleTimeoutMs, t as armPreResponseTimeout } from "./idle-iterator-CYAxUkSD.mjs";
16
- import { n as isRequestDebugEnabled, t as createRequestDebugSession } from "./request-debug-HJMoJncL.mjs";
17
- import { t as notifyRawSseEvent } from "./sse-debug-CYdjOC96.mjs";
18
- import { t as compactGrammarDefinition } from "./grammar-D-NqNUxQ.mjs";
4
+ import { B as USER_AGENT, F as $flag, N as $env, S as time, _ as parseStreamingJson, b as debug, o as readSseJson, q as getInstallId, t as structuredCloneJSON, x as error } from "./src-BwW51vA5.mjs";
5
+ import { G as fetchWithRetry, V as ProviderHttpError, _ as AbortError, b as PYTHON_HTTP2_STREAM_RESET_PATTERN, c as finalize, h as MissingApiKeyError, i as isProviderRetryableError, x as PYTHON_HTTP_INCOMPLETE_CHUNK_PATTERN } from "./error-CORgGg5a.mjs";
6
+ import { A as toolWireSchema, M as adaptSchemaForStrict, f as stripOpenAIResponsesComputerLinkedReasoningIdsForReplay, g as clearStreamingPartialJson, h as transformMessages, i as getOpenAIResponsesHistoryPayload, j as NO_STRICT, l as sanitizeOpenAIResponsesAssistantFallbackItemsForReplay, m as redactSensitiveInObject, o as normalizeSystemPrompts, r as getOpenAIResponsesHistoryItems, t as createOpenAIResponsesHistoryPayload, u as sanitizeOpenAIResponsesAssistantHistoryItemsForReplay, w as kStreamingPartialJson, z as sanitizeSchemaForOpenAIResponses } from "./utils-CUPhpw9A.mjs";
7
+ import { t as asRecord } from "./type-guards-CttAANEx.mjs";
8
+ import { B as convertResponsesInputContent, D as applyOpenAIServiceTier, Dt as escapeHarmonyControlTokens, G as encodeResponsesToolCallId, J as finalizeCustomToolCallInputDone, K as encodeTextSignatureV1, Ot as isHarmonyDialectModel, P as buildResponsesDeltaInput, Q as finalizeToolCallArgumentsDone, R as computerCallMetadata, U as createSequentialCutoffSummaryState, X as finalizePendingResponsesToolCalls, Y as finalizeMessageText, Z as finalizeReasoningThinking, _ as appendReasoningSummaryPart, a as CODEX_BASE_URL, b as appendResponsesImageResult, c as OPENAI_HEADER_VALUES, ct as mapOpenAIReasoningEffort, d as getCodexAccountId, et as getOpenAIPromptCacheKey, ft as populateResponsesUsageFromResponse, g as appendMessageTextDelta, h as appendMessageContentPart, it as hasExecutableIncompleteResponsesToolCalls, k as applyReasoningSummaryDone, kt as hasVisibleAssistantContent, l as applyCodexResidencyHeader, lt as mapOpenAIResponsesStopReason, m as accumulateToolCallArgumentsDelta, mt as promoteResponsesToolUseStopReason, n as getEnvApiKey, o as CODEX_CLIENT_VERSION, ot as isOpenAIResponsesProgressEvent, p as accumulateCustomToolCallInputDelta, q as escapeReplayedControlTokens, r as isOfficialCodexApiUrl, s as OPENAI_HEADERS, u as codexRoutingHint, ut as normalizeOpenAIPromptCacheKey, v as appendReasoningSummaryPartDone, x as appendResponsesToolResultMessages, y as appendReasoningSummaryTextDelta, z as convertResponsesAssistantMessage } from "./stream-B_7qN-bA.mjs";
9
+ import { a as toNumber } from "./utils-DeWqNWV8.mjs";
10
+ import { o as requireSupportedEffort } from "./anthropic-wire-CKuhDwZ1.mjs";
11
+ import { n as getProxyForUrl } from "./proxy-5nWqRL1f.mjs";
12
+ import "./effort-BdtQMN-_.mjs";
13
+ import { t as calculateCost } from "./models-DnXMYGcJ.mjs";
14
+ import { t as AssistantMessageEventStream } from "./event-stream-ulcDenZD.mjs";
15
+ import { n as getOpenAIStreamFirstEventTimeoutMs, o as iterateWithIdleTimeout, r as getOpenAIStreamIdleTimeoutMs, t as armPreResponseTimeout } from "./idle-iterator-DlUkEfzW.mjs";
16
+ import { n as isRequestDebugEnabled, t as createRequestDebugSession } from "./request-debug-NQN0BjHH.mjs";
17
+ import { t as notifyRawSseEvent } from "./sse-debug-B-tkLCPW.mjs";
18
+ import { n as planStableOpenAIEffort, r as compactGrammarDefinition, t as getOpenAIEffortControlState } from "./openai-configuration-update-xMYUjaK_.mjs";
19
19
  import { scheduler } from "node:timers/promises";
20
20
  import { type } from "@oh-my-pi/omptype";
21
- //#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/providers/openai-codex/request-transformer.ts
21
+ //#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.1.17/node_modules/@oh-my-pi/pi-ai/src/providers/openai-codex/request-transformer.ts
22
22
  /** Caller literal → catalog `Effort` bridge (the enum is nominal). */
23
23
  const EFFORT_BY_NAME = {
24
24
  minimal: "minimal",
@@ -29,18 +29,17 @@ const EFFORT_BY_NAME = {
29
29
  max: "max"
30
30
  };
31
31
  /**
32
- * Resolve whether a Codex request uses the Responses Lite transport: an
33
- * explicit option wins, then the `PI_CODEX_RESPONSES_LITE` env override
34
- * (`1`/`true` forces Lite, `0`/`false` forces the full Responses body),
35
- * otherwise the model's catalog flag (codex-rs `model_info.use_responses_lite`)
36
- * decides.
32
+ * Resolve whether a Codex request explicitly opts into Responses Lite.
33
+ *
34
+ * Provider-native compaction passes the model's `useResponsesLite` flag as an
35
+ * explicit option; normal inference defaults to the full Responses contract.
37
36
  */
38
- function resolveCodexResponsesLite(model, requested) {
37
+ function resolveCodexResponsesLite(requested) {
39
38
  if (requested !== void 0) return requested;
40
39
  const env = $env.PI_CODEX_RESPONSES_LITE?.trim().toLowerCase();
41
40
  if (env === "1" || env === "true") return true;
42
41
  if (env === "0" || env === "false") return false;
43
- return model.useResponsesLite === true;
42
+ return false;
44
43
  }
45
44
  /**
46
45
  * Whether to request `stream_options.reasoning_summary_delivery =
@@ -79,7 +78,7 @@ function mapCodexWireEffort(model, effort) {
79
78
  }
80
79
  function getReasoningConfig(model, effort, options) {
81
80
  const config = { effort: effort === "none" ? "none" : mapCodexWireEffort(model, effort) };
82
- if (options.reasoningSummary !== null && supportsCodexReasoningSummary(model.id)) config.summary = options.reasoningSummary ?? "auto";
81
+ if (options.reasoningSummary !== null && model.compat.supportsReasoningSummary) config.summary = options.reasoningSummary ?? "auto";
83
82
  return config;
84
83
  }
85
84
  function filterInput(input) {
@@ -297,7 +296,7 @@ async function transformRequestBody(body, model, options = {}, prompt) {
297
296
  }]
298
297
  }];
299
298
  }
300
- const responsesLite = resolveCodexResponsesLite(model, options.responsesLite);
299
+ const responsesLite = resolveCodexResponsesLite(options.responsesLite);
301
300
  if (responsesLite) applyCodexResponsesLiteShape(body);
302
301
  if (options.reasoningOff || options.reasoningEffort !== void 0 || responsesLite) {
303
302
  const reasoningConfig = options.reasoningOff ? { effort: "none" } : options.reasoningEffort !== void 0 ? getReasoningConfig(model, options.reasoningEffort, options) : {};
@@ -307,10 +306,11 @@ async function transformRequestBody(body, model, options = {}, prompt) {
307
306
  };
308
307
  if (responsesLite) body.reasoning.context = "all_turns";
309
308
  else if (options.reasoningContext !== void 0) {
310
- if (options.reasoningContext === "all_turns" && !supportsAllTurnsReasoningContext(model.id)) delete body.reasoning.context;
309
+ if (options.reasoningContext === "all_turns" && !model.compat.supportsAllTurnsReasoningContext) delete body.reasoning.context;
311
310
  else body.reasoning.context = options.reasoningContext;
312
311
  }
313
312
  } else delete body.reasoning;
313
+ if (!model.compat.supportsReasoningSummary && body.reasoning) delete body.reasoning.summary;
314
314
  if (model.reasoningMode && !options.reasoningOff) body.reasoning = {
315
315
  ...body.reasoning,
316
316
  mode: model.reasoningMode
@@ -329,7 +329,7 @@ async function transformRequestBody(body, model, options = {}, prompt) {
329
329
  return body;
330
330
  }
331
331
  //#endregion
332
- //#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/providers/openai-codex/response-handler.ts
332
+ //#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.1.17/node_modules/@oh-my-pi/pi-ai/src/providers/openai-codex/response-handler.ts
333
333
  /** Non-2xx response from the Codex backend, with the parsed body retained. */
334
334
  var CodexApiError = class CodexApiError extends ProviderHttpError {
335
335
  info;
@@ -393,7 +393,7 @@ function toInt(v) {
393
393
  return Number.isFinite(n) ? n : void 0;
394
394
  }
395
395
  //#endregion
396
- //#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/providers/openai-codex-responses.ts
396
+ //#region node_modules/.pnpm/@oh-my-pi+pi-ai@18.1.17/node_modules/@oh-my-pi/pi-ai/src/providers/openai-codex-responses.ts
397
397
  var openai_codex_responses_exports = /* @__PURE__ */ __exportAll({
398
398
  CodexWebSocketTransportError: () => CodexWebSocketTransportError,
399
399
  buildTransformedCodexRequestBody: () => buildTransformedCodexRequestBody,
@@ -517,6 +517,7 @@ const CODEX_RESERVED_METADATA_KEYS = {
517
517
  request_kind: true,
518
518
  compaction: true,
519
519
  code_mode_tool_names: true,
520
+ tool_namespaces_info: true,
520
521
  turn_started_at_unix_ms: true,
521
522
  forked_from_thread_id: true,
522
523
  parent_thread_id: true,
@@ -530,7 +531,8 @@ function createCodexMetadataSessionState(sessionId) {
530
531
  return {
531
532
  sessionId,
532
533
  threadId: crypto.randomUUID(),
533
- windowId: crypto.randomUUID()
534
+ windowId: crypto.randomUUID(),
535
+ turnStates: /* @__PURE__ */ new Map()
534
536
  };
535
537
  }
536
538
  function getOrCreateCodexMetadataSessionState(sessionId, providerState) {
@@ -541,6 +543,24 @@ function getOrCreateCodexMetadataSessionState(sessionId, providerState) {
541
543
  providerState.metadataSessions.set(sessionId, created);
542
544
  return created;
543
545
  }
546
+ function getOrCreateCodexTurnState(session, compatibilityKey) {
547
+ if (!compatibilityKey) return {};
548
+ const existing = session.turnStates.get(compatibilityKey);
549
+ if (existing) return existing;
550
+ const created = {};
551
+ session.turnStates.set(compatibilityKey, created);
552
+ return created;
553
+ }
554
+ /**
555
+ * Drop every compatibility-scoped sticky-routing token when a fresh logical
556
+ * turn begins, mirroring codex-rs's per-turn `OnceLock`. Standalone compaction
557
+ * owns a throwaway cell, so it never disturbs the live turn's tokens. Runs on
558
+ * every entry path that opens a turn — the normal stream (`createCodexRequestContext`)
559
+ * and the raw compaction routes (`createOpenAICodexCompatibilityMetadata`).
560
+ */
561
+ function clearCodexTurnStatesForNewTurn(session, startNewTurn, compaction) {
562
+ if (startNewTurn && compaction?.phase !== "standalone_turn") session.turnStates.clear();
563
+ }
544
564
  function createCodexCompatibilityIdentity(session) {
545
565
  return {
546
566
  installationId: getInstallId(),
@@ -598,7 +618,12 @@ function createCodexRequestMetadata(session, requestKind, options) {
598
618
  };
599
619
  if (session.turnStartedAtUnixMs !== void 0) turnMetadata.turn_started_at_unix_ms = session.turnStartedAtUnixMs;
600
620
  for (const key in extra) turnMetadata[key] = extra[key];
601
- const turnMetadataJson = toAsciiJsonString(turnMetadata);
621
+ const turnMetadataHeaderJson = toAsciiJsonString(turnMetadata);
622
+ let turnMetadataJson = turnMetadataHeaderJson;
623
+ if (options.toolNamespacesInfo !== void 0) {
624
+ turnMetadata.tool_namespaces_info = options.toolNamespacesInfo;
625
+ turnMetadataJson = toAsciiJsonString(turnMetadata);
626
+ }
602
627
  const clientMetadata = {
603
628
  [OPENAI_HEADERS.INSTALLATION_ID]: identity.installationId,
604
629
  session_id: identity.sessionId,
@@ -612,6 +637,7 @@ function createCodexRequestMetadata(session, requestKind, options) {
612
637
  ...identity,
613
638
  turnId: session.turnId,
614
639
  turnMetadataJson,
640
+ turnMetadataHeaderJson,
615
641
  clientMetadata
616
642
  };
617
643
  }
@@ -619,7 +645,7 @@ function applyCodexCompatibilityHeaders(headers, metadata) {
619
645
  headers.set(OPENAI_HEADERS.SCOPED_SESSION_ID, metadata.sessionId);
620
646
  headers.set(OPENAI_HEADERS.THREAD_ID, metadata.threadId);
621
647
  headers.set(OPENAI_HEADERS.WINDOW_ID, metadata.windowId);
622
- if (metadata.turnMetadataJson) headers.set(OPENAI_HEADERS.TURN_METADATA, metadata.turnMetadataJson);
648
+ if (metadata.turnMetadataHeaderJson) headers.set(OPENAI_HEADERS.TURN_METADATA, metadata.turnMetadataHeaderJson);
623
649
  else headers.delete(OPENAI_HEADERS.TURN_METADATA);
624
650
  }
625
651
  var CodexStreamRuntime = class {
@@ -775,28 +801,25 @@ var CodexStreamRuntime = class {
775
801
  const input = rawEvent.input;
776
802
  if (typeof input === "string") finalizeCustomToolCallInputDone(entry.block, input);
777
803
  }
778
- handleResponseCreated(rawEvent) {
779
- const response = rawEvent.response;
780
- const state = this.websocketState;
781
- if (state && this.transport === "websocket" && typeof response?.id === "string" && response.id.length > 0) state.lastResponseId = response.id;
782
- }
783
804
  };
784
805
  function createCodexProviderSessionState() {
785
806
  const state = {
786
807
  webSocketSessions: /* @__PURE__ */ new Map(),
787
808
  webSocketPublicToPrivate: /* @__PURE__ */ new Map(),
788
809
  metadataSessions: /* @__PURE__ */ new Map(),
810
+ effortControls: /* @__PURE__ */ new Map(),
789
811
  close: () => {
790
812
  for (const session of state.webSocketSessions.values()) session.connection?.close("session_disposed");
791
813
  state.webSocketSessions.clear();
792
814
  state.webSocketPublicToPrivate.clear();
793
815
  state.metadataSessions.clear();
816
+ state.effortControls.clear();
794
817
  }
795
818
  };
796
819
  return state;
797
820
  }
798
821
  function isCodexProviderSessionState(state) {
799
- return state !== void 0 && "webSocketSessions" in state && state.webSocketSessions instanceof Map && "webSocketPublicToPrivate" in state && state.webSocketPublicToPrivate instanceof Map && "metadataSessions" in state && state.metadataSessions instanceof Map;
822
+ return state !== void 0 && "webSocketSessions" in state && state.webSocketSessions instanceof Map && "webSocketPublicToPrivate" in state && state.webSocketPublicToPrivate instanceof Map && "metadataSessions" in state && state.metadataSessions instanceof Map && "effortControls" in state && state.effortControls instanceof Map;
800
823
  }
801
824
  function getCodexProviderSessionState(providerSessionState) {
802
825
  if (!providerSessionState) return void 0;
@@ -831,13 +854,13 @@ function toCodexHeaders(value) {
831
854
  if (!record) return void 0;
832
855
  return new Headers(record);
833
856
  }
834
- function updateCodexSessionMetadataFromHeaders(state, headers) {
835
- if (!state || !headers) return;
857
+ function updateCodexSessionMetadataFromHeaders(turnState, state, headers) {
858
+ if (!turnState && !state || !headers) return;
836
859
  const resolvedHeaders = headers instanceof Headers ? headers : new Headers(headers);
837
- const turnState = resolvedHeaders.get(X_CODEX_TURN_STATE_HEADER);
838
- if (turnState && turnState.length > 0) state.turnState = turnState;
860
+ const responseTurnState = resolvedHeaders.get(X_CODEX_TURN_STATE_HEADER);
861
+ if (turnState && turnState.value === void 0 && responseTurnState && responseTurnState.length > 0) turnState.value = responseTurnState;
839
862
  const modelsEtag = resolvedHeaders.get(X_MODELS_ETAG_HEADER);
840
- if (modelsEtag && modelsEtag.length > 0) state.modelsEtag = modelsEtag;
863
+ if (state && modelsEtag && modelsEtag.length > 0) state.modelsEtag = modelsEtag;
841
864
  }
842
865
  function extractCodexWebSocketHandshakeHeaders(socket, openEvent) {
843
866
  const eventRecord = openEvent;
@@ -979,11 +1002,8 @@ function unrollCodexComputerToolResult(message) {
979
1002
  return result;
980
1003
  }
981
1004
  function getCodexServiceTierCostMultiplier(model, serviceTier) {
982
- switch (serviceTier) {
983
- case "flex": return .5;
984
- case "priority": return model.id === "gpt-5.5" ? 2.5 : 2;
985
- default: return 1;
986
- }
1005
+ if (serviceTier !== "flex" && serviceTier !== "priority") return 1;
1006
+ return model.serviceTierCost?.[serviceTier] ?? 1;
987
1007
  }
988
1008
  function resolveCodexCostServiceTier(res, req) {
989
1009
  switch (res) {
@@ -1057,8 +1077,8 @@ function createCodexRequestContext(model, transformedBody, options, contextOptio
1057
1077
  const transportSessionId = normalizeOpenAIPromptCacheKey(options?.sessionId);
1058
1078
  const codexClientVersion = CODEX_CLIENT_VERSION;
1059
1079
  const requestHeaders = {
1060
- ...model.headers ?? {},
1061
- ...options?.headers ?? {}
1080
+ ...model.headers,
1081
+ ...options?.headers
1062
1082
  };
1063
1083
  const rawRequestDump = {
1064
1084
  provider: model.provider,
@@ -1071,7 +1091,7 @@ function createCodexRequestContext(model, transformedBody, options, contextOptio
1071
1091
  const providerSessionState = getCodexProviderSessionState(options?.providerSessionState);
1072
1092
  const isolatedTransportState = contextOptions.isolateCompactionTransport && options?.codexCompaction ? createCodexProviderSessionState() : void 0;
1073
1093
  const transportProviderSessionState = isolatedTransportState ?? providerSessionState;
1074
- const responsesLite = resolveCodexResponsesLite(model, options?.responsesLite);
1094
+ const responsesLite = resolveCodexResponsesLite(options?.responsesLite);
1075
1095
  const sessionKey = getCodexWebSocketSessionKey(transportSessionId, model, accountId, apiKey, baseUrl, responsesLite);
1076
1096
  const publicSessionKey = transportSessionId ? `${baseUrl}:${model.id}:${transportSessionId}` : void 0;
1077
1097
  if (sessionKey && publicSessionKey) transportProviderSessionState?.webSocketPublicToPrivate.set(publicSessionKey, sessionKey);
@@ -1079,20 +1099,22 @@ function createCodexRequestContext(model, transformedBody, options, contextOptio
1079
1099
  const websocketState = sessionKey && isolatedTransportState ? getCodexWebSocketSessionState(sessionKey, isolatedTransportState) : sharedWebsocketState;
1080
1100
  if (isolatedTransportState && websocketState && sharedWebsocketState) {
1081
1101
  websocketState.disableWebsocket = sharedWebsocketState.disableWebsocket;
1082
- websocketState.turnState = sharedWebsocketState.turnState;
1083
1102
  websocketState.modelsEtag = sharedWebsocketState.modelsEtag;
1084
1103
  }
1085
1104
  const metadataSession = getOrCreateCodexMetadataSessionState(transportSessionId ?? crypto.randomUUID(), providerSessionState);
1086
1105
  const compaction = options?.codexCompaction;
1087
1106
  const requestKind = compaction ? "compaction" : "turn";
1088
1107
  const startNewTurn = resolveCodexStartNewTurn(metadataSession, requestKind, compaction, contextOptions.startNewTurn);
1089
- if (websocketState && startNewTurn) websocketState.turnState = void 0;
1108
+ const standaloneCompaction = compaction?.phase === "standalone_turn";
1109
+ clearCodexTurnStatesForNewTurn(metadataSession, startNewTurn, compaction);
1110
+ const turnState = standaloneCompaction ? {} : getOrCreateCodexTurnState(metadataSession, sessionKey);
1090
1111
  const requestMetadata = createCodexRequestMetadata(metadataSession, requestKind, {
1091
1112
  startNewTurn,
1092
1113
  turnStartedAtUnixMs: compaction ? startNewTurn || !metadataSession.turnId ? Date.now() : void 0 : contextOptions.turnStartedAtUnixMs,
1093
1114
  clientMetadata: transformedBody.client_metadata,
1094
1115
  parentTurnId: options?.parentTurnId,
1095
- compaction
1116
+ compaction,
1117
+ toolNamespacesInfo: options?.toolNamespacesInfo
1096
1118
  });
1097
1119
  transformedBody.client_metadata = requestMetadata.clientMetadata;
1098
1120
  return {
@@ -1105,6 +1127,7 @@ function createCodexRequestContext(model, transformedBody, options, contextOptio
1105
1127
  providerSessionState,
1106
1128
  isolatedTransportState,
1107
1129
  websocketState,
1130
+ turnState,
1108
1131
  responsesLite,
1109
1132
  requestMetadata,
1110
1133
  codexClientVersion,
@@ -1119,11 +1142,12 @@ async function buildCodexRequestContext(model, context, options) {
1119
1142
  turnStartedAtUnixMs: options?.codexCompaction ? void 0 : getCodexTurnStartedAtUnixMs(context)
1120
1143
  });
1121
1144
  }
1122
- /** @internal Exported for tests. */
1123
- async function buildTransformedCodexRequestBody(model, context, options, promptCacheKey = getOpenAIPromptCacheKey(options)) {
1145
+ /** Serialize normal Codex turns and V2 compaction with the same cacheable prefix. */
1146
+ async function buildTransformedCodexRequestBody(model, context, options, promptCacheKey = getOpenAIPromptCacheKey(options), inputPrefix) {
1147
+ const input = convertMessages(model, context);
1124
1148
  const params = {
1125
1149
  model: model.requestModelId ?? model.id,
1126
- input: convertMessages(model, context),
1150
+ input: inputPrefix?.length ? [...inputPrefix, ...input] : input,
1127
1151
  stream: true,
1128
1152
  prompt_cache_key: promptCacheKey
1129
1153
  };
@@ -1139,7 +1163,7 @@ async function buildTransformedCodexRequestBody(model, context, options, promptC
1139
1163
  if (systemPrompts.length > 0) params.instructions = systemPrompts[0];
1140
1164
  const developerMessages = systemPrompts.slice(1);
1141
1165
  if (options?.clientMetadata && Object.keys(options.clientMetadata).length > 0) params.client_metadata = { ...options.clientMetadata };
1142
- return transformRequestBody(params, model, {
1166
+ const body = await transformRequestBody(params, model, {
1143
1167
  reasoningEffort: options?.reasoning,
1144
1168
  reasoningOff: options?.forceReasoningOff,
1145
1169
  reasoningSummary: options?.reasoningSummary,
@@ -1148,6 +1172,27 @@ async function buildTransformedCodexRequestBody(model, context, options, promptC
1148
1172
  include: options?.include,
1149
1173
  responsesLite: options?.responsesLite
1150
1174
  }, { developerMessages });
1175
+ applyCodexStableEffort(model, body, options);
1176
+ return body;
1177
+ }
1178
+ /**
1179
+ * Keep the request-level effort byte-stable across a conversation and carry
1180
+ * later changes as `configuration_update` items (GPT-6 Astra). Requires a
1181
+ * session id and provider session state to remember the baseline; without
1182
+ * them every request stands alone and sends its own effort.
1183
+ */
1184
+ function applyCodexStableEffort(model, body, options) {
1185
+ if (!model.compat.supportsConfigurationUpdate || options?.codexCompaction) return;
1186
+ const effort = body.reasoning?.effort;
1187
+ if (effort === void 0 || effort === "none" || !body.input) return;
1188
+ const providerState = getCodexProviderSessionState(options?.providerSessionState);
1189
+ const sessionId = normalizeOpenAIPromptCacheKey(options?.sessionId);
1190
+ if (!providerState || !sessionId) return;
1191
+ const state = getOpenAIEffortControlState(providerState.effortControls, `${model.id}\u0000${sessionId}`);
1192
+ body.reasoning = {
1193
+ ...body.reasoning,
1194
+ effort: planStableOpenAIEffort(state, body.input, effort)
1195
+ };
1151
1196
  }
1152
1197
  async function openInitialCodexEventStream(model, options, requestSetup, requestContext) {
1153
1198
  const { transformedBody, websocketState } = requestContext;
@@ -1182,9 +1227,9 @@ async function openInitialCodexEventStream(model, options, requestSetup, request
1182
1227
  async function openCodexWebSocketTransport(model, options, requestContext, requestSetup, websocketState, retry, onSseEvent) {
1183
1228
  const canAppendBeforeRequest = websocketState.canAppend === true;
1184
1229
  const chainedBody = buildCodexChainedRequestBody(requestContext.transformedBody, websocketState);
1185
- const websocketClientMetadata = { ...chainedBody.client_metadata ?? {} };
1230
+ const websocketClientMetadata = { ...chainedBody.client_metadata };
1186
1231
  if (requestContext.responsesLite) websocketClientMetadata[CODEX_WS_RESPONSES_LITE_CLIENT_METADATA_KEY] = "true";
1187
- if (websocketState.turnState) websocketClientMetadata[X_CODEX_TURN_STATE_HEADER] = websocketState.turnState;
1232
+ if (requestContext.turnState.value) websocketClientMetadata[X_CODEX_TURN_STATE_HEADER] = requestContext.turnState.value;
1188
1233
  let websocketRequest = {
1189
1234
  type: "response.create",
1190
1235
  ...chainedBody,
@@ -1193,7 +1238,7 @@ async function openCodexWebSocketTransport(model, options, requestContext, reque
1193
1238
  const replacementWebsocketRequest = await options?.onPayload?.(websocketRequest, model);
1194
1239
  if (replacementWebsocketRequest !== void 0) websocketRequest = replacementWebsocketRequest;
1195
1240
  recordCodexTurnRequestDiagnostics(websocketState, websocketRequest, "websocket", canAppendBeforeRequest);
1196
- const websocketHeaders = createCodexHeaders(requestContext.requestHeaders, requestContext.accountId, requestContext.apiKey, requestContext.codexClientVersion, requestContext.transportSessionId, "websocket", websocketState, requestContext.responsesLite, requestContext.requestMetadata, await getCodexAttestationHeader(requestContext.accountId));
1241
+ const websocketHeaders = createCodexHeaders(requestContext.requestHeaders, requestContext.accountId, requestContext.apiKey, requestContext.codexClientVersion, requestContext.transportSessionId, "websocket", websocketState, requestContext.turnState, requestContext.responsesLite, requestContext.requestMetadata, await getCodexAttestationHeader(requestContext.accountId), requestContext.transformedBody);
1197
1242
  const requestBodyForState = structuredCloneJSON(requestContext.transformedBody);
1198
1243
  if (websocketRequest.stream_options === void 0) delete requestBodyForState.stream_options;
1199
1244
  else requestBodyForState.stream_options = websocketRequest.stream_options;
@@ -1210,7 +1255,7 @@ async function openCodexWebSocketTransport(model, options, requestContext, reque
1210
1255
  retryBudget: CODEX_WEBSOCKET_RETRY_BUDGET
1211
1256
  });
1212
1257
  return {
1213
- eventStream: (await getOrCreateCodexWebSocketConnection(websocketState, toWebSocketUrl(requestContext.url), websocketHeaders, model.provider, requestSetup.requestSignal)).streamRequest(websocketRequest, {
1258
+ eventStream: (await getOrCreateCodexWebSocketConnection(websocketState, requestContext.turnState, toWebSocketUrl(requestContext.url), websocketHeaders, model.provider, requestSetup.requestSignal)).streamRequest(websocketRequest, {
1214
1259
  idleTimeoutMs: requestSetup.websocketIdleTimeoutMs,
1215
1260
  firstEventTimeoutMs: requestSetup.websocketFirstEventTimeoutMs
1216
1261
  }, requestSetup.requestSignal, onSseEvent),
@@ -1242,7 +1287,7 @@ function isCodexWithinTurnContinuation(context) {
1242
1287
  async function openCodexSseTransport(model, requestContext, requestSetup, options, state, body = requestContext.transformedBody) {
1243
1288
  const open = async (wireBody) => {
1244
1289
  requestContext.rawRequestDump.body = wireBody;
1245
- return requestSetup.wrapCodexSseStream(await openCodexSseEventStream(requestContext.url, requestContext.requestHeaders, requestContext.accountId, requestContext.apiKey, requestContext.transportSessionId, wireBody, state, requestContext.responsesLite, requestContext.codexClientVersion, requestContext.requestMetadata, requestSetup.requestSignal, requestSetup.firstEventTimeoutMs, options?.codexSseMaxAttempts, (event) => options?.onSseEvent?.(event, model), options?.fetch));
1290
+ return requestSetup.wrapCodexSseStream(await openCodexSseEventStream(requestContext.url, requestContext.requestHeaders, requestContext.accountId, requestContext.apiKey, requestContext.transportSessionId, wireBody, state, requestContext.turnState, requestContext.responsesLite, requestContext.codexClientVersion, requestContext.requestMetadata, requestSetup.requestSignal, requestSetup.firstEventTimeoutMs, options?.codexSseMaxAttempts, (event) => options?.onSseEvent?.(event, model), options?.fetch));
1246
1291
  };
1247
1292
  const canAppendBeforeRequest = state?.canAppend === true;
1248
1293
  let wireBody = body;
@@ -1309,20 +1354,30 @@ const CODEX_STALE_PREVIOUS_RESPONSE_CODES = {
1309
1354
  previous_response_not_found: true,
1310
1355
  codex_previous_response_stale: true
1311
1356
  };
1357
+ const CODEX_APPEND_PRESERVING_REJECTION_CODES = {
1358
+ rate_limit_exceeded: true,
1359
+ slow_down: true
1360
+ };
1312
1361
  function isCodexStalePreviousResponseError(error) {
1313
1362
  if (!(error instanceof Error)) return false;
1314
1363
  if ("code" in error && typeof error.code === "string" && Object.hasOwn(CODEX_STALE_PREVIOUS_RESPONSE_CODES, error.code)) return true;
1315
1364
  return /previous[ _]?response/i.test(error.message) && /not[ _]?found|invalid|expired|stale|unsupported/i.test(error.message);
1316
1365
  }
1366
+ function shouldPreserveCodexWebSocketAppendState(context, error) {
1367
+ if (!(error instanceof CodexProviderStreamError) || !error.code) return false;
1368
+ const state = context.requestContext.websocketState;
1369
+ return Object.hasOwn(CODEX_APPEND_PRESERVING_REJECTION_CODES, error.code.toLowerCase()) && context.runtime?.transport === "websocket" && state?.canAppend === true && state.lastRequest !== void 0 && state.lastResponseId !== void 0 && state.lastResponseItems !== void 0;
1370
+ }
1317
1371
  async function handleCodexStreamFailure(context, error) {
1318
1372
  const { output } = context;
1319
- if (context.requestContext.websocketState) {
1373
+ if (context.requestContext.websocketState && !shouldPreserveCodexWebSocketAppendState(context, error)) {
1320
1374
  resetCodexWebSocketAppendState(context.requestContext.websocketState);
1321
- context.requestContext.websocketState.turnState = void 0;
1322
1375
  context.requestContext.websocketState.modelsEtag = void 0;
1323
1376
  }
1324
1377
  const result = await finalize(error, {
1325
1378
  api: context.model.api,
1379
+ provider: context.model.provider,
1380
+ model: context.model.id,
1326
1381
  signal: context.options?.signal,
1327
1382
  rawRequestDump: context.requestContext.rawRequestDump
1328
1383
  });
@@ -1383,6 +1438,16 @@ var CodexStreamProcessor = class {
1383
1438
  firstTokenTime = this.#handleStreamEvent(rawEvent, firstTokenTime);
1384
1439
  if (this.runtime.sawTerminalEvent) break;
1385
1440
  }
1441
+ if (!this.runtime.sawTerminalEvent) {
1442
+ CODEX_DEBUG && debug("[codex] codex stream ended unexpectedly", {
1443
+ transport: this.runtime.transport,
1444
+ terminalEventSeen: false,
1445
+ unexpectedStreamEnd: true,
1446
+ sentTurnStateHeader: Boolean(this.requestContext.turnState.value),
1447
+ sentModelsEtagHeader: Boolean(this.requestContext.websocketState?.modelsEtag)
1448
+ });
1449
+ throw new CodexProviderStreamError("Codex stream ended before terminal completion event", true);
1450
+ }
1386
1451
  return { firstTokenTime };
1387
1452
  } catch (error) {
1388
1453
  if (!await this.#recoverStreamError(error)) throw error;
@@ -1518,16 +1583,12 @@ var CodexStreamProcessor = class {
1518
1583
  this.#handleOutputItemDone(rawEvent);
1519
1584
  return firstTokenTime;
1520
1585
  }
1521
- if (eventType === "response.created") {
1522
- this.runtime.handleResponseCreated(rawEvent);
1523
- return firstTokenTime;
1524
- }
1525
1586
  if (eventType === "response.completed" || eventType === "response.done" || eventType === "response.incomplete") {
1526
1587
  this.#handleResponseCompleted(rawEvent);
1527
1588
  return firstTokenTime;
1528
1589
  }
1529
1590
  if (eventType === "response.metadata") {
1530
- updateCodexSessionMetadataFromHeaders(this.requestContext.websocketState, toCodexHeaders(rawEvent.headers));
1591
+ updateCodexSessionMetadataFromHeaders(this.requestContext.turnState, this.requestContext.websocketState, toCodexHeaders(rawEvent.headers));
1531
1592
  const moderation = asRecord(rawEvent.metadata)?.[CODEX_MODERATION_METADATA_KEY];
1532
1593
  if (moderation !== void 0) try {
1533
1594
  this.options?.onModerationMetadata?.(moderation);
@@ -1693,7 +1754,7 @@ var CodexStreamProcessor = class {
1693
1754
  const incompleteDetails = response && "incomplete_details" in response && response.incomplete_details && typeof response.incomplete_details === "object" ? response.incomplete_details : void 0;
1694
1755
  const shouldPromoteIncompleteToolUse = status === "incomplete" && incompleteDetails !== void 0 && "reason" in incompleteDetails && incompleteDetails.reason === "max_output_tokens" && hasExecutableIncompleteResponsesToolCalls(output);
1695
1756
  finalizePendingResponsesToolCalls(output);
1696
- calculateCost(model, output.usage);
1757
+ calculateCost(model, output.usage, output.timestamp);
1697
1758
  applyCodexServiceTierPricing(model, output.usage, serviceTier, runtime.requestBodyForState.service_tier);
1698
1759
  output.stopReason = mapOpenAIResponsesStopReason(status);
1699
1760
  promoteResponsesToolUseStopReason(output, endTurn === true ? true : endTurn === false ? false : void 0, shouldPromoteIncompleteToolUse);
@@ -1726,7 +1787,6 @@ var CodexStreamProcessor = class {
1726
1787
  const websocketState = this.requestContext.websocketState;
1727
1788
  if (websocketState) {
1728
1789
  resetCodexWebSocketAppendState(websocketState);
1729
- websocketState.turnState = void 0;
1730
1790
  websocketState.modelsEtag = void 0;
1731
1791
  }
1732
1792
  CODEX_DEBUG && debug("[codex] retrying codex turn after whitespace-only tool-call argument loop", {
@@ -1804,7 +1864,6 @@ var CodexStreamProcessor = class {
1804
1864
  if (this.runtime.transport !== "websocket") return false;
1805
1865
  this.runtime.providerRetryAttempt += 1;
1806
1866
  resetCodexWebSocketAppendState(websocketState);
1807
- websocketState.turnState = void 0;
1808
1867
  websocketState.modelsEtag = void 0;
1809
1868
  this.runtime.resetAccumulators();
1810
1869
  this.runtime.sawTerminalEvent = false;
@@ -1846,13 +1905,44 @@ var CodexStreamProcessor = class {
1846
1905
  await this.#reopenSseStream(state);
1847
1906
  return true;
1848
1907
  }
1908
+ /**
1909
+ * Emit balancing `*_end` events for every block that opened (pushed a
1910
+ * `*_start`) but never committed visible content, so a retry that resets
1911
+ * `output` and replays cannot leave the consumer with an orphaned
1912
+ * `text_start`/`thinking_start` from the abandoned attempt. Only reachable
1913
+ * blocks are empty text/reasoning ones — a committed tool/text block blocks
1914
+ * the retry upstream.
1915
+ */
1916
+ #closeOpenBlocksForReplay() {
1917
+ const { runtime, output, stream } = this;
1918
+ const open = new Set(runtime.openItems.values());
1919
+ for (const entry of runtime.openItemsByOutputIndex.values()) open.add(entry);
1920
+ if (runtime.currentEntry) open.add(runtime.currentEntry);
1921
+ for (const entry of open) {
1922
+ const block = entry.block;
1923
+ if (block?.type === "thinking") stream.push({
1924
+ type: "thinking_end",
1925
+ contentIndex: entry.contentIndex,
1926
+ content: block.thinking,
1927
+ partial: output
1928
+ });
1929
+ else if (block?.type === "text") stream.push({
1930
+ type: "text_end",
1931
+ contentIndex: entry.contentIndex,
1932
+ content: block.text,
1933
+ partial: output
1934
+ });
1935
+ }
1936
+ }
1849
1937
  async #tryRetryProviderError(error) {
1850
- if (!(error instanceof CodexProviderStreamError && error.retryable) || this.output.content.length > 0 || this.runtime.providerRetryAttempt >= CODEX_MAX_RETRIES || this.options?.signal?.aborted) return false;
1938
+ const retryable = error instanceof CodexProviderStreamError ? error.retryable : isProviderRetryableError(error);
1939
+ const streamedContent = this.output.content.some((block) => block.type === "text" && block.text.length > 0 || block.type === "thinking" && block.thinking.length > 0);
1940
+ if (!retryable || hasVisibleAssistantContent(this.output) || streamedContent || !this.runtime.canSafelyReplayWebsocketOverSse || this.runtime.providerRetryAttempt >= CODEX_MAX_RETRIES || this.options?.signal?.aborted) return false;
1941
+ this.#closeOpenBlocksForReplay();
1851
1942
  this.runtime.providerRetryAttempt += 1;
1852
1943
  const websocketState = this.requestContext.websocketState;
1853
1944
  if (websocketState) {
1854
1945
  resetCodexWebSocketAppendState(websocketState);
1855
- websocketState.turnState = void 0;
1856
1946
  websocketState.modelsEtag = void 0;
1857
1947
  }
1858
1948
  CODEX_DEBUG && debug("[codex] retrying codex provider stream error", {
@@ -1900,21 +1990,6 @@ var CodexStreamProcessor = class {
1900
1990
  finalize(completion) {
1901
1991
  const { output } = this;
1902
1992
  if (this.options?.signal?.aborted) throw new AbortError();
1903
- if (!this.runtime.sawTerminalEvent) {
1904
- if (this.requestContext.websocketState) {
1905
- resetCodexWebSocketAppendState(this.requestContext.websocketState);
1906
- this.requestContext.websocketState.turnState = void 0;
1907
- this.requestContext.websocketState.modelsEtag = void 0;
1908
- }
1909
- CODEX_DEBUG && debug("[codex] codex stream ended unexpectedly", {
1910
- transport: this.runtime.transport,
1911
- terminalEventSeen: this.runtime.sawTerminalEvent,
1912
- unexpectedStreamEnd: true,
1913
- sentTurnStateHeader: Boolean(this.requestContext.websocketState?.turnState),
1914
- sentModelsEtagHeader: Boolean(this.requestContext.websocketState?.modelsEtag)
1915
- });
1916
- throw new CodexProviderStreamError("Codex stream ended before terminal completion event", false);
1917
- }
1918
1993
  if (output.stopReason === "aborted" || output.stopReason === "error") throw new CodexProviderStreamError("Codex response failed", false);
1919
1994
  output.providerPayload = createOpenAIResponsesHistoryPayload(this.model.provider, this.runtime.nativeOutputItems);
1920
1995
  output.duration = performance.now() - this.startTime;
@@ -1990,7 +2065,8 @@ const streamOpenAICodexResponses = (model, context, options) => {
1990
2065
  baseUrl: model.baseUrl || "https://chatgpt.com/backend-api",
1991
2066
  url: "",
1992
2067
  requestHeaders: {},
1993
- codexClientVersion: "0.144.1",
2068
+ codexClientVersion: "0.153.0",
2069
+ turnState: {},
1994
2070
  responsesLite: options?.responsesLite === true,
1995
2071
  transformedBody: { model: model.id },
1996
2072
  rawRequestDump: {
@@ -2255,10 +2331,11 @@ function recordCodexTurnUsageDiagnostics(state, rawUsage, displayedUsage) {
2255
2331
  };
2256
2332
  CODEX_DEBUG && debug("[codex] codex turn diagnostics", { diagnostics: state.stats.lastTurn });
2257
2333
  }
2334
+ const CODEX_CHAIN_TOP_LEVEL_EXCLUDE_MAP = { service_tier: true };
2258
2335
  /**
2259
- * Shape the next websocket turn's request body: when the session's append
2260
- * baseline is intact (same options, strict history prefix), chain via
2261
- * `previous_response_id` + delta-only `input`; otherwise break the chain and
2336
+ * Shape the next websocket turn's request body: when the session's strict
2337
+ * history prefix is intact and request options other than the per-turn
2338
+ * service_tier match, chain via previous_response_id + delta-only input;
2262
2339
  * replay the full transcript. SSE requests never chain — the HTTP endpoint's
2263
2340
  * request schema has no `previous_response_id` (codex-rs carries it only on
2264
2341
  * websocket `response.create` frames) and strict gateway validators 400 it
@@ -2266,19 +2343,15 @@ function recordCodexTurnUsageDiagnostics(state, rawUsage, displayedUsage) {
2266
2343
  */
2267
2344
  function buildCodexChainedRequestBody(requestBody, state) {
2268
2345
  const chainable = state?.canAppend === true;
2269
- const appendInput = chainable ? buildResponsesDeltaInput(state.lastRequest, state.lastResponseItems, requestBody) : null;
2346
+ const appendInput = chainable ? buildResponsesDeltaInput(state.lastRequest, state.lastResponseItems, requestBody, CODEX_CHAIN_TOP_LEVEL_EXCLUDE_MAP) : null;
2270
2347
  if (appendInput && appendInput.length > 0 && state?.lastResponseId) return {
2271
2348
  ...requestBody,
2272
2349
  previous_response_id: state.lastResponseId,
2273
2350
  input: appendInput
2274
2351
  };
2275
2352
  if (chainable && state) {
2276
- CODEX_DEBUG && debug("[codex] codex append reset", {
2277
- hadTurnStateHeader: Boolean(state.turnState),
2278
- hadModelsEtagHeader: Boolean(state.modelsEtag)
2279
- });
2353
+ CODEX_DEBUG && debug("[codex] codex append reset", { hadModelsEtagHeader: Boolean(state.modelsEtag) });
2280
2354
  resetCodexWebSocketAppendState(state);
2281
- state.turnState = void 0;
2282
2355
  state.modelsEtag = void 0;
2283
2356
  }
2284
2357
  return requestBody;
@@ -2360,9 +2433,18 @@ var CodexWebSocketConnection = class {
2360
2433
  return this.#headers.authorization === headers.authorization;
2361
2434
  }
2362
2435
  close(reason = "done") {
2363
- if (this.#socket && (this.#socket.readyState === WebSocket.OPEN || this.#socket.readyState === WebSocket.CONNECTING)) this.#socket.close(1e3, reason);
2436
+ const socket = this.#socket;
2364
2437
  this.#socket = null;
2365
2438
  this.#stopHeartbeat();
2439
+ if (!socket || socket.readyState !== WebSocket.OPEN && socket.readyState !== WebSocket.CONNECTING) return;
2440
+ try {
2441
+ socket.close(1e3, reason);
2442
+ } catch (error) {
2443
+ CODEX_DEBUG && debug("[codex] codex websocket close failed", {
2444
+ error: error instanceof Error ? error.message : String(error),
2445
+ reason
2446
+ });
2447
+ }
2366
2448
  }
2367
2449
  async connect(signal) {
2368
2450
  if (this.isOpen()) return;
@@ -2389,19 +2471,19 @@ var CodexWebSocketConnection = class {
2389
2471
  if (signal) signal.removeEventListener("abort", onAbort);
2390
2472
  };
2391
2473
  const onAbort = () => {
2392
- socket.close(1e3, "aborted");
2393
2474
  if (!settled) {
2394
2475
  settled = true;
2395
2476
  clearPending();
2396
- reject(new CodexWebSocketTransportError(`request was aborted`));
2477
+ reject(new CodexWebSocketTransportError(`request was aborted`, { cause: signal?.reason }));
2397
2478
  }
2479
+ this.close("aborted");
2398
2480
  };
2399
2481
  if (signal) {
2400
2482
  if (signal.aborted) onAbort();
2401
2483
  else signal.addEventListener("abort", onAbort, { once: true });
2402
2484
  }
2403
2485
  if (!settled) timeout = setTimeout(() => {
2404
- socket.close(1e3, "connect-timeout");
2486
+ this.close("connect-timeout");
2405
2487
  if (!settled) {
2406
2488
  settled = true;
2407
2489
  clearPending();
@@ -2470,13 +2552,13 @@ var CodexWebSocketConnection = class {
2470
2552
  async *streamRequest(request, timeouts, signal, onSseEvent) {
2471
2553
  if (!this.#socket || this.#socket.readyState !== WebSocket.OPEN) throw new CodexWebSocketTransportError(`websocket connection is unavailable`);
2472
2554
  if (this.#activeRequest) throw new CodexWebSocketTransportError(`websocket request already in progress`);
2473
- if (signal?.aborted) throw new CodexWebSocketTransportError(`request was aborted`);
2555
+ if (signal?.aborted) throw new CodexWebSocketTransportError(`request was aborted`, { cause: signal.reason });
2474
2556
  this.#activeRequest = true;
2475
2557
  this.#streamObserver = onSseEvent;
2476
2558
  this.#dropStaleFrames();
2477
2559
  const onAbort = () => {
2560
+ this.#push(new CodexWebSocketTransportError(`request was aborted`, { cause: signal?.reason }));
2478
2561
  this.close("aborted");
2479
- this.#push(new CodexWebSocketTransportError(`request was aborted`));
2480
2562
  };
2481
2563
  if (signal) signal.addEventListener("abort", onAbort, { once: true });
2482
2564
  try {
@@ -2491,7 +2573,10 @@ var CodexWebSocketConnection = class {
2491
2573
  const requestPayload = JSON.stringify(request);
2492
2574
  notifyCodexWebSocketOutbound(onSseEvent, request, requestPayload);
2493
2575
  const socket = this.#socket;
2494
- if (!socket || socket.readyState !== WebSocket.OPEN) throw new CodexWebSocketTransportError(`websocket connection is unavailable`);
2576
+ if (!socket || socket.readyState !== WebSocket.OPEN) {
2577
+ if (signal?.aborted) throw new CodexWebSocketTransportError(`websocket connection is unavailable`, { cause: signal.reason });
2578
+ throw new CodexWebSocketTransportError(`websocket connection is unavailable`);
2579
+ }
2495
2580
  try {
2496
2581
  socket.send(requestPayload);
2497
2582
  } catch (error) {
@@ -2717,7 +2802,7 @@ var CodexWebSocketConnection = class {
2717
2802
  return this.#queue.shift() ?? null;
2718
2803
  }
2719
2804
  };
2720
- async function getOrCreateCodexWebSocketConnection(state, url, headers, provider, signal) {
2805
+ async function getOrCreateCodexWebSocketConnection(state, turnState, url, headers, provider, signal) {
2721
2806
  const proxy = getProxyForUrl(provider, new URL(url));
2722
2807
  const headerRecord = headersToRecord(headers);
2723
2808
  for (let joinAttempt = 0; joinAttempt < 3; joinAttempt += 1) {
@@ -2745,7 +2830,7 @@ async function getOrCreateCodexWebSocketConnection(state, url, headers, provider
2745
2830
  time("codexWs:newSocket");
2746
2831
  state.connection = new CodexWebSocketConnection(url, headerRecord, {
2747
2832
  onHandshakeHeaders: (handshakeHeaders) => {
2748
- updateCodexSessionMetadataFromHeaders(state, handshakeHeaders);
2833
+ updateCodexSessionMetadataFromHeaders(turnState, state, handshakeHeaders);
2749
2834
  },
2750
2835
  proxy
2751
2836
  });
@@ -2766,8 +2851,8 @@ function compressCodexRequestBody(bodyJson, baseUrl) {
2766
2851
  return;
2767
2852
  }
2768
2853
  }
2769
- async function openCodexSseEventStream(url, requestHeaders, accountId, apiKey, sessionId, body, state, responsesLite, codexClientVersion, requestMetadata, signal, firstEventTimeoutMs, codexSseMaxAttempts, onSseEvent, fetchOverride) {
2770
- const headers = createCodexHeaders(requestHeaders, accountId, apiKey, codexClientVersion, sessionId, "sse", state, responsesLite, requestMetadata, await getCodexAttestationHeader(accountId));
2854
+ async function openCodexSseEventStream(url, requestHeaders, accountId, apiKey, sessionId, body, state, turnState, responsesLite, codexClientVersion, requestMetadata, signal, firstEventTimeoutMs, codexSseMaxAttempts, onSseEvent, fetchOverride) {
2855
+ const headers = createCodexHeaders(requestHeaders, accountId, apiKey, codexClientVersion, sessionId, "sse", state, turnState, responsesLite, requestMetadata, await getCodexAttestationHeader(accountId), body);
2771
2856
  let clearPreResponseTimeout;
2772
2857
  const fetchAttempt = async (input, init) => {
2773
2858
  try {
@@ -2827,7 +2912,7 @@ async function openCodexSseEventStream(url, requestHeaders, accountId, apiKey, s
2827
2912
  cfRay: response.headers.get("cf-ray") || null
2828
2913
  });
2829
2914
  if (!response.ok) throw await CodexApiError.fromResponse(response);
2830
- updateCodexSessionMetadataFromHeaders(state, response.headers);
2915
+ updateCodexSessionMetadataFromHeaders(turnState, state, response.headers);
2831
2916
  if (!response.body) throw new CodexProviderStreamError("No response body", false);
2832
2917
  return readSseJson(response.body, signal, (event) => onSseEvent?.({
2833
2918
  event: event.event,
@@ -2835,11 +2920,14 @@ async function openCodexSseEventStream(url, requestHeaders, accountId, apiKey, s
2835
2920
  raw: [...event.raw]
2836
2921
  }, void 0));
2837
2922
  }
2838
- function createCodexHeaders(initHeaders, accountId, accessToken, codexClientVersion, sessionId, transport = "sse", state, responsesLite = false, requestMetadata, attestation) {
2923
+ function createCodexHeaders(initHeaders, accountId, accessToken, codexClientVersion, sessionId, transport = "sse", state, turnState, responsesLite = false, requestMetadata, attestation, routedRequest) {
2839
2924
  const headers = new Headers(initHeaders ?? {});
2840
2925
  headers.delete("x-api-key");
2841
2926
  headers.set("Authorization", `Bearer ${accessToken}`);
2842
2927
  if (accountId) headers.set(OPENAI_HEADERS.ACCOUNT_ID, accountId);
2928
+ if (routedRequest) headers.set(OPENAI_HEADERS.ROUTING_HINT, codexRoutingHint(routedRequest.model, routedRequest.service_tier));
2929
+ else headers.delete(OPENAI_HEADERS.ROUTING_HINT);
2930
+ applyCodexResidencyHeader(headers, accessToken);
2843
2931
  if (attestation) headers.set(OPENAI_HEADERS.ATTESTATION, attestation);
2844
2932
  else headers.delete(OPENAI_HEADERS.ATTESTATION);
2845
2933
  const betaHeader = transport === "websocket" ? OPENAI_HEADER_VALUES.BETA_RESPONSES_WEBSOCKETS_V2 : OPENAI_HEADER_VALUES.BETA_RESPONSES;
@@ -2866,7 +2954,7 @@ function createCodexHeaders(initHeaders, accountId, accessToken, codexClientVers
2866
2954
  headers.delete(OPENAI_HEADERS.WINDOW_ID);
2867
2955
  headers.delete(OPENAI_HEADERS.TURN_METADATA);
2868
2956
  }
2869
- if (state?.turnState) headers.set(X_CODEX_TURN_STATE_HEADER, state.turnState);
2957
+ if (turnState?.value) headers.set(X_CODEX_TURN_STATE_HEADER, turnState.value);
2870
2958
  else headers.delete(X_CODEX_TURN_STATE_HEADER);
2871
2959
  if (state?.modelsEtag) headers.set(X_MODELS_ETAG_HEADER, state.modelsEtag);
2872
2960
  else headers.delete(X_MODELS_ETAG_HEADER);
@@ -3030,8 +3118,8 @@ function convertOpenAICodexResponsesTools(tools, model) {
3030
3118
  return payloads;
3031
3119
  }
3032
3120
  var CodexWebSocketTransportError = class extends Error {
3033
- constructor(detail) {
3034
- super(`${CODEX_WEBSOCKET_TRANSPORT_ERROR_PREFIX}: ${detail}`);
3121
+ constructor(detail, options) {
3122
+ super(`${CODEX_WEBSOCKET_TRANSPORT_ERROR_PREFIX}: ${detail}`, options);
3035
3123
  this.name = "CodexWebSocketTransportError";
3036
3124
  }
3037
3125
  };
@@ -3097,7 +3185,7 @@ function isRetryableCodexFailureEvent(rawEvent) {
3097
3185
  const code = error?.code ?? error?.type ?? event.code;
3098
3186
  if (code && CODEX_RETRYABLE_EVENT_CODES.has(code.toLowerCase())) return true;
3099
3187
  const message = error?.message ?? event.message ?? event.response?.message;
3100
- return !!message && CODEX_RETRYABLE_EVENT_MESSAGE.test(message);
3188
+ return !!message && (CODEX_RETRYABLE_EVENT_MESSAGE.test(message) || PYTHON_HTTP2_STREAM_RESET_PATTERN.test(message) || PYTHON_HTTP_INCOMPLETE_CHUNK_PATTERN.test(message));
3101
3189
  }
3102
3190
  function createCodexProviderStreamError(rawEvent) {
3103
3191
  const event = codexFailureEventSchema(rawEvent);