@agentuity/runtime 0.0.60 → 0.0.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_context.d.ts +11 -7
- package/dist/_context.d.ts.map +1 -1
- package/dist/_context.js +9 -2
- package/dist/_context.js.map +1 -1
- package/dist/_server.d.ts +4 -2
- package/dist/_server.d.ts.map +1 -1
- package/dist/_server.js +79 -31
- package/dist/_server.js.map +1 -1
- package/dist/_services.d.ts +1 -1
- package/dist/_services.d.ts.map +1 -1
- package/dist/_services.js +4 -2
- package/dist/_services.js.map +1 -1
- package/dist/_waituntil.d.ts.map +1 -1
- package/dist/_waituntil.js +5 -2
- package/dist/_waituntil.js.map +1 -1
- package/dist/agent.d.ts +647 -19
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +55 -6
- package/dist/agent.js.map +1 -1
- package/dist/app.d.ts +205 -28
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +181 -13
- package/dist/app.js.map +1 -1
- package/dist/index.d.ts +41 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/io/email.d.ts.map +1 -1
- package/dist/io/email.js +11 -3
- package/dist/io/email.js.map +1 -1
- package/dist/router.d.ts +282 -32
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +110 -35
- package/dist/router.js.map +1 -1
- package/dist/services/evalrun/http.d.ts.map +1 -1
- package/dist/services/evalrun/http.js +7 -5
- package/dist/services/evalrun/http.js.map +1 -1
- package/dist/services/local/_util.d.ts.map +1 -1
- package/dist/services/local/_util.js +3 -1
- package/dist/services/local/_util.js.map +1 -1
- package/dist/services/session/http.d.ts.map +1 -1
- package/dist/services/session/http.js +4 -3
- package/dist/services/session/http.js.map +1 -1
- package/dist/session.d.ts +308 -6
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +331 -23
- package/dist/session.js.map +1 -1
- package/package.json +8 -5
- package/src/_context.ts +37 -9
- package/src/_server.ts +96 -36
- package/src/_services.ts +9 -2
- package/src/_waituntil.ts +13 -2
- package/src/agent.ts +856 -68
- package/src/app.ts +238 -38
- package/src/index.ts +42 -2
- package/src/io/email.ts +23 -5
- package/src/router.ts +359 -83
- package/src/services/evalrun/http.ts +15 -4
- package/src/services/local/_util.ts +7 -1
- package/src/services/session/http.ts +5 -2
- package/src/session.ts +686 -26
package/src/_server.ts
CHANGED
|
@@ -45,6 +45,8 @@ let globalRouterInstance: Hono<Env> | null = null;
|
|
|
45
45
|
|
|
46
46
|
let globalLogger: Logger | null = null;
|
|
47
47
|
let globalTracer: Tracer | null = null;
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
49
|
+
let globalAppState: any = null;
|
|
48
50
|
|
|
49
51
|
export function getServer() {
|
|
50
52
|
return globalServerInstance;
|
|
@@ -64,6 +66,10 @@ export function getTracer() {
|
|
|
64
66
|
return globalTracer;
|
|
65
67
|
}
|
|
66
68
|
|
|
69
|
+
export function getAppState() {
|
|
70
|
+
return globalAppState;
|
|
71
|
+
}
|
|
72
|
+
|
|
67
73
|
function isDevelopment(): boolean {
|
|
68
74
|
const devmode = runtimeConfig.isDevMode();
|
|
69
75
|
const environment = runtimeConfig.getEnvironment();
|
|
@@ -131,11 +137,27 @@ export function privateContext<E extends Env>(c: HonoContext<E>) {
|
|
|
131
137
|
return c as unknown as HonoContext<{ Variables: PrivateVariables }>;
|
|
132
138
|
}
|
|
133
139
|
|
|
134
|
-
|
|
140
|
+
let startupPromise: Promise<void> | undefined;
|
|
141
|
+
let startupPromiseResolver: (() => void) | undefined;
|
|
142
|
+
let isShutdown = false;
|
|
143
|
+
|
|
144
|
+
export const notifyReady = () => {
|
|
145
|
+
startupPromiseResolver?.();
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export const createServer = async <TAppState>(
|
|
149
|
+
router: Hono<Env<TAppState>>,
|
|
150
|
+
appStateInitializer: () => Promise<TAppState>,
|
|
151
|
+
config?: AppConfig<TAppState>
|
|
152
|
+
): Promise<[Bun.Server<BunWebSocketData>, TAppState]> => {
|
|
135
153
|
if (globalServerInstance) {
|
|
136
|
-
return globalServerInstance;
|
|
154
|
+
return [globalServerInstance, globalAppState as TAppState];
|
|
137
155
|
}
|
|
138
156
|
|
|
157
|
+
const { promise, resolve } = Promise.withResolvers<void>();
|
|
158
|
+
startupPromise = promise;
|
|
159
|
+
startupPromiseResolver = resolve;
|
|
160
|
+
|
|
139
161
|
runtimeConfig.init();
|
|
140
162
|
|
|
141
163
|
const logLevel = process.env.AGENTUITY_LOG_LEVEL || 'info';
|
|
@@ -153,22 +175,13 @@ export const createServer = <E extends Env>(router: Hono<E>, config?: AppConfig)
|
|
|
153
175
|
// Create services (may return local router)
|
|
154
176
|
const servicesResult = createServices(otel.logger, config, serverUrl);
|
|
155
177
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
development: isDevelopment(),
|
|
159
|
-
fetch: router.fetch,
|
|
160
|
-
idleTimeout: 0,
|
|
161
|
-
port,
|
|
162
|
-
websocket,
|
|
163
|
-
});
|
|
178
|
+
// Create the App State
|
|
179
|
+
globalAppState = await appStateInitializer();
|
|
164
180
|
|
|
165
181
|
globalRouterInstance = router as unknown as Hono<Env>;
|
|
166
|
-
globalServerInstance = server;
|
|
167
182
|
globalLogger = otel.logger;
|
|
168
183
|
globalTracer = otel.tracer;
|
|
169
184
|
|
|
170
|
-
let isShutdown = false;
|
|
171
|
-
|
|
172
185
|
router.onError((error, _c) => {
|
|
173
186
|
if (error instanceof HTTPException) {
|
|
174
187
|
otel.logger.error('HTTP Error: %s (%d)', error.cause, error.status);
|
|
@@ -178,42 +191,45 @@ export const createServer = <E extends Env>(router: Hono<E>, config?: AppConfig)
|
|
|
178
191
|
otel.logger.error('Unauthenticated Error: %s', error.message);
|
|
179
192
|
return new Response(error.message, { status: 501 });
|
|
180
193
|
}
|
|
181
|
-
if (
|
|
182
|
-
error
|
|
183
|
-
('statusCode' in error && typeof error.statusCode === 'number')
|
|
184
|
-
) {
|
|
185
|
-
const serviceError = error as ServiceException;
|
|
194
|
+
if (error instanceof ServiceException) {
|
|
195
|
+
const serviceError = error as InstanceType<typeof ServiceException>;
|
|
186
196
|
otel.logger.error(
|
|
187
|
-
'Service Exception: %s (%s returned HTTP status code: %d)',
|
|
197
|
+
'Service Exception: %s (%s returned HTTP status code: %d%s)',
|
|
188
198
|
error.message,
|
|
189
199
|
serviceError.url,
|
|
190
|
-
serviceError.statusCode
|
|
200
|
+
serviceError.statusCode,
|
|
201
|
+
serviceError.sessionId ? `, session: ${serviceError.sessionId}` : ''
|
|
191
202
|
);
|
|
192
203
|
return new Response(error.message, {
|
|
193
204
|
status: serviceError.statusCode ?? 500,
|
|
194
205
|
});
|
|
195
206
|
}
|
|
196
|
-
otel.logger.error('Unhandled Server Error: %s',
|
|
207
|
+
otel.logger.error('Unhandled Server Error: %s', error);
|
|
197
208
|
return new Response('Internal Server Error', { status: 500 });
|
|
198
209
|
});
|
|
199
210
|
|
|
200
|
-
const
|
|
201
|
-
|
|
211
|
+
const blockOnStartup = async () => {
|
|
212
|
+
// block until completing the setup if still running
|
|
213
|
+
if (startupPromise) {
|
|
214
|
+
await startupPromise;
|
|
215
|
+
startupPromise = undefined;
|
|
216
|
+
startupPromiseResolver = undefined;
|
|
217
|
+
}
|
|
218
|
+
};
|
|
202
219
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
.catch(reject);
|
|
220
|
+
router.get('/_health', async (c) => {
|
|
221
|
+
await blockOnStartup();
|
|
222
|
+
return c.text('OK');
|
|
207
223
|
});
|
|
208
224
|
|
|
209
225
|
router.use(async (c, next) => {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
initPromise = undefined;
|
|
213
|
-
}
|
|
226
|
+
await blockOnStartup();
|
|
227
|
+
|
|
214
228
|
c.set('logger', otel.logger);
|
|
215
229
|
c.set('tracer', otel.tracer);
|
|
216
230
|
c.set('meter', otel.meter);
|
|
231
|
+
c.set('app', globalAppState);
|
|
232
|
+
|
|
217
233
|
const isWebSocket = c.req.header('upgrade')?.toLowerCase() === 'websocket';
|
|
218
234
|
const skipLogging = c.req.path.startsWith('/_agentuity/');
|
|
219
235
|
const started = performance.now();
|
|
@@ -255,7 +271,6 @@ export const createServer = <E extends Env>(router: Hono<E>, config?: AppConfig)
|
|
|
255
271
|
})
|
|
256
272
|
);
|
|
257
273
|
|
|
258
|
-
router.get('/_health', (c) => c.text('OK'));
|
|
259
274
|
router.route('/_agentuity', createAgentuityAPIs());
|
|
260
275
|
|
|
261
276
|
// Mount local storage router if using local services
|
|
@@ -275,7 +290,7 @@ export const createServer = <E extends Env>(router: Hono<E>, config?: AppConfig)
|
|
|
275
290
|
// in production there is no .agentuity folder
|
|
276
291
|
routeMappingPath = join(projectRoot, '.routemapping.json');
|
|
277
292
|
} else {
|
|
278
|
-
routeMappingPath = join(
|
|
293
|
+
routeMappingPath = join(import.meta.dirname, '..', '.routemapping.json');
|
|
279
294
|
}
|
|
280
295
|
const file = Bun.file(routeMappingPath);
|
|
281
296
|
if (!(await file.exists())) {
|
|
@@ -337,7 +352,33 @@ export const createServer = <E extends Env>(router: Hono<E>, config?: AppConfig)
|
|
|
337
352
|
process.exit(1);
|
|
338
353
|
}, 5_000);
|
|
339
354
|
try {
|
|
340
|
-
|
|
355
|
+
// stop accepting new connections
|
|
356
|
+
if (globalServerInstance) {
|
|
357
|
+
await globalServerInstance.stop();
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// wait for idle
|
|
361
|
+
const shutdownStarted = Date.now();
|
|
362
|
+
otel.logger.debug('waiting for pending connections to complete');
|
|
363
|
+
while (Date.now() - shutdownStarted < 60_000 * 2) {
|
|
364
|
+
if ((globalServerInstance?.pendingRequests ?? 0) > 0) {
|
|
365
|
+
await Bun.sleep(1_000);
|
|
366
|
+
} else {
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
otel.logger.debug('no more pending connections');
|
|
371
|
+
|
|
372
|
+
// Run agent shutdowns first
|
|
373
|
+
const { runAgentShutdowns } = await import('./agent');
|
|
374
|
+
await runAgentShutdowns(globalAppState);
|
|
375
|
+
|
|
376
|
+
// Run app shutdown if provided
|
|
377
|
+
if (config?.shutdown && globalAppState) {
|
|
378
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
379
|
+
await config.shutdown(globalAppState as any);
|
|
380
|
+
}
|
|
381
|
+
|
|
341
382
|
await otel.shutdown();
|
|
342
383
|
otel.logger.debug('shutdown completed');
|
|
343
384
|
} finally {
|
|
@@ -373,13 +414,24 @@ export const createServer = <E extends Env>(router: Hono<E>, config?: AppConfig)
|
|
|
373
414
|
process.exit(1);
|
|
374
415
|
});
|
|
375
416
|
|
|
376
|
-
|
|
417
|
+
const server = Bun.serve({
|
|
418
|
+
hostname,
|
|
419
|
+
development: isDevelopment(),
|
|
420
|
+
fetch: router.fetch,
|
|
421
|
+
idleTimeout: 0,
|
|
422
|
+
port,
|
|
423
|
+
websocket,
|
|
424
|
+
id: null,
|
|
425
|
+
});
|
|
426
|
+
globalServerInstance = server;
|
|
427
|
+
|
|
428
|
+
return [server, globalAppState];
|
|
377
429
|
};
|
|
378
430
|
|
|
379
431
|
const createAgentuityAPIs = () => {
|
|
380
432
|
const router = new Hono<Env>();
|
|
381
433
|
router.get('idle', (c) => {
|
|
382
|
-
if (isIdle()) {
|
|
434
|
+
if (isIdle() || !isShutdown) {
|
|
383
435
|
return c.text('OK', { status: 200 });
|
|
384
436
|
}
|
|
385
437
|
return c.text('NO', { status: 200 });
|
|
@@ -485,11 +537,13 @@ const otelMiddleware = createMiddleware<Env>(async (c, next) => {
|
|
|
485
537
|
await threadProvider.save(thread);
|
|
486
538
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
487
539
|
if (shouldSendSession && canSendSessionEvents) {
|
|
540
|
+
const userData = session.serializeUserData();
|
|
488
541
|
sessionEventProvider
|
|
489
542
|
.complete({
|
|
490
543
|
id: sessionId,
|
|
491
544
|
statusCode: c.res.status,
|
|
492
545
|
agentIds: Array.from(agentIds),
|
|
546
|
+
userData,
|
|
493
547
|
})
|
|
494
548
|
.then(() => {})
|
|
495
549
|
.catch((ex) => c.var.logger.error(ex));
|
|
@@ -507,12 +561,14 @@ const otelMiddleware = createMiddleware<Env>(async (c, next) => {
|
|
|
507
561
|
});
|
|
508
562
|
c.var.logger.error(message);
|
|
509
563
|
if (shouldSendSession && canSendSessionEvents) {
|
|
564
|
+
const userData = session.serializeUserData();
|
|
510
565
|
sessionEventProvider
|
|
511
566
|
.complete({
|
|
512
567
|
id: sessionId,
|
|
513
568
|
statusCode: c.res.status,
|
|
514
569
|
error: message,
|
|
515
570
|
agentIds: Array.from(agentIds),
|
|
571
|
+
userData,
|
|
516
572
|
})
|
|
517
573
|
.then(() => {})
|
|
518
574
|
.catch((ex) => c.var.logger.error(ex));
|
|
@@ -524,11 +580,13 @@ const otelMiddleware = createMiddleware<Env>(async (c, next) => {
|
|
|
524
580
|
} else {
|
|
525
581
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
526
582
|
if (shouldSendSession && canSendSessionEvents) {
|
|
583
|
+
const userData = session.serializeUserData();
|
|
527
584
|
sessionEventProvider
|
|
528
585
|
.complete({
|
|
529
586
|
id: sessionId,
|
|
530
587
|
statusCode: c.res.status,
|
|
531
588
|
agentIds: Array.from(agentIds),
|
|
589
|
+
userData,
|
|
532
590
|
})
|
|
533
591
|
.then(() => {})
|
|
534
592
|
.catch((ex) => c.var.logger.error(ex));
|
|
@@ -545,12 +603,14 @@ const otelMiddleware = createMiddleware<Env>(async (c, next) => {
|
|
|
545
603
|
});
|
|
546
604
|
c.var.logger.error(message);
|
|
547
605
|
if (shouldSendSession && canSendSessionEvents) {
|
|
606
|
+
const userData = session.serializeUserData();
|
|
548
607
|
sessionEventProvider
|
|
549
608
|
.complete({
|
|
550
609
|
id: sessionId,
|
|
551
610
|
statusCode: c.res.status,
|
|
552
611
|
error: message,
|
|
553
612
|
agentIds: Array.from(agentIds),
|
|
613
|
+
userData,
|
|
554
614
|
})
|
|
555
615
|
.then(() => {})
|
|
556
616
|
.catch((ex) => c.var.logger.error(ex));
|
package/src/_services.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
type Logger,
|
|
16
16
|
type SessionEventProvider,
|
|
17
17
|
type EvalRunEventProvider,
|
|
18
|
+
StructuredError,
|
|
18
19
|
} from '@agentuity/core';
|
|
19
20
|
import { APIClient, createServerFetchAdapter, getServiceUrls } from '@agentuity/server';
|
|
20
21
|
import {
|
|
@@ -189,7 +190,13 @@ let evalRunEvent: EvalRunEventProvider;
|
|
|
189
190
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
190
191
|
let localRouter: any | null = null;
|
|
191
192
|
|
|
192
|
-
|
|
193
|
+
const ServerUrlMissingError = StructuredError(
|
|
194
|
+
'ServerUrlMissingError',
|
|
195
|
+
'serverUrl is required when using local services'
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
199
|
+
export function createServices(logger: Logger, config?: AppConfig<any>, serverUrl?: string) {
|
|
193
200
|
const authenticated = isAuthenticated();
|
|
194
201
|
const useLocal = config?.services?.useLocal ?? false;
|
|
195
202
|
adapter = createFetchAdapter(logger);
|
|
@@ -203,7 +210,7 @@ export function createServices(logger: Logger, config?: AppConfig, serverUrl?: s
|
|
|
203
210
|
const projectPath = normalizeProjectPath();
|
|
204
211
|
|
|
205
212
|
if (!serverUrl) {
|
|
206
|
-
throw new
|
|
213
|
+
throw new ServerUrlMissingError();
|
|
207
214
|
}
|
|
208
215
|
|
|
209
216
|
logger.info('Using local services (development only)');
|
package/src/_waituntil.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { context, SpanStatusCode, type Tracer, trace } from '@opentelemetry/api';
|
|
2
2
|
import type { Logger } from './logger';
|
|
3
3
|
import { internal } from './logger/internal';
|
|
4
|
+
import { StructuredError } from '@agentuity/core';
|
|
4
5
|
|
|
5
6
|
let running = 0;
|
|
6
7
|
|
|
@@ -13,6 +14,16 @@ export function hasWaitUntilPending(): boolean {
|
|
|
13
14
|
return running > 0;
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
const WaitUntilInvalidStateError = StructuredError(
|
|
18
|
+
'WaitUntilInvalidStateError',
|
|
19
|
+
'waitUntil cannot be called after waitUntilAll has been called'
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const WaitUntilAllInvalidStateError = StructuredError(
|
|
23
|
+
'WaitUntilAllInvalidStateError',
|
|
24
|
+
'waitUntilAll can only be called once per instance'
|
|
25
|
+
);
|
|
26
|
+
|
|
16
27
|
export default class WaitUntilHandler {
|
|
17
28
|
private promises: Promise<void>[];
|
|
18
29
|
private tracer: Tracer;
|
|
@@ -26,7 +37,7 @@ export default class WaitUntilHandler {
|
|
|
26
37
|
|
|
27
38
|
public waitUntil(promise: Promise<void> | (() => void | Promise<void>)): void {
|
|
28
39
|
if (this.hasCalledWaitUntilAll) {
|
|
29
|
-
throw new
|
|
40
|
+
throw new WaitUntilInvalidStateError();
|
|
30
41
|
}
|
|
31
42
|
running++;
|
|
32
43
|
internal.debug('wait until called, running: %d', running);
|
|
@@ -69,7 +80,7 @@ export default class WaitUntilHandler {
|
|
|
69
80
|
internal.debug(`🔍 waitUntilAll() called for session ${sessionId} (count: %d)`, running);
|
|
70
81
|
|
|
71
82
|
if (this.hasCalledWaitUntilAll) {
|
|
72
|
-
throw new
|
|
83
|
+
throw new WaitUntilAllInvalidStateError();
|
|
73
84
|
}
|
|
74
85
|
this.hasCalledWaitUntilAll = true;
|
|
75
86
|
|