stitchkit 0.110.1 → 0.110.3

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 (86) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/agent-runtime/archive-projection.d.ts +10 -0
  3. package/dist/agent-runtime/archive-projection.d.ts.map +1 -0
  4. package/dist/agent-runtime/archive-spill.d.ts +61 -0
  5. package/dist/agent-runtime/archive-spill.d.ts.map +1 -0
  6. package/dist/agent-runtime/branch-contract.d.ts +102 -0
  7. package/dist/agent-runtime/branch-contract.d.ts.map +1 -0
  8. package/dist/agent-runtime/branch-events.d.ts +18 -0
  9. package/dist/agent-runtime/branch-events.d.ts.map +1 -0
  10. package/dist/agent-runtime/branch-identities.d.ts +20 -0
  11. package/dist/agent-runtime/branch-identities.d.ts.map +1 -0
  12. package/dist/agent-runtime/branch-messages.d.ts +32 -0
  13. package/dist/agent-runtime/branch-messages.d.ts.map +1 -0
  14. package/dist/agent-runtime/branch-observations.d.ts +104 -0
  15. package/dist/agent-runtime/branch-observations.d.ts.map +1 -0
  16. package/dist/agent-runtime/branch-provider.d.ts +130 -0
  17. package/dist/agent-runtime/branch-provider.d.ts.map +1 -0
  18. package/dist/agent-runtime/branch-replay.d.ts +426 -0
  19. package/dist/agent-runtime/branch-replay.d.ts.map +1 -0
  20. package/dist/agent-runtime/branch-source.d.ts +16 -0
  21. package/dist/agent-runtime/branch-source.d.ts.map +1 -0
  22. package/dist/agent-runtime/branch-transitions.d.ts +6 -0
  23. package/dist/agent-runtime/branch-transitions.d.ts.map +1 -0
  24. package/dist/agent-runtime/sqlite-events.d.ts.map +1 -1
  25. package/dist/agent-runtime/sqlite-history.d.ts.map +1 -1
  26. package/dist/agent-runtime/sqlite-purge.d.ts.map +1 -1
  27. package/dist/agent-runtime/store-archive.d.ts +1 -0
  28. package/dist/agent-runtime/store-archive.d.ts.map +1 -1
  29. package/dist/agent-runtime/store-branch.d.ts +5 -0
  30. package/dist/agent-runtime/store-branch.d.ts.map +1 -0
  31. package/dist/agent-runtime/store-conformance-branch.d.ts +4 -0
  32. package/dist/agent-runtime/store-conformance-branch.d.ts.map +1 -0
  33. package/dist/agent-runtime/store-conformance-support.d.ts +5 -5
  34. package/dist/agent-runtime/store-conformance.d.ts.map +1 -1
  35. package/dist/agent-runtime/store-create.d.ts +1 -1
  36. package/dist/agent-runtime/store-create.d.ts.map +1 -1
  37. package/dist/agent-runtime/store-driver-contract.d.ts +6 -0
  38. package/dist/agent-runtime/store-driver-contract.d.ts.map +1 -1
  39. package/dist/agent-runtime/store-events.d.ts +1131 -0
  40. package/dist/agent-runtime/store-events.d.ts.map +1 -1
  41. package/dist/agent-runtime/store-memory-archive.d.ts +8 -0
  42. package/dist/agent-runtime/store-memory-archive.d.ts.map +1 -0
  43. package/dist/agent-runtime/store-memory-events.d.ts +7 -0
  44. package/dist/agent-runtime/store-memory-events.d.ts.map +1 -0
  45. package/dist/agent-runtime/store-memory.d.ts +1 -1
  46. package/dist/agent-runtime/store-memory.d.ts.map +1 -1
  47. package/dist/agent-runtime/store-purge.d.ts +2 -0
  48. package/dist/agent-runtime/store-purge.d.ts.map +1 -1
  49. package/dist/agent-runtime/store-reduce-run.d.ts +2 -2
  50. package/dist/agent-runtime/store-reduce-run.d.ts.map +1 -1
  51. package/dist/agent-runtime/store-reduce-shared.d.ts +1 -0
  52. package/dist/agent-runtime/store-reduce-shared.d.ts.map +1 -1
  53. package/dist/agent-runtime/store-reducer.d.ts +2 -2
  54. package/dist/agent-runtime/store-reducer.d.ts.map +1 -1
  55. package/dist/agent-runtime/store-replay.d.ts +4 -0
  56. package/dist/agent-runtime/store-replay.d.ts.map +1 -0
  57. package/dist/agent-runtime/store.d.ts +3 -0
  58. package/dist/agent-runtime/store.d.ts.map +1 -1
  59. package/dist/durability/events.d.ts +4 -0
  60. package/dist/durability/events.d.ts.map +1 -1
  61. package/dist/entrypoints/agent-runtime/coding-tools.js +1 -2
  62. package/dist/entrypoints/agent-runtime/harness.js +4 -3
  63. package/dist/entrypoints/agent-runtime/sandbox.js +3 -5
  64. package/dist/entrypoints/agent-runtime/sqlite/bun.js +13 -3
  65. package/dist/entrypoints/agent-runtime/sqlite/node.js +13 -3
  66. package/dist/entrypoints/agent-runtime/testing.js +89 -5
  67. package/dist/entrypoints/agent-runtime.d.ts +2 -1
  68. package/dist/entrypoints/agent-runtime.d.ts.map +1 -1
  69. package/dist/entrypoints/agent-runtime.js +27 -15
  70. package/dist/entrypoints/tools.js +5 -3
  71. package/dist/{index-0gs4ymfj.js → index-4fgg1507.js} +31 -2
  72. package/dist/{index-c17xcx4k.js → index-56yx8dxp.js} +19 -96
  73. package/dist/{index-8rstkvcf.js → index-7c046kxr.js} +1 -1
  74. package/dist/{index-tjdsyrys.js → index-bm180f2d.js} +203 -83
  75. package/dist/{index-924500c3.js → index-ddkwkcvn.js} +2 -2
  76. package/dist/{index-c0hffcmj.js → index-dgfah0g8.js} +21 -9
  77. package/dist/index-j1cwtyk1.js +2269 -0
  78. package/dist/index-snef22zr.js +94 -0
  79. package/dist/{index-5p55xreg.js → index-w619fqvv.js} +67 -29
  80. package/llms/agent-runtime.3.txt +4 -0
  81. package/llms/agent-runtime.txt +75 -0
  82. package/llms-full.txt +79 -0
  83. package/llms.txt +1 -1
  84. package/package.json +1 -1
  85. package/dist/index-8ks9b85e.js +0 -129
  86. package/dist/index-d2h99n7d.js +0 -1071
@@ -0,0 +1,94 @@
1
+ // src/durability/contract.ts
2
+ import { z } from "zod";
3
+ var DURABILITY_STEP_EVENT_KIND2 = "durability/step";
4
+ var DURABILITY_PARK_EVENT_KIND = "durability/park";
5
+ var DURABILITY_EVENT_EVENT_KIND = "durability/event";
6
+ var DURABILITY_EFFECT_EVENT_KIND = "durability/effect";
7
+ var StepEventPayloadSchema = z.object({
8
+ runId: z.string().min(1),
9
+ stepName: z.string().min(1),
10
+ encoded: z.string()
11
+ });
12
+ var SleepParkSchema = z.object({
13
+ runId: z.string().min(1),
14
+ kind: z.literal("sleep"),
15
+ name: z.string().min(1),
16
+ deadline: z.number()
17
+ });
18
+ var WaitParkSchema = z.object({
19
+ runId: z.string().min(1),
20
+ kind: z.literal("wait"),
21
+ event: z.string().min(1),
22
+ id: z.string().min(1)
23
+ });
24
+ var ParkEventPayloadSchema = z.discriminatedUnion("kind", [
25
+ SleepParkSchema,
26
+ WaitParkSchema
27
+ ]);
28
+ var DeliveredEventPayloadSchema = z.object({
29
+ runId: z.string().min(1),
30
+ event: z.string().min(1),
31
+ id: z.string().min(1),
32
+ encoded: z.string()
33
+ });
34
+ var EffectIdentity = { runId: z.string().min(1), effectName: z.string().min(1) };
35
+ var EffectEventPayloadSchema = z.discriminatedUnion("phase", [
36
+ z.object({ ...EffectIdentity, phase: z.literal("intent") }),
37
+ z.object({
38
+ ...EffectIdentity,
39
+ phase: z.literal("accepted"),
40
+ encoded: z.string(),
41
+ via: z.enum(["run", "reconcile"])
42
+ }),
43
+ z.object({ ...EffectIdentity, phase: z.literal("uncertain") })
44
+ ]);
45
+
46
+ class StepResultDecodeError2 extends Error {
47
+ constructor(message, options) {
48
+ super(message, options);
49
+ this.name = "StepResultDecodeError";
50
+ }
51
+ }
52
+
53
+ class StepResultNotSerializableError2 extends Error {
54
+ constructor(stepName, cause) {
55
+ super(`Step "${stepName}" returned a value that is not JSON-serializable`, {
56
+ cause
57
+ });
58
+ this.name = "StepResultNotSerializableError";
59
+ }
60
+ }
61
+
62
+ class StepAbortedError2 extends Error {
63
+ constructor(stepName) {
64
+ super(`Step "${stepName}" was aborted before it started`);
65
+ this.name = "StepAbortedError";
66
+ }
67
+ }
68
+
69
+ class EffectUnresolvedError2 extends Error {
70
+ effectName;
71
+ reason;
72
+ constructor(effectName, reason, options) {
73
+ super(`Effect "${effectName}" is unresolved (${reason}); its intent stands`, options);
74
+ this.effectName = effectName;
75
+ this.reason = reason;
76
+ this.name = "EffectUnresolvedError";
77
+ }
78
+ }
79
+
80
+ class ParkRecordDecodeError2 extends Error {
81
+ constructor(message, options) {
82
+ super(message, options);
83
+ this.name = "ParkRecordDecodeError";
84
+ }
85
+ }
86
+
87
+ class ParkAbortedError2 extends Error {
88
+ constructor(park) {
89
+ super(`Park "${park}" was aborted before it was satisfied`);
90
+ this.name = "ParkAbortedError";
91
+ }
92
+ }
93
+
94
+ export { DURABILITY_STEP_EVENT_KIND2, DURABILITY_PARK_EVENT_KIND, DURABILITY_EVENT_EVENT_KIND, DURABILITY_EFFECT_EVENT_KIND, StepEventPayloadSchema, ParkEventPayloadSchema, DeliveredEventPayloadSchema, EffectEventPayloadSchema, StepResultDecodeError2, StepResultNotSerializableError2, StepAbortedError2, EffectUnresolvedError2, ParkRecordDecodeError2, ParkAbortedError2 };
@@ -2,7 +2,7 @@ import {
2
2
  AgentStoreEventEnvelopeSchema2,
3
3
  AgentStoreEventPageSchema2,
4
4
  AgentRecoverablePageSchema2
5
- } from "./index-0gs4ymfj.js";
5
+ } from "./index-4fgg1507.js";
6
6
  import {
7
7
  AgentRecordIdSchema2,
8
8
  AgentMessageSchema2
@@ -15,12 +15,64 @@ import {
15
15
  AgentHistoryMutationSchema2,
16
16
  isActiveRunState,
17
17
  replaceMessage,
18
+ ArchiveSpillSchema,
18
19
  createAgentRuntimeStore2
19
- } from "./index-d2h99n7d.js";
20
+ } from "./index-j1cwtyk1.js";
20
21
 
21
22
  // src/agent-runtime/store-memory.ts
23
+ import { z as z2 } from "zod";
24
+
25
+ // src/agent-runtime/store-memory-archive.ts
22
26
  import { z } from "zod";
23
- var RecoverableCursorSchema = z.tuple([AgentRecordIdSchema2, AgentRecordIdSchema2]);
27
+ var memoryArchive = {
28
+ async export(transaction, conversationId) {
29
+ return {
30
+ projections: [],
31
+ spills: z.array(z.json()).parse(structuredClone(transaction.spills.get(conversationId) ?? []))
32
+ };
33
+ },
34
+ async import(transaction, archive) {
35
+ const spills = archive.spills.map((value) => ArchiveSpillSchema.parse(value));
36
+ const occupied = new Set([...transaction.spills.values()].flatMap((entries) => entries.map((spill) => spill.reference)));
37
+ for (const spill of spills) {
38
+ if (occupied.has(spill.reference))
39
+ throw new TypeError("Conversation archive spill identity is already present");
40
+ occupied.add(spill.reference);
41
+ }
42
+ transaction.spills.set(archive.conversationId, structuredClone(spills));
43
+ }
44
+ };
45
+
46
+ // src/agent-runtime/store-memory-events.ts
47
+ var memoryEvents = {
48
+ async append(transaction, draft) {
49
+ const current = transaction.events.get(draft.conversationId) ?? [];
50
+ const event = AgentStoreEventEnvelopeSchema2.parse({
51
+ ...draft,
52
+ seq: (current.at(-1)?.seq ?? 0) + 1
53
+ });
54
+ if (current.some((candidate) => candidate.eventId === event.eventId)) {
55
+ throw new TypeError("Agent store event identity is already present");
56
+ }
57
+ transaction.events.set(draft.conversationId, [...current, event]);
58
+ return event;
59
+ },
60
+ async list(transaction, input) {
61
+ const selected = (transaction.events.get(input.conversationId) ?? []).filter((event) => (input.fromSeq === undefined || event.seq >= input.fromSeq) && (input.toSeq === undefined || event.seq <= input.toSeq));
62
+ const items = selected.slice(0, input.limit);
63
+ const last = items.at(-1);
64
+ return AgentStoreEventPageSchema2.parse({
65
+ items,
66
+ ...selected.length > items.length && last ? { nextSeq: last.seq + 1 } : {}
67
+ });
68
+ },
69
+ async find(transaction, input) {
70
+ return (transaction.events.get(input.conversationId) ?? []).find((event) => event.eventId === input.eventId);
71
+ }
72
+ };
73
+
74
+ // src/agent-runtime/store-memory.ts
75
+ var RecoverableCursorSchema = z2.tuple([AgentRecordIdSchema2, AgentRecordIdSchema2]);
24
76
  function recoverableCursor(input) {
25
77
  return JSON.stringify([input.conversationId, input.run.id]);
26
78
  }
@@ -46,6 +98,9 @@ function cloneHistoryMap(source) {
46
98
  ]));
47
99
  }
48
100
  var memoryConversations = {
101
+ async isEmpty(transaction, id) {
102
+ return !transaction.heads.has(id) && !transaction.runs.has(id) && !transaction.admissions.has(id) && !transaction.seeds.has(id) && !transaction.histories.has(id) && !transaction.events.has(id) && !transaction.spills.has(id);
103
+ },
49
104
  async isPurged(transaction, conversationId) {
50
105
  return transaction.purged.has(conversationId);
51
106
  },
@@ -57,6 +112,7 @@ var memoryConversations = {
57
112
  transaction.seeds.delete(conversationId);
58
113
  transaction.histories.delete(conversationId);
59
114
  transaction.events.delete(conversationId);
115
+ transaction.spills.delete(conversationId);
60
116
  }
61
117
  };
62
118
  var memoryHead = {
@@ -140,6 +196,10 @@ var memorySeeds = {
140
196
  }
141
197
  };
142
198
  var memoryHistory = {
199
+ async restore(transaction, input) {
200
+ const compacted = new Set(input.compactedMessageIds);
201
+ transaction.histories.set(input.conversationId, input.messages.filter((message) => !compacted.has(message.id)).map((message) => AgentMessageSchema2.parse(structuredClone(message))));
202
+ },
143
203
  async load(transaction, conversationId) {
144
204
  return (transaction.histories.get(conversationId) ?? []).map((message) => AgentMessageSchema2.parse(structuredClone(message)));
145
205
  },
@@ -181,32 +241,6 @@ var memoryHistory = {
181
241
  ]);
182
242
  }
183
243
  };
184
- var memoryEvents = {
185
- async append(transaction, draft) {
186
- const current = transaction.events.get(draft.conversationId) ?? [];
187
- const event = AgentStoreEventEnvelopeSchema2.parse({
188
- ...draft,
189
- seq: (current.at(-1)?.seq ?? 0) + 1
190
- });
191
- if (current.some((candidate) => candidate.eventId === event.eventId)) {
192
- throw new TypeError("Agent store event identity is already present");
193
- }
194
- transaction.events.set(draft.conversationId, [...current, event]);
195
- return event;
196
- },
197
- async list(transaction, input) {
198
- const selected = (transaction.events.get(input.conversationId) ?? []).filter((event) => (input.fromSeq === undefined || event.seq >= input.fromSeq) && (input.toSeq === undefined || event.seq <= input.toSeq));
199
- const items = selected.slice(0, input.limit);
200
- const last = items.at(-1);
201
- return AgentStoreEventPageSchema2.parse({
202
- items,
203
- ...selected.length > items.length && last ? { nextSeq: last.seq + 1 } : {}
204
- });
205
- },
206
- async find(transaction, input) {
207
- return (transaction.events.get(input.conversationId) ?? []).find((event) => event.eventId === input.eventId);
208
- }
209
- };
210
244
  function scanMemoryRecoverable(runs, input) {
211
245
  const descriptors = [...runs].flatMap(([conversationId, conversationRuns]) => [...conversationRuns.values()].filter((record) => isActiveRunState(record.run.state)).map((record) => ({ conversationId, run: record.run }))).sort((left, right) => left.conversationId.localeCompare(right.conversationId) || left.run.id.localeCompare(right.run.id));
212
246
  const cursorTuple = input.cursor ? parseRecoverableCursor(input.cursor) : undefined;
@@ -230,6 +264,7 @@ function createMemoryAgentRuntimeStore2() {
230
264
  let seeds = new Map;
231
265
  let histories = new Map;
232
266
  let events = new Map;
267
+ let spills = new Map;
233
268
  let transactionTail = Promise.resolve();
234
269
  const driver = {
235
270
  async transaction(work) {
@@ -243,6 +278,7 @@ function createMemoryAgentRuntimeStore2() {
243
278
  });
244
279
  const transaction = {
245
280
  purged: new Set(purged),
281
+ spills: structuredClone(spills),
246
282
  heads: cloneHeadMap(heads),
247
283
  runs: cloneNestedMap(runs, (record) => AgentStoredRunSchema2.parse(structuredClone(record))),
248
284
  admissions: cloneNestedMap(admissions, (receipt) => AgentAdmissionReceiptSchema2.parse(structuredClone(receipt))),
@@ -256,6 +292,7 @@ function createMemoryAgentRuntimeStore2() {
256
292
  try {
257
293
  const result = await work(transaction);
258
294
  purged = transaction.purged;
295
+ spills = transaction.spills;
259
296
  heads = transaction.heads;
260
297
  runs = transaction.runs;
261
298
  admissions = transaction.admissions;
@@ -274,6 +311,7 @@ function createMemoryAgentRuntimeStore2() {
274
311
  seeds: memorySeeds,
275
312
  history: memoryHistory,
276
313
  events: memoryEvents,
314
+ archive: memoryArchive,
277
315
  async scanRecoverable(input) {
278
316
  return scanMemoryRecoverable(runs, input);
279
317
  }
@@ -31,6 +31,9 @@ Server-only optional application runtime. See the
31
31
  | `AgentMessageSchema` / `AgentRunSchema` / `AgentSnapshotSchema` | schema | versioned canonical engine records |
32
32
  | `AgentRunQueuePrioritySchema` | schema | durable opt-in priority for queued `interrupt-next` runs |
33
33
  | `AgentRuntimeStore` | _type_ | aggregate CAS transaction boundary for message, run and compaction mutations |
34
+ | `BranchAgentConversationInputSchema` / `BranchAgentConversationInput` | schema / _type_ | strict branch request: stable request key, empty destination, settled conversation boundary or archive bytes, fresh artifact authorization |
35
+ | `AgentConversationBranchReceiptSchema` / `AgentConversationBranchReceipt` | schema / _type_ | durable lineage: request fingerprint, source/destination identities, source sequence/version/digest and creation time |
36
+ | `AgentConversationBranchResultSchema` / `AgentConversationBranchResult` | schema / _type_ | `created` or `duplicate` with the same durable receipt; `AgentRuntimeStore.branchConversation` is optional for hand-written stores |
34
37
  | `createAgentRuntimeStore` | function | build the aggregate store from one coherent transaction driver; framework owns every state transition |
35
38
  | `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 |
36
39
  | `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 |
@@ -101,6 +104,7 @@ Server-only optional application runtime. See the
101
104
  | `AgentStoreEventEnvelopeSchema` / `AgentStoreEventEnvelope` / `AgentStoreEventKindSchema` / `AgentStoreEventKind` / `AgentStoreEventPageSchema` / `AgentStoreEventPage` | schema / _type_ | append-only event envelope, closed current vocabulary (including `provider/request` and `provider/response`) and bounded page |
102
105
  | `AppendAgentStoreEventSchema` / `AppendAgentStoreEvent` / `ReadAgentStoreEventsSchema` / `ReadAgentStoreEvents` | schema / _type_ | required append and bounded-read store contracts |
103
106
  | `AgentStoreTransitionSchema` / `AgentStoreTransition` / `AgentStoreEventDraft` / `AgentStoreEventDecodeAccepted` / `AgentStoreEventDecodeIgnored` / `AgentStoreEventDecodeResult` / `decodeAgentStoreEvent` | schema / _types_ / function | normalized runtime mutations, append drafts and strict current/ignorable future-event decoding outcomes |
107
+ | `AgentStoreTransitionRecordSchema` / `AgentStoreTransitionRecord` | schema / _type_ | persisted journal payloads: full runtime mutations or hash-only streaming checkpoint observations with numeric part/byte counts; inspection does not authorize replay |
104
108
  | `defineAgentProjection` / `AgentProjectionDefinition` / `AgentProjectionValue` / `createAgentProjectionRegistry` / `createSqliteAgentProjectionStore` | functions / _type_ | deterministic folds with persisted version and honest `uptoSeq` checkpoints |
105
109
  | `agentSummaryProjection` / `agentUsageProjection` / `agentOutlineProjection` | constants | built-in list summary, provenance-carrying usage and request outline projections |
106
110
  | `agentConversationCardProjection` / `agentStateSlotsProjection` / `agentScheduleSummaryProjection` | constants | focused card, durable-state and schedule lifecycle projections |
@@ -567,6 +567,72 @@ failed attempt's reported usage stays in the run's spend. Transient events —
567
567
  deltas, reasoning, `attempt-reset` — are numbered from 1 per run, counting only
568
568
  what was published, so a cursor sees no gap on an ordinary stream.
569
569
 
570
+ ### Branch or restore with a new identity
571
+
572
+ Use `store.branchConversation()` to create an independent conversation. `importConversation()`
573
+ restores the original identity and is not a fork. The built-in memory and SQLite stores and
574
+ `createAgentRuntimeStore()` expose branching; a hand-written `AgentRuntimeStore` can advertise this
575
+ optional capability. The host authorizes the caller's source/archive access and destination
576
+ creation before calling this trusted store boundary.
577
+
578
+ ```ts
579
+ const copy = await sqlite.store.branchConversation({
580
+ requestKey: 'branch-request-1',
581
+ destinationConversationId: 'new-conversation',
582
+ source: { kind: 'conversation', conversationId: 'original', throughRunId: 'finished-run' },
583
+ // Required when selected history has spills: an explicit policy for this destination.
584
+ artifactAuthorization: { operation: 'read', path: 'approved-destination-workspace' },
585
+ })
586
+
587
+ const restored = await sqlite.store.branchConversation({
588
+ requestKey: 'restore-request-1',
589
+ destinationConversationId: 'restored-as-new',
590
+ source: { kind: 'archive', bytes: archiveBytes },
591
+ })
592
+ ```
593
+
594
+ `throughRunId` selects its exact terminal/abandon event. Omit it to include the settled tip and
595
+ compaction recorded after the last run. The selected prefix must contain no queued or acquired
596
+ runs. A later active source run does not prevent branching an earlier settled prefix. A migrated
597
+ baseline has no earlier per-run event boundary; it can be copied at its settled tip.
598
+
599
+ The result is `{ outcome: 'created' | 'duplicate', receipt }`. Keep the receipt: it binds source
600
+ and destination identity, source kind, exact `sourceSeq`/`sourceVersion`, `sourceDigest`, request
601
+ fingerprint and creation time. A retry with the same destination/key and selector returns the
602
+ original receipt even after the source advances or the destination continues. Changing the
603
+ request conflicts; no existing destination is overwritten. Archive fingerprints bind the supplied
604
+ bytes. The source digest binds the selected canonical events, artifacts and reconstructed snapshot.
605
+ Run update timestamps reconstructed from events use their recorded `occurredAt`. Abandon transitions
606
+ retain the full failed assistant in the same event; a legacy archive must retain that exact assistant
607
+ in its runtime snapshot, otherwise copying refuses instead of inventing historical content or time.
608
+
609
+ No provider or tool runs during copying. The next ordinary runtime `submit` continues the copied
610
+ history. All engine identities and typed references are new, including repeated references to one
611
+ spill. Compacted content stays in the event history and SQLite inactive rows; the model reads the
612
+ same active summaries. A hash-only checkpoint is historical digest evidence, marked
613
+ `sourceSha256`; a later full terminal record must settle its content.
614
+
615
+ A branch grants no source authority. Terminal run owners/fences and approval signatures are
616
+ removed. State, schedules, children, retries, sandbox, approval rejection and durability facts are
617
+ retained as inert `runtime/branch-observation` records; they cannot repopulate operational state
618
+ or pending effects. Spills discard source authorization and require the explicit fresh
619
+ `artifactAuthorization`; normal destination read authorization still applies. No cached projection,
620
+ schedule row or child relation is cloned. Ordinary companion projections in the export have
621
+ `{ name, version, uptoSeq, value, updatedAt }` envelopes. Branch validates their envelopes,
622
+ unique names and checkpoints within the supplied journal, then discards their values. They are
623
+ derived application caches, including ones containing source references; their values are never
624
+ replayed as state or copied as authority. Rebuild destination projections with
625
+ `createSqliteAgentProjectionStore().advance(...)` over the destination ledger. An exact earlier
626
+ boundary never inherits a later cache value.
627
+
628
+ The store validates the complete archive before writing: contiguous events, a matching runtime
629
+ snapshot, known typed forms, reference closure, and spill bytes/digests. Unsupported provider
630
+ envelopes, encrypted invocation payloads, unknown event versions, malformed projection envelopes,
631
+ missing artifacts and undocumented reference fields in opaque JSON refuse atomically. They need
632
+ an owner-defined transfer codec; never recursively rewrite internal JSON in the application.
633
+ Third-party drivers must provide atomic write transactions and archive support for spills;
634
+ `history.restore` is required for migrated baselines with inactive rows.
635
+
570
636
  ### Event ledger, projections and durable capabilities
571
637
 
572
638
  `AgentRuntimeStore` exposes bounded `readEvents`, declared `appendEvent`, canonical
@@ -578,6 +644,15 @@ upstream name comes from the model provider's own `resolveResponseProvider` —
578
644
  supplies it — so the runtime carries the fact without learning any gateway's metadata key. The normalized
579
645
  head/run/message tables remain the fast operational projection.
580
646
 
647
+ For `runtime/transition` payload inspection, use `AgentStoreTransitionRecordSchema` and its
648
+ inferred `AgentStoreTransitionRecord` type. A checkpoint record may hold either the full assistant
649
+ message or `{ id, status: 'streaming', sha256?, sourceSha256?, parts: number, bytes: number }`;
650
+ exactly one digest is present. Numeric `parts` counts parts; it is not an array of message parts.
651
+ `sourceSha256` preserves a branch's historical source digest. These hash-only records are
652
+ observations, not executable checkpoint inputs. `AgentStoreTransitionSchema` describes full
653
+ store mutations. Shape inspection does not replace branch's complete replay/reference validation.
654
+ Schema v4 archives written by 0.109.4 use the same journal representation.
655
+
581
656
  Use `defineAgentProjection` with `createSqliteAgentProjectionStore` for a
582
657
  deterministic versioned fold. Every value reports `uptoSeq`, so a caller can
583
658
  distinguish current data from a projection that still has events to consume.
package/llms-full.txt CHANGED
@@ -5765,6 +5765,72 @@ failed attempt's reported usage stays in the run's spend. Transient events —
5765
5765
  deltas, reasoning, `attempt-reset` — are numbered from 1 per run, counting only
5766
5766
  what was published, so a cursor sees no gap on an ordinary stream.
5767
5767
 
5768
+ ### Branch or restore with a new identity
5769
+
5770
+ Use `store.branchConversation()` to create an independent conversation. `importConversation()`
5771
+ restores the original identity and is not a fork. The built-in memory and SQLite stores and
5772
+ `createAgentRuntimeStore()` expose branching; a hand-written `AgentRuntimeStore` can advertise this
5773
+ optional capability. The host authorizes the caller's source/archive access and destination
5774
+ creation before calling this trusted store boundary.
5775
+
5776
+ ```ts
5777
+ const copy = await sqlite.store.branchConversation({
5778
+ requestKey: 'branch-request-1',
5779
+ destinationConversationId: 'new-conversation',
5780
+ source: { kind: 'conversation', conversationId: 'original', throughRunId: 'finished-run' },
5781
+ // Required when selected history has spills: an explicit policy for this destination.
5782
+ artifactAuthorization: { operation: 'read', path: 'approved-destination-workspace' },
5783
+ })
5784
+
5785
+ const restored = await sqlite.store.branchConversation({
5786
+ requestKey: 'restore-request-1',
5787
+ destinationConversationId: 'restored-as-new',
5788
+ source: { kind: 'archive', bytes: archiveBytes },
5789
+ })
5790
+ ```
5791
+
5792
+ `throughRunId` selects its exact terminal/abandon event. Omit it to include the settled tip and
5793
+ compaction recorded after the last run. The selected prefix must contain no queued or acquired
5794
+ runs. A later active source run does not prevent branching an earlier settled prefix. A migrated
5795
+ baseline has no earlier per-run event boundary; it can be copied at its settled tip.
5796
+
5797
+ The result is `{ outcome: 'created' | 'duplicate', receipt }`. Keep the receipt: it binds source
5798
+ and destination identity, source kind, exact `sourceSeq`/`sourceVersion`, `sourceDigest`, request
5799
+ fingerprint and creation time. A retry with the same destination/key and selector returns the
5800
+ original receipt even after the source advances or the destination continues. Changing the
5801
+ request conflicts; no existing destination is overwritten. Archive fingerprints bind the supplied
5802
+ bytes. The source digest binds the selected canonical events, artifacts and reconstructed snapshot.
5803
+ Run update timestamps reconstructed from events use their recorded `occurredAt`. Abandon transitions
5804
+ retain the full failed assistant in the same event; a legacy archive must retain that exact assistant
5805
+ in its runtime snapshot, otherwise copying refuses instead of inventing historical content or time.
5806
+
5807
+ No provider or tool runs during copying. The next ordinary runtime `submit` continues the copied
5808
+ history. All engine identities and typed references are new, including repeated references to one
5809
+ spill. Compacted content stays in the event history and SQLite inactive rows; the model reads the
5810
+ same active summaries. A hash-only checkpoint is historical digest evidence, marked
5811
+ `sourceSha256`; a later full terminal record must settle its content.
5812
+
5813
+ A branch grants no source authority. Terminal run owners/fences and approval signatures are
5814
+ removed. State, schedules, children, retries, sandbox, approval rejection and durability facts are
5815
+ retained as inert `runtime/branch-observation` records; they cannot repopulate operational state
5816
+ or pending effects. Spills discard source authorization and require the explicit fresh
5817
+ `artifactAuthorization`; normal destination read authorization still applies. No cached projection,
5818
+ schedule row or child relation is cloned. Ordinary companion projections in the export have
5819
+ `{ name, version, uptoSeq, value, updatedAt }` envelopes. Branch validates their envelopes,
5820
+ unique names and checkpoints within the supplied journal, then discards their values. They are
5821
+ derived application caches, including ones containing source references; their values are never
5822
+ replayed as state or copied as authority. Rebuild destination projections with
5823
+ `createSqliteAgentProjectionStore().advance(...)` over the destination ledger. An exact earlier
5824
+ boundary never inherits a later cache value.
5825
+
5826
+ The store validates the complete archive before writing: contiguous events, a matching runtime
5827
+ snapshot, known typed forms, reference closure, and spill bytes/digests. Unsupported provider
5828
+ envelopes, encrypted invocation payloads, unknown event versions, malformed projection envelopes,
5829
+ missing artifacts and undocumented reference fields in opaque JSON refuse atomically. They need
5830
+ an owner-defined transfer codec; never recursively rewrite internal JSON in the application.
5831
+ Third-party drivers must provide atomic write transactions and archive support for spills;
5832
+ `history.restore` is required for migrated baselines with inactive rows.
5833
+
5768
5834
  ### Event ledger, projections and durable capabilities
5769
5835
 
5770
5836
  `AgentRuntimeStore` exposes bounded `readEvents`, declared `appendEvent`, canonical
@@ -5776,6 +5842,15 @@ upstream name comes from the model provider's own `resolveResponseProvider` —
5776
5842
  supplies it — so the runtime carries the fact without learning any gateway's metadata key. The normalized
5777
5843
  head/run/message tables remain the fast operational projection.
5778
5844
 
5845
+ For `runtime/transition` payload inspection, use `AgentStoreTransitionRecordSchema` and its
5846
+ inferred `AgentStoreTransitionRecord` type. A checkpoint record may hold either the full assistant
5847
+ message or `{ id, status: 'streaming', sha256?, sourceSha256?, parts: number, bytes: number }`;
5848
+ exactly one digest is present. Numeric `parts` counts parts; it is not an array of message parts.
5849
+ `sourceSha256` preserves a branch's historical source digest. These hash-only records are
5850
+ observations, not executable checkpoint inputs. `AgentStoreTransitionSchema` describes full
5851
+ store mutations. Shape inspection does not replace branch's complete replay/reference validation.
5852
+ Schema v4 archives written by 0.109.4 use the same journal representation.
5853
+
5779
5854
  Use `defineAgentProjection` with `createSqliteAgentProjectionStore` for a
5780
5855
  deterministic versioned fold. Every value reports `uptoSeq`, so a caller can
5781
5856
  distinguish current data from a projection that still has events to consume.
@@ -21702,6 +21777,9 @@ Server-only optional application runtime. See the
21702
21777
  | `AgentMessageSchema` / `AgentRunSchema` / `AgentSnapshotSchema` | schema | versioned canonical engine records |
21703
21778
  | `AgentRunQueuePrioritySchema` | schema | durable opt-in priority for queued `interrupt-next` runs |
21704
21779
  | `AgentRuntimeStore` | _type_ | aggregate CAS transaction boundary for message, run and compaction mutations |
21780
+ | `BranchAgentConversationInputSchema` / `BranchAgentConversationInput` | schema / _type_ | strict branch request: stable request key, empty destination, settled conversation boundary or archive bytes, fresh artifact authorization |
21781
+ | `AgentConversationBranchReceiptSchema` / `AgentConversationBranchReceipt` | schema / _type_ | durable lineage: request fingerprint, source/destination identities, source sequence/version/digest and creation time |
21782
+ | `AgentConversationBranchResultSchema` / `AgentConversationBranchResult` | schema / _type_ | `created` or `duplicate` with the same durable receipt; `AgentRuntimeStore.branchConversation` is optional for hand-written stores |
21705
21783
  | `createAgentRuntimeStore` | function | build the aggregate store from one coherent transaction driver; framework owns every state transition |
21706
21784
  | `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 |
21707
21785
  | `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 |
@@ -21772,6 +21850,7 @@ Server-only optional application runtime. See the
21772
21850
  | `AgentStoreEventEnvelopeSchema` / `AgentStoreEventEnvelope` / `AgentStoreEventKindSchema` / `AgentStoreEventKind` / `AgentStoreEventPageSchema` / `AgentStoreEventPage` | schema / _type_ | append-only event envelope, closed current vocabulary (including `provider/request` and `provider/response`) and bounded page |
21773
21851
  | `AppendAgentStoreEventSchema` / `AppendAgentStoreEvent` / `ReadAgentStoreEventsSchema` / `ReadAgentStoreEvents` | schema / _type_ | required append and bounded-read store contracts |
21774
21852
  | `AgentStoreTransitionSchema` / `AgentStoreTransition` / `AgentStoreEventDraft` / `AgentStoreEventDecodeAccepted` / `AgentStoreEventDecodeIgnored` / `AgentStoreEventDecodeResult` / `decodeAgentStoreEvent` | schema / _types_ / function | normalized runtime mutations, append drafts and strict current/ignorable future-event decoding outcomes |
21853
+ | `AgentStoreTransitionRecordSchema` / `AgentStoreTransitionRecord` | schema / _type_ | persisted journal payloads: full runtime mutations or hash-only streaming checkpoint observations with numeric part/byte counts; inspection does not authorize replay |
21775
21854
  | `defineAgentProjection` / `AgentProjectionDefinition` / `AgentProjectionValue` / `createAgentProjectionRegistry` / `createSqliteAgentProjectionStore` | functions / _type_ | deterministic folds with persisted version and honest `uptoSeq` checkpoints |
21776
21855
  | `agentSummaryProjection` / `agentUsageProjection` / `agentOutlineProjection` | constants | built-in list summary, provenance-carrying usage and request outline projections |
21777
21856
  | `agentConversationCardProjection` / `agentStateSlotsProjection` / `agentScheduleSummaryProjection` | constants | focused card, durable-state and schedule lifecycle projections |
package/llms.txt CHANGED
@@ -25,7 +25,7 @@ Load the slice for each entrypoint your code imports — `import … from 'stitc
25
25
  - **stitchkit/primitives**: [llms/primitives.txt](llms/primitives.txt) 11.7 KB
26
26
  - **stitchkit/server**: [llms/server.txt](llms/server.txt) 45.3 KB → [llms/server.2.txt](llms/server.2.txt) 14.6 KB → [llms/server.3.txt](llms/server.3.txt) 45.6 KB → [llms/server.4.txt](llms/server.4.txt) 38.3 KB → [llms/server.5.txt](llms/server.5.txt) 22.1 KB
27
27
  - **stitchkit/observability**: [llms/observability.txt](llms/observability.txt) 45.9 KB
28
- - **stitchkit/agent-runtime**: [llms/agent-runtime.txt](llms/agent-runtime.txt) 37.1 KB → [llms/agent-runtime.2.txt](llms/agent-runtime.2.txt) 46.7 KB → [llms/agent-runtime.3.txt](llms/agent-runtime.3.txt) 34.7 KB
28
+ - **stitchkit/agent-runtime**: [llms/agent-runtime.txt](llms/agent-runtime.txt) 42.2 KB → [llms/agent-runtime.2.txt](llms/agent-runtime.2.txt) 46.7 KB → [llms/agent-runtime.3.txt](llms/agent-runtime.3.txt) 35.6 KB
29
29
  - **stitchkit/agent-runtime/testing**: [llms/agent-runtime-testing.txt](llms/agent-runtime-testing.txt) 2.6 KB
30
30
  - **stitchkit/agent-runtime/harness**: [llms/agent-runtime-harness.txt](llms/agent-runtime-harness.txt) 11.0 KB
31
31
  - **stitchkit/agent-runtime/coding-tools**: [llms/agent-runtime-coding-tools.txt](llms/agent-runtime-coding-tools.txt) 5.0 KB
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stitchkit",
3
- "version": "0.110.1",
3
+ "version": "0.110.3",
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",
@@ -1,129 +0,0 @@
1
- import {
2
- AppError2,
3
- STITCH_ERROR_STATUS2
4
- } from "./index-j9gxbztg.js";
5
-
6
- // src/agent-runtime/sandbox.ts
7
- import { z } from "zod";
8
- var AgentSandboxRestrictionSchema2 = z.enum([
9
- "network-denied",
10
- "write-contained",
11
- "secrets-hidden",
12
- "process-contained"
13
- ]);
14
- var AgentSandboxGradeSchema2 = z.discriminatedUnion("grade", [
15
- z.object({ grade: z.literal("full"), restrictions: z.array(AgentSandboxRestrictionSchema2) }).strict(),
16
- z.object({
17
- grade: z.literal("partial"),
18
- restrictions: z.array(AgentSandboxRestrictionSchema2),
19
- gaps: z.array(AgentSandboxRestrictionSchema2)
20
- }).strict(),
21
- z.object({ grade: z.literal("unavailable"), reason: z.string().min(1) }).strict()
22
- ]);
23
- var probes = new WeakMap;
24
- var PROBE_FAILED = "sandbox probe failed";
25
- var PROBE_INVALID = "sandbox probe returned no valid grade";
26
- async function runProbe(sandbox) {
27
- let value;
28
- try {
29
- value = await sandbox.probe();
30
- } catch (cause) {
31
- return { grade: { grade: "unavailable", reason: PROBE_FAILED }, cause };
32
- }
33
- const parsed = AgentSandboxGradeSchema2.safeParse(value);
34
- if (parsed.success)
35
- return { grade: parsed.data };
36
- return { grade: { grade: "unavailable", reason: PROBE_INVALID }, cause: parsed.error };
37
- }
38
- function probeAgentProcessSandboxOutcome(sandbox, options = {}) {
39
- if (options.refresh)
40
- probes.delete(sandbox);
41
- const present = probes.get(sandbox);
42
- if (present)
43
- return present;
44
- const pending = runProbe(sandbox);
45
- probes.set(sandbox, pending);
46
- return pending;
47
- }
48
- async function probeAgentProcessSandbox2(sandbox, options = {}) {
49
- const fresh = options.refresh === true || !probes.has(sandbox);
50
- const outcome = await probeAgentProcessSandboxOutcome(sandbox, options);
51
- if (fresh && outcome.cause !== undefined) {
52
- process.emitWarning(new Error("Sandbox probe failed", { cause: outcome.cause }));
53
- }
54
- return outcome.grade;
55
- }
56
- function missingSandboxRestrictions2(grade, required) {
57
- if (grade.grade === "unavailable")
58
- return required;
59
- const present = new Set(grade.restrictions);
60
- return required.filter((restriction) => !present.has(restriction));
61
- }
62
- async function recordAgentSandboxProbe2(input) {
63
- const grade = await probeAgentProcessSandbox2(input.sandbox);
64
- const missing = missingSandboxRestrictions2(grade, input.required);
65
- await input.store.appendEvent({
66
- conversationId: input.conversationId,
67
- kind: "sandbox/probed",
68
- payload: {
69
- result: grade,
70
- required: [...input.required],
71
- missing: [...missing]
72
- }
73
- });
74
- return grade;
75
- }
76
-
77
- // src/agent-runtime/coding-tool-refusals.ts
78
- function codingRefusal(code, message, options = {}) {
79
- throw new AppError2(code, {
80
- message,
81
- status: STITCH_ERROR_STATUS2[code],
82
- details: { message, ...options.details },
83
- hint: options.hint,
84
- ..."cause" in options && { cause: options.cause }
85
- });
86
- }
87
- function codingPathRefusal(code, message, path, options = {}) {
88
- codingRefusal(code, message, {
89
- details: { path, ...options.details },
90
- ...options.hint && { hint: options.hint }
91
- });
92
- }
93
- function refuseMissingCodingPath(error, relative) {
94
- const code = error?.code;
95
- if (error instanceof Error && error.message.includes("is not a regular file")) {
96
- codingPathRefusal("BAD_REQUEST", "This path is not a regular file", relative, {
97
- hint: "Use list_directory to see what is here."
98
- });
99
- }
100
- if (code === "ENOENT") {
101
- codingPathRefusal("NOT_FOUND", "This path does not exist", relative, {
102
- hint: "Use list_directory or glob to find the right path."
103
- });
104
- }
105
- if (code === "ENOTDIR") {
106
- codingPathRefusal("BAD_REQUEST", "A segment of this path is not a directory", relative, {
107
- hint: "Check the path with list_directory."
108
- });
109
- }
110
- if (code === "ELOOP") {
111
- codingPathRefusal("FORBIDDEN", "This path is a symlink, which is not followed", relative, {
112
- hint: "Read or write the target directly, by its own workspace-relative path."
113
- });
114
- }
115
- if (code === "EISDIR") {
116
- codingPathRefusal("BAD_REQUEST", "This path is not a regular file", relative, {
117
- hint: "Use list_directory to see what is here."
118
- });
119
- }
120
- throw error;
121
- }
122
- function refuseUnknownSpillReference(reference) {
123
- codingRefusal("SPILL_REFERENCE_UNKNOWN", `No spilled output is held under \`${reference}\``, {
124
- details: { reference },
125
- hint: "Use the reference returned by the command that spilled its output, not a session or call id."
126
- });
127
- }
128
-
129
- export { AgentSandboxRestrictionSchema2, AgentSandboxGradeSchema2, probeAgentProcessSandboxOutcome, probeAgentProcessSandbox2, missingSandboxRestrictions2, recordAgentSandboxProbe2, codingRefusal, codingPathRefusal, refuseMissingCodingPath, refuseUnknownSpillReference };