@sema-agent/core 7.49.5 → 7.50.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 +138 -0
- package/dist/agents/observer.js +3 -10
- package/dist/agents/subagent-steps.d.ts +6 -14
- package/dist/agents/subagent-steps.js +3 -17
- package/dist/brain/stream-shared.d.ts +1 -1
- package/dist/core/allow-entry.d.ts +1 -1
- package/dist/core/allow-entry.js +1 -1
- package/dist/core/ask-origin.d.ts +15 -11
- package/dist/core/ask-origin.js +6 -14
- package/dist/core/auto-mode-prompt.js +6 -2
- package/dist/core/checkpoint-store.d.ts +6 -4
- package/dist/core/checkpoint-store.js +1 -1
- package/dist/core/context-edit.d.ts +2 -2
- package/dist/core/decision-receipt.d.ts +2 -2
- package/dist/core/decision-receipt.js +30 -11
- package/dist/core/delegation-frames.d.ts +66 -18
- package/dist/core/delegation-frames.js +22 -0
- package/dist/core/engine-notice.d.ts +7 -5
- package/dist/core/frame-settlement.d.ts +6 -1
- package/dist/core/gate-fold.js +19 -13
- package/dist/core/gate-lanes.js +12 -11
- package/dist/core/gate-outcome.d.ts +2 -2
- package/dist/core/governance-codes.js +2 -0
- package/dist/core/hooks.d.ts +28 -20
- package/dist/core/human-input-projection.js +2 -0
- package/dist/core/lsp-diagnostics.d.ts +3 -0
- package/dist/core/lsp-diagnostics.js +6 -0
- package/dist/core/lsp-session.d.ts +39 -17
- package/dist/core/lsp-session.js +118 -58
- package/dist/core/lsp.d.ts +83 -3
- package/dist/core/lsp.js +146 -16
- package/dist/core/mcp.js +2 -1
- package/dist/core/media-byte-cap.d.ts +14 -0
- package/dist/core/media-byte-cap.js +15 -3
- package/dist/core/memory-engine/consolidation-driver.d.ts +23 -1
- package/dist/core/memory-engine/consolidation-driver.js +54 -6
- package/dist/core/memory-engine/consolidation-write-gate.d.ts +46 -0
- package/dist/core/memory-engine/consolidation-write-gate.js +82 -0
- package/dist/core/memory-engine/consolidation.d.ts +17 -0
- package/dist/core/memory-engine/consolidation.js +1 -0
- package/dist/core/memory-engine/distiller.d.ts +8 -2
- package/dist/core/memory-engine/distiller.js +8 -6
- package/dist/core/memory-engine/engine.d.ts +37 -4
- package/dist/core/memory-engine/engine.js +127 -38
- package/dist/core/memory-engine/file-backend.d.ts +8 -3
- package/dist/core/memory-engine/file-backend.js +44 -16
- package/dist/core/memory-engine/index.d.ts +2 -2
- package/dist/core/memory-engine/index.js +1 -1
- package/dist/core/memory-engine/landing-admission.d.ts +65 -0
- package/dist/core/memory-engine/landing-admission.js +68 -0
- package/dist/core/memory-engine/types.d.ts +23 -0
- package/dist/core/mode-policy.d.ts +3 -2
- package/dist/core/mode-policy.js +2 -0
- package/dist/core/permission-rule-model.d.ts +19 -13
- package/dist/core/permission-rule-model.js +7 -4
- package/dist/core/permission-rule-provider.d.ts +11 -0
- package/dist/core/permission-rules.d.ts +1 -1
- package/dist/core/permission-rules.js +5 -2
- package/dist/core/persisted-rule-arms.d.ts +15 -7
- package/dist/core/persisted-rule-arms.js +13 -6
- package/dist/core/reminder-mint.d.ts +5 -0
- package/dist/core/reminder-mint.js +1 -0
- package/dist/core/retired-keys.d.ts +8 -0
- package/dist/core/retired-keys.js +4 -0
- package/dist/core/rule-lane-reads.d.ts +4 -4
- package/dist/core/rule-lane-reads.js +10 -1
- package/dist/core/runner/construction-doors.d.ts +10 -4
- package/dist/core/runner/construction-doors.js +25 -2
- package/dist/core/runner/contracts.d.ts +20 -3
- package/dist/core/runner/env-capability-census.js +1 -1
- package/dist/core/runner/gate-exit.js +2 -1
- package/dist/core/runner/memory-consolidation-driver.d.ts +6 -4
- package/dist/core/runner/memory-consolidation-driver.js +5 -2
- package/dist/core/runner/memory-consolidation-write-judge.d.ts +17 -0
- package/dist/core/runner/memory-consolidation-write-judge.js +14 -0
- package/dist/core/runner/permission-rule-lanes.d.ts +16 -22
- package/dist/core/runner/permission-rule-lanes.js +13 -43
- package/dist/core/runner/person-path-rows.d.ts +244 -0
- package/dist/core/runner/person-path-rows.js +387 -0
- package/dist/core/runner/prepare-acquire-reconcile.js +8 -1
- package/dist/core/runner/prepare-artifact.d.ts +5 -3
- package/dist/core/runner/prepare-artifact.js +2 -8
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -3
- package/dist/core/runner/prepare-caps-and-workflow.js +1 -1
- package/dist/core/runner/prepare-context-lane.js +2 -2
- package/dist/core/runner/prepare-gate-stations.d.ts +3 -3
- package/dist/core/runner/prepare-gate-stations.js +1 -1
- package/dist/core/runner/prepare-hands-readface.d.ts +19 -10
- package/dist/core/runner/prepare-hands-readface.js +57 -43
- package/dist/core/runner/prepare-lsp.d.ts +15 -13
- package/dist/core/runner/prepare-lsp.js +11 -11
- package/dist/core/runner/prepare-policy-chain.d.ts +8 -4
- package/dist/core/runner/prepare-policy-chain.js +6 -7
- package/dist/core/runner/prepare-run-refs.js +1 -1
- package/dist/core/runner/prepare-task.js +24 -16
- package/dist/core/runner/prepare-turn-wiring.d.ts +13 -6
- package/dist/core/runner/prepare-turn-wiring.js +19 -8
- package/dist/core/runner/read-root-grant.d.ts +1 -25
- package/dist/core/runner/read-root-grant.js +1 -17
- package/dist/core/runner/retired-runner-deps.d.ts +2 -2
- package/dist/core/runner/run-brain-sinks.d.ts +1 -5
- package/dist/core/runner/run-brain-sinks.js +2 -4
- package/dist/core/runner/run-harness-handlers.js +5 -4
- package/dist/core/runner/run-identity-wiring.d.ts +4 -4
- package/dist/core/runner/run-identity-wiring.js +10 -1
- package/dist/core/runner/run-leg.d.ts +1 -1
- package/dist/core/runner/run-leg.js +22 -9
- package/dist/core/runner/run-settle-and-teardown.d.ts +0 -4
- package/dist/core/runner/run-settle-and-teardown.js +7 -4
- package/dist/core/runner/run-terminal-adoption.d.ts +1 -1
- package/dist/core/runner/run-terminal-adoption.js +1 -1
- package/dist/core/runner/run-turn-boundary.js +2 -2
- package/dist/core/runner/runtask.js +8 -8
- package/dist/core/runner/session-file-state-replay.d.ts +14 -4
- package/dist/core/runner/session-file-state-replay.js +8 -0
- package/dist/core/runner/stream-steer-verb.js +3 -0
- package/dist/core/runner/tool-end-body.d.ts +5 -4
- package/dist/core/runner/tool-end-body.js +4 -4
- package/dist/core/runner/tool-output-projection.d.ts +6 -4
- package/dist/core/runner/tool-output-projection.js +66 -47
- package/dist/core/runner-deps.d.ts +6 -3
- package/dist/core/shared-memory/types.d.ts +2 -2
- package/dist/core/shell-read-silence.d.ts +23 -0
- package/dist/core/shell-read-silence.js +18 -0
- package/dist/core/synthetic-read-verdict.d.ts +80 -21
- package/dist/core/synthetic-read-verdict.js +89 -18
- package/dist/core/task-event.d.ts +113 -25
- package/dist/core/task-spec.d.ts +44 -0
- package/dist/core/task-tool-shape.d.ts +1 -1
- package/dist/core/tool-catalog-entries.js +16 -2
- package/dist/core/tool-policy.d.ts +25 -15
- package/dist/core/tool-policy.js +9 -13
- package/dist/core/trace.d.ts +3 -2
- package/dist/core/types.d.ts +3 -3
- package/dist/core/types.js +1 -1
- package/dist/core/untrusted-text.d.ts +2 -2
- package/dist/core/user-attachment.d.ts +164 -0
- package/dist/core/user-attachment.js +437 -0
- package/dist/engine/compaction/compaction.js +10 -3
- package/dist/engine/compaction/utils.js +6 -0
- package/dist/engine/execution-env/node-execution-env.d.ts +19 -1
- package/dist/engine/execution-env/node-execution-env.js +125 -0
- package/dist/engine/harness/agent-harness.d.ts +12 -2
- package/dist/engine/harness/agent-harness.js +15 -3
- package/dist/engine/harness/types.d.ts +21 -0
- package/dist/engine/llm/content-block-render.d.ts +15 -0
- package/dist/engine/llm/content-block-render.js +10 -0
- package/dist/engine/llm/index.d.ts +1 -0
- package/dist/engine/llm/index.js +1 -0
- package/dist/engine/llm/types.d.ts +80 -4
- package/dist/engine/llm/types.js +43 -1
- package/dist/engine/session/import-validate.js +2 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +2 -1
- package/dist/internal/harness-types.d.ts +1 -1
- package/dist/internal/llm.d.ts +2 -2
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/workflow.d.ts +4 -5
- package/dist/orchestration/workflow.js +2 -2
- package/dist/prompts/default.d.ts +1 -1
- package/dist/tools/artifact/artifact-tool.js +1 -1
- package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
- package/dist/tools/fs/dir-entries.d.ts +4 -10
- package/dist/tools/fs/dir-entries.js +4 -11
- package/dist/tools/fs/file-read-check.js +3 -3
- package/dist/tools/fs/fs-pdf.js +2 -4
- package/dist/tools/fs/fs-read.d.ts +47 -4
- package/dist/tools/fs/fs-read.js +63 -19
- package/dist/tools/fs/fs-search-tools.d.ts +3 -3
- package/dist/tools/fs/fs-search-tools.js +7 -2
- package/dist/tools/fs/fs-write.d.ts +1 -1
- package/dist/tools/fs/fs-write.js +7 -6
- package/dist/tools/fs/index.d.ts +7 -1
- package/dist/tools/fs/index.js +56 -34
- package/dist/tools/fs/read-deny-home.d.ts +19 -1
- package/dist/tools/fs/read-deny-home.js +32 -22
- package/dist/tools/fs/read-deny.d.ts +14 -0
- package/dist/tools/fs/read-deny.js +8 -0
- package/dist/tools/fs/repo-map.d.ts +3 -2
- package/dist/tools/fs/repo-map.js +11 -3
- package/dist/tools/fs/safety.d.ts +41 -2
- package/dist/tools/fs/safety.js +12 -3
- package/dist/tools/fs/shell-read-check.d.ts +12 -3
- package/dist/tools/fs/shell-read-check.js +28 -15
- package/dist/tools/fs/shell-read-device.d.ts +1 -1
- package/dist/tools/fs/shell-read-judge.d.ts +9 -4
- package/dist/tools/fs/shell-read-judge.js +1 -1
- package/dist/tools/loop-tick.d.ts +2 -2
- package/package.json +3 -1
- package/test/export-surface.snapshot.json +39 -1
- package/wire-changes/core@7.50.0.json +1699 -0
- package/dist/core/runner/persisted-path-rows.d.ts +0 -88
- package/dist/core/runner/persisted-path-rows.js +0 -108
package/dist/core/ask-origin.js
CHANGED
|
@@ -77,7 +77,7 @@ function originLadder(decision, facts) {
|
|
|
77
77
|
return "org_unavailable";
|
|
78
78
|
if (facts.org === "rule")
|
|
79
79
|
return "org_rule";
|
|
80
|
-
if (facts.ruleCallUnreadable === true)
|
|
80
|
+
if (facts.ruleCallUnreadable === true || facts.ruleStoreUnreadable === true)
|
|
81
81
|
return "rule_store_unavailable";
|
|
82
82
|
if (decision.decisionReason === "hook")
|
|
83
83
|
return "hook";
|
|
@@ -210,7 +210,7 @@ export const MODE_ARBITRATION = {
|
|
|
210
210
|
transcript_write: { bypassImmune: false, classifierEligible: true, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: true },
|
|
211
211
|
org_rule: { bypassImmune: true, classifierEligible: false, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: false },
|
|
212
212
|
governance_unavailable: { bypassImmune: true, classifierEligible: false, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: false },
|
|
213
|
-
rule_unreadable: { bypassImmune:
|
|
213
|
+
rule_unreadable: { bypassImmune: true, classifierEligible: false, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: false },
|
|
214
214
|
ask_rule: { bypassImmune: true, classifierEligible: false, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: true },
|
|
215
215
|
denial_limit_fallback: { bypassImmune: true, classifierEligible: false, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: false },
|
|
216
216
|
classifier_no_ruling: { bypassImmune: true, classifierEligible: false, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: false },
|
|
@@ -247,7 +247,7 @@ export function releasableAskClassesFor(face) {
|
|
|
247
247
|
throw new TypeError(`releasableAskClassesFor: "${String(face)}" is not an ask face (${ASK_FACES.join(", ")})`);
|
|
248
248
|
return RELEASABLE_BY_FACE[face];
|
|
249
249
|
}
|
|
250
|
-
export const MODE_RELEASE_REASONS = Object.freeze(["
|
|
250
|
+
export const MODE_RELEASE_REASONS = Object.freeze(["target_unresolved"]);
|
|
251
251
|
const MODE_RELEASE_REASON_SET = new Set(MODE_RELEASE_REASONS);
|
|
252
252
|
export function isModeReleaseReason(v) {
|
|
253
253
|
return MODE_RELEASE_REASON_SET.has(v);
|
|
@@ -266,16 +266,8 @@ export function screenAskClassMembers(askClass, classes) {
|
|
|
266
266
|
}
|
|
267
267
|
export function decisionAskClassesOf(d) {
|
|
268
268
|
const out = new Set();
|
|
269
|
-
|
|
270
|
-
out.add(
|
|
271
|
-
if (d.guard === "unverifiable_delete")
|
|
272
|
-
out.add("unverifiable_delete");
|
|
273
|
-
if (d.guard === "unverifiable_shell_text")
|
|
274
|
-
out.add("unverifiable_shell_text");
|
|
275
|
-
if (d.guard === "transcript_write")
|
|
276
|
-
out.add("transcript_write");
|
|
277
|
-
if (d.guard === "artifact_shared_read")
|
|
278
|
-
out.add("artifact_shared_read");
|
|
269
|
+
for (const guard of d.guards ?? [])
|
|
270
|
+
out.add(guard);
|
|
279
271
|
if (d.ruleUnreadable !== undefined)
|
|
280
272
|
out.add("rule_unreadable");
|
|
281
273
|
if (d.matchedAskRule !== undefined)
|
|
@@ -324,7 +316,7 @@ export function classifyAsk(d, facts) {
|
|
|
324
316
|
classes.add("ancestor");
|
|
325
317
|
if (facts.org === "rule")
|
|
326
318
|
classes.add("org_rule");
|
|
327
|
-
if (facts.org === "unavailable")
|
|
319
|
+
if (facts.org === "unavailable" || facts.ruleStoreUnreadable === true)
|
|
328
320
|
classes.add("governance_unavailable");
|
|
329
321
|
if (facts.ruleCallUnreadable === true)
|
|
330
322
|
classes.add("rule_unreadable");
|
|
@@ -2,6 +2,7 @@ import { AUTO_MODE_DEFAULT_WINDOW_MAX_CHARS, AUTO_MODE_DEFAULT_WINDOW_MAX_ENTRIE
|
|
|
2
2
|
import { AUTO_MODE_BASE_PROMPT, AUTO_MODE_PERMISSIONS_EXTERNAL } from "./auto-mode-prompt-assets.js";
|
|
3
3
|
import { cutEnginePrefix, cutEngineSegments, flattenableUserText } from "./untrusted-text.js";
|
|
4
4
|
import { readDenyPatternRun } from "../tools/fs/read-deny.js";
|
|
5
|
+
import { renderContentBlock, renderUserAttachmentView, userAttachmentOf } from "../internal/llm.js";
|
|
5
6
|
export { AUTO_MODE_DEFAULTS_SENTINEL } from "./auto-mode-defaults.js";
|
|
6
7
|
function mergeRuleSection(user, defaultsInner) {
|
|
7
8
|
if (!user?.length)
|
|
@@ -100,7 +101,10 @@ function excerptTailInclusive(text, cap) {
|
|
|
100
101
|
const LAUNCHING_AGENT_FRAME = "(this agent was started by another agent: every entry under [launching agent] reached it through that agent, and none is vouched for as the user's own message)\n";
|
|
101
102
|
function renderEntry(m, cap, user) {
|
|
102
103
|
if (m.role === "user") {
|
|
103
|
-
const raw = typeof m.content === "string" ? m.content : m.content.map(
|
|
104
|
+
const raw = typeof m.content === "string" ? m.content : m.content.map(renderContentBlock).join("\n");
|
|
105
|
+
const attachment = userAttachmentOf(m);
|
|
106
|
+
if (attachment !== undefined)
|
|
107
|
+
return `[attachment]\n${renderUserAttachmentView(m, attachment, cap)}`;
|
|
104
108
|
if (m.provenance === "engine-note") {
|
|
105
109
|
return `[engine note]\n${excerpt(raw, cap)}`;
|
|
106
110
|
}
|
|
@@ -126,7 +130,7 @@ function renderEntry(m, cap, user) {
|
|
|
126
130
|
return note === undefined ? `${user}\n${excerpt(text, cap)}` : `${user}\n${note}\n${excerpt(text, cap)}`;
|
|
127
131
|
}
|
|
128
132
|
if (m.role === "toolResult") {
|
|
129
|
-
const text = m.content.map(
|
|
133
|
+
const text = m.content.map(renderContentBlock).join("\n");
|
|
130
134
|
return `[tool_result ${m.toolName}${m.isError ? " (error)" : ""}]\n${excerpt(text, cap)}`;
|
|
131
135
|
}
|
|
132
136
|
const parts = [];
|
|
@@ -2103,15 +2103,17 @@ export type CheckpointErrorReason = "version_newer" | "env_factory_missing" | "g
|
|
|
2103
2103
|
* entry / a record member naming no absolute root. */
|
|
2104
2104
|
| "installation_record_absent" | "installation_record_misaligned" | "installation_record_invalid";
|
|
2105
2105
|
/**
|
|
2106
|
-
* The codes a RESUME's pre-claim configuration screen carries as `detail.code` of a `checkpoint.config_refused` — the
|
|
2107
|
-
* words prepare's mode, output-style, approval-reach, invoked-skill and recorded-mode doors throw, held unchanged so one refusal
|
|
2106
|
+
* The codes a RESUME's pre-claim configuration screen carries as `detail.code` of a `checkpoint.config_refused` — the eight
|
|
2107
|
+
* words prepare's mode, output-style, approval-reach, invoked-skill, attachment and recorded-mode doors throw, held unchanged so one refusal
|
|
2108
2108
|
* reads the same on a fresh run (`TaskResult.errorCode`) and on a resume. `config.spec_retired_key`: a retired spec key;
|
|
2109
2109
|
* `config.output_style_invalid`: a malformed output-style seat; `config.permission_mode_invalid`: a mode word outside the closed
|
|
2110
2110
|
* set (the config's `permissionMode`, or one the row recorded); `config.shell_gate_value_retired`: a retired shell-floor word;
|
|
2111
2111
|
* `config.approval_reach_invalid`: an `approvalReach` outside its set; `config.user_invoked_skill_unknown` / `skill_deny_unreadable`:
|
|
2112
|
-
* `userInvokedSkills` names a skill the config does not carry / one whose `disallowed-tools` entry the grammar reads as nothing
|
|
2112
|
+
* `userInvokedSkills` names a skill the config does not carry / one whose `disallowed-tools` entry the grammar reads as nothing;
|
|
2113
|
+
* `config.user_attachment_invalid`: the config declares `userAttachments` (a resume sends no new human message) or a malformed
|
|
2114
|
+
* value there.
|
|
2113
2115
|
*/
|
|
2114
|
-
export declare const CHECKPOINT_CONFIG_REFUSAL_CODES: readonly ["config.spec_retired_key", "config.output_style_invalid", "config.permission_mode_invalid", "config.shell_gate_value_retired", "config.approval_reach_invalid", "config.user_invoked_skill_unknown", "config.skill_deny_unreadable"];
|
|
2116
|
+
export declare const CHECKPOINT_CONFIG_REFUSAL_CODES: readonly ["config.spec_retired_key", "config.output_style_invalid", "config.permission_mode_invalid", "config.shell_gate_value_retired", "config.approval_reach_invalid", "config.user_invoked_skill_unknown", "config.skill_deny_unreadable", "config.user_attachment_invalid"];
|
|
2115
2117
|
export type CheckpointConfigRefusalCode = (typeof CHECKPOINT_CONFIG_REFUSAL_CODES)[number];
|
|
2116
2118
|
export declare const isCheckpointConfigRefusalCode: (word: unknown) => word is CheckpointConfigRefusalCode;
|
|
2117
2119
|
/** A typed checkpoint-store error so callers branch on `code` (mirrors `SessionError`). */
|
|
@@ -304,7 +304,7 @@ export function summarizeCheckpoint(cp) {
|
|
|
304
304
|
...(hasBidi ? { hasBidiControls: true } : {}),
|
|
305
305
|
};
|
|
306
306
|
}
|
|
307
|
-
export const CHECKPOINT_CONFIG_REFUSAL_CODES = Object.freeze(["config.spec_retired_key", "config.output_style_invalid", "config.permission_mode_invalid", "config.shell_gate_value_retired", "config.approval_reach_invalid", "config.user_invoked_skill_unknown", "config.skill_deny_unreadable"]);
|
|
307
|
+
export const CHECKPOINT_CONFIG_REFUSAL_CODES = Object.freeze(["config.spec_retired_key", "config.output_style_invalid", "config.permission_mode_invalid", "config.shell_gate_value_retired", "config.approval_reach_invalid", "config.user_invoked_skill_unknown", "config.skill_deny_unreadable", "config.user_attachment_invalid"]);
|
|
308
308
|
export const isCheckpointConfigRefusalCode = (word) => CHECKPOINT_CONFIG_REFUSAL_CODES.some((w) => w === word);
|
|
309
309
|
export class CheckpointError extends Error {
|
|
310
310
|
code;
|
|
@@ -77,7 +77,7 @@ export declare function contextEditFrontier(window: number): number;
|
|
|
77
77
|
* runner wires it on BOTH arms by default — the frontier pass and the MC-R rejection arm share
|
|
78
78
|
* one persist closure — so the shipped default clears to a pointer, never to a dead end.
|
|
79
79
|
* ④ the TRIGGER — CC's client machine fires ONLY on the server's `context_hint` 422/424 refusal
|
|
80
|
-
* (cli250.js:58375
|
|
80
|
+
* (cli250.js:58375 `context_hint`; the `tengu_time_based_microcompact` event name is historical, its `trigger`
|
|
81
81
|
* is the constant `"context_hint"`). Under BYOM there is no such server, so the ask half is
|
|
82
82
|
* unportable and the refusal half is aligned on wire truth (the MC-R arm classifies the
|
|
83
83
|
* provider's own context-overflow refusal) — registered divergence D-3. sema additionally
|
|
@@ -92,7 +92,7 @@ export declare const MICRO_COMPACT_MACHINES: readonly ["off", "cc"];
|
|
|
92
92
|
export type MicroCompactMachine = (typeof MICRO_COMPACT_MACHINES)[number];
|
|
93
93
|
/**
|
|
94
94
|
* How many most-recent CANDIDATE tool results keep their content when the stale-result pass runs:
|
|
95
|
-
* 5 (CC 2.1.223 `uAp`; 2.1.250 `var k
|
|
95
|
+
* 5 (CC 2.1.223 `uAp`; 2.1.250 `var k=5` beside the call site, cli250.js:58373, and 2.1.245 carries
|
|
96
96
|
* the same value — zero drift across 245→250; same value again on CC 88's `timeBasedMCConfig`, i.e.
|
|
97
97
|
* stable across all three corpus generations, and it is a hard-coded constant upstream, not a
|
|
98
98
|
* setting). The #384 adjudication adopted 5 CONDITIONAL on the whole machine coming with it (20k
|
|
@@ -40,7 +40,7 @@ export declare function nestedRecordsOf(receipt: object): object[];
|
|
|
40
40
|
* carrier, the member named by `path`: an accessor (never invoked), and a member the prototype or a non-enumerable property
|
|
41
41
|
* supplies, unless the nearest descriptor holding it spells absence (an `undefined` data property). Descriptors are looked up
|
|
42
42
|
* as OWN entries of the descriptor map, so a polluted `Object.prototype` names no member. Members outside the contract are
|
|
43
|
-
* not looked at. */
|
|
43
|
+
* not looked at — but a retired one (`retired`) is refused by name when the carrier carries it by that same law. */
|
|
44
44
|
/** The receipt's own answers carry a `kind` discriminant as an own property: narrowing never asks the prototype chain (`in`) for a
|
|
45
45
|
* word, so a polluted `Object.prototype` cannot answer for the receipt either. */
|
|
46
46
|
export type Received = {
|
|
@@ -50,5 +50,5 @@ export type Received = {
|
|
|
50
50
|
kind: "refused";
|
|
51
51
|
refused: PermissionResult;
|
|
52
52
|
};
|
|
53
|
-
export declare function receiveContract(carrier: object, members: readonly string[], path: string): Received;
|
|
53
|
+
export declare function receiveContract(carrier: object, members: readonly string[], path: string, retired?: Readonly<Record<string, string>>): Received;
|
|
54
54
|
export {};
|
|
@@ -12,7 +12,7 @@ export const isEngineRefusal = (d) => typeof d === "object" && d !== null && ENG
|
|
|
12
12
|
const DECISION_REASONS = Object.freeze(["rule", "mode", "hook", "safety", "classifier", "persisted_rule", "sandbox", "org_rule", "org_unavailable", "read_only", "skill", "deployment_rule", "request_rule"]);
|
|
13
13
|
const DECISION_ACTIONS = Object.keys({ allow: 0, deny: 0, ask: 0 });
|
|
14
14
|
const GUARDS = Object.keys({ dangerous_delete: 0, unverifiable_delete: 0, unverifiable_shell_text: 0, transcript_write: 0, artifact_shared_read: 0 });
|
|
15
|
-
const RULE_UNREADABLE_WORDS = Object.keys({ content_deny: 0, content_ask: 0, persisted_call: 0 });
|
|
15
|
+
const RULE_UNREADABLE_WORDS = Object.keys({ content_deny: 0, content_ask: 0, persisted_call: 0, persisted_rows: 0 });
|
|
16
16
|
const AUTHORED_BY_WORDS = Object.keys({ deployment: 0 });
|
|
17
17
|
const memberOf = (words) => {
|
|
18
18
|
const set = new Set(words);
|
|
@@ -26,7 +26,7 @@ const CLOSED_MEMBERS = [
|
|
|
26
26
|
{ member: "classes", words: ASK_CLASSES, has: isAskClass, list: true },
|
|
27
27
|
{ member: "foldedAskClasses", words: ASK_CLASSES, has: isAskClass, list: true },
|
|
28
28
|
{ member: "mandate", words: PERSISTED_RULE_MANDATES, has: isPersistedRuleMandate },
|
|
29
|
-
{ member: "
|
|
29
|
+
{ member: "guards", words: GUARDS, has: memberOf(GUARDS), list: true },
|
|
30
30
|
{ member: "ruleUnreadable", words: RULE_UNREADABLE_WORDS, has: memberOf(RULE_UNREADABLE_WORDS) },
|
|
31
31
|
{ member: "authoredBy", words: AUTHORED_BY_WORDS, has: memberOf(AUTHORED_BY_WORDS) },
|
|
32
32
|
{ member: "classifierNoRuling", words: AUTO_MODE_FALLBACK_CAUSES, has: isAutoModeFallbackCause },
|
|
@@ -197,7 +197,7 @@ function ordinaryChain(carrier) {
|
|
|
197
197
|
}
|
|
198
198
|
return { kind: "chain", chain };
|
|
199
199
|
}
|
|
200
|
-
export function receiveContract(carrier, members, path) {
|
|
200
|
+
export function receiveContract(carrier, members, path, retired) {
|
|
201
201
|
const what = path === "" ? "a permission decision" : `a permission decision's "${path.slice(0, -1)}" record`;
|
|
202
202
|
const ordinary = ordinaryChain(carrier);
|
|
203
203
|
if (ordinary.kind === "not") {
|
|
@@ -210,6 +210,21 @@ export function receiveContract(carrier, members, path) {
|
|
|
210
210
|
catch (e) {
|
|
211
211
|
return { kind: "refused", refused: refusedOutOfContract(`${what} threw while its property descriptors were looked at (${thrownText(e)}) — not an ordinary object; denied fail-closed`) };
|
|
212
212
|
}
|
|
213
|
+
const nearest = (m) => {
|
|
214
|
+
try {
|
|
215
|
+
if (Object.hasOwn(own, m))
|
|
216
|
+
return { kind: "found", d: own[m] };
|
|
217
|
+
for (let i = 1; i < ordinary.chain.length; i++) {
|
|
218
|
+
const d = Object.getOwnPropertyDescriptor(ordinary.chain[i], m);
|
|
219
|
+
if (d !== undefined)
|
|
220
|
+
return { kind: "found", d };
|
|
221
|
+
}
|
|
222
|
+
return { kind: "found", d: undefined };
|
|
223
|
+
}
|
|
224
|
+
catch (e) {
|
|
225
|
+
return { kind: "refused", refused: refusedOutOfContract(`${what} threw while "${path}${m}" was looked for on its prototype chain (${thrownText(e)}) — not an ordinary object; denied fail-closed`) };
|
|
226
|
+
}
|
|
227
|
+
};
|
|
213
228
|
const held = Object.create(null);
|
|
214
229
|
for (const m of members) {
|
|
215
230
|
const d = Object.hasOwn(own, m) ? own[m] : undefined;
|
|
@@ -220,14 +235,10 @@ export function receiveContract(carrier, members, path) {
|
|
|
220
235
|
held[m] = d.value;
|
|
221
236
|
continue;
|
|
222
237
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
catch (e) {
|
|
229
|
-
return { kind: "refused", refused: refusedOutOfContract(`${what} threw while "${path}${m}" was looked for on its prototype chain (${thrownText(e)}) — not an ordinary object; denied fail-closed`) };
|
|
230
|
-
}
|
|
238
|
+
const found = nearest(m);
|
|
239
|
+
if (found.kind === "refused")
|
|
240
|
+
return found;
|
|
241
|
+
const reached = found.d;
|
|
231
242
|
if (reached !== undefined && !spellsAbsence(reached)) {
|
|
232
243
|
return {
|
|
233
244
|
kind: "refused",
|
|
@@ -236,5 +247,13 @@ export function receiveContract(carrier, members, path) {
|
|
|
236
247
|
};
|
|
237
248
|
}
|
|
238
249
|
}
|
|
250
|
+
for (const [m, replacement] of Object.entries(retired ?? {})) {
|
|
251
|
+
const found = nearest(m);
|
|
252
|
+
if (found.kind === "refused")
|
|
253
|
+
return found;
|
|
254
|
+
if (found.d !== undefined && !spellsAbsence(found.d)) {
|
|
255
|
+
return { kind: "refused", refused: refusedOutOfContract(`a permission decision carries the retired "${m}" member — ${replacement}; denied fail-closed rather than executing a decision with a member this layer does not read`) };
|
|
256
|
+
}
|
|
257
|
+
}
|
|
239
258
|
return { kind: "held", held };
|
|
240
259
|
}
|
|
@@ -7,11 +7,18 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { TaskStatus } from "./task-result.js";
|
|
9
9
|
import type { RunnerDeps } from "./runner-deps.js";
|
|
10
|
+
import type { TaskEvent } from "./task-event.js";
|
|
10
11
|
/**
|
|
11
12
|
* design/129-B — one lifecycle event of a BACKGROUND delegation child, delivered to the
|
|
12
13
|
* process-level {@link RunnerDeps.onBackgroundChildEvent} observer. Keys: `taskId` is the registry handle
|
|
13
14
|
* (`a*` domain — the TaskOutput/TaskStop key); `progressTaskId`/`sessionId` are the child RUN's id (uuid
|
|
14
15
|
* domain — the same key `task_progress` frames carry).
|
|
16
|
+
*
|
|
17
|
+
* `kind: "spawn"` announces a fleet ROW's birth, which is a different fact from a child RUN's start
|
|
18
|
+
* (`TaskEvent` `task_started`): an `a*` row is born when its lane registers it, before the child run
|
|
19
|
+
* prepares (and a child whose prepare throws has a row and no run start); a `wa*` row is born with the
|
|
20
|
+
* workflow's own agent record, including rows that never run a child at all (a replayed or re-parked
|
|
21
|
+
* agent). Each fact has one mint — the lane for the row, the child's spawn station for the run.
|
|
15
22
|
*/
|
|
16
23
|
export interface BackgroundChildEvent {
|
|
17
24
|
kind: "spawn" | "tick" | "terminal";
|
|
@@ -223,15 +230,19 @@ export interface BackgroundChildEvent {
|
|
|
223
230
|
* now sees every delegation lane through one seat.
|
|
224
231
|
*
|
|
225
232
|
* EMISSION CHOKEPOINT (the reason this seat covers every lane at once): frames are minted by the
|
|
226
|
-
* RUNNER at the child LEG itself —
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
* this chokepoint, so none of them needs its own emission and none can drift.
|
|
233
|
+
* RUNNER at the child LEG itself — not by the individual spawn lanes. Every delegation lane
|
|
234
|
+
* (sync/steer/background/fork/revive, workflow-spawned agents) runs its child through this
|
|
235
|
+
* chokepoint, so none of them needs its own emission and none can drift.
|
|
230
236
|
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
237
|
+
* SPAWN IS A PROJECTION, TERMINAL IS PER LEG. The `spawn` phase is not a fact of its own: it is the
|
|
238
|
+
* projection of the child's `task_started` stream frame (`TaskEvent`), delivered from that frame's one
|
|
239
|
+
* mint at the leg's spawn station, at the same instant and under the same gate — so it fires exactly
|
|
240
|
+
* when a CYCLE starts (a first spawn, or a revival of a completed child) and never for a durable
|
|
241
|
+
* RESUME leg, which continues a cycle that already started. The `terminal` phase fires for EVERY
|
|
242
|
+
* delegated leg, resume legs included (a park ends a leg with `"suspended"`; the resume leg that later
|
|
243
|
+
* redeems it ends with its own terminal). Consumers correlate legs of one delegation by
|
|
244
|
+
* `identity.taskId` / `identity.parentToolCallId` (stable across legs), and `identity.legKind`
|
|
245
|
+
* (`"resume"`) names a resume leg's terminal.
|
|
235
246
|
*
|
|
236
247
|
* HONEST ABSENCES (recorded, not gaps to fix silently):
|
|
237
248
|
* · a child whose PREPARE throws emits neither frame (there is no leg identity to report);
|
|
@@ -242,14 +253,15 @@ export interface BackgroundChildEvent {
|
|
|
242
253
|
* ({@link import("./checkpoint-store.js").CheckpointState.isDelegatedChild}) emits neither frame:
|
|
243
254
|
* the row carries no evidence the parked leg was a delegated child, and fabricating the axis
|
|
244
255
|
* would stamp delegation frames onto host-resumed root tasks. Rows minted WITH the axis resume
|
|
245
|
-
* with their
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
* the ordinary path emits it where the `TaskResult` assembles, and a
|
|
249
|
-
* stream layer converts into a synthesized failed result (e.g.
|
|
250
|
-
* past the run tail) emits the failed terminal from that
|
|
251
|
-
*
|
|
252
|
-
* both fire for one leg). A leg whose PROCESS dies mid-flight is the only
|
|
256
|
+
* with their terminal even deps-only; a resume that re-supplies trusted internals (every
|
|
257
|
+
* in-engine lane does) was never affected.
|
|
258
|
+
* TERMINAL OWED (closed the one hole): every delegated leg that reached its wiring is closed by
|
|
259
|
+
* exactly one terminal frame — the ordinary path emits it where the `TaskResult` assembles, and a
|
|
260
|
+
* POST-WIRING throw that the stream layer converts into a synthesized failed result (e.g.
|
|
261
|
+
* `resume.tool_unavailable` re-thrown past the run tail) emits the failed terminal from that
|
|
262
|
+
* backstop, gated on a carrier set at the spawn station and cleared by the ordinary terminal (so the
|
|
263
|
+
* two sites can never both fire for one leg). A leg whose PROCESS dies mid-flight is the only one
|
|
264
|
+
* left without its terminal.
|
|
253
265
|
*
|
|
254
266
|
* OBSERVATION ONLY (matrix §5.2 Q3: frame-rate lifecycle facts ride an observer seat, never
|
|
255
267
|
* onNotice): no return capability, and delivery can never alter the child run —
|
|
@@ -265,23 +277,59 @@ export interface BackgroundChildEvent {
|
|
|
265
277
|
* `frame.hasOwnProperty(...)` (throws) or implicit string coercion (`` `${frame}` `` throws).
|
|
266
278
|
*/
|
|
267
279
|
export type DelegationLifecycleEvent = {
|
|
280
|
+
/** A cycle started — the projection of the leg's `task_started` frame (one per first spawn or
|
|
281
|
+
* revival; never for a resume leg, so `identity.legKind` is `"child"` on every spawn frame). */
|
|
268
282
|
phase: "spawn";
|
|
269
283
|
/** The child LEG's identity envelope (#281 件A — the same frozen object that leg's own hook
|
|
270
284
|
* invocations carry). `isDelegatedChild` is `true` by construction on every frame here. */
|
|
271
285
|
identity: import("./hooks.js").HookInvocationIdentity;
|
|
272
286
|
} | {
|
|
273
287
|
phase: "terminal";
|
|
274
|
-
/**
|
|
288
|
+
/** The leg's identity envelope (one mint per leg — the same object as the cycle's spawn frame on
|
|
289
|
+
* the leg that started it). */
|
|
275
290
|
identity: import("./hooks.js").HookInvocationIdentity;
|
|
276
291
|
/** The leg's settled status word — the projection of the `TaskResult.terminal` the spawning lane
|
|
277
292
|
* receives (the sync lane's previously-void `settled` payload, made public). `"suspended"` means a
|
|
278
|
-
* durable park: expect a later `"resume"`-leg
|
|
293
|
+
* durable park: expect a later `"resume"`-leg terminal if it is redeemed (a resume leg starts no
|
|
294
|
+
* cycle, so no spawn frame precedes it). */
|
|
279
295
|
status: TaskStatus;
|
|
280
296
|
/** Turns the leg completed. */
|
|
281
297
|
turns: number;
|
|
282
298
|
/** The leg's terminal code (the failed cause's `code`), when one was stamped. */
|
|
283
299
|
errorCode?: string;
|
|
284
300
|
};
|
|
301
|
+
/**
|
|
302
|
+
* The ONE eligibility reading for a leg's delegated-child ROW frames — its `task_started`, its
|
|
303
|
+
* `task_progress` ticks and its terminal tick all read this and nothing else: a delegated leg, by the
|
|
304
|
+
* identity envelope's effective delegation fact. A row a consumer can open is a row it can close, so
|
|
305
|
+
* no frame of the family may ask a narrower question (whether a spawning tool call is known is
|
|
306
|
+
* attribution, carried on the frames when it exists — never eligibility).
|
|
307
|
+
*/
|
|
308
|
+
export declare function emitsChildRowFrames(identity: import("./hooks.js").HookInvocationIdentity): boolean;
|
|
309
|
+
/**
|
|
310
|
+
* The ONE constructor of a delegated child's `task_started` frame ({@link TaskEvent}); the leg's spawn
|
|
311
|
+
* station calls it once per started cycle. Every member is copied from the seat its `task_progress`
|
|
312
|
+
* twin (or the fleet row) reads — the run ids, the prepared model, the delegation facts the spawner
|
|
313
|
+
* threaded, and the display label as the identity envelope bounds it, present under the tick's own
|
|
314
|
+
* law (a label that bounds to nothing is no label) — so the frame introduces no second reading of any
|
|
315
|
+
* of them. `stamp` is the event identity the leg stamps on every frame.
|
|
316
|
+
*/
|
|
317
|
+
export declare function taskStartedFrame(run: {
|
|
318
|
+
taskId: string;
|
|
319
|
+
sessionId: string;
|
|
320
|
+
model: string;
|
|
321
|
+
identity: import("./hooks.js").HookInvocationIdentity;
|
|
322
|
+
}, spawner: {
|
|
323
|
+
delegationTaskType?: import("./task-event.js").DelegationTaskType;
|
|
324
|
+
cycleSeq?: number;
|
|
325
|
+
parentTaskId?: string;
|
|
326
|
+
parentSessionId?: string;
|
|
327
|
+
rootSessionId?: string;
|
|
328
|
+
explicitAgentName?: string;
|
|
329
|
+
spawnAgentType?: string;
|
|
330
|
+
} | undefined, stamp: import("./task-event.js").TaskEventIdentity): Extract<TaskEvent, {
|
|
331
|
+
type: "task_started";
|
|
332
|
+
}>;
|
|
285
333
|
/** Test seam (mirrors `__resetMalformedNoticeSeatAnnouncement`): never called by production code. */
|
|
286
334
|
export declare function __resetMalformedDelegationSeatAnnouncement(): void;
|
|
287
335
|
/**
|
|
@@ -1,4 +1,26 @@
|
|
|
1
1
|
import { observeThenableRejection } from "./safe-notify.js";
|
|
2
|
+
export function emitsChildRowFrames(identity) {
|
|
3
|
+
return identity.isDelegatedChild;
|
|
4
|
+
}
|
|
5
|
+
export function taskStartedFrame(run, spawner, stamp) {
|
|
6
|
+
const { identity } = run;
|
|
7
|
+
return {
|
|
8
|
+
type: "task_started",
|
|
9
|
+
taskId: run.taskId,
|
|
10
|
+
sessionId: run.sessionId,
|
|
11
|
+
...(spawner?.delegationTaskType !== undefined ? { taskType: spawner.delegationTaskType } : {}),
|
|
12
|
+
...(spawner?.cycleSeq !== undefined ? { seq: spawner.cycleSeq } : {}),
|
|
13
|
+
...(spawner?.parentTaskId !== undefined ? { parentTaskId: spawner.parentTaskId } : {}),
|
|
14
|
+
...(spawner?.parentSessionId !== undefined ? { parentSessionId: spawner.parentSessionId } : {}),
|
|
15
|
+
...(spawner?.rootSessionId !== undefined ? { rootSessionId: spawner.rootSessionId } : {}),
|
|
16
|
+
...(identity.agentName ? { name: identity.agentName } : {}),
|
|
17
|
+
...(spawner?.explicitAgentName !== undefined ? { spawnName: spawner.explicitAgentName } : {}),
|
|
18
|
+
...(spawner?.spawnAgentType !== undefined ? { agentType: spawner.spawnAgentType } : {}),
|
|
19
|
+
model: run.model,
|
|
20
|
+
startedAt: Date.now(),
|
|
21
|
+
...stamp,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
2
24
|
let malformedDelegationSeatAnnounced = false;
|
|
3
25
|
export function __resetMalformedDelegationSeatAnnouncement() {
|
|
4
26
|
malformedDelegationSeatAnnounced = false;
|
|
@@ -394,11 +394,13 @@ export interface EngineNotice {
|
|
|
394
394
|
* rowCount, sessionId, runId }` (`rows` = the first eight non-built-in rows). Audience `user`.
|
|
395
395
|
* - `"permission.rule_store_unavailable"` — the person's persisted permission rules could not be read (a read
|
|
396
396
|
* failure, a corrupt or unreadable store, a read that did not answer in time), so that read's rows were SKIPPED:
|
|
397
|
-
* none of their allow, ask or deny rows took part in the decisions it served
|
|
398
|
-
*
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
397
|
+
* none of their allow, ask or deny rows took part in the decisions it served. At `"call"` the call asks a person
|
|
398
|
+
* meanwhile (a deny row among the rows nobody could read may forbid it; the class is `governance_unavailable`,
|
|
399
|
+
* which `bypassPermissions` keeps and a headless run refuses); at `"prepare"` the run's path tables lack the rows
|
|
400
|
+
* for the whole run. `detail.at` names the read that found it first: `"prepare"` (the path rows the run's file and
|
|
401
|
+
* shell checks take at run start — the next run reads them again) or `"call"` (one call's own rule check — every
|
|
402
|
+
* later call reads again, so the rows apply as soon as a read succeeds). Once per run, whichever read fails
|
|
403
|
+
* first; the trace keeps every read's line (`permission.rule_store_unreadable`).
|
|
402
404
|
* `detail: { at, sessionId, runId }`. Audience `user`.
|
|
403
405
|
* - `"permission.rule_row_dropped"` — the person's store served project-scoped rows whose scope root is not a
|
|
404
406
|
* complete absolute path (only a foreign writer or a hand edit makes one; every engine write face refuses it): they
|
|
@@ -86,7 +86,8 @@ export declare function noteHostRewrite(seam: FrameSettlement, toolCallId: strin
|
|
|
86
86
|
* carrier (the host's decision), withheld otherwise (owed again). */
|
|
87
87
|
export declare function recordFrameReceipt(seam: FrameSettlement, carrier: string, committedContent: unknown, entryId: string): void;
|
|
88
88
|
/** The carrier a committed frame was riding, as the harness reports it at the transcript append — a tool
|
|
89
|
-
* result with the content it was committed with (after every result transformation)
|
|
89
|
+
* result with the content it was committed with (after every result transformation); a user-attachment frame by
|
|
90
|
+
* its delivery record's key (`inputId`, `ordinal`). */
|
|
90
91
|
export type CommittedFrameCarrier = {
|
|
91
92
|
kind: "engine_note";
|
|
92
93
|
payload: unknown;
|
|
@@ -94,4 +95,8 @@ export type CommittedFrameCarrier = {
|
|
|
94
95
|
kind: "tool_result";
|
|
95
96
|
toolCallId: string;
|
|
96
97
|
content: unknown;
|
|
98
|
+
} | {
|
|
99
|
+
kind: "attachment";
|
|
100
|
+
inputId: string;
|
|
101
|
+
ordinal: number;
|
|
97
102
|
};
|
package/dist/core/gate-fold.js
CHANGED
|
@@ -7,6 +7,7 @@ import { writeProtectionMandated, writeProtectionTightenDecision } from "./write
|
|
|
7
7
|
import { createGateDeadline, awaitWriteProtectionJudgment, gateWaitFailureOf, withGateTimeout } from "./gate-bounded-await.js";
|
|
8
8
|
import { thrownText } from "./thrown-value.js";
|
|
9
9
|
import { refuseOutOfContractDecision } from "./tool-policy.js";
|
|
10
|
+
import { applyUnansweredSilence, silencedBy } from "./shell-read-silence.js";
|
|
10
11
|
import { asksUnstated, permissionSeatAt, unstatedAskMessage } from "./mode-policy.js";
|
|
11
12
|
export async function runGateFold(pass) {
|
|
12
13
|
const { input, toolName, toolCallId, callSignal, ledger, notifier, adjudicate } = pass;
|
|
@@ -196,25 +197,26 @@ function applyShellReadVerdict(pass, verdict, toolName, shellGated) {
|
|
|
196
197
|
pass.shellUnplacedOptions = verdict.unplacedOptions;
|
|
197
198
|
if (verdict.finding === "unestablishable" || verdict.finding === "declined" || verdict.finding === "unanswered" || verdict.unestablished === true)
|
|
198
199
|
pass.shellReadUnestablished = true;
|
|
200
|
+
if (verdict.disposition === "refuse") {
|
|
201
|
+
pass.decision = { action: "deny", message: verdict.sentence ?? `tool "${toolName}" reads what the session's read boundary refuses` };
|
|
202
|
+
pass.deniedBy = "read_boundary";
|
|
203
|
+
if (verdict.details !== undefined)
|
|
204
|
+
pass.denyDetails = verdict.details;
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (verdict.finding === "unanswered") {
|
|
208
|
+
applyUnansweredSilence(pass, verdict, { message: shellReadAskMessage(toolName, verdict), account, tightenedBy: shellGated ? "shell_gate" : "safety" });
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
199
211
|
switch (verdict.disposition) {
|
|
200
212
|
case "vouch":
|
|
201
213
|
return;
|
|
202
|
-
case "refuse":
|
|
203
|
-
pass.decision = { action: "deny", message: verdict.sentence ?? `tool "${toolName}" reads what the session's read boundary refuses` };
|
|
204
|
-
pass.deniedBy = "read_boundary";
|
|
205
|
-
if (verdict.details !== undefined)
|
|
206
|
-
pass.denyDetails = verdict.details;
|
|
207
|
-
return;
|
|
208
214
|
case "mandated": {
|
|
209
215
|
if (verdict.details !== undefined)
|
|
210
216
|
pass.shellReadDetails = verdict.details;
|
|
211
|
-
const unreadable = verdict.finding === "unanswered";
|
|
212
217
|
if (pass.decision.action !== "allow") {
|
|
213
|
-
if (pass.decision.action === "ask")
|
|
214
|
-
pass.decision =
|
|
215
|
-
? { ...pass.decision, probeMandated: true }
|
|
216
|
-
: { ...pass.decision, requiresRealApproval: true, ...(pass.decision.guard === undefined ? { guard: "unverifiable_shell_text" } : { foldedAskClasses: [...new Set([...(pass.decision.foldedAskClasses ?? []), "unverifiable_shell_text"])] }) };
|
|
217
|
-
}
|
|
218
|
+
if (pass.decision.action === "ask")
|
|
219
|
+
pass.decision = { ...pass.decision, probeMandated: true, ...silencedBy(verdict, pass.decision) };
|
|
218
220
|
return;
|
|
219
221
|
}
|
|
220
222
|
const candidate = normalizeReadRootCandidate(verdict.readRootCandidate);
|
|
@@ -222,7 +224,8 @@ function applyShellReadVerdict(pass, verdict, toolName, shellGated) {
|
|
|
222
224
|
action: "ask",
|
|
223
225
|
message: shellReadAskMessage(toolName, verdict),
|
|
224
226
|
decisionReason: "safety",
|
|
225
|
-
|
|
227
|
+
probeMandated: true,
|
|
228
|
+
...silencedBy(verdict, {}),
|
|
226
229
|
...(account !== undefined ? { probeReason: account } : {}),
|
|
227
230
|
...(candidate !== undefined ? { probeReadRootCandidate: candidate } : {}),
|
|
228
231
|
};
|
|
@@ -235,12 +238,15 @@ function applyShellReadVerdict(pass, verdict, toolName, shellGated) {
|
|
|
235
238
|
verdict.admit?.();
|
|
236
239
|
if (verdict.details !== undefined)
|
|
237
240
|
pass.shellReadDetails = verdict.details;
|
|
241
|
+
if (pass.decision.action === "ask")
|
|
242
|
+
pass.decision = { ...pass.decision, ...silencedBy(verdict, pass.decision) };
|
|
238
243
|
if (pass.decision.action === "allow") {
|
|
239
244
|
const candidate = normalizeReadRootCandidate(verdict.readRootCandidate);
|
|
240
245
|
pass.decision = {
|
|
241
246
|
action: "ask",
|
|
242
247
|
message: shellReadAskMessage(toolName, verdict),
|
|
243
248
|
decisionReason: "safety",
|
|
249
|
+
...silencedBy(verdict, {}),
|
|
244
250
|
...(account !== undefined ? { probeReason: account } : {}),
|
|
245
251
|
...(candidate !== undefined ? { probeReadRootCandidate: candidate } : {}),
|
|
246
252
|
};
|
package/dist/core/gate-lanes.js
CHANGED
|
@@ -26,6 +26,8 @@ const QUESTION_TOOL_NAMES = new Set([ASK_USER_QUESTION_TOOL_NAME]);
|
|
|
26
26
|
function parkWith(suspendAsk, parkArgs, carry) {
|
|
27
27
|
return suspendAsk(...parkArgs, carry);
|
|
28
28
|
}
|
|
29
|
+
const ruleCallUnreadableOf = (lane) => lane?.unreadable === true && lane.reason !== undefined;
|
|
30
|
+
const ruleStoreUnreadableOf = (lane) => lane?.unreadable === true && lane.reason === undefined;
|
|
29
31
|
export async function runGateLanes(pass) {
|
|
30
32
|
const { input, toolName, toolCallId, callSignal, ledger, notifier, screening, adjudicate, resolveAsk, suspendAsk } = pass;
|
|
31
33
|
const boundedAwaitDeadlineMs = createGateDeadline(input, notifier);
|
|
@@ -42,11 +44,12 @@ export async function runGateLanes(pass) {
|
|
|
42
44
|
targetUnresolved: pass.targetUnresolved === true,
|
|
43
45
|
});
|
|
44
46
|
const readFaceNow = input.readFace?.();
|
|
45
|
-
const askOriginFacts = (org,
|
|
47
|
+
const askOriginFacts = (org, lane) => ({
|
|
46
48
|
contentQuestion: heldBy("lanes.contentQuestionClass", QUESTION_TOOL_NAMES, pass.req),
|
|
47
49
|
markedUnresolvable: markedUnresolvable(),
|
|
48
50
|
org,
|
|
49
|
-
...(
|
|
51
|
+
...(ruleCallUnreadableOf(lane) ? { ruleCallUnreadable: true } : {}),
|
|
52
|
+
...(ruleStoreUnreadableOf(lane) ? { ruleStoreUnreadable: true } : {}),
|
|
50
53
|
tightened: pass.tightenedBy,
|
|
51
54
|
mandateMarks: mandateMarksNow(),
|
|
52
55
|
...(input.toolMarkSources !== undefined ? { toolMarkSources: input.toolMarkSources } : {}),
|
|
@@ -118,13 +121,12 @@ export async function runGateLanes(pass) {
|
|
|
118
121
|
};
|
|
119
122
|
const orgAnswer = await applyOrgLayer(pass.decision, pass.policyRewrite !== undefined ? pass.policyRewrite : pass.currentInput);
|
|
120
123
|
pass.decision = orgAnswer.decision;
|
|
121
|
-
const ruleCallUnreadableOf = (lane) => lane?.unreadable === true && lane.reason !== undefined;
|
|
122
124
|
const readPersistedRules = (req) => readPersistedRuleLane(input.persistedRules, req, input.abortSignal);
|
|
123
125
|
const reread = pass.policyRewrite !== undefined ? withArgsReading(pass.req, pass.policyRewrite, pass.callSignal ?? input.abortSignal) : undefined;
|
|
124
126
|
const laneReq = reread !== undefined ? await reread : { ...pass.req, ...(pass.policyRewrite !== undefined ? { args: pass.policyRewrite } : {}) };
|
|
125
127
|
const laneAnswer = input.persistedRules !== undefined && wireOf("lanes.persistedLaneSkip", pass.req) !== ASK_USER_QUESTION_TOOL_NAME ? await readPersistedRules(laneReq) : undefined;
|
|
126
128
|
{
|
|
127
|
-
const tightened = applyPersistedTightening(pass.decision, laneAnswer);
|
|
129
|
+
const tightened = applyPersistedTightening(pass.decision, laneAnswer, laneReq);
|
|
128
130
|
pass.decision = tightened.decision;
|
|
129
131
|
if (tightened.tightened === "deny")
|
|
130
132
|
pass.deniedBy = "persisted_rule";
|
|
@@ -146,7 +148,7 @@ export async function runGateLanes(pass) {
|
|
|
146
148
|
pass.req.targetReading = laneReq.targetReading;
|
|
147
149
|
}
|
|
148
150
|
const ruleMayClear = () => ruleClearanceOf(pass.decision.action === "ask" ? pass.decision : undefined, mandateMarksNow()).ruleMayClear;
|
|
149
|
-
const classMayClear = () => pass.decision.action === "ask" && classifyAsk(pass.decision, askOriginFacts(orgAnswer.org,
|
|
151
|
+
const classMayClear = () => pass.decision.action === "ask" && classifyAsk(pass.decision, askOriginFacts(orgAnswer.org, laneAnswer)).row.ruleMayClear;
|
|
150
152
|
let personalEvidence = { dotsAbsent: input.persistedRules === undefined ? "not_wired" : "not_adjudicated" };
|
|
151
153
|
if (laneAnswer?.unreadable === true)
|
|
152
154
|
personalEvidence = { dotsAbsent: "unavailable" };
|
|
@@ -234,7 +236,7 @@ export async function runGateLanes(pass) {
|
|
|
234
236
|
const { allowRuleShadowed: _claimed, ...standing } = pass.decision;
|
|
235
237
|
pass.decision = shadows.length > 0 ? { ...standing, allowRuleShadowed: shadows } : standing;
|
|
236
238
|
}
|
|
237
|
-
const originFacts = askOriginFacts(orgAnswer.org,
|
|
239
|
+
const originFacts = askOriginFacts(orgAnswer.org, laneAnswer);
|
|
238
240
|
let noRulingMinted = false;
|
|
239
241
|
const fallbackAskOf = (standingAsk, fallback, latestBlockedAction) => {
|
|
240
242
|
const { classifierNoRuling: _why, ...standing } = standingAsk;
|
|
@@ -582,13 +584,12 @@ export async function runGateLanes(pass) {
|
|
|
582
584
|
editDenied = recheck;
|
|
583
585
|
break;
|
|
584
586
|
}
|
|
585
|
-
let
|
|
587
|
+
let editLane;
|
|
586
588
|
const editReread = withArgsReading(pass.req, editArgs, callSignal ?? input.abortSignal);
|
|
587
589
|
const editLaneReq = editReread !== undefined ? await editReread : { toolName, args: editArgs, toolCallId, ...(pass.req.face !== undefined ? { face: pass.req.face } : {}) };
|
|
588
590
|
if (input.persistedRules !== undefined && wireOf("lanes.persistedEditSkip", pass.req) !== ASK_USER_QUESTION_TOOL_NAME) {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
const editTightened = applyPersistedTightening(recheck, editLane);
|
|
591
|
+
editLane = await readPersistedRules(editLaneReq);
|
|
592
|
+
const editTightened = applyPersistedTightening(recheck, editLane, editLaneReq);
|
|
592
593
|
recheck = editTightened.decision;
|
|
593
594
|
if (editTightened.tightened === "deny")
|
|
594
595
|
pass.deniedBy = "persisted_rule";
|
|
@@ -619,7 +620,7 @@ export async function runGateLanes(pass) {
|
|
|
619
620
|
}
|
|
620
621
|
const editAskSnapshot = { ...recheck, ruleEvidence: mintRuleEvidence({ dotsAbsent: "not_adjudicated" }) };
|
|
621
622
|
markedThisRound = undefined;
|
|
622
|
-
const editFacts = askOriginFacts(editOrg.org,
|
|
623
|
+
const editFacts = askOriginFacts(editOrg.org, editLane);
|
|
623
624
|
const editAskDecision = stampAskOrigin(editAskSnapshot, editFacts, classifyStanding(editAskSnapshot, editFacts));
|
|
624
625
|
if (input.permissionMode !== undefined && pass.askClassification !== undefined) {
|
|
625
626
|
const editVerdict = arbitrateByMode(input.permissionMode(), pass.askClassification, { ...(editAskDecision.origin !== undefined ? { origin: editAskDecision.origin } : {}), ...(editAskDecision.mandate !== undefined ? { mandate: editAskDecision.mandate } : {}) });
|
|
@@ -360,8 +360,8 @@ export type GateDisposition = {
|
|
|
360
360
|
* to anyone: the mode, the disclosed class word (`askClass`, the first member of the folded set in `ASK_CLASSES`
|
|
361
361
|
* order — one of {@link releasableAskClassesFor} on the call's face), the whole set, and the origin / mandate words the card would
|
|
362
362
|
* have shown. `reason` is a member of {@link import("./ask-origin.js").MODE_RELEASE_REASONS} (`isModeReleaseReason`):
|
|
363
|
-
* `"
|
|
364
|
-
*
|
|
363
|
+
* `"target_unresolved"` marks a release (the shell face) over a write target whose reading could not say where it leads;
|
|
364
|
+
* absent, the release names none. The record carries no face, so the
|
|
365
365
|
* screen asks that SOME face releases the class.
|
|
366
366
|
*/
|
|
367
367
|
export interface ModeRelease {
|
|
@@ -47,6 +47,8 @@ export const NON_GOVERNANCE_MEMORY_CODES = new Set([
|
|
|
47
47
|
"memory.consolidation_lease_unavailable",
|
|
48
48
|
"memory.consolidation_backend_failed",
|
|
49
49
|
"memory.consolidation_gate_failed",
|
|
50
|
+
"memory.consolidation_write_refused",
|
|
51
|
+
"memory.landing_unstable",
|
|
50
52
|
"memory.active_set_collapse",
|
|
51
53
|
"memory.challenge_ledger_oversize",
|
|
52
54
|
"memory.control_plane_rebuilt",
|