chainlesschain 0.166.77 → 0.166.78

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. package/README.md +16 -7
  2. package/completions/_cc +1 -1
  3. package/completions/cc.bash +1 -1
  4. package/completions/cc.fish +1 -1
  5. package/completions/cc.ps1 +1 -1
  6. package/package.json +1 -1
  7. package/src/assets/linux-subreaper/linux-arm64/manifest.json +10 -0
  8. package/src/assets/linux-subreaper/linux-arm64/supervisor +0 -0
  9. package/src/assets/linux-subreaper/linux-x64/manifest.json +10 -0
  10. package/src/assets/linux-subreaper/linux-x64/supervisor +0 -0
  11. package/src/assets/web-panel/assets/{AIOps-CpiCBhRh.js → AIOps-DSyZEY2G.js} +1 -1
  12. package/src/assets/web-panel/assets/{ActionButton-CnU-Xvx-.js → ActionButton-DhNyZ577.js} +1 -1
  13. package/src/assets/web-panel/assets/{Analytics-BJW-CNtf.js → Analytics-HMMpxmyi.js} +3 -3
  14. package/src/assets/web-panel/assets/{AppLayout-UFQJL3G9.js → AppLayout-CwKMM5Ie.js} +5 -5
  15. package/src/assets/web-panel/assets/{Artifacts-Dr_IUDoY.js → Artifacts-CNzDmph7.js} +1 -1
  16. package/src/assets/web-panel/assets/{Audit-aglWo6rr.js → Audit-DxWpUW3V.js} +1 -1
  17. package/src/assets/web-panel/assets/{BackgroundAgents-Dm_TCiXC.js → BackgroundAgents-C1R2ST-P.js} +1 -1
  18. package/src/assets/web-panel/assets/{Backup-DUdX4-gA.js → Backup-B6biTaEV.js} +1 -1
  19. package/src/assets/web-panel/assets/{BaseInput-BTcLjy1o.js → BaseInput-CVnkD2Z5.js} +1 -1
  20. package/src/assets/web-panel/assets/{Chat-Bhy9qZrl.js → Chat-Dbewl4Je.js} +6 -6
  21. package/src/assets/web-panel/assets/{ChatBubbleRenderer-D0WrJQaQ.js → ChatBubbleRenderer-DVZ6SwC5.js} +1 -1
  22. package/src/assets/web-panel/assets/{Checkbox-CblrPa21.js → Checkbox-BqqiF1JE.js} +1 -1
  23. package/src/assets/web-panel/assets/{Codegen-SEAHzOlr.js → Codegen-BVMkGumc.js} +1 -1
  24. package/src/assets/web-panel/assets/{Col-DJz8iFOR.js → Col-DmiRHy96.js} +1 -1
  25. package/src/assets/web-panel/assets/{Community-RufKhcQt.js → Community-BDlpygqA.js} +1 -1
  26. package/src/assets/web-panel/assets/{Compact-Dlifx08U.js → Compact-B2NME_m-.js} +1 -1
  27. package/src/assets/web-panel/assets/{Compliance-DdhQWcHh.js → Compliance-BlzDLE-R.js} +1 -1
  28. package/src/assets/web-panel/assets/{Cowork-BLNn6oOm.js → Cowork-C8raPybB.js} +3 -3
  29. package/src/assets/web-panel/assets/{Cron-Dv-JWY2d.js → Cron-DA8Py0zP.js} +2 -2
  30. package/src/assets/web-panel/assets/{Crosschain-k7Pz7O-b.js → Crosschain-DU2XyHqB.js} +1 -1
  31. package/src/assets/web-panel/assets/{DID-C_10syUW.js → DID-Df098fT_.js} +2 -2
  32. package/src/assets/web-panel/assets/{Dashboard-CMyH6Szx.js → Dashboard-D1rT702x.js} +2 -2
  33. package/src/assets/web-panel/assets/{Dropdown-DjmD2Saa.js → Dropdown-BweXGo1O.js} +1 -1
  34. package/src/assets/web-panel/assets/{EmailListRenderer-36_IRUSo.js → EmailListRenderer-B9ShbgJH.js} +1 -1
  35. package/src/assets/web-panel/assets/EvolutionSettings-D75_iBoc.js +1 -0
  36. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DEgf9kyP.js → FamilyGuardDashboard-DrznZFVs.js} +1 -1
  37. package/src/assets/web-panel/assets/{Federation-DGO1wQls.js → Federation-DQZ2adIA.js} +1 -1
  38. package/src/assets/web-panel/assets/{FormItemContext-Doj1FmKW.js → FormItemContext-DN30Dowh.js} +1 -1
  39. package/src/assets/web-panel/assets/{GenericCardRenderer-GzOU27iT.js → GenericCardRenderer-DRdt0j1e.js} +1 -1
  40. package/src/assets/web-panel/assets/{Git-Dd7D1EDK.js → Git-wwRgStzk.js} +2 -2
  41. package/src/assets/web-panel/assets/{Governance-6IY8LcjI.js → Governance-CI4Uw0Nh.js} +1 -1
  42. package/src/assets/web-panel/assets/{Inference-BB9gl8q1.js → Inference-5TuE2AJI.js} +1 -1
  43. package/src/assets/web-panel/assets/{KnowledgeGraph-CeCed5wd.js → KnowledgeGraph-oXyvmFSR.js} +1 -1
  44. package/src/assets/web-panel/assets/{Logs-CYOeHuaI.js → Logs-ewudSWuv.js} +2 -2
  45. package/src/assets/web-panel/assets/{MarkdownRenderer-Bk8Zqc2R.js → MarkdownRenderer-Cz5nyufm.js} +1 -1
  46. package/src/assets/web-panel/assets/{Marketplace-D-_xgHgM.js → Marketplace-DcZeWFrs.js} +1 -1
  47. package/src/assets/web-panel/assets/{McpTools-NnaUTF5t.js → McpTools-BcV9p1RS.js} +3 -3
  48. package/src/assets/web-panel/assets/{Memory-CndN9pMt.js → Memory-CMhYvugt.js} +2 -2
  49. package/src/assets/web-panel/assets/{MobileBridge-BXblFmhY.js → MobileBridge-5RP2uwvT.js} +1 -1
  50. package/src/assets/web-panel/assets/{MobileProjects-CC26Dm2k.js → MobileProjects-BIuM9Ze4.js} +1 -1
  51. package/src/assets/web-panel/assets/{Mtc-BhaqWCiW.js → Mtc-DmBszTDe.js} +4 -4
  52. package/src/assets/web-panel/assets/{MtcAudit-D6fktM2w.js → MtcAudit-Czdp5ZGt.js} +5 -5
  53. package/src/assets/web-panel/assets/{Multisig-CFvahz7s.js → Multisig-DRWUuNr-.js} +3 -3
  54. package/src/assets/web-panel/assets/{NLProgramming-Co73Ivya.js → NLProgramming-IRQQN0-c.js} +1 -1
  55. package/src/assets/web-panel/assets/{Notes-B4g33L1o.js → Notes-CGhD1lW9.js} +4 -4
  56. package/src/assets/web-panel/assets/{NotificationSettings-lXd17EbN.js → NotificationSettings-BtyPgQAh.js} +1 -1
  57. package/src/assets/web-panel/assets/{OrderTableRenderer-BiOB0GIi.js → OrderTableRenderer-yUaqwCty.js} +1 -1
  58. package/src/assets/web-panel/assets/{Organization-JQ7_wQIA.js → Organization-C3kTVn5i.js} +4 -4
  59. package/src/assets/web-panel/assets/{Overflow-gwgJgozQ.js → Overflow-C2-0iZhq.js} +1 -1
  60. package/src/assets/web-panel/assets/{P2P-D9L_0gie.js → P2P-CISoEUxA.js} +2 -2
  61. package/src/assets/web-panel/assets/{PdhVaultBrowser-CbOPsFE9.js → PdhVaultBrowser-NfTVtvKQ.js} +5 -5
  62. package/src/assets/web-panel/assets/{Permissions-Cz42HNQf.js → Permissions-CfK0jJhm.js} +4 -4
  63. package/src/assets/web-panel/assets/{PersonalDataHub-DjorYtrF.js → PersonalDataHub-OsVxxh_j.js} +5 -5
  64. package/src/assets/web-panel/assets/{Pipeline-DyWPhmm5.js → Pipeline-DEmK_Ch2.js} +1 -1
  65. package/src/assets/web-panel/assets/{Privacy-DyfLMl2j.js → Privacy-D61s73b0.js} +1 -1
  66. package/src/assets/web-panel/assets/{ProjectInit-CyqDx1OE.js → ProjectInit-DkLF5gHb.js} +2 -2
  67. package/src/assets/web-panel/assets/{ProjectSettings-DsBw0Csy.js → ProjectSettings-BA7odTrI.js} +2 -2
  68. package/src/assets/web-panel/assets/{Projects-CRaSI25Z.js → Projects-CdI1GcAG.js} +1 -1
  69. package/src/assets/web-panel/assets/{Providers-CCI_klN-.js → Providers-D9BYyP1r.js} +1 -1
  70. package/src/assets/web-panel/assets/{QrScannerModal-DNsnlDdS.js → QrScannerModal-CXMItUDD.js} +1 -1
  71. package/src/assets/web-panel/assets/{QuickAsk-B9r2iaee.js → QuickAsk-8-tF9ffZ.js} +1 -1
  72. package/src/assets/web-panel/assets/{Recommend-BJDe03GR.js → Recommend-C2QGWOSi.js} +1 -1
  73. package/src/assets/web-panel/assets/{RemoteSession-J7JR3rRo.js → RemoteSession-B1M_v1lx.js} +3 -3
  74. package/src/assets/web-panel/assets/{Reputation-DR39AJeV.js → Reputation-D0WZHgv1.js} +1 -1
  75. package/src/assets/web-panel/assets/{Row-Dh77m3NZ.js → Row-D6nf9-c-.js} +1 -1
  76. package/src/assets/web-panel/assets/{RssFeed-BUdg28nJ.js → RssFeed-ClZ6M-mN.js} +3 -3
  77. package/src/assets/web-panel/assets/{Search-BNC7sGhj.js → Search-ZWkt8vuO.js} +1 -1
  78. package/src/assets/web-panel/assets/{Security-DISENGI7.js → Security-BUlQut2m.js} +4 -4
  79. package/src/assets/web-panel/assets/{Services-BBBGpJ1-.js → Services-Cd_3xJOc.js} +2 -2
  80. package/src/assets/web-panel/assets/{Skeleton-DMcIoIv2.js → Skeleton-C8e2-cHW.js} +1 -1
  81. package/src/assets/web-panel/assets/{Skills-QAyFbI3r.js → Skills-DucVRJp1.js} +1 -1
  82. package/src/assets/web-panel/assets/{Sla-CSg5wLH7.js → Sla-Csr5pUwI.js} +1 -1
  83. package/src/assets/web-panel/assets/{SpeechSettings-DMPxTc5x.js → SpeechSettings-CXvyaRAT.js} +1 -1
  84. package/src/assets/web-panel/assets/{SyncSettings-CPG7l30y.js → SyncSettings-KdsIcV5h.js} +2 -2
  85. package/src/assets/web-panel/assets/{Tasks-Y1kOVvVL.js → Tasks-B-eHmJm9.js} +1 -1
  86. package/src/assets/web-panel/assets/{Templates-jt9NagL0.js → Templates-BglVeaLK.js} +1 -1
  87. package/src/assets/web-panel/assets/{Tenant-DauuJICx.js → Tenant-BBbQ8qan.js} +1 -1
  88. package/src/assets/web-panel/assets/{Terminal-E9rnKeGq.js → Terminal-Ca_pCVBi.js} +2 -2
  89. package/src/assets/web-panel/assets/{TimelineRenderer-Cc7z2APG.js → TimelineRenderer-YD6XG_vZ.js} +1 -1
  90. package/src/assets/web-panel/assets/{Tokens-CV0UthRA.js → Tokens-2lRoeVli.js} +1 -1
  91. package/src/assets/web-panel/assets/{Trigger-BFcJJGfu.js → Trigger-C-3XNAU9.js} +1 -1
  92. package/src/assets/web-panel/assets/{Trust-BAydbNJA.js → Trust-k-1PxdLG.js} +1 -1
  93. package/src/assets/web-panel/assets/{UkeySign-DcOS6sqL.js → UkeySign-FG-qW646.js} +1 -1
  94. package/src/assets/web-panel/assets/{VideoEditing-BLHJZvif.js → VideoEditing-BNOe1cmd.js} +1 -1
  95. package/src/assets/web-panel/assets/{Wallet-4QFLKHwW.js → Wallet-D5C3i2Kw.js} +4 -4
  96. package/src/assets/web-panel/assets/{WebAuthn-BocEOOSj.js → WebAuthn-BOpztqd3.js} +5 -5
  97. package/src/assets/web-panel/assets/{WorkflowEditor-DCfF7D0B.js → WorkflowEditor-BpVrpUEv.js} +1 -1
  98. package/src/assets/web-panel/assets/{chat-CxvfsYGr.js → chat-DIuMHb38.js} +1 -1
  99. package/src/assets/web-panel/assets/{colors-KtQB9DmQ.js → colors-CTFJPyzQ.js} +1 -1
  100. package/src/assets/web-panel/assets/{compact-item-Dx4J6arN.js → compact-item-CONfmJcW.js} +1 -1
  101. package/src/assets/web-panel/assets/{createContext-Cq0olgzo.js → createContext-RkW5CRrz.js} +1 -1
  102. package/src/assets/web-panel/assets/devWarning-DaEBln_q.js +1 -0
  103. package/src/assets/web-panel/assets/{hasIn-Bf9-h3D-.js → hasIn-CW4XOjDC.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-CK2U_AHi.js → index-7wMSBCU7.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DMR-keCL.js → index-Akmg1WdH.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-6dDDSCHD.js → index-B54qoVff.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CmQuG0fr.js → index-B8r2t0Ch.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-ClUfSChI.js → index-B9XoBoty.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-B3xfiItB.js → index-B9aS2VLu.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DQDR-_ai.js → index-BFs1Tznc.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DZWjYfWt.js → index-BKgaRT0b.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-nmyDOh_b.js → index-BM7bOUvu.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-B_8UcDan.js → index-BMg2JFmW.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-C9yaUHm9.js → index-BRZsPxNn.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-Cz7f4Jaq.js → index-Bf19fKef.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CpO6DKuu.js → index-BkAbfBF-.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DFdEDvFn.js → index-CBjb2A5R.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-gt5N6VM_.js → index-CEZWQthY.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-0fi8DIVQ.js → index-CFGLf88d.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-hSzyoXri.js → index-CLUa68JH.js} +3 -3
  121. package/src/assets/web-panel/assets/{index-Cy865Hhq.js → index-CM2X25Er.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DDAe1UmZ.js → index-CX4T2uKN.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BMcC4cbj.js → index-CixqfdRk.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-DsCdl2Od.js → index-CkRojEip.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DnU-dUWd.js → index-Cvmc3f25.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-Br1mDMfO.js → index-D-lpTPS8.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CaIclw-E.js → index-D59GbWCN.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-DBRlZdZj.js → index-DAESljiJ.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-B8WuPI-h.js → index-DDHUx4Yz.js} +1 -1
  130. package/src/assets/web-panel/assets/index-DG1mcYTa.js +1 -0
  131. package/src/assets/web-panel/assets/{index-D2BfSIrn.js → index-DP5pPedy.js} +1 -1
  132. package/src/assets/web-panel/assets/index-DRs5Pe8u.js +1 -0
  133. package/src/assets/web-panel/assets/{index-CqnggDos.js → index-DSlXL6Ju.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-_FIz-0tp.js → index-DWCJnn2O.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-BKtQyb2o.js → index-DWY7YwDu.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-DfrFNMvz.js → index-DZTwP364.js} +1 -1
  137. package/src/assets/web-panel/assets/{index-BHmdMKYl.js → index-DidrMvOx.js} +1 -1
  138. package/src/assets/web-panel/assets/{index-BO6XvO-C.js → index-Dj3K5kHs.js} +1 -1
  139. package/src/assets/web-panel/assets/{index-iE9tqEN5.js → index-YaeGscSw.js} +1 -1
  140. package/src/assets/web-panel/assets/{index-DI5bRqNG.js → index-YlMnFNOi.js} +1 -1
  141. package/src/assets/web-panel/assets/{index-Cfsn7N18.js → index-asWsB34i.js} +1 -1
  142. package/src/assets/web-panel/assets/{index-CeYP_kT9.js → index-gkjiFjQd.js} +1 -1
  143. package/src/assets/web-panel/assets/{initDefaultProps-DvzKJ6o5.js → initDefaultProps-BOr4igh3.js} +1 -1
  144. package/src/assets/web-panel/assets/{motion-D1yTvmxW.js → motion-CK469n2j.js} +1 -1
  145. package/src/assets/web-panel/assets/{move-DxtSIF8K.js → move-DzjudlYQ.js} +1 -1
  146. package/src/assets/web-panel/assets/{mtc-parser-BDsQgIHY.js → mtc-parser-BQaKUxC6.js} +1 -1
  147. package/src/assets/web-panel/assets/{omit-UVBJW8kh.js → omit-MciovCFD.js} +1 -1
  148. package/src/assets/web-panel/assets/{pickAttrs-D4QqtTyX.js → pickAttrs-DDPJ4zAz.js} +1 -1
  149. package/src/assets/web-panel/assets/{placementArrow-QXmu6vBf.js → placementArrow-Cznyb-jI.js} +1 -1
  150. package/src/assets/web-panel/assets/{responsiveObserve-D-PmXO9M.js → responsiveObserve-AJK3SLzJ.js} +1 -1
  151. package/src/assets/web-panel/assets/{slide-CKbGxEZJ.js → slide-CPQ28wu7.js} +1 -1
  152. package/src/assets/web-panel/assets/{statusUtils-BbgXPkXm.js → statusUtils-CFjzvqf_.js} +1 -1
  153. package/src/assets/web-panel/assets/{styleChecker-DOr9rk68.js → styleChecker-BPyFfTuR.js} +1 -1
  154. package/src/assets/web-panel/assets/{useFlexGapSupport-B2wO2r36.js → useFlexGapSupport-Dq7N6R05.js} +1 -1
  155. package/src/assets/web-panel/assets/{useFs-SeVGBK34.js → useFs-C3GS0uTc.js} +1 -1
  156. package/src/assets/web-panel/assets/{usePersonalDataHub-DUJBCxjD.js → usePersonalDataHub-BhgIVzP_.js} +1 -1
  157. package/src/assets/web-panel/assets/{vnode-CF4EYsig.js → vnode-4ZD9-MDr.js} +1 -1
  158. package/src/assets/web-panel/assets/{zoom-pRUs5pqI.js → zoom-Bx4MRVNW.js} +1 -1
  159. package/src/assets/web-panel/index.html +1 -1
  160. package/src/command-help-index.json +1 -1
  161. package/src/command-manifest.json +1 -1
  162. package/src/commands/checkpoint.js +42 -7
  163. package/src/commands/orchestrate.js +85 -25
  164. package/src/commands/session-location.js +5 -0
  165. package/src/commands/session-show.js +109 -1
  166. package/src/commands/session.js +26 -2
  167. package/src/commands/tokens.js +9 -4
  168. package/src/data/changelog.json +13 -0
  169. package/src/generated/cc-agent-protocol.schema.json +71 -0
  170. package/src/harness/jsonl-session-store.js +357 -114
  171. package/src/harness/mcp-client.js +44 -1
  172. package/src/lib/agent-router.js +35 -7
  173. package/src/lib/app-server/server.js +14 -0
  174. package/src/lib/background-agent-supervisor.js +14 -4
  175. package/src/lib/causal-observability.js +64 -1
  176. package/src/lib/checkpoint-summary-projection.js +98 -0
  177. package/src/lib/checkpoint-timeline-authority.js +15 -51
  178. package/src/lib/claude-code-bridge.js +302 -60
  179. package/src/lib/codex-app-server-adapter.js +161 -35
  180. package/src/lib/cost-budget.js +4 -0
  181. package/src/lib/doctor-checkup.js +31 -2
  182. package/src/lib/durable-security-store.js +6 -1
  183. package/src/lib/evolution/evolution-artifact-identity.js +21 -0
  184. package/src/lib/evolution/evolution-artifact-ports.js +5 -11
  185. package/src/lib/evolution/evolution-eval-cohort-receipt-reconciliation.js +389 -0
  186. package/src/lib/execution-location-failure-site.js +63 -0
  187. package/src/lib/execution-location-target.js +102 -8
  188. package/src/lib/external-agent-adapters.js +2 -0
  189. package/src/lib/image-file-boundary.js +154 -0
  190. package/src/lib/image-input.js +16 -3
  191. package/src/lib/llm-pricing.js +114 -8
  192. package/src/lib/mcp-call-ledger-store.js +7 -2
  193. package/src/lib/model-capabilities.js +21 -10
  194. package/src/lib/model-context-catalog.js +60 -1
  195. package/src/lib/openai-responses.js +7 -1
  196. package/src/lib/orchestrator.js +8 -2
  197. package/src/lib/process-execution-broker/index.js +93 -1
  198. package/src/lib/process-execution-broker/linux-subreaper-artifact.js +120 -0
  199. package/src/lib/process-execution-broker/linux-subreaper-helper.js +344 -0
  200. package/src/lib/process-execution-broker/linux-subreaper-process.js +326 -0
  201. package/src/lib/process-execution-broker/linux-subreaper-supervisor.c +360 -0
  202. package/src/lib/process-execution-broker/owned-posix-process-group-worker.mjs +131 -0
  203. package/src/lib/process-execution-broker/owned-posix-process-group.js +267 -0
  204. package/src/lib/process-execution-broker/process-ownership-journal.js +297 -0
  205. package/src/lib/process-execution-broker/process-ownership-quarantine.js +91 -0
  206. package/src/lib/runtime-usage-ledger.js +3 -0
  207. package/src/lib/secure-fs.js +158 -42
  208. package/src/lib/session-branch-history.js +240 -0
  209. package/src/lib/session-history-origins.js +285 -0
  210. package/src/lib/session-input-receipt.js +110 -0
  211. package/src/lib/session-resource-budget.js +8 -8
  212. package/src/lib/session-transcript-history.js +456 -0
  213. package/src/lib/session-transcript-page.js +164 -0
  214. package/src/lib/session-transcript-reference.js +38 -0
  215. package/src/lib/session-usage.js +8 -0
  216. package/src/lib/token-tracker.js +32 -54
  217. package/src/lib/usage-pricing-context.js +93 -0
  218. package/src/runtime/headless-stream.js +202 -4
  219. package/src/assets/web-panel/assets/EvolutionSettings-CmtU0XmM.js +0 -1
  220. package/src/assets/web-panel/assets/devWarning-CmgDNkoO.js +0 -1
  221. package/src/assets/web-panel/assets/index-BpIZ2S01.js +0 -1
  222. 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
+ }
@@ -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
- return paths.map((p) => {
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
- const data = _fs.readFileSync(p).toString("base64");
78
- return { mediaType, data };
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
 
@@ -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
- return { in: e.in, out: e.out, pattern: e.match };
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
- if (!rate) {
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 = (Number(inputTokens) / 1e6) * rate.in;
234
- const outputCost = (Number(outputTokens) / 1e6) * rate.out;
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) * rate.in * cacheReadMultiplier(provider);
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) * rate.in * CACHE_WRITE_MULTIPLIER;
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
- const est = estimateCost({
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,
@@ -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 !== VERIFIED_PROJECTION_AUTHORITY_FIELDS.size ||
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 isOfficialOpenAIBaseUrl(baseUrl) {
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 === "https://api.openai.com/v1"
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
- selectedProvider === "openai" && isOfficialOpenAIBaseUrl(baseUrl);
151
+ Boolean(catalog) && isOfficialModelBaseUrl(selectedProvider, baseUrl);
142
152
  const documented =
143
- officialEndpoint &&
144
- selectedModel &&
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 (selectedProvider === "openai" && !officialEndpoint) {
224
+ if (catalog && !officialEndpoint) {
217
225
  limitations.push(
218
- "Official OpenAI model specifications are not applied to a custom endpoint.",
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-13";
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) result.usage = 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
 
@@ -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({ maxParallel: this.maxParallel }));
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,