nexus-agents 2.166.3 → 2.167.1

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/{child-mcp-config-AUA4TFBG.js → child-mcp-config-X4YLQKGK.js} +2 -2
  2. package/dist/{chunk-P54BDACX.js → chunk-2NU774CB.js} +2 -2
  3. package/dist/{chunk-JBH4CU46.js → chunk-2S7T66IQ.js} +34 -34
  4. package/dist/{chunk-UO6C5J5D.js → chunk-3T6KLPGT.js} +5 -5
  5. package/dist/{chunk-FZV4YAYT.js → chunk-6KCZA3IO.js} +190 -4
  6. package/dist/chunk-6KCZA3IO.js.map +1 -0
  7. package/dist/{chunk-ORRKK563.js → chunk-7K5LSUEU.js} +3 -3
  8. package/dist/{chunk-GS3UPAUE.js → chunk-7USEQLMS.js} +2 -2
  9. package/dist/{chunk-K2IX6BEK.js → chunk-7YD3TRDX.js} +4 -4
  10. package/dist/{chunk-IF46G2LM.js → chunk-BB7KSLNA.js} +2 -2
  11. package/dist/{chunk-NEQJSYJH.js → chunk-COIZLMGV.js} +3 -3
  12. package/dist/{chunk-Z66EEQ4A.js → chunk-CURHM4TH.js} +3 -3
  13. package/dist/{chunk-PXTZ6RPP.js → chunk-EUQNHT7O.js} +26 -7
  14. package/dist/chunk-EUQNHT7O.js.map +1 -0
  15. package/dist/{chunk-BZFF3YWU.js → chunk-GGYQTV2Y.js} +4 -4
  16. package/dist/{chunk-HNAFWKJG.js → chunk-GRWHPG72.js} +7 -7
  17. package/dist/{chunk-AWPSFL5C.js → chunk-GVNY4ZB6.js} +2 -2
  18. package/dist/{chunk-YKTVN2TF.js → chunk-IFSIKGHI.js} +2 -2
  19. package/dist/{chunk-LRBEUBZ3.js → chunk-JKUX73VD.js} +3 -3
  20. package/dist/{chunk-I7OZP6FS.js → chunk-KM3YEIEN.js} +4 -4
  21. package/dist/{chunk-THI3VWHO.js → chunk-O6VL6LA4.js} +2 -2
  22. package/dist/{chunk-6LXTT6AK.js → chunk-PC4Y4VPX.js} +2 -2
  23. package/dist/{chunk-DMFMJFRY.js → chunk-QPSYBHK6.js} +2 -2
  24. package/dist/{chunk-BFDVV3Q3.js → chunk-QV52AXTF.js} +2 -2
  25. package/dist/chunk-QZUG667L.js +56 -0
  26. package/dist/chunk-QZUG667L.js.map +1 -0
  27. package/dist/{chunk-JYVPM37A.js → chunk-RKIPSMCN.js} +5 -5
  28. package/dist/{chunk-ZI4PO2A3.js → chunk-S6HCREYY.js} +12 -62
  29. package/dist/chunk-S6HCREYY.js.map +1 -0
  30. package/dist/{chunk-F2YZ3U6O.js → chunk-SRNAXDOT.js} +2 -2
  31. package/dist/{chunk-V5RPW2ZX.js → chunk-STMW5BSR.js} +3 -3
  32. package/dist/{chunk-FQNG6ZIW.js → chunk-TGAVZ2ZL.js} +8 -8
  33. package/dist/{chunk-UWRDWX6L.js → chunk-UNIDAVVR.js} +2 -2
  34. package/dist/{chunk-76Q6GTPU.js → chunk-VNVGGM73.js} +2 -2
  35. package/dist/{chunk-FKHQWC2L.js → chunk-XUMLVCFL.js} +2 -2
  36. package/dist/{chunk-WL4SGKAW.js → chunk-ZAPCPHGZ.js} +2 -2
  37. package/dist/{chunk-PRSGZQNB.js → chunk-ZIC6ZZFU.js} +3 -3
  38. package/dist/{chunk-WOY6TQCH.js → chunk-ZSUN7BHE.js} +439 -12
  39. package/dist/chunk-ZSUN7BHE.js.map +1 -0
  40. package/dist/{chunk-3LVB5OE2.js → chunk-ZTTUXPBQ.js} +2 -2
  41. package/dist/{cli-circuit-breaker-FSUDU7BV.js → cli-circuit-breaker-2AAHSCHR.js} +4 -4
  42. package/dist/cli.js +59 -45
  43. package/dist/cli.js.map +1 -1
  44. package/dist/{composite-router-HC4YLG5W.js → composite-router-WOVGICBS.js} +2 -2
  45. package/dist/{consensus-vote-KWPS6WNH.js → consensus-vote-322S65GQ.js} +16 -15
  46. package/dist/{context-retriever-YCKTCDGM.js → context-retriever-YMJY6YBJ.js} +9 -8
  47. package/dist/{doctor-deep-4UARVVSD.js → doctor-deep-DALT3OXC.js} +3 -3
  48. package/dist/{expert-bridge-EAR6XZJA.js → expert-bridge-WNV3ST2T.js} +4 -4
  49. package/dist/factory-33HQYVCK.js +23 -0
  50. package/dist/{factory-7SVW7XMV.js → factory-TLSTFONW.js} +5 -5
  51. package/dist/{improvement-review-AHSY5ZXD.js → improvement-review-2W6LKP74.js} +5 -5
  52. package/dist/index.js +43 -317
  53. package/dist/index.js.map +1 -1
  54. package/dist/{init-opencode-5BKE7UEB.js → init-opencode-XVTVJ6FN.js} +5 -6
  55. package/dist/{init-opencode-5BKE7UEB.js.map → init-opencode-XVTVJ6FN.js.map} +1 -1
  56. package/dist/{issue-triage-TNV4R33I.js → issue-triage-CVMVZ3IV.js} +6 -6
  57. package/dist/{pr-reviewer-helpers-ZC2I5ZYD.js → pr-reviewer-helpers-SAMOVLNJ.js} +4 -4
  58. package/dist/{registry-command-O2GLHG3G.js → registry-command-5D2DJT53.js} +2 -2
  59. package/dist/{repo-security-plan-CFRLHIMY.js → repo-security-plan-F7V5SHAQ.js} +3 -3
  60. package/dist/{research-helpers-synthesize-ONWBGXHO.js → research-helpers-synthesize-F4PV4B4B.js} +4 -4
  61. package/dist/{routing-memory-XHZKEPUH.js → routing-memory-G6YBK4WI.js} +2 -2
  62. package/dist/{session-memory-5QVKDE4U.js → session-memory-DAJHLPOY.js} +3 -3
  63. package/dist/{setup-command-G7OB4QQG.js → setup-command-NUNIRAFN.js} +14 -11
  64. package/dist/{setup-config-MMBOL5CW.js → setup-config-HKUWFV5N.js} +3 -3
  65. package/dist/{setup-custom-api-RQ3BUMJC.js → setup-custom-api-XRUPWEPF.js} +3 -3
  66. package/dist/{tool-memory-VK4IZLPN.js → tool-memory-XJ5VRMNQ.js} +5 -5
  67. package/dist/{unified-registry-ZOTGM4EY.js → unified-registry-ETKPTZBU.js} +10 -9
  68. package/dist/{weather-report-MPD66LKP.js → weather-report-TWBLIHPZ.js} +2 -2
  69. package/package.json +1 -1
  70. package/dist/chunk-FZV4YAYT.js.map +0 -1
  71. package/dist/chunk-OI6H3DL6.js +0 -197
  72. package/dist/chunk-OI6H3DL6.js.map +0 -1
  73. package/dist/chunk-PXTZ6RPP.js.map +0 -1
  74. package/dist/chunk-WOY6TQCH.js.map +0 -1
  75. package/dist/chunk-ZI4PO2A3.js.map +0 -1
  76. package/dist/factory-JYAUOFEN.js +0 -22
  77. /package/dist/{child-mcp-config-AUA4TFBG.js.map → child-mcp-config-X4YLQKGK.js.map} +0 -0
  78. /package/dist/{chunk-P54BDACX.js.map → chunk-2NU774CB.js.map} +0 -0
  79. /package/dist/{chunk-JBH4CU46.js.map → chunk-2S7T66IQ.js.map} +0 -0
  80. /package/dist/{chunk-UO6C5J5D.js.map → chunk-3T6KLPGT.js.map} +0 -0
  81. /package/dist/{chunk-ORRKK563.js.map → chunk-7K5LSUEU.js.map} +0 -0
  82. /package/dist/{chunk-GS3UPAUE.js.map → chunk-7USEQLMS.js.map} +0 -0
  83. /package/dist/{chunk-K2IX6BEK.js.map → chunk-7YD3TRDX.js.map} +0 -0
  84. /package/dist/{chunk-IF46G2LM.js.map → chunk-BB7KSLNA.js.map} +0 -0
  85. /package/dist/{chunk-NEQJSYJH.js.map → chunk-COIZLMGV.js.map} +0 -0
  86. /package/dist/{chunk-Z66EEQ4A.js.map → chunk-CURHM4TH.js.map} +0 -0
  87. /package/dist/{chunk-BZFF3YWU.js.map → chunk-GGYQTV2Y.js.map} +0 -0
  88. /package/dist/{chunk-HNAFWKJG.js.map → chunk-GRWHPG72.js.map} +0 -0
  89. /package/dist/{chunk-AWPSFL5C.js.map → chunk-GVNY4ZB6.js.map} +0 -0
  90. /package/dist/{chunk-YKTVN2TF.js.map → chunk-IFSIKGHI.js.map} +0 -0
  91. /package/dist/{chunk-LRBEUBZ3.js.map → chunk-JKUX73VD.js.map} +0 -0
  92. /package/dist/{chunk-I7OZP6FS.js.map → chunk-KM3YEIEN.js.map} +0 -0
  93. /package/dist/{chunk-THI3VWHO.js.map → chunk-O6VL6LA4.js.map} +0 -0
  94. /package/dist/{chunk-6LXTT6AK.js.map → chunk-PC4Y4VPX.js.map} +0 -0
  95. /package/dist/{chunk-DMFMJFRY.js.map → chunk-QPSYBHK6.js.map} +0 -0
  96. /package/dist/{chunk-BFDVV3Q3.js.map → chunk-QV52AXTF.js.map} +0 -0
  97. /package/dist/{chunk-JYVPM37A.js.map → chunk-RKIPSMCN.js.map} +0 -0
  98. /package/dist/{chunk-F2YZ3U6O.js.map → chunk-SRNAXDOT.js.map} +0 -0
  99. /package/dist/{chunk-V5RPW2ZX.js.map → chunk-STMW5BSR.js.map} +0 -0
  100. /package/dist/{chunk-FQNG6ZIW.js.map → chunk-TGAVZ2ZL.js.map} +0 -0
  101. /package/dist/{chunk-UWRDWX6L.js.map → chunk-UNIDAVVR.js.map} +0 -0
  102. /package/dist/{chunk-76Q6GTPU.js.map → chunk-VNVGGM73.js.map} +0 -0
  103. /package/dist/{chunk-FKHQWC2L.js.map → chunk-XUMLVCFL.js.map} +0 -0
  104. /package/dist/{chunk-WL4SGKAW.js.map → chunk-ZAPCPHGZ.js.map} +0 -0
  105. /package/dist/{chunk-PRSGZQNB.js.map → chunk-ZIC6ZZFU.js.map} +0 -0
  106. /package/dist/{chunk-3LVB5OE2.js.map → chunk-ZTTUXPBQ.js.map} +0 -0
  107. /package/dist/{cli-circuit-breaker-FSUDU7BV.js.map → cli-circuit-breaker-2AAHSCHR.js.map} +0 -0
  108. /package/dist/{composite-router-HC4YLG5W.js.map → composite-router-WOVGICBS.js.map} +0 -0
  109. /package/dist/{consensus-vote-KWPS6WNH.js.map → consensus-vote-322S65GQ.js.map} +0 -0
  110. /package/dist/{context-retriever-YCKTCDGM.js.map → context-retriever-YMJY6YBJ.js.map} +0 -0
  111. /package/dist/{doctor-deep-4UARVVSD.js.map → doctor-deep-DALT3OXC.js.map} +0 -0
  112. /package/dist/{expert-bridge-EAR6XZJA.js.map → expert-bridge-WNV3ST2T.js.map} +0 -0
  113. /package/dist/{factory-7SVW7XMV.js.map → factory-33HQYVCK.js.map} +0 -0
  114. /package/dist/{factory-JYAUOFEN.js.map → factory-TLSTFONW.js.map} +0 -0
  115. /package/dist/{improvement-review-AHSY5ZXD.js.map → improvement-review-2W6LKP74.js.map} +0 -0
  116. /package/dist/{issue-triage-TNV4R33I.js.map → issue-triage-CVMVZ3IV.js.map} +0 -0
  117. /package/dist/{pr-reviewer-helpers-ZC2I5ZYD.js.map → pr-reviewer-helpers-SAMOVLNJ.js.map} +0 -0
  118. /package/dist/{registry-command-O2GLHG3G.js.map → registry-command-5D2DJT53.js.map} +0 -0
  119. /package/dist/{repo-security-plan-CFRLHIMY.js.map → repo-security-plan-F7V5SHAQ.js.map} +0 -0
  120. /package/dist/{research-helpers-synthesize-ONWBGXHO.js.map → research-helpers-synthesize-F4PV4B4B.js.map} +0 -0
  121. /package/dist/{routing-memory-XHZKEPUH.js.map → routing-memory-G6YBK4WI.js.map} +0 -0
  122. /package/dist/{session-memory-5QVKDE4U.js.map → session-memory-DAJHLPOY.js.map} +0 -0
  123. /package/dist/{setup-command-G7OB4QQG.js.map → setup-command-NUNIRAFN.js.map} +0 -0
  124. /package/dist/{setup-config-MMBOL5CW.js.map → setup-config-HKUWFV5N.js.map} +0 -0
  125. /package/dist/{setup-custom-api-RQ3BUMJC.js.map → setup-custom-api-XRUPWEPF.js.map} +0 -0
  126. /package/dist/{tool-memory-VK4IZLPN.js.map → tool-memory-XJ5VRMNQ.js.map} +0 -0
  127. /package/dist/{unified-registry-ZOTGM4EY.js.map → unified-registry-ETKPTZBU.js.map} +0 -0
  128. /package/dist/{weather-report-MPD66LKP.js.map → weather-report-TWBLIHPZ.js.map} +0 -0
@@ -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 */\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 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';\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): 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 `${tags.join(' ')}: ${v.message ?? ''}${body}`;\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\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.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)}`;\n return classified;\n }\n return super.transformError(error);\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 = mapResponseUsage(response);\n\n return {\n content,\n 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 return {\n content: [{ type: 'text', text: '' }],\n usage: mapResponseUsage(response),\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 {\n return {\n inputTokens: response.usage?.prompt_tokens ?? 0,\n outputTokens: response.usage?.completion_tokens ?? 0,\n totalTokens: response.usage?.total_tokens ?? 0,\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 chunks.push({\n type: 'message_delta',\n delta: { stop_reason: mapStopReason(choice.finish_reason) },\n usage: {\n inputTokens: 0,\n outputTokens: chunk.usage?.completion_tokens ?? 0,\n totalTokens: chunk.usage?.total_tokens ?? 0,\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: never log the resolved apiKey. Only the baseURL is\n * logged on success.\n *\n * @module config/opencode-bridge\n */\n\nimport { readFileSync } from 'node:fs';\n\nimport { createLogger } from '../core/index.js';\n\nconst logger = 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(path: string): OpencodeGatewayConfig | null {\n const raw = readFileOrNull(path);\n if (raw === null) return null;\n\n const parsed = parseJsonOrNull(raw, path);\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', { baseURL, path });\n return { baseURL, apiKey };\n}\n\nfunction readFileOrNull(path: string): 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\nfunction parseJsonOrNull(raw: string, path: string): unknown {\n try {\n return JSON.parse(raw);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.warn('opencode.json is not valid JSON; ignoring', { path, error: msg });\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';\n\nimport type {\n Result,\n CompletionRequest,\n CompletionResponse,\n ModelError,\n ModelMetadata,\n IModelAdapter,\n} from '../core/index.js';\nimport { ok, err, ConfigError, getErrorMessage, getTimeProvider } from '../core/index.js';\nimport { OpenAIAdapter } from './openai-adapter.js';\nimport { recordUsageEvent, computeCostDetail } from '../learning/usage-log.js';\nimport { readOpencodeGateway } from '../config/opencode-bridge.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\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\nfunction readGatewayFromEnv(): OpenAICompatConfig | null {\n const envUrl = process.env['NEXUS_OPENAI_COMPAT_URL']?.trim();\n const envKey = process.env['NEXUS_OPENAI_COMPAT_KEY']?.trim();\n if (envUrl === undefined || envUrl === '') return null;\n if (envKey === undefined || envKey === '') return null;\n return { baseUrl: envUrl, apiKey: envKey };\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 { baseUrl: fromFile.baseURL, apiKey: fromFile.apiKey };\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): Promise<Result<readonly DiscoveredModel[], ConfigError>> {\n try {\n const client = new OpenAI({ baseURL: config.baseUrl, apiKey: config.apiKey });\n const list = await client.models.list();\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(models);\n } catch (e: unknown) {\n return err(\n new ConfigError(\n `Failed to discover models from ${config.baseUrl}: ${getErrorMessage(e)}. ` +\n `Verify NEXUS_OPENAI_COMPAT_URL and NEXUS_OPENAI_COMPAT_KEY, 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. Recording is best-effort (telemetry never fails\n * 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): IModelAdapter {\n const inner = new OpenAIAdapter({ modelId, apiKey: config.apiKey, baseUrl: config.baseUrl });\n return withUsageRecording(inner);\n}\n\n/**\n * Wrap any IModelAdapter so that successful + failed `complete()` calls\n * append a UsageEvent to the on-disk usage log. Stream calls aren't yet\n * 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.\n */\nfunction withUsageRecording(inner: IModelAdapter): IModelAdapter {\n const wrapped: IModelAdapter = {\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 // Full-registry pricing with provenance (#4165): `priced: false`\n // marks the $0 as UNPRICED (unmeasured), not a real $0.\n const cost = computeCostDetail(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 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: result.error.code,\n });\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/**\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(): Promise<Result<\n readonly IModelAdapter[],\n ConfigError\n> | null> {\n const config = readOpenAICompatEnv();\n if (config === null) return null;\n const discovered = await discoverModels(config);\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","OpenAI","OpenAI"]}
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  loadPapersRegistry
3
- } from "./chunk-6LXTT6AK.js";
3
+ } from "./chunk-PC4Y4VPX.js";
4
4
  import {
5
5
  getErrorMessage
6
- } from "./chunk-Z66EEQ4A.js";
6
+ } from "./chunk-CURHM4TH.js";
7
7
 
8
8
  // src/cli/research-helpers-synthesize.ts
9
9
  import { z } from "zod";
@@ -876,4 +876,4 @@ export {
876
876
  AttributedInsightSchema,
877
877
  synthesizeResearch
878
878
  };
879
- //# sourceMappingURL=chunk-ORRKK563.js.map
879
+ //# sourceMappingURL=chunk-7K5LSUEU.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getRandomProvider,
3
3
  getTimeProvider
4
- } from "./chunk-Z66EEQ4A.js";
4
+ } from "./chunk-CURHM4TH.js";
5
5
 
6
6
  // src/utils/id-utils.ts
7
7
  import { randomUUID } from "crypto";
@@ -24,4 +24,4 @@ export {
24
24
  generateHyphenId,
25
25
  generateUUID
26
26
  };
27
- //# sourceMappingURL=chunk-GS3UPAUE.js.map
27
+ //# sourceMappingURL=chunk-7USEQLMS.js.map
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  GitHubProvider,
3
3
  ScmError
4
- } from "./chunk-IF46G2LM.js";
4
+ } from "./chunk-BB7KSLNA.js";
5
5
  import {
6
6
  resolveToken
7
- } from "./chunk-UWRDWX6L.js";
7
+ } from "./chunk-UNIDAVVR.js";
8
8
  import {
9
9
  err,
10
10
  ok
11
- } from "./chunk-Z66EEQ4A.js";
11
+ } from "./chunk-CURHM4TH.js";
12
12
 
13
13
  // src/scm/factory.ts
14
14
  async function createScmProvider(config) {
@@ -41,4 +41,4 @@ export {
41
41
  createScmProvider,
42
42
  createGitHubProvider
43
43
  };
44
- //# sourceMappingURL=chunk-K2IX6BEK.js.map
44
+ //# sourceMappingURL=chunk-7YD3TRDX.js.map
@@ -4,7 +4,7 @@ import {
4
4
  err,
5
5
  getErrorMessage,
6
6
  ok
7
- } from "./chunk-Z66EEQ4A.js";
7
+ } from "./chunk-CURHM4TH.js";
8
8
 
9
9
  // src/scm/types.ts
10
10
  var ScmError = class extends Error {
@@ -263,4 +263,4 @@ export {
263
263
  ScmError,
264
264
  GitHubProvider
265
265
  };
266
- //# sourceMappingURL=chunk-IF46G2LM.js.map
266
+ //# sourceMappingURL=chunk-BB7KSLNA.js.map
@@ -2,14 +2,14 @@ import {
2
2
  CircuitBreakerRegistry,
3
3
  CircuitError,
4
4
  mapCliErrorToCategory
5
- } from "./chunk-AWPSFL5C.js";
5
+ } from "./chunk-GVNY4ZB6.js";
6
6
  import {
7
7
  createLogger,
8
8
  err,
9
9
  getFallbackChainForCategory,
10
10
  getTimeProvider,
11
11
  ok
12
- } from "./chunk-Z66EEQ4A.js";
12
+ } from "./chunk-CURHM4TH.js";
13
13
 
14
14
  // src/cli-adapters/cli-circuit-breaker.ts
15
15
  var CATEGORY_TO_FALLBACK = {
@@ -152,4 +152,4 @@ export {
152
152
  CliCircuitBreakerIntegration,
153
153
  createCliCircuitBreakerIntegration
154
154
  };
155
- //# sourceMappingURL=chunk-NEQJSYJH.js.map
155
+ //# sourceMappingURL=chunk-COIZLMGV.js.map
@@ -2619,7 +2619,7 @@ function setDefaultRegistry(registry) {
2619
2619
  }
2620
2620
  async function reloadDefaultRegistry() {
2621
2621
  globalRegistry = buildDefaultRegistry();
2622
- const { resetGlobalRegistry } = await import("./unified-registry-ZOTGM4EY.js");
2622
+ const { resetGlobalRegistry } = await import("./unified-registry-ETKPTZBU.js");
2623
2623
  resetGlobalRegistry();
2624
2624
  return globalRegistry;
2625
2625
  }
@@ -14357,7 +14357,7 @@ var CompositeRouter = class _CompositeRouter {
14357
14357
  */
14358
14358
  async consultUnifiedContext(task) {
14359
14359
  try {
14360
- const { getContextForTask, inferTaskCategory } = await import("./context-retriever-YCKTCDGM.js");
14360
+ const { getContextForTask, inferTaskCategory } = await import("./context-retriever-YMJY6YBJ.js");
14361
14361
  const ctx = await getContextForTask({
14362
14362
  task: task.content,
14363
14363
  category: inferTaskCategory(task.content),
@@ -15946,4 +15946,4 @@ export {
15946
15946
  AgentCapability,
15947
15947
  OrchestratorError
15948
15948
  };
15949
- //# sourceMappingURL=chunk-Z66EEQ4A.js.map
15949
+ //# sourceMappingURL=chunk-CURHM4TH.js.map
@@ -1,3 +1,6 @@
1
+ import {
2
+ readOpenAICompatEnv
3
+ } from "./chunk-6KCZA3IO.js";
1
4
  import {
2
5
  resolveInsideRoot
3
6
  } from "./chunk-NUBSJGQZ.js";
@@ -7,10 +10,10 @@ import {
7
10
  import {
8
11
  createAllAdapters,
9
12
  probeCli
10
- } from "./chunk-ZI4PO2A3.js";
13
+ } from "./chunk-S6HCREYY.js";
11
14
  import {
12
15
  DEFAULTS
13
- } from "./chunk-P54BDACX.js";
16
+ } from "./chunk-2NU774CB.js";
14
17
  import {
15
18
  CliNameSchema,
16
19
  DEFAULT_CAPABILITIES,
@@ -27,7 +30,7 @@ import {
27
30
  ok,
28
31
  symbols,
29
32
  writeLine
30
- } from "./chunk-Z66EEQ4A.js";
33
+ } from "./chunk-CURHM4TH.js";
31
34
  import {
32
35
  getLearningDir,
33
36
  getOutcomesFile,
@@ -43,7 +46,7 @@ import {
43
46
  } from "./chunk-DHVMSIT5.js";
44
47
 
45
48
  // src/version.ts
46
- var VERSION = true ? "2.166.3" : "dev";
49
+ var VERSION = true ? "2.167.1" : "dev";
47
50
 
48
51
  // src/config/schemas-core.ts
49
52
  import { z } from "zod";
@@ -1659,6 +1662,16 @@ function printDoctorSummary(result) {
1659
1662
  writeLine(summary);
1660
1663
  writeLine("");
1661
1664
  }
1665
+ function printVoterTransportCheck(check) {
1666
+ if (check.configured) {
1667
+ writeLine(`${formatStatus(true)} Voter transport: In-process gateway`);
1668
+ return;
1669
+ }
1670
+ writeLine(`${formatStatus(true)} Voter transport: ${colors.dim}CLI subprocess${colors.reset}`);
1671
+ writeLine(
1672
+ ` ${colors.dim}Set NEXUS_OPENAI_COMPAT_URL and NEXUS_OPENAI_COMPAT_KEY for faster in-process voting${colors.reset}`
1673
+ );
1674
+ }
1662
1675
  function printDoctorResults(result) {
1663
1676
  writeLine("");
1664
1677
  writeLine(`${colors.bold}Nexus Agents Doctor${colors.reset}`);
@@ -1683,6 +1696,7 @@ function printDoctorResults(result) {
1683
1696
  writeLine(
1684
1697
  `${formatStatus(result.mcpClientReady)} MCP Client mode: ${result.mcpClientReady ? "Ready (Codex mcp-server)" : "Not ready (Codex not installed)"}`
1685
1698
  );
1699
+ printVoterTransportCheck(result.voterTransport);
1686
1700
  writeLine("");
1687
1701
  writeLine(`${colors.cyan}Checking capabilities...${colors.reset}`);
1688
1702
  writeLine("");
@@ -2104,6 +2118,9 @@ function checkSandbox() {
2104
2118
  dataDirInsideRepo
2105
2119
  };
2106
2120
  }
2121
+ function checkVoterTransport() {
2122
+ return { configured: readOpenAICompatEnv() !== null };
2123
+ }
2107
2124
  async function runDoctor() {
2108
2125
  const clis = await Promise.all([
2109
2126
  checkCli("claude"),
@@ -2123,6 +2140,7 @@ async function runDoctor() {
2123
2140
  const dataDirectory = checkDataDirectory();
2124
2141
  const sandbox = checkSandbox();
2125
2142
  const harnessAlignment = checkHarnessAlignment();
2143
+ const voterTransport = checkVoterTransport();
2126
2144
  const hasAuthMethod = apiKeys.some((k) => k.configured) || clis.some((c) => c.installed && c.authenticated);
2127
2145
  const allHealthy = nodeVersion.supported && hasAuthMethod && mcpServerReady && clis.every((c) => c.installed && c.authenticated && c.versionStatus !== "unsupported");
2128
2146
  return {
@@ -2138,6 +2156,7 @@ async function runDoctor() {
2138
2156
  dataDirectory,
2139
2157
  sandbox,
2140
2158
  harnessAlignment,
2159
+ voterTransport,
2141
2160
  allHealthy,
2142
2161
  timestamp: new Date(getTimeProvider().now())
2143
2162
  };
@@ -2159,7 +2178,7 @@ async function runDoctorFix(result) {
2159
2178
  writeLine2("\u2500".repeat(40));
2160
2179
  let fixCount = 0;
2161
2180
  if (!result.dataDirectory.rootExists || result.dataDirectory.subdirectories.some((d) => !d.exists || !d.writable)) {
2162
- const { runSetup } = await import("./setup-command-G7OB4QQG.js");
2181
+ const { runSetup } = await import("./setup-command-NUNIRAFN.js");
2163
2182
  const setupResult = runSetup({
2164
2183
  skipMcp: true,
2165
2184
  skipRules: true,
@@ -2173,7 +2192,7 @@ async function runDoctorFix(result) {
2173
2192
  }
2174
2193
  }
2175
2194
  if (!result.configFile.found) {
2176
- const { runConfigInitSync } = await import("./setup-config-MMBOL5CW.js");
2195
+ const { runConfigInitSync } = await import("./setup-config-HKUWFV5N.js");
2177
2196
  const configResult = runConfigInitSync(process.cwd(), false, false);
2178
2197
  if (configResult.success && configResult.created) {
2179
2198
  writeLine2(`\u2713 Generated config: ${configResult.path}`);
@@ -2272,4 +2291,4 @@ export {
2272
2291
  startStdioServer,
2273
2292
  closeServer
2274
2293
  };
2275
- //# sourceMappingURL=chunk-PXTZ6RPP.js.map
2294
+ //# sourceMappingURL=chunk-EUQNHT7O.js.map