chainlesschain 0.166.77 → 0.166.79
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 +9 -8
- package/completions/_cc +1 -1
- package/completions/cc.bash +1 -1
- package/completions/cc.fish +1 -1
- package/completions/cc.ps1 +1 -1
- package/package.json +1 -1
- package/src/assets/linux-subreaper/linux-arm64/manifest.json +10 -0
- package/src/assets/linux-subreaper/linux-arm64/supervisor +0 -0
- package/src/assets/linux-subreaper/linux-x64/manifest.json +10 -0
- package/src/assets/linux-subreaper/linux-x64/supervisor +0 -0
- package/src/assets/web-panel/assets/{AIOps-CpiCBhRh.js → AIOps-CwD6Pm_Y.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CnU-Xvx-.js → ActionButton-Du5Rp-O6.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BJW-CNtf.js → Analytics-DY9l72ma.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-UFQJL3G9.js → AppLayout-7t1WIaCJ.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-Dr_IUDoY.js → Artifacts-BLIA5yny.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-aglWo6rr.js → Audit-BC_N0QTg.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-Dm_TCiXC.js → BackgroundAgents-CA7SxDtg.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DUdX4-gA.js → Backup-BZ4AzS1_.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BTcLjy1o.js → BaseInput-BhiggGaH.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-Bhy9qZrl.js → Chat-CDdBoIBI.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-hsBsrl31.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-CblrPa21.js → Checkbox-asoMKSEK.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-SEAHzOlr.js → Codegen-B0gElLdm.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DJz8iFOR.js → Col-DrNzLpF6.js} +1 -1
- package/src/assets/web-panel/assets/{Community-RufKhcQt.js → Community-DCzB5qkI.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Dlifx08U.js → Compact-Db-Eua_j.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-DdhQWcHh.js → Compliance-B76NByjl.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BLNn6oOm.js → Cowork-C-nK6Qpk.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-Dv-JWY2d.js → Cron-C-GlQO19.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-k7Pz7O-b.js → Crosschain-Cuuz9IIh.js} +1 -1
- package/src/assets/web-panel/assets/{DID-C_10syUW.js → DID-gwFaT973.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CMyH6Szx.js → Dashboard-DHDt5jEf.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DjmD2Saa.js → Dropdown-CJ9kog-Y.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-36_IRUSo.js → EmailListRenderer-DOSXFRiQ.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-CmtU0XmM.js → EvolutionSettings-CHYMP7rR.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DEgf9kyP.js → FamilyGuardDashboard-C1gzG5EK.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DGO1wQls.js → Federation-CEdNVWUw.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Doj1FmKW.js → FormItemContext-CwVOWPX8.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-GzOU27iT.js → GenericCardRenderer-CgNUs3kT.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Dd7D1EDK.js → Git-DM4MNnQo.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-6IY8LcjI.js → Governance-DdOtjkvd.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BB9gl8q1.js → Inference-28PidFfr.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CeCed5wd.js → KnowledgeGraph-Bpj_qNUK.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CYOeHuaI.js → Logs-C6Ix19Ay.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-Bk8Zqc2R.js → MarkdownRenderer-Bj6mtPbf.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-D-_xgHgM.js → Marketplace-DqkhRSMP.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-NnaUTF5t.js → McpTools-1WQ2SjaE.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-CndN9pMt.js → Memory-BWTi7v6R.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BXblFmhY.js → MobileBridge-DB4wu3UE.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-CC26Dm2k.js → MobileProjects-Bh9pWx2f.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BhaqWCiW.js → Mtc-BVF1Wrno.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-D6fktM2w.js → MtcAudit-DtNfslPf.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-CFvahz7s.js → Multisig-4qcXP0bf.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Co73Ivya.js → NLProgramming-BRJl5Ehw.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-B4g33L1o.js → Notes-BRY_bgMk.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-lXd17EbN.js → NotificationSettings-DirXMFz4.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-BiOB0GIi.js → OrderTableRenderer-BlrY8lwu.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-JQ7_wQIA.js → Organization-CVzQ1vO-.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-gwgJgozQ.js → Overflow-A3rXTPG4.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-D9L_0gie.js → P2P-Db9ABWz0.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CbOPsFE9.js → PdhVaultBrowser-CPv0H2OZ.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-Cz42HNQf.js → Permissions-COnW4sIR.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-DjorYtrF.js → PersonalDataHub-C1hG7rp7.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-DyWPhmm5.js → Pipeline---GLRDEe.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DyfLMl2j.js → Privacy-aaN9R3Lu.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CyqDx1OE.js → ProjectInit-C-kw49hE.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DsBw0Csy.js → ProjectSettings-y5tTkBTC.js} +2 -2
- package/src/assets/web-panel/assets/Projects-DZHlhyPB.js +1 -0
- package/src/assets/web-panel/assets/{Providers-CCI_klN-.js → Providers-LqxnV72o.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DNsnlDdS.js → QrScannerModal-D_q-Y5F0.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-B9r2iaee.js → QuickAsk-_E_KB5o8.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BJDe03GR.js → Recommend-BN8S5WJA.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-J7JR3rRo.js → RemoteSession-BFzrY_aW.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-DR39AJeV.js → Reputation-C1HCLaTV.js} +1 -1
- package/src/assets/web-panel/assets/{Row-Dh77m3NZ.js → Row-B8T2-Qv7.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BUdg28nJ.js → RssFeed-CNQLk8v1.js} +3 -3
- package/src/assets/web-panel/assets/{Search-BNC7sGhj.js → Search-BOx720Kc.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DISENGI7.js → Security-Ds8z6PF6.js} +4 -4
- package/src/assets/web-panel/assets/{Services-BBBGpJ1-.js → Services-C0-YkRSF.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DMcIoIv2.js → Skeleton-DUHlSySD.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-QAyFbI3r.js → Skills-C8CBbbh0.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CSg5wLH7.js → Sla-lQltyYfB.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DMPxTc5x.js → SpeechSettings-B5vyOma-.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CPG7l30y.js → SyncSettings-BKDPu_y-.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-Y1kOVvVL.js → Tasks-Bgvf7LTx.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-jt9NagL0.js → Templates-BMZyYYS7.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DauuJICx.js → Tenant-7PYTig8f.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-E9rnKeGq.js → Terminal-C2W0LMdR.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-Cc7z2APG.js → TimelineRenderer-CqREew_l.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CV0UthRA.js → Tokens-BhTyxTuD.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BFcJJGfu.js → Trigger-DxNSSZy_.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BAydbNJA.js → Trust-Dy_wfbIh.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DcOS6sqL.js → UkeySign-DJC5ANqx.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BLHJZvif.js → VideoEditing-CNFevrO4.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-4QFLKHwW.js → Wallet-CXzuS1YK.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-BocEOOSj.js → WebAuthn-BWS6HP8c.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-DCfF7D0B.js → WorkflowEditor-swiN_7Vj.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CxvfsYGr.js → chat-NwH7qlBs.js} +1 -1
- package/src/assets/web-panel/assets/{colors-KtQB9DmQ.js → colors-h6nRhBTw.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-Dx4J6arN.js → compact-item-BQ6B6rP2.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-Cq0olgzo.js → createContext-CQkJuRcG.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-Bz6vqBGV.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-Bf9-h3D-.js → hasIn-Diwl1WyI.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpO6DKuu.js → index-0ZztPzIm.js} +1 -1
- package/src/assets/web-panel/assets/index-1b7DEw-w.js +1 -0
- package/src/assets/web-panel/assets/{index-DQDR-_ai.js → index-AzeSQJDK.js} +1 -1
- package/src/assets/web-panel/assets/{index-BMcC4cbj.js → index-B3QgcUBV.js} +1 -1
- package/src/assets/web-panel/assets/{index-BO6XvO-C.js → index-B5gj_uCC.js} +1 -1
- package/src/assets/web-panel/assets/{index-ClUfSChI.js → index-BI3ALCgN.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3xfiItB.js → index-BRl3KUj0.js} +1 -1
- package/src/assets/web-panel/assets/{index-DFdEDvFn.js → index-BYYb8oeV.js} +1 -1
- package/src/assets/web-panel/assets/{index-CqnggDos.js → index-BcKDUGYf.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_8UcDan.js → index-BcjlIMP9.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmQuG0fr.js → index-BheCvudN.js} +1 -1
- package/src/assets/web-panel/assets/{index-iE9tqEN5.js → index-BjcARUtr.js} +1 -1
- package/src/assets/web-panel/assets/{index-nmyDOh_b.js → index-BnQUin2K.js} +1 -1
- package/src/assets/web-panel/assets/{index-Br1mDMfO.js → index-Bs6HyCfP.js} +1 -1
- package/src/assets/web-panel/assets/{index-DZWjYfWt.js → index-BvPz6vZ8.js} +1 -1
- package/src/assets/web-panel/assets/{index-0fi8DIVQ.js → index-C3Ye1ISy.js} +1 -1
- package/src/assets/web-panel/assets/{index-hSzyoXri.js → index-C7-T-u0L.js} +3 -3
- package/src/assets/web-panel/assets/{index-DfrFNMvz.js → index-CRWpixu2.js} +1 -1
- package/src/assets/web-panel/assets/{index-C9yaUHm9.js → index-CatBQDSQ.js} +1 -1
- package/src/assets/web-panel/assets/index-CfD4tMuW.js +1 -0
- package/src/assets/web-panel/assets/{index-DMR-keCL.js → index-CqH-oOR3.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cy865Hhq.js → index-CwsoVDi-.js} +1 -1
- package/src/assets/web-panel/assets/{index-DI5bRqNG.js → index-CyBtEVLM.js} +1 -1
- package/src/assets/web-panel/assets/{index-gt5N6VM_.js → index-D5P498Rk.js} +1 -1
- package/src/assets/web-panel/assets/{index-6dDDSCHD.js → index-DKaB4xTf.js} +1 -1
- package/src/assets/web-panel/assets/{index-BKtQyb2o.js → index-DQYZa1Ci.js} +1 -1
- package/src/assets/web-panel/assets/{index-CaIclw-E.js → index-DZ9CNcbJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-_FIz-0tp.js → index-DZAsByy4.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBRlZdZj.js → index-D_HY0nyN.js} +1 -1
- package/src/assets/web-panel/assets/{index-DsCdl2Od.js → index-Da8frO_A.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cfsn7N18.js → index-DjB8IC9D.js} +1 -1
- package/src/assets/web-panel/assets/{index-CeYP_kT9.js → index-Dwpthe2b.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8WuPI-h.js → index-Fm95dO4u.js} +1 -1
- package/src/assets/web-panel/assets/{index-CK2U_AHi.js → index-GTefQSbY.js} +1 -1
- package/src/assets/web-panel/assets/{index-DnU-dUWd.js → index-OEWSrqit.js} +1 -1
- package/src/assets/web-panel/assets/{index-DDAe1UmZ.js → index-TYMmUsxZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-D2BfSIrn.js → index-iHNOr_wL.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cz7f4Jaq.js → index-mxxZtsHp.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHmdMKYl.js → index-pYwYBVeQ.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DvzKJ6o5.js → initDefaultProps-BeUrpC_H.js} +1 -1
- package/src/assets/web-panel/assets/{motion-D1yTvmxW.js → motion-CHW5EXt1.js} +1 -1
- package/src/assets/web-panel/assets/{move-DxtSIF8K.js → move-CWaoWJvF.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BDsQgIHY.js → mtc-parser-CEC6Us1u.js} +1 -1
- package/src/assets/web-panel/assets/{omit-UVBJW8kh.js → omit-1D-kP_Qj.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-D4QqtTyX.js → pickAttrs-CsS0myLl.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-QXmu6vBf.js → placementArrow-bMThOvkI.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-D-PmXO9M.js → responsiveObserve-B72knbW8.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CKbGxEZJ.js → slide-C3bI_2yy.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BbgXPkXm.js → statusUtils-0-FmcCAS.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DOr9rk68.js → styleChecker-DXUyqoWY.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-B2wO2r36.js → useFlexGapSupport-BSSnL3f1.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-SeVGBK34.js → useFs-B0Cvvl0S.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DUJBCxjD.js → usePersonalDataHub-6D-d4WU5.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CF4EYsig.js → vnode-zjIrlxT_.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-pRUs5pqI.js → zoom-Hw7NEisu.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +1 -1
- package/src/command-manifest.json +1 -1
- package/src/commands/checkpoint.js +42 -7
- package/src/commands/orchestrate.js +85 -25
- package/src/commands/session-location.js +5 -0
- package/src/commands/session-show.js +109 -1
- package/src/commands/session.js +26 -2
- package/src/commands/tokens.js +9 -4
- package/src/data/changelog.json +26 -0
- package/src/generated/cc-agent-protocol.schema.json +71 -0
- package/src/harness/jsonl-session-store.js +357 -114
- package/src/harness/mcp-client.js +44 -1
- package/src/lib/agent-router.js +35 -7
- package/src/lib/agent-sandbox.js +302 -2
- package/src/lib/app-server/server.js +14 -0
- package/src/lib/background-agent-supervisor.js +14 -4
- package/src/lib/causal-observability.js +64 -1
- package/src/lib/checkpoint-summary-projection.js +98 -0
- package/src/lib/checkpoint-timeline-authority.js +15 -51
- package/src/lib/claude-code-bridge.js +302 -60
- package/src/lib/codex-app-server-adapter.js +161 -35
- package/src/lib/cost-budget.js +4 -0
- package/src/lib/doctor-checkup.js +31 -2
- package/src/lib/durable-security-store.js +6 -1
- package/src/lib/evolution/evolution-artifact-identity.js +21 -0
- package/src/lib/evolution/evolution-artifact-ports.js +5 -11
- package/src/lib/evolution/evolution-eval-cohort-receipt-reconciliation.js +389 -0
- package/src/lib/execution-location-failure-site.js +63 -0
- package/src/lib/execution-location-target.js +102 -8
- package/src/lib/external-agent-adapters.js +2 -0
- package/src/lib/image-file-boundary.js +154 -0
- package/src/lib/image-input.js +16 -3
- package/src/lib/llm-pricing.js +114 -8
- package/src/lib/lsp/code-intelligence.js +7 -1
- package/src/lib/mcp-call-ledger-store.js +7 -2
- package/src/lib/model-capabilities.js +21 -10
- package/src/lib/model-context-catalog.js +60 -1
- package/src/lib/openai-responses.js +7 -1
- package/src/lib/orchestrator.js +8 -2
- package/src/lib/process-execution-broker/index.js +93 -1
- package/src/lib/process-execution-broker/linux-subreaper-artifact.js +120 -0
- package/src/lib/process-execution-broker/linux-subreaper-helper.js +344 -0
- package/src/lib/process-execution-broker/linux-subreaper-process.js +326 -0
- package/src/lib/process-execution-broker/linux-subreaper-supervisor.c +360 -0
- package/src/lib/process-execution-broker/owned-posix-process-group-worker.mjs +131 -0
- package/src/lib/process-execution-broker/owned-posix-process-group.js +267 -0
- package/src/lib/process-execution-broker/process-ownership-journal.js +297 -0
- package/src/lib/process-execution-broker/process-ownership-quarantine.js +91 -0
- package/src/lib/runtime-usage-ledger.js +3 -0
- package/src/lib/sandbox-docker-egress.js +507 -0
- package/src/lib/sandbox-egress-proxy.js +167 -10
- package/src/lib/sandbox-egress-worker-thread.js +38 -0
- package/src/lib/sandbox-egress-worker.js +196 -0
- package/src/lib/secure-fs.js +158 -42
- package/src/lib/session-branch-history.js +240 -0
- package/src/lib/session-history-origins.js +285 -0
- package/src/lib/session-input-receipt.js +110 -0
- package/src/lib/session-resource-budget.js +8 -8
- package/src/lib/session-transcript-history.js +456 -0
- package/src/lib/session-transcript-page.js +164 -0
- package/src/lib/session-transcript-reference.js +38 -0
- package/src/lib/session-usage.js +8 -0
- package/src/lib/token-tracker.js +32 -54
- package/src/lib/usage-pricing-context.js +93 -0
- package/src/runtime/agent-core.js +141 -21
- package/src/runtime/headless-stream.js +202 -4
- package/src/assets/web-panel/assets/ChatBubbleRenderer-D0WrJQaQ.js +0 -1
- package/src/assets/web-panel/assets/Projects-CRaSI25Z.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CmgDNkoO.js +0 -1
- package/src/assets/web-panel/assets/index-BpIZ2S01.js +0 -1
- package/src/assets/web-panel/assets/index-C-VmKuyv.js +0 -1
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
|
|
3
|
+
// CLI keeps its existing eight-image allowance; IDE composers admit four.
|
|
4
|
+
export const MAX_INPUT_IMAGES = 8;
|
|
5
|
+
export const MAX_INPUT_IMAGE_BYTES = 20 * 1024 * 1024;
|
|
6
|
+
export const MAX_INPUT_IMAGE_PIXELS = 40_000_000;
|
|
7
|
+
const MAX_HEADER_BYTES = 1024 * 1024;
|
|
8
|
+
|
|
9
|
+
/** Header admission only, not a full codec decode or animation-frame budget. */
|
|
10
|
+
export function inspectImageHeader(data) {
|
|
11
|
+
const ascii = (start, end) => data.toString("ascii", start, end);
|
|
12
|
+
if (
|
|
13
|
+
data.length >= 33 &&
|
|
14
|
+
data
|
|
15
|
+
.subarray(0, 8)
|
|
16
|
+
.equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10])) &&
|
|
17
|
+
data.readUInt32BE(8) === 13 &&
|
|
18
|
+
ascii(12, 16) === "IHDR"
|
|
19
|
+
) {
|
|
20
|
+
return {
|
|
21
|
+
mediaType: "image/png",
|
|
22
|
+
width: data.readUInt32BE(16),
|
|
23
|
+
height: data.readUInt32BE(20),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
if (data.length >= 13 && ["GIF87a", "GIF89a"].includes(ascii(0, 6))) {
|
|
27
|
+
return {
|
|
28
|
+
mediaType: "image/gif",
|
|
29
|
+
width: data.readUInt16LE(6),
|
|
30
|
+
height: data.readUInt16LE(8),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (data.length >= 30 && ascii(0, 4) === "RIFF" && ascii(8, 12) === "WEBP") {
|
|
34
|
+
const kind = ascii(12, 16);
|
|
35
|
+
if (kind === "VP8X")
|
|
36
|
+
return {
|
|
37
|
+
mediaType: "image/webp",
|
|
38
|
+
width: data.readUIntLE(24, 3) + 1,
|
|
39
|
+
height: data.readUIntLE(27, 3) + 1,
|
|
40
|
+
};
|
|
41
|
+
if (
|
|
42
|
+
kind === "VP8 " &&
|
|
43
|
+
data[23] === 157 &&
|
|
44
|
+
data[24] === 1 &&
|
|
45
|
+
data[25] === 42
|
|
46
|
+
)
|
|
47
|
+
return {
|
|
48
|
+
mediaType: "image/webp",
|
|
49
|
+
width: data.readUInt16LE(26) & 16383,
|
|
50
|
+
height: data.readUInt16LE(28) & 16383,
|
|
51
|
+
};
|
|
52
|
+
if (kind === "VP8L" && data[20] === 47) {
|
|
53
|
+
const bits = data.readUInt32LE(21);
|
|
54
|
+
return {
|
|
55
|
+
mediaType: "image/webp",
|
|
56
|
+
width: (bits & 16383) + 1,
|
|
57
|
+
height: ((bits >>> 14) & 16383) + 1,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (data.length >= 4 && data[0] === 255 && data[1] === 216) {
|
|
62
|
+
let offset = 2;
|
|
63
|
+
while (offset + 4 <= data.length) {
|
|
64
|
+
if (data[offset++] !== 255) break;
|
|
65
|
+
while (data[offset] === 255) offset++;
|
|
66
|
+
const marker = data[offset++];
|
|
67
|
+
if (marker === 217 || marker === 218) break;
|
|
68
|
+
if (marker === 1 || (marker >= 208 && marker <= 215)) continue;
|
|
69
|
+
if (offset + 2 > data.length) break;
|
|
70
|
+
const length = data.readUInt16BE(offset);
|
|
71
|
+
if (length < 2 || offset + length > data.length) break;
|
|
72
|
+
if (
|
|
73
|
+
[
|
|
74
|
+
192, 193, 194, 195, 197, 198, 199, 201, 202, 203, 205, 206, 207,
|
|
75
|
+
].includes(marker) &&
|
|
76
|
+
length >= 8
|
|
77
|
+
) {
|
|
78
|
+
return {
|
|
79
|
+
mediaType: "image/jpeg",
|
|
80
|
+
width: data.readUInt16BE(offset + 5),
|
|
81
|
+
height: data.readUInt16BE(offset + 3),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
offset += length;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
throw new Error(
|
|
88
|
+
"Unsupported or malformed image header (dimensions must occur within the first 1 MiB)",
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function readAtMost(io, fd, data) {
|
|
93
|
+
let offset = 0;
|
|
94
|
+
while (offset < data.length) {
|
|
95
|
+
const count = io.readSync(fd, data, offset, data.length - offset, offset);
|
|
96
|
+
if (count === 0) break;
|
|
97
|
+
offset += count;
|
|
98
|
+
}
|
|
99
|
+
return offset;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Pin one regular-file descriptor and cap allocation/read even if it grows. */
|
|
103
|
+
export function readBoundedImage(
|
|
104
|
+
file,
|
|
105
|
+
expectedMediaType,
|
|
106
|
+
remainingBytes,
|
|
107
|
+
io = fs,
|
|
108
|
+
) {
|
|
109
|
+
// O_NONBLOCK avoids hanging while opening a FIFO on POSIX. fstat then
|
|
110
|
+
// rejects all non-regular files; Windows has no O_NONBLOCK flag here.
|
|
111
|
+
const fd = io.openSync(
|
|
112
|
+
file,
|
|
113
|
+
fs.constants.O_RDONLY | (fs.constants.O_NONBLOCK || 0),
|
|
114
|
+
);
|
|
115
|
+
try {
|
|
116
|
+
const before = io.fstatSync(fd);
|
|
117
|
+
if (!before.isFile()) throw new Error("Image input must be a regular file");
|
|
118
|
+
if (
|
|
119
|
+
!Number.isSafeInteger(before.size) ||
|
|
120
|
+
before.size <= 0 ||
|
|
121
|
+
before.size > MAX_INPUT_IMAGE_BYTES
|
|
122
|
+
)
|
|
123
|
+
throw new Error("Image must contain 1 byte to 20 MiB");
|
|
124
|
+
if (before.size > remainingBytes)
|
|
125
|
+
throw new Error("Total image attachments exceed 20 MiB per message");
|
|
126
|
+
const header = Buffer.alloc(Math.min(before.size, MAX_HEADER_BYTES));
|
|
127
|
+
const headerSize = readAtMost(io, fd, header);
|
|
128
|
+
const info = inspectImageHeader(header.subarray(0, headerSize));
|
|
129
|
+
if (info.mediaType !== expectedMediaType)
|
|
130
|
+
throw new Error("Image extension does not match its file header");
|
|
131
|
+
if (
|
|
132
|
+
!info.width ||
|
|
133
|
+
!info.height ||
|
|
134
|
+
info.width * info.height > MAX_INPUT_IMAGE_PIXELS
|
|
135
|
+
)
|
|
136
|
+
throw new Error(
|
|
137
|
+
"Image dimensions must be positive and at most 40 megapixels",
|
|
138
|
+
);
|
|
139
|
+
const data = Buffer.alloc(before.size + 1);
|
|
140
|
+
const count = readAtMost(io, fd, data);
|
|
141
|
+
const after = io.fstatSync(fd);
|
|
142
|
+
if (
|
|
143
|
+
count !== before.size ||
|
|
144
|
+
after.size !== before.size ||
|
|
145
|
+
after.mtimeMs !== before.mtimeMs ||
|
|
146
|
+
after.ctimeMs !== before.ctimeMs ||
|
|
147
|
+
!data.subarray(0, headerSize).equals(header.subarray(0, headerSize))
|
|
148
|
+
)
|
|
149
|
+
throw new Error("Image changed while being read; select it again");
|
|
150
|
+
return data.subarray(0, count);
|
|
151
|
+
} finally {
|
|
152
|
+
io.closeSync(fd);
|
|
153
|
+
}
|
|
154
|
+
}
|
package/src/lib/image-input.js
CHANGED
|
@@ -15,6 +15,11 @@
|
|
|
15
15
|
import fs from "fs";
|
|
16
16
|
import path from "path";
|
|
17
17
|
import os from "os";
|
|
18
|
+
import {
|
|
19
|
+
MAX_INPUT_IMAGES,
|
|
20
|
+
MAX_INPUT_IMAGE_BYTES,
|
|
21
|
+
readBoundedImage,
|
|
22
|
+
} from "./image-file-boundary.js";
|
|
18
23
|
|
|
19
24
|
/**
|
|
20
25
|
* Candidate on-disk forms for a path token typed in a prompt, so a path copied
|
|
@@ -66,7 +71,10 @@ const EXT_MEDIA = {
|
|
|
66
71
|
export function resolveImages(paths, deps = {}) {
|
|
67
72
|
const _fs = deps.fs || fs;
|
|
68
73
|
if (!Array.isArray(paths) || paths.length === 0) return [];
|
|
69
|
-
|
|
74
|
+
if (paths.length > MAX_INPUT_IMAGES)
|
|
75
|
+
throw new Error(`Attach at most ${MAX_INPUT_IMAGES} images per message`);
|
|
76
|
+
let remainingBytes = MAX_INPUT_IMAGE_BYTES;
|
|
77
|
+
return paths.map((p, index) => {
|
|
70
78
|
const ext = path.extname(String(p)).toLowerCase();
|
|
71
79
|
const mediaType = EXT_MEDIA[ext];
|
|
72
80
|
if (!mediaType) {
|
|
@@ -74,8 +82,13 @@ export function resolveImages(paths, deps = {}) {
|
|
|
74
82
|
`Unsupported image type "${ext || p}" — use png/jpg/jpeg/gif/webp.`,
|
|
75
83
|
);
|
|
76
84
|
}
|
|
77
|
-
|
|
78
|
-
|
|
85
|
+
try {
|
|
86
|
+
const data = readBoundedImage(p, mediaType, remainingBytes, _fs);
|
|
87
|
+
remainingBytes -= data.length;
|
|
88
|
+
return { mediaType, data: data.toString("base64") };
|
|
89
|
+
} catch (error) {
|
|
90
|
+
throw new Error(`Image ${index + 1}: ${error.message}`, { cause: error });
|
|
91
|
+
}
|
|
79
92
|
});
|
|
80
93
|
}
|
|
81
94
|
|
package/src/lib/llm-pricing.js
CHANGED
|
@@ -15,6 +15,12 @@
|
|
|
15
15
|
* substring against the model id.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
import {
|
|
19
|
+
DOCUMENTED_OPENAI_MODELS,
|
|
20
|
+
DOCUMENTED_ANTHROPIC_MODELS,
|
|
21
|
+
GPT6_PRICING_TERMS,
|
|
22
|
+
} from "./model-context-catalog.js";
|
|
23
|
+
|
|
18
24
|
/** Providers whose models run locally and cost nothing to call. */
|
|
19
25
|
export const FREE_PROVIDERS = Object.freeze([
|
|
20
26
|
"ollama",
|
|
@@ -30,6 +36,11 @@ export const FREE_PROVIDERS = Object.freeze([
|
|
|
30
36
|
*/
|
|
31
37
|
export const PRICE_TABLE = Object.freeze({
|
|
32
38
|
anthropic: [
|
|
39
|
+
...Object.entries(DOCUMENTED_ANTHROPIC_MODELS).map(([match, model]) => ({
|
|
40
|
+
match,
|
|
41
|
+
...model.pricing,
|
|
42
|
+
exact: true,
|
|
43
|
+
})),
|
|
33
44
|
// Current Anthropic list prices (USD per 1M tokens), verified 2026-06-21
|
|
34
45
|
// against the claude-api reference. The Opus tier dropped to $5/$25 with
|
|
35
46
|
// Opus 4.5 (Nov 2025) — the old $15/$75 applies only to the retired
|
|
@@ -47,6 +58,14 @@ export const PRICE_TABLE = Object.freeze({
|
|
|
47
58
|
{ match: "haiku", in: 1, out: 5 },
|
|
48
59
|
],
|
|
49
60
|
openai: [
|
|
61
|
+
...Object.entries(DOCUMENTED_OPENAI_MODELS)
|
|
62
|
+
.filter(([, model]) => model.pricing)
|
|
63
|
+
.map(([match, model]) => ({
|
|
64
|
+
match,
|
|
65
|
+
...model.pricing,
|
|
66
|
+
exact: true,
|
|
67
|
+
terms: GPT6_PRICING_TERMS,
|
|
68
|
+
})),
|
|
50
69
|
// GPT-5 family (2026). Matching is longest-pattern-first, so dated/variant
|
|
51
70
|
// ids (gpt-5.5, gpt-5.5-pro, gpt-5.5-instant, …) resolve to the most
|
|
52
71
|
// specific rate; bare "gpt-5" is the catch-all base rate.
|
|
@@ -64,6 +83,10 @@ export const PRICE_TABLE = Object.freeze({
|
|
|
64
83
|
{ match: "o1-mini", in: 1.1, out: 4.4 },
|
|
65
84
|
{ match: "o1", in: 15, out: 60 },
|
|
66
85
|
],
|
|
86
|
+
dashscope: [
|
|
87
|
+
{ match: "qwen-turbo", in: 0.3, out: 0.6 },
|
|
88
|
+
{ match: "qwen-plus", in: 0.8, out: 2 },
|
|
89
|
+
],
|
|
67
90
|
deepseek: [
|
|
68
91
|
// DeepSeek V4 launch-list rates for the versioned 2026-04 model ids.
|
|
69
92
|
// Keep these ahead of the legacy aliases so formal budget gates never
|
|
@@ -139,9 +162,13 @@ export function mergePricing(overrides, base = PRICE_TABLE) {
|
|
|
139
162
|
Number(e.out) >= 0,
|
|
140
163
|
)
|
|
141
164
|
.map((e) => ({
|
|
165
|
+
...(base[providerKey]?.find(
|
|
166
|
+
(entry) => entry.match === e.match.toLowerCase(),
|
|
167
|
+
) || {}),
|
|
142
168
|
match: e.match.toLowerCase(),
|
|
143
169
|
in: Number(e.in),
|
|
144
170
|
out: Number(e.out),
|
|
171
|
+
explicitOverride: true,
|
|
145
172
|
}));
|
|
146
173
|
if (valid.length === 0) continue;
|
|
147
174
|
const overridden = new Set(valid.map((v) => v.match));
|
|
@@ -171,8 +198,23 @@ export function lookupRate(provider, model, table = PRICE_TABLE) {
|
|
|
171
198
|
// Longest pattern first so specific beats generic regardless of table order.
|
|
172
199
|
const sorted = [...entries].sort((a, b) => b.match.length - a.match.length);
|
|
173
200
|
for (const e of sorted) {
|
|
174
|
-
if (m.includes(e.match)) {
|
|
175
|
-
|
|
201
|
+
if (e.exact ? m === e.match : m.includes(e.match)) {
|
|
202
|
+
// An unrecognized new version must not inherit an older Opus price.
|
|
203
|
+
// Explicit operator overrides remain authoritative.
|
|
204
|
+
if (
|
|
205
|
+
e.match === "opus" &&
|
|
206
|
+
Number(/^claude-opus-(\d+)(?:[.-]|$)/u.exec(m)?.[1]) >= 5 &&
|
|
207
|
+
!e.explicitOverride &&
|
|
208
|
+
e.in === 5 &&
|
|
209
|
+
e.out === 25
|
|
210
|
+
)
|
|
211
|
+
continue;
|
|
212
|
+
return {
|
|
213
|
+
in: e.in,
|
|
214
|
+
out: e.out,
|
|
215
|
+
pattern: e.match,
|
|
216
|
+
...(e.terms ? { terms: e.terms } : {}),
|
|
217
|
+
};
|
|
176
218
|
}
|
|
177
219
|
}
|
|
178
220
|
return null;
|
|
@@ -210,10 +252,18 @@ export function estimateCost({
|
|
|
210
252
|
outputTokens = 0,
|
|
211
253
|
cacheReadTokens = 0,
|
|
212
254
|
cacheCreationTokens = 0,
|
|
255
|
+
requestInputTokens,
|
|
256
|
+
serviceTier = "standard",
|
|
257
|
+
regionalProcessing = false,
|
|
213
258
|
table,
|
|
214
259
|
} = {}) {
|
|
215
260
|
const rate = lookupRate(provider, model, table);
|
|
216
|
-
|
|
261
|
+
const tierMultiplier = rate?.terms
|
|
262
|
+
? Object.hasOwn(rate.terms.serviceMultipliers, serviceTier)
|
|
263
|
+
? rate.terms.serviceMultipliers[serviceTier]
|
|
264
|
+
: null
|
|
265
|
+
: 1;
|
|
266
|
+
if (!rate || tierMultiplier == null) {
|
|
217
267
|
return {
|
|
218
268
|
inputCost: 0,
|
|
219
269
|
outputCost: 0,
|
|
@@ -226,16 +276,34 @@ export function estimateCost({
|
|
|
226
276
|
rate: null,
|
|
227
277
|
};
|
|
228
278
|
}
|
|
279
|
+
const promptTokens =
|
|
280
|
+
requestInputTokens ??
|
|
281
|
+
Number(inputTokens) + Number(cacheReadTokens) + Number(cacheCreationTokens);
|
|
282
|
+
const longContext = rate.terms?.longContext;
|
|
283
|
+
const longPrompt = longContext && promptTokens > longContext.threshold;
|
|
284
|
+
const inputMultiplier = longPrompt ? longContext.inputMultiplier : 1;
|
|
285
|
+
const outputMultiplier = longPrompt ? longContext.outputMultiplier : 1;
|
|
286
|
+
const multiplier = tierMultiplier * (regionalProcessing ? 1.1 : 1);
|
|
229
287
|
// Keep full IEEE-754 precision throughout authority and budget arithmetic.
|
|
230
288
|
// Rounding each component to six decimals lets a real sub-microdollar call
|
|
231
289
|
// become zero and can make a hard `maxUsd` gate pass incorrectly. Display
|
|
232
290
|
// surfaces may format these values, but safety decisions consume the raw sum.
|
|
233
|
-
const inputCost =
|
|
234
|
-
|
|
291
|
+
const inputCost =
|
|
292
|
+
(Number(inputTokens) / 1e6) * rate.in * inputMultiplier * multiplier;
|
|
293
|
+
const outputCost =
|
|
294
|
+
(Number(outputTokens) / 1e6) * rate.out * outputMultiplier * multiplier;
|
|
235
295
|
const cacheReadCost =
|
|
236
|
-
(Number(cacheReadTokens) / 1e6) *
|
|
296
|
+
(Number(cacheReadTokens) / 1e6) *
|
|
297
|
+
rate.in *
|
|
298
|
+
(rate.terms?.cacheReadMultiplier ?? cacheReadMultiplier(provider)) *
|
|
299
|
+
inputMultiplier *
|
|
300
|
+
multiplier;
|
|
237
301
|
const cacheCreationCost =
|
|
238
|
-
(Number(cacheCreationTokens) / 1e6) *
|
|
302
|
+
(Number(cacheCreationTokens) / 1e6) *
|
|
303
|
+
rate.in *
|
|
304
|
+
(rate.terms?.cacheWriteMultiplier ?? CACHE_WRITE_MULTIPLIER) *
|
|
305
|
+
inputMultiplier *
|
|
306
|
+
multiplier;
|
|
239
307
|
return {
|
|
240
308
|
inputCost,
|
|
241
309
|
outputCost,
|
|
@@ -259,15 +327,53 @@ export function estimateCost({
|
|
|
259
327
|
*/
|
|
260
328
|
export function priceRollup(aggregate, { table } = {}) {
|
|
261
329
|
const byModel = (aggregate?.byModel || []).map((row) => {
|
|
262
|
-
|
|
330
|
+
let est = estimateCost({
|
|
263
331
|
provider: row.provider,
|
|
264
332
|
model: row.model,
|
|
265
333
|
inputTokens: row.inputTokens,
|
|
266
334
|
outputTokens: row.outputTokens,
|
|
267
335
|
cacheReadTokens: row.cacheReadTokens,
|
|
268
336
|
cacheCreationTokens: row.cacheCreationTokens,
|
|
337
|
+
serviceTier: row.serviceTier ?? row.service_tier ?? "standard",
|
|
338
|
+
regionalProcessing:
|
|
339
|
+
row.regionalProcessing ?? row.regional_processing ?? false,
|
|
269
340
|
table,
|
|
270
341
|
});
|
|
342
|
+
if (Array.isArray(row.pricingBuckets)) {
|
|
343
|
+
const estimates = row.pricingBuckets.map((bucket) =>
|
|
344
|
+
estimateCost({
|
|
345
|
+
provider: row.provider,
|
|
346
|
+
model: row.model,
|
|
347
|
+
...bucket,
|
|
348
|
+
table,
|
|
349
|
+
}),
|
|
350
|
+
);
|
|
351
|
+
est = { ...est, matched: estimates.every((entry) => entry.matched) };
|
|
352
|
+
for (const field of [
|
|
353
|
+
"inputCost",
|
|
354
|
+
"outputCost",
|
|
355
|
+
"cacheReadCost",
|
|
356
|
+
"cacheCreationCost",
|
|
357
|
+
"totalCost",
|
|
358
|
+
]) {
|
|
359
|
+
est[field] = estimates.reduce((sum, entry) => sum + entry[field], 0);
|
|
360
|
+
}
|
|
361
|
+
} else if (
|
|
362
|
+
lookupRate(row.provider, row.model, table)?.terms &&
|
|
363
|
+
row.calls > 1
|
|
364
|
+
) {
|
|
365
|
+
// A legacy aggregate cannot establish which individual requests crossed
|
|
366
|
+
// a pricing threshold. Exclude it rather than inventing a bill.
|
|
367
|
+
est = {
|
|
368
|
+
...est,
|
|
369
|
+
matched: false,
|
|
370
|
+
inputCost: 0,
|
|
371
|
+
outputCost: 0,
|
|
372
|
+
cacheReadCost: 0,
|
|
373
|
+
cacheCreationCost: 0,
|
|
374
|
+
totalCost: 0,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
271
377
|
return {
|
|
272
378
|
...row,
|
|
273
379
|
cost: est.totalCost,
|
|
@@ -86,7 +86,12 @@ export class CodeIntelligence {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
/** Find references to the symbol under a 1-based position. */
|
|
89
|
-
async references(
|
|
89
|
+
async references(
|
|
90
|
+
filePath,
|
|
91
|
+
line,
|
|
92
|
+
col,
|
|
93
|
+
{ includeDeclaration = true, timeoutMs } = {},
|
|
94
|
+
) {
|
|
90
95
|
const ready = await this._ensure(filePath);
|
|
91
96
|
if (ready.unavailable) return unavailable(ready.reason);
|
|
92
97
|
const result = await this._readRequest(
|
|
@@ -97,6 +102,7 @@ export class CodeIntelligence {
|
|
|
97
102
|
position: toLspPosition({ line, col }),
|
|
98
103
|
context: { includeDeclaration },
|
|
99
104
|
},
|
|
105
|
+
{ timeoutMs },
|
|
100
106
|
);
|
|
101
107
|
return { available: true, locations: this._normalizeLocations(result) };
|
|
102
108
|
}
|
|
@@ -685,10 +685,13 @@ export function assertMcpVerifiedProjectionAuthority(
|
|
|
685
685
|
const descriptors = Object.getOwnPropertyDescriptors(authority);
|
|
686
686
|
const fields = Object.keys(descriptors);
|
|
687
687
|
if (
|
|
688
|
-
fields.length !==
|
|
688
|
+
fields.length !==
|
|
689
|
+
VERIFIED_PROJECTION_AUTHORITY_FIELDS.size +
|
|
690
|
+
(descriptors.replayEvents ? 1 : 0) ||
|
|
689
691
|
fields.some(
|
|
690
692
|
(field) =>
|
|
691
|
-
!VERIFIED_PROJECTION_AUTHORITY_FIELDS.has(field)
|
|
693
|
+
(!VERIFIED_PROJECTION_AUTHORITY_FIELDS.has(field) &&
|
|
694
|
+
field !== "replayEvents") ||
|
|
692
695
|
!("value" in descriptors[field]) ||
|
|
693
696
|
!descriptors[field].enumerable,
|
|
694
697
|
)
|
|
@@ -704,6 +707,8 @@ export function assertMcpVerifiedProjectionAuthority(
|
|
|
704
707
|
!Number.isSafeInteger(projectedEventCount) ||
|
|
705
708
|
projectedEventCount < 0 ||
|
|
706
709
|
typeof descriptors.readMessages.value !== "function" ||
|
|
710
|
+
(descriptors.replayEvents &&
|
|
711
|
+
typeof descriptors.replayEvents.value !== "function") ||
|
|
707
712
|
projectedEventCount !== acceptedCount ||
|
|
708
713
|
projectedHeadHash !== headHash
|
|
709
714
|
) {
|
|
@@ -2,6 +2,7 @@ import { canonicalDigest } from "@chainlesschain/context-memory-kernel";
|
|
|
2
2
|
import {
|
|
3
3
|
CONTEXT_WINDOWS,
|
|
4
4
|
DOCUMENTED_OPENAI_MODELS,
|
|
5
|
+
DOCUMENTED_ANTHROPIC_MODELS,
|
|
5
6
|
LEGACY_MODEL_PROVIDERS,
|
|
6
7
|
MODEL_CAPABILITY_CATALOG_VERSION,
|
|
7
8
|
} from "./model-context-catalog.js";
|
|
@@ -61,7 +62,7 @@ function deepFreeze(value) {
|
|
|
61
62
|
return Object.freeze(value);
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
function
|
|
65
|
+
function isOfficialModelBaseUrl(provider, baseUrl) {
|
|
65
66
|
if (baseUrl == null || baseUrl === "") return true;
|
|
66
67
|
if (typeof baseUrl !== "string") {
|
|
67
68
|
throw new TypeError("baseUrl must be a string when provided");
|
|
@@ -71,7 +72,10 @@ function isOfficialOpenAIBaseUrl(baseUrl) {
|
|
|
71
72
|
// decorations and non-default ports. Never return or hash the input URL.
|
|
72
73
|
return (
|
|
73
74
|
baseUrl === baseUrl.trim() &&
|
|
74
|
-
new URL(baseUrl).href ===
|
|
75
|
+
new URL(baseUrl).href ===
|
|
76
|
+
(provider === "openai"
|
|
77
|
+
? "https://api.openai.com/v1"
|
|
78
|
+
: "https://api.anthropic.com/v1")
|
|
75
79
|
);
|
|
76
80
|
} catch {
|
|
77
81
|
return false;
|
|
@@ -137,13 +141,17 @@ export function resolveModelCapabilityProfile({
|
|
|
137
141
|
"contextMemoryModelWindowTokens",
|
|
138
142
|
{ min: 1024, max: MAX_CONTEXT_WINDOW_TOKENS },
|
|
139
143
|
);
|
|
144
|
+
const catalog =
|
|
145
|
+
selectedProvider === "openai"
|
|
146
|
+
? DOCUMENTED_OPENAI_MODELS
|
|
147
|
+
: selectedProvider === "anthropic"
|
|
148
|
+
? DOCUMENTED_ANTHROPIC_MODELS
|
|
149
|
+
: null;
|
|
140
150
|
const officialEndpoint =
|
|
141
|
-
|
|
151
|
+
Boolean(catalog) && isOfficialModelBaseUrl(selectedProvider, baseUrl);
|
|
142
152
|
const documented =
|
|
143
|
-
officialEndpoint &&
|
|
144
|
-
|
|
145
|
-
Object.hasOwn(DOCUMENTED_OPENAI_MODELS, selectedModel)
|
|
146
|
-
? DOCUMENTED_OPENAI_MODELS[selectedModel]
|
|
153
|
+
officialEndpoint && selectedModel && Object.hasOwn(catalog, selectedModel)
|
|
154
|
+
? catalog[selectedModel]
|
|
147
155
|
: null;
|
|
148
156
|
const legacyOwner =
|
|
149
157
|
selectedModel && Object.hasOwn(LEGACY_MODEL_PROVIDERS, selectedModel)
|
|
@@ -213,9 +221,9 @@ export function resolveModelCapabilityProfile({
|
|
|
213
221
|
"The model's legacy catalog entry belongs to another provider and was not applied.",
|
|
214
222
|
);
|
|
215
223
|
}
|
|
216
|
-
if (
|
|
224
|
+
if (catalog && !officialEndpoint) {
|
|
217
225
|
limitations.push(
|
|
218
|
-
|
|
226
|
+
`Official ${selectedProvider === "openai" ? "OpenAI" : "Anthropic"} model specifications are not applied to a custom endpoint.`,
|
|
219
227
|
);
|
|
220
228
|
}
|
|
221
229
|
if (output.requestMaxOutputTokens === null) {
|
|
@@ -234,7 +242,7 @@ export function resolveModelCapabilityProfile({
|
|
|
234
242
|
);
|
|
235
243
|
}
|
|
236
244
|
if (
|
|
237
|
-
documented &&
|
|
245
|
+
documented?.advertisedMaxOutputTokens != null &&
|
|
238
246
|
output.requestMaxOutputTokens > documented.advertisedMaxOutputTokens
|
|
239
247
|
) {
|
|
240
248
|
limitations.push(
|
|
@@ -263,6 +271,9 @@ export function resolveModelCapabilityProfile({
|
|
|
263
271
|
runtimeVerified: false,
|
|
264
272
|
...output,
|
|
265
273
|
advertisedMaxOutputTokens: documented?.advertisedMaxOutputTokens ?? null,
|
|
274
|
+
...(documented?.reasoningEfforts
|
|
275
|
+
? { reasoningEfforts: [...documented.reasoningEfforts] }
|
|
276
|
+
: {}),
|
|
266
277
|
sources: documented ? [...documented.sources] : [],
|
|
267
278
|
limitations,
|
|
268
279
|
};
|
|
@@ -45,7 +45,7 @@ export const CONTEXT_WINDOWS = Object.freeze({
|
|
|
45
45
|
}),
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
-
export const MODEL_CAPABILITY_CATALOG_VERSION = "2026-09-
|
|
48
|
+
export const MODEL_CAPABILITY_CATALOG_VERSION = "2026-09-27";
|
|
49
49
|
|
|
50
50
|
// Explicit ownership prevents a model name served by an unrelated provider
|
|
51
51
|
// from silently inheriting another provider's catalog window.
|
|
@@ -97,9 +97,68 @@ export const DOCUMENTED_OPENAI_MODELS = Object.freeze({
|
|
|
97
97
|
contextWindowTokens: 1050000,
|
|
98
98
|
advertisedMaxOutputTokens: 128000,
|
|
99
99
|
requiresResponsesForTools: true,
|
|
100
|
+
reasoningEfforts: Object.freeze(["low", "medium", "high", "xhigh", "max"]),
|
|
101
|
+
pricing: Object.freeze({ in: 10, out: 50 }),
|
|
100
102
|
sources: Object.freeze([
|
|
101
103
|
"https://developers.openai.com/api/docs/models/gpt-6-astra",
|
|
102
104
|
"https://developers.openai.com/api/docs/guides/migrate-to-responses",
|
|
103
105
|
]),
|
|
104
106
|
}),
|
|
107
|
+
...Object.fromEntries(
|
|
108
|
+
[
|
|
109
|
+
["gpt-6-sol", 2, 10],
|
|
110
|
+
["gpt-6-luna", 0.1, 0.5],
|
|
111
|
+
].map(([model, input, output]) => [
|
|
112
|
+
model,
|
|
113
|
+
Object.freeze({
|
|
114
|
+
contextWindowTokens: 1050000,
|
|
115
|
+
advertisedMaxOutputTokens: 128000,
|
|
116
|
+
requiresResponsesForTools: true,
|
|
117
|
+
reasoningEfforts: Object.freeze([
|
|
118
|
+
"none",
|
|
119
|
+
"low",
|
|
120
|
+
"medium",
|
|
121
|
+
"high",
|
|
122
|
+
"xhigh",
|
|
123
|
+
"max",
|
|
124
|
+
]),
|
|
125
|
+
pricing: Object.freeze({ in: input, out: output }),
|
|
126
|
+
sources: Object.freeze([
|
|
127
|
+
`https://developers.openai.com/api/docs/models/${model}`,
|
|
128
|
+
]),
|
|
129
|
+
}),
|
|
130
|
+
]),
|
|
131
|
+
),
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
export const DOCUMENTED_ANTHROPIC_MODELS = Object.freeze({
|
|
135
|
+
"claude-opus-5-5": Object.freeze({
|
|
136
|
+
contextWindowTokens: 1000000,
|
|
137
|
+
// The release notes establish the window and pricing, not an output cap.
|
|
138
|
+
advertisedMaxOutputTokens: null,
|
|
139
|
+
pricing: Object.freeze({ in: 4, out: 20 }),
|
|
140
|
+
sources: Object.freeze([
|
|
141
|
+
"https://code.claude.com/docs/en/changelog#2-1-280",
|
|
142
|
+
]),
|
|
143
|
+
}),
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Request-level pricing terms shared by cost reporting and hard budget gates.
|
|
147
|
+
// Never apply these tiers to a sum of multiple requests.
|
|
148
|
+
export const GPT6_PRICING_TERMS = Object.freeze({
|
|
149
|
+
cacheReadMultiplier: 0.1,
|
|
150
|
+
cacheWriteMultiplier: 1.25,
|
|
151
|
+
longContext: Object.freeze({
|
|
152
|
+
threshold: 272000,
|
|
153
|
+
inputMultiplier: 2,
|
|
154
|
+
outputMultiplier: 1.5,
|
|
155
|
+
}),
|
|
156
|
+
serviceMultipliers: Object.freeze({
|
|
157
|
+
standard: 1,
|
|
158
|
+
default: 1,
|
|
159
|
+
auto: 1,
|
|
160
|
+
batch: 0.5,
|
|
161
|
+
flex: 0.5,
|
|
162
|
+
fast: 2,
|
|
163
|
+
}),
|
|
105
164
|
});
|
|
@@ -300,7 +300,13 @@ export function normalizeOpenAIResponsesResponse(data) {
|
|
|
300
300
|
responseId: printableString(data.id) || null,
|
|
301
301
|
};
|
|
302
302
|
const usage = normalizeOpenAIResponsesUsage(data.usage);
|
|
303
|
-
if (usage)
|
|
303
|
+
if (usage)
|
|
304
|
+
result.usage = {
|
|
305
|
+
...usage,
|
|
306
|
+
...(typeof data.service_tier === "string"
|
|
307
|
+
? { service_tier: data.service_tier }
|
|
308
|
+
: {}),
|
|
309
|
+
};
|
|
304
310
|
return result;
|
|
305
311
|
}
|
|
306
312
|
|
package/src/lib/orchestrator.js
CHANGED
|
@@ -141,13 +141,16 @@ export class Orchestrator extends EventEmitter {
|
|
|
141
141
|
// Multi-path agent router
|
|
142
142
|
this._router =
|
|
143
143
|
options.agentRouter ||
|
|
144
|
-
(options.agents
|
|
144
|
+
(Array.isArray(options.agents?.backends)
|
|
145
145
|
? new AgentRouter({
|
|
146
146
|
backends: options.agents.backends || [],
|
|
147
147
|
strategy: options.agents.strategy || "round-robin",
|
|
148
148
|
maxParallel: this.maxParallel,
|
|
149
149
|
})
|
|
150
|
-
: AgentRouter.autoDetect({
|
|
150
|
+
: AgentRouter.autoDetect({
|
|
151
|
+
maxParallel: this.maxParallel,
|
|
152
|
+
strategy: options.agents?.strategy,
|
|
153
|
+
}));
|
|
151
154
|
|
|
152
155
|
// Multi-channel notification manager
|
|
153
156
|
this.notifier =
|
|
@@ -188,6 +191,9 @@ export class Orchestrator extends EventEmitter {
|
|
|
188
191
|
*/
|
|
189
192
|
async addTask(description, opts = {}) {
|
|
190
193
|
assertCLILegacyMutationAllowed("Orchestrator.addTask");
|
|
194
|
+
// Reject opaque external CLIs before notifications, Run creation or paid
|
|
195
|
+
// decomposition. This preflight never replaces the dispatch ingress gate.
|
|
196
|
+
this._router.assertDispatchAvailable?.();
|
|
191
197
|
const task = {
|
|
192
198
|
id: generateId("task"),
|
|
193
199
|
description,
|