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.
- package/dist/actions-virtual-module-Z2IXNF72.js +0 -0
- package/dist/add-W6FNTAFS.js +0 -0
- package/dist/{agent-7IGDT55V.js → agent-GXJNFW6N.js} +2 -2
- package/dist/agents-typed-client-RIJVHSX4.js +0 -0
- package/dist/app-typed-client-YCQC3MZ7.js +0 -0
- package/dist/aws-lambda-7GSCNLPY.js +0 -0
- package/dist/body-parser-web-FV5HWCY3.js +0 -0
- package/dist/broadcast-LUMOJIJT.js +0 -0
- package/dist/{build-G7WWVZTL.js → build-WD2PT5TA.js} +2 -2
- package/dist/build-request-body-preview-QMWD2IXK.js +0 -0
- package/dist/bun-KP2KES6S.js +0 -0
- package/dist/check-PD2FTKMM.js +0 -0
- package/dist/chunk-2CVV6CNN.js +0 -0
- package/dist/{chunk-BLL5LY7R.js → chunk-2JNG3P4Y.js} +465 -25
- package/dist/chunk-2JNG3P4Y.js.map +1 -0
- package/dist/chunk-45C3WUQ7.js +0 -0
- package/dist/chunk-5ODOE6EF.js +0 -0
- package/dist/chunk-AFVTEAES.js +0 -0
- package/dist/{chunk-5PY3QPVM.js → chunk-DMGVH3VG.js} +30 -1
- package/dist/chunk-DMGVH3VG.js.map +1 -0
- package/dist/chunk-FOZIR3TG.js +0 -0
- package/dist/chunk-FRUEDJFX.js +0 -0
- package/dist/chunk-GDN3PXFH.js +0 -0
- package/dist/chunk-GEQJAFSV.js +0 -0
- package/dist/{chunk-AYZCGJXA.js → chunk-GG6H76GC.js} +5 -3
- package/dist/chunk-GG6H76GC.js.map +1 -0
- package/dist/chunk-GSO77FSM.js +0 -0
- package/dist/chunk-HGZL5EOI.js +0 -0
- package/dist/chunk-HNBWZKIQ.js +0 -0
- package/dist/chunk-IEES3CHD.js +0 -0
- package/dist/chunk-JAIKGP3Q.js +0 -0
- package/dist/chunk-KXA37ONC.js +0 -0
- package/dist/{chunk-JITNAZXE.js → chunk-LVGDYTU2.js} +2 -2
- package/dist/chunk-M6NMS5LR.js +0 -0
- package/dist/chunk-P37RZRFV.js +0 -0
- package/dist/chunk-S7L6H3KP.js +812 -0
- package/dist/chunk-S7L6H3KP.js.map +1 -0
- package/dist/chunk-TERFLG67.js +0 -0
- package/dist/chunk-WR4F4EEZ.js +0 -0
- package/dist/chunk-YJWEADAW.js +0 -0
- package/dist/cli/index.js +5 -5
- package/dist/cloudflare-C6E5SPAE.js +0 -0
- package/dist/configure-agent-registry-ZOBVU3MV.js +0 -0
- package/dist/db-3UNAMSFK.js +0 -0
- package/dist/deno-deploy-RFZN56X4.js +0 -0
- package/dist/{dev-SHAN56K5.js → dev-63UNEUF6.js} +3 -3
- package/dist/dev-emit-EFQRBVYS.js +0 -0
- package/dist/dispatcher-EJHL6JMJ.js +0 -0
- package/dist/docker-LZZB4D5E.js +0 -0
- package/dist/generate-373DALPY.js +0 -0
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/info-2OOXFTJX.js +0 -0
- package/dist/internal-api-Y5REPVUS.js +0 -0
- package/dist/load-config-3EAQTXPH.js +0 -0
- package/dist/{mcp-P4MHP3VA.js → mcp-MIZFVNCL.js} +2 -2
- package/dist/netlify-PMLHVPN4.js +0 -0
- package/dist/node-BPJ3Z4DT.js +0 -0
- package/dist/openapi-ERYWAT3A.js +0 -0
- package/dist/registry-3NB7KOUI.js +0 -0
- package/dist/router-TLEAOFID.js +0 -0
- package/dist/routes-XNS3UM3B.js +0 -0
- package/dist/scan-7MJC6PYU.js +0 -0
- package/dist/schema-LYOLNHZ7.js +0 -0
- package/dist/server/define/index.js +2 -4
- package/dist/server/index.js +2 -4
- package/dist/server/index.js.map +1 -1
- package/dist/server-error-to-envelope-UUXDSLAZ.js +0 -0
- package/dist/server-routes-hmr-VZXOP5YT.js +0 -0
- package/dist/services-json-Y3XODNB5.js +0 -0
- package/dist/services-typed-client-32KMTTXR.js +0 -0
- package/dist/{start-RD5WQMIH.js → start-IFTLTEPZ.js} +5 -3
- package/dist/{start-RD5WQMIH.js.map → start-IFTLTEPZ.js.map} +1 -1
- package/dist/static-MB2CD5Y3.js +0 -0
- package/dist/storage-manager-ZSQFLEYT.js +0 -0
- package/dist/theo-cloud-DQRP6S6M.js +0 -0
- package/dist/upgrade-readiness-ACGW44JC.js +0 -0
- package/dist/vercel-J6G7ZHYQ.js +0 -0
- package/dist/vite-plugin/index.js +1 -2
- package/dist/{vite-plugin-A7WGYEMD.js → vite-plugin-ST4JZQRJ.js} +3 -3
- package/package.json +10 -10
- package/LICENSE +0 -201
- package/dist/chunk-5PY3QPVM.js.map +0 -1
- package/dist/chunk-AYZCGJXA.js.map +0 -1
- package/dist/chunk-BLL5LY7R.js.map +0 -1
- package/dist/chunk-JZHT3LW7.js +0 -32
- package/dist/chunk-JZHT3LW7.js.map +0 -1
- package/dist/chunk-LGVVX3BV.js +0 -401
- package/dist/chunk-LGVVX3BV.js.map +0 -1
- /package/dist/{agent-7IGDT55V.js.map → agent-GXJNFW6N.js.map} +0 -0
- /package/dist/{build-G7WWVZTL.js.map → build-WD2PT5TA.js.map} +0 -0
- /package/dist/{chunk-JITNAZXE.js.map → chunk-LVGDYTU2.js.map} +0 -0
- /package/dist/{dev-SHAN56K5.js.map → dev-63UNEUF6.js.map} +0 -0
- /package/dist/{mcp-P4MHP3VA.js.map → mcp-MIZFVNCL.js.map} +0 -0
- /package/dist/{vite-plugin-A7WGYEMD.js.map → vite-plugin-ST4JZQRJ.js.map} +0 -0
|
File without changes
|
package/dist/add-W6FNTAFS.js
CHANGED
|
File without changes
|
|
@@ -3,7 +3,7 @@ import "tsx/esm";
|
|
|
3
3
|
import {
|
|
4
4
|
agentCommand,
|
|
5
5
|
createAgentSsrLoader
|
|
6
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
619
|
+
//# sourceMappingURL=build-WD2PT5TA.js.map
|
|
File without changes
|
package/dist/bun-KP2KES6S.js
CHANGED
|
File without changes
|
package/dist/check-PD2FTKMM.js
CHANGED
|
File without changes
|
package/dist/chunk-2CVV6CNN.js
CHANGED
|
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 =
|
|
1351
|
+
const compiled = compileAgentModule3(mod, source);
|
|
1202
1352
|
if (compiled.skillsResolver) {
|
|
1203
|
-
const enabled = await
|
|
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
|
|
1216
|
-
const
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
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/
|
|
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
|
|
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-
|
|
3540
|
+
//# sourceMappingURL=chunk-2JNG3P4Y.js.map
|