@sema-agent/core 7.51.1 → 7.52.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 +550 -2
- package/dist/agents/agent-transcript-tool.d.ts +1 -1
- package/dist/agents/cascade.js +4 -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/read-inbox-tool.d.ts +1 -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 +5 -0
- package/dist/agents/subagent.js +7 -4
- package/dist/agents/tool-filter.d.ts +40 -13
- package/dist/agents/tool-filter.js +28 -14
- package/dist/bench/metrics.d.ts +1 -0
- package/dist/brain/anthropic.js +16 -12
- package/dist/brain/model-presets.d.ts +4 -5
- package/dist/brain/model-presets.js +4 -4
- 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 +117 -47
- package/dist/brain/route-adjudicator.js +171 -42
- package/dist/brain/route-conformance.js +2 -2
- package/dist/brain/status-sink.d.ts +18 -0
- package/dist/brain/status-sink.js +7 -0
- package/dist/core/allow-entry.d.ts +42 -8
- package/dist/core/allow-entry.js +24 -17
- package/dist/core/auto-compaction.d.ts +23 -20
- package/dist/core/auto-compaction.js +37 -16
- 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 +36 -12
- package/dist/core/checkpoint-store.js +1 -1
- package/dist/core/child-clamp-seats.d.ts +6 -0
- package/dist/core/child-clamp-seats.js +2 -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/engine-capabilities.d.ts +8 -1
- package/dist/core/engine-capabilities.js +1 -1
- package/dist/core/engine-notice.d.ts +36 -19
- package/dist/core/frontmatter-fence.d.ts +10 -0
- package/dist/core/frontmatter-fence.js +6 -0
- package/dist/core/gate-fold.js +5 -23
- package/dist/core/gate-lanes.js +356 -270
- package/dist/core/governance-codes.d.ts +9 -4
- package/dist/core/governance-codes.js +9 -3
- package/dist/core/hooks.d.ts +276 -734
- package/dist/core/hooks.js +97 -192
- 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 +26 -5
- package/dist/core/locked-config.js +31 -6
- 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 +2 -2
- package/dist/core/mcp-server-spec.d.ts +53 -7
- package/dist/core/mcp-server-spec.js +84 -1
- package/dist/core/mcp.d.ts +11 -7
- package/dist/core/mcp.js +27 -9
- 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 +8 -11
- package/dist/core/memory-engine/engine.js +9 -5
- 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 +4 -0
- package/dist/core/mode-policy.js +7 -5
- 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 +701 -0
- package/dist/core/mods/kernel/events.d.ts +242 -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 +65 -0
- package/dist/core/mods/kernel/receive.js +123 -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 +84 -0
- package/dist/core/mods/kernel/site-rules.js +104 -0
- package/dist/core/mods/stations.d.ts +350 -0
- package/dist/core/mods/stations.js +444 -0
- package/dist/core/own-property-receipt.js +11 -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-syntax.d.ts +15 -0
- package/dist/core/permission-rule-syntax.js +24 -16
- package/dist/core/permission-rules.d.ts +7 -1
- package/dist/core/permission-rules.js +26 -15
- 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/retired-keys.d.ts +4 -0
- package/dist/core/retired-keys.js +3 -0
- 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 +85 -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 +8 -2
- package/dist/core/runner/image.js +1 -2
- package/dist/core/runner/inline-image.js +1 -1
- 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/person-path-rows.js +1 -0
- 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 +5 -0
- package/dist/core/runner/prepare-config-doors.js +9 -0
- package/dist/core/runner/prepare-defer-classify.js +3 -4
- 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-inherited-gate.d.ts +8 -12
- package/dist/core/runner/prepare-inherited-gate.js +8 -21
- package/dist/core/runner/prepare-memory-engine-session.js +1 -1
- package/dist/core/runner/prepare-park-ask.js +10 -14
- package/dist/core/runner/prepare-policy-chain.d.ts +18 -16
- package/dist/core/runner/prepare-policy-chain.js +98 -101
- package/dist/core/runner/prepare-project-context.js +7 -10
- package/dist/core/runner/prepare-prompt-assembly.d.ts +45 -40
- package/dist/core/runner/prepare-prompt-assembly.js +134 -101
- package/dist/core/runner/prepare-prompt-inputs.d.ts +18 -19
- package/dist/core/runner/prepare-prompt-inputs.js +5 -7
- package/dist/core/runner/prepare-protocol-tools.d.ts +6 -4
- package/dist/core/runner/prepare-protocol-tools.js +2 -2
- 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 +33 -15
- 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 +5 -6
- package/dist/core/runner/prepare-wiring-manifest.js +7 -7
- 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-preflight.js +38 -16
- package/dist/core/runner/retired-runner-deps.js +3 -1
- 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 +62 -84
- 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 +11 -10
- 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 +33 -22
- package/dist/core/runner/run-tool-mount-facts.js +5 -3
- package/dist/core/runner/run-turn-boundary.js +23 -34
- package/dist/core/runner/runtask.d.ts +6 -7
- package/dist/core/runner/runtask.js +14 -72
- package/dist/core/runner/session-rule-policy.d.ts +6 -4
- package/dist/core/runner/session-rule-policy.js +17 -10
- 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/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 +121 -22
- package/dist/core/runner/sub-agent-deny-lists.js +228 -71
- 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 +20 -28
- package/dist/core/safety-merge-corpus.js +18 -2
- package/dist/core/secret-env.d.ts +93 -20
- package/dist/core/secret-env.js +192 -38
- package/dist/core/session-policy-store.d.ts +93 -17
- package/dist/core/session-policy-store.js +178 -25
- 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/task-event.d.ts +13 -3
- 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 +59 -18
- package/dist/core/tool-policy.js +77 -12
- 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 -1
- package/dist/core/types.js +1 -0
- 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/user-attachment.d.ts +12 -2
- package/dist/core/user-attachment.js +17 -2
- package/dist/core/wiring-manifest.d.ts +14 -13
- 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 +3 -3
- package/dist/engine/harness/types.d.ts +17 -16
- package/dist/engine/harness/types.js +7 -1
- package/dist/engine/llm/types.d.ts +12 -7
- package/dist/engine/loop/agent-loop.js +1 -1
- package/dist/engine/loop/types.d.ts +1 -1
- 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 +24 -17
- package/dist/index.js +15 -12
- package/dist/internal/harness.d.ts +1 -1
- package/dist/internal/harness.js +1 -1
- 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 +37 -56
- package/dist/prompt-assembly/artifact-store.js +31 -49
- package/dist/prompt-assembly/artifact.d.ts +89 -76
- package/dist/prompt-assembly/artifact.js +167 -146
- package/dist/prompt-assembly/assemble.d.ts +34 -29
- package/dist/prompt-assembly/assemble.js +33 -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 +59 -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 +124 -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 +24 -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 +127 -0
- package/dist/prompt-assembly/overlay.js +301 -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 +56 -0
- package/dist/prompt-assembly/select.js +69 -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 -500
- package/dist/prompts/default.js +20 -285
- package/dist/prompts/supervisor.d.ts +6 -71
- package/dist/prompts/supervisor.js +6 -117
- package/dist/stores/file/session-policy-store.d.ts +3 -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 +256 -99
- package/wire-changes/core@7.51.1.json +5 -5
- package/wire-changes/core@7.51.2.json +293 -0
- package/wire-changes/core@7.52.0.json +5859 -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
package/dist/core/mode-policy.js
CHANGED
|
@@ -112,22 +112,24 @@ export function refusePermissionModeDoors(spec) {
|
|
|
112
112
|
return mode;
|
|
113
113
|
}
|
|
114
114
|
export function refuseResumeDoors(config, recordedGate) {
|
|
115
|
-
|
|
115
|
+
asResumeConfigRefusal("taskConfig", () => {
|
|
116
116
|
refusePermissionModeDoors(config);
|
|
117
117
|
resolveOutputStyleFrame(config.outputStyle);
|
|
118
118
|
screenApprovalReach(config.approvalReach);
|
|
119
119
|
screenUserInvokedSkills(config);
|
|
120
120
|
screenUserAttachments(config.userAttachments, { resumeLeg: true });
|
|
121
121
|
});
|
|
122
|
-
|
|
122
|
+
asResumeConfigRefusal("inheritedGate", () => void recordedModeSeed(recordedGate));
|
|
123
123
|
}
|
|
124
|
-
function
|
|
124
|
+
export function asResumeConfigRefusal(field, screen) {
|
|
125
125
|
try {
|
|
126
126
|
screen();
|
|
127
127
|
}
|
|
128
128
|
catch (e) {
|
|
129
|
-
if (e instanceof Error && "code" in e && isCheckpointConfigRefusalCode(e.code))
|
|
130
|
-
|
|
129
|
+
if (e instanceof Error && "code" in e && isCheckpointConfigRefusalCode(e.code)) {
|
|
130
|
+
const reason = e.detail?.reason;
|
|
131
|
+
throw new CheckpointError("checkpoint.config_refused", e.message, { field, code: e.code, ...(reason !== undefined ? { reason } : {}) });
|
|
132
|
+
}
|
|
131
133
|
throw e;
|
|
132
134
|
}
|
|
133
135
|
}
|
|
@@ -89,7 +89,10 @@ export interface Brain {
|
|
|
89
89
|
* request it is about to make. First-party brains implement it against their own config; the
|
|
90
90
|
* decorators (routing/failover/degrading/circuit-breaker) re-dispatch it the way their `stream`
|
|
91
91
|
* would. `undefined` = this brain cannot judge (a custom brain without the face) — callers must
|
|
92
|
-
* treat that as "no judgment", never as OK or as broken.
|
|
92
|
+
* treat that as "no judgment", never as OK or as broken. A refusal is an `ok: false` verdict, never a
|
|
93
|
+
* throw (the first-party faces include the per-call key handed beside its lane's own key header,
|
|
94
|
+
* `route.credential_answer_conflict`); a throw from this face is a defect — an advisory pre-flight
|
|
95
|
+
* abstains on it, and a failover chain's face lets it escape.
|
|
93
96
|
*
|
|
94
97
|
* The same law runs again inside the first-party brains' request build (single source, called
|
|
95
98
|
* twice): a broken pairing that skips the pre-flight still refuses loudly at the request instead
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The engine's `$`: the seat view a runner hands the mods bus, and the chain bottom of each wave-one method
|
|
3
|
+
* event over it. Every method's bottom is a seat the engine already has; each method's limits are part of
|
|
4
|
+
* its contract and are checked here (a refused input is the caller's throw, "(host check)").
|
|
5
|
+
*/
|
|
6
|
+
import type { ExecutionEnv } from "../../internal/harness-types.js";
|
|
7
|
+
import type { Context, Message, Usage } from "../../internal/llm.js";
|
|
8
|
+
import type { ModDollarBase, ModMethodBottoms } from "./kernel/index.js";
|
|
9
|
+
/** `$.process.run`'s default command timeout (CC). */
|
|
10
|
+
export declare const PROCESS_RUN_DEFAULT_TIMEOUT_MS = 30000;
|
|
11
|
+
/** `$.process.run`'s largest command timeout (CC). */
|
|
12
|
+
export declare const PROCESS_RUN_MAX_TIMEOUT_MS = 600000;
|
|
13
|
+
/** `$.model.complete`'s output cap when the call names none. */
|
|
14
|
+
export declare const MODEL_COMPLETE_DEFAULT_MAX_TOKENS = 1024;
|
|
15
|
+
/** How many of the session's latest messages `$.session.messages` returns (CC). */
|
|
16
|
+
export declare const SESSION_MESSAGES_MAX = 4096;
|
|
17
|
+
/** One block of a `$.model.complete` prompt or system text (CC form): its text, and at most `cache: true`. */
|
|
18
|
+
export interface ModelCompleteBlock {
|
|
19
|
+
readonly text: string;
|
|
20
|
+
readonly cache?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** What the leg's model seat is asked: the model, the cap, and the request already in the brain's own form. */
|
|
23
|
+
export interface ModelCompleteRequest {
|
|
24
|
+
/** A model reference the leg's catalog resolves; absent ⇒ the leg's own model. */
|
|
25
|
+
readonly model?: string;
|
|
26
|
+
readonly maxTokens: number;
|
|
27
|
+
/** The system text (with its cache-span blocks on the brain's `systemBlocks` seat) and the one user message. */
|
|
28
|
+
readonly context: Pick<Context, "systemPrompt" | "systemBlocks" | "messages">;
|
|
29
|
+
}
|
|
30
|
+
export interface ModelCompleteResult {
|
|
31
|
+
readonly text: string;
|
|
32
|
+
readonly model: string;
|
|
33
|
+
/** The provider's usage, returned to the caller; the same reply is booked once on the run's account ({@link ModSeatView.book}). */
|
|
34
|
+
readonly usage?: Usage;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* What a runner hands the bus: the seats behind the wave-one methods. `env` is the leg's execution
|
|
38
|
+
* environment itself — a `$.process.run` command is the extension's, not a model tool call, so it does
|
|
39
|
+
* not pass the approval gate; the deployment's environment is its boundary.
|
|
40
|
+
*/
|
|
41
|
+
export interface ModSeatView {
|
|
42
|
+
readonly env: Pick<ExecutionEnv, "exec">;
|
|
43
|
+
/** The leg's model seat (brain / role resolution). */
|
|
44
|
+
complete(request: ModelCompleteRequest, signal: AbortSignal): Promise<ModelCompleteResult>;
|
|
45
|
+
/** The run's one account of side model calls: every `$.model.complete` reply is booked here once, its usage as the
|
|
46
|
+
* provider reported it (absent ⇒ the reply reported none). */
|
|
47
|
+
book(reply: {
|
|
48
|
+
readonly model: string;
|
|
49
|
+
readonly usage?: Usage;
|
|
50
|
+
}): void;
|
|
51
|
+
readonly session: {
|
|
52
|
+
id(): string;
|
|
53
|
+
/** The task's tracked working directory (not the environment's own cwd). */
|
|
54
|
+
cwd(): string;
|
|
55
|
+
root(): string;
|
|
56
|
+
model(): string;
|
|
57
|
+
messages(): readonly Message[];
|
|
58
|
+
};
|
|
59
|
+
/** The deployment clock (`RunnerDeps.now`). */
|
|
60
|
+
now(): number;
|
|
61
|
+
tools(): readonly string[];
|
|
62
|
+
agents(): readonly string[];
|
|
63
|
+
}
|
|
64
|
+
export interface ProcessRunResult {
|
|
65
|
+
readonly stdout: string;
|
|
66
|
+
readonly stderr: string;
|
|
67
|
+
readonly exitCode: number;
|
|
68
|
+
}
|
|
69
|
+
/** The engine `$` a handler receives on the engine bus. */
|
|
70
|
+
export interface EngineDollar extends ModDollarBase {
|
|
71
|
+
readonly process: {
|
|
72
|
+
run(args: {
|
|
73
|
+
argv: readonly string[];
|
|
74
|
+
init?: {
|
|
75
|
+
cwd?: string;
|
|
76
|
+
timeoutMs?: number;
|
|
77
|
+
};
|
|
78
|
+
}): Promise<ProcessRunResult>;
|
|
79
|
+
};
|
|
80
|
+
readonly model: {
|
|
81
|
+
complete(args: {
|
|
82
|
+
prompt: string | readonly ModelCompleteBlock[];
|
|
83
|
+
system?: string | readonly ModelCompleteBlock[];
|
|
84
|
+
model?: string;
|
|
85
|
+
maxTokens?: number;
|
|
86
|
+
}): Promise<ModelCompleteResult>;
|
|
87
|
+
};
|
|
88
|
+
readonly session: {
|
|
89
|
+
id(): Promise<string>;
|
|
90
|
+
cwd(): Promise<string>;
|
|
91
|
+
root(): Promise<string>;
|
|
92
|
+
model(): Promise<string>;
|
|
93
|
+
messages(): Promise<readonly Message[]>;
|
|
94
|
+
};
|
|
95
|
+
readonly clock: {
|
|
96
|
+
now(): Promise<number>;
|
|
97
|
+
sleep(args: {
|
|
98
|
+
ms: number;
|
|
99
|
+
}): Promise<void>;
|
|
100
|
+
};
|
|
101
|
+
readonly tool: {
|
|
102
|
+
list(): Promise<readonly string[]>;
|
|
103
|
+
};
|
|
104
|
+
readonly agent: {
|
|
105
|
+
list(): Promise<readonly string[]>;
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/** The chain bottoms of the wave-one method events over a runner's seat view. */
|
|
109
|
+
export declare function engineMethodBottoms(view: ModSeatView): ModMethodBottoms;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { shellQuote } from "../../tools/fs/search.js";
|
|
2
|
+
export const PROCESS_RUN_DEFAULT_TIMEOUT_MS = 30_000;
|
|
3
|
+
export const PROCESS_RUN_MAX_TIMEOUT_MS = 600_000;
|
|
4
|
+
export const MODEL_COMPLETE_DEFAULT_MAX_TOKENS = 1_024;
|
|
5
|
+
export const SESSION_MESSAGES_MAX = 4_096;
|
|
6
|
+
const refuse = (event, why) => new Error(`${event}: ${why} (host check)`);
|
|
7
|
+
function only(args, event, keys) {
|
|
8
|
+
const extra = Object.keys(args).filter((k) => !keys.includes(k));
|
|
9
|
+
if (extra.length > 0)
|
|
10
|
+
throw refuse(event, `takes ${keys.length === 0 ? "no input" : `{ ${keys.join(", ")} }`}; "${extra[0]}" is not one`);
|
|
11
|
+
}
|
|
12
|
+
function wholeMs(v, max) {
|
|
13
|
+
return typeof v === "number" && Number.isInteger(v) && v >= 1 && v <= max;
|
|
14
|
+
}
|
|
15
|
+
async function processRun(view, args, ctx) {
|
|
16
|
+
only(args, "process.run", ["argv", "init"]);
|
|
17
|
+
const argv = args["argv"];
|
|
18
|
+
if (!Array.isArray(argv) || argv.length === 0 || !argv.every((a) => typeof a === "string"))
|
|
19
|
+
throw refuse("process.run", "takes argv, a non-empty list of strings");
|
|
20
|
+
const init = args["init"] ?? {};
|
|
21
|
+
if (typeof init !== "object" || init === null || Array.isArray(init))
|
|
22
|
+
throw refuse("process.run", "takes init, { cwd?, timeoutMs? }");
|
|
23
|
+
const cwd = Reflect.get(init, "cwd");
|
|
24
|
+
const timeoutMs = Reflect.get(init, "timeoutMs") ?? PROCESS_RUN_DEFAULT_TIMEOUT_MS;
|
|
25
|
+
if (Object.keys(init).some((k) => k !== "cwd" && k !== "timeoutMs"))
|
|
26
|
+
throw refuse("process.run", "takes init, { cwd?, timeoutMs? }");
|
|
27
|
+
if (cwd !== undefined && (typeof cwd !== "string" || cwd === ""))
|
|
28
|
+
throw refuse("process.run", "init.cwd is a non-empty path");
|
|
29
|
+
if (!wholeMs(timeoutMs, PROCESS_RUN_MAX_TIMEOUT_MS))
|
|
30
|
+
throw refuse("process.run", `init.timeoutMs is a whole number of ms, 1 to ${PROCESS_RUN_MAX_TIMEOUT_MS}`);
|
|
31
|
+
const command = argv.map((a) => shellQuote(String(a))).join(" ");
|
|
32
|
+
const r = await view.env.exec(command, { ...(cwd !== undefined ? { cwd } : {}), timeout: timeoutMs / 1000, abortSignal: ctx.signal });
|
|
33
|
+
if (!r.ok)
|
|
34
|
+
throw new Error(`process.run: ${r.error.message}`);
|
|
35
|
+
return Object.freeze({ stdout: r.value.stdout, stderr: r.value.stderr, exitCode: r.value.exitCode });
|
|
36
|
+
}
|
|
37
|
+
const BLOCKS_FORM = "a string or a list of blocks, each { text } and at most `cache: true`";
|
|
38
|
+
function blocksOf(v) {
|
|
39
|
+
if (!Array.isArray(v))
|
|
40
|
+
return undefined;
|
|
41
|
+
const out = [];
|
|
42
|
+
for (const b of v) {
|
|
43
|
+
if (typeof b !== "object" || b === null || typeof Reflect.get(b, "text") !== "string")
|
|
44
|
+
return undefined;
|
|
45
|
+
const cache = Reflect.get(b, "cache");
|
|
46
|
+
if (Object.keys(b).some((k) => k !== "text" && k !== "cache") || (cache !== undefined && typeof cache !== "boolean"))
|
|
47
|
+
return undefined;
|
|
48
|
+
out.push(Object.freeze({ text: Reflect.get(b, "text"), ...(cache === true ? { cache: true } : {}) }));
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
function modelCompleteEnter(args) {
|
|
53
|
+
const out = { ...args };
|
|
54
|
+
for (const [key, blocksKey] of [["prompt", "promptBlocks"], ["system", "systemBlocks"]]) {
|
|
55
|
+
const given = args[key];
|
|
56
|
+
if (typeof given === "string" || (key === "system" && given === undefined))
|
|
57
|
+
continue;
|
|
58
|
+
const blocks = blocksOf(given);
|
|
59
|
+
if (blocks === undefined)
|
|
60
|
+
throw refuse("model.complete", `takes ${key} as ${BLOCKS_FORM}`);
|
|
61
|
+
out[key] = blocks.map((b) => b.text).join("");
|
|
62
|
+
out[blocksKey] = blocks;
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
function alignedBlocks(text, blocks) {
|
|
67
|
+
const kept = [];
|
|
68
|
+
let at = 0;
|
|
69
|
+
for (const b of blocks) {
|
|
70
|
+
if (b.text === "" || !text.startsWith(b.text, at))
|
|
71
|
+
break;
|
|
72
|
+
kept.push(b);
|
|
73
|
+
at += b.text.length;
|
|
74
|
+
}
|
|
75
|
+
const rest = text.slice(at);
|
|
76
|
+
return rest === "" ? kept : [...kept, { text: rest }];
|
|
77
|
+
}
|
|
78
|
+
async function modelComplete(view, args, ctx) {
|
|
79
|
+
only(args, "model.complete", ["prompt", "promptBlocks", "system", "systemBlocks", "model", "maxTokens"]);
|
|
80
|
+
const prompt = args["prompt"];
|
|
81
|
+
const system = args["system"];
|
|
82
|
+
const model = args["model"];
|
|
83
|
+
const maxTokens = args["maxTokens"] ?? MODEL_COMPLETE_DEFAULT_MAX_TOKENS;
|
|
84
|
+
if (typeof prompt !== "string" || prompt === "")
|
|
85
|
+
throw refuse("model.complete", `takes { prompt }, ${BLOCKS_FORM}, not empty`);
|
|
86
|
+
if (system !== undefined && typeof system !== "string")
|
|
87
|
+
throw refuse("model.complete", `takes system as ${BLOCKS_FORM}`);
|
|
88
|
+
const promptBlocks = args["promptBlocks"] === undefined ? [] : blocksOf(args["promptBlocks"]);
|
|
89
|
+
const systemBlocks = args["systemBlocks"] === undefined ? [] : blocksOf(args["systemBlocks"]);
|
|
90
|
+
if (promptBlocks === undefined || systemBlocks === undefined)
|
|
91
|
+
throw refuse("model.complete", `takes promptBlocks and systemBlocks that are lists of blocks, each { text } and at most \`cache: true\``);
|
|
92
|
+
if (promptBlocks.some((b) => b.cache === true))
|
|
93
|
+
throw refuse("model.complete", "`cache: true` is taken on system blocks only (a prompt block has no cache seat); put the text to cache in system");
|
|
94
|
+
if (model !== undefined && (typeof model !== "string" || model === ""))
|
|
95
|
+
throw refuse("model.complete", "model is a model reference (a non-empty string)");
|
|
96
|
+
if (typeof maxTokens !== "number" || !Number.isInteger(maxTokens) || maxTokens < 1)
|
|
97
|
+
throw refuse("model.complete", "maxTokens is a positive whole number");
|
|
98
|
+
const spans = system !== undefined && systemBlocks.some((b) => b.cache === true) ? alignedBlocks(system, systemBlocks) : undefined;
|
|
99
|
+
const context = {
|
|
100
|
+
...(system !== undefined && system !== "" ? { systemPrompt: system } : {}),
|
|
101
|
+
...(spans !== undefined ? { systemBlocks: spans.map((b) => ({ text: b.text, cacheControlBoundary: b.cache === true })) } : {}),
|
|
102
|
+
messages: [{ role: "user", content: prompt, timestamp: Date.now() }],
|
|
103
|
+
};
|
|
104
|
+
const reply = await view.complete({ ...(typeof model === "string" ? { model } : {}), maxTokens, context }, ctx.signal);
|
|
105
|
+
view.book({ model: reply.model, ...(reply.usage !== undefined ? { usage: reply.usage } : {}) });
|
|
106
|
+
return reply;
|
|
107
|
+
}
|
|
108
|
+
function sleep(args, ctx) {
|
|
109
|
+
only(args, "clock.sleep", ["ms"]);
|
|
110
|
+
const ms = args["ms"];
|
|
111
|
+
if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0)
|
|
112
|
+
throw refuse("clock.sleep", "takes { ms }, a non-negative number of milliseconds");
|
|
113
|
+
return new Promise((resolve, reject) => {
|
|
114
|
+
if (ctx.signal.aborted)
|
|
115
|
+
return reject(ctx.signal.reason);
|
|
116
|
+
const t = setTimeout(() => {
|
|
117
|
+
ctx.signal.removeEventListener("abort", stop);
|
|
118
|
+
resolve();
|
|
119
|
+
}, ms);
|
|
120
|
+
const stop = () => {
|
|
121
|
+
clearTimeout(t);
|
|
122
|
+
reject(ctx.signal.reason);
|
|
123
|
+
};
|
|
124
|
+
ctx.signal.addEventListener("abort", stop, { once: true });
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
function detachedMessage(m) {
|
|
128
|
+
try {
|
|
129
|
+
return structuredClone(m);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
throw refuse("session.messages", "a session message could not be copied; the history is not handed out live");
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const read = (event, f) => (args) => {
|
|
136
|
+
only(args, event, []);
|
|
137
|
+
return f();
|
|
138
|
+
};
|
|
139
|
+
export function engineMethodBottoms(view) {
|
|
140
|
+
const run = (f) => Object.freeze({ run: f });
|
|
141
|
+
return Object.freeze({
|
|
142
|
+
"process.run": run((args, ctx) => processRun(view, args, ctx)),
|
|
143
|
+
"model.complete": Object.freeze({ enter: modelCompleteEnter, run: (args, ctx) => modelComplete(view, args, ctx) }),
|
|
144
|
+
"session.id": run(read("session.id", () => view.session.id())),
|
|
145
|
+
"session.cwd": run(read("session.cwd", () => view.session.cwd())),
|
|
146
|
+
"session.root": run(read("session.root", () => view.session.root())),
|
|
147
|
+
"session.model": run(read("session.model", () => view.session.model())),
|
|
148
|
+
"session.messages": run(read("session.messages", () => Object.freeze(view.session.messages().slice(-SESSION_MESSAGES_MAX).map(detachedMessage)))),
|
|
149
|
+
"clock.now": run(read("clock.now", () => view.now())),
|
|
150
|
+
"clock.sleep": run((args, ctx) => sleep(args, ctx)),
|
|
151
|
+
"tool.list": run(read("tool.list", () => Object.freeze([...view.tools()]))),
|
|
152
|
+
"agent.list": run(read("agent.list", () => Object.freeze([...view.agents()]))),
|
|
153
|
+
});
|
|
154
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The engine's side of the mods bus's two outward faces: which registrations the two seats hold, the
|
|
3
|
+
* notice an admission refusal becomes, and the sink that carries handler failures to `onError`.
|
|
4
|
+
*/
|
|
5
|
+
import type { EngineNotice } from "../engine-notice.js";
|
|
6
|
+
import type { RunnerDeps } from "../runner-deps.js";
|
|
7
|
+
import type { TaskSpec } from "../task-spec.js";
|
|
8
|
+
import { type ModAdmissionRecord, type ModBusInput, type ModSeats } from "./kernel/index.js";
|
|
9
|
+
import type { EngineDollar } from "./dollar.js";
|
|
10
|
+
/**
|
|
11
|
+
* The two seats, both kept: the deployment's (`RunnerDeps.mods`) and the task's (`TaskSpec.mods`). Neither overrides the other.
|
|
12
|
+
* (A retired `hooks` key on either is not read here: it is refused by name at the retired-key doors, where every other
|
|
13
|
+
* retired seat is — `retired-keys.ts`.)
|
|
14
|
+
*/
|
|
15
|
+
export declare function modSeatsOf(spec: Pick<TaskSpec, "mods">, deps: Pick<RunnerDeps, "mods">): ModSeats<EngineDollar>;
|
|
16
|
+
/** Handler failures land on the deployment's `onError` with `phase: "hook"`; a throwing sink is swallowed. */
|
|
17
|
+
export declare function modsReportToOnError(onError: RunnerDeps["onError"], sessionId: string): ModBusInput["report"];
|
|
18
|
+
type RefusedRecord = Extract<ModAdmissionRecord, {
|
|
19
|
+
readonly refusedBy: string;
|
|
20
|
+
}>;
|
|
21
|
+
/** The notice for a registration admission refused: the run goes on without it. */
|
|
22
|
+
export declare function registrationRefusedNotice(record: RefusedRecord, sessionId: string): EngineNotice;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { MODS_REGISTRATION_REFUSED_CODE } from "./kernel/index.js";
|
|
2
|
+
export function modSeatsOf(spec, deps) {
|
|
3
|
+
return { ...(deps.mods !== undefined ? { deployment: deps.mods } : {}), ...(spec.mods !== undefined ? { task: spec.mods } : {}) };
|
|
4
|
+
}
|
|
5
|
+
export function modsReportToOnError(onError, sessionId) {
|
|
6
|
+
return (err, classification) => {
|
|
7
|
+
try {
|
|
8
|
+
onError?.(err, { phase: "hook", sessionId, ...(classification !== undefined ? { classification } : {}) });
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
const REGISTRATION_REFUSED = "mods.registration_refused";
|
|
15
|
+
export function registrationRefusedNotice(record, sessionId) {
|
|
16
|
+
return {
|
|
17
|
+
code: REGISTRATION_REFUSED,
|
|
18
|
+
message: `extension "${record.name}" (${record.seat} seat) was not mounted: ${record.refusedBy} refused it — ${record.reason}`,
|
|
19
|
+
detail: { name: record.name, seat: record.seat, tier: record.tier, refusedBy: record.refusedBy, reason: record.reason, sessionId },
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The self budget every handler runs under (CC form): a pausable timer that stops while the handler waits
|
|
3
|
+
* on `next` or on a `$` call, plus the budget constants and the bad-value fallback for `budgetMs`.
|
|
4
|
+
*/
|
|
5
|
+
/** A handler's own time when its registration declares none (CC 2.1.296 `kSe` (cli296.js:239763)). */
|
|
6
|
+
export declare const DEFAULT_MOD_BUDGET_MS = 10000;
|
|
7
|
+
/** A `.catch`'s own time (CC 2.1.296 `z3e` (cli296.js:239763)). */
|
|
8
|
+
export declare const CATCH_BUDGET_MS = 1000;
|
|
9
|
+
/** How long after its budget ran out a handler that still has not settled is reported as a runaway (CC 2.1.296 `TFe` (cli296.js:239763)). */
|
|
10
|
+
export declare const RUNAWAY_AFTER_MS = 5000;
|
|
11
|
+
/** How long an observation dispatch still waits after the task is cancelled. */
|
|
12
|
+
export declare const POST_ABORT_GRACE_MS = 1000;
|
|
13
|
+
/** `setTimeout`'s ceiling; above it the platform clamps to about 1 ms. */
|
|
14
|
+
export declare const MAX_TIMER_MS = 2147483647;
|
|
15
|
+
/** What `next.budget` reads: the handler's budget and what is left of it. */
|
|
16
|
+
export interface ModBudgetReading {
|
|
17
|
+
readonly ms: number;
|
|
18
|
+
readonly remainingMs: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* `budgetMs` as a usable budget: the declared value when it is one, the default when absent, and the
|
|
22
|
+
* default LOUDLY (one report) when it is garbage. A bad value is never a refusal.
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveModBudgetMs(supplied: unknown, report: (err: Error) => void, name: string): number;
|
|
25
|
+
export interface SelfBudget {
|
|
26
|
+
/** Resolves once, when the budget runs out (never rejects). */
|
|
27
|
+
readonly expired: Promise<"expired">;
|
|
28
|
+
isExpired(): boolean;
|
|
29
|
+
/** Stop the clock; nested pauses need as many resumes. */
|
|
30
|
+
pause(): void;
|
|
31
|
+
resume(): void;
|
|
32
|
+
/** Stop for good (the handler settled). */
|
|
33
|
+
clear(): void;
|
|
34
|
+
/** The handler's own time so far. */
|
|
35
|
+
usedMs(): number;
|
|
36
|
+
reading(): ModBudgetReading;
|
|
37
|
+
}
|
|
38
|
+
/** Start a budget of `ms`; `onExpire` runs once when it runs out. A zero budget runs out on the next timer turn. */
|
|
39
|
+
export declare function createSelfBudget(ms: number, onExpire: () => void): SelfBudget;
|
|
40
|
+
/** Run `onRunaway` once if `settled` has not settled `RUNAWAY_AFTER_MS` after a budget ran out. */
|
|
41
|
+
export declare function watchRunaway(settled: Promise<unknown>, onRunaway: () => void): void;
|
|
42
|
+
/** Let a host process exit with a watch still pending (a no-op where timers are plain numbers). */
|
|
43
|
+
export declare function unrefTimer(timer: unknown): void;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export const DEFAULT_MOD_BUDGET_MS = 10_000;
|
|
2
|
+
export const CATCH_BUDGET_MS = 1_000;
|
|
3
|
+
export const RUNAWAY_AFTER_MS = 5_000;
|
|
4
|
+
export const POST_ABORT_GRACE_MS = 1_000;
|
|
5
|
+
export const MAX_TIMER_MS = 2_147_483_647;
|
|
6
|
+
export function resolveModBudgetMs(supplied, report, name) {
|
|
7
|
+
if (supplied === undefined)
|
|
8
|
+
return DEFAULT_MOD_BUDGET_MS;
|
|
9
|
+
if (typeof supplied === "number" && Number.isFinite(supplied) && supplied >= 0 && supplied <= MAX_TIMER_MS)
|
|
10
|
+
return supplied;
|
|
11
|
+
const got = typeof supplied === "number" ? String(supplied) : typeof supplied;
|
|
12
|
+
report(new Error(`${name}: budgetMs must be a non-negative finite number no greater than ${MAX_TIMER_MS} (got ${got}) — ` +
|
|
13
|
+
`every handler of this registration falls back to the ${DEFAULT_MOD_BUDGET_MS}ms default`));
|
|
14
|
+
return DEFAULT_MOD_BUDGET_MS;
|
|
15
|
+
}
|
|
16
|
+
export function createSelfBudget(ms, onExpire) {
|
|
17
|
+
let remaining = ms;
|
|
18
|
+
let runningSince;
|
|
19
|
+
let timer;
|
|
20
|
+
let pauses = 0;
|
|
21
|
+
let done = false;
|
|
22
|
+
let expired = false;
|
|
23
|
+
let fire = () => { };
|
|
24
|
+
const expiredP = new Promise((res) => (fire = res));
|
|
25
|
+
const left = () => (runningSince === undefined ? remaining : Math.max(0, remaining - (Date.now() - runningSince)));
|
|
26
|
+
const arm = () => {
|
|
27
|
+
runningSince = Date.now();
|
|
28
|
+
timer = setTimeout(() => {
|
|
29
|
+
if (done)
|
|
30
|
+
return;
|
|
31
|
+
expired = true;
|
|
32
|
+
done = true;
|
|
33
|
+
remaining = 0;
|
|
34
|
+
runningSince = undefined;
|
|
35
|
+
fire("expired");
|
|
36
|
+
onExpire();
|
|
37
|
+
}, remaining);
|
|
38
|
+
};
|
|
39
|
+
arm();
|
|
40
|
+
return {
|
|
41
|
+
expired: expiredP,
|
|
42
|
+
isExpired: () => expired,
|
|
43
|
+
pause() {
|
|
44
|
+
if (pauses++ !== 0 || done)
|
|
45
|
+
return;
|
|
46
|
+
clearTimeout(timer);
|
|
47
|
+
remaining = left();
|
|
48
|
+
runningSince = undefined;
|
|
49
|
+
},
|
|
50
|
+
resume() {
|
|
51
|
+
if (pauses === 0)
|
|
52
|
+
return;
|
|
53
|
+
if (--pauses !== 0 || done)
|
|
54
|
+
return;
|
|
55
|
+
arm();
|
|
56
|
+
},
|
|
57
|
+
clear() {
|
|
58
|
+
if (done)
|
|
59
|
+
return;
|
|
60
|
+
remaining = left();
|
|
61
|
+
runningSince = undefined;
|
|
62
|
+
done = true;
|
|
63
|
+
clearTimeout(timer);
|
|
64
|
+
},
|
|
65
|
+
usedMs: () => ms - left(),
|
|
66
|
+
reading: () => Object.freeze({ ms, remainingMs: left() }),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
export function watchRunaway(settled, onRunaway) {
|
|
70
|
+
let over = false;
|
|
71
|
+
const mark = () => {
|
|
72
|
+
over = true;
|
|
73
|
+
};
|
|
74
|
+
settled.then(mark, mark);
|
|
75
|
+
unrefTimer(setTimeout(() => {
|
|
76
|
+
if (!over)
|
|
77
|
+
onRunaway();
|
|
78
|
+
}, RUNAWAY_AFTER_MS));
|
|
79
|
+
}
|
|
80
|
+
export function unrefTimer(timer) {
|
|
81
|
+
if (typeof timer === "object" && timer !== null && "unref" in timer && typeof timer.unref === "function")
|
|
82
|
+
timer.unref();
|
|
83
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { type ModBusSide, type ModEventName, type ModSeat } from "./events.js";
|
|
2
|
+
import { type ModAdmissionRecord, type ModDollarBase, type ModOrigin, type ModSeats } from "./registration.js";
|
|
3
|
+
import { type ModAnswerCheck, type ModEventPayload, type ModFailureCause, type ModMatcher, type ModSkip, type ProxyProbe } from "./site-rules.js";
|
|
4
|
+
/** A frame on the dispatch stack: a registration's own `$` call, or one of its handlers running. */
|
|
5
|
+
export type ModFrame = {
|
|
6
|
+
readonly kind: "dollar";
|
|
7
|
+
readonly plugin: string;
|
|
8
|
+
} | {
|
|
9
|
+
readonly kind: "handler";
|
|
10
|
+
readonly plugin: string;
|
|
11
|
+
readonly handler: number;
|
|
12
|
+
};
|
|
13
|
+
/** What a chain bottom (the core of an event) receives besides `e`. */
|
|
14
|
+
export interface ModBottomContext {
|
|
15
|
+
readonly frames: readonly ModFrame[];
|
|
16
|
+
readonly signal: AbortSignal;
|
|
17
|
+
readonly origin: ModOrigin;
|
|
18
|
+
}
|
|
19
|
+
/** A `$` method's chain bottom: the host's seat behind it. Its throw is the caller's throw. */
|
|
20
|
+
export type ModMethodBottom = (args: ModEventPayload, ctx: ModBottomContext) => unknown;
|
|
21
|
+
/**
|
|
22
|
+
* A `$` method on a bus: `run` is its chain bottom; `enter`, when the method has one, shapes the caller's (received)
|
|
23
|
+
* arguments into the event payload the chain sees — the one place a method's argument form is normalised before any
|
|
24
|
+
* handler reads it. Either one's throw is the caller's throw.
|
|
25
|
+
*/
|
|
26
|
+
export interface ModMethodSeat {
|
|
27
|
+
readonly run: ModMethodBottom;
|
|
28
|
+
readonly enter?: (args: ModEventPayload) => ModEventPayload;
|
|
29
|
+
}
|
|
30
|
+
export type ModMethodBottoms = Partial<Record<ModEventName, ModMethodSeat>>;
|
|
31
|
+
export type ModDispatchOutcome = {
|
|
32
|
+
readonly kind: "answered";
|
|
33
|
+
readonly answer: unknown;
|
|
34
|
+
readonly answeredBy?: string;
|
|
35
|
+
readonly skipped: readonly ModSkip[];
|
|
36
|
+
} | {
|
|
37
|
+
readonly kind: "failed";
|
|
38
|
+
readonly registration: string;
|
|
39
|
+
readonly cause: ModFailureCause;
|
|
40
|
+
readonly reason: string;
|
|
41
|
+
readonly skipped: readonly ModSkip[];
|
|
42
|
+
} | {
|
|
43
|
+
readonly kind: "aborted";
|
|
44
|
+
};
|
|
45
|
+
/** What a participant filter sees of one mounted handler: its registration, that registration's seat, and whether it only observes. */
|
|
46
|
+
export interface ModParticipant {
|
|
47
|
+
readonly plugin: string;
|
|
48
|
+
readonly seat: ModSeat;
|
|
49
|
+
readonly observe: boolean;
|
|
50
|
+
}
|
|
51
|
+
export interface ModDispatchOptions {
|
|
52
|
+
/** The core of the event: what the engine (or shell) does when the chain reaches the bottom. */
|
|
53
|
+
readonly bottom: (e: ModEventPayload, ctx: ModBottomContext) => unknown;
|
|
54
|
+
readonly signal?: AbortSignal;
|
|
55
|
+
/** The frames the event is raised under (a chain bottom hands its own `ctx.frames` on). */
|
|
56
|
+
readonly frames?: readonly ModFrame[];
|
|
57
|
+
readonly origin?: ModOrigin;
|
|
58
|
+
/** The raiser's reading of an answer; an answer it refuses is a violation of the site. */
|
|
59
|
+
readonly checkAnswer?: ModAnswerCheck;
|
|
60
|
+
/** Which mounted handlers take part (absent ⇒ every handler on the event). A handler it leaves out neither runs nor observes. */
|
|
61
|
+
readonly participant?: (p: ModParticipant) => boolean;
|
|
62
|
+
}
|
|
63
|
+
/** One handler as admission hung it — what a registration's `register` mounted, never its code. */
|
|
64
|
+
export interface ModMountedHandler {
|
|
65
|
+
readonly plugin: string;
|
|
66
|
+
readonly seat: ModSeat;
|
|
67
|
+
readonly pattern: string;
|
|
68
|
+
readonly matcher?: ModMatcher;
|
|
69
|
+
readonly observe: boolean;
|
|
70
|
+
/** Whether it was hung with a `.catch`. */
|
|
71
|
+
readonly caught: boolean;
|
|
72
|
+
}
|
|
73
|
+
export interface ModBus {
|
|
74
|
+
readonly records: readonly ModAdmissionRecord[];
|
|
75
|
+
/** Every mounted handler, in mount order (registrations in run order, each in the order its `register` hung them). */
|
|
76
|
+
mounted(): readonly ModMountedHandler[];
|
|
77
|
+
/** Whether any mounted handler hangs on `event` (among those `participant` admits) — no handler, no dispatch (the station skips the call). */
|
|
78
|
+
hasHandlers(event: ModEventName, participant?: (p: ModParticipant) => boolean): boolean;
|
|
79
|
+
dispatch(event: ModEventName, e: ModEventPayload, options: ModDispatchOptions): Promise<ModDispatchOutcome>;
|
|
80
|
+
}
|
|
81
|
+
export interface ModBusInput<D extends ModDollarBase = ModDollarBase> {
|
|
82
|
+
readonly side: ModBusSide;
|
|
83
|
+
readonly seats: ModSeats<D>;
|
|
84
|
+
readonly bottoms: ModMethodBottoms;
|
|
85
|
+
/** Where handler failures go (the host's error channel). Never throws back into the bus. */
|
|
86
|
+
readonly report: (err: Error, classification?: "observational-hook-verdict-ignored") => void;
|
|
87
|
+
/** The host's one rule for turning a THROWN value into text (a handler, a `.catch` or a `register` may throw
|
|
88
|
+
* anything). The bus has no rendering of its own: every failure reason it writes names the value this way. */
|
|
89
|
+
readonly describeThrown: (err: unknown) => string;
|
|
90
|
+
/** The host's Proxy probe: a Proxy a handler answers or hands on is refused before any of its traps runs (a violation
|
|
91
|
+
* of the site). Absent ⇒ a Proxy is read like any object, its traps run by the copy. */
|
|
92
|
+
readonly isProxy?: ProxyProbe;
|
|
93
|
+
readonly signal?: AbortSignal;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Screen both seats, then admit registrations one by one in run order: each is put to the
|
|
97
|
+
* `plugin.register` handlers of the registrations already admitted; a refused one is never registered
|
|
98
|
+
* (its code never runs). Throws `config.mods_invalid` for a registration the kernel cannot take.
|
|
99
|
+
*/
|
|
100
|
+
export declare function admitMods<D extends ModDollarBase = ModDollarBase>(input: ModBusInput<D>): Promise<ModBus>;
|