@nylorun/runtime 0.7.0-beta → 0.9.0-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +7 -5
  3. package/dist/adapters/sandbox/microsandbox.d.ts +2 -0
  4. package/dist/adapters/sandbox/microsandbox.js +238 -0
  5. package/dist/adapters/sandbox/virtual.d.ts +4 -0
  6. package/dist/adapters/sandbox/virtual.js +125 -0
  7. package/dist/configuration.d.ts +1 -1
  8. package/dist/configuration.js +1 -1
  9. package/dist/core/executors.d.ts +32 -0
  10. package/dist/core/executors.js +60 -0
  11. package/dist/core/main.js +7 -12
  12. package/dist/core/runtime.d.ts +24 -1
  13. package/dist/core/runtime.js +364 -43
  14. package/dist/core/store.d.ts +14 -1
  15. package/dist/core/store.js +59 -3
  16. package/dist/index.d.ts +0 -1
  17. package/dist/index.js +0 -1
  18. package/dist/mcp/pool.d.ts +13 -1
  19. package/dist/mcp/pool.js +53 -19
  20. package/dist/mcp/snapshot.d.ts +4 -0
  21. package/dist/model/catalog.d.ts +12 -0
  22. package/dist/model/catalog.js +29 -0
  23. package/dist/model/models.d.ts +3 -1
  24. package/dist/model/models.js +4 -2
  25. package/dist/model/pi-model.d.ts +9 -3
  26. package/dist/model/pi-model.js +47 -11
  27. package/dist/model/settings.d.ts +0 -2
  28. package/dist/model/settings.js +0 -47
  29. package/dist/node/index.d.ts +1 -1
  30. package/dist/node/index.js +1 -1
  31. package/dist/sandbox/manager.d.ts +61 -0
  32. package/dist/sandbox/manager.js +239 -0
  33. package/dist/sandbox/policy.d.ts +13 -0
  34. package/dist/sandbox/policy.js +67 -0
  35. package/dist/sandbox/select.d.ts +35 -0
  36. package/dist/sandbox/select.js +76 -0
  37. package/dist/sandbox/tools.d.ts +25 -0
  38. package/dist/sandbox/tools.js +165 -0
  39. package/dist/sandbox/types.d.ts +66 -0
  40. package/dist/vault/service.d.ts +41 -1
  41. package/dist/vault/service.js +291 -4
  42. package/dist/version.d.ts +1 -0
  43. package/dist/version.js +3 -0
  44. package/package.json +9 -4
  45. package/dist/config.d.ts +0 -20
  46. package/dist/model/defaults.d.ts +0 -17
  47. package/dist/model/defaults.js +0 -21
  48. package/dist/model/http-model.d.ts +0 -12
  49. package/dist/model/http-model.js +0 -299
  50. package/dist/node/local-sessions.d.ts +0 -5
  51. package/dist/node/local-sessions.js +0 -174
  52. package/dist/server/ag-ui.d.ts +0 -8
  53. package/dist/server/ag-ui.js +0 -76
  54. package/dist/server/delivery.d.ts +0 -24
  55. package/dist/server/delivery.js +0 -107
  56. package/dist/server/digests.d.ts +0 -13
  57. package/dist/server/digests.js +0 -39
  58. package/dist/server/host.d.ts +0 -70
  59. package/dist/server/host.js +0 -647
  60. package/dist/session/api.d.ts +0 -10
  61. package/dist/session/api.js +0 -15
  62. package/dist/session/default.d.ts +0 -5
  63. package/dist/session/default.js +0 -30
  64. package/dist/session/handle.d.ts +0 -27
  65. package/dist/session/handle.js +0 -199
  66. package/dist/session/index.d.ts +0 -2
  67. package/dist/session/index.js +0 -2
  68. package/dist/sessions/host.d.ts +0 -39
  69. package/dist/sessions/host.js +0 -359
  70. package/dist/sessions/store.d.ts +0 -41
  71. package/dist/sessions/store.js +0 -33
  72. /package/dist/{config.js → sandbox/types.js} +0 -0
@@ -1,647 +0,0 @@
1
- import { Hono } from "hono";
2
- import { cors } from "hono/cors";
3
- import { HTTPException } from "hono/http-exception";
4
- import { agUiEvents } from "./ag-ui.js";
5
- import { EventDelivery } from "./delivery.js";
6
- import { scrub } from "../redact.js";
7
- import { memorySessions } from "../sessions/store.js";
8
- import { SessionHost } from "../sessions/host.js";
9
- import { IMAGE_MEDIA_TYPES, MAX_IMAGE_BYTES, decodeImageBase64, } from "../media.js";
10
- import { defaultModel, processEnvironment, registerRuntimeLifecycle, } from "../model/defaults.js";
11
- import { createSessionHandle, } from "../session/handle.js";
12
- import { installDefaultRuntimeFactory } from "../session/default.js";
13
- const randomUUID = () => crypto.randomUUID();
14
- const kServe = Symbol("serve");
15
- export class Runtime {
16
- config;
17
- host;
18
- served = false;
19
- closing;
20
- constructor(config = {}) {
21
- this.config = config;
22
- this.host = new SessionHost(config.sessions ?? memorySessions());
23
- registerRuntimeLifecycle(this.close);
24
- }
25
- close = () => (this.closing ??= this.host.close());
26
- resolveModel(onPreview) {
27
- return (this.config.onModelCall ??
28
- (this.config.createModel ?? defaultModel)({
29
- environment: this.config.environment ?? processEnvironment(),
30
- onPreview,
31
- media: this.config.media,
32
- }));
33
- }
34
- openSession(agent, options) {
35
- return createSessionHandle(this, agent, options);
36
- }
37
- async listSessions(agentId) {
38
- return this.host.list(agentId);
39
- }
40
- async getSession(agentId, sessionId) {
41
- return this.host.read(agentId, sessionId);
42
- }
43
- async deleteSession(agentId, sessionId) {
44
- return this.host.delete(agentId, sessionId);
45
- }
46
- [kServe](options) {
47
- if (this.served)
48
- throw new Error("A Runtime may only be served once.");
49
- this.served = true;
50
- const agents = [...options.agents];
51
- const byId = new Map(agents.map((agent) => [agent.id, agent]));
52
- if (byId.size !== agents.length)
53
- throw new Error("Agent IDs must be unique.");
54
- for (const agent of agents) {
55
- if (!/^[a-zA-Z0-9_-]+$/.test(agent.id))
56
- throw new Error(`Invalid agent ID: ${agent.id}`);
57
- if (agent.id !== agent.manifest.id || agent.name !== agent.manifest.name)
58
- throw new Error("Agent identity must match its manifest.");
59
- }
60
- const { media } = this.config;
61
- const app = new Hono();
62
- if (processEnvironment().NYLORUN_DEV === "1")
63
- app.use("*", cors({
64
- origin: (origin) => {
65
- try {
66
- const url = new URL(origin);
67
- return ["http:", "https:"].includes(url.protocol) &&
68
- ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname) &&
69
- url.origin === origin
70
- ? origin
71
- : undefined;
72
- }
73
- catch {
74
- return undefined;
75
- }
76
- },
77
- }));
78
- app.onError((error, context) => context.json({
79
- error: String(scrub(error.message, secretValues(environment(context)))),
80
- }, error instanceof HTTPException ? error.status : 500));
81
- // Application authorization/info resolution precedes all store and media access.
82
- app.use("*", async (context, next) => {
83
- const actor = await options.getActor?.(context);
84
- const info = options.getInfo
85
- ? await options.getInfo(context)
86
- : actor
87
- ? { ...actor.context, userId: actor.id }
88
- : undefined;
89
- context.set("info", info);
90
- if (options.getEnvironment)
91
- context.set("modelEnvironment", await options.getEnvironment(context));
92
- await next();
93
- if (context.res.headers.get("content-type")?.includes("application/json")) {
94
- const value = await context.res.json();
95
- context.res = new Response(JSON.stringify(scrub(value, secretValues(environment(context)))), { status: context.res.status, headers: context.res.headers });
96
- }
97
- });
98
- const environment = (context) => context.get("modelEnvironment") ??
99
- this.config.environment ??
100
- bindingsEnvironment(context) ??
101
- processEnvironment();
102
- const path = (context, route, suffix) => `${normalizeBasePath(options.basePath ?? inferMountPath(context, route))}${suffix}`;
103
- const agentFor = (context) => {
104
- const agent = byId.get(context.req.param("agentId"));
105
- if (!agent)
106
- throw new HTTPException(404, { message: "unknown agent" });
107
- const session = context.req.param("session");
108
- if (session !== undefined && !isSessionId(session))
109
- throw new HTTPException(400, { message: "Invalid session identifier" });
110
- return agent;
111
- };
112
- const submitOptions = (context, sessionId, onPreview) => {
113
- // Leave undefined on Node so defaultModel can use the installed piModel
114
- // factory. Hono's Node adapter puts stream bindings on context.env; those
115
- // must not be treated as Workers-style provider bindings.
116
- const explicitEnvironment = context.get("modelEnvironment") ??
117
- this.config.environment ??
118
- bindingsEnvironment(context);
119
- return {
120
- info: { ...(context.get("info") ?? {}), sessionId },
121
- onEvent: (event) => {
122
- try {
123
- void Promise.resolve(this.config.observer?.({ type: event.type, ...event.payload })).catch(() => { });
124
- }
125
- catch {
126
- /* Observation cannot acknowledge persistence. */
127
- }
128
- },
129
- onModelCall: this.config.onModelCall ??
130
- (this.config.createModel ?? defaultModel)({
131
- environment: explicitEnvironment,
132
- onPreview,
133
- media,
134
- }),
135
- secrets: secretValues(environment(context)),
136
- signal: context.req.raw.signal,
137
- };
138
- };
139
- app.get("/v1/agents", (context) => context.json({
140
- protocolVersion: 2,
141
- agents: agents.map((agent) => ({
142
- id: agent.id,
143
- manifestUrl: path(context, "/v1/agents", `/${agent.id}/manifest.json`),
144
- })),
145
- }));
146
- app.get("/:agentId/manifest.json", (context) => context.json(manifest(agentFor(context), media !== undefined, (suffix) => path(context, "/:agentId/manifest.json", suffix))));
147
- app.get("/:agentId/v1/media/:session/:assetId", async (context) => {
148
- const agent = agentFor(context);
149
- const asset = await media?.read(agent.id, context.req.param("session"), context.req.param("assetId"));
150
- if (!asset)
151
- return context.json({ error: "unknown media asset" }, 404);
152
- return context.body(asset.bytes, 200, {
153
- "content-type": asset.asset.mediaType,
154
- "cache-control": "no-store",
155
- });
156
- });
157
- app.get("/:agentId/v1/sessions", async (context) => context.json({ sessions: await this.host.list(agentFor(context).id) }));
158
- app.get("/:agentId/v1/sessions/:session", async (context) => {
159
- const document = await this.host.read(agentFor(context).id, context.req.param("session"));
160
- if (!document)
161
- return context.json({ error: "unknown session" }, 404);
162
- return context.json({
163
- id: document.id,
164
- state: document.status,
165
- pending_interaction: document.state?.plan?.calls.find((call) => call.status === "interaction")?.interaction,
166
- pending_waits: document.state?.plan?.calls
167
- .filter((call) => (call.status === "interaction" || call.status === "deferred") &&
168
- call.wait)
169
- .map((call) => call.wait),
170
- });
171
- });
172
- app.delete("/:agentId/v1/sessions/:session", async (context) => {
173
- const agent = agentFor(context);
174
- const sessionId = context.req.param("session");
175
- const deleted = await this.host.delete(agent.id, sessionId);
176
- if (!deleted)
177
- return context.json({ error: "unknown session" }, 404);
178
- return context.json({ session_id: sessionId, deleted: true });
179
- });
180
- app.post("/:agentId/v1/sessions/:session", async (context) => {
181
- const agent = agentFor(context), sessionId = context.req.param("session");
182
- const payload = await context.req.json();
183
- const interaction = payload.interaction;
184
- let input;
185
- if (payload.action === "cancel") {
186
- await this.host.cancel(agent, sessionId);
187
- return context.json({ session_id: sessionId, state: "cancelled" });
188
- }
189
- if (payload.action === "interrupt") {
190
- const result = await this.host.interrupt(agent, sessionId, payload.input, submitOptions(context, sessionId));
191
- return context.json({
192
- session_id: sessionId,
193
- state: result.status === "paused" ? "waiting" : result.status,
194
- }, 202);
195
- }
196
- if (payload.settlement)
197
- input = { kind: "settle", ...payload.settlement };
198
- else if (payload.action === "wait-resolve" ||
199
- payload.waitResolve ||
200
- (interaction?.kind === "wait-resolve" &&
201
- typeof interaction.waitId === "string")) {
202
- const wait = payload.waitResolve ??
203
- (interaction?.kind === "wait-resolve" ? interaction : payload);
204
- if (typeof wait.waitId !== "string")
205
- return context.json({ error: "wait-resolve requires waitId" }, 400);
206
- input = {
207
- kind: "wait-resolve",
208
- waitId: wait.waitId,
209
- ...("value" in wait ? { value: wait.value } : {}),
210
- };
211
- }
212
- else if (interaction?.kind === "approval" &&
213
- typeof interaction.id === "string" &&
214
- typeof interaction.approved === "boolean")
215
- input = {
216
- kind: "approve",
217
- interactionId: interaction.id,
218
- approved: interaction.approved,
219
- };
220
- else if (interaction?.kind === "respond" &&
221
- typeof interaction.id === "string" &&
222
- "value" in interaction)
223
- input = {
224
- kind: "respond",
225
- interactionId: interaction.id,
226
- value: interaction.value,
227
- };
228
- else
229
- return context.json({
230
- error: "expected a correlated interaction, settlement, or wait-resolve",
231
- }, 400);
232
- const document = await this.host.read(agent.id, sessionId);
233
- if (!document || document.status !== "waiting")
234
- return context.json({ error: "interaction is no longer pending" }, 409);
235
- const result = await this.host.submit(agent, sessionId, input, submitOptions(context, sessionId));
236
- return context.json({
237
- session_id: sessionId,
238
- state: result.status === "paused" ? "waiting" : result.status,
239
- }, 202);
240
- });
241
- app.get("/:agentId/v1/sessions/:session/events", async (context) => {
242
- const document = await this.host.read(agentFor(context).id, context.req.param("session"));
243
- const after = Number(context.req.query("after") ?? "0");
244
- if (!Number.isSafeInteger(after) || after < 0)
245
- return context.json({ error: "Invalid event cursor" }, 400);
246
- const events = document?.events ?? [];
247
- return context.json({
248
- events: events.filter((event) => event.seq > after),
249
- next_cursor: events.at(-1)?.seq ?? after,
250
- });
251
- });
252
- app.get("/:agentId/v1/ag-ui/sessions/:session", async (context) => {
253
- const agent = agentFor(context);
254
- return context.json({
255
- messages: messages(agent.id, (await this.host.read(agent.id, context.req.param("session")))
256
- ?.events ?? []),
257
- });
258
- });
259
- app.post("/:agentId/v1/ag-ui", async (context) => {
260
- const agent = agentFor(context);
261
- const payload = await context.req.json();
262
- const threadId = typeof payload.threadId === "string" && payload.threadId
263
- ? payload.threadId
264
- : randomUUID();
265
- if (!isSessionId(threadId))
266
- return context.json({ error: "Invalid threadId" }, 400);
267
- const runId = typeof payload.runId === "string" && payload.runId
268
- ? payload.runId
269
- : randomUUID();
270
- const message = await latestMessage(payload.messages, media, agent.id, threadId, await options.getRequestMetadata?.(context));
271
- const controller = new AbortController();
272
- const abort = () => controller.abort(context.req.raw.signal.reason);
273
- context.req.raw.signal.addEventListener("abort", abort, { once: true });
274
- if (context.req.raw.signal.aborted)
275
- abort();
276
- const delivery = new EventDelivery(() => controller.abort(new Error("Delivery connection ended")), this.config.delivery, context.res.headers);
277
- delivery.push({ type: "RUN_STARTED", threadId, runId });
278
- const modelOptions = submitOptions(context, threadId, this.config.tokens
279
- ? (preview) => delivery.push({
280
- type: "CUSTOM",
281
- name: "nylorun.preview",
282
- value: { ...preview, runId },
283
- }, preview.invocationId)
284
- : undefined);
285
- const task = this.host.submit(agent, threadId, message.input, {
286
- ...modelOptions,
287
- runId,
288
- signal: controller.signal,
289
- started: {
290
- input_kind: "user-message",
291
- message: message.chat,
292
- ...(firstText(message.chat) === undefined
293
- ? {}
294
- : { input: firstText(message.chat) }),
295
- },
296
- onEvent: (event) => {
297
- delivery.push({
298
- type: "CUSTOM",
299
- name: "nylorun.execution",
300
- value: event,
301
- });
302
- for (const projected of agUiEvents([event], threadId, runId))
303
- if (!["RUN_STARTED", "RUN_FINISHED"].includes(String(projected.type)))
304
- delivery.push(projected);
305
- modelOptions.onEvent(event);
306
- },
307
- });
308
- void task
309
- .then((result) => {
310
- delivery.push({
311
- type: "CUSTOM",
312
- name: "nylorun.preview.settled",
313
- value: { runId, status: result.status },
314
- });
315
- if (result.status !== "failed")
316
- delivery.push({ type: "RUN_FINISHED", threadId, runId });
317
- }, (error) => {
318
- delivery.push({
319
- type: "RUN_ERROR",
320
- message: String(scrub(error instanceof Error ? error.message : String(error), modelOptions.secrets)),
321
- });
322
- })
323
- .finally(() => {
324
- context.req.raw.signal.removeEventListener("abort", abort);
325
- delivery.end();
326
- });
327
- return delivery.response;
328
- });
329
- return app;
330
- }
331
- }
332
- export function serveAgents(options) {
333
- if ("runtime" in options && options.runtime) {
334
- const { runtime, ...rest } = options;
335
- return runtime[kServe]({
336
- ...rest,
337
- agents: options.agents ?? [],
338
- });
339
- }
340
- const runtime = new Runtime({});
341
- const getInfo = options.getInfo ?? ("info" in options ? options.info : undefined);
342
- const app = runtime[kServe]({
343
- ...options,
344
- agents: options.agents ?? [],
345
- ...(getInfo ? { getInfo } : {}),
346
- });
347
- return {
348
- fetch: (request) => app.fetch(request),
349
- };
350
- }
351
- installDefaultRuntimeFactory(() => new Runtime({}));
352
- /** Workers-style provider bindings on context.env; ignore Hono Node stream slots. */
353
- function bindingsEnvironment(context) {
354
- const env = context.env;
355
- if (!env || typeof env !== "object")
356
- return undefined;
357
- const keys = Object.keys(env);
358
- if (!keys.length)
359
- return undefined;
360
- if (keys.every((key) => key === "incoming" || key === "outgoing"))
361
- return undefined;
362
- return env;
363
- }
364
- function secretValues(environment) {
365
- return Object.entries(environment).flatMap(([key, value]) => /key|token|secret|password|credential/i.test(key) &&
366
- typeof value === "string" &&
367
- value
368
- ? [value]
369
- : []);
370
- }
371
- function manifest(agent, media, publicPath) {
372
- return {
373
- protocolVersion: 2,
374
- id: agent.manifest.id,
375
- name: agent.manifest.name,
376
- manifest: agent.manifest,
377
- endpoints: {
378
- agUi: publicPath(`/${agent.id}/v1/ag-ui`),
379
- sessions: publicPath(`/${agent.id}/v1/sessions`),
380
- },
381
- ...(media
382
- ? {
383
- mediaInput: {
384
- acceptedTypes: IMAGE_MEDIA_TYPES,
385
- maxBytes: MAX_IMAGE_BYTES,
386
- },
387
- }
388
- : {}),
389
- };
390
- }
391
- function keyOf(agent, session) {
392
- return `${agent}:${session}`;
393
- }
394
- async function latestMessage(value, media, agentId, sessionId, metadata) {
395
- if (!Array.isArray(value))
396
- throw new HTTPException(400, { message: "AG-UI requires a user message." });
397
- for (let i = value.length - 1; i >= 0; i -= 1) {
398
- const item = value[i];
399
- if (item?.role !== "user")
400
- continue;
401
- const content = await incomingContent(item.content, media, agentId, sessionId, metadata);
402
- if (content)
403
- return content;
404
- }
405
- throw new HTTPException(400, {
406
- message: "AG-UI requires a non-empty user message.",
407
- });
408
- }
409
- function pending(events) {
410
- for (let i = events.length - 1; i >= 0; i -= 1) {
411
- if (events[i].type === "interaction.required")
412
- return events[i].payload.interaction;
413
- if (events[i].type === "final")
414
- return undefined;
415
- }
416
- return undefined;
417
- }
418
- function status(events) {
419
- return pending(events)
420
- ? "waiting"
421
- : events.some((event) => event.type === "final")
422
- ? "completed"
423
- : "incomplete";
424
- }
425
- function messages(agentId, events) {
426
- return events.flatMap((event) => event.type === "final" && "output" in event.payload
427
- ? [
428
- {
429
- id: String(event.seq),
430
- role: "assistant",
431
- content: finalContent(event.payload.output),
432
- },
433
- ]
434
- : event.type === "session.run.started" &&
435
- isChatMessage(event.payload.message)
436
- ? [
437
- {
438
- ...event.payload.message,
439
- id: String(event.seq),
440
- },
441
- ]
442
- : generatedImageFromEvent(event, agentId)
443
- ? [generatedImageFromEvent(event, agentId)]
444
- : []);
445
- }
446
- async function incomingContent(value, media, agentId, sessionId, metadata) {
447
- const parts = [];
448
- const chat = [];
449
- if (typeof value === "string") {
450
- if (value.trim() === "")
451
- return undefined;
452
- parts.push({ type: "text", text: value });
453
- chat.push({ type: "text", text: value });
454
- }
455
- else if (Array.isArray(value)) {
456
- let images = 0;
457
- for (const raw of value) {
458
- const part = raw;
459
- if (part?.type === "text" && typeof part.text === "string") {
460
- if (part.text !== "") {
461
- parts.push({ type: "text", text: part.text });
462
- chat.push({ type: "text", text: part.text });
463
- }
464
- continue;
465
- }
466
- if (part?.type !== "image")
467
- throw new HTTPException(400, {
468
- message: "Only text and image inputs are supported.",
469
- });
470
- if (++images > 1)
471
- throw new HTTPException(400, {
472
- message: "Attach only one image per message.",
473
- });
474
- const source = part.source;
475
- if (!source ||
476
- source.type !== "data" ||
477
- typeof source.value !== "string" ||
478
- typeof source.mimeType !== "string")
479
- throw new HTTPException(400, {
480
- message: "Image input must contain base64 data and a media type.",
481
- });
482
- if (!media)
483
- throw new HTTPException(400, {
484
- message: "This runtime does not support image input.",
485
- });
486
- try {
487
- decodeImageBase64(source.mimeType, source.value);
488
- }
489
- catch (cause) {
490
- throw new HTTPException(400, {
491
- message: cause instanceof Error ? cause.message : "Invalid image input",
492
- cause,
493
- });
494
- }
495
- const asset = await media.saveInput(agentId, sessionId, source.mimeType, source.value);
496
- parts.push({
497
- type: "media",
498
- mediaType: asset.mediaType,
499
- reference: { agentId, sessionId, assetId: asset.id },
500
- });
501
- chat.push({
502
- type: "image",
503
- url: mediaUrl(agentId, sessionId, asset.id),
504
- mediaType: asset.mediaType,
505
- });
506
- }
507
- }
508
- else
509
- return undefined;
510
- if (parts.length === 0)
511
- return undefined;
512
- return Object.freeze({
513
- input: {
514
- content: Object.freeze(parts),
515
- ...(metadata === undefined ? {} : { metadata }),
516
- },
517
- chat: { id: randomUUID(), role: "user", content: Object.freeze(chat) },
518
- });
519
- }
520
- function chatFromInput(event, agentId, sessionId) {
521
- if (event.kind !== "user-message")
522
- return undefined;
523
- if (typeof event.text === "string")
524
- return {
525
- id: randomUUID(),
526
- role: "user",
527
- content: [{ type: "text", text: event.text }],
528
- };
529
- if (!event.content)
530
- return undefined;
531
- const content = event.content.flatMap((part) => {
532
- if (part.type === "text")
533
- return [{ type: "text", text: part.text }];
534
- const reference = part.reference;
535
- return typeof reference.assetId === "string"
536
- ? [
537
- {
538
- type: "image",
539
- url: mediaUrl(agentId, sessionId, reference.assetId),
540
- mediaType: part.mediaType,
541
- },
542
- ]
543
- : [];
544
- });
545
- return content.length === 0
546
- ? undefined
547
- : { id: randomUUID(), role: "user", content };
548
- }
549
- function finalContent(output) {
550
- return typeof output === "string"
551
- ? [{ type: "text", text: output }]
552
- : [{ type: "json", value: output }];
553
- }
554
- function generatedImageMessage(event, agentId, sessionId) {
555
- if (event.type !== "tool.completed")
556
- return undefined;
557
- const image = imageFromToolResult(event.attributes);
558
- return image
559
- ? {
560
- id: randomUUID(),
561
- role: "assistant",
562
- content: [
563
- {
564
- type: "image",
565
- url: mediaUrl(agentId, sessionId, image.id),
566
- mediaType: image.mediaType,
567
- },
568
- ],
569
- }
570
- : undefined;
571
- }
572
- function generatedImageFromEvent(event, agentId) {
573
- if (event.type !== "tool.completed")
574
- return undefined;
575
- const image = imageFromToolResult(event.payload.attributes);
576
- return image
577
- ? {
578
- id: String(event.seq),
579
- role: "assistant",
580
- content: [
581
- {
582
- type: "image",
583
- url: mediaUrl(agentId, event.session, image.id),
584
- mediaType: image.mediaType,
585
- },
586
- ],
587
- }
588
- : undefined;
589
- }
590
- function imageFromToolResult(value) {
591
- if (!value || typeof value !== "object")
592
- return undefined;
593
- const result = value;
594
- if (result.kind !== "completed" ||
595
- !result.output ||
596
- typeof result.output !== "object")
597
- return undefined;
598
- const image = result.output.image;
599
- return image &&
600
- typeof image.id === "string" &&
601
- typeof image.mediaType === "string" &&
602
- image.kind === "generated"
603
- ? image
604
- : undefined;
605
- }
606
- function isChatMessage(value) {
607
- if (!value || typeof value !== "object")
608
- return false;
609
- const message = value;
610
- return (typeof message.id === "string" &&
611
- typeof message.role === "string" &&
612
- Array.isArray(message.content));
613
- }
614
- function firstText(message) {
615
- return message.content.find((part) => part.type === "text")?.text;
616
- }
617
- /** Session IDs name journal and media files; keep them path-safe up front. */
618
- function isSessionId(value) {
619
- return value !== "." && value !== ".." && /^[a-zA-Z0-9._-]+$/u.test(value);
620
- }
621
- function mediaUrl(agentId, sessionId, assetId) {
622
- return `media/${encodeURIComponent(sessionId)}/${encodeURIComponent(assetId)}`;
623
- }
624
- function normalizeBasePath(value) {
625
- if (!value || value === "/")
626
- return "";
627
- if (!value.startsWith("/") || value.endsWith("/"))
628
- throw new Error("basePath must start with / and must not end with /.");
629
- return value;
630
- }
631
- /** Public mount prefix for this request, derived without hono/route Symbols. */
632
- function inferMountPath(context, routePath) {
633
- const pathname = new URL(context.req.url).pathname;
634
- const suffix = routePath.replace(/:([A-Za-z0-9_]+)/g, (_, key) => {
635
- const value = context.req.param(key);
636
- if (value === undefined)
637
- throw new Error(`Unable to infer Runtime mount path from ${pathname}. Pass basePath matching the Hono mount.`);
638
- return value;
639
- });
640
- if (suffix !== "/" && pathname.endsWith(suffix)) {
641
- const base = pathname.slice(0, -suffix.length);
642
- return base === "" ? "/" : base;
643
- }
644
- if (pathname === suffix || `${pathname}/` === suffix)
645
- return "/";
646
- throw new Error(`Unable to infer Runtime mount path from ${pathname}. Pass basePath matching the Hono mount.`);
647
- }
@@ -1,10 +0,0 @@
1
- import type { BuiltAgent } from "@nylorun/core/define";
2
- import { setDefaultRuntime } from "./default.js";
3
- import type { OpenSessionOptions, SessionHandle } from "./handle.js";
4
- export { setDefaultRuntime };
5
- export type { OpenSessionOptions, SessionHandle };
6
- /** Open-or-create a local session with an agent (bound to the default Runtime). */
7
- export declare function openSession(agent: BuiltAgent<any, any>, options?: OpenSessionOptions): SessionHandle;
8
- export declare function listSessions(agentId: string): Promise<readonly import("../sessions/store.js").SessionSummary[]>;
9
- export declare function getSession(agentId: string, sessionId: string): Promise<import("../sessions/store.js").StoredSession | undefined>;
10
- export declare function deleteSession(agentId: string, sessionId: string): Promise<boolean>;
@@ -1,15 +0,0 @@
1
- import { getDefaultRuntime, setDefaultRuntime, } from "./default.js";
2
- export { setDefaultRuntime };
3
- /** Open-or-create a local session with an agent (bound to the default Runtime). */
4
- export function openSession(agent, options) {
5
- return getDefaultRuntime().openSession(agent, options);
6
- }
7
- export async function listSessions(agentId) {
8
- return getDefaultRuntime().listSessions(agentId);
9
- }
10
- export async function getSession(agentId, sessionId) {
11
- return getDefaultRuntime().getSession(agentId, sessionId);
12
- }
13
- export async function deleteSession(agentId, sessionId) {
14
- return getDefaultRuntime().deleteSession(agentId, sessionId);
15
- }
@@ -1,5 +0,0 @@
1
- import type { Runtime } from "../server/host.js";
2
- /** Wired from `server/host.ts` after `Runtime` is defined (avoids init cycles). */
3
- export declare function installDefaultRuntimeFactory(factory: () => Runtime): void;
4
- export declare function setDefaultRuntime(runtime: Runtime | undefined): void;
5
- export declare function getDefaultRuntime(): Runtime;