stitchkit 0.65.1 → 0.66.1

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.
Files changed (35) hide show
  1. package/dist/agent-runtime/coordinator.d.ts +8 -5
  2. package/dist/agent-runtime/coordinator.d.ts.map +1 -1
  3. package/dist/agent-runtime/events.d.ts +36 -30
  4. package/dist/agent-runtime/events.d.ts.map +1 -1
  5. package/dist/agent-runtime/injection.d.ts +28 -0
  6. package/dist/agent-runtime/injection.d.ts.map +1 -0
  7. package/dist/agent-runtime/observability.d.ts +22 -20
  8. package/dist/agent-runtime/observability.d.ts.map +1 -1
  9. package/dist/agent-runtime/prompt.d.ts +11 -1
  10. package/dist/agent-runtime/prompt.d.ts.map +1 -1
  11. package/dist/agent-runtime/run-execution.d.ts +11 -0
  12. package/dist/agent-runtime/run-execution.d.ts.map +1 -1
  13. package/dist/agent-runtime/runtime-internals.d.ts.map +1 -1
  14. package/dist/agent-runtime/runtime.d.ts.map +1 -1
  15. package/dist/agent-runtime/schemas.d.ts +75 -21
  16. package/dist/agent-runtime/schemas.d.ts.map +1 -1
  17. package/dist/agent-runtime/store-driver.d.ts +21 -15
  18. package/dist/agent-runtime/store-driver.d.ts.map +1 -1
  19. package/dist/agent-runtime/store.d.ts +280 -46
  20. package/dist/agent-runtime/store.d.ts.map +1 -1
  21. package/dist/agent-runtime/terminal-commit.d.ts +33 -3
  22. package/dist/agent-runtime/terminal-commit.d.ts.map +1 -1
  23. package/dist/agent-runtime/terminal-status.d.ts.map +1 -1
  24. package/dist/agent-runtime-openrouter.js +1 -1
  25. package/dist/agent-runtime.d.ts +1 -1
  26. package/dist/agent-runtime.d.ts.map +1 -1
  27. package/dist/agent-runtime.js +384 -97
  28. package/dist/{index-sbkyvacf.js → index-fhsmrzj7.js} +45 -5
  29. package/dist/testing/agent-store-conformance.d.ts +34 -1
  30. package/dist/testing/agent-store-conformance.d.ts.map +1 -1
  31. package/dist/testing.d.ts +1 -1
  32. package/dist/testing.d.ts.map +1 -1
  33. package/dist/testing.js +175 -4
  34. package/llms-full.txt +281 -22
  35. package/package.json +1 -1
package/llms-full.txt CHANGED
@@ -58,7 +58,7 @@ own, recorded as an ADR.
58
58
  | `stitchkit/testing` | tests on Bun or Node | stable | in-process generated clients over a real Fetch handler, plus the store and managed-resource conformance kits |
59
59
  | `stitchkit/declaration` | build and deployment tooling (Bun or Node) | evolving | `ProjectDeclarationSchema` — the one machine-readable statement a repository makes about itself |
60
60
  | `stitchkit/react` | browser | stable | `createCursorQuery`, `createCacheBridge` |
61
- | `stitchkit/agent-runtime` | server | evolving<br>_redefined in 8 of the 10 minors since 0.56.2, most recently 0.65.0_ | optional durable conversation/run loop, history, models, prompts, fencing and events |
61
+ | `stitchkit/agent-runtime` | server | evolving<br>_redefined in 9 of the 11 minors since 0.56.2, most recently 0.66.0_ | optional durable conversation/run loop, history, models, prompts, fencing and events |
62
62
  | `stitchkit/agent-runtime/openrouter` | server | evolving | isolated OpenRouter language-model adapter |
63
63
  | `stitchkit/application` | server | evolving | managed resource graph, readiness, admission, schedules and bounded shutdown |
64
64
  | `stitchkit/application/grammy` | server | evolving | isolated grammY polling and webhook lifecycle adapters |
@@ -3683,15 +3683,14 @@ input + queued run → running → execution settled → terminal CAS → succes
3683
3683
 
3684
3684
  ## What happens to a run when new input arrives
3685
3685
 
3686
- `runs.inputPolicy` decides. It takes three values, or a function returning one;
3687
- the fourth row is a behaviour that shipped and was withdrawn:
3686
+ `runs.inputPolicy` decides. It takes four values, or a function returning one:
3688
3687
 
3689
3688
  | policy | the run in flight | what it already produced |
3690
3689
  |--------|-------------------|--------------------------|
3691
3690
  | `queue` (default) | finishes first | kept |
3691
+ | `inject` | continues, and answers the new input too | kept, and built on |
3692
3692
  | `interrupt` | ends | kept, and marked as cut off |
3693
3693
  | `supersede` | ends | discarded from the prompt, kept in the record |
3694
- | _inject_ | continues | withdrawn in 0.65.0 — see below |
3695
3694
 
3696
3695
  `interrupt` and `supersede` differ in exactly one thing, and the question that
3697
3696
  picks between them is **not** "was the run interrupted" but **"did anyone see
@@ -3775,19 +3774,53 @@ const { decisions } = await projectAgentHistoryDetailed(snapshot.messages)
3775
3774
  process-local escape hatch chooses the reason, so a caller that knows the answer
3776
3775
  was never delivered can discard it without a newer input arriving.
3777
3776
 
3778
- ### The one that is not offered
3777
+ ### An input that joins a run in flight
3778
+
3779
+ `inject` is right when the new input **refines** rather than redirects, and the
3780
+ steps already taken are still worth something: *"summarise this thread… actually,
3781
+ in bullet points"* should not throw away the reading the first message paid for.
3782
+
3783
+ What happens:
3784
+
3785
+ 1. The input is admitted exactly like any other — a committed user message and a
3786
+ **queued run**, durable before anything else happens.
3787
+ 2. At the running loop's next step boundary, that input joins its prompt. Only
3788
+ that input: an unrelated queued submission is never carried in.
3789
+ 3. When the run finishes, its terminal commit — **one transaction** — records
3790
+ the input as one the run answered and settles the queued successor with
3791
+ `terminalReason: 'absorbed'` and `absorbedIntoRunId` naming the run that
3792
+ answered it. Every ticket for that successor resolves to the same answer.
3793
+
3794
+ Nothing durable happens between 1 and 3, and that is the design (→ ADR 0113).
3795
+ A run that crashes, is closed, or is interrupted after taking an input on
3796
+ commits no absorption at all, so what is left behind is an ordinary queued
3797
+ successor — the state every other policy already produces and recovery already
3798
+ handles. **There is no ordering in which an accepted input becomes
3799
+ unanswerable.** Only a run that *completes* may absorb; an interrupted one took
3800
+ the input into its prompt and then stopped, and does not get to say it answered
3801
+ it.
3802
+
3803
+ An absorbed run has **no assistant message of its own** — it produced none, and
3804
+ writing an empty one would be a record claiming otherwise. Its answer is
3805
+ reachable through `absorbedIntoRunId`, and the store follows that pointer itself
3806
+ when a submission arrives on the absorbed run's idempotency key, so a retry
3807
+ after a restart returns the answer rather than an empty terminal record.
3808
+
3809
+ It does publish one more `run-state` event, carrying `'superseded'`. It never
3810
+ enters the run executor, so that event is the only thing that tells a delivery
3811
+ surface following its `runId` that it is no longer queued.
3779
3812
 
3780
- **inject** hand the input to the loop between tool calls and let the run
3781
- continue shipped in 0.63.0 and was **withdrawn in 0.65.0**. It committed the
3782
- absorption durably at a step boundary, before the answer existed, and everything
3783
- downstream of that ordering was wrong: an accepted input could end up in a state
3784
- that was neither active, recoverable nor terminal, so `close()` could report
3785
- `settled: true` while leaving it permanently unanswerable, and a duplicate
3786
- submission of the same idempotency key was refused forever.
3813
+ With `coalescePending`, one successor can carry several inputs, and an
3814
+ absorption covers a successor **whole or not at all** a partial one would
3815
+ leave a terminal run with inputs nobody answered. Inputs that coalesce before
3816
+ the absorbing run's last step boundary join the same absorption. One that
3817
+ arrives after it cancels the absorption: the successor then answers all of its
3818
+ inputs itself, and the absorbing run has answered one of them too. A duplicate
3819
+ answer, never a missing one.
3787
3820
 
3788
- The redesign is tracked in the backlog and is not a patch to what shipped: the
3789
- absorption has to commit atomically **with** the terminal record, so that a run
3790
- which ends first simply leaves an ordinary queued successor behind.
3821
+ (0.63.0 shipped a version of this that committed the absorption at the step
3822
+ boundary, before the answer existed, and it was withdrawn in 0.65.0. ADR 0113
3823
+ records what that ordering broke.)
3791
3824
 
3792
3825
  With `runs.coalescePending: true`, an active lane has at most one queued
3793
3826
  successor. Every later accepted input is atomically appended to that successor;
@@ -3850,7 +3883,7 @@ problem, and omitting a run's cost is an operator's.
3850
3883
  ## Store operations
3851
3884
 
3852
3885
  `AgentRuntimeStore` remains the runtime-facing aggregate. Application adapters
3853
- implement the smaller `AgentRuntimeStoreDriver` rather than these nine members:
3886
+ implement the smaller `AgentRuntimeStoreDriver` rather than these eleven members:
3854
3887
 
3855
3888
  - `acceptInputAndAssignRun`
3856
3889
  - `acquireRun`
@@ -3859,11 +3892,37 @@ implement the smaller `AgentRuntimeStoreDriver` rather than these nine members:
3859
3892
  - `recoverRun`
3860
3893
  - `commitRunTerminal`
3861
3894
  - `replaceCompactedRange`
3862
- - `loadSnapshot`
3895
+ - `loadSnapshot` — the whole conversation; see **Reading a conversation** below
3896
+ - `loadRun` — one run by id, with the answer it produced if it has ended
3897
+ - `listActiveRuns` — the runs of one conversation that have not ended
3863
3898
  - `scanRecoverable` — one **bounded page** of recoverable runs; `recover()`
3864
3899
  calls this and nothing else, so an adapter that implements the interface has
3865
3900
  everything recovery needs
3866
3901
 
3902
+ ### Reading a conversation
3903
+
3904
+ Two shapes of read, and the difference matters as a conversation grows.
3905
+
3906
+ **Bounded.** `loadRun` and `listActiveRuns` read run records and the
3907
+ conversation head. Neither touches history, so neither grows with the length of
3908
+ the conversation. `loadRun` is how you resolve the `runId` that
3909
+ `submit().admission` hands back — it returns the run, the version it was read
3910
+ at, and, once the run is terminal, the answer it produced.
3911
+
3912
+ **Unbounded.** `loadSnapshot` returns every message and every run, and so does
3913
+ every mutation result: the store's reducer validates its invariants against the
3914
+ whole conversation, and the runtime builds the next prompt from the snapshot the
3915
+ mutation returns. Ask for it when you need the conversation — composing a
3916
+ prompt, or compacting — and not to look one run up.
3917
+
3918
+ So the cost of a run scales with the length of its conversation, not with the
3919
+ length of the turn. **Configure compaction** (see below) for anything
3920
+ long-running: it is the only thing in the framework that makes a conversation
3921
+ smaller, and without it a year-old assistant thread is read in full on every
3922
+ turn. This is a known limit, held deliberately rather than by omission — paged
3923
+ history would have to change what a snapshot *is*, and the store's invariants
3924
+ with it, and that is a decision on its own (→ ADR 0112).
3925
+
3867
3926
  Every mutation carries an expected run revision or snapshot version. Input
3868
3927
  assignment additionally carries an idempotency identity. A conflict is a
3869
3928
  control outcome; stale data is never silently overwritten.
@@ -4112,8 +4171,14 @@ outbox.
4112
4171
  `stitchkit/testing` exports `createAgentRaceBarrier`, `createAgentRaceDriver` and
4113
4172
  `createAgentRaceTrace`. Barriers have bounded teardown, traces assert exact partial order, and the
4114
4173
  helpers are exercised from packed Bun and Node consumers. `runAgentStoreConformance` runs duplicate,
4115
- coalescing, collision, stale checkpoint, replay safety, terminal race, compaction and recovery
4116
- invariants against any fresh durable adapter.
4174
+ coalescing, collision, stale checkpoint, replay safety, terminal race, absorption, bounded reads,
4175
+ compaction and recovery invariants against any fresh durable adapter.
4176
+
4177
+ It picks its conversation identities itself and passes them to `createStore(context)` **before the
4178
+ first mutation**, so an adapter whose runtime rows reference an application-owned conversation row
4179
+ can provision those parents; the optional `cleanup(context)` removes them again, and runs once
4180
+ whether the scenario passed or failed. A factory that owns no fixture state ignores the argument and
4181
+ keeps working unchanged.
4117
4182
 
4118
4183
 
4119
4184
  ==============================================================================
@@ -7797,9 +7862,28 @@ Prisma adapter, an in-memory one, anything — run the conformance kit against i
7797
7862
  ```ts
7798
7863
  import { runAgentStoreConformance } from 'stitchkit/testing'
7799
7864
 
7800
- await runAgentStoreConformance({ store: yourStore, conversationId: 'conformance' })
7865
+ await runAgentStoreConformance({ createStore: () => yourStore })
7801
7866
  ```
7802
7867
 
7868
+ The kit picks the conversation identities itself and hands them over **before**
7869
+ the first mutation, so a store whose runtime rows hang off an application-owned
7870
+ conversation row can provision the parents — and take them away again:
7871
+
7872
+ ```ts
7873
+ await runAgentStoreConformance({
7874
+ createStore: (context) => {
7875
+ for (const conversationId of context.conversationIds) createConversationRow(conversationId)
7876
+ return yourStore
7877
+ },
7878
+ cleanup: (context) => {
7879
+ for (const conversationId of context.conversationIds) deleteConversationRow(conversationId)
7880
+ },
7881
+ })
7882
+ ```
7883
+
7884
+ `cleanup` runs exactly once, after the scenario, whether it passed or failed —
7885
+ and a failure in it never replaces the scenario's own.
7886
+
7803
7887
  Green before and red after tells you the contract grew and where, in one run,
7804
7888
  instead of one failure at a time in production. Green both times means the
7805
7889
  upgrade owes you nothing on that surface — which is the usual answer if you
@@ -7844,6 +7928,149 @@ implement `AgentRuntimeStoreDriver` and compose the aggregate with
7844
7928
  runtime): bootstrap the server, one HTTP request, and any feature you rely on
7845
7929
  (Socket.IO connect, an MCP tool call, a multipart upload, …).
7846
7930
 
7931
+ ## Released migration: 0.66.0
7932
+
7933
+ Three changes, and only one of them is a feature. The other two are shapes that
7934
+ would have had to break later: a vocabulary that described one fact with two
7935
+ words, and a store whose only read was the whole conversation.
7936
+
7937
+ The compiler points at most of it. Two things change with no compile error —
7938
+ what a **total** says about its own provenance, and the fact that token counts
7939
+ are now validated where they were not.
7940
+
7941
+ ### An input that joins a run in flight
7942
+
7943
+ #### If you matched exhaustively on `AgentTerminalReason`
7944
+
7945
+ `'absorbed'` is new. A run ends this way when a run already in flight took its
7946
+ input on and answered it; its state is `'superseded'`, and `absorbedIntoRunId`
7947
+ names the run that has the answer.
7948
+
7949
+ ```ts
7950
+ // after
7951
+ switch (run.terminalReason) {
7952
+ // …
7953
+ case 'absorbed':
7954
+ // no assistant message of its own — follow run.absorbedIntoRunId
7955
+ break
7956
+ }
7957
+ ```
7958
+
7959
+ A run record with `terminalReason: 'absorbed'` and no `absorbedIntoRunId` is
7960
+ refused at parse time, and so is `absorbedIntoRunId` on any other reason.
7961
+
7962
+ #### If you render or export runs
7963
+
7964
+ An absorbed run has **no assistant message**. Anything that assumes "every
7965
+ terminal run has one" needs the `absorbed` case — the answer is on the run
7966
+ `absorbedIntoRunId` names, and `store.loadRun` resolves it.
7967
+
7968
+ #### If you want the policy
7969
+
7970
+ ```ts
7971
+ // after
7972
+ runs: { inputPolicy: 'inject' }
7973
+ ```
7974
+
7975
+ It was withdrawn in 0.65.0 and is back with the ordering corrected: the
7976
+ absorption commits with the terminal record, not at the step boundary. Read
7977
+ *An input that joins a run in flight* in the agent-runtime guide before turning
7978
+ it on — in particular what happens when the absorbing run does not complete, and
7979
+ how it composes with `coalescePending`.
7980
+
7981
+ #### If you implement a store driver
7982
+
7983
+ Nothing to do, but know what changed underneath: one terminal commit can now
7984
+ save **two** run records, and they must land in the same transaction. A driver
7985
+ that persists one of the pair fails `runAgentStoreConformance`.
7986
+
7987
+ ### A run read without its conversation
7988
+
7989
+ #### If you implement `AgentRuntimeStore` by hand
7990
+
7991
+ Two members to add. **If your adapter is an `AgentRuntimeStoreDriver` passed to
7992
+ `createAgentRuntimeStore`, there is nothing to do** — the driver already had
7993
+ everything both need.
7994
+
7995
+ ```ts
7996
+ // after
7997
+ loadRun(input: { conversationId: string; runId: string }): Promise<AgentRunView | undefined>
7998
+ listActiveRuns(conversationId: string): Promise<readonly AgentRun[]>
7999
+ ```
8000
+
8001
+ `AgentRunView` is `{ snapshotVersion, run, assistant? }`. `assistant` is the
8002
+ retained terminal answer, so it is present exactly when the run has ended and
8003
+ absent while it is live — a store that returns a live run's draft here lets the
8004
+ terminal path resolve a run that has not finished. `listActiveRuns` orders by
8005
+ `createdAt` then `id`, and must not report a run that has ended.
8006
+ `runAgentStoreConformance` covers both, including the boundary cases.
8007
+
8008
+ #### If you have a store **double** in your tests
8009
+
8010
+ The runtime now reads `loadRun` where it used to read `loadSnapshot`. A double
8011
+ that simulates a condition — a run drifting to another owner, a stale fencing
8012
+ token — must apply it to both reads, or the code under test will not see it.
8013
+ This is not hypothetical: it turned one of this repository's own fixtures into
8014
+ an infinite retry loop, which is how the bounded retry below was found.
8015
+
8016
+ #### Nothing else changes
8017
+
8018
+ `loadSnapshot` behaves exactly as before, and still returns the whole
8019
+ conversation — as does every mutation result. What it costs, and what bounds it,
8020
+ is now written down in *Reading a conversation* in the agent-runtime guide.
8021
+
8022
+ ### One provenance vocabulary, and integral tokens
8023
+
8024
+ #### If you match on `'measured'`
8025
+
8026
+ A **total** now says `computed`, because it is a sum this code performed rather
8027
+ than a count it took — the same rule `AgentUsage` has always applied to a run's
8028
+ spend. Two values change with no compile error:
8029
+
8030
+ ```ts
8031
+ // before
8032
+ if (result.totalTokens.provenance === 'measured') { /* exact */ }
8033
+ // after
8034
+ if (result.totalTokens.provenance === 'computed') { /* exact, and derived */ }
8035
+ ```
8036
+
8037
+ It affects `AgentHistoryBudgetResult.totalTokens` and
8038
+ `ComposedAgentPrompt.instructionTokens`. A per-message or per-section count is
8039
+ still `measured` — only the totals moved. When any part was estimated the total
8040
+ is still `estimated`: an estimate survives arithmetic, and that is the weaker
8041
+ claim, so it wins.
8042
+
8043
+ #### If you produce token counts
8044
+
8045
+ They are validated now, in the places they were not. A fractional count throws
8046
+ where it used to flow into the context-window arithmetic:
8047
+
8048
+ ```ts
8049
+ // refused from this release on
8050
+ estimateTokens: (text) => ({ value: text.length / 4, provenance: 'estimated' })
8051
+ // after
8052
+ estimateTokens: (text) => ({ value: Math.ceil(text.length / 4), provenance: 'estimated' })
8053
+ ```
8054
+
8055
+ The same applies to `ComposeAgentPromptOptions.estimateFallback` and
8056
+ `.historyTokens`, to `AgentPromptBudget.toolSchemas` / `.attachments` /
8057
+ `.providerOverhead`, and to `AgentPromptBudget.contextWindow` /
8058
+ `.reservedOutput`, which must now be non-negative safe integers.
8059
+
8060
+ `AgentUsageValue.value` is `z.int()` too, which matters if you build usage
8061
+ records by hand or in a store double. A figure arriving from a **provider** is
8062
+ not thrown — `normalizeSdkUsage` and the OpenRouter adapter turn a non-integer
8063
+ into `{ provenance: 'unavailable' }`, so a run that already answered is not
8064
+ failed over its own bookkeeping.
8065
+
8066
+ #### The new export
8067
+
8068
+ `AgentProvenanceSchema` / `AgentProvenance` is the whole vocabulary:
8069
+ `provider-reported`, `measured`, `computed`, `estimated`, `unavailable`. Each
8070
+ surface declares its subset, so nothing widened — `AgentUsageValue` still refuses
8071
+ `measured` and `AgentTokenCount` still refuses `provider-reported`. Use it when
8072
+ you want one switch over the question instead of two.
8073
+
7847
8074
  ## Released migration: 0.65.0
7848
8075
 
7849
8076
  The largest migration of the pre-1.0 line, and most of it is the compiler
@@ -10511,10 +10738,41 @@ Canonical protocol exports are `AgentProtocol`, `AgentProtocolConfig`, `AgentRec
10511
10738
  `AgentUsageValueSchema`, `AgentCostValueSchema`, `AgentUsageSchema`, `AgentUsage` and
10512
10739
  `AgentRunMetrics`.
10513
10740
 
10741
+ `AgentProvenanceSchema` / `AgentProvenance` is the entrypoint's single vocabulary for **how a
10742
+ number came to be known**: `provider-reported` (the provider stated it about a request it served),
10743
+ `measured` (this process counted it exactly, before any request was made), `computed` (arithmetic
10744
+ over other values — a sum of exact numbers is still `computed`), `estimated` (a heuristic) and
10745
+ `unavailable` (not known, so `value` is absent, which is a different fact from a reported zero).
10746
+ Each surface declares the subset it can produce: `AgentUsageValueSchema` and `AgentCostValueSchema`
10747
+ describe a request that has already happened and never say `measured`; `AgentTokenCountSchema`
10748
+ describes a prompt being composed and never says `provider-reported`. Every token count is an
10749
+ integer — `AgentUsageValueSchema` and `AgentTokenCountSchema` refuse a fractional `value`, and a
10750
+ provider figure that is not a whole number is normalised to `unavailable` rather than thrown.
10751
+ `AgentCostValueSchema.value` stays fractional, because money is.
10752
+
10753
+ `runs.inputPolicy` takes `queue` (default), `inject`, `interrupt` or `supersede`, or a function of
10754
+ the raw input returning one. `inject` lets a run in flight take a newly arrived input into its prompt
10755
+ at a step boundary and answer it too; the absorption is committed in the **same transaction** as that
10756
+ run's terminal record, via `CommitRunTerminal.absorb`, so a run that ends any other way leaves an
10757
+ ordinary queued successor. The absorbed run ends with `terminalReason: 'absorbed'`, run state
10758
+ `'superseded'`, `absorbedIntoRunId` naming the run that answered it, and **no assistant message of
10759
+ its own**; a submission on its idempotency key resolves through that pointer to the answer
10760
+ (→ ADR 0113).
10761
+
10762
+ `AgentRuntimeStore` has two **bounded** reads beside `loadSnapshot`:
10763
+ `loadRun({ conversationId, runId })` returns an `AgentRunView` — the run, the conversation version it
10764
+ was read at, and the retained answer once the run is terminal — or `undefined`; `listActiveRuns(conversationId)`
10765
+ returns the runs that have not ended, ordered by `createdAt` then `id`. Neither reads history, so
10766
+ neither grows with the length of the conversation, and neither needs anything new from
10767
+ `AgentRuntimeStoreDriver`. `loadSnapshot` and every mutation result still carry the whole
10768
+ conversation — that is what the store's reducer validates against, and what the runtime builds a
10769
+ prompt from (→ ADR 0112).
10770
+
10514
10771
  Store command/result exports are `AcceptInputAndAssignRun`, `AcceptInputAndAssignRunSchema`,
10515
10772
  `AcquireAgentRun`, `AcquireAgentRunSchema`, `CheckpointRunAssistant`,
10516
10773
  `CheckpointRunAssistantSchema`, `CommitRunTerminal`, `CommitRunTerminalSchema`,
10517
- `RequestRunInterrupt`, `RequestRunInterruptSchema`, `runStateForTerminalReason`,
10774
+ `RequestRunInterrupt`, `RequestRunInterruptSchema`, `AgentRunView`, `AgentRunViewSchema`,
10775
+ `runStateForTerminalReason`,
10518
10776
  `ACTIVE_AGENT_RUN_STATES`, `RecoverAgentRun`, `ReplaceCompactedRange`,
10519
10777
  `ReplaceCompactedRangeSchema`, `AgentStoreMutationResult`, `AgentStoreMutationResultSchema`,
10520
10778
  `AgentStoreAppliedSchema`, `AgentStoreConflictSchema`, `AgentStoreDuplicateSchema`,
@@ -10893,7 +11151,8 @@ handler pipeline without opening a TCP port.
10893
11151
  | `createHandlerTestClient` | function | one contract client backed by an in-process `FetchHandler` |
10894
11152
  | `createHandlerTestClients` | function | exact contract-registry batch form |
10895
11153
  | `runAgentStoreConformance` | function | reusable black-box duplicate/coalescing/stale/recovery contract for durable agent-store adapters |
10896
- | `AgentStoreConformanceConfig` | _type_ | factory configuration for running the same contract against a fresh adapter |
11154
+ | `AgentStoreConformanceConfig` | _type_ | `{ createStore(context), cleanup?(context) }` the factory the contract runs against, plus a teardown that runs once whether the scenario passed or failed |
11155
+ | `AgentStoreConformanceContext` | _type_ | `{ conversationIds }` — every conversation the scenario will mutate, handed over **before** the first mutation so an adapter can provision application-owned parent rows; a zero-argument factory stays valid |
10897
11156
  | `runManagedResourceConformance` | function | run the canonical deterministic lifecycle matrix against a fresh consumer-owned `ManagedResource` fixture; resolves `void` or throws `ManagedResourceConformanceError` with a stable scenario ID and normalized trace |
10898
11157
  | `ManagedResourceConformanceScenarioIdSchema` / `ManagedResourceConformanceScenarioId` | schema / _type_ | stable clean, rollback, readiness/completion, activation, shutdown-race and forced-cleanup scenario vocabulary |
10899
11158
  | `ManagedResourceConformanceScenarioSchema` / `ManagedResourceConformanceScenario` | schema / _type_ | discriminated scenario record including whether the controlled resource is required |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stitchkit",
3
- "version": "0.65.1",
3
+ "version": "0.66.1",
4
4
  "description": "Contract-first backend framework — one defineContract() into an HTTP API, MCP tools, AI-agent tools and a typed client. Bun and Node.",
5
5
  "keywords": [
6
6
  "bun",