chainlesschain 0.166.100 → 0.166.102
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 +3 -3
- 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-Cd4iUOPt.js → AIOps-CyHIMEd8.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton--ucr-zko.js → ActionButton-vuNxDpHm.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DbejYMWk.js → Analytics-D0quEM0q.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CLgKxeGw.js → AppLayout-xRSVpbCs.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-CTT5BIL5.js → Artifacts-ktfVAZBC.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DP-WBWe9.js → Audit-UJW6maH4.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-B6VqheJk.js → BackgroundAgents-BYrfdCoT.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-VWJK5zim.js → Backup-IBgsJ7BK.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-YGFO9RHd.js → BaseInput-BmP8_zxy.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CVfydnCd.js → Chat-urkw8_BF.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-BICpB-qU.js → ChatBubbleRenderer-Cw44zZbh.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-Bd5vKRMk.js → Checkbox-CYboo-__.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DHNgPHvg.js → Codegen-DaqR_Ay8.js} +1 -1
- package/src/assets/web-panel/assets/{Col-CA2BYQ8T.js → Col-04BSIj_z.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DnKJ-qpI.js → Community-DxFk7Trv.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-C9BZ8t4r.js → Compact-mjgWlMCB.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-ByyQ2FOl.js → Compliance-CC5ee7QV.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-rXTwXE_c.js → Cowork-BK4BhHZd.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-BuW-HODy.js → Cron-CP6jAxq0.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-OudNtbYW.js → Crosschain-DJPaViZS.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BQ6BxYNN.js → DID-BTLxkuOj.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-Cz5HG8tz.js → Dashboard-Djkiqh3d.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BzclHOVv.js → Dropdown-t_eUhqom.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CbJETFdy.js → EmailListRenderer-7w6USx_J.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-Dx_pJG3d.js → EvolutionSettings-mU5IHEk5.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-6JCS1MNg.js → FamilyGuardDashboard-BCh-VBBC.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BrPkMYaf.js → Federation-Be_VpjI2.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Bhc9pobs.js → FormItemContext-D_lzQ7PI.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BxOh07uQ.js → GenericCardRenderer-LYu3KapV.js} +1 -1
- package/src/assets/web-panel/assets/{Git-D_idoujr.js → Git-BBeF-PP4.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-ZGfIRE-x.js → Governance-CoF8Kzg7.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DpAmcwbw.js → Inference-C4DLMnXS.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-D1S1UTgP.js → KnowledgeGraph-B2mlNewk.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-2sc8V5XV.js → Logs-DMZ_44Ya.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-Ck7Iv_9e.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-0xlFUKbe.js → Marketplace-BqDzTew_.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-D25eJLGm.js → McpTools-BbwSbDN9.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-BLRGd9hM.js → Memory-DAaTWgrm.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-zpFINGzn.js → MobileBridge-BjbTGxoR.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-Cbyd-8kx.js → MobileProjects-DMODOBr-.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-DgXgUlHc.js → Mtc-DT9N2rCs.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-DzcL-dKH.js → MtcAudit-DagMfUVv.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-C3OrZ6VN.js → Multisig-C1BKP6nM.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Bqp_vWA7.js → NLProgramming-B5LFh72i.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Dyn45-Ht.js → Notes-Q77V3ltW.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-CLjafGZr.js → NotificationSettings-HxdpNIBs.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-Dc0DpvBH.js +1 -0
- package/src/assets/web-panel/assets/{Organization-5gr9hyLm.js → Organization-QL3NZ7uW.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BRdU02hT.js → Overflow-B_gqOKho.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DIi7fzh6.js → P2P-BBJubU8Z.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BCbS1KpA.js → PdhVaultBrowser-CFnGd-2E.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-BjeP9VtA.js → Permissions-BKkznIUM.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-y8PXOQUc.js → PersonalDataHub-DYK7ZAcd.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-B0fL5uxY.js → Pipeline-CoeKpjoN.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-C8jCDn8Z.js → Privacy-Diw4G-92.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-B_L6Dc6V.js → ProjectInit-CHBOFkma.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-Bb1CYbZh.js → ProjectSettings-BJIsgdOf.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-CUSV10Cn.js → Projects-GJjItXIk.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-mBSTDJ0E.js → Providers-o8QCimor.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CHxgalvt.js → QrScannerModal-z2W-zvhW.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DI9KIMEV.js → QuickAsk-_yubhsna.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-B5_zW1JH.js → Recommend-CucgJwih.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-BkH4bmM5.js → RemoteSession-EzfIIRg1.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-DJrAqwAq.js → Reputation-_shttE67.js} +1 -1
- package/src/assets/web-panel/assets/{Row-xZ3MAM34.js → Row-DQA_S8-9.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CCsrLLiu.js → RssFeed-BOqWawXT.js} +3 -3
- package/src/assets/web-panel/assets/{Search-CTCRKvaP.js → Search-Dx1v2xOq.js} +1 -1
- package/src/assets/web-panel/assets/{Security-D7joyfp2.js → Security-Bt4HHsT4.js} +4 -4
- package/src/assets/web-panel/assets/{Services-oqHPmTG4.js → Services-sruHiQ-r.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BR_32bTG.js → Skeleton-CiBxvmOJ.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BoRz9mln.js → Skills-De9qKODU.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-UAGUHZ9b.js → Sla-B_6yn8Wp.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DeP_rMgv.js → SpeechSettings-C2CafExS.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CSzzMmeA.js → SyncSettings-Dhh3Qmb0.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-CcqOLsLB.js → Tasks-Mvo5mTWm.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-cDbkGSDG.js → Templates-D7WVTQQy.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DmOy58cq.js → Tenant-7ur9Yfxd.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-CsRZH5vr.js → Terminal-BgzrOA6k.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BgJrk6HG.js → TimelineRenderer-Dco20pT1.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CCQglKDE.js → Tokens-hN6qBPag.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-t-Gt3oBY.js → Trigger-C4f_twAM.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DQgu2kI0.js → Trust-Wf1SMypp.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-Cod2WUGj.js → UkeySign-DUXSyg3N.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-SGN5zaVK.js → VideoEditing-BvqsJaL0.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CnLEL-LD.js → Wallet-CgAbcjKl.js} +3 -3
- package/src/assets/web-panel/assets/{WebAuthn-C2keUpD6.js → WebAuthn-DaLT0W3s.js} +2 -2
- package/src/assets/web-panel/assets/{WorkflowEditor-B1GvrwWJ.js → WorkflowEditor-CQqAXoaS.js} +1 -1
- package/src/assets/web-panel/assets/{chat-1E9_P_qY.js → chat-BhlohFTB.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DuU6Os4q.js → colors-D7HqXIL8.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-C5NfOAcM.js → compact-item-Bqk4FCLY.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-D4Fxz9qQ.js → createContext-CEmWrWf0.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-YPX_TU7w.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-C6C49iFk.js → hasIn-CDY0pFi2.js} +1 -1
- package/src/assets/web-panel/assets/{index-DP2DCKD-.js → index-1HBam9t1.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-bb-R99.js → index-6f6n0KFR.js} +1 -1
- package/src/assets/web-panel/assets/{index-BmvU4Tp_.js → index-B8L3_-sG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BsH8mFp4.js → index-BHGOdvOQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BVE2wCeb.js → index-BNrvBWDS.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJS6GTpv.js → index-BPmRkxeX.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7mh6xlu.js → index-BXRooi-O.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZKRZYTX.js → index-BiLu-ImR.js} +1 -1
- package/src/assets/web-panel/assets/{index-jFg3CPlQ.js → index-BuKGuH_y.js} +1 -1
- package/src/assets/web-panel/assets/{index-BULggEX6.js → index-BxXFRLTZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DPzunJER.js → index-BxYO6nde.js} +1 -1
- package/src/assets/web-panel/assets/{index-AO6iDCSL.js → index-C02yDu4f.js} +1 -1
- package/src/assets/web-panel/assets/{index-BU5mPkNX.js → index-C3opQg47.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSypQU1h.js → index-C9mvnSii.js} +1 -1
- package/src/assets/web-panel/assets/{index-DZgT7pH-.js → index-CVrwozwH.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpiOzt7U.js → index-CYcjOnDX.js} +1 -1
- package/src/assets/web-panel/assets/{index-BlHkc48f.js → index-Cf1ha8l0.js} +1 -1
- package/src/assets/web-panel/assets/{index-CXb8gEWh.js → index-Chxt0t-A.js} +1 -1
- package/src/assets/web-panel/assets/{index-HQXFl8fh.js → index-CkjgSHVz.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpaGe-dr.js → index-CkqBoCiu.js} +3 -3
- package/src/assets/web-panel/assets/{index-C2nO02uW.js → index-CqK0J4Sj.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bu6qMjf4.js → index-CrsM-oiD.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bk-paNL3.js → index-Cur88hoN.js} +1 -1
- package/src/assets/web-panel/assets/{index-CXn-e3ki.js → index-D0nfNmbq.js} +1 -1
- package/src/assets/web-panel/assets/index-D53szVZQ.js +1 -0
- package/src/assets/web-panel/assets/{index-CDVwN9Sv.js → index-DEzL7s7P.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_ON9La1.js → index-DGKRAO61.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQJoh5rw.js → index-DPBoWNwq.js} +1 -1
- package/src/assets/web-panel/assets/{index-cnDfwWU5.js → index-DRcDWMwP.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBVqlelF.js → index-DmKdCWq1.js} +1 -1
- package/src/assets/web-panel/assets/{index-BYg1dtne.js → index-DpI1LqJX.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5lzRoHp.js → index-DuMt3ewl.js} +1 -1
- package/src/assets/web-panel/assets/{index-gh11zJ9h.js → index-Dwob5XoD.js} +1 -1
- package/src/assets/web-panel/assets/index-Ub2nJbV2.js +1 -0
- package/src/assets/web-panel/assets/{index-D1TXgNPA.js → index-XErJQ1yF.js} +1 -1
- package/src/assets/web-panel/assets/{index-DFK6PTGJ.js → index-aBHlgMrq.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dh-vezHe.js → index-e9oCy7_4.js} +1 -1
- package/src/assets/web-panel/assets/{index-bW6vfpLH.js → index-lBAbMOzg.js} +1 -1
- package/src/assets/web-panel/assets/{index-lNmDaf3J.js → index-o_lc3eww.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-3DSfnIpD.js → initDefaultProps-CIeEUxIN.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DxGLmgA0.js → motion-IPIj1ZtP.js} +1 -1
- package/src/assets/web-panel/assets/{move-DrlLG6m5.js → move-BfSeXZ-f.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BITbrJSb.js → mtc-parser-DX03-Xp4.js} +1 -1
- package/src/assets/web-panel/assets/{omit-D7k5vIbk.js → omit-z9EannfX.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BJSvYFWo.js → pickAttrs-DXKmRkqZ.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-Bf4to1jA.js → placementArrow-k2HV7cIU.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BXzeyzTa.js → responsiveObserve-bX7CsyWy.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DLzNUNdj.js → slide-NskjQLbJ.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-wBBnrRm_.js → statusUtils-B3IoG-Er.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BnmJzXNr.js → styleChecker-DHv_UilX.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DrN8MrJb.js → useFlexGapSupport-DEqGB5Ng.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-dnkYGkjY.js → useFs-Bl9CbrqZ.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-k_xkv7-k.js → usePersonalDataHub-O-Ukv93M.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-B-v8PXpK.js → vnode-hGCHTaZt.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-Coue8wAK.js → zoom-BWhIVeKQ.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/eval.js +11 -8
- package/src/data/changelog.json +26 -0
- package/src/harness/provider-backed-compaction.js +13 -5
- package/src/lib/config-schema.js +18 -5
- package/src/lib/context-memory-kernel/live-compaction.js +142 -61
- 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/formal-budget-authority.js +533 -0
- package/src/lib/formal-budget-contract.js +609 -0
- package/src/lib/formal-budget-transport.js +345 -0
- package/src/lib/goal-condition-engine.js +25 -2
- package/src/lib/llm-config-defaults.js +10 -4
- package/src/lib/llm-pricing.js +16 -4
- 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/openai-responses.js +8 -0
- package/src/lib/skill-retrieval-router.js +1 -0
- package/src/lib/usage-pricing-context.js +33 -2
- package/src/repl/agent-repl.js +247 -153
- package/src/runtime/agent-core.js +371 -97
- package/src/runtime/coding-agent-contract-shared.cjs +14 -1
- package/src/runtime/headless-runner.js +1 -0
- package/src/runtime/headless-stream.js +137 -4
- package/src/runtime/mcp-tool-search.js +0 -0
- package/src/runtime/provider-stream-state.js +14 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-575jjYE6.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-Bx8wMauC.js +0 -1
- package/src/assets/web-panel/assets/devWarning-zDWbYMr7.js +0 -1
- package/src/assets/web-panel/assets/index-BPBsZZnT.js +0 -1
- package/src/assets/web-panel/assets/index-CtGQDg7m.js +0 -1
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import {
|
|
2
|
+
budgetError,
|
|
3
|
+
canonical,
|
|
4
|
+
requireBudget,
|
|
5
|
+
} from "./formal-budget-contract.js";
|
|
6
|
+
|
|
7
|
+
export const FORMAL_BUDGET_RUNTIME_READINESS = Object.freeze({
|
|
8
|
+
paidReady: false,
|
|
9
|
+
reason:
|
|
10
|
+
"Agent, Chat, compaction, advisor, probes, retries and child-process egress are not yet all routed through this authority",
|
|
11
|
+
});
|
|
12
|
+
export function requireFormalBudgetRuntime() {
|
|
13
|
+
throw budgetError(
|
|
14
|
+
"CC_BUDGET_RUNTIME_NOT_COVERED",
|
|
15
|
+
FORMAL_BUDGET_RUNTIME_READINESS.reason,
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// JSON.parse alone accepts duplicate keys (including escaped aliases) and
|
|
20
|
+
// overflows numeric literals to Infinity. Neither is safe accounting evidence.
|
|
21
|
+
export function parseBudgetJson(text) {
|
|
22
|
+
requireBudget(typeof text === "string", "JSON text required");
|
|
23
|
+
let at = 0;
|
|
24
|
+
const whitespace = () => {
|
|
25
|
+
while (at < text.length && /[\x20\t\r\n]/u.test(text[at])) at++;
|
|
26
|
+
};
|
|
27
|
+
function string() {
|
|
28
|
+
requireBudget(text[at] === '"', "JSON string expected");
|
|
29
|
+
const start = at++;
|
|
30
|
+
while (at < text.length) {
|
|
31
|
+
const char = text[at++];
|
|
32
|
+
if (char === '"') return JSON.parse(text.slice(start, at));
|
|
33
|
+
if (char === "\\") at++;
|
|
34
|
+
}
|
|
35
|
+
requireBudget(false, "Unterminated JSON string");
|
|
36
|
+
}
|
|
37
|
+
function value(depth) {
|
|
38
|
+
requireBudget(depth <= 64, "JSON nesting exceeds accounting parser bound");
|
|
39
|
+
whitespace();
|
|
40
|
+
if (text[at] === '"') {
|
|
41
|
+
string();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (text[at] === "{") {
|
|
45
|
+
at++;
|
|
46
|
+
whitespace();
|
|
47
|
+
const keys = new Set();
|
|
48
|
+
if (text[at] === "}") {
|
|
49
|
+
at++;
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
for (;;) {
|
|
53
|
+
whitespace();
|
|
54
|
+
const key = string();
|
|
55
|
+
requireBudget(
|
|
56
|
+
!keys.has(key),
|
|
57
|
+
"Duplicate JSON member in provider evidence",
|
|
58
|
+
);
|
|
59
|
+
keys.add(key);
|
|
60
|
+
whitespace();
|
|
61
|
+
requireBudget(text[at++] === ":", "JSON member separator expected");
|
|
62
|
+
value(depth + 1);
|
|
63
|
+
whitespace();
|
|
64
|
+
const separator = text[at++];
|
|
65
|
+
if (separator === "}") return;
|
|
66
|
+
requireBudget(separator === ",", "JSON object separator expected");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (text[at] === "[") {
|
|
70
|
+
at++;
|
|
71
|
+
whitespace();
|
|
72
|
+
if (text[at] === "]") {
|
|
73
|
+
at++;
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
for (;;) {
|
|
77
|
+
value(depth + 1);
|
|
78
|
+
whitespace();
|
|
79
|
+
const separator = text[at++];
|
|
80
|
+
if (separator === "]") return;
|
|
81
|
+
requireBudget(separator === ",", "JSON array separator expected");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
for (const literal of ["true", "false", "null"])
|
|
85
|
+
if (text.startsWith(literal, at)) {
|
|
86
|
+
at += literal.length;
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const number = text
|
|
90
|
+
.slice(at)
|
|
91
|
+
.match(/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/u)?.[0];
|
|
92
|
+
requireBudget(
|
|
93
|
+
number && Number.isFinite(Number(number)),
|
|
94
|
+
"Invalid or non-finite JSON number",
|
|
95
|
+
);
|
|
96
|
+
at += number.length;
|
|
97
|
+
}
|
|
98
|
+
value(0);
|
|
99
|
+
whitespace();
|
|
100
|
+
requireBudget(at === text.length, "Trailing JSON input");
|
|
101
|
+
return JSON.parse(text);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Allowlist only; the caller must still supply the existing OS sandbox. */
|
|
105
|
+
export function formalBudgetTaskEnvironment(environment = process.env) {
|
|
106
|
+
return Object.fromEntries(
|
|
107
|
+
[
|
|
108
|
+
"PATH",
|
|
109
|
+
"Path",
|
|
110
|
+
"SystemRoot",
|
|
111
|
+
"SYSTEMROOT",
|
|
112
|
+
"WINDIR",
|
|
113
|
+
"ComSpec",
|
|
114
|
+
"PATHEXT",
|
|
115
|
+
"TEMP",
|
|
116
|
+
"TMP",
|
|
117
|
+
"TMPDIR",
|
|
118
|
+
"LANG",
|
|
119
|
+
"LC_ALL",
|
|
120
|
+
"LC_CTYPE",
|
|
121
|
+
]
|
|
122
|
+
.filter((key) => typeof environment[key] === "string")
|
|
123
|
+
.map((key) => [key, environment[key]]),
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function boundedText(response, maximumBytes) {
|
|
128
|
+
requireBudget(response.body?.getReader, "Response body unavailable");
|
|
129
|
+
const reader = response.body.getReader(),
|
|
130
|
+
chunks = [];
|
|
131
|
+
let size = 0;
|
|
132
|
+
try {
|
|
133
|
+
for (;;) {
|
|
134
|
+
const { done, value } = await reader.read();
|
|
135
|
+
if (done) break;
|
|
136
|
+
size += value.byteLength;
|
|
137
|
+
requireBudget(
|
|
138
|
+
size <= maximumBytes,
|
|
139
|
+
"Provider response exceeded bounded parser",
|
|
140
|
+
);
|
|
141
|
+
chunks.push(Buffer.from(value));
|
|
142
|
+
}
|
|
143
|
+
} catch (error) {
|
|
144
|
+
try {
|
|
145
|
+
await reader.cancel();
|
|
146
|
+
} catch {
|
|
147
|
+
/* keep original unknown outcome */
|
|
148
|
+
}
|
|
149
|
+
throw error;
|
|
150
|
+
} finally {
|
|
151
|
+
reader.releaseLock();
|
|
152
|
+
}
|
|
153
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(
|
|
154
|
+
Buffer.concat(chunks),
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
function streamReceipt(text) {
|
|
158
|
+
let terminal = false,
|
|
159
|
+
receipt = null,
|
|
160
|
+
usage = null,
|
|
161
|
+
finishReason = null;
|
|
162
|
+
for (const frame of text.replaceAll("\r\n", "\n").split("\n\n")) {
|
|
163
|
+
if (!frame.trim()) continue;
|
|
164
|
+
const data = frame
|
|
165
|
+
.split("\n")
|
|
166
|
+
.filter((line) => line.startsWith("data:"))
|
|
167
|
+
.map((line) => line.slice(5).trimStart())
|
|
168
|
+
.join("\n");
|
|
169
|
+
if (!data) continue;
|
|
170
|
+
requireBudget(!terminal, "Unexpected stream data after terminal marker");
|
|
171
|
+
if (data === "[DONE]") {
|
|
172
|
+
requireBudget(
|
|
173
|
+
finishReason !== null,
|
|
174
|
+
"Stream ended without a completed choice",
|
|
175
|
+
);
|
|
176
|
+
terminal = true;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
const row = parseBudgetJson(data);
|
|
180
|
+
requireBudget(row && !Object.hasOwn(row, "error"), "Provider stream error");
|
|
181
|
+
const identity = {
|
|
182
|
+
id: row.id,
|
|
183
|
+
model: row.model,
|
|
184
|
+
service_tier: row.service_tier,
|
|
185
|
+
};
|
|
186
|
+
if (!receipt) receipt = identity;
|
|
187
|
+
else {
|
|
188
|
+
// Some providers only send service_tier on the final usage frame.
|
|
189
|
+
requireBudget(
|
|
190
|
+
row.id === receipt.id && row.model === receipt.model,
|
|
191
|
+
"Stream identity changed",
|
|
192
|
+
);
|
|
193
|
+
if (row.service_tier !== undefined) {
|
|
194
|
+
requireBudget(
|
|
195
|
+
receipt.service_tier === undefined ||
|
|
196
|
+
row.service_tier === receipt.service_tier,
|
|
197
|
+
"Stream tier changed",
|
|
198
|
+
);
|
|
199
|
+
receipt.service_tier = row.service_tier;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
requireBudget(
|
|
203
|
+
Array.isArray(row.choices) &&
|
|
204
|
+
row.choices.length <= 1 &&
|
|
205
|
+
row.choices.every((choice) => choice.index === 0),
|
|
206
|
+
"Multiple/unknown streamed completions",
|
|
207
|
+
);
|
|
208
|
+
for (const choice of row.choices) {
|
|
209
|
+
requireBudget(
|
|
210
|
+
finishReason === null,
|
|
211
|
+
"Choice data received after completed stream choice",
|
|
212
|
+
);
|
|
213
|
+
if (choice.finish_reason != null) {
|
|
214
|
+
requireBudget(
|
|
215
|
+
["stop", "length", "tool_calls"].includes(choice.finish_reason),
|
|
216
|
+
"Unsupported stream finish reason",
|
|
217
|
+
);
|
|
218
|
+
finishReason = choice.finish_reason;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (row.usage != null) {
|
|
222
|
+
requireBudget(
|
|
223
|
+
finishReason !== null,
|
|
224
|
+
"Usage received before complete stream choice",
|
|
225
|
+
);
|
|
226
|
+
requireBudget(
|
|
227
|
+
usage === null || canonical(usage) === canonical(row.usage),
|
|
228
|
+
"Conflicting streamed usage",
|
|
229
|
+
);
|
|
230
|
+
usage = row.usage;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
requireBudget(
|
|
234
|
+
terminal && finishReason !== null && receipt && usage,
|
|
235
|
+
"Incomplete stream or missing usage",
|
|
236
|
+
);
|
|
237
|
+
return { ...receipt, usage };
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Trusted-host JSON/SSE transport: credential stays in this closure, and every
|
|
242
|
+
* physical request consumes a durable dispatch exactly once. No auto retries.
|
|
243
|
+
* This is not the unrestricted Agent/Chat transport and is not auto-enabled.
|
|
244
|
+
*/
|
|
245
|
+
export function createFormalBudgetTransport({
|
|
246
|
+
authority,
|
|
247
|
+
credentialProvider,
|
|
248
|
+
fetchImpl = globalThis.fetch,
|
|
249
|
+
maximumResponseBytes = 16 * 1024 * 1024,
|
|
250
|
+
timeoutMs = 60_000,
|
|
251
|
+
}) {
|
|
252
|
+
requireBudget(
|
|
253
|
+
authority &&
|
|
254
|
+
typeof credentialProvider === "function" &&
|
|
255
|
+
typeof fetchImpl === "function",
|
|
256
|
+
"Authority and trusted credential provider required",
|
|
257
|
+
);
|
|
258
|
+
requireBudget(
|
|
259
|
+
Number.isSafeInteger(maximumResponseBytes) &&
|
|
260
|
+
maximumResponseBytes > 0 &&
|
|
261
|
+
maximumResponseBytes <= 16 * 1024 * 1024,
|
|
262
|
+
"Invalid response byte bound",
|
|
263
|
+
);
|
|
264
|
+
requireBudget(
|
|
265
|
+
Number.isSafeInteger(timeoutMs) && timeoutMs > 0 && timeoutMs <= 300_000,
|
|
266
|
+
"Invalid timeout",
|
|
267
|
+
);
|
|
268
|
+
return Object.freeze({
|
|
269
|
+
async dispatch({ runId, callId, body, signal }) {
|
|
270
|
+
// Snapshot before await so caller mutation cannot alter the reserved body.
|
|
271
|
+
const request = JSON.parse(canonical(body));
|
|
272
|
+
authority.reserve({ runId, callId, body: request });
|
|
273
|
+
let settled = false;
|
|
274
|
+
try {
|
|
275
|
+
const reserved = authority.reservedContract(callId);
|
|
276
|
+
const credential = await credentialProvider({
|
|
277
|
+
contractId: reserved.id,
|
|
278
|
+
provider: reserved.provider,
|
|
279
|
+
endpoint: reserved.endpoint,
|
|
280
|
+
});
|
|
281
|
+
requireBudget(
|
|
282
|
+
typeof credential === "string" &&
|
|
283
|
+
credential.length > 0 &&
|
|
284
|
+
!/[\r\n]/u.test(credential),
|
|
285
|
+
"Credential unavailable",
|
|
286
|
+
);
|
|
287
|
+
const deadline = AbortSignal.timeout(timeoutMs);
|
|
288
|
+
const options = {
|
|
289
|
+
method: "POST",
|
|
290
|
+
redirect: "error",
|
|
291
|
+
headers: {
|
|
292
|
+
"Content-Type": "application/json",
|
|
293
|
+
Authorization: `Bearer ${credential}`,
|
|
294
|
+
},
|
|
295
|
+
body: JSON.stringify(request),
|
|
296
|
+
signal: signal ? AbortSignal.any([signal, deadline]) : deadline,
|
|
297
|
+
};
|
|
298
|
+
// Final expiry/request check is AFTER every awaited preparation. There
|
|
299
|
+
// must be no await between this durable admission and physical fetch.
|
|
300
|
+
const contract = authority.markDispatched(callId, request);
|
|
301
|
+
const response = await fetchImpl(contract.endpoint, options);
|
|
302
|
+
requireBudget(response.ok, "Provider HTTP response not successful");
|
|
303
|
+
const text = await boundedText(response, maximumResponseBytes);
|
|
304
|
+
let receipt;
|
|
305
|
+
if (request.stream === true) {
|
|
306
|
+
requireBudget(
|
|
307
|
+
response.headers.get("content-type")?.includes("text/event-stream"),
|
|
308
|
+
"Unexpected stream content type",
|
|
309
|
+
);
|
|
310
|
+
receipt = streamReceipt(text);
|
|
311
|
+
} else {
|
|
312
|
+
receipt = parseBudgetJson(text);
|
|
313
|
+
requireBudget(
|
|
314
|
+
receipt && !Object.hasOwn(receipt, "error"),
|
|
315
|
+
"Provider error envelope cannot settle",
|
|
316
|
+
);
|
|
317
|
+
requireBudget(
|
|
318
|
+
Array.isArray(receipt.choices) &&
|
|
319
|
+
receipt.choices.length === 1 &&
|
|
320
|
+
receipt.choices[0].index === 0 &&
|
|
321
|
+
["stop", "length", "tool_calls"].includes(
|
|
322
|
+
receipt.choices[0].finish_reason,
|
|
323
|
+
),
|
|
324
|
+
"Incomplete or multiple completion response",
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
const cost = authority.settle(callId, receipt);
|
|
328
|
+
settled = true;
|
|
329
|
+
return { body: text, streaming: request.stream === true, cost };
|
|
330
|
+
} catch {
|
|
331
|
+
if (!settled) {
|
|
332
|
+
// Do not persist provider errors which may contain credentials/content.
|
|
333
|
+
authority.markUnknown(
|
|
334
|
+
callId,
|
|
335
|
+
"transport or settlement outcome unknown",
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
throw budgetError(
|
|
339
|
+
"CC_BUDGET_TRANSPORT_UNKNOWN",
|
|
340
|
+
"Provider outcome unknown; reservation retained and further dispatch blocked",
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
});
|
|
345
|
+
}
|
|
@@ -246,6 +246,16 @@ function whichLimitHit(state, budget, nowMs) {
|
|
|
246
246
|
* the loop stops. Does NOT mutate `state` — returns the next one.
|
|
247
247
|
*/
|
|
248
248
|
export function evaluateGoalStep(state, evaluation, budget, opts = {}) {
|
|
249
|
+
if (state.done === true) {
|
|
250
|
+
return {
|
|
251
|
+
state: { ...state },
|
|
252
|
+
decision:
|
|
253
|
+
state.outcome === "completed"
|
|
254
|
+
? GOAL_DECISION.COMPLETE
|
|
255
|
+
: GOAL_DECISION.EXHAUSTED,
|
|
256
|
+
events: [],
|
|
257
|
+
};
|
|
258
|
+
}
|
|
249
259
|
const nowMs = Number(opts.now ?? state.startedAtMs);
|
|
250
260
|
const next = {
|
|
251
261
|
...state,
|
|
@@ -326,10 +336,23 @@ export class GoalConditionEngine {
|
|
|
326
336
|
|
|
327
337
|
/** Accumulate a turn's usage before evaluating it. */
|
|
328
338
|
recordTurnUsage({ tokens = 0, costUsd = 0 } = {}) {
|
|
339
|
+
if (
|
|
340
|
+
!Number.isSafeInteger(tokens) ||
|
|
341
|
+
tokens < 0 ||
|
|
342
|
+
typeof costUsd !== "number" ||
|
|
343
|
+
!Number.isFinite(costUsd) ||
|
|
344
|
+
costUsd < 0 ||
|
|
345
|
+
!Number.isSafeInteger(this.state.tokens + tokens) ||
|
|
346
|
+
!Number.isFinite(this.state.costUsd + costUsd)
|
|
347
|
+
) {
|
|
348
|
+
throw new RangeError(
|
|
349
|
+
"Goal usage requires finite non-negative cost and safe token counts",
|
|
350
|
+
);
|
|
351
|
+
}
|
|
329
352
|
this.state = {
|
|
330
353
|
...this.state,
|
|
331
|
-
tokens: this.state.tokens +
|
|
332
|
-
costUsd: this.state.costUsd +
|
|
354
|
+
tokens: this.state.tokens + tokens,
|
|
355
|
+
costUsd: this.state.costUsd + costUsd,
|
|
333
356
|
};
|
|
334
357
|
return this.state;
|
|
335
358
|
}
|
|
@@ -38,16 +38,18 @@ export async function reconcileConfigLlmProvider(cfgLlm = {}) {
|
|
|
38
38
|
if (!cfgLlm || !cfgLlm.provider || !cfgLlm.baseUrl) {
|
|
39
39
|
return { llm: cfgLlm, changed: false };
|
|
40
40
|
}
|
|
41
|
-
const { inferProviderFromBaseUrl, modelForeignToProvider } =
|
|
42
|
-
|
|
41
|
+
const { inferProviderFromBaseUrl, modelForeignToProvider } = await import(
|
|
42
|
+
"./runnable-provider.js"
|
|
43
|
+
);
|
|
43
44
|
const inferred = inferProviderFromBaseUrl(cfgLlm.baseUrl);
|
|
44
45
|
if (!inferred || inferred === cfgLlm.provider) {
|
|
45
46
|
return { llm: cfgLlm, changed: false };
|
|
46
47
|
}
|
|
47
48
|
const corrected = { ...cfgLlm, provider: inferred };
|
|
48
49
|
if (modelForeignToProvider(inferred, cfgLlm.model)) {
|
|
49
|
-
const { selectModelForTask, TaskType } =
|
|
50
|
-
|
|
50
|
+
const { selectModelForTask, TaskType } = await import(
|
|
51
|
+
"./task-model-selector.js"
|
|
52
|
+
);
|
|
51
53
|
const def = selectModelForTask(inferred, TaskType.CHAT);
|
|
52
54
|
if (def) corrected.model = def;
|
|
53
55
|
}
|
|
@@ -88,6 +90,8 @@ export function applyConfigLlmDefaults(options = {}, cfgLlm = {}, opts = {}) {
|
|
|
88
90
|
options.provider === cfgLlm.provider
|
|
89
91
|
) {
|
|
90
92
|
if (!options.baseUrl && cfgLlm.baseUrl) options.baseUrl = cfgLlm.baseUrl;
|
|
93
|
+
if (options.serviceTier == null && cfgLlm.serviceTier != null)
|
|
94
|
+
options.serviceTier = cfgLlm.serviceTier;
|
|
91
95
|
backfillApiKey(options, cfgLlm);
|
|
92
96
|
if (!options.model && !opts.explicitModel && cfgLlm.model) {
|
|
93
97
|
options.model = cfgLlm.model;
|
|
@@ -96,6 +100,8 @@ export function applyConfigLlmDefaults(options = {}, cfgLlm = {}, opts = {}) {
|
|
|
96
100
|
}
|
|
97
101
|
if (options.provider || !cfgLlm.provider) return options;
|
|
98
102
|
options.provider = cfgLlm.provider;
|
|
103
|
+
if (options.serviceTier == null && cfgLlm.serviceTier != null)
|
|
104
|
+
options.serviceTier = cfgLlm.serviceTier;
|
|
99
105
|
if (opts.explicitModel) {
|
|
100
106
|
options.model = opts.explicitModel;
|
|
101
107
|
} else if (cfgLlm.model) {
|
package/src/lib/llm-pricing.js
CHANGED
|
@@ -67,6 +67,9 @@ export const PRICE_TABLE = Object.freeze({
|
|
|
67
67
|
exact: true,
|
|
68
68
|
terms: Object.freeze({
|
|
69
69
|
...GPT6_PRICING_TERMS,
|
|
70
|
+
...(model.serviceMultipliers
|
|
71
|
+
? { serviceMultipliers: model.serviceMultipliers }
|
|
72
|
+
: {}),
|
|
70
73
|
...(model.cacheReadMultiplier == null
|
|
71
74
|
? {}
|
|
72
75
|
: { cacheReadMultiplier: model.cacheReadMultiplier }),
|
|
@@ -259,9 +262,16 @@ export function normalizePricingTerms(value) {
|
|
|
259
262
|
Reflect.ownKeys(tiers).length === 0 ||
|
|
260
263
|
Reflect.ownKeys(tiers).some(
|
|
261
264
|
(key) =>
|
|
262
|
-
![
|
|
263
|
-
|
|
264
|
-
|
|
265
|
+
![
|
|
266
|
+
"standard",
|
|
267
|
+
"default",
|
|
268
|
+
"auto",
|
|
269
|
+
"batch",
|
|
270
|
+
"flex",
|
|
271
|
+
"fast",
|
|
272
|
+
"priority",
|
|
273
|
+
"ultrafast",
|
|
274
|
+
].includes(key) || !finite(tiers[key]),
|
|
265
275
|
)
|
|
266
276
|
)
|
|
267
277
|
fail();
|
|
@@ -378,7 +388,9 @@ export function estimateCost({
|
|
|
378
388
|
? Object.hasOwn(rate.terms.serviceMultipliers, serviceTier)
|
|
379
389
|
? rate.terms.serviceMultipliers[serviceTier]
|
|
380
390
|
: null
|
|
381
|
-
:
|
|
391
|
+
: ["standard", "default"].includes(serviceTier)
|
|
392
|
+
? 1
|
|
393
|
+
: null;
|
|
382
394
|
if (
|
|
383
395
|
!rate ||
|
|
384
396
|
tierMultiplier == null ||
|
|
@@ -263,6 +263,10 @@ export function resolveModelCapabilityProfile({
|
|
|
263
263
|
const profile = {
|
|
264
264
|
schema: PROFILE_SCHEMA,
|
|
265
265
|
catalogVersion: MODEL_CAPABILITY_CATALOG_VERSION,
|
|
266
|
+
reviewedAt: documented ? documented.reviewedAt || "2026-10-05" : null,
|
|
267
|
+
supportedServiceTiers: documented?.serviceTiers
|
|
268
|
+
? [...documented.serviceTiers]
|
|
269
|
+
: ["standard"],
|
|
266
270
|
profileId: `model-capability-v1:${identityDigest.slice(7, 39)}`,
|
|
267
271
|
provider: selectedProvider || "unknown",
|
|
268
272
|
model: selectedModel,
|
|
@@ -288,3 +292,25 @@ export function resolveModelCapabilityProfile({
|
|
|
288
292
|
profile.digest = canonicalDigest(profile, PROFILE_SCHEMA);
|
|
289
293
|
return deepFreeze(profile);
|
|
290
294
|
}
|
|
295
|
+
|
|
296
|
+
/** Resolve a requested live tier without certifying account availability. */
|
|
297
|
+
export function resolveModelServiceTier(profile, serviceTier) {
|
|
298
|
+
const requested = serviceTier ?? "standard";
|
|
299
|
+
if (
|
|
300
|
+
typeof requested !== "string" ||
|
|
301
|
+
!profile?.supportedServiceTiers?.includes(requested)
|
|
302
|
+
) {
|
|
303
|
+
throw Object.assign(
|
|
304
|
+
new RangeError(
|
|
305
|
+
`Unsupported service tier ${String(requested)} for ${profile?.provider || "unknown"}/${profile?.model || "unknown"}`,
|
|
306
|
+
),
|
|
307
|
+
{ code: "CC_MODEL_SERVICE_TIER_UNSUPPORTED" },
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
return Object.freeze({
|
|
311
|
+
requestedServiceTier: requested,
|
|
312
|
+
requestServiceTier: requested === "standard" ? null : requested,
|
|
313
|
+
effectiveServiceTier: null,
|
|
314
|
+
accountVerified: false,
|
|
315
|
+
});
|
|
316
|
+
}
|
|
@@ -65,8 +65,12 @@ export function reviewModelCatalog(review, snapshots = {}) {
|
|
|
65
65
|
"runtimeProtocol",
|
|
66
66
|
"contextWindowTokens",
|
|
67
67
|
"advertisedMaxOutputTokens",
|
|
68
|
+
"reviewedAt",
|
|
68
69
|
]) {
|
|
69
|
-
if (
|
|
70
|
+
if (
|
|
71
|
+
Object.hasOwn(expected, field) &&
|
|
72
|
+
!isDeepStrictEqual(actual[field], expected[field])
|
|
73
|
+
)
|
|
70
74
|
mismatches.push({
|
|
71
75
|
model: expected.model,
|
|
72
76
|
field,
|
|
@@ -80,6 +84,19 @@ export function reviewModelCatalog(review, snapshots = {}) {
|
|
|
80
84
|
field: "official-source",
|
|
81
85
|
actual: null,
|
|
82
86
|
});
|
|
87
|
+
if (
|
|
88
|
+
Object.hasOwn(expected, "supportedServiceTiers") &&
|
|
89
|
+
!isDeepStrictEqual(
|
|
90
|
+
actual.supportedServiceTiers,
|
|
91
|
+
expected.supportedServiceTiers,
|
|
92
|
+
)
|
|
93
|
+
)
|
|
94
|
+
mismatches.push({
|
|
95
|
+
model: expected.model,
|
|
96
|
+
field: "supportedServiceTiers",
|
|
97
|
+
expected: expected.supportedServiceTiers,
|
|
98
|
+
actual: actual.supportedServiceTiers,
|
|
99
|
+
});
|
|
83
100
|
for (const field of ["in", "out"]) {
|
|
84
101
|
if (rate?.[field] !== expected.pricing[field])
|
|
85
102
|
mismatches.push({
|
|
@@ -45,7 +45,7 @@ export const CONTEXT_WINDOWS = Object.freeze({
|
|
|
45
45
|
}),
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
-
export const MODEL_CAPABILITY_CATALOG_VERSION = "2026-10-
|
|
48
|
+
export const MODEL_CAPABILITY_CATALOG_VERSION = "2026-10-15";
|
|
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.
|
|
@@ -86,6 +86,26 @@ export const LEGACY_MODEL_PROVIDERS = Object.freeze({
|
|
|
86
86
|
// named models, not endpoint access, account entitlement, or a live CLI run.
|
|
87
87
|
export const DOCUMENTED_OPENAI_MODELS = Object.freeze({
|
|
88
88
|
"gpt-6.1-sol": Object.freeze({
|
|
89
|
+
reviewedAt: "2026-10-15",
|
|
90
|
+
serviceTiers: Object.freeze([
|
|
91
|
+
"standard",
|
|
92
|
+
"default",
|
|
93
|
+
"auto",
|
|
94
|
+
"fast",
|
|
95
|
+
"priority",
|
|
96
|
+
"flex",
|
|
97
|
+
"ultrafast",
|
|
98
|
+
]),
|
|
99
|
+
serviceMultipliers: Object.freeze({
|
|
100
|
+
standard: 1,
|
|
101
|
+
default: 1,
|
|
102
|
+
auto: 1,
|
|
103
|
+
batch: 0.5,
|
|
104
|
+
flex: 0.5,
|
|
105
|
+
fast: 2,
|
|
106
|
+
priority: 2,
|
|
107
|
+
ultrafast: 6,
|
|
108
|
+
}),
|
|
89
109
|
contextWindowTokens: 1050000,
|
|
90
110
|
advertisedMaxOutputTokens: 128000,
|
|
91
111
|
requiresResponsesForTools: true,
|
|
@@ -106,6 +126,26 @@ export const DOCUMENTED_OPENAI_MODELS = Object.freeze({
|
|
|
106
126
|
]),
|
|
107
127
|
}),
|
|
108
128
|
"gpt-6-astra": Object.freeze({
|
|
129
|
+
reviewedAt: "2026-10-15",
|
|
130
|
+
serviceTiers: Object.freeze([
|
|
131
|
+
"standard",
|
|
132
|
+
"default",
|
|
133
|
+
"auto",
|
|
134
|
+
"fast",
|
|
135
|
+
"priority",
|
|
136
|
+
"flex",
|
|
137
|
+
"ultrafast",
|
|
138
|
+
]),
|
|
139
|
+
serviceMultipliers: Object.freeze({
|
|
140
|
+
standard: 1,
|
|
141
|
+
default: 1,
|
|
142
|
+
auto: 1,
|
|
143
|
+
batch: 0.5,
|
|
144
|
+
flex: 0.5,
|
|
145
|
+
fast: 2,
|
|
146
|
+
priority: 2,
|
|
147
|
+
ultrafast: 6,
|
|
148
|
+
}),
|
|
109
149
|
contextWindowTokens: 1050000,
|
|
110
150
|
advertisedMaxOutputTokens: 128000,
|
|
111
151
|
requiresResponsesForTools: true,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { resolveModelServiceTier } from "./model-capabilities.js";
|
|
2
|
+
|
|
1
3
|
const RESPONSES_FAILURE_CODE = "CC_OPENAI_RESPONSES_FAILED";
|
|
2
4
|
const MAX_REASONING_ITEMS = 16;
|
|
3
5
|
const MAX_REASONING_SUMMARY_CHARS = 8_192;
|
|
@@ -177,7 +179,12 @@ export function createOpenAIResponsesBody({
|
|
|
177
179
|
reasoning = null,
|
|
178
180
|
stream = false,
|
|
179
181
|
modelProfile = null,
|
|
182
|
+
serviceTier = null,
|
|
180
183
|
}) {
|
|
184
|
+
const tier =
|
|
185
|
+
serviceTier == null
|
|
186
|
+
? null
|
|
187
|
+
: resolveModelServiceTier(modelProfile, serviceTier).requestServiceTier;
|
|
181
188
|
if (
|
|
182
189
|
modelProfile?.advertisedMaxOutputTokens != null &&
|
|
183
190
|
maxOutputTokens > modelProfile.advertisedMaxOutputTokens
|
|
@@ -195,6 +202,7 @@ export function createOpenAIResponsesBody({
|
|
|
195
202
|
...(maxOutputTokens ? { max_output_tokens: maxOutputTokens } : {}),
|
|
196
203
|
...(reasoning ? { reasoning } : {}),
|
|
197
204
|
...(stream ? { stream: true } : {}),
|
|
205
|
+
...(tier ? { service_tier: tier } : {}),
|
|
198
206
|
};
|
|
199
207
|
}
|
|
200
208
|
|
|
@@ -248,6 +248,7 @@ export function routeSkillDescriptors({
|
|
|
248
248
|
schema: SKILL_RETRIEVAL_RESULT_SCHEMA,
|
|
249
249
|
query: query.trim(),
|
|
250
250
|
selected: returned.length > 0 && !topConflict ? returned[0] : null,
|
|
251
|
+
matchedCount: candidates.length,
|
|
251
252
|
candidates: Object.freeze(returned.map(Object.freeze)),
|
|
252
253
|
conflicts: Object.freeze(conflicts.map(Object.freeze)),
|
|
253
254
|
rejected: Object.freeze(rejected.map(Object.freeze)),
|
|
@@ -4,6 +4,38 @@ import {
|
|
|
4
4
|
GPT6_PRICING_TERMS,
|
|
5
5
|
} from "./model-context-catalog.js";
|
|
6
6
|
|
|
7
|
+
const KNOWN_SERVICE_TIERS = new Set([
|
|
8
|
+
...Object.keys(GPT6_PRICING_TERMS.serviceMultipliers),
|
|
9
|
+
...Object.values(DOCUMENTED_OPENAI_MODELS).flatMap((model) =>
|
|
10
|
+
Object.keys(model.serviceMultipliers || {}),
|
|
11
|
+
),
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
/** Preserve response-envelope pricing labels, rejecting conflicting evidence. */
|
|
15
|
+
export function projectEnvelopePricingContext(usage = {}, envelope = {}) {
|
|
16
|
+
const input = { ...usage };
|
|
17
|
+
for (const key of ["service_tier", "regional_processing", "inference_geo"]) {
|
|
18
|
+
if (!Object.hasOwn(envelope, key)) continue;
|
|
19
|
+
if (Object.hasOwn(input, key) && input[key] !== envelope[key])
|
|
20
|
+
input.pricingContextInvalid = true;
|
|
21
|
+
input[key] = envelope[key];
|
|
22
|
+
}
|
|
23
|
+
return projectUsagePricingContext(input);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Requested paid tiers require actual response evidence for settlement. */
|
|
27
|
+
export function preserveRequestedServiceTierEvidence(usage, requested) {
|
|
28
|
+
if (
|
|
29
|
+
usage &&
|
|
30
|
+
requested != null &&
|
|
31
|
+
requested !== "standard" &&
|
|
32
|
+
(!usage.service_tier || usage.service_tier === "auto")
|
|
33
|
+
) {
|
|
34
|
+
return { ...usage, pricingContextInvalid: true };
|
|
35
|
+
}
|
|
36
|
+
return usage;
|
|
37
|
+
}
|
|
38
|
+
|
|
7
39
|
/** Keep TTL evidence distinct from the aggregate cache-write count. */
|
|
8
40
|
export function projectCacheCreationUsage(usage = {}) {
|
|
9
41
|
if (usage.cacheCreationInvalid === true)
|
|
@@ -62,8 +94,7 @@ export function projectUsagePricingContext(usage = {}) {
|
|
|
62
94
|
const value = Object.hasOwn(usage, key) ? usage[key] : usage[alias];
|
|
63
95
|
if (key === "service_tier") {
|
|
64
96
|
projected[key] =
|
|
65
|
-
typeof value === "string" &&
|
|
66
|
-
Object.hasOwn(GPT6_PRICING_TERMS.serviceMultipliers, value)
|
|
97
|
+
typeof value === "string" && KNOWN_SERVICE_TIERS.has(value)
|
|
67
98
|
? value
|
|
68
99
|
: "unknown";
|
|
69
100
|
} else {
|