chainlesschain 0.166.76 → 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.
- package/README.md +19 -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-CNaejClV.js → AIOps-DSyZEY2G.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CF_CVKT_.js → ActionButton-DhNyZ577.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-a3Z6J7gv.js → Analytics-HMMpxmyi.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BFtWEnct.js → AppLayout-CwKMM5Ie.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-BQ8oeMvX.js → Artifacts-CNzDmph7.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-NOo9bmgk.js → Audit-DxWpUW3V.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-QRc7F3Tp.js → BackgroundAgents-C1R2ST-P.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-UlVgLn2P.js → Backup-B6biTaEV.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BER9LJAr.js → BaseInput-CVnkD2Z5.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-Z8z2Fdfz.js → Chat-Dbewl4Je.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-DdmuBrdQ.js → ChatBubbleRenderer-DVZ6SwC5.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-CXPgyB8L.js → Checkbox-BqqiF1JE.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-D1vOsLJ7.js → Codegen-BVMkGumc.js} +1 -1
- package/src/assets/web-panel/assets/{Col-ucLnUJC7.js → Col-DmiRHy96.js} +1 -1
- package/src/assets/web-panel/assets/{Community-COsV9n9t.js → Community-BDlpygqA.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-D0EkBEYh.js → Compact-B2NME_m-.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-C8w9SUjt.js → Compliance-BlzDLE-R.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CmVaKEJS.js → Cowork-C8raPybB.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-B_FiMMV2.js → Cron-DA8Py0zP.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-ByO3YL8N.js → Crosschain-DU2XyHqB.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DwpsLM9r.js → DID-Df098fT_.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-B_8IUvM_.js → Dashboard-D1rT702x.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-Bo6WQkuX.js → Dropdown-BweXGo1O.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-C9LiQesx.js → EmailListRenderer-B9ShbgJH.js} +1 -1
- package/src/assets/web-panel/assets/EvolutionSettings-D75_iBoc.js +1 -0
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-Dst6VUnO.js → FamilyGuardDashboard-DrznZFVs.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-Ci7CoLkJ.js → Federation-DQZ2adIA.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-bdDyUhUM.js → FormItemContext-DN30Dowh.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CrRwOUVi.js → GenericCardRenderer-DRdt0j1e.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Dis8h-Z-.js → Git-wwRgStzk.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DX7OH5w2.js → Governance-CI4Uw0Nh.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Cavv_Q_Z.js → Inference-5TuE2AJI.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Cck8tnZn.js → KnowledgeGraph-oXyvmFSR.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BQt3aGMu.js → Logs-ewudSWuv.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-Cz5nyufm.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-CdmAKNSN.js → Marketplace-DcZeWFrs.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BUlJdyPY.js → McpTools-BcV9p1RS.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-DQRTQDr-.js → Memory-CMhYvugt.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-C0dnxgsl.js → MobileBridge-5RP2uwvT.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DQ5Gy7fa.js → MobileProjects-BIuM9Ze4.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-Xl7u2isS.js → Mtc-DmBszTDe.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-C3KX0574.js → MtcAudit-Czdp5ZGt.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-CHEhfkn8.js → Multisig-DRWUuNr-.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Ce38mH-8.js → NLProgramming-IRQQN0-c.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-C7nuTd7c.js → Notes-CGhD1lW9.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-BcoEcyq8.js → NotificationSettings-BtyPgQAh.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-D-t5hKkx.js → OrderTableRenderer-yUaqwCty.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-C_BGi4xi.js → Organization-C3kTVn5i.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BodhraDq.js → Overflow-C2-0iZhq.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BTa3sAIy.js → P2P-CISoEUxA.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BjZslP9T.js → PdhVaultBrowser-NfTVtvKQ.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-u3UDzGef.js → Permissions-CfK0jJhm.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-Cb7ybv65.js → PersonalDataHub-OsVxxh_j.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-CS24k-P7.js → Pipeline-DEmK_Ch2.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-Ddj6Kqs7.js → Privacy-D61s73b0.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Bg5uQIgg.js → ProjectInit-DkLF5gHb.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-AmPR8T12.js → ProjectSettings-BA7odTrI.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DGSbAyTK.js → Projects-CdI1GcAG.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-Dc1C3lbB.js → Providers-D9BYyP1r.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-Cv3HXpce.js → QrScannerModal-CXMItUDD.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-3dpbXARb.js → QuickAsk-8-tF9ffZ.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-5aGRVnJK.js → Recommend-C2QGWOSi.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-CTS2jx0p.js → RemoteSession-B1M_v1lx.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-BxaKI0hY.js → Reputation-D0WZHgv1.js} +1 -1
- package/src/assets/web-panel/assets/{Row-C23uQdwd.js → Row-D6nf9-c-.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-ssX9YOhm.js → RssFeed-ClZ6M-mN.js} +3 -3
- package/src/assets/web-panel/assets/{Search-C24GogII.js → Search-ZWkt8vuO.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DdAcGKkk.js → Security-BUlQut2m.js} +3 -3
- package/src/assets/web-panel/assets/{Services-D0dCiEuq.js → Services-Cd_3xJOc.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DEY44o0v.js → Skeleton-C8e2-cHW.js} +1 -1
- package/src/assets/web-panel/assets/Skills-DucVRJp1.js +1 -0
- package/src/assets/web-panel/assets/{Sla-B_bbo2vB.js → Sla-Csr5pUwI.js} +1 -1
- package/src/assets/web-panel/assets/SpeechSettings-CXvyaRAT.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-CpIXql0Z.js → SyncSettings-KdsIcV5h.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-B-eHmJm9.js +1 -0
- package/src/assets/web-panel/assets/{Templates-C_44nVPq.js → Templates-BglVeaLK.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CyZ2ey2P.js → Tenant-BBbQ8qan.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DwGNHWnp.js → Terminal-Ca_pCVBi.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BTAHNkqU.js → TimelineRenderer-YD6XG_vZ.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DCJWkUwc.js → Tokens-2lRoeVli.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BCjDO9-E.js → Trigger-C-3XNAU9.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-_YS8WbRb.js → Trust-k-1PxdLG.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-m6R8xGq7.js → UkeySign-FG-qW646.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-xOfk29c4.js → VideoEditing-BNOe1cmd.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-B1Gw0awc.js → Wallet-D5C3i2Kw.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CHK5ft18.js → WebAuthn-BOpztqd3.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-DEp1ukQQ.js → WorkflowEditor-BpVrpUEv.js} +1 -1
- package/src/assets/web-panel/assets/{chat-B2sFizun.js → chat-DIuMHb38.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DJ17YV1E.js → colors-CTFJPyzQ.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-CBhJJgEC.js → compact-item-CONfmJcW.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BZkpvNJy.js → createContext-RkW5CRrz.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DaEBln_q.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-C0ZKo6Ei.js → hasIn-CW4XOjDC.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bc3vVG2X.js → index-7wMSBCU7.js} +1 -1
- package/src/assets/web-panel/assets/{index-vFMwiAN4.js → index-Akmg1WdH.js} +1 -1
- package/src/assets/web-panel/assets/{index-DOBXNMdh.js → index-B54qoVff.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLo8Ls9u.js → index-B8r2t0Ch.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7gv9dvb.js → index-B9XoBoty.js} +1 -1
- package/src/assets/web-panel/assets/{index-DHtpMr1G.js → index-B9aS2VLu.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dxe0YlZe.js → index-BFs1Tznc.js} +1 -1
- package/src/assets/web-panel/assets/{index-DumLgj1t.js → index-BKgaRT0b.js} +1 -1
- package/src/assets/web-panel/assets/{index-BNp6HKFh.js → index-BM7bOUvu.js} +1 -1
- package/src/assets/web-panel/assets/{index-DM0rWF6z.js → index-BMg2JFmW.js} +1 -1
- package/src/assets/web-panel/assets/{index-4oULtRqE.js → index-BRZsPxNn.js} +1 -1
- package/src/assets/web-panel/assets/{index-LPPe0val.js → index-Bf19fKef.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ctguam0K.js → index-BkAbfBF-.js} +1 -1
- package/src/assets/web-panel/assets/{index-DrU5xVpF.js → index-CBjb2A5R.js} +1 -1
- package/src/assets/web-panel/assets/{index-CCOr6Q27.js → index-CEZWQthY.js} +1 -1
- package/src/assets/web-panel/assets/{index-C9gYiACH.js → index-CFGLf88d.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZW84cEf.js → index-CLUa68JH.js} +3 -3
- package/src/assets/web-panel/assets/{index-BoDUYyuo.js → index-CM2X25Er.js} +1 -1
- package/src/assets/web-panel/assets/{index-DyiCbHeL.js → index-CX4T2uKN.js} +1 -1
- package/src/assets/web-panel/assets/{index-CW5o1Gar.js → index-CixqfdRk.js} +1 -1
- package/src/assets/web-panel/assets/{index-5K2z_tgO.js → index-CkRojEip.js} +1 -1
- package/src/assets/web-panel/assets/{index-BOfPp5OV.js → index-Cvmc3f25.js} +1 -1
- package/src/assets/web-panel/assets/{index-CdxJm-HB.js → index-D-lpTPS8.js} +1 -1
- package/src/assets/web-panel/assets/{index-8ueG48gl.js → index-D59GbWCN.js} +1 -1
- package/src/assets/web-panel/assets/{index-BMxOoITz.js → index-DAESljiJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLMr5KMd.js → index-DDHUx4Yz.js} +1 -1
- package/src/assets/web-panel/assets/index-DG1mcYTa.js +1 -0
- package/src/assets/web-panel/assets/{index-BGIvhCPl.js → index-DP5pPedy.js} +1 -1
- package/src/assets/web-panel/assets/index-DRs5Pe8u.js +1 -0
- package/src/assets/web-panel/assets/{index-DjdSFO0d.js → index-DSlXL6Ju.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cn5UzvgR.js → index-DWCJnn2O.js} +1 -1
- package/src/assets/web-panel/assets/{index-Chct9tL8.js → index-DWY7YwDu.js} +1 -1
- package/src/assets/web-panel/assets/{index-BEnd5fiz.js → index-DZTwP364.js} +1 -1
- package/src/assets/web-panel/assets/{index-KzNhWykP.js → index-DidrMvOx.js} +1 -1
- package/src/assets/web-panel/assets/{index-BpyrhOeh.js → index-Dj3K5kHs.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZlkPrxb.js → index-YaeGscSw.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dfgxe-fw.js → index-YlMnFNOi.js} +1 -1
- package/src/assets/web-panel/assets/{index-IHgzfc1u.js → index-asWsB34i.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJkoJzTU.js → index-gkjiFjQd.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Cqfoq0TJ.js → initDefaultProps-BOr4igh3.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CIiVJHNu.js → motion-CK469n2j.js} +1 -1
- package/src/assets/web-panel/assets/{move-CFl1o_A8.js → move-DzjudlYQ.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DYoCxcZ1.js → mtc-parser-BQaKUxC6.js} +1 -1
- package/src/assets/web-panel/assets/{omit-C1P2q5TY.js → omit-MciovCFD.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BtTRpJtC.js → pickAttrs-DDPJ4zAz.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-Cst2PcNM.js → placementArrow-Cznyb-jI.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-CF5kalV2.js → responsiveObserve-AJK3SLzJ.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CtHGqpXN.js → slide-CPQ28wu7.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-N__biHXf.js → statusUtils-CFjzvqf_.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DR8V_H-i.js → styleChecker-BPyFfTuR.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-D274dqun.js → useFlexGapSupport-Dq7N6R05.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BwHLYU5b.js → useFs-C3GS0uTc.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BiA-hVqt.js → usePersonalDataHub-BhgIVzP_.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Bugl94dy.js → vnode-4ZD9-MDr.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DEFl8GCu.js → zoom-Bx4MRVNW.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/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/decision-layer/providers.js +84 -9
- package/src/lib/decision-layer/runtime.js +86 -49
- package/src/lib/direct-model-usage.js +14 -3
- 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/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/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/headless-runner.js +8 -0
- package/src/runtime/headless-stream.js +202 -4
- package/src/assets/web-panel/assets/EvolutionSettings-Pc1IpRfk.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-BIUeeiVA.js +0 -1
- package/src/assets/web-panel/assets/Skills-CYt0Mu2W.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-a2BBjtTL.js +0 -1
- package/src/assets/web-panel/assets/Tasks-BYQKU-GL.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DZhu13vj.js +0 -1
- package/src/assets/web-panel/assets/index-C6iFyQYz.js +0 -1
- package/src/assets/web-panel/assets/index-CztThH9f.js +0 -1
|
@@ -39,21 +39,62 @@ function projectNotification(notification) {
|
|
|
39
39
|
if (method === "turn/started") {
|
|
40
40
|
return { method: "turn/started", params: { turn: params.turn } };
|
|
41
41
|
}
|
|
42
|
+
const deltaKinds = {
|
|
43
|
+
"item/agentMessage/delta": "assistant_message",
|
|
44
|
+
"item/commandExecution/outputDelta": "tool",
|
|
45
|
+
"item/fileChange/outputDelta": "tool",
|
|
46
|
+
"item/reasoning/textDelta": "reasoning",
|
|
47
|
+
"item/reasoning/summaryTextDelta": "reasoning",
|
|
48
|
+
};
|
|
49
|
+
if (Object.hasOwn(deltaKinds, method)) {
|
|
50
|
+
return {
|
|
51
|
+
method: "item/delta",
|
|
52
|
+
params: {
|
|
53
|
+
item: {
|
|
54
|
+
id: params.itemId,
|
|
55
|
+
kind: deltaKinds[method],
|
|
56
|
+
status: "streaming",
|
|
57
|
+
delta: params.delta || "",
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
...(method === "item/agentMessage/delta"
|
|
61
|
+
? {
|
|
62
|
+
outputDelta: String(params.delta || ""),
|
|
63
|
+
outputItemId: params.itemId,
|
|
64
|
+
}
|
|
65
|
+
: {}),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (method === "thread/tokenUsage/updated") {
|
|
69
|
+
return {
|
|
70
|
+
method: "thread/usage",
|
|
71
|
+
params: { tokenUsage: params.tokenUsage },
|
|
72
|
+
usage: params.tokenUsage?.last || null,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
42
75
|
if (["item/started", "item/updated", "item/completed"].includes(method)) {
|
|
43
76
|
const item = params.item || {};
|
|
44
|
-
const
|
|
77
|
+
const tool = item.type === "commandExecution" || item.type === "fileChange";
|
|
78
|
+
let status = method === "item/completed" ? "completed" : "streaming";
|
|
79
|
+
// item/completed means lifecycle closure, not successful execution. A
|
|
80
|
+
// declined approval still closes the tool item before interrupting the
|
|
81
|
+
// turn. Preserve that outcome and never infer success for unknown states.
|
|
82
|
+
if (method === "item/completed" && tool) {
|
|
83
|
+
status = ["completed", "failed", "declined"].includes(item.status)
|
|
84
|
+
? item.status
|
|
85
|
+
: "unknown";
|
|
86
|
+
}
|
|
45
87
|
return {
|
|
46
88
|
method: method === "item/updated" ? "item/delta" : method,
|
|
47
89
|
params: {
|
|
48
90
|
item: {
|
|
49
91
|
id: item.id,
|
|
50
92
|
kind:
|
|
51
|
-
item.type === "
|
|
93
|
+
item.type === "agentMessage"
|
|
52
94
|
? "assistant_message"
|
|
53
95
|
: item.type === "reasoning"
|
|
54
96
|
? "reasoning"
|
|
55
|
-
:
|
|
56
|
-
item.type === "file_change"
|
|
97
|
+
: tool
|
|
57
98
|
? "tool"
|
|
58
99
|
: "artifact",
|
|
59
100
|
status,
|
|
@@ -61,9 +102,10 @@ function projectNotification(notification) {
|
|
|
61
102
|
},
|
|
62
103
|
},
|
|
63
104
|
output:
|
|
64
|
-
method === "item/completed" && item.type === "
|
|
105
|
+
method === "item/completed" && item.type === "agentMessage"
|
|
65
106
|
? String(item.text || "")
|
|
66
|
-
:
|
|
107
|
+
: undefined,
|
|
108
|
+
outputItemId: item.id,
|
|
67
109
|
};
|
|
68
110
|
}
|
|
69
111
|
if (method === "turn/completed" || method === "turn/failed") {
|
|
@@ -160,44 +202,97 @@ export class CodexAppServerAdapter extends EventEmitter {
|
|
|
160
202
|
}
|
|
161
203
|
const notifications = [];
|
|
162
204
|
const unknownMethods = new Set();
|
|
163
|
-
|
|
205
|
+
const outputItems = new Map();
|
|
206
|
+
let usage = null;
|
|
164
207
|
let activeThreadId = threadId;
|
|
208
|
+
let activeTurnId = null;
|
|
165
209
|
let submissionStarted = false;
|
|
166
210
|
let admissionObserved = false;
|
|
167
211
|
let observedTerminal = null;
|
|
168
212
|
let terminalResolve;
|
|
169
|
-
|
|
170
|
-
const terminal = new Promise((resolve, reject) => {
|
|
213
|
+
const terminal = new Promise((resolve) => {
|
|
171
214
|
terminalResolve = resolve;
|
|
172
|
-
terminalReject = reject;
|
|
173
215
|
});
|
|
216
|
+
let deadlineReject;
|
|
217
|
+
const deadline = new Promise((_, reject) => {
|
|
218
|
+
deadlineReject = reject;
|
|
219
|
+
});
|
|
220
|
+
// Attach immediately: startup/RPC may hang or reject before terminal await.
|
|
221
|
+
deadline.catch(() => {});
|
|
174
222
|
const timer = setTimeout(
|
|
175
223
|
() =>
|
|
176
|
-
|
|
224
|
+
deadlineReject(
|
|
177
225
|
adapterError(
|
|
178
226
|
"CC_CODEX_APP_SERVER_TIMEOUT",
|
|
179
|
-
"Codex App Server
|
|
227
|
+
"Codex App Server request timed out",
|
|
180
228
|
),
|
|
181
229
|
),
|
|
182
230
|
this.timeoutMs,
|
|
183
231
|
);
|
|
184
232
|
timer.unref?.();
|
|
233
|
+
const withinDeadline = (pending) => Promise.race([pending, deadline]);
|
|
234
|
+
let buffered = [];
|
|
235
|
+
let retainedBytes = 0;
|
|
236
|
+
let eventFailure = null;
|
|
237
|
+
const retain = (notification) => {
|
|
238
|
+
retainedBytes += Buffer.byteLength(JSON.stringify(notification));
|
|
239
|
+
if (
|
|
240
|
+
retainedBytes > 4 * 1024 * 1024 ||
|
|
241
|
+
notifications.length + buffered.length >= 4096
|
|
242
|
+
) {
|
|
243
|
+
eventFailure = adapterError(
|
|
244
|
+
"CC_CODEX_APP_SERVER_EVENT_LIMIT",
|
|
245
|
+
"Codex App Server event retention limit exceeded",
|
|
246
|
+
);
|
|
247
|
+
deadlineReject(eventFailure);
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
return true;
|
|
251
|
+
};
|
|
185
252
|
const onNotification = (notification) => {
|
|
253
|
+
if (observedTerminal || eventFailure || !submissionStarted) return;
|
|
254
|
+
const params = notification?.params || {};
|
|
255
|
+
const eventThread =
|
|
256
|
+
params.threadId ||
|
|
257
|
+
(notification.method === "thread/started" ? params.thread?.id : null);
|
|
258
|
+
if (!eventThread || eventThread !== activeThreadId) return;
|
|
259
|
+
if (!activeTurnId) {
|
|
260
|
+
if (retain(notification)) buffered.push(notification);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
const eventTurn = params.turnId || params.turn?.id;
|
|
264
|
+
// Thread-wide events carry no turn. Only thread/started is safe to
|
|
265
|
+
// project here; usage and terminal events require the exact turn ID.
|
|
266
|
+
if (
|
|
267
|
+
notification.method !== "thread/started" &&
|
|
268
|
+
eventTurn !== activeTurnId
|
|
269
|
+
)
|
|
270
|
+
return;
|
|
271
|
+
if (!retain(notification)) return;
|
|
186
272
|
const projected = projectNotification(notification);
|
|
187
|
-
if (projected.unknownMethod)
|
|
188
|
-
|
|
273
|
+
if (projected.unknownMethod) {
|
|
274
|
+
if (unknownMethods.size < 64)
|
|
275
|
+
unknownMethods.add(projected.unknownMethod);
|
|
276
|
+
} else {
|
|
277
|
+
projected.params = {
|
|
278
|
+
...projected.params,
|
|
279
|
+
threadId: activeThreadId,
|
|
280
|
+
turnId: activeTurnId,
|
|
281
|
+
};
|
|
189
282
|
notifications.push(projected);
|
|
190
283
|
this.emit("notification", projected);
|
|
191
284
|
}
|
|
192
|
-
if (
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
285
|
+
if (projected.outputItemId) {
|
|
286
|
+
if (projected.output !== undefined)
|
|
287
|
+
outputItems.set(projected.outputItemId, projected.output);
|
|
288
|
+
else if (projected.outputDelta)
|
|
289
|
+
outputItems.set(
|
|
290
|
+
projected.outputItemId,
|
|
291
|
+
(outputItems.get(projected.outputItemId) || "") +
|
|
292
|
+
projected.outputDelta,
|
|
293
|
+
);
|
|
199
294
|
}
|
|
200
|
-
if (projected.
|
|
295
|
+
if (projected.usage) usage = projected.usage;
|
|
201
296
|
if (projected.terminal) {
|
|
202
297
|
observedTerminal = projected;
|
|
203
298
|
terminalResolve(projected);
|
|
@@ -208,10 +303,11 @@ export class CodexAppServerAdapter extends EventEmitter {
|
|
|
208
303
|
Object.freeze({
|
|
209
304
|
protocol: CODEX_APP_SERVER_PROTOCOL,
|
|
210
305
|
threadId: activeThreadId,
|
|
306
|
+
turnId: activeTurnId,
|
|
211
307
|
terminal: terminalEvent.terminal,
|
|
212
|
-
output,
|
|
308
|
+
output: [...outputItems.values()].join("\n"),
|
|
213
309
|
error: terminalEvent.error || null,
|
|
214
|
-
usage: terminalEvent.usage ||
|
|
310
|
+
usage: terminalEvent.usage || usage,
|
|
215
311
|
notifications: Object.freeze(notifications),
|
|
216
312
|
unknownMethods: Object.freeze([...unknownMethods].sort()),
|
|
217
313
|
fallback: false,
|
|
@@ -219,13 +315,14 @@ export class CodexAppServerAdapter extends EventEmitter {
|
|
|
219
315
|
});
|
|
220
316
|
try {
|
|
221
317
|
if (!this.client.running && typeof this.client.start === "function") {
|
|
222
|
-
await this.client.start();
|
|
318
|
+
await withinDeadline(this.client.start());
|
|
223
319
|
}
|
|
224
320
|
if (!activeThreadId) {
|
|
225
|
-
const started = await
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
321
|
+
const started = await withinDeadline(
|
|
322
|
+
this.client.request("thread/start", {
|
|
323
|
+
ephemeral: false,
|
|
324
|
+
}),
|
|
325
|
+
);
|
|
229
326
|
activeThreadId = started?.thread?.id;
|
|
230
327
|
}
|
|
231
328
|
if (!activeThreadId) {
|
|
@@ -238,20 +335,49 @@ export class CodexAppServerAdapter extends EventEmitter {
|
|
|
238
335
|
// the server did not accept the input. Never launch a second execution
|
|
239
336
|
// path from that ambiguous state.
|
|
240
337
|
submissionStarted = true;
|
|
241
|
-
const started = await
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
338
|
+
const started = await withinDeadline(
|
|
339
|
+
this.client.request("turn/start", {
|
|
340
|
+
threadId: activeThreadId,
|
|
341
|
+
input: [{ type: "text", text: String(prompt || "") }],
|
|
342
|
+
}),
|
|
343
|
+
);
|
|
344
|
+
activeTurnId = started?.turn?.id;
|
|
345
|
+
if (typeof activeTurnId !== "string" || !activeTurnId) {
|
|
346
|
+
throw adapterError(
|
|
347
|
+
"CC_CODEX_APP_SERVER_PROTOCOL_FAILED",
|
|
348
|
+
"Codex App Server did not return a turn identity",
|
|
349
|
+
);
|
|
350
|
+
}
|
|
245
351
|
admissionObserved = true;
|
|
352
|
+
if (eventFailure) throw eventFailure;
|
|
353
|
+
const early = buffered;
|
|
354
|
+
buffered = [];
|
|
355
|
+
retainedBytes = 0;
|
|
356
|
+
for (const notification of early) onNotification(notification);
|
|
357
|
+
if (eventFailure) throw eventFailure;
|
|
358
|
+
// Some servers finish before writing the RPC response, including items
|
|
359
|
+
// in the response without separate item notifications.
|
|
360
|
+
if (!observedTerminal)
|
|
361
|
+
for (const item of started.turn.items || []) {
|
|
362
|
+
onNotification({
|
|
363
|
+
method: "item/completed",
|
|
364
|
+
params: { threadId: activeThreadId, turnId: activeTurnId, item },
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
if (eventFailure) throw eventFailure;
|
|
246
368
|
const initialStatus = String(started?.turn?.status || "");
|
|
247
369
|
const terminalEvent = ["completed", "failed", "interrupted"].includes(
|
|
248
370
|
initialStatus,
|
|
249
371
|
)
|
|
250
372
|
? projectNotification({
|
|
251
373
|
method: "turn/completed",
|
|
252
|
-
params: {
|
|
374
|
+
params: {
|
|
375
|
+
threadId: activeThreadId,
|
|
376
|
+
turn: started.turn,
|
|
377
|
+
usage: started.turn.usage || null,
|
|
378
|
+
},
|
|
253
379
|
})
|
|
254
|
-
: await terminal;
|
|
380
|
+
: await withinDeadline(terminal);
|
|
255
381
|
return buildResult(terminalEvent);
|
|
256
382
|
} catch (error) {
|
|
257
383
|
if (!submissionStarted) {
|
package/src/lib/cost-budget.js
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import { estimateCost } from "./llm-pricing.js";
|
|
21
|
+
import { projectUsagePricingContext } from "./usage-pricing-context.js";
|
|
21
22
|
|
|
22
23
|
/** Parse a `--max-budget-usd` value into a positive number, or null when unset. */
|
|
23
24
|
export function parseBudgetUsd(value) {
|
|
@@ -64,6 +65,7 @@ export class CostBudget {
|
|
|
64
65
|
// or it undercounts real spend on a cached Anthropic run and stops too late.
|
|
65
66
|
const cacheReadTokens = usage?.cache_read_input_tokens || 0;
|
|
66
67
|
const cacheCreationTokens = usage?.cache_creation_input_tokens || 0;
|
|
68
|
+
const pricingContext = projectUsagePricingContext(usage || {});
|
|
67
69
|
const est = estimateCost({
|
|
68
70
|
provider,
|
|
69
71
|
model,
|
|
@@ -71,6 +73,8 @@ export class CostBudget {
|
|
|
71
73
|
outputTokens: usage?.output_tokens || 0,
|
|
72
74
|
cacheReadTokens,
|
|
73
75
|
cacheCreationTokens,
|
|
76
|
+
serviceTier: pricingContext.service_tier ?? "standard",
|
|
77
|
+
regionalProcessing: pricingContext.regional_processing === true,
|
|
74
78
|
table: this.table,
|
|
75
79
|
});
|
|
76
80
|
const tokens =
|
|
@@ -14,6 +14,9 @@ const PROVIDERS = Object.freeze({
|
|
|
14
14
|
"system-one": { label: "System One" },
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
+
export const MAX_DECISION_REQUEST_BYTES = 256 * 1024;
|
|
18
|
+
export const MAX_DECISION_RESPONSE_BYTES = 256 * 1024;
|
|
19
|
+
|
|
17
20
|
function boundedText(value, label, limit = 160) {
|
|
18
21
|
if (
|
|
19
22
|
typeof value !== "string" ||
|
|
@@ -98,6 +101,71 @@ function providerError(status, provider) {
|
|
|
98
101
|
return error;
|
|
99
102
|
}
|
|
100
103
|
|
|
104
|
+
function bodyTooLarge(kind, maximum) {
|
|
105
|
+
const error = new Error(`decision ${kind} exceeds ${maximum} bytes`);
|
|
106
|
+
error.code = `CC_DECISION_${kind.toUpperCase()}_TOO_LARGE`;
|
|
107
|
+
return error;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function readBoundedJsonResponse(response) {
|
|
111
|
+
const declared = response.headers?.get?.("content-length");
|
|
112
|
+
if (
|
|
113
|
+
declared != null &&
|
|
114
|
+
/^\d+$/u.test(declared) &&
|
|
115
|
+
BigInt(declared) > BigInt(MAX_DECISION_RESPONSE_BYTES)
|
|
116
|
+
) {
|
|
117
|
+
try {
|
|
118
|
+
await response.body?.cancel?.();
|
|
119
|
+
} catch {
|
|
120
|
+
// The declared size remains authoritative even if cancellation fails.
|
|
121
|
+
}
|
|
122
|
+
throw bodyTooLarge("response", MAX_DECISION_RESPONSE_BYTES);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// A real Fetch Response has a stream; injected test transports may only
|
|
126
|
+
// expose json(). The latter is checked after parsing because it is trusted.
|
|
127
|
+
if (!response.body?.getReader) {
|
|
128
|
+
const value = await response.json();
|
|
129
|
+
if (
|
|
130
|
+
Buffer.byteLength(JSON.stringify(value), "utf8") >
|
|
131
|
+
MAX_DECISION_RESPONSE_BYTES
|
|
132
|
+
) {
|
|
133
|
+
throw bodyTooLarge("response", MAX_DECISION_RESPONSE_BYTES);
|
|
134
|
+
}
|
|
135
|
+
return value;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const reader = response.body.getReader();
|
|
139
|
+
const chunks = [];
|
|
140
|
+
let total = 0;
|
|
141
|
+
try {
|
|
142
|
+
for (;;) {
|
|
143
|
+
const { done, value } = await reader.read();
|
|
144
|
+
if (done) break;
|
|
145
|
+
const chunkBytes = value?.byteLength;
|
|
146
|
+
if (
|
|
147
|
+
!Number.isSafeInteger(chunkBytes) ||
|
|
148
|
+
total + chunkBytes > MAX_DECISION_RESPONSE_BYTES
|
|
149
|
+
) {
|
|
150
|
+
throw bodyTooLarge("response", MAX_DECISION_RESPONSE_BYTES);
|
|
151
|
+
}
|
|
152
|
+
const chunk = Buffer.from(value);
|
|
153
|
+
total += chunk.length;
|
|
154
|
+
chunks.push(chunk);
|
|
155
|
+
}
|
|
156
|
+
return JSON.parse(new TextDecoder().decode(Buffer.concat(chunks, total)));
|
|
157
|
+
} catch (error) {
|
|
158
|
+
try {
|
|
159
|
+
await reader.cancel();
|
|
160
|
+
} catch {
|
|
161
|
+
// The original read, size, or JSON error remains authoritative.
|
|
162
|
+
}
|
|
163
|
+
throw error;
|
|
164
|
+
} finally {
|
|
165
|
+
reader.releaseLock();
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
101
169
|
export function createDecisionProvider({
|
|
102
170
|
provider,
|
|
103
171
|
model,
|
|
@@ -119,6 +187,14 @@ export function createDecisionProvider({
|
|
|
119
187
|
provider: options.provider,
|
|
120
188
|
model: options.model,
|
|
121
189
|
decide: async (request, { signal } = {}) => {
|
|
190
|
+
const body = JSON.stringify({
|
|
191
|
+
model: options.model,
|
|
192
|
+
state: request.payload.state,
|
|
193
|
+
questions: request.payload.questions,
|
|
194
|
+
});
|
|
195
|
+
if (Buffer.byteLength(body, "utf8") > MAX_DECISION_REQUEST_BYTES) {
|
|
196
|
+
throw bodyTooLarge("request", MAX_DECISION_REQUEST_BYTES);
|
|
197
|
+
}
|
|
122
198
|
const response = await fetchImpl(endpoint, {
|
|
123
199
|
method: "POST",
|
|
124
200
|
headers: {
|
|
@@ -127,23 +203,22 @@ export function createDecisionProvider({
|
|
|
127
203
|
: { authorization: `Bearer ${secret}` }),
|
|
128
204
|
"content-type": "application/json",
|
|
129
205
|
},
|
|
130
|
-
body
|
|
131
|
-
model: options.model,
|
|
132
|
-
state: request.payload.state,
|
|
133
|
-
questions: request.payload.questions,
|
|
134
|
-
}),
|
|
206
|
+
body,
|
|
135
207
|
signal,
|
|
136
208
|
redirect: "error",
|
|
137
209
|
});
|
|
138
210
|
if (!response?.ok) {
|
|
139
211
|
throw providerError(response?.status ?? 0, options.provider);
|
|
140
212
|
}
|
|
141
|
-
const
|
|
213
|
+
const responseBody = await readBoundedJsonResponse(response);
|
|
142
214
|
return {
|
|
143
215
|
provider: options.provider,
|
|
144
|
-
model:
|
|
145
|
-
|
|
146
|
-
|
|
216
|
+
model:
|
|
217
|
+
typeof responseBody?.model === "string"
|
|
218
|
+
? responseBody.model
|
|
219
|
+
: options.model,
|
|
220
|
+
answers: responseBody?.answers,
|
|
221
|
+
usage: responseBody?.usage,
|
|
147
222
|
};
|
|
148
223
|
},
|
|
149
224
|
});
|
|
@@ -38,12 +38,28 @@ function timeoutSignal(signal, timeoutMs) {
|
|
|
38
38
|
|
|
39
39
|
function projectUnavailable(error) {
|
|
40
40
|
if (error?.name === "TimeoutError") return "provider-timeout";
|
|
41
|
+
if (error?.code === "CC_DECISION_USAGE_UNKNOWN_BLOCKED") {
|
|
42
|
+
return "provider-usage-unknown-blocked";
|
|
43
|
+
}
|
|
41
44
|
if (error?.code === "CC_DECISION_PROVIDER_HTTP_ERROR") {
|
|
42
45
|
return "provider-http-error";
|
|
43
46
|
}
|
|
44
47
|
return "provider-unavailable";
|
|
45
48
|
}
|
|
46
49
|
|
|
50
|
+
function unavailableOutcome(reasonCode) {
|
|
51
|
+
return {
|
|
52
|
+
status: "unavailable",
|
|
53
|
+
reasonCode,
|
|
54
|
+
selectedCandidateId: null,
|
|
55
|
+
selectedDigest: null,
|
|
56
|
+
selectedSkillId: null,
|
|
57
|
+
needsSkillProbability: null,
|
|
58
|
+
choiceConfidence: null,
|
|
59
|
+
resultDigest: null,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
47
63
|
function asPersistenceError(error) {
|
|
48
64
|
if (error?.runtimeLedgerPersistence === true) return error;
|
|
49
65
|
try {
|
|
@@ -63,6 +79,7 @@ export function createSkillDecisionRuntime({
|
|
|
63
79
|
persist = null,
|
|
64
80
|
observe = null,
|
|
65
81
|
sessionBudget = null,
|
|
82
|
+
initialUsageUnknown = false,
|
|
66
83
|
thresholds = {},
|
|
67
84
|
timeoutMs = DEFAULT_TIMEOUT_MS,
|
|
68
85
|
idGenerator = () => randomUUID(),
|
|
@@ -84,6 +101,7 @@ export function createSkillDecisionRuntime({
|
|
|
84
101
|
let providerAuthority = null;
|
|
85
102
|
let boundTenantId = null;
|
|
86
103
|
let boundSessionId = null;
|
|
104
|
+
let unknownUsageSeen = initialUsageUnknown === true;
|
|
87
105
|
if (normalizedMode !== "off") {
|
|
88
106
|
providerAuthority = captureDecisionProviderAuthority(provider);
|
|
89
107
|
boundTenantId = requiredText(tenantId, "tenantId");
|
|
@@ -104,6 +122,11 @@ export function createSkillDecisionRuntime({
|
|
|
104
122
|
}
|
|
105
123
|
};
|
|
106
124
|
|
|
125
|
+
const persistDecisionUsage = async (type, event) => {
|
|
126
|
+
await persist(type, event);
|
|
127
|
+
if (type === "model_usage_unknown") unknownUsageSeen = true;
|
|
128
|
+
};
|
|
129
|
+
|
|
107
130
|
const runtime = Object.freeze({
|
|
108
131
|
schema: SKILL_DECISION_RUNTIME_SCHEMA,
|
|
109
132
|
mode: normalizedMode,
|
|
@@ -144,56 +167,70 @@ export function createSkillDecisionRuntime({
|
|
|
144
167
|
}
|
|
145
168
|
let outcome;
|
|
146
169
|
let requestSignal = null;
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
170
|
+
if (unknownUsageSeen) {
|
|
171
|
+
outcome = unavailableOutcome("provider-usage-unknown-blocked");
|
|
172
|
+
} else {
|
|
173
|
+
try {
|
|
174
|
+
const { result: raw, settlement } = await runMeteredDirectModelCall({
|
|
175
|
+
sessionId: boundSessionId,
|
|
176
|
+
persist: persistDecisionUsage,
|
|
177
|
+
provider: providerAuthority.provider,
|
|
178
|
+
model: providerAuthority.model,
|
|
179
|
+
source: "model",
|
|
180
|
+
operationId: `decision:${decisionId}`,
|
|
181
|
+
sessionBudget,
|
|
182
|
+
includeSettlement: true,
|
|
183
|
+
call: () => {
|
|
184
|
+
if (unknownUsageSeen) {
|
|
185
|
+
const error = new Error("decision usage recovery is required");
|
|
186
|
+
error.code = "CC_DECISION_USAGE_UNKNOWN_BLOCKED";
|
|
187
|
+
throw error;
|
|
188
|
+
}
|
|
189
|
+
requestSignal = timeoutSignal(signal, timeoutMs);
|
|
190
|
+
return providerAuthority.decide(request, {
|
|
191
|
+
signal: requestSignal,
|
|
192
|
+
});
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
if (settlement !== "known") {
|
|
196
|
+
// The metered call already persisted model_usage_unknown. Without a
|
|
197
|
+
// budget root it may return the answer; never expose that answer.
|
|
198
|
+
outcome = unavailableOutcome("provider-usage-unknown");
|
|
199
|
+
} else {
|
|
200
|
+
const normalized = normalizeSkillDecisionProviderResult(
|
|
201
|
+
request,
|
|
202
|
+
raw,
|
|
203
|
+
);
|
|
204
|
+
const resolved = resolveSkillDecision(
|
|
205
|
+
request,
|
|
206
|
+
normalized,
|
|
207
|
+
thresholds,
|
|
208
|
+
);
|
|
209
|
+
outcome = {
|
|
210
|
+
status: resolved.status,
|
|
211
|
+
reasonCode: resolved.reasonCode,
|
|
212
|
+
selectedCandidateId: resolved.selectedCandidateId,
|
|
213
|
+
selectedDigest: resolved.selectedDigest,
|
|
214
|
+
selectedSkillId: resolved.selectedSkillId,
|
|
215
|
+
needsSkillProbability: resolved.needsSkillProbability,
|
|
216
|
+
choiceConfidence: resolved.choiceConfidence,
|
|
217
|
+
resultDigest: resolved.resultDigest,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
} catch (error) {
|
|
221
|
+
const localTimeout =
|
|
222
|
+
!signal?.aborted &&
|
|
223
|
+
requestSignal?.aborted &&
|
|
224
|
+
requestSignal.reason === error &&
|
|
225
|
+
error?.name === "TimeoutError";
|
|
226
|
+
if (
|
|
227
|
+
signal?.aborted ||
|
|
228
|
+
(isTerminalModelFailure(error) && !localTimeout)
|
|
229
|
+
) {
|
|
230
|
+
throw error;
|
|
231
|
+
}
|
|
232
|
+
outcome = unavailableOutcome(projectUnavailable(error));
|
|
186
233
|
}
|
|
187
|
-
outcome = {
|
|
188
|
-
status: "unavailable",
|
|
189
|
-
reasonCode: projectUnavailable(error),
|
|
190
|
-
selectedCandidateId: null,
|
|
191
|
-
selectedDigest: null,
|
|
192
|
-
selectedSkillId: null,
|
|
193
|
-
needsSkillProbability: null,
|
|
194
|
-
choiceConfidence: null,
|
|
195
|
-
resultDigest: null,
|
|
196
|
-
};
|
|
197
234
|
}
|
|
198
235
|
const finishedAt = now();
|
|
199
236
|
if (
|
|
@@ -54,6 +54,7 @@ function unknownUsageEvent({
|
|
|
54
54
|
* Meter one direct provider call that runs outside agentLoop. The started row is
|
|
55
55
|
* durable before the callback resumes into provider work; every outcome then
|
|
56
56
|
* settles known or unknown without persisting prompts, responses, or errors.
|
|
57
|
+
* Opt-in includeSettlement returns that persisted status with the raw result.
|
|
57
58
|
*/
|
|
58
59
|
export async function runMeteredDirectModelCall({
|
|
59
60
|
sessionId,
|
|
@@ -63,6 +64,7 @@ export async function runMeteredDirectModelCall({
|
|
|
63
64
|
source = "model",
|
|
64
65
|
operationId = undefined,
|
|
65
66
|
sessionBudget = null,
|
|
67
|
+
includeSettlement = false,
|
|
66
68
|
call,
|
|
67
69
|
}) {
|
|
68
70
|
if (typeof call !== "function") {
|
|
@@ -78,7 +80,12 @@ export async function runMeteredDirectModelCall({
|
|
|
78
80
|
);
|
|
79
81
|
}
|
|
80
82
|
}
|
|
81
|
-
if (!sessionId)
|
|
83
|
+
if (!sessionId) {
|
|
84
|
+
if (includeSettlement) {
|
|
85
|
+
throw new TypeError("direct model settlement requires a session");
|
|
86
|
+
}
|
|
87
|
+
return call();
|
|
88
|
+
}
|
|
82
89
|
if (typeof persist !== "function") {
|
|
83
90
|
throw new TypeError("metered direct model call requires persistence");
|
|
84
91
|
}
|
|
@@ -96,6 +103,9 @@ export async function runMeteredDirectModelCall({
|
|
|
96
103
|
`direct model call ${source}`,
|
|
97
104
|
);
|
|
98
105
|
let result;
|
|
106
|
+
let settlement = "unknown";
|
|
107
|
+
const returnSettled = (status) =>
|
|
108
|
+
includeSettlement ? Object.freeze({ result, settlement: status }) : result;
|
|
99
109
|
try {
|
|
100
110
|
result = await call();
|
|
101
111
|
} catch (error) {
|
|
@@ -139,7 +149,7 @@ export async function runMeteredDirectModelCall({
|
|
|
139
149
|
if (markSessionBudgetUsageUnknown(sessionBudget, unknown)) {
|
|
140
150
|
rejectSessionBudgetUsageUnknown(unknown, `direct model call ${source}`);
|
|
141
151
|
}
|
|
142
|
-
return
|
|
152
|
+
return returnSettled("unknown");
|
|
143
153
|
}
|
|
144
154
|
await persistUsageEvent(persist, "token_usage", event);
|
|
145
155
|
recordSessionBudgetUsage(
|
|
@@ -147,6 +157,7 @@ export async function runMeteredDirectModelCall({
|
|
|
147
157
|
event,
|
|
148
158
|
`direct model call ${source} usage settlement`,
|
|
149
159
|
);
|
|
160
|
+
settlement = "known";
|
|
150
161
|
} else {
|
|
151
162
|
const unknown = unknownUsageEvent({
|
|
152
163
|
callId,
|
|
@@ -161,5 +172,5 @@ export async function runMeteredDirectModelCall({
|
|
|
161
172
|
rejectSessionBudgetUsageUnknown(unknown, `direct model call ${source}`);
|
|
162
173
|
}
|
|
163
174
|
}
|
|
164
|
-
return
|
|
175
|
+
return returnSettled(settlement);
|
|
165
176
|
}
|