chainlesschain 0.166.114 → 0.166.117
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 +23 -3
- 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-CVac3rIN.js → AIOps-C9tSCImB.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-ChM9GxMl.js → ActionButton-CXKExmT_.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CV5399Js.js → Analytics-DE8WBWHo.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CuonVXhg.js → AppLayout-BdpwNM08.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-D9qKfgb6.js → Artifacts-94TQpe38.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DUvLysQc.js → Audit-DdDEv5Ej.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DfKohQeT.js → BackgroundAgents-TU9nlV7j.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CohoEI8R.js → Backup-C0GPoUUq.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BwdoA3xv.js → BaseInput-iyrVn2I6.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-DRkuz1d2.js → Chat-Dqo8spwp.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-v3pzeHNC.js → ChatBubbleRenderer-CDqHSzc4.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-B-GNGpKv.js → Checkbox-BF_XJvQi.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-Bs2lAsoZ.js → Codegen-5tUWoOa9.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Bk1mJKDZ.js → Col-BQxSeRvG.js} +1 -1
- package/src/assets/web-panel/assets/{Community-B_FDSCOo.js → Community-B2Ra7w-J.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-No1qSLLH.js → Compact-GjxJwlr0.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CcrG43-d.js → Compliance-BTUP6RTA.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DLkj2ywK.js → Cowork-DiwfL16s.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-sQHELVEz.js → Cron-1ceOo5ux.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CRTZ3GZg.js → Crosschain-aHYxLu0u.js} +1 -1
- package/src/assets/web-panel/assets/{DID-Ds2bjvxE.js → DID-eeTjzOLV.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DOONG2NX.js → Dashboard-CT3fpkvX.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-Br3PNA2L.js → Dropdown-B3UpOy-N.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DT6UUqjZ.js → EmailListRenderer-Ba2Rvoru.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-BSLuEjlT.js → EvolutionSettings-CGtn93on.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-2aEM9avE.js → FamilyGuardDashboard-C0IUdHQt.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-D3B0tlQU.js → Federation-1QIDwemn.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DTVkVVQP.js → FormItemContext-NGbSsdje.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BgFEgP4y.js → GenericCardRenderer-DzVZc2Ba.js} +1 -1
- package/src/assets/web-panel/assets/{Git-3t71m6Xd.js → Git-B_1TDbSr.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DS7WvlaX.js → Governance-BDl_ySyI.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CeT-xWrI.js → Inference-CAp-wcCK.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-BQzMncp5.js → KnowledgeGraph-DRjRcxul.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CC5DOKhV.js → Logs-qSuwMwk7.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-BgnYTegK.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-CpYDyy3o.js → Marketplace-DfiXL6UO.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DRdAZPMr.js → McpTools-D9rIvFjN.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-CBLRr-l8.js → Memory-D-p7yDzj.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Bnj9veNN.js → MobileBridge-D0XT5B6m.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-lYFPD24p.js → MobileProjects-CL9cHVIk.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BMU_C9vD.js → Mtc-CME4kDmC.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-DQV-zumU.js → MtcAudit-BjGOXFnn.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-LpqpqV1d.js → Multisig-CSzc53e0.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-C4OMklSO.js → NLProgramming-BYjZnaH8.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Cg0QCinP.js → Notes-BUPOYE0C.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-amoZoMna.js → NotificationSettings-BK8YADru.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-CxNvhf5n.js → OrderTableRenderer-B5F8bnWt.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-BetJmyX5.js → Organization-B0WNlhMd.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-DbeoPtVD.js → Overflow-CED6ZO87.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-B5sitQWT.js → P2P-CBdc8fkP.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-AP9SG2ic.js → PdhVaultBrowser-DuauYi03.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-Bc7fgNKx.js → Permissions-kfgY0ukN.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-BwdGMcWZ.js → PersonalDataHub-CDY3I1Do.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-DVuJA9BA.js → Pipeline-B9x0wKSK.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BGzwOYRG.js → Privacy-Cqhcr_Qv.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BpHcC5br.js → ProjectInit-CFhoyo57.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BI5G5gsc.js → ProjectSettings-DCBjV2Hm.js} +2 -2
- package/src/assets/web-panel/assets/Projects-C51w0LnM.js +1 -0
- package/src/assets/web-panel/assets/{Providers-CRHCcLFS.js → Providers-BuCIWZY1.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-qSeg5xag.js → QrScannerModal-CEXNL5CB.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CA8oSceR.js → QuickAsk-DgK8aLAU.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DMvPodNo.js → Recommend-BxEYQRAs.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-BWsapEyN.js → RemoteSession-PRsxNsYU.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-BZJETVmC.js → Reputation-S-tQH70r.js} +1 -1
- package/src/assets/web-panel/assets/{Row-CUE1OSMp.js → Row-U1Ws3CJl.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-DvMazcUD.js → RssFeed-BftCyeii.js} +3 -3
- package/src/assets/web-panel/assets/{Search-e1c-NXWv.js → Search-o4gK0cPy.js} +1 -1
- package/src/assets/web-panel/assets/{Security-Dc9GZsx2.js → Security-U2ZRpsbA.js} +3 -3
- package/src/assets/web-panel/assets/{Services-AFz6ke-4.js → Services-D0tRjWl_.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-gow6MYcY.js → Skeleton-DzZ8TFsB.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-h6AxYjUP.js → Skills-B1cC7rju.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-Cr4CkJ0O.js → Sla-CtIHOR0J.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Bd5yuBtH.js → SpeechSettings-CD8ZlQpW.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-1t4QZMLW.js → SyncSettings-BilFQWQk.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-u-DrjLRM.js → Tasks-Bmg2qLXl.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-C0yLUC9b.js → Templates-D6yofyC1.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-ds1YT5iS.js → Tenant-BzttD-Gp.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-BoIskW2m.js → Terminal-DyRXeYuH.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BkdVK24X.js → TimelineRenderer-Bdmkx-Tr.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-djyDgmfk.js → Tokens-10RcVAVJ.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CYefDS3H.js → Trigger-CKV-9DdV.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CE_dbep_.js → Trust-BEc-sW1q.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DwVs_fey.js → UkeySign-BSql8piX.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BTUqMHAV.js → VideoEditing-C4OH2f4s.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Bu_E7Rrc.js → Wallet-BSSvWKmv.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DTbre5AB.js → WebAuthn-LxIzXo9d.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-BsBzd3gt.js → WorkflowEditor-DWwdfcte.js} +1 -1
- package/src/assets/web-panel/assets/{chat-tdifQQvu.js → chat-DWxYYLD5.js} +1 -1
- package/src/assets/web-panel/assets/{colors-D3SNW2Vx.js → colors-BxEcQqtg.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-UBlCjrAW.js → compact-item-DNbezFOJ.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DKsnEnFt.js → createContext-DaJXc5nx.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CRyXoGo9.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BkeySXWe.js → hasIn-BMrw3sg3.js} +1 -1
- package/src/assets/web-panel/assets/{index-CXkn77ZN.js → index-2c0bL3SE.js} +1 -1
- package/src/assets/web-panel/assets/{index-DtxUSZSS.js → index-6W0V5G2t.js} +1 -1
- package/src/assets/web-panel/assets/{index-DFMrIEIt.js → index-7zzLqfvI.js} +1 -1
- package/src/assets/web-panel/assets/{index-D9m1HQzl.js → index-B9b6UaZl.js} +1 -1
- package/src/assets/web-panel/assets/{index-bOIcWW8F.js → index-BAV07GDK.js} +1 -1
- package/src/assets/web-panel/assets/{index-BV2zQteq.js → index-BCCd8Rj6.js} +1 -1
- package/src/assets/web-panel/assets/{index-DlO6HdD9.js → index-BNZDGV2q.js} +1 -1
- package/src/assets/web-panel/assets/{index-DfrW-iVs.js → index-BR4nWOmR.js} +1 -1
- package/src/assets/web-panel/assets/{index-PWScrdlX.js → index-B_b9_6wQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-SpQ26gD6.js → index-BaByEdBj.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5Umd_Z-.js → index-BcuytRTa.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dg8-Duze.js → index-Bs2QyMPQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DlEIp1gJ.js → index-Bum_aSyd.js} +1 -1
- package/src/assets/web-panel/assets/index-C-W0Ntk_.js +1 -0
- package/src/assets/web-panel/assets/{index-D6es7MSG.js → index-C25ig6EV.js} +1 -1
- package/src/assets/web-panel/assets/index-CCk_qhBx.js +1 -0
- package/src/assets/web-panel/assets/{index-Bw0k3VgD.js → index-CL-36X3A.js} +1 -1
- package/src/assets/web-panel/assets/{index-DYFjOyTH.js → index-Ca2hwPMo.js} +1 -1
- package/src/assets/web-panel/assets/{index-BVvz3ntc.js → index-CaxzeSIM.js} +1 -1
- package/src/assets/web-panel/assets/{index-D9um0YVl.js → index-CiEdfbB9.js} +1 -1
- package/src/assets/web-panel/assets/{index-DugZRCiI.js → index-Cm9DYzhC.js} +1 -1
- package/src/assets/web-panel/assets/{index-pgGKNvmm.js → index-CpwgF7vh.js} +1 -1
- package/src/assets/web-panel/assets/{index-P-ailFQY.js → index-DEvdSKT4.js} +1 -1
- package/src/assets/web-panel/assets/{index-C9ImNw5O.js → index-DL0k35f0.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSCiZJXb.js → index-DarVV5yG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BIeFLaMV.js → index-DpSp97J8.js} +1 -1
- package/src/assets/web-panel/assets/{index-C-KTHSUE.js → index-Dr18agDl.js} +1 -1
- package/src/assets/web-panel/assets/{index-DiDgwRty.js → index-Dwg38xTG.js} +1 -1
- package/src/assets/web-panel/assets/{index-D93iSDUw.js → index-DzZHBzCb.js} +1 -1
- package/src/assets/web-panel/assets/{index-6Nvzgytx.js → index-IX0g0s2t.js} +1 -1
- package/src/assets/web-panel/assets/{index-CG_b1xyX.js → index-LRb0QX6S.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cuz2QCFT.js → index-NEW5EN2w.js} +1 -1
- package/src/assets/web-panel/assets/{index-CUjyL0ZS.js → index-T4T84G6X.js} +1 -1
- package/src/assets/web-panel/assets/{index-DdyTv6yc.js → index-VD-dTYQE.js} +1 -1
- package/src/assets/web-panel/assets/{index-BEiHKah0.js → index-cCqCEa9X.js} +3 -3
- package/src/assets/web-panel/assets/{index-DD6dD3LV.js → index-cKBpcInt.js} +1 -1
- package/src/assets/web-panel/assets/{index-TLBpgN30.js → index-hPy_f08G.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSe_7MSy.js → index-pzYLf5qu.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZ6JUooI.js → index-rFaCnjXi.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-CVCXG2Hv.js → initDefaultProps-BWVLgWhF.js} +1 -1
- package/src/assets/web-panel/assets/{motion-Dv00jw87.js → motion-KJZ1xfDE.js} +1 -1
- package/src/assets/web-panel/assets/{move-BFz51iHf.js → move-DGqU6H7M.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BK2woIDE.js → mtc-parser-Dg0xkI5J.js} +1 -1
- package/src/assets/web-panel/assets/{omit-D2X_Gwoo.js → omit-B6RnMJAQ.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CLmFyJ1q.js → pickAttrs-Ctw2i3jb.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CCzPddQm.js → placementArrow-D3F3x8Jm.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-hcm_Zlxd.js → responsiveObserve-W6eHE0nM.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BxfZEFVp.js → slide-BlFf8sY5.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-kzB9pT-t.js → statusUtils-Cd6LMwmy.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-CDFd7YCI.js → styleChecker-Bg5-U4Y1.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Czl7NNhS.js → useFlexGapSupport-DTkLS3tn.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-y0SAzirG.js → useFs-CwYGzoBt.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BvdPznrA.js → usePersonalDataHub-PCgFQXZP.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-D8mNbyZ7.js → vnode-CJM7MkrB.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-_hun6w9W.js → zoom-CP0mgaFi.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/compact.js +7 -2
- package/src/data/changelog.json +28 -2
- package/src/harness/jsonl-session-store.js +78 -73
- package/src/harness/prompt-compressor.js +57 -3
- package/src/lib/context-memory-kernel/context-image-transport.js +248 -0
- package/src/lib/context-memory-kernel/jsonl-session-context-port.js +4 -1
- package/src/lib/context-memory-kernel/live-compaction.js +40 -10
- package/src/lib/context-memory-kernel/message-adapter.js +80 -10
- package/src/lib/context-memory-kernel/message-bundle-store.js +1140 -0
- package/src/lib/context-memory-kernel/provider-context.js +23 -8
- package/src/lib/evolution/agent-evolution-ingress.js +62 -12
- package/src/lib/evolution/agent-model-projection.js +90 -18
- package/src/lib/evolution/evidence-json-text.js +279 -42
- package/src/lib/evolution/evolution-evidence-projector.js +169 -26
- package/src/lib/evolution/governed-model-turn.js +2 -2
- package/src/lib/evolution/local-ui-evolution-deployment.js +2 -2
- package/src/lib/evolution/local-ui-evolution-runtime.js +4 -4
- package/src/lib/evolution/opaque-hex-id.js +8 -0
- package/src/lib/image-token-estimate.js +59 -0
- package/src/lib/read-file-loop-guard.js +9 -6
- package/src/lib/session-history-origins.js +25 -5
- package/src/lib/session-transcript-history.js +5 -1
- package/src/lib/tool-result-preview.js +276 -0
- package/src/runtime/agent-core.js +85 -78
- package/src/runtime/headless-stream.js +32 -17
- package/src/assets/web-panel/assets/MarkdownRenderer-5jYM4kYG.js +0 -1
- package/src/assets/web-panel/assets/Projects-Ce92-l1V.js +0 -1
- package/src/assets/web-panel/assets/devWarning-BBnVfJHh.js +0 -1
- package/src/assets/web-panel/assets/index-B2w_3mtS.js +0 -1
- package/src/assets/web-panel/assets/index-BoHurydC.js +0 -1
|
@@ -11,12 +11,15 @@
|
|
|
11
11
|
|
|
12
12
|
import { createHash, randomBytes } from "node:crypto";
|
|
13
13
|
import {
|
|
14
|
+
AGENT_MODEL_REQUEST_LIMITS,
|
|
15
|
+
AGENT_MODEL_IMAGE_LIMITS,
|
|
14
16
|
projectAgentOpaqueTransportBlock,
|
|
15
17
|
snapshotAgentModelRequest,
|
|
16
18
|
} from "./agent-model-projection.js";
|
|
17
19
|
import { snapshotSkillDecisionPayload } from "./skill-decision-projection.js";
|
|
18
20
|
import {
|
|
19
21
|
createEvidenceJsonTextBoundary,
|
|
22
|
+
AGENT_CODE_TEXT_RESULT_TOOLS,
|
|
20
23
|
EVIDENCE_JSON_POLICY,
|
|
21
24
|
isAgentToolArgumentsPath,
|
|
22
25
|
} from "./evidence-json-text.js";
|
|
@@ -93,6 +96,8 @@ const TRUSTED_PAYLOAD_COMMITMENT_PURPOSE =
|
|
|
93
96
|
const LEGACY_LOCAL_UI_TENANT_ID_PATTERN = /^local-ui-[a-f0-9]{32}$/u;
|
|
94
97
|
const FORMATTED_LOCAL_UI_TENANT_ID_PATTERN =
|
|
95
98
|
/^local-ui-(?:[a-f0-9]{8}-){3}[a-f0-9]{8}$/u;
|
|
99
|
+
const ENCODED_LOCAL_UI_TENANT_ID_PATTERN =
|
|
100
|
+
/^local-ui-(?:[a-p]{8}-){3}[a-p]{8}$/u;
|
|
96
101
|
|
|
97
102
|
const INPUT_KEYS = new Set(["sourceEnvelope", "payload"]);
|
|
98
103
|
const SOURCE_VERIFICATION_KEYS = new Set([
|
|
@@ -513,13 +518,41 @@ export const EVOLUTION_AGENT_MODEL_PROJECTION_RULESET_V2_DIGEST = `sha256:${crea
|
|
|
513
518
|
"utf8",
|
|
514
519
|
)
|
|
515
520
|
.digest("hex")}`;
|
|
516
|
-
const
|
|
521
|
+
const AGENT_MODEL_RULESET_V3 = Object.freeze({
|
|
517
522
|
...AGENT_MODEL_RULESET_V2,
|
|
518
523
|
schema: "chainlesschain.evolution-agent-model-projection-rules/v3",
|
|
519
524
|
version: 3,
|
|
520
525
|
opaqueTransportPolicy:
|
|
521
526
|
"digest-bound-base64-image-and-signed-thinking-no-plaintext-projection-v1",
|
|
522
527
|
});
|
|
528
|
+
export const EVOLUTION_AGENT_MODEL_PROJECTION_RULESET_V3_DIGEST = `sha256:${createHash(
|
|
529
|
+
"sha256",
|
|
530
|
+
)
|
|
531
|
+
.update(
|
|
532
|
+
`${AGENT_MODEL_RULESET_V3.schema}\0${JSON.stringify(AGENT_MODEL_RULESET_V3)}`,
|
|
533
|
+
"utf8",
|
|
534
|
+
)
|
|
535
|
+
.digest("hex")}`;
|
|
536
|
+
const AGENT_MODEL_RULESET = Object.freeze({
|
|
537
|
+
...AGENT_MODEL_RULESET_V3,
|
|
538
|
+
schema: "chainlesschain.evolution-agent-model-projection-rules/v4",
|
|
539
|
+
version: 4,
|
|
540
|
+
codeTextPolicy: "paired-code-source-and-result-literal-scan-v1",
|
|
541
|
+
codeTextResultTools: AGENT_CODE_TEXT_RESULT_TOOLS,
|
|
542
|
+
// ArtifactPorts caps the complete durable record at 1 MiB. Reserve room for
|
|
543
|
+
// provenance/findings and the record envelope; no storage limit is relaxed.
|
|
544
|
+
maxModelBytes: AGENT_MODEL_REQUEST_LIMITS.maxBytes - 128 * 1024,
|
|
545
|
+
maxStringChars: AGENT_MODEL_REQUEST_LIMITS.maxBytes - 128 * 1024,
|
|
546
|
+
maxNodes: AGENT_MODEL_REQUEST_LIMITS.maxNodes,
|
|
547
|
+
maxDepth: AGENT_MODEL_REQUEST_LIMITS.maxDepth,
|
|
548
|
+
decodedDepthPolicy: "independent-bounded-json-depth-v1",
|
|
549
|
+
imageBudget: AGENT_MODEL_IMAGE_LIMITS,
|
|
550
|
+
jsonTextPolicy: Object.freeze({
|
|
551
|
+
...EVIDENCE_JSON_POLICY,
|
|
552
|
+
version: 2,
|
|
553
|
+
maxNodes: AGENT_MODEL_REQUEST_LIMITS.maxNodes,
|
|
554
|
+
}),
|
|
555
|
+
});
|
|
523
556
|
export const EVOLUTION_AGENT_MODEL_PROJECTION_RULESET_DIGEST = `sha256:${createHash(
|
|
524
557
|
"sha256",
|
|
525
558
|
)
|
|
@@ -550,6 +583,7 @@ const SUPPORTED_RULESETS = new Map([
|
|
|
550
583
|
[RAW_RULESET_V3_DIGEST, RAW_RULESET_V3],
|
|
551
584
|
[AGENT_MODEL_RULESET_V1_DIGEST, AGENT_MODEL_RULESET_V1],
|
|
552
585
|
[EVOLUTION_AGENT_MODEL_PROJECTION_RULESET_V2_DIGEST, AGENT_MODEL_RULESET_V2],
|
|
586
|
+
[EVOLUTION_AGENT_MODEL_PROJECTION_RULESET_V3_DIGEST, AGENT_MODEL_RULESET_V3],
|
|
553
587
|
[EVOLUTION_AGENT_MODEL_PROJECTION_RULESET_DIGEST, AGENT_MODEL_RULESET],
|
|
554
588
|
]);
|
|
555
589
|
|
|
@@ -625,6 +659,7 @@ const AGENT_VALUE_PATTERNS = Object.freeze([
|
|
|
625
659
|
function valuePatterns(ruleset) {
|
|
626
660
|
return ruleset === SKILL_DECISION_RULESET ||
|
|
627
661
|
ruleset === AGENT_MODEL_RULESET ||
|
|
662
|
+
ruleset === AGENT_MODEL_RULESET_V3 ||
|
|
628
663
|
ruleset === AGENT_MODEL_RULESET_V2 ||
|
|
629
664
|
ruleset === AGENT_MODEL_RULESET_V1
|
|
630
665
|
? AGENT_VALUE_PATTERNS
|
|
@@ -688,7 +723,12 @@ function assertExactRecord(
|
|
|
688
723
|
}
|
|
689
724
|
}
|
|
690
725
|
|
|
691
|
-
function canonicalJson(
|
|
726
|
+
function canonicalJson(
|
|
727
|
+
value,
|
|
728
|
+
seen = new Set(),
|
|
729
|
+
depth = 0,
|
|
730
|
+
maximumBytes = 2 * 1024 * 1024,
|
|
731
|
+
) {
|
|
692
732
|
if (depth > 32) {
|
|
693
733
|
throw projectionError(
|
|
694
734
|
EVOLUTION_PROJECTION_INVALID_CODE,
|
|
@@ -710,10 +750,12 @@ function canonicalJson(value, seen = new Set(), depth = 0) {
|
|
|
710
750
|
output = JSON.stringify(value);
|
|
711
751
|
}
|
|
712
752
|
if (output !== undefined) {
|
|
713
|
-
if (Buffer.byteLength(output, "utf8") >
|
|
753
|
+
if (Buffer.byteLength(output, "utf8") > maximumBytes) {
|
|
714
754
|
throw projectionError(
|
|
715
755
|
EVOLUTION_PROJECTION_INVALID_CODE,
|
|
716
|
-
|
|
756
|
+
maximumBytes === 2 * 1024 * 1024
|
|
757
|
+
? "projection exceeds the 2 MiB admission limit"
|
|
758
|
+
: "Agent image transport exceeds its canonical byte budget",
|
|
717
759
|
);
|
|
718
760
|
}
|
|
719
761
|
return output;
|
|
@@ -755,7 +797,9 @@ function canonicalJson(value, seen = new Set(), depth = 0) {
|
|
|
755
797
|
"projection arrays must use enumerable own data entries",
|
|
756
798
|
);
|
|
757
799
|
}
|
|
758
|
-
entries.push(
|
|
800
|
+
entries.push(
|
|
801
|
+
canonicalJson(descriptor.value, seen, depth + 1, maximumBytes),
|
|
802
|
+
);
|
|
759
803
|
}
|
|
760
804
|
output = `[${entries.join(",")}]`;
|
|
761
805
|
} else {
|
|
@@ -782,24 +826,29 @@ function canonicalJson(value, seen = new Set(), depth = 0) {
|
|
|
782
826
|
);
|
|
783
827
|
}
|
|
784
828
|
fields.push(
|
|
785
|
-
`${JSON.stringify(key)}:${canonicalJson(descriptor.value, seen, depth + 1)}`,
|
|
829
|
+
`${JSON.stringify(key)}:${canonicalJson(descriptor.value, seen, depth + 1, maximumBytes)}`,
|
|
786
830
|
);
|
|
787
831
|
}
|
|
788
832
|
output = `{${fields.join(",")}}`;
|
|
789
833
|
}
|
|
790
834
|
seen.delete(value);
|
|
791
|
-
if (Buffer.byteLength(output, "utf8") >
|
|
835
|
+
if (Buffer.byteLength(output, "utf8") > maximumBytes) {
|
|
792
836
|
throw projectionError(
|
|
793
837
|
EVOLUTION_PROJECTION_INVALID_CODE,
|
|
794
|
-
|
|
838
|
+
maximumBytes === 2 * 1024 * 1024
|
|
839
|
+
? "projection exceeds the 2 MiB admission limit"
|
|
840
|
+
: "Agent image transport exceeds its canonical byte budget",
|
|
795
841
|
);
|
|
796
842
|
}
|
|
797
843
|
return output;
|
|
798
844
|
}
|
|
799
845
|
|
|
800
|
-
function digest(value, domain) {
|
|
846
|
+
function digest(value, domain, maximumBytes) {
|
|
801
847
|
return `sha256:${createHash("sha256")
|
|
802
|
-
.update(
|
|
848
|
+
.update(
|
|
849
|
+
`${domain}\0${canonicalJson(value, new Set(), 0, maximumBytes)}`,
|
|
850
|
+
"utf8",
|
|
851
|
+
)
|
|
803
852
|
.digest("hex")}`;
|
|
804
853
|
}
|
|
805
854
|
|
|
@@ -877,17 +926,32 @@ function normalizeId(value, label, maximum = 256) {
|
|
|
877
926
|
return value;
|
|
878
927
|
}
|
|
879
928
|
|
|
880
|
-
function
|
|
881
|
-
|
|
929
|
+
function isLocalUiTenantId(value) {
|
|
930
|
+
return (
|
|
882
931
|
typeof value === "string" &&
|
|
883
932
|
(LEGACY_LOCAL_UI_TENANT_ID_PATTERN.test(value) ||
|
|
884
|
-
FORMATTED_LOCAL_UI_TENANT_ID_PATTERN.test(value)
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
933
|
+
FORMATTED_LOCAL_UI_TENANT_ID_PATTERN.test(value) ||
|
|
934
|
+
ENCODED_LOCAL_UI_TENANT_ID_PATTERN.test(value))
|
|
935
|
+
);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
function normalizeTenantId(value, label) {
|
|
939
|
+
if (isLocalUiTenantId(value)) return value;
|
|
888
940
|
return normalizeId(value, label);
|
|
889
941
|
}
|
|
890
942
|
|
|
943
|
+
function normalizeLocalAttestationId(value, label, tenantId, suffix) {
|
|
944
|
+
// A bound local identity is already admitted as tenant metadata. Inspect its
|
|
945
|
+
// fixed reference structure without treating its random digits as content;
|
|
946
|
+
// preserve the original signed bytes and scan every other identifier fully.
|
|
947
|
+
const scanValue =
|
|
948
|
+
isLocalUiTenantId(tenantId) && value === `local-ui-${tenantId}-${suffix}`
|
|
949
|
+
? `local-ui-local-identity-${suffix}`
|
|
950
|
+
: value;
|
|
951
|
+
normalizeId(scanValue, label);
|
|
952
|
+
return value;
|
|
953
|
+
}
|
|
954
|
+
|
|
891
955
|
function normalizeDigest(
|
|
892
956
|
value,
|
|
893
957
|
label,
|
|
@@ -946,7 +1010,6 @@ function normalizeOpaqueUri(value, { label, schemes, tenantId }) {
|
|
|
946
1010
|
`${label} is invalid`,
|
|
947
1011
|
);
|
|
948
1012
|
}
|
|
949
|
-
assertNoKnownSecrets(value);
|
|
950
1013
|
if (
|
|
951
1014
|
/[?#@\\%\s]/u.test(value) ||
|
|
952
1015
|
hasUriControlOrWhitespace(value) ||
|
|
@@ -985,7 +1048,11 @@ function normalizeOpaqueUri(value, { label, schemes, tenantId }) {
|
|
|
985
1048
|
parsed.port ||
|
|
986
1049
|
parsed.search ||
|
|
987
1050
|
parsed.hash ||
|
|
988
|
-
parsed.hostname !== formatLocalUiTenantReferenceId(tenantId)
|
|
1051
|
+
(parsed.hostname !== formatLocalUiTenantReferenceId(tenantId) &&
|
|
1052
|
+
!(
|
|
1053
|
+
LEGACY_LOCAL_UI_TENANT_ID_PATTERN.test(tenantId) &&
|
|
1054
|
+
parsed.hostname === tenantId
|
|
1055
|
+
)) ||
|
|
989
1056
|
!decodedPath.startsWith("/") ||
|
|
990
1057
|
decodedPath
|
|
991
1058
|
.split("/")
|
|
@@ -996,6 +1063,14 @@ function normalizeOpaqueUri(value, { label, schemes, tenantId }) {
|
|
|
996
1063
|
`${label} is outside the tenant-scoped URI policy`,
|
|
997
1064
|
);
|
|
998
1065
|
}
|
|
1066
|
+
// Only the exact, bound local host is identity metadata. Keep the complete
|
|
1067
|
+
// original path in the scan, and never rewrite persisted URI/digest bytes.
|
|
1068
|
+
const localPrefix = `${scheme}://${parsed.hostname}`;
|
|
1069
|
+
const scanValue =
|
|
1070
|
+
isLocalUiTenantId(tenantId) && value.startsWith(`${localPrefix}/`)
|
|
1071
|
+
? `${scheme}://local-ui-identity${value.slice(localPrefix.length)}`
|
|
1072
|
+
: value;
|
|
1073
|
+
assertNoKnownSecrets(scanValue);
|
|
999
1074
|
return value;
|
|
1000
1075
|
}
|
|
1001
1076
|
|
|
@@ -1268,6 +1343,43 @@ function sanitizeString(value, path, findings, injections, ruleset, patterns) {
|
|
|
1268
1343
|
return output;
|
|
1269
1344
|
}
|
|
1270
1345
|
|
|
1346
|
+
function isAgentCodeTextPath(payload, path, resultToolNames) {
|
|
1347
|
+
if (
|
|
1348
|
+
path[0] !== "messages" ||
|
|
1349
|
+
!/^\d+$/u.test(path[1] ?? "") ||
|
|
1350
|
+
!Array.isArray(payload?.messages)
|
|
1351
|
+
) {
|
|
1352
|
+
return false;
|
|
1353
|
+
}
|
|
1354
|
+
const message = payload.messages[Number(path[1])];
|
|
1355
|
+
if (!message || typeof message !== "object") return false;
|
|
1356
|
+
if (
|
|
1357
|
+
path[2] === "tool_calls" &&
|
|
1358
|
+
/^\d+$/u.test(path[3] ?? "") &&
|
|
1359
|
+
path[4] === "function" &&
|
|
1360
|
+
path[5] === "arguments"
|
|
1361
|
+
) {
|
|
1362
|
+
const call = message.tool_calls?.[Number(path[3])];
|
|
1363
|
+
const fields = path.slice(6);
|
|
1364
|
+
if (fields[0] === "$json") fields.shift();
|
|
1365
|
+
return call?.function?.name === "run_code" && fields[0] === "code";
|
|
1366
|
+
}
|
|
1367
|
+
if (path[2] === "content" && message.role === "tool") {
|
|
1368
|
+
const callId = message.tool_call_id;
|
|
1369
|
+
return payload.messages.some(
|
|
1370
|
+
(candidate) =>
|
|
1371
|
+
candidate?.role === "assistant" &&
|
|
1372
|
+
Array.isArray(candidate.tool_calls) &&
|
|
1373
|
+
candidate.tool_calls.some(
|
|
1374
|
+
(call) =>
|
|
1375
|
+
call?.id === callId &&
|
|
1376
|
+
resultToolNames.includes(call?.function?.name),
|
|
1377
|
+
),
|
|
1378
|
+
);
|
|
1379
|
+
}
|
|
1380
|
+
return false;
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1271
1383
|
function sanitizePayload(
|
|
1272
1384
|
payload,
|
|
1273
1385
|
ruleset = RULESET,
|
|
@@ -1278,8 +1390,10 @@ function sanitizePayload(
|
|
|
1278
1390
|
let nodes = 0;
|
|
1279
1391
|
let truncated = false;
|
|
1280
1392
|
const jsonText = ruleset.jsonTextPolicy
|
|
1281
|
-
? createEvidenceJsonTextBoundary(
|
|
1282
|
-
|
|
1393
|
+
? createEvidenceJsonTextBoundary(
|
|
1394
|
+
(message) =>
|
|
1395
|
+
projectionError(EVOLUTION_PROJECTION_INVALID_CODE, message),
|
|
1396
|
+
ruleset.jsonTextPolicy,
|
|
1283
1397
|
)
|
|
1284
1398
|
: null;
|
|
1285
1399
|
const visit = (value, path, depth, layer = 0) => {
|
|
@@ -1295,7 +1409,7 @@ function sanitizePayload(
|
|
|
1295
1409
|
}
|
|
1296
1410
|
const toolArguments = jsonText && isAgentToolArgumentsPath(path);
|
|
1297
1411
|
const opaqueTransportBlock =
|
|
1298
|
-
ruleset === AGENT_MODEL_RULESET
|
|
1412
|
+
ruleset === AGENT_MODEL_RULESET || ruleset === AGENT_MODEL_RULESET_V3
|
|
1299
1413
|
? projectAgentOpaqueTransportBlock(value, path.join("."))
|
|
1300
1414
|
: null;
|
|
1301
1415
|
if (opaqueTransportBlock !== null) return opaqueTransportBlock;
|
|
@@ -1309,11 +1423,25 @@ function sanitizePayload(
|
|
|
1309
1423
|
const plain = (text) =>
|
|
1310
1424
|
sanitizeString(text, path, findings, injections, ruleset, patterns);
|
|
1311
1425
|
if (!jsonText) return plain(value);
|
|
1426
|
+
const codeText =
|
|
1427
|
+
ruleset.codeTextPolicy ===
|
|
1428
|
+
"paired-code-source-and-result-literal-scan-v1" &&
|
|
1429
|
+
isAgentCodeTextPath(payload, path, ruleset.codeTextResultTools);
|
|
1312
1430
|
const output = jsonText(value, {
|
|
1313
1431
|
layer,
|
|
1314
1432
|
objectOnly: toolArguments,
|
|
1433
|
+
codeText,
|
|
1315
1434
|
visit: (decoded, nextLayer) =>
|
|
1316
|
-
visit(
|
|
1435
|
+
visit(
|
|
1436
|
+
decoded,
|
|
1437
|
+
[...path, "$json"],
|
|
1438
|
+
// Serialized JSON has its own unchanged depth/layer limits. Its
|
|
1439
|
+
// traversal must not charge protocol nesting as decoded depth.
|
|
1440
|
+
ruleset.decodedDepthPolicy === "independent-bounded-json-depth-v1"
|
|
1441
|
+
? 0
|
|
1442
|
+
: depth + 1,
|
|
1443
|
+
nextLayer,
|
|
1444
|
+
),
|
|
1317
1445
|
plain,
|
|
1318
1446
|
equal: (left, right) => canonicalJson(left) === canonicalJson(right),
|
|
1319
1447
|
});
|
|
@@ -2291,8 +2419,18 @@ function validateAttestation(value, receipt) {
|
|
|
2291
2419
|
"projection attestation is invalid or unbound",
|
|
2292
2420
|
);
|
|
2293
2421
|
}
|
|
2294
|
-
|
|
2295
|
-
|
|
2422
|
+
normalizeLocalAttestationId(
|
|
2423
|
+
value.keyId,
|
|
2424
|
+
"attestation keyId",
|
|
2425
|
+
receipt.tenantId,
|
|
2426
|
+
"attestation",
|
|
2427
|
+
);
|
|
2428
|
+
normalizeLocalAttestationId(
|
|
2429
|
+
value.issuer,
|
|
2430
|
+
"attestation issuer",
|
|
2431
|
+
receipt.tenantId,
|
|
2432
|
+
"evolution-projector",
|
|
2433
|
+
);
|
|
2296
2434
|
return deepFreeze(cloneCanonical(value));
|
|
2297
2435
|
}
|
|
2298
2436
|
|
|
@@ -3007,7 +3145,7 @@ function validateBundleIntegrity(bundle) {
|
|
|
3007
3145
|
validateRedactionSummary(model.redactionSummary);
|
|
3008
3146
|
if (
|
|
3009
3147
|
!Array.isArray(model.injectionFindings) ||
|
|
3010
|
-
model.injectionFindings.length >
|
|
3148
|
+
model.injectionFindings.length > ruleset.maxNodes * 2
|
|
3011
3149
|
) {
|
|
3012
3150
|
throw projectionError(
|
|
3013
3151
|
EVOLUTION_PROJECTION_INVALID_CODE,
|
|
@@ -3149,12 +3287,14 @@ function validateBundleIntegrity(bundle) {
|
|
|
3149
3287
|
}
|
|
3150
3288
|
if (
|
|
3151
3289
|
ruleset === AGENT_MODEL_RULESET ||
|
|
3290
|
+
ruleset === AGENT_MODEL_RULESET_V3 ||
|
|
3152
3291
|
ruleset === AGENT_MODEL_RULESET_V2 ||
|
|
3153
3292
|
ruleset === AGENT_MODEL_RULESET_V1
|
|
3154
3293
|
) {
|
|
3155
3294
|
snapshotAgentModelRequest(model.content, {
|
|
3156
3295
|
allowStructuredArgumentText: ruleset !== AGENT_MODEL_RULESET_V1,
|
|
3157
|
-
allowOpaqueTransportBlocks:
|
|
3296
|
+
allowOpaqueTransportBlocks:
|
|
3297
|
+
ruleset === AGENT_MODEL_RULESET || ruleset === AGENT_MODEL_RULESET_V3,
|
|
3158
3298
|
});
|
|
3159
3299
|
if (
|
|
3160
3300
|
model.truncated ||
|
|
@@ -3439,6 +3579,9 @@ export class EvolutionEvidenceProjector {
|
|
|
3439
3579
|
const sourceInputDigest = digest(
|
|
3440
3580
|
payload,
|
|
3441
3581
|
"chainlesschain.evolution-raw-plaintext/v2",
|
|
3582
|
+
ruleset === AGENT_MODEL_RULESET
|
|
3583
|
+
? AGENT_MODEL_IMAGE_LIMITS.maxCanonicalRequestBytes
|
|
3584
|
+
: undefined,
|
|
3442
3585
|
);
|
|
3443
3586
|
const sourceEnvelopeDigest = digest(
|
|
3444
3587
|
input.sourceEnvelope,
|
|
@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { types } from "node:util";
|
|
3
3
|
import { captureAgentEvolutionRuntimeComposition } from "./agent-evolution-runtime-composition-brand.js";
|
|
4
4
|
import { captureAgentEvolutionIngress } from "./agent-evolution-ingress.js";
|
|
5
|
-
import {
|
|
5
|
+
import { encodeOpaqueHexId } from "./opaque-hex-id.js";
|
|
6
6
|
|
|
7
7
|
export function readEvolutionCompositionFactory(dependencies = {}) {
|
|
8
8
|
if (
|
|
@@ -44,7 +44,7 @@ export async function prepareGovernedModelTurn(
|
|
|
44
44
|
}
|
|
45
45
|
if (typeof factory !== "function")
|
|
46
46
|
throw new TypeError("Invalid evolution composition factory");
|
|
47
|
-
const runId = `${mode}-${
|
|
47
|
+
const runId = `${mode}-${encodeOpaqueHexId(
|
|
48
48
|
randomUUID().replaceAll("-", ""),
|
|
49
49
|
)}`;
|
|
50
50
|
const composition = captureAgentEvolutionRuntimeComposition(
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
flushWindowsLocalNtfsDirectory,
|
|
22
22
|
} from "./evolution-windows-directory-durability.js";
|
|
23
23
|
import { withFileLockAsync } from "../with-file-lock.js";
|
|
24
|
-
import {
|
|
24
|
+
import { encodeOpaqueHexId } from "./opaque-hex-id.js";
|
|
25
25
|
import {
|
|
26
26
|
configureEvolutionDeployment,
|
|
27
27
|
getEvolutionDeploymentStatus,
|
|
@@ -660,7 +660,7 @@ export async function initializeDefaultLocalUiEvolutionDeployment(
|
|
|
660
660
|
removeIncompleteStage(stagePath, parent);
|
|
661
661
|
fs.mkdirSync(stagePath, { mode: 0o700 });
|
|
662
662
|
privateDirectory(stagePath);
|
|
663
|
-
const tenantId = `local-ui-${
|
|
663
|
+
const tenantId = `local-ui-${encodeOpaqueHexId(
|
|
664
664
|
randomUUID().replaceAll("-", ""),
|
|
665
665
|
)}`;
|
|
666
666
|
const paths = writeDeployment(stagePath, destination, tenantId);
|
|
@@ -25,7 +25,7 @@ import { loadLocalUiEvolutionDeployment } from "./local-ui-evolution-deployment.
|
|
|
25
25
|
import { createLocalUiEvolutionFileSystem } from "./evolution-windows-directory-durability.js";
|
|
26
26
|
import {
|
|
27
27
|
formatLocalUiTenantReferenceId,
|
|
28
|
-
|
|
28
|
+
encodeOpaqueHexId,
|
|
29
29
|
} from "./opaque-hex-id.js";
|
|
30
30
|
|
|
31
31
|
const SOURCE_ENVELOPE_SCHEMA = "chainlesschain.local-ui-source-envelope/v1";
|
|
@@ -84,7 +84,7 @@ function sha256(value) {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
function sourceRefSegment(value, purpose) {
|
|
87
|
-
return
|
|
87
|
+
return encodeOpaqueHexId(
|
|
88
88
|
createHash("sha256")
|
|
89
89
|
.update(
|
|
90
90
|
`chainlesschain.local-ui-source-ref/v1\0${purpose}\0${value}`,
|
|
@@ -615,9 +615,9 @@ export async function createLocalUiEvolutionComposition({
|
|
|
615
615
|
witness,
|
|
616
616
|
},
|
|
617
617
|
evidenceIdGenerator: async () =>
|
|
618
|
-
`evidence-${
|
|
618
|
+
`evidence-${encodeOpaqueHexId(randomUUID().replaceAll("-", ""))}`,
|
|
619
619
|
ingressIdGenerator: () =>
|
|
620
|
-
`ingress-${
|
|
620
|
+
`ingress-${encodeOpaqueHexId(randomUUID().replaceAll("-", ""))}`,
|
|
621
621
|
secure: true,
|
|
622
622
|
fsImpl,
|
|
623
623
|
});
|
|
@@ -18,6 +18,14 @@ export function formatOpaqueHexId(value) {
|
|
|
18
18
|
return groups.join("-");
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
// Keep every hexadecimal nibble while preventing generated identifiers from
|
|
22
|
+
// resembling payment-card or phone numbers across their group separators.
|
|
23
|
+
export function encodeOpaqueHexId(value) {
|
|
24
|
+
return formatOpaqueHexId(value).replace(/[0-9]/gu, (digit) =>
|
|
25
|
+
String.fromCharCode(103 + Number(digit)),
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
21
29
|
export function formatLocalUiTenantReferenceId(value) {
|
|
22
30
|
const prefix = "local-ui-";
|
|
23
31
|
if (typeof value !== "string" || !value.startsWith(prefix)) return value;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Context planning estimates vision work separately from base64 transport.
|
|
2
|
+
// Providers and models meter images differently. These are planning reserves;
|
|
3
|
+
// provider usage receipts remain authoritative for token and cost settlement.
|
|
4
|
+
export const IMAGE_TOKEN_RESERVE = 8192;
|
|
5
|
+
export const LOW_DETAIL_IMAGE_TOKEN_RESERVE = 1024;
|
|
6
|
+
const BASE64_ALPHABET =
|
|
7
|
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
8
|
+
|
|
9
|
+
export function inspectCanonicalImageDataUrl(url) {
|
|
10
|
+
if (typeof url !== "string") return null;
|
|
11
|
+
const match =
|
|
12
|
+
/^data:image\/(?:png|jpeg|gif|webp);base64,([A-Za-z0-9+/]+={0,2})$/u.exec(
|
|
13
|
+
url,
|
|
14
|
+
);
|
|
15
|
+
if (!match || match[1].length % 4 !== 0) return null;
|
|
16
|
+
const data = match[1];
|
|
17
|
+
const padding = data.endsWith("==") ? 2 : data.endsWith("=") ? 1 : 0;
|
|
18
|
+
const finalValue = BASE64_ALPHABET.indexOf(data[data.length - padding - 1]);
|
|
19
|
+
if (
|
|
20
|
+
(padding === 2 && finalValue % 16 !== 0) ||
|
|
21
|
+
(padding === 1 && finalValue % 4 !== 0)
|
|
22
|
+
)
|
|
23
|
+
return null;
|
|
24
|
+
return {
|
|
25
|
+
decodedBytes: (data.length / 4) * 3 - padding,
|
|
26
|
+
encodedBytes: data.length,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function imageTransportEstimate(messages) {
|
|
31
|
+
let bytes = 0;
|
|
32
|
+
let tokens = 0;
|
|
33
|
+
for (const message of messages) {
|
|
34
|
+
if (message?.role !== "user" || !Array.isArray(message.content)) continue;
|
|
35
|
+
for (const block of message.content) {
|
|
36
|
+
if (
|
|
37
|
+
block?.type !== "image_url" ||
|
|
38
|
+
Object.keys(block).sort().join() !== "image_url,type" ||
|
|
39
|
+
!block.image_url ||
|
|
40
|
+
Object.keys(block.image_url).some(
|
|
41
|
+
(key) => !["url", "detail"].includes(key),
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
continue;
|
|
45
|
+
const { url, detail } = block.image_url;
|
|
46
|
+
if (
|
|
47
|
+
typeof url !== "string" ||
|
|
48
|
+
(detail !== undefined && !["auto", "low", "high"].includes(detail)) ||
|
|
49
|
+
!inspectCanonicalImageDataUrl(url)
|
|
50
|
+
)
|
|
51
|
+
continue;
|
|
52
|
+
// Canonical base64 data URLs are ASCII and need no JSON escaping.
|
|
53
|
+
bytes += url.length;
|
|
54
|
+
tokens +=
|
|
55
|
+
detail === "low" ? LOW_DETAIL_IMAGE_TOKEN_RESERVE : IMAGE_TOKEN_RESERVE;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return { bytes, tokens };
|
|
59
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { EXPLORATION_TOOLS } from "./task-progress-tracker.js";
|
|
3
3
|
import { isToolRecoveryPaused } from "./tool-recovery-result.js";
|
|
4
|
+
import { hostToolOutputIdentity } from "./tool-result-preview.js";
|
|
4
5
|
const MAX_FILES = 12;
|
|
5
6
|
|
|
6
7
|
function keyFor(filePath, args) {
|
|
@@ -250,7 +251,7 @@ export class ReadFileLoopGuard {
|
|
|
250
251
|
if (page.error || !page.readSpan) return page;
|
|
251
252
|
page.readRecovery = {
|
|
252
253
|
action: "continued",
|
|
253
|
-
requestedRange,
|
|
254
|
+
...(requestedRange !== undefined ? { requestedRange } : {}),
|
|
254
255
|
resumedRange: page.range,
|
|
255
256
|
};
|
|
256
257
|
newContent = true;
|
|
@@ -258,7 +259,7 @@ export class ReadFileLoopGuard {
|
|
|
258
259
|
return {
|
|
259
260
|
path: filePath,
|
|
260
261
|
fileVersion,
|
|
261
|
-
range: page.range,
|
|
262
|
+
...(page.range !== undefined ? { range: page.range } : {}),
|
|
262
263
|
hashed: args.hashed === true,
|
|
263
264
|
alreadyRead: true,
|
|
264
265
|
contentOmitted: true,
|
|
@@ -353,14 +354,16 @@ export class ReadFileLoopGuard {
|
|
|
353
354
|
} else if (
|
|
354
355
|
(tool === "run_code" || tool === "run_shell") &&
|
|
355
356
|
typeof result?.output === "string" &&
|
|
356
|
-
result.output.length >= 8000
|
|
357
|
+
(result.output.length >= 8000 ||
|
|
358
|
+
hostToolOutputIdentity(result)?.chars >= 8000)
|
|
357
359
|
) {
|
|
358
360
|
// Arbitrary code may just dump the same file again. Compare returned
|
|
359
361
|
// evidence, not code spelling or timings. Never cache/skip execution:
|
|
360
362
|
// identical stdout does not imply identical filesystem side effects.
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
.digest
|
|
363
|
+
const identity = hostToolOutputIdentity(result);
|
|
364
|
+
const fingerprint = identity
|
|
365
|
+
? `${identity.chars}:${identity.digest}`
|
|
366
|
+
: createHash("sha256").update(result.output).digest("hex");
|
|
364
367
|
if (this.largeOutputs.has(fingerprint)) this.batch.duplicates++;
|
|
365
368
|
else {
|
|
366
369
|
this.largeOutputs.add(fingerprint);
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
canonicalDigest,
|
|
3
|
+
canonicalJson,
|
|
4
|
+
} from "@chainlesschain/context-memory-kernel";
|
|
2
5
|
import {
|
|
3
6
|
contextItemsToMessages,
|
|
4
7
|
messagesToContextItems,
|
|
@@ -33,6 +36,19 @@ const historyBearing = (entry) =>
|
|
|
33
36
|
);
|
|
34
37
|
const fingerprint = (messages) =>
|
|
35
38
|
canonicalDigest(messages.map(encodePersistedMessage));
|
|
39
|
+
const sameContextItemContent = (left, right) => {
|
|
40
|
+
if (typeof left?.content === "string" || typeof right?.content === "string") {
|
|
41
|
+
return (
|
|
42
|
+
typeof left?.content === "string" &&
|
|
43
|
+
typeof right?.content === "string" &&
|
|
44
|
+
left.content === right.content
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
if (left?.contentRef === undefined || right?.contentRef === undefined) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return canonicalJson(left.contentRef) === canonicalJson(right.contentRef);
|
|
51
|
+
};
|
|
36
52
|
|
|
37
53
|
/**
|
|
38
54
|
* Origins belong to positions in the current display history, never to equal
|
|
@@ -128,7 +144,7 @@ export function createSessionHistoryOrigins() {
|
|
|
128
144
|
if (context) {
|
|
129
145
|
const originals = messagesToContextItems(
|
|
130
146
|
context.map((entry) => entry.message),
|
|
131
|
-
{ sessionId: canonical.sessionId },
|
|
147
|
+
{ sessionId: canonical.sessionId, allowExternalization: true },
|
|
132
148
|
);
|
|
133
149
|
const byDigest = new Map(
|
|
134
150
|
originals.map((item) => [item.digest, item]),
|
|
@@ -140,7 +156,9 @@ export function createSessionHistoryOrigins() {
|
|
|
140
156
|
context.slice(
|
|
141
157
|
item.sourceRef.eventSequence,
|
|
142
158
|
item.sourceRef.eventSequence +
|
|
143
|
-
contextItemsToMessages([item]
|
|
159
|
+
contextItemsToMessages([item], {
|
|
160
|
+
sessionId: canonical.sessionId,
|
|
161
|
+
}).length,
|
|
144
162
|
);
|
|
145
163
|
entries = [...canonical.outputItems]
|
|
146
164
|
.sort(
|
|
@@ -150,12 +168,14 @@ export function createSessionHistoryOrigins() {
|
|
|
150
168
|
left.itemId.localeCompare(right.itemId, "en"),
|
|
151
169
|
)
|
|
152
170
|
.flatMap((item) => {
|
|
153
|
-
const messages = contextItemsToMessages([item]
|
|
171
|
+
const messages = contextItemsToMessages([item], {
|
|
172
|
+
sessionId: canonical.sessionId,
|
|
173
|
+
});
|
|
154
174
|
const source = bySequence.get(item.sourceRef.eventSequence);
|
|
155
175
|
if (
|
|
156
176
|
item.sourceRef.store === "cli-jsonl-session" &&
|
|
157
177
|
source?.sourceRef.digest === item.sourceRef.digest &&
|
|
158
|
-
source
|
|
178
|
+
sameContextItemContent(source, item)
|
|
159
179
|
) {
|
|
160
180
|
return itemEntries(source);
|
|
161
181
|
}
|
|
@@ -77,7 +77,11 @@ function isContextCompaction(data) {
|
|
|
77
77
|
}));
|
|
78
78
|
return (
|
|
79
79
|
canonicalDigest(
|
|
80
|
-
content(
|
|
80
|
+
content(
|
|
81
|
+
contextItemsToMessages(canonical.outputItems, {
|
|
82
|
+
sessionId: canonical.sessionId,
|
|
83
|
+
}),
|
|
84
|
+
),
|
|
81
85
|
) === canonicalDigest(content(data.messages))
|
|
82
86
|
);
|
|
83
87
|
} catch {
|