@sema-agent/core 7.52.0 → 7.54.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 +470 -0
- package/LICENSE +3 -1
- package/README.md +3 -1
- package/dist/agents/cross-session-envelope.d.ts +8 -0
- package/dist/agents/cross-session-envelope.js +6 -0
- package/dist/agents/cross-session-judge.d.ts +21 -1
- package/dist/agents/cross-session-judge.js +8 -0
- package/dist/agents/cross-session-ref.d.ts +5 -0
- package/dist/agents/cross-session-ref.js +1 -0
- package/dist/agents/org-delivery-gate.d.ts +122 -0
- package/dist/agents/org-delivery-gate.js +69 -0
- package/dist/agents/peer-held-queue.d.ts +9 -4
- package/dist/agents/peer-held-queue.js +6 -5
- package/dist/agents/peer-session-drain.d.ts +35 -6
- package/dist/agents/peer-session-drain.js +271 -182
- package/dist/agents/read-inbox-tool.d.ts +7 -0
- package/dist/agents/read-inbox-tool.js +5 -1
- package/dist/agents/send-message-tool.js +3 -4
- package/dist/agents/subagent.d.ts +6 -5
- package/dist/agents/subagent.js +117 -83
- package/dist/agents/tool-filter.d.ts +25 -4
- package/dist/agents/tool-filter.js +13 -3
- package/dist/brain/anthropic.d.ts +6 -1
- package/dist/brain/anthropic.js +4 -4
- package/dist/brain/model-presets.js +2 -1
- package/dist/brain/route-adjudicator.d.ts +6 -0
- package/dist/brain/routing.d.ts +24 -1
- package/dist/brain/routing.js +54 -19
- package/dist/brain/timeout.js +5 -4
- package/dist/core/a2a.d.ts +5 -2
- package/dist/core/a2a.js +33 -14
- package/dist/core/allow-entry.d.ts +3 -1
- package/dist/core/allow-entry.js +3 -2
- package/dist/core/approval-object.d.ts +87 -0
- package/dist/core/approval-object.js +85 -0
- package/dist/core/arg-summary.d.ts +3 -2
- package/dist/core/arg-summary.js +17 -11
- package/dist/core/ask-origin.d.ts +43 -27
- package/dist/core/ask-origin.js +20 -11
- package/dist/core/ask-question.d.ts +0 -1
- package/dist/core/ask-question.js +4 -67
- package/dist/core/ask-unresolvable-notice.d.ts +3 -2
- package/dist/core/auto-compaction.d.ts +106 -50
- package/dist/core/auto-compaction.js +69 -53
- package/dist/core/auto-mode-prompt.d.ts +4 -2
- package/dist/core/auto-mode-prompt.js +4 -3
- package/dist/core/canonical-json.d.ts +69 -0
- package/dist/core/canonical-json.js +130 -8
- package/dist/core/checkpoint-requirements.d.ts +13 -7
- package/dist/core/checkpoint-requirements.js +4 -1
- package/dist/core/checkpoint-store.d.ts +60 -36
- package/dist/core/checkpoint-store.js +7 -6
- package/dist/core/child-clamp-seats.d.ts +45 -6
- package/dist/core/child-clamp-seats.js +56 -4
- package/dist/core/compliance.js +3 -1
- package/dist/core/consolidate-scope.d.ts +1 -1
- package/dist/core/cross-boundary-taint.d.ts +213 -0
- package/dist/core/cross-boundary-taint.js +196 -0
- package/dist/core/decision-receipt.d.ts +44 -1
- package/dist/core/decision-receipt.js +16 -0
- package/dist/core/effective-path-target.d.ts +28 -6
- package/dist/core/effective-path-target.js +28 -2
- package/dist/core/engine-notice.d.ts +47 -4
- package/dist/core/engine-notice.js +17 -1
- package/dist/core/engine-storage-backend.d.ts +73 -0
- package/dist/core/engine-storage-backend.js +1 -0
- package/dist/core/file-history-store.d.ts +6 -2
- package/dist/core/file-history-store.js +1 -0
- package/dist/core/gate-fold.js +13 -4
- package/dist/core/gate-lanes.js +41 -34
- package/dist/core/gate-outcome.d.ts +18 -9
- package/dist/core/governance-codes.d.ts +9 -2
- package/dist/core/governance-codes.js +9 -0
- package/dist/core/hands-band-screen.d.ts +7 -0
- package/dist/core/hands-band-screen.js +32 -0
- package/dist/core/hooks.d.ts +21 -19
- package/dist/core/hooks.js +6 -5
- package/dist/core/locked-config.d.ts +110 -31
- package/dist/core/locked-config.js +155 -42
- package/dist/core/lsp.d.ts +1 -1
- package/dist/core/mcp-probe.js +1 -1
- package/dist/core/mcp-server-spec.d.ts +152 -17
- package/dist/core/mcp-server-spec.js +223 -40
- package/dist/core/mcp.d.ts +21 -14
- package/dist/core/mcp.js +59 -54
- package/dist/core/memory-engine/engine.d.ts +14 -19
- package/dist/core/memory-engine/engine.js +9 -6
- package/dist/core/memory-engine/export-bundle.d.ts +1 -1
- package/dist/core/memory-engine/export-bundle.js +1 -1
- package/dist/core/memory-engine/file-backend.d.ts +2 -6
- package/dist/core/memory-engine/file-backend.js +1 -12
- package/dist/core/memory.d.ts +3 -3
- package/dist/core/mode-policy.d.ts +16 -26
- package/dist/core/mode-policy.js +5 -18
- package/dist/core/mods/kernel/dispatch.js +13 -15
- package/dist/core/mods/kernel/events.d.ts +9 -6
- package/dist/core/mods/kernel/events.js +2 -2
- package/dist/core/mods/kernel/receive.d.ts +41 -11
- package/dist/core/mods/kernel/receive.js +124 -54
- package/dist/core/mods/kernel/site-rules.d.ts +80 -15
- package/dist/core/mods/kernel/site-rules.js +232 -40
- package/dist/core/mods/stations.d.ts +0 -6
- package/dist/core/mods/stations.js +0 -7
- package/dist/core/mounted-mcp.d.ts +57 -0
- package/dist/core/mounted-mcp.js +71 -2
- package/dist/core/own-property-receipt.d.ts +13 -0
- package/dist/core/own-property-receipt.js +3 -1
- package/dist/core/parent-spec-seat.d.ts +12 -15
- package/dist/core/parent-spec-seat.js +14 -6
- package/dist/core/pause-registry.d.ts +35 -1
- package/dist/core/pause-registry.js +10 -0
- package/dist/core/permission-rule-consent.d.ts +18 -5
- package/dist/core/permission-rule-consent.js +13 -8
- package/dist/core/permission-rule-model.d.ts +87 -15
- package/dist/core/permission-rule-model.js +87 -8
- package/dist/core/permission-rule-org.d.ts +200 -33
- package/dist/core/permission-rule-org.js +217 -91
- package/dist/core/permission-rule-session.js +2 -2
- package/dist/core/permission-rule-store.d.ts +8 -0
- package/dist/core/permission-rule-store.js +1 -0
- package/dist/core/permission-rule-sync.js +3 -2
- package/dist/core/permission-rules.d.ts +7 -1
- package/dist/core/permission-rules.js +37 -8
- package/dist/core/read-only-shell.d.ts +1 -1
- package/dist/core/read-only-shell.js +30 -9
- package/dist/core/remote-env.d.ts +41 -1
- package/dist/core/remote-env.js +18 -0
- package/dist/core/resume-startup-cause.d.ts +18 -0
- package/dist/core/resume-startup-cause.js +12 -0
- package/dist/core/retention.js +7 -2
- package/dist/core/retired-keys.d.ts +8 -2
- package/dist/core/retired-keys.js +12 -1
- package/dist/core/roles.js +60 -10
- package/dist/core/rule-lane-reads.js +1 -1
- package/dist/core/runner/approval-feedback.d.ts +46 -0
- package/dist/core/runner/approval-feedback.js +41 -0
- package/dist/core/runner/compaction-call-options.d.ts +3 -3
- package/dist/core/runner/compaction-call-options.js +2 -2
- package/dist/core/runner/contracts.d.ts +34 -41
- package/dist/core/runner/cross-boundary-lane.d.ts +87 -0
- package/dist/core/runner/cross-boundary-lane.js +190 -0
- package/dist/core/runner/decide-continuation.d.ts +4 -4
- package/dist/core/runner/decide-continuation.js +3 -1
- package/dist/core/runner/gate-exit.d.ts +32 -12
- package/dist/core/runner/gate-exit.js +77 -34
- package/dist/core/runner/inherited-ask-grants.js +2 -2
- package/dist/core/runner/mcp-redial.d.ts +52 -10
- package/dist/core/runner/mcp-redial.js +38 -9
- package/dist/core/runner/permission-rule-lanes.d.ts +5 -2
- package/dist/core/runner/permission-rule-lanes.js +22 -10
- package/dist/core/runner/person-path-rows.d.ts +5 -3
- package/dist/core/runner/person-path-rows.js +2 -2
- package/dist/core/runner/prepare-acquire-reconcile.d.ts +3 -4
- package/dist/core/runner/prepare-acquire-reconcile.js +3 -3
- package/dist/core/runner/prepare-ask-lane.js +3 -3
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +6 -5
- package/dist/core/runner/prepare-caps-and-workflow.js +3 -3
- package/dist/core/runner/prepare-config-doors.d.ts +58 -15
- package/dist/core/runner/prepare-config-doors.js +167 -146
- package/dist/core/runner/prepare-context-lane.js +6 -3
- package/dist/core/runner/prepare-defer-classify.js +4 -7
- package/dist/core/runner/prepare-delegation-surface.d.ts +5 -4
- package/dist/core/runner/prepare-delegation-surface.js +8 -7
- package/dist/core/runner/prepare-execution-env.d.ts +1 -2
- package/dist/core/runner/prepare-execution-env.js +2 -1
- package/dist/core/runner/prepare-gate-stations.d.ts +2 -0
- package/dist/core/runner/prepare-gate-stations.js +4 -3
- package/dist/core/runner/prepare-hands-readface.d.ts +3 -3
- package/dist/core/runner/prepare-hands-readface.js +3 -2
- package/dist/core/runner/prepare-inherited-gate.d.ts +2 -0
- package/dist/core/runner/prepare-inherited-gate.js +3 -2
- package/dist/core/runner/prepare-listings.d.ts +1 -1
- package/dist/core/runner/prepare-listings.js +4 -2
- package/dist/core/runner/prepare-memory-engine-session.d.ts +0 -6
- package/dist/core/runner/prepare-memory-engine-session.js +19 -6
- package/dist/core/runner/prepare-memory.d.ts +3 -2
- package/dist/core/runner/prepare-memory.js +6 -2
- package/dist/core/runner/prepare-offload-wrappers.d.ts +4 -4
- package/dist/core/runner/prepare-offload-wrappers.js +2 -1
- package/dist/core/runner/prepare-park-ask.d.ts +1 -1
- package/dist/core/runner/prepare-park-ask.js +9 -3
- package/dist/core/runner/prepare-policy-chain.d.ts +1 -1
- package/dist/core/runner/prepare-policy-chain.js +14 -19
- package/dist/core/runner/prepare-project-context.d.ts +1 -1
- package/dist/core/runner/prepare-project-context.js +6 -4
- package/dist/core/runner/prepare-prompt-assembly.d.ts +1 -1
- package/dist/core/runner/prepare-prompt-assembly.js +20 -16
- package/dist/core/runner/prepare-prompt-inputs.d.ts +12 -6
- package/dist/core/runner/prepare-prompt-inputs.js +6 -3
- package/dist/core/runner/prepare-protocol-tools.d.ts +7 -5
- package/dist/core/runner/prepare-protocol-tools.js +19 -12
- package/dist/core/runner/prepare-question-face.d.ts +4 -2
- package/dist/core/runner/prepare-question-face.js +4 -3
- package/dist/core/runner/prepare-safety-scan.d.ts +7 -2
- package/dist/core/runner/prepare-safety-scan.js +34 -27
- package/dist/core/runner/prepare-suspend-saga.d.ts +2 -2
- package/dist/core/runner/prepare-suspend-saga.js +6 -2
- package/dist/core/runner/prepare-task.js +22 -19
- package/dist/core/runner/prepare-turn-wiring.d.ts +10 -5
- package/dist/core/runner/prepare-turn-wiring.js +14 -49
- package/dist/core/runner/prepare-wiring-manifest.d.ts +10 -5
- package/dist/core/runner/prepare-wiring-manifest.js +9 -6
- package/dist/core/runner/prepare-workspace-restore.js +2 -2
- package/dist/core/runner/resume-admission.d.ts +4 -1
- package/dist/core/runner/resume-admission.js +16 -14
- package/dist/core/runner/resume-apply.js +4 -4
- package/dist/core/runner/resume-internals-and-config.d.ts +3 -3
- package/dist/core/runner/resume-internals-and-config.js +3 -8
- package/dist/core/runner/resume-policy-outcome.d.ts +2 -2
- package/dist/core/runner/resume-policy-outcome.js +18 -15
- package/dist/core/runner/resume-preflight.js +2 -2
- package/dist/core/runner/resume-review-outcome.js +3 -3
- package/dist/core/runner/retired-runner-deps.d.ts +5 -6
- package/dist/core/runner/retired-runner-deps.js +1 -4
- package/dist/core/runner/run-leg.js +97 -43
- package/dist/core/runner/run-recovery-lanes.js +5 -3
- package/dist/core/runner/run-settle-and-teardown.js +2 -0
- package/dist/core/runner/run-terminal-adoption.js +21 -9
- package/dist/core/runner/run-turn-boundary.js +9 -3
- package/dist/core/runner/runtask.js +1 -1
- package/dist/core/runner/session-file-state-replay.d.ts +5 -2
- package/dist/core/runner/session-file-state-replay.js +3 -2
- package/dist/core/runner/skills-seat.d.ts +15 -0
- package/dist/core/runner/skills-seat.js +57 -0
- package/dist/core/runner/stream-steer-verb.js +2 -2
- package/dist/core/runner/sub-agent-deny-lists.d.ts +13 -11
- package/dist/core/runner/sub-agent-deny-lists.js +7 -5
- package/dist/core/runner/synthetic-tools.d.ts +5 -2
- package/dist/core/runner/synthetic-tools.js +2 -12
- package/dist/core/runner/tool-face-overlay.d.ts +24 -6
- package/dist/core/runner/tool-face-overlay.js +24 -15
- package/dist/core/runner-deps.d.ts +37 -22
- package/dist/core/session-policy-store.d.ts +19 -0
- package/dist/core/session-policy-store.js +22 -2
- package/dist/core/session-store.d.ts +35 -16
- package/dist/core/session-store.js +20 -12
- package/dist/core/{shell-lexer.d.ts → shell-run-candidates.d.ts} +36 -12
- package/dist/core/{shell-lexer.js → shell-run-candidates.js} +145 -225
- package/dist/core/shell-wrapper-table.d.ts +5 -3
- package/dist/core/shell-wrapper-table.js +1 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +2 -2
- package/dist/core/store-contracts/mailbox-store-contract.js +13 -0
- package/dist/core/store-contracts/session-store-contract.d.ts +49 -0
- package/dist/core/store-contracts/session-store-contract.js +639 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +12 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.js +5 -2
- package/dist/core/task-event.d.ts +44 -6
- package/dist/core/task-notification.js +2 -2
- package/dist/core/task-registry-agent.js +1 -0
- package/dist/core/task-registry-shared.d.ts +5 -0
- package/dist/core/task-registry.d.ts +7 -0
- package/dist/core/task-registry.js +17 -0
- package/dist/core/task-result.d.ts +1 -1
- package/dist/core/task-spec.d.ts +7 -7
- package/dist/core/tighten-task-spec.d.ts +6 -4
- package/dist/core/tighten-task-spec.js +2 -2
- package/dist/core/tool-catalog-entries.d.ts +1 -1
- package/dist/core/tool-catalog-entries.js +52 -52
- package/dist/core/tool-face-reader.d.ts +49 -0
- package/dist/core/tool-face-reader.js +94 -0
- package/dist/core/tool-face.d.ts +17 -8
- package/dist/core/tool-face.js +1 -0
- package/dist/core/tool-policy.d.ts +67 -23
- package/dist/core/tool-policy.js +72 -60
- package/dist/core/tool-roster.d.ts +46 -28
- package/dist/core/tool-roster.js +91 -14
- package/dist/core/tool-spec-members.js +2 -2
- package/dist/core/tool-spec.d.ts +20 -4
- package/dist/core/tools.js +2 -0
- package/dist/core/trace.d.ts +24 -2
- package/dist/core/types.d.ts +3 -3
- package/dist/core/types.js +1 -1
- package/dist/core/untrusted-text.d.ts +23 -0
- package/dist/core/untrusted-text.js +10 -10
- package/dist/core/user-attachment.d.ts +56 -2
- package/dist/core/user-attachment.js +139 -56
- package/dist/core/wiring-manifest.d.ts +4 -2
- package/dist/engine/compaction/compaction.d.ts +2 -2
- package/dist/engine/compaction/utils.d.ts +2 -2
- package/dist/engine/harness/agent-harness.js +2 -1
- package/dist/engine/harness/types.d.ts +10 -4
- package/dist/engine/llm/types.d.ts +7 -2
- package/dist/engine/llm/types.js +2 -1
- package/dist/engine/loop/agent-loop.d.ts +12 -1
- package/dist/engine/loop/agent-loop.js +17 -5
- package/dist/engine/loop/types.d.ts +7 -1
- package/dist/engine/session/repo-utils.d.ts +5 -0
- package/dist/engine/session/repo-utils.js +9 -0
- package/dist/engine/session/storage-base.js +2 -2
- package/dist/index.d.ts +37 -17
- package/dist/index.js +31 -14
- package/dist/internal/harness.d.ts +1 -0
- package/dist/internal/harness.js +1 -0
- package/dist/internal/llm.d.ts +1 -1
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/goal.d.ts +24 -1
- package/dist/orchestration/goal.js +3 -2
- package/dist/orchestration/run-workflow-tool.d.ts +3 -0
- package/dist/orchestration/run-workflow-tool.js +1 -0
- package/dist/orchestration/workflow-governance.d.ts +1 -1
- package/dist/orchestration/workflow.d.ts +3 -0
- package/dist/orchestration/workflow.js +2 -1
- package/dist/prompt-assembly/artifact-store.d.ts +44 -9
- package/dist/prompt-assembly/artifact-store.js +38 -12
- package/dist/prompt-assembly/artifact.d.ts +12 -11
- package/dist/prompt-assembly/artifact.js +52 -21
- package/dist/prompt-assembly/assemble.d.ts +2 -0
- package/dist/prompt-assembly/assemble.js +2 -1
- package/dist/prompt-assembly/catalog/index.js +2 -1
- package/dist/prompt-assembly/catalog/memory.d.ts +13 -0
- package/dist/prompt-assembly/catalog/memory.js +6 -0
- package/dist/prompt-assembly/catalog/schema.d.ts +19 -2
- package/dist/prompt-assembly/catalog/schema.js +3 -0
- package/dist/prompt-assembly/composer.d.ts +2 -0
- package/dist/prompt-assembly/composer.js +1 -1
- package/dist/prompt-assembly/overlay.d.ts +21 -11
- package/dist/prompt-assembly/overlay.js +57 -19
- package/dist/prompt-assembly/select.d.ts +21 -6
- package/dist/prompt-assembly/select.js +41 -4
- package/dist/prompts/default.d.ts +1 -12
- package/dist/prompts/default.js +0 -3
- package/dist/shell/lex.d.ts +87 -8
- package/dist/shell/lex.js +283 -49
- package/dist/stores/file/index.d.ts +8 -6
- package/dist/stores/file/permission-rule-store.d.ts +1 -1
- package/dist/stores/file/permission-rule-store.js +2 -1
- package/dist/tools/artifact/artifact-tool.js +14 -3
- package/dist/tools/fs/bash-program-position.d.ts +3 -15
- package/dist/tools/fs/bash-program-position.js +3 -10
- package/dist/tools/fs/bash-readonly-classifier.js +2 -0
- package/dist/tools/fs/fs-bash.d.ts +3 -3
- package/dist/tools/fs/fs-bash.js +72 -101
- package/dist/tools/fs/fs-read.d.ts +12 -0
- package/dist/tools/fs/fs-read.js +10 -9
- package/dist/tools/fs/fs-shared.d.ts +27 -31
- package/dist/tools/fs/fs-shared.js +12 -15
- package/dist/tools/fs/fs-write.js +1 -1
- package/dist/tools/fs/index.js +2 -2
- package/dist/tools/fs/read-deny-home.d.ts +1 -1
- package/dist/tools/fs/read-deny-home.js +5 -4
- package/dist/tools/fs/read-deny.d.ts +16 -3
- package/dist/tools/fs/read-deny.js +12 -9
- package/dist/tools/fs/safety.d.ts +7 -6
- package/dist/tools/fs/shell-read-bindings.d.ts +5 -3
- package/dist/tools/fs/shell-read-bindings.js +15 -16
- package/dist/tools/fs/shell-read-device.js +1 -1
- package/dist/tools/fs/shell-read-plan.js +36 -47
- package/dist/tools/fs/shell-read-word.d.ts +1 -6
- package/dist/tools/fs/shell-read-word.js +2 -20
- package/dist/tools/fs/shell-reentry-text.js +1 -1
- package/dist/tools/web.d.ts +2 -2
- package/package.json +4 -1
- package/test/export-surface.snapshot.json +5651 -5457
- package/wire-changes/core@7.53.0.json +1968 -0
- package/wire-changes/core@7.54.0.json +2870 -0
- package/dist/core/shell-scan.d.ts +0 -60
- package/dist/core/shell-scan.js +0 -183
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { posix } from "node:path";
|
|
2
|
-
import { readShellCommand } from "./shell-
|
|
2
|
+
import { lexedWordOf, readShellCommand } from "./shell-run-candidates.js";
|
|
3
3
|
import { descriptorsOfPlan, newLineDescriptors, standardDeviceUnrebound } from "../tools/fs/shell-read-device.js";
|
|
4
4
|
import { planShellReads } from "../tools/fs/shell-read-plan.js";
|
|
5
5
|
import { writesOnlyStandardDevices } from "../tools/fs/shell-read-write-targets.js";
|
|
@@ -33,8 +33,7 @@ const TABLE_ROWS = Object.entries(READ_ONLY_COMMAND_TABLE)
|
|
|
33
33
|
.map(([key, row]) => ({ words: key.split(" "), row }))
|
|
34
34
|
.sort((a, b) => b.words.length - a.words.length);
|
|
35
35
|
const READING_REDIRECTS = new Set(["<", "<<", "<<-", "<&", "<<<"]);
|
|
36
|
-
const
|
|
37
|
-
const ASSIGNMENT_NAME = /^([A-Za-z_][A-Za-z0-9_]*)(?:\[[^\]]*\])?\+?=/;
|
|
36
|
+
const BARE_VALUE_CHARACTERS = /^[A-Za-z0-9_./:+-]*$/;
|
|
38
37
|
const FLAG_WORD = /^-[a-zA-Z0-9_-]/;
|
|
39
38
|
const NUMBER_LITERAL = /^[-+]?(0[xX][0-9a-fA-F]+|[0-9]+#[0-9a-zA-Z]+|[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)$/;
|
|
40
39
|
const PRINTF_LENGTH = "[lLhqjzZt]*";
|
|
@@ -90,20 +89,42 @@ export function readOnlyLineObjection(command, cwd) {
|
|
|
90
89
|
return lineStructureObjection(shape) ?? (changesDirectoryBeforeGit(shape, cwd) ? CD_GIT_REASON : undefined);
|
|
91
90
|
}
|
|
92
91
|
function expansionKind(w) {
|
|
92
|
+
const lexed = lexedWordOf(w);
|
|
93
|
+
if (lexed !== undefined && (lexed.unresolved !== undefined || lexed.quotedSpans.some((s) => s.by === "$'")))
|
|
94
|
+
return "variable";
|
|
93
95
|
if (w.expands === false)
|
|
94
96
|
return "none";
|
|
95
|
-
if (
|
|
97
|
+
if (lexed === undefined)
|
|
98
|
+
return "variable";
|
|
99
|
+
const computed = (e) => VALUE_EXPANSIONS.has(e.kind) || e.inner?.some(computed) === true;
|
|
100
|
+
if (lexed.expansions.some((p) => p.expansion !== undefined && computed(p.expansion)))
|
|
96
101
|
return "variable";
|
|
97
102
|
if (w.expands === "many")
|
|
98
103
|
return "glob";
|
|
99
104
|
return "none";
|
|
100
105
|
}
|
|
106
|
+
const VALUE_EXPANSIONS = new Set(["parameter", "command", "process", "arithmetic"]);
|
|
101
107
|
function leadingAssignmentCount(argv) {
|
|
102
108
|
let k = 0;
|
|
103
|
-
while (k < argv.length &&
|
|
109
|
+
while (k < argv.length && lexedWordOf(argv[k])?.assignment?.bare === true)
|
|
104
110
|
k++;
|
|
105
111
|
return k;
|
|
106
112
|
}
|
|
113
|
+
function literalAssignmentValue(a) {
|
|
114
|
+
if (a.subscript !== undefined || a.form !== "scalar" || a.value.unresolved !== undefined || a.value.expansions.length > 0)
|
|
115
|
+
return false;
|
|
116
|
+
const [only, ...rest] = a.value.pieces;
|
|
117
|
+
if (only === undefined)
|
|
118
|
+
return true;
|
|
119
|
+
if (rest.length > 0 || only.literal === undefined)
|
|
120
|
+
return false;
|
|
121
|
+
if (only.quotedBy === undefined)
|
|
122
|
+
return BARE_VALUE_CHARACTERS.test(only.literal);
|
|
123
|
+
const oneRegion = a.value.raw.length === only.literal.length + 2;
|
|
124
|
+
if (only.quotedBy === "'")
|
|
125
|
+
return oneRegion;
|
|
126
|
+
return only.quotedBy === '"' && oneRegion && !/[$`\\]/.test(only.literal);
|
|
127
|
+
}
|
|
107
128
|
function peelBuiltinPrefix(words) {
|
|
108
129
|
let t = words;
|
|
109
130
|
for (;;) {
|
|
@@ -142,11 +163,11 @@ function segmentVerdict(seg, line, bindings) {
|
|
|
142
163
|
}
|
|
143
164
|
const k = leadingAssignmentCount(seg.argv);
|
|
144
165
|
for (const w of seg.argv.slice(0, k)) {
|
|
145
|
-
const
|
|
146
|
-
if (
|
|
166
|
+
const a = lexedWordOf(w).assignment;
|
|
167
|
+
if (!literalAssignmentValue(a))
|
|
147
168
|
return NOT(`the assignment \`${w.raw}\` is not a literal value`);
|
|
148
|
-
if (!ENV_NAMES.has(
|
|
149
|
-
return NOT(`the environment variable \`${
|
|
169
|
+
if (!ENV_NAMES.has(a.name))
|
|
170
|
+
return NOT(`the environment variable \`${a.name}\` can alter what a program does`);
|
|
150
171
|
}
|
|
151
172
|
const run = seg.argv.slice(k);
|
|
152
173
|
if (run.length === 0)
|
|
@@ -66,6 +66,19 @@ export interface WorkspaceHandle {
|
|
|
66
66
|
*/
|
|
67
67
|
deviceId?: string;
|
|
68
68
|
}
|
|
69
|
+
/** The one list of what a {@link WorkspaceHandle} is: every member the interface declares. */
|
|
70
|
+
export declare const WORKSPACE_HANDLE_MEMBERS: ReadonlyArray<keyof WorkspaceHandle>;
|
|
71
|
+
/**
|
|
72
|
+
* A frozen copy of `handle` holding exactly the declared members it carries as strings: shallow-frozen, which is deep here
|
|
73
|
+
* because every member is a string (a decoration or a function member of the source never reaches the copy), and no
|
|
74
|
+
* structured-clone step to fail on an exotic value. Each member is read the way the engine's own handle comparison reads it.
|
|
75
|
+
*
|
|
76
|
+
* ONE copy per live handle: a second call for the same object answers the copy the first call made (the members are read
|
|
77
|
+
* once), so every place the engine hands a checkpointed handle to the outside — the resume preflight's facts, the env
|
|
78
|
+
* factory's {@link ExecutionEnvFactoryContext.resumeWorkspace}, the restore's {@link VmLifecycleOptions.priorHandle} —
|
|
79
|
+
* delivers the same object, not three renderings of one fact.
|
|
80
|
+
*/
|
|
81
|
+
export declare function frozenHandleCopy(handle: WorkspaceHandle): Readonly<WorkspaceHandle>;
|
|
69
82
|
/**
|
|
70
83
|
* A reference to a secret injected at {@link RemoteExecutionEnv.connect}/{@link RemoteExecutionEnv.postResumeInit}
|
|
71
84
|
* time (design/48 §5 gap 7) — never baked into the image. The control plane resolves {@link ref} to a value out of
|
|
@@ -114,8 +127,12 @@ export interface VmLifecycleOptions {
|
|
|
114
127
|
* handle (never echo `priorHandle.mountPath` unhonored) — the engine compares the two and surfaces a
|
|
115
128
|
* divergence observation. Absent on non-resume ops and from pre-1.360 engines (adapters treat absence
|
|
116
129
|
* as the legacy current-config behavior).
|
|
130
|
+
*
|
|
131
|
+
* A frozen copy holding exactly the declared members ({@link WORKSPACE_HANDLE_MEMBERS}) the checkpoint row carries
|
|
132
|
+
* as strings — the SAME object the env factory's {@link ExecutionEnvFactoryContext.resumeWorkspace} was, for the
|
|
133
|
+
* same row — not the stored row's own object: writing to it throws, and a decoration on the stored handle is absent.
|
|
117
134
|
*/
|
|
118
|
-
priorHandle?: WorkspaceHandle
|
|
135
|
+
priorHandle?: Readonly<WorkspaceHandle>;
|
|
119
136
|
}
|
|
120
137
|
/**
|
|
121
138
|
* One chunk streamed from {@link RemoteExecutionEnv.execStream} (design/48 §5 gap 3, council BUG#3). A run is a
|
|
@@ -494,6 +511,29 @@ export interface ExecutionEnvFactoryContext {
|
|
|
494
511
|
* already shares the parent env (and its cwd).
|
|
495
512
|
*/
|
|
496
513
|
parentCwd?: string;
|
|
514
|
+
/**
|
|
515
|
+
* design/380 O1 delivery fence — the workspace a DURABLE RESUME leg is rebuilding: a frozen copy of the
|
|
516
|
+
* {@link WorkspaceHandle} the checkpoint row recorded at suspend, holding exactly the members a handle declares
|
|
517
|
+
* ({@link WORKSPACE_HANDLE_MEMBERS}) that the row carries as strings. Present ONLY on that leg — the key is
|
|
518
|
+
* absent (not an `undefined` value) on every fresh run, and on a resume whose row recorded no workspace
|
|
519
|
+
* handle. Mutating the copy reaches nothing the engine reads.
|
|
520
|
+
*
|
|
521
|
+
* A factory bound to a target (the device lane) **MUST** mint the env on the device
|
|
522
|
+
* `resumeWorkspace.deviceId` names and, when it cannot (offline, busy, the placement moved to another
|
|
523
|
+
* device), **THROW** a typed refusal. It **MUST NOT** connect some other device and leave the engine to
|
|
524
|
+
* notice, and it **MUST NOT** look the current binding up afresh from {@link placementRootSessionId} for
|
|
525
|
+
* this leg. A row recorded without `deviceId` (a non-device lane, or a row older than the field) states no
|
|
526
|
+
* device to honor; the factory then follows its ordinary routing.
|
|
527
|
+
*
|
|
528
|
+
* The minted env's `workspaceHandle()` **MUST** report the device its connection actually reached; it is
|
|
529
|
+
* never copied from `resumeWorkspace`. The engine's comparison of that report against the row (`provider`
|
|
530
|
+
* equal; `deviceId` equal whenever the row carries one) stays as the receipt check and TRUSTS the report: a
|
|
531
|
+
* factory that connected elsewhere and reports so is refused (`resume.env_failed`), only after the wrong
|
|
532
|
+
* connection was made, but one that echoes the fence while connecting elsewhere defeats its own protection
|
|
533
|
+
* and passes. The fence moves no refusal earlier than it was: it runs after the claim, so what a deployment
|
|
534
|
+
* can still catch BEFORE the claim is `RunnerDeps.resumePreflight` alone.
|
|
535
|
+
*/
|
|
536
|
+
resumeWorkspace?: Readonly<WorkspaceHandle>;
|
|
497
537
|
}
|
|
498
538
|
/**
|
|
499
539
|
* A **trusted control-plane** factory that mints a per-task {@link ExecutionEnv} (design/48 §5 answers core
|
package/dist/core/remote-env.js
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
const WORKSPACE_HANDLE_MEMBER_TABLE = { sandboxId: 1, provider: 1, mountPath: 1, snapshotId: 1, sessionToken: 1, restoreMode: 1, deviceId: 1 };
|
|
2
|
+
export const WORKSPACE_HANDLE_MEMBERS = Object.keys(WORKSPACE_HANDLE_MEMBER_TABLE);
|
|
3
|
+
const FROZEN_COPY_OF = new WeakMap();
|
|
4
|
+
export function frozenHandleCopy(handle) {
|
|
5
|
+
const known = FROZEN_COPY_OF.get(handle);
|
|
6
|
+
if (known !== undefined)
|
|
7
|
+
return known;
|
|
8
|
+
const copy = {};
|
|
9
|
+
for (const member of WORKSPACE_HANDLE_MEMBERS) {
|
|
10
|
+
const value = handle[member];
|
|
11
|
+
if (typeof value === "string")
|
|
12
|
+
copy[member] = value;
|
|
13
|
+
}
|
|
14
|
+
const frozen = Object.freeze(copy);
|
|
15
|
+
if (typeof handle === "object" && handle !== null)
|
|
16
|
+
FROZEN_COPY_OF.set(handle, frozen);
|
|
17
|
+
return frozen;
|
|
18
|
+
}
|
|
1
19
|
export const RETRYABLE_REMOTE_ERROR_CODES = [
|
|
2
20
|
"auth_transient",
|
|
3
21
|
"connect_failed",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* unsafe payload, an input the constraints refuse): correct the decision and resubmit.
|
|
24
24
|
*/
|
|
25
25
|
import type { AssertAllKeysHandled } from "./ask-origin.js";
|
|
26
|
+
import type { TerminalFailureDetail } from "./terminal-cause.js";
|
|
26
27
|
/**
|
|
27
28
|
* design/80 D-1: why a consumed checkpoint was {@link import("./checkpoint-store.js").CheckpointStore.reopen | reopened}
|
|
28
29
|
* (resolved → pending). The reason drives re-resume validation (§3 invariant #1): an `env_failed` reopen is a SYSTEM
|
|
@@ -51,6 +52,23 @@ export type ResumeStartupCause = (typeof RESUME_STARTUP_CAUSES)[number];
|
|
|
51
52
|
/** The cause a resume failure's code names; `undefined` when the code is absent or the table does not
|
|
52
53
|
* name it. Every `config.*` code is a configuration door's refusal. */
|
|
53
54
|
export declare function resumeStartupCauseOf(code: string | undefined): ResumeStartupCause | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* The members of a resume refusal's `detail` the parked-resume receipt carries beside its `cause` — the three a
|
|
57
|
+
* {@link import("./checkpoint-store.js").CheckpointError} states where its `code` alone does not say which input or which arm refused:
|
|
58
|
+
* `code` (on `checkpoint.config_refused`: prepare's own code, the word a fresh run of the same bad config reports), `field` (which
|
|
59
|
+
* input carries the refusal) and `reason` (which arm fired). Their words are those families' own; the receipt adds no word of its own.
|
|
60
|
+
*/
|
|
61
|
+
export declare const RESUME_REFUSAL_MEMBERS: readonly ["code", "field", "reason"];
|
|
62
|
+
/** {@link RESUME_REFUSAL_MEMBERS} as the receipt carries them: each a string, each present only when the failure stated it. */
|
|
63
|
+
export type ResumeRefusalDetail = {
|
|
64
|
+
readonly [K in (typeof RESUME_REFUSAL_MEMBERS)[number]]?: string;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* The refusal members a failed resume stated, read from the failure's coded account ({@link TerminalFailureDetail}, `kind: "coded"`:
|
|
68
|
+
* the `detail` its throw site stated) — never from its sentence. `undefined` when the failure carries no coded account or none of
|
|
69
|
+
* the three members is a string in it.
|
|
70
|
+
*/
|
|
71
|
+
export declare function resumeRefusalDetailOf(account: TerminalFailureDetail | undefined): ResumeRefusalDetail | undefined;
|
|
54
72
|
declare const REOPEN_REASON_OF_CAUSE: {
|
|
55
73
|
readonly environment: "env_failed";
|
|
56
74
|
readonly session_gone: "env_failed";
|
|
@@ -21,6 +21,18 @@ export function resumeStartupCauseOf(code) {
|
|
|
21
21
|
return undefined;
|
|
22
22
|
return CAUSE_OF_CODE.get(code) ?? (code.startsWith("config.") ? "configuration" : undefined);
|
|
23
23
|
}
|
|
24
|
+
export const RESUME_REFUSAL_MEMBERS = Object.freeze(["code", "field", "reason"]);
|
|
25
|
+
export function resumeRefusalDetailOf(account) {
|
|
26
|
+
if (account === undefined || account.kind !== "coded")
|
|
27
|
+
return undefined;
|
|
28
|
+
const out = {};
|
|
29
|
+
for (const member of RESUME_REFUSAL_MEMBERS) {
|
|
30
|
+
const value = Object.hasOwn(account.detail, member) ? account.detail[member] : undefined;
|
|
31
|
+
if (typeof value === "string")
|
|
32
|
+
out[member] = value;
|
|
33
|
+
}
|
|
34
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
35
|
+
}
|
|
24
36
|
const REOPEN_REASON_OF_CAUSE = {
|
|
25
37
|
environment: "env_failed",
|
|
26
38
|
session_gone: "env_failed",
|
package/dist/core/retention.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { describeRejectedValue } from "./tool-search-setting.js";
|
|
1
2
|
export const RETENTION_CASCADE_DOMAINS = Object.freeze(["checkpoints", "session-trees", "orphan-tool-results"]);
|
|
2
3
|
export const RETENTION_CASCADE_EXEMPT = Object.freeze(["session-pollution", "session-capture-optout", "lineage.json"]);
|
|
3
4
|
function codedError(code, message) {
|
|
@@ -7,8 +8,12 @@ function codedError(code, message) {
|
|
|
7
8
|
}
|
|
8
9
|
export function assertRetentionCapability(input) {
|
|
9
10
|
const { policy, locked, stores } = input;
|
|
11
|
+
const declared = policy;
|
|
12
|
+
if (declared !== undefined && (typeof declared !== "object" || declared === null || Array.isArray(declared))) {
|
|
13
|
+
throw codedError("config.retention_policy", `retentionPolicy must be an object carrying maxAgeDays (got ${declared === null ? "null" : Array.isArray(declared) ? "an array" : typeof declared}).`);
|
|
14
|
+
}
|
|
10
15
|
if (policy !== undefined && (!Number.isFinite(policy.maxAgeDays) || policy.maxAgeDays < 0)) {
|
|
11
|
-
throw codedError("config.retention_policy", `retentionPolicy.maxAgeDays must be a finite non-negative number of days (got ${
|
|
16
|
+
throw codedError("config.retention_policy", `retentionPolicy.maxAgeDays must be a finite non-negative number of days (got ${describeRejectedValue(policy.maxAgeDays)}).`);
|
|
12
17
|
}
|
|
13
18
|
const declaredRetention = (name, store) => {
|
|
14
19
|
const r = store.retention;
|
|
@@ -19,7 +24,7 @@ export function assertRetentionCapability(input) {
|
|
|
19
24
|
throw codedError("config.retention_capability", `store "${name}" declares an unparseable retention value ${JSON.stringify(r)} — expected "managed" or "none".`);
|
|
20
25
|
};
|
|
21
26
|
const declarations = stores
|
|
22
|
-
.filter((s) => s.store !== undefined)
|
|
27
|
+
.filter((s) => s.store !== undefined && s.store !== null)
|
|
23
28
|
.map(({ name, store }) => ({ name, retention: declaredRetention(name, store) }));
|
|
24
29
|
if (!locked || policy === undefined)
|
|
25
30
|
return;
|
|
@@ -46,7 +46,13 @@ export declare const RETIRED_SHELL_READ_BOUNDARY_KEYS: Readonly<Record<string, s
|
|
|
46
46
|
* decision that carries one is denied in the engine's own words, never read without it: the type retires a member only where
|
|
47
47
|
* a decision is a literal in an annotated position, and a `check` whose return type is inferred still compiles with it. */
|
|
48
48
|
export declare const RETIRED_DECISION_MEMBERS: Readonly<Record<string, string>>;
|
|
49
|
-
/**
|
|
50
|
-
|
|
49
|
+
/**
|
|
50
|
+
* The `ToolPolicy` door — every policy the engine installs passes it (a task's or deployment's seat, a combined member, an inherited
|
|
51
|
+
* constraint): `undefined` (or `null`, the seat's other absence spelling) is no policy; a value that is not an object whose `check`
|
|
52
|
+
* is a function is no policy either, and refuses by name (`config.invalid_argument`, `detail.field: "ToolPolicy"`) — a policy the
|
|
53
|
+
* engine cannot call is never installed as if it were absent, which would run the leg with nothing the deployment meant to apply;
|
|
54
|
+
* a retired member refuses by name ({@link RETIRED_TOOL_POLICY_KEYS}).
|
|
55
|
+
*/
|
|
56
|
+
export declare function assertNoRetiredToolPolicyKeys(policy: unknown): void;
|
|
51
57
|
/** The `ShellReadBoundary` door ({@link RETIRED_SHELL_READ_BOUNDARY_KEYS}). */
|
|
52
58
|
export declare function assertNoRetiredShellReadBoundaryKeys(boundary: object): void;
|
|
@@ -45,8 +45,19 @@ export const RETIRED_DECISION_MEMBERS = Object.freeze({
|
|
|
45
45
|
guard: 'write `guards: ["<word>"]` instead (the same five words, as a list: one ask may stand on several integrity guards)',
|
|
46
46
|
});
|
|
47
47
|
export function assertNoRetiredToolPolicyKeys(policy) {
|
|
48
|
-
if (policy
|
|
48
|
+
if (policy === undefined || policy === null)
|
|
49
|
+
return;
|
|
50
|
+
const isRecord = typeof policy === "object" && !Array.isArray(policy);
|
|
51
|
+
if (isRecord)
|
|
49
52
|
assertNoRetiredKeys(policy, RETIRED_TOOL_POLICY_KEYS, "ToolPolicy");
|
|
53
|
+
const check = isRecord ? policy.check : undefined;
|
|
54
|
+
if (typeof check !== "function") {
|
|
55
|
+
const got = typeof policy !== "object" ? typeof policy : Array.isArray(policy) ? "an array" : `an object whose check is ${check === null ? "null" : typeof check}`;
|
|
56
|
+
const e = new Error(`ToolPolicy must be an object whose \`check\` is a function (got ${got}) — a policy the engine cannot call is refused rather than run as no policy; omit the seat for none.`);
|
|
57
|
+
e.code = "config.invalid_argument";
|
|
58
|
+
e.detail = { field: "ToolPolicy" };
|
|
59
|
+
throw e;
|
|
60
|
+
}
|
|
50
61
|
}
|
|
51
62
|
export function assertNoRetiredShellReadBoundaryKeys(boundary) {
|
|
52
63
|
assertNoRetiredKeys(boundary, RETIRED_SHELL_READ_BOUNDARY_KEYS, "ShellReadBoundary");
|
package/dist/core/roles.js
CHANGED
|
@@ -1,11 +1,29 @@
|
|
|
1
1
|
import { selectModel } from "./select-model.js";
|
|
2
2
|
import { MODEL_ROLES } from "./types.js";
|
|
3
3
|
export { MODEL_ROLES } from "./types.js";
|
|
4
|
+
function catalogModel(ref, models) {
|
|
5
|
+
const m = models != null && (typeof models === "object" || typeof models === "function") && Object.hasOwn(models, ref) ? models[ref] : undefined;
|
|
6
|
+
return m || undefined;
|
|
7
|
+
}
|
|
8
|
+
function modelBindingRefusal(seat, reason, message) {
|
|
9
|
+
const e = new Error(message);
|
|
10
|
+
e.code = "config.unknown_role";
|
|
11
|
+
e.detail = { field: seat, reason };
|
|
12
|
+
return e;
|
|
13
|
+
}
|
|
14
|
+
function bindingShown(value) {
|
|
15
|
+
if (typeof value === "string")
|
|
16
|
+
return JSON.stringify(value.length > 80 ? `${value.slice(0, 80)}…` : value);
|
|
17
|
+
return value === null ? "null" : Array.isArray(value) ? "a list" : `a ${typeof value}`;
|
|
18
|
+
}
|
|
19
|
+
function unknownModelRefRefusal(ref, seat) {
|
|
20
|
+
return modelBindingRefusal(seat, "unknown_model_ref", `Unknown model ref ${bindingShown(ref)} in ${seat}. Provide it in RunnerDeps.models or pass a Model object.`);
|
|
21
|
+
}
|
|
4
22
|
export function resolveModel(ref, models) {
|
|
5
23
|
if (typeof ref !== "string") {
|
|
6
24
|
return ref;
|
|
7
25
|
}
|
|
8
|
-
const m =
|
|
26
|
+
const m = catalogModel(ref, models);
|
|
9
27
|
if (!m) {
|
|
10
28
|
throw new Error(`Unknown model ref "${ref}". Provide it in RunnerDeps.models or pass a Model object.`);
|
|
11
29
|
}
|
|
@@ -33,7 +51,19 @@ export function expandTiers(models, tiers) {
|
|
|
33
51
|
out[TIER_ALIAS_VIA] = aliasVia;
|
|
34
52
|
const bound = (name) => {
|
|
35
53
|
const b = Object.hasOwn(tiers, name) ? tiers[name] : undefined;
|
|
36
|
-
|
|
54
|
+
if (b === undefined)
|
|
55
|
+
return undefined;
|
|
56
|
+
const seat = `tiers.${name}`;
|
|
57
|
+
if (typeof b === "string") {
|
|
58
|
+
const held = catalogModel(b, models);
|
|
59
|
+
if (held === undefined)
|
|
60
|
+
throw unknownModelRefRefusal(b, seat);
|
|
61
|
+
return held;
|
|
62
|
+
}
|
|
63
|
+
if (typeof b !== "object" || b === null || Array.isArray(b)) {
|
|
64
|
+
throw modelBindingRefusal(seat, "not_a_model_ref", `${seat} is ${bindingShown(b)}, not a model reference — a tier binds a catalog model name or a Model object.`);
|
|
65
|
+
}
|
|
66
|
+
return b;
|
|
37
67
|
};
|
|
38
68
|
const ownKey = (k) => models !== undefined && Object.hasOwn(models, k) && Boolean(models[k]);
|
|
39
69
|
const landing = (t, self) => {
|
|
@@ -131,13 +161,16 @@ const FALLBACK = {
|
|
|
131
161
|
classifier: ["summarize", "default"],
|
|
132
162
|
consolidate: ["summarize"],
|
|
133
163
|
};
|
|
134
|
-
function specParts(s) {
|
|
164
|
+
function specParts(s, seat = "a role seat") {
|
|
135
165
|
if (s == null) {
|
|
136
166
|
return {};
|
|
137
167
|
}
|
|
138
168
|
if (typeof s === "string") {
|
|
139
169
|
return { model: s };
|
|
140
170
|
}
|
|
171
|
+
if (typeof s !== "object" && typeof s !== "function") {
|
|
172
|
+
throw modelBindingRefusal(seat, "not_a_model_ref", `${seat} is ${bindingShown(s)}, not a model reference — a role binds a catalog model name, a Model object or a { model, select, thinking, systemPrompt } record.`);
|
|
173
|
+
}
|
|
141
174
|
if ("id" in s && "api" in s) {
|
|
142
175
|
return { model: s };
|
|
143
176
|
}
|
|
@@ -191,12 +224,17 @@ function mergeRoles(base, over) {
|
|
|
191
224
|
}
|
|
192
225
|
return out;
|
|
193
226
|
}
|
|
194
|
-
function partsModel(parts, models) {
|
|
227
|
+
function partsModel(parts, models, seat = "a role seat") {
|
|
195
228
|
if (parts.model) {
|
|
196
229
|
return resolveModel(parts.model, models);
|
|
197
230
|
}
|
|
198
231
|
if (parts.select) {
|
|
199
|
-
|
|
232
|
+
const needs = parts.select.needs;
|
|
233
|
+
if (needs != null && !Array.isArray(needs)) {
|
|
234
|
+
throw modelBindingRefusal(`${seat}.select`, "not_a_model_ref", `${seat}.select.needs is ${bindingShown(needs)}, not a list of capabilities (vision / reasoning).`);
|
|
235
|
+
}
|
|
236
|
+
const held = models != null && typeof models === "object" ? Object.values(models).filter(Boolean) : [];
|
|
237
|
+
return selectModel(held, parts.select);
|
|
200
238
|
}
|
|
201
239
|
return undefined;
|
|
202
240
|
}
|
|
@@ -204,7 +242,7 @@ export function resolveTaskModel(spec, deps) {
|
|
|
204
242
|
const start = spec.modelRole ?? "default";
|
|
205
243
|
assertKnownRole(start, "modelRole");
|
|
206
244
|
if (spec.model) {
|
|
207
|
-
const startParts = specParts(mergeRoles(deps.roles, spec.roles)[start]);
|
|
245
|
+
const startParts = specParts(mergeRoles(deps.roles, spec.roles)[start], `roles.${start}`);
|
|
208
246
|
return {
|
|
209
247
|
model: resolveModel(spec.model, deps.models),
|
|
210
248
|
modelRef: spec.model,
|
|
@@ -213,10 +251,10 @@ export function resolveTaskModel(spec, deps) {
|
|
|
213
251
|
};
|
|
214
252
|
}
|
|
215
253
|
const merged = mergeRoles(deps.roles, spec.roles);
|
|
216
|
-
const startSystemPrompt = specParts(merged[start]).systemPrompt;
|
|
254
|
+
const startSystemPrompt = specParts(merged[start], `roles.${start}`).systemPrompt;
|
|
217
255
|
for (const role of [start, ...FALLBACK[start]]) {
|
|
218
|
-
const parts = specParts(merged[role]);
|
|
219
|
-
const fromParts = partsModel(parts, deps.models);
|
|
256
|
+
const parts = specParts(merged[role], `roles.${role}`);
|
|
257
|
+
const fromParts = partsModel(parts, deps.models, `roles.${role}`);
|
|
220
258
|
const model = fromParts ?? roleTierModel(role, deps.models);
|
|
221
259
|
if (model) {
|
|
222
260
|
const modelRef = fromParts !== undefined ? (parts.model ?? model) : (ROLE_TIER_DEFAULTS[role] ?? model);
|
|
@@ -227,5 +265,17 @@ export function resolveTaskModel(spec, deps) {
|
|
|
227
265
|
}
|
|
228
266
|
export function roleModelIfSet(role, spec, deps) {
|
|
229
267
|
const merged = mergeRoles(deps.roles, spec.roles);
|
|
230
|
-
|
|
268
|
+
const seat = `roles.${role}`;
|
|
269
|
+
const parts = specParts(merged[role], seat);
|
|
270
|
+
const named = parts.model;
|
|
271
|
+
if (named) {
|
|
272
|
+
if (typeof named === "string") {
|
|
273
|
+
if (catalogModel(named, deps.models) === undefined)
|
|
274
|
+
throw unknownModelRefRefusal(named, seat);
|
|
275
|
+
}
|
|
276
|
+
else if (typeof named !== "object" || Array.isArray(named)) {
|
|
277
|
+
throw modelBindingRefusal(seat, "not_a_model_ref", `${seat}.model is ${bindingShown(named)}, not a model reference — a role binds a catalog model name or a Model object.`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return partsModel(parts, deps.models, seat) ?? roleTierModel(role, deps.models);
|
|
231
281
|
}
|
|
@@ -65,7 +65,7 @@ export function normalizeOrgGateVerdict(answer, unreadable) {
|
|
|
65
65
|
if ((behavior !== "deny" && behavior !== "ask") || typeof rule !== "string")
|
|
66
66
|
return clean({ status: "unavailable", disclosures: [unreadable] });
|
|
67
67
|
const reason = ownDataValue(verdict, "unreadable");
|
|
68
|
-
const unreadableCell =
|
|
68
|
+
const unreadableCell = typeof reason === "string" ? { unreadable: reason } : {};
|
|
69
69
|
return clean({ status: "available", verdict: clean({ behavior: behavior, rule, ...unreadableCell }), ...revisionCell });
|
|
70
70
|
}
|
|
71
71
|
function copiedDenial(raw, ruleTexts) {
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the approving person wrote on the card ({@link ResumeOutcome} `policy_ask` `allow` `feedback`) — the one place that
|
|
3
|
+
* says what counts as written, which decide may carry it, and how it joins the resume continuation.
|
|
4
|
+
*
|
|
5
|
+
* ONE READING of "did the person write anything" ({@link writtenFeedback}): the text with the whitespace the card's input does
|
|
6
|
+
* not keep removed, or nothing when that leaves nothing. The pre-CAS checks and the continuation both ask it, so they cannot
|
|
7
|
+
* disagree about a blank value. (A deny's `reason` keeps its own rule, `decidersNote`: only `""` is blank there.)
|
|
8
|
+
*
|
|
9
|
+
* The words ride the resume continuation user message — the first message after the batch's tool results, once the batch's
|
|
10
|
+
* unanswered siblings have settled — as a user-lane range of their own: outside every engine segment, so a derived view reads
|
|
11
|
+
* them as user speech; verbatim, no fence, no wrapper sentence, no length bound. They are owed with the rest of the
|
|
12
|
+
* continuation: when the batch parks again before the prompt lands they ride the new row as its last parked steer.
|
|
13
|
+
*/
|
|
14
|
+
import { type PendingSteerEntry, type ResumeOutcome } from "../checkpoint-store.js";
|
|
15
|
+
type PolicyAsk = Extract<ResumeOutcome, {
|
|
16
|
+
gate: "policy_ask";
|
|
17
|
+
}>;
|
|
18
|
+
/** The words as the model is to read them, or `undefined` when nothing was written (absent, empty, whitespace-only). */
|
|
19
|
+
export declare function writtenFeedback(feedback: string | undefined): string | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Pre-CAS: a WRITTEN feedback is the allow arm's, a person's, and free of the `<system-reminder>` tag (opening or closing — the one
|
|
22
|
+
* judge `sanitizeUntrustedText`, the same rule a deny's `reason` is held to, applied here by the same call). Each is refused
|
|
23
|
+
* (`checkpoint.invalid_outcome`, the row stays pending for a well-formed decide) rather than dropped or delivered as something it
|
|
24
|
+
* is not: a deny's words are `reason`, and a machine's text must never reach the model as the user's. The twin is the captured
|
|
25
|
+
* plain data (its text already held to the string domain by the capture), never the caller's object.
|
|
26
|
+
*/
|
|
27
|
+
export declare function refuseUnfitFeedback(twin: PolicyAsk): void;
|
|
28
|
+
/** The words this resume is to deliver: a person's `allow` carrying a written feedback (the pre-CAS checks have run), else `undefined`. */
|
|
29
|
+
export declare function approvalWordsOf(outcome: ResumeOutcome): string | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* The continuation with the words as its last range. The separator glue before them is engine bytes (its own segment), so the
|
|
32
|
+
* stored message's user-lane range is exactly the words. Appends to `engineSegments` in place; the caller owns both.
|
|
33
|
+
*/
|
|
34
|
+
export declare function withApprovalWords(continuation: string, engineSegments: Array<{
|
|
35
|
+
start: number;
|
|
36
|
+
end: number;
|
|
37
|
+
}>, words: string): string;
|
|
38
|
+
/**
|
|
39
|
+
* The words as the continuation's owed content: the last parked steer, an untrusted one (the carrier that exists for an owed instruction).
|
|
40
|
+
* The frame is remembered by identity ({@link isApprovalWordsFrame}) — never by a member, which the steer store would refuse as an unknown
|
|
41
|
+
* key — so the owed account can count it as what it is (`detail.kind: "approval_feedback"`) and tell a recoverable retry from a loss.
|
|
42
|
+
*/
|
|
43
|
+
export declare function owedApprovalWords(words: string | undefined, inputId: string): Array<Omit<PendingSteerEntry, "seq">>;
|
|
44
|
+
/** Whether `frame` is one {@link owedApprovalWords} minted. */
|
|
45
|
+
export declare function isApprovalWordsFrame(frame: object): boolean;
|
|
46
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { CheckpointError } from "../checkpoint-store.js";
|
|
2
|
+
import { sanitizeUntrustedText, sentinelTagRefusal } from "../untrusted-text.js";
|
|
3
|
+
export function writtenFeedback(feedback) {
|
|
4
|
+
const trimmed = feedback?.trim();
|
|
5
|
+
return trimmed === undefined || trimmed === "" ? undefined : trimmed;
|
|
6
|
+
}
|
|
7
|
+
export function refuseUnfitFeedback(twin) {
|
|
8
|
+
const words = writtenFeedback(twin.feedback);
|
|
9
|
+
if (words === undefined)
|
|
10
|
+
return;
|
|
11
|
+
if (twin.decision !== "allow") {
|
|
12
|
+
throw new CheckpointError("checkpoint.invalid_outcome", "resume carried `feedback` on a `deny` — feedback is the approving person's words on an `allow` (a denial's words are `reason`); refusing rather than dropping it silently, the checkpoint stays pending");
|
|
13
|
+
}
|
|
14
|
+
const byPerson = twin.hostDecision.decidedBy === "person";
|
|
15
|
+
if (!byPerson) {
|
|
16
|
+
throw new CheckpointError("checkpoint.invalid_outcome", `resume carried \`feedback\` on a decide made by "${twin.hostDecision.decidedBy}" — feedback is delivered to the model as the user's own words, which only a person's decide can be; refusing rather than attributing a machine's text to the user, the checkpoint stays pending`);
|
|
17
|
+
}
|
|
18
|
+
if (sanitizeUntrustedText(words) !== words) {
|
|
19
|
+
throw new CheckpointError("checkpoint.invalid_outcome", sentinelTagRefusal("resume allow feedback"));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function approvalWordsOf(outcome) {
|
|
23
|
+
return outcome.gate === "policy_ask" && outcome.decision === "allow" ? writtenFeedback(outcome.feedback) : undefined;
|
|
24
|
+
}
|
|
25
|
+
export function withApprovalWords(continuation, engineSegments, words) {
|
|
26
|
+
const glueStart = continuation.length;
|
|
27
|
+
const withGlue = `${continuation}\n\n`;
|
|
28
|
+
engineSegments.push({ start: glueStart, end: withGlue.length });
|
|
29
|
+
return withGlue + words;
|
|
30
|
+
}
|
|
31
|
+
const APPROVAL_WORDS_FRAMES = new WeakSet();
|
|
32
|
+
export function owedApprovalWords(words, inputId) {
|
|
33
|
+
if (words === undefined)
|
|
34
|
+
return [];
|
|
35
|
+
const frame = { text: words, trusted: false, inputId };
|
|
36
|
+
APPROVAL_WORDS_FRAMES.add(frame);
|
|
37
|
+
return [frame];
|
|
38
|
+
}
|
|
39
|
+
export function isApprovalWordsFrame(frame) {
|
|
40
|
+
return APPROVAL_WORDS_FRAMES.has(frame);
|
|
41
|
+
}
|
|
@@ -23,13 +23,13 @@ import { type CompactionSettings } from "../../internal/harness.js";
|
|
|
23
23
|
* because reading it at the moment of the pass — not at prepare — is the whole of what it states.
|
|
24
24
|
*/
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
26
|
+
* The post-compaction restore (LONGRUN-2; the reference's post-compact file restore, cli296.js:249523 `attachments`).
|
|
27
27
|
*
|
|
28
28
|
* CC parity: post-compact file re-read is DEFAULT ON (CC hard-codes it;
|
|
29
29
|
* LONGRUN-2 measured ≈2.3 extra read round-trips per compaction without it). `false` opts out; an
|
|
30
30
|
* object customizes caps. Selection set = most recently READ (CC readFileState semantics) with a
|
|
31
|
-
* modified-files fallback inside maybeCompact. Returns `undefined` when
|
|
32
|
-
* task has no hands (no `
|
|
31
|
+
* modified-files fallback inside maybeCompact. Returns `undefined` when the restore is off or the
|
|
32
|
+
* task has no hands (no `compactionRestore` ⇒ nothing can be re-read).
|
|
33
33
|
*/
|
|
34
34
|
export declare function buildWorkingFileAttachments(spec: TaskSpec, prepared: Prepared): MaybeCompactOptions["workingFileAttachments"];
|
|
35
35
|
/**
|
|
@@ -3,10 +3,10 @@ import { buildToolResultRef, OFFLOAD_TOOL_NAME, PERSISTED_OUTPUT_PREFIX, toolRes
|
|
|
3
3
|
import { compactionEnabled, contextOverlayFor } from "../context-settings.js";
|
|
4
4
|
import { DEFAULT_COMPACTION_SETTINGS } from "../../internal/harness.js";
|
|
5
5
|
export function buildWorkingFileAttachments(spec, prepared) {
|
|
6
|
-
if (spec.compaction?.attachWorkingFiles === false || !prepared.
|
|
6
|
+
if (spec.compaction?.attachWorkingFiles === false || !prepared.compactionRestore)
|
|
7
7
|
return undefined;
|
|
8
8
|
return {
|
|
9
|
-
|
|
9
|
+
...prepared.compactionRestore,
|
|
10
10
|
...(prepared.recentlyReadFiles ? { recentlyReadFiles: prepared.recentlyReadFiles } : {}),
|
|
11
11
|
...(prepared.normalizeAttachmentPath ? { normalizePath: prepared.normalizeAttachmentPath } : {}),
|
|
12
12
|
...(prepared.isDedupStubResult ? { isDedupStubResult: prepared.isDedupStubResult } : {}),
|