open-multi-agent-kit 0.90.0 → 0.90.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 (168) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +20 -31
  3. package/dist/cli/args.d.ts +0 -2
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +1 -7
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/core/agent-session.d.ts +2 -0
  8. package/dist/core/agent-session.d.ts.map +1 -1
  9. package/dist/core/agent-session.js +41 -5
  10. package/dist/core/agent-session.js.map +1 -1
  11. package/dist/core/bang-skill-invocation.d.ts +26 -0
  12. package/dist/core/bang-skill-invocation.d.ts.map +1 -0
  13. package/dist/core/bang-skill-invocation.js +59 -0
  14. package/dist/core/bang-skill-invocation.js.map +1 -0
  15. package/dist/core/compactor.d.ts.map +1 -1
  16. package/dist/core/compactor.js +0 -3
  17. package/dist/core/compactor.js.map +1 -1
  18. package/dist/core/context-budget-governor-v2.d.ts +2 -1
  19. package/dist/core/context-budget-governor-v2.d.ts.map +1 -1
  20. package/dist/core/context-budget-governor-v2.js +1 -0
  21. package/dist/core/context-budget-governor-v2.js.map +1 -1
  22. package/dist/core/context-budget-headroom-types.d.ts +8 -0
  23. package/dist/core/context-budget-headroom-types.d.ts.map +1 -1
  24. package/dist/core/context-budget-headroom-types.js.map +1 -1
  25. package/dist/core/context-budget-headroom.d.ts +1 -1
  26. package/dist/core/context-budget-headroom.d.ts.map +1 -1
  27. package/dist/core/context-budget-headroom.js +17 -4
  28. package/dist/core/context-budget-headroom.js.map +1 -1
  29. package/dist/core/context-budget-system-prompt.d.ts +2 -1
  30. package/dist/core/context-budget-system-prompt.d.ts.map +1 -1
  31. package/dist/core/context-budget-system-prompt.js +6 -1
  32. package/dist/core/context-budget-system-prompt.js.map +1 -1
  33. package/dist/core/context-budget-v2-cache-hash.d.ts +3 -0
  34. package/dist/core/context-budget-v2-cache-hash.d.ts.map +1 -0
  35. package/dist/core/context-budget-v2-cache-hash.js +16 -0
  36. package/dist/core/context-budget-v2-cache-hash.js.map +1 -0
  37. package/dist/core/context-budget-v2-cache-keys.d.ts +58 -0
  38. package/dist/core/context-budget-v2-cache-keys.d.ts.map +1 -0
  39. package/dist/core/context-budget-v2-cache-keys.js +128 -0
  40. package/dist/core/context-budget-v2-cache-keys.js.map +1 -0
  41. package/dist/core/context-budget-v2-cache-provider.d.ts +23 -0
  42. package/dist/core/context-budget-v2-cache-provider.d.ts.map +1 -0
  43. package/dist/core/context-budget-v2-cache-provider.js +29 -0
  44. package/dist/core/context-budget-v2-cache-provider.js.map +1 -0
  45. package/dist/core/context-budget-v2-cache-telemetry.d.ts +36 -0
  46. package/dist/core/context-budget-v2-cache-telemetry.d.ts.map +1 -0
  47. package/dist/core/context-budget-v2-cache-telemetry.js +64 -0
  48. package/dist/core/context-budget-v2-cache-telemetry.js.map +1 -0
  49. package/dist/core/context-budget-v2-cache-validation.d.ts +36 -0
  50. package/dist/core/context-budget-v2-cache-validation.d.ts.map +1 -0
  51. package/dist/core/context-budget-v2-cache-validation.js +98 -0
  52. package/dist/core/context-budget-v2-cache-validation.js.map +1 -0
  53. package/dist/core/context-budget-v2-cache.d.ts +36 -0
  54. package/dist/core/context-budget-v2-cache.d.ts.map +1 -0
  55. package/dist/core/context-budget-v2-cache.js +50 -0
  56. package/dist/core/context-budget-v2-cache.js.map +1 -0
  57. package/dist/core/context-budget-v2-plan-cache-keys.d.ts +16 -0
  58. package/dist/core/context-budget-v2-plan-cache-keys.d.ts.map +1 -0
  59. package/dist/core/context-budget-v2-plan-cache-keys.js +49 -0
  60. package/dist/core/context-budget-v2-plan-cache-keys.js.map +1 -0
  61. package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
  62. package/dist/core/context-budget-v2-planner.js +55 -2
  63. package/dist/core/context-budget-v2-planner.js.map +1 -1
  64. package/dist/core/context-budget-v2-representation-cache.d.ts +27 -0
  65. package/dist/core/context-budget-v2-representation-cache.d.ts.map +1 -0
  66. package/dist/core/context-budget-v2-representation-cache.js +173 -0
  67. package/dist/core/context-budget-v2-representation-cache.js.map +1 -0
  68. package/dist/core/context-budget-v2-selection.d.ts +2 -0
  69. package/dist/core/context-budget-v2-selection.d.ts.map +1 -1
  70. package/dist/core/context-budget-v2-selection.js +12 -2
  71. package/dist/core/context-budget-v2-selection.js.map +1 -1
  72. package/dist/core/context-budget-v2-types.d.ts +107 -1
  73. package/dist/core/context-budget-v2-types.d.ts.map +1 -1
  74. package/dist/core/context-budget-v2-types.js.map +1 -1
  75. package/dist/core/headroom.d.ts.map +1 -1
  76. package/dist/core/headroom.js +0 -4
  77. package/dist/core/headroom.js.map +1 -1
  78. package/dist/core/hook-inventory.d.ts.map +1 -1
  79. package/dist/core/hook-inventory.js +6 -0
  80. package/dist/core/hook-inventory.js.map +1 -1
  81. package/dist/core/mcp-computer-use-presets.d.ts +64 -0
  82. package/dist/core/mcp-computer-use-presets.d.ts.map +1 -0
  83. package/dist/core/mcp-computer-use-presets.js +158 -0
  84. package/dist/core/mcp-computer-use-presets.js.map +1 -0
  85. package/dist/core/mcp-public-presets.d.ts +578 -0
  86. package/dist/core/mcp-public-presets.d.ts.map +1 -0
  87. package/dist/core/mcp-public-presets.js +647 -0
  88. package/dist/core/mcp-public-presets.js.map +1 -0
  89. package/dist/core/model-registry.d.ts.map +1 -1
  90. package/dist/core/model-registry.js +1 -0
  91. package/dist/core/model-registry.js.map +1 -1
  92. package/dist/core/pi-package-intake-candidates.d.ts +14 -1
  93. package/dist/core/pi-package-intake-candidates.d.ts.map +1 -1
  94. package/dist/core/pi-package-intake-candidates.js +182 -0
  95. package/dist/core/pi-package-intake-candidates.js.map +1 -1
  96. package/dist/core/pi-package-intake.d.ts +8 -1
  97. package/dist/core/pi-package-intake.d.ts.map +1 -1
  98. package/dist/core/pi-package-intake.js +14 -4
  99. package/dist/core/pi-package-intake.js.map +1 -1
  100. package/dist/core/reverse-skill.d.ts +2 -0
  101. package/dist/core/reverse-skill.d.ts.map +1 -0
  102. package/dist/core/reverse-skill.js +7 -0
  103. package/dist/core/reverse-skill.js.map +1 -0
  104. package/dist/core/settings-manager.d.ts +3 -3
  105. package/dist/core/settings-manager.d.ts.map +1 -1
  106. package/dist/core/settings-manager.js.map +1 -1
  107. package/dist/core/system-prompt.d.ts +2 -0
  108. package/dist/core/system-prompt.d.ts.map +1 -1
  109. package/dist/core/system-prompt.js +58 -5
  110. package/dist/core/system-prompt.js.map +1 -1
  111. package/dist/index.d.ts +1 -0
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.js +1 -0
  114. package/dist/index.js.map +1 -1
  115. package/dist/migrations.d.ts +19 -0
  116. package/dist/migrations.d.ts.map +1 -1
  117. package/dist/migrations.js +39 -15
  118. package/dist/migrations.js.map +1 -1
  119. package/dist/modes/interactive/components/control-panel-box.d.ts +3 -3
  120. package/dist/modes/interactive/components/control-panel-box.d.ts.map +1 -1
  121. package/dist/modes/interactive/components/control-panel-box.js +10 -10
  122. package/dist/modes/interactive/components/control-panel-box.js.map +1 -1
  123. package/dist/modes/interactive/components/control-panel-gradient-motion.d.ts.map +1 -1
  124. package/dist/modes/interactive/components/control-panel-gradient-motion.js +2 -1
  125. package/dist/modes/interactive/components/control-panel-gradient-motion.js.map +1 -1
  126. package/dist/modes/interactive/components/control-panel-layout.d.ts +15 -1
  127. package/dist/modes/interactive/components/control-panel-layout.d.ts.map +1 -1
  128. package/dist/modes/interactive/components/control-panel-layout.js +212 -68
  129. package/dist/modes/interactive/components/control-panel-layout.js.map +1 -1
  130. package/dist/modes/interactive/components/control-panel-runtime-status.d.ts.map +1 -1
  131. package/dist/modes/interactive/components/control-panel-runtime-status.js +10 -0
  132. package/dist/modes/interactive/components/control-panel-runtime-status.js.map +1 -1
  133. package/dist/modes/interactive/components/control-panel-sparkles.d.ts +27 -0
  134. package/dist/modes/interactive/components/control-panel-sparkles.d.ts.map +1 -0
  135. package/dist/modes/interactive/components/control-panel-sparkles.js +42 -0
  136. package/dist/modes/interactive/components/control-panel-sparkles.js.map +1 -0
  137. package/dist/modes/interactive/components/control-panel.d.ts +8 -0
  138. package/dist/modes/interactive/components/control-panel.d.ts.map +1 -1
  139. package/dist/modes/interactive/components/control-panel.js +40 -8
  140. package/dist/modes/interactive/components/control-panel.js.map +1 -1
  141. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  142. package/dist/modes/interactive/components/settings-selector.js +2 -1
  143. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  144. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  145. package/dist/modes/interactive/components/thinking-selector.js +2 -1
  146. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  147. package/dist/modes/interactive/interactive-mode.d.ts +2 -0
  148. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  149. package/dist/modes/interactive/interactive-mode.js +63 -14
  150. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  151. package/dist/modes/interactive/theme/theme.d.ts +1 -1
  152. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  153. package/dist/modes/interactive/theme/theme.js +2 -0
  154. package/dist/modes/interactive/theme/theme.js.map +1 -1
  155. package/docs/skills.md +8 -4
  156. package/docs/usage.md +4 -3
  157. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  158. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  159. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  160. package/examples/extensions/gondolin/package-lock.json +2 -2
  161. package/examples/extensions/gondolin/package.json +1 -1
  162. package/examples/extensions/preset.ts +2 -2
  163. package/examples/extensions/sandbox/package-lock.json +2 -2
  164. package/examples/extensions/sandbox/package.json +1 -1
  165. package/examples/extensions/with-deps/package-lock.json +2 -2
  166. package/examples/extensions/with-deps/package.json +1 -1
  167. package/npm-shrinkwrap.json +27 -34
  168. package/package.json +5 -5
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-public-presets.js","sourceRoot":"","sources":["../../src/core/mcp-public-presets.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\n\nexport type PublicMcpPresetKey =\n\t| \"context7\"\n\t| \"exa\"\n\t| \"githubReadOnly\"\n\t| \"astGrep\"\n\t| \"repomixCodeCompact\"\n\t| \"omkLlmlinguaCompress\"\n\t| \"doclingUnderstand\"\n\t| \"markitdownLite\"\n\t| \"firecrawlWebUnderstand\"\n\t| \"deepwikiRepoUnderstandCandidate\"\n\t| \"insaneSearchCandidate\"\n\t| \"playwrightSandboxed\"\n\t| \"microsoftLearn\"\n\t| \"officialReferenceSafePack\";\n\nexport type PublicMcpRisk = \"R1\" | \"R2\" | \"R3\";\nexport type PublicMcpLicense = \"Apache-2.0\" | \"Apache-2.0/MIT/CC-BY-4.0\" | \"MIT\" | \"Unspecified\";\nexport type PublicMcpImplementation = \"candidate-wrapper\" | \"omk-owned\" | \"upstream-mcp\";\nexport type PublicMcpReadiness = \"candidate\" | \"stable\";\nexport type PublicMcpUriScheme = \"data\" | \"file\" | \"http\" | \"https\";\nexport type PublicMcpTransport =\n\t| {\n\t\t\treadonly type: \"http\";\n\t\t\treadonly url: string;\n\t }\n\t| {\n\t\t\treadonly type: \"embedded-python-or-sidecar\";\n\t\t\treadonly package: string;\n\t }\n\t| {\n\t\t\treadonly type: \"local-package\";\n\t\t\treadonly package: string;\n\t\t\treadonly args?: readonly string[];\n\t }\n\t| {\n\t\t\treadonly type: \"stdio\";\n\t\t\treadonly command: string;\n\t\t\treadonly args: readonly string[];\n\t };\n\nexport interface PublicMcpAuthPolicy {\n\treadonly kind: \"bearer\" | \"header\" | \"none\";\n\treadonly header?: string;\n\treadonly secretRef?: string;\n}\n\nexport interface PublicMcpSecretPolicy {\n\treadonly required?: readonly string[];\n\treadonly optional?: readonly string[];\n\treadonly headers?: Readonly<Record<string, string>>;\n}\n\nexport interface PublicMcpToolPolicy {\n\treadonly allow: readonly string[];\n\treadonly conditionalAllow?: readonly string[];\n\treadonly deny?: readonly string[];\n\treadonly denyByDefault: boolean;\n\treadonly denyMutations?: boolean;\n\treadonly disabledByDefault?: readonly string[];\n\treadonly gated?: readonly string[];\n\treadonly requirePostconditions?: readonly string[];\n}\n\nexport interface PublicMcpRuntimePolicy {\n\treadonly absolutePathMustBeUnderWorkspace?: boolean;\n\treadonly allowedUriSchemes?: readonly PublicMcpUriScheme[];\n\treadonly authenticationBoundaryRequired?: boolean;\n\treadonly blockMetadataIp?: boolean;\n\treadonly blockHttpByDefault?: boolean;\n\treadonly blockNetworkUrlsByDefault?: boolean;\n\treadonly blockPrivateNetwork?: boolean;\n\treadonly blockRemoteRepositoryByDefault?: boolean;\n\treadonly cacheDocuments?: boolean;\n\treadonly cacheable?: boolean;\n\treadonly cacheMaterializedOutputs?: boolean;\n\treadonly defaultCompressionRatio?: number;\n\treadonly descriptorHashPinned?: boolean;\n\treadonly distillBeforeMainContext?: boolean;\n\treadonly disableAutoInstall?: boolean;\n\treadonly domainAllowlistOptional?: boolean;\n\treadonly denyYoutubeByDefault?: boolean;\n\treadonly denyZipByDefault?: boolean;\n\treadonly evidenceLedger?: boolean;\n\treadonly filesystemRoot?: string;\n\treadonly fileRoot?: string;\n\treadonly forkContext?: boolean;\n\treadonly ledger?: boolean;\n\treadonly localFilesUnderWorkspaceOnly?: boolean;\n\treadonly localOnly?: boolean;\n\treadonly maxBrowserActions?: number;\n\treadonly maxCompressionRatio?: number;\n\treadonly maxInputBytes?: number;\n\treadonly maxInputTokens?: number;\n\treadonly maxOutputTokens?: number;\n\treadonly maxResults?: number;\n\treadonly maxUrlsPerTask?: number;\n\treadonly markdownFullPageRequiresExplicitNeed?: boolean;\n\treadonly mutationsRequireHumanGate?: boolean;\n\treadonly mutationsRequirePostconditions?: boolean;\n\treadonly noFilesystemReadExceptModelCache?: boolean;\n\treadonly noNetwork?: boolean;\n\treadonly noSecrets?: boolean;\n\treadonly noShell?: boolean;\n\treadonly outputGuard?: boolean;\n\treadonly preferGrepBeforeFullRead?: boolean;\n\treadonly preferIncrementalRead?: boolean;\n\treadonly preferJsonExtraction?: boolean;\n\treadonly privateRepoDeniedByDefault?: boolean;\n\treadonly promptTaint?: \"external-docs\" | \"external-web\" | \"browser\";\n\treadonly publicContentOnly?: boolean;\n\treadonly publicReposOnly?: boolean;\n\treadonly readOnly?: boolean;\n\treadonly recordEvidence?: boolean;\n\treadonly rejectIfCoverageBelow?: {\n\t\treadonly hard: number;\n\t\treadonly high: number;\n\t\treadonly low: number;\n\t\treadonly medium: number;\n\t};\n\treadonly requireCoverageVerification?: boolean;\n\treadonly requireOriginAllowlistForScrape?: boolean;\n\treadonly requiresExplicitPostconditions?: boolean;\n\treadonly requiresOriginAllowlist?: boolean;\n\treadonly requiresSandbox?: boolean;\n\treadonly secretBrokerOnly?: boolean;\n\treadonly secretScanRequired?: boolean;\n\treadonly ssrfGuard?: boolean;\n\treadonly workspaceReadOnly?: boolean;\n}\n\nexport interface PublicMcpPreset {\n\treadonly defaultEnabled?: boolean;\n\treadonly id: string;\n\treadonly key: PublicMcpPresetKey;\n\treadonly license: PublicMcpLicense;\n\treadonly notes: readonly string[];\n\treadonly policy: PublicMcpRuntimePolicy;\n\treadonly implementation?: PublicMcpImplementation;\n\treadonly readiness?: PublicMcpReadiness;\n\treadonly risk: PublicMcpRisk;\n\treadonly sourceUrls: readonly string[];\n\treadonly tools: PublicMcpToolPolicy;\n\treadonly auth?: PublicMcpAuthPolicy;\n\treadonly secrets?: PublicMcpSecretPolicy;\n\treadonly servers?: readonly string[];\n\treadonly transport?: PublicMcpTransport;\n}\n\nexport interface PublicMcpObservedTool {\n\treadonly name: string;\n\treadonly descriptorHash: string;\n\treadonly description: string;\n}\n\nexport interface PublicMcpObservedServer {\n\treadonly serverIdentity: string;\n\treadonly tools: readonly PublicMcpObservedTool[];\n}\n\nexport interface PublicMcpApprovedServer {\n\treadonly serverIdentity: string;\n\treadonly tools: Readonly<Record<string, string>>;\n}\n\nexport type PublicMcpAdmissionStatus = \"allow\" | \"quarantine\";\n\nexport interface PublicMcpAdmissionDecision {\n\treadonly status: PublicMcpAdmissionStatus;\n\treadonly reasons: readonly string[];\n}\n\nexport type PublicMcpHashable =\n\t| null\n\t| boolean\n\t| number\n\t| string\n\t| readonly PublicMcpHashable[]\n\t| {\n\t\t\treadonly [key: string]: PublicMcpHashable;\n\t };\n\nexport const PUBLIC_MCP_PRESETS = {\n\tcontext7: {\n\t\tid: \"context7\",\n\t\tkey: \"context7\",\n\t\tlicense: \"MIT\",\n\t\tnotes: [\"Documentation retrieval preset; optional API key only raises rate limits.\"],\n\t\trisk: \"R1\",\n\t\tsourceUrls: [\"https://github.com/upstash/context7\"],\n\t\ttransport: {\n\t\t\ttype: \"http\",\n\t\t\turl: \"https://mcp.context7.com/mcp\",\n\t\t},\n\t\tsecrets: {\n\t\t\toptional: [\"CONTEXT7_API_KEY\"],\n\t\t\theaders: {\n\t\t\t\tCONTEXT7_API_KEY: \"secret-ref:context7\",\n\t\t\t},\n\t\t},\n\t\ttools: {\n\t\t\tallow: [\"resolve-library-id\", \"query-docs\"],\n\t\t\tdenyByDefault: true,\n\t\t},\n\t\tpolicy: {\n\t\t\tcacheable: true,\n\t\t\tmaxOutputTokens: 6000,\n\t\t\toutputGuard: true,\n\t\t\tpromptTaint: \"external-docs\",\n\t\t\treadOnly: true,\n\t\t},\n\t},\n\texa: {\n\t\tid: \"exa\",\n\t\tkey: \"exa\",\n\t\tlicense: \"MIT\",\n\t\tnotes: [\"Run searches in forked context and return distilled output to the main task.\"],\n\t\trisk: \"R1\",\n\t\tsourceUrls: [\"https://github.com/exa-labs/exa-mcp-server\"],\n\t\ttransport: {\n\t\t\ttype: \"http\",\n\t\t\turl: \"https://mcp.exa.ai/mcp\",\n\t\t},\n\t\tauth: {\n\t\t\tkind: \"header\",\n\t\t\theader: \"Authorization\",\n\t\t\tsecretRef: \"secret-ref:exa_api_key\",\n\t\t},\n\t\tsecrets: {\n\t\t\toptional: [\"EXA_API_KEY\"],\n\t\t},\n\t\ttools: {\n\t\t\tallow: [\"web_search_exa\", \"web_fetch_exa\"],\n\t\t\tconditionalAllow: [\"web_search_advanced_exa\"],\n\t\t\tdenyByDefault: true,\n\t\t},\n\t\tpolicy: {\n\t\t\tblockPrivateNetwork: true,\n\t\t\tdistillBeforeMainContext: true,\n\t\t\tdomainAllowlistOptional: true,\n\t\t\tforkContext: true,\n\t\t\tmaxOutputTokens: 5000,\n\t\t\tmaxResults: 10,\n\t\t\tssrfGuard: true,\n\t\t},\n\t},\n\tgithubReadOnly: {\n\t\tid: \"github-readonly\",\n\t\tkey: \"githubReadOnly\",\n\t\tlicense: \"MIT\",\n\t\tnotes: [\"Read-only GitHub MCP profile; mutation tools remain gated for future explicit workflows.\"],\n\t\trisk: \"R2\",\n\t\tsourceUrls: [\"https://github.com/github/github-mcp-server\"],\n\t\ttransport: {\n\t\t\ttype: \"http\",\n\t\t\turl: \"https://api.githubcopilot.com/mcp/\",\n\t\t},\n\t\tauth: {\n\t\t\tkind: \"bearer\",\n\t\t\tsecretRef: \"secret-ref:github_pat\",\n\t\t},\n\t\tsecrets: {\n\t\t\trequired: [\"GITHUB_PERSONAL_ACCESS_TOKEN\"],\n\t\t},\n\t\ttools: {\n\t\t\tallow: [\n\t\t\t\t\"actions_list\",\n\t\t\t\t\"get_file_contents\",\n\t\t\t\t\"issue_read\",\n\t\t\t\t\"list_issues\",\n\t\t\t\t\"list_pull_requests\",\n\t\t\t\t\"pull_request_read\",\n\t\t\t\t\"search_code\",\n\t\t\t\t\"search_issues\",\n\t\t\t\t\"search_pull_requests\",\n\t\t\t\t\"search_repositories\",\n\t\t\t],\n\t\t\tdenyByDefault: true,\n\t\t\trequirePostconditions: [\n\t\t\t\t\"add_comment_to_pending_review\",\n\t\t\t\t\"create_branch\",\n\t\t\t\t\"create_or_update_file\",\n\t\t\t\t\"create_pull_request\",\n\t\t\t\t\"delete_file\",\n\t\t\t\t\"issue_write\",\n\t\t\t\t\"merge_pull_request\",\n\t\t\t\t\"pull_request_review_write\",\n\t\t\t\t\"push_files\",\n\t\t\t\t\"update_pull_request\",\n\t\t\t\t\"update_pull_request_branch\",\n\t\t\t],\n\t\t},\n\t\tpolicy: {\n\t\t\tledger: true,\n\t\t\tmaxOutputTokens: 8000,\n\t\t\tmutationsRequireHumanGate: true,\n\t\t\treadOnly: true,\n\t\t\tsecretBrokerOnly: true,\n\t\t},\n\t},\n\tastGrep: {\n\t\tid: \"ast-grep\",\n\t\tkey: \"astGrep\",\n\t\tlicense: \"MIT\",\n\t\tnotes: [\"Experimental upstream; pin descriptor and wrap execution before broad enablement.\"],\n\t\trisk: \"R1\",\n\t\tsourceUrls: [\"https://github.com/ast-grep/ast-grep-mcp\"],\n\t\ttransport: {\n\t\t\ttype: \"stdio\",\n\t\t\tcommand: \"uvx\",\n\t\t\targs: [\"--from\", \"git+https://github.com/ast-grep/ast-grep-mcp\", \"ast-grep-server\"],\n\t\t},\n\t\ttools: {\n\t\t\tallow: [\"dump_syntax_tree\", \"find_code\", \"find_code_by_rule\", \"test_match_code_rule\"],\n\t\t\tdenyByDefault: true,\n\t\t},\n\t\tpolicy: {\n\t\t\tdescriptorHashPinned: true,\n\t\t\tmaxResults: 200,\n\t\t\tnoShell: true,\n\t\t\tworkspaceReadOnly: true,\n\t\t},\n\t},\n\trepomixCodeCompact: {\n\t\tdefaultEnabled: true,\n\t\tid: \"repomix-code-compact\",\n\t\timplementation: \"upstream-mcp\",\n\t\tkey: \"repomixCodeCompact\",\n\t\tlicense: \"MIT\",\n\t\tnotes: [\n\t\t\t\"Codebase packing and compression preset; remote repository packing is disabled until a task explicitly opts in.\",\n\t\t\t\"Use grep/read against packed output before full-context attachment.\",\n\t\t],\n\t\treadiness: \"stable\",\n\t\trisk: \"R1\",\n\t\tsourceUrls: [\"https://github.com/yamadashy/repomix\"],\n\t\ttransport: {\n\t\t\ttype: \"stdio\",\n\t\t\tcommand: \"npx\",\n\t\t\targs: [\"-y\", \"repomix\", \"--mcp\"],\n\t\t},\n\t\ttools: {\n\t\t\tallow: [\n\t\t\t\t\"attach_packed_output\",\n\t\t\t\t\"file_system_read_directory\",\n\t\t\t\t\"grep_repomix_output\",\n\t\t\t\t\"pack_codebase\",\n\t\t\t\t\"read_repomix_output\",\n\t\t\t],\n\t\t\tdisabledByDefault: [\"pack_remote_repository\"],\n\t\t\tgated: [\"file_system_read_file\"],\n\t\t\tdenyByDefault: true,\n\t\t},\n\t\tpolicy: {\n\t\t\tabsolutePathMustBeUnderWorkspace: true,\n\t\t\tblockRemoteRepositoryByDefault: true,\n\t\t\tdescriptorHashPinned: true,\n\t\t\tevidenceLedger: true,\n\t\t\tmaxOutputTokens: 120_000,\n\t\t\toutputGuard: true,\n\t\t\tpreferGrepBeforeFullRead: true,\n\t\t\tpreferIncrementalRead: true,\n\t\t\tsecretScanRequired: true,\n\t\t\tworkspaceReadOnly: true,\n\t\t},\n\t},\n\tomkLlmlinguaCompress: {\n\t\tdefaultEnabled: true,\n\t\tid: \"omk-llmlingua-compress\",\n\t\timplementation: \"omk-owned\",\n\t\tkey: \"omkLlmlinguaCompress\",\n\t\tlicense: \"MIT\",\n\t\tnotes: [\n\t\t\t\"First-party wrapper target for LLMLingua-style prompt and context compression.\",\n\t\t\t\"System prompts, latest user turns, and tool schemas must stay outside lossy compression.\",\n\t\t],\n\t\treadiness: \"stable\",\n\t\trisk: \"R1\",\n\t\tsourceUrls: [\"https://github.com/microsoft/LLMLingua\", \"https://arxiv.org/abs/2403.12968\"],\n\t\ttransport: {\n\t\t\ttype: \"embedded-python-or-sidecar\",\n\t\t\tpackage: \"llmlingua\",\n\t\t},\n\t\ttools: {\n\t\t\tallow: [\n\t\t\t\t\"compress_context_items\",\n\t\t\t\t\"compress_messages\",\n\t\t\t\t\"compress_prompt\",\n\t\t\t\t\"compress_representation_candidate\",\n\t\t\t\t\"verify_compression_coverage\",\n\t\t\t],\n\t\t\tdenyByDefault: true,\n\t\t},\n\t\tpolicy: {\n\t\t\tcacheMaterializedOutputs: true,\n\t\t\tdefaultCompressionRatio: 3,\n\t\t\tevidenceLedger: true,\n\t\t\tlocalOnly: true,\n\t\t\tmaxCompressionRatio: 8,\n\t\t\tmaxInputTokens: 200_000,\n\t\t\tnoFilesystemReadExceptModelCache: true,\n\t\t\tnoNetwork: true,\n\t\t\toutputGuard: true,\n\t\t\trejectIfCoverageBelow: {\n\t\t\t\thard: 0.95,\n\t\t\t\thigh: 0.8,\n\t\t\t\tmedium: 0.55,\n\t\t\t\tlow: 0.3,\n\t\t\t},\n\t\t\trequireCoverageVerification: true,\n\t\t},\n\t},\n\tdoclingUnderstand: {\n\t\tdefaultEnabled: true,\n\t\tid: \"docling-understand\",\n\t\timplementation: \"upstream-mcp\",\n\t\tkey: \"doclingUnderstand\",\n\t\tlicense: \"MIT\",\n\t\tnotes: [\n\t\t\t\"Structured document understanding preset for PDFs, Office files, tables, OCR, and layout-sensitive conversions.\",\n\t\t\t\"Parser attack surface requires sandboxing and workspace-only local file access.\",\n\t\t],\n\t\treadiness: \"stable\",\n\t\trisk: \"R2\",\n\t\tsourceUrls: [\"https://github.com/docling-project/docling\", \"https://github.com/docling-project/docling-mcp\"],\n\t\ttransport: {\n\t\t\ttype: \"stdio\",\n\t\t\tcommand: \"uvx\",\n\t\t\targs: [\"--from=docling-mcp\", \"docling-mcp-server\", \"--transport\", \"stdio\"],\n\t\t},\n\t\ttools: {\n\t\t\tallow: [\"convert_document\", \"export_docling_document_to_json\", \"export_docling_document_to_markdown\"],\n\t\t\tgated: [\"create_new_docling_document\", \"save_docling_document\"],\n\t\t\tdenyByDefault: true,\n\t\t},\n\t\tpolicy: {\n\t\t\tblockNetworkUrlsByDefault: true,\n\t\t\tcacheDocuments: true,\n\t\t\tevidenceLedger: true,\n\t\t\tlocalFilesUnderWorkspaceOnly: true,\n\t\t\tmaxInputBytes: 80_000_000,\n\t\t\tmaxOutputTokens: 80_000,\n\t\t\toutputGuard: true,\n\t\t\trequiresSandbox: true,\n\t\t},\n\t},\n\tmarkitdownLite: {\n\t\tdefaultEnabled: true,\n\t\tid: \"markitdown-lite\",\n\t\timplementation: \"upstream-mcp\",\n\t\tkey: \"markitdownLite\",\n\t\tlicense: \"MIT\",\n\t\tnotes: [\n\t\t\t\"Lightweight Markdown conversion fallback for local files and data URIs.\",\n\t\t\t\"HTTP, ZIP, and YouTube inputs stay blocked until a task explicitly needs them.\",\n\t\t],\n\t\treadiness: \"stable\",\n\t\trisk: \"R2\",\n\t\tsourceUrls: [\n\t\t\t\"https://github.com/microsoft/markitdown\",\n\t\t\t\"https://github.com/microsoft/markitdown/tree/main/packages/markitdown-mcp\",\n\t\t],\n\t\ttransport: {\n\t\t\ttype: \"stdio\",\n\t\t\tcommand: \"markitdown-mcp\",\n\t\t\targs: [],\n\t\t},\n\t\ttools: {\n\t\t\tallow: [\"convert_to_markdown\"],\n\t\t\tdenyByDefault: true,\n\t\t},\n\t\tpolicy: {\n\t\t\tallowedUriSchemes: [\"file\", \"data\"],\n\t\t\tblockHttpByDefault: true,\n\t\t\tdenyYoutubeByDefault: true,\n\t\t\tdenyZipByDefault: true,\n\t\t\tevidenceLedger: true,\n\t\t\tfileRoot: \"workspaceRoot\",\n\t\t\tmaxInputBytes: 30_000_000,\n\t\t\tmaxOutputTokens: 50_000,\n\t\t\toutputGuard: true,\n\t\t\trequiresSandbox: true,\n\t\t},\n\t},\n\tfirecrawlWebUnderstand: {\n\t\tdefaultEnabled: false,\n\t\tid: \"firecrawl-web-understand\",\n\t\timplementation: \"upstream-mcp\",\n\t\tkey: \"firecrawlWebUnderstand\",\n\t\tlicense: \"MIT\",\n\t\tnotes: [\n\t\t\t\"Opt-in live web understanding preset; search and scrape are the only default-admissible tools.\",\n\t\t\t\"Prefer JSON extraction over full-page Markdown to protect the context budget.\",\n\t\t],\n\t\treadiness: \"stable\",\n\t\trisk: \"R2\",\n\t\tsourceUrls: [\"https://github.com/firecrawl/firecrawl-mcp-server\"],\n\t\ttransport: {\n\t\t\ttype: \"http\",\n\t\t\turl: \"https://mcp.firecrawl.dev/v2/mcp\",\n\t\t},\n\t\tauth: {\n\t\t\tkind: \"bearer\",\n\t\t\tsecretRef: \"secret-ref:firecrawl_api_key\",\n\t\t},\n\t\tsecrets: {\n\t\t\toptional: [\"FIRECRAWL_API_KEY\", \"FIRECRAWL_OAUTH_TOKEN\"],\n\t\t},\n\t\ttools: {\n\t\t\tallow: [\"firecrawl_scrape\", \"firecrawl_search\"],\n\t\t\tdisabledByDefault: [\"firecrawl_agent\", \"firecrawl_crawl\", \"firecrawl_interact\", \"firecrawl_monitor\"],\n\t\t\tgated: [\"firecrawl_extract\", \"firecrawl_map\", \"firecrawl_research\"],\n\t\t\tdenyByDefault: true,\n\t\t},\n\t\tpolicy: {\n\t\t\tblockMetadataIp: true,\n\t\t\tblockPrivateNetwork: true,\n\t\t\tdistillBeforeMainContext: true,\n\t\t\tevidenceLedger: true,\n\t\t\tforkContext: true,\n\t\t\tmarkdownFullPageRequiresExplicitNeed: true,\n\t\t\tmaxOutputTokens: 40_000,\n\t\t\tmaxUrlsPerTask: 10,\n\t\t\toutputGuard: true,\n\t\t\tpreferJsonExtraction: true,\n\t\t\trequireOriginAllowlistForScrape: true,\n\t\t},\n\t},\n\tdeepwikiRepoUnderstandCandidate: {\n\t\tdefaultEnabled: false,\n\t\tid: \"deepwiki-repo-understand\",\n\t\timplementation: \"candidate-wrapper\",\n\t\tkey: \"deepwikiRepoUnderstandCandidate\",\n\t\tlicense: \"Unspecified\",\n\t\tnotes: [\n\t\t\t\"Candidate only until an official MCP endpoint, tool schema, auth model, and retention boundary are verified.\",\n\t\t\t\"Remote repository indexing is public-repo-only by default.\",\n\t\t],\n\t\treadiness: \"candidate\",\n\t\trisk: \"R2\",\n\t\tsourceUrls: [\"https://deepwiki.com/\"],\n\t\ttools: {\n\t\t\tallow: [],\n\t\t\tdenyByDefault: true,\n\t\t},\n\t\tpolicy: {\n\t\t\tdescriptorHashPinned: true,\n\t\t\tevidenceLedger: true,\n\t\t\tnoSecrets: true,\n\t\t\toutputGuard: true,\n\t\t\tprivateRepoDeniedByDefault: true,\n\t\t\tpublicReposOnly: true,\n\t\t},\n\t},\n\tinsaneSearchCandidate: {\n\t\tdefaultEnabled: false,\n\t\tid: \"insane-search-public-reader\",\n\t\timplementation: \"candidate-wrapper\",\n\t\tkey: \"insaneSearchCandidate\",\n\t\tlicense: \"MIT\",\n\t\tnotes: [\n\t\t\t\"Candidate only: upstream is a Claude Code plugin, not a verified standalone MCP transport.\",\n\t\t\t\"Any OMK integration must be a sandboxed first-party wrapper around public-content reads, with auto-install disabled.\",\n\t\t],\n\t\treadiness: \"candidate\",\n\t\trisk: \"R3\",\n\t\tsourceUrls: [\"https://github.com/fivetaku/insane-search\"],\n\t\ttools: {\n\t\t\tallow: [\"insane_search_public_read\"],\n\t\t\tdisabledByDefault: [\"insane_search_auto_install_dependencies\"],\n\t\t\tgated: [\"insane_search_browser_escalation\"],\n\t\t\tdenyByDefault: true,\n\t\t},\n\t\tpolicy: {\n\t\t\tauthenticationBoundaryRequired: true,\n\t\t\tblockMetadataIp: true,\n\t\t\tblockPrivateNetwork: true,\n\t\t\tdisableAutoInstall: true,\n\t\t\tdistillBeforeMainContext: true,\n\t\t\tevidenceLedger: true,\n\t\t\tforkContext: true,\n\t\t\tmaxBrowserActions: 20,\n\t\t\tmaxOutputTokens: 30_000,\n\t\t\toutputGuard: true,\n\t\t\tpublicContentOnly: true,\n\t\t\trequiresOriginAllowlist: true,\n\t\t\trequiresSandbox: true,\n\t\t},\n\t},\n\tplaywrightSandboxed: {\n\t\tid: \"playwright-sandboxed\",\n\t\tkey: \"playwrightSandboxed\",\n\t\tlicense: \"Apache-2.0\",\n\t\tnotes: [\"Browser automation preset; enable only with sandbox and origin controls.\"],\n\t\trisk: \"R3\",\n\t\tsourceUrls: [\"https://github.com/microsoft/playwright-mcp\"],\n\t\ttransport: {\n\t\t\ttype: \"local-package\",\n\t\t\tpackage: \"@playwright/mcp\",\n\t\t},\n\t\ttools: {\n\t\t\tallow: [\n\t\t\t\t\"browser_close\",\n\t\t\t\t\"browser_click\",\n\t\t\t\t\"browser_navigate\",\n\t\t\t\t\"browser_snapshot\",\n\t\t\t\t\"browser_type\",\n\t\t\t\t\"browser_wait_for\",\n\t\t\t],\n\t\t\tdeny: [\"browser_console_messages\", \"browser_file_upload\", \"browser_pdf_save\", \"browser_press_key\"],\n\t\t\tdenyByDefault: true,\n\t\t},\n\t\tpolicy: {\n\t\t\tblockMetadataIp: true,\n\t\t\tblockPrivateNetwork: true,\n\t\t\tledger: true,\n\t\t\tmaxBrowserActions: 40,\n\t\t\trecordEvidence: true,\n\t\t\trequiresExplicitPostconditions: true,\n\t\t\trequiresOriginAllowlist: true,\n\t\t\trequiresSandbox: true,\n\t\t},\n\t},\n\tmicrosoftLearn: {\n\t\tid: \"microsoft-learn\",\n\t\tkey: \"microsoftLearn\",\n\t\tlicense: \"Unspecified\",\n\t\tnotes: [\"Microsoft official remote documentation endpoint from the Microsoft MCP catalog.\"],\n\t\trisk: \"R1\",\n\t\tsourceUrls: [\"https://github.com/microsoft/mcp\"],\n\t\ttransport: {\n\t\t\ttype: \"http\",\n\t\t\turl: \"https://learn.microsoft.com/api/mcp\",\n\t\t},\n\t\ttools: {\n\t\t\tallow: [\"*\"],\n\t\t\tdenyByDefault: true,\n\t\t\tdenyMutations: true,\n\t\t},\n\t\tpolicy: {\n\t\t\tcacheable: true,\n\t\t\tmaxOutputTokens: 6000,\n\t\t\toutputGuard: true,\n\t\t\tpromptTaint: \"external-docs\",\n\t\t\treadOnly: true,\n\t\t},\n\t},\n\tofficialReferenceSafePack: {\n\t\tid: \"official-reference-safe-pack\",\n\t\tkey: \"officialReferenceSafePack\",\n\t\tlicense: \"Apache-2.0/MIT/CC-BY-4.0\",\n\t\tnotes: [\"Reference implementations only; wrap before production use.\"],\n\t\trisk: \"R1\",\n\t\tsourceUrls: [\"https://github.com/modelcontextprotocol/servers\"],\n\t\tservers: [\"time\", \"memory\", \"sequential-thinking\", \"git-readonly\"],\n\t\ttools: {\n\t\t\tallow: [],\n\t\t\tdenyByDefault: true,\n\t\t},\n\t\tpolicy: {\n\t\t\tblockPrivateNetwork: true,\n\t\t\tdescriptorHashPinned: true,\n\t\t\tfilesystemRoot: \"workspaceRoot\",\n\t\t\tmutationsRequirePostconditions: true,\n\t\t},\n\t},\n} as const satisfies Record<PublicMcpPresetKey, PublicMcpPreset>;\n\nexport const OMK_PUBLIC_CONTEXT_MCP_BUNDLE = {\n\tstableDefaults: [\"repomix-code-compact\", \"docling-understand\", \"markitdown-lite\", \"omk-llmlingua-compress\"],\n\toptInResearchWeb: [\"firecrawl-web-understand\"],\n\tcandidatesNeedVerification: [\"deepwiki-repo-understand\", \"insane-search-public-reader\"],\n\tinternalRouters: [\"mcp-tool-rag-router\"],\n} as const;\n\nexport function listPublicMcpPresets(): PublicMcpPreset[] {\n\treturn Object.values(PUBLIC_MCP_PRESETS).map((preset) => clonePublicMcpPreset(preset));\n}\n\nexport function canonicalMcpPolicyHash(value: PublicMcpHashable): string {\n\treturn createHash(\"sha256\").update(canonicalStringify(value)).digest(\"hex\");\n}\n\nexport function canonicalPublicMcpServerIdentity(preset: PublicMcpPreset): string {\n\treturn canonicalMcpPolicyHash({\n\t\tid: preset.id,\n\t\tservers: preset.servers ?? null,\n\t\ttransport: preset.transport ?? null,\n\t});\n}\n\nexport function admitPublicMcpServer(\n\tpreset: PublicMcpPreset,\n\tobserved: PublicMcpObservedServer,\n\tapproved: PublicMcpApprovedServer | undefined,\n): PublicMcpAdmissionDecision {\n\tif (!approved) {\n\t\treturn {\n\t\t\tstatus: \"quarantine\",\n\t\t\treasons: [\"server_not_approved\"],\n\t\t};\n\t}\n\n\tif (approved.serverIdentity !== observed.serverIdentity) {\n\t\treturn {\n\t\t\tstatus: \"quarantine\",\n\t\t\treasons: [\"server_identity_changed\"],\n\t\t};\n\t}\n\n\tconst reasons: string[] = [];\n\n\tfor (const tool of observed.tools) {\n\t\tconst approvedDescriptorHash = approved.tools[tool.name];\n\n\t\tif (!approvedDescriptorHash) {\n\t\t\treasons.push(`new_tool:${tool.name}`);\n\t\t} else if (approvedDescriptorHash !== tool.descriptorHash) {\n\t\t\treasons.push(`descriptor_changed:${tool.name}`);\n\t\t}\n\n\t\tif (!isToolAllowed(preset.tools, tool.name)) {\n\t\t\treasons.push(`tool_not_allowed:${tool.name}`);\n\t\t}\n\n\t\tif (shouldDenyMutationLikeTool(preset, tool.name)) {\n\t\t\treasons.push(`mutation_tool_denied:${tool.name}`);\n\t\t}\n\n\t\tif (detectMcpDescriptorPromptInjection(tool.description).score > 0.7) {\n\t\t\treasons.push(`descriptor_prompt_injection:${tool.name}`);\n\t\t}\n\t}\n\n\treturn {\n\t\tstatus: reasons.length === 0 ? \"allow\" : \"quarantine\",\n\t\treasons,\n\t};\n}\n\nexport function detectMcpDescriptorPromptInjection(description: string): { readonly score: number } {\n\tconst normalized = description.toLowerCase();\n\tconst suspiciousPatterns = [\n\t\t/ignore\\s+(?:all\\s+)?previous\\s+instructions/,\n\t\t/disregard\\s+(?:all\\s+)?previous\\s+instructions/,\n\t\t/exfiltrat/,\n\t\t/reveal\\s+(?:the\\s+)?(?:system\\s+)?prompt/,\n\t\t/send\\s+(?:me\\s+)?(?:all\\s+)?secrets/,\n\t];\n\tconst hits = suspiciousPatterns.filter((pattern) => pattern.test(normalized)).length;\n\n\treturn {\n\t\tscore: hits === 0 ? 0 : Math.min(1, 0.6 + hits * 0.25),\n\t};\n}\n\nfunction clonePublicMcpPreset(preset: PublicMcpPreset): PublicMcpPreset {\n\treturn {\n\t\t...preset,\n\t\tauth: preset.auth ? { ...preset.auth } : undefined,\n\t\tdefaultEnabled: preset.defaultEnabled,\n\t\timplementation: preset.implementation,\n\t\tnotes: [...preset.notes],\n\t\tpolicy: cloneRuntimePolicy(preset.policy),\n\t\treadiness: preset.readiness,\n\t\tsecrets: preset.secrets\n\t\t\t? {\n\t\t\t\t\theaders: preset.secrets.headers ? { ...preset.secrets.headers } : undefined,\n\t\t\t\t\toptional: preset.secrets.optional ? [...preset.secrets.optional] : undefined,\n\t\t\t\t\trequired: preset.secrets.required ? [...preset.secrets.required] : undefined,\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tservers: preset.servers ? [...preset.servers] : undefined,\n\t\tsourceUrls: [...preset.sourceUrls],\n\t\ttools: {\n\t\t\tallow: [...preset.tools.allow],\n\t\t\tconditionalAllow: preset.tools.conditionalAllow ? [...preset.tools.conditionalAllow] : undefined,\n\t\t\tdeny: preset.tools.deny ? [...preset.tools.deny] : undefined,\n\t\t\tdenyByDefault: preset.tools.denyByDefault,\n\t\t\tdenyMutations: preset.tools.denyMutations,\n\t\t\tdisabledByDefault: preset.tools.disabledByDefault ? [...preset.tools.disabledByDefault] : undefined,\n\t\t\tgated: preset.tools.gated ? [...preset.tools.gated] : undefined,\n\t\t\trequirePostconditions: preset.tools.requirePostconditions\n\t\t\t\t? [...preset.tools.requirePostconditions]\n\t\t\t\t: undefined,\n\t\t},\n\t\ttransport: preset.transport ? cloneTransport(preset.transport) : undefined,\n\t};\n}\n\nfunction cloneTransport(transport: PublicMcpTransport): PublicMcpTransport {\n\tif (transport.type === \"stdio\") {\n\t\treturn {\n\t\t\t...transport,\n\t\t\targs: [...transport.args],\n\t\t};\n\t}\n\n\tif (transport.type === \"local-package\") {\n\t\treturn {\n\t\t\t...transport,\n\t\t\targs: transport.args ? [...transport.args] : undefined,\n\t\t};\n\t}\n\n\tif (transport.type === \"embedded-python-or-sidecar\") {\n\t\treturn { ...transport };\n\t}\n\n\treturn { ...transport };\n}\n\nfunction cloneRuntimePolicy(policy: PublicMcpRuntimePolicy): PublicMcpRuntimePolicy {\n\treturn {\n\t\t...policy,\n\t\tallowedUriSchemes: policy.allowedUriSchemes ? [...policy.allowedUriSchemes] : undefined,\n\t\trejectIfCoverageBelow: policy.rejectIfCoverageBelow ? { ...policy.rejectIfCoverageBelow } : undefined,\n\t};\n}\n\nfunction isToolAllowed(policy: PublicMcpToolPolicy, toolName: string): boolean {\n\tif (policy.deny?.includes(toolName)) {\n\t\treturn false;\n\t}\n\n\tif (policy.allow.includes(\"*\")) {\n\t\treturn true;\n\t}\n\n\treturn policy.allow.includes(toolName);\n}\n\nfunction shouldDenyMutationLikeTool(preset: PublicMcpPreset, toolName: string): boolean {\n\tif (!preset.tools.allow.includes(\"*\")) {\n\t\treturn false;\n\t}\n\n\tif (!preset.tools.denyMutations && !preset.policy.readOnly && !preset.policy.mutationsRequirePostconditions) {\n\t\treturn false;\n\t}\n\n\treturn isMutationLikeToolName(toolName);\n}\n\nfunction isMutationLikeToolName(toolName: string): boolean {\n\treturn /(?:^|[_-])(add|approve|archive|cancel|close|create|delete|dismiss|merge|post|push|remove|send|submit|update|upload|write)(?:$|[_-])/.test(\n\t\ttoolName.toLowerCase(),\n\t);\n}\n\nfunction canonicalStringify(value: PublicMcpHashable): string {\n\tif (value === null || typeof value === \"boolean\" || typeof value === \"number\" || typeof value === \"string\") {\n\t\treturn JSON.stringify(value);\n\t}\n\n\tif (Array.isArray(value)) {\n\t\treturn `[${value.map((item) => canonicalStringify(item)).join(\",\")}]`;\n\t}\n\n\tconst record = value as { readonly [key: string]: PublicMcpHashable };\n\tconst keys = Object.keys(record).sort();\n\treturn `{${keys.map((key) => `${JSON.stringify(key)}:${canonicalStringify(record[key])}`).join(\",\")}}`;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"model-registry.d.ts","sourceRoot":"","sources":["../../src/core/model-registry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Model registry - manages built-in and custom models, provides API key resolution.\n */\n\nimport { existsSync, readFileSync } from \"fs\";\nimport {\n\ttype AnthropicMessagesCompat,\n\ttype Api,\n\ttype AssistantMessageEventStream,\n\ttype Context,\n\tgetModels,\n\tgetProviders,\n\ttype KnownProvider,\n\ttype Model,\n\ttype OAuthProviderInterface,\n\ttype OpenAICompletionsCompat,\n\ttype OpenAIResponsesCompat,\n\tregisterApiProvider,\n\tresetApiProviders,\n\ttype SimpleStreamOptions,\n} from \"omk-ai\";\nimport { registerOAuthProvider, resetOAuthProviders } from \"omk-ai/oauth\";\nimport { join } from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { Compile } from \"typebox/compile\";\nimport type { TLocalizedValidationError } from \"typebox/error\";\nimport { getAgentDir } from \"../config.ts\";\nimport { warnDeprecation } from \"../utils/deprecation.ts\";\nimport { stripJsonComments } from \"../utils/json.ts\";\nimport { normalizePath } from \"../utils/paths.ts\";\nimport type { AuthStatus, AuthStorage } from \"./auth-storage.ts\";\nimport { BUILT_IN_PROVIDER_DISPLAY_NAMES } from \"./provider-display-names.ts\";\nimport {\n\tclearConfigValueCache,\n\tgetConfigValueEnvVarNames,\n\tisCommandConfigValue,\n\tisConfigValueConfigured,\n\tisLegacyEnvVarNameConfigValue,\n\tresolveConfigValueOrThrow,\n\tresolveConfigValueUncached,\n\tresolveHeadersOrThrow,\n} from \"./resolve-config-value.ts\";\n\n// Schema for OpenRouter routing preferences\nconst PercentileCutoffsSchema = Type.Object({\n\tp50: Type.Optional(Type.Number()),\n\tp75: Type.Optional(Type.Number()),\n\tp90: Type.Optional(Type.Number()),\n\tp99: Type.Optional(Type.Number()),\n});\n\nconst OpenRouterRoutingSchema = Type.Object({\n\tallow_fallbacks: Type.Optional(Type.Boolean()),\n\trequire_parameters: Type.Optional(Type.Boolean()),\n\tdata_collection: Type.Optional(Type.Union([Type.Literal(\"deny\"), Type.Literal(\"allow\")])),\n\tzdr: Type.Optional(Type.Boolean()),\n\tenforce_distillable_text: Type.Optional(Type.Boolean()),\n\torder: Type.Optional(Type.Array(Type.String())),\n\tonly: Type.Optional(Type.Array(Type.String())),\n\tignore: Type.Optional(Type.Array(Type.String())),\n\tquantizations: Type.Optional(Type.Array(Type.String())),\n\tsort: Type.Optional(\n\t\tType.Union([\n\t\t\tType.String(),\n\t\t\tType.Object({\n\t\t\t\tby: Type.Optional(Type.String()),\n\t\t\t\tpartition: Type.Optional(Type.Union([Type.String(), Type.Null()])),\n\t\t\t}),\n\t\t]),\n\t),\n\tmax_price: Type.Optional(\n\t\tType.Object({\n\t\t\tprompt: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t\tcompletion: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t\timage: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t\taudio: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t\trequest: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t}),\n\t),\n\tpreferred_min_throughput: Type.Optional(Type.Union([Type.Number(), PercentileCutoffsSchema])),\n\tpreferred_max_latency: Type.Optional(Type.Union([Type.Number(), PercentileCutoffsSchema])),\n});\n\n// Schema for Vercel AI Gateway routing preferences\nconst VercelGatewayRoutingSchema = Type.Object({\n\tonly: Type.Optional(Type.Array(Type.String())),\n\torder: Type.Optional(Type.Array(Type.String())),\n});\n\n// Schema for thinking level support and provider-specific values\nconst ThinkingLevelMapValueSchema = Type.Union([Type.String(), Type.Null()]);\nconst ThinkingLevelMapSchema = Type.Object({\n\toff: Type.Optional(ThinkingLevelMapValueSchema),\n\tminimal: Type.Optional(ThinkingLevelMapValueSchema),\n\tlow: Type.Optional(ThinkingLevelMapValueSchema),\n\tmedium: Type.Optional(ThinkingLevelMapValueSchema),\n\thigh: Type.Optional(ThinkingLevelMapValueSchema),\n\txhigh: Type.Optional(ThinkingLevelMapValueSchema),\n});\n\nconst OpenAICompletionsCompatSchema = Type.Object({\n\tsupportsStore: Type.Optional(Type.Boolean()),\n\tsupportsDeveloperRole: Type.Optional(Type.Boolean()),\n\tsupportsReasoningEffort: Type.Optional(Type.Boolean()),\n\tsupportsUsageInStreaming: Type.Optional(Type.Boolean()),\n\tmaxTokensField: Type.Optional(Type.Union([Type.Literal(\"max_completion_tokens\"), Type.Literal(\"max_tokens\")])),\n\trequiresToolResultName: Type.Optional(Type.Boolean()),\n\trequiresAssistantAfterToolResult: Type.Optional(Type.Boolean()),\n\trequiresThinkingAsText: Type.Optional(Type.Boolean()),\n\trequiresReasoningContentOnAssistantMessages: Type.Optional(Type.Boolean()),\n\tthinkingFormat: Type.Optional(\n\t\tType.Union([\n\t\t\tType.Literal(\"openai\"),\n\t\t\tType.Literal(\"openrouter\"),\n\t\t\tType.Literal(\"together\"),\n\t\t\tType.Literal(\"deepseek\"),\n\t\t\tType.Literal(\"zai\"),\n\t\t\tType.Literal(\"qwen\"),\n\t\t\tType.Literal(\"qwen-chat-template\"),\n\t\t]),\n\t),\n\tcacheControlFormat: Type.Optional(Type.Literal(\"anthropic\")),\n\topenRouterRouting: Type.Optional(OpenRouterRoutingSchema),\n\tvercelGatewayRouting: Type.Optional(VercelGatewayRoutingSchema),\n\tsupportsStrictMode: Type.Optional(Type.Boolean()),\n\tsupportsLongCacheRetention: Type.Optional(Type.Boolean()),\n});\n\nconst OpenAIResponsesCompatSchema = Type.Object({\n\tsendSessionIdHeader: Type.Optional(Type.Boolean()),\n\tsupportsLongCacheRetention: Type.Optional(Type.Boolean()),\n});\n\nconst AnthropicMessagesCompatSchema = Type.Object({\n\tsupportsEagerToolInputStreaming: Type.Optional(Type.Boolean()),\n\tsupportsLongCacheRetention: Type.Optional(Type.Boolean()),\n\tsendSessionAffinityHeaders: Type.Optional(Type.Boolean()),\n\tsupportsCacheControlOnTools: Type.Optional(Type.Boolean()),\n\tforceAdaptiveThinking: Type.Optional(Type.Boolean()),\n});\n\nconst ProviderCompatSchema = Type.Union([\n\tOpenAICompletionsCompatSchema,\n\tOpenAIResponsesCompatSchema,\n\tAnthropicMessagesCompatSchema,\n]);\n\n// Schema for custom model definition\n// Most fields are optional with sensible defaults for local models (Ollama, LM Studio, etc.)\nconst ModelDefinitionSchema = Type.Object({\n\tid: Type.String({ minLength: 1 }),\n\tname: Type.Optional(Type.String({ minLength: 1 })),\n\tapi: Type.Optional(Type.String({ minLength: 1 })),\n\tbaseUrl: Type.Optional(Type.String({ minLength: 1 })),\n\treasoning: Type.Optional(Type.Boolean()),\n\tthinkingLevelMap: Type.Optional(ThinkingLevelMapSchema),\n\tinput: Type.Optional(Type.Array(Type.Union([Type.Literal(\"text\"), Type.Literal(\"image\")]))),\n\tcost: Type.Optional(\n\t\tType.Object({\n\t\t\tinput: Type.Number(),\n\t\t\toutput: Type.Number(),\n\t\t\tcacheRead: Type.Number(),\n\t\t\tcacheWrite: Type.Number(),\n\t\t}),\n\t),\n\tcontextWindow: Type.Optional(Type.Number()),\n\tmaxTokens: Type.Optional(Type.Number()),\n\theaders: Type.Optional(Type.Record(Type.String(), Type.String())),\n\tcompat: Type.Optional(ProviderCompatSchema),\n});\n\n// Schema for per-model overrides (all fields optional, merged with built-in model)\nconst ModelOverrideSchema = Type.Object({\n\tname: Type.Optional(Type.String({ minLength: 1 })),\n\treasoning: Type.Optional(Type.Boolean()),\n\tthinkingLevelMap: Type.Optional(ThinkingLevelMapSchema),\n\tinput: Type.Optional(Type.Array(Type.Union([Type.Literal(\"text\"), Type.Literal(\"image\")]))),\n\tcost: Type.Optional(\n\t\tType.Object({\n\t\t\tinput: Type.Optional(Type.Number()),\n\t\t\toutput: Type.Optional(Type.Number()),\n\t\t\tcacheRead: Type.Optional(Type.Number()),\n\t\t\tcacheWrite: Type.Optional(Type.Number()),\n\t\t}),\n\t),\n\tcontextWindow: Type.Optional(Type.Number()),\n\tmaxTokens: Type.Optional(Type.Number()),\n\theaders: Type.Optional(Type.Record(Type.String(), Type.String())),\n\tcompat: Type.Optional(ProviderCompatSchema),\n});\n\ntype ModelOverride = Static<typeof ModelOverrideSchema>;\n\nconst ProviderConfigSchema = Type.Object({\n\tname: Type.Optional(Type.String({ minLength: 1 })),\n\tbaseUrl: Type.Optional(Type.String({ minLength: 1 })),\n\tapiKey: Type.Optional(Type.String({ minLength: 1 })),\n\tapi: Type.Optional(Type.String({ minLength: 1 })),\n\theaders: Type.Optional(Type.Record(Type.String(), Type.String())),\n\tcompat: Type.Optional(ProviderCompatSchema),\n\tauthHeader: Type.Optional(Type.Boolean()),\n\tmodels: Type.Optional(Type.Array(ModelDefinitionSchema)),\n\tmodelOverrides: Type.Optional(Type.Record(Type.String(), ModelOverrideSchema)),\n});\n\nconst ModelsConfigSchema = Type.Object({\n\tproviders: Type.Record(Type.String(), ProviderConfigSchema),\n});\n\nconst validateModelsConfig = Compile(ModelsConfigSchema);\n\ntype ModelsConfig = Static<typeof ModelsConfigSchema>;\n\nfunction formatValidationPath(error: TLocalizedValidationError): string {\n\tif (error.keyword === \"required\") {\n\t\tconst requiredProperties = (error.params as { requiredProperties?: string[] }).requiredProperties;\n\t\tconst requiredProperty = requiredProperties?.[0];\n\t\tif (requiredProperty) {\n\t\t\tconst basePath = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n\t\t\treturn basePath ? `${basePath}.${requiredProperty}` : requiredProperty;\n\t\t}\n\t}\n\tconst path = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n\treturn path || \"root\";\n}\n\n/** Provider override config (baseUrl, compat) without request auth/headers */\ninterface ProviderOverride {\n\tbaseUrl?: string;\n\tcompat?: Model<Api>[\"compat\"];\n}\n\ninterface ProviderRequestConfig {\n\tapiKey?: string;\n\theaders?: Record<string, string>;\n\tauthHeader?: boolean;\n}\n\nfunction migrateLegacyRegisterProviderConfigValue(providerName: string, field: string, value: string): string {\n\tif (!isLegacyEnvVarNameConfigValue(value)) return value;\n\twarnDeprecation(\n\t\t`registerProvider(\"${providerName}\") ${field} value \"${value}\" is treated as a legacy environment variable reference. This will no longer be detected as an environment variable reference in a future release. Pass \"$${value}\" instead.`,\n\t);\n\treturn `$${value}`;\n}\n\nfunction migrateLegacyRegisterProviderHeaders(\n\tproviderName: string,\n\tfield: string,\n\theaders: Record<string, string> | undefined,\n): Record<string, string> | undefined {\n\tif (!headers) return undefined;\n\tlet migratedHeaders: Record<string, string> | undefined;\n\tfor (const [key, value] of Object.entries(headers)) {\n\t\tconst migratedValue = migrateLegacyRegisterProviderConfigValue(providerName, `${field} header \"${key}\"`, value);\n\t\tif (migratedValue === value) continue;\n\t\tmigratedHeaders ??= { ...headers };\n\t\tmigratedHeaders[key] = migratedValue;\n\t}\n\treturn migratedHeaders ?? headers;\n}\n\nfunction migrateLegacyRegisterProviderConfigValues(\n\tproviderName: string,\n\tconfig: ProviderConfigInput,\n): ProviderConfigInput {\n\tlet migratedConfig: ProviderConfigInput | undefined;\n\n\tconst setMigratedConfigValue = <TKey extends keyof ProviderConfigInput>(\n\t\tkey: TKey,\n\t\tvalue: ProviderConfigInput[TKey],\n\t) => {\n\t\tmigratedConfig ??= { ...config };\n\t\tmigratedConfig[key] = value;\n\t};\n\n\tif (config.apiKey) {\n\t\tconst apiKey = migrateLegacyRegisterProviderConfigValue(providerName, \"apiKey\", config.apiKey);\n\t\tif (apiKey !== config.apiKey) {\n\t\t\tsetMigratedConfigValue(\"apiKey\", apiKey);\n\t\t}\n\t}\n\n\tconst headers = migrateLegacyRegisterProviderHeaders(providerName, \"headers\", config.headers);\n\tif (headers !== config.headers) {\n\t\tsetMigratedConfigValue(\"headers\", headers);\n\t}\n\n\tif (config.models) {\n\t\tlet models: ProviderConfigInput[\"models\"] | undefined;\n\t\tfor (let index = 0; index < config.models.length; index++) {\n\t\t\tconst model = config.models[index];\n\t\t\tconst modelHeaders = migrateLegacyRegisterProviderHeaders(\n\t\t\t\tproviderName,\n\t\t\t\t`model \"${model.id}\" headers`,\n\t\t\t\tmodel.headers,\n\t\t\t);\n\t\t\tif (modelHeaders === model.headers) continue;\n\t\t\tmodels ??= [...config.models];\n\t\t\tmodels[index] = { ...model, headers: modelHeaders };\n\t\t}\n\t\tif (models) {\n\t\t\tsetMigratedConfigValue(\"models\", models);\n\t\t}\n\t}\n\n\treturn migratedConfig ?? config;\n}\n\nexport type ResolvedRequestAuth =\n\t| {\n\t\t\tok: true;\n\t\t\tapiKey?: string;\n\t\t\theaders?: Record<string, string>;\n\t }\n\t| {\n\t\t\tok: false;\n\t\t\terror: string;\n\t };\n\n/** Result of loading custom models from models.json */\ninterface CustomModelsResult {\n\tmodels: Model<Api>[];\n\t/** Providers with baseUrl/headers/apiKey overrides for built-in models */\n\toverrides: Map<string, ProviderOverride>;\n\t/** Per-model overrides: provider -> modelId -> override */\n\tmodelOverrides: Map<string, Map<string, ModelOverride>>;\n\terror: string | undefined;\n}\n\nfunction emptyCustomModelsResult(error?: string): CustomModelsResult {\n\treturn { models: [], overrides: new Map(), modelOverrides: new Map(), error };\n}\n\nfunction mergeCompat(\n\tbaseCompat: Model<Api>[\"compat\"],\n\toverrideCompat: ModelOverride[\"compat\"],\n): Model<Api>[\"compat\"] | undefined {\n\tif (!overrideCompat) return baseCompat;\n\n\tconst base = baseCompat as OpenAICompletionsCompat | OpenAIResponsesCompat | AnthropicMessagesCompat | undefined;\n\tconst override = overrideCompat as OpenAICompletionsCompat | OpenAIResponsesCompat | AnthropicMessagesCompat;\n\tconst merged = { ...base, ...override } as OpenAICompletionsCompat | OpenAIResponsesCompat | AnthropicMessagesCompat;\n\n\tconst baseCompletions = base as OpenAICompletionsCompat | undefined;\n\tconst overrideCompletions = override as OpenAICompletionsCompat;\n\tconst mergedCompletions = merged as OpenAICompletionsCompat;\n\n\tif (baseCompletions?.openRouterRouting || overrideCompletions.openRouterRouting) {\n\t\tmergedCompletions.openRouterRouting = {\n\t\t\t...baseCompletions?.openRouterRouting,\n\t\t\t...overrideCompletions.openRouterRouting,\n\t\t};\n\t}\n\n\tif (baseCompletions?.vercelGatewayRouting || overrideCompletions.vercelGatewayRouting) {\n\t\tmergedCompletions.vercelGatewayRouting = {\n\t\t\t...baseCompletions?.vercelGatewayRouting,\n\t\t\t...overrideCompletions.vercelGatewayRouting,\n\t\t};\n\t}\n\n\treturn merged as Model<Api>[\"compat\"];\n}\n\n/**\n * Deep merge a model override into a model.\n * Handles nested objects (cost, compat) by merging rather than replacing.\n */\nfunction applyModelOverride(model: Model<Api>, override: ModelOverride): Model<Api> {\n\tconst result = { ...model };\n\n\t// Simple field overrides\n\tif (override.name !== undefined) result.name = override.name;\n\tif (override.reasoning !== undefined) result.reasoning = override.reasoning;\n\tif (override.thinkingLevelMap !== undefined) {\n\t\tresult.thinkingLevelMap = { ...model.thinkingLevelMap, ...override.thinkingLevelMap };\n\t}\n\tif (override.input !== undefined) result.input = override.input as (\"text\" | \"image\")[];\n\tif (override.contextWindow !== undefined) result.contextWindow = override.contextWindow;\n\tif (override.maxTokens !== undefined) result.maxTokens = override.maxTokens;\n\n\t// Merge cost (partial override)\n\tif (override.cost) {\n\t\tresult.cost = {\n\t\t\tinput: override.cost.input ?? model.cost.input,\n\t\t\toutput: override.cost.output ?? model.cost.output,\n\t\t\tcacheRead: override.cost.cacheRead ?? model.cost.cacheRead,\n\t\t\tcacheWrite: override.cost.cacheWrite ?? model.cost.cacheWrite,\n\t\t};\n\t}\n\n\t// Deep merge compat\n\tresult.compat = mergeCompat(model.compat, override.compat);\n\n\treturn result;\n}\n\n/** Clear the config value command cache. Exported for testing. */\nexport const clearApiKeyCache = clearConfigValueCache;\n\n/**\n * Model registry - loads and manages models, resolves API keys via AuthStorage.\n */\nexport class ModelRegistry {\n\tprivate models: Model<Api>[] = [];\n\tprivate providerRequestConfigs: Map<string, ProviderRequestConfig> = new Map();\n\tprivate modelRequestHeaders: Map<string, Record<string, string>> = new Map();\n\tprivate registeredProviders: Map<string, ProviderConfigInput> = new Map();\n\tprivate loadError: string | undefined = undefined;\n\treadonly authStorage: AuthStorage;\n\tprivate modelsJsonPath: string | undefined;\n\n\tprivate constructor(authStorage: AuthStorage, modelsJsonPath: string | undefined) {\n\t\tthis.authStorage = authStorage;\n\t\tthis.modelsJsonPath = modelsJsonPath ? normalizePath(modelsJsonPath) : undefined;\n\t\tthis.loadModels();\n\t}\n\n\tstatic create(authStorage: AuthStorage, modelsJsonPath: string = join(getAgentDir(), \"models.json\")): ModelRegistry {\n\t\treturn new ModelRegistry(authStorage, modelsJsonPath);\n\t}\n\n\tstatic inMemory(authStorage: AuthStorage): ModelRegistry {\n\t\treturn new ModelRegistry(authStorage, undefined);\n\t}\n\n\t/**\n\t * Reload models from disk (built-in + custom from models.json).\n\t */\n\trefresh(): void {\n\t\tthis.providerRequestConfigs.clear();\n\t\tthis.modelRequestHeaders.clear();\n\t\tthis.loadError = undefined;\n\n\t\t// Ensure dynamic API/OAuth registrations are rebuilt from current provider state.\n\t\tresetApiProviders();\n\t\tresetOAuthProviders();\n\n\t\tthis.loadModels();\n\n\t\tfor (const [providerName, config] of this.registeredProviders.entries()) {\n\t\t\tthis.applyProviderConfig(providerName, config);\n\t\t}\n\t}\n\n\t/**\n\t * Get any error from loading models.json (undefined if no error).\n\t */\n\tgetError(): string | undefined {\n\t\treturn this.loadError;\n\t}\n\n\tprivate loadModels(): void {\n\t\t// Load custom models and overrides from models.json\n\t\tconst {\n\t\t\tmodels: customModels,\n\t\t\toverrides,\n\t\t\tmodelOverrides,\n\t\t\terror,\n\t\t} = this.modelsJsonPath ? this.loadCustomModels(this.modelsJsonPath) : emptyCustomModelsResult();\n\n\t\tif (error) {\n\t\t\tthis.loadError = error;\n\t\t\t// Keep built-in models even if custom models failed to load\n\t\t}\n\n\t\tconst builtInModels = this.loadBuiltInModels(overrides, modelOverrides);\n\t\tlet combined = this.mergeCustomModels(builtInModels, customModels);\n\n\t\t// Let OAuth providers modify their models (e.g., update baseUrl)\n\t\tfor (const oauthProvider of this.authStorage.getOAuthProviders()) {\n\t\t\tconst cred = this.authStorage.get(oauthProvider.id);\n\t\t\tif (cred?.type === \"oauth\" && oauthProvider.modifyModels) {\n\t\t\t\tcombined = oauthProvider.modifyModels(combined, cred);\n\t\t\t}\n\t\t}\n\n\t\tthis.models = combined;\n\t}\n\n\t/** Load built-in models and apply provider/model overrides */\n\tprivate loadBuiltInModels(\n\t\toverrides: Map<string, ProviderOverride>,\n\t\tmodelOverrides: Map<string, Map<string, ModelOverride>>,\n\t): Model<Api>[] {\n\t\treturn getProviders().flatMap((provider) => {\n\t\t\tconst models = getModels(provider as KnownProvider) as Model<Api>[];\n\t\t\tconst providerOverride = overrides.get(provider);\n\t\t\tconst perModelOverrides = modelOverrides.get(provider);\n\n\t\t\treturn models.map((m) => {\n\t\t\t\tlet model = m;\n\n\t\t\t\t// Apply provider-level baseUrl/headers/compat override\n\t\t\t\tif (providerOverride) {\n\t\t\t\t\tmodel = {\n\t\t\t\t\t\t...model,\n\t\t\t\t\t\tbaseUrl: providerOverride.baseUrl ?? model.baseUrl,\n\t\t\t\t\t\tcompat: mergeCompat(model.compat, providerOverride.compat),\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Apply per-model override\n\t\t\t\tconst modelOverride = perModelOverrides?.get(m.id);\n\t\t\t\tif (modelOverride) {\n\t\t\t\t\tmodel = applyModelOverride(model, modelOverride);\n\t\t\t\t}\n\n\t\t\t\treturn model;\n\t\t\t});\n\t\t});\n\t}\n\n\t/** Merge custom models into built-in list by provider+id (custom wins on conflicts). */\n\tprivate mergeCustomModels(builtInModels: Model<Api>[], customModels: Model<Api>[]): Model<Api>[] {\n\t\tconst merged = [...builtInModels];\n\t\tfor (const customModel of customModels) {\n\t\t\tconst existingIndex = merged.findIndex((m) => m.provider === customModel.provider && m.id === customModel.id);\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tmerged[existingIndex] = customModel;\n\t\t\t} else {\n\t\t\t\tmerged.push(customModel);\n\t\t\t}\n\t\t}\n\t\treturn merged;\n\t}\n\n\tprivate loadCustomModels(modelsJsonPath: string): CustomModelsResult {\n\t\tif (!existsSync(modelsJsonPath)) {\n\t\t\treturn emptyCustomModelsResult();\n\t\t}\n\n\t\ttry {\n\t\t\tconst content = readFileSync(modelsJsonPath, \"utf-8\");\n\t\t\tconst parsed = JSON.parse(stripJsonComments(content)) as unknown;\n\n\t\t\tif (!validateModelsConfig.Check(parsed)) {\n\t\t\t\tconst errors =\n\t\t\t\t\tvalidateModelsConfig\n\t\t\t\t\t\t.Errors(parsed)\n\t\t\t\t\t\t.map((error) => ` - ${formatValidationPath(error)}: ${error.message}`)\n\t\t\t\t\t\t.join(\"\\n\") || \"Unknown schema error\";\n\t\t\t\treturn emptyCustomModelsResult(`Invalid models.json schema:\\n${errors}\\n\\nFile: ${modelsJsonPath}`);\n\t\t\t}\n\n\t\t\tconst config = parsed as ModelsConfig;\n\n\t\t\t// Additional validation\n\t\t\tthis.validateConfig(config);\n\n\t\t\tconst overrides = new Map<string, ProviderOverride>();\n\t\t\tconst modelOverrides = new Map<string, Map<string, ModelOverride>>();\n\n\t\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\t\tif (providerConfig.baseUrl || providerConfig.compat) {\n\t\t\t\t\toverrides.set(providerName, {\n\t\t\t\t\t\tbaseUrl: providerConfig.baseUrl,\n\t\t\t\t\t\tcompat: providerConfig.compat,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tthis.storeProviderRequestConfig(providerName, providerConfig);\n\n\t\t\t\tif (providerConfig.modelOverrides) {\n\t\t\t\t\tmodelOverrides.set(providerName, new Map(Object.entries(providerConfig.modelOverrides)));\n\t\t\t\t\tfor (const [modelId, modelOverride] of Object.entries(providerConfig.modelOverrides)) {\n\t\t\t\t\t\tthis.storeModelHeaders(providerName, modelId, modelOverride.headers);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn { models: this.parseModels(config), overrides, modelOverrides, error: undefined };\n\t\t} catch (error) {\n\t\t\tif (error instanceof SyntaxError) {\n\t\t\t\treturn emptyCustomModelsResult(`Failed to parse models.json: ${error.message}\\n\\nFile: ${modelsJsonPath}`);\n\t\t\t}\n\t\t\treturn emptyCustomModelsResult(\n\t\t\t\t`Failed to load models.json: ${error instanceof Error ? error.message : error}\\n\\nFile: ${modelsJsonPath}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate validateConfig(config: ModelsConfig): void {\n\t\tconst builtInProviders = new Set<string>(getProviders());\n\n\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\tconst isBuiltIn = builtInProviders.has(providerName);\n\t\t\tconst hasProviderApi = !!providerConfig.api;\n\t\t\tconst models = providerConfig.models ?? [];\n\t\t\tconst hasModelOverrides =\n\t\t\t\tproviderConfig.modelOverrides && Object.keys(providerConfig.modelOverrides).length > 0;\n\n\t\t\tif (models.length === 0) {\n\t\t\t\t// Override-only config: needs baseUrl, headers, compat, modelOverrides, or some combination.\n\t\t\t\tif (!providerConfig.baseUrl && !providerConfig.headers && !providerConfig.compat && !hasModelOverrides) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Provider ${providerName}: must specify \"baseUrl\", \"headers\", \"compat\", \"modelOverrides\", or \"models\".`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else if (!isBuiltIn) {\n\t\t\t\t// Non-built-in providers with custom models require endpoint + auth.\n\t\t\t\tif (!providerConfig.baseUrl) {\n\t\t\t\t\tthrow new Error(`Provider ${providerName}: \"baseUrl\" is required when defining custom models.`);\n\t\t\t\t}\n\t\t\t\tif (!providerConfig.apiKey) {\n\t\t\t\t\tthrow new Error(`Provider ${providerName}: \"apiKey\" is required when defining custom models.`);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Built-in providers with custom models: baseUrl/apiKey/api are optional,\n\t\t\t// inherited from built-in models. Auth comes from env vars / auth storage.\n\n\t\t\tfor (const modelDef of models) {\n\t\t\t\tconst hasModelApi = !!modelDef.api;\n\n\t\t\t\tif (!hasProviderApi && !hasModelApi && !isBuiltIn) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Provider ${providerName}, model ${modelDef.id}: no \"api\" specified. Set at provider or model level.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t// For built-in providers, api is optional — inherited from built-in models.\n\n\t\t\t\tif (!modelDef.id) throw new Error(`Provider ${providerName}: model missing \"id\"`);\n\t\t\t\t// Validate contextWindow/maxTokens only if provided (they have defaults)\n\t\t\t\tif (modelDef.contextWindow !== undefined && modelDef.contextWindow <= 0)\n\t\t\t\t\tthrow new Error(`Provider ${providerName}, model ${modelDef.id}: invalid contextWindow`);\n\t\t\t\tif (modelDef.maxTokens !== undefined && modelDef.maxTokens <= 0)\n\t\t\t\t\tthrow new Error(`Provider ${providerName}, model ${modelDef.id}: invalid maxTokens`);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate parseModels(config: ModelsConfig): Model<Api>[] {\n\t\tconst models: Model<Api>[] = [];\n\t\tconst builtInProviders = new Set<string>(getProviders());\n\n\t\t// Cache built-in defaults (api, baseUrl) per provider, extracted from first model.\n\t\tconst builtInDefaultsCache = new Map<string, { api: string; baseUrl: string }>();\n\t\tconst getBuiltInDefaults = (providerName: string): { api: string; baseUrl: string } | undefined => {\n\t\t\tif (!builtInProviders.has(providerName)) return undefined;\n\t\t\tif (builtInDefaultsCache.has(providerName)) return builtInDefaultsCache.get(providerName);\n\t\t\tconst builtIn = getModels(providerName as KnownProvider) as Model<Api>[];\n\t\t\tif (builtIn.length === 0) return undefined;\n\t\t\tconst defaults = { api: builtIn[0].api, baseUrl: builtIn[0].baseUrl };\n\t\t\tbuiltInDefaultsCache.set(providerName, defaults);\n\t\t\treturn defaults;\n\t\t};\n\n\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\tconst modelDefs = providerConfig.models ?? [];\n\t\t\tif (modelDefs.length === 0) continue; // Override-only, no custom models\n\n\t\t\tconst builtInDefaults = getBuiltInDefaults(providerName);\n\n\t\t\tfor (const modelDef of modelDefs) {\n\t\t\t\tconst api = modelDef.api ?? providerConfig.api ?? builtInDefaults?.api;\n\t\t\t\tif (!api) continue;\n\n\t\t\t\tconst baseUrl = modelDef.baseUrl ?? providerConfig.baseUrl ?? builtInDefaults?.baseUrl;\n\t\t\t\tif (!baseUrl) continue;\n\n\t\t\t\tconst compat = mergeCompat(providerConfig.compat, modelDef.compat);\n\t\t\t\tthis.storeModelHeaders(providerName, modelDef.id, modelDef.headers);\n\n\t\t\t\tconst defaultCost = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };\n\t\t\t\tmodels.push({\n\t\t\t\t\tid: modelDef.id,\n\t\t\t\t\tname: modelDef.name ?? modelDef.id,\n\t\t\t\t\tapi: api as Api,\n\t\t\t\t\tprovider: providerName,\n\t\t\t\t\tbaseUrl,\n\t\t\t\t\treasoning: modelDef.reasoning ?? false,\n\t\t\t\t\tthinkingLevelMap: modelDef.thinkingLevelMap,\n\t\t\t\t\tinput: (modelDef.input ?? [\"text\"]) as (\"text\" | \"image\")[],\n\t\t\t\t\tcost: modelDef.cost ?? defaultCost,\n\t\t\t\t\tcontextWindow: modelDef.contextWindow ?? 128000,\n\t\t\t\t\tmaxTokens: modelDef.maxTokens ?? 16384,\n\t\t\t\t\theaders: undefined,\n\t\t\t\t\tcompat,\n\t\t\t\t} as Model<Api>);\n\t\t\t}\n\t\t}\n\n\t\treturn models;\n\t}\n\n\t/**\n\t * Get all models (built-in + custom).\n\t * If models.json had errors, returns only built-in models.\n\t */\n\tgetAll(): Model<Api>[] {\n\t\treturn this.models;\n\t}\n\n\t/**\n\t * Get only models that have auth configured.\n\t * This is a fast check that doesn't refresh OAuth tokens.\n\t */\n\tgetAvailable(): Model<Api>[] {\n\t\treturn this.models.filter((m) => this.hasConfiguredAuth(m));\n\t}\n\n\t/**\n\t * Find a model by provider and ID.\n\t */\n\tfind(provider: string, modelId: string): Model<Api> | undefined {\n\t\treturn this.models.find((m) => m.provider === provider && m.id === modelId);\n\t}\n\n\t/**\n\t * Get API key for a model.\n\t */\n\thasConfiguredAuth(model: Model<Api>): boolean {\n\t\tconst providerApiKey = this.providerRequestConfigs.get(model.provider)?.apiKey;\n\t\treturn (\n\t\t\tthis.authStorage.hasAuth(model.provider) ||\n\t\t\t(providerApiKey !== undefined && isConfigValueConfigured(providerApiKey))\n\t\t);\n\t}\n\n\tprivate getModelRequestKey(provider: string, modelId: string): string {\n\t\treturn `${provider}:${modelId}`;\n\t}\n\n\tprivate storeProviderRequestConfig(\n\t\tproviderName: string,\n\t\tconfig: {\n\t\t\tapiKey?: string;\n\t\t\theaders?: Record<string, string>;\n\t\t\tauthHeader?: boolean;\n\t\t},\n\t): void {\n\t\tif (!config.apiKey && !config.headers && !config.authHeader) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.providerRequestConfigs.set(providerName, {\n\t\t\tapiKey: config.apiKey,\n\t\t\theaders: config.headers,\n\t\t\tauthHeader: config.authHeader,\n\t\t});\n\t}\n\n\tprivate storeModelHeaders(providerName: string, modelId: string, headers?: Record<string, string>): void {\n\t\tconst key = this.getModelRequestKey(providerName, modelId);\n\t\tif (!headers || Object.keys(headers).length === 0) {\n\t\t\tthis.modelRequestHeaders.delete(key);\n\t\t\treturn;\n\t\t}\n\t\tthis.modelRequestHeaders.set(key, headers);\n\t}\n\n\t/**\n\t * Get API key and request headers for a model.\n\t */\n\tasync getApiKeyAndHeaders(model: Model<Api>): Promise<ResolvedRequestAuth> {\n\t\ttry {\n\t\t\tconst providerConfig = this.providerRequestConfigs.get(model.provider);\n\t\t\tconst apiKeyFromAuthStorage = await this.authStorage.getApiKey(model.provider, { includeFallback: false });\n\t\t\tconst apiKey =\n\t\t\t\tapiKeyFromAuthStorage ??\n\t\t\t\t(providerConfig?.apiKey\n\t\t\t\t\t? resolveConfigValueOrThrow(providerConfig.apiKey, `API key for provider \"${model.provider}\"`)\n\t\t\t\t\t: undefined);\n\n\t\t\tconst providerHeaders = resolveHeadersOrThrow(providerConfig?.headers, `provider \"${model.provider}\"`);\n\t\t\tconst modelHeaders = resolveHeadersOrThrow(\n\t\t\t\tthis.modelRequestHeaders.get(this.getModelRequestKey(model.provider, model.id)),\n\t\t\t\t`model \"${model.provider}/${model.id}\"`,\n\t\t\t);\n\n\t\t\tlet headers =\n\t\t\t\tmodel.headers || providerHeaders || modelHeaders\n\t\t\t\t\t? { ...model.headers, ...providerHeaders, ...modelHeaders }\n\t\t\t\t\t: undefined;\n\n\t\t\tif (providerConfig?.authHeader) {\n\t\t\t\tif (!apiKey) {\n\t\t\t\t\treturn { ok: false, error: `No API key found for \"${model.provider}\"` };\n\t\t\t\t}\n\t\t\t\theaders = { ...headers, Authorization: `Bearer ${apiKey}` };\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tok: true,\n\t\t\t\tapiKey,\n\t\t\t\theaders: headers && Object.keys(headers).length > 0 ? headers : undefined,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Return auth status for a provider, including request auth configured in models.json.\n\t * This intentionally does not execute command-backed config values.\n\t */\n\tgetProviderAuthStatus(provider: string): AuthStatus {\n\t\tconst authStatus = this.authStorage.getAuthStatus(provider);\n\t\tif (authStatus.source) {\n\t\t\treturn authStatus;\n\t\t}\n\n\t\tconst providerApiKey = this.providerRequestConfigs.get(provider)?.apiKey;\n\t\tif (!providerApiKey) {\n\t\t\treturn authStatus;\n\t\t}\n\n\t\tif (isCommandConfigValue(providerApiKey)) {\n\t\t\treturn { configured: true, source: \"models_json_command\" };\n\t\t}\n\n\t\tconst envVarNames = getConfigValueEnvVarNames(providerApiKey);\n\t\tif (envVarNames.length > 0) {\n\t\t\treturn isConfigValueConfigured(providerApiKey)\n\t\t\t\t? { configured: true, source: \"environment\", label: envVarNames.join(\", \") }\n\t\t\t\t: { configured: false };\n\t\t}\n\n\t\treturn { configured: true, source: \"models_json_key\" };\n\t}\n\n\t/**\n\t * Get display name for a provider.\n\t */\n\tgetProviderDisplayName(provider: string): string {\n\t\tconst registeredProvider = this.registeredProviders.get(provider);\n\t\tconst oauthProvider = this.authStorage.getOAuthProviders().find((p) => p.id === provider);\n\n\t\treturn (\n\t\t\tregisteredProvider?.name ??\n\t\t\tregisteredProvider?.oauth?.name ??\n\t\t\toauthProvider?.name ??\n\t\t\tBUILT_IN_PROVIDER_DISPLAY_NAMES[provider] ??\n\t\t\tprovider\n\t\t);\n\t}\n\n\t/**\n\t * Get API key for a provider.\n\t */\n\tasync getApiKeyForProvider(provider: string): Promise<string | undefined> {\n\t\tconst apiKey = await this.authStorage.getApiKey(provider, { includeFallback: false });\n\t\tif (apiKey !== undefined) {\n\t\t\treturn apiKey;\n\t\t}\n\n\t\tconst providerApiKey = this.providerRequestConfigs.get(provider)?.apiKey;\n\t\treturn providerApiKey ? resolveConfigValueUncached(providerApiKey) : undefined;\n\t}\n\n\t/**\n\t * Check if a model is using OAuth credentials (subscription).\n\t */\n\tisUsingOAuth(model: Model<Api>): boolean {\n\t\tconst cred = this.authStorage.get(model.provider);\n\t\treturn cred?.type === \"oauth\";\n\t}\n\n\t/**\n\t * Register a provider dynamically (from extensions).\n\t *\n\t * If provider has models: replaces all existing models for this provider.\n\t * If provider has only baseUrl/headers: overrides existing models' URLs.\n\t * If provider has oauth: registers OAuth provider for /login support.\n\t */\n\tregisterProvider(providerName: string, config: ProviderConfigInput): void {\n\t\tconst migratedConfig = migrateLegacyRegisterProviderConfigValues(providerName, config);\n\t\tthis.validateProviderConfig(providerName, migratedConfig);\n\t\tthis.applyProviderConfig(providerName, migratedConfig);\n\t\tthis.upsertRegisteredProvider(providerName, migratedConfig);\n\t}\n\n\t/**\n\t * Unregister a previously registered provider.\n\t *\n\t * Removes the provider from the registry and reloads models from disk so that\n\t * built-in models overridden by this provider are restored to their original state.\n\t * Also resets dynamic OAuth and API stream registrations before reapplying\n\t * remaining dynamic providers.\n\t * Has no effect if the provider was never registered.\n\t */\n\tunregisterProvider(providerName: string): void {\n\t\tif (!this.registeredProviders.has(providerName)) return;\n\t\tthis.registeredProviders.delete(providerName);\n\t\tthis.refresh();\n\t}\n\n\t/**\n\t * Upsert a provider config into registeredProviders.\n\t * If the provider is already registered, defined values in the incoming config\n\t * override existing ones; undefined values are preserved from the stored config.\n\t * If the provider is not registered, the incoming config is stored as-is.\n\t */\n\tprivate upsertRegisteredProvider(providerName: string, config: ProviderConfigInput): void {\n\t\tconst existing = this.registeredProviders.get(providerName);\n\t\tif (!existing) {\n\t\t\tthis.registeredProviders.set(providerName, config);\n\t\t\treturn;\n\t\t}\n\t\tfor (const k of Object.keys(config) as (keyof ProviderConfigInput)[]) {\n\t\t\tif (config[k] !== undefined) {\n\t\t\t\t(existing as Record<string, unknown>)[k] = config[k];\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate validateProviderConfig(providerName: string, config: ProviderConfigInput): void {\n\t\tif (config.streamSimple && !config.api) {\n\t\t\tthrow new Error(`Provider ${providerName}: \"api\" is required when registering streamSimple.`);\n\t\t}\n\n\t\tif (!config.models || config.models.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!config.baseUrl) {\n\t\t\tthrow new Error(`Provider ${providerName}: \"baseUrl\" is required when defining models.`);\n\t\t}\n\t\tif (!config.apiKey && !config.oauth) {\n\t\t\tthrow new Error(`Provider ${providerName}: \"apiKey\" or \"oauth\" is required when defining models.`);\n\t\t}\n\n\t\tfor (const modelDef of config.models) {\n\t\t\tconst api = modelDef.api || config.api;\n\t\t\tif (!api) {\n\t\t\t\tthrow new Error(`Provider ${providerName}, model ${modelDef.id}: no \"api\" specified.`);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate applyProviderConfig(providerName: string, config: ProviderConfigInput): void {\n\t\t// Register OAuth provider if provided\n\t\tif (config.oauth) {\n\t\t\t// Ensure the OAuth provider ID matches the provider name\n\t\t\tconst oauthProvider: OAuthProviderInterface = {\n\t\t\t\t...config.oauth,\n\t\t\t\tid: providerName,\n\t\t\t};\n\t\t\tregisterOAuthProvider(oauthProvider);\n\t\t}\n\n\t\tif (config.streamSimple) {\n\t\t\tconst streamSimple = config.streamSimple;\n\t\t\tregisterApiProvider(\n\t\t\t\t{\n\t\t\t\t\tapi: config.api!,\n\t\t\t\t\tstream: (model, context, options) => streamSimple(model, context, options as SimpleStreamOptions),\n\t\t\t\t\tstreamSimple,\n\t\t\t\t},\n\t\t\t\t`provider:${providerName}`,\n\t\t\t);\n\t\t}\n\n\t\tthis.storeProviderRequestConfig(providerName, config);\n\n\t\tif (config.models && config.models.length > 0) {\n\t\t\t// Full replacement: remove existing models for this provider\n\t\t\tthis.models = this.models.filter((m) => m.provider !== providerName);\n\n\t\t\t// Parse and add new models\n\t\t\tfor (const modelDef of config.models) {\n\t\t\t\tconst api = modelDef.api || config.api;\n\t\t\t\tthis.storeModelHeaders(providerName, modelDef.id, modelDef.headers);\n\n\t\t\t\tthis.models.push({\n\t\t\t\t\tid: modelDef.id,\n\t\t\t\t\tname: modelDef.name,\n\t\t\t\t\tapi: api as Api,\n\t\t\t\t\tprovider: providerName,\n\t\t\t\t\tbaseUrl: modelDef.baseUrl ?? config.baseUrl!,\n\t\t\t\t\treasoning: modelDef.reasoning,\n\t\t\t\t\tthinkingLevelMap: modelDef.thinkingLevelMap,\n\t\t\t\t\tinput: modelDef.input as (\"text\" | \"image\")[],\n\t\t\t\t\tcost: modelDef.cost,\n\t\t\t\t\tcontextWindow: modelDef.contextWindow,\n\t\t\t\t\tmaxTokens: modelDef.maxTokens,\n\t\t\t\t\theaders: undefined,\n\t\t\t\t\tcompat: modelDef.compat,\n\t\t\t\t} as Model<Api>);\n\t\t\t}\n\n\t\t\t// Apply OAuth modifyModels if credentials exist (e.g., to update baseUrl)\n\t\t\tif (config.oauth?.modifyModels) {\n\t\t\t\tconst cred = this.authStorage.get(providerName);\n\t\t\t\tif (cred?.type === \"oauth\") {\n\t\t\t\t\tthis.models = config.oauth.modifyModels(this.models, cred);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (config.baseUrl || config.headers) {\n\t\t\t// Override-only: update baseUrl for existing models. Request headers are resolved per request.\n\t\t\tthis.models = this.models.map((m) => {\n\t\t\t\tif (m.provider !== providerName) return m;\n\t\t\t\treturn {\n\t\t\t\t\t...m,\n\t\t\t\t\tbaseUrl: config.baseUrl ?? m.baseUrl,\n\t\t\t\t};\n\t\t\t});\n\t\t}\n\t}\n}\n\n/**\n * Input type for registerProvider API.\n */\nexport interface ProviderConfigInput {\n\tname?: string;\n\tbaseUrl?: string;\n\tapiKey?: string;\n\tapi?: Api;\n\tstreamSimple?: (model: Model<Api>, context: Context, options?: SimpleStreamOptions) => AssistantMessageEventStream;\n\theaders?: Record<string, string>;\n\tauthHeader?: boolean;\n\t/** OAuth provider for /login support */\n\toauth?: Omit<OAuthProviderInterface, \"id\">;\n\tmodels?: Array<{\n\t\tid: string;\n\t\tname: string;\n\t\tapi?: Api;\n\t\tbaseUrl?: string;\n\t\treasoning: boolean;\n\t\tthinkingLevelMap?: Model<Api>[\"thinkingLevelMap\"];\n\t\tinput: (\"text\" | \"image\")[];\n\t\tcost: { input: number; output: number; cacheRead: number; cacheWrite: number };\n\t\tcontextWindow: number;\n\t\tmaxTokens: number;\n\t\theaders?: Record<string, string>;\n\t\tcompat?: Model<Api>[\"compat\"];\n\t}>;\n}\n"]}
1
+ {"version":3,"file":"model-registry.d.ts","sourceRoot":"","sources":["../../src/core/model-registry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Model registry - manages built-in and custom models, provides API key resolution.\n */\n\nimport { existsSync, readFileSync } from \"fs\";\nimport {\n\ttype AnthropicMessagesCompat,\n\ttype Api,\n\ttype AssistantMessageEventStream,\n\ttype Context,\n\tgetModels,\n\tgetProviders,\n\ttype KnownProvider,\n\ttype Model,\n\ttype OAuthProviderInterface,\n\ttype OpenAICompletionsCompat,\n\ttype OpenAIResponsesCompat,\n\tregisterApiProvider,\n\tresetApiProviders,\n\ttype SimpleStreamOptions,\n} from \"omk-ai\";\nimport { registerOAuthProvider, resetOAuthProviders } from \"omk-ai/oauth\";\nimport { join } from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { Compile } from \"typebox/compile\";\nimport type { TLocalizedValidationError } from \"typebox/error\";\nimport { getAgentDir } from \"../config.ts\";\nimport { warnDeprecation } from \"../utils/deprecation.ts\";\nimport { stripJsonComments } from \"../utils/json.ts\";\nimport { normalizePath } from \"../utils/paths.ts\";\nimport type { AuthStatus, AuthStorage } from \"./auth-storage.ts\";\nimport { BUILT_IN_PROVIDER_DISPLAY_NAMES } from \"./provider-display-names.ts\";\nimport {\n\tclearConfigValueCache,\n\tgetConfigValueEnvVarNames,\n\tisCommandConfigValue,\n\tisConfigValueConfigured,\n\tisLegacyEnvVarNameConfigValue,\n\tresolveConfigValueOrThrow,\n\tresolveConfigValueUncached,\n\tresolveHeadersOrThrow,\n} from \"./resolve-config-value.ts\";\n\n// Schema for OpenRouter routing preferences\nconst PercentileCutoffsSchema = Type.Object({\n\tp50: Type.Optional(Type.Number()),\n\tp75: Type.Optional(Type.Number()),\n\tp90: Type.Optional(Type.Number()),\n\tp99: Type.Optional(Type.Number()),\n});\n\nconst OpenRouterRoutingSchema = Type.Object({\n\tallow_fallbacks: Type.Optional(Type.Boolean()),\n\trequire_parameters: Type.Optional(Type.Boolean()),\n\tdata_collection: Type.Optional(Type.Union([Type.Literal(\"deny\"), Type.Literal(\"allow\")])),\n\tzdr: Type.Optional(Type.Boolean()),\n\tenforce_distillable_text: Type.Optional(Type.Boolean()),\n\torder: Type.Optional(Type.Array(Type.String())),\n\tonly: Type.Optional(Type.Array(Type.String())),\n\tignore: Type.Optional(Type.Array(Type.String())),\n\tquantizations: Type.Optional(Type.Array(Type.String())),\n\tsort: Type.Optional(\n\t\tType.Union([\n\t\t\tType.String(),\n\t\t\tType.Object({\n\t\t\t\tby: Type.Optional(Type.String()),\n\t\t\t\tpartition: Type.Optional(Type.Union([Type.String(), Type.Null()])),\n\t\t\t}),\n\t\t]),\n\t),\n\tmax_price: Type.Optional(\n\t\tType.Object({\n\t\t\tprompt: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t\tcompletion: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t\timage: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t\taudio: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t\trequest: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t}),\n\t),\n\tpreferred_min_throughput: Type.Optional(Type.Union([Type.Number(), PercentileCutoffsSchema])),\n\tpreferred_max_latency: Type.Optional(Type.Union([Type.Number(), PercentileCutoffsSchema])),\n});\n\n// Schema for Vercel AI Gateway routing preferences\nconst VercelGatewayRoutingSchema = Type.Object({\n\tonly: Type.Optional(Type.Array(Type.String())),\n\torder: Type.Optional(Type.Array(Type.String())),\n});\n\n// Schema for thinking level support and provider-specific values\nconst ThinkingLevelMapValueSchema = Type.Union([Type.String(), Type.Null()]);\nconst ThinkingLevelMapSchema = Type.Object({\n\toff: Type.Optional(ThinkingLevelMapValueSchema),\n\tminimal: Type.Optional(ThinkingLevelMapValueSchema),\n\tlow: Type.Optional(ThinkingLevelMapValueSchema),\n\tmedium: Type.Optional(ThinkingLevelMapValueSchema),\n\thigh: Type.Optional(ThinkingLevelMapValueSchema),\n\txhigh: Type.Optional(ThinkingLevelMapValueSchema),\n\tmax: Type.Optional(ThinkingLevelMapValueSchema),\n});\n\nconst OpenAICompletionsCompatSchema = Type.Object({\n\tsupportsStore: Type.Optional(Type.Boolean()),\n\tsupportsDeveloperRole: Type.Optional(Type.Boolean()),\n\tsupportsReasoningEffort: Type.Optional(Type.Boolean()),\n\tsupportsUsageInStreaming: Type.Optional(Type.Boolean()),\n\tmaxTokensField: Type.Optional(Type.Union([Type.Literal(\"max_completion_tokens\"), Type.Literal(\"max_tokens\")])),\n\trequiresToolResultName: Type.Optional(Type.Boolean()),\n\trequiresAssistantAfterToolResult: Type.Optional(Type.Boolean()),\n\trequiresThinkingAsText: Type.Optional(Type.Boolean()),\n\trequiresReasoningContentOnAssistantMessages: Type.Optional(Type.Boolean()),\n\tthinkingFormat: Type.Optional(\n\t\tType.Union([\n\t\t\tType.Literal(\"openai\"),\n\t\t\tType.Literal(\"openrouter\"),\n\t\t\tType.Literal(\"together\"),\n\t\t\tType.Literal(\"deepseek\"),\n\t\t\tType.Literal(\"zai\"),\n\t\t\tType.Literal(\"qwen\"),\n\t\t\tType.Literal(\"qwen-chat-template\"),\n\t\t]),\n\t),\n\tcacheControlFormat: Type.Optional(Type.Literal(\"anthropic\")),\n\topenRouterRouting: Type.Optional(OpenRouterRoutingSchema),\n\tvercelGatewayRouting: Type.Optional(VercelGatewayRoutingSchema),\n\tsupportsStrictMode: Type.Optional(Type.Boolean()),\n\tsupportsLongCacheRetention: Type.Optional(Type.Boolean()),\n});\n\nconst OpenAIResponsesCompatSchema = Type.Object({\n\tsendSessionIdHeader: Type.Optional(Type.Boolean()),\n\tsupportsLongCacheRetention: Type.Optional(Type.Boolean()),\n});\n\nconst AnthropicMessagesCompatSchema = Type.Object({\n\tsupportsEagerToolInputStreaming: Type.Optional(Type.Boolean()),\n\tsupportsLongCacheRetention: Type.Optional(Type.Boolean()),\n\tsendSessionAffinityHeaders: Type.Optional(Type.Boolean()),\n\tsupportsCacheControlOnTools: Type.Optional(Type.Boolean()),\n\tforceAdaptiveThinking: Type.Optional(Type.Boolean()),\n});\n\nconst ProviderCompatSchema = Type.Union([\n\tOpenAICompletionsCompatSchema,\n\tOpenAIResponsesCompatSchema,\n\tAnthropicMessagesCompatSchema,\n]);\n\n// Schema for custom model definition\n// Most fields are optional with sensible defaults for local models (Ollama, LM Studio, etc.)\nconst ModelDefinitionSchema = Type.Object({\n\tid: Type.String({ minLength: 1 }),\n\tname: Type.Optional(Type.String({ minLength: 1 })),\n\tapi: Type.Optional(Type.String({ minLength: 1 })),\n\tbaseUrl: Type.Optional(Type.String({ minLength: 1 })),\n\treasoning: Type.Optional(Type.Boolean()),\n\tthinkingLevelMap: Type.Optional(ThinkingLevelMapSchema),\n\tinput: Type.Optional(Type.Array(Type.Union([Type.Literal(\"text\"), Type.Literal(\"image\")]))),\n\tcost: Type.Optional(\n\t\tType.Object({\n\t\t\tinput: Type.Number(),\n\t\t\toutput: Type.Number(),\n\t\t\tcacheRead: Type.Number(),\n\t\t\tcacheWrite: Type.Number(),\n\t\t}),\n\t),\n\tcontextWindow: Type.Optional(Type.Number()),\n\tmaxTokens: Type.Optional(Type.Number()),\n\theaders: Type.Optional(Type.Record(Type.String(), Type.String())),\n\tcompat: Type.Optional(ProviderCompatSchema),\n});\n\n// Schema for per-model overrides (all fields optional, merged with built-in model)\nconst ModelOverrideSchema = Type.Object({\n\tname: Type.Optional(Type.String({ minLength: 1 })),\n\treasoning: Type.Optional(Type.Boolean()),\n\tthinkingLevelMap: Type.Optional(ThinkingLevelMapSchema),\n\tinput: Type.Optional(Type.Array(Type.Union([Type.Literal(\"text\"), Type.Literal(\"image\")]))),\n\tcost: Type.Optional(\n\t\tType.Object({\n\t\t\tinput: Type.Optional(Type.Number()),\n\t\t\toutput: Type.Optional(Type.Number()),\n\t\t\tcacheRead: Type.Optional(Type.Number()),\n\t\t\tcacheWrite: Type.Optional(Type.Number()),\n\t\t}),\n\t),\n\tcontextWindow: Type.Optional(Type.Number()),\n\tmaxTokens: Type.Optional(Type.Number()),\n\theaders: Type.Optional(Type.Record(Type.String(), Type.String())),\n\tcompat: Type.Optional(ProviderCompatSchema),\n});\n\ntype ModelOverride = Static<typeof ModelOverrideSchema>;\n\nconst ProviderConfigSchema = Type.Object({\n\tname: Type.Optional(Type.String({ minLength: 1 })),\n\tbaseUrl: Type.Optional(Type.String({ minLength: 1 })),\n\tapiKey: Type.Optional(Type.String({ minLength: 1 })),\n\tapi: Type.Optional(Type.String({ minLength: 1 })),\n\theaders: Type.Optional(Type.Record(Type.String(), Type.String())),\n\tcompat: Type.Optional(ProviderCompatSchema),\n\tauthHeader: Type.Optional(Type.Boolean()),\n\tmodels: Type.Optional(Type.Array(ModelDefinitionSchema)),\n\tmodelOverrides: Type.Optional(Type.Record(Type.String(), ModelOverrideSchema)),\n});\n\nconst ModelsConfigSchema = Type.Object({\n\tproviders: Type.Record(Type.String(), ProviderConfigSchema),\n});\n\nconst validateModelsConfig = Compile(ModelsConfigSchema);\n\ntype ModelsConfig = Static<typeof ModelsConfigSchema>;\n\nfunction formatValidationPath(error: TLocalizedValidationError): string {\n\tif (error.keyword === \"required\") {\n\t\tconst requiredProperties = (error.params as { requiredProperties?: string[] }).requiredProperties;\n\t\tconst requiredProperty = requiredProperties?.[0];\n\t\tif (requiredProperty) {\n\t\t\tconst basePath = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n\t\t\treturn basePath ? `${basePath}.${requiredProperty}` : requiredProperty;\n\t\t}\n\t}\n\tconst path = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n\treturn path || \"root\";\n}\n\n/** Provider override config (baseUrl, compat) without request auth/headers */\ninterface ProviderOverride {\n\tbaseUrl?: string;\n\tcompat?: Model<Api>[\"compat\"];\n}\n\ninterface ProviderRequestConfig {\n\tapiKey?: string;\n\theaders?: Record<string, string>;\n\tauthHeader?: boolean;\n}\n\nfunction migrateLegacyRegisterProviderConfigValue(providerName: string, field: string, value: string): string {\n\tif (!isLegacyEnvVarNameConfigValue(value)) return value;\n\twarnDeprecation(\n\t\t`registerProvider(\"${providerName}\") ${field} value \"${value}\" is treated as a legacy environment variable reference. This will no longer be detected as an environment variable reference in a future release. Pass \"$${value}\" instead.`,\n\t);\n\treturn `$${value}`;\n}\n\nfunction migrateLegacyRegisterProviderHeaders(\n\tproviderName: string,\n\tfield: string,\n\theaders: Record<string, string> | undefined,\n): Record<string, string> | undefined {\n\tif (!headers) return undefined;\n\tlet migratedHeaders: Record<string, string> | undefined;\n\tfor (const [key, value] of Object.entries(headers)) {\n\t\tconst migratedValue = migrateLegacyRegisterProviderConfigValue(providerName, `${field} header \"${key}\"`, value);\n\t\tif (migratedValue === value) continue;\n\t\tmigratedHeaders ??= { ...headers };\n\t\tmigratedHeaders[key] = migratedValue;\n\t}\n\treturn migratedHeaders ?? headers;\n}\n\nfunction migrateLegacyRegisterProviderConfigValues(\n\tproviderName: string,\n\tconfig: ProviderConfigInput,\n): ProviderConfigInput {\n\tlet migratedConfig: ProviderConfigInput | undefined;\n\n\tconst setMigratedConfigValue = <TKey extends keyof ProviderConfigInput>(\n\t\tkey: TKey,\n\t\tvalue: ProviderConfigInput[TKey],\n\t) => {\n\t\tmigratedConfig ??= { ...config };\n\t\tmigratedConfig[key] = value;\n\t};\n\n\tif (config.apiKey) {\n\t\tconst apiKey = migrateLegacyRegisterProviderConfigValue(providerName, \"apiKey\", config.apiKey);\n\t\tif (apiKey !== config.apiKey) {\n\t\t\tsetMigratedConfigValue(\"apiKey\", apiKey);\n\t\t}\n\t}\n\n\tconst headers = migrateLegacyRegisterProviderHeaders(providerName, \"headers\", config.headers);\n\tif (headers !== config.headers) {\n\t\tsetMigratedConfigValue(\"headers\", headers);\n\t}\n\n\tif (config.models) {\n\t\tlet models: ProviderConfigInput[\"models\"] | undefined;\n\t\tfor (let index = 0; index < config.models.length; index++) {\n\t\t\tconst model = config.models[index];\n\t\t\tconst modelHeaders = migrateLegacyRegisterProviderHeaders(\n\t\t\t\tproviderName,\n\t\t\t\t`model \"${model.id}\" headers`,\n\t\t\t\tmodel.headers,\n\t\t\t);\n\t\t\tif (modelHeaders === model.headers) continue;\n\t\t\tmodels ??= [...config.models];\n\t\t\tmodels[index] = { ...model, headers: modelHeaders };\n\t\t}\n\t\tif (models) {\n\t\t\tsetMigratedConfigValue(\"models\", models);\n\t\t}\n\t}\n\n\treturn migratedConfig ?? config;\n}\n\nexport type ResolvedRequestAuth =\n\t| {\n\t\t\tok: true;\n\t\t\tapiKey?: string;\n\t\t\theaders?: Record<string, string>;\n\t }\n\t| {\n\t\t\tok: false;\n\t\t\terror: string;\n\t };\n\n/** Result of loading custom models from models.json */\ninterface CustomModelsResult {\n\tmodels: Model<Api>[];\n\t/** Providers with baseUrl/headers/apiKey overrides for built-in models */\n\toverrides: Map<string, ProviderOverride>;\n\t/** Per-model overrides: provider -> modelId -> override */\n\tmodelOverrides: Map<string, Map<string, ModelOverride>>;\n\terror: string | undefined;\n}\n\nfunction emptyCustomModelsResult(error?: string): CustomModelsResult {\n\treturn { models: [], overrides: new Map(), modelOverrides: new Map(), error };\n}\n\nfunction mergeCompat(\n\tbaseCompat: Model<Api>[\"compat\"],\n\toverrideCompat: ModelOverride[\"compat\"],\n): Model<Api>[\"compat\"] | undefined {\n\tif (!overrideCompat) return baseCompat;\n\n\tconst base = baseCompat as OpenAICompletionsCompat | OpenAIResponsesCompat | AnthropicMessagesCompat | undefined;\n\tconst override = overrideCompat as OpenAICompletionsCompat | OpenAIResponsesCompat | AnthropicMessagesCompat;\n\tconst merged = { ...base, ...override } as OpenAICompletionsCompat | OpenAIResponsesCompat | AnthropicMessagesCompat;\n\n\tconst baseCompletions = base as OpenAICompletionsCompat | undefined;\n\tconst overrideCompletions = override as OpenAICompletionsCompat;\n\tconst mergedCompletions = merged as OpenAICompletionsCompat;\n\n\tif (baseCompletions?.openRouterRouting || overrideCompletions.openRouterRouting) {\n\t\tmergedCompletions.openRouterRouting = {\n\t\t\t...baseCompletions?.openRouterRouting,\n\t\t\t...overrideCompletions.openRouterRouting,\n\t\t};\n\t}\n\n\tif (baseCompletions?.vercelGatewayRouting || overrideCompletions.vercelGatewayRouting) {\n\t\tmergedCompletions.vercelGatewayRouting = {\n\t\t\t...baseCompletions?.vercelGatewayRouting,\n\t\t\t...overrideCompletions.vercelGatewayRouting,\n\t\t};\n\t}\n\n\treturn merged as Model<Api>[\"compat\"];\n}\n\n/**\n * Deep merge a model override into a model.\n * Handles nested objects (cost, compat) by merging rather than replacing.\n */\nfunction applyModelOverride(model: Model<Api>, override: ModelOverride): Model<Api> {\n\tconst result = { ...model };\n\n\t// Simple field overrides\n\tif (override.name !== undefined) result.name = override.name;\n\tif (override.reasoning !== undefined) result.reasoning = override.reasoning;\n\tif (override.thinkingLevelMap !== undefined) {\n\t\tresult.thinkingLevelMap = { ...model.thinkingLevelMap, ...override.thinkingLevelMap };\n\t}\n\tif (override.input !== undefined) result.input = override.input as (\"text\" | \"image\")[];\n\tif (override.contextWindow !== undefined) result.contextWindow = override.contextWindow;\n\tif (override.maxTokens !== undefined) result.maxTokens = override.maxTokens;\n\n\t// Merge cost (partial override)\n\tif (override.cost) {\n\t\tresult.cost = {\n\t\t\tinput: override.cost.input ?? model.cost.input,\n\t\t\toutput: override.cost.output ?? model.cost.output,\n\t\t\tcacheRead: override.cost.cacheRead ?? model.cost.cacheRead,\n\t\t\tcacheWrite: override.cost.cacheWrite ?? model.cost.cacheWrite,\n\t\t};\n\t}\n\n\t// Deep merge compat\n\tresult.compat = mergeCompat(model.compat, override.compat);\n\n\treturn result;\n}\n\n/** Clear the config value command cache. Exported for testing. */\nexport const clearApiKeyCache = clearConfigValueCache;\n\n/**\n * Model registry - loads and manages models, resolves API keys via AuthStorage.\n */\nexport class ModelRegistry {\n\tprivate models: Model<Api>[] = [];\n\tprivate providerRequestConfigs: Map<string, ProviderRequestConfig> = new Map();\n\tprivate modelRequestHeaders: Map<string, Record<string, string>> = new Map();\n\tprivate registeredProviders: Map<string, ProviderConfigInput> = new Map();\n\tprivate loadError: string | undefined = undefined;\n\treadonly authStorage: AuthStorage;\n\tprivate modelsJsonPath: string | undefined;\n\n\tprivate constructor(authStorage: AuthStorage, modelsJsonPath: string | undefined) {\n\t\tthis.authStorage = authStorage;\n\t\tthis.modelsJsonPath = modelsJsonPath ? normalizePath(modelsJsonPath) : undefined;\n\t\tthis.loadModels();\n\t}\n\n\tstatic create(authStorage: AuthStorage, modelsJsonPath: string = join(getAgentDir(), \"models.json\")): ModelRegistry {\n\t\treturn new ModelRegistry(authStorage, modelsJsonPath);\n\t}\n\n\tstatic inMemory(authStorage: AuthStorage): ModelRegistry {\n\t\treturn new ModelRegistry(authStorage, undefined);\n\t}\n\n\t/**\n\t * Reload models from disk (built-in + custom from models.json).\n\t */\n\trefresh(): void {\n\t\tthis.providerRequestConfigs.clear();\n\t\tthis.modelRequestHeaders.clear();\n\t\tthis.loadError = undefined;\n\n\t\t// Ensure dynamic API/OAuth registrations are rebuilt from current provider state.\n\t\tresetApiProviders();\n\t\tresetOAuthProviders();\n\n\t\tthis.loadModels();\n\n\t\tfor (const [providerName, config] of this.registeredProviders.entries()) {\n\t\t\tthis.applyProviderConfig(providerName, config);\n\t\t}\n\t}\n\n\t/**\n\t * Get any error from loading models.json (undefined if no error).\n\t */\n\tgetError(): string | undefined {\n\t\treturn this.loadError;\n\t}\n\n\tprivate loadModels(): void {\n\t\t// Load custom models and overrides from models.json\n\t\tconst {\n\t\t\tmodels: customModels,\n\t\t\toverrides,\n\t\t\tmodelOverrides,\n\t\t\terror,\n\t\t} = this.modelsJsonPath ? this.loadCustomModels(this.modelsJsonPath) : emptyCustomModelsResult();\n\n\t\tif (error) {\n\t\t\tthis.loadError = error;\n\t\t\t// Keep built-in models even if custom models failed to load\n\t\t}\n\n\t\tconst builtInModels = this.loadBuiltInModels(overrides, modelOverrides);\n\t\tlet combined = this.mergeCustomModels(builtInModels, customModels);\n\n\t\t// Let OAuth providers modify their models (e.g., update baseUrl)\n\t\tfor (const oauthProvider of this.authStorage.getOAuthProviders()) {\n\t\t\tconst cred = this.authStorage.get(oauthProvider.id);\n\t\t\tif (cred?.type === \"oauth\" && oauthProvider.modifyModels) {\n\t\t\t\tcombined = oauthProvider.modifyModels(combined, cred);\n\t\t\t}\n\t\t}\n\n\t\tthis.models = combined;\n\t}\n\n\t/** Load built-in models and apply provider/model overrides */\n\tprivate loadBuiltInModels(\n\t\toverrides: Map<string, ProviderOverride>,\n\t\tmodelOverrides: Map<string, Map<string, ModelOverride>>,\n\t): Model<Api>[] {\n\t\treturn getProviders().flatMap((provider) => {\n\t\t\tconst models = getModels(provider as KnownProvider) as Model<Api>[];\n\t\t\tconst providerOverride = overrides.get(provider);\n\t\t\tconst perModelOverrides = modelOverrides.get(provider);\n\n\t\t\treturn models.map((m) => {\n\t\t\t\tlet model = m;\n\n\t\t\t\t// Apply provider-level baseUrl/headers/compat override\n\t\t\t\tif (providerOverride) {\n\t\t\t\t\tmodel = {\n\t\t\t\t\t\t...model,\n\t\t\t\t\t\tbaseUrl: providerOverride.baseUrl ?? model.baseUrl,\n\t\t\t\t\t\tcompat: mergeCompat(model.compat, providerOverride.compat),\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Apply per-model override\n\t\t\t\tconst modelOverride = perModelOverrides?.get(m.id);\n\t\t\t\tif (modelOverride) {\n\t\t\t\t\tmodel = applyModelOverride(model, modelOverride);\n\t\t\t\t}\n\n\t\t\t\treturn model;\n\t\t\t});\n\t\t});\n\t}\n\n\t/** Merge custom models into built-in list by provider+id (custom wins on conflicts). */\n\tprivate mergeCustomModels(builtInModels: Model<Api>[], customModels: Model<Api>[]): Model<Api>[] {\n\t\tconst merged = [...builtInModels];\n\t\tfor (const customModel of customModels) {\n\t\t\tconst existingIndex = merged.findIndex((m) => m.provider === customModel.provider && m.id === customModel.id);\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tmerged[existingIndex] = customModel;\n\t\t\t} else {\n\t\t\t\tmerged.push(customModel);\n\t\t\t}\n\t\t}\n\t\treturn merged;\n\t}\n\n\tprivate loadCustomModels(modelsJsonPath: string): CustomModelsResult {\n\t\tif (!existsSync(modelsJsonPath)) {\n\t\t\treturn emptyCustomModelsResult();\n\t\t}\n\n\t\ttry {\n\t\t\tconst content = readFileSync(modelsJsonPath, \"utf-8\");\n\t\t\tconst parsed = JSON.parse(stripJsonComments(content)) as unknown;\n\n\t\t\tif (!validateModelsConfig.Check(parsed)) {\n\t\t\t\tconst errors =\n\t\t\t\t\tvalidateModelsConfig\n\t\t\t\t\t\t.Errors(parsed)\n\t\t\t\t\t\t.map((error) => ` - ${formatValidationPath(error)}: ${error.message}`)\n\t\t\t\t\t\t.join(\"\\n\") || \"Unknown schema error\";\n\t\t\t\treturn emptyCustomModelsResult(`Invalid models.json schema:\\n${errors}\\n\\nFile: ${modelsJsonPath}`);\n\t\t\t}\n\n\t\t\tconst config = parsed as ModelsConfig;\n\n\t\t\t// Additional validation\n\t\t\tthis.validateConfig(config);\n\n\t\t\tconst overrides = new Map<string, ProviderOverride>();\n\t\t\tconst modelOverrides = new Map<string, Map<string, ModelOverride>>();\n\n\t\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\t\tif (providerConfig.baseUrl || providerConfig.compat) {\n\t\t\t\t\toverrides.set(providerName, {\n\t\t\t\t\t\tbaseUrl: providerConfig.baseUrl,\n\t\t\t\t\t\tcompat: providerConfig.compat,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tthis.storeProviderRequestConfig(providerName, providerConfig);\n\n\t\t\t\tif (providerConfig.modelOverrides) {\n\t\t\t\t\tmodelOverrides.set(providerName, new Map(Object.entries(providerConfig.modelOverrides)));\n\t\t\t\t\tfor (const [modelId, modelOverride] of Object.entries(providerConfig.modelOverrides)) {\n\t\t\t\t\t\tthis.storeModelHeaders(providerName, modelId, modelOverride.headers);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn { models: this.parseModels(config), overrides, modelOverrides, error: undefined };\n\t\t} catch (error) {\n\t\t\tif (error instanceof SyntaxError) {\n\t\t\t\treturn emptyCustomModelsResult(`Failed to parse models.json: ${error.message}\\n\\nFile: ${modelsJsonPath}`);\n\t\t\t}\n\t\t\treturn emptyCustomModelsResult(\n\t\t\t\t`Failed to load models.json: ${error instanceof Error ? error.message : error}\\n\\nFile: ${modelsJsonPath}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate validateConfig(config: ModelsConfig): void {\n\t\tconst builtInProviders = new Set<string>(getProviders());\n\n\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\tconst isBuiltIn = builtInProviders.has(providerName);\n\t\t\tconst hasProviderApi = !!providerConfig.api;\n\t\t\tconst models = providerConfig.models ?? [];\n\t\t\tconst hasModelOverrides =\n\t\t\t\tproviderConfig.modelOverrides && Object.keys(providerConfig.modelOverrides).length > 0;\n\n\t\t\tif (models.length === 0) {\n\t\t\t\t// Override-only config: needs baseUrl, headers, compat, modelOverrides, or some combination.\n\t\t\t\tif (!providerConfig.baseUrl && !providerConfig.headers && !providerConfig.compat && !hasModelOverrides) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Provider ${providerName}: must specify \"baseUrl\", \"headers\", \"compat\", \"modelOverrides\", or \"models\".`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else if (!isBuiltIn) {\n\t\t\t\t// Non-built-in providers with custom models require endpoint + auth.\n\t\t\t\tif (!providerConfig.baseUrl) {\n\t\t\t\t\tthrow new Error(`Provider ${providerName}: \"baseUrl\" is required when defining custom models.`);\n\t\t\t\t}\n\t\t\t\tif (!providerConfig.apiKey) {\n\t\t\t\t\tthrow new Error(`Provider ${providerName}: \"apiKey\" is required when defining custom models.`);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Built-in providers with custom models: baseUrl/apiKey/api are optional,\n\t\t\t// inherited from built-in models. Auth comes from env vars / auth storage.\n\n\t\t\tfor (const modelDef of models) {\n\t\t\t\tconst hasModelApi = !!modelDef.api;\n\n\t\t\t\tif (!hasProviderApi && !hasModelApi && !isBuiltIn) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Provider ${providerName}, model ${modelDef.id}: no \"api\" specified. Set at provider or model level.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t// For built-in providers, api is optional — inherited from built-in models.\n\n\t\t\t\tif (!modelDef.id) throw new Error(`Provider ${providerName}: model missing \"id\"`);\n\t\t\t\t// Validate contextWindow/maxTokens only if provided (they have defaults)\n\t\t\t\tif (modelDef.contextWindow !== undefined && modelDef.contextWindow <= 0)\n\t\t\t\t\tthrow new Error(`Provider ${providerName}, model ${modelDef.id}: invalid contextWindow`);\n\t\t\t\tif (modelDef.maxTokens !== undefined && modelDef.maxTokens <= 0)\n\t\t\t\t\tthrow new Error(`Provider ${providerName}, model ${modelDef.id}: invalid maxTokens`);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate parseModels(config: ModelsConfig): Model<Api>[] {\n\t\tconst models: Model<Api>[] = [];\n\t\tconst builtInProviders = new Set<string>(getProviders());\n\n\t\t// Cache built-in defaults (api, baseUrl) per provider, extracted from first model.\n\t\tconst builtInDefaultsCache = new Map<string, { api: string; baseUrl: string }>();\n\t\tconst getBuiltInDefaults = (providerName: string): { api: string; baseUrl: string } | undefined => {\n\t\t\tif (!builtInProviders.has(providerName)) return undefined;\n\t\t\tif (builtInDefaultsCache.has(providerName)) return builtInDefaultsCache.get(providerName);\n\t\t\tconst builtIn = getModels(providerName as KnownProvider) as Model<Api>[];\n\t\t\tif (builtIn.length === 0) return undefined;\n\t\t\tconst defaults = { api: builtIn[0].api, baseUrl: builtIn[0].baseUrl };\n\t\t\tbuiltInDefaultsCache.set(providerName, defaults);\n\t\t\treturn defaults;\n\t\t};\n\n\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\tconst modelDefs = providerConfig.models ?? [];\n\t\t\tif (modelDefs.length === 0) continue; // Override-only, no custom models\n\n\t\t\tconst builtInDefaults = getBuiltInDefaults(providerName);\n\n\t\t\tfor (const modelDef of modelDefs) {\n\t\t\t\tconst api = modelDef.api ?? providerConfig.api ?? builtInDefaults?.api;\n\t\t\t\tif (!api) continue;\n\n\t\t\t\tconst baseUrl = modelDef.baseUrl ?? providerConfig.baseUrl ?? builtInDefaults?.baseUrl;\n\t\t\t\tif (!baseUrl) continue;\n\n\t\t\t\tconst compat = mergeCompat(providerConfig.compat, modelDef.compat);\n\t\t\t\tthis.storeModelHeaders(providerName, modelDef.id, modelDef.headers);\n\n\t\t\t\tconst defaultCost = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };\n\t\t\t\tmodels.push({\n\t\t\t\t\tid: modelDef.id,\n\t\t\t\t\tname: modelDef.name ?? modelDef.id,\n\t\t\t\t\tapi: api as Api,\n\t\t\t\t\tprovider: providerName,\n\t\t\t\t\tbaseUrl,\n\t\t\t\t\treasoning: modelDef.reasoning ?? false,\n\t\t\t\t\tthinkingLevelMap: modelDef.thinkingLevelMap,\n\t\t\t\t\tinput: (modelDef.input ?? [\"text\"]) as (\"text\" | \"image\")[],\n\t\t\t\t\tcost: modelDef.cost ?? defaultCost,\n\t\t\t\t\tcontextWindow: modelDef.contextWindow ?? 128000,\n\t\t\t\t\tmaxTokens: modelDef.maxTokens ?? 16384,\n\t\t\t\t\theaders: undefined,\n\t\t\t\t\tcompat,\n\t\t\t\t} as Model<Api>);\n\t\t\t}\n\t\t}\n\n\t\treturn models;\n\t}\n\n\t/**\n\t * Get all models (built-in + custom).\n\t * If models.json had errors, returns only built-in models.\n\t */\n\tgetAll(): Model<Api>[] {\n\t\treturn this.models;\n\t}\n\n\t/**\n\t * Get only models that have auth configured.\n\t * This is a fast check that doesn't refresh OAuth tokens.\n\t */\n\tgetAvailable(): Model<Api>[] {\n\t\treturn this.models.filter((m) => this.hasConfiguredAuth(m));\n\t}\n\n\t/**\n\t * Find a model by provider and ID.\n\t */\n\tfind(provider: string, modelId: string): Model<Api> | undefined {\n\t\treturn this.models.find((m) => m.provider === provider && m.id === modelId);\n\t}\n\n\t/**\n\t * Get API key for a model.\n\t */\n\thasConfiguredAuth(model: Model<Api>): boolean {\n\t\tconst providerApiKey = this.providerRequestConfigs.get(model.provider)?.apiKey;\n\t\treturn (\n\t\t\tthis.authStorage.hasAuth(model.provider) ||\n\t\t\t(providerApiKey !== undefined && isConfigValueConfigured(providerApiKey))\n\t\t);\n\t}\n\n\tprivate getModelRequestKey(provider: string, modelId: string): string {\n\t\treturn `${provider}:${modelId}`;\n\t}\n\n\tprivate storeProviderRequestConfig(\n\t\tproviderName: string,\n\t\tconfig: {\n\t\t\tapiKey?: string;\n\t\t\theaders?: Record<string, string>;\n\t\t\tauthHeader?: boolean;\n\t\t},\n\t): void {\n\t\tif (!config.apiKey && !config.headers && !config.authHeader) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.providerRequestConfigs.set(providerName, {\n\t\t\tapiKey: config.apiKey,\n\t\t\theaders: config.headers,\n\t\t\tauthHeader: config.authHeader,\n\t\t});\n\t}\n\n\tprivate storeModelHeaders(providerName: string, modelId: string, headers?: Record<string, string>): void {\n\t\tconst key = this.getModelRequestKey(providerName, modelId);\n\t\tif (!headers || Object.keys(headers).length === 0) {\n\t\t\tthis.modelRequestHeaders.delete(key);\n\t\t\treturn;\n\t\t}\n\t\tthis.modelRequestHeaders.set(key, headers);\n\t}\n\n\t/**\n\t * Get API key and request headers for a model.\n\t */\n\tasync getApiKeyAndHeaders(model: Model<Api>): Promise<ResolvedRequestAuth> {\n\t\ttry {\n\t\t\tconst providerConfig = this.providerRequestConfigs.get(model.provider);\n\t\t\tconst apiKeyFromAuthStorage = await this.authStorage.getApiKey(model.provider, { includeFallback: false });\n\t\t\tconst apiKey =\n\t\t\t\tapiKeyFromAuthStorage ??\n\t\t\t\t(providerConfig?.apiKey\n\t\t\t\t\t? resolveConfigValueOrThrow(providerConfig.apiKey, `API key for provider \"${model.provider}\"`)\n\t\t\t\t\t: undefined);\n\n\t\t\tconst providerHeaders = resolveHeadersOrThrow(providerConfig?.headers, `provider \"${model.provider}\"`);\n\t\t\tconst modelHeaders = resolveHeadersOrThrow(\n\t\t\t\tthis.modelRequestHeaders.get(this.getModelRequestKey(model.provider, model.id)),\n\t\t\t\t`model \"${model.provider}/${model.id}\"`,\n\t\t\t);\n\n\t\t\tlet headers =\n\t\t\t\tmodel.headers || providerHeaders || modelHeaders\n\t\t\t\t\t? { ...model.headers, ...providerHeaders, ...modelHeaders }\n\t\t\t\t\t: undefined;\n\n\t\t\tif (providerConfig?.authHeader) {\n\t\t\t\tif (!apiKey) {\n\t\t\t\t\treturn { ok: false, error: `No API key found for \"${model.provider}\"` };\n\t\t\t\t}\n\t\t\t\theaders = { ...headers, Authorization: `Bearer ${apiKey}` };\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tok: true,\n\t\t\t\tapiKey,\n\t\t\t\theaders: headers && Object.keys(headers).length > 0 ? headers : undefined,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Return auth status for a provider, including request auth configured in models.json.\n\t * This intentionally does not execute command-backed config values.\n\t */\n\tgetProviderAuthStatus(provider: string): AuthStatus {\n\t\tconst authStatus = this.authStorage.getAuthStatus(provider);\n\t\tif (authStatus.source) {\n\t\t\treturn authStatus;\n\t\t}\n\n\t\tconst providerApiKey = this.providerRequestConfigs.get(provider)?.apiKey;\n\t\tif (!providerApiKey) {\n\t\t\treturn authStatus;\n\t\t}\n\n\t\tif (isCommandConfigValue(providerApiKey)) {\n\t\t\treturn { configured: true, source: \"models_json_command\" };\n\t\t}\n\n\t\tconst envVarNames = getConfigValueEnvVarNames(providerApiKey);\n\t\tif (envVarNames.length > 0) {\n\t\t\treturn isConfigValueConfigured(providerApiKey)\n\t\t\t\t? { configured: true, source: \"environment\", label: envVarNames.join(\", \") }\n\t\t\t\t: { configured: false };\n\t\t}\n\n\t\treturn { configured: true, source: \"models_json_key\" };\n\t}\n\n\t/**\n\t * Get display name for a provider.\n\t */\n\tgetProviderDisplayName(provider: string): string {\n\t\tconst registeredProvider = this.registeredProviders.get(provider);\n\t\tconst oauthProvider = this.authStorage.getOAuthProviders().find((p) => p.id === provider);\n\n\t\treturn (\n\t\t\tregisteredProvider?.name ??\n\t\t\tregisteredProvider?.oauth?.name ??\n\t\t\toauthProvider?.name ??\n\t\t\tBUILT_IN_PROVIDER_DISPLAY_NAMES[provider] ??\n\t\t\tprovider\n\t\t);\n\t}\n\n\t/**\n\t * Get API key for a provider.\n\t */\n\tasync getApiKeyForProvider(provider: string): Promise<string | undefined> {\n\t\tconst apiKey = await this.authStorage.getApiKey(provider, { includeFallback: false });\n\t\tif (apiKey !== undefined) {\n\t\t\treturn apiKey;\n\t\t}\n\n\t\tconst providerApiKey = this.providerRequestConfigs.get(provider)?.apiKey;\n\t\treturn providerApiKey ? resolveConfigValueUncached(providerApiKey) : undefined;\n\t}\n\n\t/**\n\t * Check if a model is using OAuth credentials (subscription).\n\t */\n\tisUsingOAuth(model: Model<Api>): boolean {\n\t\tconst cred = this.authStorage.get(model.provider);\n\t\treturn cred?.type === \"oauth\";\n\t}\n\n\t/**\n\t * Register a provider dynamically (from extensions).\n\t *\n\t * If provider has models: replaces all existing models for this provider.\n\t * If provider has only baseUrl/headers: overrides existing models' URLs.\n\t * If provider has oauth: registers OAuth provider for /login support.\n\t */\n\tregisterProvider(providerName: string, config: ProviderConfigInput): void {\n\t\tconst migratedConfig = migrateLegacyRegisterProviderConfigValues(providerName, config);\n\t\tthis.validateProviderConfig(providerName, migratedConfig);\n\t\tthis.applyProviderConfig(providerName, migratedConfig);\n\t\tthis.upsertRegisteredProvider(providerName, migratedConfig);\n\t}\n\n\t/**\n\t * Unregister a previously registered provider.\n\t *\n\t * Removes the provider from the registry and reloads models from disk so that\n\t * built-in models overridden by this provider are restored to their original state.\n\t * Also resets dynamic OAuth and API stream registrations before reapplying\n\t * remaining dynamic providers.\n\t * Has no effect if the provider was never registered.\n\t */\n\tunregisterProvider(providerName: string): void {\n\t\tif (!this.registeredProviders.has(providerName)) return;\n\t\tthis.registeredProviders.delete(providerName);\n\t\tthis.refresh();\n\t}\n\n\t/**\n\t * Upsert a provider config into registeredProviders.\n\t * If the provider is already registered, defined values in the incoming config\n\t * override existing ones; undefined values are preserved from the stored config.\n\t * If the provider is not registered, the incoming config is stored as-is.\n\t */\n\tprivate upsertRegisteredProvider(providerName: string, config: ProviderConfigInput): void {\n\t\tconst existing = this.registeredProviders.get(providerName);\n\t\tif (!existing) {\n\t\t\tthis.registeredProviders.set(providerName, config);\n\t\t\treturn;\n\t\t}\n\t\tfor (const k of Object.keys(config) as (keyof ProviderConfigInput)[]) {\n\t\t\tif (config[k] !== undefined) {\n\t\t\t\t(existing as Record<string, unknown>)[k] = config[k];\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate validateProviderConfig(providerName: string, config: ProviderConfigInput): void {\n\t\tif (config.streamSimple && !config.api) {\n\t\t\tthrow new Error(`Provider ${providerName}: \"api\" is required when registering streamSimple.`);\n\t\t}\n\n\t\tif (!config.models || config.models.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!config.baseUrl) {\n\t\t\tthrow new Error(`Provider ${providerName}: \"baseUrl\" is required when defining models.`);\n\t\t}\n\t\tif (!config.apiKey && !config.oauth) {\n\t\t\tthrow new Error(`Provider ${providerName}: \"apiKey\" or \"oauth\" is required when defining models.`);\n\t\t}\n\n\t\tfor (const modelDef of config.models) {\n\t\t\tconst api = modelDef.api || config.api;\n\t\t\tif (!api) {\n\t\t\t\tthrow new Error(`Provider ${providerName}, model ${modelDef.id}: no \"api\" specified.`);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate applyProviderConfig(providerName: string, config: ProviderConfigInput): void {\n\t\t// Register OAuth provider if provided\n\t\tif (config.oauth) {\n\t\t\t// Ensure the OAuth provider ID matches the provider name\n\t\t\tconst oauthProvider: OAuthProviderInterface = {\n\t\t\t\t...config.oauth,\n\t\t\t\tid: providerName,\n\t\t\t};\n\t\t\tregisterOAuthProvider(oauthProvider);\n\t\t}\n\n\t\tif (config.streamSimple) {\n\t\t\tconst streamSimple = config.streamSimple;\n\t\t\tregisterApiProvider(\n\t\t\t\t{\n\t\t\t\t\tapi: config.api!,\n\t\t\t\t\tstream: (model, context, options) => streamSimple(model, context, options as SimpleStreamOptions),\n\t\t\t\t\tstreamSimple,\n\t\t\t\t},\n\t\t\t\t`provider:${providerName}`,\n\t\t\t);\n\t\t}\n\n\t\tthis.storeProviderRequestConfig(providerName, config);\n\n\t\tif (config.models && config.models.length > 0) {\n\t\t\t// Full replacement: remove existing models for this provider\n\t\t\tthis.models = this.models.filter((m) => m.provider !== providerName);\n\n\t\t\t// Parse and add new models\n\t\t\tfor (const modelDef of config.models) {\n\t\t\t\tconst api = modelDef.api || config.api;\n\t\t\t\tthis.storeModelHeaders(providerName, modelDef.id, modelDef.headers);\n\n\t\t\t\tthis.models.push({\n\t\t\t\t\tid: modelDef.id,\n\t\t\t\t\tname: modelDef.name,\n\t\t\t\t\tapi: api as Api,\n\t\t\t\t\tprovider: providerName,\n\t\t\t\t\tbaseUrl: modelDef.baseUrl ?? config.baseUrl!,\n\t\t\t\t\treasoning: modelDef.reasoning,\n\t\t\t\t\tthinkingLevelMap: modelDef.thinkingLevelMap,\n\t\t\t\t\tinput: modelDef.input as (\"text\" | \"image\")[],\n\t\t\t\t\tcost: modelDef.cost,\n\t\t\t\t\tcontextWindow: modelDef.contextWindow,\n\t\t\t\t\tmaxTokens: modelDef.maxTokens,\n\t\t\t\t\theaders: undefined,\n\t\t\t\t\tcompat: modelDef.compat,\n\t\t\t\t} as Model<Api>);\n\t\t\t}\n\n\t\t\t// Apply OAuth modifyModels if credentials exist (e.g., to update baseUrl)\n\t\t\tif (config.oauth?.modifyModels) {\n\t\t\t\tconst cred = this.authStorage.get(providerName);\n\t\t\t\tif (cred?.type === \"oauth\") {\n\t\t\t\t\tthis.models = config.oauth.modifyModels(this.models, cred);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (config.baseUrl || config.headers) {\n\t\t\t// Override-only: update baseUrl for existing models. Request headers are resolved per request.\n\t\t\tthis.models = this.models.map((m) => {\n\t\t\t\tif (m.provider !== providerName) return m;\n\t\t\t\treturn {\n\t\t\t\t\t...m,\n\t\t\t\t\tbaseUrl: config.baseUrl ?? m.baseUrl,\n\t\t\t\t};\n\t\t\t});\n\t\t}\n\t}\n}\n\n/**\n * Input type for registerProvider API.\n */\nexport interface ProviderConfigInput {\n\tname?: string;\n\tbaseUrl?: string;\n\tapiKey?: string;\n\tapi?: Api;\n\tstreamSimple?: (model: Model<Api>, context: Context, options?: SimpleStreamOptions) => AssistantMessageEventStream;\n\theaders?: Record<string, string>;\n\tauthHeader?: boolean;\n\t/** OAuth provider for /login support */\n\toauth?: Omit<OAuthProviderInterface, \"id\">;\n\tmodels?: Array<{\n\t\tid: string;\n\t\tname: string;\n\t\tapi?: Api;\n\t\tbaseUrl?: string;\n\t\treasoning: boolean;\n\t\tthinkingLevelMap?: Model<Api>[\"thinkingLevelMap\"];\n\t\tinput: (\"text\" | \"image\")[];\n\t\tcost: { input: number; output: number; cacheRead: number; cacheWrite: number };\n\t\tcontextWindow: number;\n\t\tmaxTokens: number;\n\t\theaders?: Record<string, string>;\n\t\tcompat?: Model<Api>[\"compat\"];\n\t}>;\n}\n"]}
@@ -61,6 +61,7 @@ const ThinkingLevelMapSchema = Type.Object({
61
61
  medium: Type.Optional(ThinkingLevelMapValueSchema),
62
62
  high: Type.Optional(ThinkingLevelMapValueSchema),
63
63
  xhigh: Type.Optional(ThinkingLevelMapValueSchema),
64
+ max: Type.Optional(ThinkingLevelMapValueSchema),
64
65
  });
65
66
  const OpenAICompletionsCompatSchema = Type.Object({
66
67
  supportsStore: Type.Optional(Type.Boolean()),