@sema-agent/core 5.56.0 โ 5.58.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 +122 -0
- package/dist/agents/cascade.d.ts +1 -1
- package/dist/agents/cumulative-stats.d.ts +1 -1
- package/dist/agents/observer.d.ts +2 -2
- package/dist/agents/peer-admission.d.ts +1 -1
- package/dist/agents/retain-ledger.d.ts +2 -2
- package/dist/agents/roster-store.d.ts +8 -8
- package/dist/agents/send-message-tool.d.ts +13 -2
- package/dist/agents/send-message-tool.js +34 -12
- package/dist/agents/subagent-steps.d.ts +1 -1
- package/dist/agents/subagent.d.ts +13 -13
- package/dist/agents/team.d.ts +15 -6
- package/dist/agents/team.js +1 -0
- package/dist/agents/tool-filter.d.ts +2 -2
- package/dist/agents/verify.d.ts +1 -1
- package/dist/bench/metrics.d.ts +35 -35
- package/dist/brain/anthropic.js +15 -5
- package/dist/brain/circuit-breaker.js +2 -1
- package/dist/brain/degrading.d.ts +1 -1
- package/dist/brain/degrading.js +4 -1
- package/dist/brain/errors.d.ts +3 -3
- package/dist/brain/failover.js +16 -1
- package/dist/brain/open-responses.js +15 -5
- package/dist/brain/openai.js +16 -5
- package/dist/brain/reasoning.d.ts +2 -2
- package/dist/brain/repetition.d.ts +1 -1
- package/dist/brain/request-params.d.ts +30 -27
- package/dist/brain/request-params.js +1 -7
- package/dist/brain/route-adjudicator.d.ts +190 -0
- package/dist/brain/route-adjudicator.js +189 -0
- package/dist/brain/route-conformance.d.ts +55 -0
- package/dist/brain/route-conformance.js +136 -0
- package/dist/brain/routing.js +8 -3
- package/dist/brain/status-sink.d.ts +2 -2
- package/dist/brain/stream-shared.d.ts +1 -1
- package/dist/config/catalog.d.ts +5 -5
- package/dist/core/arg-summary.d.ts +4 -4
- package/dist/core/ask-class.d.ts +2 -2
- package/dist/core/ask-question.d.ts +1 -1
- package/dist/core/auto-compaction.d.ts +15 -15
- package/dist/core/auto-mode.d.ts +5 -5
- package/dist/core/background-agent-store.d.ts +20 -20
- package/dist/core/background-shell.d.ts +4 -4
- package/dist/core/checkpoint-store.d.ts +35 -27
- package/dist/core/context-edit.d.ts +1 -1
- package/dist/core/context-guard.d.ts +1 -1
- package/dist/core/exec-output-tail.d.ts +6 -6
- package/dist/core/file-snapshot-store.d.ts +8 -8
- package/dist/core/git-worktree-env.d.ts +3 -3
- package/dist/core/governance-codes.js +2 -0
- package/dist/core/hooks.d.ts +73 -33
- package/dist/core/hooks.js +87 -25
- package/dist/core/image-downsample.d.ts +1 -1
- package/dist/core/locked-config.d.ts +1 -1
- package/dist/core/lsp.d.ts +1 -1
- package/dist/core/mailbox-store.d.ts +1 -1
- package/dist/core/mcp.d.ts +3 -3
- package/dist/core/mcp.js +4 -4
- package/dist/core/memory-engine/consolidation-driver.d.ts +207 -0
- package/dist/core/memory-engine/consolidation-driver.js +378 -0
- package/dist/core/memory-engine/consolidation.d.ts +46 -2
- package/dist/core/memory-engine/consolidation.js +1 -0
- package/dist/core/memory-engine/data-plane.d.ts +1 -1
- package/dist/core/memory-engine/distiller.d.ts +550 -0
- package/dist/core/memory-engine/distiller.js +598 -0
- package/dist/core/memory-engine/dual-root.d.ts +1 -1
- package/dist/core/memory-engine/engine.d.ts +62 -8
- package/dist/core/memory-engine/engine.js +40 -4
- package/dist/core/memory-engine/file-backend.d.ts +1 -1
- package/dist/core/memory-engine/index.d.ts +4 -2
- package/dist/core/memory-engine/index.js +4 -2
- package/dist/core/memory-engine/origin-clearance.d.ts +1 -1
- package/dist/core/memory-engine/scope-contract.d.ts +4 -4
- package/dist/core/memory-engine/sync-client.d.ts +16 -16
- package/dist/core/memory-engine/sync.d.ts +4 -4
- package/dist/core/memory-recall.d.ts +1 -1
- package/dist/core/memory.d.ts +2 -2
- package/dist/core/permission-rule-consent.d.ts +230 -36
- package/dist/core/permission-rule-consent.js +258 -54
- package/dist/core/permission-rule-model.d.ts +295 -97
- package/dist/core/permission-rule-model.js +132 -41
- package/dist/core/permission-rules.d.ts +9 -9
- package/dist/core/remote-env.d.ts +8 -8
- package/dist/core/roles.d.ts +3 -3
- package/dist/core/roles.js +1 -0
- package/dist/core/runner/assemble-result.d.ts +2 -2
- package/dist/core/runner/compaction-call-options.d.ts +3 -3
- package/dist/core/runner/memory-consolidation-driver.d.ts +49 -0
- package/dist/core/runner/memory-consolidation-driver.js +60 -0
- package/dist/core/runner/memory-consolidation.d.ts +1 -1
- package/dist/core/runner/prepare-config-doors.d.ts +3 -3
- package/dist/core/runner/prepare-task.d.ts +21 -21
- package/dist/core/runner/prepare-task.js +54 -18
- package/dist/core/runner/prepare-workspace-restore.d.ts +2 -2
- package/dist/core/runner/runtask.d.ts +15 -12
- package/dist/core/runner/runtask.js +48 -0
- package/dist/core/runner/session-rule-policy.d.ts +1 -1
- package/dist/core/runner/teardown-bounded.d.ts +1 -1
- package/dist/core/runner/tool-disclosure.d.ts +2 -2
- package/dist/core/runner/turn-attachments.d.ts +11 -11
- package/dist/core/scheduler.d.ts +10 -5
- package/dist/core/secret-env.d.ts +1 -1
- package/dist/core/sensitive-path-policy.d.ts +1 -1
- package/dist/core/session-policy-store.d.ts +2 -2
- package/dist/core/session-reconcile.d.ts +2 -2
- package/dist/core/session-store.d.ts +3 -3
- package/dist/core/session.d.ts +1 -1
- package/dist/core/shutdown-debug.d.ts +2 -2
- package/dist/core/side-query.d.ts +14 -7
- package/dist/core/spec-contract.d.ts +1 -1
- package/dist/core/store-contracts/contract-harness.d.ts +2 -2
- package/dist/core/store-contracts/contract-kit-version.d.ts +2 -2
- package/dist/core/store-contracts/mailbox-store-contract.d.ts +1 -1
- package/dist/core/store-contracts/mailbox-store-contract.js +1 -1
- package/dist/core/task-notification.d.ts +5 -5
- package/dist/core/task-registry-agent.d.ts +12 -12
- package/dist/core/task-registry-monitor.d.ts +1 -1
- package/dist/core/task-registry-shared.d.ts +41 -41
- package/dist/core/task-registry.d.ts +12 -12
- package/dist/core/tool-detach.d.ts +2 -2
- package/dist/core/tool-errors.d.ts +3 -3
- package/dist/core/tool-policy.d.ts +55 -28
- package/dist/core/tool-result-budget.d.ts +1 -1
- package/dist/core/tool-result-store.d.ts +2 -2
- package/dist/core/tools.d.ts +1 -1
- package/dist/core/trace.d.ts +26 -23
- package/dist/core/types.d.ts +155 -70
- package/dist/core/untrusted-egress.d.ts +1 -1
- package/dist/core/untrusted-text.d.ts +7 -7
- package/dist/core/wiring-manifest.d.ts +5 -5
- package/dist/core/workflow-journal-store.d.ts +14 -14
- package/dist/core/workflow-run-store-contract.d.ts +1 -1
- package/dist/core/workflow-run-store-contract.js +1 -1
- package/dist/core/workflow-run-store.d.ts +4 -4
- package/dist/engine/compaction/compaction.d.ts +3 -3
- package/dist/engine/compaction/utils.d.ts +2 -2
- package/dist/engine/execution-env/kill-tree.d.ts +1 -1
- package/dist/engine/execution-env/node-execution-env.d.ts +8 -8
- package/dist/engine/harness/agent-harness.d.ts +6 -6
- package/dist/engine/harness/agent-harness.js +26 -1
- package/dist/engine/harness/messages.d.ts +1 -1
- package/dist/engine/harness/types.d.ts +15 -11
- package/dist/engine/llm/types.d.ts +79 -14
- package/dist/engine/loop/agent-loop.d.ts +3 -3
- package/dist/engine/loop/types.d.ts +4 -4
- package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
- package/dist/engine/session/import-validate.d.ts +1 -1
- package/dist/engine/session/log-digest.d.ts +1 -1
- package/dist/engine/session/memory-repo.d.ts +2 -2
- package/dist/engine/session/session.d.ts +4 -4
- package/dist/fixtures/index.d.ts +4 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.js +5 -2
- package/dist/internal/llm.d.ts +1 -1
- package/dist/orchestration/goal.d.ts +1 -1
- package/dist/orchestration/run-spec.d.ts +1 -1
- package/dist/orchestration/run-workflow-tool.d.ts +12 -12
- package/dist/orchestration/workflow-governance.d.ts +4 -4
- package/dist/orchestration/workflow-observe.d.ts +1 -1
- package/dist/orchestration/workflow-script-runner.d.ts +1 -1
- package/dist/orchestration/workflow-script-store.d.ts +9 -9
- package/dist/orchestration/workflow-size-guideline.d.ts +1 -1
- package/dist/orchestration/workflow-types.d.ts +5 -5
- package/dist/orchestration/workflow.d.ts +10 -10
- package/dist/prompt-assembly/artifact-store.d.ts +1 -1
- package/dist/prompt-assembly/artifact.d.ts +1 -1
- package/dist/prompt-assembly/assemble.d.ts +1 -1
- package/dist/prompt-assembly/composer.d.ts +2 -2
- package/dist/prompt-assembly/epoch.d.ts +2 -2
- package/dist/prompt-assembly/event-registry.d.ts +1 -1
- package/dist/prompt-assembly/explain.d.ts +3 -3
- package/dist/prompt-assembly/tool-catalog.d.ts +1 -1
- package/dist/prompt-assembly/turn-snapshot.d.ts +4 -4
- package/dist/prompt-assembly/types.d.ts +12 -12
- package/dist/prompts/coordinator.d.ts +1 -1
- package/dist/prompts/default.d.ts +10 -10
- package/dist/prompts/default.js +2 -0
- package/dist/prompts/simple-sections.d.ts +3 -3
- package/dist/prompts/supervisor.d.ts +2 -2
- package/dist/scenarios/full-body.d.ts +3 -3
- package/dist/scenarios/scenario-registry.d.ts +6 -2
- package/dist/scenarios/scenario-registry.js +4 -2
- package/dist/stores/cc/sidecar-transcript.d.ts +3 -3
- package/dist/stores/file/fs-atomic.d.ts +2 -2
- package/dist/stores/file/index.d.ts +1 -1
- package/dist/stores/file/session-store.d.ts +2 -2
- package/dist/stores/file/workflow-journal-store.d.ts +4 -4
- package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
- package/dist/tools/fs/encoding.d.ts +4 -4
- package/dist/tools/fs/fs-bash.d.ts +3 -3
- package/dist/tools/fs/fs-pdf.d.ts +1 -1
- package/dist/tools/fs/fs-shared.d.ts +6 -6
- package/dist/tools/fs/index.d.ts +2 -2
- package/dist/tools/fs/index.js +8 -1
- package/dist/tools/fs/notebook.d.ts +1 -1
- package/dist/tools/fs/pdf.d.ts +1 -1
- package/dist/tools/fs/read-deny.d.ts +1 -1
- package/dist/tools/fs/safety.d.ts +9 -9
- package/dist/tools/fs/search.d.ts +2 -2
- package/dist/tools/monitor.d.ts +3 -3
- package/dist/tools/scheduler-tools.js +28 -6
- package/dist/tools/task-list.d.ts +2 -2
- package/dist/tools/web.d.ts +19 -4
- package/dist/tools/web.js +8 -2
- package/dist/tools/worktree.d.ts +5 -5
- package/dist/tools/worktree.js +2 -2
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +74 -3
|
@@ -329,13 +329,13 @@ export interface Prepared {
|
|
|
329
329
|
chars: number;
|
|
330
330
|
hash: string;
|
|
331
331
|
}>;
|
|
332
|
-
/** Manifest v2 (
|
|
332
|
+
/** Manifest v2 (stage S1, additive): the compiled-IR section view (slot/carrier/cadence/
|
|
333
333
|
* cacheClass per section). `contentHash` is the
|
|
334
|
-
* digest-tiering face
|
|
334
|
+
* digest-tiering face: present ONLY on operator-declared sections (the typed
|
|
335
335
|
* `stableBlocks` lane, owner "deployment") as an UNSALTED full sha256 of the section text โ
|
|
336
336
|
* the center-publish โ manifest end-to-end reconciliation anchor. Core-native sections (env
|
|
337
337
|
* facts, memory tail, user role text) stay salted-only: a plain hash of a short guessable
|
|
338
|
-
* block is a dictionary-preimage surface for trace readers (
|
|
338
|
+
* block is a dictionary-preimage surface for trace readers ([E]). */
|
|
339
339
|
sections?: Array<{
|
|
340
340
|
id: string;
|
|
341
341
|
slot: string;
|
|
@@ -346,7 +346,7 @@ export interface Prepared {
|
|
|
346
346
|
hash: string;
|
|
347
347
|
contentHash?: string;
|
|
348
348
|
}>;
|
|
349
|
-
/**
|
|
349
|
+
/** S2 (additive): the mounted tools plane โ contract identity, durable-replay aliases,
|
|
350
350
|
* presentation-invariant shape digest and full wire digest per tool (initial mount face). */
|
|
351
351
|
tools?: ToolManifestRow[];
|
|
352
352
|
/** design/148 S3 (additive, ยง10.2): the nine-element cache identity โ digests only, no prompt
|
|
@@ -363,7 +363,7 @@ export interface Prepared {
|
|
|
363
363
|
* seat chose it. Absent when nothing is deferred (there is no disclosure to describe). */
|
|
364
364
|
toolDisclosure?: ToolDisclosureManifest;
|
|
365
365
|
};
|
|
366
|
-
/**
|
|
366
|
+
/** This run's provider-declared prompt sections (epoch declaration axis),
|
|
367
367
|
* threaded to every compaction-boundary epoch selection so boundary re-pins hash the same
|
|
368
368
|
* artifact identity as the prepare-time pin. Empty on declaration-free runs. */
|
|
369
369
|
epochDeclaredSections: import("../../prompt-assembly/epoch.js").EpochDeclaredSections;
|
|
@@ -690,7 +690,7 @@ export interface Prepared {
|
|
|
690
690
|
* RB-197: seeded entries are excluded โ their content lives in the system-prompt lane, which
|
|
691
691
|
* compaction never touches, so re-attaching them into the summary would be a duplicate. */
|
|
692
692
|
recentlyReadFiles?: () => string[];
|
|
693
|
-
/** RB-197โก(็ฌ็ซๅคๅฎก +
|
|
693
|
+
/** RB-197โก(็ฌ็ซๅคๅฎก + ๅฝไธญ,ๅทฒไฟฎ) โ canonicalizes a raw (often relative, model-typed) path the
|
|
694
694
|
* SAME way the hands toolkit does (`resolveKey` against the same containment root `readTaskFile`
|
|
695
695
|
* uses), so `maybeCompact`'s kept-tail/instruction-source exclusions compare paths in the SAME
|
|
696
696
|
* coordinate `recentlyReadFiles()` already uses โ without this a plain string match silently never
|
|
@@ -698,7 +698,7 @@ export interface Prepared {
|
|
|
698
698
|
* readTaskFile); absent there is no containment root to resolve against, and every path source is
|
|
699
699
|
* already in the same raw coordinate anyway. */
|
|
700
700
|
normalizeAttachmentPath?: (raw: string) => Promise<string>;
|
|
701
|
-
/** RB-197โก(
|
|
701
|
+
/** RB-197โก(ไบคๅๅคๅฎกๅฝไธญ,ๅทฒไฟฎ) โ recognizes the hands Read tool's own dedup-stub markers
|
|
702
702
|
* ({@link isReadDedupStubResult}), so `maybeCompact`'s kept-tail scan can tell a SUBSTANTIVE Read
|
|
703
703
|
* result from a stub hit whose original full transmission may already be summarized away. Present
|
|
704
704
|
* only with hands (same gate as readTaskFile). */
|
|
@@ -707,7 +707,7 @@ export interface Prepared {
|
|
|
707
707
|
* `MaybeCompactOptions.onApplied` by every compaction lane. Drops the non-seeded read-state entries
|
|
708
708
|
* (the summary just replaced the Read results the dedup stubs point at) and re-registers the files
|
|
709
709
|
* that were re-attached WHOLE. Present only with hands (same gate as readTaskFile).
|
|
710
|
-
* RB-197โก(
|
|
710
|
+
* RB-197โก(ๅฝไธญ,ๅทฒไฟฎ): `preserveReadState` carries the kept-tail-visible files that were
|
|
711
711
|
* deliberately skipped for re-attachment โ their existing entry must survive the clear too (same
|
|
712
712
|
* reasoning as a seeded entry: the model's view of the file did not change). */
|
|
713
713
|
onCompactionApplied?: (attachedComplete: ReadonlyArray<{
|
|
@@ -731,7 +731,7 @@ export interface Prepared {
|
|
|
731
731
|
planModeRef: {
|
|
732
732
|
active: boolean;
|
|
733
733
|
};
|
|
734
|
-
/**
|
|
734
|
+
/** A1 (design/66 anchor revision) โ the date-flip detector seam: `legDate` = the date frozen
|
|
735
735
|
* into this leg's system prefix; `today()` = the boundary-time LOCAL date (user-zone-bound closure).
|
|
736
736
|
* The run loop feeds both to the `date_change` attachment producer; the prefix itself never
|
|
737
737
|
* re-renders mid-leg (cache preservation, CC parity). Present only when the prompt carries a date. */
|
|
@@ -953,7 +953,7 @@ export interface PrepareResume {
|
|
|
953
953
|
/** Digest of that question's batch โ the id alone can repeat, so the pairing is what keeps a LATER
|
|
954
954
|
* question from inheriting the claim that an operator approved it. */
|
|
955
955
|
redeemedContentAskQuestionsHash?: string;
|
|
956
|
-
/**
|
|
956
|
+
/** true iff this resume will EXECUTE an approved pending tool (`tool_approval`
|
|
957
957
|
* checkpoint ร an `allow` winner). The divergent-restore fail-closed guard keys on THIS, not on the
|
|
958
958
|
* batch being non-empty: a deny winner executes nothing, so a workspace-root divergence must not
|
|
959
959
|
* wedge the refusal (it proceeds under the path-state rebase and records the deny). */
|
|
@@ -1089,14 +1089,14 @@ export interface InheritedGate {
|
|
|
1089
1089
|
/**
|
|
1090
1090
|
* The environment this screening face was installed against โ the source of the `HookEnvCapabilities`
|
|
1091
1091
|
* handed to it, compared BY REFERENCE, `undefined` when the installation had no env face. Part of the
|
|
1092
|
-
* installation's identity for the same reason the frozen approver is (
|
|
1092
|
+
* installation's identity for the same reason the frozen approver is (HIGH): a face that
|
|
1093
1093
|
* resolves paths through `ctx.env` answers a different question in a different environment, so an
|
|
1094
1094
|
* ancestor running against the deployment's tree and a descendant running in an isolated worktree are
|
|
1095
1095
|
* two screenings, not one. A deployment with a per-task `executionEnvFactory` therefore has its face
|
|
1096
1096
|
* consulted once per environment on the chain rather than once overall โ which is the point: the
|
|
1097
1097
|
* ancestor's environment is the only place the ancestor's verdict can be reproduced.
|
|
1098
1098
|
*
|
|
1099
|
-
* โ ๏ธ RECORDED BOUNDARY (delegation provenance
|
|
1099
|
+
* โ ๏ธ RECORDED BOUNDARY (delegation provenance): the approver half of the key compares
|
|
1100
1100
|
* through {@link askApproverIdentity}, which by its own contract answers "the same decision-maker",
|
|
1101
1101
|
* collapsing a `withDelegationProvenance` wrapper onto the approver it forwards to. Two installations
|
|
1102
1102
|
* whose approvers differ ONLY in the provenance they attach therefore count as one. Raw reference
|
|
@@ -1270,7 +1270,7 @@ export interface RunInternals {
|
|
|
1270
1270
|
*/
|
|
1271
1271
|
reminderMark?: string;
|
|
1272
1272
|
/**
|
|
1273
|
-
* RB-204 P1
|
|
1273
|
+
* RB-204 P1 โ set UNCONDITIONALLY by every core spawn path (`createSubagentTool`'s
|
|
1274
1274
|
* `childInternals` โ shared by all four spawn legs sync/steer/background/fork, its persisted
|
|
1275
1275
|
* `internalsSnapshot` for revive, and the workflow orchestrator's `spawnAttribution`), regardless
|
|
1276
1276
|
* of whether a NAMEABLE `parentTaskId`/`parentToolCallId` exists. A directly-started workflow (no
|
|
@@ -1310,7 +1310,7 @@ export interface RunInternals {
|
|
|
1310
1310
|
* Why internal (not a public `TaskSpec.goalMode`): the guidance promises "declaring done STOPS iteration and
|
|
1311
1311
|
* surfaces" โ a promise only `runGoal`'s loop makes real. A public field would let a caller inject that
|
|
1312
1312
|
* prompt with no loop behind it (ยง6.3 honesty violation). `runGoal` injects the `declare_done` tool itself;
|
|
1313
|
-
* this flag only governs the PROMPT (
|
|
1313
|
+
* this flag only governs the PROMPT (injection-ownership split).
|
|
1314
1314
|
*/
|
|
1315
1315
|
goalMode?: boolean;
|
|
1316
1316
|
/**
|
|
@@ -1353,7 +1353,7 @@ export interface RunInternals {
|
|
|
1353
1353
|
*/
|
|
1354
1354
|
agentName?: string;
|
|
1355
1355
|
/**
|
|
1356
|
-
* design/147 S3 (
|
|
1356
|
+
* design/147 S3 (label-vs-identity): the EXPLICIT `Agent({name})` spawn identity โ set
|
|
1357
1357
|
* ONLY when the spawn carried a `name` parameter, unlike {@link agentName} (a DISPLAY label:
|
|
1358
1358
|
* description or agent-type, present on nearly every spawn). Teammate semantics (hierarchy clamp,
|
|
1359
1359
|
* teammate addendum, uplink attribution) key on THIS field; keying on the display label made
|
|
@@ -1393,7 +1393,7 @@ export interface RunInternals {
|
|
|
1393
1393
|
* {@link delegationTaskType} above. TRUSTED run-scoped channel (never a TaskSpec field).
|
|
1394
1394
|
*/
|
|
1395
1395
|
cycleSeq?: number;
|
|
1396
|
-
/**
|
|
1396
|
+
/** The ROOT host session of the whole delegation tree (fixed point: the
|
|
1397
1397
|
* spawner passes its own `ctx.rootSessionId ?? ctx.sessionId`, so depth 1 gets the host session
|
|
1398
1398
|
* and every deeper level inherits it verbatim). `parentSessionId` is the IMMEDIATE spawner โ
|
|
1399
1399
|
* after a restart those intermediate sessions are dead ends, and a recovery face enumerating
|
|
@@ -1421,7 +1421,7 @@ export interface RunInternals {
|
|
|
1421
1421
|
* delegation tool resolves this axis TO that principal.
|
|
1422
1422
|
*/
|
|
1423
1423
|
registryScope?: string;
|
|
1424
|
-
/** design/148 S1
|
|
1424
|
+
/** design/148 S1 โ the spawning run's ADOPTED center artifact, threaded down the
|
|
1425
1425
|
* trusted internals chain so every child in the tree composes the SAME closure (a child must
|
|
1426
1426
|
* never spontaneously adopt the live candidate while its parent runs an older pin โ that is the
|
|
1427
1427
|
* exact mixed-version state the epoch exists to prevent). Resolved by-digest through the
|
|
@@ -1482,7 +1482,7 @@ export interface RunInternals {
|
|
|
1482
1482
|
priority?: import("../task-notification.js").SystemInjectionPriority;
|
|
1483
1483
|
}) => void;
|
|
1484
1484
|
/**
|
|
1485
|
-
* design/147 S3a
|
|
1485
|
+
* design/147 S3a โ the PARENT run's subagent-retain ledger, threaded to a CHILD so its
|
|
1486
1486
|
* SendMessage can continue a RETAINED SIBLING (the sibling's retain entry lives on the parent's
|
|
1487
1487
|
* ledger โ without this, sibling resolution succeeds but delivery always reads not-retained).
|
|
1488
1488
|
* TRUSTED chain; read-only use (the sibling leg resumes through the same fenced resume face).
|
|
@@ -1522,7 +1522,7 @@ export interface RunInternals {
|
|
|
1522
1522
|
*/
|
|
1523
1523
|
parentCwd?: string;
|
|
1524
1524
|
/**
|
|
1525
|
-
* [c209-D]
|
|
1525
|
+
* [c209-D] โ the EXPLICIT Agent.cwd request, distinct from the best-effort `parentCwd`
|
|
1526
1526
|
* inheritance hint above: inheritance may be silently ignored by a factory (or absent without one),
|
|
1527
1527
|
* but an explicit cwd the model asked for MUST either take effect or fail loud. prepareTask enforces
|
|
1528
1528
|
* the contract: no `executionEnvFactory` โ throw `config.cwd_unsupported`; after env creation the
|
|
@@ -1558,7 +1558,7 @@ export interface RunInternals {
|
|
|
1558
1558
|
*/
|
|
1559
1559
|
onActivity?: (activity: ToolActivity) => void;
|
|
1560
1560
|
/**
|
|
1561
|
-
* RB-393โ
|
|
1561
|
+
* RB-393โ โ a TRUSTED run-scoped WORKSPACE-observation sink, filled ONLY by a core caller
|
|
1562
1562
|
* (the workflow's `ctx.agent` / `ctx.agentStream`, to record an isolated agent's worktree directory on the
|
|
1563
1563
|
* persisted run record). NEVER a {@link TaskSpec} field โ same posture as {@link onActivity}.
|
|
1564
1564
|
*
|
|
@@ -1566,7 +1566,7 @@ export interface RunInternals {
|
|
|
1566
1566
|
* {@link RunnerDeps.executionEnvFactory} and lands only on the per-task env's `cwd`; no runner-outward face
|
|
1567
1567
|
* (TaskEvent union / TaskStream / TaskResult) carries it back. An orchestrator therefore could not record
|
|
1568
1568
|
* WHERE its isolated agent worked โ the recovery path after an interrupted run had to enumerate the
|
|
1569
|
-
* worktrees directory and guess, which is exactly the contradiction
|
|
1569
|
+
* worktrees directory and guess, which is exactly the contradiction recorded against the
|
|
1570
1570
|
* "isolate-only, userland decides verify/merge" intent.
|
|
1571
1571
|
*
|
|
1572
1572
|
* Called at most ONCE per prepared run with the task's FINAL working root (see {@link ResolvedWorkspace}),
|
|
@@ -22,7 +22,7 @@ import { createSendMessageTool, SEND_MESSAGE_TOOL_NAME } from "../../agents/send
|
|
|
22
22
|
import { SubagentRetainLedger } from "../../agents/retain-ledger.js";
|
|
23
23
|
import { askApproverIdentity, checkToolPolicyProjection, combinePolicies, constraintChainDigest, constraintChainEntryOf, isApprovalSettledBy, isAskDenyResolution, screenApproverAttribution, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, describeThrown, refuseOutOfContractDecision, resolveAsk, toolPolicyNameSets, tryCloneArgs } from "../tool-policy.js";
|
|
24
24
|
const PERSISTED_RULE_TOOL = "Bash";
|
|
25
|
-
import { findAdmittingRule, suggestRulesForCommand } from "../permission-rule-model.js";
|
|
25
|
+
import { findAdmittingRule, segmentCoverageOf, suggestRulesForCommand } from "../permission-rule-model.js";
|
|
26
26
|
import { ActiveSkillScope, createActiveSkillScopePolicy } from "./active-skill-scope.js";
|
|
27
27
|
import { CHANGED_FILES_MTIME_EPS_MS, fenceMcpServerInstructions, renderAgentListingDelta } from "./turn-attachments.js";
|
|
28
28
|
import { inlineUntrusted } from "../untrusted-text.js";
|
|
@@ -35,6 +35,7 @@ import { createWriteProtectionCheck } from "../write-protect.js";
|
|
|
35
35
|
import { orgRuleVerdictFor } from "../permission-rule-org.js";
|
|
36
36
|
import { CacheBreakDetector, toolsToFingerprintInputs } from "../cache-break-detector.js";
|
|
37
37
|
import { reservedCollisions, reservedFor } from "../../brain/request-params.js";
|
|
38
|
+
import { adjudicateDerivedRoute, fallbackToPrimaryNotice, sameRouteIdentity } from "../../brain/route-adjudicator.js";
|
|
38
39
|
import { STALL_CONNECT_MS, STALL_FIRST_TOKEN_MS, STALL_IDLE_MS, withBrainCallGuardrail } from "../../brain/timeout.js";
|
|
39
40
|
import { defineTool, isDefineToolProduct } from "../tools.js";
|
|
40
41
|
import { RETIRED_TOOL_NAMES } from "../tool-name-aliases.js";
|
|
@@ -436,7 +437,9 @@ function orgRevisionEvidenceOf(resolution, onDefect) {
|
|
|
436
437
|
return {};
|
|
437
438
|
}
|
|
438
439
|
function persistedRuleHitOf(admitting) {
|
|
439
|
-
return admitting === undefined
|
|
440
|
+
return admitting === undefined
|
|
441
|
+
? undefined
|
|
442
|
+
: { rules: admitting.map((r) => ({ rule: r.rule, dots: r.adds.map((a) => ({ actor: a.dot.actor, counter: a.dot.counter })) })) };
|
|
440
443
|
}
|
|
441
444
|
function cwdConflictsRestoreError(requestedCwd) {
|
|
442
445
|
const e = new Error(`RunInternals.requestedCwd ("${requestedCwd}") cannot be combined with a checkpoint workspace restore โ ` +
|
|
@@ -472,6 +475,20 @@ async function adoptReminderMark(session, sessionId, seedMark, spawnMark, onErro
|
|
|
472
475
|
}
|
|
473
476
|
return { reminderMark, reminderDisclosureCounts: {} };
|
|
474
477
|
}
|
|
478
|
+
async function derivedRouteFallsBack(args) {
|
|
479
|
+
try {
|
|
480
|
+
if (sameRouteIdentity(args.derived, args.primary))
|
|
481
|
+
return false;
|
|
482
|
+
const verdict = await adjudicateDerivedRoute({ brain: args.brain, model: args.derived, getApiKeyAndHeaders: args.getApiKeyAndHeaders });
|
|
483
|
+
if (verdict === undefined || verdict.ok)
|
|
484
|
+
return false;
|
|
485
|
+
deliverEngineNotice(args.onNotice, fallbackToPrimaryNotice({ seat: args.seat, from: args.derived.id, to: args.primary.id, verdict }));
|
|
486
|
+
return true;
|
|
487
|
+
}
|
|
488
|
+
catch {
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
475
492
|
export async function prepareTask(spec, deps, sessions, resume, internals, runnerSelf) {
|
|
476
493
|
const doors = prepareConfigDoors({ spec, deps, sessions, resume, internals });
|
|
477
494
|
spec = doors.spec;
|
|
@@ -489,7 +506,13 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
489
506
|
const sessionId = acquired.sessionId;
|
|
490
507
|
const hostTaskId = spec.taskId ?? sessionId;
|
|
491
508
|
const delegation = effectiveDelegationFacts(internals, resume?.seed.isDelegatedChild);
|
|
492
|
-
|
|
509
|
+
let effectiveCompModel = compModel;
|
|
510
|
+
if (spec.compactionModel === undefined &&
|
|
511
|
+
compModel !== undefined &&
|
|
512
|
+
(await derivedRouteFallsBack({ seat: "compaction-summary", derived: compModel, primary: model, brain: deps.brain, getApiKeyAndHeaders: spec.getApiKeyAndHeaders, onNotice: deps.onNotice }))) {
|
|
513
|
+
effectiveCompModel = undefined;
|
|
514
|
+
}
|
|
515
|
+
warnCompactionWindowHazard(deps.tracer, spec, model, effectiveCompModel, hostTaskId);
|
|
493
516
|
const taskScope = internals?.registryScope ?? spec.principal ?? "default";
|
|
494
517
|
internals?.peerSelfRef?.addAxis("s", sessionId);
|
|
495
518
|
internals?.peerSelfRef?.addAxis("t", hostTaskId);
|
|
@@ -1073,6 +1096,9 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1073
1096
|
catch {
|
|
1074
1097
|
classifierModel = model;
|
|
1075
1098
|
}
|
|
1099
|
+
if (await derivedRouteFallsBack({ seat: "auto-mode-classifier", derived: classifierModel, primary: model, brain: deps.brain, getApiKeyAndHeaders: spec.getApiKeyAndHeaders, onNotice: deps.onNotice })) {
|
|
1100
|
+
classifierModel = model;
|
|
1101
|
+
}
|
|
1076
1102
|
const classifierSystemPrompt = buildAutoModePrompt(am);
|
|
1077
1103
|
const classifierRuntime = brainToRuntime(deps.brain);
|
|
1078
1104
|
autoModeDecider = createAutoModeDecider({
|
|
@@ -1083,7 +1109,12 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1083
1109
|
const ctx = await session.buildContext();
|
|
1084
1110
|
const known = ctx.messages.filter((m) => m.role === "user" || m.role === "assistant" || m.role === "toolResult");
|
|
1085
1111
|
const userPrompt = renderAutoModeWindow(known, am.window) + renderAutoModeAction(input);
|
|
1086
|
-
const
|
|
1112
|
+
const classifierAuth = await spec.getApiKeyAndHeaders?.(classifierModel);
|
|
1113
|
+
const response = await classifierRuntime.completeSimple(classifierModel, { systemPrompt: classifierSystemPrompt, messages: [{ role: "user", content: userPrompt, timestamp: Date.now() }] }, {
|
|
1114
|
+
signal,
|
|
1115
|
+
...(classifierAuth?.apiKey !== undefined ? { apiKey: classifierAuth.apiKey } : {}),
|
|
1116
|
+
...(classifierAuth?.headers !== undefined ? { headers: classifierAuth.headers } : {}),
|
|
1117
|
+
});
|
|
1087
1118
|
return response.content
|
|
1088
1119
|
.filter((c) => c.type === "text")
|
|
1089
1120
|
.map((c) => c.text)
|
|
@@ -1412,7 +1443,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1412
1443
|
owner: hostTaskId,
|
|
1413
1444
|
scope: taskScope,
|
|
1414
1445
|
...(sessionId !== undefined ? { sessionId } : {}),
|
|
1415
|
-
...(internals?.onTaskNotification !== undefined ? { notify: internals.onTaskNotification } : {}),
|
|
1446
|
+
...(internals?.onTaskNotification !== undefined ? { notify: internals.onTaskNotification } : {}), ...(spec.oneShot !== undefined ? { oneShot: spec.oneShot } : {}),
|
|
1416
1447
|
...(internals?.onSubagentSpawn !== undefined ? { sink: internals.onSubagentSpawn } : {}),
|
|
1417
1448
|
...(internals?.parentNotify !== undefined
|
|
1418
1449
|
? { uplink: internals.parentNotify, ...(internals.parentPeerRef !== undefined ? { uplinkRecipient: internals.parentPeerRef } : {}) }
|
|
@@ -2990,7 +3021,11 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2990
3021
|
}));
|
|
2991
3022
|
return { unreadable: true };
|
|
2992
3023
|
}
|
|
2993
|
-
|
|
3024
|
+
const admitting = findAdmittingRule(listed.rules, { tool: req.toolName, command, cwd: root });
|
|
3025
|
+
if (admitting !== undefined)
|
|
3026
|
+
return persistedRuleHitOf(admitting);
|
|
3027
|
+
const coverage = segmentCoverageOf(command, { persisted: listed.rules }, { tool: req.toolName, cwd: root });
|
|
3028
|
+
return coverage !== undefined ? { segmentCoverage: coverage } : undefined;
|
|
2994
3029
|
},
|
|
2995
3030
|
};
|
|
2996
3031
|
})();
|
|
@@ -3020,7 +3055,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3020
3055
|
},
|
|
3021
3056
|
};
|
|
3022
3057
|
})();
|
|
3023
|
-
const
|
|
3058
|
+
const ruleOffersOf = (toolName, args, ask) => {
|
|
3024
3059
|
if (permissionRuleLane === undefined || toolName !== PERSISTED_RULE_TOOL)
|
|
3025
3060
|
return {};
|
|
3026
3061
|
if ((spec.principal === undefined || spec.principal === "") && deps.localOwnerRules !== true)
|
|
@@ -3042,8 +3077,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3042
3077
|
const command = args?.command;
|
|
3043
3078
|
if (typeof command !== "string")
|
|
3044
3079
|
return {};
|
|
3045
|
-
const
|
|
3046
|
-
return
|
|
3080
|
+
const offers = suggestRulesForCommand(command, ask?.segmentCoverage !== undefined ? { coverage: ask.segmentCoverage } : undefined);
|
|
3081
|
+
return offers.length > 0 ? { ruleOffers: offers } : {};
|
|
3047
3082
|
};
|
|
3048
3083
|
const frozenClassifierExcluded = (d) => d.decisionReason === "hook" || d.matchedAskRule !== undefined;
|
|
3049
3084
|
const recheckApprovedEdit = async (pol, onAskOf, creq, edit, csignal, ancestorDecider) => {
|
|
@@ -3092,7 +3127,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3092
3127
|
toolName: creq.toolName,
|
|
3093
3128
|
toolCallId: creq.toolCallId,
|
|
3094
3129
|
args: editArgs,
|
|
3095
|
-
...
|
|
3130
|
+
...ruleOffersOf(creq.toolName, editArgs, { ...(re ?? {}), ancestorResolved: true }),
|
|
3096
3131
|
message: re.message ?? `approval required for "${creq.toolName}" (inherited parent policy)`,
|
|
3097
3132
|
...askSourceIdentity(),
|
|
3098
3133
|
...riskAxesOf(creq.toolName),
|
|
@@ -3178,7 +3213,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3178
3213
|
toolName: creq.toolName,
|
|
3179
3214
|
toolCallId: creq.toolCallId,
|
|
3180
3215
|
args: presentedArgs,
|
|
3181
|
-
...
|
|
3216
|
+
...ruleOffersOf(creq.toolName, presentedArgs, { ...(first.action === "ask" ? first : {}), ancestorResolved: true }),
|
|
3182
3217
|
message: first.message ?? `approval required for "${creq.toolName}" (inherited parent policy)`,
|
|
3183
3218
|
...askSourceIdentity(),
|
|
3184
3219
|
...riskAxesOf(creq.toolName),
|
|
@@ -3266,7 +3301,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3266
3301
|
toolName: creq.toolName,
|
|
3267
3302
|
toolCallId: creq.toolCallId,
|
|
3268
3303
|
args: presentedArgs,
|
|
3269
|
-
...
|
|
3304
|
+
...ruleOffersOf(creq.toolName, presentedArgs, { ...(decision.action === "ask" ? decision : {}), ancestorResolved: true }),
|
|
3270
3305
|
message: decision.message ?? `approval required for "${creq.toolName}" (inherited parent policy)`,
|
|
3271
3306
|
...askSourceIdentity(),
|
|
3272
3307
|
...riskAxesOf(creq.toolName),
|
|
@@ -3558,7 +3593,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3558
3593
|
const preview = approvalPreviewOf(req.toolName, req.args);
|
|
3559
3594
|
return preview !== undefined ? { preview } : {};
|
|
3560
3595
|
})(),
|
|
3561
|
-
...
|
|
3596
|
+
...ruleOffersOf(req.toolName, req.args, decision.action === "ask" ? decision : undefined),
|
|
3562
3597
|
message: decision.message ?? `approval required for "${req.toolName}"`,
|
|
3563
3598
|
...askSourceIdentity(),
|
|
3564
3599
|
...riskAxesOf(req.toolName),
|
|
@@ -4035,7 +4070,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4035
4070
|
}
|
|
4036
4071
|
};
|
|
4037
4072
|
const suspendAsk = parkLaneArmed && checkpointStore !== undefined
|
|
4038
|
-
? async (req, postHookArgs, safety, liveFaceUnavailable, realApproval, shadowedRule, askDecisionReason, probeReason, probeCause) => {
|
|
4073
|
+
? async (req, postHookArgs, safety, liveFaceUnavailable, realApproval, shadowedRule, askDecisionReason, probeReason, probeCause, segmentCoverage) => {
|
|
4039
4074
|
const syncFirstEligible = req.toolName === ASK_USER_QUESTION_TOOL_NAME ? contentAskRoutable(req.toolCallId) : isLiveApproverSeat(onAsk);
|
|
4040
4075
|
if (syncFirstEligible &&
|
|
4041
4076
|
runtimeCaps?.forceDurableGate !== true &&
|
|
@@ -4196,11 +4231,12 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4196
4231
|
const preview = approvalPreviewOf(req.toolName, parkedArgs);
|
|
4197
4232
|
return preview !== undefined ? { preview } : {};
|
|
4198
4233
|
})(),
|
|
4199
|
-
...
|
|
4234
|
+
...ruleOffersOf(req.toolName, parkedArgs, {
|
|
4200
4235
|
...(realApproval !== undefined ? { requiresRealApproval: true } : {}),
|
|
4201
4236
|
...(shadowedRule !== undefined ? { persistedRuleShadowed: shadowedRule } : {}),
|
|
4202
4237
|
...(askDecisionReason !== undefined ? { decisionReason: askDecisionReason } : {}),
|
|
4203
4238
|
...(inheritedUnavailableAsks.has(req.toolCallId) ? { inheritedUnresolved: true } : {}),
|
|
4239
|
+
...(segmentCoverage !== undefined ? { segmentCoverage } : {}),
|
|
4204
4240
|
}),
|
|
4205
4241
|
boundInputHash: boundInputHashOf(parkedArgs),
|
|
4206
4242
|
batchToolCallIds,
|
|
@@ -4326,11 +4362,11 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4326
4362
|
admits: permissionRuleLane.admits,
|
|
4327
4363
|
onResolved: (info) => emitTrace(deps.tracer, () => ({
|
|
4328
4364
|
kind: "permission.persisted_rule_allowed",
|
|
4329
|
-
version:
|
|
4365
|
+
version: 2,
|
|
4330
4366
|
taskId: spec.taskId ?? sessionId,
|
|
4331
4367
|
toolName: info.toolName,
|
|
4332
4368
|
toolCallId: info.toolCallId,
|
|
4333
|
-
|
|
4369
|
+
rules: [...info.rules],
|
|
4334
4370
|
ts: Date.now(),
|
|
4335
4371
|
})),
|
|
4336
4372
|
},
|
|
@@ -4733,7 +4769,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4733
4769
|
const effectiveReadFaceObserved = carrierReadFace();
|
|
4734
4770
|
const effectiveReadDenyObserved = readDenyAdditionsNormalized.length > 0 ? readDenyAdditionsNormalized.map((e) => ({ ...e })) : undefined;
|
|
4735
4771
|
const preparedHolder = {};
|
|
4736
|
-
const buildPrepared = () => ({ harness, session, sessionId, reminderMark, reminderDisclosureCounts, taskRootPath: taskRootFinal, model, thinking, compModel, mcp: mcp, ...(a2a !== undefined && a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, approvalSettlement, batchHaltRef, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), ...(effectiveReadFaceObserved !== undefined ? { effectiveReadFace: effectiveReadFaceObserved } : {}), ...(effectiveReadDenyObserved !== undefined ? { effectiveReadDenyPatterns: effectiveReadDenyObserved } : {}), effectiveMemoryScopes: memoryEffectiveScopes, cwdRef: handsCwdRef, ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), denyNarrowingPolicy, ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), ...(permissionRuleOrgLane !== undefined ? { permissionRuleOrg: permissionRuleOrgLane } : {}), releaseSignal, settleContentAskBindings, cacheBreakDetector, cacheFingerprint, wiringManifest, promptManifest, epochDeclaredSections, activeTools, ...(deferred.size > 0 ? { deferredToolNames: deferred } : {}), toolMaterializeStatic, deferDirectCall, ...(staticFaceForRef.current !== undefined ? { staticFaceFor: staticFaceForRef.current } : {}), ownedEnv, suspendRef, suspendProgressRef, reviewRef, remoteEnvFailures, reviewRequestRef, suspendLoopRef, suspendForResource, ...(suspendForPlatformLimit !== undefined ? { suspendForPlatformLimit } : {}), ...(envLifetimeSuspendAt !== undefined ? { envLifetimeSuspendAt } : {}), ...(usageGovernance !== undefined ? { usageGovernance } : {}), callIssuedAtRef, brainCallGuardrailRef, suspendForReview, resourceLedger: priorLedger, liveSpendRef, humanReviewRef, now, tools, toolEffects, wakeRecovered, promptOverheadTokens, lastBrainContext, readTaskFile, recentlyReadFiles, normalizeAttachmentPath, isDedupStubResult, ...(onCompactionApplied ? { onCompactionApplied } : {}), compactionReuseRef, trimPressureRef, ...(memoryEngineSession ? { memoryEngineSession } : {}), ...(subagentRetain ? { subagentRetain } : {}), ...(lspDiagnostics && nudgeLspOnEdit ? { lspDiagnostics: { registry: lspDiagnostics, nudge: nudgeLspOnEdit, runIdent: lspRunIdent } } : {}), planModeRef, ...(dateChange ? { dateChange } : {}), ...(instructionSources ? { instructionSources } : {}), ...(workflowSizeGuideline ? { workflowSizeGuideline } : {}), ...(detectExternalChanges ? { detectExternalChanges } : {}), ...(toolsDeltaRef ? { toolsDeltaRef } : {}), ...(agentListing ? { agentListing } : {}), ...(skillsListing ? { skillsListing } : {}), announcedListingsRef, gitStatusRef, listBackgroundTasks, hookIdentity, hookTimeoutMs, ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}) });
|
|
4772
|
+
const buildPrepared = () => ({ harness, session, sessionId, reminderMark, reminderDisclosureCounts, taskRootPath: taskRootFinal, model, thinking, compModel: effectiveCompModel, mcp: mcp, ...(a2a !== undefined && a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, approvalSettlement, batchHaltRef, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), ...(effectiveReadFaceObserved !== undefined ? { effectiveReadFace: effectiveReadFaceObserved } : {}), ...(effectiveReadDenyObserved !== undefined ? { effectiveReadDenyPatterns: effectiveReadDenyObserved } : {}), effectiveMemoryScopes: memoryEffectiveScopes, cwdRef: handsCwdRef, ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), denyNarrowingPolicy, ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), ...(permissionRuleOrgLane !== undefined ? { permissionRuleOrg: permissionRuleOrgLane } : {}), releaseSignal, settleContentAskBindings, cacheBreakDetector, cacheFingerprint, wiringManifest, promptManifest, epochDeclaredSections, activeTools, ...(deferred.size > 0 ? { deferredToolNames: deferred } : {}), toolMaterializeStatic, deferDirectCall, ...(staticFaceForRef.current !== undefined ? { staticFaceFor: staticFaceForRef.current } : {}), ownedEnv, suspendRef, suspendProgressRef, reviewRef, remoteEnvFailures, reviewRequestRef, suspendLoopRef, suspendForResource, ...(suspendForPlatformLimit !== undefined ? { suspendForPlatformLimit } : {}), ...(envLifetimeSuspendAt !== undefined ? { envLifetimeSuspendAt } : {}), ...(usageGovernance !== undefined ? { usageGovernance } : {}), callIssuedAtRef, brainCallGuardrailRef, suspendForReview, resourceLedger: priorLedger, liveSpendRef, humanReviewRef, now, tools, toolEffects, wakeRecovered, promptOverheadTokens, lastBrainContext, readTaskFile, recentlyReadFiles, normalizeAttachmentPath, isDedupStubResult, ...(onCompactionApplied ? { onCompactionApplied } : {}), compactionReuseRef, trimPressureRef, ...(memoryEngineSession ? { memoryEngineSession } : {}), ...(subagentRetain ? { subagentRetain } : {}), ...(lspDiagnostics && nudgeLspOnEdit ? { lspDiagnostics: { registry: lspDiagnostics, nudge: nudgeLspOnEdit, runIdent: lspRunIdent } } : {}), planModeRef, ...(dateChange ? { dateChange } : {}), ...(instructionSources ? { instructionSources } : {}), ...(workflowSizeGuideline ? { workflowSizeGuideline } : {}), ...(detectExternalChanges ? { detectExternalChanges } : {}), ...(toolsDeltaRef ? { toolsDeltaRef } : {}), ...(agentListing ? { agentListing } : {}), ...(skillsListing ? { skillsListing } : {}), announcedListingsRef, gitStatusRef, listBackgroundTasks, hookIdentity, hookTimeoutMs, ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}) });
|
|
4737
4773
|
const prepared = buildPrepared();
|
|
4738
4774
|
preparedHolder.current = prepared;
|
|
4739
4775
|
return prepared;
|
|
@@ -3,7 +3,7 @@ import type { ExecutionEnv } from "../../internal/harness.js";
|
|
|
3
3
|
import type { RemoteEnvFailureNote, RunnerDeps, TaskSpec } from "../types.js";
|
|
4
4
|
import type { PrepareResume, RunInternals } from "./prepare-task.js";
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* rebase one checkpointed absolute path from the OLD workspace root onto the RESTORED
|
|
7
7
|
* one (divergent `resumeVM`). POSIX-ONLY by contract: every remote lane's `mountPath` is a container
|
|
8
8
|
* path (e2b/k8s/ssh/adb/local-docker are all Linux targets), so a backslash ANYWHERE in the inputs marks
|
|
9
9
|
* the value outside this function's domain and it returns `p` UNCHANGED โ an un-rebased path is honestly
|
|
@@ -71,7 +71,7 @@ export interface PrepareWorkspaceRestoreInput {
|
|
|
71
71
|
internals: Pick<RunInternals, "onWorkspaceResolved" | "isolation"> | undefined;
|
|
72
72
|
/** borrowed-readonly โ the durable-resume seats this phase reads: the checkpointed
|
|
73
73
|
* `workspaceHandle` (restore target) and `executesApprovedAction` (the divergence fail-closed
|
|
74
|
-
* key
|
|
74
|
+
* key). Absent for a fresh/non-durable run: the phase is then root-passthrough. */
|
|
75
75
|
resume: Pick<PrepareResume, "workspaceHandle" | "executesApprovedAction"> | undefined;
|
|
76
76
|
/** owned (value) โ the pre-restore task root (isolation-aware initial derivation, computed in the
|
|
77
77
|
* driver). Dead after this call by design (R-5): later phases read the returned
|
|
@@ -145,17 +145,17 @@ export declare class Runner {
|
|
|
145
145
|
readonly sessions: SessionStore;
|
|
146
146
|
/** Per-sessionId serialization so two tasks never mutate one session concurrently. */
|
|
147
147
|
private sessionLocks;
|
|
148
|
-
/**
|
|
148
|
+
/** (a) โ roots whose rewind-files snapshot hit `too_large`, with the refusal time.
|
|
149
149
|
* A 20G workspace otherwise pays a full bounded tree-walk (stat tens of thousands of files) EVERY
|
|
150
150
|
* task just to re-discover the same refusal; once too_large, skip further snapshots for that root
|
|
151
151
|
* (announced once via onError). E19 semantics unchanged โ rewind for that root was already
|
|
152
|
-
* impossible.
|
|
152
|
+
* impossible. TTL'd (30min), not permanent โ a long-lived Runner over a tree the
|
|
153
153
|
* user later SHRINKS re-probes instead of being locked out until restart.
|
|
154
154
|
* RB-430-b: `skipAnnounced` makes the SKIP itself observable โ one announcement per cooldown window,
|
|
155
155
|
* so an operator can tell "this turn produced no snapshot" from "snapshots are working", without the
|
|
156
156
|
* per-turn log spam the latch exists to prevent. Cleared with the entry when the window elapses. */
|
|
157
157
|
private snapshotTooLargeRoots;
|
|
158
|
-
/**
|
|
158
|
+
/** task notifications born BETWEEN turns (run torn down / harness already idle), parked
|
|
159
159
|
* per session and drained into the session's next run at its first boundary. Runner-lived (outlives any
|
|
160
160
|
* single run, like the registry handles that produce into it); bounded + drop-disclosing, see
|
|
161
161
|
* {@link PendingSessionNotifications}. Not checkpointed โ the producing handles are process-local. */
|
|
@@ -189,7 +189,7 @@ export declare class Runner {
|
|
|
189
189
|
builtinAgents?: boolean;
|
|
190
190
|
models?: Record<string, Model>;
|
|
191
191
|
};
|
|
192
|
-
/** design/125 (
|
|
192
|
+
/** design/125 (ๅฎ็ฐๅฎก B1) โ the deployment-level gating baseline, exposed READ-ONLY so thin
|
|
193
193
|
* assemblers over the Runner (`runSpec`) can COMPOSE with it. The task-level engine semantic is a
|
|
194
194
|
* WHOLE-SLOT override (`spec.toolPolicy ?? deps.toolPolicy`, same for hooks โ prepare-task), so any
|
|
195
195
|
* assembler that sets `spec.toolPolicy`/`spec.hooks` without folding these in silently shadows the
|
|
@@ -219,13 +219,16 @@ export declare class Runner {
|
|
|
219
219
|
* - `tiers` omitted โ the current tier bindings are kept (and re-applied over the new models);
|
|
220
220
|
* explicitly passed (including `undefined`) โ replaced.
|
|
221
221
|
* - Success is announced via `config.models_swapped` (models/tiers counts โ key material only,
|
|
222
|
-
* never the catalog itself).
|
|
222
|
+
* never the catalog itself). A swap may additionally emit the advisory
|
|
223
|
+
* `route.base_url_changed_key_unchanged` notice (deliberately conservative โ see its entry in
|
|
224
|
+
* the notice directory) for same-name entries whose URL moved while the Model-visible
|
|
225
|
+
* credential fingerprint did not.
|
|
223
226
|
*/
|
|
224
227
|
swapModels(next: {
|
|
225
228
|
models: Record<string, Model>;
|
|
226
229
|
tiers?: Record<string, ModelRef>;
|
|
227
230
|
}): void;
|
|
228
|
-
/**
|
|
231
|
+
/** one-shot brain-routed utility query (see {@link runSideQuery} for the full contract):
|
|
229
232
|
* preserves system/multi-turn messages/tool DEFINITIONS, routes through the deployment's brain with
|
|
230
233
|
* the same model resolution as tasks, returns real usage/model. No session, no tool execution, no
|
|
231
234
|
* policy gate, no accounting โ caller-trusted. */
|
|
@@ -249,7 +252,7 @@ export declare class Runner {
|
|
|
249
252
|
/**
|
|
250
253
|
* design/101 ยงE19 โ capture a working-tree snapshot of the just-finished turn, keyed by the leaf
|
|
251
254
|
* `SessionTreeEntry.id`. Best-effort + never throws (errors route to `onError(phase:"rewind")`). Runs against
|
|
252
|
-
* ANY ExecutionEnv (local or remote) when a `fileSnapshotStore` is wired (GATE-SPLIT
|
|
255
|
+
* ANY ExecutionEnv (local or remote) when a `fileSnapshotStore` is wired (GATE-SPLIT) โ the
|
|
253
256
|
* snapshot is portable (env FileSystem ops). A deployment wanting VM-snapshot instead wires a VM-backed store.
|
|
254
257
|
*/
|
|
255
258
|
private snapshotTurn;
|
|
@@ -273,7 +276,7 @@ export declare class Runner {
|
|
|
273
276
|
* v1 serves only the `human`/`policy_ask` gate (F4). A `task_done` checkpoint (1C Path A) is not
|
|
274
277
|
* resumable here โ the caller orchestrates that one and reads its handle directly.
|
|
275
278
|
*
|
|
276
|
-
* **๐ Authorization boundary (design/80 D-2
|
|
279
|
+
* **๐ Authorization boundary (design/80 D-2 invariant #1) โ token-as-auth, scope is store-level
|
|
277
280
|
* isolation, NOT caller authorization.** `resume` is TOKEN-AS-AUTH: whoever presents a valid, still-`pending`
|
|
278
281
|
* checkpoint token resolves it. The scope passed to the store CAS is the checkpoint's OWN `cp.scope` (read
|
|
279
282
|
* off the row), so the store's scope-WHERE is store-level multi-tenant DATA isolation (one tenant's reaper /
|
|
@@ -315,13 +318,13 @@ export declare class Runner {
|
|
|
315
318
|
* trigger to execute the pending action โ a lost CAS rejects, never returns a re-running stream).
|
|
316
319
|
*
|
|
317
320
|
* **Eager (like {@link runTaskStream}):** once this resolves, the resumed run is already executing โ the
|
|
318
|
-
* pending action runs exactly once and the run-loop tail's `teardownOwnedEnv`
|
|
321
|
+
* pending action runs exactly once and the run-loop tail's `teardownOwnedEnv` tears down the
|
|
319
322
|
* rebuilt remote env even if you never iterate the stream. So abandoning the returned stream is safe (no leak,
|
|
320
323
|
* no hang); it only means you
|
|
321
324
|
* don't observe the resumed segment's events.
|
|
322
325
|
*/
|
|
323
326
|
resumeStream(token: CheckpointToken, outcome: ResumeOutcome, taskConfig: ResumeTaskConfig,
|
|
324
|
-
/**
|
|
327
|
+
/** the TRUSTED run-internals seam, symmetric with {@link runTaskStream} โ a resume leg
|
|
325
328
|
* otherwise has no `onForwardEvent`ๅธญไฝ, so a subagent's task_progress ticks (child-isolated stream,
|
|
326
329
|
* only exit = the forward sink) were unreachable on resume. Deployment-owned, never a TaskSpec field.
|
|
327
330
|
* Parent effective-policy inheritance CONTRACT: a checkpoint whose `state.inheritedGate.
|
|
@@ -394,7 +397,7 @@ export declare class Runner {
|
|
|
394
397
|
private recordCompactionReuse;
|
|
395
398
|
private finish;
|
|
396
399
|
/**
|
|
397
|
-
* design/48 remote seam
|
|
400
|
+
* design/48 remote seam +: tear down a per-task env minted by `executionEnvFactory` (e.g. a
|
|
398
401
|
* remote container, or a `withWorktreeIsolation` worktree) โ this task owned its lifetime. Best-effort, like
|
|
399
402
|
* `mcp.dispose`: a `destroy()` failure must not break the run. Only `ownedEnv` (factory-produced) is destroyed;
|
|
400
403
|
* a caller-owned static `deps.executionEnv` outlives the task and is left untouched. The service control plane's
|
|
@@ -402,7 +405,7 @@ export declare class Runner {
|
|
|
402
405
|
*
|
|
403
406
|
* Runs from the run-loop tail AFTER every env-reader (finish()'s compaction `attachWorkingFiles` +
|
|
404
407
|
* `snapshotTurn`'s rewind-files capture), so the working tree is still readable when they run. This ORDER is the
|
|
405
|
-
* fix for
|
|
408
|
+
* fix for a teardown-order defect: the old in-`finish` destroy ran BEFORE `snapshotTurn`, so a factory-minted
|
|
406
409
|
* remote/worktree lane snapshotted an already-destroyed env (plain host/static lanes were false-green).
|
|
407
410
|
*
|
|
408
411
|
* design/49 v1.5 / design/76 ยง2.5: a SUSPENDED (`suspendRef.token`) or `needs_review` (`reviewRef.token`) pause
|
|
@@ -20,6 +20,7 @@ import { emitTaskOutcome } from "../task-outcome.js";
|
|
|
20
20
|
import { isDegenerateCutMessage } from "../../brain/terminal-cause.js";
|
|
21
21
|
import { primaryActivityArg } from "../arg-summary.js";
|
|
22
22
|
import { resolveReasoning } from "../../brain/reasoning.js";
|
|
23
|
+
import { adjudicateDerivedRoute, authCarrierFingerprint, fallbackToPrimaryNotice, normalizeBaseUrl, sameRouteIdentity } from "../../brain/route-adjudicator.js";
|
|
23
24
|
import { readDegradation } from "../../brain/degrading.js";
|
|
24
25
|
import { runWithBrainTelemetry, runWithReasoningWireFacts, runWithStatusSink } from "../../brain/status-sink.js";
|
|
25
26
|
import { expandTiers, resolveModel, resolveTaskModel } from "../roles.js";
|
|
@@ -1511,6 +1512,22 @@ export class Runner {
|
|
|
1511
1512
|
...(h.timeoutMs !== undefined ? { timeoutMs: h.timeoutMs } : {}),
|
|
1512
1513
|
}
|
|
1513
1514
|
: undefined;
|
|
1515
|
+
const MIRRORED_HOOK_KEYS = [
|
|
1516
|
+
"preToolUse",
|
|
1517
|
+
"preToolUseObservational",
|
|
1518
|
+
"postToolUse",
|
|
1519
|
+
"userPromptSubmit",
|
|
1520
|
+
"stop",
|
|
1521
|
+
"postToolUseFailure",
|
|
1522
|
+
"postToolBatch",
|
|
1523
|
+
"preCompact",
|
|
1524
|
+
"postCompact",
|
|
1525
|
+
"stopFailure",
|
|
1526
|
+
"permissionDenied",
|
|
1527
|
+
"timeoutMs",
|
|
1528
|
+
];
|
|
1529
|
+
const _mirrorIsComplete = true;
|
|
1530
|
+
void _mirrorIsComplete;
|
|
1514
1531
|
return {
|
|
1515
1532
|
...(deps.toolPolicy !== undefined
|
|
1516
1533
|
? {
|
|
@@ -1552,6 +1569,17 @@ export class Runner {
|
|
|
1552
1569
|
}
|
|
1553
1570
|
const tiers = Object.hasOwn(next, "tiers") ? next.tiers : this.deps.tiers;
|
|
1554
1571
|
const expanded = tiers && Object.keys(tiers).length > 0 ? expandTiers({ ...next.models }, tiers) : { ...next.models };
|
|
1572
|
+
const movedEntries = [];
|
|
1573
|
+
for (const [name, nextModel] of Object.entries(expanded ?? {})) {
|
|
1574
|
+
const prior = this.deps.models?.[name];
|
|
1575
|
+
if (!prior)
|
|
1576
|
+
continue;
|
|
1577
|
+
const from = normalizeBaseUrl(prior.baseUrl);
|
|
1578
|
+
const to = normalizeBaseUrl(nextModel.baseUrl);
|
|
1579
|
+
if (from !== to && authCarrierFingerprint(prior.headers) === authCarrierFingerprint(nextModel.headers)) {
|
|
1580
|
+
movedEntries.push({ modelId: name, from, to });
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1555
1583
|
this.deps = { ...this.deps, models: expanded, ...(tiers !== undefined ? { tiers } : {}) };
|
|
1556
1584
|
if (tiers === undefined)
|
|
1557
1585
|
delete this.deps.tiers;
|
|
@@ -1560,6 +1588,18 @@ export class Runner {
|
|
|
1560
1588
|
message: `model catalog swapped: ${Object.keys(next.models).length} model(s), ${tiers ? Object.keys(tiers).length : 0} tier binding(s); in-flight tasks finish on their resolved models, new tasks resolve against the new catalog`,
|
|
1561
1589
|
detail: { models: Object.keys(next.models).length, tiers: tiers ? Object.keys(tiers).length : 0 },
|
|
1562
1590
|
});
|
|
1591
|
+
if (movedEntries.length > 0) {
|
|
1592
|
+
const RENDER_CAP = 8;
|
|
1593
|
+
const rendered = movedEntries.slice(0, RENDER_CAP);
|
|
1594
|
+
deliverEngineNotice(this.deps.onNotice, {
|
|
1595
|
+
code: "route.base_url_changed_key_unchanged",
|
|
1596
|
+
message: `model catalog swap moved ${movedEntries.length} entry/entries to a new baseUrl while the Model-visible credential half stayed unchanged: ` +
|
|
1597
|
+
rendered.map((e) => `"${e.modelId}" ${e.from || "(config root)"} โ ${e.to || "(config root)"}`).join("; ") +
|
|
1598
|
+
(movedEntries.length > rendered.length ? `; +${movedEntries.length - rendered.length} more` : "") +
|
|
1599
|
+
" โ if the provider changed (not just its domain), update the credential reference in the same step",
|
|
1600
|
+
detail: { entries: rendered, total: movedEntries.length },
|
|
1601
|
+
});
|
|
1602
|
+
}
|
|
1563
1603
|
}
|
|
1564
1604
|
sideQuery(spec) {
|
|
1565
1605
|
return runWithReasoningWireFacts(() => { }, () => runSideQuery(spec, { brain: this.deps.brain, models: this.deps.models, roles: this.deps.roles }));
|
|
@@ -3890,6 +3930,14 @@ export class Runner {
|
|
|
3890
3930
|
}
|
|
3891
3931
|
catch {
|
|
3892
3932
|
}
|
|
3933
|
+
if (!sameRouteIdentity(model, prepared.model)) {
|
|
3934
|
+
const verdict = await adjudicateDerivedRoute({ brain: this.deps.brain, model, getApiKeyAndHeaders: spec.getApiKeyAndHeaders });
|
|
3935
|
+
if (verdict !== undefined && !verdict.ok) {
|
|
3936
|
+
deliverEngineNotice(this.deps.onNotice, fallbackToPrimaryNotice({ seat: "prompt-suggestions", from: model.id, to: prepared.model.id, verdict }));
|
|
3937
|
+
model = prepared.model;
|
|
3938
|
+
thinking = prepared.thinking;
|
|
3939
|
+
}
|
|
3940
|
+
}
|
|
3893
3941
|
const pricing = this.deps.pricing?.[model.id] ?? modelCostToPricing(model.cost);
|
|
3894
3942
|
const ctx = await prepared.session.buildContext();
|
|
3895
3943
|
const transcript = ctx.messages.slice(-SUGGESTIONS_TRANSCRIPT_MESSAGES);
|
|
@@ -15,7 +15,7 @@ import type { SessionPermissionRules } from "../session-policy-store.js";
|
|
|
15
15
|
* skill face is a separate capability decision with its own review). */
|
|
16
16
|
export declare const PATH_WRITE_TOOLS: ReadonlySet<string>;
|
|
17
17
|
/** The FULL path-confinable write-tool set: {@link PATH_WRITE_TOOLS} plus `NotebookEdit`, whose write
|
|
18
|
-
* target is `notebook_path` and is extracted by the shared tool-aware {@link writeTargetPath} (
|
|
18
|
+
* target is `notebook_path` and is extracted by the shared tool-aware {@link writeTargetPath} (
|
|
19
19
|
* notebook_path outranks a decoy `file_path` for that tool).
|
|
20
20
|
*
|
|
21
21
|
* REF-B3 โ the ONE spelling of "tools this codebase can confine by path". Consumers:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* RB-470 (
|
|
2
|
+
* RB-470 (the D4 never-settle class) โ bounded await for BEST-EFFORT teardown /
|
|
3
3
|
* cleanup legs on a run's settle path.
|
|
4
4
|
*
|
|
5
5
|
* The defect class: `resume()`/`runTask` settle only when the run body returns, and the body's tail
|