@sema-agent/core 7.51.2 → 7.53.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 +698 -2
- package/README.md +3 -1
- package/dist/agents/agent-transcript-tool.d.ts +1 -1
- package/dist/agents/cascade.js +4 -0
- 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/cumulative-stats.d.ts +3 -0
- package/dist/agents/cumulative-stats.js +3 -0
- package/dist/agents/list-agents-tool.d.ts +1 -1
- 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 -5
- package/dist/agents/peer-session-drain.js +271 -180
- package/dist/agents/read-inbox-tool.d.ts +8 -1
- package/dist/agents/read-inbox-tool.js +5 -1
- package/dist/agents/repair-loop.js +4 -0
- package/dist/agents/send-message-tool.d.ts +11 -16
- package/dist/agents/send-message-tool.js +11 -13
- package/dist/agents/subagent.d.ts +3 -0
- package/dist/agents/subagent.js +105 -76
- package/dist/agents/tool-filter.d.ts +58 -13
- package/dist/agents/tool-filter.js +34 -14
- package/dist/bench/metrics.d.ts +1 -0
- package/dist/brain/anthropic.d.ts +6 -1
- package/dist/brain/anthropic.js +17 -13
- package/dist/brain/model-presets.d.ts +4 -5
- package/dist/brain/model-presets.js +6 -5
- package/dist/brain/open-responses.js +16 -12
- package/dist/brain/openai.js +16 -12
- package/dist/brain/request-params.d.ts +12 -33
- package/dist/brain/request-params.js +5 -2
- package/dist/brain/request-route.d.ts +9 -8
- package/dist/brain/request-route.js +1 -0
- package/dist/brain/route-adjudicator.d.ts +123 -47
- package/dist/brain/route-adjudicator.js +171 -42
- package/dist/brain/route-conformance.js +2 -2
- package/dist/brain/routing.d.ts +24 -1
- package/dist/brain/routing.js +54 -19
- package/dist/brain/status-sink.d.ts +18 -0
- package/dist/brain/status-sink.js +7 -0
- package/dist/brain/timeout.js +5 -4
- package/dist/core/a2a.d.ts +5 -2
- package/dist/core/a2a.js +30 -13
- package/dist/core/allow-entry.d.ts +42 -9
- package/dist/core/allow-entry.js +25 -18
- package/dist/core/auto-compaction.d.ts +80 -20
- package/dist/core/auto-compaction.js +65 -18
- package/dist/core/auto-promote.d.ts +2 -1
- package/dist/core/auto-promote.js +2 -2
- package/dist/core/caller-tool-name.d.ts +9 -0
- package/dist/core/caller-tool-name.js +13 -0
- package/dist/core/checkpoint-requirements.d.ts +7 -1
- package/dist/core/checkpoint-requirements.js +2 -0
- package/dist/core/checkpoint-store.d.ts +57 -24
- package/dist/core/checkpoint-store.js +3 -3
- package/dist/core/child-clamp-seats.d.ts +6 -0
- package/dist/core/child-clamp-seats.js +2 -1
- package/dist/core/compliance.js +3 -1
- package/dist/core/credential-vocabulary.d.ts +33 -8
- package/dist/core/credential-vocabulary.js +32 -7
- package/dist/core/decision-receipt.d.ts +2 -2
- package/dist/core/delegation-frames.d.ts +9 -2
- package/dist/core/delegation-name.d.ts +18 -0
- package/dist/core/delegation-name.js +47 -0
- package/dist/core/effective-path-target.d.ts +25 -6
- package/dist/core/effective-path-target.js +24 -2
- package/dist/core/engine-capabilities.d.ts +8 -1
- package/dist/core/engine-capabilities.js +1 -1
- package/dist/core/engine-notice.d.ts +49 -21
- package/dist/core/frontmatter-fence.d.ts +10 -0
- package/dist/core/frontmatter-fence.js +6 -0
- package/dist/core/gate-fold.js +8 -25
- package/dist/core/gate-lanes.js +358 -274
- package/dist/core/gate-outcome.d.ts +11 -6
- package/dist/core/governance-codes.d.ts +11 -4
- package/dist/core/governance-codes.js +12 -3
- 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 +283 -739
- package/dist/core/hooks.js +100 -193
- package/dist/{tools/fs → core}/image-admission.d.ts +21 -3
- package/dist/{tools/fs → core}/image-admission.js +24 -6
- package/dist/core/locked-config.d.ts +84 -32
- package/dist/core/locked-config.js +128 -42
- package/dist/core/mcp-connection-pool.d.ts +4 -1
- package/dist/core/mcp-connection-pool.js +7 -2
- package/dist/core/mcp-probe.d.ts +12 -9
- package/dist/core/mcp-probe.js +3 -3
- package/dist/core/mcp-server-spec.d.ts +104 -10
- package/dist/core/mcp-server-spec.js +183 -33
- package/dist/core/mcp.d.ts +31 -20
- package/dist/core/mcp.js +66 -56
- package/dist/core/memory-engine/data-plane.js +5 -1
- package/dist/core/memory-engine/distiller.js +16 -2
- package/dist/core/memory-engine/engine.d.ts +22 -30
- package/dist/core/memory-engine/engine.js +16 -10
- package/dist/core/memory-engine/frontmatter.d.ts +6 -0
- package/dist/core/memory-engine/frontmatter.js +19 -16
- package/dist/core/memory.d.ts +2 -2
- package/dist/core/mode-policy.d.ts +5 -16
- package/dist/core/mode-policy.js +7 -19
- package/dist/core/model-seat.d.ts +4 -1
- package/dist/core/mods/dollar.d.ts +109 -0
- package/dist/core/mods/dollar.js +154 -0
- package/dist/core/mods/host.d.ts +23 -0
- package/dist/core/mods/host.js +21 -0
- package/dist/core/mods/kernel/budget.d.ts +43 -0
- package/dist/core/mods/kernel/budget.js +83 -0
- package/dist/core/mods/kernel/dispatch.d.ts +100 -0
- package/dist/core/mods/kernel/dispatch.js +699 -0
- package/dist/core/mods/kernel/events.d.ts +245 -0
- package/dist/core/mods/kernel/events.js +210 -0
- package/dist/core/mods/kernel/index.d.ts +6 -0
- package/dist/core/mods/kernel/index.js +5 -0
- package/dist/core/mods/kernel/receive.d.ts +94 -0
- package/dist/core/mods/kernel/receive.js +188 -0
- package/dist/core/mods/kernel/registration.d.ts +131 -0
- package/dist/core/mods/kernel/registration.js +102 -0
- package/dist/core/mods/kernel/site-rules.d.ts +149 -0
- package/dist/core/mods/kernel/site-rules.js +296 -0
- package/dist/core/mods/stations.d.ts +344 -0
- package/dist/core/mods/stations.js +437 -0
- 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 +13 -23
- package/dist/core/parent-spec-seat.d.ts +18 -7
- package/dist/core/parent-spec-seat.js +6 -2
- package/dist/core/path-identity.js +2 -1
- package/dist/core/permission-rule-model.d.ts +58 -9
- package/dist/core/permission-rule-model.js +81 -7
- package/dist/core/permission-rule-org.d.ts +163 -33
- package/dist/core/permission-rule-org.js +205 -71
- package/dist/core/permission-rule-syntax.d.ts +15 -0
- package/dist/core/permission-rule-syntax.js +24 -16
- package/dist/core/permission-rules.d.ts +14 -2
- package/dist/core/permission-rules.js +63 -23
- package/dist/core/prompt-section-seat.d.ts +15 -27
- package/dist/core/prompt-section-seat.js +73 -40
- package/dist/core/protocol-http-auth.d.ts +3 -1
- package/dist/core/protocol-http-auth.js +2 -0
- package/dist/core/reminder-mint.d.ts +2 -2
- package/dist/core/remote-env.d.ts +24 -12
- package/dist/core/remote-env.js +1 -0
- package/dist/core/resume-startup-cause.d.ts +16 -1
- package/dist/core/resume-startup-cause.js +4 -1
- package/dist/core/retention.js +7 -2
- package/dist/core/retired-keys.d.ts +12 -2
- package/dist/core/retired-keys.js +15 -1
- package/dist/core/roles.js +60 -10
- package/dist/core/rule-lane-reads.js +1 -1
- package/dist/core/runner/announce-once-ledger.d.ts +31 -1
- package/dist/core/runner/announce-once-ledger.js +22 -0
- package/dist/core/runner/assemble-result.d.ts +9 -0
- package/dist/core/runner/assemble-result.js +3 -1
- package/dist/core/runner/call-hook-stations.d.ts +23 -27
- package/dist/core/runner/call-hook-stations.js +58 -42
- package/dist/core/runner/caller-stop-gate.d.ts +25 -0
- package/dist/core/runner/caller-stop-gate.js +7 -0
- package/dist/core/runner/compaction-seams.d.ts +8 -22
- package/dist/core/runner/compaction-seams.js +28 -53
- package/dist/core/runner/construction-doors.js +11 -1
- package/dist/core/runner/contracts.d.ts +86 -83
- package/dist/core/runner/credential-origin-seat.d.ts +2 -0
- package/dist/core/runner/credential-origin-seat.js +19 -0
- package/dist/core/runner/extra-body-dropped-seat.d.ts +2 -6
- package/dist/core/runner/gate-exit.d.ts +47 -36
- package/dist/core/runner/gate-exit.js +12 -5
- package/dist/core/runner/image.js +1 -2
- package/dist/core/runner/inline-image.js +1 -1
- package/dist/core/runner/mcp-redial.d.ts +52 -10
- package/dist/core/runner/mcp-redial.js +38 -9
- package/dist/core/runner/notice-seat-input.d.ts +11 -0
- package/dist/core/runner/notice-seat-input.js +1 -0
- 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 +3 -1
- package/dist/core/runner/person-path-rows.js +3 -2
- package/dist/core/runner/prepare-acquire-reconcile.js +5 -1
- package/dist/core/runner/prepare-ask-lane.d.ts +5 -7
- package/dist/core/runner/prepare-ask-lane.js +6 -15
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -2
- package/dist/core/runner/prepare-caps-and-workflow.js +25 -8
- package/dist/core/runner/prepare-config-doors.d.ts +52 -1
- package/dist/core/runner/prepare-config-doors.js +168 -143
- package/dist/core/runner/prepare-defer-classify.js +7 -11
- package/dist/core/runner/prepare-delegation-surface.d.ts +2 -2
- package/dist/core/runner/prepare-delegation-surface.js +7 -5
- package/dist/core/runner/prepare-gate-stations.d.ts +8 -11
- package/dist/core/runner/prepare-gate-stations.js +11 -10
- package/dist/core/runner/prepare-hands-readface.d.ts +1 -1
- package/dist/core/runner/prepare-hands-readface.js +2 -1
- package/dist/core/runner/prepare-inherited-gate.d.ts +8 -12
- package/dist/core/runner/prepare-inherited-gate.js +10 -23
- 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 +20 -7
- 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.js +10 -14
- package/dist/core/runner/prepare-policy-chain.d.ts +17 -15
- package/dist/core/runner/prepare-policy-chain.js +104 -109
- package/dist/core/runner/prepare-project-context.d.ts +1 -1
- package/dist/core/runner/prepare-project-context.js +11 -12
- package/dist/core/runner/prepare-prompt-assembly.d.ts +45 -40
- package/dist/core/runner/prepare-prompt-assembly.js +138 -101
- package/dist/core/runner/prepare-prompt-inputs.d.ts +28 -23
- package/dist/core/runner/prepare-prompt-inputs.js +11 -10
- package/dist/core/runner/prepare-protocol-tools.d.ts +11 -7
- package/dist/core/runner/prepare-protocol-tools.js +20 -13
- 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.js +6 -10
- package/dist/core/runner/prepare-suspend-saga.d.ts +6 -0
- package/dist/core/runner/prepare-suspend-saga.js +7 -5
- package/dist/core/runner/prepare-task.js +41 -23
- package/dist/core/runner/prepare-turn-wiring.d.ts +13 -15
- package/dist/core/runner/prepare-turn-wiring.js +29 -27
- package/dist/core/runner/prepare-wiring-manifest.d.ts +13 -9
- package/dist/core/runner/prepare-wiring-manifest.js +14 -11
- package/dist/core/runner/resume-admission.d.ts +4 -1
- package/dist/core/runner/resume-admission.js +7 -5
- package/dist/core/runner/resume-apply.d.ts +5 -2
- package/dist/core/runner/resume-apply.js +24 -42
- package/dist/core/runner/resume-checkpoint-screen.d.ts +1 -0
- package/dist/core/runner/resume-checkpoint-screen.js +9 -1
- 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-preflight.js +38 -16
- package/dist/core/runner/retired-runner-deps.d.ts +5 -6
- package/dist/core/runner/retired-runner-deps.js +4 -5
- package/dist/core/runner/run-brain-sinks.d.ts +3 -2
- package/dist/core/runner/run-brain-sinks.js +5 -1
- package/dist/core/runner/run-compaction-machinery.d.ts +7 -1
- package/dist/core/runner/run-compaction-machinery.js +7 -33
- package/dist/core/runner/run-harness-handlers.js +4 -2
- package/dist/core/runner/run-identity-wiring.d.ts +3 -1
- package/dist/core/runner/run-identity-wiring.js +3 -2
- package/dist/core/runner/run-leg.js +103 -95
- package/dist/core/runner/run-notification-lane.js +1 -0
- package/dist/core/runner/run-recovery-lanes.d.ts +3 -0
- package/dist/core/runner/run-recovery-lanes.js +14 -11
- package/dist/core/runner/run-settle-and-teardown.js +9 -28
- package/dist/core/runner/run-stop-and-final-verify.js +18 -25
- package/dist/core/runner/run-terminal-adoption.d.ts +3 -0
- package/dist/core/runner/run-terminal-adoption.js +34 -22
- package/dist/core/runner/run-tool-mount-facts.js +5 -3
- package/dist/core/runner/run-turn-boundary.js +32 -37
- package/dist/core/runner/runtask.d.ts +6 -7
- package/dist/core/runner/runtask.js +15 -73
- package/dist/core/runner/session-rule-policy.d.ts +5 -5
- package/dist/core/runner/session-rule-policy.js +13 -8
- package/dist/core/runner/side-call-account.d.ts +68 -0
- package/dist/core/runner/side-call-account.js +61 -0
- package/dist/core/runner/skills-seat.d.ts +15 -0
- package/dist/core/runner/skills-seat.js +57 -0
- package/dist/core/runner/stream-halt-verbs.js +12 -17
- package/dist/core/runner/stream-lifecycle-verbs.js +8 -5
- package/dist/core/runner/stream-steer-verb.d.ts +1 -1
- package/dist/core/runner/stream-steer-verb.js +20 -38
- package/dist/core/runner/sub-agent-deny-lists.d.ts +124 -23
- package/dist/core/runner/sub-agent-deny-lists.js +230 -71
- package/dist/core/runner/synthetic-tools.d.ts +5 -2
- package/dist/core/runner/synthetic-tools.js +2 -12
- package/dist/core/runner/tool-end-body.d.ts +5 -6
- package/dist/core/runner/tool-end-body.js +6 -4
- package/dist/core/runner/tool-not-executed.d.ts +15 -0
- package/dist/core/runner/tool-not-executed.js +30 -0
- package/dist/core/runner/tool-occurrence.d.ts +8 -7
- package/dist/core/runner/tool-occurrence.js +5 -5
- package/dist/core/runner/tool-result-media-seat.d.ts +1 -1
- package/dist/core/runner-deps.d.ts +43 -36
- package/dist/core/safety-merge-corpus.js +18 -2
- package/dist/core/secret-env.d.ts +88 -20
- package/dist/core/secret-env.js +192 -38
- package/dist/core/session-policy-store.d.ts +71 -16
- package/dist/core/session-policy-store.js +138 -28
- package/dist/core/session-reconcile.d.ts +4 -0
- package/dist/core/session-reconcile.js +2 -1
- package/dist/core/shell-read-silence.js +3 -32
- package/dist/core/side-query.d.ts +5 -3
- package/dist/core/skill-grant.d.ts +3 -2
- package/dist/core/skill-grant.js +17 -9
- package/dist/core/skills-directory.d.ts +31 -11
- package/dist/core/skills-directory.js +655 -104
- package/dist/core/store-contracts/mailbox-store-contract.js +13 -0
- package/dist/core/task-event.d.ts +49 -3
- package/dist/core/task-notification.js +2 -2
- package/dist/core/task-result.d.ts +8 -0
- package/dist/core/task-spec.d.ts +20 -19
- package/dist/core/task-stream.d.ts +14 -4
- package/dist/core/tighten-task-spec.d.ts +4 -3
- package/dist/core/tighten-task-spec.js +2 -4
- package/dist/core/tool-check-reading.d.ts +74 -0
- package/dist/core/tool-check-reading.js +80 -0
- package/dist/core/tool-policy.d.ts +62 -18
- package/dist/core/tool-policy.js +86 -15
- package/dist/core/tool-registry.d.ts +20 -0
- package/dist/core/tool-registry.js +4 -0
- package/dist/core/tool-spec.d.ts +10 -6
- package/dist/core/tools.js +2 -0
- package/dist/core/trace.d.ts +51 -32
- package/dist/core/types.d.ts +2 -2
- package/dist/core/types.js +1 -1
- package/dist/core/unc-spelling.d.ts +10 -0
- package/dist/core/unc-spelling.js +3 -0
- package/dist/core/untrusted-egress.d.ts +8 -0
- package/dist/core/untrusted-egress.js +4 -1
- package/dist/core/untrusted-text.d.ts +16 -0
- package/dist/core/untrusted-text.js +7 -2
- package/dist/core/user-attachment.d.ts +25 -4
- package/dist/core/user-attachment.js +63 -42
- package/dist/core/wiring-manifest.d.ts +18 -15
- package/dist/core/wiring-manifest.js +2 -2
- package/dist/engine/compaction/utils.js +1 -2
- package/dist/engine/execution-env/node-execution-env.d.ts +4 -3
- package/dist/engine/execution-env/symlink-chain.js +1 -1
- package/dist/engine/harness/agent-harness.d.ts +1 -1
- package/dist/engine/harness/agent-harness.js +5 -4
- package/dist/engine/harness/types.d.ts +20 -16
- package/dist/engine/harness/types.js +7 -1
- package/dist/engine/llm/types.d.ts +12 -7
- package/dist/engine/loop/agent-loop.d.ts +12 -1
- package/dist/engine/loop/agent-loop.js +18 -6
- package/dist/engine/loop/types.d.ts +8 -2
- package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
- package/dist/engine/session/import-validate.js +3 -10
- package/dist/engine/session/session.d.ts +4 -4
- package/dist/engine/session/session.js +4 -4
- package/dist/index.d.ts +33 -23
- package/dist/index.js +23 -15
- package/dist/internal/harness.d.ts +2 -1
- package/dist/internal/harness.js +2 -1
- package/dist/orchestration/goal.d.ts +24 -1
- package/dist/orchestration/goal.js +3 -2
- package/dist/orchestration/run-spec.d.ts +4 -6
- package/dist/orchestration/run-spec.js +39 -63
- package/dist/orchestration/run-workflow-tool.js +1 -2
- package/dist/orchestration/workflow.d.ts +11 -3
- package/dist/orchestration/workflow.js +11 -2
- package/dist/prompt-assembly/artifact-store.d.ts +72 -56
- package/dist/prompt-assembly/artifact-store.js +60 -52
- package/dist/prompt-assembly/artifact.d.ts +90 -76
- package/dist/prompt-assembly/artifact.js +197 -145
- package/dist/prompt-assembly/assemble.d.ts +36 -29
- package/dist/prompt-assembly/assemble.js +34 -220
- package/dist/prompt-assembly/bands.d.ts +20 -0
- package/dist/prompt-assembly/bands.js +18 -0
- package/dist/prompt-assembly/catalog/constitution.d.ts +23 -0
- package/dist/prompt-assembly/catalog/constitution.js +69 -0
- package/dist/prompt-assembly/catalog/core-behavior.d.ts +9 -0
- package/dist/prompt-assembly/catalog/core-behavior.js +85 -0
- package/dist/prompt-assembly/catalog/index.d.ts +11 -0
- package/dist/prompt-assembly/catalog/index.js +60 -0
- package/dist/prompt-assembly/catalog/memory.d.ts +13 -0
- package/dist/prompt-assembly/catalog/memory.js +6 -0
- package/dist/prompt-assembly/catalog/modes.d.ts +15 -0
- package/dist/prompt-assembly/catalog/modes.js +137 -0
- package/dist/prompt-assembly/catalog/role.d.ts +10 -0
- package/dist/prompt-assembly/catalog/role.js +157 -0
- package/dist/prompt-assembly/catalog/schema.d.ts +138 -0
- package/dist/prompt-assembly/catalog/schema.js +25 -0
- package/dist/prompt-assembly/catalog/sections.d.ts +9 -0
- package/dist/prompt-assembly/catalog/sections.js +98 -0
- package/dist/prompt-assembly/catalog/team.d.ts +4 -0
- package/dist/prompt-assembly/catalog/team.js +258 -0
- package/dist/prompt-assembly/composer.d.ts +26 -28
- package/dist/prompt-assembly/composer.js +124 -46
- package/dist/prompt-assembly/epoch.d.ts +89 -79
- package/dist/prompt-assembly/epoch.js +115 -142
- package/dist/prompt-assembly/explain.d.ts +58 -34
- package/dist/prompt-assembly/explain.js +21 -24
- package/dist/prompt-assembly/overlay.d.ts +137 -0
- package/dist/prompt-assembly/overlay.js +339 -0
- package/dist/prompt-assembly/renderers.d.ts +21 -0
- package/dist/prompt-assembly/renderers.js +39 -0
- package/dist/prompt-assembly/section-usage.d.ts +3 -3
- package/dist/prompt-assembly/section-usage.js +1 -1
- package/dist/prompt-assembly/select.d.ts +71 -0
- package/dist/prompt-assembly/select.js +106 -0
- package/dist/prompt-assembly/sugar.d.ts +31 -0
- package/dist/prompt-assembly/sugar.js +20 -0
- package/dist/prompt-assembly/turn-snapshot.d.ts +3 -2
- package/dist/prompt-assembly/types.d.ts +45 -148
- package/dist/prompts/coordinator.d.ts +2 -21
- package/dist/prompts/coordinator.js +3 -255
- package/dist/prompts/cowork.d.ts +27 -16
- package/dist/prompts/cowork.js +2 -23
- package/dist/prompts/default.d.ts +38 -511
- package/dist/prompts/default.js +20 -288
- package/dist/prompts/supervisor.d.ts +6 -71
- package/dist/prompts/supervisor.js +6 -117
- 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 +4 -3
- package/dist/tools/fs/bash-readonly-classifier.d.ts +6 -5
- package/dist/tools/fs/dir-entries.d.ts +4 -2
- package/dist/tools/fs/dir-entries.js +16 -4
- package/dist/tools/fs/fs-bash.d.ts +1 -1
- package/dist/tools/fs/fs-bash.js +22 -11
- package/dist/tools/fs/fs-pdf.js +17 -13
- package/dist/tools/fs/fs-read.js +4 -3
- package/dist/tools/fs/fs-shared.d.ts +1 -10
- package/dist/tools/fs/fs-shared.js +3 -4
- package/dist/tools/fs/fs-write.js +2 -1
- package/dist/tools/fs/notebook.js +1 -1
- package/dist/tools/fs/pdf.d.ts +20 -10
- package/dist/tools/fs/pdf.js +19 -10
- package/dist/tools/fs/program-read-model.d.ts +68 -8
- package/dist/tools/fs/program-read-model.js +112 -33
- package/dist/tools/fs/program-read-model.rows.js +30 -10
- package/dist/tools/fs/read-deny-home.d.ts +25 -9
- package/dist/tools/fs/read-deny-home.js +28 -27
- package/dist/tools/fs/read-deny.d.ts +41 -11
- package/dist/tools/fs/read-deny.js +51 -5
- package/dist/tools/fs/safety.d.ts +4 -26
- package/dist/tools/fs/safety.js +10 -32
- package/dist/tools/fs/search.js +15 -10
- package/dist/tools/fs/shell-read-argv.d.ts +3 -2
- package/dist/tools/fs/shell-read-argv.js +118 -38
- package/dist/tools/fs/shell-read-establish.d.ts +5 -5
- package/dist/tools/fs/shell-read-establish.js +11 -61
- package/dist/tools/fs/shell-read-identity.js +6 -3
- package/dist/tools/fs/shell-read-judge.d.ts +13 -15
- package/dist/tools/fs/shell-read-judge.js +18 -4
- package/dist/tools/fs/shell-read-plan.d.ts +2 -2
- package/dist/tools/web.js +1 -1
- package/package.json +13 -1
- package/test/export-surface.snapshot.json +306 -103
- package/wire-changes/core@7.52.0.json +5859 -0
- package/wire-changes/core@7.53.0.json +1946 -0
- package/dist/core/hook-seats.d.ts +0 -66
- package/dist/core/hook-seats.js +0 -37
- package/dist/prompt-assembly/packs/sema-default.d.ts +0 -2
- package/dist/prompt-assembly/packs/sema-default.js +0 -147
- package/dist/prompts/simple-sections.d.ts +0 -58
- package/dist/prompts/simple-sections.js +0 -43
|
@@ -47,7 +47,10 @@
|
|
|
47
47
|
* The NAME lane is the same shape for the tools of `NAME_RULE_FACES` (the `Skill` tool): a `Skill(<name>)` / `Skill(<prefix>:*)`
|
|
48
48
|
* deny or ask — the reference's own spelling — compiles through the same validator (the model's name grammar) and is judged on the
|
|
49
49
|
* one string the call names (`nameRuleSubjectOf`) with `nameRuleAdmits`, the reader the persisted rule store uses. The parameter
|
|
50
|
-
* spelling `Skill(skill:<name>)` those tools used to take is retired: refused loudly, its sentence naming the CC form.
|
|
50
|
+
* spelling `Skill(skill:<name>)` those tools used to take is retired: refused loudly, its sentence naming the CC form. A KEYED
|
|
51
|
+
* value tool (`Artifact(action:<word>)`) takes the same lane for content keyed by its own parameter (`nameGrammarReads`); its
|
|
52
|
+
* other arguments stay on the generic `param:pattern` lane. A call of it that names no value for the key as the tool reads it
|
|
53
|
+
* is refused by the key's deny or ask rule (`keyedValueAbsentReason`, the persisted lane's reading).
|
|
51
54
|
*
|
|
52
55
|
* 🔴 与 CC 的有意差(design/127 r2):
|
|
53
56
|
* - CC 参数级 generic 道无 allow lane(gnn 只有 deny/ask)—— 我们同样,且整个 policy 无 allow 臂。
|
|
@@ -73,7 +76,13 @@ export interface PermissionRuleIssue {
|
|
|
73
76
|
rule: string;
|
|
74
77
|
/** `invalid.*` = 语法/语义错;`unsupported.*` = CC 合法但 v1 不支持的 lane(独立
|
|
75
78
|
* 分类,绝不静默 no-op —— `Bash(npm run:*)` 被当 generic 参数规则接受后永不匹配是最危险的失败形态)。 */
|
|
76
|
-
code: "invalid.empty_tool" | "invalid.paren"
|
|
79
|
+
code: "invalid.empty_tool" | "invalid.paren"
|
|
80
|
+
/** A rule the rule syntax reads no rule in (`ruleSpellingOf`) whose name is the reason: blanks around the rule, a
|
|
81
|
+
* character outside a tool name's spelling (a variation selector, a filler, a zero-width space), a blank or an invisible
|
|
82
|
+
* character before the `(`, a leading `-`. Refused — the lenient reading would deny a tool under another spelling, or none.
|
|
83
|
+
* Also a rule whose tool name the syntax reads as the wildcard `*` (`*`, `*()`, `*(*)`): a rule reaches the tool it
|
|
84
|
+
* names, and `*` names none. */
|
|
85
|
+
| "invalid.tool_name" | "invalid.param_split" | "invalid.primary_field" | "invalid.cap_exceeded"
|
|
77
86
|
/** An ALLOW rule (any spelling): a policy fold says deny / ask only — "this does not need asking" is the allow
|
|
78
87
|
* layer's (`TaskSpec.allowedTools`, `RunnerDeps.allowedTools`). One issue per allow rule. */
|
|
79
88
|
| "unsupported.allow"
|
|
@@ -120,6 +129,9 @@ export interface PermissionRuleCaps {
|
|
|
120
129
|
* 的热路径成本上界。 */
|
|
121
130
|
maxScalarValueChars: number;
|
|
122
131
|
}
|
|
132
|
+
/** The caps a rule set is held to unless the caller names its own — `maxRules` is the ONE bound on how many rules a set
|
|
133
|
+
* carries, read by the compiler here and by the org layer's list judgment (which refuses a longer list before it is copied). */
|
|
134
|
+
export declare const DEFAULT_CAPS: Readonly<PermissionRuleCaps>;
|
|
123
135
|
export interface PermissionRulePolicyOptions {
|
|
124
136
|
/** Invalid/unsupported rules: `"throw"`(default — 部署作者写错要立刻知道)aggregates ALL issues
|
|
125
137
|
* into one error; `"skip"` drops them (pair with {@link validatePermissionRules} for a report, and/or
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { attest } from "./tool-policy.js";
|
|
2
2
|
import { MCP_NAMESPACE, protocolOf } from "./protocol-table.js";
|
|
3
3
|
import { catalogRuleFaceOf, isShellFaceToolName, pathTargetOf } from "./tool-registry.js";
|
|
4
|
-
import { indexOfUnescaped, lastIndexOfUnescaped, parsePermissionRule } from "./permission-rule-syntax.js";
|
|
5
|
-
import { COMMAND_RULE_TOOL, NAME_RULE_FACES, PATH_RULE_BASE_LABEL, PATH_RULE_FACES, callPathFaceOf, isUsablePathBase, laneToolNamesOf, nameRuleAdmits, nameRuleSubjectOf, parseRuleText, programRunReachOf, ruleBasesNeeded
|
|
4
|
+
import { indexOfUnescaped, lastIndexOfUnescaped, parsePermissionRule, ruleSpellingOf } from "./permission-rule-syntax.js";
|
|
5
|
+
import { COMMAND_RULE_TOOL, NAME_RULE_FACES, PATH_RULE_BASE_LABEL, PATH_RULE_FACES, callPathFaceOf, isUsablePathBase, keyedValueAbsentReason, laneToolNamesOf, nameGrammarReads, nameRuleAdmits, nameRuleSubjectOf, parseRuleText, programRunReachOf, ruleBasesNeeded } from "./permission-rule-model.js";
|
|
6
6
|
import { pathFamilyOf } from "../tools/fs/safety.js";
|
|
7
|
-
import { callTargetReadingOf, callTargetViewsOf } from "./effective-path-target.js";
|
|
7
|
+
import { argsAsTheToolReads, callTargetReadingOf, callTargetViewsOf } from "./effective-path-target.js";
|
|
8
|
+
import { canonicalize, UNCANONICALIZABLE } from "./canonical-json.js";
|
|
8
9
|
import { bindPathRules, judgeRuleRows, policyAnchors, rowsWhereTheyLead } from "./path-rule-binding.js";
|
|
9
10
|
import { ruleDenialSentence } from "./rule-denial-sentence.js";
|
|
10
11
|
import { heldValues } from "./tool-name-readings.js";
|
|
@@ -24,7 +25,7 @@ function describeBehavior(v) {
|
|
|
24
25
|
default: return v === null ? "null" : "an object";
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
|
-
const DEFAULT_CAPS = {
|
|
28
|
+
export const DEFAULT_CAPS = {
|
|
28
29
|
maxRules: 256,
|
|
29
30
|
maxRuleLength: 512,
|
|
30
31
|
maxPatternLength: 256,
|
|
@@ -50,6 +51,25 @@ function countStars(s) {
|
|
|
50
51
|
n++;
|
|
51
52
|
return n;
|
|
52
53
|
}
|
|
54
|
+
function unreadableRuleIssue(text) {
|
|
55
|
+
const lenient = parsePermissionRule(text);
|
|
56
|
+
if (!lenient.toolName)
|
|
57
|
+
return { code: "invalid.empty_tool", message: "tool name cannot be empty" };
|
|
58
|
+
if (lenient.ruleContent === undefined && /[()\\]/.test(lenient.toolName)) {
|
|
59
|
+
return { code: "invalid.paren", message: "tool name still contains paren/escape characters — a mis-escaped rule would compile to a dead bare rule" };
|
|
60
|
+
}
|
|
61
|
+
const open = indexOfUnescaped(text, "(");
|
|
62
|
+
if (lenient.ruleContent === undefined && open !== -1) {
|
|
63
|
+
const close = lastIndexOfUnescaped(text, ")");
|
|
64
|
+
const legitimateBare = close === text.length - 1 && ["", "*"].includes(text.substring(open + 1, close));
|
|
65
|
+
if (!legitimateBare)
|
|
66
|
+
return { code: "invalid.paren", message: "malformed parentheses / trailing characters (would silently downgrade to a bare-tool rule)" };
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
code: "invalid.tool_name",
|
|
70
|
+
message: `the tool name is a spelling no tool name can have — the rule syntax reads no rule in it (blanks around the rule, a character outside a tool name's spelling, or one before the "("), so the rule would name no tool; fix the entry`,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
53
73
|
function compile(rules, caps, primaryFieldGeneric, ruleFaces, pathBases = {}) {
|
|
54
74
|
const faceOf = (toolName) => {
|
|
55
75
|
if (ruleFaces !== undefined) {
|
|
@@ -84,24 +104,16 @@ function compile(rules, caps, primaryFieldGeneric, ruleFaces, pathBases = {}) {
|
|
|
84
104
|
bad(text, "invalid.cap_exceeded", `rule longer than ${caps.maxRuleLength} chars`);
|
|
85
105
|
continue;
|
|
86
106
|
}
|
|
87
|
-
const parsed =
|
|
88
|
-
if (
|
|
89
|
-
|
|
107
|
+
const parsed = ruleSpellingOf(text);
|
|
108
|
+
if (parsed === undefined) {
|
|
109
|
+
const why = unreadableRuleIssue(text);
|
|
110
|
+
bad(text, why.code, why.message);
|
|
90
111
|
continue;
|
|
91
112
|
}
|
|
92
|
-
if (parsed.
|
|
93
|
-
bad(text, "invalid.
|
|
113
|
+
if (parsed.toolName === "*") {
|
|
114
|
+
bad(text, "invalid.tool_name", `\`*\` names no tool — a rule reaches the tool it names, so this one would compile and never match; name the tool, or state the answer for every call no rule reaches with \`defaultAction\``);
|
|
94
115
|
continue;
|
|
95
116
|
}
|
|
96
|
-
if (parsed.ruleContent === undefined && indexOfUnescaped(text, "(") !== -1) {
|
|
97
|
-
const open = indexOfUnescaped(text, "(");
|
|
98
|
-
const close = lastIndexOfUnescaped(text, ")");
|
|
99
|
-
const legitimateBare = close === text.length - 1 && ["", "*"].includes(text.substring(open + 1, close));
|
|
100
|
-
if (!legitimateBare) {
|
|
101
|
-
bad(text, "invalid.paren", "malformed parentheses / trailing characters (would silently downgrade to a bare-tool rule)");
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
117
|
const toolName = parsed.toolName;
|
|
106
118
|
const parenthesised = parsed.ruleContent !== undefined || indexOfUnescaped(text, "(") !== -1;
|
|
107
119
|
if (toolName.startsWith(MCP_NAMESPACE.prefix) && parenthesised) {
|
|
@@ -153,7 +165,7 @@ function compile(rules, caps, primaryFieldGeneric, ruleFaces, pathBases = {}) {
|
|
|
153
165
|
continue;
|
|
154
166
|
}
|
|
155
167
|
const face = resolved.face;
|
|
156
|
-
if (
|
|
168
|
+
if (nameGrammarReads(toolName, content)) {
|
|
157
169
|
const parsedName = parseRuleText(text, verb);
|
|
158
170
|
if ("reject" in parsedName) {
|
|
159
171
|
bad(text, "invalid.command_rule", `${parsedName.reject.code}: ${parsedName.reject.message}`);
|
|
@@ -231,12 +243,16 @@ export function validatePermissionRules(rules, opts) {
|
|
|
231
243
|
function isPlainObjectArgs(args) {
|
|
232
244
|
return typeof args === "object" && args !== null && !Array.isArray(args);
|
|
233
245
|
}
|
|
234
|
-
function matchParamRules(rules,
|
|
246
|
+
function matchParamRules(rules, req, maxScalarValueChars) {
|
|
247
|
+
const args = req.args;
|
|
235
248
|
if (!isPlainObjectArgs(args))
|
|
236
249
|
return undefined;
|
|
237
250
|
for (const r of rules) {
|
|
238
|
-
if (!Object.hasOwn(args, r.param))
|
|
251
|
+
if (!Object.hasOwn(args, r.param)) {
|
|
252
|
+
if (readingAbsorbs(req, r.param, r.pattern))
|
|
253
|
+
return r;
|
|
239
254
|
continue;
|
|
255
|
+
}
|
|
240
256
|
const raw = args[r.param];
|
|
241
257
|
if (raw === undefined || raw === null)
|
|
242
258
|
continue;
|
|
@@ -251,6 +267,17 @@ function matchParamRules(rules, args, maxScalarValueChars) {
|
|
|
251
267
|
}
|
|
252
268
|
return undefined;
|
|
253
269
|
}
|
|
270
|
+
function readingAbsorbs(req, param, pattern) {
|
|
271
|
+
if (pattern.includes("*"))
|
|
272
|
+
return false;
|
|
273
|
+
try {
|
|
274
|
+
const read = canonicalize(argsAsTheToolReads(req, { ...req.args, [param]: pattern }));
|
|
275
|
+
return read !== UNCANONICALIZABLE && read === canonicalize(req.args);
|
|
276
|
+
}
|
|
277
|
+
catch {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
254
281
|
function ruleDenial(req, ruleText, source) {
|
|
255
282
|
return ruleDenialSentence({ source: "permission", tool: req.toolName, rule: ruleText, ...(source ? { origin: source } : {}) });
|
|
256
283
|
}
|
|
@@ -376,6 +403,16 @@ export function createPermissionRulePolicy(rules, opts) {
|
|
|
376
403
|
}
|
|
377
404
|
return unreadable;
|
|
378
405
|
};
|
|
406
|
+
const keylessRefusal = (entry, req) => {
|
|
407
|
+
for (const r of [...entry.content.deny, ...entry.content.ask]) {
|
|
408
|
+
if (r.parsed.match !== "name" || nameRuleSubjectOf(r.parsed.tool, req.args) !== undefined)
|
|
409
|
+
continue;
|
|
410
|
+
const absent = keyedValueAbsentReason(r.parsed.tool);
|
|
411
|
+
if (absent !== undefined)
|
|
412
|
+
return ruleDenialSentence({ source: "permission", tool: req.toolName, rule: r.ruleText, ...(r.source ? { origin: r.source } : {}), detail: absent });
|
|
413
|
+
}
|
|
414
|
+
return undefined;
|
|
415
|
+
};
|
|
379
416
|
const unreadableAsk = (hit, lane, req) => ({
|
|
380
417
|
action: "ask",
|
|
381
418
|
message: `tool "${req.toolName}" needs approval: the call could not be read against the permission rule ${hit.rule.ruleText} (${hit.unreadable}) — a person must decide`,
|
|
@@ -422,11 +459,14 @@ export function createPermissionRulePolicy(rules, opts) {
|
|
|
422
459
|
return face !== undefined ? attest(denied, req, { pathDenial: { rule: contentDeny.rule.ruleText, view: contentDeny.view, face } }) : denied;
|
|
423
460
|
}
|
|
424
461
|
if (entry) {
|
|
425
|
-
const paramDeny = matchParamRules(entry.param.deny, req
|
|
462
|
+
const paramDeny = matchParamRules(entry.param.deny, req, caps.maxScalarValueChars);
|
|
426
463
|
if (paramDeny) {
|
|
427
464
|
return { action: "deny", message: ruleDenial(req, paramDeny.ruleText, paramDeny.source) };
|
|
428
465
|
}
|
|
429
466
|
}
|
|
467
|
+
const keyless = entry !== undefined ? keylessRefusal(entry, req) : undefined;
|
|
468
|
+
if (keyless !== undefined)
|
|
469
|
+
return { action: "deny", message: keyless };
|
|
430
470
|
if (contentDeny?.unreadable !== undefined)
|
|
431
471
|
return unreadableAsk({ rule: contentDeny.rule, unreadable: contentDeny.unreadable }, "content_deny", req);
|
|
432
472
|
if (entry) {
|
|
@@ -447,7 +487,7 @@ export function createPermissionRulePolicy(rules, opts) {
|
|
|
447
487
|
return { action: "ask", message: ruleAskMessage(contentAsk.rule.ruleText, contentAsk.rule.source), matchedAskRule: contentAsk.rule.ruleText };
|
|
448
488
|
}
|
|
449
489
|
if (entry) {
|
|
450
|
-
const paramAsk = matchParamRules(entry.param.ask, req
|
|
490
|
+
const paramAsk = matchParamRules(entry.param.ask, req, caps.maxScalarValueChars);
|
|
451
491
|
if (paramAsk) {
|
|
452
492
|
return { action: "ask", message: ruleAskMessage(paramAsk.ruleText, paramAsk.source), matchedAskRule: paramAsk.ruleText };
|
|
453
493
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
import type { LegModBus } from "./mods/stations.js";
|
|
2
|
+
/** The named sections whose entries the host may dispose of — a closed set (the event's `name`). */
|
|
2
3
|
export declare const DISPOSABLE_PROMPT_SECTIONS: readonly ["core/discovery.mcp-instructions"];
|
|
3
4
|
export type DisposablePromptSection = (typeof DISPOSABLE_PROMPT_SECTIONS)[number];
|
|
4
|
-
/** One entry of a named section, as the engine computed it, before it reaches the model.
|
|
5
|
-
* writing to it changes nothing. */
|
|
5
|
+
/** One entry of a named section, as the engine computed it, before it reaches the model. */
|
|
6
6
|
export interface PromptSectionEntry {
|
|
7
7
|
readonly section: DisposablePromptSection;
|
|
8
8
|
/** The entry's key within the section: the MCP server's declared name. */
|
|
@@ -12,35 +12,16 @@ export interface PromptSectionEntry {
|
|
|
12
12
|
/** The tools this leg mounted from that server, by their namespaced names. */
|
|
13
13
|
readonly mountedTools: readonly string[];
|
|
14
14
|
}
|
|
15
|
-
/** The host's answer. `undefined` = include the entry as computed. */
|
|
16
|
-
export type PromptSectionDisposition = {
|
|
17
|
-
readonly op: "drop";
|
|
18
|
-
} | {
|
|
19
|
-
readonly op: "replace";
|
|
20
|
-
readonly text: string;
|
|
21
|
-
};
|
|
22
15
|
/** Who wrote the text an entry carries into the model's view. */
|
|
23
16
|
export type PromptSectionAuthor = "server" | "host";
|
|
24
|
-
export interface PromptSectionSeat {
|
|
25
|
-
/**
|
|
26
|
-
* Answer the disposition of one entry of a named section ({@link DISPOSABLE_PROMPT_SECTIONS}): return
|
|
27
|
-
* nothing to include it, `{ op: "drop" }` to leave it out of the model's view on every lane, or
|
|
28
|
-
* `{ op: "replace", text }` to place the host's own non-blank text instead — host text, rendered
|
|
29
|
-
* without the untrusted-data fence the server's text rides in, under the same per-entry bound and the same
|
|
30
|
-
* disclosed cut. Called once each time the entry's text
|
|
31
|
-
* enters the run (a re-dial asks again). Synchronous. A throw, a Promise, or any other value includes
|
|
32
|
-
* the entry and raises a coded operator warning (`prompt.section_answer_invalid`).
|
|
33
|
-
*/
|
|
34
|
-
section?(entry: PromptSectionEntry): PromptSectionDisposition | undefined;
|
|
35
|
-
}
|
|
36
17
|
/** One server's entry of the MCP instructions section as the run carries it, after the host's disposition. */
|
|
37
18
|
export interface McpInstructionsEntry {
|
|
38
19
|
readonly server: string;
|
|
39
20
|
readonly text: string;
|
|
40
21
|
readonly author: PromptSectionAuthor;
|
|
41
22
|
}
|
|
42
|
-
/** What one
|
|
43
|
-
* sentence when
|
|
23
|
+
/** What one disposition leaves in the run: the entry's text and author, absent when dropped, plus the defect
|
|
24
|
+
* sentence when an answer could not be taken. */
|
|
44
25
|
export interface DisposedSectionEntry {
|
|
45
26
|
readonly kept?: {
|
|
46
27
|
readonly text: string;
|
|
@@ -48,7 +29,14 @@ export interface DisposedSectionEntry {
|
|
|
48
29
|
};
|
|
49
30
|
readonly defect?: string;
|
|
50
31
|
}
|
|
51
|
-
/**
|
|
52
|
-
export
|
|
53
|
-
/**
|
|
32
|
+
/** The disposition the dial reads: one entry in, its disposition out. */
|
|
33
|
+
export type PromptSectionDisposer = (entry: PromptSectionEntry) => Promise<DisposedSectionEntry>;
|
|
34
|
+
/**
|
|
35
|
+
* The disposer over the leg's bus, or undefined when no handler hangs on `prompt.section` (the dial then keeps
|
|
36
|
+
* every entry as computed, with nothing raised).
|
|
37
|
+
*/
|
|
38
|
+
export declare function sectionDisposerOf(bus: LegModBus | undefined, signal?: AbortSignal): PromptSectionDisposer | undefined;
|
|
39
|
+
/** One entry's disposition at its dial: the leg's disposer when one is wired, else the entry as the engine computed it. */
|
|
40
|
+
export declare function disposeSectionEntry(disposer: PromptSectionDisposer | undefined, entry: PromptSectionEntry): Promise<DisposedSectionEntry>;
|
|
41
|
+
/** The operator warning for an answer the station could not take. */
|
|
54
42
|
export declare function sectionAnswerWarning(defect: string): Error;
|
|
@@ -1,48 +1,81 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { bandOf } from "../prompt-assembly/bands.js";
|
|
2
|
+
import { lockedTextIn, receivePromptData } from "../prompt-assembly/overlay.js";
|
|
2
3
|
import { inlineUntrusted } from "./untrusted-text.js";
|
|
3
|
-
import {
|
|
4
|
+
import { egressThrownText, extensionWords } from "./untrusted-egress.js";
|
|
4
5
|
export const DISPOSABLE_PROMPT_SECTIONS = Object.freeze(["core/discovery.mcp-instructions"]);
|
|
5
|
-
const ANSWER_KEYS = { drop: ["op"], replace: ["op", "text"] };
|
|
6
|
-
const FOREIGN_VALUE_MAX = 200;
|
|
7
|
-
const STRAY_KEYS_NAMED = 5;
|
|
8
6
|
const DEFECT_MAX = 600;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
7
|
+
function readAnswer(answer, seat) {
|
|
8
|
+
if (typeof answer !== "object" || answer === null || Array.isArray(answer))
|
|
9
|
+
return `answered ${answer === null ? "null" : Array.isArray(answer) ? "an array" : typeof answer}; prompt.section takes { text: string | null }`;
|
|
10
|
+
const received = receivePromptData(answer);
|
|
11
|
+
if ("notData" in received)
|
|
12
|
+
return `a prompt.section answer is data (plain objects, arrays, strings, booleans); it holds ${received.notData}`;
|
|
13
|
+
const data = received.value;
|
|
14
|
+
const keys = Object.keys(data);
|
|
15
|
+
const stray = keys.filter((k) => k !== "text");
|
|
16
|
+
if (stray.length > 0)
|
|
17
|
+
return `the answer carries ${stray.slice(0, 5).map((k) => JSON.stringify(extensionWords(k, 40))).join(", ")} (text only)`;
|
|
18
|
+
if (!keys.includes("text"))
|
|
19
|
+
return "the answer has no text (a string to place, null to leave the entry out)";
|
|
20
|
+
const text = data["text"];
|
|
21
|
+
const op = text === null ? "drop" : "replace";
|
|
22
|
+
if (text !== null && (typeof text !== "string" || text.trim() === ""))
|
|
23
|
+
return `text is ${typeof text === "string" ? "blank" : typeof text}; it is a non-blank string or null`;
|
|
24
|
+
const source = seat === "deployment" ? "deploy" : "task";
|
|
25
|
+
if (!bandOf("discovery").ops[source].includes(op))
|
|
26
|
+
return `a ${source} answer may not ${op} a discovery entry`;
|
|
27
|
+
if (typeof text === "string") {
|
|
28
|
+
const hits = lockedTextIn(text);
|
|
29
|
+
if (hits.length > 0)
|
|
30
|
+
return `the text contains, verbatim, the locked text of ${[...new Set(hits.map((h) => h.split("#")[0]))].join(", ")}`;
|
|
31
|
+
}
|
|
32
|
+
return { text };
|
|
33
|
+
}
|
|
34
|
+
export function sectionDisposerOf(bus, signal) {
|
|
35
|
+
if (bus === undefined || !bus.hasHandlers("prompt.section"))
|
|
36
|
+
return undefined;
|
|
37
|
+
return async (entry) => {
|
|
38
|
+
const computed = { text: entry.text, author: "server" };
|
|
39
|
+
const where = `prompt section "${entry.section}" entry "${inlineUntrusted(entry.server, 160)}"`;
|
|
40
|
+
const e = { name: entry.section, key: entry.server, mountedTools: Object.freeze([...entry.mountedTools]), text: entry.text };
|
|
41
|
+
const bottom = Object.freeze({ text: entry.text });
|
|
42
|
+
const taken = new WeakMap([[bottom, entry.text]]);
|
|
43
|
+
let outcome;
|
|
44
|
+
try {
|
|
45
|
+
outcome = await bus.dispatch("prompt.section", e, {
|
|
46
|
+
bottom: () => bottom,
|
|
47
|
+
...(signal !== undefined ? { signal } : {}),
|
|
48
|
+
checkAnswer: (a, _e, by) => {
|
|
49
|
+
if (typeof a === "object" && a !== null && taken.has(a))
|
|
50
|
+
return undefined;
|
|
51
|
+
const read = readAnswer(a, by.seat);
|
|
52
|
+
if (typeof read === "string")
|
|
53
|
+
return read;
|
|
54
|
+
taken.set(a, read.text);
|
|
55
|
+
return undefined;
|
|
56
|
+
},
|
|
57
|
+
});
|
|
27
58
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (op !== "drop" && op !== "replace")
|
|
31
|
-
return unread(`the answer's op is ${typeof op === "string" ? `"${foreign(op, 40)}"` : typeof op}, not "drop" or "replace"`);
|
|
32
|
-
const stray = Object.keys(record).filter((k) => !ANSWER_KEYS[op].includes(k));
|
|
33
|
-
if (stray.length > 0) {
|
|
34
|
-
const named = stray.slice(0, STRAY_KEYS_NAMED).map((k) => foreign(k, 40)).join(", ");
|
|
35
|
-
return unread(`a "${op}" answer carries ${named}${stray.length > STRAY_KEYS_NAMED ? ` and ${stray.length - STRAY_KEYS_NAMED} more` : ""}`);
|
|
59
|
+
catch (err) {
|
|
60
|
+
return { kept: computed, defect: inlineUntrusted(`${where}: the station could not be raised (${inlineUntrusted(egressThrownText("same-principal", err), 200)}) — the entry is included as the engine computed it`, DEFECT_MAX) };
|
|
36
61
|
}
|
|
37
|
-
if (
|
|
38
|
-
return {};
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
62
|
+
if (outcome.kind === "aborted")
|
|
63
|
+
return { kept: computed };
|
|
64
|
+
const skipped = outcome.skipped.map((s) => `extension "${extensionWords(s.registration, 80)}" ${s.cause === "violation" ? "gave an answer the station cannot take" : s.cause}: ${extensionWords(s.reason, 200)}`);
|
|
65
|
+
const defect = skipped.length > 0 ? inlineUntrusted(`${where}: ${skipped.join("; ")} — that answer is skipped; what is below it stands`, DEFECT_MAX) : undefined;
|
|
66
|
+
if (outcome.kind === "failed")
|
|
67
|
+
return { kept: computed, ...(defect !== undefined ? { defect } : {}) };
|
|
68
|
+
const answer = outcome.answer;
|
|
69
|
+
const text = typeof answer === "object" && answer !== null ? taken.get(answer) : undefined;
|
|
70
|
+
if (text === undefined) {
|
|
71
|
+
return { kept: computed, defect: inlineUntrusted(`${where}: the chain's answer is not one the station took — the entry is included as the engine computed it`, DEFECT_MAX) };
|
|
72
|
+
}
|
|
73
|
+
const disposed = text === null ? {} : typeof text === "string" && text !== entry.text ? { kept: { text, author: "host" } } : { kept: computed };
|
|
74
|
+
return { ...disposed, ...(defect !== undefined ? { defect } : {}) };
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export function disposeSectionEntry(disposer, entry) {
|
|
78
|
+
return disposer === undefined ? Promise.resolve({ kept: { text: entry.text, author: "server" } }) : disposer(entry);
|
|
46
79
|
}
|
|
47
80
|
export function sectionAnswerWarning(defect) {
|
|
48
81
|
return Object.assign(new Error(defect), { code: "prompt.section_answer_invalid" });
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
* header (`principalHeader`) — and the one rule they obey, for MCP and A2A alike: they travel only to the
|
|
4
4
|
* endpoints the declaration names, and every header name has exactly one owner, compared the way HTTP
|
|
5
5
|
* compares names (case-insensitively). The principal header's owner is the engine: it sends the task's
|
|
6
|
-
* principal under that name, or nothing under it when the task has none.
|
|
6
|
+
* principal under that name, or nothing under it when the task has none. A static header the credential vocabulary
|
|
7
|
+
* reads as a credential is one the engine holds from the moment it resolves it: no child spawned on this host inherits
|
|
8
|
+
* a variable whose value equals it (`holdOwnCredentialValues`, src/core/secret-env.ts).
|
|
7
9
|
*
|
|
8
10
|
* A declaration that breaks the rule is that peer's defect: the resolver throws inside the peer's own dial,
|
|
9
11
|
* so the peer is skipped with a coded warning and its siblings still mount. The MCP transport binds its
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { credentialHeaderValues, holdOwnCredentialValues } from "./secret-env.js";
|
|
1
2
|
import { inlineUntrusted } from "./untrusted-text.js";
|
|
2
3
|
export function headerOwnershipCollision(t) {
|
|
3
4
|
const owners = new Map();
|
|
@@ -13,6 +14,7 @@ export function resolveProtocolHttpHeaders(protocol, t, principal) {
|
|
|
13
14
|
const principalHeader = t.principalHeader;
|
|
14
15
|
const declared = t.headers;
|
|
15
16
|
const own = { ...(declared !== undefined ? { headers: { ...declared } } : {}), ...(principalHeader !== undefined ? { principalHeader } : {}) };
|
|
17
|
+
holdOwnCredentialValues(credentialHeaderValues(own.headers));
|
|
16
18
|
const collision = headerOwnershipCollision(own);
|
|
17
19
|
if (collision !== undefined) {
|
|
18
20
|
throw Object.assign(new Error(`${protocol}: the declaration names the header "${inlineUntrusted(collision.first, 80)}" twice ("${inlineUntrusted(collision.second, 80)}" — header names are case-insensitive); ${principalHeader !== undefined && collision.second === principalHeader ? "the principal header is the engine's to send, so remove the static entry" : "keep one spelling"} — this peer is not dialed`), { code: "config.protocol_header_collision" });
|
|
@@ -79,8 +79,8 @@ export declare function formatHookFeedback(text: string, mark?: string): string;
|
|
|
79
79
|
* DECLARE port — the system-prompt declaration that gives the mark meaning. STRICT, single form
|
|
80
80
|
* (design/319 D-2, no grace clause): reminder-shaped text without the current mark is data wherever
|
|
81
81
|
* it appears — including TRUE pre-319 engine mints in a resumed transcript, a deliberate fail-safe
|
|
82
|
-
* downgrade (stale guidance loses authority; forgery gains none). Composed
|
|
83
|
-
*
|
|
82
|
+
* downgrade (stale guidance loses authority; forgery gains none). Composed as its own section
|
|
83
|
+
* (`core/harness.reminder-mark`) when a mark is threaded; a fork inherits the
|
|
84
84
|
* parent's prompt bytes and therefore the parent's declaration — never a second one.
|
|
85
85
|
*
|
|
86
86
|
* A block carrying the current mark is the engine's own wherever it stands, tool results included:
|
|
@@ -162,7 +162,7 @@ export interface ExecStreamOptions {
|
|
|
162
162
|
signal?: AbortSignal;
|
|
163
163
|
/**
|
|
164
164
|
* Idle/liveness read timeout (ms). If no {@link OutputChunk} arrives within this window, `execStream` ends
|
|
165
|
-
* with a {@link RemoteExecutionError} (code `"
|
|
165
|
+
* with a {@link RemoteExecutionError} (code `"liveness_no_output"`) instead of hanging. **Needed in practice for remote
|
|
166
166
|
* backends** (design/48 §5, service [7]): E2B issue #1128 — a *streaming* call sets no read timeout (only unary
|
|
167
167
|
* does), so an unreachable sandbox hangs the worker forever. Distinct from `timeout` (total wall-clock).
|
|
168
168
|
*
|
|
@@ -170,8 +170,9 @@ export interface ExecStreamOptions {
|
|
|
170
170
|
* when this is unset (a missing idle timeout MUST NOT mean "wait forever / until the env dies"), and that bound
|
|
171
171
|
* MUST cover the **command-creation/handshake RPC**, not only the post-first-chunk loop — a provider hang
|
|
172
172
|
* typically occurs at creation, before any chunk arrives, so an idle timer started only after the first chunk
|
|
173
|
-
* misses it. On trigger, throw {@link RemoteExecutionError} with code `"
|
|
174
|
-
* the command's idempotency — the adapter MUST NOT blind-retry).
|
|
173
|
+
* misses it. On trigger, throw {@link RemoteExecutionError} with code `"liveness_no_output"` (retryable by the
|
|
174
|
+
* caller per the command's idempotency — the adapter MUST NOT blind-retry). The wall-clock {@link timeout}
|
|
175
|
+
* keeps `"timeout"`: the two cuts are different words because they explain themselves with different numbers.
|
|
175
176
|
*/
|
|
176
177
|
readTimeoutMs?: number;
|
|
177
178
|
/** Per-call output cap (design/48 §5 gap 8): stop streaming after this many bytes to avoid a `find /` flooding the control plane. */
|
|
@@ -190,12 +191,22 @@ export type RemoteExecutionErrorCode =
|
|
|
190
191
|
/** The command/stream was aborted via its `AbortSignal`. */
|
|
191
192
|
| "aborted"
|
|
192
193
|
/**
|
|
193
|
-
* A command's wall-clock {@link ExecStreamOptions.timeout} or
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
194
|
+
* A bound on elapsed time was exceeded: a command's wall-clock {@link ExecStreamOptions.timeout}, or the idle
|
|
195
|
+
* bound of a lifecycle / filesystem RPC (service [45]/[59]). **Retryable** by the caller per the op's
|
|
196
|
+
* idempotency (the adapter MUST NOT blind-retry). Distinct from `"aborted"` (a caller-driven `AbortSignal`),
|
|
197
|
+
* `"connect_failed"` (workspace provisioning, not a per-command hang) and `"liveness_no_output"` (an exec
|
|
198
|
+
* stream's silence window — below).
|
|
197
199
|
*/
|
|
198
200
|
| "timeout"
|
|
201
|
+
/**
|
|
202
|
+
* An exec stream produced no {@link OutputChunk} for its liveness window ({@link ExecStreamOptions.readTimeoutMs},
|
|
203
|
+
* or the adapter's default bound) — including a provider RPC hang at command creation, before the first chunk
|
|
204
|
+
* (service [45]/[59]). A hang detector, not a budget: it is the word for the cut that used to share `"timeout"`
|
|
205
|
+
* with the wall-clock budget, and the two explain themselves with different numbers (the window versus the
|
|
206
|
+
* budget the caller asked for), so a consumer must be able to tell them apart by code. **Retryable** by the
|
|
207
|
+
* caller per the command's idempotency (the adapter MUST NOT blind-retry), exactly as `"timeout"` is.
|
|
208
|
+
*/
|
|
209
|
+
| "liveness_no_output"
|
|
199
210
|
/**
|
|
200
211
|
* The op is not supported by this adapter's capabilities (design/61 §9 A) — e.g. `suspendVM`/`resumeVM` on a
|
|
201
212
|
* non-suspendable SSH/ADB env. Permanent for this env; check {@link RemoteExecutionEnv.capabilities} first.
|
|
@@ -235,8 +246,8 @@ export type RemoteExecutionErrorCode =
|
|
|
235
246
|
/**
|
|
236
247
|
* The RETRYABLE half of {@link RemoteExecutionErrorCode} — the codes whose own contract above says a retry
|
|
237
248
|
* can succeed (`auth_transient`: retry-exactly-once after the device is authorized; `connect_failed`: the
|
|
238
|
-
* workspace could not be reached/provisioned this attempt; `timeout`: a
|
|
239
|
-
* `transport_lost`: re-establish the connection). Every OTHER code is permanent for this attempt
|
|
249
|
+
* workspace could not be reached/provisioned this attempt; `timeout` / `liveness_no_output`: a time bound
|
|
250
|
+
* tripped; `transport_lost`: re-establish the connection). Every OTHER code is permanent for this attempt
|
|
240
251
|
* (`auth_failed`/`unsupported`), caller-driven (`aborted`), unclassifiable (`unknown`), or
|
|
241
252
|
* outcome-unknowable (`outcome_unknown` — design/380 O12: the op may have ALREADY executed, so a retry
|
|
242
253
|
* re-drives committed side effects) — retrying them burns budget or, worse, re-drives a rejected
|
|
@@ -284,8 +295,8 @@ export declare class RemoteExecutionError extends Error {
|
|
|
284
295
|
* wall-clock would false-kill the (durable-checkpoint *命门*) path. So such ops bound on an **idle/no-heartbeat**
|
|
285
296
|
* window (reset by observable progress), not total elapsed time. Cheap control RPCs (`isRunning`, a small
|
|
286
297
|
* `connect` handshake) may use a short wall-clock. The adapter sizes the bound per op class.
|
|
287
|
-
* 3. **A liveness breach surfaces as a typed, retryable error**: `RemoteExecutionError` code `"
|
|
288
|
-
*
|
|
298
|
+
* 3. **A liveness breach surfaces as a typed, retryable error**: `RemoteExecutionError` code `"liveness_no_output"`
|
|
299
|
+
* for an exec stream's silence window and `"timeout"` for the lifecycle ops' idle bound; for the inherited filesystem ops (which return the vendored `Result<_, FileError>`),
|
|
289
300
|
* a `FileError` — but still **bounded, never an unbounded wait**. Retry is the caller's decision per the op's
|
|
290
301
|
* idempotency; the adapter MUST NOT blind-retry.
|
|
291
302
|
*/
|
|
@@ -418,7 +429,8 @@ export interface RemoteExecutionEnv extends ExecutionEnv {
|
|
|
418
429
|
* per-command timeout is **independent of the env/sandbox lifetime** and an adapter MUST NOT fall back to the
|
|
419
430
|
* lifetime when none is given (else a hung provider RPC pins the worker for the whole sandbox lifetime). An
|
|
420
431
|
* adapter SHOULD enforce a bounded default liveness/idle timeout that also covers the command-creation RPC, and
|
|
421
|
-
* surface a
|
|
432
|
+
* surface a silence breach as a typed, retryable {@link RemoteExecutionError} code `"liveness_no_output"` and a
|
|
433
|
+
* wall-clock breach as `"timeout"`. See
|
|
422
434
|
* {@link ExecStreamOptions.timeout} / {@link ExecStreamOptions.readTimeoutMs}.
|
|
423
435
|
*/
|
|
424
436
|
execStream(command: string, options?: ExecStreamOptions): AsyncIterable<OutputChunk>;
|
package/dist/core/remote-env.js
CHANGED
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
* · `environment` — the leg's infrastructure failed (the workspace restore, an abort): the decision is
|
|
10
10
|
* untouched, and a retry replays it;
|
|
11
11
|
* · `session_gone` — the resumed agent's transcript session is missing;
|
|
12
|
+
* · `transcript_corrupt` — the resumed agent's transcript session is THERE but cannot be read as a session: its log
|
|
13
|
+
* has no header its store wrote (`corrupt_session`), or its entry tree is structurally unusable — a leaf or parent
|
|
14
|
+
* entry that is not in the log (`invalid_session`). Distinct from `session_gone`: the bytes exist, so deleting or
|
|
15
|
+
* restoring the transcript is the remedy, not re-creating a session;
|
|
12
16
|
* · `tool_unavailable` — the approved tool is not available to the resumed leg (gone, replaced by a
|
|
13
17
|
* different contract, or an inherited tool the drive cannot hand over): this approval cannot run, and a
|
|
14
18
|
* fresh decision resolves it;
|
|
@@ -18,6 +22,7 @@
|
|
|
18
22
|
* · `decision_rejected` — the supplied decision does not fit the checkpoint (another gate's answer, an
|
|
19
23
|
* unsafe payload, an input the constraints refuse): correct the decision and resubmit.
|
|
20
24
|
*/
|
|
25
|
+
import type { AssertAllKeysHandled } from "./ask-origin.js";
|
|
21
26
|
/**
|
|
22
27
|
* design/80 D-1: why a consumed checkpoint was {@link import("./checkpoint-store.js").CheckpointStore.reopen | reopened}
|
|
23
28
|
* (resolved → pending). The reason drives re-resume validation (§3 invariant #1): an `env_failed` reopen is a SYSTEM
|
|
@@ -41,11 +46,20 @@
|
|
|
41
46
|
*/
|
|
42
47
|
export declare const REOPEN_REASONS: readonly ["env_failed", "tool_unavailable", "constraint_rejected", "config_refused"];
|
|
43
48
|
export type ReopenReason = (typeof REOPEN_REASONS)[number];
|
|
44
|
-
export declare const RESUME_STARTUP_CAUSES: readonly ["environment", "session_gone", "tool_unavailable", "configuration", "decision_rejected"];
|
|
49
|
+
export declare const RESUME_STARTUP_CAUSES: readonly ["environment", "session_gone", "transcript_corrupt", "tool_unavailable", "configuration", "decision_rejected"];
|
|
45
50
|
export type ResumeStartupCause = (typeof RESUME_STARTUP_CAUSES)[number];
|
|
46
51
|
/** The cause a resume failure's code names; `undefined` when the code is absent or the table does not
|
|
47
52
|
* name it. Every `config.*` code is a configuration door's refusal. */
|
|
48
53
|
export declare function resumeStartupCauseOf(code: string | undefined): ResumeStartupCause | undefined;
|
|
54
|
+
declare const REOPEN_REASON_OF_CAUSE: {
|
|
55
|
+
readonly environment: "env_failed";
|
|
56
|
+
readonly session_gone: "env_failed";
|
|
57
|
+
readonly transcript_corrupt: "env_failed";
|
|
58
|
+
readonly tool_unavailable: "tool_unavailable";
|
|
59
|
+
readonly configuration: "config_refused";
|
|
60
|
+
readonly decision_rejected: "constraint_rejected";
|
|
61
|
+
};
|
|
62
|
+
export type ReopenReasonTableCoversEveryCause = AssertAllKeysHandled<Exclude<ResumeStartupCause, keyof typeof REOPEN_REASON_OF_CAUSE>>;
|
|
49
63
|
/**
|
|
50
64
|
* The reason a consumed checkpoint whose approved action never started returns to pending under. A failure
|
|
51
65
|
* whose cause is not known reopens as `env_failed`: the leg went away before the action ran, the human's
|
|
@@ -54,3 +68,4 @@ export declare function resumeStartupCauseOf(code: string | undefined): ResumeSt
|
|
|
54
68
|
export declare function reopenReasonOf(cause: ResumeStartupCause | undefined): ReopenReason;
|
|
55
69
|
/** What the result of a returned resume leg says after its checkpoint was reopened, per reason. */
|
|
56
70
|
export declare function reopenedUnstartedSentence(reason: ReopenReason): string;
|
|
71
|
+
export {};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
export const REOPEN_REASONS = Object.freeze(["env_failed", "tool_unavailable", "constraint_rejected", "config_refused"]);
|
|
2
|
-
export const RESUME_STARTUP_CAUSES = Object.freeze(["environment", "session_gone", "tool_unavailable", "configuration", "decision_rejected"]);
|
|
2
|
+
export const RESUME_STARTUP_CAUSES = Object.freeze(["environment", "session_gone", "transcript_corrupt", "tool_unavailable", "configuration", "decision_rejected"]);
|
|
3
3
|
const CAUSE_OF_CODE = new Map([
|
|
4
4
|
["resume.env_failed", "environment"],
|
|
5
5
|
["checkpoint.resume_aborted", "environment"],
|
|
6
6
|
["resume.session_not_found", "session_gone"],
|
|
7
|
+
["corrupt_session", "transcript_corrupt"],
|
|
8
|
+
["invalid_session", "transcript_corrupt"],
|
|
7
9
|
["resume.tool_unavailable", "tool_unavailable"],
|
|
8
10
|
["resume.tool_contract_mismatch", "tool_unavailable"],
|
|
9
11
|
["checkpoint.config_refused", "configuration"],
|
|
@@ -22,6 +24,7 @@ export function resumeStartupCauseOf(code) {
|
|
|
22
24
|
const REOPEN_REASON_OF_CAUSE = {
|
|
23
25
|
environment: "env_failed",
|
|
24
26
|
session_gone: "env_failed",
|
|
27
|
+
transcript_corrupt: "env_failed",
|
|
25
28
|
tool_unavailable: "tool_unavailable",
|
|
26
29
|
configuration: "config_refused",
|
|
27
30
|
decision_rejected: "constraint_rejected",
|
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;
|