chainlesschain 0.166.101 → 0.166.103
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/package.json +2 -2
- package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
- package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-BjBS_29I.js → AIOps-BLrXpdnP.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CUnnQUaj.js → ActionButton-C0xy9uFy.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BqYZxgnY.js → Analytics-C6EephQP.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-m8B886ka.js → AppLayout-ZCXdOD9y.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-JEOxU3Ug.js → Artifacts-D4MfZ-pl.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DAXS5c9J.js → Audit-BQ8c3bBu.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-e3a9XHw3.js → BackgroundAgents-BOA7_ljM.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-D3Qmp68h.js → Backup-60uiQjGT.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-C7CXyiUl.js → BaseInput-BDvEbGs_.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-2AHlAGi8.js → Chat-B3IkAuFQ.js} +6 -6
- package/src/assets/web-panel/assets/ChatBubbleRenderer-n6BVStHf.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-YfBuQlBH.js → Checkbox-njGbfJWq.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DCCQDfTL.js → Codegen-CF7DtdxC.js} +1 -1
- package/src/assets/web-panel/assets/{Col-03i2WfrV.js → Col-C_3Zix40.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CJQIpng6.js → Community-CzU-ZC2d.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CCtcQ2pq.js → Compact-BgeqsPRh.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Vxl7ZszJ.js → Compliance-6l7cwiqp.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DN-BwA8I.js → Cowork-D4s905fI.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-Dc2Q46X7.js → Cron-CGTYSxRS.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CQCblsl-.js → Crosschain-BnSo-Yt3.js} +1 -1
- package/src/assets/web-panel/assets/{DID-YYvqUR8C.js → DID-Dm4vk2X1.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-Cafy3DZT.js → Dashboard-D7H-PZ_N.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BOyYpIpv.js → Dropdown-COslkgxn.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-B7NYjc1j.js → EmailListRenderer-CJWEetmk.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-C5wfxztf.js → EvolutionSettings-BbzebAWe.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-aA7KnDGK.js → FamilyGuardDashboard-BsoTOXwk.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DlgXUu1L.js → Federation-Ck5kM_5H.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-B5YsrLDg.js → FormItemContext-gShxCqtF.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DaWojPFw.js → GenericCardRenderer-DarN1G-z.js} +1 -1
- package/src/assets/web-panel/assets/{Git-dkhh6Fx2.js → Git-CJfpLyP5.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-Cz6vmkjc.js → Governance-CVcJmpQz.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DWt0hbh8.js → Inference-ComU_ig8.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-BZJ0Z-nL.js → KnowledgeGraph-35hprFJy.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BaBBmL1A.js → Logs-BQDqBTz0.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-BpdGAVCC.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-ct8sgQ0s.js → Marketplace-B9O9OKnn.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CXKCRGYQ.js → McpTools-VMKxA4Wc.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-O7ZwlS6a.js → Memory-CcBbf3Bc.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-By12C-eC.js → MobileBridge-D7myz46N.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-Ba-EVdex.js → MobileProjects-Da5KBXyx.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-g-932zV2.js → Mtc-x3NPZfuL.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-BW8hB0ly.js → MtcAudit-CwnzptEC.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-zspLaMbT.js → Multisig-CCAxf4Ye.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-dJeUPDoq.js → NLProgramming-CptHKz-Q.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-C4msiRQL.js → Notes-0uEp4DCJ.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-MOCHM-qg.js → NotificationSettings-DthvrOLd.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-CX0T66NM.js → OrderTableRenderer-CxXuPzZg.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DOZurBfk.js → Organization-BWf2tmQQ.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-qOT9BhUp.js → Overflow-BbvAtEth.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BMoy7Eo4.js → P2P-zBo6enit.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-ByyV1q-D.js → PdhVaultBrowser-D_LMQ4A4.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-6Qyro4ye.js → Permissions-C1ucb2ck.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-DR3DRNSX.js → PersonalDataHub-Bz64RddJ.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-Cr6TTdud.js → Pipeline-DXJt3y3_.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-B70otG0l.js → Privacy-DiZ8b_ut.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BHCqxoSk.js → ProjectInit-DfLKKrJ4.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-B80GZpZk.js → ProjectSettings-Ct6kJuIY.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-cq-b9-fQ.js → Projects-BBUMlZ3m.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-dsVTimHa.js → Providers-DYVQPHvc.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DRJ8YepZ.js → QrScannerModal-23Il7iPp.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BSXdEjIB.js → QuickAsk-WgOZKrv1.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CQLJGyKC.js → Recommend-CRIka6xT.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-BF9WUFVZ.js → RemoteSession-DOy3GjVZ.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-Cy9o5tvW.js → Reputation-BXyi6xeR.js} +1 -1
- package/src/assets/web-panel/assets/{Row-BP346_3b.js → Row-CoMxuIcR.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BKulxXf3.js → RssFeed-87hPkoM6.js} +3 -3
- package/src/assets/web-panel/assets/{Search-EemQj2Dv.js → Search-B1EqFCO4.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DcWPAwwk.js → Security-HcC41eGs.js} +4 -4
- package/src/assets/web-panel/assets/{Services-Bltqciay.js → Services-BqLwmvCM.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BwRyOGY8.js → Skeleton-CIMmjW4r.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-D98qlvpJ.js → Skills-CgurezJU.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BUTtBMY0.js → Sla-CJuRuqPE.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-C7kcY_98.js → SpeechSettings-BUwsbd1o.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-Bsk6lKvT.js → SyncSettings-qo04TOX-.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-QEFENVsp.js +1 -0
- package/src/assets/web-panel/assets/{Templates-BUM6LwPs.js → Templates-D1PTczPW.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-D9TkOm7z.js → Tenant-Bi0FkEPR.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-CP8ZVErN.js → Terminal-DfSt3bIF.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-V3SoKZ1T.js → TimelineRenderer-B7bIVs4R.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CCRlUTOA.js → Tokens-B6w5XrMb.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CznUcPme.js → Trigger-XXVSDWiF.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-D1GIk_NF.js → Trust-DYvlgcK-.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DHtvtyC-.js → UkeySign-XyYwJMBM.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CVxdaJIq.js → VideoEditing-C47WbtHH.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-D221OjyE.js → Wallet-CYfqTj_C.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-Cw0-ESsq.js → WebAuthn-3AduFn1l.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-ZYScrBx3.js → WorkflowEditor-DHYEHjMJ.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BU0e1obR.js → chat-AeehErSw.js} +1 -1
- package/src/assets/web-panel/assets/{colors-gzYweuha.js → colors-DKXJ8paX.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-ChAXal_k.js → compact-item-BOlCiomD.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-of3FolD7.js → createContext-BAP6U85b.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-rGldFhxo.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-4PsK_Kx8.js → hasIn-BLmeL1Xe.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cn1clrxx.js → index-B0IjlB9m.js} +1 -1
- package/src/assets/web-panel/assets/{index-BOeX7BzS.js → index-BAS2QqLn.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cx4Z6nUl.js → index-BRcJlKSa.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjRAIRX7.js → index-BSOenF5s.js} +1 -1
- package/src/assets/web-panel/assets/{index-Djfgsjfy.js → index-BTnp4Nt3.js} +1 -1
- package/src/assets/web-panel/assets/{index-BfI4dXbi.js → index-BhcpWl5z.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_5LTPMH.js → index-Bn54FU3i.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyDQNprx.js → index-Bpx54vfs.js} +1 -1
- package/src/assets/web-panel/assets/{index-DEXBckNR.js → index-Bs2O3f81.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ef5YkVAn.js → index-Bt-FCVzh.js} +1 -1
- package/src/assets/web-panel/assets/{index-E8oDMSAo.js → index-BuUwKmEI.js} +1 -1
- package/src/assets/web-panel/assets/{index-BdxRVNPY.js → index-C5AKY6bJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Wr91cnWr.js → index-C8qi53Ki.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5L7zddz.js → index-CFKzWIo8.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dy0ojH6G.js → index-CRa4pAaM.js} +3 -3
- package/src/assets/web-panel/assets/{index-wo0De0iG.js → index-CaHhfpBi.js} +1 -1
- package/src/assets/web-panel/assets/{index-D-Zss5KL.js → index-CdNSmvog.js} +1 -1
- package/src/assets/web-panel/assets/{index-DEzjUgkl.js → index-CgtaOzMo.js} +1 -1
- package/src/assets/web-panel/assets/{index-DDYj14Q4.js → index-CiqeF0Pf.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_9k680X.js → index-ClpwxOXo.js} +1 -1
- package/src/assets/web-panel/assets/{index-D1PGrfHE.js → index-Co7pjF53.js} +1 -1
- package/src/assets/web-panel/assets/index-Cw-lfvvV.js +1 -0
- package/src/assets/web-panel/assets/{index-CeEE_SGZ.js → index-DE7cbDDe.js} +1 -1
- package/src/assets/web-panel/assets/{index-CxzBcXOa.js → index-DQLQuwpA.js} +1 -1
- package/src/assets/web-panel/assets/{index-DEB5fQqG.js → index-DWYqOI1A.js} +1 -1
- package/src/assets/web-panel/assets/{index-CO2owKe0.js → index-De2fPxdb.js} +1 -1
- package/src/assets/web-panel/assets/{index-1dzYRBbg.js → index-DpZqbc4w.js} +1 -1
- package/src/assets/web-panel/assets/{index-CGFL59q4.js → index-DsQ38fVY.js} +1 -1
- package/src/assets/web-panel/assets/{index-DsoV9rzn.js → index-Dv8-g1pY.js} +1 -1
- package/src/assets/web-panel/assets/{index-yMf7zmWv.js → index-EKNODw4P.js} +1 -1
- package/src/assets/web-panel/assets/{index-CHv_63Cp.js → index-FPXLIXoy.js} +1 -1
- package/src/assets/web-panel/assets/{index-CCLsbul3.js → index-IlzfIRNh.js} +1 -1
- package/src/assets/web-panel/assets/{index-cFkMIx1x.js → index-OLKhib9T.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bftq5rJR.js → index-PEe9OWEQ.js} +1 -1
- package/src/assets/web-panel/assets/index-QBXRSyoZ.js +1 -0
- package/src/assets/web-panel/assets/{index-DJVrzXtk.js → index-T28naovw.js} +1 -1
- package/src/assets/web-panel/assets/{index-By-pper5.js → index-ZMbXl5lo.js} +1 -1
- package/src/assets/web-panel/assets/{index-DZ0oKtBg.js → index-urPvyUVk.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_ialOHx.js → index-wyKpTsGM.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-D0Bx6pgr.js → initDefaultProps-CDWa1rnn.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BnLuJqJ5.js → motion-CX2Cnsd5.js} +1 -1
- package/src/assets/web-panel/assets/{move-Bxpq9xgR.js → move-Bfe1NcEF.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BdmrNhOs.js → mtc-parser-DbdqleHE.js} +1 -1
- package/src/assets/web-panel/assets/{omit-tjJD34BZ.js → omit-CE2K7NVv.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CMFzLt7b.js → pickAttrs-y_bZgxWG.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BZf6O3cd.js → placementArrow-BOHR4zwr.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DFDLazsV.js → responsiveObserve-B8Jwq05-.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CMbTvp4Y.js → slide-BD7RJ3Kn.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-FOan8MI7.js → statusUtils-BuxDJeDx.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DTABspd4.js → styleChecker-DgYQ2Q0o.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CNHXWBpY.js → useFlexGapSupport-DAHF0Fwi.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-5K-c_RoL.js → useFs-D4kDyLFp.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-Di0hL4G-.js → usePersonalDataHub-BHtSxW4A.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DTyDv4ja.js → vnode-CHKtdqW0.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-ontRt8ft.js → zoom-CIZAMma9.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +1 -1
- package/src/commands/agent.js +64 -40
- package/src/commands/ask.js +6 -4
- package/src/commands/team.js +28 -19
- package/src/data/changelog.json +26 -0
- package/src/harness/prompt-compressor.js +2 -0
- package/src/lib/advisor-runtime.js +4 -2
- package/src/lib/agent-ipc-bus.js +2 -0
- package/src/lib/background-agent-keeper-client.js +3 -0
- package/src/lib/browser-automation.js +4 -0
- package/src/lib/cc-android-bridge.js +4 -0
- package/src/lib/chat-core.js +11 -9
- package/src/lib/cloud/cloud-client.js +10 -1
- package/src/lib/config-schema.js +18 -5
- package/src/lib/context-memory-kernel/memory-query-index.js +5 -2
- package/src/lib/context-memory-kernel/runtime.js +4 -0
- package/src/lib/context-memory-kernel/segmented-memory-port.js +28 -3
- package/src/lib/context-source-ledger.js +52 -9
- package/src/lib/cowork-adapter.js +4 -3
- package/src/lib/decision-layer/providers.js +16 -11
- package/src/lib/evolution/governed-hub-llm.js +31 -16
- package/src/lib/evolution/governed-hub-resolver.js +4 -0
- package/src/lib/evolution/governed-skill-synthesis-process-grader.js +4 -0
- package/src/lib/evomap-client.js +14 -2
- package/src/lib/formal-budget-authority.js +191 -59
- package/src/lib/formal-budget-contract.js +7 -13
- package/src/lib/formal-budget-errors.js +31 -0
- package/src/lib/formal-budget-lineage-registry.js +612 -0
- package/src/lib/formal-budget-provider-scope.js +143 -0
- package/src/lib/formal-budget-transport.js +235 -100
- package/src/lib/gateway-client-resilience.js +5 -0
- package/src/lib/goal-condition-engine.js +25 -2
- package/src/lib/hub-llm-client.js +25 -16
- package/src/lib/llm-config-defaults.js +10 -4
- package/src/lib/llm-connection-probe.js +17 -10
- package/src/lib/llm-pricing.js +16 -4
- package/src/lib/llm-providers.js +4 -1
- package/src/lib/model-capabilities.js +26 -0
- package/src/lib/model-catalog-review.js +18 -1
- package/src/lib/model-context-catalog.js +41 -1
- package/src/lib/model-failure-policy.js +2 -0
- package/src/lib/openai-responses.js +8 -0
- package/src/lib/plugin-runtime/marketplace-network.js +9 -5
- package/src/lib/process-execution-broker/credential-agent.js +7 -2
- package/src/lib/process-execution-broker/credential-transport.js +4 -0
- package/src/lib/process-execution-broker/index.js +8 -0
- package/src/lib/provider-stream.js +28 -13
- package/src/lib/sandbox-egress-worker.js +3 -0
- package/src/lib/skill-retrieval-router.js +1 -0
- package/src/lib/stream-retry.js +2 -0
- package/src/lib/sub-agent-context.js +6 -3
- package/src/lib/usage-pricing-context.js +33 -2
- package/src/lib/web-fetch.js +2 -0
- package/src/lib/web-search.js +5 -0
- package/src/repl/agent-repl.js +247 -153
- package/src/runtime/agent-core.js +228 -96
- package/src/runtime/coding-agent-contract-shared.cjs +14 -1
- package/src/runtime/headless-runner.js +1 -0
- package/src/runtime/headless-stream.js +1 -0
- package/src/runtime/mcp-tool-search.js +0 -0
- package/src/runtime/provider-stream-state.js +14 -1
- package/src/assets/web-panel/assets/ChatBubbleRenderer-D3KsyCUV.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-C1yByobo.js +0 -1
- package/src/assets/web-panel/assets/Tasks-DvSrtz0P.js +0 -1
- package/src/assets/web-panel/assets/devWarning-Pa13TVrO.js +0 -1
- package/src/assets/web-panel/assets/index-BhQg-v6V.js +0 -1
- package/src/assets/web-panel/assets/index-DUD5o-vW.js +0 -1
package/src/lib/agent-ipc-bus.js
CHANGED
|
@@ -13,6 +13,7 @@ import { EventEmitter } from "node:events";
|
|
|
13
13
|
import crypto from "node:crypto";
|
|
14
14
|
import { EventRuntimeProducer } from "./event-runtime-producer.js";
|
|
15
15
|
import { EventRuntimeStore } from "./event-runtime-store.js";
|
|
16
|
+
import { requireUnscopedDescendantControl } from "./formal-budget-provider-scope.js";
|
|
16
17
|
import executionBroker from "./process-execution-broker/index.js";
|
|
17
18
|
import {
|
|
18
19
|
AGENT_IPC_DEFAULT_LIMITS,
|
|
@@ -284,6 +285,7 @@ class AgentIPCBus extends EventEmitter {
|
|
|
284
285
|
* @returns {Promise<{process: ChildProcess, agentId: string}>}
|
|
285
286
|
*/
|
|
286
287
|
async spawnAgentProcess(command, args = [], options = {}) {
|
|
288
|
+
requireUnscopedDescendantControl();
|
|
287
289
|
const agentId = options.agentId || crypto.randomUUID();
|
|
288
290
|
if (
|
|
289
291
|
this._childTransports.has(agentId) ||
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import net from "node:net";
|
|
2
2
|
import { randomBytes } from "node:crypto";
|
|
3
3
|
import { createNdjsonReader } from "./background-session-transport.js";
|
|
4
|
+
import { requireUnscopedDescendantControl } from "./formal-budget-provider-scope.js";
|
|
4
5
|
import {
|
|
5
6
|
BACKGROUND_AGENT_KEEPER_ARM,
|
|
6
7
|
BACKGROUND_AGENT_KEEPER_ARMED,
|
|
@@ -67,6 +68,7 @@ async function connectWithDeadline(pipePath, timeoutMs) {
|
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
export async function connectBackgroundAgentKeeper(options = {}) {
|
|
71
|
+
requireUnscopedDescendantControl();
|
|
70
72
|
const hello = normalizeBackgroundAgentKeeperHello(options);
|
|
71
73
|
const connectTimeoutMs = Math.max(
|
|
72
74
|
1,
|
|
@@ -234,6 +236,7 @@ export async function connectBackgroundAgentKeeper(options = {}) {
|
|
|
234
236
|
|
|
235
237
|
return Object.freeze({
|
|
236
238
|
async arm(turn) {
|
|
239
|
+
requireUnscopedDescendantControl();
|
|
237
240
|
const normalized = normalizeBackgroundAgentKeeperTurn(turn);
|
|
238
241
|
if (activeTurn) {
|
|
239
242
|
throw keeperError(
|
|
@@ -3,10 +3,13 @@
|
|
|
3
3
|
* Uses built-in fetch for basic operations, optional playwright for screenshots.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { requireUnscopedExternalToolAccess } from "./formal-budget-provider-scope.js";
|
|
7
|
+
|
|
6
8
|
/**
|
|
7
9
|
* Fetch a URL and return the raw HTML.
|
|
8
10
|
*/
|
|
9
11
|
export async function fetchPage(url, options = {}) {
|
|
12
|
+
requireUnscopedExternalToolAccess();
|
|
10
13
|
const timeout = options.timeout || 30000;
|
|
11
14
|
const controller = new AbortController();
|
|
12
15
|
const timer = setTimeout(() => controller.abort(), timeout);
|
|
@@ -179,6 +182,7 @@ export function extractLinks(html, baseUrl) {
|
|
|
179
182
|
* Returns null if playwright is not installed.
|
|
180
183
|
*/
|
|
181
184
|
export async function takeScreenshot(url, outputPath, options = {}) {
|
|
185
|
+
requireUnscopedExternalToolAccess();
|
|
182
186
|
try {
|
|
183
187
|
const { chromium } = await import("playwright");
|
|
184
188
|
const browser = await chromium.launch({ headless: true });
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
|
|
33
33
|
import { readFileSync, existsSync } from "node:fs";
|
|
34
34
|
import { join, dirname } from "node:path";
|
|
35
|
+
import { requireUnscopedExternalToolAccess } from "./formal-budget-provider-scope.js";
|
|
35
36
|
|
|
36
37
|
const ANDROID_PREFIX = "/data/data/com.chainlesschain.android/";
|
|
37
38
|
|
|
@@ -72,6 +73,7 @@ function resolveBridgeConfigDir() {
|
|
|
72
73
|
* (server not started yet, or running off-device without override).
|
|
73
74
|
*/
|
|
74
75
|
export function loadBridgeConfig() {
|
|
76
|
+
requireUnscopedExternalToolAccess();
|
|
75
77
|
const dir = resolveBridgeConfigDir();
|
|
76
78
|
if (!dir) return null;
|
|
77
79
|
try {
|
|
@@ -109,6 +111,7 @@ export class AndroidBridgeUnavailableError extends Error {
|
|
|
109
111
|
* - Method name unknown (server returns {"error": "UNKNOWN_METHOD"})
|
|
110
112
|
*/
|
|
111
113
|
export async function invoke(method, params = {}) {
|
|
114
|
+
requireUnscopedExternalToolAccess();
|
|
112
115
|
if (typeof method !== "string" || method.length === 0) {
|
|
113
116
|
throw new TypeError(
|
|
114
117
|
"cc-android-bridge.invoke: method must be non-empty string",
|
|
@@ -170,6 +173,7 @@ export async function invoke(method, params = {}) {
|
|
|
170
173
|
* Returns `{ available: boolean, reason?: string, port?: number }`.
|
|
171
174
|
*/
|
|
172
175
|
export function caps() {
|
|
176
|
+
requireUnscopedExternalToolAccess();
|
|
173
177
|
if (process.env.CC_ANDROID_BRIDGE_OVERRIDE === "1") {
|
|
174
178
|
return { available: true, reason: "test-override" };
|
|
175
179
|
}
|
package/src/lib/chat-core.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { providerFetch } from "./formal-budget-provider-scope.js";
|
|
1
2
|
/**
|
|
2
3
|
* Chat Core — transport-independent streaming chat logic
|
|
3
4
|
*
|
|
@@ -21,6 +22,7 @@ import {
|
|
|
21
22
|
waitForStreamRetry,
|
|
22
23
|
} from "./stream-retry.js";
|
|
23
24
|
import { throwIfAborted } from "./abort-utils.js";
|
|
25
|
+
import { isFormalBudgetError } from "./formal-budget-errors.js";
|
|
24
26
|
|
|
25
27
|
// A streaming chat call must not hang forever if the API accepts the connection
|
|
26
28
|
// but then goes silent (TCP up, no bytes). Abort the request if no data arrives
|
|
@@ -132,7 +134,7 @@ export async function streamOllama(
|
|
|
132
134
|
guard.bump();
|
|
133
135
|
let response;
|
|
134
136
|
try {
|
|
135
|
-
response = await
|
|
137
|
+
response = await providerFetch(`${baseUrl}/api/chat`, {
|
|
136
138
|
method: "POST",
|
|
137
139
|
headers: { "Content-Type": "application/json" },
|
|
138
140
|
body: JSON.stringify({
|
|
@@ -146,7 +148,7 @@ export async function streamOllama(
|
|
|
146
148
|
});
|
|
147
149
|
} catch (e) {
|
|
148
150
|
guard.stop();
|
|
149
|
-
throw guard.stalled()
|
|
151
|
+
throw guard.stalled() && !isFormalBudgetError(e)
|
|
150
152
|
? new Error(
|
|
151
153
|
`Ollama request stalled (no response in ${STREAM_STALL_MS / 1000}s)`,
|
|
152
154
|
)
|
|
@@ -213,7 +215,7 @@ export async function streamOllama(
|
|
|
213
215
|
}
|
|
214
216
|
} catch (e) {
|
|
215
217
|
throw attachStreamRetryMetadata(
|
|
216
|
-
guard.stalled()
|
|
218
|
+
guard.stalled() && !isFormalBudgetError(e)
|
|
217
219
|
? new Error(
|
|
218
220
|
`Ollama stream stalled (no data in ${STREAM_STALL_MS / 1000}s)`,
|
|
219
221
|
)
|
|
@@ -247,7 +249,7 @@ export async function streamOpenAI(
|
|
|
247
249
|
guard.bump();
|
|
248
250
|
let response;
|
|
249
251
|
try {
|
|
250
|
-
response = await
|
|
252
|
+
response = await providerFetch(`${baseUrl}/chat/completions`, {
|
|
251
253
|
method: "POST",
|
|
252
254
|
headers: {
|
|
253
255
|
"Content-Type": "application/json",
|
|
@@ -267,7 +269,7 @@ export async function streamOpenAI(
|
|
|
267
269
|
});
|
|
268
270
|
} catch (e) {
|
|
269
271
|
guard.stop();
|
|
270
|
-
throw guard.stalled()
|
|
272
|
+
throw guard.stalled() && !isFormalBudgetError(e)
|
|
271
273
|
? new Error(
|
|
272
274
|
`API request stalled (no response in ${STREAM_STALL_MS / 1000}s)`,
|
|
273
275
|
)
|
|
@@ -344,7 +346,7 @@ export async function streamOpenAI(
|
|
|
344
346
|
}
|
|
345
347
|
} catch (e) {
|
|
346
348
|
throw attachStreamRetryMetadata(
|
|
347
|
-
guard.stalled()
|
|
349
|
+
guard.stalled() && !isFormalBudgetError(e)
|
|
348
350
|
? new Error(
|
|
349
351
|
`API stream stalled (no data in ${STREAM_STALL_MS / 1000}s)`,
|
|
350
352
|
)
|
|
@@ -392,7 +394,7 @@ export async function streamAnthropic(
|
|
|
392
394
|
guard.bump();
|
|
393
395
|
let response;
|
|
394
396
|
try {
|
|
395
|
-
response = await
|
|
397
|
+
response = await providerFetch(`${baseUrl}/messages`, {
|
|
396
398
|
method: "POST",
|
|
397
399
|
headers: {
|
|
398
400
|
"Content-Type": "application/json",
|
|
@@ -412,7 +414,7 @@ export async function streamAnthropic(
|
|
|
412
414
|
});
|
|
413
415
|
} catch (e) {
|
|
414
416
|
guard.stop();
|
|
415
|
-
throw guard.stalled()
|
|
417
|
+
throw guard.stalled() && !isFormalBudgetError(e)
|
|
416
418
|
? new Error(
|
|
417
419
|
`Anthropic request stalled (no response in ${STREAM_STALL_MS / 1000}s)`,
|
|
418
420
|
)
|
|
@@ -486,7 +488,7 @@ export async function streamAnthropic(
|
|
|
486
488
|
}
|
|
487
489
|
} catch (e) {
|
|
488
490
|
throw attachStreamRetryMetadata(
|
|
489
|
-
guard.stalled()
|
|
491
|
+
guard.stalled() && !isFormalBudgetError(e)
|
|
490
492
|
? new Error(
|
|
491
493
|
`Anthropic stream stalled (no data in ${STREAM_STALL_MS / 1000}s)`,
|
|
492
494
|
)
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
import { join } from "node:path";
|
|
29
29
|
import { getHomeDir } from "../paths.js";
|
|
30
30
|
import { ResilientGatewayClient } from "../gateway-client-resilience.js";
|
|
31
|
+
import { requireUnscopedDescendantControl } from "../formal-budget-provider-scope.js";
|
|
31
32
|
|
|
32
33
|
export const _deps = { fetch: (...a) => globalThis.fetch(...a) };
|
|
33
34
|
|
|
@@ -78,6 +79,7 @@ export class CloudClient {
|
|
|
78
79
|
* @param {object} opts { baseUrl, token, deps? }
|
|
79
80
|
*/
|
|
80
81
|
constructor(opts = {}) {
|
|
82
|
+
requireUnscopedDescendantControl();
|
|
81
83
|
this.baseUrl = String(opts.baseUrl || "").replace(/\/+$/, "");
|
|
82
84
|
if (!this.baseUrl) {
|
|
83
85
|
throw new Error(
|
|
@@ -109,6 +111,7 @@ export class CloudClient {
|
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
async _json(method, path, body) {
|
|
114
|
+
requireUnscopedDescendantControl();
|
|
112
115
|
const res = await this.deps.fetch(`${this.baseUrl}${path}`, {
|
|
113
116
|
method,
|
|
114
117
|
headers: this._headers(),
|
|
@@ -121,7 +124,9 @@ export class CloudClient {
|
|
|
121
124
|
}
|
|
122
125
|
|
|
123
126
|
/** Submit a job. `bundle` is a base64 git bundle of the branch. */
|
|
124
|
-
async submit(
|
|
127
|
+
async submit(payload) {
|
|
128
|
+
requireUnscopedDescendantControl();
|
|
129
|
+
const { task, bundle, branch, baseSha } = payload;
|
|
125
130
|
const data = await this._json("POST", "/v1/jobs", {
|
|
126
131
|
task,
|
|
127
132
|
bundle,
|
|
@@ -133,10 +138,12 @@ export class CloudClient {
|
|
|
133
138
|
}
|
|
134
139
|
|
|
135
140
|
async status(jobId) {
|
|
141
|
+
requireUnscopedDescendantControl();
|
|
136
142
|
return this._json("GET", `/v1/jobs/${encodeURIComponent(jobId)}`);
|
|
137
143
|
}
|
|
138
144
|
|
|
139
145
|
async result(jobId) {
|
|
146
|
+
requireUnscopedDescendantControl();
|
|
140
147
|
return this._json("GET", `/v1/jobs/${encodeURIComponent(jobId)}/result`);
|
|
141
148
|
}
|
|
142
149
|
|
|
@@ -146,6 +153,7 @@ export class CloudClient {
|
|
|
146
153
|
* runners remain compatible with status()/result().
|
|
147
154
|
*/
|
|
148
155
|
async events(jobId, options = {}) {
|
|
156
|
+
requireUnscopedDescendantControl();
|
|
149
157
|
if (!/^[\w.-]+$/.test(String(jobId || ""))) {
|
|
150
158
|
throw new Error(`invalid job id: ${jobId}`);
|
|
151
159
|
}
|
|
@@ -175,6 +183,7 @@ export const TERMINAL_CLOUD_STATUS = new Set(["done", "failed"]);
|
|
|
175
183
|
* `sleep`/`now` injected for tests.
|
|
176
184
|
*/
|
|
177
185
|
export async function pollUntilDone(client, jobId, opts = {}) {
|
|
186
|
+
requireUnscopedDescendantControl();
|
|
178
187
|
const intervalMs = opts.intervalMs ?? 3000;
|
|
179
188
|
const timeoutMs = opts.timeoutMs ?? 30 * 60_000;
|
|
180
189
|
const sleep = opts.sleep || ((ms) => new Promise((r) => setTimeout(r, ms)));
|
package/src/lib/config-schema.js
CHANGED
|
@@ -69,6 +69,19 @@ const DESCRIPTORS = [
|
|
|
69
69
|
default: DEFAULT_CONFIG.llm.model,
|
|
70
70
|
description: "Default model id",
|
|
71
71
|
}),
|
|
72
|
+
descriptor("llm.serviceTier", "string", {
|
|
73
|
+
enum: [
|
|
74
|
+
"standard",
|
|
75
|
+
"default",
|
|
76
|
+
"auto",
|
|
77
|
+
"fast",
|
|
78
|
+
"priority",
|
|
79
|
+
"flex",
|
|
80
|
+
"ultrafast",
|
|
81
|
+
],
|
|
82
|
+
description:
|
|
83
|
+
"Requested live service tier; model and endpoint support are checked before dispatch",
|
|
84
|
+
}),
|
|
72
85
|
descriptor("llm.visionModel", ["string", "null"], {
|
|
73
86
|
description: "Model used for image turns",
|
|
74
87
|
}),
|
|
@@ -502,11 +515,11 @@ function valueIssue(key, code, message) {
|
|
|
502
515
|
function isPersistedSecretRef(value) {
|
|
503
516
|
return Boolean(
|
|
504
517
|
value &&
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
518
|
+
typeof value === "object" &&
|
|
519
|
+
!Array.isArray(value) &&
|
|
520
|
+
Object.keys(value).length === 1 &&
|
|
521
|
+
typeof value.__cc_secret_ref === "string" &&
|
|
522
|
+
value.__cc_secret_ref.length > 0,
|
|
510
523
|
);
|
|
511
524
|
}
|
|
512
525
|
|
|
@@ -2,6 +2,9 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
|
|
3
3
|
export const MEMORY_QUERY_INDEX_SCHEMA = "chainlesschain.memory-query-index/v1";
|
|
4
4
|
const CURSOR_SCHEMA = "chainlesschain.memory-list-cursor/v1";
|
|
5
|
+
// Preserve the existing English collation while avoiding constructing locale
|
|
6
|
+
// options for every comparison during shard sorts, cursor search and merging.
|
|
7
|
+
const memoryRowCollator = new Intl.Collator("en");
|
|
5
8
|
|
|
6
9
|
export function queryDigest(bytes) {
|
|
7
10
|
return `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
|
|
@@ -10,8 +13,8 @@ export function queryDigest(bytes) {
|
|
|
10
13
|
export function compareMemoryRows(left, right) {
|
|
11
14
|
return (
|
|
12
15
|
right.importance - left.importance ||
|
|
13
|
-
right.updatedAt
|
|
14
|
-
left.memoryId
|
|
16
|
+
memoryRowCollator.compare(right.updatedAt, left.updatedAt) ||
|
|
17
|
+
memoryRowCollator.compare(left.memoryId, right.memoryId)
|
|
15
18
|
);
|
|
16
19
|
}
|
|
17
20
|
|
|
@@ -22,6 +22,10 @@ export function createCliContextMemoryRuntime(options = {}) {
|
|
|
22
22
|
const memoryPort =
|
|
23
23
|
options.memoryPort ||
|
|
24
24
|
new SegmentedMemoryPort({
|
|
25
|
+
queryIndexCacheMode:
|
|
26
|
+
options.memoryQueryIndexCacheMode ||
|
|
27
|
+
(options.env || process.env).CC_CONTEXT_MEMORY_QUERY_CACHE ||
|
|
28
|
+
"validate-disk",
|
|
25
29
|
readOnly: !decision.canonical,
|
|
26
30
|
...(options.memoryFilePath ? { filePath: options.memoryFilePath } : {}),
|
|
27
31
|
});
|
|
@@ -170,6 +170,7 @@ export class SegmentedMemoryPort extends DurableJsonMemoryPort {
|
|
|
170
170
|
maxTotalBytes = DEFAULT_MAX_TOTAL_BYTES,
|
|
171
171
|
maxEvents = DEFAULT_SEGMENTED_MAX_EVENTS,
|
|
172
172
|
readOnly = false,
|
|
173
|
+
queryIndexCacheMode = "validate-disk",
|
|
173
174
|
...options
|
|
174
175
|
} = {}) {
|
|
175
176
|
super({ ...options, maxEvents });
|
|
@@ -177,6 +178,9 @@ export class SegmentedMemoryPort extends DurableJsonMemoryPort {
|
|
|
177
178
|
throw new TypeError("maxTotalBytes must be a positive safe integer");
|
|
178
179
|
this.maxTotalBytes = maxTotalBytes;
|
|
179
180
|
this.readOnly = Boolean(readOnly);
|
|
181
|
+
if (!["validate-disk", "verified-memory"].includes(queryIndexCacheMode))
|
|
182
|
+
throw new TypeError("Unknown query index cache mode");
|
|
183
|
+
this.queryIndexCacheMode = queryIndexCacheMode;
|
|
180
184
|
this.filePath = resolve(this.filePath);
|
|
181
185
|
this.shardDirectory = `${this.filePath}.shards`;
|
|
182
186
|
this._queryIndexes = new Map();
|
|
@@ -656,6 +660,27 @@ export class SegmentedMemoryPort extends DurableJsonMemoryPort {
|
|
|
656
660
|
|
|
657
661
|
_readQueryIndex(manifest, bucket) {
|
|
658
662
|
const descriptor = manifest.shards[bucket];
|
|
663
|
+
const binding = JSON.stringify([
|
|
664
|
+
manifest.digest,
|
|
665
|
+
manifest.storeRevision,
|
|
666
|
+
descriptor.digest,
|
|
667
|
+
descriptor.queryDigest,
|
|
668
|
+
descriptor.queryBytes,
|
|
669
|
+
descriptor.recordCount,
|
|
670
|
+
]);
|
|
671
|
+
const cached = this._queryIndexes.get(bucket);
|
|
672
|
+
// This is an already verified, host-owned decoded snapshot, never a trust
|
|
673
|
+
// decision based on filesystem timestamps. Re-read and verify the current
|
|
674
|
+
// manifest on every operation; any generation/authority change invalidates
|
|
675
|
+
// this binding. Selected authority shards are still read and verified.
|
|
676
|
+
// Disk repair remains eager in validate-disk mode; verified-memory repairs
|
|
677
|
+
// a derived index on the next cache miss, rather than every warm query.
|
|
678
|
+
if (
|
|
679
|
+
this.queryIndexCacheMode === "verified-memory" &&
|
|
680
|
+
descriptor.queryDigest &&
|
|
681
|
+
cached?.binding === binding
|
|
682
|
+
)
|
|
683
|
+
return cached.index;
|
|
659
684
|
let bytes;
|
|
660
685
|
if (descriptor.queryDigest) {
|
|
661
686
|
const file = this._queryIndexPath(bucket, descriptor);
|
|
@@ -705,8 +730,8 @@ export class SegmentedMemoryPort extends DurableJsonMemoryPort {
|
|
|
705
730
|
bytes = encodeQueryIndex(this._readShard(manifest, bucket));
|
|
706
731
|
}
|
|
707
732
|
const digest = descriptor.queryDigest || queryDigest(bytes);
|
|
708
|
-
|
|
709
|
-
|
|
733
|
+
if (cached?.digest === digest && cached.binding === binding)
|
|
734
|
+
return cached.index;
|
|
710
735
|
let index;
|
|
711
736
|
try {
|
|
712
737
|
index = compileQueryIndex(bytes, descriptor);
|
|
@@ -717,7 +742,7 @@ export class SegmentedMemoryPort extends DurableJsonMemoryPort {
|
|
|
717
742
|
cause,
|
|
718
743
|
);
|
|
719
744
|
}
|
|
720
|
-
this._queryIndexes.set(bucket, { digest, index });
|
|
745
|
+
this._queryIndexes.set(bucket, { digest, binding, index });
|
|
721
746
|
return index;
|
|
722
747
|
}
|
|
723
748
|
|
|
@@ -40,7 +40,28 @@ class ContextSourceLedger {
|
|
|
40
40
|
* @returns {string} entryId
|
|
41
41
|
*/
|
|
42
42
|
record(entry) {
|
|
43
|
+
if (
|
|
44
|
+
entry.tokenCount != null &&
|
|
45
|
+
(!Number.isSafeInteger(entry.tokenCount) || entry.tokenCount < 0)
|
|
46
|
+
) {
|
|
47
|
+
throw new TypeError(
|
|
48
|
+
"Context tokenCount must be a non-negative safe integer",
|
|
49
|
+
);
|
|
50
|
+
}
|
|
43
51
|
const entryId = entry.entryId || crypto.randomUUID();
|
|
52
|
+
const previous = this._entries.get(entryId);
|
|
53
|
+
if (previous) {
|
|
54
|
+
for (const [index, key] of [
|
|
55
|
+
[this._byTurn, previous.turnId],
|
|
56
|
+
[this._bySession, previous.sessionId],
|
|
57
|
+
]) {
|
|
58
|
+
const remaining = (index.get(key) || []).filter(
|
|
59
|
+
(item) => item.entryId !== entryId,
|
|
60
|
+
);
|
|
61
|
+
if (remaining.length) index.set(key, remaining);
|
|
62
|
+
else index.delete(key);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
44
65
|
const full = {
|
|
45
66
|
entryId,
|
|
46
67
|
traceId: entry.traceId || null,
|
|
@@ -53,6 +74,7 @@ class ContextSourceLedger {
|
|
|
53
74
|
summary: entry.summary,
|
|
54
75
|
metadata: entry.metadata,
|
|
55
76
|
tokenCount: entry.tokenCount || 0,
|
|
77
|
+
tokenBasis: entry.tokenBasis === "observed" ? "observed" : "estimated",
|
|
56
78
|
insertedAt: new Date(),
|
|
57
79
|
tags: entry.tags || [],
|
|
58
80
|
};
|
|
@@ -64,7 +86,8 @@ class ContextSourceLedger {
|
|
|
64
86
|
this._byTurn.get(full.turnId).push(full);
|
|
65
87
|
|
|
66
88
|
// Index by session
|
|
67
|
-
if (!this._bySession.has(full.sessionId))
|
|
89
|
+
if (!this._bySession.has(full.sessionId))
|
|
90
|
+
this._bySession.set(full.sessionId, []);
|
|
68
91
|
this._bySession.get(full.sessionId).push(full);
|
|
69
92
|
|
|
70
93
|
return entryId;
|
|
@@ -82,6 +105,7 @@ class ContextSourceLedger {
|
|
|
82
105
|
summary: entry.summary || entry.content,
|
|
83
106
|
metadata: entry.metadata,
|
|
84
107
|
tokenCount: entry.tokenCount ?? entry.tokens ?? 0,
|
|
108
|
+
tokenBasis: entry.tokenBasis,
|
|
85
109
|
traceId: entry.traceId,
|
|
86
110
|
});
|
|
87
111
|
}
|
|
@@ -95,14 +119,31 @@ class ContextSourceLedger {
|
|
|
95
119
|
}
|
|
96
120
|
|
|
97
121
|
/** Aggregate token usage by source type. */
|
|
98
|
-
getTokenBreakdown() {
|
|
99
|
-
const
|
|
122
|
+
getTokenBreakdown(options = {}) {
|
|
123
|
+
const sources = new Map();
|
|
100
124
|
let total = 0;
|
|
101
|
-
for (const entry of this.
|
|
125
|
+
for (const entry of this.getProvenance(options)) {
|
|
102
126
|
total += entry.tokenCount;
|
|
103
|
-
|
|
127
|
+
sources.set(
|
|
128
|
+
entry.sourceType,
|
|
129
|
+
(sources.get(entry.sourceType) || 0) + entry.tokenCount,
|
|
130
|
+
);
|
|
104
131
|
}
|
|
105
|
-
return { total, bySource };
|
|
132
|
+
return { total, bySource: Object.fromEntries(sources) };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Source attribution is separate from provider request usage and billing. */
|
|
136
|
+
getTokenReport(options = {}) {
|
|
137
|
+
const entries = this.getProvenance(options);
|
|
138
|
+
const byBasis = { estimated: 0, observed: 0 };
|
|
139
|
+
for (const entry of entries) byBasis[entry.tokenBasis] += entry.tokenCount;
|
|
140
|
+
return {
|
|
141
|
+
...this.getTokenBreakdown(options),
|
|
142
|
+
byBasis,
|
|
143
|
+
entries: entries.length,
|
|
144
|
+
currentRequestVerified: false,
|
|
145
|
+
billingVerified: false,
|
|
146
|
+
};
|
|
106
147
|
}
|
|
107
148
|
|
|
108
149
|
/** Clear the in-memory ledger (test/runtime lifecycle boundary). */
|
|
@@ -146,7 +187,8 @@ class ContextSourceLedger {
|
|
|
146
187
|
|
|
147
188
|
for (const e of entries) {
|
|
148
189
|
byType[e.sourceType] = (byType[e.sourceType] || 0) + 1;
|
|
149
|
-
byPermission[e.permissionMode] =
|
|
190
|
+
byPermission[e.permissionMode] =
|
|
191
|
+
(byPermission[e.permissionMode] || 0) + 1;
|
|
150
192
|
bySource[e.sourceId] = (bySource[e.sourceId] || 0) + 1;
|
|
151
193
|
totalTokens += e.tokenCount;
|
|
152
194
|
avgConfidence += e.confidence;
|
|
@@ -162,7 +204,7 @@ class ContextSourceLedger {
|
|
|
162
204
|
byType,
|
|
163
205
|
byPermission,
|
|
164
206
|
bySource,
|
|
165
|
-
entries: entries.map(e => ({
|
|
207
|
+
entries: entries.map((e) => ({
|
|
166
208
|
sourceType: e.sourceType,
|
|
167
209
|
sourceId: e.sourceId,
|
|
168
210
|
permissionMode: e.permissionMode,
|
|
@@ -184,8 +226,9 @@ class ContextSourceLedger {
|
|
|
184
226
|
this._entries.delete(e.entryId);
|
|
185
227
|
const turnEntries = this._byTurn.get(e.turnId);
|
|
186
228
|
if (turnEntries) {
|
|
187
|
-
const idx = turnEntries.findIndex(x => x.entryId === e.entryId);
|
|
229
|
+
const idx = turnEntries.findIndex((x) => x.entryId === e.entryId);
|
|
188
230
|
if (idx >= 0) turnEntries.splice(idx, 1);
|
|
231
|
+
if (!turnEntries.length) this._byTurn.delete(e.turnId);
|
|
189
232
|
}
|
|
190
233
|
}
|
|
191
234
|
this._bySession.delete(sessionId);
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* - Module initialization helper
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { providerFetch } from "./formal-budget-provider-scope.js";
|
|
10
11
|
import { LLMProviderRegistry, BUILT_IN_PROVIDERS } from "./llm-providers.js";
|
|
11
12
|
import { loadConfig } from "./config-manager.js";
|
|
12
13
|
import { applyConfigLlmDefaults } from "./llm-config-defaults.js";
|
|
@@ -174,7 +175,7 @@ export function createChatFn(options = {}) {
|
|
|
174
175
|
currentModel,
|
|
175
176
|
async ({ signal = opts.signal || resolved.signal } = {}) => {
|
|
176
177
|
const modelMessages = await prepareMessages();
|
|
177
|
-
const res = await
|
|
178
|
+
const res = await providerFetch(`${baseUrl}/api/chat`, {
|
|
178
179
|
method: "POST",
|
|
179
180
|
signal: requestSignal(signal),
|
|
180
181
|
headers: { "Content-Type": "application/json" },
|
|
@@ -214,7 +215,7 @@ export function createChatFn(options = {}) {
|
|
|
214
215
|
? { system: systemMsgs.map((m) => m.content).join("\n") }
|
|
215
216
|
: {}),
|
|
216
217
|
};
|
|
217
|
-
const res = await
|
|
218
|
+
const res = await providerFetch(`${baseUrl}/messages`, {
|
|
218
219
|
method: "POST",
|
|
219
220
|
signal: requestSignal(signal),
|
|
220
221
|
headers: {
|
|
@@ -245,7 +246,7 @@ export function createChatFn(options = {}) {
|
|
|
245
246
|
currentModel,
|
|
246
247
|
async ({ signal = opts.signal || resolved.signal } = {}) => {
|
|
247
248
|
const modelMessages = await prepareMessages();
|
|
248
|
-
const res = await
|
|
249
|
+
const res = await providerFetch(`${baseUrl}/chat/completions`, {
|
|
249
250
|
method: "POST",
|
|
250
251
|
signal: requestSignal(signal),
|
|
251
252
|
headers: {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { openDecisionProviderAuthority } from "./provider-authority.js";
|
|
2
|
+
import { providerFetch } from "../formal-budget-provider-scope.js";
|
|
2
3
|
|
|
3
4
|
const PROVIDERS = Object.freeze({
|
|
4
5
|
typesafe: {
|
|
@@ -195,18 +196,22 @@ export function createDecisionProvider({
|
|
|
195
196
|
if (Buffer.byteLength(body, "utf8") > MAX_DECISION_REQUEST_BYTES) {
|
|
196
197
|
throw bodyTooLarge("request", MAX_DECISION_REQUEST_BYTES);
|
|
197
198
|
}
|
|
198
|
-
const response = await
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
199
|
+
const response = await providerFetch(
|
|
200
|
+
endpoint,
|
|
201
|
+
{
|
|
202
|
+
method: "POST",
|
|
203
|
+
headers: {
|
|
204
|
+
...(secret === undefined
|
|
205
|
+
? {}
|
|
206
|
+
: { authorization: `Bearer ${secret}` }),
|
|
207
|
+
"content-type": "application/json",
|
|
208
|
+
},
|
|
209
|
+
body,
|
|
210
|
+
signal,
|
|
211
|
+
redirect: "error",
|
|
205
212
|
},
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
redirect: "error",
|
|
209
|
-
});
|
|
213
|
+
fetchImpl,
|
|
214
|
+
);
|
|
210
215
|
if (!response?.ok) {
|
|
211
216
|
throw providerError(response?.status ?? 0, options.provider);
|
|
212
217
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { types } from "node:util";
|
|
3
3
|
import { prepareGovernedModelTurn } from "./governed-model-turn.js";
|
|
4
|
+
import {
|
|
5
|
+
providerFetch,
|
|
6
|
+
requireUnscopedModelTransport,
|
|
7
|
+
} from "../formal-budget-provider-scope.js";
|
|
4
8
|
|
|
5
9
|
const { createAuthenticatedEvolutionModelClient } = createRequire(
|
|
6
10
|
import.meta.url,
|
|
@@ -97,21 +101,25 @@ function captureHubTransport(llm, sdk) {
|
|
|
97
101
|
const signal = options.signal
|
|
98
102
|
? AbortSignal.any([controller.signal, options.signal])
|
|
99
103
|
: controller.signal;
|
|
100
|
-
const response = await
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
104
|
+
const response = await providerFetch(
|
|
105
|
+
`${baseUrl}/api/chat`,
|
|
106
|
+
{
|
|
107
|
+
method: "POST",
|
|
108
|
+
headers: { "Content-Type": "application/json" },
|
|
109
|
+
redirect: "error",
|
|
110
|
+
signal,
|
|
111
|
+
body: JSON.stringify({
|
|
112
|
+
model,
|
|
113
|
+
messages,
|
|
114
|
+
stream: false,
|
|
115
|
+
options: {
|
|
116
|
+
temperature: options.temperature ?? 0.2,
|
|
117
|
+
...(options.numCtx ? { num_ctx: options.numCtx } : {}),
|
|
118
|
+
},
|
|
119
|
+
}),
|
|
120
|
+
},
|
|
121
|
+
fetchImpl,
|
|
122
|
+
);
|
|
115
123
|
if (!response.ok)
|
|
116
124
|
throw new Error(
|
|
117
125
|
`Hub Ollama request failed: HTTP ${response.status}`,
|
|
@@ -202,6 +210,7 @@ function captureHubTransport(llm, sdk) {
|
|
|
202
210
|
);
|
|
203
211
|
},
|
|
204
212
|
async chat(messages, options) {
|
|
213
|
+
requireUnscopedModelTransport();
|
|
205
214
|
const result = await chat(messages, options);
|
|
206
215
|
const text =
|
|
207
216
|
result?.content ??
|
|
@@ -233,7 +242,13 @@ function captureHubTransport(llm, sdk) {
|
|
|
233
242
|
},
|
|
234
243
|
};
|
|
235
244
|
}
|
|
236
|
-
return {
|
|
245
|
+
return {
|
|
246
|
+
assertIdentity() {},
|
|
247
|
+
chat(messages, options) {
|
|
248
|
+
requireUnscopedModelTransport();
|
|
249
|
+
return llm.chat(messages, options);
|
|
250
|
+
},
|
|
251
|
+
};
|
|
237
252
|
}
|
|
238
253
|
|
|
239
254
|
// A scoped wrapper preserves the Hub's independent local/cloud consent check.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { prepareGovernedModelTurn } from "./governed-model-turn.js";
|
|
2
|
+
import { requireUnscopedModelTransport } from "../formal-budget-provider-scope.js";
|
|
2
3
|
import {
|
|
3
4
|
captureGovernedHubSdkPorts,
|
|
4
5
|
createGovernedHubLlm,
|
|
@@ -48,6 +49,9 @@ function captureEmbeddingTransport(stage, sdk) {
|
|
|
48
49
|
);
|
|
49
50
|
},
|
|
50
51
|
async embed(profile) {
|
|
52
|
+
// Neither arbitrary embedding callbacks nor the native embeddings
|
|
53
|
+
// protocol have a verified Chat billing contract in this scope.
|
|
54
|
+
requireUnscopedModelTransport();
|
|
51
55
|
if (!defaultOllama) return await embed.call(stage, profile);
|
|
52
56
|
// The raw SDK ollamaEmbed remains closed. This private transport is only
|
|
53
57
|
// invoked below, after the scoped Run projected the profile.
|