@agentuity/runtime 0.0.104 → 0.0.106

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 (125) hide show
  1. package/README.md +61 -35
  2. package/dist/_context.d.ts +2 -1
  3. package/dist/_context.d.ts.map +1 -1
  4. package/dist/_context.js +1 -0
  5. package/dist/_context.js.map +1 -1
  6. package/dist/_metadata.d.ts +4 -0
  7. package/dist/_metadata.d.ts.map +1 -1
  8. package/dist/_metadata.js +28 -1
  9. package/dist/_metadata.js.map +1 -1
  10. package/dist/_server.d.ts +1 -1
  11. package/dist/_server.d.ts.map +1 -1
  12. package/dist/_server.js +4 -1
  13. package/dist/_server.js.map +1 -1
  14. package/dist/_services.d.ts +2 -1
  15. package/dist/_services.d.ts.map +1 -1
  16. package/dist/_services.js +11 -2
  17. package/dist/_services.js.map +1 -1
  18. package/dist/_standalone.d.ts +2 -1
  19. package/dist/_standalone.d.ts.map +1 -1
  20. package/dist/_standalone.js +1 -0
  21. package/dist/_standalone.js.map +1 -1
  22. package/dist/_tokens.d.ts +9 -1
  23. package/dist/_tokens.d.ts.map +1 -1
  24. package/dist/_tokens.js +5 -8
  25. package/dist/_tokens.js.map +1 -1
  26. package/dist/agent.d.ts +26 -2
  27. package/dist/agent.d.ts.map +1 -1
  28. package/dist/agent.js +10 -0
  29. package/dist/agent.js.map +1 -1
  30. package/dist/app.d.ts +7 -3
  31. package/dist/app.d.ts.map +1 -1
  32. package/dist/app.js.map +1 -1
  33. package/dist/bun-s3-patch.d.ts +26 -0
  34. package/dist/bun-s3-patch.d.ts.map +1 -0
  35. package/dist/bun-s3-patch.js +65 -0
  36. package/dist/bun-s3-patch.js.map +1 -0
  37. package/dist/handlers/cron.d.ts +47 -0
  38. package/dist/handlers/cron.d.ts.map +1 -0
  39. package/dist/handlers/cron.js +49 -0
  40. package/dist/handlers/cron.js.map +1 -0
  41. package/dist/handlers/index.d.ts +5 -0
  42. package/dist/handlers/index.d.ts.map +1 -0
  43. package/dist/handlers/index.js +5 -0
  44. package/dist/handlers/index.js.map +1 -0
  45. package/dist/handlers/sse.d.ts +74 -0
  46. package/dist/handlers/sse.d.ts.map +1 -0
  47. package/dist/handlers/sse.js +70 -0
  48. package/dist/handlers/sse.js.map +1 -0
  49. package/dist/handlers/stream.d.ts +52 -0
  50. package/dist/handlers/stream.d.ts.map +1 -0
  51. package/dist/handlers/stream.js +75 -0
  52. package/dist/handlers/stream.js.map +1 -0
  53. package/dist/handlers/websocket.d.ts +49 -0
  54. package/dist/handlers/websocket.d.ts.map +1 -0
  55. package/dist/handlers/websocket.js +130 -0
  56. package/dist/handlers/websocket.js.map +1 -0
  57. package/dist/index.d.ts +2 -1
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +4 -2
  60. package/dist/index.js.map +1 -1
  61. package/dist/middleware.d.ts +1 -1
  62. package/dist/middleware.d.ts.map +1 -1
  63. package/dist/middleware.js +8 -6
  64. package/dist/middleware.js.map +1 -1
  65. package/dist/otel/logger.d.ts +1 -4
  66. package/dist/otel/logger.d.ts.map +1 -1
  67. package/dist/otel/logger.js +11 -2
  68. package/dist/otel/logger.js.map +1 -1
  69. package/dist/router.d.ts +46 -236
  70. package/dist/router.d.ts.map +1 -1
  71. package/dist/router.js +82 -349
  72. package/dist/router.js.map +1 -1
  73. package/dist/services/sandbox/http.d.ts +13 -0
  74. package/dist/services/sandbox/http.d.ts.map +1 -0
  75. package/dist/services/sandbox/http.js +130 -0
  76. package/dist/services/sandbox/http.js.map +1 -0
  77. package/dist/services/sandbox/index.d.ts +2 -0
  78. package/dist/services/sandbox/index.d.ts.map +1 -0
  79. package/dist/services/sandbox/index.js +2 -0
  80. package/dist/services/sandbox/index.js.map +1 -0
  81. package/dist/services/session/http.d.ts +12 -1
  82. package/dist/services/session/http.d.ts.map +1 -1
  83. package/dist/services/session/http.js +31 -1
  84. package/dist/services/session/http.js.map +1 -1
  85. package/dist/services/thread/local.d.ts.map +1 -1
  86. package/dist/services/thread/local.js +7 -6
  87. package/dist/services/thread/local.js.map +1 -1
  88. package/dist/session.d.ts +35 -8
  89. package/dist/session.d.ts.map +1 -1
  90. package/dist/session.js +25 -24
  91. package/dist/session.js.map +1 -1
  92. package/dist/workbench.d.ts +6 -2
  93. package/dist/workbench.d.ts.map +1 -1
  94. package/dist/workbench.js +40 -34
  95. package/dist/workbench.js.map +1 -1
  96. package/package.json +5 -7
  97. package/src/_context.ts +2 -0
  98. package/src/_metadata.ts +37 -1
  99. package/src/_server.ts +4 -1
  100. package/src/_services.ts +12 -2
  101. package/src/_standalone.ts +7 -1
  102. package/src/_tokens.ts +5 -9
  103. package/src/agent.ts +40 -1
  104. package/src/app.ts +9 -2
  105. package/src/bun-s3-patch.ts +91 -0
  106. package/src/handlers/cron.ts +70 -0
  107. package/src/handlers/index.ts +4 -0
  108. package/src/handlers/sse.ts +118 -0
  109. package/src/handlers/stream.ts +86 -0
  110. package/src/handlers/websocket.ts +153 -0
  111. package/src/index.ts +18 -3
  112. package/src/middleware.ts +8 -10
  113. package/src/otel/logger.ts +13 -2
  114. package/src/router.ts +110 -597
  115. package/src/services/sandbox/http.ts +215 -0
  116. package/src/services/sandbox/index.ts +1 -0
  117. package/src/services/session/http.ts +39 -1
  118. package/src/services/thread/local.ts +8 -5
  119. package/src/session.ts +58 -32
  120. package/src/workbench.ts +41 -39
  121. package/dist/io/email.d.ts +0 -77
  122. package/dist/io/email.d.ts.map +0 -1
  123. package/dist/io/email.js +0 -162
  124. package/dist/io/email.js.map +0 -1
  125. package/src/io/email.ts +0 -191
@@ -0,0 +1,118 @@
1
+ import type { Context, Handler } from 'hono';
2
+ import { streamSSE as honoStreamSSE } from 'hono/streaming';
3
+ import { getAgentAsyncLocalStorage } from '../_context';
4
+ import type { Env } from '../app';
5
+
6
+ /**
7
+ * SSE message format for Server-Sent Events.
8
+ */
9
+ export interface SSEMessage {
10
+ data: string;
11
+ event?: string;
12
+ id?: string;
13
+ retry?: number;
14
+ }
15
+
16
+ /**
17
+ * SSE stream interface for writing Server-Sent Events.
18
+ */
19
+ export interface SSEStream {
20
+ /**
21
+ * Write a simple value as SSE data.
22
+ * Strings, numbers, and booleans are converted to string data.
23
+ * Objects are passed through as SSE message format.
24
+ */
25
+ write: (data: string | number | boolean | SSEMessage) => Promise<void>;
26
+ /**
27
+ * Write a properly formatted SSE message.
28
+ */
29
+ writeSSE: (message: SSEMessage) => Promise<void>;
30
+ /**
31
+ * Register a callback for when the client aborts the connection.
32
+ */
33
+ onAbort: (callback: () => void) => void;
34
+ /**
35
+ * Close the SSE stream.
36
+ */
37
+ close: () => void;
38
+ }
39
+
40
+ /**
41
+ * Handler function for SSE connections.
42
+ * Receives the Hono context and SSE stream with a flattened signature.
43
+ */
44
+ export type SSEHandler<E extends Env = Env> = (
45
+ c: Context<E>,
46
+ stream: SSEStream
47
+ ) => void | Promise<void>;
48
+
49
+ /**
50
+ * Creates an SSE (Server-Sent Events) middleware for streaming updates to clients.
51
+ *
52
+ * Use with router.get() to create an SSE endpoint:
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * import { createRouter, sse } from '@agentuity/runtime';
57
+ *
58
+ * const router = createRouter();
59
+ *
60
+ * router.get('/events', sse((c, stream) => {
61
+ * let count = 0;
62
+ * const interval = setInterval(() => {
63
+ * stream.writeSSE({
64
+ * data: `Event ${++count}`,
65
+ * event: 'update'
66
+ * });
67
+ * if (count >= 10) {
68
+ * clearInterval(interval);
69
+ * stream.close();
70
+ * }
71
+ * }, 1000);
72
+ *
73
+ * stream.onAbort(() => {
74
+ * clearInterval(interval);
75
+ * });
76
+ * }));
77
+ * ```
78
+ *
79
+ * @param handler - Handler function receiving context and SSE stream
80
+ * @returns Hono handler for SSE streaming
81
+ */
82
+ export function sse<E extends Env = Env>(handler: SSEHandler<E>): Handler<E> {
83
+ return (c: Context<E>) => {
84
+ const asyncLocalStorage = getAgentAsyncLocalStorage();
85
+ const capturedContext = asyncLocalStorage.getStore();
86
+
87
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
88
+ return honoStreamSSE(c, async (stream: any) => {
89
+ const wrappedStream: SSEStream = {
90
+ write: async (data) => {
91
+ if (
92
+ typeof data === 'string' ||
93
+ typeof data === 'number' ||
94
+ typeof data === 'boolean'
95
+ ) {
96
+ return stream.writeSSE({ data: String(data) });
97
+ } else if (typeof data === 'object' && data !== null) {
98
+ return stream.writeSSE(data);
99
+ }
100
+ return stream.writeSSE({ data: String(data) });
101
+ },
102
+ writeSSE: stream.writeSSE.bind(stream),
103
+ onAbort: stream.onAbort.bind(stream),
104
+ close: stream.close?.bind(stream) ?? (() => {}),
105
+ };
106
+
107
+ const runInContext = async () => {
108
+ await handler(c, wrappedStream);
109
+ };
110
+
111
+ if (capturedContext) {
112
+ await asyncLocalStorage.run(capturedContext, runInContext);
113
+ } else {
114
+ await runInContext();
115
+ }
116
+ });
117
+ };
118
+ }
@@ -0,0 +1,86 @@
1
+ import type { Context, Handler } from 'hono';
2
+ import { stream as honoStream } from 'hono/streaming';
3
+ import { getAgentAsyncLocalStorage } from '../_context';
4
+ import type { Env } from '../app';
5
+
6
+ /**
7
+ * Handler function for streaming responses.
8
+ * Returns a ReadableStream that will be piped to the response.
9
+ */
10
+ export type StreamHandler<E extends Env = Env> = (
11
+ c: Context<E>
12
+ ) => ReadableStream<Uint8Array | string> | Promise<ReadableStream<Uint8Array | string>>;
13
+
14
+ /**
15
+ * Creates a streaming middleware for returning ReadableStream responses.
16
+ *
17
+ * Use with router.post() (or any HTTP method) to create a streaming endpoint:
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * import { createRouter, stream } from '@agentuity/runtime';
22
+ *
23
+ * const router = createRouter();
24
+ *
25
+ * router.post('/events', stream((c) => {
26
+ * return new ReadableStream({
27
+ * start(controller) {
28
+ * controller.enqueue('event 1\n');
29
+ * controller.enqueue('event 2\n');
30
+ * controller.close();
31
+ * }
32
+ * });
33
+ * }));
34
+ * ```
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * // Async stream with data from request body
39
+ * router.post('/process', stream(async (c) => {
40
+ * const body = await c.req.json();
41
+ *
42
+ * return new ReadableStream({
43
+ * async start(controller) {
44
+ * for (const item of body.items) {
45
+ * controller.enqueue(`Processing: ${item}\n`);
46
+ * await new Promise(r => setTimeout(r, 100));
47
+ * }
48
+ * controller.close();
49
+ * }
50
+ * });
51
+ * }));
52
+ * ```
53
+ *
54
+ * @param handler - Handler function returning a ReadableStream
55
+ * @returns Hono handler for streaming response
56
+ */
57
+ export function stream<E extends Env = Env>(handler: StreamHandler<E>): Handler<E> {
58
+ return (c: Context<E>) => {
59
+ const asyncLocalStorage = getAgentAsyncLocalStorage();
60
+ const capturedContext = asyncLocalStorage.getStore();
61
+
62
+ c.header('Content-Type', 'application/octet-stream');
63
+
64
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
65
+ return honoStream(c, async (s: any) => {
66
+ const runInContext = async () => {
67
+ try {
68
+ let streamResult = handler(c);
69
+ if (streamResult instanceof Promise) {
70
+ streamResult = await streamResult;
71
+ }
72
+ await s.pipe(streamResult);
73
+ } catch (err) {
74
+ c.var.logger?.error('Stream error:', err);
75
+ throw err;
76
+ }
77
+ };
78
+
79
+ if (capturedContext) {
80
+ await asyncLocalStorage.run(capturedContext, runInContext);
81
+ } else {
82
+ await runInContext();
83
+ }
84
+ });
85
+ };
86
+ }
@@ -0,0 +1,153 @@
1
+ import type { Context, MiddlewareHandler } from 'hono';
2
+ import { upgradeWebSocket } from 'hono/bun';
3
+ import { getAgentAsyncLocalStorage } from '../_context';
4
+ import type { Env } from '../app';
5
+
6
+ /**
7
+ * WebSocket connection interface for handling WebSocket events.
8
+ */
9
+ export interface WebSocketConnection {
10
+ onOpen: (handler: (event: Event) => void | Promise<void>) => void;
11
+ onMessage: (handler: (event: MessageEvent) => void | Promise<void>) => void;
12
+ onClose: (handler: (event: CloseEvent) => void | Promise<void>) => void;
13
+ send: (data: string | ArrayBuffer | Uint8Array) => void;
14
+ }
15
+
16
+ /**
17
+ * Handler function for WebSocket connections.
18
+ * Receives the Hono context and WebSocket connection with a flattened signature.
19
+ */
20
+ export type WebSocketHandler<E extends Env = Env> = (
21
+ c: Context<E>,
22
+ ws: WebSocketConnection
23
+ ) => void | Promise<void>;
24
+
25
+ /**
26
+ * Creates a WebSocket middleware for handling WebSocket connections.
27
+ *
28
+ * Use with router.get() to create a WebSocket endpoint:
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * import { createRouter, websocket } from '@agentuity/runtime';
33
+ *
34
+ * const router = createRouter();
35
+ *
36
+ * router.get('/ws', websocket((c, ws) => {
37
+ * ws.onOpen(() => {
38
+ * c.var.logger.info('WebSocket opened');
39
+ * ws.send('Welcome!');
40
+ * });
41
+ *
42
+ * ws.onMessage((event) => {
43
+ * c.var.logger.info('Received:', event.data);
44
+ * ws.send('Echo: ' + event.data);
45
+ * });
46
+ *
47
+ * ws.onClose(() => {
48
+ * c.var.logger.info('WebSocket closed');
49
+ * });
50
+ * }));
51
+ * ```
52
+ *
53
+ * @param handler - Handler function receiving context and WebSocket connection
54
+ * @returns Hono middleware handler for WebSocket upgrade
55
+ */
56
+ export function websocket<E extends Env = Env>(handler: WebSocketHandler<E>): MiddlewareHandler<E> {
57
+ const wsHandler = upgradeWebSocket((c: Context<E>) => {
58
+ let openHandler: ((event: Event) => void | Promise<void>) | undefined;
59
+ let messageHandler: ((event: MessageEvent) => void | Promise<void>) | undefined;
60
+ let closeHandler: ((event: CloseEvent) => void | Promise<void>) | undefined;
61
+ let initialized = false;
62
+
63
+ const asyncLocalStorage = getAgentAsyncLocalStorage();
64
+ const capturedContext = asyncLocalStorage.getStore();
65
+
66
+ const wsConnection: WebSocketConnection = {
67
+ onOpen: (h) => {
68
+ openHandler = h;
69
+ },
70
+ onMessage: (h) => {
71
+ messageHandler = h;
72
+ },
73
+ onClose: (h) => {
74
+ closeHandler = h;
75
+ },
76
+ send: (_data: string | ArrayBuffer | Uint8Array) => {
77
+ // This will be bound to the actual ws in the handlers
78
+ },
79
+ };
80
+
81
+ const runHandler = () => {
82
+ if (capturedContext) {
83
+ asyncLocalStorage.run(capturedContext, () => handler(c, wsConnection));
84
+ } else {
85
+ handler(c, wsConnection);
86
+ }
87
+ initialized = true;
88
+ };
89
+
90
+ runHandler();
91
+
92
+ return {
93
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
94
+ onOpen: async (event: Event, ws: any) => {
95
+ try {
96
+ wsConnection.send = (data) => ws.send(data);
97
+
98
+ if (openHandler) {
99
+ const h = openHandler;
100
+ if (capturedContext) {
101
+ await asyncLocalStorage.run(capturedContext, () => h(event));
102
+ } else {
103
+ await h(event);
104
+ }
105
+ }
106
+ } catch (err) {
107
+ c.var.logger?.error('WebSocket onOpen error:', err);
108
+ throw err;
109
+ }
110
+ },
111
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
112
+ onMessage: async (event: MessageEvent, ws: any) => {
113
+ try {
114
+ if (!initialized) {
115
+ wsConnection.send = (data) => ws.send(data);
116
+ runHandler();
117
+ }
118
+ if (messageHandler) {
119
+ const h = messageHandler;
120
+ if (capturedContext) {
121
+ await asyncLocalStorage.run(capturedContext, () => h(event));
122
+ } else {
123
+ await h(event);
124
+ }
125
+ }
126
+ } catch (err) {
127
+ c.var.logger?.error('WebSocket onMessage error:', err);
128
+ throw err;
129
+ }
130
+ },
131
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
132
+ onClose: async (event: CloseEvent, _ws: any) => {
133
+ try {
134
+ if (closeHandler) {
135
+ const h = closeHandler;
136
+ if (capturedContext) {
137
+ await asyncLocalStorage.run(capturedContext, () => h(event));
138
+ } else {
139
+ await h(event);
140
+ }
141
+ }
142
+ } catch (err) {
143
+ c.var.logger?.error('WebSocket onClose error:', err);
144
+ }
145
+ },
146
+ };
147
+ });
148
+
149
+ const middleware: MiddlewareHandler<E> = (c, next) =>
150
+ (wsHandler as unknown as MiddlewareHandler<E>)(c, next);
151
+
152
+ return middleware;
153
+ }
package/src/index.ts CHANGED
@@ -65,6 +65,21 @@ export { registerDevModeRoutes } from './devmode';
65
65
  // router.ts exports
66
66
  export { type HonoEnv, type WebSocketConnection, createRouter } from './router';
67
67
 
68
+ // protocol handler exports (websocket, sse, stream, cron)
69
+ export {
70
+ websocket,
71
+ type WebSocketHandler,
72
+ sse,
73
+ type SSEMessage,
74
+ type SSEStream,
75
+ type SSEHandler,
76
+ stream,
77
+ type StreamHandler,
78
+ cron,
79
+ type CronHandler,
80
+ type CronMetadata,
81
+ } from './handlers';
82
+
68
83
  // eval.ts exports
69
84
  export {
70
85
  EvalHandlerResultSchema,
@@ -143,9 +158,6 @@ export {
143
158
  type InvokeOptions,
144
159
  } from './_standalone';
145
160
 
146
- // io/email exports
147
- export { Email, parseEmail } from './io/email';
148
-
149
161
  // services/evalrun exports
150
162
  export {
151
163
  HTTPEvalRunEventProvider,
@@ -204,3 +216,6 @@ export interface AppState {}
204
216
  // This allows generated code to import from @agentuity/runtime instead of having
205
217
  // a direct dependency on @agentuity/server
206
218
  export { bootstrapRuntimeEnv, type RuntimeBootstrapOptions } from '@agentuity/server';
219
+
220
+ // bun-s3-patch.ts exports
221
+ export { patchBunS3ForStorageDev, isAgentuityStorageEndpoint } from './bun-s3-patch';
package/src/middleware.ts CHANGED
@@ -38,6 +38,7 @@ export const AGENT_CONTEXT_PROPERTIES = [
38
38
  'kv',
39
39
  'stream',
40
40
  'vector',
41
+ 'sandbox',
41
42
  'state',
42
43
  'thread',
43
44
  'session',
@@ -94,6 +95,7 @@ export function createBaseMiddleware(config: MiddlewareConfig) {
94
95
  c.set('kv', services.kv);
95
96
  c.set('stream', services.stream);
96
97
  c.set('vector', services.vector);
98
+ c.set('sandbox', services.sandbox);
97
99
 
98
100
  installContextPropertyHelpers(c);
99
101
 
@@ -278,17 +280,17 @@ export function createOtelMiddleware() {
278
280
  (c as any).set('trigger', 'api');
279
281
 
280
282
  // Send session start event (so evalruns can reference this session)
283
+ // The provider decides whether to send based on available data (orgId, projectId, etc.)
281
284
  const sessionEventProvider = getSessionEventProvider();
282
- const shouldSendSession = !!(orgId && projectId);
283
- if (shouldSendSession && sessionEventProvider) {
285
+ if (sessionEventProvider) {
284
286
  try {
285
287
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
286
288
  const routeId = (c as any).var?.routeId || '';
287
289
  await sessionEventProvider.start({
288
290
  id: sessionId,
289
291
  threadId: thread.id,
290
- orgId,
291
- projectId,
292
+ orgId: orgId || '',
293
+ projectId: projectId || '',
292
294
  deploymentId: deploymentId || undefined,
293
295
  devmode: isDevMode,
294
296
  trigger: 'api',
@@ -322,12 +324,8 @@ export function createOtelMiddleware() {
322
324
  throw ex;
323
325
  } finally {
324
326
  // Send session complete event
325
- internal.info(
326
- '[session] shouldSendSession: %s, hasSessionEventProvider: %s',
327
- shouldSendSession,
328
- !!sessionEventProvider
329
- );
330
- if (shouldSendSession && sessionEventProvider) {
327
+ // The provider decides whether to actually send based on its requirements
328
+ if (sessionEventProvider) {
331
329
  try {
332
330
  const userData = session.serializeUserData();
333
331
  internal.info(
@@ -5,9 +5,20 @@ import type { Logger } from '../logger';
5
5
  import ConsoleLogger from '../logger/console';
6
6
 
7
7
  /**
8
- * Reference to the original console object before patching
8
+ * Reference to the original console object before patching.
9
+ * We use a global symbol to ensure we only capture the original console once,
10
+ * preventing double-patching on hot reload.
9
11
  */
10
- export const __originalConsole = Object.create(console); // save the original console before we patch it
12
+ const ORIGINAL_CONSOLE_KEY = Symbol.for('agentuity.originalConsole');
13
+
14
+ // Check if we've already saved the original console (prevents double-patching on reload)
15
+ const existingOriginal = (globalThis as Record<symbol, Console>)[ORIGINAL_CONSOLE_KEY];
16
+ export const __originalConsole: Console = existingOriginal ?? Object.create(console);
17
+
18
+ // Save to global if not already saved
19
+ if (!existingOriginal) {
20
+ (globalThis as Record<symbol, Console>)[ORIGINAL_CONSOLE_KEY] = __originalConsole;
21
+ }
11
22
 
12
23
  export class OtelLogger implements Logger {
13
24
  private readonly delegate: LogsAPI.Logger;