@alma-harness/single-call
v0.12.0
Published
Governed one-dispatch model execution for Alma.
Readme
@alma-harness/single-call
Governed one-dispatch model calls. The text/JSON runner is tool-free; the structured step runner preserves native tool calls. Use matching core, execution, providers, memory and PostgreSQL packages. Node >=22. This engine is separate from the legacy conversation and batch runners.
createSingleCallRunner(config) owns policy, versioned prices, monetary caps,
complete cache controls, output schema/validator and technical limits. run
accepts a verified scope/session/operation key/input revision/intent, an optional
AbortSignal and a lazy loadInput(): Promise<Msg[]>. The host resolves identity
and immutable input authorization; never forward browser-supplied scope/revision
without that resolution. Only text user/assistant messages are supported.
Supply ExecutionStore, ExecutionResultStore, UsageInbox, GovernedCostSettlementStore, a SpendStore.peek reading the same counters, and an awaited AuditLog. Use InMemoryGovernedCostSettlementStore.peek with its own volatile settlement store; PostgresSpendStore and PostgresCostSettlementStore share the durable tables. Only governed settlement writes financial rows. AuditLog.cost and SpendStore.add are never invoked by this engine. Routing/access carry operation/attempt/call IDs.
Configuration includes policyVersion, priceVersion, outputContractVersion, prices,
caps, consumers, system, maxTokens, maxInputChars, maxOutputChars, deadlineMs,
resultRetentionMs, clients and onBackgroundError. Optional cache overrides the
policy cache, including false; omitted uses the policy choice. Optional output
is {name, schema, validate} for native JSON; validate must synchronously return
true. Configuration data is snapshotted; host version identifiers must describe
immutable policy/output contracts. Clients/policy/validator are trusted capabilities.
Use the providers package's explicit SingleDispatch constructors: default clients
with automatic retries are rejected. No fallback, repair, tools or user streaming.
Results are reserved before loading context. Duplicate keys read status or the original authorized envelope, never load input or redispatch. Changed session, intent, revision or policy/output/price version conflicts. Monetary warnings preserve results. Explicit block caps retain preflight/post-call blocking; known cost is always settled before a successful output is suppressed.
read(scope,key) returns null or a view: in_progress, reconciliation_required,
not_dispatched or completed. Completed includes the current authorized envelope,
original financial receipt and historical journal metadata. Erased/expired output
is unavailable even when the historical completion was successful. Persistence
failure rejects; reread/recover resolves what committed without a provider retry.
recover(scope,key,{leaseMs}) acquires an eligible accounting-only fence, uses the
original policy/prices/day and completes available or unavailable output. A policy
refusal during unfinished recovery leaves completion pending rather than replacing
a previously stored envelope. It never
fetches input. Call reconcileExpired(scope,{limit?}) from the host scheduler to
fence overdue prepared/dispatching executions. Unknown/unpriced evidence requires
operator reconciliation; late inbox evidence does not automatically rewrite it.
reconcileUsage(scope,{limit?,after?}) acknowledges only exact observations whose
completed accounting or not-dispatched proof is durable. Page size defaults to50,
maximum100. It returns scanned/acknowledged counts and the last inspected cursor.
Restart each pass from the beginning to see late commits. Unknown/conflicting
observations remain pending. Financial projections have independent consumers. The optional third argument { skip(operationKey) } leaves rows pending. Runtime
maintenance uses it to keep a governed call's usage on the step path, which also
checks root accounting (spec: runtime-maintenance).
The public run promise is bounded by deadline/abort, including hanging dependencies. A dispatched stream remains drained for late evidence; background errors reach the required metadata-only onBackgroundError callback. Process death or a permanently hung custom adapter cannot guarantee final usage arrival. Hosts monitor unresolved records and schedule recovery; this package starts no persistent worker.
Migrate journal, results, inbox, governed costs and audit before deploying the matching readers/writers. Result retention must allow execution/recovery and its erasure surface must be registered by the host. Completion does not mean a business mutation or portal/WhatsApp delivery happened: those have independent identities. Erasure can still race egress after the final reservation check; stored content cannot be resurrected. See spec.
Optional temperature is a host configuration snapshot, persisted with execution
controls before dispatch. Provider validation applies before claim. Replay and
accounting recovery retain the original value; callers cannot override it. Bump
policyVersion when changing this immutable configuration. See the providers
package's deliberately bounded support matrix (spec: explicit-temperature-controls).
Governed model steps
createGovernedStepRunner(config) is the official buffered primitive for a
one-call structured response and the primitive adopted by conversations. It accepts a trusted, already planned OperationCallInput and root fence,
plus a lazy loadRequest and routing rationale. Supply the same execution/result/
inbox/settlement/spend/audit capabilities, OperationTreeStore, OperationAccountingStore,
single-dispatch clients and runTimeoutMs/maxRequestChars/maxOutputChars. The host
builds registry-derived tools and enforces authorization before handing it over.
Input prices, policy, controls, IDs and retention are immutable original snapshots.
The root slot is reserved before journal claim; result policy and correlated audit
precede content loading. One dispatch produces one governed charge plus one root
receipt. No legacy financial writer, tool handler, session append or channel send
runs here. Warn preserves output; configured block caps use the inclusive root
cost. A successful view includes the original receipts and step: neutral text,
toolCalls, reasoning, providerBlocks, stop and an order index preserving their
interleaving. Text ranges use UTF-16 offsets; adjacent text deltas are coalesced. This is backstage harness data,
not a public reply. The adopting loop must hide reasoning and authorize tools.
Opaque JSON is preserved; invalid/non-JSON/oversized output cannot authorize tools.
Malformed tool arguments retain an empty input and boolean marker, never raw text.
read({scope,rootKey,operationKey}) and recover(key,{leaseMs}) bind the call to
its registered root. Both financial receipts are required for completed status;
recover repairs missing aggregation even if the journal is already complete.
Recovery loads no request and dispatches no provider/tool. Lost output becomes
unavailable; erased/expired content cannot be regenerated. Root closure prevents
new admission but does not cancel a previously reserved call before its deadline.
The root owner closes/reconciles roots and owns whole-turn/effect uncertainty.
reconcileUsage({scope,rootKey},query?) acknowledges exact evidence only when that
root's completion/accounting (or not-dispatched proof) is durable. It scans bounded
scoped inbox pages; restart subsequent passes to see late commits. The public run
is bounded by runTimeoutMs (max five minutes), external abort and, for new calls,
the original deadline. Its background drain reports metadata-only failures.
The conversation package adopts this step; legacy runners remain separate.
See spec.
A clean attested Anthropic context rejection stores a metadata-only refusal after the original zero settlement and root receipt. Any content (even rejected by the collector), missing reference, repeated/different stop or stream failure invalidates the proof. Accounting recovery never resumes a conversation automatically (spec: safe-context-rejection-rotation).
Explicit tool selection
Set the same toolChoice on call.execution.controls and the lazy ModelRequest,
for example {type:"tool",name:"extract_record"}. The request's tools must come
from the host-authorized registry. The primitive validates the selected name
against these actual ToolSpecs even when a custom client validator does nothing;
provider validation additionally applies its documented support matrix before
network access. Selection never executes a tool or grants permission to do so.
Choices are immutable execution metadata. An identical replay returns original
receipts and retained output without loading input; a changed choice (including
absent versus explicit auto) under the same identity conflicts. Accounting recovery
never dispatches another request. Older records without toolChoice remain readable.
The text/JSON createSingleCallRunner rejects toolChoice on configuration or run
input; use createGovernedStepRunner for structured tool responses.
A completed view alone is insufficient: inspect result.outcome, step.stop, the
expected name in step.toolCalls and its malformed marker before validating its
arguments against the business schema. Refusal, truncation, unavailable output and
malformed arguments must not be treated as a valid extraction. Non-success views
may withhold partial blocks while retaining the original stop and financial receipt.
Structured single calls
createStructuredCallRunner(config) is the one-call structured response with the
text runner's call shape: run({scope, sessionId, operationKey, inputRevision,
intent, loadInput, signal?}). Use it for a forced tool acting as an extraction
schema. Configuration is the text runner's, without output, plus trees,
accounting, trusted registry tools and an optional toolChoice. Tool names
are validated and deduplicated at construction.
The runner owns the operation root, the identities, the replay check and the
closure. Every identifier is alma-structured-v1:<kind>:<sha256> over the scope
and the host key: bounded, domain-separated and never embedding the key. That
prefix is reserved; do not use it for other keys. Replay compares the root's
immutable binding without its deadline, so no occurrence time is needed. The
binding covers session, intent, input revision and a digest of all configuration
data, including prices and tools. Changes in trusted policy.resolve behavior
cannot be digested: bump policyVersion. The session/day block preflight runs
before any root exists.
A completed view is the unchanged governed step view: inspect result.outcome,
step.stop, the selected call and its malformed marker before using it. A
failed root closure never hides a completed result: closure is detached housekeeping, and an unclosed root expires and is reconciled. Without an execution record,
read reports not_dispatched only for a non-active root with zero reserved
calls, proven by the store under its root lock. A reserved call without a
journal record reads reconciliation_required; an active root reads
in_progress, whatever the application clock says. One key is one call:
unusable outcomes are final, so retry with a new key.
recover(scope, key, {leaseMs}) and reconcileUsage(scope, key, query?) take the
host key. reconcileExpired(scope, {limit?}) is scope-wide and returns {roots,
executions}. See spec.
