@personaai/runtime 0.5.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/index.cjs ADDED
@@ -0,0 +1,1439 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ RUNTIME_VERSION: () => RUNTIME_VERSION,
24
+ RuntimeHttpError: () => RuntimeHttpError,
25
+ createRuntime: () => createRuntime
26
+ });
27
+ module.exports = __toCommonJS(index_exports);
28
+
29
+ // src/routing.ts
30
+ function splitPath(path) {
31
+ return path.split("/").filter((segment) => segment.length > 0);
32
+ }
33
+ function matchRoute(routes, method, path) {
34
+ const requested = splitPath(path);
35
+ let sawPathMatch = false;
36
+ const allowed = /* @__PURE__ */ new Set();
37
+ for (const route of routes) {
38
+ if (route.pattern.length !== requested.length) continue;
39
+ const params = {};
40
+ let matched = true;
41
+ for (let i = 0; i < route.pattern.length; i++) {
42
+ const patternSegment = route.pattern[i];
43
+ const requestedSegment = requested[i];
44
+ if (patternSegment.startsWith(":")) {
45
+ params[patternSegment.slice(1)] = decodeURIComponent(requestedSegment);
46
+ } else if (patternSegment !== requestedSegment) {
47
+ matched = false;
48
+ break;
49
+ }
50
+ }
51
+ if (!matched) continue;
52
+ sawPathMatch = true;
53
+ allowed.add(route.method);
54
+ if (route.method === method) {
55
+ return { kind: "matched", route, params };
56
+ }
57
+ }
58
+ if (sawPathMatch) return { kind: "method-not-allowed", allowed: [...allowed] };
59
+ return { kind: "not-found" };
60
+ }
61
+ function stripMountPath(path, mountPath) {
62
+ if (!mountPath) return path;
63
+ const normalizedMount = mountPath.endsWith("/") ? mountPath.slice(0, -1) : mountPath;
64
+ if (!normalizedMount) return path;
65
+ if (path === normalizedMount) return "/";
66
+ if (path.startsWith(`${normalizedMount}/`)) return path.slice(normalizedMount.length);
67
+ return path;
68
+ }
69
+
70
+ // src/client-factory.ts
71
+ var import_sdk = require("@personaai/sdk");
72
+ function createClientForRequest(options, userId) {
73
+ return new import_sdk.PersonaClient({
74
+ baseUrl: options.baseUrl,
75
+ credential: options.credential,
76
+ externalUserId: userId ?? void 0,
77
+ fetch: options.fetch
78
+ });
79
+ }
80
+
81
+ // src/errors.ts
82
+ var import_sdk2 = require("@personaai/sdk");
83
+ var RuntimeHttpError = class _RuntimeHttpError extends Error {
84
+ status;
85
+ code;
86
+ constructor(status, code, message) {
87
+ super(message);
88
+ this.name = "RuntimeHttpError";
89
+ this.status = status;
90
+ this.code = code;
91
+ Object.setPrototypeOf(this, _RuntimeHttpError.prototype);
92
+ }
93
+ };
94
+ function mapErrorToRuntimeError(err, mode) {
95
+ const dev = mode === "development";
96
+ if (err instanceof RuntimeHttpError) {
97
+ return { status: err.status, code: err.code, message: err.message };
98
+ }
99
+ if (err instanceof import_sdk2.PersonaApiError) {
100
+ return {
101
+ status: err.statusCode,
102
+ code: err.code,
103
+ message: err.message,
104
+ ...dev ? { detail: err.response } : {}
105
+ };
106
+ }
107
+ const message = err instanceof Error ? err.message : String(err);
108
+ return {
109
+ status: 500,
110
+ code: "INTERNAL_ERROR",
111
+ message: dev ? message : "An internal error occurred.",
112
+ ...dev ? {
113
+ detail: {
114
+ name: err instanceof Error ? err.name : typeof err,
115
+ stack: err instanceof Error ? err.stack : void 0
116
+ }
117
+ } : {}
118
+ };
119
+ }
120
+ function errorToResponse(err, mode) {
121
+ const mapped = mapErrorToRuntimeError(err, mode);
122
+ return {
123
+ kind: "buffered",
124
+ status: mapped.status,
125
+ headers: { "content-type": "application/json" },
126
+ body: JSON.stringify({
127
+ error: {
128
+ code: mapped.code,
129
+ message: mapped.message,
130
+ ...mapped.detail !== void 0 ? { detail: mapped.detail } : {}
131
+ }
132
+ })
133
+ };
134
+ }
135
+
136
+ // src/runRegistry.ts
137
+ var DEFAULT_RUN_GRACE_MS = 5 * 60 * 1e3;
138
+ var DEFAULT_MAX_TRACKED_RUNS = 1e3;
139
+ function evictStaleRuns(runs, now, graceMs = DEFAULT_RUN_GRACE_MS, maxTracked = DEFAULT_MAX_TRACKED_RUNS) {
140
+ for (const [id, driver] of runs) {
141
+ if (driver.isFinished() && driver.finishedAt !== void 0 && now - driver.finishedAt > graceMs) {
142
+ runs.delete(id);
143
+ }
144
+ }
145
+ const overBy = runs.size - maxTracked;
146
+ if (overBy <= 0) return;
147
+ const finished = [...runs.entries()].filter(([, driver]) => driver.isFinished()).sort((a, b) => (a[1].finishedAt ?? 0) - (b[1].finishedAt ?? 0));
148
+ let remaining = overBy;
149
+ for (const [id] of finished) {
150
+ if (remaining <= 0) break;
151
+ runs.delete(id);
152
+ remaining -= 1;
153
+ }
154
+ }
155
+
156
+ // src/version.ts
157
+ var RUNTIME_VERSION = "0.5.0";
158
+
159
+ // src/routes/health.ts
160
+ var alwaysOnCapabilities = {
161
+ chat: true,
162
+ threads: true,
163
+ agents: true,
164
+ files: true,
165
+ memory: true,
166
+ mcpOAuth: true
167
+ };
168
+ var healthRoute = async (_request, ctx) => {
169
+ try {
170
+ await ctx.client.whoami();
171
+ } catch (err) {
172
+ const failed = errorToResponse(err, ctx.mode);
173
+ return { ...failed, status: 503 };
174
+ }
175
+ return {
176
+ kind: "buffered",
177
+ status: 200,
178
+ headers: { "content-type": "application/json" },
179
+ body: JSON.stringify({
180
+ status: "ok",
181
+ version: RUNTIME_VERSION,
182
+ capabilities: { ...alwaysOnCapabilities, ...ctx.capabilities }
183
+ })
184
+ };
185
+ };
186
+
187
+ // src/runDriver.ts
188
+ var import_sdk3 = require("@personaai/sdk");
189
+ function formatSseFrame(event) {
190
+ return `data: ${JSON.stringify(event)}
191
+
192
+ `;
193
+ }
194
+ function runErrorFrame(err, mode) {
195
+ const mapped = mapErrorToRuntimeError(err, mode);
196
+ return formatSseFrame({
197
+ type: import_sdk3.EventType.RUN_ERROR,
198
+ code: mapped.code,
199
+ message: mapped.message
200
+ });
201
+ }
202
+ function newAccumulator() {
203
+ return {
204
+ text: "",
205
+ interrupted: false,
206
+ erroredInBand: false,
207
+ threadCreateFired: false,
208
+ toolNames: /* @__PURE__ */ new Map()
209
+ };
210
+ }
211
+ async function processEvent(event, acc, runCtx, hooks) {
212
+ const e = event;
213
+ switch (e.type) {
214
+ case import_sdk3.EventType.RUN_STARTED: {
215
+ const threadId = typeof e.threadId === "string" ? e.threadId : void 0;
216
+ if (runCtx.kind === "chat" && runCtx.agentId && !acc.threadCreateFired && !runCtx.threadId && threadId) {
217
+ acc.threadCreateFired = true;
218
+ await hooks?.onThreadCreate?.({ userId: runCtx.userId, agentId: runCtx.agentId, threadId });
219
+ }
220
+ break;
221
+ }
222
+ case import_sdk3.EventType.TEXT_MESSAGE_CHUNK: {
223
+ const delta = e.delta;
224
+ if (typeof delta === "string") acc.text += delta;
225
+ break;
226
+ }
227
+ case import_sdk3.EventType.CUSTOM: {
228
+ if (e.name === "hitl_request" || e.name === "clarification_request") acc.interrupted = true;
229
+ break;
230
+ }
231
+ case import_sdk3.EventType.RUN_ERROR: {
232
+ acc.erroredInBand = true;
233
+ break;
234
+ }
235
+ case import_sdk3.EventType.TOOL_CALL_START: {
236
+ const toolCallId = typeof e.toolCallId === "string" ? e.toolCallId : void 0;
237
+ const toolCallName = typeof e.toolCallName === "string" ? e.toolCallName : "unknown_tool";
238
+ if (toolCallId) {
239
+ acc.toolNames.set(toolCallId, toolCallName);
240
+ await hooks?.beforeToolCall?.({
241
+ userId: runCtx.userId,
242
+ agentId: runCtx.agentId,
243
+ threadId: runCtx.threadId,
244
+ toolName: toolCallName,
245
+ toolCallId
246
+ });
247
+ }
248
+ break;
249
+ }
250
+ case import_sdk3.EventType.TOOL_CALL_RESULT: {
251
+ const toolCallId = typeof e.toolCallId === "string" ? e.toolCallId : void 0;
252
+ if (toolCallId) {
253
+ await hooks?.afterToolCall?.(
254
+ {
255
+ userId: runCtx.userId,
256
+ agentId: runCtx.agentId,
257
+ threadId: runCtx.threadId,
258
+ toolName: acc.toolNames.get(toolCallId) ?? "unknown_tool",
259
+ toolCallId
260
+ },
261
+ e.content
262
+ );
263
+ }
264
+ break;
265
+ }
266
+ default:
267
+ break;
268
+ }
269
+ }
270
+ var RunDriver = class {
271
+ runId;
272
+ runCtx;
273
+ createdAt = Date.now();
274
+ finishedAt;
275
+ frames = [];
276
+ listeners = /* @__PURE__ */ new Set();
277
+ doneListeners = /* @__PURE__ */ new Set();
278
+ finished = false;
279
+ firstFrameSettled = false;
280
+ firstFramePromise;
281
+ resolveFirstFrame;
282
+ rejectFirstFrame;
283
+ constructor(runId, runCtx, source, hooks, mode) {
284
+ this.runId = runId;
285
+ this.runCtx = runCtx;
286
+ this.firstFramePromise = new Promise((resolve, reject) => {
287
+ this.resolveFirstFrame = resolve;
288
+ this.rejectFirstFrame = reject;
289
+ });
290
+ void this.pump(source, hooks, mode);
291
+ }
292
+ push(frame) {
293
+ const seq = this.frames.length;
294
+ this.frames.push(frame);
295
+ for (const listener of this.listeners) listener(seq, frame);
296
+ if (!this.firstFrameSettled) {
297
+ this.firstFrameSettled = true;
298
+ this.resolveFirstFrame();
299
+ }
300
+ }
301
+ finish() {
302
+ this.finished = true;
303
+ this.finishedAt = Date.now();
304
+ for (const listener of this.doneListeners) listener();
305
+ }
306
+ async pump(source, hooks, mode) {
307
+ const acc = newAccumulator();
308
+ let count = 0;
309
+ try {
310
+ for await (const event of source) {
311
+ await processEvent(event, acc, this.runCtx, hooks);
312
+ count += 1;
313
+ this.push(formatSseFrame(event));
314
+ }
315
+ if (!this.firstFrameSettled) {
316
+ this.firstFrameSettled = true;
317
+ this.resolveFirstFrame();
318
+ }
319
+ const result = {
320
+ text: acc.text,
321
+ eventCount: count,
322
+ interrupted: acc.interrupted,
323
+ erroredInBand: acc.erroredInBand
324
+ };
325
+ await hooks?.afterRun?.(this.runCtx, result);
326
+ } catch (err) {
327
+ await hooks?.onError?.(
328
+ {
329
+ userId: this.runCtx.userId,
330
+ phase: this.runCtx.kind,
331
+ agentId: this.runCtx.agentId,
332
+ threadId: this.runCtx.threadId
333
+ },
334
+ err
335
+ );
336
+ if (!this.firstFrameSettled) {
337
+ this.firstFrameSettled = true;
338
+ this.rejectFirstFrame(err);
339
+ return;
340
+ }
341
+ this.push(runErrorFrame(err, mode));
342
+ } finally {
343
+ this.finish();
344
+ }
345
+ }
346
+ /** Resolves once the first frame has been buffered, or rejects if the run failed before producing any frame at all. */
347
+ waitForFirstFrame() {
348
+ return this.firstFramePromise;
349
+ }
350
+ isFinished() {
351
+ return this.finished;
352
+ }
353
+ /** Total frames buffered so far — also the highest valid `since` a caller can request without missing anything. */
354
+ get frameCount() {
355
+ return this.frames.length;
356
+ }
357
+ /** Number of currently-live subscriptions (each `subscribe()` iterator that's been started but not yet exhausted/torn down). Exposed for tests verifying subscriptions clean up after themselves. */
358
+ get subscriberCount() {
359
+ return this.listeners.size;
360
+ }
361
+ /**
362
+ * An async iterable that replays every buffered frame after `sinceSeq`
363
+ * (`-1` for "from the start"), then continues yielding new frames live
364
+ * as the run produces them, until the run finishes. Each call returns an
365
+ * independent subscription — multiple concurrent subscribers (e.g. the
366
+ * original connection plus a reconnect that raced it) are supported.
367
+ */
368
+ subscribe(sinceSeq) {
369
+ const buffered = this.frames.slice(Math.max(sinceSeq + 1, 0));
370
+ const finishedAtSubscribeTime = this.finished;
371
+ const listeners = this.listeners;
372
+ const doneListeners = this.doneListeners;
373
+ return {
374
+ [Symbol.asyncIterator]() {
375
+ const queue = [...buffered];
376
+ let live = !finishedAtSubscribeTime;
377
+ let wake = null;
378
+ const onFrame = (_seq, frame) => {
379
+ queue.push(frame);
380
+ wake?.();
381
+ };
382
+ const onDone = () => {
383
+ live = false;
384
+ wake?.();
385
+ };
386
+ if (live) {
387
+ listeners.add(onFrame);
388
+ doneListeners.add(onDone);
389
+ }
390
+ const cleanup = () => {
391
+ listeners.delete(onFrame);
392
+ doneListeners.delete(onDone);
393
+ };
394
+ return {
395
+ async next() {
396
+ for (; ; ) {
397
+ if (queue.length > 0) return { done: false, value: queue.shift() };
398
+ if (!live) {
399
+ cleanup();
400
+ return { done: true, value: void 0 };
401
+ }
402
+ await new Promise((resolve) => wake = resolve);
403
+ }
404
+ },
405
+ async return() {
406
+ cleanup();
407
+ return { done: true, value: void 0 };
408
+ }
409
+ };
410
+ }
411
+ };
412
+ }
413
+ };
414
+
415
+ // src/heartbeat.ts
416
+ var HEARTBEAT_FRAME = ": heartbeat\n\n";
417
+ var TIMEOUT = /* @__PURE__ */ Symbol("heartbeat-timeout");
418
+ function heartbeatTimer(ms) {
419
+ let handle;
420
+ const promise = new Promise((resolve) => {
421
+ handle = setTimeout(() => resolve(TIMEOUT), ms);
422
+ });
423
+ return { promise, cancel: () => clearTimeout(handle) };
424
+ }
425
+ async function* withHeartbeats(source, intervalMs = 15e3) {
426
+ const iterator = source[Symbol.asyncIterator]();
427
+ try {
428
+ let pending = null;
429
+ for (; ; ) {
430
+ pending ??= iterator.next();
431
+ const timer = heartbeatTimer(intervalMs);
432
+ const winner = await Promise.race([pending, timer.promise]);
433
+ timer.cancel();
434
+ if (winner === TIMEOUT) {
435
+ yield HEARTBEAT_FRAME;
436
+ continue;
437
+ }
438
+ pending = null;
439
+ if (winner.done) return;
440
+ yield winner.value;
441
+ }
442
+ } finally {
443
+ await iterator.return?.();
444
+ }
445
+ }
446
+
447
+ // src/routes/chat.ts
448
+ function parseChatBody(body) {
449
+ if (typeof body !== "object" || body === null) {
450
+ throw new RuntimeHttpError(400, "INVALID_REQUEST", "Request body must be a JSON object.");
451
+ }
452
+ const b = body;
453
+ if (typeof b.agentId !== "string" || b.agentId.length === 0) {
454
+ throw new RuntimeHttpError(
455
+ 400,
456
+ "INVALID_REQUEST",
457
+ '"agentId" is required and must be a string.'
458
+ );
459
+ }
460
+ if (!Array.isArray(b.messages)) {
461
+ throw new RuntimeHttpError(
462
+ 400,
463
+ "INVALID_REQUEST",
464
+ '"messages" is required and must be an array.'
465
+ );
466
+ }
467
+ return {
468
+ agentId: b.agentId,
469
+ messages: b.messages,
470
+ threadId: typeof b.threadId === "string" ? b.threadId : void 0,
471
+ resume: b.resume ?? void 0,
472
+ contextOverride: typeof b.contextOverride === "string" ? b.contextOverride : void 0
473
+ };
474
+ }
475
+ var chatRoute = async (request, ctx) => {
476
+ const body = parseChatBody(request.body);
477
+ const userId = request.userId;
478
+ const runCtx = {
479
+ userId,
480
+ kind: "chat",
481
+ agentId: body.agentId,
482
+ threadId: body.threadId,
483
+ messages: body.messages
484
+ };
485
+ await ctx.hooks?.beforeRun?.(runCtx);
486
+ const stream = ctx.client.chat.stream(body.agentId, {
487
+ messages: body.messages,
488
+ threadId: body.threadId,
489
+ resume: body.resume,
490
+ contextOverride: body.contextOverride
491
+ });
492
+ const runId = crypto.randomUUID();
493
+ const driver = new RunDriver(runId, runCtx, stream, ctx.hooks, ctx.mode);
494
+ ctx.runs.set(runId, driver);
495
+ await driver.waitForFirstFrame();
496
+ return {
497
+ kind: "stream",
498
+ status: 200,
499
+ headers: {
500
+ "content-type": "text/event-stream",
501
+ "cache-control": "no-cache",
502
+ connection: "keep-alive",
503
+ "x-persona-run-id": runId
504
+ },
505
+ body: withHeartbeats(driver.subscribe(-1), ctx.heartbeatIntervalMs)
506
+ };
507
+ };
508
+
509
+ // src/routes/architect.ts
510
+ function parseArchitectBody(body) {
511
+ if (typeof body !== "object" || body === null) {
512
+ throw new RuntimeHttpError(400, "INVALID_REQUEST", "Request body must be a JSON object.");
513
+ }
514
+ const b = body;
515
+ if (!Array.isArray(b.messages)) {
516
+ throw new RuntimeHttpError(
517
+ 400,
518
+ "INVALID_REQUEST",
519
+ '"messages" is required and must be an array.'
520
+ );
521
+ }
522
+ return {
523
+ messages: b.messages,
524
+ resume: b.resume ?? void 0
525
+ };
526
+ }
527
+ var architectRoute = async (request, ctx) => {
528
+ const body = parseArchitectBody(request.body);
529
+ const userId = request.userId;
530
+ const runCtx = {
531
+ userId,
532
+ kind: "architect",
533
+ messages: body.messages
534
+ };
535
+ await ctx.hooks?.beforeRun?.(runCtx);
536
+ const stream = ctx.client.architect.stream({
537
+ messages: body.messages,
538
+ resume: body.resume
539
+ });
540
+ const runId = crypto.randomUUID();
541
+ const driver = new RunDriver(runId, runCtx, stream, ctx.hooks, ctx.mode);
542
+ ctx.runs.set(runId, driver);
543
+ await driver.waitForFirstFrame();
544
+ return {
545
+ kind: "stream",
546
+ status: 200,
547
+ headers: {
548
+ "content-type": "text/event-stream",
549
+ "cache-control": "no-cache",
550
+ connection: "keep-alive",
551
+ "x-persona-run-id": runId
552
+ },
553
+ body: withHeartbeats(driver.subscribe(-1), ctx.heartbeatIntervalMs)
554
+ };
555
+ };
556
+
557
+ // src/routes/resume.ts
558
+ function createResumeRoute(expectedKind) {
559
+ return async (request, ctx) => {
560
+ const runId = ctx.params.runId;
561
+ if (!runId) {
562
+ throw new RuntimeHttpError(400, "INVALID_REQUEST", '"runId" path parameter is required.');
563
+ }
564
+ const driver = ctx.runs.get(runId);
565
+ if (!driver || driver.runCtx.userId !== request.userId || driver.runCtx.kind !== expectedKind) {
566
+ throw new RuntimeHttpError(
567
+ 404,
568
+ "RUN_NOT_FOUND",
569
+ `No resumable run found for id "${runId}". It may have finished and been evicted, or never existed.`
570
+ );
571
+ }
572
+ const sinceRaw = request.query.since;
573
+ const parsed = sinceRaw !== void 0 ? Number.parseInt(sinceRaw, 10) : -1;
574
+ const sinceSeq = Number.isNaN(parsed) ? -1 : parsed;
575
+ return {
576
+ kind: "stream",
577
+ status: 200,
578
+ headers: {
579
+ "content-type": "text/event-stream",
580
+ "cache-control": "no-cache",
581
+ connection: "keep-alive",
582
+ "x-persona-run-id": runId
583
+ },
584
+ body: withHeartbeats(driver.subscribe(sinceSeq), ctx.heartbeatIntervalMs)
585
+ };
586
+ };
587
+ }
588
+
589
+ // src/routeHelpers.ts
590
+ function json(status, value) {
591
+ return {
592
+ kind: "buffered",
593
+ status,
594
+ headers: { "content-type": "application/json" },
595
+ body: JSON.stringify(value)
596
+ };
597
+ }
598
+ function noContent() {
599
+ return { kind: "buffered", status: 204, headers: {}, body: "" };
600
+ }
601
+ function requireParam(params, name) {
602
+ const value = params[name];
603
+ if (!value) {
604
+ throw new RuntimeHttpError(400, "INVALID_REQUEST", `"${name}" path parameter is required.`);
605
+ }
606
+ return value;
607
+ }
608
+ function requireQueryParam(query, name) {
609
+ const value = query[name];
610
+ if (!value) {
611
+ throw new RuntimeHttpError(400, "INVALID_REQUEST", `"${name}" query parameter is required.`);
612
+ }
613
+ return value;
614
+ }
615
+ function toInt(value) {
616
+ if (value === void 0) return void 0;
617
+ const parsed = Number.parseInt(value, 10);
618
+ return Number.isNaN(parsed) ? void 0 : parsed;
619
+ }
620
+ function requireBodyObject(body) {
621
+ if (typeof body !== "object" || body === null) {
622
+ throw new RuntimeHttpError(400, "INVALID_REQUEST", "Request body must be a JSON object.");
623
+ }
624
+ return body;
625
+ }
626
+ function requireStringField(body, field) {
627
+ const value = body[field];
628
+ if (typeof value !== "string" || value.length === 0) {
629
+ throw new RuntimeHttpError(
630
+ 400,
631
+ "INVALID_REQUEST",
632
+ `"${field}" is required and must be a string.`
633
+ );
634
+ }
635
+ return value;
636
+ }
637
+
638
+ // src/routes/threads.ts
639
+ var listThreads = async (request, ctx) => {
640
+ const items = await ctx.client.threads.list({
641
+ page: toInt(request.query.page),
642
+ limit: toInt(request.query.limit)
643
+ });
644
+ return json(200, items);
645
+ };
646
+ var createThread = async (request, ctx) => {
647
+ const body = requireBodyObject(request.body);
648
+ const agentId = requireStringField(body, "agentId");
649
+ const thread = await ctx.client.threads.create({ agentId });
650
+ await ctx.hooks?.onThreadCreate?.({
651
+ userId: request.userId,
652
+ agentId,
653
+ threadId: thread._id
654
+ });
655
+ return json(201, thread);
656
+ };
657
+ var getThread = async (_request, ctx) => {
658
+ const thread = await ctx.client.threads.get(requireParam(ctx.params, "id"));
659
+ return json(200, thread);
660
+ };
661
+ var updateThread = async (request, ctx) => {
662
+ const body = request.body ?? {};
663
+ const thread = await ctx.client.threads.update(requireParam(ctx.params, "id"), body);
664
+ return json(200, thread);
665
+ };
666
+ var deleteThread = async (_request, ctx) => {
667
+ await ctx.client.threads.delete(requireParam(ctx.params, "id"));
668
+ return noContent();
669
+ };
670
+ var bulkDeleteThreads = async (request, ctx) => {
671
+ const body = requireBodyObject(request.body);
672
+ const ids = Array.isArray(body.ids) ? body.ids : [];
673
+ const result = await ctx.client.threads.bulkDelete(ids);
674
+ return json(200, result);
675
+ };
676
+ var getThreadMessages = async (_request, ctx) => {
677
+ const messages = await ctx.client.threads.getMessages(requireParam(ctx.params, "id"));
678
+ return json(200, messages);
679
+ };
680
+
681
+ // src/routes/agents.ts
682
+ var listAgents = async (request, ctx) => {
683
+ const items = await ctx.client.agents.list({
684
+ page: toInt(request.query.page),
685
+ limit: toInt(request.query.limit),
686
+ search: request.query.search,
687
+ category: request.query.category,
688
+ scope: request.query.scope === "mine" ? "mine" : void 0
689
+ });
690
+ return json(200, items);
691
+ };
692
+ var createAgent = async (request, ctx) => {
693
+ const body = requireBodyObject(request.body);
694
+ const input = {
695
+ name: requireStringField(body, "name"),
696
+ systemPrompt: requireStringField(body, "systemPrompt"),
697
+ providerId: requireStringField(body, "providerId"),
698
+ description: typeof body.description === "string" ? body.description : void 0,
699
+ avatar: typeof body.avatar === "string" ? body.avatar : void 0,
700
+ tags: Array.isArray(body.tags) ? body.tags : void 0,
701
+ tagline: typeof body.tagline === "string" ? body.tagline : void 0,
702
+ bio: typeof body.bio === "string" ? body.bio : void 0,
703
+ socialLinks: body.socialLinks ?? void 0,
704
+ modelName: typeof body.modelName === "string" ? body.modelName : void 0,
705
+ webSearchEnabled: typeof body.webSearchEnabled === "boolean" ? body.webSearchEnabled : void 0,
706
+ visibility: body.visibility,
707
+ category: body.category,
708
+ skills: Array.isArray(body.skills) ? body.skills : void 0,
709
+ mcps: Array.isArray(body.mcps) ? body.mcps : void 0,
710
+ knowledgeBases: Array.isArray(body.knowledgeBases) ? body.knowledgeBases : void 0,
711
+ storeMounts: Array.isArray(body.storeMounts) ? body.storeMounts : void 0,
712
+ interruptOn: body.interruptOn ?? void 0,
713
+ isActive: typeof body.isActive === "boolean" ? body.isActive : void 0
714
+ };
715
+ const agent = await ctx.client.agents.create(input);
716
+ return json(201, agent);
717
+ };
718
+ var getAgent = async (_request, ctx) => {
719
+ const agent = await ctx.client.agents.get(requireParam(ctx.params, "id"));
720
+ return json(200, agent);
721
+ };
722
+ var updateAgent = async (request, ctx) => {
723
+ const body = request.body ?? {};
724
+ const agent = await ctx.client.agents.update(requireParam(ctx.params, "id"), body);
725
+ return json(200, agent);
726
+ };
727
+ var deleteAgent = async (_request, ctx) => {
728
+ await ctx.client.agents.delete(requireParam(ctx.params, "id"));
729
+ return noContent();
730
+ };
731
+ var bulkDeleteAgents = async (request, ctx) => {
732
+ const body = requireBodyObject(request.body);
733
+ const ids = Array.isArray(body.ids) ? body.ids : [];
734
+ const result = await ctx.client.agents.bulkDelete(ids);
735
+ return json(200, result);
736
+ };
737
+
738
+ // src/routes/files.ts
739
+ var listFiles = async (request, ctx) => {
740
+ const items = await ctx.client.files.list({
741
+ page: toInt(request.query.page),
742
+ limit: toInt(request.query.limit)
743
+ });
744
+ return json(200, items);
745
+ };
746
+ var uploadFile = async (request, ctx) => {
747
+ if (!request.file) {
748
+ throw new RuntimeHttpError(
749
+ 400,
750
+ "INVALID_REQUEST",
751
+ 'A "file" part is required on this request.'
752
+ );
753
+ }
754
+ const fields = request.body ?? {};
755
+ const agentId = typeof fields.agentId === "string" ? fields.agentId : void 0;
756
+ const threadId = typeof fields.threadId === "string" ? fields.threadId : void 0;
757
+ const file = await ctx.client.files.upload({
758
+ filename: request.file.filename,
759
+ content: request.file.content,
760
+ contentType: request.file.contentType,
761
+ agentId,
762
+ threadId
763
+ });
764
+ await ctx.hooks?.onFileUpload?.({
765
+ userId: request.userId,
766
+ fileName: request.file.filename,
767
+ mimeType: request.file.contentType
768
+ });
769
+ return json(201, file);
770
+ };
771
+ var downloadFile = async (_request, ctx) => {
772
+ const response = await ctx.client.files.download(requireParam(ctx.params, "id"));
773
+ const headers = {};
774
+ const contentType = response.headers.get("content-type");
775
+ const contentDisposition = response.headers.get("content-disposition");
776
+ if (contentType) headers["content-type"] = contentType;
777
+ if (contentDisposition) headers["content-disposition"] = contentDisposition;
778
+ if (!response.body) {
779
+ return { kind: "binary", status: response.status, headers, body: (async function* () {
780
+ })() };
781
+ }
782
+ return {
783
+ kind: "binary",
784
+ status: response.status,
785
+ headers,
786
+ body: response.body
787
+ };
788
+ };
789
+ var deleteFile = async (_request, ctx) => {
790
+ await ctx.client.files.delete(requireParam(ctx.params, "id"));
791
+ return noContent();
792
+ };
793
+ var bulkDeleteFiles = async (request, ctx) => {
794
+ const body = requireBodyObject(request.body);
795
+ const ids = Array.isArray(body.ids) ? body.ids : [];
796
+ const result = await ctx.client.files.bulkDelete(ids);
797
+ return json(200, result);
798
+ };
799
+
800
+ // src/routes/memory.ts
801
+ function requireScope(query) {
802
+ const scope = query.scope === "agent" ? "agent" : query.scope === "user" ? "user" : void 0;
803
+ if (scope === "agent" && !query.agentId) {
804
+ throw new RuntimeHttpError(
805
+ 400,
806
+ "INVALID_REQUEST",
807
+ '"agentId" is required when scope is "agent".'
808
+ );
809
+ }
810
+ return { scope, agentId: query.agentId };
811
+ }
812
+ var listMemory = async (_request, ctx) => {
813
+ const result = await ctx.client.memory.list();
814
+ return json(200, result);
815
+ };
816
+ var getMemoryFile = async (request, ctx) => {
817
+ const path = requireQueryParam(request.query, "path");
818
+ const { scope, agentId } = requireScope(request.query);
819
+ const file = await ctx.client.memory.getFile({ path, scope, agentId });
820
+ return json(200, file);
821
+ };
822
+ var writeMemoryFile = async (request, ctx) => {
823
+ const body = requireBodyObject(request.body);
824
+ const path = requireStringField(body, "path");
825
+ const content = requireStringField(body, "content");
826
+ const scope = body.scope === "agent" ? "agent" : body.scope === "user" ? "user" : void 0;
827
+ const agentId = typeof body.agentId === "string" ? body.agentId : void 0;
828
+ if (scope === "agent" && !agentId) {
829
+ throw new RuntimeHttpError(
830
+ 400,
831
+ "INVALID_REQUEST",
832
+ '"agentId" is required when scope is "agent".'
833
+ );
834
+ }
835
+ const file = await ctx.client.memory.writeFile({ path, content, scope, agentId });
836
+ await ctx.hooks?.onMemoryWrite?.({ userId: request.userId, agentId, path });
837
+ return json(200, file);
838
+ };
839
+ var deleteMemoryFile = async (request, ctx) => {
840
+ const path = requireQueryParam(request.query, "path");
841
+ const { scope, agentId } = requireScope(request.query);
842
+ await ctx.client.memory.deleteFile({ path, scope, agentId });
843
+ return noContent();
844
+ };
845
+
846
+ // src/routes/mcpOAuth.ts
847
+ var getOwnerAuthorizeUrl = async (_request, ctx) => {
848
+ const result = await ctx.client.mcps.oauth.getOwnerAuthorizeUrl(requireParam(ctx.params, "id"));
849
+ return json(200, result);
850
+ };
851
+ var getUserAuthorizeUrl = async (request, ctx) => {
852
+ const result = await ctx.client.mcps.oauth.getUserAuthorizeUrl(
853
+ requireParam(ctx.params, "id"),
854
+ request.query.returnTo
855
+ );
856
+ return json(200, result);
857
+ };
858
+ var getUserConnectionStatus = async (_request, ctx) => {
859
+ const result = await ctx.client.mcps.oauth.getUserConnectionStatus(
860
+ requireParam(ctx.params, "id")
861
+ );
862
+ return json(200, result);
863
+ };
864
+ var disconnectUserConnection = async (_request, ctx) => {
865
+ await ctx.client.mcps.oauth.disconnectUserConnection(requireParam(ctx.params, "id"));
866
+ return noContent();
867
+ };
868
+ var disconnectOwnerConnection = async (_request, ctx) => {
869
+ await ctx.client.mcps.oauth.disconnectOwnerConnection(requireParam(ctx.params, "id"));
870
+ return noContent();
871
+ };
872
+
873
+ // src/routes/mcps.ts
874
+ var listMcps = async (request, ctx) => {
875
+ const items = await ctx.client.mcps.list({
876
+ page: toInt(request.query.page),
877
+ limit: toInt(request.query.limit),
878
+ search: request.query.search,
879
+ scope: request.query.scope === "mine" ? "mine" : void 0
880
+ });
881
+ return json(200, items);
882
+ };
883
+ var createMcp = async (request, ctx) => {
884
+ const body = requireBodyObject(request.body);
885
+ const input = {
886
+ name: requireStringField(body, "name"),
887
+ transport: requireStringField(body, "transport"),
888
+ url: requireStringField(body, "url"),
889
+ description: typeof body.description === "string" ? body.description : void 0,
890
+ authType: body.authType,
891
+ authMode: body.authMode,
892
+ oauth: body.oauth,
893
+ apiKey: typeof body.apiKey === "string" ? body.apiKey : void 0
894
+ };
895
+ const mcp = await ctx.client.mcps.create(input);
896
+ return json(201, mcp);
897
+ };
898
+ var getMcp = async (_request, ctx) => {
899
+ const mcp = await ctx.client.mcps.get(requireParam(ctx.params, "id"));
900
+ return json(200, mcp);
901
+ };
902
+ var updateMcp = async (request, ctx) => {
903
+ const body = request.body ?? {};
904
+ const mcp = await ctx.client.mcps.update(requireParam(ctx.params, "id"), body);
905
+ return json(200, mcp);
906
+ };
907
+ var deleteMcp = async (_request, ctx) => {
908
+ await ctx.client.mcps.delete(requireParam(ctx.params, "id"));
909
+ return noContent();
910
+ };
911
+ var bulkDeleteMcps = async (request, ctx) => {
912
+ const body = requireBodyObject(request.body);
913
+ const ids = Array.isArray(body.ids) ? body.ids : [];
914
+ const result = await ctx.client.mcps.bulkDelete(ids);
915
+ return json(200, result);
916
+ };
917
+ var getMcpUsage = async (_request, ctx) => {
918
+ const usage = await ctx.client.mcps.getUsage(requireParam(ctx.params, "id"));
919
+ return json(200, usage);
920
+ };
921
+ var testMcpConnection = async (_request, ctx) => {
922
+ const result = await ctx.client.mcps.testConnection(requireParam(ctx.params, "id"));
923
+ return json(200, result);
924
+ };
925
+ var readMcpResource = async (request, ctx) => {
926
+ const uri = requireQueryParam(request.query, "uri");
927
+ const result = await ctx.client.mcps.readResource(requireParam(ctx.params, "id"), uri);
928
+ return json(200, result);
929
+ };
930
+ var callMcpTool = async (request, ctx) => {
931
+ const body = requireBodyObject(request.body);
932
+ const name = requireStringField(body, "name");
933
+ const args = body.arguments ?? void 0;
934
+ const result = await ctx.client.mcps.callTool(requireParam(ctx.params, "id"), name, args);
935
+ return json(200, result);
936
+ };
937
+
938
+ // src/routes/providers.ts
939
+ var listProviders = async (_request, ctx) => {
940
+ const items = await ctx.client.providers.list();
941
+ return json(200, items);
942
+ };
943
+ var createProvider = async (request, ctx) => {
944
+ const body = requireBodyObject(request.body);
945
+ const input = {
946
+ label: requireStringField(body, "label"),
947
+ baseURL: requireStringField(body, "baseURL"),
948
+ apiKey: requireStringField(body, "apiKey"),
949
+ defaultModel: requireStringField(body, "defaultModel"),
950
+ isDefault: typeof body.isDefault === "boolean" ? body.isDefault : void 0
951
+ };
952
+ const provider = await ctx.client.providers.create(input);
953
+ return json(201, provider);
954
+ };
955
+ var getProvider = async (_request, ctx) => {
956
+ const provider = await ctx.client.providers.get(requireParam(ctx.params, "id"));
957
+ return json(200, provider);
958
+ };
959
+ var updateProvider = async (request, ctx) => {
960
+ const body = request.body ?? {};
961
+ const provider = await ctx.client.providers.update(requireParam(ctx.params, "id"), body);
962
+ return json(200, provider);
963
+ };
964
+ var deleteProvider = async (_request, ctx) => {
965
+ await ctx.client.providers.delete(requireParam(ctx.params, "id"));
966
+ return noContent();
967
+ };
968
+ var bulkDeleteProviders = async (request, ctx) => {
969
+ const body = requireBodyObject(request.body);
970
+ const ids = Array.isArray(body.ids) ? body.ids : [];
971
+ const result = await ctx.client.providers.bulkDelete(ids);
972
+ return json(200, result);
973
+ };
974
+ var testProviderConnection = async (_request, ctx) => {
975
+ const result = await ctx.client.providers.testConnection(requireParam(ctx.params, "id"));
976
+ return json(200, result);
977
+ };
978
+ var getProviderModels = async (_request, ctx) => {
979
+ const models = await ctx.client.providers.getModels(requireParam(ctx.params, "id"));
980
+ return json(200, models);
981
+ };
982
+ var getProviderUsage = async (_request, ctx) => {
983
+ const usage = await ctx.client.providers.getUsage(requireParam(ctx.params, "id"));
984
+ return json(200, usage);
985
+ };
986
+
987
+ // src/routes/skills.ts
988
+ var listSkills = async (request, ctx) => {
989
+ const items = await ctx.client.skills.list({
990
+ page: toInt(request.query.page),
991
+ limit: toInt(request.query.limit),
992
+ search: request.query.search,
993
+ scope: request.query.scope === "mine" ? "mine" : void 0
994
+ });
995
+ return json(200, items);
996
+ };
997
+ var createSkill = async (request, ctx) => {
998
+ const body = requireBodyObject(request.body);
999
+ const input = {
1000
+ name: requireStringField(body, "name"),
1001
+ description: requireStringField(body, "description"),
1002
+ instructions: requireStringField(body, "instructions"),
1003
+ isPublic: typeof body.isPublic === "boolean" ? body.isPublic : void 0,
1004
+ files: Array.isArray(body.files) ? body.files : void 0
1005
+ };
1006
+ const skill = await ctx.client.skills.create(input);
1007
+ return json(201, skill);
1008
+ };
1009
+ var getSkill = async (_request, ctx) => {
1010
+ const skill = await ctx.client.skills.get(requireParam(ctx.params, "id"));
1011
+ return json(200, skill);
1012
+ };
1013
+ var updateSkill = async (request, ctx) => {
1014
+ const body = request.body ?? {};
1015
+ const skill = await ctx.client.skills.update(requireParam(ctx.params, "id"), body);
1016
+ return json(200, skill);
1017
+ };
1018
+ var deleteSkill = async (_request, ctx) => {
1019
+ await ctx.client.skills.delete(requireParam(ctx.params, "id"));
1020
+ return noContent();
1021
+ };
1022
+ var bulkDeleteSkills = async (request, ctx) => {
1023
+ const body = requireBodyObject(request.body);
1024
+ const ids = Array.isArray(body.ids) ? body.ids : [];
1025
+ const result = await ctx.client.skills.bulkDelete(ids);
1026
+ return json(200, result);
1027
+ };
1028
+ var getSkillUsage = async (_request, ctx) => {
1029
+ const usage = await ctx.client.skills.getUsage(requireParam(ctx.params, "id"));
1030
+ return json(200, usage);
1031
+ };
1032
+
1033
+ // src/routes/knowledge.ts
1034
+ var listKnowledgeBases = async (request, ctx) => {
1035
+ const items = await ctx.client.knowledge.list({
1036
+ page: toInt(request.query.page),
1037
+ limit: toInt(request.query.limit),
1038
+ search: request.query.search,
1039
+ scope: request.query.scope === "mine" ? "mine" : void 0
1040
+ });
1041
+ return json(200, items);
1042
+ };
1043
+ var createKnowledgeBase = async (request, ctx) => {
1044
+ const body = requireBodyObject(request.body);
1045
+ const input = {
1046
+ name: requireStringField(body, "name"),
1047
+ providerId: requireStringField(body, "providerId"),
1048
+ description: typeof body.description === "string" ? body.description : void 0,
1049
+ isPublic: typeof body.isPublic === "boolean" ? body.isPublic : void 0,
1050
+ embeddingModel: typeof body.embeddingModel === "string" ? body.embeddingModel : void 0,
1051
+ chunkSize: typeof body.chunkSize === "number" ? body.chunkSize : void 0,
1052
+ chunkOverlap: typeof body.chunkOverlap === "number" ? body.chunkOverlap : void 0,
1053
+ topK: typeof body.topK === "number" ? body.topK : void 0
1054
+ };
1055
+ const kb = await ctx.client.knowledge.create(input);
1056
+ return json(201, kb);
1057
+ };
1058
+ var getKnowledgeBase = async (_request, ctx) => {
1059
+ const kb = await ctx.client.knowledge.get(requireParam(ctx.params, "id"));
1060
+ return json(200, kb);
1061
+ };
1062
+ var updateKnowledgeBase = async (request, ctx) => {
1063
+ const body = request.body ?? {};
1064
+ const kb = await ctx.client.knowledge.update(requireParam(ctx.params, "id"), body);
1065
+ return json(200, kb);
1066
+ };
1067
+ var deleteKnowledgeBase = async (_request, ctx) => {
1068
+ await ctx.client.knowledge.delete(requireParam(ctx.params, "id"));
1069
+ return noContent();
1070
+ };
1071
+ var bulkDeleteKnowledgeBases = async (request, ctx) => {
1072
+ const body = requireBodyObject(request.body);
1073
+ const ids = Array.isArray(body.ids) ? body.ids : [];
1074
+ const result = await ctx.client.knowledge.bulkDelete(ids);
1075
+ return json(200, result);
1076
+ };
1077
+ var getKnowledgeBaseUsage = async (_request, ctx) => {
1078
+ const usage = await ctx.client.knowledge.getUsage(requireParam(ctx.params, "id"));
1079
+ return json(200, usage);
1080
+ };
1081
+ var uploadKnowledgeDocuments = async (request, ctx) => {
1082
+ if (!request.files || request.files.length === 0) {
1083
+ throw new RuntimeHttpError(
1084
+ 400,
1085
+ "INVALID_REQUEST",
1086
+ 'At least one "files" part is required on this request.'
1087
+ );
1088
+ }
1089
+ const result = await ctx.client.knowledge.uploadDocuments(
1090
+ requireParam(ctx.params, "id"),
1091
+ request.files.map((file) => ({
1092
+ filename: file.filename,
1093
+ content: file.content,
1094
+ contentType: file.contentType
1095
+ }))
1096
+ );
1097
+ return json(201, result);
1098
+ };
1099
+ var listKnowledgeDocuments = async (_request, ctx) => {
1100
+ const documents = await ctx.client.knowledge.listDocuments(requireParam(ctx.params, "id"));
1101
+ return json(200, documents);
1102
+ };
1103
+ var deleteKnowledgeDocument = async (_request, ctx) => {
1104
+ const result = await ctx.client.knowledge.deleteDocument(
1105
+ requireParam(ctx.params, "id"),
1106
+ requireParam(ctx.params, "sourceName")
1107
+ );
1108
+ return json(200, result);
1109
+ };
1110
+ var searchKnowledgeBase = async (request, ctx) => {
1111
+ const body = requireBodyObject(request.body);
1112
+ const query = requireStringField(body, "query");
1113
+ const topK = typeof body.topK === "number" ? body.topK : void 0;
1114
+ const results = await ctx.client.knowledge.search(requireParam(ctx.params, "id"), query, {
1115
+ topK
1116
+ });
1117
+ return json(200, results);
1118
+ };
1119
+
1120
+ // src/routes/stores.ts
1121
+ var listStores = async (request, ctx) => {
1122
+ const items = await ctx.client.stores.list({
1123
+ page: toInt(request.query.page),
1124
+ limit: toInt(request.query.limit),
1125
+ search: request.query.search
1126
+ });
1127
+ return json(200, items);
1128
+ };
1129
+ var createStore = async (request, ctx) => {
1130
+ const body = requireBodyObject(request.body);
1131
+ const input = {
1132
+ name: requireStringField(body, "name"),
1133
+ description: typeof body.description === "string" ? body.description : void 0,
1134
+ scope: requireStringField(body, "scope"),
1135
+ accessMode: body.accessMode
1136
+ };
1137
+ const store = await ctx.client.stores.create(input);
1138
+ return json(201, store);
1139
+ };
1140
+ var getStore = async (_request, ctx) => {
1141
+ const store = await ctx.client.stores.get(requireParam(ctx.params, "id"));
1142
+ return json(200, store);
1143
+ };
1144
+ var updateStore = async (request, ctx) => {
1145
+ const body = request.body ?? {};
1146
+ const store = await ctx.client.stores.update(requireParam(ctx.params, "id"), body);
1147
+ return json(200, store);
1148
+ };
1149
+ var deleteStore = async (_request, ctx) => {
1150
+ await ctx.client.stores.delete(requireParam(ctx.params, "id"));
1151
+ return noContent();
1152
+ };
1153
+ var listStoreFiles = async (_request, ctx) => {
1154
+ const files = await ctx.client.stores.listFiles(requireParam(ctx.params, "id"));
1155
+ return json(200, files);
1156
+ };
1157
+ var getStoreFile = async (request, ctx) => {
1158
+ const path = requireQueryParam(request.query, "path");
1159
+ const file = await ctx.client.stores.getFile(requireParam(ctx.params, "id"), { path });
1160
+ return json(200, file);
1161
+ };
1162
+ var writeStoreFile = async (request, ctx) => {
1163
+ const body = requireBodyObject(request.body);
1164
+ const input = {
1165
+ path: requireStringField(body, "path"),
1166
+ content: requireStringField(body, "content")
1167
+ };
1168
+ const file = await ctx.client.stores.writeFile(requireParam(ctx.params, "id"), input);
1169
+ return json(200, file);
1170
+ };
1171
+ var deleteStoreFile = async (request, ctx) => {
1172
+ const path = requireQueryParam(request.query, "path");
1173
+ await ctx.client.stores.deleteFile(requireParam(ctx.params, "id"), { path });
1174
+ return noContent();
1175
+ };
1176
+
1177
+ // src/routes/auditLogs.ts
1178
+ var listAuditLogs = async (request, ctx) => {
1179
+ const items = await ctx.client.auditLogs.list({
1180
+ page: toInt(request.query.page),
1181
+ limit: toInt(request.query.limit),
1182
+ eventType: request.query.eventType
1183
+ });
1184
+ return json(200, items);
1185
+ };
1186
+
1187
+ // src/runtime.ts
1188
+ function resolveCapabilities(capabilities) {
1189
+ return {
1190
+ agentsWrite: capabilities?.agentsWrite ?? false,
1191
+ mcps: capabilities?.mcps ?? false,
1192
+ providers: capabilities?.providers ?? false,
1193
+ skills: capabilities?.skills ?? false,
1194
+ knowledge: capabilities?.knowledge ?? false,
1195
+ stores: capabilities?.stores ?? false,
1196
+ auditLogs: capabilities?.auditLogs ?? false,
1197
+ architect: capabilities?.architect ?? false
1198
+ };
1199
+ }
1200
+ function buildRoutes(capabilities) {
1201
+ const routes = [
1202
+ { method: "GET", pattern: ["health"], handler: healthRoute, requiresAuth: false },
1203
+ // Chat — always on, the core runtime feature.
1204
+ { method: "POST", pattern: ["chat"], handler: chatRoute },
1205
+ { method: "GET", pattern: ["chat", ":runId", "resume"], handler: createResumeRoute("chat") },
1206
+ // Threads — always on, end-user-scoped conversation history.
1207
+ { method: "GET", pattern: ["threads"], handler: listThreads },
1208
+ { method: "POST", pattern: ["threads"], handler: createThread },
1209
+ { method: "POST", pattern: ["threads", "bulk-delete"], handler: bulkDeleteThreads },
1210
+ { method: "GET", pattern: ["threads", ":id"], handler: getThread },
1211
+ { method: "PATCH", pattern: ["threads", ":id"], handler: updateThread },
1212
+ { method: "DELETE", pattern: ["threads", ":id"], handler: deleteThread },
1213
+ { method: "GET", pattern: ["threads", ":id", "messages"], handler: getThreadMessages },
1214
+ // Agents — read-only discovery always on; write ops behind agentsWrite.
1215
+ { method: "GET", pattern: ["agents"], handler: listAgents },
1216
+ // Files — always on, end-user-scoped uploads.
1217
+ { method: "GET", pattern: ["files"], handler: listFiles },
1218
+ { method: "POST", pattern: ["files"], handler: uploadFile },
1219
+ { method: "POST", pattern: ["files", "bulk-delete"], handler: bulkDeleteFiles },
1220
+ { method: "GET", pattern: ["files", ":id"], handler: downloadFile },
1221
+ { method: "DELETE", pattern: ["files", ":id"], handler: deleteFile },
1222
+ // Memory — always on, end-user-scoped.
1223
+ { method: "GET", pattern: ["memory"], handler: listMemory },
1224
+ { method: "GET", pattern: ["memory", "file"], handler: getMemoryFile },
1225
+ { method: "PUT", pattern: ["memory", "file"], handler: writeMemoryFile },
1226
+ { method: "DELETE", pattern: ["memory", "file"], handler: deleteMemoryFile },
1227
+ // MCP OAuth — always on, end-user connects their own account.
1228
+ {
1229
+ method: "GET",
1230
+ pattern: ["mcps", ":id", "oauth", "owner", "authorize"],
1231
+ handler: getOwnerAuthorizeUrl
1232
+ },
1233
+ {
1234
+ method: "GET",
1235
+ pattern: ["mcps", ":id", "oauth", "user", "authorize"],
1236
+ handler: getUserAuthorizeUrl
1237
+ },
1238
+ {
1239
+ method: "GET",
1240
+ pattern: ["mcps", ":id", "oauth", "user", "status"],
1241
+ handler: getUserConnectionStatus
1242
+ },
1243
+ {
1244
+ method: "DELETE",
1245
+ pattern: ["mcps", ":id", "oauth", "user", "connection"],
1246
+ handler: disconnectUserConnection
1247
+ },
1248
+ {
1249
+ method: "DELETE",
1250
+ pattern: ["mcps", ":id", "oauth", "owner", "connection"],
1251
+ handler: disconnectOwnerConnection
1252
+ }
1253
+ ];
1254
+ if (capabilities.agentsWrite) {
1255
+ routes.push(
1256
+ { method: "POST", pattern: ["agents"], handler: createAgent },
1257
+ { method: "POST", pattern: ["agents", "bulk-delete"], handler: bulkDeleteAgents },
1258
+ { method: "GET", pattern: ["agents", ":id"], handler: getAgent },
1259
+ { method: "PATCH", pattern: ["agents", ":id"], handler: updateAgent },
1260
+ { method: "DELETE", pattern: ["agents", ":id"], handler: deleteAgent }
1261
+ );
1262
+ }
1263
+ if (capabilities.mcps) {
1264
+ routes.push(
1265
+ { method: "GET", pattern: ["mcps"], handler: listMcps },
1266
+ { method: "POST", pattern: ["mcps"], handler: createMcp },
1267
+ { method: "POST", pattern: ["mcps", "bulk-delete"], handler: bulkDeleteMcps },
1268
+ { method: "GET", pattern: ["mcps", ":id"], handler: getMcp },
1269
+ { method: "PATCH", pattern: ["mcps", ":id"], handler: updateMcp },
1270
+ { method: "DELETE", pattern: ["mcps", ":id"], handler: deleteMcp },
1271
+ { method: "GET", pattern: ["mcps", ":id", "usage"], handler: getMcpUsage },
1272
+ { method: "POST", pattern: ["mcps", ":id", "test"], handler: testMcpConnection },
1273
+ { method: "GET", pattern: ["mcps", ":id", "resource"], handler: readMcpResource },
1274
+ { method: "POST", pattern: ["mcps", ":id", "call-tool"], handler: callMcpTool }
1275
+ );
1276
+ }
1277
+ if (capabilities.providers) {
1278
+ routes.push(
1279
+ { method: "GET", pattern: ["providers"], handler: listProviders },
1280
+ { method: "POST", pattern: ["providers"], handler: createProvider },
1281
+ { method: "POST", pattern: ["providers", "bulk-delete"], handler: bulkDeleteProviders },
1282
+ { method: "GET", pattern: ["providers", ":id"], handler: getProvider },
1283
+ { method: "PATCH", pattern: ["providers", ":id"], handler: updateProvider },
1284
+ { method: "DELETE", pattern: ["providers", ":id"], handler: deleteProvider },
1285
+ { method: "POST", pattern: ["providers", ":id", "test"], handler: testProviderConnection },
1286
+ { method: "GET", pattern: ["providers", ":id", "models"], handler: getProviderModels },
1287
+ { method: "GET", pattern: ["providers", ":id", "usage"], handler: getProviderUsage }
1288
+ );
1289
+ }
1290
+ if (capabilities.skills) {
1291
+ routes.push(
1292
+ { method: "GET", pattern: ["skills"], handler: listSkills },
1293
+ { method: "POST", pattern: ["skills"], handler: createSkill },
1294
+ { method: "POST", pattern: ["skills", "bulk-delete"], handler: bulkDeleteSkills },
1295
+ { method: "GET", pattern: ["skills", ":id"], handler: getSkill },
1296
+ { method: "PATCH", pattern: ["skills", ":id"], handler: updateSkill },
1297
+ { method: "DELETE", pattern: ["skills", ":id"], handler: deleteSkill },
1298
+ { method: "GET", pattern: ["skills", ":id", "usage"], handler: getSkillUsage }
1299
+ );
1300
+ }
1301
+ if (capabilities.knowledge) {
1302
+ routes.push(
1303
+ { method: "GET", pattern: ["knowledge"], handler: listKnowledgeBases },
1304
+ { method: "POST", pattern: ["knowledge"], handler: createKnowledgeBase },
1305
+ { method: "POST", pattern: ["knowledge", "bulk-delete"], handler: bulkDeleteKnowledgeBases },
1306
+ { method: "GET", pattern: ["knowledge", ":id"], handler: getKnowledgeBase },
1307
+ { method: "PATCH", pattern: ["knowledge", ":id"], handler: updateKnowledgeBase },
1308
+ { method: "DELETE", pattern: ["knowledge", ":id"], handler: deleteKnowledgeBase },
1309
+ { method: "GET", pattern: ["knowledge", ":id", "usage"], handler: getKnowledgeBaseUsage },
1310
+ {
1311
+ method: "POST",
1312
+ pattern: ["knowledge", ":id", "documents"],
1313
+ handler: uploadKnowledgeDocuments
1314
+ },
1315
+ {
1316
+ method: "GET",
1317
+ pattern: ["knowledge", ":id", "documents"],
1318
+ handler: listKnowledgeDocuments
1319
+ },
1320
+ {
1321
+ method: "DELETE",
1322
+ pattern: ["knowledge", ":id", "documents", ":sourceName"],
1323
+ handler: deleteKnowledgeDocument
1324
+ },
1325
+ { method: "POST", pattern: ["knowledge", ":id", "search"], handler: searchKnowledgeBase }
1326
+ );
1327
+ }
1328
+ if (capabilities.stores) {
1329
+ routes.push(
1330
+ { method: "GET", pattern: ["stores"], handler: listStores },
1331
+ { method: "POST", pattern: ["stores"], handler: createStore },
1332
+ { method: "GET", pattern: ["stores", ":id"], handler: getStore },
1333
+ { method: "PATCH", pattern: ["stores", ":id"], handler: updateStore },
1334
+ { method: "DELETE", pattern: ["stores", ":id"], handler: deleteStore },
1335
+ { method: "GET", pattern: ["stores", ":id", "files"], handler: listStoreFiles },
1336
+ { method: "GET", pattern: ["stores", ":id", "file"], handler: getStoreFile },
1337
+ { method: "PUT", pattern: ["stores", ":id", "file"], handler: writeStoreFile },
1338
+ { method: "DELETE", pattern: ["stores", ":id", "file"], handler: deleteStoreFile }
1339
+ );
1340
+ }
1341
+ if (capabilities.auditLogs) {
1342
+ routes.push({ method: "GET", pattern: ["audit-logs"], handler: listAuditLogs });
1343
+ }
1344
+ if (capabilities.architect) {
1345
+ routes.push(
1346
+ { method: "POST", pattern: ["architect"], handler: architectRoute },
1347
+ {
1348
+ method: "GET",
1349
+ pattern: ["architect", ":runId", "resume"],
1350
+ handler: createResumeRoute("architect")
1351
+ }
1352
+ );
1353
+ }
1354
+ return routes;
1355
+ }
1356
+ function resolveMode(options) {
1357
+ if (options.mode) return options.mode;
1358
+ return process.env.NODE_ENV === "development" ? "development" : "production";
1359
+ }
1360
+ function createRuntime(options) {
1361
+ if (!options.baseUrl) throw new Error('createRuntime: "baseUrl" is required');
1362
+ if (!options.credential) throw new Error('createRuntime: "credential" is required');
1363
+ if (!options.resolveUser) throw new Error('createRuntime: "resolveUser" is required');
1364
+ const capabilities = resolveCapabilities(options.capabilities);
1365
+ const routes = buildRoutes(capabilities);
1366
+ const mode = resolveMode(options);
1367
+ const heartbeatIntervalMs = options.heartbeatIntervalMs ?? 15e3;
1368
+ const runGraceMs = options.runGraceMs ?? DEFAULT_RUN_GRACE_MS;
1369
+ const maxTrackedRuns = options.maxTrackedRuns ?? DEFAULT_MAX_TRACKED_RUNS;
1370
+ const runs = /* @__PURE__ */ new Map();
1371
+ const evictionTimer = setInterval(
1372
+ () => evictStaleRuns(runs, Date.now(), runGraceMs, maxTrackedRuns),
1373
+ 6e4
1374
+ );
1375
+ evictionTimer.unref?.();
1376
+ async function handle(request) {
1377
+ try {
1378
+ const path = stripMountPath(request.path, options.mountPath);
1379
+ const match = matchRoute(routes, request.method, path);
1380
+ if (match.kind === "not-found") {
1381
+ throw new RuntimeHttpError(
1382
+ 404,
1383
+ "NOT_FOUND",
1384
+ `No route for ${request.method} ${request.path}`
1385
+ );
1386
+ }
1387
+ if (match.kind === "method-not-allowed") {
1388
+ const err = new RuntimeHttpError(
1389
+ 405,
1390
+ "METHOD_NOT_ALLOWED",
1391
+ `${request.method} not allowed on ${request.path}. Allowed: ${match.allowed.join(", ")}.`
1392
+ );
1393
+ const response = errorToResponse(err, mode);
1394
+ return { ...response, headers: { ...response.headers, Allow: match.allowed.join(", ") } };
1395
+ }
1396
+ let userId = null;
1397
+ if (match.route.requiresAuth !== false) {
1398
+ try {
1399
+ userId = await options.resolveUser(request);
1400
+ } catch {
1401
+ userId = null;
1402
+ }
1403
+ if (userId === null) {
1404
+ throw new RuntimeHttpError(
1405
+ 401,
1406
+ "UNAUTHORIZED",
1407
+ "Could not resolve an authenticated user for this request."
1408
+ );
1409
+ }
1410
+ }
1411
+ const resolvedRequest = { ...request, userId };
1412
+ const client = createClientForRequest(options, userId);
1413
+ return await match.route.handler(resolvedRequest, {
1414
+ client,
1415
+ hooks: options.hooks,
1416
+ mode,
1417
+ params: match.params,
1418
+ heartbeatIntervalMs,
1419
+ runs,
1420
+ capabilities
1421
+ });
1422
+ } catch (err) {
1423
+ return errorToResponse(err, mode);
1424
+ }
1425
+ }
1426
+ return {
1427
+ handle,
1428
+ close() {
1429
+ clearInterval(evictionTimer);
1430
+ }
1431
+ };
1432
+ }
1433
+ // Annotate the CommonJS export names for ESM import in node:
1434
+ 0 && (module.exports = {
1435
+ RUNTIME_VERSION,
1436
+ RuntimeHttpError,
1437
+ createRuntime
1438
+ });
1439
+ //# sourceMappingURL=index.cjs.map