@sema-agent/core 7.52.0 → 7.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +470 -0
- package/LICENSE +3 -1
- package/README.md +3 -1
- package/dist/agents/cross-session-envelope.d.ts +8 -0
- package/dist/agents/cross-session-envelope.js +6 -0
- package/dist/agents/cross-session-judge.d.ts +21 -1
- package/dist/agents/cross-session-judge.js +8 -0
- package/dist/agents/cross-session-ref.d.ts +5 -0
- package/dist/agents/cross-session-ref.js +1 -0
- package/dist/agents/org-delivery-gate.d.ts +122 -0
- package/dist/agents/org-delivery-gate.js +69 -0
- package/dist/agents/peer-held-queue.d.ts +9 -4
- package/dist/agents/peer-held-queue.js +6 -5
- package/dist/agents/peer-session-drain.d.ts +35 -6
- package/dist/agents/peer-session-drain.js +271 -182
- package/dist/agents/read-inbox-tool.d.ts +7 -0
- package/dist/agents/read-inbox-tool.js +5 -1
- package/dist/agents/send-message-tool.js +3 -4
- package/dist/agents/subagent.d.ts +6 -5
- package/dist/agents/subagent.js +117 -83
- package/dist/agents/tool-filter.d.ts +25 -4
- package/dist/agents/tool-filter.js +13 -3
- package/dist/brain/anthropic.d.ts +6 -1
- package/dist/brain/anthropic.js +4 -4
- package/dist/brain/model-presets.js +2 -1
- package/dist/brain/route-adjudicator.d.ts +6 -0
- package/dist/brain/routing.d.ts +24 -1
- package/dist/brain/routing.js +54 -19
- package/dist/brain/timeout.js +5 -4
- package/dist/core/a2a.d.ts +5 -2
- package/dist/core/a2a.js +33 -14
- package/dist/core/allow-entry.d.ts +3 -1
- package/dist/core/allow-entry.js +3 -2
- package/dist/core/approval-object.d.ts +87 -0
- package/dist/core/approval-object.js +85 -0
- package/dist/core/arg-summary.d.ts +3 -2
- package/dist/core/arg-summary.js +17 -11
- package/dist/core/ask-origin.d.ts +43 -27
- package/dist/core/ask-origin.js +20 -11
- package/dist/core/ask-question.d.ts +0 -1
- package/dist/core/ask-question.js +4 -67
- package/dist/core/ask-unresolvable-notice.d.ts +3 -2
- package/dist/core/auto-compaction.d.ts +106 -50
- package/dist/core/auto-compaction.js +69 -53
- package/dist/core/auto-mode-prompt.d.ts +4 -2
- package/dist/core/auto-mode-prompt.js +4 -3
- package/dist/core/canonical-json.d.ts +69 -0
- package/dist/core/canonical-json.js +130 -8
- package/dist/core/checkpoint-requirements.d.ts +13 -7
- package/dist/core/checkpoint-requirements.js +4 -1
- package/dist/core/checkpoint-store.d.ts +60 -36
- package/dist/core/checkpoint-store.js +7 -6
- package/dist/core/child-clamp-seats.d.ts +45 -6
- package/dist/core/child-clamp-seats.js +56 -4
- package/dist/core/compliance.js +3 -1
- package/dist/core/consolidate-scope.d.ts +1 -1
- package/dist/core/cross-boundary-taint.d.ts +213 -0
- package/dist/core/cross-boundary-taint.js +196 -0
- package/dist/core/decision-receipt.d.ts +44 -1
- package/dist/core/decision-receipt.js +16 -0
- package/dist/core/effective-path-target.d.ts +28 -6
- package/dist/core/effective-path-target.js +28 -2
- package/dist/core/engine-notice.d.ts +47 -4
- package/dist/core/engine-notice.js +17 -1
- package/dist/core/engine-storage-backend.d.ts +73 -0
- package/dist/core/engine-storage-backend.js +1 -0
- package/dist/core/file-history-store.d.ts +6 -2
- package/dist/core/file-history-store.js +1 -0
- package/dist/core/gate-fold.js +13 -4
- package/dist/core/gate-lanes.js +41 -34
- package/dist/core/gate-outcome.d.ts +18 -9
- package/dist/core/governance-codes.d.ts +9 -2
- package/dist/core/governance-codes.js +9 -0
- package/dist/core/hands-band-screen.d.ts +7 -0
- package/dist/core/hands-band-screen.js +32 -0
- package/dist/core/hooks.d.ts +21 -19
- package/dist/core/hooks.js +6 -5
- package/dist/core/locked-config.d.ts +110 -31
- package/dist/core/locked-config.js +155 -42
- package/dist/core/lsp.d.ts +1 -1
- package/dist/core/mcp-probe.js +1 -1
- package/dist/core/mcp-server-spec.d.ts +152 -17
- package/dist/core/mcp-server-spec.js +223 -40
- package/dist/core/mcp.d.ts +21 -14
- package/dist/core/mcp.js +59 -54
- package/dist/core/memory-engine/engine.d.ts +14 -19
- package/dist/core/memory-engine/engine.js +9 -6
- package/dist/core/memory-engine/export-bundle.d.ts +1 -1
- package/dist/core/memory-engine/export-bundle.js +1 -1
- package/dist/core/memory-engine/file-backend.d.ts +2 -6
- package/dist/core/memory-engine/file-backend.js +1 -12
- package/dist/core/memory.d.ts +3 -3
- package/dist/core/mode-policy.d.ts +16 -26
- package/dist/core/mode-policy.js +5 -18
- package/dist/core/mods/kernel/dispatch.js +13 -15
- package/dist/core/mods/kernel/events.d.ts +9 -6
- package/dist/core/mods/kernel/events.js +2 -2
- package/dist/core/mods/kernel/receive.d.ts +41 -11
- package/dist/core/mods/kernel/receive.js +124 -54
- package/dist/core/mods/kernel/site-rules.d.ts +80 -15
- package/dist/core/mods/kernel/site-rules.js +232 -40
- package/dist/core/mods/stations.d.ts +0 -6
- package/dist/core/mods/stations.js +0 -7
- package/dist/core/mounted-mcp.d.ts +57 -0
- package/dist/core/mounted-mcp.js +71 -2
- package/dist/core/own-property-receipt.d.ts +13 -0
- package/dist/core/own-property-receipt.js +3 -1
- package/dist/core/parent-spec-seat.d.ts +12 -15
- package/dist/core/parent-spec-seat.js +14 -6
- package/dist/core/pause-registry.d.ts +35 -1
- package/dist/core/pause-registry.js +10 -0
- package/dist/core/permission-rule-consent.d.ts +18 -5
- package/dist/core/permission-rule-consent.js +13 -8
- package/dist/core/permission-rule-model.d.ts +87 -15
- package/dist/core/permission-rule-model.js +87 -8
- package/dist/core/permission-rule-org.d.ts +200 -33
- package/dist/core/permission-rule-org.js +217 -91
- package/dist/core/permission-rule-session.js +2 -2
- package/dist/core/permission-rule-store.d.ts +8 -0
- package/dist/core/permission-rule-store.js +1 -0
- package/dist/core/permission-rule-sync.js +3 -2
- package/dist/core/permission-rules.d.ts +7 -1
- package/dist/core/permission-rules.js +37 -8
- package/dist/core/read-only-shell.d.ts +1 -1
- package/dist/core/read-only-shell.js +30 -9
- package/dist/core/remote-env.d.ts +41 -1
- package/dist/core/remote-env.js +18 -0
- package/dist/core/resume-startup-cause.d.ts +18 -0
- package/dist/core/resume-startup-cause.js +12 -0
- package/dist/core/retention.js +7 -2
- package/dist/core/retired-keys.d.ts +8 -2
- package/dist/core/retired-keys.js +12 -1
- package/dist/core/roles.js +60 -10
- package/dist/core/rule-lane-reads.js +1 -1
- package/dist/core/runner/approval-feedback.d.ts +46 -0
- package/dist/core/runner/approval-feedback.js +41 -0
- package/dist/core/runner/compaction-call-options.d.ts +3 -3
- package/dist/core/runner/compaction-call-options.js +2 -2
- package/dist/core/runner/contracts.d.ts +34 -41
- package/dist/core/runner/cross-boundary-lane.d.ts +87 -0
- package/dist/core/runner/cross-boundary-lane.js +190 -0
- package/dist/core/runner/decide-continuation.d.ts +4 -4
- package/dist/core/runner/decide-continuation.js +3 -1
- package/dist/core/runner/gate-exit.d.ts +32 -12
- package/dist/core/runner/gate-exit.js +77 -34
- package/dist/core/runner/inherited-ask-grants.js +2 -2
- package/dist/core/runner/mcp-redial.d.ts +52 -10
- package/dist/core/runner/mcp-redial.js +38 -9
- package/dist/core/runner/permission-rule-lanes.d.ts +5 -2
- package/dist/core/runner/permission-rule-lanes.js +22 -10
- package/dist/core/runner/person-path-rows.d.ts +5 -3
- package/dist/core/runner/person-path-rows.js +2 -2
- package/dist/core/runner/prepare-acquire-reconcile.d.ts +3 -4
- package/dist/core/runner/prepare-acquire-reconcile.js +3 -3
- package/dist/core/runner/prepare-ask-lane.js +3 -3
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +6 -5
- package/dist/core/runner/prepare-caps-and-workflow.js +3 -3
- package/dist/core/runner/prepare-config-doors.d.ts +58 -15
- package/dist/core/runner/prepare-config-doors.js +167 -146
- package/dist/core/runner/prepare-context-lane.js +6 -3
- package/dist/core/runner/prepare-defer-classify.js +4 -7
- package/dist/core/runner/prepare-delegation-surface.d.ts +5 -4
- package/dist/core/runner/prepare-delegation-surface.js +8 -7
- package/dist/core/runner/prepare-execution-env.d.ts +1 -2
- package/dist/core/runner/prepare-execution-env.js +2 -1
- package/dist/core/runner/prepare-gate-stations.d.ts +2 -0
- package/dist/core/runner/prepare-gate-stations.js +4 -3
- package/dist/core/runner/prepare-hands-readface.d.ts +3 -3
- package/dist/core/runner/prepare-hands-readface.js +3 -2
- package/dist/core/runner/prepare-inherited-gate.d.ts +2 -0
- package/dist/core/runner/prepare-inherited-gate.js +3 -2
- package/dist/core/runner/prepare-listings.d.ts +1 -1
- package/dist/core/runner/prepare-listings.js +4 -2
- package/dist/core/runner/prepare-memory-engine-session.d.ts +0 -6
- package/dist/core/runner/prepare-memory-engine-session.js +19 -6
- package/dist/core/runner/prepare-memory.d.ts +3 -2
- package/dist/core/runner/prepare-memory.js +6 -2
- package/dist/core/runner/prepare-offload-wrappers.d.ts +4 -4
- package/dist/core/runner/prepare-offload-wrappers.js +2 -1
- package/dist/core/runner/prepare-park-ask.d.ts +1 -1
- package/dist/core/runner/prepare-park-ask.js +9 -3
- package/dist/core/runner/prepare-policy-chain.d.ts +1 -1
- package/dist/core/runner/prepare-policy-chain.js +14 -19
- package/dist/core/runner/prepare-project-context.d.ts +1 -1
- package/dist/core/runner/prepare-project-context.js +6 -4
- package/dist/core/runner/prepare-prompt-assembly.d.ts +1 -1
- package/dist/core/runner/prepare-prompt-assembly.js +20 -16
- package/dist/core/runner/prepare-prompt-inputs.d.ts +12 -6
- package/dist/core/runner/prepare-prompt-inputs.js +6 -3
- package/dist/core/runner/prepare-protocol-tools.d.ts +7 -5
- package/dist/core/runner/prepare-protocol-tools.js +19 -12
- package/dist/core/runner/prepare-question-face.d.ts +4 -2
- package/dist/core/runner/prepare-question-face.js +4 -3
- package/dist/core/runner/prepare-safety-scan.d.ts +7 -2
- package/dist/core/runner/prepare-safety-scan.js +34 -27
- package/dist/core/runner/prepare-suspend-saga.d.ts +2 -2
- package/dist/core/runner/prepare-suspend-saga.js +6 -2
- package/dist/core/runner/prepare-task.js +22 -19
- package/dist/core/runner/prepare-turn-wiring.d.ts +10 -5
- package/dist/core/runner/prepare-turn-wiring.js +14 -49
- package/dist/core/runner/prepare-wiring-manifest.d.ts +10 -5
- package/dist/core/runner/prepare-wiring-manifest.js +9 -6
- package/dist/core/runner/prepare-workspace-restore.js +2 -2
- package/dist/core/runner/resume-admission.d.ts +4 -1
- package/dist/core/runner/resume-admission.js +16 -14
- package/dist/core/runner/resume-apply.js +4 -4
- package/dist/core/runner/resume-internals-and-config.d.ts +3 -3
- package/dist/core/runner/resume-internals-and-config.js +3 -8
- package/dist/core/runner/resume-policy-outcome.d.ts +2 -2
- package/dist/core/runner/resume-policy-outcome.js +18 -15
- package/dist/core/runner/resume-preflight.js +2 -2
- package/dist/core/runner/resume-review-outcome.js +3 -3
- package/dist/core/runner/retired-runner-deps.d.ts +5 -6
- package/dist/core/runner/retired-runner-deps.js +1 -4
- package/dist/core/runner/run-leg.js +97 -43
- package/dist/core/runner/run-recovery-lanes.js +5 -3
- package/dist/core/runner/run-settle-and-teardown.js +2 -0
- package/dist/core/runner/run-terminal-adoption.js +21 -9
- package/dist/core/runner/run-turn-boundary.js +9 -3
- package/dist/core/runner/runtask.js +1 -1
- package/dist/core/runner/session-file-state-replay.d.ts +5 -2
- package/dist/core/runner/session-file-state-replay.js +3 -2
- package/dist/core/runner/skills-seat.d.ts +15 -0
- package/dist/core/runner/skills-seat.js +57 -0
- package/dist/core/runner/stream-steer-verb.js +2 -2
- package/dist/core/runner/sub-agent-deny-lists.d.ts +13 -11
- package/dist/core/runner/sub-agent-deny-lists.js +7 -5
- package/dist/core/runner/synthetic-tools.d.ts +5 -2
- package/dist/core/runner/synthetic-tools.js +2 -12
- package/dist/core/runner/tool-face-overlay.d.ts +24 -6
- package/dist/core/runner/tool-face-overlay.js +24 -15
- package/dist/core/runner-deps.d.ts +37 -22
- package/dist/core/session-policy-store.d.ts +19 -0
- package/dist/core/session-policy-store.js +22 -2
- package/dist/core/session-store.d.ts +35 -16
- package/dist/core/session-store.js +20 -12
- package/dist/core/{shell-lexer.d.ts → shell-run-candidates.d.ts} +36 -12
- package/dist/core/{shell-lexer.js → shell-run-candidates.js} +145 -225
- package/dist/core/shell-wrapper-table.d.ts +5 -3
- package/dist/core/shell-wrapper-table.js +1 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +2 -2
- package/dist/core/store-contracts/mailbox-store-contract.js +13 -0
- package/dist/core/store-contracts/session-store-contract.d.ts +49 -0
- package/dist/core/store-contracts/session-store-contract.js +639 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +12 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.js +5 -2
- package/dist/core/task-event.d.ts +44 -6
- package/dist/core/task-notification.js +2 -2
- package/dist/core/task-registry-agent.js +1 -0
- package/dist/core/task-registry-shared.d.ts +5 -0
- package/dist/core/task-registry.d.ts +7 -0
- package/dist/core/task-registry.js +17 -0
- package/dist/core/task-result.d.ts +1 -1
- package/dist/core/task-spec.d.ts +7 -7
- package/dist/core/tighten-task-spec.d.ts +6 -4
- package/dist/core/tighten-task-spec.js +2 -2
- package/dist/core/tool-catalog-entries.d.ts +1 -1
- package/dist/core/tool-catalog-entries.js +52 -52
- package/dist/core/tool-face-reader.d.ts +49 -0
- package/dist/core/tool-face-reader.js +94 -0
- package/dist/core/tool-face.d.ts +17 -8
- package/dist/core/tool-face.js +1 -0
- package/dist/core/tool-policy.d.ts +67 -23
- package/dist/core/tool-policy.js +72 -60
- package/dist/core/tool-roster.d.ts +46 -28
- package/dist/core/tool-roster.js +91 -14
- package/dist/core/tool-spec-members.js +2 -2
- package/dist/core/tool-spec.d.ts +20 -4
- package/dist/core/tools.js +2 -0
- package/dist/core/trace.d.ts +24 -2
- package/dist/core/types.d.ts +3 -3
- package/dist/core/types.js +1 -1
- package/dist/core/untrusted-text.d.ts +23 -0
- package/dist/core/untrusted-text.js +10 -10
- package/dist/core/user-attachment.d.ts +56 -2
- package/dist/core/user-attachment.js +139 -56
- package/dist/core/wiring-manifest.d.ts +4 -2
- package/dist/engine/compaction/compaction.d.ts +2 -2
- package/dist/engine/compaction/utils.d.ts +2 -2
- package/dist/engine/harness/agent-harness.js +2 -1
- package/dist/engine/harness/types.d.ts +10 -4
- package/dist/engine/llm/types.d.ts +7 -2
- package/dist/engine/llm/types.js +2 -1
- package/dist/engine/loop/agent-loop.d.ts +12 -1
- package/dist/engine/loop/agent-loop.js +17 -5
- package/dist/engine/loop/types.d.ts +7 -1
- package/dist/engine/session/repo-utils.d.ts +5 -0
- package/dist/engine/session/repo-utils.js +9 -0
- package/dist/engine/session/storage-base.js +2 -2
- package/dist/index.d.ts +37 -17
- package/dist/index.js +31 -14
- package/dist/internal/harness.d.ts +1 -0
- package/dist/internal/harness.js +1 -0
- package/dist/internal/llm.d.ts +1 -1
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/goal.d.ts +24 -1
- package/dist/orchestration/goal.js +3 -2
- package/dist/orchestration/run-workflow-tool.d.ts +3 -0
- package/dist/orchestration/run-workflow-tool.js +1 -0
- package/dist/orchestration/workflow-governance.d.ts +1 -1
- package/dist/orchestration/workflow.d.ts +3 -0
- package/dist/orchestration/workflow.js +2 -1
- package/dist/prompt-assembly/artifact-store.d.ts +44 -9
- package/dist/prompt-assembly/artifact-store.js +38 -12
- package/dist/prompt-assembly/artifact.d.ts +12 -11
- package/dist/prompt-assembly/artifact.js +52 -21
- package/dist/prompt-assembly/assemble.d.ts +2 -0
- package/dist/prompt-assembly/assemble.js +2 -1
- package/dist/prompt-assembly/catalog/index.js +2 -1
- package/dist/prompt-assembly/catalog/memory.d.ts +13 -0
- package/dist/prompt-assembly/catalog/memory.js +6 -0
- package/dist/prompt-assembly/catalog/schema.d.ts +19 -2
- package/dist/prompt-assembly/catalog/schema.js +3 -0
- package/dist/prompt-assembly/composer.d.ts +2 -0
- package/dist/prompt-assembly/composer.js +1 -1
- package/dist/prompt-assembly/overlay.d.ts +21 -11
- package/dist/prompt-assembly/overlay.js +57 -19
- package/dist/prompt-assembly/select.d.ts +21 -6
- package/dist/prompt-assembly/select.js +41 -4
- package/dist/prompts/default.d.ts +1 -12
- package/dist/prompts/default.js +0 -3
- package/dist/shell/lex.d.ts +87 -8
- package/dist/shell/lex.js +283 -49
- package/dist/stores/file/index.d.ts +8 -6
- package/dist/stores/file/permission-rule-store.d.ts +1 -1
- package/dist/stores/file/permission-rule-store.js +2 -1
- package/dist/tools/artifact/artifact-tool.js +14 -3
- package/dist/tools/fs/bash-program-position.d.ts +3 -15
- package/dist/tools/fs/bash-program-position.js +3 -10
- package/dist/tools/fs/bash-readonly-classifier.js +2 -0
- package/dist/tools/fs/fs-bash.d.ts +3 -3
- package/dist/tools/fs/fs-bash.js +72 -101
- package/dist/tools/fs/fs-read.d.ts +12 -0
- package/dist/tools/fs/fs-read.js +10 -9
- package/dist/tools/fs/fs-shared.d.ts +27 -31
- package/dist/tools/fs/fs-shared.js +12 -15
- package/dist/tools/fs/fs-write.js +1 -1
- package/dist/tools/fs/index.js +2 -2
- package/dist/tools/fs/read-deny-home.d.ts +1 -1
- package/dist/tools/fs/read-deny-home.js +5 -4
- package/dist/tools/fs/read-deny.d.ts +16 -3
- package/dist/tools/fs/read-deny.js +12 -9
- package/dist/tools/fs/safety.d.ts +7 -6
- package/dist/tools/fs/shell-read-bindings.d.ts +5 -3
- package/dist/tools/fs/shell-read-bindings.js +15 -16
- package/dist/tools/fs/shell-read-device.js +1 -1
- package/dist/tools/fs/shell-read-plan.js +36 -47
- package/dist/tools/fs/shell-read-word.d.ts +1 -6
- package/dist/tools/fs/shell-read-word.js +2 -20
- package/dist/tools/fs/shell-reentry-text.js +1 -1
- package/dist/tools/web.d.ts +2 -2
- package/package.json +4 -1
- package/test/export-surface.snapshot.json +5651 -5457
- package/wire-changes/core@7.53.0.json +1968 -0
- package/wire-changes/core@7.54.0.json +2870 -0
- package/dist/core/shell-scan.d.ts +0 -60
- package/dist/core/shell-scan.js +0 -183
|
@@ -1,13 +1,35 @@
|
|
|
1
|
+
import type { RunnerDeps } from "../core/runner-deps.js";
|
|
1
2
|
import { type ArtifactVerifyCode, type PromptArtifact, type PublishedPromptArtifact } from "./artifact.js";
|
|
3
|
+
/** Why a copy a store holds could not be used: the verifier refused it (its code and reason — a retired schema's reason
|
|
4
|
+
* names the republish rewrite), or the store could not read it back (`unreadable`, the reason naming the read error). */
|
|
5
|
+
export interface StoredArtifactRefusal {
|
|
6
|
+
readonly code: ArtifactVerifyCode | "unreadable";
|
|
7
|
+
readonly reason: string;
|
|
8
|
+
}
|
|
9
|
+
/** What a read tells its caller when a copy was there and could not be used. */
|
|
10
|
+
export type OnArtifactRefused = (refusal: StoredArtifactRefusal) => void;
|
|
11
|
+
/** The clause every reader says of a copy that could not be used, by its cause — one wording, wherever it is said. */
|
|
12
|
+
export declare function refusalClause(refusal: StoredArtifactRefusal): string;
|
|
13
|
+
/**
|
|
14
|
+
* The operator line for a stored center artifact that could not be read back: which copy, why — refused or unreadable
|
|
15
|
+
* (the clause above), or no copy at all — and what follows from it. The one sentence a boot restore and a pinned resume
|
|
16
|
+
* say.
|
|
17
|
+
*/
|
|
18
|
+
export declare function storedArtifactLine(artifactDigest: string, refusal: StoredArtifactRefusal | undefined, consequence: string): string;
|
|
2
19
|
export interface PromptArtifactStore {
|
|
3
|
-
/**
|
|
4
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Verified read by digest — undefined on a miss OR on a copy that cannot be used. When a copy was there and could not
|
|
22
|
+
* be used — the verifier refused its bytes, or the store could not read them — `onRefused` is told once before the
|
|
23
|
+
* read answers undefined, so a caller can tell a refused or unreadable copy (a retired schema, a corrupt file, a file
|
|
24
|
+
* the process may not read) from a missing one. A store that holds a copy it cannot use calls it.
|
|
25
|
+
*/
|
|
26
|
+
get(artifactDigest: string, onRefused?: OnArtifactRefused): Promise<PublishedPromptArtifact | undefined>;
|
|
5
27
|
/** Write by digest (the caller verified before putting). */
|
|
6
28
|
put(artifact: PublishedPromptArtifact): Promise<void>;
|
|
7
29
|
}
|
|
8
30
|
export declare class MemoryPromptArtifactStore implements PromptArtifactStore {
|
|
9
31
|
private readonly byDigest;
|
|
10
|
-
get(artifactDigest: string): Promise<PublishedPromptArtifact | undefined>;
|
|
32
|
+
get(artifactDigest: string, onRefused?: OnArtifactRefused): Promise<PublishedPromptArtifact | undefined>;
|
|
11
33
|
put(artifact: PublishedPromptArtifact): Promise<void>;
|
|
12
34
|
}
|
|
13
35
|
/** `artifacts/<hex>.json` under a caller-owned directory; atomic tmp+rename writes. */
|
|
@@ -15,7 +37,9 @@ export declare class FilePromptArtifactStore implements PromptArtifactStore {
|
|
|
15
37
|
private readonly dir;
|
|
16
38
|
constructor(dir: string);
|
|
17
39
|
private fileFor;
|
|
18
|
-
|
|
40
|
+
/** A file that is not there is a miss; one that is there and cannot be read (a directory in its place, a file the
|
|
41
|
+
* process may not open, too many open files) is told to `onRefused` as `unreadable`, by its error code. */
|
|
42
|
+
get(artifactDigest: string, onRefused?: OnArtifactRefused): Promise<PublishedPromptArtifact | undefined>;
|
|
19
43
|
put(artifact: PublishedPromptArtifact): Promise<void>;
|
|
20
44
|
}
|
|
21
45
|
export type PromptSourceState = {
|
|
@@ -47,8 +71,10 @@ export declare class FilePromptSourceStateStore implements PromptSourceStateStor
|
|
|
47
71
|
export interface PromptArtifactSource {
|
|
48
72
|
/** The current verified candidate new sessions (and every top-level session at a compaction) adopt; undefined = none. */
|
|
49
73
|
current(): PublishedPromptArtifact | undefined;
|
|
50
|
-
/** Resolve a PINNED digest (the resume path). Undefined = unavailable — the caller fails loud.
|
|
51
|
-
|
|
74
|
+
/** Resolve a PINNED digest (the resume path). Undefined = unavailable — the caller fails loud. `onRefused` is the
|
|
75
|
+
* store's (see {@link PromptArtifactStore.get}): told when a copy was there and could not be used, so the caller says
|
|
76
|
+
* why. */
|
|
77
|
+
get(artifactDigest: string, onRefused?: OnArtifactRefused): Promise<PromptArtifact | undefined>;
|
|
52
78
|
/** The tri-state every adoption decision keys on: `"active"` = a verified candidate is live; `"disabled"` = an
|
|
53
79
|
* EXPLICIT verified revocation (`applyDisabled`) — the one state that empties a pinned center layer;
|
|
54
80
|
* `"unavailable"` = no verified state (never configured, or a store miss at boot) — an outage never strips policy,
|
|
@@ -61,12 +87,16 @@ export interface PromptArtifactSource {
|
|
|
61
87
|
* in-memory swap. Any verification failure leaves EVERYTHING unchanged.
|
|
62
88
|
* - `applyDisabled(sourceRevision)` — an explicit, successful disable/delete response: persist disabled state +
|
|
63
89
|
* drop the candidate. (Network failure/304 = simply don't call anything.)
|
|
64
|
-
* - `restore()` — boot: re-resolve the persisted active state through the verified store; a miss
|
|
65
|
-
* boots stateless (no candidate) without touching the persisted record
|
|
90
|
+
* - `restore()` — boot: re-resolve the persisted active state through the verified store; a miss, an unreadable copy
|
|
91
|
+
* or a verify failure boots stateless (no candidate) without touching the persisted record, and says which on
|
|
92
|
+
* `onError` (a refused copy — a retired schema's reason names the republish rewrite — and an unreadable one are told
|
|
93
|
+
* apart from no copy at all).
|
|
66
94
|
*/
|
|
67
95
|
export declare class CenterPromptSource implements PromptArtifactSource {
|
|
68
96
|
private readonly store;
|
|
69
97
|
private readonly stateStore;
|
|
98
|
+
private readonly onError;
|
|
99
|
+
private readonly notifier;
|
|
70
100
|
private candidate;
|
|
71
101
|
private state;
|
|
72
102
|
/** Serialization tail for the three STATE-MUTATING entry points. Each is a multi-await sequence ending in a
|
|
@@ -78,12 +108,17 @@ export declare class CenterPromptSource implements PromptArtifactSource {
|
|
|
78
108
|
private tail;
|
|
79
109
|
/** Run `fn` after every previously-queued mutation settles (success OR failure — a failed apply must not wedge the queue). */
|
|
80
110
|
private exclusive;
|
|
111
|
+
/** `onError` is the operator channel of the source's own acts (a boot restore that finds its persisted artifact
|
|
112
|
+
* refused, unreadable or gone) — the Runner's sink, in its shape (`RunnerDeps.onError`): pass the Runner's. A boot
|
|
113
|
+
* restore belongs to no session: its context is `{ phase: "prompt-constitution", sessionId: "", classification:
|
|
114
|
+
* "center-source-restore" }`. Omitted = those acts are silent. */
|
|
81
115
|
constructor(opts: {
|
|
82
116
|
store: PromptArtifactStore;
|
|
83
117
|
stateStore?: PromptSourceStateStore;
|
|
118
|
+
onError?: RunnerDeps["onError"];
|
|
84
119
|
});
|
|
85
120
|
current(): PublishedPromptArtifact | undefined;
|
|
86
|
-
get(artifactDigest: string): Promise<PromptArtifact | undefined>;
|
|
121
|
+
get(artifactDigest: string, onRefused?: OnArtifactRefused): Promise<PromptArtifact | undefined>;
|
|
87
122
|
restore(): Promise<void>;
|
|
88
123
|
sourceState(): "active" | "disabled" | "unavailable";
|
|
89
124
|
applySnapshot(raw: unknown): Promise<{
|
|
@@ -1,22 +1,37 @@
|
|
|
1
1
|
import { mkdirSync, promises as fs } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { createSafeNotifier, observeThenableRejection } from "../core/safe-notify.js";
|
|
3
4
|
import { verifyPromptArtifact } from "./artifact.js";
|
|
4
|
-
function
|
|
5
|
+
export function refusalClause(refusal) {
|
|
6
|
+
return refusal.code === "unreadable" ? `unreadable (${refusal.reason})` : `refused by this engine (${refusal.code}: ${refusal.reason})`;
|
|
7
|
+
}
|
|
8
|
+
export function storedArtifactLine(artifactDigest, refusal, consequence) {
|
|
9
|
+
return `center prompt artifact ${artifactDigest.slice(0, 23)}… ${refusal !== undefined ? `is ${refusalClause(refusal)}` : "has no stored copy"} — ${consequence}`;
|
|
10
|
+
}
|
|
11
|
+
function tellRefused(onRefused, refusal) {
|
|
12
|
+
const notifier = createSafeNotifier();
|
|
13
|
+
notifier.notify(() => observeThenableRejection(onRefused?.(refusal), notifier, "artifact-store.onRefused"), "artifact-store.onRefused");
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
function verifiedRead(bytes, artifactDigest, onRefused) {
|
|
17
|
+
const refuse = (refusal) => tellRefused(onRefused, refusal);
|
|
5
18
|
let parsed;
|
|
6
19
|
try {
|
|
7
20
|
parsed = JSON.parse(bytes);
|
|
8
21
|
}
|
|
9
22
|
catch {
|
|
10
|
-
return
|
|
23
|
+
return refuse({ code: "shape", reason: "the stored bytes are not JSON" });
|
|
11
24
|
}
|
|
12
25
|
const v = verifyPromptArtifact(parsed);
|
|
13
|
-
|
|
26
|
+
if (!v.ok)
|
|
27
|
+
return refuse({ code: v.code, reason: v.reason });
|
|
28
|
+
return v.artifact.artifactDigest === artifactDigest ? v.artifact : refuse({ code: "digest", reason: "the stored artifact is not the one its digest names" });
|
|
14
29
|
}
|
|
15
30
|
export class MemoryPromptArtifactStore {
|
|
16
31
|
byDigest = new Map();
|
|
17
|
-
async get(artifactDigest) {
|
|
32
|
+
async get(artifactDigest, onRefused) {
|
|
18
33
|
const bytes = this.byDigest.get(artifactDigest);
|
|
19
|
-
return bytes === undefined ? undefined : verifiedRead(bytes, artifactDigest);
|
|
34
|
+
return bytes === undefined ? undefined : verifiedRead(bytes, artifactDigest, onRefused);
|
|
20
35
|
}
|
|
21
36
|
async put(artifact) {
|
|
22
37
|
this.byDigest.set(artifact.artifactDigest, JSON.stringify(artifact));
|
|
@@ -32,7 +47,7 @@ export class FilePromptArtifactStore {
|
|
|
32
47
|
const m = /^sha256:([0-9a-f]{64})$/.exec(artifactDigest);
|
|
33
48
|
return m ? path.join(this.dir, "artifacts", `${m[1]}.json`) : undefined;
|
|
34
49
|
}
|
|
35
|
-
async get(artifactDigest) {
|
|
50
|
+
async get(artifactDigest, onRefused) {
|
|
36
51
|
const file = this.fileFor(artifactDigest);
|
|
37
52
|
if (file === undefined)
|
|
38
53
|
return undefined;
|
|
@@ -40,10 +55,13 @@ export class FilePromptArtifactStore {
|
|
|
40
55
|
try {
|
|
41
56
|
bytes = await fs.readFile(file, "utf8");
|
|
42
57
|
}
|
|
43
|
-
catch {
|
|
44
|
-
|
|
58
|
+
catch (err) {
|
|
59
|
+
const code = typeof err === "object" && err !== null ? err.code : undefined;
|
|
60
|
+
if (code === "ENOENT")
|
|
61
|
+
return undefined;
|
|
62
|
+
return tellRefused(onRefused, { code: "unreadable", reason: `the store could not read its file: ${typeof code === "string" ? code : "an error with no code"}` });
|
|
45
63
|
}
|
|
46
|
-
return verifiedRead(bytes, artifactDigest);
|
|
64
|
+
return verifiedRead(bytes, artifactDigest, onRefused);
|
|
47
65
|
}
|
|
48
66
|
async put(artifact) {
|
|
49
67
|
const file = this.fileFor(artifact.artifactDigest);
|
|
@@ -99,6 +117,8 @@ export class FilePromptSourceStateStore {
|
|
|
99
117
|
export class CenterPromptSource {
|
|
100
118
|
store;
|
|
101
119
|
stateStore;
|
|
120
|
+
onError;
|
|
121
|
+
notifier = createSafeNotifier();
|
|
102
122
|
candidate;
|
|
103
123
|
state = "unavailable";
|
|
104
124
|
tail = Promise.resolve();
|
|
@@ -110,14 +130,15 @@ export class CenterPromptSource {
|
|
|
110
130
|
constructor(opts) {
|
|
111
131
|
this.store = opts.store;
|
|
112
132
|
this.stateStore = opts.stateStore ?? new MemoryPromptSourceStateStore();
|
|
133
|
+
this.onError = opts.onError;
|
|
113
134
|
}
|
|
114
135
|
current() {
|
|
115
136
|
return this.candidate;
|
|
116
137
|
}
|
|
117
|
-
async get(artifactDigest) {
|
|
138
|
+
async get(artifactDigest, onRefused) {
|
|
118
139
|
if (this.candidate?.artifactDigest === artifactDigest)
|
|
119
140
|
return this.candidate;
|
|
120
|
-
return this.store.get(artifactDigest);
|
|
141
|
+
return this.store.get(artifactDigest, onRefused);
|
|
121
142
|
}
|
|
122
143
|
async restore() {
|
|
123
144
|
return this.exclusive(async () => {
|
|
@@ -132,9 +153,14 @@ export class CenterPromptSource {
|
|
|
132
153
|
this.state = "unavailable";
|
|
133
154
|
return;
|
|
134
155
|
}
|
|
135
|
-
const
|
|
156
|
+
const refused = {};
|
|
157
|
+
const stored = await this.store.get(state.artifactDigest, (r) => void (refused.current = r));
|
|
136
158
|
this.candidate = stored !== undefined ? { ...stored, sourceRevision: state.sourceRevision } : undefined;
|
|
137
159
|
this.state = stored !== undefined ? "active" : "unavailable";
|
|
160
|
+
if (stored === undefined) {
|
|
161
|
+
const line = new Error(storedArtifactLine(state.artifactDigest, refused.current, "the source boots unavailable: a new session has no center layer until a verified artifact is applied"));
|
|
162
|
+
this.notifier.notify(() => observeThenableRejection(this.onError?.(line, { phase: "prompt-constitution", sessionId: "", classification: "center-source-restore" }), this.notifier, "center-source.onError"), "center-source.onError");
|
|
163
|
+
}
|
|
138
164
|
});
|
|
139
165
|
}
|
|
140
166
|
sourceState() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type OverlayOp, type PromptTrait } from "./catalog/schema.js";
|
|
2
2
|
import { type PromptOverlay, type SourcedOverlay } from "./overlay.js";
|
|
3
3
|
/** What an artifact needs from the engine that composes it: the targets it names (each with what kind of target it
|
|
4
|
-
* is), the operations it uses, the traits its `when` conditions read, and the bindings
|
|
4
|
+
* is), the operations it uses, the traits its `when` conditions read, and the bindings they name. */
|
|
5
5
|
export interface PromptArtifactRequires {
|
|
6
6
|
readonly targets: readonly {
|
|
7
7
|
readonly id: string;
|
|
@@ -18,9 +18,9 @@ export interface PromptArtifactEvidence {
|
|
|
18
18
|
}
|
|
19
19
|
/** The digested part of an artifact. */
|
|
20
20
|
export interface PromptArtifactPayload {
|
|
21
|
-
readonly schemaVersion:
|
|
21
|
+
readonly schemaVersion: 3;
|
|
22
22
|
readonly requires: PromptArtifactRequires;
|
|
23
|
-
/** Every overlay is of the `center` class; `
|
|
23
|
+
/** Every overlay is of the `center` class; one with no `when.binding` applies under every binding. */
|
|
24
24
|
readonly overlays: readonly PromptOverlay[];
|
|
25
25
|
readonly evidence: PromptArtifactEvidence;
|
|
26
26
|
}
|
|
@@ -33,7 +33,8 @@ export interface PromptArtifact {
|
|
|
33
33
|
export interface PublishedPromptArtifact extends PromptArtifact {
|
|
34
34
|
readonly sourceRevision: string;
|
|
35
35
|
}
|
|
36
|
-
/** Validator bounds: they bound abuse and runaway publishes, not legitimate artifacts.
|
|
36
|
+
/** Validator bounds: they bound abuse and runaway publishes, not legitimate artifacts. A `…Chars` bound counts Unicode
|
|
37
|
+
* code points (`codePointsOver`, the verifier's one character unit); a `…Bytes` bound counts UTF-8 bytes. */
|
|
37
38
|
export declare const ARTIFACT_LIMITS: Readonly<{
|
|
38
39
|
maxOverlays: 64;
|
|
39
40
|
maxOverlayTextBytes: 32000;
|
|
@@ -85,17 +86,17 @@ export type CenterAdoption = {
|
|
|
85
86
|
artifact: PromptArtifact;
|
|
86
87
|
sourceRevision?: string;
|
|
87
88
|
};
|
|
88
|
-
/**
|
|
89
|
-
*
|
|
90
|
-
|
|
91
|
-
*/
|
|
92
|
-
export declare function centerOverlaysOf(adoption: CenterAdoption | undefined, binding: string | undefined): readonly SourcedOverlay[];
|
|
89
|
+
/** The center class's overlays for an adopted artifact, in the artifact's order. Which of them apply to a run is their
|
|
90
|
+
* `when` (the binding included), read where every class's is — at the composition. */
|
|
91
|
+
export declare function centerOverlaysOf(adoption: CenterAdoption | undefined): readonly SourcedOverlay[];
|
|
93
92
|
/** An artifact a source handed a run, re-checked by this engine before the run adopts it; undefined when it fails. */
|
|
94
93
|
export declare function adoptCenter(artifact: PromptArtifact, sourceRevision: string | undefined): CenterAdoption | undefined;
|
|
95
94
|
/**
|
|
96
95
|
* Build a published artifact from overlays and evidence — the one builder (a center's publish pipeline calls it):
|
|
97
|
-
* `requires` is derived, the digest computed over the payload's JSON form (what travels)
|
|
98
|
-
*
|
|
96
|
+
* `requires` is derived, the digest computed over the payload's JSON form (what travels) with each overlay as the
|
|
97
|
+
* overlay door leaves it (its `when` in normal form, so one meaning is one digest), and the result goes through the
|
|
98
|
+
* verifier, so the caller holds either a valid artifact or the reason it is not one. An overlay the door refuses goes on
|
|
99
|
+
* as it was given: the verifier names it, in its own order of checks.
|
|
99
100
|
*/
|
|
100
101
|
export declare function buildPromptArtifact(opts: {
|
|
101
102
|
overlays: readonly PromptOverlay[];
|
|
@@ -3,7 +3,7 @@ import { isBandId } from "./bands.js";
|
|
|
3
3
|
import { SEMA_DEFAULT_CATALOG } from "./catalog/index.js";
|
|
4
4
|
import { OVERLAY_OPS, PROMPT_TRAITS, isWordOf } from "./catalog/schema.js";
|
|
5
5
|
import { canonical } from "./epoch.js";
|
|
6
|
-
import { sectionOfMessage, validateOverlay } from "./overlay.js";
|
|
6
|
+
import { codePointsOver, sectionOfMessage, validateOverlay } from "./overlay.js";
|
|
7
7
|
export const ARTIFACT_LIMITS = Object.freeze({
|
|
8
8
|
maxOverlays: 64,
|
|
9
9
|
maxOverlayTextBytes: 32_000,
|
|
@@ -37,8 +37,8 @@ export function requiresOf(overlays) {
|
|
|
37
37
|
need(o.message, "message");
|
|
38
38
|
for (const t of [...(o.when?.traits?.allOf ?? []), ...(o.when?.traits?.noneOf ?? [])])
|
|
39
39
|
traits.add(t);
|
|
40
|
-
|
|
41
|
-
bindings.add(
|
|
40
|
+
for (const b of [...(o.when?.binding?.anyOf ?? []), ...(o.when?.binding?.noneOf ?? [])])
|
|
41
|
+
bindings.add(b);
|
|
42
42
|
}
|
|
43
43
|
const byText = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
|
|
44
44
|
return {
|
|
@@ -77,24 +77,49 @@ function requiresShaped(v) {
|
|
|
77
77
|
strings(v.traits) &&
|
|
78
78
|
strings(v.bindings));
|
|
79
79
|
}
|
|
80
|
+
const bindingListOf = (b) => {
|
|
81
|
+
if (b === undefined)
|
|
82
|
+
return undefined;
|
|
83
|
+
const names = b.anyOf !== undefined ? b.anyOf : b.noneOf;
|
|
84
|
+
return { anyOf: b.anyOf !== undefined, names, set: new Set(names) };
|
|
85
|
+
};
|
|
86
|
+
function bindingsMeet(a, b) {
|
|
87
|
+
if (a === undefined || b === undefined)
|
|
88
|
+
return true;
|
|
89
|
+
if (a.anyOf && b.anyOf)
|
|
90
|
+
return a.names.some((x) => b.set.has(x));
|
|
91
|
+
if (a.anyOf)
|
|
92
|
+
return a.names.some((x) => !b.set.has(x));
|
|
93
|
+
if (b.anyOf)
|
|
94
|
+
return b.names.some((x) => !a.set.has(x));
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
80
97
|
function replaceConflict(overlays) {
|
|
81
|
-
const
|
|
98
|
+
const groups = new Map();
|
|
82
99
|
for (const o of overlays) {
|
|
83
100
|
if (o.op !== "replace")
|
|
84
101
|
continue;
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
102
|
+
const { binding, ...rest } = o.when ?? {};
|
|
103
|
+
const key = canonical({ target: o.target, when: rest });
|
|
104
|
+
groups.set(key, [...(groups.get(key) ?? []), { o, list: bindingListOf(binding) }]);
|
|
105
|
+
}
|
|
106
|
+
for (const group of groups.values()) {
|
|
107
|
+
for (let i = 0; i < group.length; i++) {
|
|
108
|
+
for (let j = i + 1; j < group.length; j++) {
|
|
109
|
+
const [{ o: p, list: pl }, { o: q, list: ql }] = [group[i], group[j]];
|
|
110
|
+
if (bindingsMeet(pl, ql)) {
|
|
111
|
+
return `overlays "${p.id}" and "${q.id}" both replace "${p.target}" under one condition that can hold in the same run (write exclusive binding conditions: "noneOf": [x] beside "anyOf": [x])`;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
90
115
|
}
|
|
91
116
|
return undefined;
|
|
92
117
|
}
|
|
93
118
|
export function verifyPromptArtifact(raw) {
|
|
94
119
|
if (!isRecord(raw))
|
|
95
120
|
return { ok: false, code: "shape", reason: "the published artifact is not an object" };
|
|
96
|
-
if (typeof raw.sourceRevision !== "string" || raw.sourceRevision.length === 0 || raw.sourceRevision
|
|
97
|
-
return { ok: false, code: "shape", reason:
|
|
121
|
+
if (typeof raw.sourceRevision !== "string" || raw.sourceRevision.length === 0 || codePointsOver(raw.sourceRevision, ARTIFACT_LIMITS.maxSourceRevisionChars)) {
|
|
122
|
+
return { ok: false, code: "shape", reason: `sourceRevision missing or over ${ARTIFACT_LIMITS.maxSourceRevisionChars} characters (code points)` };
|
|
98
123
|
}
|
|
99
124
|
const v = verifyPromptArtifactBody(raw);
|
|
100
125
|
return v.ok ? { ok: true, artifact: { ...v.artifact, sourceRevision: raw.sourceRevision } } : v;
|
|
@@ -111,8 +136,10 @@ export function verifyPromptArtifactBody(raw) {
|
|
|
111
136
|
const payload = raw.payload;
|
|
112
137
|
if (!isRecord(payload))
|
|
113
138
|
return fail("shape", "payload is not an object");
|
|
114
|
-
if (payload.schemaVersion !==
|
|
115
|
-
|
|
139
|
+
if (payload.schemaVersion !== 3) {
|
|
140
|
+
const republish = payload.schemaVersion === 2 ? `; republish under schemaVersion 3 — an overlay's "scope": { "binding": b } becomes "when": { "binding": { "anyOf": [b] } }` : "";
|
|
141
|
+
return fail("schema", `unsupported schemaVersion ${JSON.stringify(payload.schemaVersion)?.slice(0, 40)} (this engine reads schemaVersion 3 only${republish})`);
|
|
142
|
+
}
|
|
116
143
|
for (const k of Object.keys(payload))
|
|
117
144
|
if (k !== "schemaVersion" && k !== "requires" && k !== "overlays" && k !== "evidence")
|
|
118
145
|
return fail("shape", `payload carries ${JSON.stringify(k).slice(0, 60)}`);
|
|
@@ -151,11 +178,11 @@ export function verifyPromptArtifactBody(raw) {
|
|
|
151
178
|
if (conflict !== undefined)
|
|
152
179
|
return fail("overlay", conflict);
|
|
153
180
|
const evidence = payload.evidence;
|
|
154
|
-
if (!isRecord(evidence) || typeof evidence.intent !== "string" || evidence.intent.trim() === "" || evidence.intent
|
|
155
|
-
return fail("evidence", `evidence.intent is a non-blank string of at most ${ARTIFACT_LIMITS.maxIntentChars} characters`);
|
|
181
|
+
if (!isRecord(evidence) || typeof evidence.intent !== "string" || evidence.intent.trim() === "" || codePointsOver(evidence.intent, ARTIFACT_LIMITS.maxIntentChars)) {
|
|
182
|
+
return fail("evidence", `evidence.intent is a non-blank string of at most ${ARTIFACT_LIMITS.maxIntentChars} characters (code points)`);
|
|
156
183
|
}
|
|
157
|
-
if (!Array.isArray(evidence.refs) || evidence.refs.length > ARTIFACT_LIMITS.maxRefs || evidence.refs.some((r) => typeof r !== "string" || r.trim() === "" || r
|
|
158
|
-
return fail("evidence", `evidence.refs is a list of at most ${ARTIFACT_LIMITS.maxRefs} non-blank references`);
|
|
184
|
+
if (!Array.isArray(evidence.refs) || evidence.refs.length > ARTIFACT_LIMITS.maxRefs || evidence.refs.some((r) => typeof r !== "string" || r.trim() === "" || codePointsOver(r, ARTIFACT_LIMITS.maxRefChars))) {
|
|
185
|
+
return fail("evidence", `evidence.refs is a list of at most ${ARTIFACT_LIMITS.maxRefs} non-blank references of at most ${ARTIFACT_LIMITS.maxRefChars} characters (code points) each`);
|
|
159
186
|
}
|
|
160
187
|
for (const k of Object.keys(evidence))
|
|
161
188
|
if (k !== "intent" && k !== "refs")
|
|
@@ -165,7 +192,7 @@ export function verifyPromptArtifactBody(raw) {
|
|
|
165
192
|
return fail("evidence", `overlay "${behaviorReplace.id}" replaces core-behavior text; evidence.refs names at least one evaluation or golden`);
|
|
166
193
|
}
|
|
167
194
|
const normalized = {
|
|
168
|
-
schemaVersion:
|
|
195
|
+
schemaVersion: 3,
|
|
169
196
|
requires: requiresOf(overlays),
|
|
170
197
|
overlays,
|
|
171
198
|
evidence: { intent: evidence.intent, refs: [...evidence.refs] },
|
|
@@ -175,16 +202,20 @@ export function verifyPromptArtifactBody(raw) {
|
|
|
175
202
|
return { ok: true, artifact: { payload: normalized, artifactDigest: raw.artifactDigest } };
|
|
176
203
|
}
|
|
177
204
|
const CENTER_ORIGIN = Object.freeze({ source: "center", by: "center" });
|
|
178
|
-
export function centerOverlaysOf(adoption
|
|
205
|
+
export function centerOverlaysOf(adoption) {
|
|
179
206
|
if (adoption === undefined)
|
|
180
207
|
return [];
|
|
181
|
-
return adoption.artifact.payload.overlays.
|
|
208
|
+
return adoption.artifact.payload.overlays.map((overlay) => ({ overlay, origin: CENTER_ORIGIN }));
|
|
182
209
|
}
|
|
183
210
|
export function adoptCenter(artifact, sourceRevision) {
|
|
184
211
|
const v = verifyPromptArtifactBody(artifact);
|
|
185
212
|
return v.ok ? { artifact: v.artifact, ...(sourceRevision !== undefined ? { sourceRevision } : {}) } : undefined;
|
|
186
213
|
}
|
|
187
214
|
export function buildPromptArtifact(opts) {
|
|
188
|
-
const
|
|
215
|
+
const overlays = opts.overlays.map((o) => {
|
|
216
|
+
const v = validateOverlay(o, { source: "center" });
|
|
217
|
+
return "overlay" in v ? v.overlay : o;
|
|
218
|
+
});
|
|
219
|
+
const payload = JSON.parse(JSON.stringify({ schemaVersion: 3, requires: requiresOf(overlays), overlays, evidence: opts.evidence }));
|
|
189
220
|
return verifyPromptArtifact({ payload, artifactDigest: sha256Hex(canonical(payload)), sourceRevision: opts.sourceRevision });
|
|
190
221
|
}
|
|
@@ -24,6 +24,8 @@ export interface AssembleInputs {
|
|
|
24
24
|
role?: HostRole;
|
|
25
25
|
form?: HostForm;
|
|
26
26
|
};
|
|
27
|
+
/** The run's binding (`TaskSpec.promptBinding`), read by every overlay's `when.binding`. */
|
|
28
|
+
binding?: string;
|
|
27
29
|
tools: readonly AgentTool[];
|
|
28
30
|
facts: PromptRuntimeFacts;
|
|
29
31
|
/** The task's working directory (the Cowork role base's `{{workspaceFolder}}`). */
|
|
@@ -3,7 +3,7 @@ import { composeCatalog, layoutSystemBlocks } from "./composer.js";
|
|
|
3
3
|
import { ABSENT_THIS_RUN } from "./overlay.js";
|
|
4
4
|
function supersededLine(s) {
|
|
5
5
|
return s.supersededBy === ABSENT_THIS_RUN
|
|
6
|
-
? `prompt overlay "${s.id}" (${s.source}, ${s.by}) on "${s.target}" changed nothing: the selector
|
|
6
|
+
? `prompt overlay "${s.id}" (${s.source}, ${s.by}) on "${s.target}" changed nothing: what it names is not in this run (the selector chose no variant of its target, or of the catalog message it takes its text from; or the lower entry it drops was never added — its own condition left it out, or the layer that added it is not in force)`
|
|
7
7
|
: `prompt overlay "${s.id}" (${s.source}, ${s.by}) on "${s.target}" is superseded by "${s.supersededBy}", applied after it (source order task < center < deploy; within a source, declaration order)`;
|
|
8
8
|
}
|
|
9
9
|
export function assemblePrompt(inputs) {
|
|
@@ -17,6 +17,7 @@ export function assemblePrompt(inputs) {
|
|
|
17
17
|
const plan = {
|
|
18
18
|
catalog: SEMA_DEFAULT_CATALOG,
|
|
19
19
|
...(inputs.host !== undefined ? { host: inputs.host } : {}),
|
|
20
|
+
...(inputs.binding !== undefined ? { binding: inputs.binding } : {}),
|
|
20
21
|
overlays: [...inputs.taskOverlays, ...inputs.centerOverlays, ...inputs.deployOverlays],
|
|
21
22
|
};
|
|
22
23
|
const toolNames = inputs.tools.map((t) => t.name);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CONSTITUTION_MESSAGES } from "./constitution.js";
|
|
2
2
|
import { CORE_BEHAVIOR_MESSAGES } from "./core-behavior.js";
|
|
3
|
+
import { MEMORY_MESSAGES } from "./memory.js";
|
|
3
4
|
import { MODE_MESSAGES } from "./modes.js";
|
|
4
5
|
import { ROLE_MESSAGES } from "./role.js";
|
|
5
6
|
import { SECTIONS } from "./sections.js";
|
|
@@ -9,7 +10,7 @@ import { RENDERER_IDS, isWordOf } from "./schema.js";
|
|
|
9
10
|
export const SEMA_DEFAULT_CATALOG = {
|
|
10
11
|
id: "sema-default@2",
|
|
11
12
|
bands: BANDS,
|
|
12
|
-
messages: [...ROLE_MESSAGES, ...CONSTITUTION_MESSAGES, ...CORE_BEHAVIOR_MESSAGES, ...MODE_MESSAGES, ...TEAM_MESSAGES],
|
|
13
|
+
messages: [...ROLE_MESSAGES, ...CONSTITUTION_MESSAGES, ...CORE_BEHAVIOR_MESSAGES, ...MODE_MESSAGES, ...TEAM_MESSAGES, ...MEMORY_MESSAGES],
|
|
13
14
|
sections: SECTIONS,
|
|
14
15
|
};
|
|
15
16
|
export function validateCatalog(catalog) {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catalog messages of the `memory` band. No section places them: the band's bytes are the memory renderer's
|
|
3
|
+
* input, which the memory phase composes (prepare-memory.ts `composeInjection`); these are the texts it reads.
|
|
4
|
+
*
|
|
5
|
+
* - `core/memory.no-persistent-store`: the run has no memory store configured and no channel to persist through
|
|
6
|
+
* (the roster-wide persistence verdict is false). Without it the model, asked "remember X", answers with a
|
|
7
|
+
* receipt for a save that has nowhere to land. A store that is configured but did not mount this run does not
|
|
8
|
+
* get this sentence (it is categorical, and a mount can succeed next time): it gets the engine's
|
|
9
|
+
* writes-unavailable-right-now notice, with the failed mount as its cause. Name-free: it names no tool, so no
|
|
10
|
+
* toolkit can make it stale.
|
|
11
|
+
*/
|
|
12
|
+
import type { CatalogMessage } from "./schema.js";
|
|
13
|
+
export declare const MEMORY_MESSAGES: readonly CatalogMessage[];
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
const NO_PERSISTENT_STORE = `# Memory
|
|
2
|
+
|
|
3
|
+
You have no persistent memory store: what is said in this conversation is not automatically retained for future sessions. If the user asks you to remember something for later, say plainly that you cannot store it — do not claim to have noted or saved it. If you have file tools, you may offer to write it into a project file instead (files persist; conversation memory does not).`;
|
|
4
|
+
export const MEMORY_MESSAGES = [
|
|
5
|
+
{ id: "core/memory.no-persistent-store", variants: [{ id: "default", when: {}, text: NO_PERSISTENT_STORE }], attribution: { form: "sema-owned" } },
|
|
6
|
+
];
|
|
@@ -33,6 +33,9 @@ export interface BandRow {
|
|
|
33
33
|
* task (`TaskSpec.promptRole`); absent ⇒ `general`. */
|
|
34
34
|
export declare const HOST_ROLES: readonly ["general", "code", "coordinator", "cowork"];
|
|
35
35
|
export type HostRole = (typeof HOST_ROLES)[number];
|
|
36
|
+
/** Membership test for {@link HostRole} — the one reading of "is this a role base the engine selects": the task door
|
|
37
|
+
* (`TaskSpec.promptRole`) and the overlay grammar (`when.host.role`) both ask it. */
|
|
38
|
+
export declare function isHostRole(v: unknown): v is HostRole;
|
|
36
39
|
/** The host form: `minimal` leaves the core-behavior band out (the locked bands stay). Written only by
|
|
37
40
|
* `TaskSpec.promptForm`; absent ⇒ `standard`. */
|
|
38
41
|
export declare const HOST_FORMS: readonly ["standard", "minimal"];
|
|
@@ -69,15 +72,29 @@ export interface Attribution {
|
|
|
69
72
|
export interface Variant {
|
|
70
73
|
/** Reported in the manifest — one of the answers to "why this sentence". */
|
|
71
74
|
readonly id: string;
|
|
72
|
-
readonly when:
|
|
75
|
+
readonly when: CatalogVariantWhen;
|
|
73
76
|
readonly text: string;
|
|
74
77
|
}
|
|
75
|
-
/**
|
|
78
|
+
/** A condition on the run's binding (`TaskSpec.promptBinding`, a deployment's scenario name): exactly one list. A run
|
|
79
|
+
* with no binding is outside every `anyOf` and inside every `noneOf`. */
|
|
80
|
+
export type BindingCondition = {
|
|
81
|
+
readonly anyOf: readonly string[];
|
|
82
|
+
readonly noneOf?: never;
|
|
83
|
+
} | {
|
|
84
|
+
readonly noneOf: readonly string[];
|
|
85
|
+
readonly anyOf?: never;
|
|
86
|
+
};
|
|
87
|
+
/** The selector condition a variant (or an overlay) is chosen on: a conjunction over traits, host, facts and binding. */
|
|
76
88
|
export interface VariantWhen {
|
|
77
89
|
readonly traits?: TraitCondition;
|
|
78
90
|
readonly host?: HostCondition;
|
|
79
91
|
readonly facts?: FactConjunction;
|
|
92
|
+
readonly binding?: BindingCondition;
|
|
80
93
|
}
|
|
94
|
+
/** The condition a BUNDLED catalog variant is chosen on: a {@link VariantWhen} without the binding. A binding is a
|
|
95
|
+
* deployment's own vocabulary (scenario names the engine cannot know), so no catalog variant can name one — the type
|
|
96
|
+
* refuses it where the catalog data is written. */
|
|
97
|
+
export type CatalogVariantWhen = Omit<VariantWhen, "binding">;
|
|
81
98
|
export interface CatalogMessage {
|
|
82
99
|
/** `core/<area>.<name>`. */
|
|
83
100
|
readonly id: string;
|
|
@@ -3,6 +3,9 @@ export function isWordOf(words, v) {
|
|
|
3
3
|
}
|
|
4
4
|
export const OVERLAY_OPS = Object.freeze(["replace", "append", "add", "drop"]);
|
|
5
5
|
export const HOST_ROLES = Object.freeze(["general", "code", "coordinator", "cowork"]);
|
|
6
|
+
export function isHostRole(v) {
|
|
7
|
+
return isWordOf(HOST_ROLES, v);
|
|
8
|
+
}
|
|
6
9
|
export const HOST_FORMS = Object.freeze(["standard", "minimal"]);
|
|
7
10
|
export const PROMPT_TRAITS = Object.freeze(["lean_prompt", "fable_5_mitigations"]);
|
|
8
11
|
export const PROMPT_FACT_NAMES = Object.freeze([
|
|
@@ -9,6 +9,8 @@ export interface CompositionPlan {
|
|
|
9
9
|
readonly role?: HostRole;
|
|
10
10
|
readonly form?: HostForm;
|
|
11
11
|
};
|
|
12
|
+
/** The run's binding (`TaskSpec.promptBinding`; absent ⇒ none) — what every overlay's `when.binding` reads. */
|
|
13
|
+
readonly binding?: string;
|
|
12
14
|
/** Validated overlays, already in application order (`bundled < task < center < deploy`, then declaration order). */
|
|
13
15
|
readonly overlays?: readonly SourcedOverlay[];
|
|
14
16
|
}
|
|
@@ -91,7 +91,7 @@ function renderAdded(e, fold) {
|
|
|
91
91
|
};
|
|
92
92
|
}
|
|
93
93
|
export function composeCatalog(plan, inputs) {
|
|
94
|
-
const s = selectorsOf(inputs.facts, plan.host);
|
|
94
|
+
const s = selectorsOf(inputs.facts, plan.host, plan.binding);
|
|
95
95
|
const bases = basesOf(plan.catalog, inputs, s);
|
|
96
96
|
const selectedText = selectedTextOf(plan.catalog, bases);
|
|
97
97
|
const overlayText = (o) => {
|
|
@@ -10,11 +10,8 @@ export interface PromptOverlay {
|
|
|
10
10
|
readonly text?: string;
|
|
11
11
|
/** A catalog message whose selected variant is the overlay's text; exclusive with `text`. */
|
|
12
12
|
readonly message?: string;
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
readonly binding?: string;
|
|
16
|
-
};
|
|
17
|
-
/** The overlay applies to this run only when this holds (the variant selector's own closed vocabulary). */
|
|
13
|
+
/** The overlay applies to this run only when this holds (the variant selector's own vocabulary, the binding
|
|
14
|
+
* included) — the one applicability condition of every source class. */
|
|
18
15
|
readonly when?: VariantWhen;
|
|
19
16
|
}
|
|
20
17
|
/** The source classes in application order (later wins). `bundled` is the catalog itself and writes no overlay. */
|
|
@@ -59,10 +56,23 @@ export declare function receivePromptData(raw: unknown): {
|
|
|
59
56
|
} | {
|
|
60
57
|
readonly notData: string;
|
|
61
58
|
};
|
|
59
|
+
/** The longest binding a task may name (`TaskSpec.promptBinding`), counted in Unicode code points (`[...s].length`) — not
|
|
60
|
+
* in UTF-16 code units; every binding a `when.binding` list names is held to the same bound. Exported so a host screens
|
|
61
|
+
* with the engine's number and the engine's unit. Code points are the one unit of every character bound of the prompt
|
|
62
|
+
* artifact verifier ({@link codePointsOver}: a binding, an overlay id, `sourceRevision`, `evidence.intent`, a
|
|
63
|
+
* reference), so a character outside the BMP (an emoji, a rare CJK ideograph) counts one, not two; the overlay text
|
|
64
|
+
* budgets are UTF-8 bytes and are named so. */
|
|
65
|
+
export declare const PROMPT_BINDING_MAX_CHARS = 128;
|
|
66
|
+
/** The most bindings one `when.binding` list names — it bounds what a publisher can make the conflict check walk. */
|
|
67
|
+
export declare const PROMPT_BINDING_LIST_MAX = 64;
|
|
68
|
+
/** Whether `s` holds more than `max` Unicode code points — the one length unit of the prompt artifact verifier's
|
|
69
|
+
* character bounds. A string of at most `max` code units fits (a code point is one or two of them); one of more than
|
|
70
|
+
* twice `max` does not; only a string in between is counted — counted, never copied whole. */
|
|
71
|
+
export declare function codePointsOver(s: string, max: number): boolean;
|
|
62
72
|
/**
|
|
63
|
-
* The run's
|
|
64
|
-
* Its one writer is the task (a deployment names its scenario); absent ⇒ undefined. A value outside the
|
|
65
|
-
* refused by name (`config.prompt_selector_invalid`), never read as absent.
|
|
73
|
+
* The run's binding (`TaskSpec.promptBinding`): the scenario a `when.binding` condition reads, on an overlay of any
|
|
74
|
+
* source class. Its one writer is the task (a deployment names its scenario); absent ⇒ undefined. A value outside the
|
|
75
|
+
* grammar is refused by name (`config.prompt_selector_invalid`), never read as absent.
|
|
66
76
|
*/
|
|
67
77
|
export declare function resolvePromptBinding(task: {
|
|
68
78
|
readonly promptBinding?: unknown;
|
|
@@ -79,9 +89,9 @@ export interface OverlayValidationContext {
|
|
|
79
89
|
readonly lowerAdds?: ReadonlyMap<string, BandId>;
|
|
80
90
|
}
|
|
81
91
|
/**
|
|
82
|
-
* Validate one overlay for one source class. Returns the overlay (a frozen copy of its known members
|
|
83
|
-
* a violation: shape, namespace, op, text/message, `when`,
|
|
84
|
-
*
|
|
92
|
+
* Validate one overlay for one source class. Returns the overlay (a frozen copy of its known members, its `when` in
|
|
93
|
+
* normal form — {@link canonicalWhen}) or why it is a violation: shape, namespace, op, text/message, `when`, target existence, band authorization (and the band's mods
|
|
94
|
+
* write port), and the locked-text guard.
|
|
85
95
|
*/
|
|
86
96
|
export declare function validateOverlay(raw: unknown, ctx: OverlayValidationContext): {
|
|
87
97
|
readonly overlay: PromptOverlay;
|