@sema-agent/core 7.7.0 → 7.9.0
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/CHANGELOG.md +88 -0
- package/dist/agents/agent-transcript-tool.js +2 -2
- package/dist/agents/list-agents-tool.js +2 -3
- package/dist/agents/observer.js +2 -2
- package/dist/agents/send-message-tool.js +2 -1
- package/dist/agents/subagent-steps.js +5 -4
- package/dist/agents/subagent.d.ts +1 -1
- package/dist/agents/subagent.js +2 -3
- package/dist/core/ask-origin.d.ts +12 -1
- package/dist/core/ask-origin.js +5 -1
- package/dist/core/ask-question.js +2 -2
- package/dist/core/checkpoint-store.d.ts +64 -24
- package/dist/core/context-edit.d.ts +0 -22
- package/dist/core/context-edit.js +2 -11
- package/dist/core/engine-notice.d.ts +6 -0
- package/dist/core/fs-write-gate-policy.d.ts +7 -1
- package/dist/core/fs-write-gate-policy.js +7 -7
- package/dist/core/gate-fold.js +2 -2
- package/dist/core/gate-lanes.js +53 -26
- package/dist/core/gate-outcome.d.ts +8 -4
- package/dist/core/gate-outcome.js +2 -1
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +6 -0
- package/dist/core/hooks.d.ts +64 -33
- package/dist/core/hooks.js +1 -1
- package/dist/core/lsp.js +2 -2
- package/dist/core/mcp-server-spec.d.ts +17 -0
- package/dist/core/mcp.js +3 -1
- package/dist/core/memory-engine/tools.js +4 -12
- package/dist/core/permission-rule-consent.d.ts +29 -36
- package/dist/core/permission-rule-consent.js +110 -60
- package/dist/core/permission-rule-model.d.ts +254 -55
- package/dist/core/permission-rule-model.js +323 -43
- package/dist/core/permission-rule-org.d.ts +9 -8
- package/dist/core/permission-rule-org.js +6 -15
- package/dist/core/permission-rule-provider.d.ts +10 -6
- package/dist/core/permission-rule-provider.js +12 -8
- package/dist/core/permission-rule-session.d.ts +7 -6
- package/dist/core/permission-rule-session.js +29 -10
- package/dist/core/permission-rule-store.d.ts +40 -18
- package/dist/core/permission-rule-store.js +68 -42
- package/dist/core/permission-rule-sync.d.ts +9 -3
- package/dist/core/permission-rule-sync.js +29 -25
- package/dist/core/permission-rule-syntax.d.ts +30 -0
- package/dist/core/permission-rule-syntax.js +44 -0
- package/dist/core/permission-rules.d.ts +85 -33
- package/dist/core/permission-rules.js +104 -88
- package/dist/core/persisted-rule-arms.d.ts +56 -0
- package/dist/core/persisted-rule-arms.js +48 -0
- package/dist/core/present-plan-tool.js +3 -4
- package/dist/core/runner/active-skill-scope.js +7 -4
- package/dist/core/runner/compaction-call-options.d.ts +1 -1
- package/dist/core/runner/contracts.d.ts +46 -3
- package/dist/core/runner/permission-rule-lanes.d.ts +33 -26
- package/dist/core/runner/permission-rule-lanes.js +27 -21
- package/dist/core/runner/prepare-ask-lane.d.ts +1 -1
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +5 -4
- package/dist/core/runner/prepare-caps-and-workflow.js +16 -11
- package/dist/core/runner/prepare-defer-classify.d.ts +5 -26
- package/dist/core/runner/prepare-defer-classify.js +10 -10
- package/dist/core/runner/prepare-delegation-surface.d.ts +5 -4
- package/dist/core/runner/prepare-delegation-surface.js +15 -17
- package/dist/core/runner/prepare-gate-stations.d.ts +4 -1
- package/dist/core/runner/prepare-gate-stations.js +4 -2
- package/dist/core/runner/prepare-hands-readface.d.ts +3 -2
- package/dist/core/runner/prepare-hands-readface.js +3 -2
- package/dist/core/runner/prepare-inherited-gate.d.ts +1 -1
- package/dist/core/runner/prepare-inherited-gate.js +1 -0
- package/dist/core/runner/prepare-lsp.d.ts +4 -3
- package/dist/core/runner/prepare-lsp.js +3 -2
- package/dist/core/runner/prepare-memory-engine-session.d.ts +4 -4
- package/dist/core/runner/prepare-memory-engine-session.js +4 -2
- package/dist/core/runner/prepare-offload-wrappers.js +7 -5
- package/dist/core/runner/prepare-park-ask.d.ts +4 -0
- package/dist/core/runner/prepare-park-ask.js +4 -1
- package/dist/core/runner/prepare-project-context.d.ts +5 -23
- package/dist/core/runner/prepare-project-context.js +7 -5
- package/dist/core/runner/prepare-prompt-assembly.d.ts +1 -1
- package/dist/core/runner/prepare-protocol-tools.d.ts +5 -1
- package/dist/core/runner/prepare-protocol-tools.js +38 -21
- package/dist/core/runner/prepare-question-face.d.ts +4 -3
- package/dist/core/runner/prepare-question-face.js +5 -3
- package/dist/core/runner/prepare-run-refs.d.ts +16 -0
- package/dist/core/runner/prepare-run-refs.js +6 -0
- package/dist/core/runner/prepare-safety-scan.js +48 -2
- package/dist/core/runner/prepare-task.js +37 -19
- package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +5 -2
- package/dist/core/runner/prepare-tool-disclosure-mount.js +3 -1
- package/dist/core/runner/prepare-wiring-manifest.d.ts +4 -0
- package/dist/core/runner/prepare-wiring-manifest.js +3 -8
- package/dist/core/runner/resume-admission.d.ts +53 -0
- package/dist/core/runner/resume-admission.js +83 -0
- package/dist/core/runner/resume-apply.d.ts +50 -0
- package/dist/core/runner/resume-apply.js +184 -0
- package/dist/core/runner/resume-checkpoint-screen.d.ts +18 -0
- package/dist/core/runner/resume-checkpoint-screen.js +108 -0
- package/dist/core/runner/resume-claim.d.ts +32 -0
- package/dist/core/runner/resume-claim.js +27 -0
- package/dist/core/runner/resume-internals-and-config.d.ts +33 -0
- package/dist/core/runner/resume-internals-and-config.js +50 -0
- package/dist/core/runner/resume-policy-outcome.d.ts +31 -0
- package/dist/core/runner/resume-policy-outcome.js +127 -0
- package/dist/core/runner/resume-preflight.d.ts +40 -0
- package/dist/core/runner/resume-preflight.js +122 -0
- package/dist/core/runner/resume-review-outcome.d.ts +30 -0
- package/dist/core/runner/resume-review-outcome.js +88 -0
- package/dist/core/runner/run-harness-handlers.d.ts +46 -0
- package/dist/core/runner/run-harness-handlers.js +345 -0
- package/dist/core/runner/run-turn-boundary.d.ts +69 -0
- package/dist/core/runner/run-turn-boundary.js +694 -0
- package/dist/core/runner/runtask.d.ts +20 -0
- package/dist/core/runner/runtask.js +129 -1774
- package/dist/core/runner/session-rule-policy.js +9 -4
- package/dist/core/runner/synthetic-tools.js +5 -8
- package/dist/core/runner/tool-disclosure.d.ts +4 -0
- package/dist/core/runner/tool-disclosure.js +9 -5
- package/dist/core/runner/tool-end-body.d.ts +12 -5
- package/dist/core/runner/tool-end-body.js +8 -7
- package/dist/core/runner/tool-face-overlay.d.ts +40 -0
- package/dist/core/runner/tool-face-overlay.js +125 -0
- package/dist/core/runner/tool-output-projection.d.ts +14 -1
- package/dist/core/runner/tool-output-projection.js +24 -18
- package/dist/core/runner/turn-attachments.d.ts +2 -2
- package/dist/core/sensitive-path-policy.d.ts +3 -0
- package/dist/core/sensitive-path-policy.js +6 -5
- package/dist/core/shared-memory/tools.js +3 -6
- package/dist/core/store-contracts/checkpoint-store-contract.js +23 -0
- package/dist/core/store-contracts/permission-rule-sync-contract.js +29 -10
- package/dist/core/task-event.d.ts +10 -0
- package/dist/core/task-registry.js +4 -5
- package/dist/core/task-spec.d.ts +8 -0
- package/dist/core/tool-catalog-entries.d.ts +48 -0
- package/dist/core/tool-catalog-entries.js +174 -0
- package/dist/core/tool-conformance.d.ts +22 -0
- package/dist/core/tool-conformance.js +37 -0
- package/dist/core/tool-face.d.ts +171 -0
- package/dist/core/tool-face.js +25 -0
- package/dist/core/tool-policy.d.ts +24 -0
- package/dist/core/tool-policy.js +4 -2
- package/dist/core/tool-registry.d.ts +114 -0
- package/dist/core/tool-registry.js +114 -0
- package/dist/core/tool-result-budget.d.ts +0 -3
- package/dist/core/tool-result-budget.js +4 -3
- package/dist/core/tool-result-store.d.ts +0 -18
- package/dist/core/tool-result-store.js +2 -18
- package/dist/core/tool-roster.d.ts +459 -0
- package/dist/core/tool-roster.js +507 -0
- package/dist/core/tool-spec.d.ts +54 -3
- package/dist/core/tools.js +7 -0
- package/dist/core/wiring-manifest.d.ts +13 -0
- package/dist/core/wiring-manifest.js +2 -1
- package/dist/core/write-protect.d.ts +2 -1
- package/dist/core/write-protect.js +5 -4
- package/dist/engine/compaction/utils.d.ts +6 -0
- package/dist/engine/compaction/utils.js +19 -19
- package/dist/engine/loop/types.d.ts +6 -0
- package/dist/index.d.ts +17 -6
- package/dist/index.js +17 -6
- package/dist/orchestration/goal.js +2 -1
- package/dist/orchestration/run-spec.js +3 -5
- package/dist/orchestration/run-workflow-tool.js +2 -2
- package/dist/prompt-assembly/event-registry.js +3 -3
- package/dist/prompt-assembly/tool-catalog.d.ts +2 -2
- package/dist/stores/file/checkpoint-store.js +1 -1
- package/dist/stores/file/permission-rule-store.d.ts +28 -23
- package/dist/stores/file/permission-rule-store.js +64 -16
- package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
- package/dist/tools/fs/fs-bash.d.ts +1 -1
- package/dist/tools/fs/fs-bash.js +7 -11
- package/dist/tools/fs/fs-pdf.d.ts +1 -1
- package/dist/tools/fs/fs-read.js +2 -2
- package/dist/tools/fs/fs-search-tools.d.ts +0 -7
- package/dist/tools/fs/fs-search-tools.js +3 -16
- package/dist/tools/fs/fs-write.js +4 -6
- package/dist/tools/fs/notebook.d.ts +1 -1
- package/dist/tools/fs/repo-map.js +2 -2
- package/dist/tools/fs/safety.d.ts +3 -2
- package/dist/tools/fs/safety.js +6 -5
- package/dist/tools/monitor.js +2 -2
- package/dist/tools/scheduler-tools.js +5 -8
- package/dist/tools/task-list.js +5 -8
- package/dist/tools/todo.js +2 -2
- package/dist/tools/web.js +3 -6
- package/dist/tools/worktree.js +3 -4
- package/package.json +4 -1
- package/test/export-surface.snapshot.json +189 -17
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tool FACE vocabulary (design/388 §2.1–§2.2): the closed word sets and the small declaration
|
|
3
|
+
* shapes that describe a tool WITHOUT executing it — its display family, the parameter that names its
|
|
4
|
+
* path target, the parameter vocabulary a permission rule may speak about it, the render hints a shell
|
|
5
|
+
* may read, and the mount-condition tags the static catalog lists it under.
|
|
6
|
+
*
|
|
7
|
+
* Layer-0 vocabulary: nothing here reads an env, a deps object, or a tool instance. `ToolSpec`
|
|
8
|
+
* (tool-spec.ts) carries the declaration half of these shapes as optional fields; the static catalog
|
|
9
|
+
* (tool-catalog-entries.ts) lists every built-in's face; the effect roster (tool-roster.ts) reads the
|
|
10
|
+
* same shapes off the MOUNTED instance. One vocabulary, three readers, no second table.
|
|
11
|
+
*/
|
|
12
|
+
/** The display / dispatch family of a tool. INPUT to grouping and card pre-selection only — never an
|
|
13
|
+
* authorization source (a `"file-write"` family grants nothing; the path-confinable predicate reads
|
|
14
|
+
* {@link ToolPathTarget}, and the approval card is chosen by {@link ToolRenderHints.approvalCard}). */
|
|
15
|
+
export declare const TOOL_FAMILIES: readonly ["shell", "file-read", "file-write", "search", "web", "delegate", "plan", "scaffold", "memory", "protocol", "other"];
|
|
16
|
+
export type ToolFamily = (typeof TOOL_FAMILIES)[number];
|
|
17
|
+
/**
|
|
18
|
+
* The closed set of MOUNT-CONDITION tags a static catalog entry is listed under. The static half of the
|
|
19
|
+
* catalog carries an ARRAY (a tool can be mounted by more than one condition — TaskOutput rides both the
|
|
20
|
+
* hand band and the delegation surface); the effect roster records the ONE tag that actually fired.
|
|
21
|
+
*
|
|
22
|
+
* - `hands` — the hand band (an execution env is wired: `deps.executionEnv` / `executionEnvFactory`);
|
|
23
|
+
* - `backgroundTasks` — the background-task surface (`Monitor`);
|
|
24
|
+
* - `workflow` — the workflow tool surface (`Workflow`);
|
|
25
|
+
* - `delegation` — the union of the background-task and workflow surfaces (TaskOutput/TaskStop/
|
|
26
|
+
* AgentTranscript, SendMessage's first condition);
|
|
27
|
+
* - `hostInternals` — a host-internal seat is present (`RunInternals.parentNotify`);
|
|
28
|
+
* - `peerLane` — the peer-session lane is mounted;
|
|
29
|
+
* - `scheduler` — the env carries a scheduler daemon (the Cron family + ScheduleWakeup);
|
|
30
|
+
* - `memory` — an engine-memory / shared-memory session is wired;
|
|
31
|
+
* - `scenario` — mounted by a HOST scenario factory through `TaskSpec.tools` (core defines the tool,
|
|
32
|
+
* the host decides to mount it);
|
|
33
|
+
* - `always` — mounted on every task unless excluded (ReportBlocked/ReportFindings);
|
|
34
|
+
* - `optional` — mounted by a per-task opt-in or a wired seat (plan mode, an output schema, an
|
|
35
|
+
* offload store, a question face, a skills listing, an MCP configuration).
|
|
36
|
+
*/
|
|
37
|
+
export declare const TOOL_MOUNT_TAGS: readonly ["hands", "backgroundTasks", "workflow", "delegation", "hostInternals", "peerLane", "scheduler", "memory", "scenario", "always", "optional"];
|
|
38
|
+
export type ToolMountTag = (typeof TOOL_MOUNT_TAGS)[number];
|
|
39
|
+
import type { AssertAllKeysHandled } from "./ask-origin.js";
|
|
40
|
+
/** The closed set of specialised approval cards a shell may pre-select from a render hint. The hint is a
|
|
41
|
+
* PRE-FILTER: the shell owns each card's input schema and validates the call's full args before
|
|
42
|
+
* mounting the card (design/388 §2.5 boundary ①). */
|
|
43
|
+
export declare const TOOL_APPROVAL_CARDS: readonly ["file-edit", "file-write", "notebook-edit", "shell", "fetch", "plan", "question", "generic"];
|
|
44
|
+
export type ToolApprovalCard = (typeof TOOL_APPROVAL_CARDS)[number];
|
|
45
|
+
/** How a path-targeting tool touches its target. `read` never enters a write-confinement face. */
|
|
46
|
+
export declare const TOOL_PATH_ACCESSES: readonly ["read", "create", "edit"];
|
|
47
|
+
export type ToolPathAccess = (typeof TOOL_PATH_ACCESSES)[number];
|
|
48
|
+
/**
|
|
49
|
+
* The parameter that names this tool's filesystem target, and how the target is touched. Present ⇔ the
|
|
50
|
+
* tool can be confirmed BY PATH (write confinement, sensitive-path guards, edited-file tracking, the
|
|
51
|
+
* transcript-directory gate). `param` outranks every alias (NotebookEdit's `notebook_path` beats a decoy
|
|
52
|
+
* `file_path`). `skillScopeEligible` (default false) is the SEPARATE authorization domain of the
|
|
53
|
+
* active-skill `allowPaths` face — a confinable write tool is not automatically eligible there.
|
|
54
|
+
*/
|
|
55
|
+
export interface ToolPathTarget {
|
|
56
|
+
param: string;
|
|
57
|
+
aliases?: readonly string[];
|
|
58
|
+
access: ToolPathAccess;
|
|
59
|
+
skillScopeEligible?: true;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The parameter vocabulary a permission rule (`Tool(param:pattern)`) may name. DERIVED by default from
|
|
63
|
+
* the tool's schema: the SCALAR top-level parameters (string/number/integer/boolean and their enum/const/
|
|
64
|
+
* union forms) plus {@link ToolPathTarget.aliases}; object/array parameters never enter (a rule on them
|
|
65
|
+
* can never match — `matchParamRules` skips non-scalar values). A declaration can only NARROW the derived
|
|
66
|
+
* set; `primaryParams` defaults to the path target's `param` + aliases.
|
|
67
|
+
*/
|
|
68
|
+
export interface ToolRuleFace {
|
|
69
|
+
primaryParams?: readonly string[];
|
|
70
|
+
params?: readonly string[];
|
|
71
|
+
}
|
|
72
|
+
/** The roster's WIRE bounds on a tool name and a contract member (design/388 §2.5 / B20). Distinct from
|
|
73
|
+
* protocol-naming's `TOOL_NAME_MAX_CHARS` (64), the provider-facing bound the MCP/A2A namespacing helper
|
|
74
|
+
* budgets a MINTED name to — a minted name is always inside this wire bound by construction; a CALLER
|
|
75
|
+
* declaration is judged against it at prepare. */
|
|
76
|
+
export declare const TOOL_WIRE_NAME_MAX_CHARS = 128;
|
|
77
|
+
export declare const TOOL_CONTRACT_MAX_CHARS = 64;
|
|
78
|
+
/** The roster's wire bound on a KEY — a schema property name, a path-target `param`/alias, a rule-face param. A key is a
|
|
79
|
+
* SEMANTIC name every fence reads an argument by, so it is never truncated: a declaration over the bound is refused at
|
|
80
|
+
* the door (caller) or dropped with a disclosed reason (MCP intake), and a row carries every key exactly. */
|
|
81
|
+
export declare const TOOL_KEY_MAX_CHARS = 256;
|
|
82
|
+
/** The roster's bound on how many top-level keys one row carries (the same refuse/drop treatment). */
|
|
83
|
+
export declare const TOOL_KEYS_MAX = 1024;
|
|
84
|
+
/** Bounds every render-hint string is held to on the roster (design/388 §2.2 ④). */
|
|
85
|
+
export declare const RENDER_HINT_MAX_CHARS = 64;
|
|
86
|
+
export declare const RENDER_HINT_ACTIVITY_MAX_CHARS = 32;
|
|
87
|
+
export declare const RENDER_HINT_MAX_LIST = 16;
|
|
88
|
+
/**
|
|
89
|
+
* Declarative, template-free display hints (design/388 §2.2 ④, D-4). UNTRUSTED display input on the
|
|
90
|
+
* wire: the engine length-caps them at the roster mint; the shell strips control / newline / bidi
|
|
91
|
+
* characters before rendering. `resultCards` may only name cards in the tool's OWN namespace
|
|
92
|
+
* (`caller:<contractId>/<type>`) — engine cards (`builtin:*`, `mcp`, the refusal cards) are minted by
|
|
93
|
+
* the engine alone and a declaration naming one is refused at prepare.
|
|
94
|
+
*/
|
|
95
|
+
export interface ToolRenderHints {
|
|
96
|
+
userFacingName?: string;
|
|
97
|
+
activity?: string;
|
|
98
|
+
summaryParams?: readonly string[];
|
|
99
|
+
resultCards?: readonly string[];
|
|
100
|
+
approvalCard?: ToolApprovalCard;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* The static FACE of a tool — the subset of `ToolSpec` a catalog entry declares and a definition module
|
|
104
|
+
* spreads into its spec. Everything here is readable without an env or a deps object; the effect roster
|
|
105
|
+
* reads the same members off the mounted instance.
|
|
106
|
+
*/
|
|
107
|
+
export interface ToolFaceDeclaration {
|
|
108
|
+
family: ToolFamily;
|
|
109
|
+
effect?: import("./tool-spec.js").ToolEffect;
|
|
110
|
+
egress?: true;
|
|
111
|
+
irreversibility?: "never" | "maybe" | "always";
|
|
112
|
+
contentOrigin?: import("./tool-spec.js").ToolContentOrigin;
|
|
113
|
+
contract?: {
|
|
114
|
+
contractId: string;
|
|
115
|
+
implementationRevision: string;
|
|
116
|
+
};
|
|
117
|
+
aliases?: string[];
|
|
118
|
+
pathTarget?: ToolPathTarget;
|
|
119
|
+
ruleFace?: ToolRuleFace;
|
|
120
|
+
renderHints?: ToolRenderHints;
|
|
121
|
+
offload?: boolean;
|
|
122
|
+
offloadThresholdChars?: number;
|
|
123
|
+
compactable?: true;
|
|
124
|
+
budgetExempt?: true;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* One row of the static tool catalog (design/388 §2.1 "静态目录"). Keyed by DEFINITION identity, not by
|
|
128
|
+
* name: two definitions may share a wire name (the full and the read-only shell both answer to `Bash`),
|
|
129
|
+
* and every catalog predicate counts a name as a member when ANY entry under it matches.
|
|
130
|
+
*/
|
|
131
|
+
export interface ToolCatalogEntry {
|
|
132
|
+
/** Definition identity — unique across the catalog (`bash`, `bash-readonly`). */
|
|
133
|
+
id: string;
|
|
134
|
+
/** Wire name; may repeat across entries. */
|
|
135
|
+
name: string;
|
|
136
|
+
/** `builtin` = a core definition mounted by core or by a host factory; `synthetic` = core mints it
|
|
137
|
+
* per task with a per-task shape (the structured-output tool). */
|
|
138
|
+
source: "builtin" | "synthetic";
|
|
139
|
+
/** Where the definition lives (repo-relative), so a catalog gate can name the file. */
|
|
140
|
+
definedIn: string;
|
|
141
|
+
/** The conditions under which core (or a host scenario) mounts this definition. */
|
|
142
|
+
mountedBy: readonly ToolMountTag[];
|
|
143
|
+
/** The `details.type` cards this definition mints on `tool_end.structured`. */
|
|
144
|
+
cards: readonly string[];
|
|
145
|
+
/** The declared face — spread into the definition's `ToolSpec` by the module that owns it. */
|
|
146
|
+
face: ToolFaceDeclaration;
|
|
147
|
+
/** A `modelGate` class the default-bundle assembler stamps on this definition's default arm. */
|
|
148
|
+
modelGate?: string;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* The band-membership table over the mount tags: a host derives its hand band as the definitions listed under a
|
|
152
|
+
* TRUE row (server B-1). Every tag has a row — the fence reds `tsc` when a tag is added without one. The
|
|
153
|
+
* background-task surface is hands-derived (`backgroundTaskToolsActive` requires the shell), so a definition
|
|
154
|
+
* mounted by it alone is a band member that is NOT dual-use.
|
|
155
|
+
*/
|
|
156
|
+
export declare const MOUNT_TAG_IN_HANDS_BAND: {
|
|
157
|
+
readonly hands: true;
|
|
158
|
+
readonly backgroundTasks: true;
|
|
159
|
+
readonly workflow: false;
|
|
160
|
+
readonly delegation: true;
|
|
161
|
+
readonly hostInternals: true;
|
|
162
|
+
readonly peerLane: true;
|
|
163
|
+
readonly scheduler: false;
|
|
164
|
+
readonly memory: false;
|
|
165
|
+
readonly scenario: false;
|
|
166
|
+
readonly always: false;
|
|
167
|
+
readonly optional: false;
|
|
168
|
+
};
|
|
169
|
+
export type HandsBandTableCoversEveryMountTag = AssertAllKeysHandled<Exclude<ToolMountTag, keyof typeof MOUNT_TAG_IN_HANDS_BAND>>;
|
|
170
|
+
/** The tags whose definitions form the hand band a host derives (server B-1 `HANDS_BAND_TAGS`). */
|
|
171
|
+
export declare const HANDS_BAND_TAGS: ReadonlySet<ToolMountTag>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const TOOL_FAMILIES = ["shell", "file-read", "file-write", "search", "web", "delegate", "plan", "scaffold", "memory", "protocol", "other"];
|
|
2
|
+
export const TOOL_MOUNT_TAGS = ["hands", "backgroundTasks", "workflow", "delegation", "hostInternals", "peerLane", "scheduler", "memory", "scenario", "always", "optional"];
|
|
3
|
+
export const TOOL_APPROVAL_CARDS = ["file-edit", "file-write", "notebook-edit", "shell", "fetch", "plan", "question", "generic"];
|
|
4
|
+
export const TOOL_PATH_ACCESSES = ["read", "create", "edit"];
|
|
5
|
+
export const TOOL_WIRE_NAME_MAX_CHARS = 128;
|
|
6
|
+
export const TOOL_CONTRACT_MAX_CHARS = 64;
|
|
7
|
+
export const TOOL_KEY_MAX_CHARS = 256;
|
|
8
|
+
export const TOOL_KEYS_MAX = 1024;
|
|
9
|
+
export const RENDER_HINT_MAX_CHARS = 64;
|
|
10
|
+
export const RENDER_HINT_ACTIVITY_MAX_CHARS = 32;
|
|
11
|
+
export const RENDER_HINT_MAX_LIST = 16;
|
|
12
|
+
export const MOUNT_TAG_IN_HANDS_BAND = {
|
|
13
|
+
hands: true,
|
|
14
|
+
backgroundTasks: true,
|
|
15
|
+
workflow: false,
|
|
16
|
+
delegation: true,
|
|
17
|
+
hostInternals: true,
|
|
18
|
+
peerLane: true,
|
|
19
|
+
scheduler: false,
|
|
20
|
+
memory: false,
|
|
21
|
+
scenario: false,
|
|
22
|
+
always: false,
|
|
23
|
+
optional: false,
|
|
24
|
+
};
|
|
25
|
+
export const HANDS_BAND_TAGS = new Set(Object.keys(MOUNT_TAG_IN_HANDS_BAND).filter((t) => MOUNT_TAG_IN_HANDS_BAND[t]));
|
|
@@ -1,10 +1,34 @@
|
|
|
1
1
|
import type { AskOrigin } from "./ask-origin.js";
|
|
2
2
|
import type { Settlement } from "./gate-outcome.js";
|
|
3
3
|
/** A tool call presented to a policy before it executes. */
|
|
4
|
+
/** design/388 B6 — the per-call face (see {@link ToolCallRequest.face}). */
|
|
5
|
+
export interface ToolCallFace {
|
|
6
|
+
family: import("./tool-face.js").ToolFamily;
|
|
7
|
+
pathTarget?: {
|
|
8
|
+
param: string;
|
|
9
|
+
aliases: readonly string[];
|
|
10
|
+
access: "read" | "create" | "edit";
|
|
11
|
+
skillScopeEligible: boolean;
|
|
12
|
+
};
|
|
13
|
+
capabilityId: string;
|
|
14
|
+
contractId: string;
|
|
15
|
+
shapeDigest: string;
|
|
16
|
+
implementationRevision: string;
|
|
17
|
+
}
|
|
4
18
|
export interface ToolCallRequest {
|
|
5
19
|
toolName: string;
|
|
6
20
|
args: unknown;
|
|
7
21
|
toolCallId: string;
|
|
22
|
+
/**
|
|
23
|
+
* design/388 B6 (additive) — the mounted tool's FACE as the leg's roster minted it: the declared path target
|
|
24
|
+
* (how the target may be confirmed by path), the display family, and the engine-minted identity
|
|
25
|
+
* (`capabilityId` / `contractId` / `shapeDigest`) an exemption store keys on. Stamped at the gate entry
|
|
26
|
+
* from the live roster, so identity follows the OBJECT the call dispatches to — a caller tool that merely
|
|
27
|
+
* took a built-in's name carries its own face, never the built-in's. ABSENT when a policy is invoked
|
|
28
|
+
* outside a Runner (a bare producer): a path-confining face then reads the catalog's declaration for the
|
|
29
|
+
* NAME (the pre-388 posture, never wider), and a skill-scope face treats the write as unconfirmable.
|
|
30
|
+
*/
|
|
31
|
+
face?: ToolCallFace;
|
|
8
32
|
/**
|
|
9
33
|
* RB-108 — the LIVE working directory this call's RELATIVE path arguments will actually resolve
|
|
10
34
|
* against, read at adjudication time from the same tracked `cwdRef` the fs hand tools resolve with
|
package/dist/core/tool-policy.js
CHANGED
|
@@ -4,6 +4,7 @@ import { brandPolicyAskClass } from "./ask-class.js";
|
|
|
4
4
|
import { sanitizeAutoModeArmingRecipe } from "./auto-mode-arming.js";
|
|
5
5
|
import { join, normalize as normalizePath, posix as posixPath, sep, win32 as winPath } from "node:path";
|
|
6
6
|
import { BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName } from "../tools/fs/index.js";
|
|
7
|
+
import { protectivePathTargetOf } from "./tool-registry.js";
|
|
7
8
|
import { boundInputHashOf } from "./canonical-json.js";
|
|
8
9
|
import { delimitUntrusted, inlineUntrusted, REVIEWER_NOTE_MAX_BODY } from "./untrusted-text.js";
|
|
9
10
|
import { isNamespacedCoveringRuleName, namespacedRuleNameCovers, parsePermissionRule } from "./permission-rules.js";
|
|
@@ -847,8 +848,9 @@ export function createTranscriptIntegrityPolicy(opts) {
|
|
|
847
848
|
? "the shell's working directory is inside the transcript directory and this is not a single read-only command (fail-closed)"
|
|
848
849
|
: "the command references the transcript directory and is not a single read-only command (fail-closed)");
|
|
849
850
|
}
|
|
850
|
-
|
|
851
|
-
|
|
851
|
+
const writeTarget = protectivePathTargetOf(req);
|
|
852
|
+
if (writeTarget !== undefined && writeTarget.access !== "read") {
|
|
853
|
+
const p = writeTargetPath(req);
|
|
852
854
|
if (typeof p === "string" && inProtectedDir(p, req.cwd)) {
|
|
853
855
|
return askReason(`"${p}" is inside the session-transcript directory`);
|
|
854
856
|
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The static tool catalog's READ FACE (design/388 §2.1): `describeToolCatalog()` and the predicates
|
|
3
|
+
* every former name table is now DERIVED from. Readable without an env, a deps object or a tool
|
|
4
|
+
* instance — a host predicts a leg's roster from it (`predictMountedToolNames`), a policy module
|
|
5
|
+
* derives its covered set from it, a shell renders it.
|
|
6
|
+
*
|
|
7
|
+
* Every predicate here answers over DEFINITIONS and folds to names with "any definition under this
|
|
8
|
+
* name matches" — the rule that pins the two fail-open shapes a per-name table had (one name, two
|
|
9
|
+
* definitions; the table could only hold one).
|
|
10
|
+
*
|
|
11
|
+
* Layer-0 vocabulary: depends on the leaf catalog and the face vocabulary only.
|
|
12
|
+
*/
|
|
13
|
+
import { type ToolCatalogEntry, type ToolMountTag, type ToolPathAccess } from "./tool-face.js";
|
|
14
|
+
/** The whole static catalog, one frozen row per definition (design/388 §2.1 `describeToolCatalog()`).
|
|
15
|
+
* Replaces the retired name-keyed exports `HAND_TOOL_EFFECTS` / `DEFAULT_BUDGET_EXEMPT_TOOLS` /
|
|
16
|
+
* `COMPACTABLE_TOOLS`: filter this instead (`e.mountedBy.includes("hands")`, `e.face.budgetExempt`,
|
|
17
|
+
* `e.face.compactable`). */
|
|
18
|
+
export declare function describeToolCatalog(): readonly ToolCatalogEntry[];
|
|
19
|
+
/** Every definition under a wire name (a name may carry more than one — the two shells). */
|
|
20
|
+
export declare function catalogEntriesNamed(name: string): readonly ToolCatalogEntry[];
|
|
21
|
+
/** Every wire name the catalog knows, aliases included (a set — the two shells fold to one name). */
|
|
22
|
+
export declare function catalogToolNames(): ReadonlySet<string>;
|
|
23
|
+
/** A-11/12/13/14 — tools this engine can CONFINE BY PATH on a write: `pathTarget.access ≠ read`.
|
|
24
|
+
* Today {Write, Edit, NotebookEdit}. */
|
|
25
|
+
export declare function pathConfinableWriteToolNames(): ReadonlySet<string>;
|
|
26
|
+
/** A-11 (the SECOND authorization domain) — the active-skill `allowPaths` face: confinable AND the
|
|
27
|
+
* definition opted into skill scoping. Today {Write, Edit} — NotebookEdit is deliberately outside. */
|
|
28
|
+
export declare function skillScopeWriteToolNames(): ReadonlySet<string>;
|
|
29
|
+
/** A-8 — every definition that names a path target at all (read or write): the file-tool glob lane. */
|
|
30
|
+
export declare function pathTargetingToolNames(): ReadonlySet<string>;
|
|
31
|
+
/** A-10 — the micro-compaction whitelist (`compactable: true`). */
|
|
32
|
+
export declare function compactableToolNames(): ReadonlySet<string>;
|
|
33
|
+
/** A-5 — the aggregate-budget exemptions (`budgetExempt: true`). */
|
|
34
|
+
export declare function budgetExemptToolNames(): ReadonlySet<string>;
|
|
35
|
+
/** The value a call's args carry under a path target: `param` first, then each alias, first non-empty string wins. */
|
|
36
|
+
export declare function pathTargetValue(args: unknown, pt: {
|
|
37
|
+
param: string;
|
|
38
|
+
aliases?: readonly string[];
|
|
39
|
+
}): string | undefined;
|
|
40
|
+
/** The path target of a wire name — the FIRST definition's (every definition under one name declares
|
|
41
|
+
* the same target; the conformance test pins that). */
|
|
42
|
+
/** A gated call as every fence sees it: the wire name, the args, and the OBJECT face a prepared leg stamped on the
|
|
43
|
+
* request (absent on a BARE request — a policy invoked outside a Runner). */
|
|
44
|
+
export interface ToolCallLike {
|
|
45
|
+
toolName: string;
|
|
46
|
+
args: unknown;
|
|
47
|
+
face?: {
|
|
48
|
+
pathTarget?: {
|
|
49
|
+
param: string;
|
|
50
|
+
aliases?: readonly string[];
|
|
51
|
+
access: ToolPathAccess;
|
|
52
|
+
};
|
|
53
|
+
} | undefined;
|
|
54
|
+
}
|
|
55
|
+
type CallPathTarget = {
|
|
56
|
+
param: string;
|
|
57
|
+
aliases?: readonly string[];
|
|
58
|
+
access: ToolPathAccess;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* design/388 B6/B17 — the path target a PROTECTIVE fence reads (a deny-list judging a write's target: sensitive paths,
|
|
62
|
+
* frozen paths, write protection, the transcript gate; edit tracking): the object face's own declaration first, the
|
|
63
|
+
* catalog's declaration for the NAME as the FLOOR — for a bare request (a policy invoked outside a Runner) and for a
|
|
64
|
+
* face that declares none. Reading the catalog for an undeclared same-name tool can only TIGHTEN a deny-list (it adds
|
|
65
|
+
* a slot to judge — the pre-388 posture, never wider), which is exactly why this floor is wrong for a grant.
|
|
66
|
+
*/
|
|
67
|
+
export declare function protectivePathTargetOf(call: ToolCallLike): CallPathTarget | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* The path target a CONTAINMENT fence reads (a grant admitting a write BY its path: session `allowDirs`, the fs-write
|
|
70
|
+
* gate's accept/exempt dirs; the active-skill allowPaths face reads its own eligibility bit the same way): the object
|
|
71
|
+
* face's OWN declaration only — a same-name tool that declares no path target is an UNCONFIRMABLE write (the catalog's
|
|
72
|
+
* slot may not be the one it writes; a decoy in that slot would buy an admission), so the fence fails closed. A BARE
|
|
73
|
+
* request (no face at all — a policy invoked outside a Runner) reads the catalog for the name: the pre-388 reading, the
|
|
74
|
+
* documented migration seam for bare producers.
|
|
75
|
+
*/
|
|
76
|
+
export declare function declaredPathTargetOf(call: ToolCallLike): CallPathTarget | undefined;
|
|
77
|
+
/** Is this call a write a PROTECTIVE fence judges (a protected target whose access ≠ read)? The name sets are its static view. */
|
|
78
|
+
export declare function isProtectedWrite(call: ToolCallLike): boolean;
|
|
79
|
+
/** Is this call a write a CONTAINMENT fence may ADMIT by its path (a declared target whose access ≠ read)? */
|
|
80
|
+
export declare function isDeclaredWrite(call: ToolCallLike): boolean;
|
|
81
|
+
/** design/388 A-18 — the file-op access a compaction summary records for a LIVE tool name: only the FILE families'
|
|
82
|
+
* path targets name a file (a search tool's `path` is a search ROOT, not a file the model read); every other name
|
|
83
|
+
* records nothing (retired spellings in persisted transcripts read the frozen history table at the call site). */
|
|
84
|
+
export declare function fileOpAccessOf(name: string): ToolPathAccess | undefined;
|
|
85
|
+
export declare function pathTargetOf(name: string): ToolCatalogEntry["face"]["pathTarget"];
|
|
86
|
+
/**
|
|
87
|
+
* The rule vocabulary of a wire name from the STATIC catalog: `primaryParams` = the declared primaries, else
|
|
88
|
+
* the path target's `param` + aliases; `params` = the declared vocabulary, else the path target's names —
|
|
89
|
+
* and UNDEFINED when the catalog cannot know the full vocabulary (a definition whose schema is built inside
|
|
90
|
+
* its factory and declares no `ruleFace.params`): the static half never claims a vocabulary it has not
|
|
91
|
+
* read, so the rule compiler judges only what it knows and the leg's roster (which reads the schema)
|
|
92
|
+
* judges the rest. `undefined` as a whole for a name with nothing to say.
|
|
93
|
+
*/
|
|
94
|
+
export declare function catalogRuleFaceOf(name: string): {
|
|
95
|
+
primaryParams: string[];
|
|
96
|
+
params?: string[];
|
|
97
|
+
} | undefined;
|
|
98
|
+
/** A-1 / server B-1 — the hand band's declared effects by name (any `hands` definition; the WRITE shell
|
|
99
|
+
* wins the name when both are listed, matching the by-name table this replaces — the read-only shell's
|
|
100
|
+
* own instance carries `effect: "read"` and the effect roster reports THAT). */
|
|
101
|
+
export declare function handBandEffects(): ReadonlyMap<string, NonNullable<ToolCatalogEntry["face"]["effect"]>>;
|
|
102
|
+
/** A-3 / L4 — every `details.type` card the engine owns: the catalog's per-definition cards plus the
|
|
103
|
+
* engine-minted ones (protocol channels, fs refusals). */
|
|
104
|
+
export declare function engineCardTypes(): ReadonlySet<string>;
|
|
105
|
+
/**
|
|
106
|
+
* L3 — the STATIC PREDICTION of a leg's core-mounted names for a set of active mount conditions:
|
|
107
|
+
* every definition listed under at least one active tag. `scenario` and `optional` definitions mount
|
|
108
|
+
* only when the vector names their tag (a host factory / a per-task opt-in decides them). Names are
|
|
109
|
+
* folded (the two shells predict one `Bash`).
|
|
110
|
+
*/
|
|
111
|
+
export declare function predictMountedToolNames(active: ReadonlySet<ToolMountTag>): ReadonlySet<string>;
|
|
112
|
+
/** The closed set as a Set, for callers that validate a tag read off the wire. */
|
|
113
|
+
export declare const TOOL_MOUNT_TAG_SET: ReadonlySet<string>;
|
|
114
|
+
export { HANDS_BAND_TAGS, MOUNT_TAG_IN_HANDS_BAND } from "./tool-face.js";
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { TOOL_MOUNT_TAGS } from "./tool-face.js";
|
|
2
|
+
import { ENGINE_CARDS, TOOL_CATALOG_ENTRIES } from "./tool-catalog-entries.js";
|
|
3
|
+
export function describeToolCatalog() {
|
|
4
|
+
return TOOL_CATALOG_ENTRIES;
|
|
5
|
+
}
|
|
6
|
+
export function catalogEntriesNamed(name) {
|
|
7
|
+
return TOOL_CATALOG_ENTRIES.filter((e) => e.name === name);
|
|
8
|
+
}
|
|
9
|
+
export function catalogToolNames() {
|
|
10
|
+
const out = new Set();
|
|
11
|
+
for (const e of TOOL_CATALOG_ENTRIES) {
|
|
12
|
+
out.add(e.name);
|
|
13
|
+
for (const a of e.face.aliases ?? [])
|
|
14
|
+
out.add(a);
|
|
15
|
+
}
|
|
16
|
+
return out;
|
|
17
|
+
}
|
|
18
|
+
const names = (pred) => {
|
|
19
|
+
const out = new Set();
|
|
20
|
+
for (const e of TOOL_CATALOG_ENTRIES)
|
|
21
|
+
if (pred(e))
|
|
22
|
+
out.add(e.name);
|
|
23
|
+
return out;
|
|
24
|
+
};
|
|
25
|
+
export function pathConfinableWriteToolNames() {
|
|
26
|
+
return names((e) => e.face.pathTarget !== undefined && e.face.pathTarget.access !== "read");
|
|
27
|
+
}
|
|
28
|
+
export function skillScopeWriteToolNames() {
|
|
29
|
+
return names((e) => e.face.pathTarget !== undefined && e.face.pathTarget.access !== "read" && e.face.pathTarget.skillScopeEligible === true);
|
|
30
|
+
}
|
|
31
|
+
export function pathTargetingToolNames() {
|
|
32
|
+
return names((e) => e.face.pathTarget !== undefined);
|
|
33
|
+
}
|
|
34
|
+
export function compactableToolNames() {
|
|
35
|
+
return names((e) => e.face.compactable === true);
|
|
36
|
+
}
|
|
37
|
+
export function budgetExemptToolNames() {
|
|
38
|
+
return names((e) => e.face.budgetExempt === true);
|
|
39
|
+
}
|
|
40
|
+
export function pathTargetValue(args, pt) {
|
|
41
|
+
if (args === null || typeof args !== "object")
|
|
42
|
+
return undefined;
|
|
43
|
+
const a = args;
|
|
44
|
+
for (const k of [pt.param, ...(pt.aliases ?? [])]) {
|
|
45
|
+
const v = a[k];
|
|
46
|
+
if (typeof v === "string" && v.length > 0)
|
|
47
|
+
return v;
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
export function protectivePathTargetOf(call) {
|
|
52
|
+
return call.face?.pathTarget ?? pathTargetOf(call.toolName);
|
|
53
|
+
}
|
|
54
|
+
export function declaredPathTargetOf(call) {
|
|
55
|
+
return call.face !== undefined ? call.face.pathTarget : pathTargetOf(call.toolName);
|
|
56
|
+
}
|
|
57
|
+
export function isProtectedWrite(call) {
|
|
58
|
+
const pt = protectivePathTargetOf(call);
|
|
59
|
+
return pt !== undefined && pt.access !== "read";
|
|
60
|
+
}
|
|
61
|
+
export function isDeclaredWrite(call) {
|
|
62
|
+
const pt = declaredPathTargetOf(call);
|
|
63
|
+
return pt !== undefined && pt.access !== "read";
|
|
64
|
+
}
|
|
65
|
+
export function fileOpAccessOf(name) {
|
|
66
|
+
for (const e of TOOL_CATALOG_ENTRIES) {
|
|
67
|
+
if (e.name === name && (e.face.family === "file-read" || e.face.family === "file-write") && e.face.pathTarget !== undefined)
|
|
68
|
+
return e.face.pathTarget.access;
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
export function pathTargetOf(name) {
|
|
73
|
+
for (const e of TOOL_CATALOG_ENTRIES)
|
|
74
|
+
if (e.name === name && e.face.pathTarget !== undefined)
|
|
75
|
+
return e.face.pathTarget;
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
export function catalogRuleFaceOf(name) {
|
|
79
|
+
for (const e of TOOL_CATALOG_ENTRIES) {
|
|
80
|
+
if (e.name !== name)
|
|
81
|
+
continue;
|
|
82
|
+
const pt = e.face.pathTarget;
|
|
83
|
+
const primary = e.face.ruleFace?.primaryParams ?? (pt !== undefined ? [pt.param, ...(pt.aliases ?? [])] : []);
|
|
84
|
+
const params = e.face.ruleFace?.params ?? (pt !== undefined ? [pt.param, ...(pt.aliases ?? [])] : undefined);
|
|
85
|
+
if (params === undefined && primary.length === 0)
|
|
86
|
+
continue;
|
|
87
|
+
return { primaryParams: [...primary], ...(params !== undefined ? { params: [...new Set([...params, ...primary])] } : {}) };
|
|
88
|
+
}
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
export function handBandEffects() {
|
|
92
|
+
const out = new Map();
|
|
93
|
+
for (const e of TOOL_CATALOG_ENTRIES) {
|
|
94
|
+
if (!e.mountedBy.includes("hands"))
|
|
95
|
+
continue;
|
|
96
|
+
const eff = e.face.effect ?? "write";
|
|
97
|
+
const prior = out.get(e.name);
|
|
98
|
+
if (prior === undefined || prior === "read")
|
|
99
|
+
out.set(e.name, eff);
|
|
100
|
+
}
|
|
101
|
+
return out;
|
|
102
|
+
}
|
|
103
|
+
export function engineCardTypes() {
|
|
104
|
+
const out = new Set(Object.keys(ENGINE_CARDS));
|
|
105
|
+
for (const e of TOOL_CATALOG_ENTRIES)
|
|
106
|
+
for (const card of e.cards)
|
|
107
|
+
out.add(card);
|
|
108
|
+
return out;
|
|
109
|
+
}
|
|
110
|
+
export function predictMountedToolNames(active) {
|
|
111
|
+
return names((e) => e.mountedBy.some((t) => active.has(t)));
|
|
112
|
+
}
|
|
113
|
+
export const TOOL_MOUNT_TAG_SET = new Set(TOOL_MOUNT_TAGS);
|
|
114
|
+
export { HANDS_BAND_TAGS, MOUNT_TAG_IN_HANDS_BAND } from "./tool-face.js";
|
|
@@ -46,8 +46,5 @@ export interface AggregateBudgetOptions {
|
|
|
46
46
|
results: number;
|
|
47
47
|
}) => void;
|
|
48
48
|
}
|
|
49
|
-
/** Default exemptions: tools whose result is self-bounded (read_file errors at its own token cap; the
|
|
50
|
-
* offload reader pages small slices). grep/bash/glob/web_fetch/MCP are the risk sources, NOT exempt. */
|
|
51
|
-
export declare const DEFAULT_BUDGET_EXEMPT_TOOLS: ReadonlySet<string>;
|
|
52
49
|
/** Cap each over-budget turn-batch (run of consecutive tool_result messages). Request-only; see file docs. */
|
|
53
50
|
export declare function capAggregateToolResults(messages: AgentMessage[], opts: AggregateBudgetOptions): Promise<AgentMessage[]>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isToolResult } from "./message-utils.js";
|
|
2
|
-
import { buildPreview, buildToolResultRef,
|
|
2
|
+
import { buildPreview, buildToolResultRef, PERSISTED_OUTPUT_PREFIX, toolResultContentSegment, toolResultProvenanceOf, } from "./tool-result-store.js";
|
|
3
|
+
import { budgetExemptToolNames } from "./tool-registry.js";
|
|
3
4
|
export const AGGREGATE_TOOL_RESULT_BUDGET_CHARS = 200_000;
|
|
4
5
|
const HEAD = 1_000;
|
|
5
6
|
const TAIL = 1_000;
|
|
@@ -33,10 +34,10 @@ function truncationPreview(full, head = HEAD, tail = TAIL) {
|
|
|
33
34
|
`…[${total} chars total; ${tailStart - head} omitted to fit the per-turn result budget — re-run with a narrower query to see the rest.]\n` +
|
|
34
35
|
`${full.slice(tailStart)}`);
|
|
35
36
|
}
|
|
36
|
-
|
|
37
|
+
const CATALOG_BUDGET_EXEMPT_TOOLS = budgetExemptToolNames();
|
|
37
38
|
export async function capAggregateToolResults(messages, opts) {
|
|
38
39
|
const budget = opts.budgetChars ?? AGGREGATE_TOOL_RESULT_BUDGET_CHARS;
|
|
39
|
-
const exempt = opts.exemptTools ??
|
|
40
|
+
const exempt = opts.exemptTools ?? CATALOG_BUDGET_EXEMPT_TOOLS;
|
|
40
41
|
let out;
|
|
41
42
|
let i = 0;
|
|
42
43
|
while (i < messages.length) {
|
|
@@ -446,24 +446,6 @@ export declare function offloadPagebackHint(ref: string, form: "preview" | "clea
|
|
|
446
446
|
export declare const PERSISTED_OUTPUT_PREFIX = "<persisted-output ref=";
|
|
447
447
|
/** Default per-result offload threshold (chars). ~5K tokens; configurable globally or per tool. */
|
|
448
448
|
export declare const DEFAULT_TOOL_RESULT_THRESHOLD_CHARS = 20000;
|
|
449
|
-
/**
|
|
450
|
-
* CC 198 per-tool persistence thresholds, mirrored for the first-party mounts (PARITY-SPOT-USAGE-CONSTANTS
|
|
451
|
-
* 2026-07-10 F1/F2). CC's GIa framework (pretty.js:286716-286721) resolves each tool's persist threshold as
|
|
452
|
-
* `min(maxResultSizeChars, w6t=50000)`:
|
|
453
|
-
* - Read declares `maxResultSizeChars: 1/0` (:478260) → **never persisted**. Read already owns its bound
|
|
454
|
-
* (25K-token first-page auto-pagination) and the aggregate budget exempts it — wrapping it in offload
|
|
455
|
-
* re-truncated a page the tool had already sized (the F1 two-layer inconsistency). Structural exemption:
|
|
456
|
-
* applies even when a deployment sets an explicit global threshold.
|
|
457
|
-
* - Bash 30000 (:335231) / Grep 20000 (:333220) / Monitor 1e4 (:450030); everything else first-party
|
|
458
|
-
* declares 1e5 (Agent :453402, Glob :333570, TaskOutput :458260, …) → min(1e5, 50000) = 50000.
|
|
459
|
-
* Unknown tools keep the deployment default ({@link DEFAULT_TOOL_RESULT_THRESHOLD_CHARS}) — we deliberately
|
|
460
|
-
* do NOT mirror KIa's bare `$xa=400000` undeclared-tool fallback: our aggregate budget is 200K chars, so a
|
|
461
|
-
* 400K inline result is unrepresentable anyway.
|
|
462
|
-
*/
|
|
463
|
-
export declare function firstPartyOffloadPolicy(toolName: string): {
|
|
464
|
-
offload?: boolean;
|
|
465
|
-
offloadThresholdChars?: number;
|
|
466
|
-
};
|
|
467
449
|
/** Head+tail preview of an offloaded result, pointing at {@link OFFLOAD_TOOL_NAME} via `ref`. Exported so
|
|
468
450
|
* the per-message aggregate budget (design/64 §17.2) produces the SAME preview format (deterministic →
|
|
469
451
|
* byte-identical across queries → prompt-cache safe).
|
|
@@ -4,6 +4,7 @@ import { uuidv7 } from "../engine/session/uuid.js";
|
|
|
4
4
|
import { defineTool, errorResult } from "./tools.js";
|
|
5
5
|
import { deliverEngineNotice } from "./types.js";
|
|
6
6
|
import { TOOL_SEARCH_NAME } from "./runner/tool-disclosure.js";
|
|
7
|
+
import { toolFace } from "./tool-catalog-entries.js";
|
|
7
8
|
export const TOOL_RESULT_REF_CONFLICT_CODE = "tool_result.ref_conflict";
|
|
8
9
|
export class ToolResultRefConflictError extends Error {
|
|
9
10
|
ref;
|
|
@@ -202,22 +203,6 @@ export function offloadPagebackHint(ref, form, reachableTools) {
|
|
|
202
203
|
}
|
|
203
204
|
export const PERSISTED_OUTPUT_PREFIX = "<persisted-output ref=";
|
|
204
205
|
export const DEFAULT_TOOL_RESULT_THRESHOLD_CHARS = 20_000;
|
|
205
|
-
export function firstPartyOffloadPolicy(toolName) {
|
|
206
|
-
switch (toolName) {
|
|
207
|
-
case "Read":
|
|
208
|
-
return { offload: false };
|
|
209
|
-
case "Write":
|
|
210
|
-
return { offload: false };
|
|
211
|
-
case "Bash":
|
|
212
|
-
return { offloadThresholdChars: 30_000 };
|
|
213
|
-
case "Grep":
|
|
214
|
-
return { offloadThresholdChars: 20_000 };
|
|
215
|
-
case "Monitor":
|
|
216
|
-
return { offloadThresholdChars: 10_000 };
|
|
217
|
-
default:
|
|
218
|
-
return { offloadThresholdChars: 50_000 };
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
206
|
const PREVIEW_HEAD_CHARS = 1_000;
|
|
222
207
|
const PREVIEW_TAIL_CHARS = 1_000;
|
|
223
208
|
const READ_DEFAULT_LIMIT = 4_000;
|
|
@@ -398,7 +383,7 @@ async function offloadOversizedDetailStrings(details, store, thresholdChars, ses
|
|
|
398
383
|
export function createReadToolResultTool(store) {
|
|
399
384
|
return defineTool({
|
|
400
385
|
name: OFFLOAD_TOOL_NAME,
|
|
401
|
-
|
|
386
|
+
...toolFace("read-tool-result"),
|
|
402
387
|
description: `Read the full content of a tool result that was too large and persisted (you saw it as ` +
|
|
403
388
|
`<persisted-output ref="..."> with a preview). Pass the ref; use offset/limit to page through it.`,
|
|
404
389
|
parameters: Type.Object({
|
|
@@ -406,7 +391,6 @@ export function createReadToolResultTool(store) {
|
|
|
406
391
|
offset: Type.Optional(Type.Number({ description: "Char offset to start at (default 0)." })),
|
|
407
392
|
limit: Type.Optional(Type.Number({ description: `Max chars to return (default ${READ_DEFAULT_LIMIT}, capped ${READ_MAX_LIMIT}).` })),
|
|
408
393
|
}),
|
|
409
|
-
effect: "read",
|
|
410
394
|
execute: async (args) => {
|
|
411
395
|
const { ref, offset, limit } = args;
|
|
412
396
|
const off = Math.max(0, intOr(offset, 0));
|