nexus-agents 8.85.2 → 8.85.3

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 (128) hide show
  1. package/dist/{ast-rule-runner-GDCEI7BW.js → ast-rule-runner-6XKCMMSK.js} +3 -3
  2. package/dist/{child-mcp-config-HAXDNULH.js → child-mcp-config-DMTIHAH5.js} +2 -2
  3. package/dist/{chunk-U33OOJOK.js → chunk-3HU4VVD7.js} +2 -2
  4. package/dist/{chunk-CDHUCQ44.js → chunk-5JQL2KOJ.js} +10 -10
  5. package/dist/{chunk-FOODF33L.js → chunk-6ZCKENQU.js} +4 -4
  6. package/dist/{chunk-4RHGZLKP.js → chunk-ABIS6ZE7.js} +2 -2
  7. package/dist/{chunk-WKZSEYV7.js → chunk-AHJUIF44.js} +8 -8
  8. package/dist/{chunk-23DTC2UV.js → chunk-ALJPZZ57.js} +4 -4
  9. package/dist/{chunk-ARWTQGSY.js → chunk-AOSBH5H7.js} +9 -9
  10. package/dist/{chunk-KC3AZWVQ.js → chunk-CJ2LQLZV.js} +3 -3
  11. package/dist/{chunk-7L6KI365.js → chunk-CPW3LHST.js} +3 -3
  12. package/dist/{chunk-K6VACGLH.js → chunk-DMUVBBOD.js} +3 -3
  13. package/dist/{chunk-7NLTUPYN.js → chunk-DSIJ5L3Y.js} +2 -2
  14. package/dist/chunk-DSIJ5L3Y.js.map +1 -0
  15. package/dist/{chunk-Z33AE45S.js → chunk-FQ6UCX2J.js} +5 -5
  16. package/dist/{chunk-WZRXZ6P2.js → chunk-GNTWB3O2.js} +5 -5
  17. package/dist/{chunk-PBXABL7H.js → chunk-HQQ3ES3J.js} +2 -2
  18. package/dist/{chunk-JHNS5FYV.js → chunk-HXSR24QG.js} +2 -2
  19. package/dist/{chunk-3EK4V5JS.js → chunk-KUZV4AW5.js} +2 -2
  20. package/dist/{chunk-QLYONNVR.js → chunk-KVDXUGMQ.js} +2 -2
  21. package/dist/{chunk-PB4SXWBA.js → chunk-LBIFDT6N.js} +2 -2
  22. package/dist/{chunk-GFFQHVSC.js → chunk-LJNUMK67.js} +2 -2
  23. package/dist/{chunk-XLYTLQAT.js → chunk-LKNT7XND.js} +2 -2
  24. package/dist/{chunk-L3PGHZH7.js → chunk-O6TFBXE5.js} +3 -3
  25. package/dist/{chunk-WIBR5HMY.js → chunk-OHM625YL.js} +2 -2
  26. package/dist/{chunk-YGOTLETF.js → chunk-OMIR6ISN.js} +47 -33
  27. package/dist/chunk-OMIR6ISN.js.map +1 -0
  28. package/dist/{chunk-TYHKIUUX.js → chunk-PFZSS67U.js} +2 -2
  29. package/dist/{chunk-M6U6UHFA.js → chunk-QFL3BFIV.js} +2 -2
  30. package/dist/{chunk-NL7I35TJ.js → chunk-QW343BTQ.js} +5 -5
  31. package/dist/chunk-QW343BTQ.js.map +1 -0
  32. package/dist/{chunk-B3PR26HR.js → chunk-RIB56PWI.js} +2 -2
  33. package/dist/{chunk-P5BZ3DNM.js → chunk-T2ZQUZQW.js} +7 -7
  34. package/dist/{chunk-IKLDY3HI.js → chunk-TECOLJ4Z.js} +36 -36
  35. package/dist/{chunk-HSMW4KIV.js → chunk-UWAJUJKU.js} +2 -2
  36. package/dist/{chunk-Y2ARXXPF.js → chunk-UXUOJOXL.js} +2 -2
  37. package/dist/{chunk-ILGHDIYO.js → chunk-VEMKYAW4.js} +2 -2
  38. package/dist/{chunk-VYZRGIY5.js → chunk-XGAMDSC5.js} +4 -4
  39. package/dist/{cli-circuit-breaker-TOE7GRYI.js → cli-circuit-breaker-VRTWILPB.js} +3 -3
  40. package/dist/cli.js +42 -42
  41. package/dist/{composite-router-UD3FGSSS.js → composite-router-LAMVSGZ3.js} +2 -2
  42. package/dist/{consensus-vote-YW6LAIH7.js → consensus-vote-ZB72SHTV.js} +16 -16
  43. package/dist/{context-retriever-CH3GEH2Z.js → context-retriever-VRAIKZTE.js} +8 -8
  44. package/dist/{doctor-deep-LMEUFKDA.js → doctor-deep-ZZWIF64Z.js} +3 -3
  45. package/dist/{doctor-live-O25NTC5D.js → doctor-live-KKIWEO3K.js} +10 -10
  46. package/dist/{expert-bridge-ZQSYVUC2.js → expert-bridge-TMHBUOUK.js} +4 -4
  47. package/dist/{factory-O4U4BJFT.js → factory-KAMTEOXC.js} +9 -9
  48. package/dist/{factory-ZOM2QJPC.js → factory-WAI626V6.js} +5 -5
  49. package/dist/{improvement-review-RL6VHCCY.js → improvement-review-BI3B3PQ2.js} +5 -5
  50. package/dist/index.d.ts +4 -4
  51. package/dist/index.js +30 -30
  52. package/dist/{init-opencode-RMMHBIQ2.js → init-opencode-EY7TUIML.js} +5 -5
  53. package/dist/issue-triage-VAWDVGET.js +16 -0
  54. package/dist/model-registry.generated.json +2949 -3961
  55. package/dist/{pr-reviewer-helpers-S53B7TYK.js → pr-reviewer-helpers-3A6ZFECZ.js} +4 -4
  56. package/dist/{registry-command-TWHRKWDB.js → registry-command-PWWFOIT3.js} +2 -2
  57. package/dist/{repo-security-plan-HYJ7HTOS.js → repo-security-plan-Y6PXBY44.js} +3 -3
  58. package/dist/{research-helpers-synthesize-G3WV7AHW.js → research-helpers-synthesize-L22FP57N.js} +4 -4
  59. package/dist/{routing-memory-HQTEZF2S.js → routing-memory-XFJJT5AW.js} +2 -2
  60. package/dist/{session-memory-M5MEGJJZ.js → session-memory-SRH5ZJRX.js} +3 -3
  61. package/dist/{setup-config-L5QGPDH6.js → setup-config-T64H4UOO.js} +3 -3
  62. package/dist/{setup-custom-api-LRL6J7RN.js → setup-custom-api-RQW6VSLO.js} +4 -4
  63. package/dist/setup-data-dir-ZD4N4CEP.js +32 -0
  64. package/dist/{tool-memory-24PMDECK.js → tool-memory-72T6Z6H4.js} +5 -5
  65. package/dist/{unified-registry-NODUOBMA.js → unified-registry-J2PCYXUU.js} +10 -10
  66. package/dist/{weather-report-IGEXNIWL.js → weather-report-GPYYWU5C.js} +2 -2
  67. package/package.json +1 -1
  68. package/dist/chunk-7NLTUPYN.js.map +0 -1
  69. package/dist/chunk-NL7I35TJ.js.map +0 -1
  70. package/dist/chunk-YGOTLETF.js.map +0 -1
  71. package/dist/issue-triage-DQAOBZEP.js +0 -16
  72. package/dist/setup-data-dir-WZXMTSDN.js +0 -32
  73. /package/dist/{ast-rule-runner-GDCEI7BW.js.map → ast-rule-runner-6XKCMMSK.js.map} +0 -0
  74. /package/dist/{child-mcp-config-HAXDNULH.js.map → child-mcp-config-DMTIHAH5.js.map} +0 -0
  75. /package/dist/{chunk-U33OOJOK.js.map → chunk-3HU4VVD7.js.map} +0 -0
  76. /package/dist/{chunk-CDHUCQ44.js.map → chunk-5JQL2KOJ.js.map} +0 -0
  77. /package/dist/{chunk-FOODF33L.js.map → chunk-6ZCKENQU.js.map} +0 -0
  78. /package/dist/{chunk-4RHGZLKP.js.map → chunk-ABIS6ZE7.js.map} +0 -0
  79. /package/dist/{chunk-WKZSEYV7.js.map → chunk-AHJUIF44.js.map} +0 -0
  80. /package/dist/{chunk-23DTC2UV.js.map → chunk-ALJPZZ57.js.map} +0 -0
  81. /package/dist/{chunk-ARWTQGSY.js.map → chunk-AOSBH5H7.js.map} +0 -0
  82. /package/dist/{chunk-KC3AZWVQ.js.map → chunk-CJ2LQLZV.js.map} +0 -0
  83. /package/dist/{chunk-7L6KI365.js.map → chunk-CPW3LHST.js.map} +0 -0
  84. /package/dist/{chunk-K6VACGLH.js.map → chunk-DMUVBBOD.js.map} +0 -0
  85. /package/dist/{chunk-Z33AE45S.js.map → chunk-FQ6UCX2J.js.map} +0 -0
  86. /package/dist/{chunk-WZRXZ6P2.js.map → chunk-GNTWB3O2.js.map} +0 -0
  87. /package/dist/{chunk-PBXABL7H.js.map → chunk-HQQ3ES3J.js.map} +0 -0
  88. /package/dist/{chunk-JHNS5FYV.js.map → chunk-HXSR24QG.js.map} +0 -0
  89. /package/dist/{chunk-3EK4V5JS.js.map → chunk-KUZV4AW5.js.map} +0 -0
  90. /package/dist/{chunk-QLYONNVR.js.map → chunk-KVDXUGMQ.js.map} +0 -0
  91. /package/dist/{chunk-PB4SXWBA.js.map → chunk-LBIFDT6N.js.map} +0 -0
  92. /package/dist/{chunk-GFFQHVSC.js.map → chunk-LJNUMK67.js.map} +0 -0
  93. /package/dist/{chunk-XLYTLQAT.js.map → chunk-LKNT7XND.js.map} +0 -0
  94. /package/dist/{chunk-L3PGHZH7.js.map → chunk-O6TFBXE5.js.map} +0 -0
  95. /package/dist/{chunk-WIBR5HMY.js.map → chunk-OHM625YL.js.map} +0 -0
  96. /package/dist/{chunk-TYHKIUUX.js.map → chunk-PFZSS67U.js.map} +0 -0
  97. /package/dist/{chunk-M6U6UHFA.js.map → chunk-QFL3BFIV.js.map} +0 -0
  98. /package/dist/{chunk-B3PR26HR.js.map → chunk-RIB56PWI.js.map} +0 -0
  99. /package/dist/{chunk-P5BZ3DNM.js.map → chunk-T2ZQUZQW.js.map} +0 -0
  100. /package/dist/{chunk-IKLDY3HI.js.map → chunk-TECOLJ4Z.js.map} +0 -0
  101. /package/dist/{chunk-HSMW4KIV.js.map → chunk-UWAJUJKU.js.map} +0 -0
  102. /package/dist/{chunk-Y2ARXXPF.js.map → chunk-UXUOJOXL.js.map} +0 -0
  103. /package/dist/{chunk-ILGHDIYO.js.map → chunk-VEMKYAW4.js.map} +0 -0
  104. /package/dist/{chunk-VYZRGIY5.js.map → chunk-XGAMDSC5.js.map} +0 -0
  105. /package/dist/{cli-circuit-breaker-TOE7GRYI.js.map → cli-circuit-breaker-VRTWILPB.js.map} +0 -0
  106. /package/dist/{composite-router-UD3FGSSS.js.map → composite-router-LAMVSGZ3.js.map} +0 -0
  107. /package/dist/{consensus-vote-YW6LAIH7.js.map → consensus-vote-ZB72SHTV.js.map} +0 -0
  108. /package/dist/{context-retriever-CH3GEH2Z.js.map → context-retriever-VRAIKZTE.js.map} +0 -0
  109. /package/dist/{doctor-deep-LMEUFKDA.js.map → doctor-deep-ZZWIF64Z.js.map} +0 -0
  110. /package/dist/{doctor-live-O25NTC5D.js.map → doctor-live-KKIWEO3K.js.map} +0 -0
  111. /package/dist/{expert-bridge-ZQSYVUC2.js.map → expert-bridge-TMHBUOUK.js.map} +0 -0
  112. /package/dist/{factory-O4U4BJFT.js.map → factory-KAMTEOXC.js.map} +0 -0
  113. /package/dist/{factory-ZOM2QJPC.js.map → factory-WAI626V6.js.map} +0 -0
  114. /package/dist/{improvement-review-RL6VHCCY.js.map → improvement-review-BI3B3PQ2.js.map} +0 -0
  115. /package/dist/{init-opencode-RMMHBIQ2.js.map → init-opencode-EY7TUIML.js.map} +0 -0
  116. /package/dist/{issue-triage-DQAOBZEP.js.map → issue-triage-VAWDVGET.js.map} +0 -0
  117. /package/dist/{pr-reviewer-helpers-S53B7TYK.js.map → pr-reviewer-helpers-3A6ZFECZ.js.map} +0 -0
  118. /package/dist/{registry-command-TWHRKWDB.js.map → registry-command-PWWFOIT3.js.map} +0 -0
  119. /package/dist/{repo-security-plan-HYJ7HTOS.js.map → repo-security-plan-Y6PXBY44.js.map} +0 -0
  120. /package/dist/{research-helpers-synthesize-G3WV7AHW.js.map → research-helpers-synthesize-L22FP57N.js.map} +0 -0
  121. /package/dist/{routing-memory-HQTEZF2S.js.map → routing-memory-XFJJT5AW.js.map} +0 -0
  122. /package/dist/{session-memory-M5MEGJJZ.js.map → session-memory-SRH5ZJRX.js.map} +0 -0
  123. /package/dist/{setup-config-L5QGPDH6.js.map → setup-config-T64H4UOO.js.map} +0 -0
  124. /package/dist/{setup-custom-api-LRL6J7RN.js.map → setup-custom-api-RQW6VSLO.js.map} +0 -0
  125. /package/dist/{setup-data-dir-WZXMTSDN.js.map → setup-data-dir-ZD4N4CEP.js.map} +0 -0
  126. /package/dist/{tool-memory-24PMDECK.js.map → tool-memory-72T6Z6H4.js.map} +0 -0
  127. /package/dist/{unified-registry-NODUOBMA.js.map → unified-registry-J2PCYXUU.js.map} +0 -0
  128. /package/dist/{weather-report-IGEXNIWL.js.map → weather-report-GPYYWU5C.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getRandomProvider,
3
3
  getTimeProvider
4
- } from "./chunk-YGOTLETF.js";
4
+ } from "./chunk-OMIR6ISN.js";
5
5
 
6
6
  // src/utils/id-utils.ts
7
7
  import { randomUUID } from "node:crypto";
@@ -24,4 +24,4 @@ export {
24
24
  generateHyphenId,
25
25
  generateUUID
26
26
  };
27
- //# sourceMappingURL=chunk-TYHKIUUX.js.map
27
+ //# sourceMappingURL=chunk-PFZSS67U.js.map
@@ -4,7 +4,7 @@ import {
4
4
  err,
5
5
  getErrorMessage,
6
6
  ok
7
- } from "./chunk-YGOTLETF.js";
7
+ } from "./chunk-OMIR6ISN.js";
8
8
 
9
9
  // src/scm/types.ts
10
10
  var ScmError = class extends Error {
@@ -281,4 +281,4 @@ export {
281
281
  ScmError,
282
282
  GitHubProvider
283
283
  };
284
- //# sourceMappingURL=chunk-M6U6UHFA.js.map
284
+ //# sourceMappingURL=chunk-QFL3BFIV.js.map
@@ -4,12 +4,12 @@ import {
4
4
  planOptionalParams,
5
5
  requireApiKey,
6
6
  validateApiKeyPresence
7
- } from "./chunk-7NLTUPYN.js";
7
+ } from "./chunk-DSIJ5L3Y.js";
8
8
  import {
9
9
  assertCustomApiHostResolvesPublic,
10
10
  hostnameOf,
11
11
  redactApiKey
12
- } from "./chunk-B3PR26HR.js";
12
+ } from "./chunk-RIB56PWI.js";
13
13
  import {
14
14
  sanitizeErrorDetails
15
15
  } from "./chunk-2NDA4DHW.js";
@@ -31,7 +31,7 @@ import {
31
31
  isEndpointArmId,
32
32
  ok,
33
33
  recordUsageEvent
34
- } from "./chunk-YGOTLETF.js";
34
+ } from "./chunk-OMIR6ISN.js";
35
35
 
36
36
  // src/adapters/openai-types.ts
37
37
  var OPENAI_MODELS = {
@@ -40,7 +40,7 @@ var OPENAI_MODELS = {
40
40
  GPT_5_2_PRO: "gpt-5.2-pro",
41
41
  /**
42
42
  * Registry-derived: resolves to `codex-5.2`'s `cliModelName`, which since
43
- * #5091 is `gpt-5.3-codex-spark`, not a "5.2" model. The key name lags its
43
+ * 2026-09-23 is `gpt-5.6-luna`, not a "5.2" model. The key name lags its
44
44
  * value; renaming it is a public-API change tracked in #5489.
45
45
  */
46
46
  GPT_5_2_CODEX: getCliModelName("codex-5.2"),
@@ -886,4 +886,4 @@ export {
886
886
  discoverModels,
887
887
  buildOpenAICompatAdapters
888
888
  };
889
- //# sourceMappingURL=chunk-NL7I35TJ.js.map
889
+ //# sourceMappingURL=chunk-QW343BTQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/openai-types.ts","../src/adapters/openai-adapter.ts","../src/adapters/openai-mappers.ts","../src/config/opencode-bridge.ts","../src/adapters/openai-compat-adapter.ts"],"sourcesContent":["/**\n * nexus-agents/adapters - OpenAI Type Helpers\n *\n * Type definitions and constants for the OpenAI direct-API SDK adapter.\n *\n * **Architectural boundary (#2200 Child 3):** these constants do NOT live\n * in `config/in-tree-data.ts`. The canonical registry's `cliName`\n * dimension targets CLI tools (`claude` / `gemini` / `codex` / `opencode`)\n * — there is no `openai` CLI binary. Adding `'openai'` to the CLI_NAMES\n * enum would force a fifth case in 4+ exhaustive switches across the\n * codebase, violating the semantic of \"CLI tool name.\"\n *\n * The OpenAI direct adapter is conceptually different from CLI adapters:\n * it talks to the OpenAI HTTPS API directly, not via a subprocess CLI.\n * Its model identifiers are OpenAI's own (`gpt-4o-2024-11-20`,\n * `gpt-3.5-turbo-0125`, etc.) — these are upstream API constants, not\n * versions WE chose. They drift only when OpenAI ships new dated releases.\n *\n * This file is the single source of truth for OpenAI direct-API model\n * identifiers. The model-string drift fitness-guard (#2199) treats it as\n * a documented architectural exception in the allowlist.\n */\n\nimport type { ModelCapability } from '../core/index.js';\nimport { ModelCapability as MC } from '../core/index.js';\nimport { getCliModelName } from '../config/model-config-helpers.js';\n\n/**\n * Supported OpenAI direct-API model identifiers (OpenAI's own dated names).\n *\n * GPT_5_2_CODEX derives from the canonical registry (codex-5.2's cliModelName)\n * because it overlaps with the Codex CLI; the rest are pure-API constants.\n * Since #5091 that entry has been repointed to whatever slug codex serves\n * (`gpt-5.6-luna` as of 2026-09-23), so the key's name lags its value; renaming\n * the key is a public-API change and is tracked separately.\n */\nexport const OPENAI_MODELS = {\n GPT_5_2: 'gpt-5.2',\n GPT_5_2_INSTANT: 'gpt-5.2-chat-latest',\n GPT_5_2_PRO: 'gpt-5.2-pro',\n /**\n * Registry-derived: resolves to `codex-5.2`'s `cliModelName`, which since\n * 2026-09-23 is `gpt-5.6-luna`, not a \"5.2\" model. The key name lags its\n * value; renaming it is a public-API change tracked in #5489.\n */\n GPT_5_2_CODEX: getCliModelName('codex-5.2'),\n GPT_4O: 'gpt-4o-2024-11-20',\n GPT_4O_MINI: 'gpt-4o-mini-2024-07-18',\n GPT_4_TURBO: 'gpt-4-turbo-2024-04-09',\n GPT_35_TURBO: 'gpt-3.5-turbo-0125',\n} as const;\n\n/**\n * User-friendly OpenAI aliases → dated model identifiers.\n *\n * Identity-only mappings (e.g., `'gpt-5.2-pro' → 'gpt-5.2-pro'`) were\n * removed in #2200 Child 3 — `resolveModelId` already passes unknown ids\n * through unchanged via `?? modelId`. Only entries that translate a\n * shorthand into a dated version remain.\n */\nexport const OPENAI_MODEL_ALIASES: Record<string, string> = {\n 'gpt-5.2-instant': OPENAI_MODELS.GPT_5_2_INSTANT,\n 'gpt-4o': OPENAI_MODELS.GPT_4O,\n 'gpt-4o-mini': OPENAI_MODELS.GPT_4O_MINI,\n 'gpt-4-turbo': OPENAI_MODELS.GPT_4_TURBO,\n 'gpt-3.5-turbo': OPENAI_MODELS.GPT_35_TURBO,\n} as const;\n\n/**\n * Configuration specific to OpenAIAdapter.\n */\nexport interface OpenAIAdapterConfig {\n /** Model ID (e.g., 'gpt-4o' or full model identifier) */\n modelId: string;\n /** API key for OpenAI API (required) */\n apiKey: string;\n /** Base URL for API (optional, defaults to OpenAI's API) */\n baseUrl?: string;\n /** Request timeout in milliseconds (optional) */\n timeout?: number;\n /** Maximum retries for failed requests (optional) */\n maxRetries?: number;\n /** Organization ID (optional) */\n organization?: string;\n}\n\n// Note: Token estimation moved to core/token-estimator.ts (unified TokenEstimator)\n\n/**\n * Default maximum tokens for OpenAI models.\n */\nexport const DEFAULT_MAX_TOKENS = 4096;\n\n/**\n * Tool call type for extracting function info.\n */\nexport interface FunctionToolCall {\n id: string;\n type: 'function';\n function: {\n name: string;\n arguments: string;\n };\n}\n\n/**\n * Type guard for function tool calls.\n * Note: typeof null === 'object' is true, so we need to check tc !== null\n */\nexport function isFunctionToolCall(toolCall: unknown): toolCall is FunctionToolCall {\n if (typeof toolCall !== 'object' || toolCall === null) {\n return false;\n }\n const tc = toolCall as Record<string, unknown>;\n return tc['type'] === 'function' && typeof tc['function'] === 'object' && tc['function'] !== null;\n}\n\n/**\n * Resolves model alias to full model identifier.\n */\nexport function resolveModelId(modelId: string): string {\n return OPENAI_MODEL_ALIASES[modelId] ?? modelId;\n}\n\n/**\n * Determines capabilities based on model ID.\n */\nexport function getModelCapabilities(modelId: string): readonly ModelCapability[] {\n const capabilities: ModelCapability[] = [MC.COMPLETION, MC.STREAMING, MC.TOOL_USE];\n\n const resolvedId = resolveModelId(modelId);\n\n // Vision is available on GPT-4o, GPT-4-turbo, and GPT-5.2 models\n if (\n resolvedId.includes('gpt-4o') ||\n resolvedId.includes('gpt-4-turbo') ||\n resolvedId.includes('gpt-5.2')\n ) {\n capabilities.push(MC.VISION);\n }\n\n // Extended thinking is available on GPT-5.2 models\n if (resolvedId.includes('gpt-5.2')) {\n capabilities.push(MC.EXTENDED_THINKING);\n }\n\n return capabilities;\n}\n","/**\n * nexus-agents/adapters - OpenAI Model Adapter\n *\n * Adapter for OpenAI models (GPT-4o, GPT-4-turbo, GPT-3.5-turbo).\n * Implements the IModelAdapter interface with streaming support, rate limiting,\n * and proper error handling.\n *\n * Verified 2026-01-03: openai@6.15.0 is current stable\n * (Source: npm registry)\n */\n\nimport OpenAI, { APIError } from 'openai';\nimport type { ChatCompletionMessageParam, ChatCompletion } from 'openai/resources/chat/completions';\nimport type {\n Result,\n CompletionRequest,\n CompletionResponse,\n ModelMetadata,\n StreamChunk,\n TokenUsage,\n} from '../core/index.js';\nimport { ok, err, ModelError, ConfigError, getTokenEstimator } from '../core/index.js';\nimport {\n BaseAdapter,\n type BaseAdapterConfig,\n requireApiKey,\n validateApiKeyPresence,\n} from './base-adapter.js';\nimport { createStream } from './streaming.js';\nimport {\n DEFAULT_MAX_TOKENS,\n resolveModelId,\n getModelCapabilities,\n type OpenAIAdapterConfig,\n} from './openai-types.js';\nimport { planOptionalParams, type DroppedParam } from './optional-params.js';\nimport {\n mapMessage,\n mapTool,\n mapStopReason,\n mapChoiceToContentBlocks,\n mapResponseUsage,\n mapStreamChunk,\n} from './openai-mappers.js';\nimport { sanitizeErrorDetails } from '../security/output-sanitizer.js';\n\n// Re-export types and constants for public API\nexport { OPENAI_MODELS, OPENAI_MODEL_ALIASES, type OpenAIAdapterConfig } from './openai-types.js';\n\n/**\n * OpenAI model adapter.\n *\n * Provides a unified interface for interacting with OpenAI's GPT models.\n * Supports completion, streaming, tool use, and vision capabilities.\n *\n * @example\n * ```typescript\n * const adapter = new OpenAIAdapter({\n * modelId: 'gpt-4o',\n * apiKey: process.env.OPENAI_API_KEY,\n * });\n *\n * const result = await adapter.complete({\n * messages: [{ role: 'user', content: 'Hello!' }],\n * maxTokens: 1024,\n * });\n *\n * if (result.ok) {\n * console.log(result.value.content);\n * }\n * ```\n */\n\n/**\n * Compose a diagnostic string from an OpenAI SDK `APIError`'s real fields\n * (#4047). The SDK's `.message` alone can be as useless as\n * `\"400 status code (no body)\"` for an OpenAI-compatible gateway; this pulls the\n * HTTP status, structured error fields, and the raw body so the actual rejection\n * reason is visible.\n */\n/** Typed structural view of the OpenAI SDK `APIError` fields we read (the SDK's\n * generic `APIError<any,…>` otherwise leaks `any`). */\ninterface ApiErrorView {\n readonly status?: number | null;\n readonly type?: string | null;\n readonly code?: string | null;\n readonly param?: string | null;\n readonly requestID?: string | null;\n readonly error?: unknown;\n readonly message?: string;\n}\n\n/** `key=value` tag, or `''` when the value is absent. */\nfunction kvTag(key: string, val: string | number | null | undefined): string {\n return val === null || val === undefined || val === '' ? '' : `${key}=${String(val)}`;\n}\n\nfunction describeOpenAIApiError(v: ApiErrorView, apiKey?: string): string {\n const tags = [\n `HTTP ${String(v.status ?? 'unknown')}`,\n kvTag('type', v.type),\n kvTag('code', v.code),\n kvTag('param', v.param),\n kvTag('request_id', v.requestID),\n ].filter((t) => t !== '');\n let body = '';\n if (v.error !== undefined && v.error !== null) {\n try {\n const raw = JSON.stringify(v.error);\n body = ` body=${raw.length > MAX_ERROR_BODY_CHARS ? `${raw.slice(0, MAX_ERROR_BODY_CHARS)}…` : raw}`;\n } catch {\n body = ' body=<unserializable>';\n }\n }\n return sanitizeErrorDetails(`${tags.join(' ')}: ${v.message ?? ''}${body}`, apiKey);\n}\n\n/** Cap the surfaced gateway error body so a huge response can't bloat logs/messages. */\nconst MAX_ERROR_BODY_CHARS = 600;\n\nexport class OpenAIAdapter extends BaseAdapter {\n private readonly client: OpenAI;\n private readonly resolvedModelId: string;\n private readonly apiKey: string | undefined;\n\n /**\n * Creates a new OpenAIAdapter instance.\n *\n * @param config - OpenAI adapter configuration\n * @throws {ConfigError} If API key is missing\n */\n constructor(config: OpenAIAdapterConfig) {\n const resolvedModelId = resolveModelId(config.modelId);\n\n // Build baseConfig conditionally to satisfy exactOptionalPropertyTypes\n const baseConfig: BaseAdapterConfig = {\n providerId: 'openai',\n modelId: resolvedModelId,\n capabilities: getModelCapabilities(config.modelId),\n apiKey: config.apiKey,\n };\n\n // Only set optional properties if defined\n if (config.baseUrl !== undefined) {\n baseConfig.baseUrl = config.baseUrl;\n }\n if (config.timeout !== undefined) {\n baseConfig.timeout = config.timeout;\n }\n if (config.maxRetries !== undefined) {\n baseConfig.maxRetries = config.maxRetries;\n }\n\n super(baseConfig);\n\n this.apiKey = config.apiKey;\n this.resolvedModelId = resolvedModelId;\n\n // Validate API key presence\n requireApiKey(config.apiKey, 'OpenAI', config.modelId);\n\n this.client = this.createClient(config);\n }\n\n /**\n * Creates the OpenAI client with configuration.\n */\n private createClient(config: OpenAIAdapterConfig): OpenAI {\n const clientOptions: ConstructorParameters<typeof OpenAI>[0] = {\n apiKey: config.apiKey,\n maxRetries: config.maxRetries ?? 2,\n };\n\n if (config.baseUrl !== undefined) {\n clientOptions.baseURL = config.baseUrl;\n }\n if (config.timeout !== undefined) {\n clientOptions.timeout = config.timeout;\n }\n if (config.organization !== undefined) {\n clientOptions.organization = config.organization;\n }\n\n return new OpenAI(clientOptions);\n }\n\n /**\n * Validates adapter configuration.\n * Extends base validation with OpenAI-specific checks.\n */\n override validateConfig(): Result<void, ConfigError> {\n const baseResult = super.validateConfig();\n if (!baseResult.ok) {\n return baseResult;\n }\n\n // Validate API key is present\n const keyResult = validateApiKeyPresence(this.config.apiKey, this.providerId, this.modelId);\n if (!keyResult.ok) return keyResult;\n\n return ok(undefined);\n }\n\n /**\n * Send a completion request to OpenAI.\n *\n * @param request - The completion request\n * @returns Result with response or ModelError\n */\n async complete(request: CompletionRequest): Promise<Result<CompletionResponse, ModelError>> {\n this.logRequest(request);\n\n try {\n const response = await this.executeCompletion(request);\n this.logResponse(response);\n return ok(response);\n } catch (error) {\n return err(this.transformError(error));\n }\n }\n\n /**\n * Surface an OpenAI / OpenAI-compatible gateway's REAL HTTP status + response\n * body in the error (#4047). The OpenAI SDK's default message collapses a\n * gateway rejection to e.g. `\"400 status code (no body)\"`, which hides WHY a\n * litellm-style gateway rejected a request — exactly the wall hit when\n * diagnosing degraded voter panels on a custom gateway. We re-message with the\n * status/type/code/param/request-id/body. Error-code routing is unchanged: we\n * classify on the ORIGINAL signal (`status`/`code`/`message`) via a clean probe\n * error, so the diagnostic `request_id`/`body` can't pollute the message-\n * substring classifier, then re-message the result with the full detail.\n * Applies to direct OpenAI and the compat gateway alike.\n */\n protected override transformError(error: unknown): ModelError {\n if (error instanceof APIError) {\n const v = error as ApiErrorView;\n // Classify on the original SDK message + status/code/param only. #4069: thread\n // `param` so a param-naming 400 classifies as MODEL_PARAMETER_UNSUPPORTED and\n // the param name reaches the error context.\n const probe: Error & {\n status?: number | undefined;\n code?: string | null | undefined;\n param?: string | undefined;\n } = new Error(typeof v.message === 'string' ? v.message : '');\n probe.status = typeof v.status === 'number' ? v.status : undefined;\n probe.code = v.code ?? undefined;\n probe.param = typeof v.param === 'string' && v.param !== '' ? v.param : undefined;\n probe.cause = error;\n const classified = super.transformError(probe);\n // Surface the full diagnostic detail in the final message (code/cause kept).\n classified.message = `${this.providerId}/${this.modelId}: ${describeOpenAIApiError(v, this.apiKey)}`;\n return classified;\n }\n const err = super.transformError(error);\n err.message = sanitizeErrorDetails(err.message, this.apiKey);\n return err;\n }\n\n /**\n * Stream a completion request from OpenAI.\n *\n * @param request - The completion request\n * @yields StreamChunk objects as they arrive\n */\n async *stream(request: CompletionRequest): AsyncIterable<StreamChunk> {\n this.logRequest(request);\n\n const [controller, iterable] = createStream<StreamChunk>();\n\n // Start streaming in the background\n this.executeStream(request, controller).catch((error: unknown) => {\n const modelError = this.transformError(error);\n controller.error(modelError);\n });\n\n yield* iterable;\n }\n\n /**\n * Count tokens in text using OpenAI-specific estimation.\n *\n * @param text - Text to count tokens for\n * @returns Approximate token count\n */\n override countTokens(text: string): Promise<number> {\n // Use unified TokenEstimator with OpenAI-specific ratio (~4 chars/token)\n return Promise.resolve(getTokenEstimator().estimateText(text, 'openai'));\n }\n\n /**\n * Executes the completion request against the OpenAI API.\n */\n private async executeCompletion(request: CompletionRequest): Promise<CompletionResponse> {\n const { params, dropped } = this.buildRequestParams(request);\n // #3036: forward AbortSignal into the OpenAI SDK so withWatchdog\n // timeouts cancel the HTTP request instead of leaking it past the\n // Promise.race boundary. Branch on signal presence — vitest 4\n // toHaveBeenCalledWith treats `(params, undefined)` as a distinct\n // call shape from `(params)`.\n const response =\n request.signal !== undefined\n ? await this.client.chat.completions.create(params, { signal: request.signal })\n : await this.client.chat.completions.create(params);\n // #4069: surface params dropped by the seam (e.g. temperature) as warnings.\n return this.mapResponse(response, dropped);\n }\n\n /**\n * Executes streaming completion and pushes chunks to the controller.\n */\n private async executeStream(\n request: CompletionRequest,\n controller: {\n push: (chunk: StreamChunk) => Result<void, Error>;\n complete: () => void;\n error: (error: Error) => void;\n }\n ): Promise<void> {\n try {\n const { params } = this.buildRequestParams(request);\n const stream = await this.client.chat.completions.create({ ...params, stream: true });\n\n let contentIndex = 0;\n let hasStarted = false;\n\n for await (const chunk of stream) {\n const mappedChunks = mapStreamChunk(chunk, contentIndex, hasStarted);\n\n for (const mappedChunk of mappedChunks) {\n if (mappedChunk.type === 'message_start') {\n hasStarted = true;\n }\n if (mappedChunk.type === 'content_block_start') {\n contentIndex++;\n }\n controller.push(mappedChunk);\n }\n }\n\n controller.complete();\n } catch (error) {\n const modelError = this.transformError(error);\n controller.error(modelError);\n }\n }\n\n /**\n * Builds OpenAI API request parameters from our CompletionRequest.\n */\n private buildRequestParams(request: CompletionRequest): {\n params: OpenAI.Chat.ChatCompletionCreateParamsNonStreaming;\n dropped: readonly DroppedParam[];\n } {\n const messages = this.buildMessages(request);\n\n const params: OpenAI.Chat.ChatCompletionCreateParamsNonStreaming = {\n model: this.resolvedModelId,\n messages,\n max_completion_tokens: request.maxTokens ?? DEFAULT_MAX_TOKENS,\n };\n\n const dropped = this.addOptionalParams(params, request);\n return { params, dropped };\n }\n\n /**\n * Builds the messages array for the request.\n */\n private buildMessages(request: CompletionRequest): ChatCompletionMessageParam[] {\n const messages: ChatCompletionMessageParam[] = [];\n\n // Add system prompt if provided explicitly\n if (request.systemPrompt !== undefined && request.systemPrompt !== '') {\n messages.push({ role: 'system', content: request.systemPrompt });\n }\n\n // Map and add all messages (filtering out system if already added via systemPrompt)\n for (const msg of request.messages) {\n if (msg.role === 'system' && request.systemPrompt !== undefined) {\n continue;\n }\n messages.push(mapMessage(msg));\n }\n\n return messages;\n }\n\n /**\n * Adds optional parameters to the request.\n */\n private addOptionalParams(\n params: OpenAI.Chat.ChatCompletionCreateParamsNonStreaming,\n request: CompletionRequest\n ): readonly DroppedParam[] {\n // #4068: the temperature drop-decision (#4061: a gateway routing to a Claude\n // model after Opus 4.6, or an OpenAI reasoning model, rejects a non-1.0\n // temperature with a 400; omit it so a gateway-routed voter panel at the\n // default 0.3 does not 400) is centralized in the shared planOptionalParams\n // seam. NOTE: a gateway that injects its OWN default when the field is absent\n // is outside our control — our contract is only to not SEND a rejected value.\n const plan = planOptionalParams(request, this.resolvedModelId);\n if (plan.temperature !== undefined) {\n params.temperature = plan.temperature;\n }\n\n if (request.stop !== undefined && request.stop.length > 0) {\n params.stop = request.stop;\n }\n\n if (request.tools !== undefined && request.tools.length > 0) {\n params.tools = request.tools.map(mapTool);\n }\n\n this.addResponseFormat(params, request);\n\n // #4069: report dropped params so mapResponse can surface them as warnings.\n return plan.dropped;\n }\n\n /**\n * Adds response format to the request if specified.\n */\n private addResponseFormat(\n params: OpenAI.Chat.ChatCompletionCreateParamsNonStreaming,\n request: CompletionRequest\n ): void {\n if (request.responseFormat === undefined) {\n return;\n }\n\n if (request.responseFormat.type === 'json_object') {\n params.response_format = { type: 'json_object' };\n } else if (request.responseFormat.type === 'json_schema') {\n params.response_format = {\n type: 'json_schema',\n json_schema: {\n name: 'response',\n schema: request.responseFormat.schema,\n },\n };\n }\n }\n\n /**\n * Maps OpenAI API response to our CompletionResponse format.\n */\n private mapResponse(\n response: ChatCompletion,\n dropped: readonly DroppedParam[] = []\n ): CompletionResponse {\n const firstChoice = response.choices[0];\n\n // Handle case where no choices are returned\n if (firstChoice === undefined) {\n return this.createEmptyResponse(response, dropped);\n }\n\n const content = mapChoiceToContentBlocks(firstChoice);\n const usage: TokenUsage | undefined = mapResponseUsage(response);\n\n return {\n content,\n ...(usage !== undefined ? { usage } : {}),\n stopReason: mapStopReason(firstChoice.finish_reason),\n model: response.model,\n // #4069: surface dropped params (e.g. an omitted temperature). Omitted\n // entirely when nothing was dropped (exactOptionalPropertyTypes).\n ...(dropped.length > 0 ? { warnings: dropped } : {}),\n };\n }\n\n /**\n * Creates an empty response when no choices are returned.\n */\n private createEmptyResponse(\n response: ChatCompletion,\n dropped: readonly DroppedParam[] = []\n ): CompletionResponse {\n const emptyUsage = mapResponseUsage(response);\n return {\n content: [{ type: 'text', text: '' }],\n ...(emptyUsage !== undefined ? { usage: emptyUsage } : {}),\n stopReason: 'end_turn',\n model: response.model,\n ...(dropped.length > 0 ? { warnings: dropped } : {}),\n };\n }\n\n /**\n * (#2529) List models served by this OpenAI-compatible endpoint.\n *\n * Wraps `GET /v1/models`. Result is cached for `LIST_MODELS_TTL_MS`\n * so identity resolution doesn't round-trip on every adapter.\n * Concurrent callers share the in-flight promise.\n *\n * Throws on non-2xx so the harness-side identity resolver knows to\n * fall back to modelId parsing — silent empty-list returns would be\n * indistinguishable from \"this gateway has no models\", which a\n * misconfigured endpoint shouldn't be allowed to claim.\n */\n async listModels(): Promise<readonly ModelMetadata[]> {\n const now = Date.now();\n if (this.modelsCache !== null && now - this.modelsCache.fetchedAt < LIST_MODELS_TTL_MS) {\n return this.modelsCache.value;\n }\n if (this.modelsInFlight !== null) {\n return this.modelsInFlight;\n }\n const inFlight = this.fetchModels();\n this.modelsInFlight = inFlight;\n try {\n const value = await inFlight;\n this.modelsCache = { value, fetchedAt: Date.now() };\n return value;\n } finally {\n this.modelsInFlight = null;\n }\n }\n\n private modelsCache: { value: readonly ModelMetadata[]; fetchedAt: number } | null = null;\n private modelsInFlight: Promise<readonly ModelMetadata[]> | null = null;\n\n private async fetchModels(): Promise<readonly ModelMetadata[]> {\n const list = await this.client.models.list();\n return list.data.map((m): ModelMetadata => {\n const meta: ModelMetadata = { id: m.id };\n if (typeof m.owned_by === 'string') {\n return { ...meta, ownedBy: m.owned_by, createdAt: m.created };\n }\n if (typeof m.created === 'number') {\n return { ...meta, createdAt: m.created };\n }\n return meta;\n });\n }\n}\n\nconst LIST_MODELS_TTL_MS = 5 * 60 * 1000;\n\n/**\n * Creates an OpenAIAdapter with the specified configuration.\n * Factory function for cleaner API.\n *\n * @param config - OpenAI adapter configuration\n * @returns A configured OpenAIAdapter instance\n *\n * @example\n * ```typescript\n * const adapter = createOpenAIAdapter({\n * modelId: 'gpt-4o',\n * apiKey: process.env.OPENAI_API_KEY!,\n * });\n * ```\n */\nexport function createOpenAIAdapter(config: OpenAIAdapterConfig): OpenAIAdapter {\n return new OpenAIAdapter(config);\n}\n","/**\n * nexus-agents/adapters - OpenAI Message Mappers\n *\n * Functions for mapping between Nexus and OpenAI message formats.\n */\n\nimport type OpenAI from 'openai';\nimport type {\n ChatCompletionMessageParam,\n ChatCompletionTool,\n ChatCompletion,\n ChatCompletionChunk,\n} from 'openai/resources/chat/completions';\nimport type {\n ContentBlock,\n Message,\n ToolDefinition,\n TokenUsage,\n StopReason,\n StreamChunk,\n} from '../core/index.js';\nimport { isFunctionToolCall } from './openai-types.js';\n\n/**\n * Maps OpenAI finish reasons to our StopReason type.\n */\nexport function mapStopReason(openaiReason: string | null | undefined): StopReason {\n switch (openaiReason) {\n case 'stop':\n return 'end_turn';\n case 'length':\n return 'max_tokens';\n case 'tool_calls':\n case 'function_call':\n return 'tool_use';\n case 'content_filter':\n return 'end_turn';\n default:\n return 'end_turn';\n }\n}\n\n/**\n * Maps OpenAI choice to our ContentBlock array.\n */\nexport function mapChoiceToContentBlocks(choice: ChatCompletion.Choice): ContentBlock[] {\n const blocks: ContentBlock[] = [];\n const message = choice.message;\n\n // Add text content if present\n if (message.content !== null && message.content !== '') {\n blocks.push({ type: 'text', text: message.content });\n }\n\n // Add tool calls if present\n if (message.tool_calls !== undefined && message.tool_calls.length > 0) {\n for (const toolCall of message.tool_calls) {\n if (isFunctionToolCall(toolCall)) {\n let parsedInput: unknown;\n try {\n parsedInput = JSON.parse(toolCall.function.arguments) as unknown;\n } catch {\n parsedInput = { _raw: toolCall.function.arguments };\n }\n blocks.push({\n type: 'tool_use',\n id: toolCall.id,\n name: toolCall.function.name,\n input: parsedInput,\n });\n }\n }\n }\n\n // If no content at all, return empty text block\n if (blocks.length === 0) {\n blocks.push({ type: 'text', text: '' });\n }\n\n return blocks;\n}\n\n/**\n * Maps our Message format to OpenAI's ChatCompletionMessageParam format.\n */\nexport function mapMessage(message: Message): ChatCompletionMessageParam {\n // Handle system messages\n if (message.role === 'system') {\n return mapSystemMessage(message);\n }\n\n // Handle user messages\n if (message.role === 'user') {\n return mapUserMessage(message);\n }\n\n // Handle assistant messages\n return mapAssistantMessage(message);\n}\n\n/**\n * Maps a system message.\n */\nfunction mapSystemMessage(message: Message): ChatCompletionMessageParam {\n const content =\n typeof message.content === 'string'\n ? message.content\n : message.content\n .filter((b): b is { type: 'text'; text: string } => b.type === 'text')\n .map((b) => b.text)\n .join('\\n');\n return { role: 'system', content };\n}\n\n/**\n * Maps a user message.\n */\nfunction mapUserMessage(message: Message): ChatCompletionMessageParam {\n if (typeof message.content === 'string') {\n return { role: 'user', content: message.content };\n }\n\n // Check for tool results - these need special handling\n const toolResults = message.content.filter(\n (b): b is { type: 'tool_result'; tool_use_id: string; content: string; is_error?: boolean } =>\n b.type === 'tool_result'\n );\n\n if (toolResults.length > 0) {\n // Return first tool result as a tool message\n const firstResult = toolResults[0];\n if (firstResult !== undefined) {\n return {\n role: 'tool',\n tool_call_id: firstResult.tool_use_id,\n content: firstResult.content,\n };\n }\n }\n\n // Map to user message with content array\n const content = message.content.map((block) => {\n if (block.type === 'text') {\n return { type: 'text' as const, text: block.text };\n }\n if (block.type === 'image') {\n return {\n type: 'image_url' as const,\n image_url: {\n url: `data:${block.source.media_type};base64,${block.source.data}`,\n },\n };\n }\n // Fallback for other types\n return { type: 'text' as const, text: '' };\n });\n\n return { role: 'user', content };\n}\n\n/**\n * Maps an assistant message.\n */\nfunction mapAssistantMessage(message: Message): ChatCompletionMessageParam {\n if (typeof message.content === 'string') {\n return { role: 'assistant', content: message.content };\n }\n\n // Check for tool uses in assistant message\n const toolUses = message.content.filter(\n (b): b is { type: 'tool_use'; id: string; name: string; input: unknown } =>\n b.type === 'tool_use'\n );\n\n const textContent = message.content\n .filter((b): b is { type: 'text'; text: string } => b.type === 'text')\n .map((b) => b.text)\n .join('');\n\n if (toolUses.length > 0) {\n const assistantMessage: ChatCompletionMessageParam = {\n role: 'assistant',\n content: textContent !== '' ? textContent : null,\n tool_calls: toolUses.map((tool) => ({\n id: tool.id,\n type: 'function' as const,\n function: {\n name: tool.name,\n arguments: JSON.stringify(tool.input),\n },\n })),\n };\n return assistantMessage;\n }\n\n return { role: 'assistant', content: textContent };\n}\n\n/**\n * Maps our ToolDefinition to OpenAI's tool format.\n */\nexport function mapTool(tool: ToolDefinition): ChatCompletionTool {\n return {\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description,\n parameters: tool.inputSchema,\n },\n };\n}\n\n/**\n * Maps OpenAI API response to our CompletionResponse format.\n */\nexport function mapResponseUsage(response: ChatCompletion): TokenUsage | undefined {\n const u = response.usage;\n // #4439: `?? 0` here synthesised a measurement the vendor never sent. An\n // absent usage block must stay absent so the decision-cost rollup can tell\n // \"zero tokens\" from \"we do not know\".\n if (u === undefined) return undefined;\n const cached = u.prompt_tokens_details?.cached_tokens;\n return {\n inputTokens: u.prompt_tokens,\n outputTokens: u.completion_tokens,\n totalTokens: u.total_tokens,\n ...(cached !== undefined ? { cachedInputTokens: cached } : {}),\n };\n}\n\n/**\n * Maps content delta from stream chunk.\n */\nfunction mapContentDelta(\n delta: OpenAI.Chat.ChatCompletionChunk.Choice.Delta,\n currentIndex: number,\n hasStarted: boolean\n): StreamChunk[] {\n const chunks: StreamChunk[] = [];\n\n if (delta.content !== undefined && delta.content !== null && delta.content !== '') {\n // Start content block if this is the first content\n if (currentIndex === 0 && !hasStarted) {\n chunks.push({\n type: 'content_block_start',\n index: 0,\n contentBlock: { type: 'text', text: '' },\n });\n }\n\n chunks.push({\n type: 'content_block_delta',\n index: currentIndex,\n delta: { type: 'text_delta', text: delta.content },\n });\n }\n\n return chunks;\n}\n\n/**\n * Maps tool calls from stream chunk delta.\n */\nfunction mapToolCallsDelta(delta: OpenAI.Chat.ChatCompletionChunk.Choice.Delta): StreamChunk[] {\n const chunks: StreamChunk[] = [];\n\n if (delta.tool_calls !== undefined && delta.tool_calls.length > 0) {\n for (const toolCall of delta.tool_calls) {\n if (toolCall.function?.name !== undefined) {\n chunks.push({\n type: 'content_block_start',\n index: toolCall.index,\n contentBlock: {\n type: 'tool_use',\n id: toolCall.id ?? '',\n name: toolCall.function.name,\n input: {},\n },\n });\n }\n }\n }\n\n return chunks;\n}\n\n/**\n * Maps finish reason from stream chunk.\n */\nfunction mapFinishChunks(\n choice: ChatCompletionChunk.Choice,\n chunk: ChatCompletionChunk,\n currentIndex: number\n): StreamChunk[] {\n const chunks: StreamChunk[] = [];\n\n if (choice.finish_reason !== null) {\n // End current content block\n chunks.push({\n type: 'content_block_stop',\n index: currentIndex,\n });\n\n // Emit message_delta with stop reason.\n //\n // NO `usage` on this path. OpenAI populates `chunk.usage` on a streaming\n // response only when the request sets `stream_options: { include_usage:\n // true }`, and nothing in this tree does — so both `??` fallbacks always\n // took the `0` branch and every stream emitted\n // `{inputTokens: 0, outputTokens: 0, totalTokens: 0}`: a usage block in\n // which nothing whatsoever was measured.\n //\n // `inputTokensMeasured: false` covered only the first of those three. Its\n // own contract is \"whether `inputTokens` is a measurement\", and there is no\n // `outputTokensMeasured`, so a consumer honouring the flag correctly\n // discounted `inputTokens` and then read `outputTokens: 0` as a measured\n // zero. That is the #4439 policy this violated, stated on the field itself:\n // \"Where NOTHING is known, prefer omitting `usage` entirely.\" The SDK\n // adapter's stream path already does exactly that (#4835), for the same\n // reason.\n chunks.push({\n type: 'message_delta',\n delta: { stop_reason: mapStopReason(choice.finish_reason) },\n // A stream whose usage IS reported keeps it — when `include_usage` is\n // wired, this is the branch that carries a real measurement.\n ...(chunk.usage !== undefined && chunk.usage !== null\n ? {\n usage: {\n // OpenAI still omits prompt_tokens on the final chunk (#4835).\n inputTokens: 0,\n inputTokensMeasured: false,\n outputTokens: chunk.usage.completion_tokens,\n totalTokens: chunk.usage.total_tokens,\n },\n }\n : {}),\n });\n\n // Emit message_stop\n chunks.push({ type: 'message_stop' });\n }\n\n return chunks;\n}\n\n/**\n * Maps OpenAI stream chunks to our StreamChunk format.\n */\nexport function mapStreamChunk(\n chunk: ChatCompletionChunk,\n currentIndex: number,\n hasStarted: boolean\n): StreamChunk[] {\n const chunks: StreamChunk[] = [];\n const choice = chunk.choices[0];\n\n // Emit message_start on first chunk\n if (!hasStarted) {\n chunks.push({\n type: 'message_start',\n message: { model: chunk.model },\n });\n }\n\n if (choice === undefined) {\n return chunks;\n }\n\n const delta = choice.delta;\n\n // Map content delta\n chunks.push(...mapContentDelta(delta, currentIndex, hasStarted));\n\n // Map tool calls\n chunks.push(...mapToolCallsDelta(delta));\n\n // Map finish reason\n chunks.push(...mapFinishChunks(choice, chunk, currentIndex));\n\n return chunks;\n}\n","/**\n * opencode.json gateway-config bridge (#2503, child 3 of epic #2500).\n *\n * When nexus-agents runs as an MCP loaded by OpenCode (typically inside a\n * Docker sandbox), OpenCode's `opencode.json` already declares the\n * OpenAI-compatible gateway the harness uses. Reading it from there saves\n * the operator from re-declaring the same `baseURL` + `apiKey` as\n * NEXUS_OPENAI_COMPAT_* env vars.\n *\n * Scope (per direction discussion 2026-05-09):\n * - **Only** reads `providers.openai-compat.options.{baseURL, apiKey}`.\n * Does NOT read OpenCode's MCP config, model list, logging, or other\n * settings. nexus-agents' own behaviour stays driven by\n * `nexus-agents.yaml` + `NEXUS_*` env vars.\n * - Resolves OpenCode's `{env:VAR}` interpolation in the apiKey field.\n * - Returns `null` on any failure path (missing file, parse error,\n * missing fields, unset interpolated env var) — caller falls back to\n * env-var precedence; we don't throw.\n *\n * Precedence (applied in `openai-compat-adapter.ts`):\n * 1. `NEXUS_OPENAI_COMPAT_URL` + `NEXUS_OPENAI_COMPAT_KEY` env vars (if both set)\n * 2. `NEXUS_OPENCODE_CONFIG` → `opencode.json` → `providers.openai-compat`\n * 3. Unconfigured → `null`, no adapter registered\n *\n * Sanitised logging (#4392 increment 3 tightened it): never log the resolved\n * apiKey, never log file contents — Node's JSON parse error embeds a source\n * snippet, so only the error NAME is logged — and log the gateway's hostname\n * rather than the baseURL, which can carry userinfo.\n *\n * @module config/opencode-bridge\n */\n\nimport { readFileSync } from 'node:fs';\n\nimport type { ILogger } from '../core/index.js';\nimport { createLogger } from '../core/index.js';\nimport { hostnameOf } from '../adapters/sdk/gateway-env.js';\n\nconst defaultLogger = createLogger({ component: 'opencode-bridge' });\n\nexport interface OpencodeGatewayConfig {\n readonly baseURL: string;\n readonly apiKey: string;\n}\n\n/**\n * Read `providers.openai-compat.options.{baseURL, apiKey}` from the given\n * opencode.json path. Returns `null` on any failure — the caller falls\n * back to env-var precedence.\n */\nexport function readOpencodeGateway(\n path: string,\n logger: ILogger = defaultLogger\n): OpencodeGatewayConfig | null {\n const raw = readFileOrNull(path, logger);\n if (raw === null) return null;\n\n const parsed = parseJsonOrNull(raw, path, logger);\n if (parsed === null) return null;\n\n const options = extractOpenAICompatOptions(parsed);\n if (options === null) {\n logger.debug('opencode.json has no providers.openai-compat.options block', { path });\n return null;\n }\n\n const baseURL = typeof options.baseURL === 'string' ? options.baseURL.trim() : '';\n const apiKeyRaw = typeof options.apiKey === 'string' ? options.apiKey.trim() : '';\n if (baseURL === '' || apiKeyRaw === '') {\n logger.warn('opencode.json providers.openai-compat missing baseURL or apiKey', { path });\n return null;\n }\n\n const apiKey = resolveEnvInterpolation(apiKeyRaw);\n if (apiKey === null) {\n logger.warn(\n 'opencode.json apiKey references an env var that is not set; gateway not configured',\n { path }\n );\n return null;\n }\n\n logger.info('Gateway config sourced from opencode.json', { host: hostnameOf(baseURL), path });\n return { baseURL, apiKey };\n}\n\nfunction readFileOrNull(path: string, logger: ILogger): string | null {\n try {\n return readFileSync(path, 'utf8');\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.debug('Could not read opencode.json', { path, error: msg });\n return null;\n }\n}\n\n/**\n * Logs the error NAME only. On Node 22 a `SyntaxError` from `JSON.parse`\n * quotes the offending source (`... \"{\"apiKey\": sk-...\" is not valid JSON`),\n * so the message is a channel for the file's contents (#4392 increment 3).\n */\nfunction parseJsonOrNull(raw: string, path: string, logger: ILogger): unknown {\n try {\n return JSON.parse(raw);\n } catch (err: unknown) {\n const name = err instanceof Error ? err.name : 'unknown error';\n logger.warn('opencode.json is not valid JSON; ignoring', { path, error: name });\n return null;\n }\n}\n\n/**\n * Pull `providers.openai-compat.options` out of the parsed JSON without\n * coupling to a Zod schema. OpenCode's config has many keys we don't\n * care about; we only navigate to the one we need.\n */\nfunction extractOpenAICompatOptions(\n parsed: unknown\n): { baseURL?: unknown; apiKey?: unknown } | null {\n if (typeof parsed !== 'object' || parsed === null) return null;\n const root = parsed as { providers?: unknown };\n const providers = root.providers;\n if (typeof providers !== 'object' || providers === null) return null;\n const provider = (providers as Record<string, unknown>)['openai-compat'];\n if (typeof provider !== 'object' || provider === null) return null;\n const options = (provider as { options?: unknown }).options;\n if (typeof options !== 'object' || options === null) return null;\n return options;\n}\n\n/**\n * Resolve OpenCode's `{env:VAR}` interpolation. Only the literal pattern\n * is supported (no shell expansion, no defaults). Returns the string as-is\n * when no interpolation is present; returns `null` when the referenced\n * env var is not set.\n */\nfunction resolveEnvInterpolation(value: string): string | null {\n const match = /^\\{env:([A-Z0-9_]+)\\}$/.exec(value);\n if (match === null) return value;\n const envName = match[1];\n if (envName === undefined) return null;\n const resolved = process.env[envName];\n if (resolved === undefined || resolved === '') return null;\n return resolved;\n}\n","/**\n * OpenAI-compatible gateway adapter — talk to any HTTP gateway that exposes\n * the OpenAI Chat Completions API. The gateway may itself be a multi-model\n * router (Bedrock/Vertex/Azure proxy, OpenRouter, vLLM, etc.). nexus-agents\n * sees one adapter, the gateway exposes N models, and the existing routing\n * pipeline picks among them.\n *\n * Source: Issue #2468 (epic #2467 child).\n *\n * Configuration precedence (#2503, child 3 of epic #2500):\n * 1. NEXUS_OPENAI_COMPAT_URL + NEXUS_OPENAI_COMPAT_KEY env vars (both required)\n * 2. NEXUS_OPENCODE_CONFIG path → opencode.json → providers.openai-compat\n * 3. Unconfigured → adapter not built\n *\n * Models are discovered via GET {base}/v1/models at first use. Each model\n * the gateway exposes can be selected by ID; the adapter wraps the existing\n * `OpenAIAdapter` for the actual chat-completions request, so streaming +\n * tool use + the full IModelAdapter contract come for free.\n */\n\nimport OpenAI from 'openai';\nimport { assertCustomApiHostResolvesPublic } from './sdk/custom-api-validation.js';\n\nimport type {\n Result,\n CompletionRequest,\n CompletionResponse,\n ILogger,\n ModelError,\n ModelMetadata,\n IModelAdapter,\n} from '../core/index.js';\nimport {\n ok,\n err,\n ConfigError,\n createLogger,\n getErrorMessage,\n getTimeProvider,\n} from '../core/index.js';\nimport { OpenAIAdapter } from './openai-adapter.js';\nimport { recordUsageEvent } from '../learning/usage-log.js';\nimport { gatewayCostDetail } from '../cli-adapters/budget-arm-cost.js';\nimport { readOpencodeGateway } from '../config/opencode-bridge.js';\nimport { isEndpointArmId, type EndpointArmId } from '../cli-adapters/types-core.js';\nimport { gatewayEndpointRejection } from './sdk/gateway-cost.js';\nimport {\n DEFAULT_OPENAI_COMPAT_ENDPOINT,\n OPENAI_COMPAT_ENDPOINT_ENV,\n OPENAI_COMPAT_KEY_ENV,\n OPENAI_COMPAT_URL_ENV,\n} from './sdk/types.js';\nimport { hostnameOf, redactApiKey } from './sdk/gateway-env.js';\n\nexport interface OpenAICompatConfig {\n /** Gateway base URL — must reach `/v1/models` and `/v1/chat/completions`. */\n readonly baseUrl: string;\n /** API key the gateway expects. */\n readonly apiKey: string;\n /**\n * Endpoint identity the gateway registers as — the `<endpoint>` of its\n * `api:<endpoint>` arm (#4392 increment 2, step 2). Always set by\n * {@link readOpenAICompatEnv}; optional on the type so a hand-built config\n * (tests, embedders) keeps working, with the default applying at\n * registration. Never the URL.\n */\n readonly endpoint?: string;\n}\n\n/**\n * A per-model gateway adapter, marked with the `api:<endpoint>` arm it\n * registers under (#4392 increment 2, step 4). The telemetry writers key on\n * this — the usage log here, the vote rollup in `decision-cost-recording` —\n * to price a call by the arm's `NEXUS_GATEWAY_COST` declaration instead of\n * by the model id alone. `providerId` stays `'openai'` on purpose:\n * `inFamilyFallback` and `authRemediation` take their inputs from it.\n * Reached through {@link isGatewayModelAdapter} (narrowing) and\n * {@link createOpenAICompatAdapter} (construction); not exported by name\n * because nothing outside this module needs to spell it.\n */\ninterface GatewayModelAdapter extends IModelAdapter {\n readonly gatewayArm: EndpointArmId;\n}\n\n/**\n * True iff `adapter` carries a valid gateway arm id. Checked by shape, not\n * by construction site: a hand-built config can name an endpoint that is not\n * an endpoint id, and a marker that fails the id rule is no marker.\n */\nexport function isGatewayModelAdapter(adapter: IModelAdapter): adapter is GatewayModelAdapter {\n const arm: unknown = (adapter as Partial<GatewayModelAdapter>).gatewayArm;\n return typeof arm === 'string' && isEndpointArmId(arm);\n}\n\nexport interface DiscoveredModel {\n readonly id: string;\n /** Unix epoch seconds when the model was created (per OpenAI API). */\n readonly created?: number;\n /** Owning organization or upstream provider name. */\n readonly ownedBy?: string;\n}\n\n/**\n * Read the gateway config with the precedence chain documented in the\n * module docstring: env vars > opencode.json > unconfigured.\n *\n * The env-var path (#2468) wins when both `NEXUS_OPENAI_COMPAT_URL` and\n * `NEXUS_OPENAI_COMPAT_KEY` are set. Otherwise, when `NEXUS_OPENCODE_CONFIG`\n * names a path, the opencode.json bridge tries to source the gateway from\n * `providers.openai-compat.options.{baseURL, apiKey}` (#2503). Returns\n * `null` when neither path yields a config — caller treats unset gateway\n * as \"no adapter from this source.\"\n */\nexport function readOpenAICompatEnv(): OpenAICompatConfig | null {\n const fromEnv = readGatewayFromEnv();\n if (fromEnv !== null) return fromEnv;\n return readGatewayFromOpencode();\n}\n\n/**\n * Reads the NEW names only. The deprecated `NEXUS_CUSTOM_API_*` pair is an\n * alias for the single-model `custom-openai` reader (`sdk/gateway-env.ts`)\n * and deliberately not for this one (#4392 increment 3, panel option C):\n * renaming is what opts an operator into discovery, in-process voters and\n * the `api:<endpoint>` arm, so the legacy pair alone must leave this null.\n */\nfunction readGatewayFromEnv(): OpenAICompatConfig | null {\n const envUrl = process.env[OPENAI_COMPAT_URL_ENV]?.trim();\n const envKey = process.env[OPENAI_COMPAT_KEY_ENV]?.trim();\n if (envUrl === undefined || envUrl === '') return null;\n if (envKey === undefined || envKey === '') return null;\n return { baseUrl: envUrl, apiKey: envKey, endpoint: readOpenAICompatEndpoint() };\n}\n\nfunction readGatewayFromOpencode(): OpenAICompatConfig | null {\n const opencodePath = process.env['NEXUS_OPENCODE_CONFIG']?.trim();\n if (opencodePath === undefined || opencodePath === '') return null;\n const fromFile = readOpencodeGateway(opencodePath);\n if (fromFile === null) return null;\n return {\n baseUrl: fromFile.baseURL,\n apiKey: fromFile.apiKey,\n endpoint: readOpenAICompatEndpoint(),\n };\n}\n\nconst endpointLogger = createLogger({ component: 'openai-compat-adapter' });\n\n/**\n * The gateway's endpoint identity (#4392 increment 2, step 2):\n * `NEXUS_OPENAI_COMPAT_ENDPOINT` when `api:<value>` is a GATEWAY arm id, else\n * {@link DEFAULT_OPENAI_COMPAT_ENDPOINT}. The fallback is deliberate: the env\n * schema reports an invalid value at startup, and this reader must never turn\n * a pasted URL — or a credential inside one — into an arm id, telemetry key\n * or display string, nor register the gateway as a VENDOR arm (`api:openai`),\n * where its cost declaration is unreachable (#6409). The same rule decides\n * both (`gatewayEndpointRejection`), and the fallback is warned with the\n * reason, never the value. Both config paths (env, opencode.json) share it.\n */\nexport function readOpenAICompatEndpoint(\n env: NodeJS.ProcessEnv = process.env,\n logger: ILogger = endpointLogger\n): string {\n const raw = env[OPENAI_COMPAT_ENDPOINT_ENV]?.trim();\n if (raw === undefined || raw === '') return DEFAULT_OPENAI_COMPAT_ENDPOINT;\n const reason = gatewayEndpointRejection(raw);\n if (reason === undefined) return raw;\n logger.warn(\n `${OPENAI_COMPAT_ENDPOINT_ENV} ignored (${reason}); the gateway registers as api:${DEFAULT_OPENAI_COMPAT_ENDPOINT}`,\n { env: OPENAI_COMPAT_ENDPOINT_ENV, reason, value: '<redacted>' }\n );\n return DEFAULT_OPENAI_COMPAT_ENDPOINT;\n}\n\n/**\n * Ceiling on how many models one gateway may contribute.\n *\n * `buildOpenAICompatAdapters` constructs one adapter per discovered model, so an\n * unbounded list becomes unbounded objects during bootstrap. Aggregators\n * legitimately serve hundreds — models.dev lists 339 for one and 620 for\n * another — so this is a sanity ceiling on adapter construction, not a claim\n * about what a gateway may offer.\n */\nconst MAX_DISCOVERED_MODELS = 256;\n\n/** Bound on the discovery call. Bootstrap must not hang on a dead gateway. */\nconst MODEL_DISCOVERY_TIMEOUT_MS = 10_000;\n\n/**\n * Shape of a model id this adapter will dispatch to (#4392 increment 2, step\n * 2). A discovered id becomes a request field, a usage-log key and — through\n * the gateway catalogue — a pricing key, so whitespace and control characters\n * are refused; `/`, `:`, `.` and `_` are kept because aggregators use them\n * (`org/model:tag`). Length is capped at 128.\n */\nconst MODEL_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/;\n\n/**\n * Keep the ids that satisfy {@link MODEL_ID_PATTERN}. Warns with the dropped\n * COUNT only — an offending id is exactly the string that must not reach a\n * log line, and the count is what tells an operator the gateway's listing\n * needs a look.\n */\nfunction keepValidModelIds(\n models: readonly DiscoveredModel[],\n logger: ILogger | undefined\n): readonly DiscoveredModel[] {\n const kept = models.filter((m) => MODEL_ID_PATTERN.test(m.id));\n const dropped = models.length - kept.length;\n if (dropped > 0) {\n logger?.warn(\n `Dropped ${String(dropped)} gateway model id(s) that are not a valid model id shape (whitespace, control characters, or over 128 chars)`,\n { dropped, kept: kept.length }\n );\n }\n return kept;\n}\n\n/**\n * Discover available models by calling `GET {baseUrl}/v1/models`. Uses the\n * official `openai` SDK's `client.models.list()` so we benefit from its\n * pagination + retry handling. The list is the strongly authoritative\n * source: nexus-agents won't try to dispatch to a model the gateway doesn't\n * expose.\n */\nexport async function discoverModels(\n config: OpenAICompatConfig,\n logger?: ILogger\n): Promise<Result<readonly DiscoveredModel[], ConfigError>> {\n // Reuse the SDK path's DNS-resolve-time SSRF guard (#3426) rather than\n // growing a second one. This path needs it at least as much: it can read its\n // base URL from a FILE (`NEXUS_OPENCODE_CONFIG` -> opencode.json), not only\n // from an env var, so the input is not always direct operator intent.\n // The guard fails OPEN on transient resolver errors and rejects only a\n // confirmed private/loopback/link-local resolution.\n const hostCheck = await assertCustomApiHostResolvesPublic(hostnameOf(config.baseUrl));\n if (!hostCheck.ok) {\n return err(new ConfigError(`Gateway URL rejected: ${hostCheck.error.message}`));\n }\n try {\n const client = new OpenAI({\n baseURL: config.baseUrl,\n apiKey: config.apiKey,\n // Discovery runs during server bootstrap, so an unresponsive gateway must\n // not stall startup indefinitely. The SDK's own default is far longer.\n timeout: MODEL_DISCOVERY_TIMEOUT_MS,\n maxRetries: 1,\n });\n const list = await client.models.list();\n if (list.data.length > MAX_DISCOVERED_MODELS) {\n return err(\n new ConfigError(\n `Gateway ${hostnameOf(config.baseUrl)} listed ${String(list.data.length)} models, above the ` +\n `${String(MAX_DISCOVERED_MODELS)} cap. Refusing to build an adapter per model.`\n )\n );\n }\n const models: readonly DiscoveredModel[] = list.data.map((m) => ({\n id: m.id,\n created: m.created,\n ownedBy: m.owned_by,\n }));\n return ok(keepValidModelIds(models, logger));\n } catch (e: unknown) {\n // This message lands on cli-server-gateway's probe-failed warn line, so it\n // names the host (a base URL can carry userinfo) and never the key: a\n // gateway's 401 body may echo the bearer it rejected (#4392 increment 3).\n return err(\n new ConfigError(\n `Failed to discover models from ${hostnameOf(config.baseUrl)}: ` +\n `${redactApiKey(getErrorMessage(e), config.apiKey)}. ` +\n `Verify ${OPENAI_COMPAT_URL_ENV} and ${OPENAI_COMPAT_KEY_ENV}, then retry.`\n )\n );\n }\n}\n\n/**\n * Create an OpenAIAdapter pointed at the gateway for a specific model ID,\n * wrapped with usage recording so every completion appends a UsageEvent\n * to the JSONL log consumed by `nexus-agents usage`.\n *\n * The wrapper is transparent — same IModelAdapter contract, same fields,\n * same error handling — plus the {@link GatewayModelAdapter} arm marker,\n * `api:<config.endpoint>` (the default endpoint when a hand-built config\n * omits it, matching registration). Recording is best-effort (telemetry\n * never fails the user's call).\n *\n * When invoked via MCP, the host harness's model identifier is passed\n * through verbatim — nexus-agents doesn't second-guess what the host is\n * already routing.\n */\nexport function createOpenAICompatAdapter(\n modelId: string,\n config: OpenAICompatConfig\n): GatewayModelAdapter {\n const inner = new OpenAIAdapter({ modelId, apiKey: config.apiKey, baseUrl: config.baseUrl });\n return withUsageRecording(inner, `api:${config.endpoint ?? DEFAULT_OPENAI_COMPAT_ENDPOINT}`);\n}\n\n/**\n * Wrap a gateway model adapter so that successful + failed `complete()`\n * calls append a UsageEvent to the on-disk usage log. Stream calls aren't\n * yet instrumented (a future PR can add streaming-aware recording).\n *\n * The returned object preserves the IModelAdapter contract identically;\n * downstream code can't tell the difference except that one extra JSONL\n * line gets written per call. The line is priced by `gatewayArm`'s\n * `NEXUS_GATEWAY_COST` declaration ({@link gatewayCostDetail}, #4392 step 4):\n * an undeclared gateway records `priced: false`, never the model id's vendor\n * list price.\n */\nfunction withUsageRecording(inner: IModelAdapter, gatewayArm: EndpointArmId): GatewayModelAdapter {\n const wrapped: GatewayModelAdapter = {\n gatewayArm,\n providerId: inner.providerId,\n modelId: inner.modelId,\n capabilities: inner.capabilities,\n countTokens: (text) => inner.countTokens(text),\n validateConfig: () => inner.validateConfig(),\n stream: (request) => inner.stream(request),\n async complete(request: CompletionRequest): Promise<Result<CompletionResponse, ModelError>> {\n const start = getTimeProvider().now();\n const result = await inner.complete(request);\n const latencyMs = getTimeProvider().now() - start;\n try {\n if (result.ok) {\n const u = result.value.usage;\n // No vendor usage ⇒ nothing to record. Zero-filling here would write\n // a fabricated measurement into the usage log, which is the defect\n // #4439 exists to remove — a lost latency datapoint is the cheaper\n // loss than a false token count.\n if (u === undefined) return result;\n // Declaration-first pricing with provenance (#4165, #4392 step 4):\n // `priced: false` marks the $0 as UNPRICED (unmeasured), not a real $0.\n const cost = gatewayCostDetail(gatewayArm, inner.modelId, u.inputTokens, u.outputTokens);\n recordUsageEvent({\n timestamp: new Date().toISOString(),\n modelId: inner.modelId,\n providerId: inner.providerId,\n inputTokens: u.inputTokens,\n outputTokens: u.outputTokens,\n usdCost: cost.costUsd,\n latencyMs,\n success: true,\n priced: cost.priced,\n ...(cost.priced ? { priceSource: cost.resolvedId } : {}),\n });\n } else {\n recordFailedCall(inner, latencyMs, result.error.code);\n }\n } catch {\n // Telemetry must not break user calls.\n }\n return result;\n },\n };\n attachListModels(wrapped, inner);\n return wrapped;\n}\n\n/** The usage line for a failed call: no tokens, no cost — the error code is the datum. */\nfunction recordFailedCall(inner: IModelAdapter, latencyMs: number, errorCode: string): void {\n recordUsageEvent({\n timestamp: new Date().toISOString(),\n modelId: inner.modelId,\n providerId: inner.providerId,\n inputTokens: 0,\n outputTokens: 0,\n usdCost: 0,\n latencyMs,\n success: false,\n errorCode,\n });\n}\n\n/**\n * (#2540) Forward `listModels` through the wrapper when the inner adapter\n * exposes one. Only attach when defined so the wrapper's `listModels?:`\n * hint stays accurate for the resolver. The inner reference is captured\n * by closure so the forwarded call binds `this` to the inner adapter.\n */\nfunction attachListModels(wrapped: IModelAdapter, inner: IModelAdapter): void {\n const list = inner.listModels?.bind(inner);\n if (list === undefined) return;\n wrapped.listModels = (): Promise<readonly ModelMetadata[]> => list();\n}\n\n/**\n * Convenience: read env, discover, return adapter instances for every\n * discovered model. Returns `null` (not an error) when env vars aren't set\n * — the caller treats unset gateway as \"no adapter from this source.\"\n *\n * Use case: the unified registry / factory calls this at startup; if the\n * operator has configured a gateway, every discovered model becomes a\n * dispatch target alongside the existing claude/codex/gemini/opencode\n * adapter slots.\n */\nexport async function buildOpenAICompatAdapters(\n logger?: ILogger\n): Promise<Result<readonly IModelAdapter[], ConfigError> | null> {\n const config = readOpenAICompatEnv();\n if (config === null) return null;\n const discovered = await discoverModels(config, logger);\n if (!discovered.ok) return discovered;\n return ok(discovered.value.map((m) => createOpenAICompatAdapter(m.id, config)));\n}\n"],"mappings":"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","names":["err","err","OpenAI","OpenAI"]}
@@ -7,7 +7,7 @@ import {
7
7
  createLogger,
8
8
  err,
9
9
  ok
10
- } from "./chunk-YGOTLETF.js";
10
+ } from "./chunk-OMIR6ISN.js";
11
11
 
12
12
  // src/adapters/sdk/gateway-env.ts
13
13
  function readTrimmed(env, name) {
@@ -315,4 +315,4 @@ export {
315
315
  validateCustomApiBaseUrl,
316
316
  assertCustomApiHostResolvesPublic
317
317
  };
318
- //# sourceMappingURL=chunk-B3PR26HR.js.map
318
+ //# sourceMappingURL=chunk-RIB56PWI.js.map
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  resolveCliSlot
3
- } from "./chunk-PBXABL7H.js";
3
+ } from "./chunk-HQQ3ES3J.js";
4
4
  import {
5
5
  createLogger,
6
6
  getTimeProvider,
7
7
  isRateLimitText
8
- } from "./chunk-YGOTLETF.js";
8
+ } from "./chunk-OMIR6ISN.js";
9
9
 
10
10
  // src/pipeline/expert-bridge.ts
11
11
  function resolveCliFromModelString(model) {
@@ -21,7 +21,7 @@ async function getMcpConfigPath() {
21
21
  if (cachedMcpConfigPath !== null) return cachedMcpConfigPath;
22
22
  mcpConfigInitPromise ??= (async () => {
23
23
  try {
24
- const { generateMcpConfig } = await import("./child-mcp-config-HAXDNULH.js");
24
+ const { generateMcpConfig } = await import("./child-mcp-config-DMTIHAH5.js");
25
25
  const config = await generateMcpConfig();
26
26
  cachedMcpConfigPath = config.configPath;
27
27
  cachedMcpConfigCleanup = config.cleanup;
@@ -93,8 +93,8 @@ var routerInitPromise = null;
93
93
  async function getRouter() {
94
94
  if (cachedRouter !== null) return cachedRouter;
95
95
  routerInitPromise ??= (async () => {
96
- const { createAllAdapters } = await import("./factory-O4U4BJFT.js");
97
- const { createCompositeRouter } = await import("./composite-router-UD3FGSSS.js");
96
+ const { createAllAdapters } = await import("./factory-KAMTEOXC.js");
97
+ const { createCompositeRouter } = await import("./composite-router-LAMVSGZ3.js");
98
98
  const adapters = createAllAdapters();
99
99
  if (adapters.size === 0) {
100
100
  routerInitPromise = null;
@@ -102,7 +102,7 @@ async function getRouter() {
102
102
  }
103
103
  cachedRouter = adaptCompositeRouter(createCompositeRouter(adapters));
104
104
  try {
105
- const { createCliCircuitBreakerIntegration } = await import("./cli-circuit-breaker-TOE7GRYI.js");
105
+ const { createCliCircuitBreakerIntegration } = await import("./cli-circuit-breaker-VRTWILPB.js");
106
106
  cachedCircuitBreaker = createCliCircuitBreakerIntegration([...adapters.values()]);
107
107
  } catch (error) {
108
108
  const msg = error instanceof Error ? error.message : String(error);
@@ -216,4 +216,4 @@ export {
216
216
  tokenSplitFromUsage,
217
217
  executeExpert
218
218
  };
219
- //# sourceMappingURL=chunk-P5BZ3DNM.js.map
219
+ //# sourceMappingURL=chunk-T2ZQUZQW.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  generateSecurityPlan
3
- } from "./chunk-3EK4V5JS.js";
3
+ } from "./chunk-KUZV4AW5.js";
4
4
  import {
5
5
  analyzeGitHubRepo
6
6
  } from "./chunk-4GDMHCKX.js";
@@ -21,10 +21,10 @@ import {
21
21
  import {
22
22
  DEFAULT_TASK_TTL_MS,
23
23
  clampTaskTtl
24
- } from "./chunk-CDHUCQ44.js";
24
+ } from "./chunk-5JQL2KOJ.js";
25
25
  import {
26
26
  executeExpert
27
- } from "./chunk-P5BZ3DNM.js";
27
+ } from "./chunk-T2ZQUZQW.js";
28
28
  import {
29
29
  DEPRECATED_MODE_ALIAS_INPUT,
30
30
  JobStatusSchema,
@@ -72,7 +72,7 @@ import {
72
72
  updateStage,
73
73
  withWarnings,
74
74
  writeJobCancelled
75
- } from "./chunk-ARWTQGSY.js";
75
+ } from "./chunk-AOSBH5H7.js";
76
76
  import {
77
77
  allOf,
78
78
  anyOf
@@ -80,7 +80,7 @@ import {
80
80
  import {
81
81
  normalizeTopicToCanonical,
82
82
  synthesizeResearch
83
- } from "./chunk-KC3AZWVQ.js";
83
+ } from "./chunk-CJ2LQLZV.js";
84
84
  import {
85
85
  IssueTriage,
86
86
  createAuditTrail,
@@ -89,13 +89,13 @@ import {
89
89
  createGraphAuditBridge,
90
90
  emitPipelinePolicyEvent,
91
91
  readActionRefusal
92
- } from "./chunk-Z33AE45S.js";
92
+ } from "./chunk-FQ6UCX2J.js";
93
93
  import {
94
94
  sanitizeInput
95
- } from "./chunk-PB4SXWBA.js";
95
+ } from "./chunk-LBIFDT6N.js";
96
96
  import {
97
97
  withPrerequisite
98
- } from "./chunk-L3PGHZH7.js";
98
+ } from "./chunk-O6TFBXE5.js";
99
99
  import {
100
100
  NOOP_NOTIFIER,
101
101
  RateLimiter,
@@ -120,14 +120,14 @@ import {
120
120
  toolSuccessStructured,
121
121
  withProgressHeartbeat,
122
122
  wrapToolWithTimeout
123
- } from "./chunk-K6VACGLH.js";
123
+ } from "./chunk-DMUVBBOD.js";
124
124
  import {
125
125
  EventTopics,
126
126
  UNRESOLVED_MODEL_ID,
127
127
  createEvent,
128
128
  getGlobalEventBus,
129
129
  getGlobalRegistry
130
- } from "./chunk-FOODF33L.js";
130
+ } from "./chunk-6ZCKENQU.js";
131
131
  import {
132
132
  IDENTIFIER_RE,
133
133
  LANG_VALUES,
@@ -160,7 +160,7 @@ import {
160
160
  parseRegistry,
161
161
  sourceExistsInRegistry,
162
162
  summarizeContextForPrompt
163
- } from "./chunk-WZRXZ6P2.js";
163
+ } from "./chunk-GNTWB3O2.js";
164
164
  import {
165
165
  REGISTRY_PATH,
166
166
  getProjectRoot,
@@ -168,25 +168,25 @@ import {
168
168
  loadTechniquesRegistry,
169
169
  resolveInsideRoot,
170
170
  resolveRegistryRoot
171
- } from "./chunk-U33OOJOK.js";
171
+ } from "./chunk-3HU4VVD7.js";
172
172
  import {
173
173
  getTokenEnvVars,
174
174
  resolveToken
175
- } from "./chunk-WIBR5HMY.js";
175
+ } from "./chunk-OHM625YL.js";
176
176
  import {
177
177
  DEFAULT_RELEVANCE_CONFIG,
178
178
  MemoryImportance,
179
179
  MemoryType,
180
180
  calculateTextJaccardSimilarity,
181
181
  getToolMemory
182
- } from "./chunk-VYZRGIY5.js";
182
+ } from "./chunk-XGAMDSC5.js";
183
183
  import {
184
184
  STOPWORDS,
185
185
  truncateWithInfo
186
186
  } from "./chunk-7LP6VJRP.js";
187
187
  import {
188
188
  createSessionMemory
189
- } from "./chunk-QLYONNVR.js";
189
+ } from "./chunk-KVDXUGMQ.js";
190
190
  import {
191
191
  BUILT_IN_EXPERTS,
192
192
  BuiltInExpertTypeSchema,
@@ -204,24 +204,24 @@ import {
204
204
  getAvailableClis,
205
205
  sleep,
206
206
  withTimeout
207
- } from "./chunk-WKZSEYV7.js";
207
+ } from "./chunk-AHJUIF44.js";
208
208
  import {
209
209
  BaseAdapter,
210
210
  createStream,
211
211
  requireApiKey,
212
212
  validateApiKeyPresence
213
- } from "./chunk-7NLTUPYN.js";
213
+ } from "./chunk-DSIJ5L3Y.js";
214
214
  import {
215
215
  DEFAULTS
216
- } from "./chunk-Y2ARXXPF.js";
216
+ } from "./chunk-UXUOJOXL.js";
217
217
  import {
218
218
  resolveGatewayEnv
219
- } from "./chunk-B3PR26HR.js";
219
+ } from "./chunk-RIB56PWI.js";
220
220
  import {
221
221
  getAvailabilityCache,
222
222
  getCliForModelId,
223
223
  resolveFallback
224
- } from "./chunk-PBXABL7H.js";
224
+ } from "./chunk-HQQ3ES3J.js";
225
225
  import {
226
226
  sanitizeErrorDetails
227
227
  } from "./chunk-2NDA4DHW.js";
@@ -233,7 +233,7 @@ import {
233
233
  import {
234
234
  generateHyphenId,
235
235
  generateUUID
236
- } from "./chunk-TYHKIUUX.js";
236
+ } from "./chunk-PFZSS67U.js";
237
237
  import {
238
238
  AGENT_ROUTER_TIMEOUTS,
239
239
  API_TIMEOUTS,
@@ -349,7 +349,7 @@ import {
349
349
  selectStrategyByManifest,
350
350
  toExpertTaskAnalysisResult,
351
351
  withStep
352
- } from "./chunk-YGOTLETF.js";
352
+ } from "./chunk-OMIR6ISN.js";
353
353
  import {
354
354
  ensureLearningDir,
355
355
  getMetaOutcomesFile,
@@ -30305,7 +30305,7 @@ function execIdFields(executionId) {
30305
30305
  async function populateUnifiedContextOnState(state, options) {
30306
30306
  const taskCandidate = state["task"];
30307
30307
  if (typeof taskCandidate !== "string" || taskCandidate === "") return;
30308
- const { getContextForTask: getContextForTask2, inferTaskCategory: inferTaskCategory2 } = await import("./context-retriever-CH3GEH2Z.js");
30308
+ const { getContextForTask: getContextForTask2, inferTaskCategory: inferTaskCategory2 } = await import("./context-retriever-VRAIKZTE.js");
30309
30309
  const category = inferTaskCategory2(taskCandidate);
30310
30310
  const executionId = options?.executionId;
30311
30311
  const execFields = execIdFields(executionId);
@@ -45732,7 +45732,7 @@ async function tryIssueTriage(task) {
45732
45732
  try {
45733
45733
  const issueMatch = task.match(/github\.com\/([^/]+\/[^/]+)\/issues\/(\d+)/);
45734
45734
  if (issueMatch === null) return null;
45735
- const { createIssueTriage } = await import("./issue-triage-DQAOBZEP.js");
45735
+ const { createIssueTriage } = await import("./issue-triage-VAWDVGET.js");
45736
45736
  const triage = createIssueTriage();
45737
45737
  const owner = issueMatch[1] ?? "";
45738
45738
  const num2 = issueMatch[2] ?? "";
@@ -45760,7 +45760,7 @@ var VALID_TEMPLATES = /* @__PURE__ */ new Set([
45760
45760
  ]);
45761
45761
  async function classifyWithLLM(task) {
45762
45762
  try {
45763
- const { executeExpert: executeExpert2 } = await import("./expert-bridge-ZQSYVUC2.js");
45763
+ const { executeExpert: executeExpert2 } = await import("./expert-bridge-TMHBUOUK.js");
45764
45764
  const prompt = [
45765
45765
  "Classify this task into exactly one pipeline template.",
45766
45766
  "Templates: dev (implementation/bug fix/refactor), research (investigate/evaluate/compare),",
@@ -46134,7 +46134,7 @@ function buildVotingInput(plan, config) {
46134
46134
  }
46135
46135
  async function executeSingleVote(plan, config, log) {
46136
46136
  try {
46137
- const { executeVoting } = await import("./consensus-vote-YW6LAIH7.js");
46137
+ const { executeVoting } = await import("./consensus-vote-ZB72SHTV.js");
46138
46138
  const input = buildVotingInput(plan, config);
46139
46139
  const result = await executeVoting(input, log);
46140
46140
  return parseVotingResult(result);
@@ -46838,7 +46838,7 @@ var memoryInitPromise = null;
46838
46838
  async function initPipelineMemory() {
46839
46839
  if (cachedMemory !== null) return cachedMemory;
46840
46840
  try {
46841
- const { createSessionMemory: createSessionMemory2 } = await import("./session-memory-M5MEGJJZ.js");
46841
+ const { createSessionMemory: createSessionMemory2 } = await import("./session-memory-SRH5ZJRX.js");
46842
46842
  const { getLearningDir } = await import("./learning-persistence-7BEPQEGN.js");
46843
46843
  const mem = createSessionMemory2(getLearningDir());
46844
46844
  mem.startSession(`pipeline-${String(getTimeProvider().now())}`);
@@ -46900,7 +46900,7 @@ function recordRoutingExperience(category, success, durationMs, tokensUsed = 0,
46900
46900
  callRecord(routingMemoryCache);
46901
46901
  return;
46902
46902
  }
46903
- routingMemoryInitPromise ??= import("./routing-memory-HQTEZF2S.js").then(({ createRoutingMemory }) => {
46903
+ routingMemoryInitPromise ??= import("./routing-memory-XFJJT5AW.js").then(({ createRoutingMemory }) => {
46904
46904
  routingMemoryCache ??= createRoutingMemory();
46905
46905
  return routingMemoryCache;
46906
46906
  }).catch((error) => {
@@ -47057,7 +47057,7 @@ function createVoteStage({ config, startStage }) {
47057
47057
  const strategy = config.votingStrategy ?? "higher_order";
47058
47058
  await postProgress(config, "Vote", `Running consensus with ${strategy} strategy...`);
47059
47059
  try {
47060
- const { executeVoting } = await import("./consensus-vote-YW6LAIH7.js");
47060
+ const { executeVoting } = await import("./consensus-vote-ZB72SHTV.js");
47061
47061
  const votingResult = await executeVoting(
47062
47062
  {
47063
47063
  proposal: buildVoteProposal(plan, research),
@@ -47816,7 +47816,7 @@ ${text}` : "";
47816
47816
  }
47817
47817
  async function getWeatherContext() {
47818
47818
  try {
47819
- const { generateWeatherReport: generateWeatherReport2 } = await import("./weather-report-IGEXNIWL.js");
47819
+ const { generateWeatherReport: generateWeatherReport2 } = await import("./weather-report-GPYYWU5C.js");
47820
47820
  const report = generateWeatherReport2({ includeAdaptive: true });
47821
47821
  const mappings = "recommendedMappings" in report ? report.recommendedMappings : [];
47822
47822
  if (!Array.isArray(mappings) || mappings.length === 0) return "";
@@ -47834,7 +47834,7 @@ ${lines}
47834
47834
  }
47835
47835
  async function getMemoryContext(task) {
47836
47836
  try {
47837
- const { createSessionMemory: createSessionMemory2 } = await import("./session-memory-M5MEGJJZ.js");
47837
+ const { createSessionMemory: createSessionMemory2 } = await import("./session-memory-SRH5ZJRX.js");
47838
47838
  const { getLearningDir } = await import("./learning-persistence-7BEPQEGN.js");
47839
47839
  const memory = createSessionMemory2(getLearningDir(), { maxLearningsInContext: 10 });
47840
47840
  const learnings = memory.searchLearnings(task.slice(0, 200));
@@ -48401,7 +48401,7 @@ async function searchCodebaseForTask(task) {
48401
48401
  }
48402
48402
  async function queryResearchRegistry(task) {
48403
48403
  try {
48404
- const { synthesizeResearch: synthesizeResearch2 } = await import("./research-helpers-synthesize-G3WV7AHW.js");
48404
+ const { synthesizeResearch: synthesizeResearch2 } = await import("./research-helpers-synthesize-L22FP57N.js");
48405
48405
  const topic = task.split(/[.!?\n]/).filter((s) => s.trim().length > 10)[0]?.trim();
48406
48406
  if (topic === void 0) return null;
48407
48407
  const result = await synthesizeResearch2(topic.slice(0, 50));
@@ -48472,7 +48472,7 @@ function createScanStageWrapper() {
48472
48472
  try {
48473
48473
  const slug = ctx.task.match(/([a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+)/)?.[1];
48474
48474
  if (slug !== void 0) {
48475
- const { generateSecurityPlan: generateSecurityPlan2 } = await import("./repo-security-plan-HYJ7HTOS.js");
48475
+ const { generateSecurityPlan: generateSecurityPlan2 } = await import("./repo-security-plan-Y6PXBY44.js");
48476
48476
  const plan = await generateSecurityPlan2({ repo: slug, maxScanners: 10 });
48477
48477
  const recs = plan.recommendations.slice(0, 5).map((r) => `${r.priority}: ${r.displayName} (${r.category})`).join("; ");
48478
48478
  return output(PIPELINE_STATE_KEYS.FINDINGS, recs, getTimeProvider().now() - start, true);
@@ -52216,7 +52216,7 @@ var GitHubTaskTracker = class {
52216
52216
  cachedProvider = null;
52217
52217
  async getProvider() {
52218
52218
  if (this.cachedProvider !== null) return this.cachedProvider;
52219
- const { createScmProvider } = await import("./factory-ZOM2QJPC.js");
52219
+ const { createScmProvider } = await import("./factory-WAI626V6.js");
52220
52220
  const result = await createScmProvider({ repo: this.config.repo ?? "" });
52221
52221
  if (!result.ok) throw new Error(`SCM provider error: ${result.error.message}`);
52222
52222
  this.cachedProvider = result.value;
@@ -53183,7 +53183,7 @@ async function probeSource(source, includeModelIds) {
53183
53183
  }
53184
53184
  }
53185
53185
  async function defaultSources(includeOpenRouter) {
53186
- const { createAllAdapters: createAllAdapters2 } = await import("./factory-O4U4BJFT.js");
53186
+ const { createAllAdapters: createAllAdapters2 } = await import("./factory-KAMTEOXC.js");
53187
53187
  const adapters = createAllAdapters2();
53188
53188
  return buildDefaultModelSources(adapters, { includeOpenRouter });
53189
53189
  }
@@ -56508,4 +56508,4 @@ export {
56508
56508
  startPipelineEventBridge,
56509
56509
  shutdownPipelineEventBridge
56510
56510
  };
56511
- //# sourceMappingURL=chunk-IKLDY3HI.js.map
56511
+ //# sourceMappingURL=chunk-TECOLJ4Z.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getErrorMessage
3
- } from "./chunk-YGOTLETF.js";
3
+ } from "./chunk-OMIR6ISN.js";
4
4
 
5
5
  // src/cli/setup-config.ts
6
6
  import { copyFileSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
@@ -77,4 +77,4 @@ function ensureBackup(outputPath) {
77
77
  export {
78
78
  runConfigInitSync
79
79
  };
80
- //# sourceMappingURL=chunk-HSMW4KIV.js.map
80
+ //# sourceMappingURL=chunk-UWAJUJKU.js.map
@@ -8,7 +8,7 @@ import {
8
8
  MCP_TIMEOUTS,
9
9
  TEST_TIMEOUTS,
10
10
  WORKFLOW_TIMEOUTS
11
- } from "./chunk-YGOTLETF.js";
11
+ } from "./chunk-OMIR6ISN.js";
12
12
  import {
13
13
  createGetToolRateLimit
14
14
  } from "./chunk-RNDHNRSX.js";
@@ -223,4 +223,4 @@ export {
223
223
  CUSTOM_API_DEFAULT_MODEL,
224
224
  DEFAULTS
225
225
  };
226
- //# sourceMappingURL=chunk-Y2ARXXPF.js.map
226
+ //# sourceMappingURL=chunk-UXUOJOXL.js.map
@@ -1,6 +1,6 @@
1
1
  // src/version.ts
2
2
  import semver from "semver";
3
- var VERSION = true ? "8.85.2" : "dev";
3
+ var VERSION = true ? "8.85.3" : "dev";
4
4
  var NODE_ENGINE_RANGE = ">=22.5.0";
5
5
  function isNodeVersionSupported(version) {
6
6
  return semver.satisfies(version, NODE_ENGINE_RANGE);
@@ -11,4 +11,4 @@ export {
11
11
  NODE_ENGINE_RANGE,
12
12
  isNodeVersionSupported
13
13
  };
14
- //# sourceMappingURL=chunk-ILGHDIYO.js.map
14
+ //# sourceMappingURL=chunk-VEMKYAW4.js.map