theokit 0.24.0 → 0.26.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 (30) hide show
  1. package/dist/{agent-7474NDZD.js → agent-GXJNFW6N.js} +2 -2
  2. package/dist/{build-CVWAK4UE.js → build-WD2PT5TA.js} +2 -2
  3. package/dist/{chunk-FARW5PH6.js → chunk-2JNG3P4Y.js} +267 -21
  4. package/dist/chunk-2JNG3P4Y.js.map +1 -0
  5. package/dist/{chunk-IEA4O6ZN.js → chunk-GG6H76GC.js} +5 -3
  6. package/dist/chunk-GG6H76GC.js.map +1 -0
  7. package/dist/{chunk-ZGKGXXZG.js → chunk-LVGDYTU2.js} +2 -2
  8. package/dist/{chunk-VK553I55.js → chunk-S7L6H3KP.js} +264 -20
  9. package/dist/chunk-S7L6H3KP.js.map +1 -0
  10. package/dist/cli/index.js +5 -5
  11. package/dist/{dev-FSTYMPPF.js → dev-63UNEUF6.js} +3 -3
  12. package/dist/index.js +1 -1
  13. package/dist/{mcp-TOYHKCB6.js → mcp-MIZFVNCL.js} +2 -2
  14. package/dist/server/index.d.ts +10 -5
  15. package/dist/server/index.js +31 -7
  16. package/dist/server/index.js.map +1 -1
  17. package/dist/{start-LEDGWJF2.js → start-IFTLTEPZ.js} +5 -3
  18. package/dist/{start-LEDGWJF2.js.map → start-IFTLTEPZ.js.map} +1 -1
  19. package/dist/vite-plugin/index.js +1 -1
  20. package/dist/{vite-plugin-HSOWPMK4.js → vite-plugin-ST4JZQRJ.js} +3 -3
  21. package/package.json +1 -1
  22. package/dist/chunk-FARW5PH6.js.map +0 -1
  23. package/dist/chunk-IEA4O6ZN.js.map +0 -1
  24. package/dist/chunk-VK553I55.js.map +0 -1
  25. /package/dist/{agent-7474NDZD.js.map → agent-GXJNFW6N.js.map} +0 -0
  26. /package/dist/{build-CVWAK4UE.js.map → build-WD2PT5TA.js.map} +0 -0
  27. /package/dist/{chunk-ZGKGXXZG.js.map → chunk-LVGDYTU2.js.map} +0 -0
  28. /package/dist/{dev-FSTYMPPF.js.map → dev-63UNEUF6.js.map} +0 -0
  29. /package/dist/{mcp-TOYHKCB6.js.map → mcp-MIZFVNCL.js.map} +0 -0
  30. /package/dist/{vite-plugin-HSOWPMK4.js.map → vite-plugin-ST4JZQRJ.js.map} +0 -0
@@ -3,7 +3,7 @@ import "tsx/esm";
3
3
  import {
4
4
  agentCommand,
5
5
  createAgentSsrLoader
6
- } from "./chunk-ZGKGXXZG.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-7474NDZD.js.map
15
+ //# sourceMappingURL=agent-GXJNFW6N.js.map
@@ -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-HSOWPMK4.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-CVWAK4UE.js.map
619
+ //# sourceMappingURL=build-WD2PT5TA.js.map
@@ -1155,11 +1155,43 @@ function handleListApprovals(registry2) {
1155
1155
  }
1156
1156
 
1157
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
1158
1161
  import {
1159
1162
  compileAgentModule as compileAgentModule2,
1160
1163
  resolveEnabledSkills,
1161
1164
  streamAgentUIMessages
1162
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
+ }
1163
1195
 
1164
1196
  // src/server/agent/durable-ui-message-stream-response.ts
1165
1197
  var SSE_BASE_HEADERS = {
@@ -1216,6 +1248,9 @@ function createInMemoryRunEventCache(opts = {}) {
1216
1248
  return buf;
1217
1249
  }
1218
1250
  return {
1251
+ begin(runId) {
1252
+ getOrCreate(runId);
1253
+ },
1219
1254
  append(runId, data) {
1220
1255
  const buf = getOrCreate(runId);
1221
1256
  const seq = buf.frames.length;
@@ -1313,9 +1348,9 @@ async function mountAgent(mod, request, apiKey, source = "agent module", csrfMod
1313
1348
  return jsonError2(403, "CSRF_FAILED", `CSRF check failed: ${csrf.reason}`);
1314
1349
  }
1315
1350
  }
1316
- const compiled = compileAgentModule2(mod, source);
1351
+ const compiled = compileAgentModule3(mod, source);
1317
1352
  if (compiled.skillsResolver) {
1318
- const enabled = await resolveEnabledSkills(compiled.skillsResolver, compiled.runContext ?? {});
1353
+ const enabled = await resolveEnabledSkills2(compiled.skillsResolver, compiled.runContext ?? {});
1319
1354
  if (enabled !== void 0) compiled.skills = { enabled, autoInject: true };
1320
1355
  }
1321
1356
  let body = null;
@@ -1327,23 +1362,10 @@ async function mountAgent(mod, request, apiKey, source = "agent module", csrfMod
1327
1362
  if (input === null) {
1328
1363
  return jsonError2(400, "BAD_REQUEST", "Request must contain a non-empty message or messages[].");
1329
1364
  }
1330
- const gated = compiled.hitl;
1331
- const registry2 = getApprovalRegistry();
1332
- const hitl = gated && gated.size > 0 ? {
1333
- gated,
1334
- awaitApproval: (approvalId, opts, toolName) => registry2.register(approvalId, {
1335
- timeoutMs: opts.timeout ?? 3e5,
1336
- onTimeout: opts.onTimeout ?? "abort",
1337
- // M14 — surface toolName + question in GET /approvals (the plugin forwards c.name).
1338
- toolName,
1339
- question: opts.question,
1340
- // M20 — carry the declared custom-payload schema into GET /approvals.
1341
- ...opts.payloadSchema !== void 0 ? { payloadSchema: opts.payloadSchema } : {}
1342
- })
1343
- } : void 0;
1365
+ const hitl = buildAgentHitl(compiled);
1344
1366
  const runId = mintRunId();
1345
1367
  return durableUiMessageStreamResponse(
1346
- streamAgentUIMessages(compiled, apiKey, { ...input, hitl, signal: request.signal }),
1368
+ streamAgentUIMessages2(compiled, apiKey, { ...input, hitl, signal: request.signal }),
1347
1369
  { runId, cache: getRunEventCache() }
1348
1370
  );
1349
1371
  }
@@ -1459,13 +1481,202 @@ function handleAgentRunReconnect(runId, request, cache) {
1459
1481
  return new Response(stream, { headers: { ...SSE_BASE_HEADERS, [RUN_ID_HEADER]: runId } });
1460
1482
  }
1461
1483
 
1462
- // src/server/agent/serve-aux-routes.ts
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);
1463
1570
  function jsonError3(status, code, message) {
1464
1571
  return new Response(JSON.stringify({ error: { code, message } }), {
1465
1572
  status,
1466
1573
  headers: { "content-type": "application/json; charset=utf-8" }
1467
1574
  });
1468
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
+ }
1469
1680
  async function serveAgentAuxRoute(request, urlPath, deps) {
1470
1681
  const method = request.method.toUpperCase();
1471
1682
  const cardName = isAgentCardPath(urlPath);
@@ -1486,12 +1697,45 @@ async function serveAgentAuxRoute(request, urlPath, deps) {
1486
1697
  if (!deps.agents.some((a) => a.name === runStream.name)) return null;
1487
1698
  return handleAgentRunReconnect(runStream.runId, request, getRunEventCache());
1488
1699
  }
1700
+ const threadResponse = await serveThreadRoute(request, method, urlPath, deps);
1701
+ if (threadResponse !== null) return threadResponse;
1489
1702
  const mcpName = isMcpPath(urlPath);
1490
1703
  if (mcpName !== null) {
1491
1704
  return serveMcpRoute(request, method, mcpName, deps);
1492
1705
  }
1493
1706
  return null;
1494
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
+ }
1495
1739
  async function serveMcpRoute(request, method, mcpName, deps) {
1496
1740
  if (method !== "POST") return null;
1497
1741
  const agent = deps.agents.find((a) => a.name === mcpName);
@@ -1501,7 +1745,7 @@ async function serveMcpRoute(request, method, mcpName, deps) {
1501
1745
  const csrfMode = deps.csrfMode ?? "strict";
1502
1746
  if (csrfMode === "strict") {
1503
1747
  const csrf = validateCsrfRequest(request);
1504
- 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}`);
1505
1749
  }
1506
1750
  let body = null;
1507
1751
  try {
@@ -1635,7 +1879,9 @@ async function serveAux(req, res, next, urlPath, deps) {
1635
1879
  agents: scanAgents(deps.projectRoot, deps.agentsDir),
1636
1880
  loadModule: deps.loadModule,
1637
1881
  baseUrl: `http://${req.headers.host ?? "localhost"}`,
1638
- 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
1639
1885
  });
1640
1886
  if (response === null) {
1641
1887
  next();
@@ -3291,4 +3537,4 @@ export {
3291
3537
  theoPluginAsync,
3292
3538
  theoPlugin
3293
3539
  };
3294
- //# sourceMappingURL=chunk-FARW5PH6.js.map
3540
+ //# sourceMappingURL=chunk-2JNG3P4Y.js.map