@sema-agent/core 7.50.2 → 7.51.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 +263 -0
- package/dist/agents/child-failure.d.ts +5 -16
- package/dist/agents/child-failure.js +4 -24
- package/dist/agents/subagent-steps.js +2 -2
- package/dist/agents/subagent.d.ts +4 -13
- package/dist/agents/subagent.js +94 -204
- package/dist/agents/tool-filter.d.ts +2 -2
- package/dist/brain/anthropic.d.ts +1 -1
- package/dist/brain/anthropic.js +7 -5
- package/dist/brain/open-responses.d.ts +1 -1
- package/dist/brain/open-responses.js +3 -2
- package/dist/brain/openai.d.ts +1 -1
- package/dist/brain/openai.js +3 -2
- package/dist/brain/request-route.d.ts +2 -2
- package/dist/brain/route-adjudicator.d.ts +16 -7
- package/dist/brain/route-adjudicator.js +23 -7
- package/dist/brain/route-conformance.js +23 -5
- package/dist/brain/stream-engine.js +9 -3
- package/dist/core/a2a.js +6 -8
- package/dist/core/allow-entry.d.ts +45 -26
- package/dist/core/allow-entry.js +48 -24
- package/dist/core/arg-summary.d.ts +8 -85
- package/dist/core/arg-summary.js +4 -386
- package/dist/core/ask-origin.d.ts +35 -33
- package/dist/core/ask-origin.js +9 -11
- package/dist/core/checkpoint-requirements.d.ts +6 -0
- package/dist/core/checkpoint-requirements.js +1 -0
- package/dist/core/checkpoint-store.d.ts +15 -34
- package/dist/core/checkpoint-store.js +5 -4
- package/dist/core/classifier-unavailable-arm.d.ts +12 -8
- package/dist/core/classifier-unavailable-arm.js +7 -2
- package/dist/core/credential-vocabulary.d.ts +3 -2
- package/dist/core/credential-vocabulary.js +27 -18
- package/dist/core/delegation-frames.d.ts +40 -15
- package/dist/core/delegation-frames.js +34 -0
- package/dist/core/engine-notice.d.ts +35 -11
- package/dist/core/gate-fold.js +9 -7
- package/dist/core/gate-lanes.js +6 -4
- package/dist/core/gate-outcome.d.ts +81 -15
- package/dist/core/gate-outcome.js +168 -67
- package/dist/core/governance-codes.d.ts +7 -1
- package/dist/core/governance-codes.js +9 -0
- package/dist/core/hooks.d.ts +4 -4
- package/dist/core/hooks.js +4 -3
- package/dist/core/mcp-connection-pool.d.ts +2 -0
- package/dist/core/mcp-connection-pool.js +2 -1
- package/dist/core/mcp-failure.js +2 -1
- package/dist/core/mcp-server-spec.d.ts +27 -5
- package/dist/core/mcp.d.ts +13 -38
- package/dist/core/mcp.js +28 -23
- package/dist/core/media-byte-cap.d.ts +25 -0
- package/dist/core/media-byte-cap.js +18 -2
- package/dist/core/memory-engine/consolidation-driver.js +1 -1
- package/dist/core/mode-policy.d.ts +25 -1
- package/dist/core/mode-policy.js +28 -13
- package/dist/core/own-property-receipt.d.ts +18 -0
- package/dist/core/own-property-receipt.js +39 -0
- package/dist/core/permission-rule-model.d.ts +32 -11
- package/dist/core/permission-rule-model.js +12 -7
- package/dist/core/persisted-rule-arms.d.ts +3 -3
- package/dist/core/prompt-section-seat.d.ts +54 -0
- package/dist/core/prompt-section-seat.js +49 -0
- package/dist/core/protocol-http-auth.d.ts +44 -0
- package/dist/core/protocol-http-auth.js +45 -0
- package/dist/core/read-face-seats.d.ts +30 -0
- package/dist/core/read-face-seats.js +38 -0
- package/dist/core/redaction-passes.d.ts +82 -0
- package/dist/core/redaction-passes.js +378 -0
- package/dist/core/remote-env.d.ts +4 -3
- package/dist/core/resume-startup-cause.d.ts +56 -0
- package/dist/core/resume-startup-cause.js +43 -0
- package/dist/core/rule-denial-sentence.d.ts +2 -2
- package/dist/core/runner/announce-once-ledger.js +2 -2
- package/dist/core/runner/classifier-ladder.d.ts +17 -13
- package/dist/core/runner/classifier-ladder.js +12 -10
- package/dist/core/runner/construction-doors.js +9 -20
- package/dist/core/runner/contracts.d.ts +4 -4
- package/dist/core/runner/gate-exit.js +2 -2
- package/dist/core/runner/memory-consolidation-write-judge.d.ts +53 -9
- package/dist/core/runner/memory-consolidation-write-judge.js +39 -1
- package/dist/core/runner/permission-rule-lanes.d.ts +8 -13
- package/dist/core/runner/person-path-rows.d.ts +4 -3
- package/dist/core/runner/policy-throw.js +4 -4
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -3
- package/dist/core/runner/prepare-caps-and-workflow.js +8 -6
- package/dist/core/runner/prepare-gate-stations.js +4 -4
- package/dist/core/runner/prepare-hands-readface.js +1 -19
- package/dist/core/runner/prepare-inherited-gate.js +10 -9
- package/dist/core/runner/prepare-policy-chain.d.ts +3 -5
- package/dist/core/runner/prepare-policy-chain.js +10 -13
- package/dist/core/runner/prepare-project-context.d.ts +4 -4
- package/dist/core/runner/prepare-project-context.js +2 -1
- package/dist/core/runner/prepare-prompt-assembly.js +1 -0
- package/dist/core/runner/prepare-prompt-inputs.d.ts +1 -1
- package/dist/core/runner/prepare-prompt-inputs.js +4 -4
- package/dist/core/runner/prepare-protocol-tools.d.ts +4 -3
- package/dist/core/runner/prepare-protocol-tools.js +3 -2
- package/dist/core/runner/prepare-task.js +6 -4
- package/dist/core/runner/prepare-turn-wiring.d.ts +16 -13
- package/dist/core/runner/prepare-turn-wiring.js +8 -7
- package/dist/core/runner/run-harness-handlers.js +2 -2
- package/dist/core/runner/run-leg.js +10 -9
- package/dist/core/runner/run-settle-and-teardown.js +5 -5
- package/dist/core/runner/run-turn-boundary.js +3 -2
- package/dist/core/runner/runtask.d.ts +1 -2
- package/dist/core/runner/runtask.js +8 -12
- package/dist/core/runner/session-rule-policy.d.ts +15 -11
- package/dist/core/runner/session-rule-policy.js +43 -33
- package/dist/core/runner/stream-lifecycle-verbs.js +2 -2
- package/dist/core/runner/stream-settle-backstop.js +2 -1
- package/dist/core/runner/sub-agent-deny-lists.d.ts +12 -8
- package/dist/core/runner/sub-agent-deny-lists.js +23 -12
- package/dist/core/runner/terminal-account.js +3 -3
- package/dist/core/runner/tool-output-projection.js +3 -8
- package/dist/core/runner/tool-result-media-seat.d.ts +19 -0
- package/dist/core/runner/tool-result-media-seat.js +13 -0
- package/dist/core/runner/turn-attachments.d.ts +13 -12
- package/dist/core/runner/turn-attachments.js +11 -7
- package/dist/core/runner-deps.d.ts +4 -3
- package/dist/core/safety-merge-corpus.js +21 -21
- package/dist/core/secret-env.js +1 -1
- package/dist/core/session-policy-store.d.ts +89 -72
- package/dist/core/session-policy-store.js +100 -93
- package/dist/core/shell-read-silence.d.ts +38 -4
- package/dist/core/shell-read-silence.js +102 -0
- package/dist/core/side-query.d.ts +7 -8
- package/dist/core/skill-grant-binding.d.ts +32 -11
- package/dist/core/skill-grant-binding.js +11 -3
- package/dist/core/skill-grant.d.ts +4 -3
- package/dist/core/skill-grant.js +5 -4
- package/dist/core/skills-directory.d.ts +12 -1
- package/dist/core/skills-directory.js +17 -8
- package/dist/core/store-contracts/checkpoint-store-contract.d.ts +2 -0
- package/dist/core/store-contracts/checkpoint-store-contract.js +3 -0
- package/dist/core/swappable-deps.d.ts +15 -1
- package/dist/core/swappable-deps.js +25 -1
- package/dist/core/synthetic-read-verdict.d.ts +16 -14
- package/dist/core/synthetic-read-verdict.js +28 -8
- package/dist/core/task-notification.d.ts +13 -3
- package/dist/core/task-notification.js +12 -1
- package/dist/core/task-spec.d.ts +14 -15
- package/dist/core/tool-name-readings.d.ts +0 -4
- package/dist/core/tool-name-readings.js +0 -1
- package/dist/core/tool-policy.d.ts +40 -9
- package/dist/core/tool-policy.js +25 -7
- package/dist/core/types.d.ts +3 -3
- package/dist/core/types.js +1 -1
- package/dist/core/untrusted-egress.d.ts +60 -11
- package/dist/core/untrusted-egress.js +120 -9
- package/dist/core/untrusted-text.js +16 -0
- package/dist/core/wiring-manifest.d.ts +22 -8
- package/dist/core/wiring-manifest.js +12 -4
- package/dist/engine/harness/agent-harness.d.ts +2 -1
- package/dist/engine/harness/agent-harness.js +4 -1
- package/dist/engine/harness/types.d.ts +3 -0
- package/dist/engine/llm/types.d.ts +7 -9
- package/dist/engine/loop/agent-loop.d.ts +8 -3
- package/dist/engine/loop/agent-loop.js +26 -9
- package/dist/engine/loop/types.d.ts +10 -0
- package/dist/index.d.ts +17 -5
- package/dist/index.js +14 -5
- package/dist/orchestration/run-workflow-tool.js +8 -8
- package/dist/orchestration/workflow.js +2 -2
- package/dist/prompt-assembly/assemble.d.ts +3 -1
- package/dist/prompt-assembly/assemble.js +6 -0
- package/dist/prompts/cowork.d.ts +42 -0
- package/dist/prompts/cowork.js +529 -0
- package/dist/prompts/default.d.ts +14 -1
- package/dist/prompts/default.js +3 -0
- package/dist/stores/file/session-policy-store.d.ts +6 -3
- package/dist/stores/file/session-policy-store.js +5 -16
- package/dist/tools/artifact/artifact-tool.js +2 -0
- package/dist/tools/fs/image-admission.d.ts +57 -4
- package/dist/tools/fs/image-admission.js +85 -0
- package/dist/tools/fs/path-containment.d.ts +2 -0
- package/dist/tools/fs/path-containment.js +5 -0
- package/dist/tools/fs/shell-read-check.d.ts +31 -6
- package/dist/tools/fs/shell-read-check.js +2 -4
- package/dist/tools/fs/shell-read-environment.d.ts +10 -25
- package/dist/tools/fs/shell-read-environment.js +6 -18
- package/dist/tools/fs/shell-read-establish.d.ts +3 -2
- package/dist/tools/fs/shell-read-establish.js +5 -5
- package/dist/tools/fs/shell-read-judge.d.ts +38 -8
- package/dist/tools/fs/shell-read-judge.js +12 -10
- package/dist/tools/web.js +2 -2
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +94 -10
- package/wire-changes/core@7.51.0.json +2421 -0
|
@@ -19,7 +19,6 @@ function probeFaceWord(face) {
|
|
|
19
19
|
throw new Error(`synthetic probe id: the probe face must be a lowercase word (letters and hyphens), got ${JSON.stringify(face)}`);
|
|
20
20
|
return face;
|
|
21
21
|
}
|
|
22
|
-
const ABORTED = AbortSignal.abort();
|
|
23
22
|
function sameArguments(value, probed) {
|
|
24
23
|
try {
|
|
25
24
|
return deepJsonEqual(value, probed);
|
|
@@ -28,6 +27,22 @@ function sameArguments(value, probed) {
|
|
|
28
27
|
return false;
|
|
29
28
|
}
|
|
30
29
|
}
|
|
30
|
+
function layerWait(run) {
|
|
31
|
+
const wait = new AbortController();
|
|
32
|
+
const runEnded = () => wait.abort(run?.reason);
|
|
33
|
+
if (run?.aborted === true)
|
|
34
|
+
runEnded();
|
|
35
|
+
else
|
|
36
|
+
run?.addEventListener("abort", runEnded, { once: true });
|
|
37
|
+
return {
|
|
38
|
+
signal: wait.signal,
|
|
39
|
+
end: () => {
|
|
40
|
+
run?.removeEventListener("abort", runEnded);
|
|
41
|
+
if (!wait.signal.aborted)
|
|
42
|
+
wait.abort(new DOMException("the judgment stopped waiting for this layer", "TimeoutError"));
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
31
46
|
export function createSyntheticReadJudge(layers) {
|
|
32
47
|
const judge = createProbeJudge(layers, "read");
|
|
33
48
|
return async (call, face, budget) => {
|
|
@@ -61,9 +76,10 @@ export function createSyntheticWriteJudge(layers, facts) {
|
|
|
61
76
|
}
|
|
62
77
|
function createProbeJudge(layers, kind) {
|
|
63
78
|
const everyAskHeld = kind === "write";
|
|
64
|
-
return async (
|
|
79
|
+
return async (unstated, budget) => {
|
|
65
80
|
const deadlineAt = budget?.deadlineAt ?? Date.now() + ORG_ADJUDICATION_TIMEOUT_MS;
|
|
66
81
|
const left = () => Math.max(0, Math.min(ORG_ADJUDICATION_TIMEOUT_MS, deadlineAt - Date.now()));
|
|
82
|
+
const probe = { ...unstated, approvalReach: "none" };
|
|
67
83
|
const probedArgs = structuredClone(probe.args);
|
|
68
84
|
const stamped = layers.stampCallTarget?.(probe, layers.signal);
|
|
69
85
|
const req = stamped !== undefined ? await stamped : probe;
|
|
@@ -84,7 +100,7 @@ function createProbeJudge(layers, kind) {
|
|
|
84
100
|
cannot(layer, "timed_out", "the judgment's wait budget was spent before this layer was asked");
|
|
85
101
|
return true;
|
|
86
102
|
};
|
|
87
|
-
const policyLayer = async (layer, policy,
|
|
103
|
+
const policyLayer = async (layer, policy, ancestorOwned = false) => {
|
|
88
104
|
if (spent(layer))
|
|
89
105
|
return undefined;
|
|
90
106
|
const waitMs = left();
|
|
@@ -92,18 +108,22 @@ function createProbeJudge(layers, kind) {
|
|
|
92
108
|
let thrown = undefined;
|
|
93
109
|
const TIMEOUT = Symbol("timeout");
|
|
94
110
|
let d;
|
|
111
|
+
const wait = layerWait(layers.signal);
|
|
95
112
|
try {
|
|
96
113
|
d = await settleOrgVerdictWithin(Promise.resolve()
|
|
97
|
-
.then(() => policy.check(req, signal))
|
|
114
|
+
.then(() => policy.check(req, wait.signal))
|
|
98
115
|
.catch((err) => {
|
|
99
116
|
thrown = { err };
|
|
100
117
|
return TIMEOUT;
|
|
101
|
-
}), TIMEOUT, {
|
|
118
|
+
}), TIMEOUT, { signal: wait.signal, timeoutMs: waitMs, onFallback: () => void (timedOut = true) });
|
|
102
119
|
}
|
|
103
120
|
catch (err) {
|
|
104
121
|
cannot(layer, "threw", describeThrown(err));
|
|
105
122
|
return undefined;
|
|
106
123
|
}
|
|
124
|
+
finally {
|
|
125
|
+
wait.end();
|
|
126
|
+
}
|
|
107
127
|
if (thrown !== undefined) {
|
|
108
128
|
cannot(layer, "threw", describeThrown(thrown.err));
|
|
109
129
|
return undefined;
|
|
@@ -144,19 +164,19 @@ function createProbeJudge(layers, kind) {
|
|
|
144
164
|
cannot("skill_rows", "threw", describeThrown(err));
|
|
145
165
|
}
|
|
146
166
|
if (layers.denyNarrowingPolicy !== undefined) {
|
|
147
|
-
const v = await policyLayer("narrowing", layers.denyNarrowingPolicy
|
|
167
|
+
const v = await policyLayer("narrowing", layers.denyNarrowingPolicy);
|
|
148
168
|
if (v !== undefined)
|
|
149
169
|
return v;
|
|
150
170
|
}
|
|
151
171
|
if (layers.callerPolicy !== undefined) {
|
|
152
|
-
const v = await policyLayer("caller_policy", layers.callerPolicy,
|
|
172
|
+
const v = await policyLayer("caller_policy", layers.callerPolicy, (layers.inheritedPolicies ?? []).includes(layers.callerPolicy));
|
|
153
173
|
if (v !== undefined)
|
|
154
174
|
return v;
|
|
155
175
|
}
|
|
156
176
|
for (const parent of layers.inheritedPolicies ?? []) {
|
|
157
177
|
if (parent === layers.callerPolicy)
|
|
158
178
|
continue;
|
|
159
|
-
const v = await policyLayer("inherited_constraint", parent,
|
|
179
|
+
const v = await policyLayer("inherited_constraint", parent, true);
|
|
160
180
|
if (v !== undefined)
|
|
161
181
|
return v;
|
|
162
182
|
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { MailboxAppendMessage, MailboxStore } from "./mailbox-store.js";
|
|
2
|
+
/** The TERMINAL words of {@link TaskNotificationStatus}: the one table every "is this frame a completion?"
|
|
3
|
+
* reading asks, exported as a value so a consumer outside the package reads these words rather than its own list. */
|
|
4
|
+
export declare const TASK_NOTIFICATION_TERMINAL_STATUSES: readonly ["completed", "failed", "killed", "cancelled"];
|
|
5
|
+
export type TaskNotificationTerminalStatus = (typeof TASK_NOTIFICATION_TERMINAL_STATUSES)[number];
|
|
2
6
|
/** design/135 G2: `"event"` is the ONE non-terminal member — a Monitor batch notification (new stdout
|
|
3
7
|
* lines from a still-running watch). Everything else is a terminal completion notification. */
|
|
4
|
-
export type TaskNotificationStatus =
|
|
8
|
+
export type TaskNotificationStatus = TaskNotificationTerminalStatus | "event";
|
|
5
9
|
export type SystemInjectionPriority = "now" | "next" | "later";
|
|
6
10
|
/**
|
|
7
11
|
* The outcome an injection entry settles with — what the session did with the frame:
|
|
@@ -84,8 +88,8 @@ export interface TaskNotificationPayload {
|
|
|
84
88
|
* `inlineUntrusted` + attribute-escaping, never as authority. Absent on every internal lane. */
|
|
85
89
|
source?: string;
|
|
86
90
|
/** design/134 §3.3: only on `status:"killed"` — who stopped it. MIRROR of task-registry `StopSource`
|
|
87
|
-
* (the single source; inlined here to avoid an import cycle — task-registry imports this module;
|
|
88
|
-
*
|
|
91
|
+
* (the single source; inlined here to avoid an import cycle — task-registry imports this module);
|
|
92
|
+
* `BackgroundChildEvent.stoppedBy` is typed by this member and projected from it. OPEN ENUM:
|
|
89
93
|
* consumers must tolerate unknown values (a future "timeout" etc. is not breaking) and fall back
|
|
90
94
|
* to default copy. */
|
|
91
95
|
stoppedBy?: "user" | "parent" | "system" | (string & {});
|
|
@@ -507,6 +511,12 @@ export declare function terminalFrameFacets(facts: {
|
|
|
507
511
|
warning?: string | undefined;
|
|
508
512
|
compaction?: TaskNotificationPayload["compaction"] | undefined;
|
|
509
513
|
}): Pick<TaskNotificationPayload, "spawnName" | "handback" | "compaction">;
|
|
514
|
+
/**
|
|
515
|
+
* A delegated child's report as its completion frame carries it — the one value the parent's notification and the fleet
|
|
516
|
+
* terminal projected from that frame both read: redacted BEFORE the cut, with the pass the task row's copy uses (a token
|
|
517
|
+
* across the cut is never half-shown), then cut with an honest total. Absent in ⇒ absent out.
|
|
518
|
+
*/
|
|
519
|
+
export declare function notifyResultField(result: string | undefined): string | undefined;
|
|
510
520
|
/** The codec version this engine writes into an `engine_frame` record and the highest it reads. */
|
|
511
521
|
export declare const ENGINE_FRAME_CODEC_VERSION = 1;
|
|
512
522
|
/** The engine's own lanes — the only frames the durable park may encode (an `external` event never is). */
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
2
|
import { escapeEnvelopeTag, inlineUntrusted, sanitizeUntrustedText } from "./untrusted-text.js";
|
|
3
|
+
import { egressText } from "./untrusted-egress.js";
|
|
3
4
|
import { PEER_MESSAGE_NOTICE } from "../agents/peer-admission.js";
|
|
4
5
|
import { buildCrossSessionEnvelope, CROSS_SESSION_MESSAGE_NOTICE, neutralizePeerBody } from "../agents/cross-session-envelope.js";
|
|
6
|
+
export const TASK_NOTIFICATION_TERMINAL_STATUSES = Object.freeze(["completed", "failed", "killed", "cancelled"]);
|
|
5
7
|
export const NOTIFICATION_INJECTION_OUTCOMES = Object.freeze(["queued", "parked", "parked_durably", "dropped_duplicate"]);
|
|
6
8
|
export function isNotificationInjectionOutcome(value) {
|
|
7
9
|
return typeof value === "string" && NOTIFICATION_INJECTION_OUTCOMES.includes(value);
|
|
@@ -175,6 +177,15 @@ export function terminalFrameFacets(facts) {
|
|
|
175
177
|
...(facts.compaction !== undefined ? { compaction: { passes: facts.compaction.passes, breakerOpen: facts.compaction.breakerOpen, ...(facts.compaction.kind !== undefined ? { kind: facts.compaction.kind } : {}) } } : {}),
|
|
176
178
|
};
|
|
177
179
|
}
|
|
180
|
+
const COMPLETION_REPORT_MAX = 2_000;
|
|
181
|
+
export function notifyResultField(result) {
|
|
182
|
+
if (!result)
|
|
183
|
+
return undefined;
|
|
184
|
+
const report = egressText("same-principal", result);
|
|
185
|
+
return report.length > COMPLETION_REPORT_MAX
|
|
186
|
+
? `${report.slice(0, COMPLETION_REPORT_MAX)}\n[result truncated: ${report.length} chars total — ask the agent for it via SendMessage, or read it with TaskOutput where mounted]`
|
|
187
|
+
: report;
|
|
188
|
+
}
|
|
178
189
|
export const ENGINE_FRAME_CODEC_VERSION = 1;
|
|
179
190
|
export const ENGINE_FRAME_TASK_TYPES = Object.freeze(["background_agent", "monitor", "workflow"]);
|
|
180
191
|
const SHELL_LESS_CARRIERS = ["agentMessage", "crossSessionMessage", "crossSessionNotice", "inboxNotice", "_sema_provenance"];
|
|
@@ -257,7 +268,7 @@ export function engineFrameRecordOf(payload, priority, box) {
|
|
|
257
268
|
};
|
|
258
269
|
}
|
|
259
270
|
const MAX_TOMBSTONES = 5_000;
|
|
260
|
-
const TERMINAL_STATUSES = new Set(
|
|
271
|
+
const TERMINAL_STATUSES = new Set(TASK_NOTIFICATION_TERMINAL_STATUSES);
|
|
261
272
|
export function isDelegatedAgentTerminal(n) {
|
|
262
273
|
return n.task_type === "background_agent" && TERMINAL_STATUSES.has(n.status);
|
|
263
274
|
}
|
package/dist/core/task-spec.d.ts
CHANGED
|
@@ -478,10 +478,10 @@ export interface TaskSpec {
|
|
|
478
478
|
*
|
|
479
479
|
* Entries are read like {@link excludeTools}: a wire name or an alias it declares, `mcp__srv` / `mcp__srv__*` for every tool
|
|
480
480
|
* of a server (including tools it lists later), a glob over the tool segment. The engine resolves the list against its OWN
|
|
481
|
-
* roster at prepare — a host passes the names it was given
|
|
482
|
-
*
|
|
483
|
-
* compiled selector is applied on every later roster change (an MCP refresh or re-dial, the
|
|
484
|
-
*
|
|
481
|
+
* roster at prepare — a host passes the names it was given. A spelling no tool name can have, `mcp__*`, or an entry that is not
|
|
482
|
+
* a string is REFUSED at prepare (`config.tool_face_control`); a name no tool answers to is kept and told once (`onError`, phase
|
|
483
|
+
* `"config"`). The same compiled selector is applied on every later roster change (an MCP refresh or re-dial, the
|
|
484
|
+
* deferred-search lane). Deferral is reached through ToolSearch, so a list that leaves it out defers nothing.
|
|
485
485
|
*
|
|
486
486
|
* A tool a leg relies on (a delegated child's ReportBlocked, a teammate's SendMessage, a goal iteration's DeclareDone, an
|
|
487
487
|
* observer's report tool — the catalog's protocol column) is not an allowlist's to name; a denylist that reaches one on such a
|
|
@@ -494,8 +494,8 @@ export interface TaskSpec {
|
|
|
494
494
|
* ships the schema bytes every request — measured at zero token savings). The DENY half of the run's tool selector, read
|
|
495
495
|
* exactly as a sub-agent's denied tools are: a wire name or an alias it declares; `Tool(content)` names the whole `Tool`;
|
|
496
496
|
* `mcp__srv` / `mcp__srv__*` / a glob over the tool segment for a server's tools, `mcp__*` for every MCP tool (including tools
|
|
497
|
-
* a server lists later). A
|
|
498
|
-
* (
|
|
497
|
+
* a server lists later). A spelling no tool name can have, `"*"`, or an entry that is not a string is REFUSED at prepare; a name
|
|
498
|
+
* no tool answers to is kept (it hides a tool of that name mounted later) and told once. A deny wins over {@link allowTools}.
|
|
499
499
|
* ⚠️ A list that reaches a tool this kind of leg relies on (see {@link allowTools}) is refused; excluding a host-requested
|
|
500
500
|
* structural tool (the structured-output tool) can still strand the task — the caller owns that risk.
|
|
501
501
|
*/
|
|
@@ -610,15 +610,14 @@ export interface TaskSpec {
|
|
|
610
610
|
* real model ref passed through — core carries no model-word vocabulary). When set (non-empty),
|
|
611
611
|
* `prepareTask` REBUILDS the mounted delegation tool (via {@link ToolSpec.withAgents}) so its roster
|
|
612
612
|
* is the UNION of the boot roster and these definitions — a same-name per-task definition WINS over
|
|
613
|
-
* the boot one. Validation contract (
|
|
614
|
-
*
|
|
615
|
-
*
|
|
616
|
-
*
|
|
617
|
-
*
|
|
618
|
-
*
|
|
619
|
-
*
|
|
620
|
-
*
|
|
621
|
-
* host and hides nothing; and
|
|
613
|
+
* the boot one. Validation contract (the reference's shape — an agent's tool list filters by name,
|
|
614
|
+
* and a name nothing answers never fails the run): both lists are judged once, here and for the
|
|
615
|
+
* delegation tool's own lists alike; a `denyTools` entry is read as the reference reads it
|
|
616
|
+
* (`Tool(content)` hides the whole `Tool`, with a host notice); an entry whose spelling no tool name
|
|
617
|
+
* can have is REJECTED at task start (`config.agent.unknown_tool`); an entry naming a tool that does
|
|
618
|
+
* not exist (a server this deployment does not declare, a stale or misspelt name) is kept as written
|
|
619
|
+
* — it denies, or admits, a tool of that name if one is mounted later — and told to the host once
|
|
620
|
+
* via `RunnerDeps.onError` phase `"config"` (zero model-facing warning); and
|
|
622
621
|
* providing this field with NO delegation tool mounted is rejected too
|
|
623
622
|
* (`config.agents.no_delegation_tool`) — never a silent no-op. POLICY-NEUTRAL: a
|
|
624
623
|
* roster listing only; the 1.294 tighten-only parent-policy inheritance is applied at spawn time,
|
|
@@ -126,10 +126,6 @@ export declare const NAME_READINGS: {
|
|
|
126
126
|
readonly kind: "any";
|
|
127
127
|
readonly file: string;
|
|
128
128
|
};
|
|
129
|
-
readonly "policy.sessionRules": {
|
|
130
|
-
readonly kind: "any";
|
|
131
|
-
readonly file: string;
|
|
132
|
-
};
|
|
133
129
|
readonly "policy.sessionRules.effect": {
|
|
134
130
|
readonly kind: "wire";
|
|
135
131
|
readonly file: string;
|
|
@@ -33,7 +33,6 @@ export const NAME_READINGS = {
|
|
|
33
33
|
"policy.nameLists": any(POLICY),
|
|
34
34
|
"policy.shellToolsList": any(POLICY),
|
|
35
35
|
"policy.projectionReplay": any(POLICY),
|
|
36
|
-
"policy.sessionRules": any("src/core/runner/session-rule-policy.ts"),
|
|
37
36
|
"policy.sessionRules.effect": wire("src/core/runner/session-rule-policy.ts"),
|
|
38
37
|
"allowEntry.names": any("src/core/allow-entry.ts"),
|
|
39
38
|
"skillGrant.binding": wire("src/core/skill-grant.ts"),
|
|
@@ -130,6 +130,18 @@ export interface ToolCallRequest {
|
|
|
130
130
|
* a Runner with no `memoryEngineDir` would stamp. Read-only, frozen.
|
|
131
131
|
*/
|
|
132
132
|
exemptRoots?: readonly string[];
|
|
133
|
+
/**
|
|
134
|
+
* The request's statement that nobody can be asked about THIS call — the word of a run's own declaration
|
|
135
|
+
* (`TaskSpec.approvalReach`, the closed set `APPROVAL_REACH`), stated per request. Present (`"none"`) on every request the
|
|
136
|
+
* engine's synthetic probes hand a policy layer (the "would this call be refused outright?" judgments: the visibility
|
|
137
|
+
* probes of a file the model did not ask to read, the background memory consolidation's write probes); absent on a call
|
|
138
|
+
* the gate adjudicates, and on a bare request. A policy that would put the call to a person — an approval seat it awaits,
|
|
139
|
+
* a hook it invokes, a card or a message it sends — answers at once instead: the engine's own factories read this member
|
|
140
|
+
* before reaching a seat and answer {@link noApproverSeatDeny}; a deployment closure does the same. The signal handed
|
|
141
|
+
* beside such a request is LIVE (the judge's wait for that layer): an aborted one means only that the task ended.
|
|
142
|
+
* Read-only.
|
|
143
|
+
*/
|
|
144
|
+
approvalReach?: import("./wiring-manifest.js").ApprovalReach;
|
|
133
145
|
/**
|
|
134
146
|
* design/80 D-E-core: read-only per-run budget snapshot so a STATELESS policy can self-limit against
|
|
135
147
|
* state that survives suspend/resume (a fresh in-memory counter would reset every leg — the supervisor
|
|
@@ -272,11 +284,25 @@ export declare function attest<T extends object>(d: T, call: {
|
|
|
272
284
|
}, members: AttestationMembers): T;
|
|
273
285
|
/** `d` carrying `record` (a fresh object), or `d` itself when there is no record to put on it. */
|
|
274
286
|
export declare function withAttestation<T extends object>(d: T, record: EngineAttestation | undefined): T;
|
|
287
|
+
/** The `no_approver`-attested deny an engine policy answers on a request that states nobody can be asked about it
|
|
288
|
+
* ({@link ToolCallRequest.approvalReach}) instead of reaching a seat — read by a probe as "would ask an approver". */
|
|
289
|
+
export declare function noApproverSeatDeny(req: {
|
|
290
|
+
toolCallId: string;
|
|
291
|
+
toolName: string;
|
|
292
|
+
}, message: string, origin: AskOrigin): PermissionResult;
|
|
275
293
|
/** The `task_aborted`-attested deny an engine policy answers on an aborted signal instead of reaching a seat. */
|
|
276
294
|
export declare function abortedSeatDeny(req: {
|
|
277
295
|
toolCallId: string;
|
|
278
296
|
toolName: string;
|
|
279
297
|
}, message: string, origin: AskOrigin): PermissionResult;
|
|
298
|
+
/** THE question every engine factory asks before it would reach a person (an approver it awaits, a hook it invokes): may the
|
|
299
|
+
* seat be reached? Not when the task ended (an aborted signal ⇒ {@link abortedSeatDeny}, read first) nor when the request
|
|
300
|
+
* states that nobody can be asked about the call ({@link ToolCallRequest.approvalReach} ⇒ {@link noApproverSeatDeny});
|
|
301
|
+
* `undefined` ⇒ it may. `say` is the factory's own sentence for each. */
|
|
302
|
+
export declare function unaskedSeatAnswer(req: Pick<ToolCallRequest, "toolCallId" | "toolName" | "approvalReach">, signal: AbortSignal | undefined, say: {
|
|
303
|
+
aborted: string;
|
|
304
|
+
unreachable: string;
|
|
305
|
+
}, origin: AskOrigin): PermissionResult | undefined;
|
|
280
306
|
/**
|
|
281
307
|
* design/252 G-7 — how long an approver-attribution identifier may be.
|
|
282
308
|
*
|
|
@@ -575,12 +601,14 @@ export declare function decisionText(d: PermissionResult): string | undefined;
|
|
|
575
601
|
*
|
|
576
602
|
* `check` may be async, which is also how **human-in-the-loop approval** works: a deployment can
|
|
577
603
|
* hold the promise open until an operator approves/denies. `signal` fires when the task aborts
|
|
578
|
-
* (timeout / max turns / cancel) or the asking turn is interrupted (design/384)
|
|
579
|
-
* pending approval (F4; the Runner also races `check` against it). An
|
|
604
|
+
* (timeout / max turns / cancel) or the asking turn is interrupted (design/384), and on a synthetic probe when the judge
|
|
605
|
+
* stops waiting for this layer — honor it to release a pending approval (F4; the Runner also races `check` against it). An
|
|
606
|
+
* already-aborted one: see `check`. A request that states nobody can be asked about it: {@link ToolCallRequest.approvalReach}.
|
|
580
607
|
*/
|
|
581
608
|
export interface ToolPolicy {
|
|
582
609
|
/** @contract policy.check.aborted_signal_reaches_nobody — handed an already-aborted signal, `check` reaches no person and
|
|
583
|
-
* no external approval (it answers at once, or with a `task_aborted` deny)
|
|
610
|
+
* no external approval (it answers at once, or with a `task_aborted` deny). The engine's probes do not rely on it: they hand a
|
|
611
|
+
* live signal and state on the request that nobody can be asked (`approvalReach: "none"`, answered with `noApproverSeatDeny`). */
|
|
584
612
|
check(req: ToolCallRequest, signal?: AbortSignal): PermissionResult | Promise<PermissionResult>;
|
|
585
613
|
/**
|
|
586
614
|
* The policy's CONSTRAINT PROJECTION — its deterministic DENY-verdict half expressed as pure data
|
|
@@ -1295,10 +1323,12 @@ export interface AskRequest {
|
|
|
1295
1323
|
* mint site added later is covered by construction); optional on the type because a deployment may
|
|
1296
1324
|
* invoke its approver function directly. */
|
|
1297
1325
|
readonly boundInputHash?: string;
|
|
1298
|
-
/** A call to the engine's `Skill` tool: the hash of {@link boundGrants} — the digest a parked approval of the same card is judged by, so a live card reconciles against its parked row by `(toolCallId, boundGrantDigest)` and an answer is remembered by "this tool + this binding". Present exactly on that call (whoever asked, however the question was worded)
|
|
1326
|
+
/** A call to the engine's `Skill` tool: the hash of {@link boundGrants} — the digest a parked approval of the same card is judged by, so a live card reconciles against its parked row by `(toolCallId, boundGrantDigest)` and an answer is remembered by "this tool + this binding". Present exactly on that call (whoever asked, however the question was worded); every other card carries {@link boundGrantAbsence} instead; `message` renders the same lists narrowed to what releases in the leg's mode. Reconciliation metadata, never adjudication input. */
|
|
1299
1327
|
readonly boundGrantDigest?: string;
|
|
1300
1328
|
/** The value {@link boundGrantDigest} hashes: `{ skill, allowedTools, disallowedTools }` in canonical spelling (de-duplicated, sorted), `skill: null` when no loaded skill is named; a fresh copy per ask; same presence. Display metadata (deployment text — render with contextual escaping). */
|
|
1301
1329
|
readonly boundGrants?: import("./skill-grant-binding.js").BoundSkillGrants;
|
|
1330
|
+
/** Why this card carries no {@link boundGrantDigest} — every card the engine mints carries exactly one of the two: `not_bindable` (the call is not an activation of the engine's `Skill` tool, so it binds no grant and an answer may be remembered by the tool) or `unreadable` (a Skill card whose binding cannot be read — said by a stored row's reader; a live card always has its digest). The same factory mints both members; the park row and the inbox projection carry the same member. Reconciliation metadata, never adjudication input. */
|
|
1331
|
+
readonly boundGrantAbsence?: import("./skill-grant-binding.js").BoundGrantAbsence;
|
|
1302
1332
|
/**
|
|
1303
1333
|
* design/179 §4, re-formed by design/375 §3.1 (BREAKING — this seat REPLACES the retired
|
|
1304
1334
|
* `ruleSuggestions` key, which is never emitted again; the new name is the safe failure posture for
|
|
@@ -1358,8 +1388,9 @@ export interface AskRequest {
|
|
|
1358
1388
|
* seat's to say: it is answered per ask by {@link readRootCandidate}, which is present exactly when
|
|
1359
1389
|
* widening the session's read directories would clear this one and absent for every other member of
|
|
1360
1390
|
* the family — so a surface reads that seat and never infers an answer from this word;
|
|
1361
|
-
* · `"
|
|
1362
|
-
*
|
|
1391
|
+
* · `"allow_outranked"` — an allow-layer member already matched this call and this question outranks it
|
|
1392
|
+
* ({@link allowRuleShadowed} says which): another allow rule would be outranked the same way;
|
|
1393
|
+
* · `"ask_rule_matched"` — an explicit `ask` rule matched: it keeps asking while it stands;
|
|
1363
1394
|
* · `"lane_cannot_speak"` — the lane is armed and this ask IS clearable, but the offer lane
|
|
1364
1395
|
* produced no rule for this command. Usually because the grammar has no text for it (a
|
|
1365
1396
|
* substitution, a subshell, a backgrounded process, or a simple command carrying a redirection —
|
|
@@ -1381,7 +1412,7 @@ export interface AskRequest {
|
|
|
1381
1412
|
* and a surface that ignores it renders exactly the card it rendered before. The durable park row
|
|
1382
1413
|
* carries the same seat under the same contract, filled by the same one factory.
|
|
1383
1414
|
*/
|
|
1384
|
-
readonly ruleOffersAbsence?: "
|
|
1415
|
+
readonly ruleOffersAbsence?: import("./ask-origin.js").RuleOffersAbsence;
|
|
1385
1416
|
/** The human/model-readable prompt explaining what needs approval. */
|
|
1386
1417
|
message: string;
|
|
1387
1418
|
/** Runner-filled source identity (design S1d §1): the end-user {@link AskRequest} issuing task's
|
|
@@ -1444,7 +1475,7 @@ export interface AskRequest {
|
|
|
1444
1475
|
* remembered from an earlier call, at any scope, a session included — can retire this question; it is
|
|
1445
1476
|
* answered only for THIS call, by an answerer (see the ask-arm member of the same name for who may). ABSENT is not the inverse claim: a person's own explicit `ask` rule and a
|
|
1446
1477
|
* matching allow rule the lane already refused both leave it absent and still block rule clearance
|
|
1447
|
-
* ({@link ruleOffersAbsence} words
|
|
1478
|
+
* ({@link ruleOffersAbsence} words them `ask_rule_matched` / `allow_outranked`). The wire twin of the
|
|
1448
1479
|
* {@link PermissionResult} ask-arm member of the same name, minted once by the engine at the gate's
|
|
1449
1480
|
* origin stamp and copied here by the four mint stations. The DOORS are enumerated once, at
|
|
1450
1481
|
* {@link import("./ask-origin.js").ruleClearanceOf}: the tool seat's own egress / irreversibility
|
|
@@ -1452,7 +1483,7 @@ export interface AskRequest {
|
|
|
1452
1483
|
* that could not answer, a write the protection judge matched or could not resolve, governance
|
|
1453
1484
|
* ({@link requiresRealApproval}), a hook's screening authority, and an ask an ANCESTOR's approver
|
|
1454
1485
|
* decides. Not a door: a person's own explicit `ask` rule, which {@link ruleOffersAbsence} words
|
|
1455
|
-
* `
|
|
1486
|
+
* `ask_rule_matched` — a rule they wrote is speaking, and a posture answering it crosses no mandate.
|
|
1456
1487
|
*
|
|
1457
1488
|
* WHY a surface must read THIS member and not its neighbour. {@link ruleOffersAbsence} answers what
|
|
1458
1489
|
* the RULE-OFFER LANE has to give, and that lane is structurally silent for any tool it does not
|
package/dist/core/tool-policy.js
CHANGED
|
@@ -15,7 +15,7 @@ import { heldBy } from "./tool-name-readings.js";
|
|
|
15
15
|
import { boundInputHashOf } from "./canonical-json.js";
|
|
16
16
|
import { delimitUntrusted, inlineUntrusted, REVIEWER_NOTE_MAX_BODY } from "./untrusted-text.js";
|
|
17
17
|
import { describeRejectedValue } from "./tool-search-setting.js";
|
|
18
|
-
import {
|
|
18
|
+
import { egressText, egressThrownText } from "./untrusted-egress.js";
|
|
19
19
|
import { assertNoRetiredToolPolicyKeys, RETIRED_DECISION_MEMBERS } from "./retired-keys.js";
|
|
20
20
|
import { isEngineRefusal, nestedRecordsOf, receiveContract, receiveNestedRecords, refusedOutOfContract, screenContractValues } from "./decision-receipt.js";
|
|
21
21
|
export { isEngineRefusal } from "./decision-receipt.js";
|
|
@@ -102,8 +102,25 @@ export function attest(d, call, members) {
|
|
|
102
102
|
export function withAttestation(d, record) {
|
|
103
103
|
return record === undefined ? d : { ...d, attestation: record };
|
|
104
104
|
}
|
|
105
|
+
const UNASKED_SEAT_SETTLEMENTS = new Set(["task_aborted", "no_approver"]);
|
|
106
|
+
function seatNeverAsked(settlement) {
|
|
107
|
+
return settlement !== undefined && UNASKED_SEAT_SETTLEMENTS.has(settlement.kind);
|
|
108
|
+
}
|
|
109
|
+
function unaskedSeatDeny(req, kind, message, origin) {
|
|
110
|
+
return attest({ action: "deny", message }, req, { settlement: settledByNobody(kind), origin });
|
|
111
|
+
}
|
|
112
|
+
export function noApproverSeatDeny(req, message, origin) {
|
|
113
|
+
return unaskedSeatDeny(req, "no_approver", message, origin);
|
|
114
|
+
}
|
|
105
115
|
export function abortedSeatDeny(req, message, origin) {
|
|
106
|
-
return
|
|
116
|
+
return unaskedSeatDeny(req, "task_aborted", message, origin);
|
|
117
|
+
}
|
|
118
|
+
export function unaskedSeatAnswer(req, signal, say, origin) {
|
|
119
|
+
if (signal?.aborted === true)
|
|
120
|
+
return abortedSeatDeny(req, say.aborted, origin);
|
|
121
|
+
if (req.approvalReach === "none")
|
|
122
|
+
return noApproverSeatDeny(req, say.unreachable, origin);
|
|
123
|
+
return undefined;
|
|
107
124
|
}
|
|
108
125
|
export const APPROVER_ATTRIBUTION_MAX_CHARS = 256;
|
|
109
126
|
const APPROVER_REFUSED_CHARS_RE = /[\u0000-\u001f\u007f-\u009f\u061c\u200e\u200f\u2028\u2029\u202a-\u202e\u2066-\u2069]/u;
|
|
@@ -442,8 +459,9 @@ export function createApprovalPolicy(opts) {
|
|
|
442
459
|
}
|
|
443
460
|
if (nameListHolds(need, req) || namespacedCoveringHit(needCovering, req)) {
|
|
444
461
|
const attestOver = (inputDigest) => (d, settlement) => ({ ...d, attestation: mintAttestation(req, { settlement, origin: "policy", inputDigest }) });
|
|
445
|
-
|
|
446
|
-
|
|
462
|
+
const unasked = unaskedSeatAnswer(req, signal, { aborted: `approval aborted for "${req.toolName}" (run or turn interrupted)`, unreachable: `approval for "${req.toolName}" was not requested: nobody can be asked about this call` }, "policy");
|
|
463
|
+
if (unasked !== undefined)
|
|
464
|
+
return unasked;
|
|
447
465
|
const shown = tryCloneArgs(req.args);
|
|
448
466
|
if (!shown.ok) {
|
|
449
467
|
return attestOver(boundInputHashOf(req.args))({ action: "deny", message: `approval for "${req.toolName}" could not present the args safely (unclonable value: ${shown.reason}) — denied fail-closed` }, settledByNobody("presentation_failed"));
|
|
@@ -565,7 +583,7 @@ export function combinePolicies(...policies) {
|
|
|
565
583
|
for (const p of policies) {
|
|
566
584
|
const d = refuseOutOfContractDecision(await p.check(current, signal));
|
|
567
585
|
if (d.action === "deny") {
|
|
568
|
-
if (attestationOf(d, current)?.settlement
|
|
586
|
+
if (!seatNeverAsked(attestationOf(d, current)?.settlement))
|
|
569
587
|
return settleDeny(d);
|
|
570
588
|
seatDeny ??= settleDeny(d);
|
|
571
589
|
continue;
|
|
@@ -854,10 +872,10 @@ export function tryCloneArgs(v) {
|
|
|
854
872
|
}
|
|
855
873
|
}
|
|
856
874
|
export function describeThrown(err) {
|
|
857
|
-
const contained = containThrownText(
|
|
875
|
+
const contained = containThrownText(egressThrownText("same-principal", err));
|
|
858
876
|
if (contained !== "")
|
|
859
877
|
return contained;
|
|
860
|
-
return containThrownText(describeRejectedValue(err));
|
|
878
|
+
return containThrownText(egressText("same-principal", describeRejectedValue(err)));
|
|
861
879
|
}
|
|
862
880
|
const THROWN_TEXT_MAX = 300;
|
|
863
881
|
function containThrownText(text) {
|
package/dist/core/types.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export type { PermissionMode } from "./ask-origin.js";
|
|
|
18
18
|
export type { ToolEffect, ToolContentOrigin, ReversibilityVerdict, ReadRootGrantCandidate, ToolSpec, ToolReturn, NestedUsage, NestedUsageAccum, ToolExecuteContext } from "./tool-spec.js";
|
|
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
|
-
export type { McpServerSpec, A2aServerSpec, McpElicitRequest, McpElicitResponse, OnElicit } from "./mcp-server-spec.js";
|
|
21
|
+
export type { McpServerSpec, A2aServerSpec, McpElicitRequest, McpElicitResponse, OnElicit, McpRevocationLedger, McpMountIdentity } from "./mcp-server-spec.js";
|
|
22
22
|
export type { TaskLimits } from "./task-limits.js";
|
|
23
23
|
export type { TaskStatus, RemoteEnvFailureNote, EffectiveMemoryScopes, TaskResult, HumanReviewGateRow } from "./task-result.js";
|
|
24
24
|
export type { TerminalCause, PausedCause } from "./terminal-cause.js";
|
|
@@ -26,8 +26,8 @@ export type { TaskEventIdentity, BrainStatusPhase, BrainRetryErrClass, BrainStat
|
|
|
26
26
|
export type { TaskStream } from "./task-stream.js";
|
|
27
27
|
export type { WorkflowGovernanceBaseline, RuntimeCaps, AutoModeDenySource } from "./runtime-caps.js";
|
|
28
28
|
export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./runtime-caps.js";
|
|
29
|
-
export type { BackgroundChildEvent, DelegationLifecycleEvent } from "./delegation-frames.js";
|
|
30
|
-
export { __resetMalformedDelegationSeatAnnouncement, deliverDelegationLifecycle, emitsChildRowFrames, taskStartedFrame } from "./delegation-frames.js";
|
|
29
|
+
export type { BackgroundChildEvent, BackgroundChildRow, DelegationLifecycleEvent } from "./delegation-frames.js";
|
|
30
|
+
export { __resetMalformedDelegationSeatAnnouncement, backgroundChildTerminal, deliverDelegationLifecycle, emitsChildRowFrames, taskStartedFrame } from "./delegation-frames.js";
|
|
31
31
|
export type { ProjectMemoryLoad, ResumePreflightInfo, ResumePreflightVerdict, RunnerDeps } from "./runner-deps.js";
|
|
32
32
|
export type { EngineNotice, OwedUserInputAccount, UserInputUndrainedCause } from "./engine-notice.js";
|
|
33
33
|
export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES, USER_INPUT_UNDRAINED_FAMILIES } from "./engine-notice.js";
|
package/dist/core/types.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { MODEL_ROLES } from "./model-seat.js";
|
|
2
2
|
export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./runtime-caps.js";
|
|
3
|
-
export { __resetMalformedDelegationSeatAnnouncement, deliverDelegationLifecycle, emitsChildRowFrames, taskStartedFrame } from "./delegation-frames.js";
|
|
3
|
+
export { __resetMalformedDelegationSeatAnnouncement, backgroundChildTerminal, deliverDelegationLifecycle, emitsChildRowFrames, taskStartedFrame } from "./delegation-frames.js";
|
|
4
4
|
export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES, USER_INPUT_UNDRAINED_FAMILIES } from "./engine-notice.js";
|
|
@@ -1,18 +1,67 @@
|
|
|
1
|
-
import { type RedactionReport } from "./
|
|
2
|
-
export type { RedactionFinding, RedactionReport, RedactionConfidence, RedactionSource, SummarizableFinding, } from "./
|
|
3
|
-
export { summarizeRedactions } from "./
|
|
4
|
-
export declare function redactSecrets(s: string, report?: RedactionReport): string;
|
|
5
|
-
export declare function redactHostLeaks(s: string, report?: RedactionReport): string;
|
|
6
|
-
/** Secret-redact + size-bound (NO injection fence) — the SAME-PRINCIPAL tier: workflow outputs/results/errors
|
|
7
|
-
* riding back to the launching model/script, run rows behind scope-gated observe. Paths/URLs survive
|
|
8
|
-
* (the assertion pattern depends on them); secrets never do. */
|
|
9
|
-
export declare function boundedRedactedSummary(value: unknown, max: number): string;
|
|
1
|
+
import { type RedactionReport } from "./redaction-passes.js";
|
|
2
|
+
export type { RedactionFinding, RedactionReport, RedactionConfidence, RedactionSource, SummarizableFinding, } from "./redaction-passes.js";
|
|
3
|
+
export { summarizeRedactions } from "./redaction-passes.js";
|
|
10
4
|
/**
|
|
11
|
-
*
|
|
5
|
+
* Every exit that redacts — into a model's context, a host's event or error lane, a log line, a person's screen — does it
|
|
6
|
+
* with ONE pass, its tier's, and nothing else redacts: a text through {@link egressText}, a thrown value's text through
|
|
7
|
+
* {@link egressThrownText}, a value with members (a thrown error, a marks bag) through {@link egressValue}, which runs the
|
|
8
|
+
* same pass over every string member. What comes out is an {@link Egress}: a string the type checker knows came out of
|
|
9
|
+
* that tier. What a tool RETURNS is its content, read by the model that asked for it, and is not redacted (CC redacts
|
|
10
|
+
* nothing there either); what is redacted is what the engine itself words or carries: errors, summaries, run rows.
|
|
11
|
+
*
|
|
12
|
+
* Two tiers, because the faces have two audiences (CC 2.1.212 alignment):
|
|
13
|
+
* - **`same-principal`** — the model, the script and the host that launched the work (tool results, workflow agent
|
|
14
|
+
* outputs / results / errors, run rows behind the scope-gated observe API, host error lanes): the credential
|
|
15
|
+
* vocabulary only. Paths and URLs in a worker's answer are the caller's OWN machine's paths — redacting them killed the
|
|
16
|
+
* cross-agent assertion pattern ("return the file you wrote" → `[redacted-path]`) while protecting no one;
|
|
17
|
+
* cross-tenant isolation on these faces is ACCESS CONTROL (scope gates), not string surgery. CC redacts nothing here;
|
|
18
|
+
* sema keeps the credential pass as a declared superset.
|
|
19
|
+
* - **`human`** — text shown to a person or exported beyond the launching principal: the credential vocabulary plus
|
|
20
|
+
* every URL and absolute path — host internals, and exfil-lure links in untrusted text.
|
|
21
|
+
* {@link untrustedEgressForHuman} additionally FENCES its text (design/97 CORE-2), so untrusted content cannot pose as
|
|
22
|
+
* instructions to its reader.
|
|
23
|
+
*/
|
|
24
|
+
export type EgressTier = "same-principal" | "human";
|
|
25
|
+
declare const EGRESS_TIER: unique symbol;
|
|
26
|
+
/** A string that came out of tier `T`'s pass. Only this module mints one. */
|
|
27
|
+
export type Egress<T extends EgressTier> = string & {
|
|
28
|
+
readonly [EGRESS_TIER]: T;
|
|
29
|
+
};
|
|
30
|
+
/** Tier `tier`'s one pass over a text. */
|
|
31
|
+
export declare function egressText<T extends EgressTier>(tier: T, text: string, report?: RedactionReport): Egress<T>;
|
|
32
|
+
/** The text a thrown value reads as (`thrownText`), through tier `tier`'s pass: the one form a thrown value's words take
|
|
33
|
+
* on their way out of the engine. */
|
|
34
|
+
export declare function egressThrownText<T extends EgressTier>(tier: T, err: unknown): Egress<T>;
|
|
35
|
+
/** The `same-principal` tier's pass, under the name hosts call it by (the engine calls {@link egressText}). */
|
|
36
|
+
export declare function redactSecrets(s: string, report?: RedactionReport): Egress<"same-principal">;
|
|
37
|
+
/** The `human` tier's pass, under the name hosts call it by (the engine calls {@link egressText}). */
|
|
38
|
+
export declare function redactHostLeaks(s: string, report?: RedactionReport): Egress<"human">;
|
|
39
|
+
/**
|
|
40
|
+
* Tier `tier`'s pass over every string member of `value`, returned as a DATA SNAPSHOT — never the value itself, so nothing
|
|
41
|
+
* that leaves can run the value's code again (a getter, a serializer, a proxy trap): a host's serializer, a log's inspector
|
|
42
|
+
* and the loop's own readers (`thrownText`, `thrownMarksOf`) reach what was read, once, and passed. The rules, one each:
|
|
43
|
+
* - a string goes through {@link egressText}, and so does every member NAME; a function is code, not data, and is not
|
|
44
|
+
* carried at any depth (the value handed in included: it comes back `undefined`); any other primitive is itself;
|
|
45
|
+
* - an error (any realm, any class) is re-minted as a plain `Error` — never on the thrown value's prototype, whose
|
|
46
|
+
* serializers and accessors would run again — carrying EVERY own member (`message`, `stack`, `cause`, `errors`,
|
|
47
|
+
* `details`, `code` …) and its `name`, `message`, `code` and `stack` read once through its chain, all as own data;
|
|
48
|
+
* - any other object is what JSON reads: its `toJSON(name)` when it has one (a `URL` is its `href`, a `Date` its ISO
|
|
49
|
+
* text; one that answers itself is read for its members), otherwise its own enumerable members;
|
|
50
|
+
* - a member whose name is a credential name (the vocabulary's record-key view: `password`, `Authorization`,
|
|
51
|
+
* `x-api-key`) and whose reading is a string is the marker whole;
|
|
52
|
+
* - cycles and shared members stay shared on the snapshot.
|
|
53
|
+
*/
|
|
54
|
+
export declare function egressValue<T extends EgressTier, V>(tier: T, value: V): V;
|
|
55
|
+
/** The `same-principal` tier's pass + size-bound (NO injection fence): workflow outputs/results/errors riding back to
|
|
56
|
+
* the launching model/script, run rows behind scope-gated observe. Paths/URLs survive (the assertion pattern depends on
|
|
57
|
+
* them); secrets never do. */
|
|
58
|
+
export declare function boundedRedactedSummary(value: unknown, max: number): Egress<"same-principal">;
|
|
59
|
+
/**
|
|
60
|
+
* The FULL untrusted-egress transform (design/97 CORE-2): the `human` tier's pass + size-bound + FENCE. Use
|
|
12
61
|
* for any worker prompt/output (#5 transcript) or steer content (#6) shown to a HUMAN or exported beyond the
|
|
13
62
|
* launching principal, so untrusted text can neither leak host internals nor pose as instructions.
|
|
14
63
|
*/
|
|
15
64
|
export declare function untrustedEgressForHuman(value: unknown, opts: {
|
|
16
65
|
label: string;
|
|
17
66
|
max: number;
|
|
18
|
-
}):
|
|
67
|
+
}): Egress<"human">;
|