@sema-agent/core 7.16.0 → 7.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +209 -0
- package/dist/agents/builtin-agents.d.ts +3 -3
- package/dist/agents/cross-session-envelope.d.ts +0 -1
- package/dist/agents/cross-session-envelope.js +0 -1
- package/dist/agents/peer-notices.d.ts +0 -9
- package/dist/agents/peer-notices.js +0 -63
- package/dist/agents/subagent.js +7 -15
- package/dist/brain/request-params.d.ts +2 -2
- package/dist/config/defaults.d.ts +0 -7
- package/dist/config/defaults.js +0 -2
- package/dist/core/artifact-host.d.ts +218 -0
- package/dist/core/artifact-host.js +92 -0
- package/dist/core/ask-origin.d.ts +29 -3
- package/dist/core/ask-origin.js +17 -9
- package/dist/core/ask-question.d.ts +25 -0
- package/dist/core/ask-question.js +4 -0
- package/dist/core/ask-unresolvable-notice.d.ts +30 -21
- package/dist/core/ask-unresolvable-notice.js +16 -8
- package/dist/core/auto-compaction.d.ts +10 -10
- package/dist/core/auto-mode-arming.d.ts +2 -2
- package/dist/core/background-agent-store.d.ts +5 -5
- package/dist/core/background-shell.d.ts +1 -1
- package/dist/core/checkpoint-execution-record.d.ts +0 -3
- package/dist/core/checkpoint-execution-record.js +0 -4
- package/dist/core/checkpoint-store.d.ts +71 -99
- package/dist/core/checkpoint-store.js +9 -16
- package/dist/core/context-edit.d.ts +36 -104
- package/dist/core/context-edit.js +37 -60
- package/dist/core/effective-path-target.d.ts +68 -8
- package/dist/core/effective-path-target.js +42 -30
- package/dist/core/engine-notice.d.ts +46 -32
- package/dist/core/env-budget.d.ts +31 -0
- package/dist/core/env-budget.js +39 -0
- package/dist/core/exec-output-tail.d.ts +5 -5
- package/dist/core/file-history-store.js +3 -6
- package/dist/core/fs-write-gate-policy.d.ts +1 -1
- package/dist/core/fs-write-gate-policy.js +3 -3
- package/dist/core/gate-lanes.js +9 -15
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +2 -0
- package/dist/core/hands-band.d.ts +1 -1
- package/dist/core/hooks.d.ts +18 -17
- package/dist/core/lsp-session.d.ts +1 -1
- package/dist/core/lsp.d.ts +1 -1
- package/dist/core/lsp.js +5 -4
- package/dist/core/mcp.d.ts +5 -5
- package/dist/core/mcp.js +4 -48
- package/dist/core/memory-engine/engine.js +2 -1
- package/dist/core/memory-engine/layout.d.ts +18 -6
- package/dist/core/memory-engine/layout.js +40 -21
- package/dist/core/memory-recall.d.ts +0 -8
- package/dist/core/memory.d.ts +1 -1
- package/dist/core/oracle-isolation.js +2 -2
- package/dist/core/parent-spec-seat.d.ts +66 -0
- package/dist/core/parent-spec-seat.js +47 -0
- package/dist/core/permission-rule-model.d.ts +11 -6
- package/dist/core/permission-rule-model.js +53 -37
- package/dist/core/permission-rules.js +8 -3
- package/dist/core/physical-path.d.ts +37 -0
- package/dist/core/physical-path.js +30 -0
- package/dist/core/protocol-naming.d.ts +2 -2
- package/dist/core/remote-env.d.ts +1 -1
- package/dist/core/retired-keys.d.ts +19 -0
- package/dist/core/retired-keys.js +15 -0
- package/dist/core/runner/active-skill-scope.js +3 -3
- package/dist/core/runner/assemble-result.d.ts +15 -13
- package/dist/core/runner/assemble-result.js +5 -4
- package/dist/core/runner/compaction-call-options.d.ts +25 -89
- package/dist/core/runner/contracts.d.ts +11 -10
- package/dist/core/runner/gate-exit.js +15 -1
- package/dist/core/runner/halt-attribution.d.ts +35 -0
- package/dist/core/runner/halt-attribution.js +16 -0
- package/dist/core/runner/memory-consolidation.d.ts +0 -2
- package/dist/core/runner/memory-consolidation.js +0 -1
- package/dist/core/runner/prepare-artifact.d.ts +52 -0
- package/dist/core/runner/prepare-artifact.js +63 -0
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -2
- package/dist/core/runner/prepare-caps-and-workflow.js +2 -3
- package/dist/core/runner/prepare-config-doors.d.ts +3 -3
- package/dist/core/runner/prepare-config-doors.js +5 -2
- package/dist/core/runner/prepare-context-lane.d.ts +2 -2
- package/dist/core/runner/prepare-context-lane.js +2 -13
- package/dist/core/runner/prepare-file-history.d.ts +1 -1
- package/dist/core/runner/prepare-file-history.js +3 -52
- package/dist/core/runner/prepare-hands-readface.d.ts +4 -7
- package/dist/core/runner/prepare-hands-readface.js +3 -2
- package/dist/core/runner/prepare-inherited-gate.d.ts +5 -2
- package/dist/core/runner/prepare-inherited-gate.js +7 -8
- package/dist/core/runner/prepare-memory.d.ts +4 -6
- package/dist/core/runner/prepare-memory.js +4 -2
- package/dist/core/runner/prepare-policy-chain.d.ts +3 -3
- package/dist/core/runner/prepare-policy-chain.js +15 -30
- package/dist/core/runner/prepare-prompt-assembly.js +1 -1
- package/dist/core/runner/prepare-question-face.js +2 -1
- package/dist/core/runner/prepare-safety-scan.d.ts +1 -1
- package/dist/core/runner/prepare-suspend-saga.js +0 -2
- package/dist/core/runner/prepare-task.js +12 -11
- package/dist/core/runner/prepare-wiring-manifest.js +9 -7
- package/dist/core/runner/resume-admission.js +2 -1
- package/dist/core/runner/resume-internals-and-config.js +4 -0
- package/dist/core/runner/retired-runner-deps.d.ts +3 -0
- package/dist/core/runner/retired-runner-deps.js +7 -0
- package/dist/core/runner/run-harness-handlers.js +5 -3
- package/dist/core/runner/run-settle-and-teardown.d.ts +1 -1
- package/dist/core/runner/run-settle-and-teardown.js +3 -1
- package/dist/core/runner/session-file-state-replay.js +3 -3
- package/dist/core/runner/session-rule-policy.js +3 -4
- package/dist/core/runner/stream-halt-verbs.js +1 -1
- package/dist/core/runner/stream-steer-verb.js +1 -4
- package/dist/core/runner/workspace-path.js +3 -0
- package/dist/core/runner-deps.d.ts +30 -49
- package/dist/core/safe-notify.d.ts +1 -1
- package/dist/core/sensitive-path-policy.d.ts +1 -1
- package/dist/core/sensitive-path-policy.js +11 -12
- package/dist/core/session.d.ts +2 -2
- package/dist/core/skill-tool-specifier.d.ts +1 -1
- package/dist/core/skills-directory.d.ts +1 -1
- package/dist/core/skills-directory.js +4 -3
- package/dist/core/spec-contract.js +5 -4
- package/dist/core/store-contracts/checkpoint-store-contract.js +1 -1
- package/dist/core/strategy-store.d.ts +8 -11
- package/dist/core/task-event.d.ts +20 -17
- package/dist/core/task-limits.d.ts +1 -1
- package/dist/core/task-notification.d.ts +5 -5
- package/dist/core/task-registry-agent.d.ts +5 -5
- package/dist/core/task-registry-monitor.d.ts +2 -2
- package/dist/core/task-registry-shared.d.ts +32 -28
- package/dist/core/task-registry-shared.js +4 -13
- package/dist/core/task-registry.d.ts +8 -8
- package/dist/core/task-result.d.ts +37 -37
- package/dist/core/task-spec.d.ts +5 -5
- package/dist/core/task-stream.d.ts +16 -11
- package/dist/core/tool-catalog-entries.d.ts +1 -0
- package/dist/core/tool-catalog-entries.js +6 -1
- package/dist/core/tool-conformance.d.ts +0 -2
- package/dist/core/tool-conformance.js +1 -3
- package/dist/core/tool-errors.d.ts +5 -0
- package/dist/core/tool-errors.js +1 -0
- package/dist/core/tool-policy.d.ts +66 -22
- package/dist/core/tool-policy.js +31 -5
- package/dist/core/tool-result-budget.d.ts +1 -1
- package/dist/core/tool-result-store.d.ts +11 -11
- package/dist/core/tool-spec.d.ts +34 -38
- package/dist/core/tools.d.ts +2 -2
- package/dist/core/trace.d.ts +12 -15
- package/dist/core/untrusted-text.d.ts +1 -1
- package/dist/core/wiring-manifest.d.ts +4 -3
- package/dist/core/workflow-journal-store.d.ts +11 -11
- package/dist/engine/execution-env/node-execution-env.d.ts +3 -2
- package/dist/engine/execution-env/node-execution-env.js +8 -5
- package/dist/engine/harness/agent-harness.d.ts +47 -4
- package/dist/engine/harness/agent-harness.js +52 -9
- package/dist/engine/loop/agent-loop.js +15 -8
- package/dist/engine/loop/types.d.ts +5 -0
- package/dist/index.d.ts +20 -14
- package/dist/index.js +16 -10
- package/dist/internal/harness.d.ts +1 -0
- package/dist/orchestration/run-spec.d.ts +3 -0
- package/dist/orchestration/run-spec.js +3 -3
- package/dist/orchestration/run-workflow-tool.d.ts +12 -6
- package/dist/orchestration/run-workflow-tool.js +23 -5
- package/dist/orchestration/workflow-primitives.d.ts +4 -2
- package/dist/orchestration/workflow-primitives.js +1 -4
- package/dist/orchestration/workflow-script-store.js +9 -25
- package/dist/orchestration/workflow-types.d.ts +34 -4
- package/dist/orchestration/workflow-types.js +2 -0
- package/dist/orchestration/workflow.d.ts +39 -7
- package/dist/orchestration/workflow.js +237 -113
- package/dist/prompt-assembly/assemble.d.ts +2 -2
- package/dist/prompt-assembly/assemble.js +9 -9
- package/dist/prompt-assembly/composer.d.ts +6 -7
- package/dist/prompt-assembly/composer.js +10 -10
- package/dist/prompt-assembly/epoch.js +1 -1
- package/dist/prompt-assembly/event-registry.d.ts +0 -21
- package/dist/prompt-assembly/packs/sema-default.js +30 -30
- package/dist/prompt-assembly/types.d.ts +14 -14
- package/dist/prompts/coordinator.d.ts +0 -13
- package/dist/prompts/coordinator.js +0 -3
- package/dist/stores/cc/task-list-store.js +2 -10
- package/dist/stores/file/checkpoint-store.js +1 -5
- package/dist/stores/file/file-history-store.js +2 -2
- package/dist/stores/file/fs-atomic.d.ts +15 -18
- package/dist/stores/file/fs-atomic.js +4 -14
- package/dist/stores/file/mailbox-store.d.ts +7 -11
- package/dist/stores/file/mailbox-store.js +4 -11
- package/dist/stores/file/permission-rule-store.d.ts +4 -35
- package/dist/stores/file/permission-rule-store.js +4 -148
- package/dist/tools/artifact/artifact-text.d.ts +62 -0
- package/dist/tools/artifact/artifact-text.js +68 -0
- package/dist/tools/artifact/artifact-tool.d.ts +52 -0
- package/dist/tools/artifact/artifact-tool.js +351 -0
- package/dist/tools/artifact/local-stub.d.ts +26 -0
- package/dist/tools/artifact/local-stub.js +297 -0
- package/dist/tools/fs/bash-readonly-classifier.d.ts +90 -8
- package/dist/tools/fs/bash-readonly-classifier.js +294 -70
- package/dist/tools/fs/fs-bash.d.ts +14 -10
- package/dist/tools/fs/fs-bash.js +50 -33
- package/dist/tools/fs/fs-search-tools.js +5 -2
- package/dist/tools/fs/fs-shared.d.ts +2 -0
- package/dist/tools/fs/fs-shared.js +3 -11
- package/dist/tools/fs/index.d.ts +4 -0
- package/dist/tools/fs/index.js +4 -1
- package/dist/tools/fs/safety.d.ts +117 -1
- package/dist/tools/fs/safety.js +131 -31
- package/dist/tools/fs/search.js +8 -6
- package/package.json +2 -1
- package/test/export-surface.snapshot.json +119 -39
|
@@ -28,7 +28,7 @@ import type { AutoModeDecider, AutoModeDenialTracker } from "../auto-mode.js";
|
|
|
28
28
|
import type { CacheBreakDetector, ToolFingerprintInput } from "../cache-break-detector.js";
|
|
29
29
|
import type { ActorAssertion, Checkpoint, CheckpointState, CheckpointStore, CheckpointToken, PendingSteerEntry, PlatformLimitReason, ReopenReason, ResourceLedger, ResourceLimitReason, ResumeOutcome, SerializedCheckpointState } from "../checkpoint-store.js";
|
|
30
30
|
import type { ExecutionOutcomeRecordWord } from "../checkpoint-execution-record.js";
|
|
31
|
-
import type { ClearedProjectionLedger,
|
|
31
|
+
import type { ClearedProjectionLedger, MicroCompactMachine, OccurrenceIndex } from "../context-edit.js";
|
|
32
32
|
import type { HookInvocationIdentity, Hooks, OrgGateVerdict, PermissionDeniedPayload, PostToolBatchCall, PostToolBatchResult, ToolGateInput } from "../hooks.js";
|
|
33
33
|
import type { MaterializedMcp } from "../mcp.js";
|
|
34
34
|
import type { MemoryEngine } from "../memory-engine/engine.js";
|
|
@@ -1051,16 +1051,14 @@ export interface Prepared {
|
|
|
1051
1051
|
* `context-edit.ts`'s ledger note; per-run in-memory, so durable resume / `resumeAt` rebuilds
|
|
1052
1052
|
* start EMPTY by construction), the last request's projection seat (what the provider actually
|
|
1053
1053
|
* saw — the MC-R rejection arm computes its candidates and savings on THIS view, never on the
|
|
1054
|
-
* raw session rebuild), the MC-R knob, and the slice-3 arm-B seat.
|
|
1055
|
-
* (`machine: "legacy"` + MC-R off) ⇒ the ledger never gains an entry and every replay is a
|
|
1056
|
-
* same-reference no-op (opt-out bytes unchanged). */
|
|
1054
|
+
* raw session rebuild), the MC-R knob, and the slice-3 arm-B seat. */
|
|
1057
1055
|
microCompact: PreparedMicroCompact;
|
|
1058
1056
|
}
|
|
1059
1057
|
/** See {@link Prepared.microCompact}. */
|
|
1060
1058
|
export interface PreparedMicroCompact {
|
|
1061
|
-
/** The frontier-machine selection — `"off"` = no proactive frontier clearing (the
|
|
1062
|
-
*
|
|
1063
|
-
machine:
|
|
1059
|
+
/** The frontier-machine selection — `"off"` = no proactive frontier clearing (the machine
|
|
1060
|
+
* instead gets its one blocking-point shot, slice-3 arm A). */
|
|
1061
|
+
machine: MicroCompactMachine;
|
|
1064
1062
|
/** MC-R: one-shot clear-and-retry on a provider input-too-long rejection.
|
|
1065
1063
|
* Default true since the slice-3 flip. */
|
|
1066
1064
|
clearOnRejection: boolean;
|
|
@@ -1105,7 +1103,7 @@ export interface PrepareResume {
|
|
|
1105
1103
|
* crash-interrupted; closing them with `[INTERRUPTED]` would DESTROY the suspended batch, §15.2 #7). */
|
|
1106
1104
|
suspendedBatch: ReadonlySet<string>;
|
|
1107
1105
|
/** The §4.bis correctness-state snapshot to re-seed (activeTools / outputRef / nestedStats /
|
|
1108
|
-
*
|
|
1106
|
+
* readFileState). */
|
|
1109
1107
|
seed: CheckpointState;
|
|
1110
1108
|
/** How many times this task already suspended (the resumed checkpoint's
|
|
1111
1109
|
* `suspendCount`). The next suspend mints `priorSuspendCount + 1`; past `maxSuspends` it fails
|
|
@@ -1393,7 +1391,10 @@ export interface RunInternals {
|
|
|
1393
1391
|
* `"interactive"` tree's engine-stripped legs are exempt). TRUST POSTURE (ruled 2026-08-05):
|
|
1394
1392
|
* RunInternals is a public trusted-caller parameter, so this flag is an honesty channel, not a
|
|
1395
1393
|
* security gate — a caller forging it is a deployment lying to itself; resource-face safety
|
|
1396
|
-
* stays with its own fail-closed mechanisms.
|
|
1394
|
+
* stays with its own fail-closed mechanisms. INHERITS DOWN THE TREE: a stripped leg's descendants are faceless by
|
|
1395
|
+
* the same engine act (the trusted ctx carries it as `ToolExecuteContext.questionFaceStripped`, the Workflow mount as
|
|
1396
|
+
* `parentQuestionFaceStripped`), so the posture-door exemption travels with the facelessness it explains; a leg
|
|
1397
|
+
* that strips on its own mints the same flag.
|
|
1397
1398
|
*/
|
|
1398
1399
|
questionFaceStripped?: true;
|
|
1399
1400
|
/**
|
|
@@ -1516,7 +1517,7 @@ export interface RunInternals {
|
|
|
1516
1517
|
workflowParkedResume?: ReadonlyArray<{
|
|
1517
1518
|
runId: string;
|
|
1518
1519
|
token: CheckpointToken;
|
|
1519
|
-
outcome
|
|
1520
|
+
outcome?: ResumeOutcome;
|
|
1520
1521
|
inheritedGate?: InheritedGate;
|
|
1521
1522
|
}>;
|
|
1522
1523
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { screenGateOutcome, SETTLEMENT_IS_REFUSAL } from "../gate-outcome.js";
|
|
2
|
-
import { classifierDenyCauseOf, decisionText, engineSettlementOf } from "../tool-policy.js";
|
|
2
|
+
import { askUnresolvableCauseOf, classifierDenyCauseOf, decisionText, engineSettlementOf } from "../tool-policy.js";
|
|
3
3
|
import { inlineUntrusted } from "../untrusted-text.js";
|
|
4
4
|
import { formatHookFeedback } from "../reminder-mint.js";
|
|
5
5
|
export function mintGateOutcome(facts) {
|
|
@@ -96,6 +96,15 @@ export function hookDenyExit(pass, r) {
|
|
|
96
96
|
preToolContext: pass.preToolContext,
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
|
+
function unresolvableCauseOfSettlement(gate) {
|
|
100
|
+
if (gate.disposition.kind !== "denied" || gate.disposition.deniedBy !== "ask_resolution" || gate.settlement === undefined)
|
|
101
|
+
return undefined;
|
|
102
|
+
if (gate.settlement.kind === "approver_unavailable")
|
|
103
|
+
return "approver_unavailable";
|
|
104
|
+
if (gate.settlement.kind === "no_approver")
|
|
105
|
+
return "no_approver_wired";
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
99
108
|
export async function exitGate(pass) {
|
|
100
109
|
const { input, event, toolName, toolCallId, ledger, notifyPermissionDenied } = pass;
|
|
101
110
|
if (pass.decision.action === "deny") {
|
|
@@ -106,6 +115,11 @@ export async function exitGate(pass) {
|
|
|
106
115
|
if (pass.deniedBy === undefined)
|
|
107
116
|
throw new Error(`the tool gate refused "${toolName}" without a refusing layer — every deny site attributes itself`);
|
|
108
117
|
const gate = mintGateOutcome({ deniedBy: pass.deniedBy, ...(pass.denyCause !== undefined ? { cause: pass.denyCause } : {}), ...(ledger.settled !== undefined ? { settled: ledger.settled } : {}) });
|
|
118
|
+
const unresolvable = askUnresolvableCauseOf(pass.decision, { toolCallId, toolName }) ?? unresolvableCauseOfSettlement(gate);
|
|
119
|
+
if (unresolvable !== undefined) {
|
|
120
|
+
const cause = unresolvable;
|
|
121
|
+
pass.notifier.notify(() => input.onAskUnresolvable?.({ toolName, toolCallId, cause, parkLaneExisted: pass.suspendAsk !== undefined }), "toolGate.onAskUnresolvable");
|
|
122
|
+
}
|
|
109
123
|
await notifyPermissionDenied({
|
|
110
124
|
toolName,
|
|
111
125
|
input: cloneObserverInput(pass.currentInput),
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Halt attribution, the consumer half: the ONE predicate that turns the harness's
|
|
3
|
+
* consumption statement ({@link HaltConsumption}) into the result's `haltedByUser` seat, and the disclosure
|
|
4
|
+
* for the halt that was accepted but never consumed. Both readers of the statement live here so the law
|
|
5
|
+
* has one spelling: signed ⇔ consumed; unconsumed ⇔ absent + `task.halt_unconsumed`.
|
|
6
|
+
*/
|
|
7
|
+
import type { HaltConsumption } from "../../internal/harness.js";
|
|
8
|
+
import { type RunnerDeps } from "../types.js";
|
|
9
|
+
/**
|
|
10
|
+
* The attribution law: `haltedByUser` ⇔ the halt was CONSUMED by the machinery — its cut settled a turn (the
|
|
11
|
+
* loop's report, stamped `"halt"` at the seat's abort) OR its stop request was among the sources a boundary
|
|
12
|
+
* consult stopped the loop for. A halt merely ACCEPTED (latched, receipt answered) while the run ended for its
|
|
13
|
+
* own reason is not consumed and never signs (fail-closed: rather absent than guessed).
|
|
14
|
+
*/
|
|
15
|
+
export declare function haltConsumed(c: HaltConsumption | undefined): boolean;
|
|
16
|
+
export interface UnconsumedHaltDisclosureInput {
|
|
17
|
+
/** The verb's acceptance fact (`loopLatch.userHalted`): a halt was latched on this run. */
|
|
18
|
+
accepted: boolean;
|
|
19
|
+
/** The harness's statement, read after the prompt settled. */
|
|
20
|
+
consumption: HaltConsumption | undefined;
|
|
21
|
+
onNotice: RunnerDeps["onNotice"];
|
|
22
|
+
sessionId: string;
|
|
23
|
+
runId: string;
|
|
24
|
+
taskId: string | undefined;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The ACCEPTED-but-UNCONSUMED halt: the verb latched the stop (and may have cut a seat), but the run ended for
|
|
28
|
+
* its own reason before the machinery consumed it — no settlement took the halt's cut as its cause and no
|
|
29
|
+
* boundary consult stopped the loop for it (a brain minting its own `aborted` final, a natural completion past
|
|
30
|
+
* the final commit point, an approval park whose commit won the race). The result reads the run's own terminal
|
|
31
|
+
* without `haltedByUser`; this notice is the halt's trace — the same code the verb mints on its own arm (a halt
|
|
32
|
+
* refused by an already-owned ending), one fact with one spelling, the two mint points disjoint: the verb arm mints
|
|
33
|
+
* only while NO halt has been accepted on the run; once one was, this arm alone speaks. One per such run. Returns whether it was minted.
|
|
34
|
+
*/
|
|
35
|
+
export declare function discloseUnconsumedHalt(input: UnconsumedHaltDisclosureInput): boolean;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { deliverEngineNotice } from "../types.js";
|
|
2
|
+
export function haltConsumed(c) {
|
|
3
|
+
return c?.turnCut === "halt" || c?.boundaryStop?.sources.includes("halt") === true;
|
|
4
|
+
}
|
|
5
|
+
export function discloseUnconsumedHalt(input) {
|
|
6
|
+
if (!input.accepted || haltConsumed(input.consumption))
|
|
7
|
+
return false;
|
|
8
|
+
deliverEngineNotice(input.onNotice, {
|
|
9
|
+
code: "task.halt_unconsumed",
|
|
10
|
+
message: "a user halt was accepted, but the run ended for its own reason before the halt stopped or cut anything: " +
|
|
11
|
+
"no turn was settled as its cut and no boundary stopped for it — the run's own ending stands, and the result " +
|
|
12
|
+
"will not carry haltedByUser for this halt.",
|
|
13
|
+
detail: { sessionId: input.sessionId, runId: input.runId, ...(input.taskId !== undefined ? { taskId: input.taskId } : {}) },
|
|
14
|
+
});
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
@@ -23,8 +23,6 @@ export declare const DEFAULT_CONSOLIDATION_BAND: {
|
|
|
23
23
|
export declare const DEFAULT_CONSOLIDATION_SEARCH_LIMIT = 20;
|
|
24
24
|
/** Default cap on this-task notes consolidated in one batch (F6 token bound). */
|
|
25
25
|
export declare const DEFAULT_CONSOLIDATION_MAX_NOTES = 50;
|
|
26
|
-
/** Default independent timeout for the whole consolidation pass (seconds). */
|
|
27
|
-
export declare const DEFAULT_CONSOLIDATION_TIMEOUT_SEC = 30;
|
|
28
26
|
/** Normalize a note body for the EXACT-restatement check in the `<lo` near-dup cheap path. Case- + whitespace-
|
|
29
27
|
* insensitive ONLY (lower-case, collapse whitespace runs, trim); it PRESERVES every symbol/punctuation so it can
|
|
30
28
|
* NOT false-equate semantically-distinct facts. (The earlier `[^\p{L}\p{N}]`-stripping
|
|
@@ -4,7 +4,6 @@ import { cacheFamilyOf, usageCostMicroUsd } from "./usage-accounting.js";
|
|
|
4
4
|
export const DEFAULT_CONSOLIDATION_BAND = { lo: 0.05, hi: 0.3 };
|
|
5
5
|
export const DEFAULT_CONSOLIDATION_SEARCH_LIMIT = 20;
|
|
6
6
|
export const DEFAULT_CONSOLIDATION_MAX_NOTES = 50;
|
|
7
|
-
export const DEFAULT_CONSOLIDATION_TIMEOUT_SEC = 30;
|
|
8
7
|
export function normalizeForExactMatch(s) {
|
|
9
8
|
return s.toLowerCase().replace(/\s+/g, " ").trim();
|
|
10
9
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PrepareTask's Artifact phase: the `RunnerDeps.artifactHost` seat is read once; an absent seat mounts
|
|
3
|
+
* nothing and announces nothing; a seat whose declaration fails an invariant mounts nothing and announces
|
|
4
|
+
* `config.artifact_host_invalid` (operator audience) so a bad wiring can never read as "no hosting"; a
|
|
5
|
+
* valid seat mounts ONE `Artifact` tool assembled from the declaration, on the same optional band the LSP
|
|
6
|
+
* seat uses. The tool's local-file read goes through the run's fs fence (root containment, read-deny, read
|
|
7
|
+
* face) exactly as `Read` does, then reads the bytes once from the execution env. A local stub's store
|
|
8
|
+
* (`capabilities.storageDir`) must lie OUTSIDE every root the run may write or read — a ledger the model can
|
|
9
|
+
* edit through the fs tools is not a trust boundary — and a store inside one refuses the mount, naming both.
|
|
10
|
+
* Synchronous: the stretch has no await (the file read is a closure the tool calls later).
|
|
11
|
+
*/
|
|
12
|
+
import type { ExecutionEnv } from "../../internal/harness.js";
|
|
13
|
+
import { type ArtifactPlane } from "../artifact-host.js";
|
|
14
|
+
import { RosterBuilder } from "../tool-roster.js";
|
|
15
|
+
import type { AgentTool, RunnerDeps } from "../types.js";
|
|
16
|
+
import type { ReadDenyMatcher, ReadFace } from "../../tools/fs/index.js";
|
|
17
|
+
import type { Prepared } from "./contracts.js";
|
|
18
|
+
export interface PrepareArtifactInput {
|
|
19
|
+
/** borrowed-readonly — the deployment's hosting seat and the notice sink the refusal arm announces on. */
|
|
20
|
+
deps: Pick<RunnerDeps, "artifactHost" | "onNotice">;
|
|
21
|
+
/** borrowed-readonly — the engine-minted run id: the host's `onMount` key and every call context's `runId`. */
|
|
22
|
+
runId: string;
|
|
23
|
+
/** borrowed-readonly — the host task id, the call context's audit attribution. */
|
|
24
|
+
taskId: string;
|
|
25
|
+
/** borrowed-readonly — the acquired session id (notice attribution and the call context's `sessionId`). */
|
|
26
|
+
sessionId: string;
|
|
27
|
+
/** borrowed-readonly — the spawned name this run carries, when any (call-context attribution only). */
|
|
28
|
+
agentName: string | undefined;
|
|
29
|
+
/** borrowed-readonly — the run's resolved env: the byte source of a published local file. */
|
|
30
|
+
executionEnv: ExecutionEnv;
|
|
31
|
+
/** borrowed-readonly — the canonical task root the fs fence contains reads to; undefined ⇒ no local-file publish. */
|
|
32
|
+
rootCanonical: string | undefined;
|
|
33
|
+
/** borrowed-readonly — the extra containment roots (write and read-only) the fence admits. */
|
|
34
|
+
additionalRootsCanonical: readonly string[];
|
|
35
|
+
/** borrowed-readonly — the read-deny matcher in force for the run, when any. */
|
|
36
|
+
readDenyMatcher: ReadDenyMatcher | undefined;
|
|
37
|
+
/** borrowed-readonly — the resolved read face (`"open"` lifts root containment for reads). */
|
|
38
|
+
resolvedReadFace: ReadFace | undefined;
|
|
39
|
+
/** borrowed-readonly — the tracked-cwd cell; `current` is read per call as the relative-path base. */
|
|
40
|
+
handsCwdRef: Prepared["cwdRef"];
|
|
41
|
+
/** borrowed-mutable — the run's roster builder; writer here: ONE mount when the seat is valid. */
|
|
42
|
+
roster: RosterBuilder;
|
|
43
|
+
/** borrowed-readonly — the first-party result-offload wrapper every core mount passes through (a large read or a conflict snapshot is offloaded, not inlined). */
|
|
44
|
+
firstPartyOffload: (tool: AgentTool) => AgentTool;
|
|
45
|
+
/** borrowed-mutable — the env-hand membership set the memory content-origin face reads (a tool that reads the execution env's files is a hand); writer here: `add("Artifact")` on the mount. */
|
|
46
|
+
envHandToolNames: Set<string>;
|
|
47
|
+
}
|
|
48
|
+
export interface PrepareArtifactResult {
|
|
49
|
+
/** owned — the mounted face's plane, or undefined when nothing mounted (absent seat, or an invalid one). */
|
|
50
|
+
artifactPlane: ArtifactPlane | undefined;
|
|
51
|
+
}
|
|
52
|
+
export declare function prepareArtifact(input: PrepareArtifactInput): PrepareArtifactResult;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { readArtifactHostCapabilities } from "../artifact-host.js";
|
|
2
|
+
import { ARTIFACT_TOOL_NAME } from "../tool-catalog-entries.js";
|
|
3
|
+
import { deliverEngineNotice } from "../engine-notice.js";
|
|
4
|
+
import { RosterBuilder } from "../tool-roster.js";
|
|
5
|
+
import { defineTool } from "../tools.js";
|
|
6
|
+
import { inlineUntrusted } from "../untrusted-text.js";
|
|
7
|
+
import { physicalPathOfExisting } from "../physical-path.js";
|
|
8
|
+
import { resolveKey, violationDetails, violationText, withinAnyRoot } from "../../tools/fs/safety.js";
|
|
9
|
+
import { createArtifactTool } from "../../tools/artifact/artifact-tool.js";
|
|
10
|
+
export function prepareArtifact(input) {
|
|
11
|
+
const { deps, runId, taskId, sessionId, agentName, executionEnv, rootCanonical, additionalRootsCanonical, readDenyMatcher, resolvedReadFace, handsCwdRef, roster, firstPartyOffload, envHandToolNames } = input;
|
|
12
|
+
const host = deps.artifactHost;
|
|
13
|
+
if (host === undefined)
|
|
14
|
+
return { artifactPlane: undefined };
|
|
15
|
+
const refuse = (problem) => {
|
|
16
|
+
deliverEngineNotice(deps.onNotice, {
|
|
17
|
+
code: "config.artifact_host_invalid",
|
|
18
|
+
message: `RunnerDeps.artifactHost is wired but unusable, so no Artifact tool is mounted for this task: ${problem}`,
|
|
19
|
+
detail: { problem, sessionId, runId },
|
|
20
|
+
});
|
|
21
|
+
return { artifactPlane: undefined };
|
|
22
|
+
};
|
|
23
|
+
const verdict = readArtifactHostCapabilities(host);
|
|
24
|
+
if (!verdict.ok)
|
|
25
|
+
return refuse(verdict.problem);
|
|
26
|
+
const storageDir = verdict.capabilities.storageDir;
|
|
27
|
+
if (storageDir !== undefined && rootCanonical !== undefined) {
|
|
28
|
+
const real = physicalPathOfExisting(storageDir);
|
|
29
|
+
const inside = [rootCanonical, ...additionalRootsCanonical].find((root) => withinAnyRoot([root], real));
|
|
30
|
+
if (inside !== undefined)
|
|
31
|
+
return refuse(`the local artifact store ${storageDir} lies inside a root this run may reach through its file tools (${inside}); put the store outside every task root and additional directory`);
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
host.onMount?.(runId);
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
return refuse(`artifactHost.onMount threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
38
|
+
}
|
|
39
|
+
const readLocalFile = async (path, maxBytes, signal) => {
|
|
40
|
+
if (rootCanonical === undefined)
|
|
41
|
+
return { ok: false, reason: "refused", text: "Error (Artifact): this task has no filesystem root, so a local file cannot be published." };
|
|
42
|
+
const rk = await resolveKey(executionEnv, rootCanonical, path, signal, handsCwdRef?.current, additionalRootsCanonical, undefined, readDenyMatcher, resolvedReadFace);
|
|
43
|
+
if (!rk.ok)
|
|
44
|
+
return { ok: false, reason: "refused", text: violationText("Artifact", rk.violation), details: violationDetails(rk.violation) };
|
|
45
|
+
const meta = await executionEnv.fileInfo(rk.key, signal);
|
|
46
|
+
if (!meta.ok)
|
|
47
|
+
return { ok: false, reason: "refused", text: `Error (Artifact): cannot stat ${inlineUntrusted(path, 200)} (${inlineUntrusted(meta.error.code, 40)}).` };
|
|
48
|
+
if (meta.value.kind !== "file")
|
|
49
|
+
return { ok: false, reason: "not_a_file", kind: meta.value.kind };
|
|
50
|
+
if (meta.value.size > maxBytes)
|
|
51
|
+
return { ok: false, reason: "too_large", size: meta.value.size, limit: maxBytes, judgedOn: "metadata" };
|
|
52
|
+
const r = await executionEnv.readBinaryFile(rk.key, signal);
|
|
53
|
+
if (!r.ok)
|
|
54
|
+
return { ok: false, reason: "refused", text: `Error (Artifact): cannot read ${inlineUntrusted(path, 200)} (${inlineUntrusted(r.error.code, 40)}).` };
|
|
55
|
+
if (r.value.byteLength > maxBytes)
|
|
56
|
+
return { ok: false, reason: "too_large", size: r.value.byteLength, limit: maxBytes, judgedOn: "bytes" };
|
|
57
|
+
return { ok: true, key: rk.key, bytes: r.value };
|
|
58
|
+
};
|
|
59
|
+
const artifactSpec = createArtifactTool({ host, capabilities: verdict.capabilities, runId, taskId, sessionId, ...(agentName !== undefined ? { agentName } : {}), readLocalFile });
|
|
60
|
+
roster.mount(firstPartyOffload(defineTool(artifactSpec)), { source: "builtin", mountedBy: "optional" });
|
|
61
|
+
envHandToolNames.add(ARTIFACT_TOOL_NAME);
|
|
62
|
+
return { artifactPlane: verdict.capabilities.plane };
|
|
63
|
+
}
|
|
@@ -37,10 +37,11 @@ import type { ReadFace } from "../../tools/fs/index.js";
|
|
|
37
37
|
import type { InheritedGate, Prepared, RunInternals, RunnerSelfSeat, ToolFaceSnapshot } from "./contracts.js";
|
|
38
38
|
import { type BlockedRef } from "./synthetic-tools.js";
|
|
39
39
|
import { RosterBuilder } from "../tool-roster.js";
|
|
40
|
+
import type { ParentSpecSeat } from "../parent-spec-seat.js";
|
|
40
41
|
export interface PrepareCapsAndWorkflowInput {
|
|
41
42
|
/** borrowed-readonly — the REBOUND spec, whole: the roster map reads `tools`; the mounts read `enableBlockedReport`,
|
|
42
43
|
* `enablePlanMode`, `interactiveTools`; the caps/compliance stations read `principal`, `selfOrchestration`,
|
|
43
|
-
* `enableFork`, `getApiKeyAndHeaders`; the Workflow mount forwards `
|
|
44
|
+
* `enableFork`, `getApiKeyAndHeaders`; the Workflow mount forwards `handsReadOnly`, `interactiveTools`. The
|
|
44
45
|
* self-orchestration predicate takes the whole spec. Never mutated. */
|
|
45
46
|
spec: TaskSpec;
|
|
46
47
|
/** borrowed-readonly — the deployment seats, whole: `runtimeCapsResolver`, `compliancePostureResolver`, `onError`, `onNotice`,
|
|
@@ -54,7 +55,7 @@ export interface PrepareCapsAndWorkflowInput {
|
|
|
54
55
|
checkpointSeat: CheckpointSeat | undefined;
|
|
55
56
|
/** borrowed-readonly — the trusted spawn-side channel; the Workflow mount forwards `rootSessionId`, `placementRoot`,
|
|
56
57
|
* `onTaskNotification`, `workflowDepth`, and the capture-floor getter reads `memoryCaptureAncestors`. */
|
|
57
|
-
internals: Pick<RunInternals, "rootSessionId" | "placementRoot" | "onTaskNotification" | "workflowDepth" | "memoryCaptureAncestors" | "workflowParkedResume"> | undefined;
|
|
58
|
+
internals: Pick<RunInternals, "rootSessionId" | "placementRoot" | "onTaskNotification" | "workflowDepth" | "memoryCaptureAncestors" | "workflowParkedResume" | "questionFaceStripped"> | undefined;
|
|
58
59
|
/** borrowed-readonly — the acquired session; the classifier leg rebuilds its transcript window from `buildContext`. */
|
|
59
60
|
session: Pick<StoredSession, "buildContext">;
|
|
60
61
|
/** borrowed-readonly — the acquired session id (operator-line context, the refusal codes' phase record). */
|
|
@@ -88,6 +89,7 @@ export interface PrepareCapsAndWorkflowInput {
|
|
|
88
89
|
};
|
|
89
90
|
/** borrowed-readonly — the FROZEN approver seat (the Workflow mount's parentOnAsk). */
|
|
90
91
|
frozenOnAsk: OnAsk | undefined;
|
|
92
|
+
/** borrowed-readonly — the parent SPEC seat the children inherit (minted once by the inherited-gate phase; the Workflow mount's dep, the same value the delegation ctx carries). */ parentSpecSeat: ParentSpecSeat;
|
|
91
93
|
/** borrowed-readonly — the ONE read-face carrier expression (the Workflow mount's parentReadFace getter calls it). */
|
|
92
94
|
carrierReadFace: () => ReadFace | undefined;
|
|
93
95
|
/** borrowed-readonly — the filtered display-forwarding wrapper (the Workflow mount's forwardEvent; absent ⇒ no key). */
|
|
@@ -112,7 +112,7 @@ function autoModeArmReasonOf(intent, facePresent, caps, capsFaulted) {
|
|
|
112
112
|
return { armed: true, reason: "armed" };
|
|
113
113
|
}
|
|
114
114
|
export async function prepareCapsAndWorkflow(input) {
|
|
115
|
-
const { spec, deps, checkpointSeat, internals, session, sessionId, runId, hostTaskId, taskScope, taskRootFinal, model, thinking, lockedPreflight, toolEffects, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, harnessRef, frozenOnAsk, carrierReadFace, forwardEvent, inheritedGateForChildren, enrichSpecToolCtx, maybeOffload, requestReview, enterPlanMode, autoModeIntent, peerLaneActive, peerSendMessageBuiltIn, runnerSelf } = input;
|
|
115
|
+
const { spec, deps, parentSpecSeat, checkpointSeat, internals, session, sessionId, runId, hostTaskId, taskScope, taskRootFinal, model, thinking, lockedPreflight, toolEffects, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, harnessRef, frozenOnAsk, carrierReadFace, forwardEvent, inheritedGateForChildren, enrichSpecToolCtx, maybeOffload, requestReview, enterPlanMode, autoModeIntent, peerLaneActive, peerSendMessageBuiltIn, runnerSelf } = input;
|
|
116
116
|
const roster = new RosterBuilder(toolEffects);
|
|
117
117
|
for (const t of spec.tools ?? []) {
|
|
118
118
|
const mounted = mountCallerTool(t);
|
|
@@ -312,8 +312,7 @@ export async function prepareCapsAndWorkflow(input) {
|
|
|
312
312
|
return mine.length > 0 ? mine : undefined;
|
|
313
313
|
} }
|
|
314
314
|
: {}),
|
|
315
|
-
|
|
316
|
-
oneShot: spec.oneShot,
|
|
315
|
+
parentSpecSeat, ...(internals?.questionFaceStripped === true ? { parentQuestionFaceStripped: true } : {}),
|
|
317
316
|
...(resolvedInteractionPosture !== undefined ? { parentInteractionPosture: resolvedInteractionPosture } : {}),
|
|
318
317
|
parentMemoryCaptureState: () => {
|
|
319
318
|
const memoryEngineSession = input.memoryEngineSession();
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
import { type BrainCallGuardrailRef } from "../../brain/timeout.js";
|
|
23
23
|
import type { Model } from "../../internal/llm.js";
|
|
24
24
|
import type { ThinkingLevel } from "../../internal/harness.js";
|
|
25
|
-
import type
|
|
25
|
+
import { type MicroCompactMachine } from "../context-edit.js";
|
|
26
26
|
import { type LockedPreflight } from "../locked-config.js";
|
|
27
27
|
import { type ResolvedRole } from "../roles.js";
|
|
28
28
|
import type { SessionStore } from "../session.js";
|
|
@@ -150,7 +150,7 @@ export interface PrepareConfigDoorsResult {
|
|
|
150
150
|
* for the door + placement reasoning). The per-run state builder consumes exactly these values —
|
|
151
151
|
* the deps bag is never re-read after this door. */
|
|
152
152
|
microCompactKnob: {
|
|
153
|
-
machine:
|
|
153
|
+
machine: MicroCompactMachine;
|
|
154
154
|
clearOnRejection: boolean;
|
|
155
155
|
};
|
|
156
156
|
/** owned — the resolved role; its `systemPrompt` seat is still read at prompt-input time. */
|
|
@@ -213,7 +213,7 @@ export interface PrepareConfigDoorsResult {
|
|
|
213
213
|
* it must refuse exactly like a malformed field, never fold to the defaults. The RESOLVED values
|
|
214
214
|
* returned here are immutable and are the state builder's ONLY source — nothing re-reads the bag. */
|
|
215
215
|
export declare function resolveMicroCompactKnob(bag: RunnerDeps["microCompact"]): {
|
|
216
|
-
machine:
|
|
216
|
+
machine: MicroCompactMachine;
|
|
217
217
|
clearOnRejection: boolean;
|
|
218
218
|
};
|
|
219
219
|
export declare function prepareConfigDoors(input: PrepareConfigDoorsInput): PrepareConfigDoorsResult;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { resolveBrainCallGuardrailMs } from "../../brain/timeout.js";
|
|
2
2
|
import { assertReadFaceValue } from "../../tools/fs/index.js";
|
|
3
|
+
import { MICRO_COMPACT_MACHINES } from "../context-edit.js";
|
|
4
|
+
import { assertNoRetiredRunnerDeps } from "./retired-runner-deps.js";
|
|
3
5
|
import { resolveCheckpointStore } from "../checkpoint-store.js";
|
|
4
6
|
import { isModelPriced, malformedPricingField, modelCostToPricing } from "../pricing.js";
|
|
5
7
|
import { preflightLockedConfig } from "../locked-config.js";
|
|
@@ -133,8 +135,8 @@ export function resolveMicroCompactKnob(bag) {
|
|
|
133
135
|
throw microCompactConfigError(undefined, bag, "an object carrying optional machine/clearOnRejection keys");
|
|
134
136
|
}
|
|
135
137
|
const declaredMachine = bag?.machine;
|
|
136
|
-
if (declaredMachine !== undefined && declaredMachine
|
|
137
|
-
throw microCompactConfigError("machine", declaredMachine, `"
|
|
138
|
+
if (declaredMachine !== undefined && !MICRO_COMPACT_MACHINES.includes(declaredMachine)) {
|
|
139
|
+
throw microCompactConfigError("machine", declaredMachine, MICRO_COMPACT_MACHINES.map((m) => `"${m}"`).join(" | "));
|
|
138
140
|
}
|
|
139
141
|
return { machine: declaredMachine ?? "cc", clearOnRejection: resolveClearOnRejection(bag) };
|
|
140
142
|
}
|
|
@@ -148,6 +150,7 @@ function resolveClearOnRejection(bag) {
|
|
|
148
150
|
export function prepareConfigDoors(input) {
|
|
149
151
|
const { deps, sessions, resume, internals } = input;
|
|
150
152
|
let spec = input.spec;
|
|
153
|
+
assertNoRetiredRunnerDeps(deps);
|
|
151
154
|
assertRestoreGatedToolsValue(spec.restoreGatedTools);
|
|
152
155
|
const microCompactKnob = resolveMicroCompactKnob(deps.microCompact);
|
|
153
156
|
const assertToolNameListValue = (value, seat) => {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { type AgentHarness, type AgentMessage } from "../../internal/harness.js";
|
|
19
19
|
import type { Model } from "../../internal/llm.js";
|
|
20
|
-
import { type
|
|
20
|
+
import { type MicroCompactMachine, type OccurrenceIndex } from "../context-edit.js";
|
|
21
21
|
import { type ToolResultStore } from "../tool-result-store.js";
|
|
22
22
|
import { type RunnerDeps } from "../types.js";
|
|
23
23
|
import type { Prepared, PreparedMicroCompact } from "./contracts.js";
|
|
@@ -39,7 +39,7 @@ export interface PrepareContextLaneInput {
|
|
|
39
39
|
offloadStore: ToolResultStore | undefined;
|
|
40
40
|
/** borrowed-readonly — the doors' RESOLVED microCompact knob (immutable values, never the deps bag). */
|
|
41
41
|
microCompactKnob: {
|
|
42
|
-
machine:
|
|
42
|
+
machine: MicroCompactMachine;
|
|
43
43
|
clearOnRejection: boolean;
|
|
44
44
|
};
|
|
45
45
|
/** borrowed-mutable — the built harness. Writer here: `on("context", …)` — the ONE registration of the request-build
|
|
@@ -44,14 +44,8 @@ export function prepareContextLane(input) {
|
|
|
44
44
|
let ccPass;
|
|
45
45
|
const edited = microCompact.machine === "off" ? mediaCapped : clearStaleToolResults(mediaCapped, {
|
|
46
46
|
budgetTokens: editAt,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
...(microCompact.machine === "cc"
|
|
50
|
-
? {
|
|
51
|
-
clearSource: replayed,
|
|
52
|
-
onCleared: (pass) => { ccPass = pass; },
|
|
53
|
-
}
|
|
54
|
-
: {}),
|
|
47
|
+
clearSource: replayed,
|
|
48
|
+
onCleared: (pass) => { ccPass = pass; },
|
|
55
49
|
anchoredTotalTokens: estimateContextTokens(mediaCapped, charsPerToken).tokens,
|
|
56
50
|
charsPerToken,
|
|
57
51
|
...(offloadStore
|
|
@@ -193,15 +187,10 @@ export async function runGuardChain(args) {
|
|
|
193
187
|
};
|
|
194
188
|
let working = edited;
|
|
195
189
|
let anchoredWorking = estimateContextTokens(working, charsPerToken).tokens;
|
|
196
|
-
if (microCompact.machine === "legacy") {
|
|
197
|
-
const t = applyGuardTrim(working, anchoredWorking);
|
|
198
|
-
return { working, trimmed: t.trimmed, trimDroppedMessages: t.dropped };
|
|
199
|
-
}
|
|
200
190
|
if (microCompact.machine === "off" && anchoredWorking > guardAt) {
|
|
201
191
|
let blockingPass;
|
|
202
192
|
const blockingEdited = clearStaleToolResults(working, {
|
|
203
193
|
budgetTokens: guardAt,
|
|
204
|
-
machine: "cc",
|
|
205
194
|
clearSource: args.replayed,
|
|
206
195
|
onCleared: (pass) => { blockingPass = pass; },
|
|
207
196
|
anchoredTotalTokens: anchoredWorking,
|
|
@@ -25,7 +25,7 @@ import type { FileHistoryBoundarySeat, RunInternals } from "./contracts.js";
|
|
|
25
25
|
export interface PrepareFileHistoryInput {
|
|
26
26
|
/** borrowed-readonly — the deployment seats this phase reads: the first-touch failure policy and the
|
|
27
27
|
* history store (both validated HERE, once), the incident sink, and the retired-epoch diagnostic probe. */
|
|
28
|
-
deps: Pick<RunnerDeps, "onTrackFailure" | "fileHistoryStore" | "onError"
|
|
28
|
+
deps: Pick<RunnerDeps, "onTrackFailure" | "fileHistoryStore" | "onError">;
|
|
29
29
|
/** borrowed-readonly — the REBOUND spec's rewind request fields (the retired `rewindFiles` spelling is
|
|
30
30
|
* read off the same object as an unknown key) and the caller's cancel signal for the restore. */
|
|
31
31
|
spec: Pick<TaskSpec, "resumeAt" | "resumeAtMode" | "restoreFiles" | "rewindFilesTo" | "acceptPartialRestore" | "signal">;
|
|
@@ -63,7 +63,6 @@ export async function prepareFileHistory(input) {
|
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
const legacyEpochTail = (entryId, form = "at-or-above") => legacyRewindEpochTail(deps, sessionId, entryId, form);
|
|
67
66
|
let restoredFilePaths = [];
|
|
68
67
|
if (rewindTarget !== undefined && fileHistoryStore !== undefined && handsEnabled) {
|
|
69
68
|
const historyStore = fileHistoryStore;
|
|
@@ -85,7 +84,7 @@ export async function prepareFileHistory(input) {
|
|
|
85
84
|
}
|
|
86
85
|
}
|
|
87
86
|
if (anchor === undefined) {
|
|
88
|
-
const e = new Error(`rewind-files: no file-history boundary exists at or above the "before" branch point on session "${sessionId}" — cannot restore files consistent with the rewound context. ${
|
|
87
|
+
const e = new Error(`rewind-files: no file-history boundary exists at or above the "before" branch point on session "${sessionId}" — cannot restore files consistent with the rewound context. ${rewindRefusalTail("at-or-above")}`);
|
|
89
88
|
e.code = "rewind_snapshot.unresolvable";
|
|
90
89
|
throw e;
|
|
91
90
|
}
|
|
@@ -99,7 +98,7 @@ export async function prepareFileHistory(input) {
|
|
|
99
98
|
if (restored.error?.code === "not_found") {
|
|
100
99
|
const e = new Error(rewindBefore
|
|
101
100
|
? `rewind-files: the resolved "before" history anchor "${rewindTarget}" disappeared before restore — files were NOT rewound`
|
|
102
|
-
: `rewind-files: no file-history boundary exists for entry "${rewindTarget}" on session "${sessionId}" — the working tree was NOT rewound. ${
|
|
101
|
+
: `rewind-files: no file-history boundary exists for entry "${rewindTarget}" on session "${sessionId}" — the working tree was NOT rewound. ${rewindRefusalTail("keyed")}`);
|
|
103
102
|
e.code = "rewind_snapshot.unresolvable";
|
|
104
103
|
throw e;
|
|
105
104
|
}
|
|
@@ -192,55 +191,7 @@ function resolveWiredFileHistoryStore(candidate) {
|
|
|
192
191
|
}
|
|
193
192
|
return candidate;
|
|
194
193
|
}
|
|
195
|
-
|
|
196
|
-
const LEGACY_PROBE_TIMED_OUT = Symbol("legacy-rewind-probe-timeout");
|
|
197
|
-
async function legacyRewindEpochTail(deps, sessionId, entryId, form) {
|
|
198
|
-
const probe = deps.legacyRewindBoundaryProbe;
|
|
199
|
-
let verdict;
|
|
200
|
-
if (probe !== undefined) {
|
|
201
|
-
try {
|
|
202
|
-
let timer;
|
|
203
|
-
const timeout = new Promise((resolve) => {
|
|
204
|
-
timer = setTimeout(() => resolve(LEGACY_PROBE_TIMED_OUT), LEGACY_PROBE_TIMEOUT_MS);
|
|
205
|
-
});
|
|
206
|
-
try {
|
|
207
|
-
verdict = await Promise.race([Promise.resolve(probe({ sessionId, entryId })), timeout]);
|
|
208
|
-
}
|
|
209
|
-
finally {
|
|
210
|
-
clearTimeout(timer);
|
|
211
|
-
}
|
|
212
|
-
if (verdict === LEGACY_PROBE_TIMED_OUT) {
|
|
213
|
-
verdict = undefined;
|
|
214
|
-
try {
|
|
215
|
-
deps.onError?.(new Error(`RunnerDeps.legacyRewindBoundaryProbe did not answer within ${LEGACY_PROBE_TIMEOUT_MS}ms while explaining a rewind refusal — the refusal stands and names both possibilities`), { phase: "rewind", sessionId });
|
|
216
|
-
}
|
|
217
|
-
catch {
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
catch (err) {
|
|
222
|
-
verdict = undefined;
|
|
223
|
-
try {
|
|
224
|
-
deps.onError?.(new Error(`RunnerDeps.legacyRewindBoundaryProbe threw while explaining a rewind refusal (${err.message}) — the refusal stands and names both possibilities`), { phase: "rewind", sessionId });
|
|
225
|
-
}
|
|
226
|
-
catch {
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
if (verdict !== undefined && typeof verdict !== "boolean") {
|
|
230
|
-
try {
|
|
231
|
-
deps.onError?.(new Error(`RunnerDeps.legacyRewindBoundaryProbe answered ${JSON.stringify(String(verdict))} for entry "${entryId}" — only true/false/undefined are meaningful, so the refusal names both possibilities instead of trusting it`), { phase: "rewind", sessionId });
|
|
232
|
-
}
|
|
233
|
-
catch {
|
|
234
|
-
}
|
|
235
|
-
verdict = undefined;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
if (verdict === true) {
|
|
239
|
-
return `This deployment's legacy-epoch probe reports that entry "${entryId}" DOES carry a boundary from the retired whole-tree snapshot era, which this engine's per-edited-file seat does not restore — the two epochs are not interchangeable (a whole-tree manifest carries no tracked-set provenance, so replaying it here would converge files this session never edited). Restore it with the whole-tree-era tooling this deployment kept, or re-run the turns under the current engine.`;
|
|
240
|
-
}
|
|
241
|
-
if (verdict === false) {
|
|
242
|
-
return `This deployment's legacy-epoch probe reports no whole-tree-era boundary for entry "${entryId}" either, so the boundary simply does not exist: its turns ran without a RunnerDeps.fileHistoryStore wired, or it was reaped.`;
|
|
243
|
-
}
|
|
194
|
+
function rewindRefusalTail(form) {
|
|
244
195
|
return form === "keyed"
|
|
245
196
|
? `Boundaries are keyed by a turn's INITIAL entry and exist only for turns that ran with a RunnerDeps.fileHistoryStore wired; a boundary from the retired whole-tree snapshot era is not restorable by this seat, and reaped boundaries have none.`
|
|
246
197
|
: `Either the boundary does not exist (its turns ran without a RunnerDeps.fileHistoryStore, or it was reaped), or it was produced in the retired whole-tree snapshot era, which this engine's per-edited-file seat does not restore.`;
|
|
@@ -162,13 +162,10 @@ export interface PrepareHandsReadFaceInput {
|
|
|
162
162
|
* when no file restore ran. Fail-closed by construction — dropping a read record only ever
|
|
163
163
|
* produces refusals. */
|
|
164
164
|
restoredFilePaths?: readonly string[];
|
|
165
|
-
/** borrowed-readonly —
|
|
166
|
-
* the band's beforeWrite
|
|
167
|
-
*
|
|
168
|
-
|
|
169
|
-
memoryWriteGateRef: {
|
|
170
|
-
current?: BeforeWriteHook;
|
|
171
|
-
};
|
|
165
|
+
/** borrowed-readonly — the memory write gate the memory phase minted (it runs BEFORE this phase: the memory root
|
|
166
|
+
* must be known before the toolkit compiles), composed into the band's beforeWrite below; undefined for a
|
|
167
|
+
* memory-less run (every write passes the engine half). */
|
|
168
|
+
memoryWriteGate: BeforeWriteHook | undefined;
|
|
172
169
|
/** borrowed-mutable — the advertised-writable-directory seat (see its module header for the one
|
|
173
170
|
* rule). Present on the hands leg only (a fence exists). The memory phase, which runs BEFORE this one,
|
|
174
171
|
* has already admitted its write root through it; this phase admits the deployment's scratchpad and
|
|
@@ -123,7 +123,7 @@ export function resolveHandsLessReadFace(input) {
|
|
|
123
123
|
}
|
|
124
124
|
export async function prepareHandsMount(input) {
|
|
125
125
|
const envHandToolNames = new Set();
|
|
126
|
-
const { handsEnabled, executionEnv, taskRootFinal, rebaseRestoredPath, resume, session, sessionId, hostTaskId, taskScope, fullShellReachable, effectiveShellGate, toolFaceSnapshot, model, spec, deps, internals,
|
|
126
|
+
const { handsEnabled, executionEnv, taskRootFinal, rebaseRestoredPath, resume, session, sessionId, hostTaskId, taskScope, fullShellReachable, effectiveShellGate, toolFaceSnapshot, model, spec, deps, internals, memoryWriteGate, advertisedWritableDirs, firstPartyOffload, roster, egressTools, irreversibilityTier, irreversibleTools, reversibilityProbes } = input;
|
|
127
127
|
assertStringArraySeat(spec.additionalDirectories, "TaskSpec.additionalDirectories", "strings");
|
|
128
128
|
assertStringArraySeat(spec.additionalReadDirectories, "TaskSpec.additionalReadDirectories", "strings");
|
|
129
129
|
assertStringArraySeat(deps.readDenyPatterns, "RunnerDeps.readDenyPatterns", "compiler-owned");
|
|
@@ -328,7 +328,7 @@ export async function prepareHandsMount(input) {
|
|
|
328
328
|
if (verdict !== undefined && verdict.ok === false)
|
|
329
329
|
return verdict;
|
|
330
330
|
}
|
|
331
|
-
return
|
|
331
|
+
return memoryWriteGate?.(w);
|
|
332
332
|
},
|
|
333
333
|
mountBackgroundTaskTools: false,
|
|
334
334
|
monitorToolActive: backgroundTaskToolsActive && !(toolFaceSnapshot.exclude?.includes("Monitor") ?? false),
|
|
@@ -354,6 +354,7 @@ export async function prepareHandsMount(input) {
|
|
|
354
354
|
const shellReadBoundary = () => ({
|
|
355
355
|
roots: [rootCanonical, ...additionalRootsCanonical, ...additionalReadRootsCanonical],
|
|
356
356
|
...(handsCwdRef?.current !== undefined ? { cwd: handsCwdRef.current } : {}),
|
|
357
|
+
...(executionEnv.homeDir !== undefined ? { homeDir: executionEnv.homeDir } : {}),
|
|
357
358
|
denyMatch: (p) => readDenyMatcher?.matchPath(p)?.pattern ?? null,
|
|
358
359
|
...(resolvedReadFace !== undefined ? { face: resolvedReadFace } : {}),
|
|
359
360
|
});
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* freeze with its tighten-only intersection and the monotonic governed bit), the effective shellGate against the
|
|
6
6
|
* spec, the three cells later phases fill for the children's chain (own session rules, own admitted org scopes,
|
|
7
7
|
* own org verdict), the checkpoint-section closures the suspend serializer reads (face / org / F-012 stamps), the
|
|
8
|
-
* FROZEN ask and question seats (spec over deps), the two delegation refs the memory phase binds late, the ONE
|
|
8
|
+
* FROZEN ask and question seats (spec over deps), the parent SPEC seat the children inherit, the two delegation refs the memory phase binds late, the ONE
|
|
9
9
|
* child-chain assembly `inheritedGateForChildren`, the caller-tool ctx enrichment `enrichSpecToolCtx` shared by
|
|
10
10
|
* the roster wrap and the revival spawner, the denial-limit stop seat, and the full-shell reachability predicate.
|
|
11
11
|
* The interface is the dependency list the segment had implicitly.
|
|
@@ -36,6 +36,7 @@ import type { ReadFace } from "../../tools/fs/index.js";
|
|
|
36
36
|
import type { AutoModeArmingRecipe } from "../auto-mode-arming.js";
|
|
37
37
|
import type { AutoModeDecider, AutoModeDenialTracker } from "../auto-mode.js";
|
|
38
38
|
import { type OnQuestion } from "../ask-question.js";
|
|
39
|
+
import { type ParentSpecSeat } from "../parent-spec-seat.js";
|
|
39
40
|
import { type HookEnvCapabilities, type Hooks } from "../hooks.js";
|
|
40
41
|
import type { LockedPreflight } from "../locked-config.js";
|
|
41
42
|
import type { OwnOrgAdmissionVerdict } from "../memory-admission.js";
|
|
@@ -65,7 +66,7 @@ export interface PrepareInheritedGateInput {
|
|
|
65
66
|
/** borrowed-readonly — the trusted spawn-side channel: `inheritedGate` (the LIVE half of the chain fold), `ownOrgAdmissionRef`
|
|
66
67
|
* (the same-session continuation's freeze), `delegationProvenance` (the F-012 stamp), and the identity / peer / notification
|
|
67
68
|
* seats the ctx enrichment forwards. Never mutated. */
|
|
68
|
-
internals: Pick<RunInternals, "inheritedGate" | "ownOrgAdmissionRef" | "delegationProvenance" | "memoryCaptureAncestors" | "parentTaskId" | "parentSessionId" | "rootSessionId" | "placementRoot" | "explicitAgentName" | "peerSelfRef" | "peerInboundChainRef" | "onTaskNotification" | "onSubagentSpawn" | "insideFork"> | undefined;
|
|
69
|
+
internals: Pick<RunInternals, "inheritedGate" | "ownOrgAdmissionRef" | "delegationProvenance" | "memoryCaptureAncestors" | "parentTaskId" | "parentSessionId" | "rootSessionId" | "placementRoot" | "explicitAgentName" | "peerSelfRef" | "peerInboundChainRef" | "onTaskNotification" | "onSubagentSpawn" | "insideFork" | "questionFaceStripped"> | undefined;
|
|
69
70
|
/** borrowed-readonly — the resume leg, or undefined on a fresh one: `seed.inheritedGate` is the CHECKPOINT half of the chain
|
|
70
71
|
* fold (the trust floor the live half may only tighten), `seed.readFace` the hands-less re-park's carried section. */
|
|
71
72
|
resume: Pick<PrepareResume, "seed"> | undefined;
|
|
@@ -240,6 +241,8 @@ export interface PrepareInheritedGateResult {
|
|
|
240
241
|
notifyOwnHookCrash: (err: unknown) => void;
|
|
241
242
|
/** owned — the FROZEN question seat (spec over deps), the content-ask twin of `frozenOnAsk`. */
|
|
242
243
|
frozenOnQuestion: OnQuestion | undefined;
|
|
244
|
+
/** owned — the parent SPEC seat this run hands its children (`parentSpecSeatOf(spec, frozenOnQuestion)`): the ctx seat and the Workflow mount dep are this one value; both lanes apply it with `applyParentSpecSeat` (one law). */
|
|
245
|
+
parentSpecSeat: ParentSpecSeat;
|
|
243
246
|
/** borrowed-mutable — the delegation runtime-provenance arming face. Writer: the memory-engine-session phase
|
|
244
247
|
* (prepareMemoryEngineSession), once per leg when it arms. Read lazily by delegation tools through the ctx. */
|
|
245
248
|
provenanceForChildrenRef: {
|