stitchkit 0.85.2 → 0.87.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 (118) hide show
  1. package/CHANGELOG.md +243 -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/conversations.d.ts +11 -0
  19. package/dist/agent-runtime/conversations.d.ts.map +1 -1
  20. package/dist/agent-runtime/event-schema.d.ts +34 -0
  21. package/dist/agent-runtime/event-schema.d.ts.map +1 -1
  22. package/dist/agent-runtime/event-search-tools.d.ts +53 -0
  23. package/dist/agent-runtime/event-search-tools.d.ts.map +1 -0
  24. package/dist/agent-runtime/event-search.d.ts +23 -0
  25. package/dist/agent-runtime/event-search.d.ts.map +1 -0
  26. package/dist/agent-runtime/fault-bench.d.ts +45 -0
  27. package/dist/agent-runtime/fault-bench.d.ts.map +1 -0
  28. package/dist/agent-runtime/observability.d.ts +6 -0
  29. package/dist/agent-runtime/observability.d.ts.map +1 -1
  30. package/dist/agent-runtime/projections.d.ts +69 -0
  31. package/dist/agent-runtime/projections.d.ts.map +1 -0
  32. package/dist/agent-runtime/provider-failure.d.ts +5 -1
  33. package/dist/agent-runtime/provider-failure.d.ts.map +1 -1
  34. package/dist/agent-runtime/provider-origin.d.ts +12 -0
  35. package/dist/agent-runtime/provider-origin.d.ts.map +1 -0
  36. package/dist/agent-runtime/retry-policy.d.ts +27 -0
  37. package/dist/agent-runtime/retry-policy.d.ts.map +1 -0
  38. package/dist/agent-runtime/run-execution.d.ts +0 -9
  39. package/dist/agent-runtime/run-execution.d.ts.map +1 -1
  40. package/dist/agent-runtime/run-operation-lifecycle.d.ts.map +1 -1
  41. package/dist/agent-runtime/runtime.d.ts +15 -0
  42. package/dist/agent-runtime/runtime.d.ts.map +1 -1
  43. package/dist/agent-runtime/sandbox.d.ts +66 -0
  44. package/dist/agent-runtime/sandbox.d.ts.map +1 -0
  45. package/dist/agent-runtime/schedule-tools.d.ts +35 -0
  46. package/dist/agent-runtime/schedule-tools.d.ts.map +1 -0
  47. package/dist/agent-runtime/schedules.d.ts +63 -0
  48. package/dist/agent-runtime/schedules.d.ts.map +1 -0
  49. package/dist/agent-runtime/schemas.d.ts +9 -0
  50. package/dist/agent-runtime/schemas.d.ts.map +1 -1
  51. package/dist/agent-runtime/spill.d.ts +24 -0
  52. package/dist/agent-runtime/spill.d.ts.map +1 -0
  53. package/dist/agent-runtime/sqlite-purge.d.ts.map +1 -1
  54. package/dist/agent-runtime/sqlite.d.ts +26 -0
  55. package/dist/agent-runtime/sqlite.d.ts.map +1 -1
  56. package/dist/agent-runtime/state-slots.d.ts +48 -0
  57. package/dist/agent-runtime/state-slots.d.ts.map +1 -0
  58. package/dist/agent-runtime/state-tools.d.ts +58 -0
  59. package/dist/agent-runtime/state-tools.d.ts.map +1 -0
  60. package/dist/agent-runtime/store-driver.d.ts +13 -0
  61. package/dist/agent-runtime/store-driver.d.ts.map +1 -1
  62. package/dist/agent-runtime/store-events.d.ts +829 -0
  63. package/dist/agent-runtime/store-events.d.ts.map +1 -0
  64. package/dist/agent-runtime/store-migrations/v1-to-v2.d.ts +6 -0
  65. package/dist/agent-runtime/store-migrations/v1-to-v2.d.ts.map +1 -0
  66. package/dist/agent-runtime/store.d.ts +45 -0
  67. package/dist/agent-runtime/store.d.ts.map +1 -1
  68. package/dist/agent-runtime/terminal-commit.d.ts +1 -1
  69. package/dist/agent-runtime-browser.js +5 -3
  70. package/dist/agent-runtime-coding-tools.js +144 -15
  71. package/dist/agent-runtime-harness.js +12 -11
  72. package/dist/agent-runtime-sqlite-bun.d.ts +1 -1
  73. package/dist/agent-runtime-sqlite-bun.d.ts.map +1 -1
  74. package/dist/agent-runtime-sqlite-bun.js +5 -4
  75. package/dist/agent-runtime-sqlite-node.d.ts +1 -1
  76. package/dist/agent-runtime-sqlite-node.d.ts.map +1 -1
  77. package/dist/agent-runtime-sqlite-node.js +5 -4
  78. package/dist/agent-runtime-testing.d.ts +3 -0
  79. package/dist/agent-runtime-testing.d.ts.map +1 -0
  80. package/dist/agent-runtime-testing.js +156 -0
  81. package/dist/agent-runtime.d.ts +16 -2
  82. package/dist/agent-runtime.d.ts.map +1 -1
  83. package/dist/agent-runtime.js +1632 -156
  84. package/dist/application.js +14 -14
  85. package/dist/cli.js +6 -6
  86. package/dist/{index-fwbkp2jn.js → index-0vfdh685.js} +2 -2
  87. package/dist/{index-5z8tezpx.js → index-0ydchz76.js} +3 -3
  88. package/dist/{index-3ds42w1w.js → index-1szetq6f.js} +33 -4
  89. package/dist/{index-2jg7b11j.js → index-35aefxby.js} +879 -424
  90. package/dist/index-3yrqvza8.js +964 -0
  91. package/dist/{index-fq492hg0.js → index-5wezxcxx.js} +238 -161
  92. package/dist/index-9553432s.js +26 -0
  93. package/dist/{index-27487ay5.js → index-9hw9eq48.js} +4 -4
  94. package/dist/index-cnyk6te3.js +77 -0
  95. package/dist/index-gskm1k5a.js +50 -0
  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-dggwnnjv.js → index-wn9cb82y.js} +1 -1
  102. package/dist/index-z1m86vc8.js +334 -0
  103. package/dist/{index-ff0kcqvp.js → index-z2452tsw.js} +3 -3
  104. package/dist/internal/sqlite.d.ts +13 -0
  105. package/dist/internal/sqlite.d.ts.map +1 -1
  106. package/dist/testing/agent-store-conformance.d.ts.map +1 -1
  107. package/dist/testing.js +89 -80
  108. package/dist/tool-invoker.js +4 -4
  109. package/dist/tools/internal/surface-projector.d.ts.map +1 -1
  110. package/dist/tools/manifest.d.ts +16 -0
  111. package/dist/tools/manifest.d.ts.map +1 -1
  112. package/dist/tools.d.ts +1 -1
  113. package/dist/tools.d.ts.map +1 -1
  114. package/dist/tools.js +10 -8
  115. package/llms-full.txt +373 -16
  116. package/package.json +6 -1
  117. package/dist/index-66nxrgy0.js +0 -554
  118. package/dist/index-y2s6h5bf.js +0 -83
@@ -0,0 +1,964 @@
1
+ import {
2
+ AgentConversationMessagePageSchema,
3
+ AgentConversationPageSchema
4
+ } from "./index-9553432s.js";
5
+ import {
6
+ AgentAdmissionReceiptSchema,
7
+ AgentConversationPurgedError,
8
+ AgentHistoryMutationSchema,
9
+ AgentRuntimeHeadSchema,
10
+ AgentStoredRunSchema,
11
+ createAgentRuntimeStore
12
+ } from "./index-5wezxcxx.js";
13
+ import {
14
+ AgentRecoverableDescriptorSchema,
15
+ AgentRecoverablePageSchema,
16
+ AgentStoreEventEnvelopeSchema,
17
+ AgentStoreEventPageSchema,
18
+ AppendAgentStoreEventSchema,
19
+ agentStoreEventDraft,
20
+ canonicalAgentJson
21
+ } from "./index-z1m86vc8.js";
22
+ import {
23
+ AgentMessageSchema,
24
+ AgentRunSchema
25
+ } from "./index-p1b1y93x.js";
26
+
27
+ // src/agent-runtime/sqlite.ts
28
+ import { AsyncLocalStorage } from "node:async_hooks";
29
+ import { createHash } from "node:crypto";
30
+ import { z as z2 } from "zod";
31
+
32
+ // src/agent-runtime/sqlite-purge.ts
33
+ var OWNED_TABLES = [
34
+ "stitchkit_agent_runtime_spills",
35
+ "stitchkit_agent_runtime_schedules",
36
+ "stitchkit_agent_runtime_projections",
37
+ "stitchkit_agent_runtime_events",
38
+ "stitchkit_agent_runtime_messages",
39
+ "stitchkit_agent_runtime_admissions",
40
+ "stitchkit_agent_runtime_runs",
41
+ "stitchkit_agent_runtime_heads"
42
+ ];
43
+ function initializeSqliteConversationPurge(database) {
44
+ database.exec(`
45
+ CREATE TABLE IF NOT EXISTS stitchkit_agent_runtime_purged (
46
+ conversation_id TEXT PRIMARY KEY
47
+ );
48
+ `);
49
+ for (const table of OWNED_TABLES) {
50
+ for (const operation of ["INSERT", "UPDATE"]) {
51
+ database.exec(`
52
+ CREATE TRIGGER IF NOT EXISTS ${table}_purge_${operation.toLowerCase()}
53
+ BEFORE ${operation} ON ${table}
54
+ WHEN EXISTS (
55
+ SELECT 1 FROM stitchkit_agent_runtime_purged WHERE conversation_id = NEW.conversation_id
56
+ )
57
+ BEGIN SELECT RAISE(ABORT, 'Agent conversation has been purged'); END;
58
+ `);
59
+ }
60
+ }
61
+ }
62
+ function sqliteConversationPurge(database) {
63
+ const table = database.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'stitchkit_agent_runtime_purged'").get();
64
+ if (table === null || table === undefined)
65
+ return;
66
+ return {
67
+ async isPurged(transaction, conversationId) {
68
+ const row = transaction.prepare("SELECT conversation_id FROM stitchkit_agent_runtime_purged WHERE conversation_id = ?").get(conversationId);
69
+ return row !== null && row !== undefined;
70
+ },
71
+ async remove(transaction, conversationId) {
72
+ transaction.prepare("INSERT INTO stitchkit_agent_runtime_purged (conversation_id) VALUES (?)").run(conversationId);
73
+ for (const table2 of OWNED_TABLES) {
74
+ transaction.prepare(`DELETE FROM ${table2} WHERE conversation_id = ?`).run(conversationId);
75
+ }
76
+ transaction.prepare("DELETE FROM stitchkit_agent_runtime_children WHERE parent_conversation_id = ? OR child_conversation_id = ?").run(conversationId, conversationId);
77
+ }
78
+ };
79
+ }
80
+
81
+ // src/agent-runtime/store-migrations/v1-to-v2.ts
82
+ import { randomUUID } from "node:crypto";
83
+ import { z } from "zod";
84
+ var ConversationRowSchema = z.object({
85
+ conversation_id: z.string().min(1),
86
+ version: z.int().nonnegative()
87
+ });
88
+ var PayloadRowSchema = z.object({
89
+ payload: z.string(),
90
+ terminal_assistant_payload: z.string().nullable().optional()
91
+ });
92
+ var HistoryRowSchema = z.object({
93
+ payload: z.string(),
94
+ active: z.union([z.literal(0), z.literal(1)])
95
+ });
96
+ var AdmissionRowSchema = z.object({
97
+ conversation_id: z.string(),
98
+ idempotency_key: z.string(),
99
+ input_payload: z.string(),
100
+ run_id: z.string(),
101
+ assistant_message_id: z.string()
102
+ });
103
+ function parseJson(value) {
104
+ return JSON.parse(value);
105
+ }
106
+ function createDurableTables(database) {
107
+ database.exec(`
108
+ CREATE TABLE IF NOT EXISTS stitchkit_agent_runtime_events (
109
+ row_id INTEGER PRIMARY KEY AUTOINCREMENT,
110
+ conversation_id TEXT NOT NULL,
111
+ seq INTEGER NOT NULL CHECK (seq > 0),
112
+ event_id TEXT NOT NULL UNIQUE,
113
+ schema_version INTEGER NOT NULL CHECK (schema_version > 0),
114
+ kind TEXT NOT NULL,
115
+ occurred_at TEXT NOT NULL,
116
+ ignorable INTEGER NOT NULL DEFAULT 0 CHECK (ignorable IN (0, 1)),
117
+ payload TEXT NOT NULL,
118
+ UNIQUE (conversation_id, seq)
119
+ );
120
+ CREATE INDEX IF NOT EXISTS stitchkit_agent_runtime_events_time
121
+ ON stitchkit_agent_runtime_events (conversation_id, occurred_at, seq);
122
+ CREATE TABLE IF NOT EXISTS stitchkit_agent_runtime_projections (
123
+ conversation_id TEXT NOT NULL,
124
+ name TEXT NOT NULL,
125
+ version INTEGER NOT NULL CHECK (version > 0),
126
+ upto_seq INTEGER NOT NULL CHECK (upto_seq >= 0),
127
+ payload TEXT NOT NULL,
128
+ updated_at TEXT NOT NULL,
129
+ PRIMARY KEY (conversation_id, name)
130
+ );
131
+ CREATE INDEX IF NOT EXISTS stitchkit_agent_runtime_projection_updates
132
+ ON stitchkit_agent_runtime_projections (name, updated_at, conversation_id);
133
+ CREATE TABLE IF NOT EXISTS stitchkit_agent_runtime_spills (
134
+ reference_id TEXT PRIMARY KEY,
135
+ conversation_id TEXT NOT NULL,
136
+ run_id TEXT,
137
+ tool_call_id TEXT,
138
+ media_type TEXT NOT NULL,
139
+ bytes INTEGER NOT NULL CHECK (bytes >= 0),
140
+ sha256 TEXT NOT NULL,
141
+ created_at TEXT NOT NULL,
142
+ expires_at TEXT,
143
+ authorization_payload TEXT,
144
+ payload BLOB NOT NULL
145
+ );
146
+ CREATE INDEX IF NOT EXISTS stitchkit_agent_runtime_spills_owner
147
+ ON stitchkit_agent_runtime_spills (conversation_id, created_at);
148
+ CREATE TABLE IF NOT EXISTS stitchkit_agent_runtime_schedules (
149
+ id TEXT PRIMARY KEY,
150
+ conversation_id TEXT NOT NULL,
151
+ kind TEXT NOT NULL,
152
+ next_at TEXT NOT NULL,
153
+ interval_ms INTEGER,
154
+ time_zone TEXT,
155
+ input_payload TEXT NOT NULL,
156
+ state TEXT NOT NULL,
157
+ occurrence INTEGER NOT NULL DEFAULT 0 CHECK (occurrence >= 0),
158
+ claim_owner TEXT,
159
+ claim_until TEXT,
160
+ created_at TEXT NOT NULL,
161
+ updated_at TEXT NOT NULL
162
+ );
163
+ CREATE INDEX IF NOT EXISTS stitchkit_agent_runtime_schedules_due
164
+ ON stitchkit_agent_runtime_schedules (state, next_at);
165
+ CREATE TABLE IF NOT EXISTS stitchkit_agent_runtime_children (
166
+ parent_conversation_id TEXT NOT NULL,
167
+ child_conversation_id TEXT NOT NULL UNIQUE,
168
+ seed_upto_seq INTEGER,
169
+ state TEXT NOT NULL,
170
+ budget_payload TEXT NOT NULL,
171
+ usage_payload TEXT NOT NULL,
172
+ result_reference TEXT,
173
+ created_at TEXT NOT NULL,
174
+ updated_at TEXT NOT NULL,
175
+ PRIMARY KEY (parent_conversation_id, child_conversation_id)
176
+ );
177
+ `);
178
+ try {
179
+ database.exec(`
180
+ CREATE VIRTUAL TABLE IF NOT EXISTS stitchkit_agent_runtime_events_fts
181
+ USING fts5(
182
+ conversation_id UNINDEXED,
183
+ event_seq UNINDEXED,
184
+ occurred_at UNINDEXED,
185
+ body,
186
+ tokenize = 'unicode61 remove_diacritics 2'
187
+ );
188
+ CREATE TRIGGER IF NOT EXISTS stitchkit_agent_runtime_events_fts_insert
189
+ AFTER INSERT ON stitchkit_agent_runtime_events BEGIN
190
+ INSERT INTO stitchkit_agent_runtime_events_fts(
191
+ rowid, conversation_id, event_seq, occurred_at, body
192
+ ) VALUES (new.row_id, new.conversation_id, new.seq, new.occurred_at, new.payload);
193
+ END;
194
+ CREATE TRIGGER IF NOT EXISTS stitchkit_agent_runtime_events_fts_delete
195
+ AFTER DELETE ON stitchkit_agent_runtime_events BEGIN
196
+ DELETE FROM stitchkit_agent_runtime_events_fts WHERE rowid = old.row_id;
197
+ END;
198
+ `);
199
+ } catch (error) {
200
+ throw new Error("SQLite agent-runtime requires FTS5 support", { cause: error });
201
+ }
202
+ }
203
+ function writeBaselines(database, migratedAt) {
204
+ const conversations = database.prepare("SELECT conversation_id, version FROM stitchkit_agent_runtime_heads ORDER BY conversation_id").all().map((row) => ConversationRowSchema.parse(row));
205
+ const insert = database.prepare(`
206
+ INSERT INTO stitchkit_agent_runtime_events (
207
+ conversation_id, seq, event_id, schema_version, kind, occurred_at, ignorable, payload
208
+ ) VALUES (?, 1, ?, 1, 'runtime/baseline', ?, 0, ?)
209
+ `);
210
+ for (const conversation of conversations) {
211
+ const rows = database.prepare("SELECT payload, active FROM stitchkit_agent_runtime_messages WHERE conversation_id = ? ORDER BY position, rowid").all(conversation.conversation_id).map((row) => {
212
+ const parsed = HistoryRowSchema.parse(row);
213
+ return {
214
+ message: AgentMessageSchema.parse(parseJson(parsed.payload)),
215
+ active: parsed.active === 1
216
+ };
217
+ });
218
+ const messages = rows.map((row) => row.message);
219
+ const compacted = rows.filter((row) => !row.active).map((row) => row.message.id);
220
+ const runs = database.prepare("SELECT payload, terminal_assistant_payload FROM stitchkit_agent_runtime_runs WHERE conversation_id = ? ORDER BY created_at, run_id").all(conversation.conversation_id).map((value) => {
221
+ const row = PayloadRowSchema.parse(value);
222
+ return {
223
+ schemaVersion: 1,
224
+ run: AgentRunSchema.parse(parseJson(row.payload)),
225
+ ...row.terminal_assistant_payload ? {
226
+ terminalAssistant: AgentMessageSchema.parse(parseJson(row.terminal_assistant_payload))
227
+ } : {}
228
+ };
229
+ });
230
+ const admissions = database.prepare("SELECT conversation_id, idempotency_key, input_payload, run_id, assistant_message_id FROM stitchkit_agent_runtime_admissions WHERE conversation_id = ? ORDER BY idempotency_key").all(conversation.conversation_id).map((value) => {
231
+ const row = AdmissionRowSchema.parse(value);
232
+ return {
233
+ schemaVersion: 1,
234
+ conversationId: row.conversation_id,
235
+ idempotencyKey: row.idempotency_key,
236
+ input: AgentMessageSchema.parse(parseJson(row.input_payload)),
237
+ runId: row.run_id,
238
+ assistantMessageId: row.assistant_message_id
239
+ };
240
+ });
241
+ const asOf = messages.at(-1)?.createdAt ?? runs.at(-1)?.run.createdAt;
242
+ insert.run(conversation.conversation_id, randomUUID(), migratedAt, canonicalAgentJson({
243
+ migratedAt,
244
+ ...asOf !== undefined && { asOf },
245
+ head: {
246
+ schemaVersion: 1,
247
+ conversationId: conversation.conversation_id,
248
+ version: conversation.version
249
+ },
250
+ messages,
251
+ ...compacted.length > 0 && { compacted },
252
+ runs,
253
+ admissions
254
+ }));
255
+ }
256
+ }
257
+ function migrateAgentRuntimeSqliteV1ToV2(database, migratedAt = new Date().toISOString()) {
258
+ createDurableTables(database);
259
+ writeBaselines(database, migratedAt);
260
+ database.prepare("UPDATE stitchkit_agent_runtime_meta SET value = '2' WHERE key = 'schema_version'").run();
261
+ }
262
+ function createAgentRuntimeSqliteV2Tables(database) {
263
+ createDurableTables(database);
264
+ }
265
+
266
+ // src/agent-runtime/sqlite.ts
267
+ var HeadRowSchema = z2.object({ version: z2.number().int().nonnegative() });
268
+ var RunRowSchema = z2.object({
269
+ payload: z2.string(),
270
+ terminal_assistant_payload: z2.string().nullable()
271
+ });
272
+ var AdmissionRowSchema2 = z2.object({
273
+ conversation_id: z2.string(),
274
+ idempotency_key: z2.string(),
275
+ input_payload: z2.string(),
276
+ run_id: z2.string(),
277
+ assistant_message_id: z2.string()
278
+ });
279
+ var MessageRowSchema = z2.object({ payload: z2.string() });
280
+ var PositionedMessageRowSchema = z2.object({ position: z2.number().int().nonnegative() });
281
+ var RecoverableRowSchema = z2.object({
282
+ conversation_id: z2.string(),
283
+ run_id: z2.string(),
284
+ payload: z2.string()
285
+ });
286
+ var MetaRowSchema = z2.object({ value: z2.string() });
287
+ var TableRowSchema = z2.object({ name: z2.string() });
288
+ var ConversationHeadRowSchema = z2.object({
289
+ conversation_id: z2.string(),
290
+ version: z2.number().int().nonnegative()
291
+ });
292
+ var CountRowSchema = z2.object({ count: z2.number().int().nonnegative() });
293
+ var MessagePageRowSchema = z2.object({
294
+ row_id: z2.number().int().positive(),
295
+ position: z2.number().int().nonnegative(),
296
+ active: z2.union([z2.literal(0), z2.literal(1)]),
297
+ payload: z2.string()
298
+ });
299
+ var EventRowSchema = z2.object({
300
+ event_id: z2.string(),
301
+ conversation_id: z2.string(),
302
+ seq: z2.int().positive(),
303
+ schema_version: z2.int().positive(),
304
+ kind: z2.string(),
305
+ occurred_at: z2.string(),
306
+ ignorable: z2.union([z2.literal(0), z2.literal(1)]),
307
+ payload: z2.string()
308
+ });
309
+ var ArchiveProjectionRowSchema = z2.object({
310
+ name: z2.string(),
311
+ version: z2.int().positive(),
312
+ upto_seq: z2.int().nonnegative(),
313
+ payload: z2.string(),
314
+ updated_at: z2.string()
315
+ });
316
+ var ArchiveSpillRowSchema = z2.object({
317
+ reference_id: z2.string(),
318
+ run_id: z2.string().nullable(),
319
+ tool_call_id: z2.string().nullable(),
320
+ media_type: z2.string(),
321
+ bytes: z2.int().nonnegative(),
322
+ sha256: z2.string(),
323
+ created_at: z2.string(),
324
+ expires_at: z2.string().nullable(),
325
+ authorization_payload: z2.string().nullable(),
326
+ payload: z2.instanceof(Uint8Array)
327
+ });
328
+ var SCHEMA_VERSION = 2;
329
+ var TABLES = [
330
+ "stitchkit_agent_runtime_heads",
331
+ "stitchkit_agent_runtime_runs",
332
+ "stitchkit_agent_runtime_admissions",
333
+ "stitchkit_agent_runtime_messages",
334
+ "stitchkit_agent_runtime_events",
335
+ "stitchkit_agent_runtime_projections",
336
+ "stitchkit_agent_runtime_spills",
337
+ "stitchkit_agent_runtime_schedules",
338
+ "stitchkit_agent_runtime_children"
339
+ ];
340
+ function parseJson2(value) {
341
+ return JSON.parse(value);
342
+ }
343
+ function encodeJson(value) {
344
+ return JSON.stringify(value);
345
+ }
346
+ function missing(value) {
347
+ return value === null || value === undefined;
348
+ }
349
+ function placeholders(count) {
350
+ return Array.from({ length: count }, () => "?").join(", ");
351
+ }
352
+ function parseRunRow(value) {
353
+ const row = RunRowSchema.parse(value);
354
+ return AgentStoredRunSchema.parse({
355
+ schemaVersion: 1,
356
+ run: AgentRunSchema.parse(parseJson2(row.payload)),
357
+ ...row.terminal_assistant_payload === null ? {} : {
358
+ terminalAssistant: AgentMessageSchema.parse(parseJson2(row.terminal_assistant_payload))
359
+ }
360
+ });
361
+ }
362
+ function parseEventRow(value) {
363
+ const row = EventRowSchema.parse(value);
364
+ return AgentStoreEventEnvelopeSchema.parse({
365
+ schemaVersion: row.schema_version,
366
+ eventId: row.event_id,
367
+ conversationId: row.conversation_id,
368
+ seq: row.seq,
369
+ kind: row.kind,
370
+ occurredAt: row.occurred_at,
371
+ payload: parseJson2(row.payload),
372
+ ...row.ignorable === 1 && { ignorable: true }
373
+ });
374
+ }
375
+ function recoveryCursor(conversationId, runId) {
376
+ return encodeJson([conversationId, runId]);
377
+ }
378
+ function parseRecoveryCursor(cursor) {
379
+ return z2.tuple([z2.string().min(1), z2.string().min(1)]).parse(parseJson2(cursor));
380
+ }
381
+ function conversationCursor(conversationId) {
382
+ return encodeJson([conversationId]);
383
+ }
384
+ function parseConversationCursor(cursor) {
385
+ return z2.tuple([z2.string().min(1)]).parse(parseJson2(cursor))[0];
386
+ }
387
+ function messageCursor(position, rowId) {
388
+ return encodeJson([position, rowId]);
389
+ }
390
+ function parseMessageCursor(cursor) {
391
+ const parsed = z2.union([
392
+ z2.tuple([z2.int().nonnegative(), z2.int().positive()]),
393
+ z2.tuple([z2.int().nonnegative()])
394
+ ]).parse(parseJson2(cursor));
395
+ const [position, rowId] = parsed;
396
+ return { position, ...rowId !== undefined && { rowId } };
397
+ }
398
+ function messagePreview(message) {
399
+ const text = message.parts.find((part) => part.type === "text");
400
+ return text?.type === "text" ? text.text.slice(0, 160) : message.role;
401
+ }
402
+ function initializeAgentRuntimeSqlite(database) {
403
+ database.exec("BEGIN IMMEDIATE");
404
+ try {
405
+ const existing = database.prepare(`SELECT name FROM sqlite_master WHERE type = 'table' AND name LIKE 'stitchkit_agent_runtime_%' ORDER BY name`).all().map((row) => TableRowSchema.parse(row).name);
406
+ const hasMeta = existing.includes("stitchkit_agent_runtime_meta");
407
+ if (!hasMeta && existing.length > 0) {
408
+ throw new Error("Refusing an unversioned partial Stitchkit agent-runtime SQLite schema");
409
+ }
410
+ database.exec(`
411
+ CREATE TABLE IF NOT EXISTS stitchkit_agent_runtime_meta (
412
+ key TEXT PRIMARY KEY,
413
+ value TEXT NOT NULL
414
+ );
415
+ `);
416
+ const versionRow = database.prepare("SELECT value FROM stitchkit_agent_runtime_meta WHERE key = 'schema_version'").get();
417
+ if (!missing(versionRow)) {
418
+ const version = Number(MetaRowSchema.parse(versionRow).value);
419
+ if (version === 1) {
420
+ migrateAgentRuntimeSqliteV1ToV2(database);
421
+ initializeSqliteConversationPurge(database);
422
+ database.exec("COMMIT");
423
+ return;
424
+ }
425
+ if (version !== SCHEMA_VERSION) {
426
+ throw new Error(`Unsupported Stitchkit agent-runtime SQLite schema version ${version}; expected ${SCHEMA_VERSION}`);
427
+ }
428
+ const missingTables = TABLES.filter((table) => !existing.includes(table));
429
+ if (missingTables.length > 0) {
430
+ throw new Error(`Refusing a partial Stitchkit agent-runtime SQLite schema; missing ${missingTables.join(", ")}`);
431
+ }
432
+ initializeSqliteConversationPurge(database);
433
+ database.exec("COMMIT");
434
+ return;
435
+ }
436
+ if (existing.some((table) => table !== "stitchkit_agent_runtime_meta")) {
437
+ throw new Error("Refusing an unversioned partial Stitchkit agent-runtime SQLite schema");
438
+ }
439
+ database.exec(`
440
+ CREATE TABLE stitchkit_agent_runtime_heads (
441
+ conversation_id TEXT PRIMARY KEY,
442
+ version INTEGER NOT NULL CHECK (version >= 0)
443
+ );
444
+ CREATE TABLE stitchkit_agent_runtime_runs (
445
+ conversation_id TEXT NOT NULL,
446
+ run_id TEXT NOT NULL,
447
+ assistant_message_id TEXT NOT NULL,
448
+ state TEXT NOT NULL,
449
+ created_at TEXT NOT NULL,
450
+ payload TEXT NOT NULL,
451
+ terminal_assistant_payload TEXT,
452
+ PRIMARY KEY (conversation_id, run_id),
453
+ UNIQUE (conversation_id, assistant_message_id)
454
+ );
455
+ CREATE INDEX stitchkit_agent_runtime_recoverable
456
+ ON stitchkit_agent_runtime_runs (state, conversation_id, run_id);
457
+ CREATE TABLE stitchkit_agent_runtime_admissions (
458
+ conversation_id TEXT NOT NULL,
459
+ idempotency_key TEXT NOT NULL,
460
+ input_message_id TEXT NOT NULL,
461
+ run_id TEXT NOT NULL,
462
+ assistant_message_id TEXT NOT NULL,
463
+ input_payload TEXT NOT NULL,
464
+ PRIMARY KEY (conversation_id, idempotency_key),
465
+ UNIQUE (conversation_id, input_message_id)
466
+ );
467
+ CREATE TABLE stitchkit_agent_runtime_messages (
468
+ conversation_id TEXT NOT NULL,
469
+ id TEXT NOT NULL,
470
+ position INTEGER NOT NULL CHECK (position >= 0),
471
+ active INTEGER NOT NULL DEFAULT 1 CHECK (active IN (0, 1)),
472
+ payload TEXT NOT NULL,
473
+ PRIMARY KEY (conversation_id, id)
474
+ );
475
+ `);
476
+ createAgentRuntimeSqliteV2Tables(database);
477
+ database.prepare("INSERT INTO stitchkit_agent_runtime_meta (key, value) VALUES ('schema_version', '2')").run();
478
+ initializeSqliteConversationPurge(database);
479
+ database.exec("COMMIT");
480
+ } catch (error) {
481
+ database.exec("ROLLBACK");
482
+ throw error;
483
+ }
484
+ }
485
+ function createSqliteAgentRuntimeStore(config) {
486
+ const database = config.database;
487
+ if (config.initialize !== false) {
488
+ try {
489
+ initializeAgentRuntimeSqlite(database);
490
+ } catch (error) {
491
+ database.close();
492
+ throw error;
493
+ }
494
+ }
495
+ let closing = false;
496
+ let closed = false;
497
+ let tail = Promise.resolve();
498
+ const insideScope = new AsyncLocalStorage;
499
+ const serial = (work) => {
500
+ if (closing || closed) {
501
+ return Promise.reject(new Error("SQLite agent-runtime store is closing"));
502
+ }
503
+ if (insideScope.getStore()) {
504
+ return Promise.reject(new Error("SQLite agent-runtime store called from inside its own transaction scope; use scope.database and scope.appendEvent"));
505
+ }
506
+ const result = tail.then(work, work);
507
+ tail = result.then(() => {
508
+ return;
509
+ }, () => {
510
+ return;
511
+ });
512
+ return result;
513
+ };
514
+ const runTransaction = (access, work) => serial(async () => {
515
+ database.exec(access === "read" ? "BEGIN" : "BEGIN IMMEDIATE");
516
+ try {
517
+ const result = await work(database);
518
+ database.exec("COMMIT");
519
+ return result;
520
+ } catch (error) {
521
+ database.exec("ROLLBACK");
522
+ throw error;
523
+ }
524
+ });
525
+ const driver = {
526
+ conversations: sqliteConversationPurge(database),
527
+ transaction: (work, options) => runTransaction(options?.access ?? "write", work),
528
+ head: {
529
+ async load(transaction, conversationId) {
530
+ const value = transaction.prepare("SELECT version FROM stitchkit_agent_runtime_heads WHERE conversation_id = ?").get(conversationId);
531
+ if (missing(value))
532
+ return;
533
+ const row = HeadRowSchema.parse(value);
534
+ return AgentRuntimeHeadSchema.parse({
535
+ schemaVersion: 1,
536
+ conversationId,
537
+ version: row.version
538
+ });
539
+ },
540
+ async compareAndSwap(transaction, input) {
541
+ const current = transaction.prepare("SELECT version FROM stitchkit_agent_runtime_heads WHERE conversation_id = ?").get(input.conversationId);
542
+ const actualVersion = missing(current) ? 0 : HeadRowSchema.parse(current).version;
543
+ if (actualVersion !== input.expectedVersion)
544
+ return { outcome: "conflict", actualVersion };
545
+ transaction.prepare(`
546
+ INSERT INTO stitchkit_agent_runtime_heads (conversation_id, version)
547
+ VALUES (?, ?)
548
+ ON CONFLICT (conversation_id) DO UPDATE SET version = excluded.version
549
+ `).run(input.conversationId, input.next.version);
550
+ return { outcome: "applied" };
551
+ }
552
+ },
553
+ runs: {
554
+ async load(transaction, input) {
555
+ const row = transaction.prepare(`
556
+ SELECT payload, terminal_assistant_payload
557
+ FROM stitchkit_agent_runtime_runs
558
+ WHERE conversation_id = ? AND run_id = ?
559
+ `).get(input.conversationId, input.runId);
560
+ return missing(row) ? undefined : parseRunRow(row);
561
+ },
562
+ async loadByAssistantMessageId(transaction, input) {
563
+ const row = transaction.prepare(`
564
+ SELECT payload, terminal_assistant_payload
565
+ FROM stitchkit_agent_runtime_runs
566
+ WHERE conversation_id = ? AND assistant_message_id = ?
567
+ `).get(input.conversationId, input.assistantMessageId);
568
+ return missing(row) ? undefined : parseRunRow(row);
569
+ },
570
+ async loadMany(transaction, input) {
571
+ if (input.runIds.length === 0)
572
+ return [];
573
+ return transaction.prepare(`
574
+ SELECT payload, terminal_assistant_payload
575
+ FROM stitchkit_agent_runtime_runs
576
+ WHERE conversation_id = ? AND run_id IN (${placeholders(input.runIds.length)})
577
+ `).all(input.conversationId, ...input.runIds).map(parseRunRow);
578
+ },
579
+ async listActive(transaction, conversationId) {
580
+ return transaction.prepare(`
581
+ SELECT payload, terminal_assistant_payload
582
+ FROM stitchkit_agent_runtime_runs
583
+ WHERE conversation_id = ? AND state IN ('queued', 'running', 'interrupt_requested')
584
+ `).all(conversationId).map(parseRunRow);
585
+ },
586
+ async save(transaction, rawRecord) {
587
+ const record = AgentStoredRunSchema.parse(rawRecord);
588
+ transaction.prepare(`
589
+ INSERT INTO stitchkit_agent_runtime_runs (
590
+ conversation_id, run_id, assistant_message_id, state, created_at, payload,
591
+ terminal_assistant_payload
592
+ ) VALUES (?, ?, ?, ?, ?, ?, ?)
593
+ ON CONFLICT (conversation_id, run_id) DO UPDATE SET
594
+ assistant_message_id = excluded.assistant_message_id,
595
+ state = excluded.state,
596
+ created_at = excluded.created_at,
597
+ payload = excluded.payload,
598
+ terminal_assistant_payload = excluded.terminal_assistant_payload
599
+ `).run(record.run.conversationId, record.run.id, record.run.assistantMessageId, record.run.state, record.run.createdAt, encodeJson(record.run), record.terminalAssistant ? encodeJson(record.terminalAssistant) : null);
600
+ }
601
+ },
602
+ admissions: {
603
+ async load(transaction, input) {
604
+ const value = transaction.prepare(`
605
+ SELECT conversation_id, idempotency_key, input_payload, run_id, assistant_message_id
606
+ FROM stitchkit_agent_runtime_admissions
607
+ WHERE conversation_id = ? AND idempotency_key = ?
608
+ `).get(input.conversationId, input.idempotencyKey);
609
+ if (missing(value))
610
+ return;
611
+ const row = AdmissionRowSchema2.parse(value);
612
+ return AgentAdmissionReceiptSchema.parse({
613
+ schemaVersion: 1,
614
+ conversationId: row.conversation_id,
615
+ idempotencyKey: row.idempotency_key,
616
+ input: AgentMessageSchema.parse(parseJson2(row.input_payload)),
617
+ runId: row.run_id,
618
+ assistantMessageId: row.assistant_message_id
619
+ });
620
+ },
621
+ async loadByInputMessageId(transaction, input) {
622
+ const value = transaction.prepare(`
623
+ SELECT conversation_id, idempotency_key, input_payload, run_id, assistant_message_id
624
+ FROM stitchkit_agent_runtime_admissions
625
+ WHERE conversation_id = ? AND input_message_id = ?
626
+ `).get(input.conversationId, input.inputMessageId);
627
+ if (missing(value))
628
+ return;
629
+ const row = AdmissionRowSchema2.parse(value);
630
+ return AgentAdmissionReceiptSchema.parse({
631
+ schemaVersion: 1,
632
+ conversationId: row.conversation_id,
633
+ idempotencyKey: row.idempotency_key,
634
+ input: AgentMessageSchema.parse(parseJson2(row.input_payload)),
635
+ runId: row.run_id,
636
+ assistantMessageId: row.assistant_message_id
637
+ });
638
+ },
639
+ async create(transaction, rawReceipt) {
640
+ const receipt = AgentAdmissionReceiptSchema.parse(rawReceipt);
641
+ transaction.prepare(`
642
+ INSERT INTO stitchkit_agent_runtime_admissions (
643
+ conversation_id, idempotency_key, input_message_id, run_id,
644
+ assistant_message_id, input_payload
645
+ ) VALUES (?, ?, ?, ?, ?, ?)
646
+ `).run(receipt.conversationId, receipt.idempotencyKey, receipt.input.id, receipt.runId, receipt.assistantMessageId, encodeJson(receipt.input));
647
+ }
648
+ },
649
+ history: {
650
+ async load(transaction, conversationId) {
651
+ return transaction.prepare(`
652
+ SELECT payload FROM stitchkit_agent_runtime_messages
653
+ WHERE conversation_id = ? AND active = 1 ORDER BY position ASC
654
+ `).all(conversationId).map((value) => AgentMessageSchema.parse(parseJson2(MessageRowSchema.parse(value).payload)));
655
+ },
656
+ async apply(transaction, rawMutation) {
657
+ const mutation = AgentHistoryMutationSchema.parse(rawMutation);
658
+ const message = mutation.type === "admit" ? mutation.input : mutation.type === "upsert-assistant" ? mutation.message : mutation.summary;
659
+ if (mutation.type === "replace-compacted-range") {
660
+ const parameters = mutation.replacedMessageIds;
661
+ const rows = transaction.prepare(`
662
+ SELECT position FROM stitchkit_agent_runtime_messages
663
+ WHERE conversation_id = ? AND active = 1
664
+ AND id IN (${placeholders(parameters.length)})
665
+ ORDER BY position ASC
666
+ `).all(message.conversationId, ...parameters).map((row) => PositionedMessageRowSchema.parse(row));
667
+ const first = rows[0];
668
+ if (!first || rows.length !== parameters.length) {
669
+ throw new Error("Compaction range changed inside the transaction");
670
+ }
671
+ transaction.prepare(`
672
+ UPDATE stitchkit_agent_runtime_messages SET active = 0
673
+ WHERE conversation_id = ? AND id IN (${placeholders(parameters.length)})
674
+ `).run(message.conversationId, ...parameters);
675
+ transaction.prepare(`
676
+ INSERT INTO stitchkit_agent_runtime_messages
677
+ (conversation_id, id, position, active, payload)
678
+ VALUES (?, ?, ?, 1, ?)
679
+ `).run(message.conversationId, message.id, first.position, encodeJson(message));
680
+ return;
681
+ }
682
+ const existing = transaction.prepare(`
683
+ SELECT position FROM stitchkit_agent_runtime_messages
684
+ WHERE conversation_id = ? AND id = ?
685
+ `).get(message.conversationId, message.id);
686
+ if (!missing(existing)) {
687
+ transaction.prepare(`
688
+ UPDATE stitchkit_agent_runtime_messages SET payload = ?, active = 1
689
+ WHERE conversation_id = ? AND id = ?
690
+ `).run(encodeJson(message), message.conversationId, message.id);
691
+ return;
692
+ }
693
+ const last = transaction.prepare(`
694
+ SELECT position FROM stitchkit_agent_runtime_messages
695
+ WHERE conversation_id = ? ORDER BY position DESC LIMIT 1
696
+ `).get(message.conversationId);
697
+ const position = missing(last) ? 0 : PositionedMessageRowSchema.parse(last).position + 1;
698
+ transaction.prepare(`
699
+ INSERT INTO stitchkit_agent_runtime_messages
700
+ (conversation_id, id, position, active, payload)
701
+ VALUES (?, ?, ?, 1, ?)
702
+ `).run(message.conversationId, message.id, position, encodeJson(message));
703
+ }
704
+ },
705
+ events: {
706
+ async append(transaction, rawEvent) {
707
+ const event = rawEvent;
708
+ const last = transaction.prepare("SELECT COALESCE(MAX(seq), 0) AS count FROM stitchkit_agent_runtime_events WHERE conversation_id = ?").get(event.conversationId);
709
+ const seq = CountRowSchema.parse(last).count + 1;
710
+ transaction.prepare(`
711
+ INSERT INTO stitchkit_agent_runtime_events (
712
+ conversation_id, seq, event_id, schema_version, kind, occurred_at, ignorable, payload
713
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
714
+ `).run(event.conversationId, seq, event.eventId, event.schemaVersion, event.kind, event.occurredAt, event.ignorable ? 1 : 0, encodeJson(event.payload));
715
+ return AgentStoreEventEnvelopeSchema.parse({ ...event, seq });
716
+ },
717
+ async list(transaction, input) {
718
+ const clauses = ["conversation_id = ?"];
719
+ const values = [input.conversationId];
720
+ if (input.fromSeq !== undefined) {
721
+ clauses.push("seq >= ?");
722
+ values.push(input.fromSeq);
723
+ }
724
+ if (input.toSeq !== undefined) {
725
+ clauses.push("seq <= ?");
726
+ values.push(input.toSeq);
727
+ }
728
+ const rows = transaction.prepare(`
729
+ SELECT event_id, conversation_id, seq, schema_version, kind, occurred_at,
730
+ ignorable, payload
731
+ FROM stitchkit_agent_runtime_events
732
+ WHERE ${clauses.join(" AND ")}
733
+ ORDER BY seq ASC LIMIT ?
734
+ `).all(...values, input.limit + 1).map(parseEventRow);
735
+ const hasMore = rows.length > input.limit;
736
+ const items = rows.slice(0, input.limit);
737
+ const lastEvent = items.at(-1);
738
+ return AgentStoreEventPageSchema.parse({
739
+ items,
740
+ ...hasMore && lastEvent ? { nextSeq: lastEvent.seq + 1 } : {}
741
+ });
742
+ }
743
+ },
744
+ archive: {
745
+ async export(transaction, conversationId) {
746
+ const projections = transaction.prepare(`
747
+ SELECT name, version, upto_seq, payload, updated_at
748
+ FROM stitchkit_agent_runtime_projections
749
+ WHERE conversation_id = ? ORDER BY name
750
+ `).all(conversationId).map((raw) => {
751
+ const row = ArchiveProjectionRowSchema.parse(raw);
752
+ return {
753
+ name: row.name,
754
+ version: row.version,
755
+ uptoSeq: row.upto_seq,
756
+ value: z2.json().parse(parseJson2(row.payload)),
757
+ updatedAt: row.updated_at
758
+ };
759
+ });
760
+ const spills = transaction.prepare(`
761
+ SELECT reference_id, run_id, tool_call_id, media_type, bytes, sha256,
762
+ created_at, expires_at, authorization_payload, payload
763
+ FROM stitchkit_agent_runtime_spills
764
+ WHERE conversation_id = ? ORDER BY created_at, reference_id
765
+ `).all(conversationId).map((raw) => {
766
+ const row = ArchiveSpillRowSchema.parse(raw);
767
+ return {
768
+ reference: row.reference_id,
769
+ ...row.run_id && { runId: row.run_id },
770
+ ...row.tool_call_id && { toolCallId: row.tool_call_id },
771
+ mediaType: row.media_type,
772
+ bytes: row.bytes,
773
+ sha256: row.sha256,
774
+ createdAt: row.created_at,
775
+ ...row.expires_at && { expiresAt: row.expires_at },
776
+ ...row.authorization_payload && {
777
+ authorization: z2.json().parse(parseJson2(row.authorization_payload))
778
+ },
779
+ base64: Buffer.from(row.payload).toString("base64")
780
+ };
781
+ });
782
+ return { projections, spills };
783
+ },
784
+ async import(transaction, archive) {
785
+ for (const raw of archive.projections) {
786
+ if (typeof raw === "object" && raw !== null && !Array.isArray(raw) && raw.archiveType === "runtime-snapshot") {
787
+ continue;
788
+ }
789
+ const projection = z2.object({
790
+ name: z2.string(),
791
+ version: z2.int().positive(),
792
+ uptoSeq: z2.int().nonnegative(),
793
+ value: z2.json(),
794
+ updatedAt: z2.string()
795
+ }).strict().parse(raw);
796
+ transaction.prepare(`
797
+ INSERT INTO stitchkit_agent_runtime_projections
798
+ (conversation_id, name, version, upto_seq, payload, updated_at)
799
+ VALUES (?, ?, ?, ?, ?, ?)
800
+ `).run(archive.conversationId, projection.name, projection.version, projection.uptoSeq, encodeJson(projection.value), projection.updatedAt);
801
+ }
802
+ for (const raw of archive.spills) {
803
+ const spill = z2.object({
804
+ reference: z2.string(),
805
+ runId: z2.string().optional(),
806
+ toolCallId: z2.string().optional(),
807
+ mediaType: z2.string(),
808
+ bytes: z2.int().nonnegative(),
809
+ sha256: z2.string(),
810
+ createdAt: z2.string(),
811
+ expiresAt: z2.string().optional(),
812
+ authorization: z2.json().optional(),
813
+ base64: z2.string()
814
+ }).strict().parse(raw);
815
+ const payload = Buffer.from(spill.base64, "base64");
816
+ if (payload.byteLength !== spill.bytes) {
817
+ throw new TypeError("Conversation archive spill byte count is inconsistent");
818
+ }
819
+ if (createHash("sha256").update(payload).digest("hex") !== spill.sha256) {
820
+ throw new TypeError("Conversation archive spill digest is inconsistent");
821
+ }
822
+ transaction.prepare(`
823
+ INSERT INTO stitchkit_agent_runtime_spills (
824
+ reference_id, conversation_id, run_id, tool_call_id, media_type,
825
+ bytes, sha256, created_at, expires_at, authorization_payload, payload
826
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
827
+ `).run(spill.reference, archive.conversationId, spill.runId ?? null, spill.toolCallId ?? null, spill.mediaType, spill.bytes, spill.sha256, spill.createdAt, spill.expiresAt ?? null, spill.authorization ? encodeJson(spill.authorization) : null, payload);
828
+ }
829
+ }
830
+ },
831
+ scanRecoverable: (input) => runTransaction("read", async () => {
832
+ const cursor = input.cursor ? parseRecoveryCursor(input.cursor) : undefined;
833
+ const values = cursor ? [cursor[0], cursor[0], cursor[1], input.limit + 1] : [input.limit + 1];
834
+ const rows = database.prepare(`
835
+ SELECT conversation_id, run_id, payload
836
+ FROM stitchkit_agent_runtime_runs
837
+ WHERE state IN ('queued', 'running', 'interrupt_requested')
838
+ ${cursor ? "AND (conversation_id > ? OR (conversation_id = ? AND run_id > ?))" : ""}
839
+ ORDER BY conversation_id ASC, run_id ASC LIMIT ?
840
+ `).all(...values).map((row) => RecoverableRowSchema.parse(row));
841
+ const hasMore = rows.length > input.limit;
842
+ const pageRows = rows.slice(0, input.limit);
843
+ const items = pageRows.map((row) => {
844
+ const run = AgentRunSchema.parse(parseJson2(row.payload));
845
+ return AgentRecoverableDescriptorSchema.parse({
846
+ conversationId: row.conversation_id,
847
+ run
848
+ });
849
+ });
850
+ const last = pageRows.at(-1);
851
+ return AgentRecoverablePageSchema.parse({
852
+ items,
853
+ ...hasMore && last ? { nextCursor: recoveryCursor(last.conversation_id, last.run_id) } : {}
854
+ });
855
+ })
856
+ };
857
+ return {
858
+ store: createAgentRuntimeStore(driver),
859
+ database,
860
+ transaction: (work) => runTransaction("write", (transaction) => insideScope.run(true, () => work({
861
+ database: transaction,
862
+ appendEvent: async (input) => {
863
+ const parsed = AppendAgentStoreEventSchema.parse(input);
864
+ if (await driver.conversations?.isPurged(transaction, parsed.conversationId)) {
865
+ throw new AgentConversationPurgedError;
866
+ }
867
+ return driver.events.append(transaction, agentStoreEventDraft(parsed));
868
+ }
869
+ }))),
870
+ conversations: {
871
+ list: (input) => runTransaction("read", async () => {
872
+ if (!Number.isSafeInteger(input.limit) || input.limit < 1 || input.limit > 1000) {
873
+ throw new TypeError("Conversation page limit must be between 1 and 1000");
874
+ }
875
+ const cursor = input.cursor ? parseConversationCursor(input.cursor) : undefined;
876
+ const search = input.search?.trim();
877
+ const clauses = [
878
+ ...cursor ? ["conversation_id > ?"] : [],
879
+ ...search ? ["instr(conversation_id, ?) > 0"] : []
880
+ ];
881
+ const parameters = [
882
+ ...cursor ? [cursor] : [],
883
+ ...search ? [search] : [],
884
+ input.limit + 1
885
+ ];
886
+ const rows = database.prepare(`
887
+ SELECT conversation_id, version FROM stitchkit_agent_runtime_heads
888
+ ${clauses.length > 0 ? `WHERE ${clauses.join(" AND ")}` : ""}
889
+ ORDER BY conversation_id ASC LIMIT ?
890
+ `).all(...parameters).map((row) => ConversationHeadRowSchema.parse(row));
891
+ const hasMore = rows.length > input.limit;
892
+ const pageRows = rows.slice(0, input.limit);
893
+ const items = pageRows.map((row) => {
894
+ const latestRaw = database.prepare(`
895
+ SELECT payload FROM stitchkit_agent_runtime_messages
896
+ WHERE conversation_id = ? AND active = 1
897
+ ORDER BY position DESC LIMIT 1
898
+ `).get(row.conversation_id);
899
+ if (missing(latestRaw)) {
900
+ throw new Error("Agent conversation head has no active history");
901
+ }
902
+ const latest = AgentMessageSchema.parse(parseJson2(MessageRowSchema.parse(latestRaw).payload));
903
+ const active = CountRowSchema.parse(database.prepare(`
904
+ SELECT count(*) AS count FROM stitchkit_agent_runtime_runs
905
+ WHERE conversation_id = ?
906
+ AND state IN ('queued', 'running', 'interrupt_requested')
907
+ `).get(row.conversation_id));
908
+ return {
909
+ conversationId: row.conversation_id,
910
+ version: row.version,
911
+ updatedAt: latest.updatedAt,
912
+ preview: messagePreview(latest),
913
+ activeRuns: active.count
914
+ };
915
+ });
916
+ const last = pageRows.at(-1);
917
+ return AgentConversationPageSchema.parse({
918
+ items,
919
+ ...hasMore && last ? { nextCursor: conversationCursor(last.conversation_id) } : {}
920
+ });
921
+ }),
922
+ messages: (input) => runTransaction("read", async () => {
923
+ if (!Number.isSafeInteger(input.limit) || input.limit < 1 || input.limit > 1000) {
924
+ throw new TypeError("Conversation message page limit must be between 1 and 1000");
925
+ }
926
+ const cursor = input.cursor ? parseMessageCursor(input.cursor) : undefined;
927
+ const before = input.direction === "before";
928
+ const direction = before ? "DESC" : "ASC";
929
+ const comparison = cursor === undefined ? "" : cursor.rowId === undefined ? `AND position ${before ? "<" : ">"} ?` : `AND (position, rowid) ${before ? "<" : ">"} (?, ?)`;
930
+ const rows = database.prepare(`
931
+ SELECT rowid AS row_id, position, active, payload
932
+ FROM stitchkit_agent_runtime_messages
933
+ WHERE conversation_id = ?
934
+ ${input.includeCompacted === true ? "" : "AND active = 1"}
935
+ ${comparison}
936
+ ORDER BY position ${direction}, rowid ${direction} LIMIT ?
937
+ `).all(input.conversationId, ...cursor === undefined ? [] : cursor.rowId === undefined ? [cursor.position] : [cursor.position, cursor.rowId], input.limit + 1).map((row) => MessagePageRowSchema.parse(row));
938
+ const hasMore = rows.length > input.limit;
939
+ const pageRows = rows.slice(0, input.limit);
940
+ const ordered = before ? [...pageRows].reverse() : pageRows;
941
+ const boundary = pageRows.at(-1);
942
+ const items = ordered.map((row) => ({
943
+ message: AgentMessageSchema.parse(parseJson2(row.payload)),
944
+ active: row.active === 1
945
+ }));
946
+ return AgentConversationMessagePageSchema.parse({
947
+ items: items.map((entry) => entry.message),
948
+ compacted: items.filter((entry) => !entry.active).map((entry) => entry.message.id),
949
+ ...hasMore && boundary ? { nextCursor: messageCursor(boundary.position, boundary.row_id) } : {}
950
+ });
951
+ })
952
+ },
953
+ async close() {
954
+ if (closed)
955
+ return;
956
+ closing = true;
957
+ await tail;
958
+ database.close();
959
+ closed = true;
960
+ }
961
+ };
962
+ }
963
+
964
+ export { initializeAgentRuntimeSqlite, createSqliteAgentRuntimeStore };