stitchkit 0.85.1 → 0.86.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.
Files changed (114) hide show
  1. package/CHANGELOG.md +178 -0
  2. package/README.md +3 -0
  3. package/dist/agent-runtime/agent-tool.d.ts +25 -0
  4. package/dist/agent-runtime/agent-tool.d.ts.map +1 -0
  5. package/dist/agent-runtime/child-tools.d.ts +69 -0
  6. package/dist/agent-runtime/child-tools.d.ts.map +1 -0
  7. package/dist/agent-runtime/children.d.ts +113 -0
  8. package/dist/agent-runtime/children.d.ts.map +1 -0
  9. package/dist/agent-runtime/coding-tool-contract.d.ts +29 -0
  10. package/dist/agent-runtime/coding-tool-contract.d.ts.map +1 -1
  11. package/dist/agent-runtime/coding-tool-refusals.d.ts +2 -0
  12. package/dist/agent-runtime/coding-tool-refusals.d.ts.map +1 -1
  13. package/dist/agent-runtime/coding-tool-shell.d.ts.map +1 -1
  14. package/dist/agent-runtime/coding-tools.d.ts +1 -0
  15. package/dist/agent-runtime/coding-tools.d.ts.map +1 -1
  16. package/dist/agent-runtime/control-schema.d.ts +17 -0
  17. package/dist/agent-runtime/control-schema.d.ts.map +1 -1
  18. package/dist/agent-runtime/event-schema.d.ts +34 -0
  19. package/dist/agent-runtime/event-schema.d.ts.map +1 -1
  20. package/dist/agent-runtime/event-search-tools.d.ts +53 -0
  21. package/dist/agent-runtime/event-search-tools.d.ts.map +1 -0
  22. package/dist/agent-runtime/event-search.d.ts +23 -0
  23. package/dist/agent-runtime/event-search.d.ts.map +1 -0
  24. package/dist/agent-runtime/fault-bench.d.ts +45 -0
  25. package/dist/agent-runtime/fault-bench.d.ts.map +1 -0
  26. package/dist/agent-runtime/observability.d.ts +6 -0
  27. package/dist/agent-runtime/observability.d.ts.map +1 -1
  28. package/dist/agent-runtime/projections.d.ts +69 -0
  29. package/dist/agent-runtime/projections.d.ts.map +1 -0
  30. package/dist/agent-runtime/provider-failure.d.ts +5 -1
  31. package/dist/agent-runtime/provider-failure.d.ts.map +1 -1
  32. package/dist/agent-runtime/provider-origin.d.ts +12 -0
  33. package/dist/agent-runtime/provider-origin.d.ts.map +1 -0
  34. package/dist/agent-runtime/retry-policy.d.ts +27 -0
  35. package/dist/agent-runtime/retry-policy.d.ts.map +1 -0
  36. package/dist/agent-runtime/run-execution.d.ts +0 -9
  37. package/dist/agent-runtime/run-execution.d.ts.map +1 -1
  38. package/dist/agent-runtime/run-mutation-queue.d.ts +21 -0
  39. package/dist/agent-runtime/run-mutation-queue.d.ts.map +1 -0
  40. package/dist/agent-runtime/run-operation-lifecycle.d.ts +3 -0
  41. package/dist/agent-runtime/run-operation-lifecycle.d.ts.map +1 -1
  42. package/dist/agent-runtime/runtime.d.ts +15 -0
  43. package/dist/agent-runtime/runtime.d.ts.map +1 -1
  44. package/dist/agent-runtime/sandbox.d.ts +66 -0
  45. package/dist/agent-runtime/sandbox.d.ts.map +1 -0
  46. package/dist/agent-runtime/schedule-tools.d.ts +35 -0
  47. package/dist/agent-runtime/schedule-tools.d.ts.map +1 -0
  48. package/dist/agent-runtime/schedules.d.ts +63 -0
  49. package/dist/agent-runtime/schedules.d.ts.map +1 -0
  50. package/dist/agent-runtime/schemas.d.ts +9 -0
  51. package/dist/agent-runtime/schemas.d.ts.map +1 -1
  52. package/dist/agent-runtime/spill.d.ts +24 -0
  53. package/dist/agent-runtime/spill.d.ts.map +1 -0
  54. package/dist/agent-runtime/sqlite-purge.d.ts.map +1 -1
  55. package/dist/agent-runtime/sqlite.d.ts +26 -0
  56. package/dist/agent-runtime/sqlite.d.ts.map +1 -1
  57. package/dist/agent-runtime/state-slots.d.ts +48 -0
  58. package/dist/agent-runtime/state-slots.d.ts.map +1 -0
  59. package/dist/agent-runtime/state-tools.d.ts +58 -0
  60. package/dist/agent-runtime/state-tools.d.ts.map +1 -0
  61. package/dist/agent-runtime/store-driver.d.ts +13 -0
  62. package/dist/agent-runtime/store-driver.d.ts.map +1 -1
  63. package/dist/agent-runtime/store-events.d.ts +829 -0
  64. package/dist/agent-runtime/store-events.d.ts.map +1 -0
  65. package/dist/agent-runtime/store-migrations/v1-to-v2.d.ts +6 -0
  66. package/dist/agent-runtime/store-migrations/v1-to-v2.d.ts.map +1 -0
  67. package/dist/agent-runtime/store.d.ts +45 -0
  68. package/dist/agent-runtime/store.d.ts.map +1 -1
  69. package/dist/agent-runtime/terminal-commit.d.ts +1 -1
  70. package/dist/agent-runtime-browser.js +5 -3
  71. package/dist/agent-runtime-coding-tools.js +144 -15
  72. package/dist/agent-runtime-harness.js +12 -10
  73. package/dist/agent-runtime-sqlite-bun.d.ts +1 -1
  74. package/dist/agent-runtime-sqlite-bun.d.ts.map +1 -1
  75. package/dist/agent-runtime-sqlite-bun.js +4 -3
  76. package/dist/agent-runtime-sqlite-node.d.ts +1 -1
  77. package/dist/agent-runtime-sqlite-node.d.ts.map +1 -1
  78. package/dist/agent-runtime-sqlite-node.js +4 -3
  79. package/dist/agent-runtime-testing.d.ts +3 -0
  80. package/dist/agent-runtime-testing.d.ts.map +1 -0
  81. package/dist/agent-runtime-testing.js +156 -0
  82. package/dist/agent-runtime.d.ts +16 -2
  83. package/dist/agent-runtime.d.ts.map +1 -1
  84. package/dist/agent-runtime.js +1591 -154
  85. package/dist/application.js +14 -14
  86. package/dist/cli.js +6 -6
  87. package/dist/{index-fwbkp2jn.js → index-0vfdh685.js} +2 -2
  88. package/dist/{index-5z8tezpx.js → index-0ydchz76.js} +3 -3
  89. package/dist/{index-3ds42w1w.js → index-1szetq6f.js} +33 -4
  90. package/dist/{index-jpp7jd1p.js → index-33xckd7h.js} +898 -425
  91. package/dist/{index-27487ay5.js → index-9hw9eq48.js} +4 -4
  92. package/dist/{index-66nxrgy0.js → index-b7qwhbzq.js} +428 -46
  93. package/dist/index-cnyk6te3.js +77 -0
  94. package/dist/index-gskm1k5a.js +50 -0
  95. package/dist/{index-fq492hg0.js → index-hber83mk.js} +254 -157
  96. package/dist/{index-4hk633vz.js → index-hkm6wysp.js} +9 -2
  97. package/dist/{index-dx9xehwt.js → index-kc6h6hg0.js} +1 -1
  98. package/dist/{index-x15ss2dx.js → index-p1b1y93x.js} +3 -0
  99. package/dist/{index-mgtxfe6b.js → index-r159gjwy.js} +8 -1
  100. package/dist/{index-s4ckmrac.js → index-rcgsnrr6.js} +3 -3
  101. package/dist/index-vfgb58nf.js +252 -0
  102. package/dist/{index-dggwnnjv.js → index-wn9cb82y.js} +1 -1
  103. package/dist/{index-ff0kcqvp.js → index-z2452tsw.js} +3 -3
  104. package/dist/testing/agent-store-conformance.d.ts.map +1 -1
  105. package/dist/testing.js +54 -80
  106. package/dist/tool-invoker.js +4 -4
  107. package/dist/tools/internal/surface-projector.d.ts.map +1 -1
  108. package/dist/tools/manifest.d.ts +16 -0
  109. package/dist/tools/manifest.d.ts.map +1 -1
  110. package/dist/tools.d.ts +1 -1
  111. package/dist/tools.d.ts.map +1 -1
  112. package/dist/tools.js +10 -8
  113. package/llms-full.txt +321 -13
  114. package/package.json +6 -1
package/dist/tools.js CHANGED
@@ -19,8 +19,9 @@ import {
19
19
  } from "./index-xbppf54a.js";
20
20
  import {
21
21
  buildToolManifest,
22
+ describeToolCatalog,
22
23
  mountAgent
23
- } from "./index-3ds42w1w.js";
24
+ } from "./index-1szetq6f.js";
24
25
  import"./index-3xnq72rz.js";
25
26
  import {
26
27
  argumentsDigest
@@ -36,7 +37,7 @@ import {
36
37
  } from "./index-4fpa9dy2.js";
37
38
  import {
38
39
  createToolInvoker
39
- } from "./index-5z8tezpx.js";
40
+ } from "./index-0ydchz76.js";
40
41
  import {
41
42
  WaitTimeoutError,
42
43
  createCli,
@@ -45,26 +46,26 @@ import {
45
46
  fetchPinnedDocument,
46
47
  readCapped,
47
48
  runWaitOperation
48
- } from "./index-27487ay5.js";
49
+ } from "./index-9hw9eq48.js";
49
50
  import"./index-sbdmyz75.js";
50
51
  import {
51
52
  collectToolSurface
52
- } from "./index-s4ckmrac.js";
53
+ } from "./index-rcgsnrr6.js";
53
54
  import {
54
55
  createRuntimeToolFactory,
55
56
  defineRuntimeTool
56
- } from "./index-dx9xehwt.js";
57
+ } from "./index-kc6h6hg0.js";
57
58
  import {
58
59
  collectTools,
59
60
  createToolRunner,
60
61
  formatToolError
61
- } from "./index-fwbkp2jn.js";
62
+ } from "./index-0vfdh685.js";
62
63
  import {
63
64
  ToolExecutionControlError,
64
65
  executeToolMethod,
65
66
  isToolExecutionControlError,
66
67
  toolResultFromError
67
- } from "./index-dggwnnjv.js";
68
+ } from "./index-wn9cb82y.js";
68
69
  import {
69
70
  getRequestContext,
70
71
  getTraceId,
@@ -81,7 +82,7 @@ import {
81
82
  prepareProjectedMcpTools,
82
83
  presentationMetadata,
83
84
  validateMcpRoundPolicy
84
- } from "./index-mgtxfe6b.js";
85
+ } from "./index-r159gjwy.js";
85
86
  import"./index-cby4ar3v.js";
86
87
  import {
87
88
  coerceJsonArgs
@@ -2641,6 +2642,7 @@ export {
2641
2642
  flattenToolJsonSchema,
2642
2643
  findUntypedProperties,
2643
2644
  findNonPortableFormats,
2645
+ describeToolCatalog,
2644
2646
  defineWaitTool,
2645
2647
  defineViewFileTool,
2646
2648
  defineUploadTool,
package/llms-full.txt CHANGED
@@ -63,11 +63,12 @@ own, recorded as an ADR.
63
63
  | `stitchkit/tracking/server` | server (Bun or Node) | evolving | the decisions a tracking backend makes — dispositions, visit lease over an application-owned store, active intervals, presence; no database |
64
64
  | `stitchkit/release` | browser **and** server | evolving | a page follows the release it was built for — `createReleaseMarker` on the server, `createReleaseWatcher` in the browser, the `X-Build-Id` header and a socket event between them |
65
65
  | `stitchkit/geo` | server (Bun or Node) | evolving | managed GeoIP reader generations, last-known-good reload and the optional MaxMind adapter |
66
- | `stitchkit/observability` | server | stable<br>_redefined in 1 of the 30 minors since 0.56.2, most recently 0.83.0_ | request/tool event projections — `createObservability`, trace context, sanitisation |
66
+ | `stitchkit/observability` | server | stable<br>_redefined in 1 of the 31 minors since 0.56.2, most recently 0.83.0_ | request/tool event projections — `createObservability`, trace context, sanitisation |
67
67
  | `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 |
68
68
  | `stitchkit/declaration` | browser + build and deployment tooling (Bun or Node) | evolving | `ProjectDeclarationSchema` — the one machine-readable statement a repository makes about itself |
69
69
  | `stitchkit/react` | browser + server rendering | stable | `createCursorQuery`, `createCacheBridge`, QueryClient and `ApiError` retry policy |
70
- | `stitchkit/agent-runtime` | server | evolving<br>_redefined in 16 of the 30 minors since 0.56.2, most recently 0.85.0_ | optional durable conversation/run loop, history, models, prompts, fencing and events |
70
+ | `stitchkit/agent-runtime` | server | evolving<br>_redefined in 17 of the 31 minors since 0.56.2, most recently 0.86.0_ | optional durable conversation/run loop, history, models, prompts, fencing and events |
71
+ | `stitchkit/agent-runtime/testing` | tests on Bun or Node | evolving | credential-free replay, scripted provider faults and deterministic race controls |
71
72
  | `stitchkit/agent-runtime/harness` | server | evolving | resource-aware process-local facade over the canonical Agent runtime; supervision stays outside |
72
73
  | `stitchkit/agent-runtime/coding-tools` | server (Bun or Node) | evolving | bounded host-authorized direct file and shell tools; a root boundary, not an OS sandbox |
73
74
  | `stitchkit/agent-runtime/openrouter` | server | evolving | isolated OpenRouter language-model adapter |
@@ -75,7 +76,7 @@ own, recorded as an ADR.
75
76
  | `stitchkit/agent-runtime/sqlite/bun` | server (Bun) | evolving | durable built-in SQLite store for the agent runtime |
76
77
  | `stitchkit/agent-runtime/sqlite/node` | server (Node ≥ 22.5) | evolving | durable built-in SQLite store for the agent runtime |
77
78
  | `stitchkit-tui` | terminal (Bun) | evolving | optional official OpenTUI host over a caller-composed headless runtime |
78
- | `stitchkit/application` | browser + server | evolving<br>_redefined in 7 of the 30 minors since 0.56.2, most recently 0.83.0_ | managed resource graph, readiness, admission, schedules, subtree restart and bounded shutdown |
79
+ | `stitchkit/application` | browser + server | evolving<br>_redefined in 7 of the 31 minors since 0.56.2, most recently 0.83.0_ | managed resource graph, readiness, admission, schedules, subtree restart and bounded shutdown |
79
80
  | `stitchkit/application/grammy` | server | evolving | isolated grammY polling and webhook lifecycle adapters |
80
81
  | `stitchkit/application/opentelemetry` | server | evolving | maps application snapshots onto an injected OpenTelemetry `Meter` |
81
82
  | `stitchkit/application/schemas` | browser + server | evolving | the application's snapshot, health and shutdown schemas alone, without the kernel |
@@ -4884,7 +4885,7 @@ const sqlite = createNodeSqliteAgentRuntimeStore({ filename: './agent-runtime.sq
4884
4885
  ```
4885
4886
 
4886
4887
  Initialization creates only `stitchkit_agent_runtime_*` tables and records
4887
- schema version 1 in `stitchkit_agent_runtime_meta`; it does not use
4888
+ schema version 2 in `stitchkit_agent_runtime_meta`; it does not use
4888
4889
  `PRAGMA user_version` or mutate application tables. An unknown schema version or
4889
4890
  unversioned partial Stitchkit schema is refused. The connection is owned by the
4890
4891
  returned handle and closes only after accepted operations drain.
@@ -4908,6 +4909,111 @@ atomically or replace an application outbox. If a product row must commit with
4908
4909
  an agent transition, implement `AgentRuntimeStoreDriver` over the application's
4909
4910
  own transaction boundary instead.
4910
4911
 
4912
+ Opening a version 1 store migrates it in one transaction, forward only — back
4913
+ the file up first, a 0.85.x package refuses a migrated file. Existing
4914
+ normalized state becomes one `runtime/baseline` event per conversation, dated
4915
+ when the migration ran and carrying `asOf` for the last message it describes;
4916
+ search and projections address that pre-migration history as one snapshot at
4917
+ `seq 1`. New transitions continue the monotonic conversation sequence. Version
4918
+ 2 requires SQLite FTS5 because event search is an advertised capability, so a
4919
+ build without FTS5 is a startup error (`requires FTS5 support`) rather than an
4920
+ empty search result; check with
4921
+ `SELECT sqlite_compileoption_used('ENABLE_FTS5')`.
4922
+
4923
+ The handle returned by `createBunSqliteAgentRuntimeStore` /
4924
+ `createNodeSqliteAgentRuntimeStore` is `{ store, conversations, database,
4925
+ transaction, close }`. `database` is the shared connection and `transaction`
4926
+ is one write transaction in the store's own serialization: the SQLite
4927
+ companions — `createSqliteAgentProjectionStore`, `createSqliteAgentSpillStore`,
4928
+ `createSqliteAgentChildManager`, `createAgentScheduleService` — take `{ sqlite }`
4929
+ and write their rows and events through it, so a row and its event land
4930
+ together or not at all.
4931
+
4932
+ ### Retried provider streams
4933
+
4934
+ With `loop.retry` set, a provider stream that fails before any tool call in the
4935
+ attempt is retried at the step boundary. Subscribers see `attempt-reset` for the
4936
+ run before the next attempt's first delta and drop what the failed attempt
4937
+ streamed; the durable draft is checkpointed after that output is discarded; an
4938
+ input injected into the failed attempt is taken again by the retry; and the
4939
+ failed attempt's reported usage stays in the run's spend. Transient events —
4940
+ deltas, reasoning, `attempt-reset` — are numbered from 1 per run, counting only
4941
+ what was published, so a cursor sees no gap on an ordinary stream.
4942
+
4943
+ ### Event ledger, projections and durable capabilities
4944
+
4945
+ `AgentRuntimeStore` exposes bounded `readEvents`, declared `appendEvent`,
4946
+ canonical `exportConversation` and empty-target `importConversation`. Runtime
4947
+ transitions and exact provider requests enter the same append-only ledger; the
4948
+ normalized head/run/message tables remain the fast operational projection.
4949
+
4950
+ Use `defineAgentProjection` with `createSqliteAgentProjectionStore` for a
4951
+ deterministic versioned fold. Every value reports `uptoSeq`, so a caller can
4952
+ distinguish current data from a projection that still has events to consume.
4953
+ Changing the projection version folds from sequence one.
4954
+
4955
+ The built-ins are `agentSummaryProjection`, `agentUsageProjection` and
4956
+ `agentOutlineProjection`; focused card, state-slot and schedule projections are
4957
+ also available. `list(projection)` reads all materialized conversation rows in
4958
+ one SQLite query instead of reopening their event logs.
4959
+
4960
+ Durable state is declared once and injected on every provider request:
4961
+
4962
+ ```ts
4963
+ const goal = defineStateSlot({
4964
+ name: 'goal',
4965
+ schema: z.object({ objective: z.string(), status: z.string() }),
4966
+ })
4967
+
4968
+ const slots = createAgentStateSlotStore({ store: sqlite.store, definitions: [goal] })
4969
+ await slots.set({
4970
+ conversationId,
4971
+ name: 'goal',
4972
+ value: { objective: 'finish migration', status: 'active' },
4973
+ actor: 'human',
4974
+ })
4975
+
4976
+ const runtime = createAgentRuntime({ ...config, store: sqlite.store, stateSlots: [goal] })
4977
+ ```
4978
+
4979
+ `createAgentStateTools` binds `create_goal`, `update_goal`, `get_goal` and
4980
+ `todo_write` to one conversation. Human changes call the same slot store with
4981
+ `actor: 'human'`; they remain structured `state/set` facts rather than forged
4982
+ chat messages.
4983
+
4984
+ `createSqliteAgentSpillStore` persists oversized output separately and records
4985
+ its locator, hash and lifecycle in the ledger. `read_output` and
4986
+ `search_output` re-run both locator authorization and the originating tool
4987
+ authorization before reading bytes. `createSqliteAgentEventSearch` returns the
4988
+ exact conversation and event sequence; cross-conversation results are denied
4989
+ unless `authorizeConversation` approves each target.
4990
+ `createAgentEventSearchTools` supplies `session_search`, `session_trace` and
4991
+ `session_event` over the same bounded APIs.
4992
+
4993
+ For credential-free failure tests, import `createFaultProviderServer` and
4994
+ `createReplayAgentProvider` from `stitchkit/agent-runtime/testing`. Runtime
4995
+ `loop.retry` applies an explicit `AgentRetryPolicy`: each decision is recorded
4996
+ as `retry/scheduled`, each new attempt as `retry/started`, and an attempt that
4997
+ has invoked a tool is never automatically replayed.
4998
+
4999
+ `createAgentScheduleService` persists `at`, `after` and `every` input. Repeating
5000
+ schedules require an explicit IANA time zone. Dispatch uses a stable
5001
+ `schedule:<id>:<occurrence>` idempotency key, and restart lateness is recorded.
5002
+ `createAgentScheduleTools` exposes the exact `schedule_after`, `schedule_at`,
5003
+ `schedule_every`, `schedule_list` and `schedule_cancel` surface.
5004
+
5005
+ `createSqliteAgentChildManager` seeds a child from the parent's ledger through
5006
+ an exact sequence, stores the graph, clamps requested limits to a durable parent
5007
+ remainder and stops budget overruns at the next step boundary as
5008
+ `policy_stop`. That enforcement runs inside the child's own runtime: the host that spawns it gives the child
5009
+ `loop.stopPolicies: [agentChildBudgetStopPolicy({ manager, childConversationId })]`, which
5010
+ calls `recordStepUsage` at every step boundary; `recordStepUsage` alone measures and decides,
5011
+ and reports `enforced: false` when the deciding process holds no handle to stop. Given to `createAgentRuntime` as `children`, the manager stops the parent's children after the parent's terminal is durable — interrupted, cancelled, timed out or shut down; a successful, policy-stopped, superseded or failed parent leaves them to the conversation (ADR 0175 carries the table); without `children` nothing cascades; an unreachable child is recorded
5012
+ as `lost`, not misreported as a provider failure.
5013
+ `createAgentChildTools` adds `subagent`, `subagent_fork`, `list_agents`,
5014
+ `send_message` and `interrupt_agent`; final output stays behind its bounded
5015
+ result locator.
5016
+
4911
5017
  ## Durable order
4912
5018
 
4913
5019
  `acceptInputAndAssignRun` is one atomic operation. It is followed by ownership
@@ -5261,6 +5367,12 @@ transaction. Drivers without this guarantee must leave the capability absent. Se
5261
5367
 
5262
5368
  ## Events and reconnect
5263
5369
 
5370
+ A subscriber that switches over `event.type` handles one transient event
5371
+ beyond deltas and reasoning: `attempt-reset`, published when `loop.retry`
5372
+ starts a new attempt, meaning everything this run streamed before it is
5373
+ withdrawn. `reduceAgentControlEvent` does that; a hand-written reducer must,
5374
+ or it keeps the failed attempt's partial text on screen.
5375
+
5264
5376
  `publish` receives event classes with different guarantees:
5265
5377
 
5266
5378
  - `admission` follows a successful acceptance CAS and carries the same complete
@@ -5382,8 +5494,12 @@ prepareStep: (step) => {
5382
5494
 
5383
5495
  That deliberate refusal ends the run as `context_overflow` on the durable
5384
5496
  record, delivery terminal and operator event. Stitchkit does not inspect error
5385
- messages: every other `prepareStep` or provider error remains
5386
- `provider_failure`, and operator-only observability retains its original cause.
5497
+ messages it recognises failures by identity, not by text. A store refusing an
5498
+ owned mutation ends the run `storage_conflict`; `protocol.acceptTerminal`
5499
+ refusing a finished message ends it `output_rejected`; a check the SDK runs on
5500
+ what this runtime handed it ends it `runtime_failure`. Every error the runtime
5501
+ cannot identify as its own remains `provider_failure`, and operator-only
5502
+ observability retains its original cause in all of them.
5387
5503
 
5388
5504
  Completion validity belongs to the protocol and is checked before the terminal
5389
5505
  CAS. Protocols that require a visible answer opt in explicitly:
@@ -10096,6 +10212,38 @@ sink never escapes into application code.
10096
10212
  stitchkit's own test suite runs on `bun:test`. The contract makes most of an
10097
10213
  API testable without a live socket.
10098
10214
 
10215
+ ### Agent runtime faults and replay
10216
+
10217
+ `stitchkit/agent-runtime/testing` is a credential-free test entrypoint for Bun
10218
+ and Node. It provides a local OpenAI-compatible SSE server with a deterministic
10219
+ fault plan, a replay provider for model fixtures, and named race barriers for
10220
+ event-order assertions:
10221
+
10222
+ ```ts
10223
+ import {
10224
+ createFaultProviderServer,
10225
+ createReplayAgentProvider,
10226
+ } from 'stitchkit/agent-runtime/testing'
10227
+
10228
+ const server = await createFaultProviderServer({
10229
+ scenario: [
10230
+ { kind: 'stream-cut', afterBytes: 50 },
10231
+ { kind: 'pass', text: 'recovered' },
10232
+ ],
10233
+ })
10234
+
10235
+ const provider = createReplayAgentProvider({
10236
+ attempts: { primary: [firstModel, recoveredModel] },
10237
+ })
10238
+ ```
10239
+
10240
+ The fault vocabulary also covers connection refusal, timeout before the first
10241
+ byte, HTTP errors, malformed JSON, slow streams and missing usage. Configure
10242
+ runtime retry explicitly through `loop.retry`. A retry is recorded at the
10243
+ durable provider-step boundary; once a tool has executed, the runtime will not
10244
+ replay that attempt automatically. Always close the local server in test
10245
+ teardown with `await server.close()`.
10246
+
10099
10247
  ### Test generated clients in process
10100
10248
 
10101
10249
  `createHandlerTestClient` runs the real generated client against the real Fetch
@@ -11048,6 +11196,125 @@ of the range if you want a different one.
11048
11196
  So upgrading is: read the `### ⚠️ Breaking changes` of every version *above* your
11049
11197
  current one *up to* your target, and apply each snippet.
11050
11198
 
11199
+ ## Released migration: 0.86.0
11200
+
11201
+ Only if you branch on `AgentTerminalReason` or show it to a person. Three
11202
+ failures that used to arrive as `provider_failure` now arrive as themselves:
11203
+
11204
+ ```ts
11205
+ // before
11206
+ if (run.terminalReason === 'provider_failure') showOutage()
11207
+
11208
+ // after
11209
+ switch (run.terminalReason) {
11210
+ case 'provider_failure':
11211
+ showOutage()
11212
+ break
11213
+ case 'storage_conflict':
11214
+ // Another writer took this run's revision, or the store refused the write.
11215
+ retryOrReport()
11216
+ break
11217
+ case 'output_rejected':
11218
+ // Your own `protocol.acceptTerminal` refused the finished message.
11219
+ reportRejectedAnswer()
11220
+ break
11221
+ case 'runtime_failure':
11222
+ // The runtime, or a check the SDK ran on what it was handed, failed
11223
+ // before the provider was reached.
11224
+ reportInternal()
11225
+ break
11226
+ }
11227
+ ```
11228
+
11229
+ A run that never reached the provider can no longer report `provider_failure`,
11230
+ so an alert keyed on that value stops firing for causes that were never the
11231
+ provider's.
11232
+
11233
+ If you implement `AgentRuntimeStore` directly, add the event-ledger surface:
11234
+
11235
+ ```ts
11236
+ const store: AgentRuntimeStore = {
11237
+ // existing normalized operations
11238
+ appendEvent,
11239
+ readEvents,
11240
+ exportConversation,
11241
+ importConversation,
11242
+ }
11243
+ ```
11244
+
11245
+ If you implement an `AgentRuntimeStoreDriver` (Prisma, Postgres, any external
11246
+ database), the ledger is yours to keep: `events` is a required member, and it
11247
+ needs a table.
11248
+
11249
+ ```ts
11250
+ // before
11251
+ const driver: AgentRuntimeStoreDriver<Tx> = { transaction, head, runs, admissions, history, scanRecoverable }
11252
+
11253
+ // after
11254
+ const driver: AgentRuntimeStoreDriver<Tx> = {
11255
+ transaction, head, runs, admissions, history, scanRecoverable,
11256
+ events: {
11257
+ // One row per event; `seq` is per conversation, starts at 1, and is
11258
+ // assigned inside the caller's transaction so concurrent appends cannot
11259
+ // share or skip a number.
11260
+ append: async (tx, draft) => {
11261
+ // Two transactions that both read max(seq) and both insert max + 1
11262
+ // collide on the primary key; under SERIALIZABLE the snapshot predates
11263
+ // any lock you take here. Treat a unique violation on this table as a
11264
+ // serialization conflict and re-run the whole transaction — see
11265
+ // `runTransaction` in examples/agent-store-prisma/adapter.ts.
11266
+ const seq = (await tx.event.aggregate({ _max: { seq: true }, where: { conversationId: draft.conversationId } }))._max.seq ?? 0
11267
+ await tx.event.create({ data: { ...draft, seq: seq + 1, payload: JSON.stringify(draft.payload) } })
11268
+ return { ...draft, seq: seq + 1 }
11269
+ },
11270
+ // Ordered by `seq`, bounded by `fromSeq`/`toSeq`/`limit`; `nextSeq` when
11271
+ // more remain.
11272
+ list: async (tx, input) => { /* see examples/agent-store-prisma/adapter.ts */ },
11273
+ },
11274
+ }
11275
+ ```
11276
+
11277
+ The table carries `eventId` (unique), `conversationId`, `seq`, `schemaVersion`,
11278
+ `kind`, `occurredAt`, `ignorable` and `payload`. `runAgentStoreConformance`
11279
+ from `stitchkit/testing` now exercises it — contiguous `seq` under twenty
11280
+ concurrent appends, bounded reads, the `ignorable` flag, a byte-stable export
11281
+ — so run it against your driver before deploying. Expect one more insert per
11282
+ run operation (`runtime/transition`) and one per model step
11283
+ (`provider/request`) on the hot path; there is no opt-out.
11284
+
11285
+ If you operate a built-in SQLite store file:
11286
+
11287
+ 1. Back the file up. The first open by 0.86.0 migrates it to schema 2 in one
11288
+ transaction and there is no way back: a 0.85.x package refuses a migrated
11289
+ file with `Unsupported Stitchkit agent-runtime SQLite schema version 2`.
11290
+ 2. Check the build for FTS5 before deploying:
11291
+
11292
+ ```sql
11293
+ SELECT sqlite_compileoption_used('ENABLE_FTS5');
11294
+ ```
11295
+
11296
+ A build without it is refused at open with `requires FTS5 support`. On the
11297
+ machine this was verified, Bun 1.3 `bun:sqlite` and Node 24.18 `node:sqlite`
11298
+ both carry it; verify your own build rather than assuming — the table of
11299
+ supported runtimes says Node ≥ 22.5, and FTS5 there is not verified here.
11300
+ 3. Know what the migration wrote. Each existing conversation becomes one
11301
+ `runtime/baseline` event at `seq 1`, dated when the migration ran, with
11302
+ `asOf` inside the payload naming the last message it describes. Event
11303
+ search and projections address that conversation's pre-migration history as
11304
+ one snapshot at `seq 1`; event-level precision begins with the first event
11305
+ after the migration.
11306
+
11307
+ If you subscribe to `AgentRuntimeEvent` and switch over `event.type`
11308
+ exhaustively, add the transient `attempt-reset` case — drop the run's
11309
+ transient text — or the reducer stops compiling; a reducer that ignores it
11310
+ keeps a failed attempt's partial text on screen.
11311
+
11312
+ New in this release, not a migration: child runs cascade only when the manager
11313
+ is given to the runtime —
11314
+ `createAgentRuntime({ ...config, children: createSqliteAgentChildManager({ sqlite, spawn }) })`
11315
+ — and the SQLite companions take the store handle (`{ sqlite }`), whose
11316
+ `database` and `transaction` they share.
11317
+
11051
11318
  ## Released migration: 0.85.0
11052
11319
 
11053
11320
  Only if you implement `AgentRuntimeStore` directly. Add the new durable
@@ -15144,7 +15411,8 @@ Server-only optional application runtime. See the
15144
15411
  | `AgentRunQueuePrioritySchema` | schema | durable opt-in priority for queued `interrupt-next` runs |
15145
15412
  | `AgentRuntimeStore` | _type_ | aggregate CAS transaction boundary for message, run and compaction mutations |
15146
15413
  | `createAgentRuntimeStore` | function | build the aggregate store from one coherent transaction driver; framework owns every state transition |
15147
- | `AgentRuntimeStoreDriver` | _type_ | ORM-neutral transaction over a bounded head, normalized runs/admissions, product history and indexed run recovery; optional `{ access: 'read' }` selects a coherent read transaction while absent options remain write-safe |
15414
+ | `AgentRuntimeStoreDriver` | _type_ | ORM-neutral transaction over a bounded head, normalized runs/admissions, product history, a **required** `events: { append, list }` ledger table, an optional `archive: { export, import }` for driver-owned durable payloads, and indexed run recovery; optional `{ access: 'read' }` selects a coherent read transaction while absent options remain write-safe |
15415
+ | `recordAgentRetryDecision` / `AgentRetryPolicy` | function / _type_ | `loop.retry` policy and the ledger record of a retry decision: explicit retryability and backoff at a durable provider-step boundary |
15148
15416
  | `AgentRuntimeHeadSchema` | schema | constant-size conversation identity plus monotonic runtime version |
15149
15417
  | `AgentStoredRunSchema` | schema | canonical normalized run with an optional retained terminal assistant |
15150
15418
  | `AgentAdmissionReceiptSchema` | schema | durable idempotency receipt with canonical input and assigned run/assistant identities |
@@ -15196,6 +15464,29 @@ Server-only optional application runtime. See the
15196
15464
  | `RecordRunOperationSchema` / `RecordRunOperation` | schema / _type_ | owner/fencing/revision-checked mutation of `AgentRun.lastOperation` |
15197
15465
  | `createAgentObservability` | function | separate agent-run sink over the shared bounded observability lifecycle |
15198
15466
 
15467
+ ### Durable capability layer
15468
+
15469
+ | Export | Kind | Summary |
15470
+ |--------|------|---------|
15471
+ | `AgentConversationArchiveSchema` / `AgentConversationArchive` / `encodeAgentConversationArchive` / `decodeAgentConversationArchive` / `canonicalAgentJson` | schema / _type_ / functions | canonical validated conversation archive with exact ledger events, recovery projection and durable spill payloads |
15472
+ | `AgentStoreEventEnvelopeSchema` / `AgentStoreEventEnvelope` / `AgentStoreEventKindSchema` / `AgentStoreEventKind` / `AgentStoreEventPageSchema` / `AgentStoreEventPage` | schema / _type_ | append-only event envelope, closed current vocabulary and bounded page |
15473
+ | `AppendAgentStoreEventSchema` / `AppendAgentStoreEvent` / `ReadAgentStoreEventsSchema` / `ReadAgentStoreEvents` | schema / _type_ | required append and bounded-read store contracts |
15474
+ | `AgentStoreTransitionSchema` / `AgentStoreTransition` / `AgentStoreEventDraft` / `AgentStoreEventDecodeAccepted` / `AgentStoreEventDecodeIgnored` / `AgentStoreEventDecodeResult` / `decodeAgentStoreEvent` | schema / _types_ / function | normalized runtime mutations, append drafts and strict current/ignorable future-event decoding outcomes |
15475
+ | `defineAgentProjection` / `AgentProjectionDefinition` / `AgentProjectionValue` / `createAgentProjectionRegistry` / `createSqliteAgentProjectionStore` | functions / _type_ | deterministic folds with persisted version and honest `uptoSeq` checkpoints |
15476
+ | `agentSummaryProjection` / `agentUsageProjection` / `agentOutlineProjection` | constants | built-in list summary, provenance-carrying usage and request outline projections |
15477
+ | `agentConversationCardProjection` / `agentStateSlotsProjection` / `agentScheduleSummaryProjection` | constants | focused card, durable-state and schedule lifecycle projections |
15478
+ | `defineStateSlot` / `AgentStateSlotDefinition` / `AgentStateSlotStore` / `AgentStateSlotValue` / `AnyAgentStateSlot` / `createAgentStateSlotStore` / `renderAgentStateSlots` | functions / _types_ | typed durable state written as ledger events and injected on every provider request |
15479
+ | `agentGoalStateSlot` / `agentTodoStateSlot` / `createAgentStateTools` | constants / function | built-in goal/todo state and bound `goal_*` / `todo_write` Agent tools |
15480
+ | `AgentSandboxGradeSchema` / `AgentSandboxGrade` / `AgentSandboxRestrictionSchema` / `AgentSandboxRestriction` / `AgentProcessSandbox` | schema / _type_ | host-provided process sandbox capability and explicit restriction vocabulary |
15481
+ | `probeAgentProcessSandbox` / `missingSandboxRestrictions` / `recordAgentSandboxProbe` | functions | process-cached probe, fail-closed required-gap calculation and durable probe record |
15482
+ | `AgentEventSearchResultSchema` / `AgentEventSearchResult` / `createSqliteAgentEventSearch` / `createAgentEventSearchTools` | schema / _type_ / functions | authorized FTS5 search with exact event addresses and `session_*` tools |
15483
+ | `createSqliteAgentSpillStore` | function | durable content-address-checked artifact storage, bounded read/search, retention facts and archive participation |
15484
+ | `AgentScheduleSchema` / `AgentSchedule` / `AgentScheduleService` / `createAgentScheduleService` / `createAgentScheduleTools` | schema / _types_ / functions | durable `at`/`after`/timezone-explicit `every`, stable dispatch identity and Agent tools |
15485
+ | `AgentChildBudgetSchema` / `AgentChildBudget` / `AgentChildStateSchema` / `AgentChildState` / `AgentChildRecordSchema` / `AgentChildRecord` | schema / _type_ | durable child graph, bounded seed and measured budget state |
15486
+ | `AgentChildHandle` / `AgentChildManager` / `createSqliteAgentChildManager` / `createAgentChildTools` / `agentChildBudgetStopPolicy` | _type_ / functions | host execution port, child lifecycle, cascade (given to `createAgentRuntime` as `children`), messaging, Agent tools, and the child runtime's own budget stop policy — `recordStepUsage` at every step boundary, `policy_stop` as `child-budget` when spent |
15487
+ | `AgentToolDefinition` | _type_ | peer-neutral shape returned by the bound agent-only state, search, schedule and child tool factories |
15488
+ | `AgentProviderStreamCutError` | class | explicit retryable provider stream truncation evidence |
15489
+
15199
15490
  ### Complete runtime inventory
15200
15491
 
15201
15492
  The entrypoint deliberately exports the schemas beside their inferred types so persistence and
@@ -15322,7 +15613,7 @@ Model exports are `AgentLanguageModelProvider`, `AgentModelCapability`,
15322
15613
  provider and required capabilities without constructing the model; runtime `models.preflight`
15323
15614
  runs before durable admission.
15324
15615
 
15325
- Delivery exports are `AgentAdmissionEventSchema`, `AgentCheckpointEventSchema`,
15616
+ Delivery exports are `AgentAdmissionEventSchema`, `AgentAttemptResetEventSchema`, `AgentCheckpointEventSchema`,
15326
15617
  `AgentRunStateEventSchema`, `AgentRunOperationEventSchema`, `AgentTerminalEventSchema`,
15327
15618
  `AgentTransientDeltaEventSchema`,
15328
15619
  `AgentReasoningStartEventSchema`, `AgentReasoningDeltaEventSchema`,
@@ -15340,6 +15631,20 @@ Managed effects and operator telemetry additionally export `AgentToolFenceConfig
15340
15631
  may accompany checkpoint/terminal writes and tool context; internal causes are redacted unless an
15341
15632
  operator-only observability sink explicitly opts in.
15342
15633
 
15634
+ ## `stitchkit/agent-runtime/testing`
15635
+
15636
+ Credential-free provider and concurrency fixtures for Bun and Node tests.
15637
+
15638
+ | Export | Kind | Summary |
15639
+ |--------|------|---------|
15640
+ | `createFaultProviderServer` | function | start an OpenAI-compatible local SSE endpoint with deterministic pass, connection-refused, timeout, stream-cut, HTTP, malformed JSON, slow-stream and missing-usage steps |
15641
+ | `AgentFaultStepSchema` / `AgentFaultStep` | schema / _type_ | strict fault-plan step vocabulary |
15642
+ | `defineAgentFaultPlan` | function | validate a non-empty deterministic fault sequence |
15643
+ | `createReplayAgentProvider` | function | serve a declared sequence of credential-free language-model fixtures per model ID |
15644
+ | `createAgentRaceBarrier` / `AgentRaceBarrier` | function / _type_ | named bounded deterministic concurrency barrier |
15645
+ | `createAgentRaceTrace` / `AgentRaceTrace` / `AgentRaceTraceEntry` | function / _type_ | record and assert exact event order without wall-clock guesses |
15646
+ | `createAgentRaceDriver` / `AgentRaceDriver` | function / _type_ | collect named barriers and release their teardown together |
15647
+
15343
15648
  ## `stitchkit/agent-runtime/harness`
15344
15649
 
15345
15650
  Server-only evolving facade over the canonical Agent runtime. It requires the optional `ai` peer
@@ -15411,7 +15716,8 @@ not path filtering, to constrain its filesystem access. → ADR 0172.
15411
15716
 
15412
15717
  Browser-safe canonical agent data. It re-exports the run, message, part, usage,
15413
15718
  terminal and provider-envelope schemas/types listed under
15414
- `stitchkit/agent-runtime`, together with all runtime delivery event schemas,
15719
+ `stitchkit/agent-runtime`, together with all runtime delivery event schemas (durable and transient,
15720
+ including `AgentAttemptResetEventSchema` for `attempt-reset`),
15415
15721
  `AgentRuntimeEventCursorSchema`, `advanceAgentRuntimeEventCursor`,
15416
15722
  `AgentControlRequestSchema` / `AgentControlRequest`, `AgentControlResponseSchema` /
15417
15723
  `AgentControlResponse`, `AgentControlDeliverySchema` / `AgentControlDelivery`, `AgentMultiSessionCursorSchema` /
@@ -15442,12 +15748,12 @@ loaded by the neutral, browser or Node runtime surfaces.
15442
15748
 
15443
15749
  | Export | Kind | Summary |
15444
15750
  |--------|------|---------|
15445
- | `createBunSqliteAgentRuntimeStore` | function | open an owned Bun SQLite connection, initialize/validate schema v1 and return `{ store, conversations, close }` |
15751
+ | `createBunSqliteAgentRuntimeStore` | function | open an owned Bun SQLite connection, initialize/validate schema v2, migrate v1 transactionally and return `{ store, conversations, database, transaction, close }` |
15446
15752
  | `BunSqliteAgentRuntimeStoreConfig` | _type_ | database filename plus optional create and initialization policies |
15447
15753
  | `createSqliteAgentRuntimeStore` | function | build the normalized store over an injected synchronous SQLite boundary |
15448
15754
  | `initializeAgentRuntimeSqlite` | function | initialize or validate only Stitchkit's namespaced SQLite schema |
15449
15755
  | `SqliteDatabase` / `SqliteStatement` / `SqliteValue` | _type_ | minimal runtime-neutral synchronous SQLite boundary |
15450
- | `SqliteAgentRuntimeStore` / `SqliteAgentRuntimeStoreConfig` | _type_ | durable store handle, owned connection lifecycle and initialization policy |
15756
+ | `SqliteAgentRuntimeStore` / `SqliteAgentRuntimeStoreConfig` / `SqliteStoreTransaction` | _type_ | durable store handle — `store`, `conversations`, `database`, `transaction`, `close` — owned connection lifecycle, initialization policy, and the one write transaction the SQLite companions share |
15451
15757
 
15452
15758
  ---
15453
15759
 
@@ -15498,11 +15804,11 @@ the Bun leaf but imports only `node:sqlite`.
15498
15804
 
15499
15805
  | Export | Kind | Summary |
15500
15806
  |--------|------|---------|
15501
- | `createNodeSqliteAgentRuntimeStore` | function | open an owned Node `DatabaseSync`, initialize/validate schema v1 and return `{ store, close }` |
15807
+ | `createNodeSqliteAgentRuntimeStore` | function | open an owned Node `DatabaseSync`, initialize/validate schema v2, migrate v1 transactionally and return `{ store, conversations, database, transaction, close }` |
15502
15808
  | `NodeSqliteAgentRuntimeStoreConfig` | _type_ | database filename plus optional read-only and initialization policies; read-only requires an initialized schema |
15503
15809
  | `createSqliteAgentRuntimeStore` / `initializeAgentRuntimeSqlite` | function | shared normalized adapter and namespaced schema lifecycle |
15504
15810
  | `SqliteDatabase` / `SqliteStatement` / `SqliteValue` | _type_ | minimal runtime-neutral synchronous SQLite boundary |
15505
- | `SqliteAgentRuntimeStore` / `SqliteAgentRuntimeStoreConfig` | _type_ | durable store handle, owned connection lifecycle and initialization policy |
15811
+ | `SqliteAgentRuntimeStore` / `SqliteAgentRuntimeStoreConfig` / `SqliteStoreTransaction` | _type_ | durable store handle — `store`, `conversations`, `database`, `transaction`, `close` — owned connection lifecycle, initialization policy, and the one write transaction the SQLite companions share |
15506
15812
 
15507
15813
  ## `stitchkit/observability`
15508
15814
 
@@ -15621,6 +15927,8 @@ payload.
15621
15927
  | `validateMcpSchemas` | function | object-shaped assertion over the exact advertised schema surface — compatibility, typed properties and portable formats ([guide](../guide/mcp-and-agents.md#mcp-schema-validation-profile)) |
15622
15928
  | `listToolNames` | function | every contract/runtime tool name with origin, identity and transports — for stable snapshots — [guide](../guide/mcp-and-agents.md#pinning-tool-names--listtoolnames) |
15623
15929
  | `listContractToolNames` | function | the same listing straight from contracts — no handlers or stub services needed |
15930
+ | `describeToolCatalog` | function | inspect the exact model-facing names, source identities, schema byte sizes and deferred state; an explicit total byte budget fails closed |
15931
+ | `ToolCatalogConfig` / `ToolCatalogEntry` | _type_ | catalog source, transport, optional explicit schema budget and one inspectable result row |
15624
15932
  | `McpHandlerConfig` | _type_ | server surface plus stateless HTTP transport config |
15625
15933
  | `McpHttpConfig` | _type_ | HTTP auth, protected-resource, legacy-era and security options |
15626
15934
  | `McpHttpHandler` | _type_ | framework-owned `{ fetch(request), close() }` lifecycle |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stitchkit",
3
- "version": "0.85.1",
3
+ "version": "0.86.0",
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",
@@ -101,6 +101,10 @@
101
101
  "types": "./dist/agent-runtime.d.ts",
102
102
  "import": "./dist/agent-runtime.js"
103
103
  },
104
+ "./agent-runtime/testing": {
105
+ "types": "./dist/agent-runtime-testing.d.ts",
106
+ "import": "./dist/agent-runtime-testing.js"
107
+ },
104
108
  "./agent-runtime/harness": {
105
109
  "types": "./dist/agent-runtime-harness.d.ts",
106
110
  "import": "./dist/agent-runtime-harness.js"
@@ -198,6 +202,7 @@
198
202
  "smoke:next-ssr": "node scripts/next-ssr-retry-smoke.mjs",
199
203
  "consumer-lane": "bun scripts/consumer-lane/run.mjs",
200
204
  "bench:mcp-preparation": "bun scripts/benchmark-mcp-preparation.ts",
205
+ "bench:durable-store": "bun scripts/bench-durable-store.ts",
201
206
  "build:entrypoints": "bun scripts/build-entrypoints.mjs"
202
207
  },
203
208
  "peerDependencies": {