theokit 0.23.1 → 0.25.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 (95) hide show
  1. package/dist/actions-virtual-module-Z2IXNF72.js +0 -0
  2. package/dist/add-W6FNTAFS.js +0 -0
  3. package/dist/{agent-7IGDT55V.js → agent-GXJNFW6N.js} +2 -2
  4. package/dist/agents-typed-client-RIJVHSX4.js +0 -0
  5. package/dist/app-typed-client-YCQC3MZ7.js +0 -0
  6. package/dist/aws-lambda-7GSCNLPY.js +0 -0
  7. package/dist/body-parser-web-FV5HWCY3.js +0 -0
  8. package/dist/broadcast-LUMOJIJT.js +0 -0
  9. package/dist/{build-G7WWVZTL.js → build-WD2PT5TA.js} +2 -2
  10. package/dist/build-request-body-preview-QMWD2IXK.js +0 -0
  11. package/dist/bun-KP2KES6S.js +0 -0
  12. package/dist/check-PD2FTKMM.js +0 -0
  13. package/dist/chunk-2CVV6CNN.js +0 -0
  14. package/dist/{chunk-BLL5LY7R.js → chunk-2JNG3P4Y.js} +465 -25
  15. package/dist/chunk-2JNG3P4Y.js.map +1 -0
  16. package/dist/chunk-45C3WUQ7.js +0 -0
  17. package/dist/chunk-5ODOE6EF.js +0 -0
  18. package/dist/chunk-AFVTEAES.js +0 -0
  19. package/dist/{chunk-5PY3QPVM.js → chunk-DMGVH3VG.js} +30 -1
  20. package/dist/chunk-DMGVH3VG.js.map +1 -0
  21. package/dist/chunk-FOZIR3TG.js +0 -0
  22. package/dist/chunk-FRUEDJFX.js +0 -0
  23. package/dist/chunk-GDN3PXFH.js +0 -0
  24. package/dist/chunk-GEQJAFSV.js +0 -0
  25. package/dist/{chunk-AYZCGJXA.js → chunk-GG6H76GC.js} +5 -3
  26. package/dist/chunk-GG6H76GC.js.map +1 -0
  27. package/dist/chunk-GSO77FSM.js +0 -0
  28. package/dist/chunk-HGZL5EOI.js +0 -0
  29. package/dist/chunk-HNBWZKIQ.js +0 -0
  30. package/dist/chunk-IEES3CHD.js +0 -0
  31. package/dist/chunk-JAIKGP3Q.js +0 -0
  32. package/dist/chunk-KXA37ONC.js +0 -0
  33. package/dist/{chunk-JITNAZXE.js → chunk-LVGDYTU2.js} +2 -2
  34. package/dist/chunk-M6NMS5LR.js +0 -0
  35. package/dist/chunk-P37RZRFV.js +0 -0
  36. package/dist/chunk-S7L6H3KP.js +812 -0
  37. package/dist/chunk-S7L6H3KP.js.map +1 -0
  38. package/dist/chunk-TERFLG67.js +0 -0
  39. package/dist/chunk-WR4F4EEZ.js +0 -0
  40. package/dist/chunk-YJWEADAW.js +0 -0
  41. package/dist/cli/index.js +5 -5
  42. package/dist/cloudflare-C6E5SPAE.js +0 -0
  43. package/dist/configure-agent-registry-ZOBVU3MV.js +0 -0
  44. package/dist/db-3UNAMSFK.js +0 -0
  45. package/dist/deno-deploy-RFZN56X4.js +0 -0
  46. package/dist/{dev-SHAN56K5.js → dev-63UNEUF6.js} +3 -3
  47. package/dist/dev-emit-EFQRBVYS.js +0 -0
  48. package/dist/dispatcher-EJHL6JMJ.js +0 -0
  49. package/dist/docker-LZZB4D5E.js +0 -0
  50. package/dist/generate-373DALPY.js +0 -0
  51. package/dist/index.js +1 -2
  52. package/dist/index.js.map +1 -1
  53. package/dist/info-2OOXFTJX.js +0 -0
  54. package/dist/internal-api-Y5REPVUS.js +0 -0
  55. package/dist/load-config-3EAQTXPH.js +0 -0
  56. package/dist/{mcp-P4MHP3VA.js → mcp-MIZFVNCL.js} +2 -2
  57. package/dist/netlify-PMLHVPN4.js +0 -0
  58. package/dist/node-BPJ3Z4DT.js +0 -0
  59. package/dist/openapi-ERYWAT3A.js +0 -0
  60. package/dist/registry-3NB7KOUI.js +0 -0
  61. package/dist/router-TLEAOFID.js +0 -0
  62. package/dist/routes-XNS3UM3B.js +0 -0
  63. package/dist/scan-7MJC6PYU.js +0 -0
  64. package/dist/schema-LYOLNHZ7.js +0 -0
  65. package/dist/server/define/index.js +2 -4
  66. package/dist/server/index.js +2 -4
  67. package/dist/server/index.js.map +1 -1
  68. package/dist/server-error-to-envelope-UUXDSLAZ.js +0 -0
  69. package/dist/server-routes-hmr-VZXOP5YT.js +0 -0
  70. package/dist/services-json-Y3XODNB5.js +0 -0
  71. package/dist/services-typed-client-32KMTTXR.js +0 -0
  72. package/dist/{start-RD5WQMIH.js → start-IFTLTEPZ.js} +5 -3
  73. package/dist/{start-RD5WQMIH.js.map → start-IFTLTEPZ.js.map} +1 -1
  74. package/dist/static-MB2CD5Y3.js +0 -0
  75. package/dist/storage-manager-ZSQFLEYT.js +0 -0
  76. package/dist/theo-cloud-DQRP6S6M.js +0 -0
  77. package/dist/upgrade-readiness-ACGW44JC.js +0 -0
  78. package/dist/vercel-J6G7ZHYQ.js +0 -0
  79. package/dist/vite-plugin/index.js +1 -2
  80. package/dist/{vite-plugin-A7WGYEMD.js → vite-plugin-ST4JZQRJ.js} +3 -3
  81. package/package.json +10 -10
  82. package/LICENSE +0 -201
  83. package/dist/chunk-5PY3QPVM.js.map +0 -1
  84. package/dist/chunk-AYZCGJXA.js.map +0 -1
  85. package/dist/chunk-BLL5LY7R.js.map +0 -1
  86. package/dist/chunk-JZHT3LW7.js +0 -32
  87. package/dist/chunk-JZHT3LW7.js.map +0 -1
  88. package/dist/chunk-LGVVX3BV.js +0 -401
  89. package/dist/chunk-LGVVX3BV.js.map +0 -1
  90. /package/dist/{agent-7IGDT55V.js.map → agent-GXJNFW6N.js.map} +0 -0
  91. /package/dist/{build-G7WWVZTL.js.map → build-WD2PT5TA.js.map} +0 -0
  92. /package/dist/{chunk-JITNAZXE.js.map → chunk-LVGDYTU2.js.map} +0 -0
  93. /package/dist/{dev-SHAN56K5.js.map → dev-63UNEUF6.js.map} +0 -0
  94. /package/dist/{mcp-P4MHP3VA.js.map → mcp-MIZFVNCL.js.map} +0 -0
  95. /package/dist/{vite-plugin-A7WGYEMD.js.map → vite-plugin-ST4JZQRJ.js.map} +0 -0
File without changes
File without changes
@@ -3,7 +3,7 @@ import "tsx/esm";
3
3
  import {
4
4
  agentCommand,
5
5
  createAgentSsrLoader
6
- } from "./chunk-JITNAZXE.js";
6
+ } from "./chunk-LVGDYTU2.js";
7
7
  import "./chunk-M6NMS5LR.js";
8
8
  import "./chunk-GDN3PXFH.js";
9
9
  import "./chunk-TERFLG67.js";
@@ -12,4 +12,4 @@ export {
12
12
  agentCommand,
13
13
  createAgentSsrLoader
14
14
  };
15
- //# sourceMappingURL=agent-7IGDT55V.js.map
15
+ //# sourceMappingURL=agent-GXJNFW6N.js.map
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -531,7 +531,7 @@ async function buildCommand(options) {
531
531
  `);
532
532
  }
533
533
  async function runAdapterBuild(target, config, cwd) {
534
- const { theoPluginAsync } = await import("./vite-plugin-A7WGYEMD.js");
534
+ const { theoPluginAsync } = await import("./vite-plugin-ST4JZQRJ.js");
535
535
  const { default: react } = await import("@vitejs/plugin-react");
536
536
  const ctx = {
537
537
  // `react()` may return Plugin or Plugin[] depending on version; spread the
@@ -616,4 +616,4 @@ function relativize3(absPath, root) {
616
616
  export {
617
617
  buildCommand
618
618
  };
619
- //# sourceMappingURL=build-G7WWVZTL.js.map
619
+ //# sourceMappingURL=build-WD2PT5TA.js.map
File without changes
File without changes
File without changes
File without changes
@@ -44,9 +44,6 @@ import {
44
44
  import {
45
45
  importUserModule
46
46
  } from "./chunk-7MQOHNHE.js";
47
- import {
48
- uiMessageStreamResponse
49
- } from "./chunk-JZHT3LW7.js";
50
47
  import {
51
48
  BATCH_PATH,
52
49
  TRACE_HEADER,
@@ -1158,11 +1155,164 @@ function handleListApprovals(registry2) {
1158
1155
  }
1159
1156
 
1160
1157
  // src/server/agent/mount-agent.ts
1158
+ import { compileAgentModule as compileAgentModule3, resolveEnabledSkills as resolveEnabledSkills2, streamAgentUIMessages as streamAgentUIMessages2 } from "@theokit/agents";
1159
+
1160
+ // src/server/agent/build-agent-streamer.ts
1161
1161
  import {
1162
1162
  compileAgentModule as compileAgentModule2,
1163
1163
  resolveEnabledSkills,
1164
1164
  streamAgentUIMessages
1165
1165
  } from "@theokit/agents";
1166
+ function buildAgentHitl(compiled) {
1167
+ const gated = compiled.hitl;
1168
+ if (gated === void 0 || gated.size === 0) return void 0;
1169
+ const registry2 = getApprovalRegistry();
1170
+ return {
1171
+ gated,
1172
+ awaitApproval: (approvalId, opts, toolName) => registry2.register(approvalId, {
1173
+ timeoutMs: opts.timeout ?? 3e5,
1174
+ onTimeout: opts.onTimeout ?? "abort",
1175
+ toolName,
1176
+ question: opts.question,
1177
+ ...opts.payloadSchema !== void 0 ? { payloadSchema: opts.payloadSchema } : {}
1178
+ })
1179
+ };
1180
+ }
1181
+ function makeThreadStartRun(mod, apiKey, source) {
1182
+ return (sessionId, message) => (async function* () {
1183
+ const compiled = compileAgentModule2(mod, source);
1184
+ if (compiled.skillsResolver) {
1185
+ const enabled = await resolveEnabledSkills(
1186
+ compiled.skillsResolver,
1187
+ compiled.runContext ?? {}
1188
+ );
1189
+ if (enabled !== void 0) compiled.skills = { enabled, autoInject: true };
1190
+ }
1191
+ const hitl = buildAgentHitl(compiled);
1192
+ yield* streamAgentUIMessages(compiled, apiKey, { message, sessionId, hitl });
1193
+ })();
1194
+ }
1195
+
1196
+ // src/server/agent/durable-ui-message-stream-response.ts
1197
+ var SSE_BASE_HEADERS = {
1198
+ "content-type": "text/event-stream",
1199
+ "x-vercel-ai-ui-message-stream": "v1"
1200
+ };
1201
+ var RUN_ID_HEADER = "x-theokit-run-id";
1202
+ var SSE_DONE_FRAME = "data: [DONE]\n\n";
1203
+ function formatSseFrame(seq, data) {
1204
+ return `id: ${seq}
1205
+ data: ${data}
1206
+
1207
+ `;
1208
+ }
1209
+ function encodeSse(text) {
1210
+ return new TextEncoder().encode(text);
1211
+ }
1212
+ function durableUiMessageStreamResponse(chunks, deps) {
1213
+ const { runId, cache } = deps;
1214
+ const stream = new ReadableStream({
1215
+ async start(controller) {
1216
+ try {
1217
+ for await (const chunk of chunks) {
1218
+ const data = JSON.stringify(chunk);
1219
+ const seq = cache.append(runId, data);
1220
+ controller.enqueue(encodeSse(formatSseFrame(seq, data)));
1221
+ }
1222
+ } catch {
1223
+ } finally {
1224
+ cache.end(runId);
1225
+ controller.enqueue(encodeSse(SSE_DONE_FRAME));
1226
+ controller.close();
1227
+ }
1228
+ }
1229
+ });
1230
+ return new Response(stream, {
1231
+ headers: { ...SSE_BASE_HEADERS, [RUN_ID_HEADER]: runId }
1232
+ });
1233
+ }
1234
+
1235
+ // src/server/agent/run-event-cache.ts
1236
+ var DEFAULT_EVICT_AFTER_MS = 5 * 6e4;
1237
+ var NOOP_UNSUBSCRIBE = () => {
1238
+ };
1239
+ function createInMemoryRunEventCache(opts = {}) {
1240
+ const evictAfterMs = opts.evictAfterMs ?? DEFAULT_EVICT_AFTER_MS;
1241
+ const runs = /* @__PURE__ */ new Map();
1242
+ function getOrCreate(runId) {
1243
+ let buf = runs.get(runId);
1244
+ if (buf === void 0) {
1245
+ buf = { frames: [], ended: false, listeners: /* @__PURE__ */ new Set() };
1246
+ runs.set(runId, buf);
1247
+ }
1248
+ return buf;
1249
+ }
1250
+ return {
1251
+ begin(runId) {
1252
+ getOrCreate(runId);
1253
+ },
1254
+ append(runId, data) {
1255
+ const buf = getOrCreate(runId);
1256
+ const seq = buf.frames.length;
1257
+ const frame = { seq, data };
1258
+ buf.frames.push(frame);
1259
+ for (const l of buf.listeners) {
1260
+ try {
1261
+ l.onFrame(frame);
1262
+ } catch {
1263
+ }
1264
+ }
1265
+ return seq;
1266
+ },
1267
+ has(runId) {
1268
+ return runs.has(runId);
1269
+ },
1270
+ end(runId) {
1271
+ const buf = runs.get(runId);
1272
+ if (buf === void 0 || buf.ended) return;
1273
+ buf.ended = true;
1274
+ for (const l of buf.listeners) {
1275
+ try {
1276
+ l.onEnd();
1277
+ } catch {
1278
+ }
1279
+ }
1280
+ buf.listeners.clear();
1281
+ buf.evictTimer = setTimeout(() => runs.delete(runId), evictAfterMs);
1282
+ buf.evictTimer.unref();
1283
+ },
1284
+ attach(runId, afterSeq, onFrame, onEnd) {
1285
+ const buf = runs.get(runId);
1286
+ if (buf === void 0) {
1287
+ return { known: false, replay: [], ended: false, unsubscribe: NOOP_UNSUBSCRIBE };
1288
+ }
1289
+ const replay = buf.frames.filter((f) => f.seq > afterSeq);
1290
+ if (buf.ended) {
1291
+ return { known: true, replay, ended: true, unsubscribe: NOOP_UNSUBSCRIBE };
1292
+ }
1293
+ const listener = { onFrame, onEnd };
1294
+ buf.listeners.add(listener);
1295
+ return {
1296
+ known: true,
1297
+ replay,
1298
+ ended: false,
1299
+ unsubscribe: () => {
1300
+ buf.listeners.delete(listener);
1301
+ }
1302
+ };
1303
+ }
1304
+ };
1305
+ }
1306
+ var serverCache;
1307
+ function getRunEventCache() {
1308
+ serverCache ??= createInMemoryRunEventCache();
1309
+ return serverCache;
1310
+ }
1311
+ function mintRunId() {
1312
+ return `run-${crypto.randomUUID()}`;
1313
+ }
1314
+
1315
+ // src/server/agent/mount-agent.ts
1166
1316
  function partText(part) {
1167
1317
  if (typeof part !== "object" || part === null) return "";
1168
1318
  const p = part;
@@ -1198,9 +1348,9 @@ async function mountAgent(mod, request, apiKey, source = "agent module", csrfMod
1198
1348
  return jsonError2(403, "CSRF_FAILED", `CSRF check failed: ${csrf.reason}`);
1199
1349
  }
1200
1350
  }
1201
- const compiled = compileAgentModule2(mod, source);
1351
+ const compiled = compileAgentModule3(mod, source);
1202
1352
  if (compiled.skillsResolver) {
1203
- const enabled = await resolveEnabledSkills(compiled.skillsResolver, compiled.runContext ?? {});
1353
+ const enabled = await resolveEnabledSkills2(compiled.skillsResolver, compiled.runContext ?? {});
1204
1354
  if (enabled !== void 0) compiled.skills = { enabled, autoInject: true };
1205
1355
  }
1206
1356
  let body = null;
@@ -1212,22 +1362,11 @@ async function mountAgent(mod, request, apiKey, source = "agent module", csrfMod
1212
1362
  if (input === null) {
1213
1363
  return jsonError2(400, "BAD_REQUEST", "Request must contain a non-empty message or messages[].");
1214
1364
  }
1215
- const gated = compiled.hitl;
1216
- const registry2 = getApprovalRegistry();
1217
- const hitl = gated && gated.size > 0 ? {
1218
- gated,
1219
- awaitApproval: (approvalId, opts, toolName) => registry2.register(approvalId, {
1220
- timeoutMs: opts.timeout ?? 3e5,
1221
- onTimeout: opts.onTimeout ?? "abort",
1222
- // M14 — surface toolName + question in GET /approvals (the plugin forwards c.name).
1223
- toolName,
1224
- question: opts.question,
1225
- // M20 — carry the declared custom-payload schema into GET /approvals.
1226
- ...opts.payloadSchema !== void 0 ? { payloadSchema: opts.payloadSchema } : {}
1227
- })
1228
- } : void 0;
1229
- return uiMessageStreamResponse(
1230
- streamAgentUIMessages(compiled, apiKey, { ...input, hitl, signal: request.signal })
1365
+ const hitl = buildAgentHitl(compiled);
1366
+ const runId = mintRunId();
1367
+ return durableUiMessageStreamResponse(
1368
+ streamAgentUIMessages2(compiled, apiKey, { ...input, hitl, signal: request.signal }),
1369
+ { runId, cache: getRunEventCache() }
1231
1370
  );
1232
1371
  }
1233
1372
 
@@ -1271,13 +1410,273 @@ function resolveProvider() {
1271
1410
  );
1272
1411
  }
1273
1412
 
1274
- // src/server/agent/serve-aux-routes.ts
1413
+ // src/server/agent/handle-agent-run-reconnect.ts
1414
+ var RUN_STREAM_PATH = /^\/api\/agents\/([^/]+)\/runs\/([^/]+)\/stream$/;
1415
+ function isAgentRunStreamPath(urlPath) {
1416
+ const m = RUN_STREAM_PATH.exec(urlPath);
1417
+ return m ? { name: decodeURIComponent(m[1]), runId: decodeURIComponent(m[2]) } : null;
1418
+ }
1419
+ function parseLastEventId(raw) {
1420
+ if (raw === null) return -1;
1421
+ const n = Number.parseInt(raw, 10);
1422
+ return Number.isInteger(n) && n >= 0 ? n : -1;
1423
+ }
1424
+ function handleAgentRunReconnect(runId, request, cache) {
1425
+ if (!cache.has(runId)) {
1426
+ return new Response(
1427
+ JSON.stringify({ error: { code: "RUN_NOT_FOUND", message: `Unknown run '${runId}'.` } }),
1428
+ {
1429
+ status: 404,
1430
+ headers: { "content-type": "application/json" }
1431
+ }
1432
+ );
1433
+ }
1434
+ const afterSeq = parseLastEventId(request.headers.get("last-event-id"));
1435
+ const stream = new ReadableStream({
1436
+ start(controller) {
1437
+ let closed = false;
1438
+ const safeEnqueue = (text) => {
1439
+ if (closed) return;
1440
+ try {
1441
+ controller.enqueue(encodeSse(text));
1442
+ } catch {
1443
+ }
1444
+ };
1445
+ const close = () => {
1446
+ if (closed) return;
1447
+ safeEnqueue(SSE_DONE_FRAME);
1448
+ closed = true;
1449
+ try {
1450
+ controller.close();
1451
+ } catch {
1452
+ }
1453
+ };
1454
+ const res = cache.attach(
1455
+ runId,
1456
+ afterSeq,
1457
+ (frame) => {
1458
+ safeEnqueue(formatSseFrame(frame.seq, frame.data));
1459
+ },
1460
+ () => {
1461
+ close();
1462
+ }
1463
+ );
1464
+ if (!res.known) {
1465
+ close();
1466
+ return;
1467
+ }
1468
+ for (const frame of res.replay) {
1469
+ safeEnqueue(formatSseFrame(frame.seq, frame.data));
1470
+ }
1471
+ if (res.ended) {
1472
+ close();
1473
+ return;
1474
+ }
1475
+ request.signal.addEventListener("abort", () => {
1476
+ res.unsubscribe();
1477
+ close();
1478
+ });
1479
+ }
1480
+ });
1481
+ return new Response(stream, { headers: { ...SSE_BASE_HEADERS, [RUN_ID_HEADER]: runId } });
1482
+ }
1483
+
1484
+ // src/server/agent/thread-dispatcher.ts
1485
+ function postThreadFollowUp(deps, sessionId, message) {
1486
+ if (deps.registry.getActive(sessionId) !== null) {
1487
+ deps.registry.queue(sessionId, { message });
1488
+ return { queued: true };
1489
+ }
1490
+ return { runId: startAndPump(deps, sessionId, message) };
1491
+ }
1492
+ function startAndPump(deps, sessionId, message) {
1493
+ const runId = mintRunId();
1494
+ deps.cache.begin(runId);
1495
+ deps.registry.startRun(sessionId, runId);
1496
+ pumpIntoCache(deps, sessionId, runId, deps.startRun(sessionId, message));
1497
+ return runId;
1498
+ }
1499
+ function pumpIntoCache(deps, sessionId, runId, chunks) {
1500
+ void (async () => {
1501
+ try {
1502
+ for await (const chunk of chunks) {
1503
+ deps.cache.append(runId, JSON.stringify(chunk));
1504
+ }
1505
+ } catch {
1506
+ } finally {
1507
+ deps.cache.end(runId);
1508
+ const next = deps.registry.endRun(sessionId, runId);
1509
+ if (next !== void 0) startAndPump(deps, sessionId, next.message);
1510
+ }
1511
+ })();
1512
+ }
1513
+
1514
+ // src/server/agent/thread-run-registry.ts
1515
+ function createInProcessThreadRunRegistry() {
1516
+ const threads = /* @__PURE__ */ new Map();
1517
+ const ensure = (sessionId) => {
1518
+ let s = threads.get(sessionId);
1519
+ if (s === void 0) {
1520
+ s = { activeRunId: null, queue: [], waiters: /* @__PURE__ */ new Set() };
1521
+ threads.set(sessionId, s);
1522
+ }
1523
+ return s;
1524
+ };
1525
+ return {
1526
+ getActive(sessionId) {
1527
+ return threads.get(sessionId)?.activeRunId ?? null;
1528
+ },
1529
+ startRun(sessionId, runId) {
1530
+ const s = ensure(sessionId);
1531
+ s.activeRunId = runId;
1532
+ const waiters = [...s.waiters];
1533
+ s.waiters.clear();
1534
+ for (const cb of waiters) cb(runId);
1535
+ },
1536
+ endRun(sessionId, runId) {
1537
+ const s = threads.get(sessionId);
1538
+ if (s?.activeRunId !== runId) return void 0;
1539
+ s.activeRunId = null;
1540
+ return s.queue.shift();
1541
+ },
1542
+ queue(sessionId, followUp) {
1543
+ ensure(sessionId).queue.push(followUp);
1544
+ },
1545
+ onNextRun(sessionId, cb) {
1546
+ const s = ensure(sessionId);
1547
+ s.waiters.add(cb);
1548
+ return () => {
1549
+ s.waiters.delete(cb);
1550
+ };
1551
+ }
1552
+ };
1553
+ }
1554
+ var serverRegistry2;
1555
+ function getThreadRunRegistry() {
1556
+ serverRegistry2 ??= createInProcessThreadRunRegistry();
1557
+ return serverRegistry2;
1558
+ }
1559
+
1560
+ // src/server/agent/handle-thread-routes.ts
1561
+ var THREAD_MESSAGE_PATH = /^\/api\/agents\/([^/]+)\/threads\/([^/]+)\/message$/;
1562
+ var THREAD_STREAM_PATH = /^\/api\/agents\/([^/]+)\/threads\/([^/]+)\/stream$/;
1563
+ var DEFAULT_IDLE_WAIT_MS = 3e4;
1564
+ function matchThread(re, urlPath) {
1565
+ const m = re.exec(urlPath);
1566
+ return m ? { name: decodeURIComponent(m[1]), sessionId: decodeURIComponent(m[2]) } : null;
1567
+ }
1568
+ var isThreadMessagePath = (urlPath) => matchThread(THREAD_MESSAGE_PATH, urlPath);
1569
+ var isThreadStreamPath = (urlPath) => matchThread(THREAD_STREAM_PATH, urlPath);
1275
1570
  function jsonError3(status, code, message) {
1276
1571
  return new Response(JSON.stringify({ error: { code, message } }), {
1277
1572
  status,
1278
1573
  headers: { "content-type": "application/json; charset=utf-8" }
1279
1574
  });
1280
1575
  }
1576
+ async function handleThreadMessage(args) {
1577
+ const { mod, apiKey, sessionId, request, source, csrfMode = "strict" } = args;
1578
+ if (csrfMode === "strict") {
1579
+ const csrf = validateCsrfRequest(request);
1580
+ if (!csrf.valid) return jsonError3(403, "CSRF_FAILED", `CSRF check failed: ${csrf.reason}`);
1581
+ }
1582
+ let body = null;
1583
+ try {
1584
+ body = await request.json();
1585
+ } catch {
1586
+ }
1587
+ const input = parseAgentRequestBody(body);
1588
+ if (input === null) {
1589
+ return jsonError3(400, "BAD_REQUEST", "Request must contain a non-empty message.");
1590
+ }
1591
+ const result = postThreadFollowUp(
1592
+ {
1593
+ registry: getThreadRunRegistry(),
1594
+ cache: getRunEventCache(),
1595
+ startRun: makeThreadStartRun(mod, apiKey, source)
1596
+ },
1597
+ sessionId,
1598
+ input.message
1599
+ );
1600
+ const headers = { "content-type": "application/json; charset=utf-8" };
1601
+ if ("runId" in result) headers[RUN_ID_HEADER] = result.runId;
1602
+ return new Response(JSON.stringify(result), { status: 202, headers });
1603
+ }
1604
+ function handleThreadStream(sessionId, request, registry2 = getThreadRunRegistry(), cache = getRunEventCache(), idleWaitMs = DEFAULT_IDLE_WAIT_MS) {
1605
+ const active = registry2.getActive(sessionId);
1606
+ if (active !== null && cache.has(active)) {
1607
+ return handleAgentRunReconnect(active, request, cache);
1608
+ }
1609
+ return waitThenAttachStream(sessionId, request, registry2, cache, idleWaitMs);
1610
+ }
1611
+ function waitThenAttachStream(sessionId, request, registry2, cache, idleWaitMs) {
1612
+ const stream = new ReadableStream({
1613
+ start(controller) {
1614
+ let closed = false;
1615
+ const send = (text) => {
1616
+ if (closed) return;
1617
+ try {
1618
+ controller.enqueue(encodeSse(text));
1619
+ } catch {
1620
+ }
1621
+ };
1622
+ let detachAttach;
1623
+ const close = () => {
1624
+ if (closed) return;
1625
+ send(SSE_DONE_FRAME);
1626
+ closed = true;
1627
+ try {
1628
+ controller.close();
1629
+ } catch {
1630
+ }
1631
+ };
1632
+ const offNext = registry2.onNextRun(sessionId, (runId) => {
1633
+ const res = cache.attach(
1634
+ runId,
1635
+ -1,
1636
+ (frame) => {
1637
+ send(formatSseFrame(frame.seq, frame.data));
1638
+ },
1639
+ () => {
1640
+ close();
1641
+ }
1642
+ );
1643
+ if (!res.known) {
1644
+ close();
1645
+ return;
1646
+ }
1647
+ for (const frame of res.replay) send(formatSseFrame(frame.seq, frame.data));
1648
+ if (res.ended) {
1649
+ close();
1650
+ return;
1651
+ }
1652
+ detachAttach = res.unsubscribe;
1653
+ });
1654
+ const teardownWaiter = () => {
1655
+ offNext();
1656
+ detachAttach?.();
1657
+ };
1658
+ const timer = setTimeout(() => {
1659
+ teardownWaiter();
1660
+ close();
1661
+ }, idleWaitMs);
1662
+ timer.unref();
1663
+ request.signal.addEventListener("abort", () => {
1664
+ teardownWaiter();
1665
+ clearTimeout(timer);
1666
+ close();
1667
+ });
1668
+ }
1669
+ });
1670
+ return new Response(stream, { headers: { ...SSE_BASE_HEADERS } });
1671
+ }
1672
+
1673
+ // src/server/agent/serve-aux-routes.ts
1674
+ function jsonError4(status, code, message) {
1675
+ return new Response(JSON.stringify({ error: { code, message } }), {
1676
+ status,
1677
+ headers: { "content-type": "application/json; charset=utf-8" }
1678
+ });
1679
+ }
1281
1680
  async function serveAgentAuxRoute(request, urlPath, deps) {
1282
1681
  const method = request.method.toUpperCase();
1283
1682
  const cardName = isAgentCardPath(urlPath);
@@ -1292,12 +1691,51 @@ async function serveAgentAuxRoute(request, urlPath, deps) {
1292
1691
  if (method !== "GET") return null;
1293
1692
  return handleListApprovals(getApprovalRegistry());
1294
1693
  }
1694
+ const runStream = isAgentRunStreamPath(urlPath);
1695
+ if (runStream !== null) {
1696
+ if (method !== "GET") return null;
1697
+ if (!deps.agents.some((a) => a.name === runStream.name)) return null;
1698
+ return handleAgentRunReconnect(runStream.runId, request, getRunEventCache());
1699
+ }
1700
+ const threadResponse = await serveThreadRoute(request, method, urlPath, deps);
1701
+ if (threadResponse !== null) return threadResponse;
1295
1702
  const mcpName = isMcpPath(urlPath);
1296
1703
  if (mcpName !== null) {
1297
1704
  return serveMcpRoute(request, method, mcpName, deps);
1298
1705
  }
1299
1706
  return null;
1300
1707
  }
1708
+ async function serveThreadRoute(request, method, urlPath, deps) {
1709
+ const stream = isThreadStreamPath(urlPath);
1710
+ if (stream !== null) {
1711
+ if (method !== "GET") return null;
1712
+ if (!deps.agents.some((a) => a.name === stream.name)) return null;
1713
+ return handleThreadStream(stream.sessionId, request);
1714
+ }
1715
+ const msg = isThreadMessagePath(urlPath);
1716
+ if (msg !== null) {
1717
+ if (method !== "POST") return null;
1718
+ const agent = deps.agents.find((a) => a.name === msg.name);
1719
+ if (!agent) return null;
1720
+ if (deps.resolveApiKey === void 0) {
1721
+ return jsonError4(
1722
+ 501,
1723
+ "NOT_CONFIGURED",
1724
+ "Thread follow-up requires a provider API key (resolveApiKey was not provided to serveAgentAuxRoute)."
1725
+ );
1726
+ }
1727
+ const mod = await deps.loadModule(agent.filePath);
1728
+ return handleThreadMessage({
1729
+ mod,
1730
+ apiKey: deps.resolveApiKey(),
1731
+ sessionId: msg.sessionId,
1732
+ request,
1733
+ source: `agent "${msg.name}"`,
1734
+ csrfMode: deps.csrfMode ?? "strict"
1735
+ });
1736
+ }
1737
+ return null;
1738
+ }
1301
1739
  async function serveMcpRoute(request, method, mcpName, deps) {
1302
1740
  if (method !== "POST") return null;
1303
1741
  const agent = deps.agents.find((a) => a.name === mcpName);
@@ -1307,7 +1745,7 @@ async function serveMcpRoute(request, method, mcpName, deps) {
1307
1745
  const csrfMode = deps.csrfMode ?? "strict";
1308
1746
  if (csrfMode === "strict") {
1309
1747
  const csrf = validateCsrfRequest(request);
1310
- if (!csrf.valid) return jsonError3(403, "CSRF_FAILED", `CSRF check failed: ${csrf.reason}`);
1748
+ if (!csrf.valid) return jsonError4(403, "CSRF_FAILED", `CSRF check failed: ${csrf.reason}`);
1311
1749
  }
1312
1750
  let body = null;
1313
1751
  try {
@@ -1441,7 +1879,9 @@ async function serveAux(req, res, next, urlPath, deps) {
1441
1879
  agents: scanAgents(deps.projectRoot, deps.agentsDir),
1442
1880
  loadModule: deps.loadModule,
1443
1881
  baseUrl: `http://${req.headers.host ?? "localhost"}`,
1444
- csrfMode: deps.csrfMode
1882
+ csrfMode: deps.csrfMode,
1883
+ // M39 — the thread follow-up route drives the agent; resolve the key on demand.
1884
+ resolveApiKey: () => resolveProvider().apiKey
1445
1885
  });
1446
1886
  if (response === null) {
1447
1887
  next();
@@ -3097,4 +3537,4 @@ export {
3097
3537
  theoPluginAsync,
3098
3538
  theoPlugin
3099
3539
  };
3100
- //# sourceMappingURL=chunk-BLL5LY7R.js.map
3540
+ //# sourceMappingURL=chunk-2JNG3P4Y.js.map