@calliopelabs/cli 3.1.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -7
- package/dist/acp.d.ts +1 -4
- package/dist/acp.d.ts.map +1 -1
- package/dist/acp.js +118 -217
- package/dist/acp.js.map +1 -1
- package/dist/approvals/commands.d.ts +35 -0
- package/dist/approvals/commands.d.ts.map +1 -0
- package/dist/approvals/commands.js +51 -0
- package/dist/approvals/commands.js.map +1 -0
- package/dist/approvals/index.d.ts +6 -0
- package/dist/approvals/index.d.ts.map +1 -0
- package/dist/approvals/index.js +6 -0
- package/dist/approvals/index.js.map +1 -0
- package/dist/approvals/queue.d.ts +18 -0
- package/dist/approvals/queue.d.ts.map +1 -0
- package/dist/approvals/queue.js +46 -0
- package/dist/approvals/queue.js.map +1 -0
- package/dist/approvals/request.d.ts +13 -0
- package/dist/approvals/request.d.ts.map +1 -0
- package/dist/approvals/request.js +102 -0
- package/dist/approvals/request.js.map +1 -0
- package/dist/approvals/store.d.ts +24 -0
- package/dist/approvals/store.d.ts.map +1 -0
- package/dist/approvals/store.js +229 -0
- package/dist/approvals/store.js.map +1 -0
- package/dist/approvals/types.d.ts +27 -0
- package/dist/approvals/types.d.ts.map +1 -0
- package/dist/approvals/types.js +4 -0
- package/dist/approvals/types.js.map +1 -0
- package/dist/auto-compressor.d.ts +3 -2
- package/dist/auto-compressor.d.ts.map +1 -1
- package/dist/auto-compressor.js +9 -9
- package/dist/auto-compressor.js.map +1 -1
- package/dist/bin.d.ts.map +1 -1
- package/dist/bin.js +125 -22
- package/dist/bin.js.map +1 -1
- package/dist/brain/access.d.ts +65 -0
- package/dist/brain/access.d.ts.map +1 -0
- package/dist/brain/access.js +216 -0
- package/dist/brain/access.js.map +1 -0
- package/dist/brain/actions.d.ts +120 -0
- package/dist/brain/actions.d.ts.map +1 -0
- package/dist/brain/actions.js +270 -0
- package/dist/brain/actions.js.map +1 -0
- package/dist/brain/cli.d.ts +17 -0
- package/dist/brain/cli.d.ts.map +1 -0
- package/dist/brain/cli.js +206 -0
- package/dist/brain/cli.js.map +1 -0
- package/dist/brain/index.d.ts +16 -0
- package/dist/brain/index.d.ts.map +1 -0
- package/dist/brain/index.js +16 -0
- package/dist/brain/index.js.map +1 -0
- package/dist/brain/journal.d.ts +17 -0
- package/dist/brain/journal.d.ts.map +1 -0
- package/dist/brain/journal.js +189 -0
- package/dist/brain/journal.js.map +1 -0
- package/dist/brain/kg.d.ts +23 -0
- package/dist/brain/kg.d.ts.map +1 -0
- package/dist/brain/kg.js +36 -0
- package/dist/brain/kg.js.map +1 -0
- package/dist/brain/presentation.d.ts +3 -0
- package/dist/brain/presentation.d.ts.map +1 -0
- package/dist/brain/presentation.js +48 -0
- package/dist/brain/presentation.js.map +1 -0
- package/dist/brain/queries.d.ts +179 -0
- package/dist/brain/queries.d.ts.map +1 -0
- package/dist/brain/queries.js +210 -0
- package/dist/brain/queries.js.map +1 -0
- package/dist/brain/run-ingest.d.ts +29 -0
- package/dist/brain/run-ingest.d.ts.map +1 -0
- package/dist/brain/run-ingest.js +200 -0
- package/dist/brain/run-ingest.js.map +1 -0
- package/dist/brain/sqlite.d.ts +19 -0
- package/dist/brain/sqlite.d.ts.map +1 -0
- package/dist/brain/sqlite.js +252 -0
- package/dist/brain/sqlite.js.map +1 -0
- package/dist/brain/store.d.ts +31 -0
- package/dist/brain/store.d.ts.map +1 -0
- package/dist/brain/store.js +324 -0
- package/dist/brain/store.js.map +1 -0
- package/dist/brain/tool-query.d.ts +6 -0
- package/dist/brain/tool-query.d.ts.map +1 -0
- package/dist/brain/tool-query.js +42 -0
- package/dist/brain/tool-query.js.map +1 -0
- package/dist/brain/tools.d.ts +13 -0
- package/dist/brain/tools.d.ts.map +1 -0
- package/dist/brain/tools.js +20 -0
- package/dist/brain/tools.js.map +1 -0
- package/dist/brain/transfer.d.ts +57 -0
- package/dist/brain/transfer.d.ts.map +1 -0
- package/dist/brain/transfer.js +266 -0
- package/dist/brain/transfer.js.map +1 -0
- package/dist/brain/types.d.ts +145 -0
- package/dist/brain/types.d.ts.map +1 -0
- package/dist/brain/types.js +38 -0
- package/dist/brain/types.js.map +1 -0
- package/dist/brain/validation.d.ts +15 -0
- package/dist/brain/validation.d.ts.map +1 -0
- package/dist/brain/validation.js +163 -0
- package/dist/brain/validation.js.map +1 -0
- package/dist/budget.d.ts +5 -4
- package/dist/budget.d.ts.map +1 -1
- package/dist/budget.js +16 -38
- package/dist/budget.js.map +1 -1
- package/dist/cancellation.d.ts +8 -0
- package/dist/cancellation.d.ts.map +1 -0
- package/dist/cancellation.js +42 -0
- package/dist/cancellation.js.map +1 -0
- package/dist/checkpoint.d.ts +2 -2
- package/dist/checkpoint.d.ts.map +1 -1
- package/dist/checkpoint.js +5 -5
- package/dist/checkpoint.js.map +1 -1
- package/dist/config.d.ts +13 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +32 -8
- package/dist/config.js.map +1 -1
- package/dist/doctor.d.ts +30 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +124 -0
- package/dist/doctor.js.map +1 -0
- package/dist/errors.d.ts +15 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +33 -9
- package/dist/errors.js.map +1 -1
- package/dist/execution/attribution.d.ts +17 -0
- package/dist/execution/attribution.d.ts.map +1 -0
- package/dist/execution/attribution.js +21 -0
- package/dist/execution/attribution.js.map +1 -0
- package/dist/execution/authority.d.ts +22 -0
- package/dist/execution/authority.d.ts.map +1 -0
- package/dist/execution/authority.js +134 -0
- package/dist/execution/authority.js.map +1 -0
- package/dist/execution/billing.d.ts +100 -0
- package/dist/execution/billing.d.ts.map +1 -0
- package/dist/execution/billing.js +166 -0
- package/dist/execution/billing.js.map +1 -0
- package/dist/execution/child-grants.d.ts +9 -0
- package/dist/execution/child-grants.d.ts.map +1 -0
- package/dist/execution/child-grants.js +55 -0
- package/dist/execution/child-grants.js.map +1 -0
- package/dist/execution/files.d.ts +6 -0
- package/dist/execution/files.d.ts.map +1 -0
- package/dist/execution/files.js +159 -0
- package/dist/execution/files.js.map +1 -0
- package/dist/execution/guard.d.ts +50 -0
- package/dist/execution/guard.d.ts.map +1 -0
- package/dist/execution/guard.js +158 -0
- package/dist/execution/guard.js.map +1 -0
- package/dist/execution/index.d.ts +12 -0
- package/dist/execution/index.d.ts.map +1 -0
- package/dist/execution/index.js +12 -0
- package/dist/execution/index.js.map +1 -0
- package/dist/execution/ledger.d.ts +23 -0
- package/dist/execution/ledger.d.ts.map +1 -0
- package/dist/execution/ledger.js +379 -0
- package/dist/execution/ledger.js.map +1 -0
- package/dist/execution/project-spend.d.ts +45 -0
- package/dist/execution/project-spend.d.ts.map +1 -0
- package/dist/execution/project-spend.js +274 -0
- package/dist/execution/project-spend.js.map +1 -0
- package/dist/execution/quote.d.ts +19 -0
- package/dist/execution/quote.d.ts.map +1 -0
- package/dist/execution/quote.js +116 -0
- package/dist/execution/quote.js.map +1 -0
- package/dist/execution/types.d.ts +113 -0
- package/dist/execution/types.d.ts.map +1 -0
- package/dist/execution/types.js +9 -0
- package/dist/execution/types.js.map +1 -0
- package/dist/execution/writer-recovery.d.ts +3 -0
- package/dist/execution/writer-recovery.d.ts.map +1 -0
- package/dist/execution/writer-recovery.js +85 -0
- package/dist/execution/writer-recovery.js.map +1 -0
- package/dist/goals/accounting.d.ts +69 -0
- package/dist/goals/accounting.d.ts.map +1 -0
- package/dist/goals/accounting.js +100 -0
- package/dist/goals/accounting.js.map +1 -0
- package/dist/goals/actions.d.ts +33 -0
- package/dist/goals/actions.d.ts.map +1 -0
- package/dist/goals/actions.js +261 -0
- package/dist/goals/actions.js.map +1 -0
- package/dist/goals/authority.d.ts +9 -0
- package/dist/goals/authority.d.ts.map +1 -0
- package/dist/goals/authority.js +47 -0
- package/dist/goals/authority.js.map +1 -0
- package/dist/goals/cli.d.ts +10 -0
- package/dist/goals/cli.d.ts.map +1 -0
- package/dist/goals/cli.js +169 -0
- package/dist/goals/cli.js.map +1 -0
- package/dist/goals/contracts.d.ts +18 -0
- package/dist/goals/contracts.d.ts.map +1 -0
- package/dist/goals/contracts.js +127 -0
- package/dist/goals/contracts.js.map +1 -0
- package/dist/goals/index.d.ts +17 -0
- package/dist/goals/index.d.ts.map +1 -0
- package/dist/goals/index.js +16 -0
- package/dist/goals/index.js.map +1 -0
- package/dist/goals/journal.d.ts +5 -0
- package/dist/goals/journal.d.ts.map +1 -0
- package/dist/goals/journal.js +142 -0
- package/dist/goals/journal.js.map +1 -0
- package/dist/goals/metrics.d.ts +53 -0
- package/dist/goals/metrics.d.ts.map +1 -0
- package/dist/goals/metrics.js +141 -0
- package/dist/goals/metrics.js.map +1 -0
- package/dist/goals/repair.d.ts +10 -0
- package/dist/goals/repair.d.ts.map +1 -0
- package/dist/goals/repair.js +50 -0
- package/dist/goals/repair.js.map +1 -0
- package/dist/goals/routing.d.ts +18 -0
- package/dist/goals/routing.d.ts.map +1 -0
- package/dist/goals/routing.js +60 -0
- package/dist/goals/routing.js.map +1 -0
- package/dist/goals/store.d.ts +30 -0
- package/dist/goals/store.d.ts.map +1 -0
- package/dist/goals/store.js +314 -0
- package/dist/goals/store.js.map +1 -0
- package/dist/goals/supervised-cli.d.ts +5 -0
- package/dist/goals/supervised-cli.d.ts.map +1 -0
- package/dist/goals/supervised-cli.js +44 -0
- package/dist/goals/supervised-cli.js.map +1 -0
- package/dist/goals/supervised.d.ts +8 -0
- package/dist/goals/supervised.d.ts.map +1 -0
- package/dist/goals/supervised.js +65 -0
- package/dist/goals/supervised.js.map +1 -0
- package/dist/goals/team.d.ts +8 -0
- package/dist/goals/team.d.ts.map +1 -0
- package/dist/goals/team.js +64 -0
- package/dist/goals/team.js.map +1 -0
- package/dist/goals/types.d.ts +174 -0
- package/dist/goals/types.d.ts.map +1 -0
- package/dist/goals/types.js +2 -0
- package/dist/goals/types.js.map +1 -0
- package/dist/goals/validation.d.ts +17 -0
- package/dist/goals/validation.d.ts.map +1 -0
- package/dist/goals/validation.js +172 -0
- package/dist/goals/validation.js.map +1 -0
- package/dist/headless.d.ts +1 -0
- package/dist/headless.d.ts.map +1 -1
- package/dist/headless.js +98 -275
- package/dist/headless.js.map +1 -1
- package/dist/health/index.d.ts +5 -0
- package/dist/health/index.d.ts.map +1 -0
- package/dist/health/index.js +5 -0
- package/dist/health/index.js.map +1 -0
- package/dist/health/store.d.ts +24 -0
- package/dist/health/store.d.ts.map +1 -0
- package/dist/health/store.js +190 -0
- package/dist/health/store.js.map +1 -0
- package/dist/health/summary.d.ts +10 -0
- package/dist/health/summary.d.ts.map +1 -0
- package/dist/health/summary.js +95 -0
- package/dist/health/summary.js.map +1 -0
- package/dist/health/target.d.ts +3 -0
- package/dist/health/target.d.ts.map +1 -0
- package/dist/health/target.js +53 -0
- package/dist/health/target.js.map +1 -0
- package/dist/health/types.d.ts +72 -0
- package/dist/health/types.d.ts.map +1 -0
- package/dist/health/types.js +2 -0
- package/dist/health/types.js.map +1 -0
- package/dist/hooks.d.ts +7 -2
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +35 -17
- package/dist/hooks.js.map +1 -1
- package/dist/improvement/actions.d.ts +27 -0
- package/dist/improvement/actions.d.ts.map +1 -0
- package/dist/improvement/actions.js +116 -0
- package/dist/improvement/actions.js.map +1 -0
- package/dist/improvement/cli.d.ts +9 -0
- package/dist/improvement/cli.d.ts.map +1 -0
- package/dist/improvement/cli.js +58 -0
- package/dist/improvement/cli.js.map +1 -0
- package/dist/improvement/feedback.d.ts +30 -0
- package/dist/improvement/feedback.d.ts.map +1 -0
- package/dist/improvement/feedback.js +7 -0
- package/dist/improvement/feedback.js.map +1 -0
- package/dist/improvement/index.d.ts +7 -0
- package/dist/improvement/index.d.ts.map +1 -0
- package/dist/improvement/index.js +7 -0
- package/dist/improvement/index.js.map +1 -0
- package/dist/improvement/metrics.d.ts +4 -0
- package/dist/improvement/metrics.d.ts.map +1 -0
- package/dist/improvement/metrics.js +38 -0
- package/dist/improvement/metrics.js.map +1 -0
- package/dist/improvement/projection.d.ts +7 -0
- package/dist/improvement/projection.d.ts.map +1 -0
- package/dist/improvement/projection.js +135 -0
- package/dist/improvement/projection.js.map +1 -0
- package/dist/improvement/types.d.ts +115 -0
- package/dist/improvement/types.d.ts.map +1 -0
- package/dist/improvement/types.js +2 -0
- package/dist/improvement/types.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/instructions.d.ts +10 -0
- package/dist/instructions.d.ts.map +1 -0
- package/dist/instructions.js +93 -0
- package/dist/instructions.js.map +1 -0
- package/dist/isolation/contracts.d.ts +42 -0
- package/dist/isolation/contracts.d.ts.map +1 -0
- package/dist/isolation/contracts.js +33 -0
- package/dist/isolation/contracts.js.map +1 -0
- package/dist/isolation/coordinator.d.ts +10 -0
- package/dist/isolation/coordinator.d.ts.map +1 -0
- package/dist/isolation/coordinator.js +79 -0
- package/dist/isolation/coordinator.js.map +1 -0
- package/dist/isolation/index.d.ts +5 -0
- package/dist/isolation/index.d.ts.map +1 -0
- package/dist/isolation/index.js +5 -0
- package/dist/isolation/index.js.map +1 -0
- package/dist/isolation/process.d.ts +11 -0
- package/dist/isolation/process.d.ts.map +1 -0
- package/dist/isolation/process.js +131 -0
- package/dist/isolation/process.js.map +1 -0
- package/dist/isolation/worktree.d.ts +25 -0
- package/dist/isolation/worktree.d.ts.map +1 -0
- package/dist/isolation/worktree.js +282 -0
- package/dist/isolation/worktree.js.map +1 -0
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +5 -1
- package/dist/memory.js.map +1 -1
- package/dist/model-detection.d.ts +14 -18
- package/dist/model-detection.d.ts.map +1 -1
- package/dist/model-detection.js +287 -149
- package/dist/model-detection.js.map +1 -1
- package/dist/models/index.d.ts +3 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/index.js +3 -0
- package/dist/models/index.js.map +1 -0
- package/dist/models/metadata.d.ts +43 -0
- package/dist/models/metadata.d.ts.map +1 -0
- package/dist/models/metadata.js +72 -0
- package/dist/models/metadata.js.map +1 -0
- package/dist/models/openrouter.d.ts +6 -0
- package/dist/models/openrouter.d.ts.map +1 -0
- package/dist/models/openrouter.js +38 -0
- package/dist/models/openrouter.js.map +1 -0
- package/dist/orchestration/accounting.d.ts +35 -0
- package/dist/orchestration/accounting.d.ts.map +1 -0
- package/dist/orchestration/accounting.js +27 -0
- package/dist/orchestration/accounting.js.map +1 -0
- package/dist/orchestration/actions.d.ts +23 -0
- package/dist/orchestration/actions.d.ts.map +1 -0
- package/dist/orchestration/actions.js +65 -0
- package/dist/orchestration/actions.js.map +1 -0
- package/dist/orchestration/cli.d.ts +28 -0
- package/dist/orchestration/cli.d.ts.map +1 -0
- package/dist/orchestration/cli.js +178 -0
- package/dist/orchestration/cli.js.map +1 -0
- package/dist/orchestration/coordinator-actions.d.ts +15 -0
- package/dist/orchestration/coordinator-actions.d.ts.map +1 -0
- package/dist/orchestration/coordinator-actions.js +79 -0
- package/dist/orchestration/coordinator-actions.js.map +1 -0
- package/dist/orchestration/coordinator-types.d.ts +193 -0
- package/dist/orchestration/coordinator-types.d.ts.map +1 -0
- package/dist/orchestration/coordinator-types.js +2 -0
- package/dist/orchestration/coordinator-types.js.map +1 -0
- package/dist/orchestration/coordinator.d.ts +32 -0
- package/dist/orchestration/coordinator.d.ts.map +1 -0
- package/dist/orchestration/coordinator.js +405 -0
- package/dist/orchestration/coordinator.js.map +1 -0
- package/dist/orchestration/execution-cli.d.ts +11 -0
- package/dist/orchestration/execution-cli.d.ts.map +1 -0
- package/dist/orchestration/execution-cli.js +183 -0
- package/dist/orchestration/execution-cli.js.map +1 -0
- package/dist/orchestration/execution-journal.d.ts +15 -0
- package/dist/orchestration/execution-journal.d.ts.map +1 -0
- package/dist/orchestration/execution-journal.js +477 -0
- package/dist/orchestration/execution-journal.js.map +1 -0
- package/dist/orchestration/execution-store.d.ts +39 -0
- package/dist/orchestration/execution-store.d.ts.map +1 -0
- package/dist/orchestration/execution-store.js +325 -0
- package/dist/orchestration/execution-store.js.map +1 -0
- package/dist/orchestration/execution.d.ts +8 -0
- package/dist/orchestration/execution.d.ts.map +1 -0
- package/dist/orchestration/execution.js +47 -0
- package/dist/orchestration/execution.js.map +1 -0
- package/dist/orchestration/index.d.ts +20 -0
- package/dist/orchestration/index.d.ts.map +1 -0
- package/dist/orchestration/index.js +17 -0
- package/dist/orchestration/index.js.map +1 -0
- package/dist/orchestration/progress.d.ts +19 -0
- package/dist/orchestration/progress.d.ts.map +1 -0
- package/dist/orchestration/progress.js +20 -0
- package/dist/orchestration/progress.js.map +1 -0
- package/dist/orchestration/recovery.d.ts +4 -0
- package/dist/orchestration/recovery.d.ts.map +1 -0
- package/dist/orchestration/recovery.js +121 -0
- package/dist/orchestration/recovery.js.map +1 -0
- package/dist/orchestration/request-accounting.d.ts +35 -0
- package/dist/orchestration/request-accounting.d.ts.map +1 -0
- package/dist/orchestration/request-accounting.js +71 -0
- package/dist/orchestration/request-accounting.js.map +1 -0
- package/dist/orchestration/routing.d.ts +20 -0
- package/dist/orchestration/routing.d.ts.map +1 -0
- package/dist/orchestration/routing.js +38 -0
- package/dist/orchestration/routing.js.map +1 -0
- package/dist/orchestration/store.d.ts +26 -0
- package/dist/orchestration/store.d.ts.map +1 -0
- package/dist/orchestration/store.js +381 -0
- package/dist/orchestration/store.js.map +1 -0
- package/dist/orchestration/types.d.ts +201 -0
- package/dist/orchestration/types.d.ts.map +1 -0
- package/dist/orchestration/types.js +11 -0
- package/dist/orchestration/types.js.map +1 -0
- package/dist/orchestration/validation.d.ts +29 -0
- package/dist/orchestration/validation.d.ts.map +1 -0
- package/dist/orchestration/validation.js +440 -0
- package/dist/orchestration/validation.js.map +1 -0
- package/dist/orchestration/verification.d.ts +30 -0
- package/dist/orchestration/verification.d.ts.map +1 -0
- package/dist/orchestration/verification.js +204 -0
- package/dist/orchestration/verification.js.map +1 -0
- package/dist/orchestration/worker-context.d.ts +33 -0
- package/dist/orchestration/worker-context.d.ts.map +1 -0
- package/dist/orchestration/worker-context.js +31 -0
- package/dist/orchestration/worker-context.js.map +1 -0
- package/dist/policy.d.ts +1 -0
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +25 -5
- package/dist/policy.js.map +1 -1
- package/dist/preferences/controls.d.ts +21 -0
- package/dist/preferences/controls.d.ts.map +1 -0
- package/dist/preferences/controls.js +36 -0
- package/dist/preferences/controls.js.map +1 -0
- package/dist/preferences/flags.d.ts +8 -0
- package/dist/preferences/flags.d.ts.map +1 -0
- package/dist/preferences/flags.js +27 -0
- package/dist/preferences/flags.js.map +1 -0
- package/dist/preferences/index.d.ts +9 -0
- package/dist/preferences/index.d.ts.map +1 -0
- package/dist/preferences/index.js +9 -0
- package/dist/preferences/index.js.map +1 -0
- package/dist/preferences/once.d.ts +8 -0
- package/dist/preferences/once.d.ts.map +1 -0
- package/dist/preferences/once.js +28 -0
- package/dist/preferences/once.js.map +1 -0
- package/dist/preferences/resolve.d.ts +14 -0
- package/dist/preferences/resolve.d.ts.map +1 -0
- package/dist/preferences/resolve.js +58 -0
- package/dist/preferences/resolve.js.map +1 -0
- package/dist/preferences/store.d.ts +19 -0
- package/dist/preferences/store.d.ts.map +1 -0
- package/dist/preferences/store.js +147 -0
- package/dist/preferences/store.js.map +1 -0
- package/dist/preferences/submission.d.ts +16 -0
- package/dist/preferences/submission.d.ts.map +1 -0
- package/dist/preferences/submission.js +29 -0
- package/dist/preferences/submission.js.map +1 -0
- package/dist/preferences/types.d.ts +23 -0
- package/dist/preferences/types.d.ts.map +1 -0
- package/dist/preferences/types.js +2 -0
- package/dist/preferences/types.js.map +1 -0
- package/dist/preferences/validate.d.ts +3 -0
- package/dist/preferences/validate.d.ts.map +1 -0
- package/dist/preferences/validate.js +15 -0
- package/dist/preferences/validate.js.map +1 -0
- package/dist/process-cancellation.d.ts +6 -0
- package/dist/process-cancellation.d.ts.map +1 -0
- package/dist/process-cancellation.js +39 -0
- package/dist/process-cancellation.js.map +1 -0
- package/dist/providers/anthropic.d.ts +7 -2
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +72 -41
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/bedrock.d.ts +1 -1
- package/dist/providers/bedrock.d.ts.map +1 -1
- package/dist/providers/bedrock.js +39 -23
- package/dist/providers/bedrock.js.map +1 -1
- package/dist/providers/compat.d.ts +4 -3
- package/dist/providers/compat.d.ts.map +1 -1
- package/dist/providers/compat.js +49 -31
- package/dist/providers/compat.js.map +1 -1
- package/dist/providers/deepseek-reasoning.d.ts +64 -0
- package/dist/providers/deepseek-reasoning.d.ts.map +1 -0
- package/dist/providers/deepseek-reasoning.js +28 -0
- package/dist/providers/deepseek-reasoning.js.map +1 -0
- package/dist/providers/google.d.ts +4 -3
- package/dist/providers/google.d.ts.map +1 -1
- package/dist/providers/google.js +128 -19
- package/dist/providers/google.js.map +1 -1
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +216 -36
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/ollama.d.ts.map +1 -1
- package/dist/providers/ollama.js +79 -43
- package/dist/providers/ollama.js.map +1 -1
- package/dist/providers/openai.d.ts +2 -2
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +50 -46
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/openrouter-bounds.d.ts +22 -0
- package/dist/providers/openrouter-bounds.d.ts.map +1 -0
- package/dist/providers/openrouter-bounds.js +16 -0
- package/dist/providers/openrouter-bounds.js.map +1 -0
- package/dist/providers/stream-attempt.d.ts +29 -0
- package/dist/providers/stream-attempt.d.ts.map +1 -0
- package/dist/providers/stream-attempt.js +63 -0
- package/dist/providers/stream-attempt.js.map +1 -0
- package/dist/providers/types.d.ts +40 -4
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/types.js +19 -0
- package/dist/providers/types.js.map +1 -1
- package/dist/replay.d.ts.map +1 -1
- package/dist/replay.js +16 -0
- package/dist/replay.js.map +1 -1
- package/dist/risk.d.ts.map +1 -1
- package/dist/risk.js +5 -0
- package/dist/risk.js.map +1 -1
- package/dist/router.d.ts +7 -110
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +0 -451
- package/dist/router.js.map +1 -1
- package/dist/routing/index.d.ts +6 -0
- package/dist/routing/index.d.ts.map +1 -0
- package/dist/routing/index.js +5 -0
- package/dist/routing/index.js.map +1 -0
- package/dist/routing/prompt.d.ts +4 -0
- package/dist/routing/prompt.d.ts.map +1 -0
- package/dist/routing/prompt.js +14 -0
- package/dist/routing/prompt.js.map +1 -0
- package/dist/routing/select.d.ts +9 -0
- package/dist/routing/select.d.ts.map +1 -0
- package/dist/routing/select.js +279 -0
- package/dist/routing/select.js.map +1 -0
- package/dist/routing/smart.d.ts +31 -0
- package/dist/routing/smart.d.ts.map +1 -0
- package/dist/routing/smart.js +46 -0
- package/dist/routing/smart.js.map +1 -0
- package/dist/routing/types.d.ts +79 -0
- package/dist/routing/types.d.ts.map +1 -0
- package/dist/routing/types.js +2 -0
- package/dist/routing/types.js.map +1 -0
- package/dist/runlog.d.ts +32 -4
- package/dist/runlog.d.ts.map +1 -1
- package/dist/runlog.js +22 -6
- package/dist/runlog.js.map +1 -1
- package/dist/runtime/index.d.ts +6 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +6 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/permissions.d.ts +21 -0
- package/dist/runtime/permissions.d.ts.map +1 -0
- package/dist/runtime/permissions.js +110 -0
- package/dist/runtime/permissions.js.map +1 -0
- package/dist/runtime/repair.d.ts +20 -0
- package/dist/runtime/repair.d.ts.map +1 -0
- package/dist/runtime/repair.js +50 -0
- package/dist/runtime/repair.js.map +1 -0
- package/dist/runtime/tool-retry.d.ts +3 -0
- package/dist/runtime/tool-retry.d.ts.map +1 -0
- package/dist/runtime/tool-retry.js +12 -0
- package/dist/runtime/tool-retry.js.map +1 -0
- package/dist/runtime/turn.d.ts +97 -0
- package/dist/runtime/turn.d.ts.map +1 -0
- package/dist/runtime/turn.js +437 -0
- package/dist/runtime/turn.js.map +1 -0
- package/dist/runtime/types.d.ts +11 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +5 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/sandbox/docker.d.ts +4 -4
- package/dist/sandbox/docker.d.ts.map +1 -1
- package/dist/sandbox/docker.js +55 -16
- package/dist/sandbox/docker.js.map +1 -1
- package/dist/sandbox/native.d.ts +1 -0
- package/dist/sandbox/native.d.ts.map +1 -1
- package/dist/sandbox/native.js +11 -2
- package/dist/sandbox/native.js.map +1 -1
- package/dist/scope.d.ts +5 -9
- package/dist/scope.d.ts.map +1 -1
- package/dist/scope.js +43 -20
- package/dist/scope.js.map +1 -1
- package/dist/session-management/actions.d.ts +28 -0
- package/dist/session-management/actions.d.ts.map +1 -0
- package/dist/session-management/actions.js +78 -0
- package/dist/session-management/actions.js.map +1 -0
- package/dist/session-management/cli.d.ts +24 -0
- package/dist/session-management/cli.d.ts.map +1 -0
- package/dist/session-management/cli.js +92 -0
- package/dist/session-management/cli.js.map +1 -0
- package/dist/session-management/files.d.ts +5 -0
- package/dist/session-management/files.d.ts.map +1 -0
- package/dist/session-management/files.js +92 -0
- package/dist/session-management/files.js.map +1 -0
- package/dist/session-management/index.d.ts +7 -0
- package/dist/session-management/index.d.ts.map +1 -0
- package/dist/session-management/index.js +7 -0
- package/dist/session-management/index.js.map +1 -0
- package/dist/session-management/permissions.d.ts +12 -0
- package/dist/session-management/permissions.d.ts.map +1 -0
- package/dist/session-management/permissions.js +33 -0
- package/dist/session-management/permissions.js.map +1 -0
- package/dist/session-management/presentation.d.ts +5 -0
- package/dist/session-management/presentation.d.ts.map +1 -0
- package/dist/session-management/presentation.js +10 -0
- package/dist/session-management/presentation.js.map +1 -0
- package/dist/session-management/transfer.d.ts +9 -0
- package/dist/session-management/transfer.d.ts.map +1 -0
- package/dist/session-management/transfer.js +39 -0
- package/dist/session-management/transfer.js.map +1 -0
- package/dist/sessions/context.d.ts +4 -0
- package/dist/sessions/context.d.ts.map +1 -0
- package/dist/sessions/context.js +6 -0
- package/dist/sessions/context.js.map +1 -0
- package/dist/sessions/format.d.ts +38 -0
- package/dist/sessions/format.d.ts.map +1 -0
- package/dist/sessions/format.js +116 -0
- package/dist/sessions/format.js.map +1 -0
- package/dist/sessions/history.d.ts +37 -0
- package/dist/sessions/history.d.ts.map +1 -0
- package/dist/sessions/history.js +197 -0
- package/dist/sessions/history.js.map +1 -0
- package/dist/sessions/index.d.ts +8 -0
- package/dist/sessions/index.d.ts.map +1 -0
- package/dist/sessions/index.js +8 -0
- package/dist/sessions/index.js.map +1 -0
- package/dist/sessions/output.d.ts +31 -0
- package/dist/sessions/output.d.ts.map +1 -0
- package/dist/sessions/output.js +115 -0
- package/dist/sessions/output.js.map +1 -0
- package/dist/sessions/portable.d.ts +26 -0
- package/dist/sessions/portable.d.ts.map +1 -0
- package/dist/sessions/portable.js +105 -0
- package/dist/sessions/portable.js.map +1 -0
- package/dist/sessions/snapshot.d.ts +11 -0
- package/dist/sessions/snapshot.d.ts.map +1 -0
- package/dist/sessions/snapshot.js +118 -0
- package/dist/sessions/snapshot.js.map +1 -0
- package/dist/sessions/tool-state.d.ts +11 -0
- package/dist/sessions/tool-state.d.ts.map +1 -0
- package/dist/sessions/tool-state.js +152 -0
- package/dist/sessions/tool-state.js.map +1 -0
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +13 -5
- package/dist/setup.js.map +1 -1
- package/dist/spawning/actions.d.ts +23 -0
- package/dist/spawning/actions.d.ts.map +1 -0
- package/dist/spawning/actions.js +120 -0
- package/dist/spawning/actions.js.map +1 -0
- package/dist/spawning/authority.d.ts +15 -0
- package/dist/spawning/authority.d.ts.map +1 -0
- package/dist/spawning/authority.js +16 -0
- package/dist/spawning/authority.js.map +1 -0
- package/dist/spawning/cli.d.ts +4 -0
- package/dist/spawning/cli.d.ts.map +1 -0
- package/dist/spawning/cli.js +46 -0
- package/dist/spawning/cli.js.map +1 -0
- package/dist/spawning/execution.d.ts +13 -0
- package/dist/spawning/execution.d.ts.map +1 -0
- package/dist/spawning/execution.js +59 -0
- package/dist/spawning/execution.js.map +1 -0
- package/dist/spawning/index.d.ts +8 -0
- package/dist/spawning/index.d.ts.map +1 -0
- package/dist/spawning/index.js +8 -0
- package/dist/spawning/index.js.map +1 -0
- package/dist/spawning/store.d.ts +12 -0
- package/dist/spawning/store.d.ts.map +1 -0
- package/dist/spawning/store.js +93 -0
- package/dist/spawning/store.js.map +1 -0
- package/dist/spawning/types.d.ts +34 -0
- package/dist/spawning/types.d.ts.map +1 -0
- package/dist/spawning/types.js +2 -0
- package/dist/spawning/types.js.map +1 -0
- package/dist/spawning/validation.d.ts +14 -0
- package/dist/spawning/validation.d.ts.map +1 -0
- package/dist/spawning/validation.js +95 -0
- package/dist/spawning/validation.js.map +1 -0
- package/dist/storage.d.ts +29 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +112 -40
- package/dist/storage.js.map +1 -1
- package/dist/supervision/approval.d.ts +4 -0
- package/dist/supervision/approval.d.ts.map +1 -0
- package/dist/supervision/approval.js +7 -0
- package/dist/supervision/approval.js.map +1 -0
- package/dist/supervision/availability.d.ts +34 -0
- package/dist/supervision/availability.d.ts.map +1 -0
- package/dist/supervision/availability.js +44 -0
- package/dist/supervision/availability.js.map +1 -0
- package/dist/supervision/context.d.ts +36 -0
- package/dist/supervision/context.d.ts.map +1 -0
- package/dist/supervision/context.js +52 -0
- package/dist/supervision/context.js.map +1 -0
- package/dist/supervision/contracts.d.ts +7 -0
- package/dist/supervision/contracts.d.ts.map +1 -0
- package/dist/supervision/contracts.js +86 -0
- package/dist/supervision/contracts.js.map +1 -0
- package/dist/supervision/effects.d.ts +15 -0
- package/dist/supervision/effects.d.ts.map +1 -0
- package/dist/supervision/effects.js +19 -0
- package/dist/supervision/effects.js.map +1 -0
- package/dist/supervision/evidence.d.ts +32 -0
- package/dist/supervision/evidence.d.ts.map +1 -0
- package/dist/supervision/evidence.js +68 -0
- package/dist/supervision/evidence.js.map +1 -0
- package/dist/supervision/health.d.ts +16 -0
- package/dist/supervision/health.d.ts.map +1 -0
- package/dist/supervision/health.js +86 -0
- package/dist/supervision/health.js.map +1 -0
- package/dist/supervision/index.d.ts +13 -0
- package/dist/supervision/index.d.ts.map +1 -0
- package/dist/supervision/index.js +13 -0
- package/dist/supervision/index.js.map +1 -0
- package/dist/supervision/journal.d.ts +16 -0
- package/dist/supervision/journal.d.ts.map +1 -0
- package/dist/supervision/journal.js +311 -0
- package/dist/supervision/journal.js.map +1 -0
- package/dist/supervision/receipts.d.ts +4 -0
- package/dist/supervision/receipts.d.ts.map +1 -0
- package/dist/supervision/receipts.js +21 -0
- package/dist/supervision/receipts.js.map +1 -0
- package/dist/supervision/reply.d.ts +12 -0
- package/dist/supervision/reply.d.ts.map +1 -0
- package/dist/supervision/reply.js +50 -0
- package/dist/supervision/reply.js.map +1 -0
- package/dist/supervision/runtime.d.ts +8 -0
- package/dist/supervision/runtime.d.ts.map +1 -0
- package/dist/supervision/runtime.js +188 -0
- package/dist/supervision/runtime.js.map +1 -0
- package/dist/supervision/types.d.ts +174 -0
- package/dist/supervision/types.d.ts.map +1 -0
- package/dist/supervision/types.js +2 -0
- package/dist/supervision/types.js.map +1 -0
- package/dist/tools.d.ts +12 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +131 -23
- package/dist/tools.js.map +1 -1
- package/dist/turn-controller.d.ts +12 -0
- package/dist/turn-controller.d.ts.map +1 -0
- package/dist/turn-controller.js +51 -0
- package/dist/turn-controller.js.map +1 -0
- package/dist/types.d.ts +7 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -1
- package/dist/ui/agent.d.ts +11 -10
- package/dist/ui/agent.d.ts.map +1 -1
- package/dist/ui/agent.js +293 -897
- package/dist/ui/agent.js.map +1 -1
- package/dist/ui/commands.d.ts +20 -2
- package/dist/ui/commands.d.ts.map +1 -1
- package/dist/ui/commands.js +208 -155
- package/dist/ui/commands.js.map +1 -1
- package/dist/ui/completions.d.ts.map +1 -1
- package/dist/ui/completions.js +16 -5
- package/dist/ui/completions.js.map +1 -1
- package/dist/ui/index.d.ts +6 -2
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +13 -11
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/messages.d.ts.map +1 -1
- package/dist/ui/messages.js +5 -0
- package/dist/ui/messages.js.map +1 -1
- package/dist/ui/modals/index.d.ts +1 -0
- package/dist/ui/modals/index.d.ts.map +1 -1
- package/dist/ui/modals/index.js +1 -0
- package/dist/ui/modals/index.js.map +1 -1
- package/dist/ui/modals/prompts.d.ts +4 -7
- package/dist/ui/modals/prompts.d.ts.map +1 -1
- package/dist/ui/modals/prompts.js +14 -10
- package/dist/ui/modals/prompts.js.map +1 -1
- package/dist/ui/modals/selectors.d.ts +1 -0
- package/dist/ui/modals/selectors.d.ts.map +1 -1
- package/dist/ui/modals/selectors.js +3 -2
- package/dist/ui/modals/selectors.js.map +1 -1
- package/dist/ui/modals/tool-output.d.ts +8 -0
- package/dist/ui/modals/tool-output.d.ts.map +1 -0
- package/dist/ui/modals/tool-output.js +26 -0
- package/dist/ui/modals/tool-output.js.map +1 -0
- package/dist/ui/model-commands.d.ts +4 -0
- package/dist/ui/model-commands.d.ts.map +1 -0
- package/dist/ui/model-commands.js +69 -0
- package/dist/ui/model-commands.js.map +1 -0
- package/dist/ui/regions/modal-host.d.ts +3 -0
- package/dist/ui/regions/modal-host.d.ts.map +1 -1
- package/dist/ui/regions/modal-host.js +7 -1
- package/dist/ui/regions/modal-host.js.map +1 -1
- package/dist/ui/regions/status-region.d.ts +2 -1
- package/dist/ui/regions/status-region.d.ts.map +1 -1
- package/dist/ui/regions/status-region.js +2 -2
- package/dist/ui/regions/status-region.js.map +1 -1
- package/dist/ui/regions/tool-activity.d.ts +6 -0
- package/dist/ui/regions/tool-activity.d.ts.map +1 -0
- package/dist/ui/regions/tool-activity.js +9 -0
- package/dist/ui/regions/tool-activity.js.map +1 -0
- package/dist/ui/regions/transcript-region.d.ts.map +1 -1
- package/dist/ui/regions/transcript-region.js +2 -1
- package/dist/ui/regions/transcript-region.js.map +1 -1
- package/dist/ui/regions/workflow-region.d.ts +9 -0
- package/dist/ui/regions/workflow-region.d.ts.map +1 -0
- package/dist/ui/regions/workflow-region.js +11 -0
- package/dist/ui/regions/workflow-region.js.map +1 -0
- package/dist/ui/session-commands.d.ts +3 -0
- package/dist/ui/session-commands.d.ts.map +1 -0
- package/dist/ui/session-commands.js +141 -0
- package/dist/ui/session-commands.js.map +1 -0
- package/dist/ui/state/use-approval-state.d.ts +9 -0
- package/dist/ui/state/use-approval-state.d.ts.map +1 -0
- package/dist/ui/state/use-approval-state.js +18 -0
- package/dist/ui/state/use-approval-state.js.map +1 -0
- package/dist/ui/state/use-chat-controller.d.ts +4 -1
- package/dist/ui/state/use-chat-controller.d.ts.map +1 -1
- package/dist/ui/state/use-chat-controller.js +256 -180
- package/dist/ui/state/use-chat-controller.js.map +1 -1
- package/dist/ui/state/use-modal-state.d.ts +6 -8
- package/dist/ui/state/use-modal-state.d.ts.map +1 -1
- package/dist/ui/state/use-modal-state.js +3 -4
- package/dist/ui/state/use-modal-state.js.map +1 -1
- package/dist/ui/state/use-model-state.d.ts +7 -3
- package/dist/ui/state/use-model-state.d.ts.map +1 -1
- package/dist/ui/state/use-model-state.js +24 -17
- package/dist/ui/state/use-model-state.js.map +1 -1
- package/dist/ui/state/use-queue-state.d.ts +4 -3
- package/dist/ui/state/use-queue-state.d.ts.map +1 -1
- package/dist/ui/state/use-queue-state.js +11 -8
- package/dist/ui/state/use-queue-state.js.map +1 -1
- package/dist/ui/state/use-session-init.d.ts +4 -0
- package/dist/ui/state/use-session-init.d.ts.map +1 -1
- package/dist/ui/state/use-session-init.js +19 -3
- package/dist/ui/state/use-session-init.js.map +1 -1
- package/dist/ui/state/use-transcript-state.d.ts +6 -3
- package/dist/ui/state/use-transcript-state.d.ts.map +1 -1
- package/dist/ui/state/use-transcript-state.js +27 -15
- package/dist/ui/state/use-transcript-state.js.map +1 -1
- package/dist/ui/status-bar.d.ts +2 -1
- package/dist/ui/status-bar.d.ts.map +1 -1
- package/dist/ui/status-bar.js +2 -2
- package/dist/ui/status-bar.js.map +1 -1
- package/dist/ui/tool-output-cache.d.ts +12 -0
- package/dist/ui/tool-output-cache.d.ts.map +1 -0
- package/dist/ui/tool-output-cache.js +27 -0
- package/dist/ui/tool-output-cache.js.map +1 -0
- package/dist/ui/tool-output-commands.d.ts +3 -0
- package/dist/ui/tool-output-commands.d.ts.map +1 -0
- package/dist/ui/tool-output-commands.js +37 -0
- package/dist/ui/tool-output-commands.js.map +1 -0
- package/dist/ui/tool-output-wrap.d.ts +3 -0
- package/dist/ui/tool-output-wrap.d.ts.map +1 -0
- package/dist/ui/tool-output-wrap.js +24 -0
- package/dist/ui/tool-output-wrap.js.map +1 -0
- package/dist/ui/tool-progress.d.ts +23 -0
- package/dist/ui/tool-progress.d.ts.map +1 -0
- package/dist/ui/tool-progress.js +42 -0
- package/dist/ui/tool-progress.js.map +1 -0
- package/dist/ui/types.d.ts +8 -0
- package/dist/ui/types.d.ts.map +1 -1
- package/dist/ui/workflow-progress.d.ts +21 -0
- package/dist/ui/workflow-progress.d.ts.map +1 -0
- package/dist/ui/workflow-progress.js +107 -0
- package/dist/ui/workflow-progress.js.map +1 -0
- package/package.json +13 -4
- package/scripts/verify-runlog.mjs +208 -0
package/dist/model-detection.js
CHANGED
|
@@ -6,7 +6,65 @@
|
|
|
6
6
|
import OpenAI from 'openai';
|
|
7
7
|
import { select } from '@inquirer/prompts';
|
|
8
8
|
import * as config from './config.js';
|
|
9
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
10
|
+
import { cancellable, throwIfCancelled } from './cancellation.js';
|
|
11
|
+
import { bindProcessCancellation, detachedProcess } from './process-cancellation.js';
|
|
12
|
+
import { createHash } from 'node:crypto';
|
|
13
|
+
import { ModelDiscoveryError, compatibleMetadata, anthropicMetadata, openRouterPricing, capability, positiveLimit, price, stringList, validateModels } from './models/index.js';
|
|
9
14
|
const DEBUG = process.env.CALLIOPE_DEBUG === '1';
|
|
15
|
+
const discoveryContext = new AsyncLocalStorage();
|
|
16
|
+
function fetchModelMetadata(input, init) {
|
|
17
|
+
const signal = discoveryContext.getStore()?.signal;
|
|
18
|
+
throwIfCancelled(signal);
|
|
19
|
+
if (!signal)
|
|
20
|
+
return init === undefined ? fetch(input) : fetch(input, init);
|
|
21
|
+
return fetch(input, { ...init, signal: init?.signal ? AbortSignal.any([signal, init.signal]) : signal });
|
|
22
|
+
}
|
|
23
|
+
function discoveryTransportOptions() {
|
|
24
|
+
return discoveryContext.getStore()?.signal ? { fetch: fetchModelMetadata, maxRetries: 0 } : {};
|
|
25
|
+
}
|
|
26
|
+
/** Follow provider cursors only on the original endpoint, with fixed page/item caps. */
|
|
27
|
+
async function modelPages(endpoint, kind, headers) {
|
|
28
|
+
const models = [], seen = new Set();
|
|
29
|
+
let cursor = '';
|
|
30
|
+
for (let page = 0; page < 20; page++) {
|
|
31
|
+
const url = new URL(endpoint);
|
|
32
|
+
if (cursor)
|
|
33
|
+
url.searchParams.set(kind === 'anthropic' ? 'after_id' : 'pageToken', cursor);
|
|
34
|
+
const response = await fetchModelMetadata(url.toString(), headers ? { headers } : undefined);
|
|
35
|
+
if (!response.ok)
|
|
36
|
+
throw new Error(`Model discovery HTTP ${response.status}`);
|
|
37
|
+
const data = await response.json();
|
|
38
|
+
const items = data[kind === 'anthropic' ? 'data' : 'models'];
|
|
39
|
+
if (!Array.isArray(items) || models.length + items.length > 10000)
|
|
40
|
+
throw new ModelDiscoveryError('Invalid model discovery page');
|
|
41
|
+
models.push(...items);
|
|
42
|
+
if (kind === 'anthropic' && data.has_more !== undefined && typeof data.has_more !== 'boolean')
|
|
43
|
+
throw new ModelDiscoveryError('Invalid discovery pagination');
|
|
44
|
+
if (kind === 'anthropic' && data.has_more && (typeof data.last_id !== 'string' || !data.last_id))
|
|
45
|
+
throw new ModelDiscoveryError('Missing discovery cursor');
|
|
46
|
+
const next = kind === 'anthropic' ? (data.has_more ? data.last_id : undefined) : data.nextPageToken;
|
|
47
|
+
if (next === undefined || next === null || next === '')
|
|
48
|
+
return models;
|
|
49
|
+
if (typeof next !== 'string' || next.length > 4096 || seen.has(next))
|
|
50
|
+
throw new ModelDiscoveryError('Invalid model discovery cursor');
|
|
51
|
+
seen.add(next);
|
|
52
|
+
cursor = next;
|
|
53
|
+
}
|
|
54
|
+
throw new ModelDiscoveryError('Model discovery page budget exceeded');
|
|
55
|
+
}
|
|
56
|
+
/** Scope transport cancellation to this discovery call, including concurrent probes. */
|
|
57
|
+
export async function getAvailableModels(provider, options = {}) {
|
|
58
|
+
throwIfCancelled(options.signal);
|
|
59
|
+
return discoveryContext.run({ ...options, cleanups: [] }, async () => {
|
|
60
|
+
try {
|
|
61
|
+
return await cancellable(loadAvailableModels(provider, options), options.signal);
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
await Promise.allSettled(discoveryContext.getStore().cleanups);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
10
68
|
function logModelDetectionWarning(message, error, options = {}) {
|
|
11
69
|
if (options.quiet || !DEBUG) {
|
|
12
70
|
return;
|
|
@@ -25,7 +83,10 @@ const PROVIDER_BASE_URLS = {
|
|
|
25
83
|
fireworks: 'https://api.fireworks.ai/inference/v1',
|
|
26
84
|
mistral: 'https://api.mistral.ai/v1',
|
|
27
85
|
ai21: 'https://api.ai21.com/studio/v1',
|
|
28
|
-
huggingface: 'https://
|
|
86
|
+
huggingface: 'https://router.huggingface.co/v1',
|
|
87
|
+
deepseek: 'https://api.deepseek.com',
|
|
88
|
+
xai: 'https://api.x.ai/v1',
|
|
89
|
+
cerebras: 'https://api.cerebras.ai/v1',
|
|
29
90
|
// Bedrock uses a configurable gateway URL, not a fixed URL
|
|
30
91
|
};
|
|
31
92
|
/**
|
|
@@ -57,6 +118,7 @@ const INCOMPATIBLE_MODEL_PATTERNS = {
|
|
|
57
118
|
/^text-embedding/, // Text embedding
|
|
58
119
|
/^aqa/, // Attributed QA (not chat)
|
|
59
120
|
/embedding$/, // Any model ending in embedding
|
|
121
|
+
/computer-use/i, // Requires the dedicated Computer Use tool contract
|
|
60
122
|
],
|
|
61
123
|
groq: [
|
|
62
124
|
/^whisper/, // Speech-to-text
|
|
@@ -114,6 +176,48 @@ function isCompatibleModel(modelId, provider) {
|
|
|
114
176
|
// Model cache to avoid repeated API calls
|
|
115
177
|
const modelCache = new Map();
|
|
116
178
|
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
|
|
179
|
+
const previousDiscovery = new Map();
|
|
180
|
+
/** Stale negative capability evidence still blocks an unverified fallback. */
|
|
181
|
+
export function getPreviousDiscoveredModels(provider) {
|
|
182
|
+
const previous = previousDiscovery.get(provider);
|
|
183
|
+
return previous?.target === modelCacheTarget(provider) ? structuredClone(previous.models) : undefined;
|
|
184
|
+
}
|
|
185
|
+
function modelCacheTarget(provider) {
|
|
186
|
+
const profile = provider === 'bedrock' ? config.getProviderCred(provider) : { profile: undefined, region: undefined };
|
|
187
|
+
return createHash('sha256').update(JSON.stringify([provider, config.getBaseUrl(provider), config.getApiKey(provider), profile.profile, profile.region])).digest('hex');
|
|
188
|
+
}
|
|
189
|
+
export function getDiscoveredModels(provider) {
|
|
190
|
+
const cached = modelCache.get(provider);
|
|
191
|
+
if (!cached || cached.target !== modelCacheTarget(provider) || Date.now() - cached.timestamp >= CACHE_DURATION || cached.models.some(model => model.evidence?.source !== 'live'))
|
|
192
|
+
return undefined;
|
|
193
|
+
return structuredClone(cached.models);
|
|
194
|
+
}
|
|
195
|
+
/** Anthropic explicitly supports resolving aliases through Models.retrieve. */
|
|
196
|
+
export async function resolveModelAlias(provider, alias, signal) {
|
|
197
|
+
if (provider !== 'anthropic')
|
|
198
|
+
return undefined;
|
|
199
|
+
throwIfCancelled(signal);
|
|
200
|
+
const key = config.getApiKey(provider);
|
|
201
|
+
if (!key)
|
|
202
|
+
return undefined;
|
|
203
|
+
const target = modelCacheTarget(provider);
|
|
204
|
+
const response = await cancellable(fetch(`${(config.getBaseUrl('anthropic') || 'https://api.anthropic.com').replace(/\/v1\/?$/, '').replace(/\/$/, '')}/v1/models/${encodeURIComponent(alias)}`, {
|
|
205
|
+
headers: { 'x-api-key': key, 'anthropic-version': '2023-06-01' }, signal,
|
|
206
|
+
}), signal);
|
|
207
|
+
if (!response.ok)
|
|
208
|
+
return undefined;
|
|
209
|
+
const body = await cancellable(response.json(), signal);
|
|
210
|
+
const model = { id: body.id, name: body.display_name, aliases: [alias], ...anthropicMetadata(body), evidence: { source: 'live', at: new Date().toISOString() } };
|
|
211
|
+
validateModels([model]);
|
|
212
|
+
throwIfCancelled(signal);
|
|
213
|
+
const cached = modelCache.get(provider);
|
|
214
|
+
if (cached?.target === target && modelCacheTarget(provider) === target) {
|
|
215
|
+
model.aliases = [...new Set([...(cached.models.find(item => item.id === model.id)?.aliases ?? []), alias])];
|
|
216
|
+
cached.models = [...cached.models.filter(item => item.id !== model.id), model];
|
|
217
|
+
previousDiscovery.set(provider, { models: structuredClone(cached.models), target });
|
|
218
|
+
}
|
|
219
|
+
return model;
|
|
220
|
+
}
|
|
117
221
|
/**
|
|
118
222
|
* Get available models for a provider with interactive selection
|
|
119
223
|
*/
|
|
@@ -158,8 +262,8 @@ function formatModelChoice(model) {
|
|
|
158
262
|
display += ` (${formatContextLength(model.contextLength)})`;
|
|
159
263
|
}
|
|
160
264
|
if (model.pricing) {
|
|
161
|
-
const inputPrice = model.pricing.input ? `$${model.pricing.input.toFixed(2)}/1M` : '';
|
|
162
|
-
const outputPrice = model.pricing.output ? `$${model.pricing.output.toFixed(2)}/1M` : '';
|
|
265
|
+
const inputPrice = model.pricing.input !== undefined ? `$${model.pricing.input.toFixed(2)}/1M` : '';
|
|
266
|
+
const outputPrice = model.pricing.output !== undefined ? `$${model.pricing.output.toFixed(2)}/1M` : '';
|
|
163
267
|
if (inputPrice || outputPrice) {
|
|
164
268
|
display += ` - ${inputPrice}${inputPrice && outputPrice ? '/' : ''}${outputPrice}`;
|
|
165
269
|
}
|
|
@@ -183,11 +287,15 @@ function formatContextLength(tokens) {
|
|
|
183
287
|
/**
|
|
184
288
|
* Get available models for a provider
|
|
185
289
|
*/
|
|
186
|
-
|
|
290
|
+
async function loadAvailableModels(provider, options) {
|
|
187
291
|
// Check cache first
|
|
188
292
|
const cached = modelCache.get(provider);
|
|
189
|
-
|
|
190
|
-
|
|
293
|
+
const target = modelCacheTarget(provider);
|
|
294
|
+
// Strict callers require current wire evidence; a cached emergency fallback
|
|
295
|
+
// must never masquerade as successful live discovery.
|
|
296
|
+
if (cached?.target === target && Date.now() - cached.timestamp < CACHE_DURATION &&
|
|
297
|
+
(!options.throwOnError || (options.cache === 'live' && cached.models.every(model => model.evidence?.source === 'live')))) {
|
|
298
|
+
return structuredClone(cached.models);
|
|
191
299
|
}
|
|
192
300
|
let models = [];
|
|
193
301
|
try {
|
|
@@ -222,6 +330,9 @@ export async function getAvailableModels(provider, options = {}) {
|
|
|
222
330
|
case 'ai21':
|
|
223
331
|
case 'huggingface':
|
|
224
332
|
case 'fireworks':
|
|
333
|
+
case 'deepseek':
|
|
334
|
+
case 'xai':
|
|
335
|
+
case 'cerebras':
|
|
225
336
|
models = await getOpenAICompatibleModels(provider);
|
|
226
337
|
break;
|
|
227
338
|
case 'bedrock':
|
|
@@ -233,8 +344,16 @@ export async function getAvailableModels(provider, options = {}) {
|
|
|
233
344
|
default:
|
|
234
345
|
throw new Error(`Model detection not implemented for ${provider}`);
|
|
235
346
|
}
|
|
347
|
+
throwIfCancelled(options.signal);
|
|
236
348
|
// Cache the results
|
|
237
|
-
|
|
349
|
+
const timestamp = Date.now();
|
|
350
|
+
models = validateModels(models).map(model => ({ ...model, evidence: model.evidence ?? { source: 'live', at: new Date(timestamp).toISOString() } }));
|
|
351
|
+
// Endpoint/credential changes during discovery cannot populate a new target's cache.
|
|
352
|
+
if (modelCacheTarget(provider) === target) {
|
|
353
|
+
modelCache.set(provider, { models: structuredClone(models), timestamp, target });
|
|
354
|
+
if (models.every(model => model.evidence?.source === 'live'))
|
|
355
|
+
previousDiscovery.set(provider, { models: structuredClone(models), target });
|
|
356
|
+
}
|
|
238
357
|
}
|
|
239
358
|
catch (error) {
|
|
240
359
|
logModelDetectionWarning(`Failed to fetch models for ${provider}:`, error, options);
|
|
@@ -251,37 +370,28 @@ async function getAnthropicModels(options = {}) {
|
|
|
251
370
|
if (!apiKey)
|
|
252
371
|
throw new Error('Anthropic API key not configured');
|
|
253
372
|
try {
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
'x-api-key': apiKey,
|
|
257
|
-
'anthropic-version': '2023-06-01'
|
|
258
|
-
}
|
|
259
|
-
});
|
|
260
|
-
if (!response.ok) {
|
|
261
|
-
throw new Error(`Anthropic API error: ${response.status}`);
|
|
262
|
-
}
|
|
263
|
-
const data = await response.json();
|
|
264
|
-
return data.data
|
|
373
|
+
const models = await modelPages(`${(config.getBaseUrl('anthropic') || 'https://api.anthropic.com').replace(/\/v1\/?$/, '').replace(/\/$/, '')}/v1/models`, 'anthropic', { 'x-api-key': apiKey, 'anthropic-version': '2023-06-01' });
|
|
374
|
+
return models
|
|
265
375
|
.filter(model => model.id.startsWith('claude'))
|
|
266
376
|
.map(model => ({
|
|
267
377
|
id: model.id,
|
|
268
378
|
name: model.display_name || formatModelName(model.id),
|
|
269
379
|
description: getAnthropicModelDescription(model.id),
|
|
270
|
-
|
|
271
|
-
// derive it per model family rather than hardcoding a single value.
|
|
272
|
-
contextLength: getModelContextLimit('anthropic', model.id),
|
|
380
|
+
...anthropicMetadata(model),
|
|
273
381
|
}))
|
|
274
382
|
.sort((a, b) => b.id.localeCompare(a.id)); // Newest first
|
|
275
383
|
}
|
|
276
384
|
catch (error) {
|
|
277
385
|
// Emergency fallback when the API is unreachable. Keep these as the current
|
|
278
386
|
// shipping models — discovery is the source of truth; this is the offline net.
|
|
387
|
+
if (options.throwOnError)
|
|
388
|
+
throw error;
|
|
279
389
|
logModelDetectionWarning('Failed to fetch Anthropic models, using fallback list', error, options);
|
|
280
390
|
return [
|
|
281
391
|
{ id: 'claude-opus-4-8', name: 'Claude Opus 4.8', description: 'Most capable model', contextLength: 1000000 },
|
|
282
392
|
{ id: 'claude-sonnet-4-6', name: 'Claude Sonnet 4.6', description: 'Balanced intelligence and speed', contextLength: 1000000 },
|
|
283
393
|
{ id: 'claude-haiku-4-5', name: 'Claude Haiku 4.5', description: 'Fast and affordable', contextLength: 200000 },
|
|
284
|
-
];
|
|
394
|
+
].map(model => ({ ...model, evidence: { source: 'emergency', at: new Date().toISOString() } }));
|
|
285
395
|
}
|
|
286
396
|
}
|
|
287
397
|
function formatModelName(modelId) {
|
|
@@ -311,12 +421,8 @@ async function getGoogleModels(options = {}) {
|
|
|
311
421
|
throw new Error('Google API key not configured');
|
|
312
422
|
try {
|
|
313
423
|
// Use REST API directly for model listing
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
throw new Error(`Google API error: ${response.status}`);
|
|
317
|
-
}
|
|
318
|
-
const data = await response.json();
|
|
319
|
-
return data.models
|
|
424
|
+
const models = await modelPages(`${(config.getBaseUrl('google') || 'https://generativelanguage.googleapis.com').replace(/\/v1beta\/?$/, '').replace(/\/$/, '')}/v1beta/models?key=${encodeURIComponent(apiKey)}`, 'google');
|
|
425
|
+
return models
|
|
320
426
|
.filter(model => {
|
|
321
427
|
const modelId = model.name.replace('models/', '');
|
|
322
428
|
return model.name.includes('gemini') && isCompatibleModel(modelId, 'google');
|
|
@@ -325,12 +431,16 @@ async function getGoogleModels(options = {}) {
|
|
|
325
431
|
id: model.name.replace('models/', ''),
|
|
326
432
|
name: model.displayName || model.name.replace('models/', ''),
|
|
327
433
|
description: model.description || 'Google Gemini model',
|
|
328
|
-
contextLength: model.inputTokenLimit
|
|
434
|
+
contextLength: positiveLimit(model.inputTokenLimit),
|
|
435
|
+
maxOutputTokens: positiveLimit(model.outputTokenLimit),
|
|
436
|
+
capabilities: { chat: stringList(model.supportedGenerationMethods)?.includes('generateContent'), thinking: capability(model.thinking) },
|
|
329
437
|
}))
|
|
330
438
|
.sort((a, b) => b.id.localeCompare(a.id)); // Newest first
|
|
331
439
|
}
|
|
332
440
|
catch (error) {
|
|
333
441
|
// Fallback to known models if API fails
|
|
442
|
+
if (options.throwOnError)
|
|
443
|
+
throw error;
|
|
334
444
|
logModelDetectionWarning('Failed to fetch Google models, using fallback list', error, options);
|
|
335
445
|
return [
|
|
336
446
|
{ id: 'gemini-2.5-pro-preview-06-05', name: 'Gemini 2.5 Pro', description: 'Most capable', contextLength: 1048576 },
|
|
@@ -338,7 +448,7 @@ async function getGoogleModels(options = {}) {
|
|
|
338
448
|
{ id: 'gemini-2.0-flash', name: 'Gemini 2.0 Flash', description: 'Multimodal', contextLength: 1048576 },
|
|
339
449
|
{ id: 'gemini-1.5-pro-latest', name: 'Gemini 1.5 Pro', description: 'Complex reasoning', contextLength: 2097152 },
|
|
340
450
|
{ id: 'gemini-1.5-flash-latest', name: 'Gemini 1.5 Flash', description: 'Fast and versatile', contextLength: 1048576 },
|
|
341
|
-
];
|
|
451
|
+
].map(model => ({ ...model, evidence: { source: 'emergency', at: new Date().toISOString() } }));
|
|
342
452
|
}
|
|
343
453
|
}
|
|
344
454
|
/**
|
|
@@ -348,7 +458,7 @@ async function getOpenAIModels() {
|
|
|
348
458
|
const apiKey = config.getApiKey('openai');
|
|
349
459
|
if (!apiKey)
|
|
350
460
|
throw new Error('OpenAI API key not configured');
|
|
351
|
-
const client = new OpenAI({ apiKey });
|
|
461
|
+
const client = new OpenAI({ apiKey, baseURL: config.getBaseUrl('openai'), ...discoveryTransportOptions() });
|
|
352
462
|
const response = await client.models.list();
|
|
353
463
|
// Filter for chat-compatible models (GPT and reasoning models)
|
|
354
464
|
return response.data
|
|
@@ -361,6 +471,7 @@ async function getOpenAIModels() {
|
|
|
361
471
|
id: model.id,
|
|
362
472
|
name: model.id,
|
|
363
473
|
description: getOpenAIModelDescription(model.id),
|
|
474
|
+
...compatibleMetadata(model),
|
|
364
475
|
}))
|
|
365
476
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
366
477
|
}
|
|
@@ -371,7 +482,7 @@ async function getOpenRouterModels() {
|
|
|
371
482
|
const apiKey = config.getApiKey('openrouter');
|
|
372
483
|
if (!apiKey)
|
|
373
484
|
throw new Error('OpenRouter API key not configured');
|
|
374
|
-
const response = await
|
|
485
|
+
const response = await fetchModelMetadata(`${(config.getBaseUrl('openrouter') || 'https://openrouter.ai/api/v1').replace(/\/+$/, '')}/models`, {
|
|
375
486
|
headers: {
|
|
376
487
|
'Authorization': `Bearer ${apiKey}`,
|
|
377
488
|
'HTTP-Referer': 'https://calliope.ai',
|
|
@@ -409,11 +520,11 @@ async function getOpenRouterModels() {
|
|
|
409
520
|
id: model.id,
|
|
410
521
|
name: model.name,
|
|
411
522
|
description: model.description,
|
|
412
|
-
contextLength: model.context_length,
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
523
|
+
contextLength: positiveLimit(model.context_length),
|
|
524
|
+
maxOutputTokens: positiveLimit(model.top_provider?.max_completion_tokens),
|
|
525
|
+
capabilities: { chat: true, tools: model.supported_parameters ? model.supported_parameters.includes('tools') : undefined,
|
|
526
|
+
vision: model.architecture?.input_modalities ? model.architecture.input_modalities.includes('image') : undefined },
|
|
527
|
+
pricing: openRouterPricing(model.pricing)
|
|
417
528
|
}));
|
|
418
529
|
}
|
|
419
530
|
/**
|
|
@@ -424,7 +535,7 @@ async function getTogetherModels() {
|
|
|
424
535
|
if (!apiKey)
|
|
425
536
|
throw new Error('Together API key not configured');
|
|
426
537
|
// Together's API returns a raw array, not wrapped in { data: [...] } like OpenAI
|
|
427
|
-
const response = await
|
|
538
|
+
const response = await fetchModelMetadata(`${(config.getBaseUrl('together') || 'https://api.together.xyz/v1').replace(/\/+$/, '')}/models`, {
|
|
428
539
|
headers: {
|
|
429
540
|
'Authorization': `Bearer ${apiKey}`,
|
|
430
541
|
}
|
|
@@ -440,10 +551,11 @@ async function getTogetherModels() {
|
|
|
440
551
|
id: model.id,
|
|
441
552
|
name: model.display_name || model.id,
|
|
442
553
|
description: getTogetherModelDescription(model.id),
|
|
443
|
-
|
|
554
|
+
...compatibleMetadata(model),
|
|
555
|
+
contextLength: positiveLimit(model.context_length),
|
|
444
556
|
pricing: model.pricing ? {
|
|
445
|
-
input: model.pricing.input,
|
|
446
|
-
output: model.pricing.output,
|
|
557
|
+
input: price(model.pricing.input),
|
|
558
|
+
output: price(model.pricing.output),
|
|
447
559
|
} : undefined,
|
|
448
560
|
}))
|
|
449
561
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -456,8 +568,9 @@ async function getGroqModels() {
|
|
|
456
568
|
if (!apiKey)
|
|
457
569
|
throw new Error('Groq API key not configured');
|
|
458
570
|
const client = new OpenAI({
|
|
571
|
+
...discoveryTransportOptions(),
|
|
459
572
|
apiKey,
|
|
460
|
-
baseURL: 'https://api.groq.com/openai/v1'
|
|
573
|
+
baseURL: config.getBaseUrl('groq') || 'https://api.groq.com/openai/v1'
|
|
461
574
|
});
|
|
462
575
|
const response = await client.models.list();
|
|
463
576
|
return response.data
|
|
@@ -466,6 +579,7 @@ async function getGroqModels() {
|
|
|
466
579
|
id: model.id,
|
|
467
580
|
name: model.id,
|
|
468
581
|
description: 'High-speed inference model',
|
|
582
|
+
...compatibleMetadata(model),
|
|
469
583
|
}));
|
|
470
584
|
}
|
|
471
585
|
/**
|
|
@@ -476,8 +590,9 @@ async function getMistralModels() {
|
|
|
476
590
|
if (!apiKey)
|
|
477
591
|
throw new Error('Mistral API key not configured');
|
|
478
592
|
const client = new OpenAI({
|
|
593
|
+
...discoveryTransportOptions(),
|
|
479
594
|
apiKey,
|
|
480
|
-
baseURL: 'https://api.mistral.ai/v1'
|
|
595
|
+
baseURL: config.getBaseUrl('mistral') || 'https://api.mistral.ai/v1'
|
|
481
596
|
});
|
|
482
597
|
const response = await client.models.list();
|
|
483
598
|
return response.data
|
|
@@ -486,6 +601,7 @@ async function getMistralModels() {
|
|
|
486
601
|
id: model.id,
|
|
487
602
|
name: model.id,
|
|
488
603
|
description: getMistralModelDescription(model.id),
|
|
604
|
+
...compatibleMetadata(model),
|
|
489
605
|
}));
|
|
490
606
|
}
|
|
491
607
|
/**
|
|
@@ -498,7 +614,7 @@ async function getOllamaModels() {
|
|
|
498
614
|
baseUrl = baseUrl.slice(0, -3);
|
|
499
615
|
}
|
|
500
616
|
try {
|
|
501
|
-
const response = await
|
|
617
|
+
const response = await fetchModelMetadata(`${baseUrl}/api/tags`);
|
|
502
618
|
if (!response.ok) {
|
|
503
619
|
throw new Error(`Ollama API error: ${response.status}`);
|
|
504
620
|
}
|
|
@@ -508,26 +624,30 @@ async function getOllamaModels() {
|
|
|
508
624
|
const results = [];
|
|
509
625
|
for (const model of models) {
|
|
510
626
|
let contextLength;
|
|
627
|
+
let capabilities;
|
|
511
628
|
try {
|
|
512
|
-
const showResp = await
|
|
629
|
+
const showResp = await fetchModelMetadata(`${baseUrl}/api/show`, {
|
|
513
630
|
method: 'POST',
|
|
514
631
|
headers: { 'Content-Type': 'application/json' },
|
|
515
632
|
body: JSON.stringify({ name: model.name }),
|
|
516
633
|
});
|
|
517
634
|
if (showResp.ok) {
|
|
518
635
|
const showData = await showResp.json();
|
|
636
|
+
const supported = stringList(showData.capabilities);
|
|
637
|
+
if (supported)
|
|
638
|
+
capabilities = { chat: supported.includes('completion'), tools: supported.includes('tools'), vision: supported.includes('vision'), thinking: supported.includes('thinking') };
|
|
519
639
|
// Check model_info for context length keys
|
|
520
640
|
if (showData.model_info) {
|
|
521
641
|
const ctxKey = Object.keys(showData.model_info).find(k => k.includes('context_length') || k.includes('context_window'));
|
|
522
642
|
if (ctxKey && typeof showData.model_info[ctxKey] === 'number') {
|
|
523
|
-
contextLength = showData.model_info[ctxKey];
|
|
643
|
+
contextLength = positiveLimit(showData.model_info[ctxKey]);
|
|
524
644
|
}
|
|
525
645
|
}
|
|
526
646
|
// Also check Modelfile parameters for num_ctx override
|
|
527
647
|
if (showData.parameters) {
|
|
528
648
|
const numCtxMatch = showData.parameters.match(/num_ctx\s+(\d+)/);
|
|
529
649
|
if (numCtxMatch) {
|
|
530
|
-
contextLength = parseInt(numCtxMatch[1], 10);
|
|
650
|
+
contextLength = positiveLimit(parseInt(numCtxMatch[1], 10));
|
|
531
651
|
}
|
|
532
652
|
}
|
|
533
653
|
}
|
|
@@ -537,14 +657,20 @@ async function getOllamaModels() {
|
|
|
537
657
|
}
|
|
538
658
|
results.push({
|
|
539
659
|
id: model.name,
|
|
660
|
+
capabilities,
|
|
540
661
|
name: model.name,
|
|
541
662
|
description: `Size: ${formatSize(model.size)}${model.details?.parameter_size ? ` (${model.details.parameter_size})` : ''}`,
|
|
542
663
|
contextLength,
|
|
664
|
+
// Ollama does not expose a separate output limit. Bound generation by
|
|
665
|
+
// the live context window so execution admission can remain fail-closed.
|
|
666
|
+
maxOutputTokens: contextLength === undefined ? undefined : Math.min(contextLength, 8192),
|
|
543
667
|
});
|
|
544
668
|
}
|
|
545
669
|
return results;
|
|
546
670
|
}
|
|
547
671
|
catch (error) {
|
|
672
|
+
if (error instanceof ModelDiscoveryError || error instanceof SyntaxError || error instanceof TypeError)
|
|
673
|
+
throw error;
|
|
548
674
|
throw new Error(`Failed to connect to Ollama at ${baseUrl}. Is Ollama running? Try: ollama serve`);
|
|
549
675
|
}
|
|
550
676
|
}
|
|
@@ -584,7 +710,7 @@ async function getLiteLLMModels() {
|
|
|
584
710
|
baseUrl = baseUrl.slice(0, -3);
|
|
585
711
|
}
|
|
586
712
|
try {
|
|
587
|
-
const response = await
|
|
713
|
+
const response = await fetchModelMetadata(`${baseUrl}/v1/models`);
|
|
588
714
|
if (!response.ok) {
|
|
589
715
|
throw new Error(`LiteLLM API error: ${response.status}`);
|
|
590
716
|
}
|
|
@@ -595,9 +721,12 @@ async function getLiteLLMModels() {
|
|
|
595
721
|
id: model.id,
|
|
596
722
|
name: model.id,
|
|
597
723
|
description: 'Proxied via LiteLLM',
|
|
724
|
+
...compatibleMetadata(model),
|
|
598
725
|
}));
|
|
599
726
|
}
|
|
600
727
|
catch (error) {
|
|
728
|
+
if (error instanceof ModelDiscoveryError || error instanceof SyntaxError || error instanceof TypeError)
|
|
729
|
+
throw error;
|
|
601
730
|
throw new Error(`Failed to connect to LiteLLM at ${baseUrl}`);
|
|
602
731
|
}
|
|
603
732
|
}
|
|
@@ -614,7 +743,7 @@ async function getBedrockModels() {
|
|
|
614
743
|
if (apiKey) {
|
|
615
744
|
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
616
745
|
}
|
|
617
|
-
const response = await
|
|
746
|
+
const response = await fetchModelMetadata(modelsUrl, { headers });
|
|
618
747
|
if (response.ok) {
|
|
619
748
|
const data = await response.json();
|
|
620
749
|
return data.data
|
|
@@ -623,7 +752,7 @@ async function getBedrockModels() {
|
|
|
623
752
|
id: model.id,
|
|
624
753
|
name: model.id,
|
|
625
754
|
description: getBedrockModelDescription(model.id),
|
|
626
|
-
|
|
755
|
+
...compatibleMetadata(model),
|
|
627
756
|
}));
|
|
628
757
|
}
|
|
629
758
|
throw new Error(`Bedrock gateway ${baseUrl} returned ${response.status}. Check BEDROCK_BASE_URL / BEDROCK_API_KEY.`);
|
|
@@ -639,12 +768,44 @@ async function getBedrockModels() {
|
|
|
639
768
|
async function resolveAwsCredentialsViaCli(profile) {
|
|
640
769
|
try {
|
|
641
770
|
const { execFileSync } = await import('child_process');
|
|
771
|
+
const signal = discoveryContext.getStore()?.signal;
|
|
772
|
+
const read = async (format) => {
|
|
773
|
+
const args = ['configure', 'export-credentials', '--profile', profile, '--format', format];
|
|
774
|
+
if (!signal)
|
|
775
|
+
return execFileSync('aws', args, { encoding: 'utf-8', timeout: 10000, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
776
|
+
throwIfCancelled(signal);
|
|
777
|
+
const { spawn } = await import('node:child_process');
|
|
778
|
+
throwIfCancelled(signal);
|
|
779
|
+
return new Promise((resolve, reject) => {
|
|
780
|
+
const capacity = new AbortController();
|
|
781
|
+
const combined = AbortSignal.any([signal, AbortSignal.timeout(10000), capacity.signal]);
|
|
782
|
+
const child = spawn('aws', args, { stdio: ['ignore', 'pipe', 'pipe'], detached: detachedProcess });
|
|
783
|
+
const cleanup = bindProcessCancellation(child, combined);
|
|
784
|
+
discoveryContext.getStore()?.cleanups.push(cleanup);
|
|
785
|
+
const chunks = [];
|
|
786
|
+
let size = 0;
|
|
787
|
+
child.stdout.on('data', (chunk) => {
|
|
788
|
+
size += chunk.length;
|
|
789
|
+
if (size > 1024 * 1024)
|
|
790
|
+
capacity.abort();
|
|
791
|
+
else
|
|
792
|
+
chunks.push(chunk);
|
|
793
|
+
});
|
|
794
|
+
child.stderr.resume();
|
|
795
|
+
child.once('error', () => { void cleanup.then(() => reject(new Error('AWS profile credential resolution failed'))); });
|
|
796
|
+
child.once('close', code => {
|
|
797
|
+
void cleanup.then(() => code === 0 && !combined.aborted
|
|
798
|
+
? resolve(Buffer.concat(chunks).toString('utf8')) : reject(new Error('AWS profile credential resolution failed')));
|
|
799
|
+
});
|
|
800
|
+
});
|
|
801
|
+
};
|
|
642
802
|
let output = '';
|
|
643
803
|
try {
|
|
644
|
-
output =
|
|
804
|
+
output = await read('env-no-export');
|
|
645
805
|
}
|
|
646
806
|
catch {
|
|
647
|
-
|
|
807
|
+
throwIfCancelled(signal);
|
|
808
|
+
output = await read('env');
|
|
648
809
|
}
|
|
649
810
|
const envs = {};
|
|
650
811
|
for (const rawLine of output.split(/\r?\n/)) {
|
|
@@ -764,7 +925,7 @@ async function discoverBedrockModelsNative() {
|
|
|
764
925
|
const signingKey = hmacFn(kService, 'aws4_request');
|
|
765
926
|
const signature = createHmac('sha256', signingKey).update(stringToSign).digest('hex');
|
|
766
927
|
headers['Authorization'] = `AWS4-HMAC-SHA256 Credential=${accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
|
|
767
|
-
return
|
|
928
|
+
return fetchModelMetadata(url, { headers });
|
|
768
929
|
};
|
|
769
930
|
// 1. ListFoundationModels (direct on-demand access).
|
|
770
931
|
// Dropped the byInferenceType=ON_DEMAND filter — newer Claude models are only
|
|
@@ -781,49 +942,55 @@ async function discoverBedrockModelsNative() {
|
|
|
781
942
|
'(2) IAM role missing bedrock:ListFoundationModels; (3) SSO token expired — run `aws sso login`.'));
|
|
782
943
|
}
|
|
783
944
|
const foundationData = await foundationResp.json();
|
|
784
|
-
|
|
945
|
+
if (!Array.isArray(foundationData.modelSummaries))
|
|
946
|
+
throw new ModelDiscoveryError('Invalid Bedrock foundation discovery');
|
|
947
|
+
const foundationModels = foundationData.modelSummaries
|
|
785
948
|
.filter(m => m.inputModalities?.includes('TEXT') && m.outputModalities?.includes('TEXT'))
|
|
786
|
-
.filter(m => bedrockSupportsConverseTools(m.modelId))
|
|
787
949
|
.map(m => ({
|
|
788
950
|
id: m.modelId,
|
|
789
951
|
name: m.modelName || m.modelId,
|
|
790
952
|
description: `${m.providerName || 'Unknown'} — ${getBedrockModelDescription(m.modelId)}`,
|
|
791
|
-
|
|
953
|
+
capabilities: { streaming: capability(m.responseStreamingSupported), vision: stringList(m.inputModalities)?.includes('IMAGE') },
|
|
792
954
|
}));
|
|
793
955
|
// 2. ListInferenceProfiles — cross-region profile IDs (e.g. us.anthropic.claude-sonnet-4-5-*).
|
|
794
956
|
// Many modern models are ONLY reachable via these, not direct foundation-model IDs.
|
|
795
957
|
// Failures here are non-fatal (older accounts / regions may not support it).
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
958
|
+
const profileModels = [], coveredBaseIds = new Set();
|
|
959
|
+
const seen = new Set();
|
|
960
|
+
let nextToken = '';
|
|
961
|
+
for (let page = 0; page < 20; page++) {
|
|
962
|
+
const profileResp = await signedGet('/inference-profiles', nextToken ? `nextToken=${encodeURIComponent(nextToken)}` : '');
|
|
963
|
+
if (!profileResp.ok)
|
|
964
|
+
break; // Profiles are optional; foundation evidence remains usable.
|
|
965
|
+
const data = await profileResp.json();
|
|
966
|
+
if (!Array.isArray(data.inferenceProfileSummaries) || profileModels.length + data.inferenceProfileSummaries.length > 10000)
|
|
967
|
+
throw new ModelDiscoveryError('Invalid Bedrock profile discovery');
|
|
968
|
+
for (const profile of data.inferenceProfileSummaries) {
|
|
969
|
+
if (profile.status === 'INACTIVE')
|
|
970
|
+
continue;
|
|
971
|
+
const baseIds = profile.models?.map(model => model.modelArn.split(':foundation-model/')[1]).filter((id) => !!id) ?? [];
|
|
972
|
+
const bases = baseIds.map(id => foundationModels.find(model => model.id === id));
|
|
973
|
+
// Only profile-provided ARNs establish a relationship to foundation models.
|
|
974
|
+
// Inherit a capability only when every regional model reports the same value.
|
|
975
|
+
const shared = (key) => {
|
|
976
|
+
const values = bases.map(model => model?.capabilities?.[key]);
|
|
977
|
+
return values.length && values.every(value => value === values[0]) ? values[0] : undefined;
|
|
978
|
+
};
|
|
979
|
+
for (const id of baseIds)
|
|
980
|
+
coveredBaseIds.add(id);
|
|
981
|
+
profileModels.push({ id: profile.inferenceProfileId, name: profile.inferenceProfileName || profile.inferenceProfileId,
|
|
982
|
+
description: 'Bedrock inference profile', capabilities: { streaming: shared('streaming'), vision: shared('vision') } });
|
|
810
983
|
}
|
|
984
|
+
if (data.nextToken == null || data.nextToken === '')
|
|
985
|
+
break;
|
|
986
|
+
if (typeof data.nextToken !== 'string' || data.nextToken.length > 2048 || seen.has(data.nextToken))
|
|
987
|
+
throw new ModelDiscoveryError('Invalid Bedrock discovery cursor');
|
|
988
|
+
seen.add(data.nextToken);
|
|
989
|
+
nextToken = data.nextToken;
|
|
990
|
+
if (page === 19)
|
|
991
|
+
throw new ModelDiscoveryError('Bedrock discovery page budget exceeded');
|
|
811
992
|
}
|
|
812
|
-
|
|
813
|
-
// Non-fatal — foundation models alone is still useful.
|
|
814
|
-
}
|
|
815
|
-
// Merge. For every inference profile, strip the region prefix (e.g. `us.`,
|
|
816
|
-
// `eu.`, `apac.`, `jp.`) to get the base foundation-model ID it wraps, and
|
|
817
|
-
// drop that base from the foundation list — because newer Claude 4.x / Haiku
|
|
818
|
-
// 4.5 models can ONLY be invoked via their inference profile on on-demand
|
|
819
|
-
// throughput. Showing both would let users pick the invokable-broken raw ID.
|
|
820
|
-
const coveredBaseIds = new Set();
|
|
821
|
-
for (const p of profileModels) {
|
|
822
|
-
const base = p.id.replace(/^[a-z]{2,5}\./, '');
|
|
823
|
-
if (base !== p.id)
|
|
824
|
-
coveredBaseIds.add(base);
|
|
825
|
-
}
|
|
826
|
-
const filteredFoundation = foundationModels.filter(m => !coveredBaseIds.has(m.id));
|
|
993
|
+
const filteredFoundation = foundationModels.filter(model => !coveredBaseIds.has(model.id));
|
|
827
994
|
const merged = new Map();
|
|
828
995
|
for (const m of filteredFoundation)
|
|
829
996
|
merged.set(m.id, m);
|
|
@@ -831,38 +998,6 @@ async function discoverBedrockModelsNative() {
|
|
|
831
998
|
merged.set(m.id, m);
|
|
832
999
|
return Array.from(merged.values()).sort((a, b) => a.id.localeCompare(b.id));
|
|
833
1000
|
}
|
|
834
|
-
/**
|
|
835
|
-
* Bedrock Converse API tool-calling support. Maintained as a local allowlist
|
|
836
|
-
* because AWS doesn't expose per-model tool capability via the list APIs.
|
|
837
|
-
* See: https://docs.aws.amazon.com/bedrock/latest/userguide/conversation-inference-supported-models-features.html
|
|
838
|
-
* Matches both raw foundation model IDs (e.g. anthropic.claude-3-5-sonnet-*)
|
|
839
|
-
* and cross-region inference profile IDs (e.g. us.anthropic.claude-sonnet-4-5-*).
|
|
840
|
-
*/
|
|
841
|
-
function bedrockSupportsConverseTools(modelId) {
|
|
842
|
-
const id = modelId.toLowerCase();
|
|
843
|
-
// Anthropic Claude 3, 3.5, 3.7, 4, 4.5 (all support tools). Excludes Claude 2.x / Instant.
|
|
844
|
-
if (/anthropic\.claude-(3|opus-4|sonnet-4|haiku-4|3-5|3-7)/.test(id))
|
|
845
|
-
return true;
|
|
846
|
-
// Amazon Nova (Pro / Lite / Micro support Converse tools; Nova Canvas/Reel are image models — excluded)
|
|
847
|
-
if (/amazon\.nova-(pro|lite|micro|premier)/.test(id))
|
|
848
|
-
return true;
|
|
849
|
-
// Cohere Command R / R+ support tools (older Command models do not)
|
|
850
|
-
if (/cohere\.command-r/.test(id))
|
|
851
|
-
return true;
|
|
852
|
-
// Mistral Large (2402, 2407), Pixtral Large, Mistral Small, Nemo
|
|
853
|
-
if (/mistral\.(mistral-large|pixtral|mistral-small|mistral-nemo)/.test(id))
|
|
854
|
-
return true;
|
|
855
|
-
// Meta Llama 3.1+ supports tools via Converse (3.0 and earlier do not)
|
|
856
|
-
if (/meta\.llama(3-1|3-2|3-3|4)/.test(id))
|
|
857
|
-
return true;
|
|
858
|
-
// AI21 Jamba 1.5 supports tools
|
|
859
|
-
if (/ai21\.jamba-1-5/.test(id))
|
|
860
|
-
return true;
|
|
861
|
-
// DeepSeek R1 supports tools
|
|
862
|
-
if (/deepseek\.r1/.test(id))
|
|
863
|
-
return true;
|
|
864
|
-
return false;
|
|
865
|
-
}
|
|
866
1001
|
function getBedrockModelDescription(modelId) {
|
|
867
1002
|
if (modelId.includes('claude') && modelId.includes('opus'))
|
|
868
1003
|
return 'Most capable Claude model on Bedrock';
|
|
@@ -880,21 +1015,6 @@ function getBedrockModelDescription(modelId) {
|
|
|
880
1015
|
return 'Cohere model on Bedrock';
|
|
881
1016
|
return 'AWS Bedrock model';
|
|
882
1017
|
}
|
|
883
|
-
function getBedrockContextLength(modelId) {
|
|
884
|
-
if (modelId.includes('claude'))
|
|
885
|
-
return 200000;
|
|
886
|
-
if (modelId.includes('llama3-1') || modelId.includes('llama3.1'))
|
|
887
|
-
return 128000;
|
|
888
|
-
if (modelId.includes('mistral-large'))
|
|
889
|
-
return 128000;
|
|
890
|
-
if (modelId.includes('command-r'))
|
|
891
|
-
return 128000;
|
|
892
|
-
if (modelId.includes('titan-text-premier'))
|
|
893
|
-
return 32000;
|
|
894
|
-
if (modelId.includes('titan-text-express'))
|
|
895
|
-
return 8192;
|
|
896
|
-
return 32000;
|
|
897
|
-
}
|
|
898
1018
|
/**
|
|
899
1019
|
* Get models from a generic OpenAI-compatible server (e.g. LM Studio, Jan, LocalAI, vLLM)
|
|
900
1020
|
*/
|
|
@@ -903,15 +1023,17 @@ async function getOpenAICompatModels() {
|
|
|
903
1023
|
if (!baseUrl.endsWith('/v1'))
|
|
904
1024
|
baseUrl = `${baseUrl}/v1`;
|
|
905
1025
|
const apiKey = config.getApiKey('openai-compat') || 'openai-compat';
|
|
906
|
-
const response = await
|
|
1026
|
+
const response = await fetchModelMetadata(`${baseUrl}/models`, {
|
|
907
1027
|
headers: { 'Authorization': `Bearer ${apiKey}` },
|
|
908
1028
|
});
|
|
909
1029
|
if (!response.ok) {
|
|
910
1030
|
throw new Error(`OpenAI-compat server error: ${response.status}`);
|
|
911
1031
|
}
|
|
912
1032
|
const data = await response.json();
|
|
913
|
-
|
|
914
|
-
|
|
1033
|
+
if (!Array.isArray(data.data))
|
|
1034
|
+
throw new ModelDiscoveryError('Invalid model discovery response');
|
|
1035
|
+
const models = data.data;
|
|
1036
|
+
return models.map(m => ({ id: m.id, name: m.id, description: 'OpenAI-compatible server', ...compatibleMetadata(m) }));
|
|
915
1037
|
}
|
|
916
1038
|
/**
|
|
917
1039
|
* Get models for OpenAI-compatible providers
|
|
@@ -920,17 +1042,27 @@ async function getOpenAICompatibleModels(provider) {
|
|
|
920
1042
|
const apiKey = config.getApiKey(provider);
|
|
921
1043
|
if (!apiKey)
|
|
922
1044
|
throw new Error(`${provider} API key not configured`);
|
|
923
|
-
const baseURL = PROVIDER_BASE_URLS[provider];
|
|
1045
|
+
const baseURL = config.getBaseUrl(provider) || PROVIDER_BASE_URLS[provider];
|
|
924
1046
|
if (!baseURL)
|
|
925
1047
|
throw new Error(`Unknown provider: ${provider}`);
|
|
926
|
-
|
|
1048
|
+
// Cerebras exposes richer limits, pricing and capability metadata on its
|
|
1049
|
+
// public catalog; the OpenAI-compatible /v1/models endpoint only returns
|
|
1050
|
+
// identifiers, which makes bounded tool execution impossible to quote.
|
|
1051
|
+
if (provider === 'cerebras') {
|
|
1052
|
+
const publicUrl = `${new URL(baseURL).origin}/public/v1/models`;
|
|
1053
|
+
const metadataResponse = await fetchModelMetadata(publicUrl, { headers: { Authorization: `Bearer ${apiKey}` } });
|
|
1054
|
+
if (metadataResponse.ok) {
|
|
1055
|
+
const payload = await metadataResponse.json();
|
|
1056
|
+
if (!Array.isArray(payload.data))
|
|
1057
|
+
throw new ModelDiscoveryError('Invalid Cerebras model discovery response');
|
|
1058
|
+
return payload.data
|
|
1059
|
+
.filter(model => { const id = typeof model === 'object' && model !== null ? model.id : undefined; return typeof id === 'string' && isCompatibleModel(id, provider); })
|
|
1060
|
+
.map(model => { const id = model.id; return { id, name: id, ...compatibleMetadata(model) }; });
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
const client = new OpenAI({ apiKey, baseURL, ...discoveryTransportOptions() });
|
|
927
1064
|
const response = await client.models.list();
|
|
928
|
-
return response.data
|
|
929
|
-
.filter(model => isCompatibleModel(model.id, provider))
|
|
930
|
-
.map(model => ({
|
|
931
|
-
id: model.id,
|
|
932
|
-
name: model.id,
|
|
933
|
-
}));
|
|
1065
|
+
return response.data.filter(model => isCompatibleModel(model.id, provider)).map(model => ({ id: model.id, name: model.id, ...compatibleMetadata(model) }));
|
|
934
1066
|
}
|
|
935
1067
|
/**
|
|
936
1068
|
* Helper functions for model descriptions
|
|
@@ -989,36 +1121,42 @@ function formatSize(bytes) {
|
|
|
989
1121
|
export function clearModelCache(provider) {
|
|
990
1122
|
if (provider) {
|
|
991
1123
|
modelCache.delete(provider);
|
|
1124
|
+
previousDiscovery.delete(provider);
|
|
992
1125
|
}
|
|
993
1126
|
else {
|
|
994
1127
|
modelCache.clear();
|
|
1128
|
+
previousDiscovery.clear();
|
|
995
1129
|
}
|
|
996
1130
|
}
|
|
997
1131
|
/**
|
|
998
1132
|
* Pre-warm model cache for configured providers
|
|
999
1133
|
* Runs in background, doesn't block startup
|
|
1000
1134
|
*/
|
|
1001
|
-
export async function preWarmModelCache() {
|
|
1135
|
+
export async function preWarmModelCache(parentSignal) {
|
|
1002
1136
|
const configuredProviders = config.getConfiguredProviders();
|
|
1137
|
+
const deadline = AbortSignal.timeout(30000);
|
|
1138
|
+
const signal = parentSignal ? AbortSignal.any([parentSignal, deadline]) : deadline;
|
|
1003
1139
|
// Fetch models for all configured providers in parallel
|
|
1004
|
-
await Promise.allSettled(configuredProviders.map(provider => getAvailableModels(provider, { quiet: true })));
|
|
1140
|
+
await Promise.allSettled(configuredProviders.map(provider => getAvailableModels(provider, { quiet: true, signal })));
|
|
1005
1141
|
}
|
|
1006
1142
|
/**
|
|
1007
1143
|
* Get model info from cache by ID
|
|
1008
1144
|
*/
|
|
1009
1145
|
export function getModelInfo(provider, modelId) {
|
|
1010
1146
|
const cached = modelCache.get(provider);
|
|
1011
|
-
if (!cached)
|
|
1147
|
+
if (!cached || cached.target !== modelCacheTarget(provider) || Date.now() - cached.timestamp >= CACHE_DURATION)
|
|
1012
1148
|
return undefined;
|
|
1013
1149
|
// Exact match first.
|
|
1014
|
-
const exact = cached.models.find(m => m.id === modelId);
|
|
1150
|
+
const exact = cached.models.find(m => m.id === modelId || m.aliases?.includes(modelId));
|
|
1015
1151
|
if (exact)
|
|
1016
|
-
return exact;
|
|
1152
|
+
return structuredClone(exact);
|
|
1153
|
+
if (cached.models.every(model => model.evidence?.source === 'live'))
|
|
1154
|
+
return undefined;
|
|
1017
1155
|
// Otherwise only accept an UNAMBIGUOUS prefix relationship. Loose substring
|
|
1018
1156
|
// matching wrongly resolved e.g. `gpt-4` -> `gpt-4o` or `claude-opus-4` ->
|
|
1019
1157
|
// `claude-opus-4-8`, returning a different model's context/pricing.
|
|
1020
1158
|
const related = cached.models.filter(m => m.id.startsWith(modelId) || modelId.startsWith(m.id));
|
|
1021
|
-
return related.length === 1 ? related[0] : undefined;
|
|
1159
|
+
return related.length === 1 ? structuredClone(related[0]) : undefined;
|
|
1022
1160
|
}
|
|
1023
1161
|
/**
|
|
1024
1162
|
* Default context limits by model family (fallback when API doesn't provide it)
|