@jasonews/agent-squad-gateway 1.0.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 (149) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +200 -0
  3. package/SECURITY.md +44 -0
  4. package/dist/bin/agent-squad-gateway.js +55 -0
  5. package/dist/bin/agent-squad-gateway.js.map +1 -0
  6. package/dist/config/config.js +124 -0
  7. package/dist/config/config.js.map +1 -0
  8. package/dist/config/paths.js +16 -0
  9. package/dist/config/paths.js.map +1 -0
  10. package/dist/control-plane/clients.js +77 -0
  11. package/dist/control-plane/clients.js.map +1 -0
  12. package/dist/control-plane/core-connection.js +54 -0
  13. package/dist/control-plane/core-connection.js.map +1 -0
  14. package/dist/control-plane/credentials.js +134 -0
  15. package/dist/control-plane/credentials.js.map +1 -0
  16. package/dist/control-plane/db.js +33 -0
  17. package/dist/control-plane/db.js.map +1 -0
  18. package/dist/control-plane/extensions.js +59 -0
  19. package/dist/control-plane/extensions.js.map +1 -0
  20. package/dist/control-plane/grants.js +107 -0
  21. package/dist/control-plane/grants.js.map +1 -0
  22. package/dist/control-plane/idempotency.js +132 -0
  23. package/dist/control-plane/idempotency.js.map +1 -0
  24. package/dist/control-plane/migrations.js +133 -0
  25. package/dist/control-plane/migrations.js.map +1 -0
  26. package/dist/control-plane/response-sessions.js +359 -0
  27. package/dist/control-plane/response-sessions.js.map +1 -0
  28. package/dist/control-plane/retention.js +138 -0
  29. package/dist/control-plane/retention.js.map +1 -0
  30. package/dist/control-plane/runs.js +156 -0
  31. package/dist/control-plane/runs.js.map +1 -0
  32. package/dist/control-plane/targets.js +449 -0
  33. package/dist/control-plane/targets.js.map +1 -0
  34. package/dist/control-plane/types.js +2 -0
  35. package/dist/control-plane/types.js.map +1 -0
  36. package/dist/core-client/client.js +275 -0
  37. package/dist/core-client/client.js.map +1 -0
  38. package/dist/core-client/event-proxy.js +105 -0
  39. package/dist/core-client/event-proxy.js.map +1 -0
  40. package/dist/core-client/types.js +2 -0
  41. package/dist/core-client/types.js.map +1 -0
  42. package/dist/extensions/contract.js +2 -0
  43. package/dist/extensions/contract.js.map +1 -0
  44. package/dist/extensions/openai/auth.js +16 -0
  45. package/dist/extensions/openai/auth.js.map +1 -0
  46. package/dist/extensions/openai/chat.js +403 -0
  47. package/dist/extensions/openai/chat.js.map +1 -0
  48. package/dist/extensions/openai/errors.js +79 -0
  49. package/dist/extensions/openai/errors.js.map +1 -0
  50. package/dist/extensions/openai/image-input.js +79 -0
  51. package/dist/extensions/openai/image-input.js.map +1 -0
  52. package/dist/extensions/openai/models.js +40 -0
  53. package/dist/extensions/openai/models.js.map +1 -0
  54. package/dist/extensions/openai/responses.js +731 -0
  55. package/dist/extensions/openai/responses.js.map +1 -0
  56. package/dist/extensions/openai/routes.js +81 -0
  57. package/dist/extensions/openai/routes.js.map +1 -0
  58. package/dist/extensions/openai/run-attempt.js +96 -0
  59. package/dist/extensions/openai/run-attempt.js.map +1 -0
  60. package/dist/extensions/openai/schemas.js +176 -0
  61. package/dist/extensions/openai/schemas.js.map +1 -0
  62. package/dist/extensions/openai/sse.js +421 -0
  63. package/dist/extensions/openai/sse.js.map +1 -0
  64. package/dist/extensions/openai/tools.js +727 -0
  65. package/dist/extensions/openai/tools.js.map +1 -0
  66. package/dist/extensions/registry.js +30 -0
  67. package/dist/extensions/registry.js.map +1 -0
  68. package/dist/lifecycle/daemon.js +437 -0
  69. package/dist/lifecycle/daemon.js.map +1 -0
  70. package/dist/lifecycle/pidfile.js +34 -0
  71. package/dist/lifecycle/pidfile.js.map +1 -0
  72. package/dist/provider-runtime/antigravity/adapter.js +398 -0
  73. package/dist/provider-runtime/antigravity/adapter.js.map +1 -0
  74. package/dist/provider-runtime/antigravity/conversation.js +31 -0
  75. package/dist/provider-runtime/antigravity/conversation.js.map +1 -0
  76. package/dist/provider-runtime/capability-service.js +191 -0
  77. package/dist/provider-runtime/capability-service.js.map +1 -0
  78. package/dist/provider-runtime/claude/adapter.js +397 -0
  79. package/dist/provider-runtime/claude/adapter.js.map +1 -0
  80. package/dist/provider-runtime/claude/protocol.js +143 -0
  81. package/dist/provider-runtime/claude/protocol.js.map +1 -0
  82. package/dist/provider-runtime/codex/adapter.js +440 -0
  83. package/dist/provider-runtime/codex/adapter.js.map +1 -0
  84. package/dist/provider-runtime/codex/json-rpc-client.js +182 -0
  85. package/dist/provider-runtime/codex/json-rpc-client.js.map +1 -0
  86. package/dist/provider-runtime/codex/protocol.js +128 -0
  87. package/dist/provider-runtime/codex/protocol.js.map +1 -0
  88. package/dist/provider-runtime/command-discovery.js +106 -0
  89. package/dist/provider-runtime/command-discovery.js.map +1 -0
  90. package/dist/provider-runtime/cursor/adapter.js +427 -0
  91. package/dist/provider-runtime/cursor/adapter.js.map +1 -0
  92. package/dist/provider-runtime/cursor/protocol.js +81 -0
  93. package/dist/provider-runtime/cursor/protocol.js.map +1 -0
  94. package/dist/provider-runtime/fake/adapter.js +138 -0
  95. package/dist/provider-runtime/fake/adapter.js.map +1 -0
  96. package/dist/provider-runtime/image-assets.js +409 -0
  97. package/dist/provider-runtime/image-assets.js.map +1 -0
  98. package/dist/provider-runtime/image-support.js +5 -0
  99. package/dist/provider-runtime/image-support.js.map +1 -0
  100. package/dist/provider-runtime/invocation-service.js +503 -0
  101. package/dist/provider-runtime/invocation-service.js.map +1 -0
  102. package/dist/provider-runtime/kimi/adapter.js +657 -0
  103. package/dist/provider-runtime/kimi/adapter.js.map +1 -0
  104. package/dist/provider-runtime/opencode/adapter.js +610 -0
  105. package/dist/provider-runtime/opencode/adapter.js.map +1 -0
  106. package/dist/provider-runtime/opencode/server.js +46 -0
  107. package/dist/provider-runtime/opencode/server.js.map +1 -0
  108. package/dist/provider-runtime/process/line-reader.js +49 -0
  109. package/dist/provider-runtime/process/line-reader.js.map +1 -0
  110. package/dist/provider-runtime/process/managed-process.js +151 -0
  111. package/dist/provider-runtime/process/managed-process.js.map +1 -0
  112. package/dist/provider-runtime/provider-input.js +77 -0
  113. package/dist/provider-runtime/provider-input.js.map +1 -0
  114. package/dist/provider-runtime/register-providers.js +26 -0
  115. package/dist/provider-runtime/register-providers.js.map +1 -0
  116. package/dist/provider-runtime/registry.js +35 -0
  117. package/dist/provider-runtime/registry.js.map +1 -0
  118. package/dist/provider-runtime/replay-buffer.js +168 -0
  119. package/dist/provider-runtime/replay-buffer.js.map +1 -0
  120. package/dist/provider-runtime/scheduler.js +155 -0
  121. package/dist/provider-runtime/scheduler.js.map +1 -0
  122. package/dist/provider-runtime/types.js +2 -0
  123. package/dist/provider-runtime/types.js.map +1 -0
  124. package/dist/provider-runtime/workspaces.js +814 -0
  125. package/dist/provider-runtime/workspaces.js.map +1 -0
  126. package/dist/security/admin-auth.js +109 -0
  127. package/dist/security/admin-auth.js.map +1 -0
  128. package/dist/security/crypto.js +52 -0
  129. package/dist/security/crypto.js.map +1 -0
  130. package/dist/security/secret-files.js +33 -0
  131. package/dist/security/secret-files.js.map +1 -0
  132. package/dist/server/admin-routes.js +610 -0
  133. package/dist/server/admin-routes.js.map +1 -0
  134. package/dist/server/app.js +178 -0
  135. package/dist/server/app.js.map +1 -0
  136. package/dist/server/auth-hooks.js +43 -0
  137. package/dist/server/auth-hooks.js.map +1 -0
  138. package/dist/server/core-routes.js +127 -0
  139. package/dist/server/core-routes.js.map +1 -0
  140. package/dist/server/errors.js +19 -0
  141. package/dist/server/errors.js.map +1 -0
  142. package/dist/server/ui-routes.js +77 -0
  143. package/dist/server/ui-routes.js.map +1 -0
  144. package/dist/web/assets/index-BhqNoPpE.js +206 -0
  145. package/dist/web/assets/index-BhqNoPpE.js.map +1 -0
  146. package/dist/web/assets/index-C5nnaBfZ.css +1 -0
  147. package/dist/web/index.html +14 -0
  148. package/package.json +74 -0
  149. package/translations/README.zh-CN.md +175 -0
@@ -0,0 +1,359 @@
1
+ const RESPONSE_SESSION_TTL_MS = 30 * 24 * 60 * 60 * 1000;
2
+ function toResponseSessionRecord(row) {
3
+ return {
4
+ responseId: row.response_id,
5
+ chainId: row.chain_id,
6
+ targetId: row.target_id,
7
+ nativeSessionId: row.native_session_id,
8
+ parentResponseId: row.parent_response_id,
9
+ childResponseId: row.child_response_id,
10
+ workspacePath: row.workspace_path,
11
+ stored: row.stored === 1,
12
+ state: row.state,
13
+ expiresAt: row.expires_at,
14
+ createdAt: row.created_at,
15
+ updatedAt: row.updated_at,
16
+ };
17
+ }
18
+ export class ResponseSessionRepository {
19
+ db;
20
+ retentionHidden = new Set();
21
+ constructor(db) {
22
+ this.db = db;
23
+ }
24
+ create(input) {
25
+ assertIdentifier(input.responseId, 'response_id');
26
+ assertIdentifier(input.targetId, 'response_target');
27
+ const now = toIsoTimestamp(input.now);
28
+ const stored = input.store !== false;
29
+ const record = {
30
+ responseId: input.responseId,
31
+ chainId: input.responseId,
32
+ targetId: input.targetId,
33
+ nativeSessionId: stored ? input.nativeSessionId ?? null : null,
34
+ parentResponseId: null,
35
+ childResponseId: null,
36
+ workspacePath: stored ? input.workspacePath ?? null : null,
37
+ stored,
38
+ state: stored ? 'open' : 'not_stored',
39
+ expiresAt: plusTtl(now),
40
+ createdAt: now,
41
+ updatedAt: now,
42
+ };
43
+ const transaction = this.db.raw.transaction(() => this.db.prepare(`
44
+ INSERT INTO response_sessions (
45
+ response_id, chain_id, target_id, native_session_id, parent_response_id,
46
+ child_response_id, workspace_path, stored, state, expires_at, created_at, updated_at
47
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
48
+ `).run(record.responseId, record.chainId, record.targetId, record.nativeSessionId, record.parentResponseId, record.childResponseId, record.workspacePath, record.stored ? 1 : 0, record.state, record.expiresAt, record.createdAt, record.updatedAt));
49
+ transaction.immediate();
50
+ return record;
51
+ }
52
+ acquireContinuation(parentResponseId, targetId, now) {
53
+ assertIdentifier(parentResponseId, 'parent_response_id');
54
+ assertIdentifier(targetId, 'response_target');
55
+ const timestamp = toIsoTimestamp(now);
56
+ const transaction = this.db.raw.transaction(() => {
57
+ const result = this.db.prepare(`
58
+ UPDATE response_sessions
59
+ SET state = 'continuing', updated_at = ?
60
+ WHERE response_id = ? AND target_id = ? AND state = 'open'
61
+ AND stored = 1 AND expires_at > ?
62
+ `).run(timestamp, parentResponseId, targetId, timestamp);
63
+ if (result.changes !== 1)
64
+ this.classifyAcquireFailure(parentResponseId, targetId, timestamp);
65
+ const parent = this.requireRow(parentResponseId);
66
+ const chain = this.requireValidChain(parent);
67
+ this.assertActiveTail(chain, parent);
68
+ return toResponseSessionRecord(parent);
69
+ });
70
+ return transaction.immediate();
71
+ }
72
+ completeContinuation(input) {
73
+ assertIdentifier(input.parentResponseId, 'parent_response_id');
74
+ assertIdentifier(input.childResponseId, 'child_response_id');
75
+ const now = toIsoTimestamp(input.now);
76
+ const transaction = this.db.raw.transaction(() => {
77
+ const parent = this.findRow(input.parentResponseId);
78
+ this.assertCompletableParent(parent, now);
79
+ const chain = this.requireValidChain(parent);
80
+ this.assertActiveTail(chain, parent);
81
+ const expiresAt = plusTtl(now);
82
+ this.db.prepare(`
83
+ INSERT INTO response_sessions (
84
+ response_id, chain_id, target_id, native_session_id, parent_response_id,
85
+ child_response_id, workspace_path, stored, state, expires_at, created_at, updated_at
86
+ ) VALUES (?, ?, ?, ?, ?, NULL, ?, 1, 'open', ?, ?, ?)
87
+ `).run(input.childResponseId, parent.chain_id, parent.target_id, input.nativeSessionId ?? null, parent.response_id, input.workspacePath ?? null, expiresAt, now, now);
88
+ const completed = this.db.prepare(`
89
+ UPDATE response_sessions
90
+ SET state = 'continued', child_response_id = ?, updated_at = ?
91
+ WHERE response_id = ? AND chain_id = ? AND target_id = ?
92
+ AND state = 'continuing' AND child_response_id IS NULL
93
+ `).run(input.childResponseId, now, input.parentResponseId, parent.chain_id, parent.target_id);
94
+ if (completed.changes !== 1)
95
+ throw new Error('response_state_invalid');
96
+ const refreshed = this.db.prepare(`
97
+ UPDATE response_sessions
98
+ SET expires_at = ?, updated_at = ?
99
+ WHERE chain_id = ? AND target_id = ?
100
+ `).run(expiresAt, now, parent.chain_id, parent.target_id);
101
+ if (refreshed.changes !== chain.rows.length + 1)
102
+ throw new Error('response_chain_invalid');
103
+ return toResponseSessionRecord(this.requireRow(input.childResponseId));
104
+ });
105
+ return transaction.immediate();
106
+ }
107
+ releaseBeforeStart(parentResponseId, now) {
108
+ assertIdentifier(parentResponseId, 'parent_response_id');
109
+ const timestamp = toIsoTimestamp(now);
110
+ const transaction = this.db.raw.transaction(() => {
111
+ const parent = this.findRow(parentResponseId);
112
+ if (!parent || parent.state !== 'continuing')
113
+ return false;
114
+ const chain = this.requireValidChain(parent);
115
+ this.assertActiveTail(chain, parent);
116
+ return this.db.prepare(`
117
+ UPDATE response_sessions
118
+ SET state = 'open', updated_at = ?
119
+ WHERE response_id = ? AND state = 'continuing'
120
+ `).run(timestamp, parentResponseId).changes === 1;
121
+ });
122
+ return transaction.immediate();
123
+ }
124
+ failTerminal(responseId, now) {
125
+ assertIdentifier(responseId, 'response_id');
126
+ const timestamp = toIsoTimestamp(now);
127
+ const transaction = this.db.raw.transaction(() => {
128
+ const session = this.findRow(responseId);
129
+ this.assertCompletableParent(session, timestamp);
130
+ const chain = this.requireValidChain(session);
131
+ this.assertActiveTail(chain, session);
132
+ const failed = this.db.prepare(`
133
+ UPDATE response_sessions
134
+ SET state = 'terminal_failure', updated_at = ?
135
+ WHERE chain_id = ? AND target_id = ?
136
+ `).run(timestamp, session.chain_id, session.target_id);
137
+ if (failed.changes !== chain.rows.length)
138
+ throw new Error('response_chain_invalid');
139
+ return failed.changes;
140
+ });
141
+ return transaction.immediate();
142
+ }
143
+ get(responseId) {
144
+ assertIdentifier(responseId, 'response_id');
145
+ if (this.retentionHidden.has(responseId))
146
+ return undefined;
147
+ const row = this.findRow(responseId);
148
+ return row ? toResponseSessionRecord(row) : undefined;
149
+ }
150
+ findExpiredForRetention(now) {
151
+ const timestamp = toIsoTimestamp(now);
152
+ const rows = this.db.prepare(`
153
+ SELECT candidate.response_id, candidate.chain_id, candidate.workspace_path
154
+ FROM response_sessions AS candidate
155
+ WHERE candidate.chain_id IN (
156
+ SELECT chain_id
157
+ FROM response_sessions
158
+ GROUP BY chain_id
159
+ HAVING MAX(expires_at) <= ?
160
+ AND SUM(CASE WHEN state = 'continuing' THEN 1 ELSE 0 END) = 0
161
+ )
162
+ ORDER BY candidate.chain_id, candidate.response_id
163
+ `).all(timestamp);
164
+ const chains = new Map();
165
+ for (const row of rows) {
166
+ let chain = chains.get(row.chain_id);
167
+ if (!chain) {
168
+ chain = { chainId: row.chain_id, responseIds: [], workspacePaths: [] };
169
+ chains.set(row.chain_id, chain);
170
+ }
171
+ chain.responseIds.push(row.response_id);
172
+ if (row.workspace_path !== null && !chain.workspacePaths.includes(row.workspace_path)) {
173
+ chain.workspacePaths.push(row.workspace_path);
174
+ }
175
+ }
176
+ return [...chains.values()];
177
+ }
178
+ hideForRetention(chains) {
179
+ for (const chain of chains) {
180
+ for (const responseId of chain.responseIds)
181
+ this.retentionHidden.add(responseId);
182
+ }
183
+ }
184
+ releaseRetentionHidden(chains) {
185
+ for (const chain of chains) {
186
+ for (const responseId of chain.responseIds)
187
+ this.retentionHidden.delete(responseId);
188
+ }
189
+ }
190
+ unlinkAndDeleteForRetention(chainIds) {
191
+ let deleted = 0;
192
+ const unlink = this.db.prepare(`
193
+ UPDATE response_sessions
194
+ SET parent_response_id = NULL, child_response_id = NULL
195
+ WHERE chain_id = ?
196
+ `);
197
+ const remove = this.db.prepare('DELETE FROM response_sessions WHERE chain_id = ?');
198
+ for (const chainId of chainIds) {
199
+ unlink.run(chainId);
200
+ deleted += remove.run(chainId).changes;
201
+ }
202
+ return deleted;
203
+ }
204
+ expire(now) {
205
+ const timestamp = toIsoTimestamp(now);
206
+ const transaction = this.db.raw.transaction(() => this.db.prepare(`
207
+ UPDATE response_sessions AS candidate
208
+ SET state = 'expired', updated_at = ?
209
+ WHERE candidate.expires_at <= ? AND candidate.state != 'expired'
210
+ AND NOT EXISTS (
211
+ SELECT 1
212
+ FROM response_sessions AS lease
213
+ WHERE lease.chain_id = candidate.chain_id
214
+ AND lease.target_id = candidate.target_id
215
+ AND lease.state = 'continuing'
216
+ )
217
+ `).run(timestamp, timestamp).changes);
218
+ return transaction.immediate();
219
+ }
220
+ findRow(responseId) {
221
+ return this.db.prepare(`
222
+ SELECT
223
+ response_id, chain_id, target_id, native_session_id, parent_response_id,
224
+ child_response_id, workspace_path, stored, state, expires_at, created_at, updated_at
225
+ FROM response_sessions
226
+ WHERE response_id = ?
227
+ `).get(responseId);
228
+ }
229
+ requireRow(responseId) {
230
+ const row = this.findRow(responseId);
231
+ if (!row)
232
+ throw new Error('response_not_found');
233
+ return row;
234
+ }
235
+ findChainRows(chainId) {
236
+ return this.db.prepare(`
237
+ SELECT
238
+ response_id, chain_id, target_id, native_session_id, parent_response_id,
239
+ child_response_id, workspace_path, stored, state, expires_at, created_at, updated_at
240
+ FROM response_sessions
241
+ WHERE chain_id = ?
242
+ `).all(chainId);
243
+ }
244
+ assertTarget(row, targetId) {
245
+ if (!row)
246
+ throw new Error('response_not_found');
247
+ if (row.target_id !== targetId)
248
+ throw new Error('response_target_mismatch');
249
+ }
250
+ assertCompletableParent(row, now) {
251
+ if (!row)
252
+ throw new Error('response_not_found');
253
+ if (row.stored !== 1 || row.state === 'not_stored')
254
+ throw new Error('response_not_stored');
255
+ if (row.state === 'continuing')
256
+ return;
257
+ if (row.state === 'expired' || row.expires_at <= now)
258
+ throw new Error('response_expired');
259
+ switch (row.state) {
260
+ case 'open': throw new Error('response_continuation_not_acquired');
261
+ case 'continued': throw new Error('response_already_continued');
262
+ case 'terminal_failure': throw new Error('response_terminal_failure');
263
+ default: throw new Error('response_state_invalid');
264
+ }
265
+ }
266
+ assertAcquirableState(row) {
267
+ switch (row.state) {
268
+ case 'open': return;
269
+ case 'continuing': throw new Error('response_in_progress');
270
+ case 'continued': throw new Error('response_already_continued');
271
+ case 'terminal_failure': throw new Error('response_terminal_failure');
272
+ case 'not_stored': throw new Error('response_not_stored');
273
+ case 'expired': throw new Error('response_expired');
274
+ default: throw new Error('response_state_invalid');
275
+ }
276
+ }
277
+ classifyAcquireFailure(responseId, targetId, now) {
278
+ if (this.retentionHidden.has(responseId))
279
+ throw new Error('response_not_found');
280
+ const parent = this.findRow(responseId);
281
+ this.assertTarget(parent, targetId);
282
+ this.assertStoredAndUnexpired(parent, now);
283
+ this.assertAcquirableState(parent);
284
+ throw new Error('response_state_invalid');
285
+ }
286
+ assertStoredAndUnexpired(row, now) {
287
+ if (row.stored !== 1 || row.state === 'not_stored')
288
+ throw new Error('response_not_stored');
289
+ if (row.state === 'expired' || row.expires_at <= now)
290
+ throw new Error('response_expired');
291
+ }
292
+ requireValidChain(session) {
293
+ const rows = this.findChainRows(session.chain_id);
294
+ const byId = new Map(rows.map((row) => [row.response_id, row]));
295
+ const root = byId.get(session.chain_id);
296
+ if (!root
297
+ || root.response_id !== root.chain_id
298
+ || root.parent_response_id !== null
299
+ || root.target_id !== session.target_id) {
300
+ throw new Error('response_chain_invalid');
301
+ }
302
+ for (const row of rows) {
303
+ if (row.chain_id !== session.chain_id || row.target_id !== session.target_id) {
304
+ throw new Error('response_chain_invalid');
305
+ }
306
+ if (row.response_id !== root.response_id) {
307
+ const parent = row.parent_response_id === null ? undefined : byId.get(row.parent_response_id);
308
+ if (!parent || parent.child_response_id !== row.response_id) {
309
+ throw new Error('response_chain_invalid');
310
+ }
311
+ }
312
+ if (row.child_response_id !== null) {
313
+ const child = byId.get(row.child_response_id);
314
+ if (!child || child.parent_response_id !== row.response_id) {
315
+ throw new Error('response_chain_invalid');
316
+ }
317
+ }
318
+ }
319
+ const ordered = [];
320
+ const visited = new Set();
321
+ let current = root;
322
+ while (current) {
323
+ if (visited.has(current.response_id))
324
+ throw new Error('response_chain_invalid');
325
+ visited.add(current.response_id);
326
+ ordered.push(current);
327
+ current = current.child_response_id === null ? undefined : byId.get(current.child_response_id);
328
+ }
329
+ if (ordered.length !== rows.length)
330
+ throw new Error('response_chain_invalid');
331
+ const tail = ordered.at(-1);
332
+ if (!tail)
333
+ throw new Error('response_chain_invalid');
334
+ return { rows: ordered, tail };
335
+ }
336
+ assertActiveTail(chain, session) {
337
+ if (chain.tail.response_id !== session.response_id || session.child_response_id !== null) {
338
+ throw new Error('response_chain_invalid');
339
+ }
340
+ for (const row of chain.rows.slice(0, -1)) {
341
+ if (row.stored !== 1 || row.state !== 'continued')
342
+ throw new Error('response_state_invalid');
343
+ }
344
+ }
345
+ }
346
+ function assertIdentifier(value, name) {
347
+ if (typeof value !== 'string' || value.trim().length === 0)
348
+ throw new Error(`invalid_${name}`);
349
+ }
350
+ function toIsoTimestamp(value) {
351
+ const date = value === undefined ? new Date() : new Date(value);
352
+ if (Number.isNaN(date.getTime()))
353
+ throw new Error('invalid_response_timestamp');
354
+ return date.toISOString();
355
+ }
356
+ function plusTtl(now) {
357
+ return new Date(new Date(now).getTime() + RESPONSE_SESSION_TTL_MS).toISOString();
358
+ }
359
+ //# sourceMappingURL=response-sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-sessions.js","sourceRoot":"","sources":["../../src/control-plane/response-sessions.ts"],"names":[],"mappings":"AAEA,MAAM,uBAAuB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AA0EzD,SAAS,uBAAuB,CAAC,GAAuB;IACtD,OAAO;QACL,UAAU,EAAE,GAAG,CAAC,WAAW;QAC3B,OAAO,EAAE,GAAG,CAAC,QAAQ;QACrB,QAAQ,EAAE,GAAG,CAAC,SAAS;QACvB,eAAe,EAAE,GAAG,CAAC,iBAAiB;QACtC,gBAAgB,EAAE,GAAG,CAAC,kBAAkB;QACxC,eAAe,EAAE,GAAG,CAAC,iBAAiB;QACtC,aAAa,EAAE,GAAG,CAAC,cAAc;QACjC,MAAM,EAAE,GAAG,CAAC,MAAM,KAAK,CAAC;QACxB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,SAAS,EAAE,GAAG,CAAC,UAAU;KAC1B,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,yBAAyB;IAGP;IAFZ,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;IAErD,YAA6B,EAAa;QAAb,OAAE,GAAF,EAAE,CAAW;IAAG,CAAC;IAE9C,MAAM,CAAC,KAAiC;QACtC,gBAAgB,CAAC,KAAK,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;QAClD,gBAAgB,CAAC,KAAK,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;QACpD,MAAM,GAAG,GAAG,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC;QACrC,MAAM,MAAM,GAA0B;YACpC,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,OAAO,EAAE,KAAK,CAAC,UAAU;YACzB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,eAAe,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI;YAC9D,gBAAgB,EAAE,IAAI;YACtB,eAAe,EAAE,IAAI;YACrB,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI;YAC1D,MAAM;YACN,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY;YACrC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC;YACvB,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;SACf,CAAC;QAEF,MAAM,WAAW,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;KAKjE,CAAC,CAAC,GAAG,CACJ,MAAM,CAAC,UAAU,EACjB,MAAM,CAAC,OAAO,EACd,MAAM,CAAC,QAAQ,EACf,MAAM,CAAC,eAAe,EACtB,MAAM,CAAC,gBAAgB,EACvB,MAAM,CAAC,eAAe,EACtB,MAAM,CAAC,aAAa,EACpB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACrB,MAAM,CAAC,KAAK,EACZ,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,SAAS,CACjB,CAAC,CAAC;QACH,WAAW,CAAC,SAAS,EAAE,CAAC;QACxB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,mBAAmB,CAAC,gBAAwB,EAAE,QAAgB,EAAE,GAAY;QAC1E,gBAAgB,CAAC,gBAAgB,EAAE,oBAAoB,CAAC,CAAC;QACzD,gBAAgB,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,WAAW,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE;YAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;OAK9B,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;YACzD,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC;gBAAE,IAAI,CAAC,sBAAsB,CAAC,gBAAgB,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;YAE7F,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YACjD,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;YAC7C,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAErC,OAAO,uBAAuB,CAAC,MAAM,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,OAAO,WAAW,CAAC,SAAS,EAAE,CAAC;IACjC,CAAC;IAED,oBAAoB,CAAC,KAAgC;QACnD,gBAAgB,CAAC,KAAK,CAAC,gBAAgB,EAAE,oBAAoB,CAAC,CAAC;QAC/D,gBAAgB,CAAC,KAAK,CAAC,eAAe,EAAE,mBAAmB,CAAC,CAAC;QAC7D,MAAM,GAAG,GAAG,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,WAAW,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE;YAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;YACpD,IAAI,CAAC,uBAAuB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;YAC7C,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YACrC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;YAE/B,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;OAKf,CAAC,CAAC,GAAG,CACJ,KAAK,CAAC,eAAe,EACrB,MAAM,CAAC,QAAQ,EACf,MAAM,CAAC,SAAS,EAChB,KAAK,CAAC,eAAe,IAAI,IAAI,EAC7B,MAAM,CAAC,WAAW,EAClB,KAAK,CAAC,aAAa,IAAI,IAAI,EAC3B,SAAS,EACT,GAAG,EACH,GAAG,CACJ,CAAC;YAEF,MAAM,SAAS,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;OAKjC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,eAAe,EAAE,GAAG,EAAE,KAAK,CAAC,gBAAgB,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;YAC9F,IAAI,SAAS,CAAC,OAAO,KAAK,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;YAEvE,MAAM,SAAS,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;OAIjC,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;YAC1D,IAAI,SAAS,CAAC,OAAO,KAAK,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;YAE3F,OAAO,uBAAuB,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;QACzE,CAAC,CAAC,CAAC;QAEH,OAAO,WAAW,CAAC,SAAS,EAAE,CAAC;IACjC,CAAC;IAED,kBAAkB,CAAC,gBAAwB,EAAE,GAAY;QACvD,gBAAgB,CAAC,gBAAgB,EAAE,oBAAoB,CAAC,CAAC;QACzD,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,WAAW,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE;YAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;YAC9C,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,KAAK,YAAY;gBAAE,OAAO,KAAK,CAAC;YAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;YAC7C,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAErC,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;OAItB,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;QAEH,OAAO,WAAW,CAAC,SAAS,EAAE,CAAC;IACjC,CAAC;IAED,YAAY,CAAC,UAAkB,EAAE,GAAY;QAC3C,gBAAgB,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;QAC5C,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,WAAW,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE;YAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YACzC,IAAI,CAAC,uBAAuB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;YACjD,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;YAC9C,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YACtC,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;OAI9B,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;YACvD,IAAI,MAAM,CAAC,OAAO,KAAK,KAAK,CAAC,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;YACpF,OAAO,MAAM,CAAC,OAAO,CAAC;QACxB,CAAC,CAAC,CAAC;QAEH,OAAO,WAAW,CAAC,SAAS,EAAE,CAAC;IACjC,CAAC;IAED,GAAG,CAAC,UAAkB;QACpB,gBAAgB,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;QAC5C,IAAI,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC;YAAE,OAAO,SAAS,CAAC;QAC3D,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACrC,OAAO,GAAG,CAAC,CAAC,CAAC,uBAAuB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACxD,CAAC;IAED,uBAAuB,CAAC,GAAW;QACjC,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAiC;;;;;;;;;;;KAW5D,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAClB,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkC,CAAC;QACzD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACrC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,KAAK,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC;gBACvE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YAClC,CAAC;YACD,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACxC,IAAI,GAAG,CAAC,cAAc,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;gBACtF,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9B,CAAC;IAED,gBAAgB,CAAC,MAAyC;QACxD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,KAAK,MAAM,UAAU,IAAI,KAAK,CAAC,WAAW;gBAAE,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;IAED,sBAAsB,CAAC,MAAyC;QAC9D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,KAAK,MAAM,UAAU,IAAI,KAAK,CAAC,WAAW;gBAAE,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;IAED,2BAA2B,CAAC,QAA2B;QACrD,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;KAI9B,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,kDAAkD,CAAC,CAAC;QACnF,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACpB,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;QACzC,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,CAAC,GAAY;QACjB,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,WAAW,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;;;;;;;KAWjE,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC;QAEtC,OAAO,WAAW,CAAC,SAAS,EAAE,CAAC;IACjC,CAAC;IAEO,OAAO,CAAC,UAAkB;QAChC,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO,CAA+B;;;;;;KAMpD,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACrB,CAAC;IAEO,UAAU,CAAC,UAAkB;QACnC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACrC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAChD,OAAO,GAAG,CAAC;IACb,CAAC;IAEO,aAAa,CAAC,OAAe;QACnC,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO,CAA+B;;;;;;KAMpD,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAClB,CAAC;IAEO,YAAY,CAAC,GAAmC,EAAE,QAAgB;QACxE,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAChD,IAAI,GAAG,CAAC,SAAS,KAAK,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAC9E,CAAC;IAEO,uBAAuB,CAAC,GAAmC,EAAE,GAAW;QAC9E,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAChD,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,YAAY;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QAC3F,IAAI,GAAG,CAAC,KAAK,KAAK,YAAY;YAAE,OAAO;QACvC,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAC1F,QAAQ,GAAG,CAAC,KAAK,EAAE,CAAC;YAClB,KAAK,MAAM,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;YACnE,KAAK,WAAW,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAChE,KAAK,kBAAkB,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;YACtE,OAAO,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAEO,qBAAqB,CAAC,GAAuB;QACnD,QAAQ,GAAG,CAAC,KAAK,EAAE,CAAC;YAClB,KAAK,MAAM,CAAC,CAAC,OAAO;YACpB,KAAK,YAAY,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;YAC3D,KAAK,WAAW,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAChE,KAAK,kBAAkB,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;YACtE,KAAK,YAAY,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;YAC1D,KAAK,SAAS,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;YACpD,OAAO,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAEO,sBAAsB,CAAC,UAAkB,EAAE,QAAgB,EAAE,GAAW;QAC9E,IAAI,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAChF,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACxC,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACpC,IAAI,CAAC,wBAAwB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC3C,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IAEO,wBAAwB,CAAC,GAAuB,EAAE,GAAW;QACnE,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,YAAY;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QAC3F,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAC5F,CAAC;IAEO,iBAAiB,CAAC,OAA2B;QACnD,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QAChE,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACxC,IACE,CAAC,IAAI;eACF,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC,QAAQ;eAClC,IAAI,CAAC,kBAAkB,KAAK,IAAI;eAChC,IAAI,CAAC,SAAS,KAAK,OAAO,CAAC,SAAS,EACvC,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAC5C,CAAC;QAED,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,CAAC,QAAQ,IAAI,GAAG,CAAC,SAAS,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC;gBAC7E,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;YAC5C,CAAC;YACD,IAAI,GAAG,CAAC,WAAW,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;gBACzC,MAAM,MAAM,GAAG,GAAG,CAAC,kBAAkB,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;gBAC9F,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,iBAAiB,KAAK,GAAG,CAAC,WAAW,EAAE,CAAC;oBAC5D,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC;YACD,IAAI,GAAG,CAAC,iBAAiB,KAAK,IAAI,EAAE,CAAC;gBACnC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;gBAC9C,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,kBAAkB,KAAK,GAAG,CAAC,WAAW,EAAE,CAAC;oBAC3D,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,OAAO,GAAyB,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;QAClC,IAAI,OAAO,GAAmC,IAAI,CAAC;QACnD,OAAO,OAAO,EAAE,CAAC;YACf,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;YAChF,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YACjC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACtB,OAAO,GAAG,OAAO,CAAC,iBAAiB,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACjG,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAE9E,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACrD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACjC,CAAC;IAEO,gBAAgB,CAAC,KAAyB,EAAE,OAA2B;QAC7E,IAAI,KAAK,CAAC,IAAI,CAAC,WAAW,KAAK,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,iBAAiB,KAAK,IAAI,EAAE,CAAC;YACzF,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAC5C,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1C,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,WAAW;gBAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAC/F,CAAC;IACH,CAAC;CACF;AAED,SAAS,gBAAgB,CAAC,KAAa,EAAE,IAAY;IACnD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;AACjG,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACpC,MAAM,IAAI,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;IAChE,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChF,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;AAC5B,CAAC;AAED,SAAS,OAAO,CAAC,GAAW;IAC1B,OAAO,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,GAAG,uBAAuB,CAAC,CAAC,WAAW,EAAE,CAAC;AACnF,CAAC"}
@@ -0,0 +1,138 @@
1
+ const HOUR_MS = 60 * 60 * 1000;
2
+ const RUN_RETENTION_MS = 30 * 24 * HOUR_MS;
3
+ export class RetentionService {
4
+ db;
5
+ responses;
6
+ workspaces;
7
+ now;
8
+ setIntervalFn;
9
+ clearIntervalFn;
10
+ onTimerError;
11
+ timer;
12
+ activeSweep;
13
+ constructor(db, responses, workspaces, options = {}) {
14
+ this.db = db;
15
+ this.responses = responses;
16
+ this.workspaces = workspaces;
17
+ this.now = options.now ?? Date.now;
18
+ this.setIntervalFn = options.setInterval
19
+ ?? ((callback, intervalMs) => setInterval(callback, intervalMs));
20
+ this.clearIntervalFn = options.clearInterval
21
+ ?? ((timer) => clearInterval(timer));
22
+ this.onTimerError = options.onTimerError
23
+ ?? ((error) => { console.error('Gateway retention sweep failed', error); });
24
+ }
25
+ async reconcileStartup(now = new Date(this.now())) {
26
+ const timestamp = validTimestamp(now);
27
+ const transaction = this.db.raw.transaction(() => {
28
+ const result = emptyResult();
29
+ result.interruptedRuns = this.db.prepare(`
30
+ UPDATE runs
31
+ SET status = 'interrupted', completed_at = ?,
32
+ latency_ms = CASE
33
+ WHEN started_at IS NULL THEN NULL
34
+ ELSE MAX(0, CAST((julianday(?) - julianday(started_at)) * 86400000 AS INTEGER))
35
+ END
36
+ WHERE status IN ('queued', 'running')
37
+ `).run(timestamp, timestamp).changes;
38
+ result.terminalResponseChains = this.db.prepare(`
39
+ SELECT COUNT(DISTINCT chain_id) AS count
40
+ FROM response_sessions
41
+ WHERE state = 'continuing'
42
+ `).get()?.count ?? 0;
43
+ this.db.prepare(`
44
+ UPDATE response_sessions
45
+ SET state = 'terminal_failure', updated_at = ?
46
+ WHERE chain_id IN (
47
+ SELECT chain_id FROM response_sessions WHERE state = 'continuing'
48
+ )
49
+ `).run(timestamp);
50
+ return result;
51
+ });
52
+ return transaction.immediate();
53
+ }
54
+ sweep(now = new Date(this.now())) {
55
+ if (this.activeSweep !== undefined) {
56
+ return Promise.reject(new Error('retention_sweep_in_progress'));
57
+ }
58
+ const operation = this.performSweep(now);
59
+ let tracked;
60
+ tracked = operation.finally(() => {
61
+ if (this.activeSweep === tracked)
62
+ this.activeSweep = undefined;
63
+ });
64
+ this.activeSweep = tracked;
65
+ return tracked;
66
+ }
67
+ async performSweep(now) {
68
+ const timestamp = validTimestamp(now);
69
+ const chains = this.responses.findExpiredForRetention(timestamp);
70
+ this.responses.hideForRetention(chains);
71
+ const paths = uniqueWorkspacePaths(chains);
72
+ const outcomes = paths.length === 0
73
+ ? []
74
+ : await this.workspaces.cleanupForRetention(paths);
75
+ const outcomeByPath = new Map(outcomes.map((outcome) => [outcome.path, outcome.status]));
76
+ const eligibleChains = chains.filter((chain) => chain.workspacePaths.every((path) => outcomeByPath.get(path) !== 'retry' && outcomeByPath.has(path)));
77
+ const cutoff = new Date(now.getTime() - RUN_RETENTION_MS).toISOString();
78
+ const transaction = this.db.raw.transaction(() => {
79
+ const result = emptyResult();
80
+ result.deletedResponses = this.responses.unlinkAndDeleteForRetention(eligibleChains.map((chain) => chain.chainId));
81
+ result.deletedIdempotencyKeys = this.db.prepare(`
82
+ DELETE FROM idempotency_keys
83
+ WHERE expires_at <= ? AND status != 'active'
84
+ `).run(timestamp).changes;
85
+ result.deletedRuns = this.db.prepare(`
86
+ DELETE FROM runs
87
+ WHERE status IN ('completed', 'failed', 'cancelled', 'interrupted')
88
+ AND completed_at < ?
89
+ AND NOT EXISTS (
90
+ SELECT 1 FROM idempotency_keys WHERE idempotency_keys.run_id = runs.id
91
+ )
92
+ `).run(cutoff).changes;
93
+ result.deletedAdminSessions = this.db.prepare('DELETE FROM admin_sessions WHERE expires_at <= ?').run(timestamp).changes;
94
+ result.deletedWorkspaces = outcomes.filter((outcome) => outcome.status === 'removed').length;
95
+ return result;
96
+ });
97
+ const result = transaction.immediate();
98
+ this.responses.releaseRetentionHidden(eligibleChains);
99
+ return result;
100
+ }
101
+ start() {
102
+ if (this.timer !== undefined)
103
+ return;
104
+ this.timer = this.setIntervalFn(() => {
105
+ if (this.activeSweep !== undefined)
106
+ return;
107
+ void this.sweep().catch(this.onTimerError);
108
+ }, HOUR_MS);
109
+ this.timer.unref?.();
110
+ }
111
+ async stop() {
112
+ if (this.timer !== undefined) {
113
+ this.clearIntervalFn(this.timer);
114
+ this.timer = undefined;
115
+ }
116
+ await this.activeSweep;
117
+ }
118
+ }
119
+ function emptyResult() {
120
+ return {
121
+ interruptedRuns: 0,
122
+ terminalResponseChains: 0,
123
+ deletedRuns: 0,
124
+ deletedResponses: 0,
125
+ deletedIdempotencyKeys: 0,
126
+ deletedAdminSessions: 0,
127
+ deletedWorkspaces: 0,
128
+ };
129
+ }
130
+ function validTimestamp(value) {
131
+ if (Number.isNaN(value.getTime()))
132
+ throw new Error('invalid_retention_time');
133
+ return value.toISOString();
134
+ }
135
+ function uniqueWorkspacePaths(chains) {
136
+ return [...new Set(chains.flatMap((chain) => chain.workspacePaths))].sort();
137
+ }
138
+ //# sourceMappingURL=retention.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retention.js","sourceRoot":"","sources":["../../src/control-plane/retention.ts"],"names":[],"mappings":"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"}