@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/README.md +411 -0
- package/dist/index.cjs +1439 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +247 -0
- package/dist/index.d.ts +247 -0
- package/dist/index.js +1410 -0
- package/dist/index.js.map +1 -0
- package/package.json +71 -0
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
|