stitchkit 0.58.0 → 0.59.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.
@@ -1 +1 @@
1
- {"version":3,"file":"agent-store-conformance.d.ts","sourceRoot":"","sources":["../../src/testing/agent-store-conformance.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,MAAM,WAAW,2BAA2B;IAC1C,WAAW,IAAI,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC/D;AAwCD,gFAAgF;AAChF,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,2BAA2B,GAClC,OAAO,CAAC,IAAI,CAAC,CAmPf"}
1
+ {"version":3,"file":"agent-store-conformance.d.ts","sourceRoot":"","sources":["../../src/testing/agent-store-conformance.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,MAAM,WAAW,2BAA2B;IAC1C,WAAW,IAAI,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC/D;AAwCD,gFAAgF;AAChF,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,2BAA2B,GAClC,OAAO,CAAC,IAAI,CAAC,CAmRf"}
package/dist/testing.js CHANGED
@@ -315,6 +315,35 @@ async function runAgentStoreConformance(config) {
315
315
  if (terminalOutcomes.join(",") !== "applied,conflict") {
316
316
  throw new Error(`Terminal race was not linearized: ${terminalOutcomes.join(",")}`);
317
317
  }
318
+ const terminalApplied = terminalResults.find((result) => result.outcome === "applied");
319
+ if (terminalApplied?.outcome !== "applied") {
320
+ throw new Error("Terminal race produced no applied result");
321
+ }
322
+ const compactedTerminal = await store.replaceCompactedRange({
323
+ conversationId,
324
+ expectedVersion: terminalApplied.snapshot.version,
325
+ replacedMessageIds: ["summary-1", terminalAssistant.id],
326
+ summary: AgentMessageSchema.parse({
327
+ schemaVersion: 1,
328
+ id: "summary-2",
329
+ conversationId,
330
+ role: "summary",
331
+ status: "committed",
332
+ parts: [{ type: "text", text: "terminal history" }],
333
+ createdAt: "2026-08-22T00:00:03.000Z",
334
+ updatedAt: "2026-08-22T00:00:03.000Z"
335
+ })
336
+ });
337
+ requireOutcome(compactedTerminal, "applied");
338
+ const duplicateTerminal = await store.acceptInputAndAssignRun({
339
+ idempotencyKey: "request-1",
340
+ input: userMessage(conversationId, "discarded-terminal-input"),
341
+ run: queuedRun(conversationId, "discarded-terminal-input", "discarded-terminal-run")
342
+ });
343
+ requireOutcome(duplicateTerminal, "duplicate");
344
+ if (duplicateTerminal.run.terminalReason !== "success" || JSON.stringify(duplicateTerminal.assistant) !== JSON.stringify(terminalAssistant)) {
345
+ throw new Error("Compaction discarded the canonical duplicate terminal result");
346
+ }
318
347
  const recoveryConversationId = `${conversationId}-recovery`;
319
348
  const recoveryInput = userMessage(recoveryConversationId, "recovery-input");
320
349
  const recoveryRun = queuedRun(recoveryConversationId, recoveryInput.id, "recovery-run");
package/llms-full.txt CHANGED
@@ -3500,29 +3500,40 @@ provide one database transaction driver:
3500
3500
  ```ts
3501
3501
  const store = createAgentRuntimeStore({
3502
3502
  transaction: work => db.transaction(tx => work(tx)),
3503
- state: {
3504
- load: (tx, conversationId) => loadRuntimeState(tx, conversationId),
3505
- compareAndSwap: (tx, operation) => casRuntimeState(tx, operation),
3503
+ head: {
3504
+ load: (tx, conversationId) => loadRuntimeHead(tx, conversationId),
3505
+ compareAndSwap: (tx, operation) => casRuntimeHead(tx, operation),
3506
+ },
3507
+ runs: {
3508
+ load: (tx, identity) => loadRun(tx, identity),
3509
+ loadByAssistantMessageId: (tx, identity) => loadRunByAssistant(tx, identity),
3510
+ loadMany: (tx, identities) => loadRuns(tx, identities),
3511
+ listActive: (tx, conversationId) => listActiveRuns(tx, conversationId),
3512
+ save: (tx, record) => saveRun(tx, record),
3513
+ },
3514
+ admissions: {
3515
+ load: (tx, identity) => loadAdmission(tx, identity),
3516
+ loadByInputMessageId: (tx, identity) => loadAdmissionByInput(tx, identity),
3517
+ create: (tx, receipt) => createAdmission(tx, receipt),
3506
3518
  },
3507
3519
  history: {
3508
3520
  load: (tx, conversationId) => loadCanonicalMessages(tx, conversationId),
3509
- loadById: (tx, identity) => loadActiveOrArchivedMessage(tx, identity),
3510
3521
  apply: (tx, mutation) => applyCanonicalHistoryMutation(tx, mutation),
3511
3522
  },
3512
3523
  scanRecoverable: page => scanRecoverableRuns(page),
3513
3524
  })
3514
3525
  ```
3515
3526
 
3516
- The same opaque `tx` reaches state and history callbacks. The adapter maps rows
3527
+ The same opaque `tx` reaches head, run, admission and history callbacks. The adapter maps rows
3517
3528
  and supplies atomicity; Stitchkit owns transition validation and revision
3518
3529
  arithmetic. The executable reference is
3519
3530
  [`examples/agent-store-prisma/adapter.ts`](../../examples/agent-store-prisma/adapter.ts).
3520
3531
  `compareAndSwap` returns either `{ outcome: 'applied' }` or
3521
- `{ outcome: 'conflict', actualVersion }`; on a winning write it also persists the
3522
- framework-provided `recoverable` descriptors in the same transaction. Recovery
3523
- scans that bounded index instead of loading every aggregate. Compaction may hide
3524
- rows from `history.load`, but `history.loadById` must retain canonical admitted
3525
- inputs for durable duplicate receipts.
3532
+ `{ outcome: 'conflict', actualVersion }`. The head contains only schema version,
3533
+ conversation identity and monotonic version. Runs and admission receipts are normalized records;
3534
+ recovery queries active run states directly instead of maintaining a second projection.
3535
+ An admission receipt retains its canonical input, and a terminal run retains its canonical
3536
+ assistant, so physical product-history compaction cannot break idempotent retries.
3526
3537
 
3527
3538
  ## Durable order
3528
3539
 
@@ -6576,33 +6587,43 @@ current one *up to* your target, and apply each snippet.
6576
6587
  runtime): bootstrap the server, one HTTP request, and any feature you rely on
6577
6588
  (Socket.IO connect, an MCP tool call, a multipart upload, …).
6578
6589
 
6579
- ## Unreleased migration: complete agent admission identity
6590
+ ## Unreleased migration: normalized agent runtime persistence
6591
+
6592
+ `AgentRuntimeStoreDriver` no longer reads and rewrites a lifetime `AgentStoredState` JSON
6593
+ aggregate. Migrate that row and its recoverable/archive projections once:
6580
6594
 
6581
- Custom `AgentRuntimeStore` adapters must persist and return the input and
6582
- assistant identities associated with an idempotency key:
6595
+ 1. Copy `conversationId` and `version` into the bounded runtime head.
6596
+ 2. Write every `AgentStoredState.runs[]` entry as one normalized run record.
6597
+ 3. Write every `AgentStoredState.admissions[]` entry as one admission receipt and copy its
6598
+ canonical input into that receipt.
6599
+ 4. For terminal runs, retain the canonical assistant on the run record before deleting any old
6600
+ history/archive rows.
6601
+ 5. Replace the recoverable projection with an index over normalized run `state`.
6602
+ 6. Cut the adapter over atomically; there is no compatibility driver or dual-write mode.
6583
6603
 
6584
6604
  ```ts
6585
6605
  // before
6586
- return { outcome: 'duplicate', runId, snapshot }
6606
+ createAgentRuntimeStore({
6607
+ state: { load, compareAndSwap },
6608
+ history: { load, loadById, apply },
6609
+ scanRecoverable,
6610
+ })
6587
6611
 
6588
6612
  // after
6589
- return { outcome: 'duplicate', input, inputMessageId, runId, assistantMessageId, snapshot }
6613
+ createAgentRuntimeStore({
6614
+ head: { load, compareAndSwap },
6615
+ runs: { load, loadByAssistantMessageId, loadMany, listActive, save },
6616
+ admissions: { load, loadByInputMessageId, create },
6617
+ history: { load, apply },
6618
+ scanRecoverable,
6619
+ })
6590
6620
  ```
6591
6621
 
6592
- Prefer replacing the custom aggregate reducer with `createAgentRuntimeStore()`;
6593
- its `AgentStoredState.admissions` record and transaction driver implement this
6594
- contract automatically. `history.loadById()` must retain access to compacted
6595
- admitted inputs so the framework can return the canonical record.
6596
-
6597
- `AgentRuntimeEvent` also adds a post-commit `admission` variant. Add it to any
6598
- exhaustive publisher switch. Its `assistant` is either the pending placeholder
6599
- for a new assignment or the canonical persisted assistant for a duplicate:
6600
-
6601
- ```ts
6602
- case 'admission':
6603
- await persistProductProjection(event.input, event.run, event.assistant)
6604
- break
6605
- ```
6622
+ `AgentRuntimeHeadSchema`, `AgentStoredRunSchema` and `AgentAdmissionReceiptSchema` replace
6623
+ `AgentStoredStateSchema` and `AgentAdmissionIdentitySchema`. Run
6624
+ `runAgentStoreConformance()` against the migrated adapter before switching production traffic.
6625
+ If an application implements `AgentRuntimeStore` directly, its duplicate result must also include
6626
+ the canonical `run` and the retained `assistant` for a terminal run.
6606
6627
 
6607
6628
  ## Released migration: 0.56.0
6608
6629
 
@@ -8044,8 +8065,10 @@ Server-only optional application runtime. See the
8044
8065
  | `AgentMessageSchema` / `AgentRunSchema` / `AgentSnapshotSchema` | schema | versioned canonical engine records |
8045
8066
  | `AgentRuntimeStore` | _type_ | aggregate CAS transaction boundary for message, run and compaction mutations |
8046
8067
  | `createAgentRuntimeStore` | function | build the aggregate store from one coherent transaction driver; framework owns every state transition |
8047
- | `AgentRuntimeStoreDriver` | _type_ | ORM-neutral transactional state load/exact-version CAS, active-plus-archived history codec and bounded recoverable-run index scan |
8048
- | `AgentStoredStateSchema` | schema | versioned runs and full idempotency admission identities without duplicated message history |
8068
+ | `AgentRuntimeStoreDriver` | _type_ | ORM-neutral transaction over a bounded head, normalized runs/admissions, product history and indexed run recovery |
8069
+ | `AgentRuntimeHeadSchema` | schema | constant-size conversation identity plus monotonic runtime version |
8070
+ | `AgentStoredRunSchema` | schema | canonical normalized run with an optional retained terminal assistant |
8071
+ | `AgentAdmissionReceiptSchema` | schema | durable idempotency receipt with canonical input and assigned run/assistant identities |
8049
8072
  | `AgentHistoryMutationSchema` | schema | typed canonical message mutation applied inside the winning state transaction |
8050
8073
  | `RecoverAgentRunSchema` | schema | explicit abandon/requeue recovery decision; acquired runs require replay-safe evidence |
8051
8074
  | `createMemoryAgentRuntimeStore` | function | process-local reference adapter, not production durability |
@@ -8095,8 +8118,8 @@ Store command/result exports are `AcceptInputAndAssignRun`, `AcceptInputAndAssig
8095
8118
  `RequestRunInterrupt`, `RequestRunInterruptSchema`, `RecoverAgentRun`, `ReplaceCompactedRange`,
8096
8119
  `ReplaceCompactedRangeSchema`, `AgentStoreMutationResult`, `AgentStoreMutationResultSchema`,
8097
8120
  `AgentStoreAppliedSchema`, `AgentStoreConflictSchema`, `AgentStoreDuplicateSchema`,
8098
- `AgentStoreNotFoundSchema`, `AgentAdmissionIdentity`, `AgentAdmissionIdentitySchema`,
8099
- `AgentStoredState`, `AgentStoreCompareAndSwapResult`, `AgentHistoryMutation`,
8121
+ `AgentStoreNotFoundSchema`, `AgentAdmissionReceipt`, `AgentAdmissionReceiptSchema`,
8122
+ `AgentRuntimeHead`, `AgentStoredRun`, `AgentStoreCompareAndSwapResult`, `AgentHistoryMutation`,
8100
8123
  `AgentRecoverableDescriptor`, `AgentRecoverableDescriptorSchema`, `AgentRecoverablePage` and
8101
8124
  `AgentRecoverablePageSchema`.
8102
8125
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stitchkit",
3
- "version": "0.58.0",
3
+ "version": "0.59.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",