@sema-agent/core 7.52.0 → 7.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +194 -0
- 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 -5
- package/dist/agents/peer-session-drain.js +271 -180
- package/dist/agents/read-inbox-tool.d.ts +7 -0
- package/dist/agents/read-inbox-tool.js +5 -1
- package/dist/agents/subagent.d.ts +3 -0
- package/dist/agents/subagent.js +99 -72
- package/dist/agents/tool-filter.d.ts +18 -0
- package/dist/agents/tool-filter.js +6 -0
- 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 +30 -13
- package/dist/core/allow-entry.d.ts +2 -1
- package/dist/core/allow-entry.js +2 -2
- package/dist/core/auto-compaction.d.ts +57 -0
- package/dist/core/auto-compaction.js +28 -2
- package/dist/core/checkpoint-store.d.ts +29 -20
- package/dist/core/checkpoint-store.js +3 -3
- package/dist/core/compliance.js +3 -1
- package/dist/core/effective-path-target.d.ts +25 -6
- package/dist/core/effective-path-target.js +24 -2
- package/dist/core/engine-notice.d.ts +13 -2
- package/dist/core/gate-fold.js +3 -2
- package/dist/core/gate-lanes.js +11 -13
- package/dist/core/gate-outcome.d.ts +11 -6
- package/dist/core/governance-codes.d.ts +3 -1
- package/dist/core/governance-codes.js +3 -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 +7 -5
- package/dist/core/hooks.js +5 -3
- package/dist/core/locked-config.d.ts +84 -32
- package/dist/core/locked-config.js +128 -42
- package/dist/core/mcp-probe.js +1 -1
- package/dist/core/mcp-server-spec.d.ts +88 -10
- package/dist/core/mcp-server-spec.js +183 -33
- package/dist/core/mcp.d.ts +21 -14
- package/dist/core/mcp.js +55 -51
- package/dist/core/memory-engine/engine.d.ts +14 -19
- package/dist/core/memory-engine/engine.js +7 -5
- package/dist/core/mode-policy.d.ts +3 -18
- package/dist/core/mode-policy.js +2 -16
- 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 +39 -10
- package/dist/core/mods/kernel/receive.js +119 -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 +2 -2
- package/dist/core/permission-rule-model.d.ts +58 -9
- package/dist/core/permission-rule-model.js +81 -7
- package/dist/core/permission-rule-org.d.ts +163 -33
- package/dist/core/permission-rule-org.js +205 -71
- package/dist/core/permission-rules.d.ts +7 -1
- package/dist/core/permission-rules.js +37 -8
- 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/contracts.d.ts +1 -0
- package/dist/core/runner/gate-exit.js +4 -3
- 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 +3 -1
- package/dist/core/runner/person-path-rows.js +2 -2
- package/dist/core/runner/prepare-config-doors.d.ts +48 -2
- package/dist/core/runner/prepare-config-doors.js +161 -145
- package/dist/core/runner/prepare-defer-classify.js +4 -7
- package/dist/core/runner/prepare-delegation-surface.d.ts +2 -2
- package/dist/core/runner/prepare-delegation-surface.js +7 -5
- package/dist/core/runner/prepare-hands-readface.d.ts +1 -1
- package/dist/core/runner/prepare-hands-readface.js +2 -1
- package/dist/core/runner/prepare-inherited-gate.js +2 -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-policy-chain.d.ts +1 -1
- package/dist/core/runner/prepare-policy-chain.js +12 -12
- 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-task.js +10 -10
- package/dist/core/runner/prepare-wiring-manifest.d.ts +8 -3
- package/dist/core/runner/prepare-wiring-manifest.js +8 -5
- package/dist/core/runner/resume-admission.d.ts +4 -1
- package/dist/core/runner/resume-admission.js +7 -5
- 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/retired-runner-deps.d.ts +5 -6
- package/dist/core/runner/retired-runner-deps.js +1 -4
- package/dist/core/runner/run-leg.js +42 -12
- package/dist/core/runner/run-recovery-lanes.js +5 -3
- package/dist/core/runner/run-terminal-adoption.js +6 -5
- package/dist/core/runner/run-turn-boundary.js +9 -3
- package/dist/core/runner/runtask.js +1 -1
- package/dist/core/runner/skills-seat.d.ts +15 -0
- package/dist/core/runner/skills-seat.js +57 -0
- 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-deps.d.ts +29 -14
- package/dist/core/session-policy-store.d.ts +19 -0
- package/dist/core/session-policy-store.js +22 -2
- package/dist/core/store-contracts/mailbox-store-contract.js +13 -0
- package/dist/core/task-event.d.ts +38 -2
- package/dist/core/task-notification.js +2 -2
- package/dist/core/task-spec.d.ts +1 -1
- package/dist/core/tool-policy.d.ts +3 -0
- package/dist/core/tool-policy.js +10 -4
- package/dist/core/types.d.ts +2 -2
- package/dist/core/types.js +1 -1
- package/dist/core/untrusted-text.d.ts +16 -0
- package/dist/core/untrusted-text.js +7 -2
- package/dist/core/user-attachment.d.ts +13 -2
- package/dist/core/user-attachment.js +47 -41
- package/dist/core/wiring-manifest.d.ts +4 -2
- package/dist/engine/harness/agent-harness.js +2 -1
- package/dist/engine/harness/types.d.ts +3 -0
- 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/index.d.ts +15 -9
- package/dist/index.js +12 -6
- package/dist/internal/harness.d.ts +1 -0
- package/dist/internal/harness.js +1 -0
- package/dist/orchestration/goal.d.ts +24 -1
- package/dist/orchestration/goal.js +3 -2
- 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 +16 -2
- 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 +55 -17
- package/dist/prompt-assembly/select.d.ts +21 -6
- package/dist/prompt-assembly/select.js +39 -2
- package/dist/prompts/default.d.ts +0 -11
- package/dist/prompts/default.js +0 -3
- package/dist/stores/file/permission-rule-store.d.ts +1 -1
- package/dist/stores/file/permission-rule-store.js +2 -1
- package/dist/tools/artifact/artifact-tool.js +4 -3
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +65 -5
- package/wire-changes/core@7.53.0.json +1946 -0
package/dist/index.js
CHANGED
|
@@ -91,7 +91,7 @@ export { RemoteExecutionError, hasDestroy, isRemoteExecutionEnv, isSuspendable,
|
|
|
91
91
|
export { withRetry } from "./core/with-retry.js";
|
|
92
92
|
export { addWorktree, pruneWorktrees, WORKTREE_PARENT } from "./core/git-worktree-env.js";
|
|
93
93
|
export { runExecGate } from "./core/exec-gate.js";
|
|
94
|
-
export { sanitizeUntrustedText, delimitUntrusted, inlineUntrusted } from "./core/untrusted-text.js";
|
|
94
|
+
export { sanitizeUntrustedText, delimitUntrusted, inlineUntrusted, isMintableProbeReason } from "./core/untrusted-text.js";
|
|
95
95
|
export { mintReminderMark, isValidReminderMark, openSystemReminder, mintSystemReminder, reminderMarkDeclaration } from "./core/reminder-mint.js";
|
|
96
96
|
export { deriveInvariants, checkInvariants } from "./core/property-harness.js";
|
|
97
97
|
export { bashReversibilityProbe, BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName, classifyCompoundReadonly, MAX_EDIT_BYTES } from "./tools/fs/index.js";
|
|
@@ -219,9 +219,10 @@ export { runMemoryConsolidation, CONSOLIDATION_SYSTEM_PROMPT, DEFAULT_CONSOLIDAT
|
|
|
219
219
|
export { consolidateScope, advanceCursorAfterInline, } from "./core/consolidate-scope.js";
|
|
220
220
|
export { resolveMemoryConsolidationDriver, autoRunOnRecommendationEffective, } from "./core/runner/memory-consolidation-driver.js";
|
|
221
221
|
export { DEFAULT_COMPACTION_INSTRUCTIONS } from "./core/auto-compaction.js";
|
|
222
|
-
export { DEFAULT_SYSTEM_PROMPT, CODE_AGENT_PROMPT, SUBAGENT_PROMPT, CODE_SYSTEM_PROMPT, MEMORY_GUIDANCE, MEMORY_SAFETY, MEMORY_HYGIENE,
|
|
222
|
+
export { DEFAULT_SYSTEM_PROMPT, CODE_AGENT_PROMPT, SUBAGENT_PROMPT, CODE_SYSTEM_PROMPT, MEMORY_GUIDANCE, MEMORY_SAFETY, MEMORY_HYGIENE, OUTPUT_EFFICIENCY, CYBER_RISK, HARNESS_SECTION_ANCHOR, URL_SAFETY, SUMMARIZE_TOOL_RESULTS, EXECUTION_ENVIRONMENT, EXECUTION_ENVIRONMENT_OPEN_READS, executionEnvironmentBlockFor, buildEnvironmentContext, buildGitSnapshot, buildScratchpadSection, GIT_STATUS_MAX_CHARS, formatLocalDate, } from "./prompts/default.js";
|
|
223
223
|
export { SUPERVISOR_PROMPT, ORCHESTRATION_GUIDANCE, ORCHESTRATION_AWARENESS, GOAL_COMPLETION_GUIDANCE } from "./prompts/supervisor.js";
|
|
224
224
|
export { OVERLAY_SOURCE_ORDER } from "./prompt-assembly/overlay.js";
|
|
225
|
+
export { PROMPT_BINDING_LIST_MAX, PROMPT_BINDING_MAX_CHARS } from "./prompt-assembly/overlay.js";
|
|
225
226
|
export { BANDS as PROMPT_BANDS } from "./prompt-assembly/bands.js";
|
|
226
227
|
export { OVERLAY_OPS, HOST_ROLES, HOST_FORMS } from "./prompt-assembly/catalog/schema.js";
|
|
227
228
|
export { SEMA_DEFAULT_CATALOG, catalogText } from "./prompt-assembly/catalog/index.js";
|
|
@@ -300,6 +301,11 @@ export { TEAM_ROLES, DIRECTION_RELATIONS, teamRoleOf, mayDirect } from "./agents
|
|
|
300
301
|
export { createListAgentsTool, LIST_AGENTS_TOOL_NAME, LIST_AGENTS_TOOL_ALIAS, LIST_AGENTS_MAX_RESULT_CHARS, PEER_LISTING_FRESH_WINDOW_MS, isFreshPeerRow } from "./agents/list-agents-tool.js";
|
|
301
302
|
export { CROSS_SESSION_CLASSIFIER_RULE } from "./agents/cross-session-envelope.js";
|
|
302
303
|
export { PEER_SESSION_ID_UNGRAMMATICAL_CODE, PEER_RESUPPLY_CAP } from "./agents/peer-session-drain.js";
|
|
304
|
+
export { ORG_DELIVERY_REFUSAL_CODES, isOrgDeliveryRefusalCode, mintCrossPrincipalRecord, isGateMintedRecord, PRINCIPAL_INBOX_TRIAGE_POLICIES, principalInboxTriagePolicy, principalInboxSideEffectKey, principalInboxConsumerOf, PRINCIPAL_INBOX_CONSUMER_INVALID_CODE, } from "./agents/org-delivery-gate.js";
|
|
305
|
+
export { PRINCIPAL_INBOX_HANDLE } from "./agents/cross-session-ref.js";
|
|
306
|
+
export { CROSS_PRINCIPAL_MESSAGE_NOTICE } from "./agents/cross-session-envelope.js";
|
|
307
|
+
export { principalInboundLayers } from "./agents/cross-session-judge.js";
|
|
308
|
+
export { PRINCIPAL_INBOX_UNMINTED_CAUSE } from "./agents/peer-session-drain.js";
|
|
303
309
|
export { renderCrossSessionMessageFrame, renderCrossSessionNoticeLine } from "./core/task-notification.js";
|
|
304
310
|
export { PEER_HELD_QUEUE_CAP, PEER_IDLE_SUBSCRIPTION_TTL_MS, PEER_IDLE_SUBSCRIBER_TABLE_CAP, PEER_IDLE_OUTSTANDING_CAP, PEER_IDLE_PRIORS_KEPT, PEER_IDLE_FIRE_DEBOUNCE_MS, PEER_IDLE_HELD_BACKOFF_MS, PEER_IDLE_LABEL_MAX, CROSS_SESSION_DIALOG_EXPIRY_VALUES, CROSS_SESSION_DIALOG_EXPIRY_DEFAULT, resolveCrossSessionDialogExpiry, PEER_HELD_REVIEW_CAUSES, PEER_DELIVERY_RECEIPT_STATES, isPeerDeliveryReceiptState, PEER_DROP_REASONS, peerRecipientSuffix, renderCrossSessionDeliveryNotice, describePeerDropReasons, renderCrossSessionDroppedNotice, PEER_IDLE_NOTICE_KINDS, isPeerIdleNoticeKind, PEER_IDLE_UNAVAILABLE_CAUSES, peerIdleNoticeLabel, formatPeerNoticeClock, renderCrossSessionIdleNotice, describePeerIdleSubscription, } from "./agents/peer-notices.js";
|
|
305
311
|
export { createPeerHeldQueue, peerHeldQueueFor, peerHeldQueueIfAny, peerHeldQueueKey, realPeerClock, } from "./agents/peer-held-queue.js";
|
|
@@ -312,17 +318,17 @@ export { builtinAgentDefinitions, BUILTIN_READONLY_DENY_TOOLS, EXPLORE_WHEN_TO_U
|
|
|
312
318
|
export { createTaskServer, } from "./server/http.js";
|
|
313
319
|
export { clearStaleToolResults, editBudget, } from "./core/context-edit.js";
|
|
314
320
|
export { createOpenAIBrain } from "./brain/openai.js";
|
|
315
|
-
export { createAnthropicBrain } from "./brain/anthropic.js";
|
|
321
|
+
export { createAnthropicBrain, ANTHROPIC_DEFAULT_BASE_URL } from "./brain/anthropic.js";
|
|
316
322
|
export { createOpenResponsesBrain } from "./brain/open-responses.js";
|
|
317
323
|
export { FABLE_5_COMPAT, fable5Model } from "./brain/model-presets.js";
|
|
318
324
|
export { createFailoverBrain } from "./brain/failover.js";
|
|
319
|
-
export { createRoutingBrain } from "./brain/routing.js";
|
|
325
|
+
export { createRoutingBrain, brainLaneOf } from "./brain/routing.js";
|
|
320
326
|
export { repairTextToolCalls } from "./brain/tool-call-repair.js";
|
|
321
327
|
export { createCircuitBreakerBrain, CIRCUIT_OPEN_MARKER, } from "./brain/circuit-breaker.js";
|
|
322
328
|
export { createDegradingBrain, readDegradation, DEGRADED_DIAGNOSTIC_TYPE, } from "./brain/degrading.js";
|
|
323
329
|
export { retryBackoffMs, parseRetryAfter } from "./brain/retry.js";
|
|
324
330
|
export { WAITING_FIRST_TOKEN_AFTER_MS, WAITING_FIRST_TOKEN_EVERY_MS } from "./brain/stream-engine.js";
|
|
325
|
-
export { adjudicateModelRoute, resolveRouteCredential, routeRefusalText, routePairingStatus, routeKeyOf, displayUrlOf, resolveRequestRoot, resolveRequestRootOf, joinRequestUrl, hasAuthCarrier, __resetCredentialOriginBindings, } from "./brain/route-adjudicator.js";
|
|
331
|
+
export { adjudicateModelRoute, resolveRouteCredential, admitRouteRequest, routeRefusalText, routePairingStatus, routeKeyOf, displayUrlOf, resolveRequestRoot, resolveRequestRootOf, joinRequestUrl, hasAuthCarrier, __resetCredentialOriginBindings, } from "./brain/route-adjudicator.js";
|
|
326
332
|
export { ROUTE_CREDENTIAL_SOURCES, ROUTE_CARRIERS, ROUTE_CARRIER_BAGS, REQUEST_ROOT_ORIGINS, ROUTE_CREDENTIAL_PAIRING, requestRouteOf, routePairingRowOf, } from "./brain/request-route.js";
|
|
327
333
|
export { ROUTE_ADJUDICATION_CONFORMANCE_CORPUS } from "./brain/route-conformance.js";
|
|
328
334
|
export {} from "./brain/timeout.js";
|
|
@@ -334,4 +340,4 @@ export { SHADOW_REASON, allowRuleShadowSentence, cardDisclosureOf } from "./core
|
|
|
334
340
|
export { RULE_OFFERS_ABSENCES } from "./core/ask-origin.js";
|
|
335
341
|
export { BOUND_GRANT_ABSENCES } from "./core/skill-grant-binding.js";
|
|
336
342
|
export { DISPOSABLE_PROMPT_SECTIONS } from "./core/prompt-section-seat.js";
|
|
337
|
-
export { readMcpToolAxes } from "./core/mcp-server-spec.js";
|
|
343
|
+
export { readToolAxes, readMcpToolAxes } from "./core/mcp-server-spec.js";
|
|
@@ -23,6 +23,7 @@ export { BaseSessionStorage, leafIdAfterEntry } from "../engine/session/storage-
|
|
|
23
23
|
export { InMemorySessionStorage } from "../engine/session/memory-storage.js";
|
|
24
24
|
export { InMemorySessionRepo } from "../engine/session/memory-repo.js";
|
|
25
25
|
export { uuidv7 } from "../engine/session/uuid.js";
|
|
26
|
+
export { readToolCallArguments } from "../engine/loop/agent-loop.js";
|
|
26
27
|
export { SessionError } from "../engine/harness/types.js";
|
|
27
28
|
export type { AnnouncedListingSnapshot, AnnouncedListingSnapshotInput, AnnouncedMcpFailure } from "../engine/harness/types.js";
|
|
28
29
|
export { normalizeGitAnnouncement } from "../engine/harness/types.js";
|
package/dist/internal/harness.js
CHANGED
|
@@ -11,6 +11,7 @@ export { BaseSessionStorage, leafIdAfterEntry } from "../engine/session/storage-
|
|
|
11
11
|
export { InMemorySessionStorage } from "../engine/session/memory-storage.js";
|
|
12
12
|
export { InMemorySessionRepo } from "../engine/session/memory-repo.js";
|
|
13
13
|
export { uuidv7 } from "../engine/session/uuid.js";
|
|
14
|
+
export { readToolCallArguments } from "../engine/loop/agent-loop.js";
|
|
14
15
|
export { SessionError } from "../engine/harness/types.js";
|
|
15
16
|
export { normalizeGitAnnouncement } from "../engine/harness/types.js";
|
|
16
17
|
export { gitFrameContextVisible } from "../engine/session/session.js";
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import type { RunnerSelfSeat } from "../core/runner/contracts.js";
|
|
15
15
|
import type { CheckpointToken } from "../core/checkpoint-store.js";
|
|
16
|
-
import type {
|
|
16
|
+
import type { GateKind, PAUSE_REGISTRY } from "../core/pause-registry.js";
|
|
17
|
+
import type { PausedCause, TaskResult, TaskSpec } from "../core/types.js";
|
|
17
18
|
/** Read-only snapshot a `doneCheck` sees after one iteration. */
|
|
18
19
|
export interface GoalTurnState {
|
|
19
20
|
/** This iteration's full {@link TaskResult}. */
|
|
@@ -73,6 +74,18 @@ export type GoalStatus = "achieved" | "max_iterations" | "budget" | "blocked" |
|
|
|
73
74
|
* objective / raise `budgetTokens`), `"walltime"` = `totalTimeoutMs` elapsed (give it more time).
|
|
74
75
|
*/
|
|
75
76
|
export type GoalBudgetCause = "tokens" | "walltime";
|
|
77
|
+
/**
|
|
78
|
+
* The gates a pause can carry when the status word reads `suspended`: the pause registry's rows whose `taskStatus` column is `suspended` —
|
|
79
|
+
* the column {@link pauseFamily} projects the status word from. The type reads the same table the status word does, so a row added to the
|
|
80
|
+
* table moves both, and a gate that reaches the mint below with that word is always one of these. Of the four kinds, a run's own pause is
|
|
81
|
+
* `human`, `irreversible_ask` or `resource_limit`; `task_done` is the handle a deployment parks, which the engine mints in no run but which
|
|
82
|
+
* a custom runner seat may return as a paused terminal, and which the table reads `suspended` too. The review kinds are `needs_review`.
|
|
83
|
+
*/
|
|
84
|
+
type SuspendedGate = Extract<PausedCause["gate"], {
|
|
85
|
+
kind: {
|
|
86
|
+
[K in GateKind]: (typeof PAUSE_REGISTRY)[K]["taskStatus"] extends "suspended" ? K : never;
|
|
87
|
+
}[GateKind];
|
|
88
|
+
}>;
|
|
76
89
|
export interface GoalResult {
|
|
77
90
|
readonly status: GoalStatus;
|
|
78
91
|
/** Last iteration's result; absent on a preflight-terminate (a stop BEFORE iteration 1 ran). */
|
|
@@ -93,6 +106,15 @@ export interface GoalResult {
|
|
|
93
106
|
/** #111 — present IFF `status === "budget"` (the KEY is absent otherwise, so presence alone reads
|
|
94
107
|
* as "stopped on a ceiling"). See {@link GoalBudgetCause}. */
|
|
95
108
|
readonly budgetCause?: GoalBudgetCause;
|
|
109
|
+
/** Present IFF `status === "suspended"` — every suspended result carries it, no other carries the KEY: WHY the run is parked, as the
|
|
110
|
+
* gate it parked at (the checkpoint's own gate, the same object as `result.terminal.gate`; its words are the closed sets of
|
|
111
|
+
* {@link import("../core/checkpoint-store.js").CheckpointGate}, narrowed to the kinds whose status word is `suspended`: `human`,
|
|
112
|
+
* `irreversible_ask`, `resource_limit` — and `task_done`, the handle a deployment parks, which a run of this engine never mints but a custom
|
|
113
|
+
* runner seat may return). The cause is read from the gate alone, never from the caller's signal:
|
|
114
|
+
* `{ kind: "resource_limit", reason: "usage_window" }` waits for quota (`resumeAfterMs`); `reason: "preempt"` is the host's own resumable
|
|
115
|
+
* stop (`TaskSpec.preemptSignal`); `human` / `irreversible_ask` wait on an approval; another `resource_limit` reason waits on an
|
|
116
|
+
* allowance. A caller's abort that ended the run is `status: "aborted"` (no checkpoint); a park that won the race with it is that park. */
|
|
117
|
+
readonly suspendGate?: SuspendedGate;
|
|
96
118
|
}
|
|
97
119
|
/** Reserved name of the goal-completion signal tool (injected by `runGoal` when there is no outputSchema). */
|
|
98
120
|
export declare const DECLARE_DONE_TOOL_NAME = "DeclareDone";
|
|
@@ -104,3 +126,4 @@ export declare const DECLARE_DONE_TOOL_NAME = "DeclareDone";
|
|
|
104
126
|
* cancel; a durable pause (suspended/needs_review) is a hard boundary that surfaces the checkpointToken.
|
|
105
127
|
*/
|
|
106
128
|
export declare function runGoal(runner: RunnerSelfSeat, spec: GoalSpec): Promise<GoalResult>;
|
|
129
|
+
export {};
|
|
@@ -100,9 +100,10 @@ export async function runGoal(runner, spec) {
|
|
|
100
100
|
verificationKind,
|
|
101
101
|
accepted: false,
|
|
102
102
|
cumulativeTokens,
|
|
103
|
-
checkpointToken: over?.
|
|
103
|
+
checkpointToken: over?.paused?.token,
|
|
104
104
|
errorCode: over?.errorCode,
|
|
105
105
|
...(status === "budget" && over?.budgetCause !== undefined ? { budgetCause: over.budgetCause } : {}),
|
|
106
|
+
...(status === "suspended" && over?.paused !== undefined ? { suspendGate: over.paused.gate } : {}),
|
|
106
107
|
};
|
|
107
108
|
if (verificationKind === "mechanical" && status !== "suspended" && status !== "needs_review") {
|
|
108
109
|
runner.emitTaskOutcome?.({
|
|
@@ -145,7 +146,7 @@ export async function runGoal(runner, spec) {
|
|
|
145
146
|
spentCostMicroUsd += (result.stats.costMicroUsd ?? 0) + (result.stats.nested?.costMicroUsd ?? 0);
|
|
146
147
|
spentTurns += (result.stats.turns ?? 0) + (result.stats.nested?.turns ?? 0);
|
|
147
148
|
if (isDurablePause(result.terminal)) {
|
|
148
|
-
return mk(pauseFamily(result.terminal), iteration, { result,
|
|
149
|
+
return mk(pauseFamily(result.terminal), iteration, { result, paused: result.terminal });
|
|
149
150
|
}
|
|
150
151
|
const midStop = classifyStop();
|
|
151
152
|
if (midStop)
|
|
@@ -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[];
|