@sema-agent/core 7.42.1 → 7.44.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 +173 -0
- package/dist/agents/send-message-tool.js +1 -0
- package/dist/agents/subagent.d.ts +3 -1
- package/dist/agents/subagent.js +5 -3
- package/dist/agents/teacher.js +1 -1
- package/dist/agents/verify.js +2 -0
- package/dist/brain/errors.d.ts +23 -2
- package/dist/brain/errors.js +26 -2
- package/dist/brain/stream-engine.d.ts +2 -1
- package/dist/brain/stream-engine.js +10 -9
- package/dist/core/allow-entry.d.ts +50 -31
- package/dist/core/allow-entry.js +100 -37
- package/dist/core/ask-origin.d.ts +16 -5
- package/dist/core/ask-origin.js +11 -3
- package/dist/core/ask-unresolvable-notice.d.ts +3 -2
- package/dist/core/ask-unresolvable-notice.js +1 -1
- package/dist/core/auto-mode.d.ts +5 -4
- package/dist/core/auto-mode.js +3 -1
- package/dist/core/checkpoint-store.d.ts +44 -20
- package/dist/core/checkpoint-store.js +10 -16
- package/dist/core/child-clamp-seats.d.ts +15 -1
- package/dist/core/child-clamp-seats.js +6 -2
- package/dist/core/classifier-unavailable-arm.d.ts +42 -23
- package/dist/core/classifier-unavailable-arm.js +14 -3
- package/dist/core/decision-receipt.js +2 -0
- package/dist/core/engine-notice.d.ts +16 -14
- package/dist/core/engine-notice.js +4 -3
- package/dist/core/gate-lanes.js +37 -29
- package/dist/core/governance-codes.d.ts +4 -3
- package/dist/core/governance-codes.js +1 -0
- package/dist/core/hooks.d.ts +6 -1
- package/dist/core/hooks.js +3 -0
- package/dist/core/memory-engine/engine.d.ts +2 -2
- package/dist/core/memory-engine/engine.js +7 -14
- package/dist/core/memory-engine/file-backend.d.ts +2 -2
- package/dist/core/memory-engine/file-backend.js +5 -7
- package/dist/core/memory-engine/layout.d.ts +37 -4
- package/dist/core/memory-engine/layout.js +34 -5
- package/dist/core/mode-policy.d.ts +5 -4
- package/dist/core/mode-policy.js +4 -0
- package/dist/core/permission-rule-consent.d.ts +3 -2
- package/dist/core/permission-rule-consent.js +25 -20
- package/dist/core/permission-rule-model.d.ts +47 -7
- package/dist/core/permission-rule-model.js +80 -6
- package/dist/core/permission-rules.d.ts +8 -2
- package/dist/core/permission-rules.js +26 -9
- package/dist/core/runner/classifier-ladder.d.ts +10 -8
- package/dist/core/runner/classifier-ladder.js +3 -1
- package/dist/core/runner/contracts.d.ts +1 -16
- package/dist/core/runner/denial-limit-arms.d.ts +25 -8
- package/dist/core/runner/denial-limit-arms.js +24 -10
- package/dist/core/runner/gate-exit.js +2 -1
- package/dist/core/runner/permission-rule-lanes.d.ts +2 -2
- package/dist/core/runner/permission-rule-lanes.js +8 -2
- package/dist/core/runner/prepare-ask-lane.d.ts +3 -0
- package/dist/core/runner/prepare-ask-lane.js +2 -1
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +2 -3
- package/dist/core/runner/prepare-caps-and-workflow.js +3 -2
- package/dist/core/runner/prepare-config-doors.d.ts +3 -0
- package/dist/core/runner/prepare-config-doors.js +6 -5
- package/dist/core/runner/prepare-gate-stations.js +1 -1
- package/dist/core/runner/prepare-inherited-gate.d.ts +7 -5
- package/dist/core/runner/prepare-inherited-gate.js +5 -3
- package/dist/core/runner/prepare-park-ask.d.ts +4 -4
- package/dist/core/runner/prepare-park-ask.js +2 -4
- package/dist/core/runner/prepare-policy-chain.d.ts +7 -1
- package/dist/core/runner/prepare-policy-chain.js +59 -38
- package/dist/core/runner/prepare-project-context.js +6 -2
- package/dist/core/runner/prepare-task.js +6 -6
- package/dist/core/runner/prepare-wiring-manifest.d.ts +6 -5
- package/dist/core/runner/prepare-wiring-manifest.js +8 -9
- package/dist/core/runner/resume-checkpoint-screen.js +1 -1
- package/dist/core/runner/runtask.js +1 -5
- package/dist/core/runner/steer-admission.d.ts +10 -11
- package/dist/core/runner/steer-admission.js +6 -8
- package/dist/core/runner/stream-steer-verb.d.ts +5 -4
- package/dist/core/runner/stream-steer-verb.js +6 -8
- package/dist/core/runner/synthetic-tools.d.ts +3 -2
- package/dist/core/runner/synthetic-tools.js +1 -1
- package/dist/core/session-policy-store.d.ts +3 -3
- package/dist/core/session-policy-store.js +18 -4
- package/dist/core/skill-grant-binding.d.ts +44 -0
- package/dist/core/skill-grant-binding.js +22 -0
- package/dist/core/skill-grant.d.ts +59 -28
- package/dist/core/skill-grant.js +96 -23
- package/dist/core/steer-replay.d.ts +46 -0
- package/dist/core/steer-replay.js +22 -0
- package/dist/core/task-event.d.ts +3 -2
- package/dist/core/task-spec.d.ts +14 -1
- package/dist/core/task-stream.d.ts +12 -6
- package/dist/core/tighten-task-spec.d.ts +2 -0
- package/dist/core/tighten-task-spec.js +3 -0
- package/dist/core/tool-errors.d.ts +2 -2
- package/dist/core/tool-name-aliases.d.ts +35 -5
- package/dist/core/tool-name-aliases.js +29 -4
- package/dist/core/tool-policy.d.ts +10 -0
- package/dist/core/tool-policy.js +9 -2
- package/dist/core/tool-spec.d.ts +7 -0
- package/dist/core/types.d.ts +2 -2
- package/dist/core/types.js +1 -1
- package/dist/core/wiring-manifest.d.ts +56 -14
- package/dist/core/wiring-manifest.js +29 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.js +5 -4
- package/dist/orchestration/run-workflow-tool.d.ts +4 -0
- package/dist/orchestration/run-workflow-tool.js +1 -1
- package/dist/orchestration/workflow-primitives.d.ts +3 -1
- package/dist/orchestration/workflow-primitives.js +6 -6
- package/dist/orchestration/workflow-types.d.ts +5 -0
- package/dist/orchestration/workflow.d.ts +3 -2
- package/dist/orchestration/workflow.js +14 -6
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +21 -5
- package/wire-changes/core@7.43.0.json +985 -0
- package/wire-changes/core@7.44.0.json +469 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ProtocolNamespace } from "./protocol-table.js";
|
|
1
2
|
/**
|
|
2
3
|
* RB-476-A stage 2 (ruling 2026-08-02, RB-476 "no compatibility surface survives", replay
|
|
3
4
|
* resolution included) — the durable-name machinery this module used to hold is RETIRED:
|
|
@@ -26,17 +27,23 @@
|
|
|
26
27
|
* wider tool: writing it would deny more than the entry did, so it is no current name), or `removed — `.
|
|
27
28
|
*/
|
|
28
29
|
export declare const RETIRED_TOOL_NAMES: ReadonlyMap<string, string>;
|
|
29
|
-
/** The
|
|
30
|
-
export declare const RULE_TOOL_NAME_VERDICTS: readonly ["current", "retired", "unprefixed_namespace"];
|
|
30
|
+
/** The four answers {@link judgeRuleToolName} gives — a closed set. */
|
|
31
|
+
export declare const RULE_TOOL_NAME_VERDICTS: readonly ["current", "retired", "unprefixed_namespace", "unmintable_segment"];
|
|
31
32
|
/**
|
|
32
33
|
* Whether a tool name written in a rule is a stale name — one that, against `roster`, names no tool and never can:
|
|
33
|
-
* - `current` — not a stale name: the roster mounts it, or it is
|
|
34
|
-
*
|
|
34
|
+
* - `current` — not a stale name: the roster mounts it, or it is none of the three below. (Whether a current name matches
|
|
35
|
+
* anything THIS run is a different question — an unknown name is the prepare audit's advisory.)
|
|
35
36
|
* - `retired` — a name in {@link RETIRED_TOOL_NAMES} the roster does not mount; `guidance` is that table's line, and
|
|
36
37
|
* `currentName` the 1:1 successor when there is one (see the module header's grammar).
|
|
37
38
|
* - `unprefixed_namespace` — carries the `__` namespace separator with no protocol prefix. The roster cannot clear it:
|
|
38
39
|
* a caller tool name or alias carrying `__` is refused at prepare, every engine tool name is `__`-free, and every
|
|
39
40
|
* protocol tool is minted with its prefix.
|
|
41
|
+
* - `unmintable_segment` — carries a protocol prefix, but its peer segment (the server / remote agent) is not a spelling
|
|
42
|
+
* the mint produces for any peer: the name is read as written (peers compare exactly), and every mounted tool carries
|
|
43
|
+
* the minted spelling, so the name reaches none of them. `guidance` says so in one line; `currentName` is the whole name
|
|
44
|
+
* rewritten with the spelling the mint produces (`mcp__github.com__*` → `mcp__github_com__*`), absent when the peer
|
|
45
|
+
* segment is empty and there is nothing to rewrite. The tool segment after the peer is never judged: it is a literal
|
|
46
|
+
* tool name or a glob over one, and an unmatched one is the audit's advisory.
|
|
40
47
|
*
|
|
41
48
|
* `roster` = the tool names (aliases included) the reader knows are mounted: a run's assembled roster at prepare, the
|
|
42
49
|
* names a deployment DECLARES it mounts its own tools under at a session-rule store (an empty set when it declares none).
|
|
@@ -49,6 +56,29 @@ export type RuleToolNameVerdict = {
|
|
|
49
56
|
readonly currentName?: string;
|
|
50
57
|
} | {
|
|
51
58
|
readonly kind: "unprefixed_namespace";
|
|
59
|
+
} | {
|
|
60
|
+
readonly kind: "unmintable_segment";
|
|
61
|
+
readonly guidance: string;
|
|
62
|
+
readonly currentName?: string;
|
|
52
63
|
};
|
|
53
|
-
/**
|
|
64
|
+
/**
|
|
65
|
+
* A name in ANY protocol namespace split into its owning namespace, its peer segment and its optional tool segment —
|
|
66
|
+
* CC `rP` (:70710) verbatim, re-anchored on the {@link protocolOf} lookup instead of CC's literal `"mcp"` first split element.
|
|
67
|
+
* `undefined` for a name that is not namespaced (no protocol prefix). The peer is the first segment — EMPTY for `mcp____x` and
|
|
68
|
+
* for the bare prefix, which name no peer; the tool segment is the REST of the split rejoined, so a tool whose minted segment
|
|
69
|
+
* itself carries the separator (charset normalization maps `get..issue` → `get__issue`) decomposes back to one tool name, and
|
|
70
|
+
* is absent when the name stops at the peer (`mcp__srv`). The one decomposition: the judgment, the covering matcher and the
|
|
71
|
+
* allow-entry grammar all read a namespaced name through it.
|
|
72
|
+
*/
|
|
73
|
+
export declare function splitNamespacedName(name: string): {
|
|
74
|
+
readonly ns: ProtocolNamespace;
|
|
75
|
+
readonly peer: string;
|
|
76
|
+
readonly tool?: string;
|
|
77
|
+
} | undefined;
|
|
78
|
+
/** See {@link RuleToolNameVerdict}. Pure; the one answer to "is this rule's tool name a name that reaches no tool". */
|
|
54
79
|
export declare function judgeRuleToolName(name: string, roster: ReadonlySet<string>): RuleToolNameVerdict;
|
|
80
|
+
/** The names a run mounts — every tool's primary name and its aliases: the roster {@link judgeRuleToolName} is given. */
|
|
81
|
+
export declare function mountedToolNames(tools: ReadonlyArray<{
|
|
82
|
+
readonly name: string;
|
|
83
|
+
readonly aliases?: readonly string[];
|
|
84
|
+
}>): Set<string>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { carriesNamespaceSeparator, protocolOf } from "./protocol-table.js";
|
|
2
|
+
import { mintNamespacePrefix } from "./protocol-naming.js";
|
|
2
3
|
export const RETIRED_TOOL_NAMES = new Map([
|
|
3
4
|
["read_file", 'renamed "Read"'],
|
|
4
5
|
["edit_file", 'renamed "Edit"'],
|
|
@@ -41,9 +42,29 @@ export const RETIRED_TOOL_NAMES = new Map([
|
|
|
41
42
|
["Recall", "removed — memory is file-based; read the memory directory with the ordinary file tools"],
|
|
42
43
|
["recall", "removed — memory is file-based; read the memory directory with the ordinary file tools"],
|
|
43
44
|
]);
|
|
44
|
-
export const RULE_TOOL_NAME_VERDICTS = Object.freeze(["current", "retired", "unprefixed_namespace"]);
|
|
45
|
+
export const RULE_TOOL_NAME_VERDICTS = Object.freeze(["current", "retired", "unprefixed_namespace", "unmintable_segment"]);
|
|
45
46
|
const CURRENT = Object.freeze({ kind: "current" });
|
|
46
47
|
const UNPREFIXED = Object.freeze({ kind: "unprefixed_namespace" });
|
|
48
|
+
const NAMESPACE_SEPARATOR = "__";
|
|
49
|
+
export function splitNamespacedName(name) {
|
|
50
|
+
const ns = protocolOf(name);
|
|
51
|
+
if (ns === undefined)
|
|
52
|
+
return undefined;
|
|
53
|
+
const [peer = "", ...rest] = name.slice(ns.prefix.length).split(NAMESPACE_SEPARATOR);
|
|
54
|
+
return rest.length > 0 ? { ns, peer, tool: rest.join(NAMESPACE_SEPARATOR) } : { ns, peer };
|
|
55
|
+
}
|
|
56
|
+
function unmintableSegmentOf({ ns, peer, tool }) {
|
|
57
|
+
if (peer === "")
|
|
58
|
+
return { kind: "unmintable_segment", guidance: `the ${ns.id} name has an empty peer segment — no tool is minted under it` };
|
|
59
|
+
const minted = mintNamespacePrefix(ns, peer).slice(ns.prefix.length, -NAMESPACE_SEPARATOR.length);
|
|
60
|
+
if (minted === peer)
|
|
61
|
+
return undefined;
|
|
62
|
+
return {
|
|
63
|
+
kind: "unmintable_segment",
|
|
64
|
+
guidance: `the ${ns.id} peer segment ${JSON.stringify(peer)} is not a spelling the engine mints — its tools are named ${ns.prefix}${minted}${NAMESPACE_SEPARATOR}<tool>, and a rule's peer segment must be spelled the way its tools are`,
|
|
65
|
+
currentName: `${ns.prefix}${minted}${tool !== undefined ? `${NAMESPACE_SEPARATOR}${tool}` : ""}`,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
47
68
|
export function judgeRuleToolName(name, roster) {
|
|
48
69
|
if (roster.has(name))
|
|
49
70
|
return CURRENT;
|
|
@@ -52,7 +73,11 @@ export function judgeRuleToolName(name, roster) {
|
|
|
52
73
|
const currentName = /^renamed "([^"]+)"/.exec(guidance)?.[1];
|
|
53
74
|
return currentName !== undefined ? { kind: "retired", guidance, currentName } : { kind: "retired", guidance };
|
|
54
75
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
76
|
+
const split = splitNamespacedName(name);
|
|
77
|
+
if (split === undefined)
|
|
78
|
+
return carriesNamespaceSeparator(name) ? UNPREFIXED : CURRENT;
|
|
79
|
+
return unmintableSegmentOf(split) ?? CURRENT;
|
|
80
|
+
}
|
|
81
|
+
export function mountedToolNames(tools) {
|
|
82
|
+
return new Set(tools.flatMap((t) => [t.name, ...(t.aliases ?? [])]));
|
|
58
83
|
}
|
|
@@ -303,6 +303,9 @@ export type PermissionResult = {
|
|
|
303
303
|
* same safe direction as `matchedAskRule`); it cannot state a window of its own, because the
|
|
304
304
|
* route it would be a window for has not been chosen yet. */
|
|
305
305
|
denialLimitFallback?: import("./auto-mode.js").UnarmedDenialLimitFallback;
|
|
306
|
+
/** WHY a classifier station handed this call to a person: the classification did not rule (`error` / `timeout` — it could
|
|
307
|
+
* not run; `parse_error` — no verdict). Engine-stamped with `requiresRealApproval`; class `classifier_no_ruling`. */
|
|
308
|
+
classifierNoRuling?: import("./auto-mode.js").AutoModeFallbackCause;
|
|
306
309
|
/** The allow layer's DISCLOSURE: the members that MATCHED this call and could not clear the ask (it is a class
|
|
307
310
|
* no allow rule clears — a mandated, governance, hook, ask-rule or mode question — or the call reached the layer
|
|
308
311
|
* marked), one record per member ({@link AllowRuleShadow}). ENGINE-STAMPED by the allow layer, overwriting a
|
|
@@ -1201,6 +1204,10 @@ export interface AskRequest {
|
|
|
1201
1204
|
* mint site added later is covered by construction); optional on the type because a deployment may
|
|
1202
1205
|
* invoke its approver function directly. */
|
|
1203
1206
|
readonly boundInputHash?: string;
|
|
1207
|
+
/** 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), absent on every other card; `message` renders the same lists narrowed to what releases in the leg's mode. Reconciliation metadata, never adjudication input. */
|
|
1208
|
+
readonly boundGrantDigest?: string;
|
|
1209
|
+
/** 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). */
|
|
1210
|
+
readonly boundGrants?: import("./skill-grant-binding.js").BoundSkillGrants;
|
|
1204
1211
|
/**
|
|
1205
1212
|
* design/179 §4, re-formed by design/375 §3.1 (BREAKING — this seat REPLACES the retired
|
|
1206
1213
|
* `ruleSuggestions` key, which is never emitted again; the new name is the safe failure posture for
|
|
@@ -1396,6 +1403,9 @@ export interface AskRequest {
|
|
|
1396
1403
|
* that forwards a decision's member here does not compile, which is the point: the window is the
|
|
1397
1404
|
* route's fact, and forwarding it silently is how a configured window becomes a wait with none. */
|
|
1398
1405
|
readonly denialLimitFallback?: import("./auto-mode.js").DenialLimitFallback;
|
|
1406
|
+
/** The {@link PermissionResult} ask-arm member of the same name (class `classifier_no_ruling`), carried by the four mint
|
|
1407
|
+
* stations; the `message`'s second paragraph says the same for a client that does not read this. */
|
|
1408
|
+
readonly classifierNoRuling?: import("./auto-mode.js").AutoModeFallbackCause;
|
|
1399
1409
|
/** (additive) WHICH AUTHORITY raised this ask — the wire twin of the {@link PermissionResult} ask-arm
|
|
1400
1410
|
* member of the same name, one word from the closed {@link import("./ask-origin.js").AskOrigin} set.
|
|
1401
1411
|
* The gate's own mint station copies the engine-stamped word; the three inherited-lane stations
|
package/dist/core/tool-policy.js
CHANGED
|
@@ -259,7 +259,7 @@ const ALLOW = Object.freeze({ action: "allow" });
|
|
|
259
259
|
const ALLOW_BY_RULE = Object.freeze({ action: "allow", decisionReason: "rule" });
|
|
260
260
|
const RETIRED_TEXT_FIELD = "reason";
|
|
261
261
|
export const DECISION_MEMBERS = Object.keys({
|
|
262
|
-
action: 0, updatedInput: 0, message: 0, decisionReason: 0, requiresRealApproval: 0, denialLimitFallback: 0, allowRuleShadowed: 0, probeReason: 0,
|
|
262
|
+
action: 0, updatedInput: 0, message: 0, decisionReason: 0, requiresRealApproval: 0, denialLimitFallback: 0, classifierNoRuling: 0, allowRuleShadowed: 0, probeReason: 0,
|
|
263
263
|
probeCause: 0, probeMandated: 0, mandated: 0, mandate: 0, probeReadRootCandidate: 0, matchedAskRule: 0, ruleEvidence: 0, segmentCoverage: 0,
|
|
264
264
|
origin: 0, askClass: 0, classes: 0, guard: 0, ruleUnreadable: 0, authoredBy: 0, foldedAskClasses: 0,
|
|
265
265
|
});
|
|
@@ -551,6 +551,7 @@ export function combinePolicies(...policies) {
|
|
|
551
551
|
let probeMandateSeen = false;
|
|
552
552
|
let mandateSeen = false;
|
|
553
553
|
let fallbackSeen;
|
|
554
|
+
let noRulingSeen;
|
|
554
555
|
let authoredBySeen = false;
|
|
555
556
|
const contributors = [];
|
|
556
557
|
const settleDeny = (d) => {
|
|
@@ -597,6 +598,8 @@ export function combinePolicies(...policies) {
|
|
|
597
598
|
mandateSeen = true;
|
|
598
599
|
if (d.action === "ask" && d.denialLimitFallback !== undefined && fallbackSeen === undefined)
|
|
599
600
|
fallbackSeen = d.denialLimitFallback;
|
|
601
|
+
if (d.action === "ask" && d.classifierNoRuling !== undefined && noRulingSeen === undefined)
|
|
602
|
+
noRulingSeen = d.classifierNoRuling;
|
|
600
603
|
if (d.action === "ask" && d.authoredBy === "deployment")
|
|
601
604
|
authoredBySeen = true;
|
|
602
605
|
if (d.action === "ask")
|
|
@@ -610,12 +613,16 @@ export function combinePolicies(...policies) {
|
|
|
610
613
|
const withMark = probeMandateSeen && withRuleAsk.probeMandated !== true ? { ...withRuleAsk, probeMandated: true } : withRuleAsk;
|
|
611
614
|
const withMandate = mandateSeen && withMark.mandated !== true ? { ...withMark, mandated: true } : withMark;
|
|
612
615
|
const withFallback = fallbackSeen !== undefined && withMandate.denialLimitFallback === undefined ? { ...withMandate, denialLimitFallback: fallbackSeen, requiresRealApproval: true } : withMandate;
|
|
613
|
-
const
|
|
616
|
+
const withNoRuling = noRulingSeen !== undefined && withFallback.classifierNoRuling === undefined ? { ...withFallback, classifierNoRuling: noRulingSeen, requiresRealApproval: true } : withFallback;
|
|
617
|
+
const withAuthor = authoredBySeen && withNoRuling.authoredBy === undefined ? { ...withNoRuling, authoredBy: "deployment" } : withNoRuling;
|
|
614
618
|
const folded = new Set(withAuthor.foldedAskClasses ?? []);
|
|
615
619
|
for (const c of contributors)
|
|
616
620
|
if (c !== asked)
|
|
617
621
|
for (const k of decisionAskClassesOf(c))
|
|
618
622
|
folded.add(k);
|
|
623
|
+
if (withNoRuling !== withMandate)
|
|
624
|
+
for (const k of decisionAskClassesOf(asked))
|
|
625
|
+
folded.add(k);
|
|
619
626
|
const withClasses = folded.size > 0 ? { ...withAuthor, foldedAskClasses: [...folded] } : withAuthor;
|
|
620
627
|
const out = merged !== undefined ? { ...withClasses, updatedInput: merged } : withClasses;
|
|
621
628
|
if (folded.size > 0)
|
package/dist/core/tool-spec.d.ts
CHANGED
|
@@ -952,6 +952,13 @@ export interface ToolExecuteContext {
|
|
|
952
952
|
* is deliberately NOT inherited).
|
|
953
953
|
*/
|
|
954
954
|
interactiveTools?: false;
|
|
955
|
+
/**
|
|
956
|
+
* The run's declaration that nobody on it can be asked to approve ({@link TaskSpec.approvalReach} `"none"`),
|
|
957
|
+
* Runner-filled read-only on the same trusted seat, present ONLY when declared. A delegation tool copies it onto every
|
|
958
|
+
* child spec (the clamp carrier): the child's own seat resolution would otherwise fall back to the deployment's live
|
|
959
|
+
* approver, because a declared-none parent hands down no approver of its own ({@link onAsk} is absent on its ctx).
|
|
960
|
+
*/
|
|
961
|
+
approvalReach?: "none";
|
|
955
962
|
/**
|
|
956
963
|
* Read-only mirror of {@link "./types.js".TaskSpec.oneShot} (same trust tier/seat as
|
|
957
964
|
* `principal`): this RUN has no later turn for an async background notification to land in (a
|
package/dist/core/types.d.ts
CHANGED
|
@@ -29,6 +29,6 @@ export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./runtime-caps.js"
|
|
|
29
29
|
export type { BackgroundChildEvent, DelegationLifecycleEvent } from "./delegation-frames.js";
|
|
30
30
|
export { __resetMalformedDelegationSeatAnnouncement, deliverDelegationLifecycle } from "./delegation-frames.js";
|
|
31
31
|
export type { ProjectMemoryLoad, ResumePreflightInfo, ResumePreflightVerdict, RunnerDeps } from "./runner-deps.js";
|
|
32
|
-
export type { EngineNotice, OwedUserInputAccount,
|
|
33
|
-
export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices,
|
|
32
|
+
export type { EngineNotice, OwedUserInputAccount, UserInputUndrainedCause } from "./engine-notice.js";
|
|
33
|
+
export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES } from "./engine-notice.js";
|
|
34
34
|
export type { AgentTool, Model, StreamFn, ThinkingLevel, ToolInputValidationContext, ToolInputVerdict };
|
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
3
|
export { __resetMalformedDelegationSeatAnnouncement, deliverDelegationLifecycle } from "./delegation-frames.js";
|
|
4
|
-
export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices,
|
|
4
|
+
export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES } from "./engine-notice.js";
|
|
@@ -26,6 +26,7 @@ import { type StoreDurability } from "./checkpoint-store.js";
|
|
|
26
26
|
import type { WiringManifestHookEntry } from "./hook-seats.js";
|
|
27
27
|
import type { McpDelivered, McpFailureKind, McpServerLiveness } from "./mcp-failure.js";
|
|
28
28
|
import type { WriteProtectionTargetView } from "./write-protect.js";
|
|
29
|
+
import type { OnAsk } from "./tool-policy.js";
|
|
29
30
|
export type { StoreDurability };
|
|
30
31
|
/** The manifest-face projection of {@link StoreDurability}: `"declared_durable"` (the name says it —
|
|
31
32
|
* a DECLARATION relayed, not a verification) vs `"process_local"` (declared so, or fail-closed
|
|
@@ -37,11 +38,29 @@ export type ManifestDurability = "declared_durable" | "process_local";
|
|
|
37
38
|
* child's manifest rides the CHILD's event stream and is deliberately not in the parent-forwarding
|
|
38
39
|
* whitelist — a host that wants a child's assembly evidence subscribes to the child. */
|
|
39
40
|
export type WiringLegKind = "root" | "child" | "resume";
|
|
40
|
-
/** The shape of the resolved permission-ask seat (
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
|
|
41
|
+
/** The shape of the resolved permission-ask seat ({@link resolveAskSeat}): a live approver callback, a blanket
|
|
42
|
+
* `"allow"`/`"deny"` policy setting, nothing at all, or `"declared_none"` — the run declared that nobody on it can be
|
|
43
|
+
* asked (`TaskSpec.approvalReach: "none"`), so a callback beside the declaration is not this run's approver. `"deny"` (a
|
|
44
|
+
* deliberate policy) and `"absent"` (no seat supplied a value — a degrade to the headless auto-deny default) are DISTINCT
|
|
45
|
+
* on purpose — design/173 — and so are `"absent"` and `"declared_none"`: one says nothing was wired, the other that
|
|
46
|
+
* the run said nobody can answer. */
|
|
47
|
+
export type AskSeamForm = "callback" | "allow" | "deny" | "absent" | "declared_none";
|
|
48
|
+
/**
|
|
49
|
+
* The closed set of a run's approval-reach declaration (`TaskSpec.approvalReach`): `"none"` — nobody on this run can be
|
|
50
|
+
* asked to approve. It removes the one seat that could be a person (a callback); it never approves or releases anything.
|
|
51
|
+
* There is no positive word: "a person is reachable" is the `interactionPosture: "interactive"` promise, which has its own
|
|
52
|
+
* door.
|
|
53
|
+
*/
|
|
54
|
+
export declare const APPROVAL_REACH: readonly ["none"];
|
|
55
|
+
export type ApprovalReach = (typeof APPROVAL_REACH)[number];
|
|
56
|
+
/** Membership test for {@link ApprovalReach}. */
|
|
57
|
+
export declare function isApprovalReach(v: unknown): v is ApprovalReach;
|
|
58
|
+
/**
|
|
59
|
+
* The declaration's door: absent passes as absent, a member passes, anything else present is refused loudly
|
|
60
|
+
* (`config.approval_reach_invalid`) — a declaration nobody can read must not fold to "a person may be asked" (or to
|
|
61
|
+
* "nobody may"). Prepare, the static half and a resume's pre-claim screen call this one function.
|
|
62
|
+
*/
|
|
63
|
+
export declare function screenApprovalReach(v: unknown): ApprovalReach | undefined;
|
|
45
64
|
/** What a policy `ask` actually reaches under this assembly. `"unresolved"` = not computable from
|
|
46
65
|
* the facts at hand (the static half's park-dependent arm). */
|
|
47
66
|
export type AskEffective = "human_reachable" | "auto_allow" | "auto_deny" | "park_only" | "unresolved";
|
|
@@ -178,8 +197,8 @@ export interface WiringManifest {
|
|
|
178
197
|
peerPresence?: import("../agents/peer-directory.js").PeerPresence;
|
|
179
198
|
ask: {
|
|
180
199
|
form: AskSeamForm;
|
|
181
|
-
/** Absent iff
|
|
182
|
-
* a false fact
|
|
200
|
+
/** Absent iff no seat supplied a value (`"absent"`, or `"declared_none"` with nothing wired) — a fabricated provenance
|
|
201
|
+
* would be a false fact. */
|
|
183
202
|
provenance?: SeamProvenance;
|
|
184
203
|
/** OMITTED on the static half (design/173 §8.4): the absent-form arm depends on the park lane,
|
|
185
204
|
* which the static half cannot always resolve. Always present on the effective half. */
|
|
@@ -556,7 +575,7 @@ export interface WiringFacts {
|
|
|
556
575
|
* single-source shapes, no parallel hand-copied interface). */
|
|
557
576
|
export type StaticWiringDeps = Pick<RunnerDeps, "onAsk" | "onQuestion" | "interactionPosture" | "onElicit" | "checkpointStore" | "sessionStore" | "backgroundAgentStore" | "onBackgroundChildEvent" | "lockedConfig" | "compliancePostureResolver" | "memoryScopeAdmission" | "retentionPolicy" | "permissionRuleStore" | "permissionRuleSyncWired">;
|
|
558
577
|
/** Named view of the spec seats the static half reads (a `Pick` of the real {@link TaskSpec}). */
|
|
559
|
-
export type StaticWiringSpec = Pick<TaskSpec, "onAsk" | "onQuestion" | "checkpointStore" | "durableApproval" | "mcp" | "interactiveTools" | "interactionPosture">;
|
|
578
|
+
export type StaticWiringSpec = Pick<TaskSpec, "onAsk" | "approvalReach" | "onQuestion" | "checkpointStore" | "durableApproval" | "mcp" | "interactiveTools" | "interactionPosture">;
|
|
560
579
|
/**
|
|
561
580
|
* Read a store's {@link StoreDurability} declaration: absent ⇒ `"process-local"` (fail-closed —
|
|
562
581
|
* under-promise, never over-promise), a declared value passes through, and an UNPARSEABLE value is
|
|
@@ -613,8 +632,9 @@ export declare function resolveSubagentTranscriptTier(agentStoreWired: boolean,
|
|
|
613
632
|
* so on an armed park lane the ask parks and the honest report is `park_only` — reporting the
|
|
614
633
|
* blanket as what the ask "reaches" would be a false fact of exactly the kind this module refuses.
|
|
615
634
|
* Off the park lane the blanket is what happens: the deliberate auto policies;
|
|
616
|
-
* - no seat at all ⇒ the park lane decides: armed ⇒
|
|
617
|
-
*
|
|
635
|
+
* - no seat at all, or a run that declared nobody can be asked (`declared_none`) ⇒ the park lane decides: armed ⇒
|
|
636
|
+
* `park_only` (the deployment's park is its own statement that an answer can wait for a person), unresolved ⇒
|
|
637
|
+
* `unresolved`, else the headless degrade `auto_deny`.
|
|
618
638
|
*/
|
|
619
639
|
export declare function deriveAskEffective(form: AskSeamForm, parkEffective: boolean | "unresolved", mode?: PermissionMode): AskEffective;
|
|
620
640
|
/**
|
|
@@ -637,10 +657,32 @@ export declare function askReachesPerson(ask: {
|
|
|
637
657
|
readonly effective?: AskEffective;
|
|
638
658
|
}): boolean;
|
|
639
659
|
export declare function deriveWiringManifest(facts: WiringFacts): WiringManifest;
|
|
640
|
-
/**
|
|
641
|
-
*
|
|
642
|
-
*
|
|
643
|
-
export
|
|
660
|
+
/** A run's approval seat as its one resolution froze it: the value every reader that needs the approver itself reads
|
|
661
|
+
* (`undefined` when nothing on this run can be asked), the form the manifest reports and every reader of the word derives
|
|
662
|
+
* from, the seat that supplied the value, and the declaration when the run made one. */
|
|
663
|
+
export interface AskSeat {
|
|
664
|
+
readonly value: OnAsk | undefined;
|
|
665
|
+
readonly form: AskSeamForm;
|
|
666
|
+
/** Absent iff no seat supplied a value. A callback the declaration set aside still names its seat. */
|
|
667
|
+
readonly provenance?: SeamProvenance;
|
|
668
|
+
readonly reach?: ApprovalReach;
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* THE approval-seat resolution — the one place a run's `spec.onAsk` / `deps.onAsk` are read. Prepare calls it once, at
|
|
672
|
+
* its config doors (before any resource is taken), and hands the frozen result down; the static half calls it for its
|
|
673
|
+
* own self-check. The seat is the spec's when the spec's key is PRESENT, else the deployment's (presence, not `??`: a
|
|
674
|
+
* spec `null` is a junk value, never a fall-through to the deployment). A value outside the `OnAsk` union is refused
|
|
675
|
+
* loudly (`config.interaction_wiring`), a declaration outside {@link APPROVAL_REACH} too (`config.approval_reach_invalid`).
|
|
676
|
+
*
|
|
677
|
+
* `approvalReach: "none"` is one sentence here: a blanket `"allow"` / `"deny"` stays what it is (a policy setting never
|
|
678
|
+
* claimed to be a person); a callback, or no seat, becomes `declared_none` with NO value — so the readers of the value
|
|
679
|
+
* (the approver lane, the park's sync-first decline, the durable-mandate source, a child's inherited seat) and the readers
|
|
680
|
+
* of the word ({@link deriveAskEffective}) cannot disagree about whether a person is there.
|
|
681
|
+
*/
|
|
682
|
+
export declare function resolveAskSeat(spec: Pick<TaskSpec, "onAsk" | "approvalReach">, deps: Pick<RunnerDeps, "onAsk">): AskSeat;
|
|
683
|
+
/** The form and provenance half of {@link resolveAskSeat} — the projection the manifest's two halves and a server's
|
|
684
|
+
* per-leg judgment read (hand it the request's `approvalReach` beside the seat). */
|
|
685
|
+
export declare function resolveAskSeamForm(spec: Pick<TaskSpec, "onAsk" | "approvalReach">, deps: Pick<RunnerDeps, "onAsk">): {
|
|
644
686
|
form: AskSeamForm;
|
|
645
687
|
provenance?: SeamProvenance;
|
|
646
688
|
};
|
|
@@ -5,6 +5,22 @@ import { canonicalize } from "./canonical-json.js";
|
|
|
5
5
|
import { resolveCheckpointStore } from "./checkpoint-store.js";
|
|
6
6
|
import { isLiveQuestionFace } from "./ask-question.js";
|
|
7
7
|
import { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./runtime-caps.js";
|
|
8
|
+
import { describeRejectedValue } from "./tool-search-setting.js";
|
|
9
|
+
export const APPROVAL_REACH = Object.freeze(["none"]);
|
|
10
|
+
const APPROVAL_REACH_SET = new Set(APPROVAL_REACH);
|
|
11
|
+
export function isApprovalReach(v) {
|
|
12
|
+
return APPROVAL_REACH_SET.has(v);
|
|
13
|
+
}
|
|
14
|
+
export function screenApprovalReach(v) {
|
|
15
|
+
if (v === undefined)
|
|
16
|
+
return undefined;
|
|
17
|
+
if (isApprovalReach(v))
|
|
18
|
+
return v;
|
|
19
|
+
const e = new Error(`approvalReach ${describeRejectedValue(v)} is not a recognized declaration (${APPROVAL_REACH.map((w) => JSON.stringify(w)).join(" | ")}) — ` +
|
|
20
|
+
`omit it when a person may be asked; an unreadable declaration is refused, never folded to either reading.`);
|
|
21
|
+
e.code = "config.approval_reach_invalid";
|
|
22
|
+
throw e;
|
|
23
|
+
}
|
|
8
24
|
export const AUTO_MODE_ARM_REASONS = Object.freeze(["armed", "no_intent", "no_face", "denied", "resolver_fault"]);
|
|
9
25
|
export const LSP_LANES = Object.freeze(["tool", "diagnostics", "tool_and_diagnostics"]);
|
|
10
26
|
export function deriveHandsSeam(handsMounted) {
|
|
@@ -53,6 +69,7 @@ export function deriveAskEffective(form, parkEffective, mode) {
|
|
|
53
69
|
case "deny":
|
|
54
70
|
return parkEffective === true ? "park_only" : parkEffective === "unresolved" ? "unresolved" : "auto_deny";
|
|
55
71
|
case "absent":
|
|
72
|
+
case "declared_none":
|
|
56
73
|
return parkEffective === true ? "park_only" : parkEffective === "unresolved" ? "unresolved" : "auto_deny";
|
|
57
74
|
default: {
|
|
58
75
|
const _exhaustive = form;
|
|
@@ -211,10 +228,12 @@ export function deriveWiringManifest(facts) {
|
|
|
211
228
|
}
|
|
212
229
|
return manifest;
|
|
213
230
|
}
|
|
214
|
-
export function
|
|
215
|
-
const
|
|
231
|
+
export function resolveAskSeat(spec, deps) {
|
|
232
|
+
const specValue = spec.onAsk;
|
|
233
|
+
const seat = specValue !== undefined ? { value: specValue, provenance: "spec" } : ((v) => (v !== undefined ? { value: v, provenance: "deps" } : undefined))(deps.onAsk);
|
|
234
|
+
const reach = screenApprovalReach(spec.approvalReach);
|
|
216
235
|
if (seat === undefined)
|
|
217
|
-
return { form: "absent" };
|
|
236
|
+
return Object.freeze(reach === undefined ? { value: undefined, form: "absent" } : { value: undefined, form: "declared_none", reach });
|
|
218
237
|
const v = seat.value;
|
|
219
238
|
const form = typeof v === "function" ? "callback" : v === "allow" ? "allow" : v === "deny" ? "deny" : undefined;
|
|
220
239
|
if (form === undefined) {
|
|
@@ -223,7 +242,13 @@ export function resolveAskSeamForm(spec, deps) {
|
|
|
223
242
|
e.code = "config.interaction_wiring";
|
|
224
243
|
throw e;
|
|
225
244
|
}
|
|
226
|
-
|
|
245
|
+
if (reach !== undefined && form === "callback")
|
|
246
|
+
return Object.freeze({ value: undefined, form: "declared_none", provenance: seat.provenance, reach });
|
|
247
|
+
return Object.freeze({ value: v, form, provenance: seat.provenance, ...(reach !== undefined ? { reach } : {}) });
|
|
248
|
+
}
|
|
249
|
+
export function resolveAskSeamForm(spec, deps) {
|
|
250
|
+
const seat = resolveAskSeat(spec, deps);
|
|
251
|
+
return { form: seat.form, ...(seat.provenance !== undefined ? { provenance: seat.provenance } : {}) };
|
|
227
252
|
}
|
|
228
253
|
export function resolveQuestionSeam(spec, deps) {
|
|
229
254
|
const seat = spec.onQuestion !== undefined ? { value: spec.onQuestion, provenance: "spec" } : deps.onQuestion !== undefined ? { value: deps.onQuestion, provenance: "deps" } : undefined;
|
package/dist/index.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ export { StdioLspTransport, type LspChildProcess } from "./engine/lsp/stdio-lsp-
|
|
|
42
42
|
export { encodeFrame, createFrameDecoder } from "./engine/lsp/frame-decoder.js";
|
|
43
43
|
export { resolveModel, resolveTaskModel, parseModelMention, expandTiers, DEFAULT_TIER_ORDER, CC_MODEL_TIER_ALIASES, ROLE_TIER_DEFAULTS, MODEL_ROLES, type ModelRole, type RoleSpec, type ModelRoles, type ResolvedRole, type ModelMention, } from "./core/roles.js";
|
|
44
44
|
export { selectModel, selectModelOrThrow, type ModelCriteria, type ModelTier } from "./core/select-model.js";
|
|
45
|
-
export { BrainError, classifyHttp, isProviderEchoShape, PROVIDER_ECHO_SHAPE, type BrainErrorCode } from "./brain/errors.js";
|
|
45
|
+
export { BrainError, classifyHttp, isProviderEchoShape, PROVIDER_ECHO_SHAPE, PROXY_TUNNEL_REFUSED, type BrainErrorCode } from "./brain/errors.js";
|
|
46
46
|
export { looksDegenerate, inspectDegenerate, trimDegenerateTail } from "./brain/repetition.js";
|
|
47
47
|
export type { RepetitionEvent, RepetitionInspection } from "./brain/repetition.js";
|
|
48
48
|
export { computeCostMicroUsd, isModelPriced, modelCostToPricing, type ModelPricing, type TokenCounts, } from "./core/pricing.js";
|
|
@@ -63,7 +63,8 @@ export { MCP_FAILURE_KINDS, MCP_DELIVERY_VERDICTS, MCP_LIVENESS_STATES, classify
|
|
|
63
63
|
export { MCP_INJECTION_DROP_REASONS, MCP_INJECTION_DROP_TEXT, mcpInjectionDroppedNotice, type McpInjectionDropReason, type McpInjectionDropFacts } from "./core/mcp-injection-drop.js";
|
|
64
64
|
export { askUnresolvableNotice, type AskUnresolvableFacts } from "./core/ask-unresolvable-notice.js";
|
|
65
65
|
export { ASK_UNRESOLVABLE_CAUSES } from "./core/ask-unresolvable-notice.js";
|
|
66
|
-
export {
|
|
66
|
+
export { USER_INPUT_UNDRAINED_CAUSES, type UserInputUndrainedCause } from "./core/engine-notice.js";
|
|
67
|
+
export { STEER_REPLAY_FACETS, type SteerReplayFacet } from "./core/steer-replay.js";
|
|
67
68
|
export { TOOL_TURN_INCOMPLETE_CAUSES, type ToolTurnIncompleteCause } from "./internal/llm.js";
|
|
68
69
|
export { DURABLE_MANDATE_SOURCES } from "./core/tool-policy.js";
|
|
69
70
|
export { TERMINAL_CAUSE_IS_REPLAYABLE, type TerminalFailureDetail, type TerminalBlockedDetail, PROMPT_BLOCK_CAUSES, type PromptBlockCause, isPromptBlockCause } from "./core/terminal-cause.js";
|
|
@@ -162,7 +163,7 @@ export { parkedToolIdentity } from "./core/tool-roster.js";
|
|
|
162
163
|
export { type ToolCallIdentity } from "./core/fs-write-gate-policy.js";
|
|
163
164
|
export { type RuleFaceView, catalogRuleFaceView } from "./core/permission-rules.js";
|
|
164
165
|
export { DURABLE_HISTORY_NAMES } from "./engine/compaction/utils.js";
|
|
165
|
-
export { describeStaticWiring, deriveWiringManifest, deriveAskEffective, resolveDeclaredDurability, resolveSubagentTranscriptTier, type SubagentTranscriptTier, resolveAskSeamForm, resolveQuestionSeam, countElicitOptIns, AUTO_MODE_ARM_REASONS, type AutoModeArmReason, type AutoModeArmFact, type WiringManifest, type WiringManifestMcpEntry, LSP_LANES, type LspLane, type WiringFacts, type WiringLegKind, type AskSeamForm, type AskEffective, type QuestionChannelState, type SeamProvenance, type ParkLaneReason, type ManifestDurability, type StaticWiringDeps, type StaticWiringSpec, } from "./core/wiring-manifest.js";
|
|
166
|
+
export { describeStaticWiring, deriveWiringManifest, deriveAskEffective, resolveDeclaredDurability, resolveSubagentTranscriptTier, type SubagentTranscriptTier, resolveAskSeamForm, resolveQuestionSeam, countElicitOptIns, AUTO_MODE_ARM_REASONS, type AutoModeArmReason, type AutoModeArmFact, type WiringManifest, type WiringManifestMcpEntry, LSP_LANES, type LspLane, type WiringFacts, type WiringLegKind, type AskSeamForm, APPROVAL_REACH, type ApprovalReach, isApprovalReach, type AskEffective, type QuestionChannelState, type SeamProvenance, type ParkLaneReason, type ManifestDurability, type StaticWiringDeps, type StaticWiringSpec, } from "./core/wiring-manifest.js";
|
|
166
167
|
export { probeParkRoundTrip, durableParkGapOf, durableParkGapFor, PARK_SELFCHECK_SCOPE_PREFIX, type ParkSelfCheckResult, type ParkProbeFinding, type ParkProbeFindingCode, } from "./core/park-selfcheck.js";
|
|
167
168
|
export { type StoreDurability } from "./core/checkpoint-store.js";
|
|
168
169
|
export { type StoreFidelity } from "./core/checkpoint-store.js";
|
|
@@ -192,7 +193,7 @@ export { createAllowDenyPolicy, createApprovalPolicy,
|
|
|
192
193
|
* members that seat has no lane for (`"unavailable"`, a routing answer; `updatedInput`, an operator edit a
|
|
193
194
|
* policy verdict cannot get re-adjudicated). Exported so a host can NAME it instead of deriving it through
|
|
194
195
|
* `Parameters<typeof createApprovalPolicy>[0]["approve"]`. */
|
|
195
|
-
type ApprovalSeatOutcome, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, receiveHookResult, isEngineRefusal, wrapToolPolicy, decisionText, resolveAsk, toolPolicyNameSets, toolPolicyPathDenyRules, type ToolPolicyNameSets, type NamedToolPolicy, type ToolPolicyProjection, type ToolPolicyProjectionComponent, type ConstraintChainEntry, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, type ToolPolicy, type ToolCallRequest, type PermissionResult, type DecisionReason, screenApproverAttribution, APPROVER_ATTRIBUTION_MAX_CHARS, type OnAsk, type AskOutcome, type ResolvedAsk, type AskRequest, type AskDelegationProvenance, type AskRuleEvidence, type AskEvidenceAbsence, ASK_EVIDENCE_ABSENCE_VALUES, } from "./core/tool-policy.js";
|
|
196
|
+
type ApprovalSeatOutcome, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, abortedSeatDeny, receiveHookResult, isEngineRefusal, wrapToolPolicy, decisionText, resolveAsk, toolPolicyNameSets, toolPolicyPathDenyRules, type ToolPolicyNameSets, type NamedToolPolicy, type ToolPolicyProjection, type ToolPolicyProjectionComponent, type ConstraintChainEntry, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, type ToolPolicy, type ToolCallRequest, type PermissionResult, type DecisionReason, screenApproverAttribution, APPROVER_ATTRIBUTION_MAX_CHARS, type OnAsk, type AskOutcome, type ResolvedAsk, type AskRequest, type AskDelegationProvenance, type AskRuleEvidence, type AskEvidenceAbsence, ASK_EVIDENCE_ABSENCE_VALUES, } from "./core/tool-policy.js";
|
|
196
197
|
export { type ReadRootGrantScreen } from "./core/read-root-grant-screen.js";
|
|
197
198
|
export { type AskOrigin, ASK_ORIGINS, isAskOrigin, ORIGIN_IMPLIES_REAL_APPROVAL, PERSISTED_RULE_MANDATES, type PersistedRuleMandate, isPersistedRuleMandate, screenAskClassMembers } from "./core/ask-origin.js";
|
|
198
199
|
export { PERMISSION_MODES, type PermissionMode, isPermissionMode, PERMISSION_MODE_RANK, clampPermissionMode, ASK_CLASSES, type AskClass, isAskClass, MODE_ARBITRATION, type ModeArbitrationRow, RELEASABLE_ASK_CLASSES, MODE_RELEASE_REASONS, type ModeReleaseReason, isModeReleaseReason, RRA_EXPLAINERS, classifyAsk, foldArbitrationRow, type AskClassification, type AskClassFacts, type ToolMarkSource, arbitrateByMode, type Arbitration, fileCommandOptionsSentence } from "./core/ask-origin.js";
|
|
@@ -200,6 +201,7 @@ export { modePolicyOf, type ModePolicy, PERMISSION_MODE_FOLD_REASONS, type Permi
|
|
|
200
201
|
export type { PermissionSeatInputs, PermissionSeatReading } from "./core/mode-policy.js";
|
|
201
202
|
export type { SkillGateSeats, SkillGrantHit, SkillGrantLane, SkillGrantOrigin, SkillGrantRecord } from "./core/skill-grant.js";
|
|
202
203
|
export { SKILL_GRANT_ORIGINS } from "./core/skill-grant.js";
|
|
204
|
+
export type { BoundSkillGrants } from "./core/skill-grant-binding.js";
|
|
203
205
|
export { ALLOW_ENTRY_INERT_REASONS, compileAllowEntry, compileAllowList, type AllowEntryInertReason, type CompiledAllowEntry, type AllowEntryGateSeats, type AllowEntryLane, type AllowEntryHit } from "./core/allow-entry.js";
|
|
204
206
|
export { ALLOW_RULE_MEMBERS, type AllowRuleMember, type AllowRuleShadow } from "./core/allow-rule-shadow.js";
|
|
205
207
|
export { mintNamespacePrefix } from "./core/protocol-naming.js";
|
package/dist/index.js
CHANGED
|
@@ -29,7 +29,7 @@ export { StdioLspTransport } from "./engine/lsp/stdio-lsp-transport.js";
|
|
|
29
29
|
export { encodeFrame, createFrameDecoder } from "./engine/lsp/frame-decoder.js";
|
|
30
30
|
export { resolveModel, resolveTaskModel, parseModelMention, expandTiers, DEFAULT_TIER_ORDER, CC_MODEL_TIER_ALIASES, ROLE_TIER_DEFAULTS, MODEL_ROLES, } from "./core/roles.js";
|
|
31
31
|
export { selectModel, selectModelOrThrow } from "./core/select-model.js";
|
|
32
|
-
export { BrainError, classifyHttp, isProviderEchoShape, PROVIDER_ECHO_SHAPE } from "./brain/errors.js";
|
|
32
|
+
export { BrainError, classifyHttp, isProviderEchoShape, PROVIDER_ECHO_SHAPE, PROXY_TUNNEL_REFUSED } from "./brain/errors.js";
|
|
33
33
|
export { looksDegenerate, inspectDegenerate, trimDegenerateTail } from "./brain/repetition.js";
|
|
34
34
|
export { computeCostMicroUsd, isModelPriced, modelCostToPricing, } from "./core/pricing.js";
|
|
35
35
|
export { cacheFamilyOf, promptTokensOf, uncachedInputTokensOf } from "./core/runner/usage-accounting.js";
|
|
@@ -49,7 +49,8 @@ export { MCP_FAILURE_KINDS, MCP_DELIVERY_VERDICTS, MCP_LIVENESS_STATES, classify
|
|
|
49
49
|
export { MCP_INJECTION_DROP_REASONS, MCP_INJECTION_DROP_TEXT, mcpInjectionDroppedNotice } from "./core/mcp-injection-drop.js";
|
|
50
50
|
export { askUnresolvableNotice } from "./core/ask-unresolvable-notice.js";
|
|
51
51
|
export { ASK_UNRESOLVABLE_CAUSES } from "./core/ask-unresolvable-notice.js";
|
|
52
|
-
export {
|
|
52
|
+
export { USER_INPUT_UNDRAINED_CAUSES } from "./core/engine-notice.js";
|
|
53
|
+
export { STEER_REPLAY_FACETS } from "./core/steer-replay.js";
|
|
53
54
|
export { TOOL_TURN_INCOMPLETE_CAUSES } from "./internal/llm.js";
|
|
54
55
|
export { DURABLE_MANDATE_SOURCES } from "./core/tool-policy.js";
|
|
55
56
|
export { TERMINAL_CAUSE_IS_REPLAYABLE, PROMPT_BLOCK_CAUSES, isPromptBlockCause } from "./core/terminal-cause.js";
|
|
@@ -134,7 +135,7 @@ export { parkedToolIdentity } from "./core/tool-roster.js";
|
|
|
134
135
|
export {} from "./core/fs-write-gate-policy.js";
|
|
135
136
|
export { catalogRuleFaceView } from "./core/permission-rules.js";
|
|
136
137
|
export { DURABLE_HISTORY_NAMES } from "./engine/compaction/utils.js";
|
|
137
|
-
export { describeStaticWiring, deriveWiringManifest, deriveAskEffective, resolveDeclaredDurability, resolveSubagentTranscriptTier, resolveAskSeamForm, resolveQuestionSeam, countElicitOptIns, AUTO_MODE_ARM_REASONS, LSP_LANES, } from "./core/wiring-manifest.js";
|
|
138
|
+
export { describeStaticWiring, deriveWiringManifest, deriveAskEffective, resolveDeclaredDurability, resolveSubagentTranscriptTier, resolveAskSeamForm, resolveQuestionSeam, countElicitOptIns, AUTO_MODE_ARM_REASONS, LSP_LANES, APPROVAL_REACH, isApprovalReach, } from "./core/wiring-manifest.js";
|
|
138
139
|
export { probeParkRoundTrip, durableParkGapOf, durableParkGapFor, PARK_SELFCHECK_SCOPE_PREFIX, } from "./core/park-selfcheck.js";
|
|
139
140
|
export {} from "./core/checkpoint-store.js";
|
|
140
141
|
export {} from "./core/checkpoint-store.js";
|
|
@@ -157,7 +158,7 @@ export { hasScheduler, isValidCronExpr, SchedulerError } from "./core/scheduler.
|
|
|
157
158
|
export { createSchedulerTools, SCHEDULE_WAKEUP_TOOL_NAME, AUTONOMOUS_LOOP_SENTINEL, AUTONOMOUS_LOOP_DYNAMIC_SENTINEL, } from "./tools/scheduler-tools.js";
|
|
158
159
|
export { resolveAutonomousLoopPrompt, AUTONOMOUS_LOOP_PREAMBLE, AUTONOMOUS_LOOP_PREAMBLE_PERSISTENT, } from "./tools/loop-tick.js";
|
|
159
160
|
export { tightenTaskSpec, TaskSpecTightenError } from "./core/tighten-task-spec.js";
|
|
160
|
-
export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, receiveHookResult, isEngineRefusal, wrapToolPolicy, decisionText, resolveAsk, toolPolicyNameSets, toolPolicyPathDenyRules, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, screenApproverAttribution, APPROVER_ATTRIBUTION_MAX_CHARS, ASK_EVIDENCE_ABSENCE_VALUES, } from "./core/tool-policy.js";
|
|
161
|
+
export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, abortedSeatDeny, receiveHookResult, isEngineRefusal, wrapToolPolicy, decisionText, resolveAsk, toolPolicyNameSets, toolPolicyPathDenyRules, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, screenApproverAttribution, APPROVER_ATTRIBUTION_MAX_CHARS, ASK_EVIDENCE_ABSENCE_VALUES, } from "./core/tool-policy.js";
|
|
161
162
|
export {} from "./core/read-root-grant-screen.js";
|
|
162
163
|
export { ASK_ORIGINS, isAskOrigin, ORIGIN_IMPLIES_REAL_APPROVAL, PERSISTED_RULE_MANDATES, isPersistedRuleMandate, screenAskClassMembers } from "./core/ask-origin.js";
|
|
163
164
|
export { PERMISSION_MODES, isPermissionMode, PERMISSION_MODE_RANK, clampPermissionMode, ASK_CLASSES, isAskClass, MODE_ARBITRATION, RELEASABLE_ASK_CLASSES, MODE_RELEASE_REASONS, isModeReleaseReason, RRA_EXPLAINERS, classifyAsk, foldArbitrationRow, arbitrateByMode, fileCommandOptionsSentence } from "./core/ask-origin.js";
|
|
@@ -293,6 +293,10 @@ export interface RunWorkflowToolDeps {
|
|
|
293
293
|
* `ToolExecuteContext.interactiveTools` seat — without it a headless-clamped host's workflow
|
|
294
294
|
* children could re-mount the interactive tool the host run disabled. */
|
|
295
295
|
parentInteractiveTools?: false;
|
|
296
|
+
/** The HOST task's declaration that nobody on it can be asked to approve (`TaskSpec.approvalReach: "none"`), same
|
|
297
|
+
* carriage rules as the two clamps above: only `"none"` travels, and the auto-mount's minimal ctx makes this dep its one
|
|
298
|
+
* carrier — without it a declared-none host's workflow children fell back to the deployment's live approver. */
|
|
299
|
+
parentApprovalReach?: "none";
|
|
296
300
|
/** Call-time getter for the HOST task's RESOLVED model AND the word that chose it: a spawned agent whose
|
|
297
301
|
* fold chain produced no model inherits the object on its spec and the word on its trusted channel
|
|
298
302
|
* (the subagent lane's `ctx.model` / `ctx.modelRef` pair). Word-less ⇒ the object alone, i.e. a pin. */
|
|
@@ -509,7 +509,7 @@ export async function createRunWorkflowTool(d) {
|
|
|
509
509
|
const childParkSeat = ctx.checkpointStoreForChildren ?? d.parentCheckpointStore;
|
|
510
510
|
const parkStore = checkpointStoreOfSeat(childParkSeat);
|
|
511
511
|
const scriptFn = (wfCtx) => {
|
|
512
|
-
const primitives = buildWorkflowPrimitives(wfCtx, runGovernance, d.onAgentSpawn, childParkSeat, parentFaceSeat(ctx.readFace, d.parentReadFace), parentFaceSeat(ctx.writeFace, d.parentWriteFace), d.parentReadDenyPatterns, ctx.handsReadOnly === true || d.parentHandsReadOnly === true, ctx.interactiveTools === false || d.parentInteractiveTools === false);
|
|
512
|
+
const primitives = buildWorkflowPrimitives(wfCtx, runGovernance, d.onAgentSpawn, childParkSeat, parentFaceSeat(ctx.readFace, d.parentReadFace), parentFaceSeat(ctx.writeFace, d.parentWriteFace), d.parentReadDenyPatterns, ctx.handsReadOnly === true || d.parentHandsReadOnly === true, ctx.interactiveTools === false || d.parentInteractiveTools === false, ctx.approvalReach === "none" || d.parentApprovalReach === "none");
|
|
513
513
|
return d.scriptRunner.run({ scriptSource: script, primitives, scriptArgs: effectiveArgs, signal: wfCtx.signal }).then((r) => r.result);
|
|
514
514
|
};
|
|
515
515
|
if (ctx.signal?.aborted) {
|
|
@@ -60,4 +60,6 @@ parentReadDenyPatterns?: () => TaskSpec["readDenyPatterns"],
|
|
|
60
60
|
parentHandsReadOnly?: boolean,
|
|
61
61
|
/** #345 ③ — the HOST task's hard-headless clamp is ON (`spec.interactiveTools === false`).
|
|
62
62
|
* Same tighten-only injection; only the disabling value ever arrives here as `true`. */
|
|
63
|
-
parentInteractiveToolsOff?: boolean
|
|
63
|
+
parentInteractiveToolsOff?: boolean,
|
|
64
|
+
/** The HOST task declared that nobody on it can be asked (`approvalReach: "none"`). Same tighten-only injection. */
|
|
65
|
+
parentApprovalReachNone?: boolean): WorkflowPrimitives;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { assertSupportedAgentIsolation } from "./workflow.js";
|
|
2
|
-
import { childClampSeats } from "../core/child-clamp-seats.js";
|
|
2
|
+
import { childClampSeats, postureUnderClamps } from "../core/child-clamp-seats.js";
|
|
3
3
|
import { WorkflowScriptError } from "./workflow-meta.js";
|
|
4
4
|
import { buildGovernedChildSpec, emitIgnoredAgentOptionsNotice, overlayWorktreeBaseline, MAX_ANNOUNCED_KEYS, SPEC_KEY_ALIASES, WHITELIST_KEYS, } from "./workflow-governance.js";
|
|
5
5
|
const ACCEPTED_AGENT_OPTION_KEYS = ["label", "phase", "schema", "agentType", "isolation"];
|
|
@@ -66,7 +66,7 @@ function formatResourceClampNote(notes) {
|
|
|
66
66
|
const parts = notes.map((n) => `${n.field}: requested ${n.requested === undefined ? "unset" : n.requested} → applied ${n.applied}`);
|
|
67
67
|
return `workflow governance tightened this agent's resource limits (${parts.join("; ")})`;
|
|
68
68
|
}
|
|
69
|
-
export function buildWorkflowPrimitives(ctx, governance, onAgentSpawn, parentCheckpointStore, parentReadFace, parentWriteFace, parentReadDenyPatterns, parentHandsReadOnly, parentInteractiveToolsOff) {
|
|
69
|
+
export function buildWorkflowPrimitives(ctx, governance, onAgentSpawn, parentCheckpointStore, parentReadFace, parentWriteFace, parentReadDenyPatterns, parentHandsReadOnly, parentInteractiveToolsOff, parentApprovalReachNone) {
|
|
70
70
|
const agent = (spec, opts) => {
|
|
71
71
|
if (typeof spec === "string")
|
|
72
72
|
spec = { objective: spec };
|
|
@@ -82,15 +82,15 @@ export function buildWorkflowPrimitives(ctx, governance, onAgentSpawn, parentChe
|
|
|
82
82
|
const workflowChildClamps = childClampSeats({
|
|
83
83
|
handsReadOnly: parentHandsReadOnly,
|
|
84
84
|
interactiveTools: parentInteractiveToolsOff === true ? false : undefined,
|
|
85
|
+
approvalReach: parentApprovalReachNone === true ? "none" : undefined,
|
|
85
86
|
readFace: parentReadFace?.() === "roots" ? "roots" : childSpec.readFace,
|
|
86
87
|
writeFace: parentWriteFace?.() === "roots" ? "roots" : childSpec.writeFace,
|
|
87
88
|
readDenyPatterns: pd !== undefined && pd.length > 0 ? [...(childSpec.readDenyPatterns ?? []), ...pd] : childSpec.readDenyPatterns,
|
|
88
89
|
});
|
|
89
90
|
Object.assign(childSpec, workflowChildClamps);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
91
|
+
const posture = postureUnderClamps(childSpec.interactionPosture, { interactiveTools: parentInteractiveToolsOff === true ? false : undefined, approvalReach: parentApprovalReachNone === true ? "none" : undefined });
|
|
92
|
+
if (posture !== undefined)
|
|
93
|
+
childSpec.interactionPosture = posture;
|
|
94
94
|
if (onAgentSpawn) {
|
|
95
95
|
return ctx.agentStream(childSpec, agentOpts).then((handle) => {
|
|
96
96
|
onAgentSpawn(handle);
|
|
@@ -421,6 +421,9 @@ export interface WorkflowRun {
|
|
|
421
421
|
* read or written carrying this token's `parked` entry, so
|
|
422
422
|
* absence is the confirmed state and an entry written before this member reads as confirmed, exactly as it did; the
|
|
423
423
|
* engine's own material read identity-checks what it finds, so an unconfirmed origin degrades rather than mis-binds.
|
|
424
|
+
* `parkedBy` is the run standing on the park: a record's run holds it iff `entry.parkedBy === record.id` (never
|
|
425
|
+
* `originRunId`); inheritance keeps it. `generation` is the inherited entry's, else `0`, plus one per admission — the
|
|
426
|
+
* highest on a session is the chain's tail, a tie is a fork. Both or neither; an older entry has neither (no holder).
|
|
424
427
|
*/
|
|
425
428
|
parks?: Array<{
|
|
426
429
|
callKey: string;
|
|
@@ -428,6 +431,8 @@ export interface WorkflowRun {
|
|
|
428
431
|
token: string;
|
|
429
432
|
originRunId: string;
|
|
430
433
|
originUnconfirmed?: true;
|
|
434
|
+
parkedBy?: string;
|
|
435
|
+
generation?: number;
|
|
431
436
|
}>;
|
|
432
437
|
/**
|
|
433
438
|
* Set (`true`) on a resume run's record from its creation and REMOVED the moment its admission completes — so a record
|
|
@@ -223,8 +223,9 @@ export interface WorkflowAgentHandle {
|
|
|
223
223
|
* legs of one steering ingress are equally replay-safe. ⚠️ ONE arm of that contract is NOT reachable through this
|
|
224
224
|
* handle, deliberately: the idempotent-REPLAY arm ("same id, same payload ⇒ injects nothing"). Each call mints a
|
|
225
225
|
* FRESH unguessable correlation marker into the framing it delivers, so a retry under the same id is a
|
|
226
|
-
* same-id-DIFFERENT-instruction call and refuses typed `steering.duplicate_input_id
|
|
227
|
-
* lane is therefore AT-MOST-ONCE: a retried ingress is refused
|
|
226
|
+
* same-id-DIFFERENT-instruction call and refuses typed `steering.duplicate_input_id` (`detail.differs` always names
|
|
227
|
+
* `text` on this lane). What the key buys on this lane is therefore AT-MOST-ONCE: a retried ingress is refused
|
|
228
|
+
* LOUDLY instead of injecting a second copy.
|
|
228
229
|
*/
|
|
229
230
|
steer(content: string, opts?: {
|
|
230
231
|
inputId?: string;
|