@agentuity/runtime 0.0.60 → 0.0.61
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 +71 -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 +284 -4
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +2 -2
- package/dist/session.js.map +1 -1
- package/package.json +5 -4
- package/src/_context.ts +37 -9
- package/src/_server.ts +88 -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 +297 -4
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
|
+
startupPromise = new Promise((resolve) => {
|
|
158
|
+
startupPromiseResolver = resolve;
|
|
159
|
+
});
|
|
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 });
|
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
|
|