@sema-agent/core 7.53.0 → 7.54.1
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 +291 -1
- package/LICENSE +3 -1
- package/dist/agents/peer-session-drain.d.ts +0 -1
- package/dist/agents/peer-session-drain.js +0 -2
- package/dist/agents/send-message-tool.js +3 -4
- package/dist/agents/subagent.d.ts +3 -5
- package/dist/agents/subagent.js +18 -11
- package/dist/agents/tool-filter.d.ts +7 -4
- package/dist/agents/tool-filter.js +7 -3
- package/dist/core/a2a.js +4 -2
- package/dist/core/allow-entry.d.ts +1 -0
- package/dist/core/allow-entry.js +1 -0
- package/dist/core/approval-object.d.ts +87 -0
- package/dist/core/approval-object.js +85 -0
- package/dist/core/arg-summary.d.ts +3 -2
- package/dist/core/arg-summary.js +17 -11
- package/dist/core/ask-origin.d.ts +43 -27
- package/dist/core/ask-origin.js +20 -11
- package/dist/core/ask-question.d.ts +0 -1
- package/dist/core/ask-question.js +4 -67
- package/dist/core/ask-unresolvable-notice.d.ts +3 -2
- package/dist/core/auto-compaction.d.ts +49 -50
- package/dist/core/auto-compaction.js +41 -51
- package/dist/core/auto-mode-prompt.d.ts +4 -2
- package/dist/core/auto-mode-prompt.js +4 -3
- package/dist/core/canonical-json.d.ts +69 -0
- package/dist/core/canonical-json.js +130 -8
- package/dist/core/checkpoint-requirements.d.ts +13 -7
- package/dist/core/checkpoint-requirements.js +4 -1
- package/dist/core/checkpoint-store.d.ts +33 -18
- package/dist/core/checkpoint-store.js +5 -4
- package/dist/core/child-clamp-seats.d.ts +45 -6
- package/dist/core/child-clamp-seats.js +56 -4
- package/dist/core/consolidate-scope.d.ts +1 -1
- package/dist/core/cross-boundary-taint.d.ts +213 -0
- package/dist/core/cross-boundary-taint.js +196 -0
- package/dist/core/decision-receipt.d.ts +44 -1
- package/dist/core/decision-receipt.js +16 -0
- package/dist/core/effective-path-target.d.ts +3 -0
- package/dist/core/effective-path-target.js +4 -0
- package/dist/core/engine-notice.d.ts +34 -2
- package/dist/core/engine-notice.js +17 -1
- package/dist/core/engine-storage-backend.d.ts +73 -0
- package/dist/core/engine-storage-backend.js +1 -0
- package/dist/core/file-history-store.d.ts +6 -2
- package/dist/core/file-history-store.js +1 -0
- package/dist/core/gate-fold.js +10 -2
- package/dist/core/gate-lanes.js +30 -21
- package/dist/core/gate-outcome.d.ts +7 -3
- package/dist/core/governance-codes.d.ts +7 -2
- package/dist/core/governance-codes.js +6 -0
- package/dist/core/hooks.d.ts +14 -14
- package/dist/core/hooks.js +1 -2
- package/dist/core/locked-config.d.ts +28 -1
- package/dist/core/locked-config.js +30 -3
- package/dist/core/lsp.d.ts +1 -1
- package/dist/core/mcp-server-spec.d.ts +66 -9
- package/dist/core/mcp-server-spec.js +52 -19
- package/dist/core/mcp.js +5 -4
- package/dist/core/memory-engine/engine.js +2 -1
- package/dist/core/memory-engine/export-bundle.d.ts +1 -1
- package/dist/core/memory-engine/export-bundle.js +1 -1
- package/dist/core/memory-engine/file-backend.d.ts +2 -6
- package/dist/core/memory-engine/file-backend.js +1 -12
- package/dist/core/memory.d.ts +3 -3
- package/dist/core/mode-policy.d.ts +13 -8
- package/dist/core/mode-policy.js +3 -2
- package/dist/core/mods/kernel/receive.d.ts +2 -1
- package/dist/core/mods/kernel/receive.js +7 -2
- package/dist/core/parent-spec-seat.d.ts +10 -13
- package/dist/core/parent-spec-seat.js +14 -6
- package/dist/core/pause-registry.d.ts +35 -1
- package/dist/core/pause-registry.js +10 -0
- package/dist/core/permission-rule-consent.d.ts +18 -5
- package/dist/core/permission-rule-consent.js +13 -8
- package/dist/core/permission-rule-model.d.ts +29 -6
- package/dist/core/permission-rule-model.js +6 -1
- package/dist/core/permission-rule-org.d.ts +37 -0
- package/dist/core/permission-rule-org.js +34 -42
- package/dist/core/permission-rule-session.js +2 -2
- package/dist/core/permission-rule-store.d.ts +8 -0
- package/dist/core/permission-rule-store.js +1 -0
- package/dist/core/permission-rule-sync.js +3 -2
- package/dist/core/read-only-shell.d.ts +1 -1
- package/dist/core/read-only-shell.js +30 -9
- package/dist/core/remote-env.d.ts +41 -1
- package/dist/core/remote-env.js +18 -0
- package/dist/core/resume-startup-cause.d.ts +18 -0
- package/dist/core/resume-startup-cause.js +12 -0
- package/dist/core/runner/approval-feedback.d.ts +46 -0
- package/dist/core/runner/approval-feedback.js +41 -0
- package/dist/core/runner/compaction-call-options.d.ts +3 -3
- package/dist/core/runner/compaction-call-options.js +2 -2
- package/dist/core/runner/contracts.d.ts +33 -41
- package/dist/core/runner/cross-boundary-lane.d.ts +87 -0
- package/dist/core/runner/cross-boundary-lane.js +190 -0
- package/dist/core/runner/decide-continuation.d.ts +4 -4
- package/dist/core/runner/decide-continuation.js +3 -1
- package/dist/core/runner/gate-exit.d.ts +32 -12
- package/dist/core/runner/gate-exit.js +75 -33
- package/dist/core/runner/inherited-ask-grants.js +2 -2
- package/dist/core/runner/person-path-rows.d.ts +2 -2
- package/dist/core/runner/prepare-acquire-reconcile.d.ts +7 -9
- package/dist/core/runner/prepare-acquire-reconcile.js +8 -6
- package/dist/core/runner/prepare-ask-lane.js +3 -3
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +6 -5
- package/dist/core/runner/prepare-caps-and-workflow.js +3 -3
- package/dist/core/runner/prepare-config-doors.d.ts +12 -15
- package/dist/core/runner/prepare-config-doors.js +8 -3
- package/dist/core/runner/prepare-context-lane.js +6 -3
- package/dist/core/runner/prepare-delegation-surface.d.ts +3 -2
- package/dist/core/runner/prepare-delegation-surface.js +2 -3
- package/dist/core/runner/prepare-execution-env.d.ts +1 -2
- package/dist/core/runner/prepare-execution-env.js +2 -1
- package/dist/core/runner/prepare-gate-stations.d.ts +2 -0
- package/dist/core/runner/prepare-gate-stations.js +4 -3
- package/dist/core/runner/prepare-hands-readface.d.ts +2 -2
- package/dist/core/runner/prepare-hands-readface.js +1 -1
- package/dist/core/runner/prepare-inherited-gate.d.ts +2 -0
- package/dist/core/runner/prepare-inherited-gate.js +1 -0
- package/dist/core/runner/prepare-park-ask.d.ts +1 -1
- package/dist/core/runner/prepare-park-ask.js +9 -3
- package/dist/core/runner/prepare-policy-chain.js +2 -7
- package/dist/core/runner/prepare-safety-scan.d.ts +7 -2
- package/dist/core/runner/prepare-safety-scan.js +34 -27
- package/dist/core/runner/prepare-suspend-saga.d.ts +2 -2
- package/dist/core/runner/prepare-suspend-saga.js +6 -2
- package/dist/core/runner/prepare-task.js +13 -10
- package/dist/core/runner/prepare-turn-wiring.d.ts +10 -5
- package/dist/core/runner/prepare-turn-wiring.js +14 -49
- package/dist/core/runner/prepare-wiring-manifest.d.ts +2 -2
- package/dist/core/runner/prepare-wiring-manifest.js +2 -2
- package/dist/core/runner/prepare-workspace-restore.js +2 -2
- package/dist/core/runner/resume-admission.js +9 -9
- package/dist/core/runner/resume-apply.js +4 -4
- package/dist/core/runner/resume-policy-outcome.d.ts +2 -2
- package/dist/core/runner/resume-policy-outcome.js +18 -15
- package/dist/core/runner/resume-preflight.js +2 -2
- package/dist/core/runner/resume-review-outcome.js +3 -3
- package/dist/core/runner/run-leg.js +57 -33
- package/dist/core/runner/run-settle-and-teardown.js +2 -0
- package/dist/core/runner/run-terminal-adoption.js +15 -4
- package/dist/core/runner/session-file-state-replay.d.ts +5 -2
- package/dist/core/runner/session-file-state-replay.js +3 -2
- package/dist/core/runner/stream-steer-verb.js +2 -2
- package/dist/core/runner/tool-face-overlay.d.ts +24 -6
- package/dist/core/runner/tool-face-overlay.js +24 -15
- package/dist/core/runner-deps.d.ts +9 -9
- package/dist/core/session-store.d.ts +35 -16
- package/dist/core/session-store.js +20 -12
- package/dist/core/{shell-lexer.d.ts → shell-run-candidates.d.ts} +36 -12
- package/dist/core/{shell-lexer.js → shell-run-candidates.js} +145 -225
- package/dist/core/shell-wrapper-table.d.ts +5 -3
- package/dist/core/shell-wrapper-table.js +1 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +2 -2
- package/dist/core/store-contracts/session-store-contract.d.ts +49 -0
- package/dist/core/store-contracts/session-store-contract.js +683 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +12 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.js +5 -2
- package/dist/core/task-event.d.ts +6 -4
- package/dist/core/task-registry-agent.js +1 -0
- package/dist/core/task-registry-shared.d.ts +5 -0
- package/dist/core/task-registry.d.ts +7 -0
- package/dist/core/task-registry.js +17 -0
- package/dist/core/task-result.d.ts +1 -1
- package/dist/core/task-spec.d.ts +6 -6
- package/dist/core/tighten-task-spec.d.ts +6 -4
- package/dist/core/tighten-task-spec.js +2 -2
- package/dist/core/tool-catalog-entries.d.ts +1 -1
- package/dist/core/tool-catalog-entries.js +52 -52
- package/dist/core/tool-face-reader.d.ts +49 -0
- package/dist/core/tool-face-reader.js +94 -0
- package/dist/core/tool-face.d.ts +17 -8
- package/dist/core/tool-face.js +1 -0
- package/dist/core/tool-policy.d.ts +64 -23
- package/dist/core/tool-policy.js +62 -56
- package/dist/core/tool-roster.d.ts +46 -28
- package/dist/core/tool-roster.js +91 -14
- package/dist/core/tool-spec-members.js +2 -2
- package/dist/core/tool-spec.d.ts +20 -4
- package/dist/core/tools.js +2 -0
- package/dist/core/trace.d.ts +24 -2
- package/dist/core/types.d.ts +2 -2
- package/dist/core/types.js +1 -1
- package/dist/core/untrusted-text.d.ts +7 -0
- package/dist/core/untrusted-text.js +3 -8
- package/dist/core/user-attachment.d.ts +43 -0
- package/dist/core/user-attachment.js +92 -15
- package/dist/engine/compaction/compaction.d.ts +2 -2
- package/dist/engine/compaction/utils.d.ts +2 -2
- package/dist/engine/harness/types.d.ts +7 -4
- package/dist/engine/llm/types.d.ts +7 -2
- package/dist/engine/llm/types.js +2 -1
- package/dist/engine/session/parent-chain-guard.d.ts +10 -0
- package/dist/engine/session/parent-chain-guard.js +10 -0
- package/dist/engine/session/repo-utils.d.ts +5 -0
- package/dist/engine/session/repo-utils.js +9 -0
- package/dist/engine/session/storage-base.js +5 -2
- package/dist/index.d.ts +23 -9
- package/dist/index.js +19 -8
- package/dist/internal/harness.d.ts +1 -0
- package/dist/internal/harness.js +1 -0
- package/dist/internal/llm.d.ts +1 -1
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/run-workflow-tool.d.ts +3 -0
- package/dist/orchestration/run-workflow-tool.js +1 -0
- package/dist/orchestration/workflow-governance.d.ts +1 -1
- package/dist/orchestration/workflow.d.ts +3 -0
- package/dist/orchestration/workflow.js +2 -1
- package/dist/prompt-assembly/catalog/schema.d.ts +3 -0
- package/dist/prompt-assembly/catalog/schema.js +3 -0
- package/dist/prompt-assembly/overlay.js +2 -2
- package/dist/prompt-assembly/select.js +2 -2
- package/dist/prompts/default.d.ts +1 -1
- package/dist/shell/lex.d.ts +87 -8
- package/dist/shell/lex.js +283 -49
- package/dist/stores/file/index.d.ts +8 -6
- package/dist/tools/artifact/artifact-tool.js +10 -0
- package/dist/tools/fs/bash-program-position.d.ts +3 -15
- package/dist/tools/fs/bash-program-position.js +3 -10
- package/dist/tools/fs/bash-readonly-classifier.js +2 -0
- package/dist/tools/fs/fs-bash.d.ts +3 -3
- package/dist/tools/fs/fs-bash.js +72 -101
- package/dist/tools/fs/fs-read.d.ts +12 -0
- package/dist/tools/fs/fs-read.js +10 -9
- package/dist/tools/fs/fs-shared.d.ts +27 -31
- package/dist/tools/fs/fs-shared.js +12 -15
- package/dist/tools/fs/fs-write.js +1 -1
- package/dist/tools/fs/index.js +2 -2
- package/dist/tools/fs/read-deny-home.d.ts +1 -1
- package/dist/tools/fs/read-deny-home.js +5 -4
- package/dist/tools/fs/read-deny.d.ts +16 -3
- package/dist/tools/fs/read-deny.js +12 -9
- package/dist/tools/fs/safety.d.ts +7 -6
- package/dist/tools/fs/shell-read-bindings.d.ts +5 -3
- package/dist/tools/fs/shell-read-bindings.js +15 -16
- package/dist/tools/fs/shell-read-device.js +1 -1
- package/dist/tools/fs/shell-read-plan.js +36 -47
- package/dist/tools/fs/shell-read-word.d.ts +1 -6
- package/dist/tools/fs/shell-read-word.js +2 -20
- package/dist/tools/fs/shell-reentry-text.js +1 -1
- package/dist/tools/web.d.ts +2 -2
- package/package.json +4 -1
- package/test/export-surface.snapshot.json +5654 -5520
- package/wire-changes/core@7.53.0.json +30 -8
- package/wire-changes/core@7.54.0.json +2870 -0
- package/wire-changes/core@7.54.1.json +37 -0
- package/dist/core/shell-scan.d.ts +0 -60
- package/dist/core/shell-scan.js +0 -183
|
@@ -2,6 +2,7 @@ import { Type, type Static, type TSchema } from "typebox";
|
|
|
2
2
|
import type { AgentTool } from "../internal/harness-types.js";
|
|
3
3
|
import { type ReservedApprovalCard, type ToolApprovalCard, type ToolFamily, type ToolRosterPathTarget, type ToolMountTag, type ToolPathTarget, type ToolRenderHints, type ToolRuleFace } from "./tool-face.js";
|
|
4
4
|
import type { ToolContentOrigin, ToolEffect } from "./tool-spec.js";
|
|
5
|
+
import type { ToolMarkSource } from "./ask-origin.js";
|
|
5
6
|
export declare const ROSTER_SOURCES: readonly ["builtin", "caller", "host", "mcp", "a2a", "external", "synthetic"];
|
|
6
7
|
export type RosterSource = (typeof ROSTER_SOURCES)[number];
|
|
7
8
|
export declare const ToolRosterRenderHints: Type.TObject<{
|
|
@@ -50,6 +51,9 @@ export declare const ToolRosterEntry: Type.TObject<{
|
|
|
50
51
|
contentOrigin: Type.TUnion<[Type.TLiteral<"local">, Type.TLiteral<"execution">, Type.TLiteral<"external">]>;
|
|
51
52
|
contentOriginProvenance: Type.TUnion<[Type.TLiteral<"declared">, Type.TLiteral<"server">, Type.TLiteral<"exempted">, Type.TLiteral<"default">]>;
|
|
52
53
|
family: Type.TUnion<[Type.TLiteral<"shell">, Type.TLiteral<"file-read">, Type.TLiteral<"file-write">, Type.TLiteral<"search">, Type.TLiteral<"web">, Type.TLiteral<"delegate">, Type.TLiteral<"plan">, Type.TLiteral<"scaffold">, Type.TLiteral<"memory">, Type.TLiteral<"protocol">, Type.TLiteral<"other">]>;
|
|
54
|
+
/** The legs a call of this tool travels (`BOUNDARY_LEGS`), or `"per_call"` when its dispatch gives them per call: the engine's own
|
|
55
|
+
* definitions and the protocol tools state them, every other row follows its `effect` (`rosterBoundaryLegs`). */
|
|
56
|
+
boundaryLegs: Type.TUnion<[Type.TLiteral<"per_call">, Type.TArray<Type.TUnion<[Type.TLiteral<"env">, Type.TLiteral<"outside_read">, Type.TLiteral<"outside_write">]>>]>;
|
|
53
57
|
pathTarget: Type.TOptional<Type.TObject<{
|
|
54
58
|
param: Type.TString;
|
|
55
59
|
aliases: Type.TArray<Type.TString>;
|
|
@@ -124,6 +128,9 @@ export declare const ToolRoster: Type.TObject<{
|
|
|
124
128
|
contentOrigin: Type.TUnion<[Type.TLiteral<"local">, Type.TLiteral<"execution">, Type.TLiteral<"external">]>;
|
|
125
129
|
contentOriginProvenance: Type.TUnion<[Type.TLiteral<"declared">, Type.TLiteral<"server">, Type.TLiteral<"exempted">, Type.TLiteral<"default">]>;
|
|
126
130
|
family: Type.TUnion<[Type.TLiteral<"shell">, Type.TLiteral<"file-read">, Type.TLiteral<"file-write">, Type.TLiteral<"search">, Type.TLiteral<"web">, Type.TLiteral<"delegate">, Type.TLiteral<"plan">, Type.TLiteral<"scaffold">, Type.TLiteral<"memory">, Type.TLiteral<"protocol">, Type.TLiteral<"other">]>;
|
|
131
|
+
/** The legs a call of this tool travels (`BOUNDARY_LEGS`), or `"per_call"` when its dispatch gives them per call: the engine's own
|
|
132
|
+
* definitions and the protocol tools state them, every other row follows its `effect` (`rosterBoundaryLegs`). */
|
|
133
|
+
boundaryLegs: Type.TUnion<[Type.TLiteral<"per_call">, Type.TArray<Type.TUnion<[Type.TLiteral<"env">, Type.TLiteral<"outside_read">, Type.TLiteral<"outside_write">]>>]>;
|
|
127
134
|
pathTarget: Type.TOptional<Type.TObject<{
|
|
128
135
|
param: Type.TString;
|
|
129
136
|
aliases: Type.TArray<Type.TString>;
|
|
@@ -206,6 +213,9 @@ export declare const ToolRosterDelta: Type.TObject<{
|
|
|
206
213
|
contentOrigin: Type.TUnion<[Type.TLiteral<"local">, Type.TLiteral<"execution">, Type.TLiteral<"external">]>;
|
|
207
214
|
contentOriginProvenance: Type.TUnion<[Type.TLiteral<"declared">, Type.TLiteral<"server">, Type.TLiteral<"exempted">, Type.TLiteral<"default">]>;
|
|
208
215
|
family: Type.TUnion<[Type.TLiteral<"shell">, Type.TLiteral<"file-read">, Type.TLiteral<"file-write">, Type.TLiteral<"search">, Type.TLiteral<"web">, Type.TLiteral<"delegate">, Type.TLiteral<"plan">, Type.TLiteral<"scaffold">, Type.TLiteral<"memory">, Type.TLiteral<"protocol">, Type.TLiteral<"other">]>;
|
|
216
|
+
/** The legs a call of this tool travels (`BOUNDARY_LEGS`), or `"per_call"` when its dispatch gives them per call: the engine's own
|
|
217
|
+
* definitions and the protocol tools state them, every other row follows its `effect` (`rosterBoundaryLegs`). */
|
|
218
|
+
boundaryLegs: Type.TUnion<[Type.TLiteral<"per_call">, Type.TArray<Type.TUnion<[Type.TLiteral<"env">, Type.TLiteral<"outside_read">, Type.TLiteral<"outside_write">]>>]>;
|
|
209
219
|
pathTarget: Type.TOptional<Type.TObject<{
|
|
210
220
|
param: Type.TString;
|
|
211
221
|
aliases: Type.TArray<Type.TString>;
|
|
@@ -281,15 +291,10 @@ export declare function approvalCardMemberOf(call: {
|
|
|
281
291
|
* other aliases — the ONE order of a call's names: a reader that must pick one of them by position (a `member` seat)
|
|
282
292
|
* picks the spelling first, as the same call was judged before name resolution. */
|
|
283
293
|
export declare function toolCallFaceOf(roster: ToolRoster | undefined, toolName: string): import("./tool-policy.js").ToolCallFace | undefined;
|
|
284
|
-
/** design/388 B18 — the identity members a park row carries
|
|
285
|
-
*
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
contractId?: string;
|
|
289
|
-
shapeDigest?: string;
|
|
290
|
-
implementationRevision?: string;
|
|
291
|
-
rosterDigest?: string;
|
|
292
|
-
};
|
|
294
|
+
/** design/388 B18 — the identity members a park row carries (the tool member of its approval object,
|
|
295
|
+
* `approval-object.ts`), read off a roster snapshot by name; an empty object when the name is not on the snapshot
|
|
296
|
+
* (the row then reads pre-identity and the resume binds the name alone). */
|
|
297
|
+
export declare function parkedToolIdentity(roster: ToolRoster | undefined, toolName: string): Partial<ToolIdentity>;
|
|
293
298
|
/** design/388 B6 × B18 — the FACE members a park row carries beside its identity: the display family, the declared
|
|
294
299
|
* path target and the names the parked call was judged under. `names` is copied from the face the gate stamped on the
|
|
295
300
|
* request (the model's spelling first — the row carries the judged fact, it is not re-derived); a request with no face
|
|
@@ -375,7 +380,7 @@ export type RosterBoundCode = "config.tool_name_too_long" | "config.tool_contrac
|
|
|
375
380
|
* undefined when every member fits. Read by the declaration door (a `TaskSpec.tools` entry, refused before session
|
|
376
381
|
* acquire) and by the row mint (every source — an MCP/A2A peer, a definition that reached the mint by a route the
|
|
377
382
|
* door does not cover — refused before the row exists). A member over its bound is NEVER truncated onto the row: a
|
|
378
|
-
* truncated identity is a different identity (`
|
|
383
|
+
* truncated identity is a different identity (`judgeApprovalObject` compares it across a park; the card
|
|
379
384
|
* namespace door reads it), and the schema's own bounds would then describe a row the mint never made.
|
|
380
385
|
*/
|
|
381
386
|
export declare function rosterMemberBoundProblem(m: RosterBoundMembers): {
|
|
@@ -427,6 +432,7 @@ export interface MountedToolFace {
|
|
|
427
432
|
compactable?: true;
|
|
428
433
|
budgetExempt?: true;
|
|
429
434
|
modelGate?: string;
|
|
435
|
+
boundaryLegs?: unknown;
|
|
430
436
|
}
|
|
431
437
|
export declare const faceOf: (t: AgentTool) => MountedToolFace;
|
|
432
438
|
/** The leg facts the snapshot reads beside the instances — the safety scan's folds and the per-task knobs. */
|
|
@@ -441,20 +447,32 @@ export interface RosterSnapshotFacts {
|
|
|
441
447
|
/** `TaskSpec.memory.trustedTools` — the exemption channel for an undeclared content class. */
|
|
442
448
|
trustedTools: ReadonlySet<string>;
|
|
443
449
|
}
|
|
450
|
+
/** The leg's per-name safety-axis tables the builder keeps aligned with its mounts beside the effect map (the safety scan mints
|
|
451
|
+
* them; the protocol folds and the shell seat also write them). */
|
|
452
|
+
export interface RosterAxisTables {
|
|
453
|
+
irreversibilityTier: Map<string, "never" | "maybe" | "always">;
|
|
454
|
+
irreversibleTools: Set<string>;
|
|
455
|
+
reversibilityProbes: Map<string, unknown>;
|
|
456
|
+
egressTools: Set<string>;
|
|
457
|
+
toolMarkSources: Map<string, Set<ToolMarkSource>>;
|
|
458
|
+
}
|
|
444
459
|
export declare class RosterBuilder {
|
|
445
460
|
#private;
|
|
446
|
-
|
|
461
|
+
/** `axes` — the leg's safety-axis tables beside the effect map (a builder for a single probe tool may go without). */
|
|
462
|
+
constructor(effects: Map<string, ToolEffect>, axes?: RosterAxisTables);
|
|
447
463
|
/** The mount array as a READ face. The order is the wire order. */
|
|
448
464
|
get tools(): readonly AgentTool[];
|
|
449
465
|
get length(): number;
|
|
450
466
|
metaOf(tool: AgentTool): RosterMountMeta | undefined;
|
|
451
467
|
/** Mount one instance at the tail. An engine-lane instance that DECLARES an effect writes it into the leg's effect
|
|
452
468
|
* map — the later mount under a name is the one the harness dispatches to (`snapshot`'s yield rule), so its
|
|
453
|
-
* declaration is the map's truth for that name
|
|
454
|
-
*
|
|
469
|
+
* declaration is the map's truth for that name — an engine tool's effect reaches the map from its own declaration, here at its
|
|
470
|
+
* mount (nothing writes it by name beforehand; a protocol axis fills a name no mounted instance declares, and the gate's
|
|
471
|
+
* post-assembly sync a kept instance the map still lacks). The `scenario` lane never writes the map: its
|
|
455
472
|
* declarations were latched by the safety scan BEFORE any mount (on the kept instance of each name, on the
|
|
456
473
|
* synchronous doors+scan stretch — a microtask cannot flip them), so a scenario mount, kept or dropped, leaves
|
|
457
|
-
* the map as the scan made it; an engine lane's mount under that name still displaces it
|
|
474
|
+
* the map as the scan made it; an engine lane's mount under that name still displaces it, and the aliases the displaced
|
|
475
|
+
* instance answered to move to the member they now resolve to (`#resettleAliases`). */
|
|
458
476
|
mount(tool: AgentTool, meta: RosterMountMeta): void;
|
|
459
477
|
/** An ENGINE-INJECTED instance the harness list carries outside the mount array (the ToolSearch lane): a roster
|
|
460
478
|
* row — the model can call it — never a mount-array element (the disclosure lane owns that list and appends the
|
|
@@ -497,6 +515,20 @@ export declare function rosterCardId(source: RosterSource, toolName: string, pee
|
|
|
497
515
|
/** The card namespace a `TaskSpec.tools` entry will own once mounted — the same mint the row makes, so the prepare
|
|
498
516
|
* door and the roster row cannot disagree about which namespace a caller card must live under. */
|
|
499
517
|
export declare function callerCardIdOf(tool: Pick<AgentTool, "name" | "parameters">): string;
|
|
518
|
+
/** The protocol segment of a mounted protocol tool's name (`mcp__srv__write_file` ⇒ `write_file`): the name itself when no protocol owns it.
|
|
519
|
+
* ONE reading, asked by the row's mint below and by the judge that holds an MCP face's cards to the namespace that row will own. */
|
|
520
|
+
export declare function protocolToolOf(toolName: string): string;
|
|
521
|
+
/** The refusal of a `boundaryLegs` declaration that is not one — the ONE sentence the roster's declaration door and the row mint both
|
|
522
|
+
* throw (`config.tool_face_invalid`, the code a caller tool's bad face has). */
|
|
523
|
+
export declare function boundaryLegsRefusal(toolName: unknown): Error & {
|
|
524
|
+
code: string;
|
|
525
|
+
};
|
|
526
|
+
/** The judge of a caller roster's `boundaryLegs` where the roster enters, every entry the caller handed, mounted or not: the config-door
|
|
527
|
+
* phase over the snapshot's faces and a resume's screen before its claim over the entries it is handed (one function, so the row stays
|
|
528
|
+
* pending). A declaration that is not one is refused. Not judged here — the snapshot reads it, and only by running the caller's code:
|
|
529
|
+
* an entry or a list of another prototype (its prototype chain answers), a Proxy, an accessor (or a non-enumerable member the receipt
|
|
530
|
+
* does not take) as the name, the declaration or a slot of the list. The row mint judges every other source. */
|
|
531
|
+
export declare function assertToolBoundaryLegs(tools: unknown): void;
|
|
500
532
|
/** One row (design/388 §2.5). Every axis is read off the instance or the leg facts; nothing off a name table. */
|
|
501
533
|
export declare function mintRosterEntry(tool: AgentTool, meta: RosterMountMeta, facts: RosterSnapshotFacts): ToolRosterEntry;
|
|
502
534
|
/**
|
|
@@ -533,20 +565,6 @@ export declare function ruleFacesFromRoster(roster: ToolRoster): (toolName: stri
|
|
|
533
565
|
} | undefined;
|
|
534
566
|
/** The delta between two snapshots (design/388 §2.5): the whole `next` roster plus the name summary. */
|
|
535
567
|
export declare function diffToolRoster(prev: ToolRoster, next: ToolRoster): ToolRosterDelta;
|
|
536
|
-
/**
|
|
537
|
-
* The resume-side identity judgement (design/388 §2.5 boundary ②, B18/B19): a parked action carrying the
|
|
538
|
-
* four identity members is redeemed only against a same-name row whose four members ALL match; a row
|
|
539
|
-
* whose contract / shape / revision / source-peer moved is a replacement wearing the name, and the
|
|
540
|
-
* resume refuses it (`resume.tool_contract_mismatch`, same family and disposition as
|
|
541
|
-
* `resume.tool_unavailable`). A parked action minted BEFORE the identity members existed (all four absent)
|
|
542
|
-
* follows the name-only path and is never widened by their absence.
|
|
543
|
-
*/
|
|
544
|
-
export declare function judgeParkedToolIdentity(pending: {
|
|
545
|
-
capabilityId?: string;
|
|
546
|
-
contractId?: string;
|
|
547
|
-
shapeDigest?: string;
|
|
548
|
-
implementationRevision?: string;
|
|
549
|
-
}, row: ToolRosterEntry | undefined): "match" | "mismatch" | "name_only" | "absent";
|
|
550
568
|
/** The card-namespace check a CALLER declaration must pass at prepare (design/388 §2.2 ④): a `resultCards`
|
|
551
569
|
* entry must live under the tool's own `cardId`; naming an engine card (`builtin:*`, or a bare engine card
|
|
552
570
|
* type) is refused. Returns the offending entry, or undefined. */
|
package/dist/core/tool-roster.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import { types } from "node:util";
|
|
2
3
|
import { Type } from "typebox";
|
|
4
|
+
import { findToolByName } from "../internal/llm.js";
|
|
3
5
|
import { getToolContract } from "../prompt-assembly/tool-catalog.js";
|
|
4
6
|
import { protocolOf } from "./protocol-table.js";
|
|
5
7
|
import { describeToolCatalog } from "./tool-registry.js";
|
|
@@ -7,6 +9,8 @@ import { RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_CHARS, RENDER_HINT_MAX_
|
|
|
7
9
|
import { ASK_USER_QUESTION_TOOL_NAME } from "./ask-question.js";
|
|
8
10
|
import { PRESENT_PLAN_TOOL_NAME } from "./present-plan-tool.js";
|
|
9
11
|
import { wireOf } from "./tool-name-readings.js";
|
|
12
|
+
import { BOUNDARY_LEGS, rosterBoundaryLegs } from "./cross-boundary-taint.js";
|
|
13
|
+
import { isPlainRecord, receive } from "./mods/kernel/receive.js";
|
|
10
14
|
function lit(values) {
|
|
11
15
|
return Type.Union(values.map((v) => Type.Literal(v)));
|
|
12
16
|
}
|
|
@@ -46,6 +50,7 @@ export const ToolRosterEntry = Type.Object({
|
|
|
46
50
|
contentOrigin: lit(["local", "execution", "external"]),
|
|
47
51
|
contentOriginProvenance: lit(["declared", "server", "exempted", "default"]),
|
|
48
52
|
family: lit(TOOL_FAMILIES),
|
|
53
|
+
boundaryLegs: Type.Union([Type.Literal("per_call"), Type.Array(lit(BOUNDARY_LEGS), { uniqueItems: true })]),
|
|
49
54
|
pathTarget: Type.Optional(Type.Object({
|
|
50
55
|
param: Key,
|
|
51
56
|
aliases: Type.Array(Key),
|
|
@@ -122,9 +127,7 @@ export function parkedToolIdentity(roster, toolName) {
|
|
|
122
127
|
if (roster === undefined)
|
|
123
128
|
return {};
|
|
124
129
|
const e = rosterEntryNamed(roster, toolName);
|
|
125
|
-
|
|
126
|
-
return {};
|
|
127
|
-
return { capabilityId: e.capabilityId, contractId: e.contract.contractId, shapeDigest: e.shapeDigest, implementationRevision: e.contract.implementationRevision, rosterDigest: roster.digest };
|
|
130
|
+
return e === undefined ? {} : toolIdentityOf(e);
|
|
128
131
|
}
|
|
129
132
|
export function parkedToolFace(roster, req) {
|
|
130
133
|
if (roster === undefined)
|
|
@@ -301,6 +304,18 @@ export function survivorsByName(mounted) {
|
|
|
301
304
|
return winner;
|
|
302
305
|
}
|
|
303
306
|
export const faceOf = (t) => t;
|
|
307
|
+
const setOrClear = (m, key, value) => {
|
|
308
|
+
if (value === undefined)
|
|
309
|
+
m.delete(key);
|
|
310
|
+
else
|
|
311
|
+
m.set(key, value);
|
|
312
|
+
};
|
|
313
|
+
const memberIf = (s, key, member) => {
|
|
314
|
+
if (member)
|
|
315
|
+
s.add(key);
|
|
316
|
+
else
|
|
317
|
+
s.delete(key);
|
|
318
|
+
};
|
|
304
319
|
function configError(code, message) {
|
|
305
320
|
const e = new Error(message);
|
|
306
321
|
e.code = code;
|
|
@@ -311,8 +326,10 @@ export class RosterBuilder {
|
|
|
311
326
|
#engineLane = [];
|
|
312
327
|
#meta = new WeakMap();
|
|
313
328
|
#effects;
|
|
314
|
-
|
|
329
|
+
#axes;
|
|
330
|
+
constructor(effects, axes) {
|
|
315
331
|
this.#effects = effects;
|
|
332
|
+
this.#axes = axes;
|
|
316
333
|
}
|
|
317
334
|
get tools() {
|
|
318
335
|
return this.#tools;
|
|
@@ -324,12 +341,18 @@ export class RosterBuilder {
|
|
|
324
341
|
return this.#meta.get(tool);
|
|
325
342
|
}
|
|
326
343
|
mount(tool, meta) {
|
|
344
|
+
const displaced = this.#survivorNamed(tool.name);
|
|
327
345
|
this.#admit(tool, meta);
|
|
328
346
|
this.#tools.push(tool);
|
|
347
|
+
if (meta.mountedBy !== "scenario")
|
|
348
|
+
this.#resettleAliases([...(displaced?.aliases ?? []), ...(tool.aliases ?? [])]);
|
|
329
349
|
}
|
|
330
350
|
mountEngineLane(tool, meta) {
|
|
351
|
+
const displaced = this.#survivorNamed(tool.name);
|
|
331
352
|
this.#admit(tool, meta);
|
|
332
353
|
this.#engineLane.push(tool);
|
|
354
|
+
if (meta.mountedBy !== "scenario")
|
|
355
|
+
this.#resettleAliases([...(displaced?.aliases ?? []), ...(tool.aliases ?? [])]);
|
|
333
356
|
}
|
|
334
357
|
#admit(tool, meta) {
|
|
335
358
|
if ((meta.source === "mcp" || meta.source === "a2a" || meta.source === "external") !== (meta.origin !== undefined)) {
|
|
@@ -342,6 +365,32 @@ export class RosterBuilder {
|
|
|
342
365
|
if (eff !== undefined && meta.mountedBy !== "scenario")
|
|
343
366
|
this.#effects.set(tool.name, eff);
|
|
344
367
|
}
|
|
368
|
+
#survivorNamed(name) {
|
|
369
|
+
return survivorsByName([...this.#tools, ...this.#engineLane]).get(name);
|
|
370
|
+
}
|
|
371
|
+
#resettleAliases(aliases) {
|
|
372
|
+
if (aliases.length === 0)
|
|
373
|
+
return;
|
|
374
|
+
const live = [...survivorsByName([...this.#tools, ...this.#engineLane]).values()];
|
|
375
|
+
for (const a of new Set(aliases)) {
|
|
376
|
+
const owner = findToolByName(live, a);
|
|
377
|
+
if (owner?.name === a)
|
|
378
|
+
continue;
|
|
379
|
+
this.#repoint(a, owner?.name);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
#repoint(key, from) {
|
|
383
|
+
const pick = (m) => (from === undefined ? undefined : m.get(from));
|
|
384
|
+
const marks = this.#axes === undefined ? undefined : pick(this.#axes.toolMarkSources);
|
|
385
|
+
setOrClear(this.#effects, key, pick(this.#effects));
|
|
386
|
+
if (this.#axes === undefined)
|
|
387
|
+
return;
|
|
388
|
+
setOrClear(this.#axes.irreversibilityTier, key, pick(this.#axes.irreversibilityTier));
|
|
389
|
+
setOrClear(this.#axes.reversibilityProbes, key, pick(this.#axes.reversibilityProbes));
|
|
390
|
+
setOrClear(this.#axes.toolMarkSources, key, marks === undefined ? undefined : new Set(marks));
|
|
391
|
+
memberIf(this.#axes.irreversibleTools, key, from !== undefined && this.#axes.irreversibleTools.has(from));
|
|
392
|
+
memberIf(this.#axes.egressTools, key, from !== undefined && this.#axes.egressTools.has(from));
|
|
393
|
+
}
|
|
345
394
|
mountAll(tools, meta) {
|
|
346
395
|
for (const t of tools)
|
|
347
396
|
this.mount(t, meta);
|
|
@@ -355,6 +404,10 @@ export class RosterBuilder {
|
|
|
355
404
|
removed.unshift(t);
|
|
356
405
|
}
|
|
357
406
|
}
|
|
407
|
+
for (const t of removed)
|
|
408
|
+
if (this.#survivorNamed(t.name) === undefined)
|
|
409
|
+
this.#effects.delete(t.name);
|
|
410
|
+
this.#resettleAliases(removed.flatMap((t) => t.aliases ?? []));
|
|
358
411
|
return removed;
|
|
359
412
|
}
|
|
360
413
|
replaceAt(index, tool) {
|
|
@@ -449,18 +502,50 @@ export function callerCardIdOf(tool) {
|
|
|
449
502
|
const t = tool;
|
|
450
503
|
return rosterCardId(callerMountSource(t), t.name, null, t.name, getToolContract(t, "caller").contractId);
|
|
451
504
|
}
|
|
505
|
+
export function protocolToolOf(toolName) {
|
|
506
|
+
return protocolOf(toolName)?.parse(toolName)?.tool ?? toolName;
|
|
507
|
+
}
|
|
508
|
+
export function boundaryLegsRefusal(toolName) {
|
|
509
|
+
const named = typeof toolName === "string" ? JSON.stringify(toolName.slice(0, 128)) : `(a ${typeof toolName} name)`;
|
|
510
|
+
return configError("config.tool_face_invalid", `tool ${named}: its boundaryLegs declaration is neither "per_call" nor a list of ${BOUNDARY_LEGS.join(" | ")}`);
|
|
511
|
+
}
|
|
512
|
+
const ROSTER_LEGS_RECEIPT = Object.freeze({ accessors: "refuse", depth: 3, others: "as-is", contain: true, isProxy: (v) => types.isProxy(v) });
|
|
513
|
+
const SLOT = /^(?:0|[1-9]\d*)$/;
|
|
514
|
+
export function assertToolBoundaryLegs(tools) {
|
|
515
|
+
const got = receive(tools, ROSTER_LEGS_RECEIPT);
|
|
516
|
+
if (!got.ok || !Array.isArray(got.value))
|
|
517
|
+
return;
|
|
518
|
+
const unread = new Set();
|
|
519
|
+
for (const f of got.faults ?? []) {
|
|
520
|
+
const [at, member, slot] = f.path;
|
|
521
|
+
if (at !== undefined && (member === "name" || (member === "boundaryLegs" && slot !== undefined && SLOT.test(slot))))
|
|
522
|
+
unread.add(at);
|
|
523
|
+
}
|
|
524
|
+
got.value.forEach((t, i) => {
|
|
525
|
+
if (!isPlainRecord(t) || unread.has(String(i)))
|
|
526
|
+
return;
|
|
527
|
+
const legs = t["boundaryLegs"];
|
|
528
|
+
if (Array.isArray(legs) && Object.getPrototypeOf(legs) !== Array.prototype)
|
|
529
|
+
return;
|
|
530
|
+
if (rosterBoundaryLegs("caller", legs, "write") === undefined)
|
|
531
|
+
throw boundaryLegsRefusal(t["name"]);
|
|
532
|
+
});
|
|
533
|
+
}
|
|
452
534
|
export function mintRosterEntry(tool, meta, facts) {
|
|
453
535
|
const face = faceOf(tool);
|
|
454
536
|
const fallbackOrigin = meta.source === "builtin" ? "core" : meta.source === "synthetic" ? "synthetic" : meta.source === "mcp" || meta.source === "a2a" ? meta.source : "caller";
|
|
455
537
|
const d = getToolContract(tool, fallbackOrigin);
|
|
456
538
|
const peer = meta.origin?.peer ?? null;
|
|
457
|
-
const protocolTool = peer !== null ?
|
|
539
|
+
const protocolTool = peer !== null ? protocolToolOf(tool.name) : tool.name;
|
|
458
540
|
const cardId = rosterCardId(meta.source, tool.name, peer, protocolTool, d.contractId);
|
|
459
541
|
const { keys: inputKeys } = inputKeysOf(tool.parameters);
|
|
460
542
|
const declaredEffect = face.effect;
|
|
461
543
|
const foldedEffect = facts.effects.get(tool.name);
|
|
462
544
|
const effect = declaredEffect ?? foldedEffect ?? "write";
|
|
463
545
|
const effectProvenance = declaredEffect !== undefined ? (meta.source === "synthetic" ? "synthetic" : "declared") : foldedEffect !== undefined && (meta.source === "mcp" || meta.source === "a2a") ? "caller" : "default";
|
|
546
|
+
const boundaryLegs = rosterBoundaryLegs(meta.source, face.boundaryLegs, effect);
|
|
547
|
+
if (boundaryLegs === undefined)
|
|
548
|
+
throw boundaryLegsRefusal(tool.name);
|
|
464
549
|
const egress = face.egress === true || facts.egress.has(tool.name);
|
|
465
550
|
const egressProvenance = face.egress === true ? "declared" : egress ? "caller" : "default";
|
|
466
551
|
const irreversibility = face.irreversibility ?? facts.irreversibilityTier.get(tool.name);
|
|
@@ -505,6 +590,7 @@ export function mintRosterEntry(tool, meta, facts) {
|
|
|
505
590
|
contentOrigin,
|
|
506
591
|
contentOriginProvenance,
|
|
507
592
|
family: face.family !== undefined && TOOL_FAMILIES.includes(face.family) ? face.family : "other",
|
|
593
|
+
boundaryLegs: boundaryLegs === "per_call" ? boundaryLegs : [...boundaryLegs],
|
|
508
594
|
...(pathTarget !== undefined
|
|
509
595
|
? {
|
|
510
596
|
pathTarget: {
|
|
@@ -608,15 +694,6 @@ export function diffToolRoster(prev, next) {
|
|
|
608
694
|
removed.push(name);
|
|
609
695
|
return { fromDigest: prev.digest, roster: next, summary: { added, removed, changed } };
|
|
610
696
|
}
|
|
611
|
-
export function judgeParkedToolIdentity(pending, row) {
|
|
612
|
-
const carried = pending.capabilityId !== undefined || pending.contractId !== undefined || pending.shapeDigest !== undefined || pending.implementationRevision !== undefined;
|
|
613
|
-
if (row === undefined)
|
|
614
|
-
return "absent";
|
|
615
|
-
if (!carried)
|
|
616
|
-
return "name_only";
|
|
617
|
-
const id = toolIdentityOf(row);
|
|
618
|
-
return pending.capabilityId === id.capabilityId && pending.contractId === id.contractId && pending.shapeDigest === id.shapeDigest && pending.implementationRevision === id.implementationRevision ? "match" : "mismatch";
|
|
619
|
-
}
|
|
620
697
|
export function offendingResultCard(hints, cardId, engineCards) {
|
|
621
698
|
for (const c of hints?.resultCards ?? []) {
|
|
622
699
|
if (typeof c !== "string")
|
|
@@ -5,9 +5,9 @@ export const TOOL_SPEC_MEMBERS = Object.keys({
|
|
|
5
5
|
contentOrigin: true, offload: true, offloadThresholdChars: true, defer: true, alwaysLoad: true, prepareArguments: true,
|
|
6
6
|
validateInput: true, approvalPreview: true, family: true, pathTarget: true, ruleFace: true, renderHints: true, compactable: true,
|
|
7
7
|
budgetExempt: true, modelGate: true, contract: true, agentListing: true, agentModels: true, agentToolFaces: true,
|
|
8
|
-
agentToolLevelAllowTools: true, agentToolLevelDenyTools: true, agentToolPool: true, agentToolInheritsMcp: true, withAgents: true,
|
|
8
|
+
agentToolLevelAllowTools: true, agentToolLevelDenyTools: true, agentToolPool: true, agentToolInheritsMcp: true, withAgents: true, boundaryLegs: true, boundaryLegsFor: true,
|
|
9
9
|
});
|
|
10
|
-
const FUNCTION_MEMBERS = new Set(["execute", "prepareArguments", "validateInput", "approvalPreview", "reversibilityProbe", "isConcurrencySafe", "withAgents"]);
|
|
10
|
+
const FUNCTION_MEMBERS = new Set(["execute", "prepareArguments", "validateInput", "approvalPreview", "reversibilityProbe", "isConcurrencySafe", "withAgents", "boundaryLegsFor"]);
|
|
11
11
|
const NAME_LIST_MEMBERS = new Set(["aliases", "agentModels", "agentToolLevelAllowTools", "agentToolLevelDenyTools"]);
|
|
12
12
|
const FACE_LIST_KEYS = new Set(["allowTools", "denyTools"]);
|
|
13
13
|
const FACE_PLACES = { elementKeys: FACE_LIST_KEYS };
|
package/dist/core/tool-spec.d.ts
CHANGED
|
@@ -306,10 +306,10 @@ export interface ToolSpec<TParams extends TSchema = TSchema> {
|
|
|
306
306
|
egress?: true;
|
|
307
307
|
/**
|
|
308
308
|
* The tool's PERMISSION SEAT. `"passthrough"`: the tool states no permission of its own — under an asking permission mode
|
|
309
|
-
* (`default` / `acceptEdits` / `plan` / `auto` / `dontAsk`) a
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
* classifier may answer, and `bypassPermissions` never raises. The MCP and A2A materializers set it on a remote peer's
|
|
309
|
+
* (`default` / `acceptEdits` / `plan` / `auto` / `dontAsk`) a policy fold's allow is "no objection" and gets the mode's
|
|
310
|
+
* question (class `unstated`, origin `policy`) unless an approver's yes was given for the bytes that run; the allow layer
|
|
311
|
+
* answers it (an allow entry in `RunnerDeps.allowedTools` / `TaskSpec.allowedTools`, a stored row, a skill's list, a PreToolUse
|
|
312
|
+
* hook's own `allow`), dontAsk refuses it, auto's classifier may answer it, and `bypassPermissions` never raises it. The MCP and A2A materializers set it on a remote peer's
|
|
313
313
|
* tool. Absent: the tool answers for itself (the engine's own stations and the deployment's declarations). Tightening only —
|
|
314
314
|
* it can make a tool ask, never let one run.
|
|
315
315
|
*/
|
|
@@ -524,6 +524,18 @@ export interface ToolSpec<TParams extends TSchema = TSchema> {
|
|
|
524
524
|
* missing declaration rather than defaulting it).
|
|
525
525
|
*/
|
|
526
526
|
family?: ToolFamily;
|
|
527
|
+
/**
|
|
528
|
+
* The legs a call of this tool travels across the device boundary — the engine's own definitions declare it on their catalog face
|
|
529
|
+
* ({@link import("./tool-face.js").ToolFaceDeclaration.boundaryLegs}, required there), and this member carries it onto the mounted
|
|
530
|
+
* instance. Read only on a roster row of source `builtin` / `synthetic` (a `TaskSpec.tools` entry is one only when it carries a core
|
|
531
|
+
* contract); any other tool's row states legs from its `effect`. A value that is neither `"per_call"` nor a list of legs is refused
|
|
532
|
+
* (`config.tool_face_invalid`): for a `TaskSpec.tools` entry where the roster enters, whether or not the entry mounts.
|
|
533
|
+
*/
|
|
534
|
+
boundaryLegs?: import("./cross-boundary-taint.js").BoundaryLegsDeclaration;
|
|
535
|
+
/** The per-call half of a `"per_call"` {@link boundaryLegs} declaration, written beside the code that dispatches the call: the legs one
|
|
536
|
+
* call travels, given its arguments as the tool reads them ({@link import("./cross-boundary-taint.js").BoundaryLegsFor}). Read only for
|
|
537
|
+
* a row that declares `"per_call"`; such a row with no resolver, or a resolver that throws, reads as every leg off-target. */
|
|
538
|
+
boundaryLegsFor?: import("./cross-boundary-taint.js").BoundaryLegsFor;
|
|
527
539
|
/**
|
|
528
540
|
* design/388 §2.2 ② — the parameter that names this tool's filesystem TARGET and how it is touched.
|
|
529
541
|
* Present ⇔ the tool can be confirmed BY PATH: write confinement (`allowDirs`, the fs-write gate,
|
|
@@ -1156,6 +1168,10 @@ export interface ToolExecuteContext {
|
|
|
1156
1168
|
* tool runs outside a Runner task.
|
|
1157
1169
|
*/
|
|
1158
1170
|
inheritedGateForChildren?: () => import("./runner/contracts.js").InheritedGate;
|
|
1171
|
+
/** The run tree's cross-boundary token ({@link import("./runner/contracts.js").RunInternals.crossBoundaryTree}) — Runner-filled, opaque
|
|
1172
|
+
* and frozen; a delegation or workflow tool hands this SAME token into its child's trusted internals (and records it on a background
|
|
1173
|
+
* handle), so the child joins the tree and a bit any leg sets is read by every other. No tool reads or writes the state through it. */
|
|
1174
|
+
crossBoundaryTreeForChildren?: import("./cross-boundary-taint.js").CrossBoundaryTreeToken;
|
|
1159
1175
|
/**
|
|
1160
1176
|
* design/180 half A — the delegation runtime-provenance ARMING face. Runner-filled; a delegation
|
|
1161
1177
|
* tool calls it at spawn time: a non-undefined return means this (parent) run is armed (it mounts
|
package/dist/core/tools.js
CHANGED
|
@@ -95,6 +95,8 @@ function buildProduct(spec, owner, options) {
|
|
|
95
95
|
...(spec.alwaysLoad !== undefined ? { alwaysLoad: spec.alwaysLoad } : {}),
|
|
96
96
|
...(spec.prepareArguments ? { prepareArguments: spec.prepareArguments } : {}),
|
|
97
97
|
...(spec.family !== undefined ? { family: spec.family } : {}),
|
|
98
|
+
...(spec.boundaryLegs !== undefined ? { boundaryLegs: spec.boundaryLegs } : {}),
|
|
99
|
+
...(spec.boundaryLegsFor !== undefined ? { boundaryLegsFor: spec.boundaryLegsFor } : {}),
|
|
98
100
|
...(spec.pathTarget !== undefined ? { pathTarget: spec.pathTarget } : {}),
|
|
99
101
|
...(spec.ruleFace !== undefined ? { ruleFace: spec.ruleFace } : {}),
|
|
100
102
|
...(spec.renderHints !== undefined ? { renderHints: spec.renderHints } : {}),
|
package/dist/core/trace.d.ts
CHANGED
|
@@ -332,8 +332,11 @@ export type TraceEvent = {
|
|
|
332
332
|
* `tool.call.turn`. Lets a bridge put a `chat` span and the `execute_tool` spans of the tools that
|
|
333
333
|
* call requested under one parent without re-deriving turn boundaries from event order.
|
|
334
334
|
*
|
|
335
|
-
* ABSENT on the
|
|
336
|
-
*
|
|
335
|
+
* ABSENT on every provider call fired beside the loop — the compaction summarizer (it fires from the turn-boundary hook), the
|
|
336
|
+
* classifier gate, a mod's own call: none is a loop turn, so any number here would be a different measurement wearing the same
|
|
337
|
+
* name. So `turn` present ⇔ the call is the main loop's own; absent ⇔ a call outside the loop. Those rows also carry
|
|
338
|
+
* `latencyMs: 0` (no wall time is measured for them), so a latency average taken over the rows that carry a `turn` is not diluted
|
|
339
|
+
* by them.
|
|
337
340
|
*/
|
|
338
341
|
turn?: number;
|
|
339
342
|
/** Normalized prompt tokens that MISSED the cache (Anthropic-protocol `input_tokens`
|
|
@@ -555,6 +558,25 @@ export type TraceEvent = {
|
|
|
555
558
|
* joined — provider failure, refused snapshot, rollback refusal, missing durable persistence. */
|
|
556
559
|
message: string;
|
|
557
560
|
ts: number;
|
|
561
|
+
} | {
|
|
562
|
+
/**
|
|
563
|
+
* The device lane's cross-boundary TAINT on a tree that executes on a target device: once when a leg is prepared on an armed
|
|
564
|
+
* tree (`phase: "prepare"`; `"resume"` on a durable resume's leg), and once when this leg first lets an off-target read into the
|
|
565
|
+
* tree (`"observed"`, with the call). A tree that never armed emits none. Metadata only.
|
|
566
|
+
*/
|
|
567
|
+
kind: "permission.cross_boundary_taint";
|
|
568
|
+
version: 1;
|
|
569
|
+
taskId: string;
|
|
570
|
+
runId: string;
|
|
571
|
+
phase: "prepare" | "resume" | "observed";
|
|
572
|
+
/** The tree's taint bits after the event. */
|
|
573
|
+
taint: readonly import("./cross-boundary-taint.js").CrossBoundaryTaintBit[];
|
|
574
|
+
/** The tree has run under the `multi_tenant` posture since it armed. */
|
|
575
|
+
governed: boolean;
|
|
576
|
+
/** The call that let the off-target read in (`observed` only). */
|
|
577
|
+
toolName?: string;
|
|
578
|
+
toolCallId?: string;
|
|
579
|
+
ts: number;
|
|
558
580
|
} | {
|
|
559
581
|
/**
|
|
560
582
|
* F-012 L2 — a pending ask was AUTO-ADMITTED by the sandbox-admission leg: the deployment's
|
package/dist/core/types.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export type { ToolEffect, ToolContentOrigin, ReversibilityVerdict, ReadRootGrant
|
|
|
19
19
|
export type { BeforeWriteRequest, BeforeWriteResult, BeforeWriteHook, TrackEditRequest, TrackEditResult, TrackFileEditHook, FileEditedNotice, FileEditedHook, HandsBandOptions } from "./hands-band.js";
|
|
20
20
|
export type { AgentDefinition, SkillSpec } from "./agent-definition.js";
|
|
21
21
|
export type { McpServerSpec, A2aServerSpec, McpElicitRequest, McpElicitResponse, OnElicit, McpRevocationLedger, McpMountIdentity, DeclarationFault, DeclarationPathRule, DeclarationRead, ToolAxesRead, ToolAxesSurface } from "./mcp-server-spec.js";
|
|
22
|
-
export { DECLARATION_PATH_RULES, declarationFaultOf, declarerWord, readMcpToolAxes, readToolAxes, receiveDeclaration, toolAxesRefusal } from "./mcp-server-spec.js";
|
|
22
|
+
export { DECLARATION_PATH_RULES, NO_DECLARATION_PATH_RULES, dataKind, declarationFaultOf, declarerWord, perToolEmptyName, perToolEntryRefusal, quotedName, readMcpToolAxes, readToolAxes, receiveDeclaration, receivePerToolDeclaration, toolAxesRefusal } from "./mcp-server-spec.js";
|
|
23
23
|
export type { TaskLimits } from "./task-limits.js";
|
|
24
24
|
export type { TaskStatus, RemoteEnvFailureNote, EffectiveMemoryScopes, TaskResult, HumanReviewGateRow } from "./task-result.js";
|
|
25
25
|
export type { TerminalCause, PausedCause } from "./terminal-cause.js";
|
|
@@ -30,6 +30,6 @@ export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./runtime-caps.js"
|
|
|
30
30
|
export type { BackgroundChildEvent, BackgroundChildRow, DelegationLifecycleEvent } from "./delegation-frames.js";
|
|
31
31
|
export { __resetMalformedDelegationSeatAnnouncement, backgroundChildTerminal, deliverDelegationLifecycle, emitsChildRowFrames, taskStartedFrame } from "./delegation-frames.js";
|
|
32
32
|
export type { ProjectMemoryLoad, ResumePreflightInfo, ResumePreflightVerdict, RunnerDeps } from "./runner-deps.js";
|
|
33
|
-
export type { EngineNotice, OwedUserInputAccount, UserInputUndrainedCause } from "./engine-notice.js";
|
|
33
|
+
export type { ApprovalCarryRefusal, EngineNotice, OwedUserInputAccount, UserInputUndrainedCause } from "./engine-notice.js";
|
|
34
34
|
export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES, USER_INPUT_UNDRAINED_FAMILIES } from "./engine-notice.js";
|
|
35
35
|
export type { AgentTool, Model, StreamFn, ThinkingLevel, ToolInputValidationContext, ToolInputVerdict };
|
package/dist/core/types.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { MODEL_ROLES } from "./model-seat.js";
|
|
2
|
-
export { DECLARATION_PATH_RULES, declarationFaultOf, declarerWord, readMcpToolAxes, readToolAxes, receiveDeclaration, toolAxesRefusal } from "./mcp-server-spec.js";
|
|
2
|
+
export { DECLARATION_PATH_RULES, NO_DECLARATION_PATH_RULES, dataKind, declarationFaultOf, declarerWord, perToolEmptyName, perToolEntryRefusal, quotedName, readMcpToolAxes, readToolAxes, receiveDeclaration, receivePerToolDeclaration, toolAxesRefusal } from "./mcp-server-spec.js";
|
|
3
3
|
export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./runtime-caps.js";
|
|
4
4
|
export { __resetMalformedDelegationSeatAnnouncement, backgroundChildTerminal, deliverDelegationLifecycle, emitsChildRowFrames, taskStartedFrame } from "./delegation-frames.js";
|
|
5
5
|
export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES, USER_INPUT_UNDRAINED_FAMILIES } from "./engine-notice.js";
|
|
@@ -238,6 +238,13 @@ export declare function defuseExactMarkInSegments(segments: readonly string[], m
|
|
|
238
238
|
* {@link FENCED_LANE_ENVELOPE_TAGS}) and at each envelope's own mint site (the registry's guard column).
|
|
239
239
|
*/
|
|
240
240
|
export declare function sanitizeUntrustedText(text: string, extraTags?: string[]): string;
|
|
241
|
+
/**
|
|
242
|
+
* THE sentence every arm speaks when it refuses a person's text because {@link sanitizeUntrustedText} would change it — the engine's own
|
|
243
|
+
* sentinel tag, opening (with or without attributes) or closing, which the judge refuses alike. `subject` names what carried it. Produced
|
|
244
|
+
* once, here beside the judge, so the sentence and the rule cannot drift apart by arm (the decide's deny / reject `reason`, a plan's
|
|
245
|
+
* `editedPlan`, an allow's `feedback`, a trusted live steer).
|
|
246
|
+
*/
|
|
247
|
+
export declare function sentinelTagRefusal(subject: string): string;
|
|
241
248
|
/**
|
|
242
249
|
* [c209-C] 收口 C1/C2 (metadata-driven, replaces the shape-anchored
|
|
243
250
|
* `stripLeadingSystemReminders`) — cut the engine-prepended prefix off a user-lane message using the
|
|
@@ -66,14 +66,6 @@ export const ENGINE_ENVELOPES = Object.freeze([
|
|
|
66
66
|
fenced: true,
|
|
67
67
|
disclosed: true,
|
|
68
68
|
},
|
|
69
|
-
{
|
|
70
|
-
tag: "working-file",
|
|
71
|
-
kind: "framing",
|
|
72
|
-
mint: "core/auto-compaction.ts (post-compaction working-file snapshot)",
|
|
73
|
-
guard: "sanitizeUntrustedText(WORKING_FILE_BREAKOUT_TAGS) + escapeWorkingFilePathAttr",
|
|
74
|
-
fenced: false,
|
|
75
|
-
disclosed: false,
|
|
76
|
-
},
|
|
77
69
|
{
|
|
78
70
|
tag: "summary",
|
|
79
71
|
kind: "framing",
|
|
@@ -482,6 +474,9 @@ export function defuseExactMarkInSegments(segments, mark) {
|
|
|
482
474
|
export function sanitizeUntrustedText(text, extraTags = []) {
|
|
483
475
|
return text.replace(breakoutRe(extraTags), (m) => ESCAPED_LT + m.slice(1));
|
|
484
476
|
}
|
|
477
|
+
export function sentinelTagRefusal(subject) {
|
|
478
|
+
return `${subject} must not contain a <system-reminder> tag (opening or closing)`;
|
|
479
|
+
}
|
|
485
480
|
export function cutEnginePrefix(text, enginePrefixChars) {
|
|
486
481
|
if (typeof enginePrefixChars === "number" &&
|
|
487
482
|
Number.isInteger(enginePrefixChars) &&
|
|
@@ -27,6 +27,8 @@ import type { HumanInputAttachment } from "./task-event.js";
|
|
|
27
27
|
import { type ModelFileReader } from "../tools/fs/fs-read.js";
|
|
28
28
|
import type { SyntheticReadJudge } from "./synthetic-read-verdict.js";
|
|
29
29
|
import { type ReminderDisclosureCounts } from "./reminder-disclosure.js";
|
|
30
|
+
import { type AgentMessage } from "../internal/harness.js";
|
|
31
|
+
import type { ReadEntry } from "../tools/fs/safety.js";
|
|
30
32
|
import type { ContextWindowOverlay } from "./context-settings.js";
|
|
31
33
|
/** At most this many attachments on one objective. */
|
|
32
34
|
export declare const USER_ATTACHMENTS_MAX = 20;
|
|
@@ -116,6 +118,13 @@ export declare function userAttachmentDeclarations(screened: readonly ScreenedUs
|
|
|
116
118
|
* run on the captured values before any attachment is read or delivered. Throws `config.user_attachment_invalid`.
|
|
117
119
|
*/
|
|
118
120
|
export declare function admitUserAttachmentImages(screened: readonly ScreenedUserAttachment[]): Promise<ReadonlyMap<number, ImageContent>>;
|
|
121
|
+
/** The transmission an attachment frame is (the read-state entry its delivery records carries it): when the frame leaves
|
|
122
|
+
* the request — a trim drops it — the entry retires with it. One spelling for the mint and every remover. */
|
|
123
|
+
export declare function attachmentTransmissionId(a: Pick<UserMessageAttachment, "inputId" | "ordinal">): string;
|
|
124
|
+
/** The transmissions a request-view drop took out: those of `view`'s messages that no message of `kept` still carries (a
|
|
125
|
+
* reused call id kept elsewhere is not gone). The guard trim retires the read-state entries they delivered (so the next
|
|
126
|
+
* Read sends the contents again); a later read of the same file is a transmission of its own and stays. */
|
|
127
|
+
export declare function droppedTransmissions(view: ReadonlyArray<AgentMessage>, kept: ReadonlyArray<AgentMessage>): string[];
|
|
119
128
|
/** One minted frame: the trailing message's seed, and the commit its delivery owes (absent ⇒ nothing to commit). */
|
|
120
129
|
export interface MintedAttachmentFrame {
|
|
121
130
|
readonly seed: {
|
|
@@ -160,6 +169,40 @@ export declare function readObjectiveAttachments(prepared: Pick<import("./runner
|
|
|
160
169
|
frames: MintedAttachmentFrame[];
|
|
161
170
|
chars: number;
|
|
162
171
|
}>;
|
|
172
|
+
/** What a compaction's restore reads with: the leg's one file reader (the Read tool's) and the run's synthetic-Read judge,
|
|
173
|
+
* and where a file it does not deliver is reported (a restored file's outcome has no wire face of its own). */
|
|
174
|
+
export interface CompactionRestoreSeat {
|
|
175
|
+
readonly reader: ModelFileReader;
|
|
176
|
+
readonly judge: SyntheticReadJudge;
|
|
177
|
+
readonly cwd: () => string | undefined;
|
|
178
|
+
readonly mark: string | undefined;
|
|
179
|
+
readonly counts: ReminderDisclosureCounts | undefined;
|
|
180
|
+
readonly signal: AbortSignal;
|
|
181
|
+
readonly report: (path: string, reason: string) => void;
|
|
182
|
+
}
|
|
183
|
+
/** One restore: the files to re-read (most recent first) and its bounds. */
|
|
184
|
+
export interface CompactionRestoreRequest {
|
|
185
|
+
readonly candidates: readonly string[];
|
|
186
|
+
readonly maxFiles: number;
|
|
187
|
+
/** What one file may deliver, in its own characters (before the Read's line numbers); an image the estimator's fixed
|
|
188
|
+
* weight × `charsPerToken`. A file over it, or whose frame would send more of its contents (line numbers included)
|
|
189
|
+
* than what is left of `totalChars`, is named, not sent. */
|
|
190
|
+
readonly perFileChars: number;
|
|
191
|
+
readonly totalChars: number;
|
|
192
|
+
readonly charsPerToken: number;
|
|
193
|
+
/** The read state of the context the summary leaves (`readFileStateAfterSummary`): what the reads dedup against. */
|
|
194
|
+
readonly dedupAgainst: ReadonlyMap<string, ReadEntry>;
|
|
195
|
+
}
|
|
196
|
+
/** The synthetic-Read judge's probe face for the restore (probe id `compaction-restore-visibility-probe`). */
|
|
197
|
+
export declare const COMPACTION_RESTORE_PROBE_FACE = "compaction-restore";
|
|
198
|
+
/**
|
|
199
|
+
* Re-read the files a compaction restores and mint their frames — each a Read on the model's behalf ({@link readRestored}),
|
|
200
|
+
* deduplicated against the context the summary leaves, so a file the summary takes out of view is never answered
|
|
201
|
+
* "unchanged"; the frame is the attachment seat's own. A file the context still holds is skipped; a file over
|
|
202
|
+
* its share is a frame that names it and says it is too large (no part of its contents); a refused file is a frame with
|
|
203
|
+
* the reason. Side-effect free toward the run: each frame carries the commit its delivery owes.
|
|
204
|
+
*/
|
|
205
|
+
export declare function readCompactionRestore(seat: CompactionRestoreSeat, req: CompactionRestoreRequest): Promise<MintedAttachmentFrame[]>;
|
|
163
206
|
/** The last attachment frame of the group the message `id` opens, or `id` when it has none (a `resumeAt` that keeps the
|
|
164
207
|
* message keeps its group). The frames of one input are appended one after another under its message (each the child of
|
|
165
208
|
* the one before), all carrying its input id. */
|