@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/agent.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
import {
|
|
3
|
+
StructuredError,
|
|
4
|
+
type KeyValueStorage,
|
|
5
|
+
type ObjectStorage,
|
|
6
|
+
type StandardSchemaV1,
|
|
7
|
+
type StreamStorage,
|
|
8
|
+
type VectorStorage,
|
|
8
9
|
} from '@agentuity/core';
|
|
9
10
|
import { context, SpanStatusCode, type Tracer, trace } from '@opentelemetry/api';
|
|
10
11
|
import type { Context, MiddlewareHandler } from 'hono';
|
|
@@ -21,11 +22,12 @@ import type {
|
|
|
21
22
|
import { internal } from './logger/internal';
|
|
22
23
|
import { getApp } from './app';
|
|
23
24
|
import type { Thread, Session } from './session';
|
|
24
|
-
import { privateContext } from './_server';
|
|
25
|
+
import { privateContext, notifyReady } from './_server';
|
|
25
26
|
import { generateId } from './session';
|
|
26
27
|
import { getEvalRunEventProvider } from './_services';
|
|
27
28
|
import * as runtimeConfig from './_config';
|
|
28
29
|
import type { EvalRunStartEvent } from '@agentuity/core';
|
|
30
|
+
import type { AppState } from './index';
|
|
29
31
|
|
|
30
32
|
export type AgentEventName = 'started' | 'completed' | 'errored';
|
|
31
33
|
|
|
@@ -47,29 +49,235 @@ export type AgentEventCallback<TAgent extends Agent<any, any, any>> =
|
|
|
47
49
|
data: Error
|
|
48
50
|
) => Promise<void> | void);
|
|
49
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Context object passed to every agent handler providing access to runtime services and state.
|
|
54
|
+
*
|
|
55
|
+
* @template TAgentRegistry - Registry of all available agents (auto-generated, strongly-typed)
|
|
56
|
+
* @template TCurrent - Current agent runner type
|
|
57
|
+
* @template TParent - Parent agent runner type (if called from another agent)
|
|
58
|
+
* @template TConfig - Agent-specific configuration type from setup function
|
|
59
|
+
* @template TAppState - Application-wide state type from createApp
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* const agent = createAgent({
|
|
64
|
+
* handler: async (ctx, input) => {
|
|
65
|
+
* // Logging
|
|
66
|
+
* ctx.logger.info('Processing request', { input });
|
|
67
|
+
*
|
|
68
|
+
* // Call another agent
|
|
69
|
+
* const result = await ctx.agent.otherAgent.run({ data: input });
|
|
70
|
+
*
|
|
71
|
+
* // Store data
|
|
72
|
+
* await ctx.kv.set('key', { value: result });
|
|
73
|
+
*
|
|
74
|
+
* // Access config from setup
|
|
75
|
+
* const cache = ctx.config.cache;
|
|
76
|
+
*
|
|
77
|
+
* // Background task
|
|
78
|
+
* ctx.waitUntil(async () => {
|
|
79
|
+
* await ctx.logger.info('Cleanup complete');
|
|
80
|
+
* });
|
|
81
|
+
*
|
|
82
|
+
* return result;
|
|
83
|
+
* }
|
|
84
|
+
* });
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
50
87
|
export interface AgentContext<
|
|
51
88
|
TAgentRegistry extends AgentRegistry = AgentRegistry,
|
|
52
89
|
TCurrent extends AgentRunner<any, any, any> | undefined = AgentRunner<any, any, any> | undefined,
|
|
53
90
|
TParent extends AgentRunner<any, any, any> | undefined = AgentRunner<any, any, any> | undefined,
|
|
91
|
+
TConfig = unknown,
|
|
92
|
+
TAppState = Record<string, never>,
|
|
54
93
|
> {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
94
|
+
/**
|
|
95
|
+
* Schedule a background task that continues after the response is sent.
|
|
96
|
+
* Useful for cleanup, logging, or async operations that don't block the response.
|
|
97
|
+
*
|
|
98
|
+
* @param promise - Promise or function that returns void or Promise<void>
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* ctx.waitUntil(async () => {
|
|
103
|
+
* await ctx.kv.set('processed', Date.now());
|
|
104
|
+
* ctx.logger.info('Background task complete');
|
|
105
|
+
* });
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
58
108
|
waitUntil: (promise: Promise<void> | (() => void | Promise<void>)) => void;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Registry of all agents in the application. Strongly-typed and auto-generated.
|
|
112
|
+
* Use to call other agents from within your handler.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* const emailResult = await ctx.agent.email.run({ to: 'user@example.com' });
|
|
117
|
+
* const smsResult = await ctx.agent.sms.run({ phone: '+1234567890' });
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
agent: TAgentRegistry;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Information about the currently executing agent.
|
|
124
|
+
*/
|
|
125
|
+
current: TCurrent;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Information about the parent agent (if this agent was called by another agent).
|
|
129
|
+
* Use ctx.agent.parentName for strongly-typed access.
|
|
130
|
+
*/
|
|
131
|
+
parent: TParent;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Name of the current agent being executed.
|
|
135
|
+
*/
|
|
62
136
|
agentName: AgentName;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Structured logger with OpenTelemetry integration.
|
|
140
|
+
* Logs are automatically correlated with traces.
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* ctx.logger.info('Processing started', { userId: input.id });
|
|
145
|
+
* ctx.logger.warn('Rate limit approaching', { remaining: 10 });
|
|
146
|
+
* ctx.logger.error('Operation failed', { error: err.message });
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
63
149
|
logger: Logger;
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Unique session identifier for this request. Consistent across agent calls in the same session.
|
|
153
|
+
*/
|
|
64
154
|
sessionId: string;
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* OpenTelemetry tracer for creating custom spans and tracking performance.
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* const span = ctx.tracer.startSpan('database-query');
|
|
162
|
+
* try {
|
|
163
|
+
* const result = await database.query();
|
|
164
|
+
* span.setStatus({ code: SpanStatusCode.OK });
|
|
165
|
+
* return result;
|
|
166
|
+
* } finally {
|
|
167
|
+
* span.end();
|
|
168
|
+
* }
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
65
171
|
tracer: Tracer;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Key-value storage for simple data persistence.
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```typescript
|
|
178
|
+
* await ctx.kv.set('user:123', { name: 'Alice', age: 30 });
|
|
179
|
+
* const user = await ctx.kv.get('user:123');
|
|
180
|
+
* await ctx.kv.delete('user:123');
|
|
181
|
+
* const keys = await ctx.kv.list('user:*');
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
66
184
|
kv: KeyValueStorage;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Object storage for files and blobs (S3-compatible).
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```typescript
|
|
191
|
+
* await ctx.objectstore.put('images/photo.jpg', buffer);
|
|
192
|
+
* const file = await ctx.objectstore.get('images/photo.jpg');
|
|
193
|
+
* await ctx.objectstore.delete('images/photo.jpg');
|
|
194
|
+
* const objects = await ctx.objectstore.list('images/');
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
67
197
|
objectstore: ObjectStorage;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Stream storage for real-time data streams and logs.
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```typescript
|
|
204
|
+
* const stream = await ctx.stream.create('agent-logs');
|
|
205
|
+
* await ctx.stream.write(stream.id, 'Processing step 1');
|
|
206
|
+
* await ctx.stream.write(stream.id, 'Processing step 2');
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
68
209
|
stream: StreamStorage;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Vector storage for embeddings and similarity search.
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```typescript
|
|
216
|
+
* await ctx.vector.upsert('docs', [
|
|
217
|
+
* { id: '1', values: [0.1, 0.2, 0.3], metadata: { text: 'Hello' } }
|
|
218
|
+
* ]);
|
|
219
|
+
* const results = await ctx.vector.query('docs', [0.1, 0.2, 0.3], { topK: 5 });
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
69
222
|
vector: VectorStorage;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* In-memory state storage scoped to the current request.
|
|
226
|
+
* Use for passing data between middleware and handlers.
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* ```typescript
|
|
230
|
+
* ctx.state.set('startTime', Date.now());
|
|
231
|
+
* const duration = Date.now() - (ctx.state.get('startTime') as number);
|
|
232
|
+
* ```
|
|
233
|
+
*/
|
|
70
234
|
state: Map<string, unknown>;
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Thread information for multi-turn conversations.
|
|
238
|
+
*/
|
|
71
239
|
thread: Thread;
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Session information for the current request.
|
|
243
|
+
*/
|
|
72
244
|
session: Session;
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Agent-specific configuration returned from the setup function.
|
|
248
|
+
* Type is inferred from your setup function's return value.
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* ```typescript
|
|
252
|
+
* createAgent({
|
|
253
|
+
* setup: async () => ({ cache: new Map(), db: await connectDB() }),
|
|
254
|
+
* handler: async (ctx, input) => {
|
|
255
|
+
* ctx.config.cache.set('key', 'value'); // Strongly typed!
|
|
256
|
+
* await ctx.config.db.query('SELECT * FROM users');
|
|
257
|
+
* }
|
|
258
|
+
* });
|
|
259
|
+
* ```
|
|
260
|
+
*/
|
|
261
|
+
config: TConfig;
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Application-wide state returned from createApp setup function.
|
|
265
|
+
* Shared across all agents in the application.
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```typescript
|
|
269
|
+
* const app = createApp({
|
|
270
|
+
* setup: async () => ({ db: await connectDB(), redis: await connectRedis() })
|
|
271
|
+
* });
|
|
272
|
+
*
|
|
273
|
+
* // Later in any agent:
|
|
274
|
+
* handler: async (ctx, input) => {
|
|
275
|
+
* await ctx.app.db.query('SELECT 1');
|
|
276
|
+
* await ctx.app.redis.set('key', 'value');
|
|
277
|
+
* }
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
280
|
+
app: TAppState;
|
|
73
281
|
}
|
|
74
282
|
|
|
75
283
|
type InternalAgentMetadata = {
|
|
@@ -108,77 +316,281 @@ type ExternalAgentMetadata = {
|
|
|
108
316
|
|
|
109
317
|
type AgentMetadata = InternalAgentMetadata & ExternalAgentMetadata;
|
|
110
318
|
|
|
111
|
-
|
|
112
|
-
|
|
319
|
+
/**
|
|
320
|
+
* Configuration object for creating an agent evaluation function.
|
|
321
|
+
*
|
|
322
|
+
* @template TInput - Input schema type from the parent agent
|
|
323
|
+
* @template TOutput - Output schema type from the parent agent
|
|
324
|
+
*/
|
|
325
|
+
export interface CreateEvalConfig<
|
|
113
326
|
TInput extends StandardSchemaV1 | undefined = any,
|
|
114
327
|
TOutput extends StandardSchemaV1 | undefined = any,
|
|
115
|
-
>
|
|
328
|
+
> {
|
|
329
|
+
/**
|
|
330
|
+
* Optional metadata for the evaluation function.
|
|
331
|
+
*
|
|
332
|
+
* @example
|
|
333
|
+
* ```typescript
|
|
334
|
+
* metadata: {
|
|
335
|
+
* name: 'Validate positive output',
|
|
336
|
+
* description: 'Ensures output is greater than zero'
|
|
337
|
+
* }
|
|
338
|
+
* ```
|
|
339
|
+
*/
|
|
116
340
|
metadata?: Partial<ExternalEvalMetadata>;
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Evaluation handler function that tests the agent's behavior.
|
|
344
|
+
* Return true if the evaluation passes, false if it fails.
|
|
345
|
+
*
|
|
346
|
+
* @param run - Evaluation run context containing input and metadata
|
|
347
|
+
* @param result - The output from the agent handler
|
|
348
|
+
* @returns Boolean indicating pass/fail, or evaluation result object
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* ```typescript
|
|
352
|
+
* handler: async (run, result) => {
|
|
353
|
+
* // Assert that output is positive
|
|
354
|
+
* if (result <= 0) {
|
|
355
|
+
* return false; // Evaluation failed
|
|
356
|
+
* }
|
|
357
|
+
* return true; // Evaluation passed
|
|
358
|
+
* }
|
|
359
|
+
* ```
|
|
360
|
+
*
|
|
361
|
+
* @example
|
|
362
|
+
* ```typescript
|
|
363
|
+
* // With detailed result
|
|
364
|
+
* handler: async (run, result) => {
|
|
365
|
+
* const passed = result.length > 5;
|
|
366
|
+
* return {
|
|
367
|
+
* passed,
|
|
368
|
+
* score: passed ? 1.0 : 0.0,
|
|
369
|
+
* message: passed ? 'Output length is valid' : 'Output too short'
|
|
370
|
+
* };
|
|
371
|
+
* }
|
|
372
|
+
* ```
|
|
373
|
+
*/
|
|
117
374
|
handler: EvalFunction<
|
|
118
375
|
TInput extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<TInput> : undefined,
|
|
119
376
|
TOutput extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<TOutput> : undefined
|
|
120
377
|
>;
|
|
121
|
-
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Type for createEval method
|
|
381
|
+
type CreateEvalMethod<
|
|
382
|
+
TInput extends StandardSchemaV1 | undefined = any,
|
|
383
|
+
TOutput extends StandardSchemaV1 | undefined = any,
|
|
384
|
+
> = (config: CreateEvalConfig<TInput, TOutput>) => Eval<TInput, TOutput>;
|
|
122
385
|
|
|
123
386
|
/**
|
|
124
|
-
*
|
|
387
|
+
* Agent instance type returned by createAgent().
|
|
388
|
+
* Represents a fully configured agent with metadata, handler, lifecycle hooks, and event listeners.
|
|
389
|
+
*
|
|
390
|
+
* @template TInput - Input schema type (StandardSchemaV1 or undefined)
|
|
391
|
+
* @template TOutput - Output schema type (StandardSchemaV1 or undefined)
|
|
392
|
+
* @template TStream - Whether the agent returns a stream (true/false)
|
|
393
|
+
* @template TConfig - Agent-specific configuration type from setup function
|
|
394
|
+
* @template TAppState - Application state type from createApp
|
|
395
|
+
*
|
|
396
|
+
* @example
|
|
397
|
+
* ```typescript
|
|
398
|
+
* const agent = createAgent({
|
|
399
|
+
* metadata: { name: 'My Agent' },
|
|
400
|
+
* schema: { input: z.string(), output: z.number() },
|
|
401
|
+
* handler: async (ctx, input) => input.length
|
|
402
|
+
* });
|
|
403
|
+
*
|
|
404
|
+
* // Access agent properties
|
|
405
|
+
* console.log(agent.metadata.name); // "My Agent"
|
|
406
|
+
*
|
|
407
|
+
* // Add event listeners
|
|
408
|
+
* agent.addEventListener('started', (eventName, agent, ctx) => {
|
|
409
|
+
* console.log('Agent started:', ctx.sessionId);
|
|
410
|
+
* });
|
|
411
|
+
*
|
|
412
|
+
* // Create evals for testing
|
|
413
|
+
* const eval1 = agent.createEval({
|
|
414
|
+
* handler: async (run, result) => {
|
|
415
|
+
* return result > 5; // Assert output is greater than 5
|
|
416
|
+
* }
|
|
417
|
+
* });
|
|
418
|
+
* ```
|
|
125
419
|
*/
|
|
126
420
|
export type Agent<
|
|
127
421
|
TInput extends StandardSchemaV1 | undefined = any,
|
|
128
422
|
TOutput extends StandardSchemaV1 | undefined = any,
|
|
129
423
|
TStream extends boolean = false,
|
|
424
|
+
TConfig = unknown,
|
|
425
|
+
TAppState = Record<string, never>,
|
|
130
426
|
> = {
|
|
427
|
+
/**
|
|
428
|
+
* Agent metadata including name, description, id, version, and filename.
|
|
429
|
+
*/
|
|
131
430
|
metadata: AgentMetadata;
|
|
132
|
-
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* The main handler function that processes agent requests.
|
|
434
|
+
* Receives AgentContext and validated input, returns output or stream.
|
|
435
|
+
*/
|
|
436
|
+
handler: (
|
|
437
|
+
ctx: AgentContext<any, any, any, TConfig, TAppState>,
|
|
438
|
+
...args: any[]
|
|
439
|
+
) => any | Promise<any>;
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Array of evaluation functions created via agent.createEval().
|
|
443
|
+
* Used for testing and validating agent behavior.
|
|
444
|
+
*/
|
|
133
445
|
evals?: Eval[];
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Create an evaluation function for testing this agent.
|
|
449
|
+
* Evals can assert correctness of agent input/output during test runs.
|
|
450
|
+
*
|
|
451
|
+
* @param config - Eval configuration
|
|
452
|
+
* @param config.metadata - Optional eval metadata (name, description)
|
|
453
|
+
* @param config.handler - Eval handler function receiving run context and result
|
|
454
|
+
*
|
|
455
|
+
* @example
|
|
456
|
+
* ```typescript
|
|
457
|
+
* const agent = createAgent({
|
|
458
|
+
* schema: { input: z.string(), output: z.number() },
|
|
459
|
+
* handler: async (ctx, input) => input.length
|
|
460
|
+
* });
|
|
461
|
+
*
|
|
462
|
+
* // Create eval to validate output
|
|
463
|
+
* agent.createEval({
|
|
464
|
+
* metadata: { name: 'Check positive output' },
|
|
465
|
+
* handler: async (run, result) => {
|
|
466
|
+
* return result > 0; // Assert output is positive
|
|
467
|
+
* }
|
|
468
|
+
* });
|
|
469
|
+
* ```
|
|
470
|
+
*/
|
|
134
471
|
createEval: CreateEvalMethod<TInput, TOutput>;
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Optional setup function called once when app starts.
|
|
475
|
+
* Returns agent-specific configuration available via ctx.config.
|
|
476
|
+
*/
|
|
477
|
+
setup?: (app: TAppState) => Promise<TConfig> | TConfig;
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Optional shutdown function called when app stops.
|
|
481
|
+
* Receives app state and agent config for cleanup.
|
|
482
|
+
*/
|
|
483
|
+
shutdown?: (app: TAppState, config: TConfig) => Promise<void> | void;
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Register an event listener for when the agent starts execution.
|
|
487
|
+
*
|
|
488
|
+
* @param eventName - Must be 'started'
|
|
489
|
+
* @param callback - Function called when agent execution begins
|
|
490
|
+
*
|
|
491
|
+
* @example
|
|
492
|
+
* ```typescript
|
|
493
|
+
* agent.addEventListener('started', (eventName, agent, ctx) => {
|
|
494
|
+
* console.log(`${agent.metadata.name} started at ${new Date()}`);
|
|
495
|
+
* });
|
|
496
|
+
* ```
|
|
497
|
+
*/
|
|
135
498
|
addEventListener(
|
|
136
499
|
eventName: 'started',
|
|
137
500
|
callback: (
|
|
138
501
|
eventName: 'started',
|
|
139
|
-
agent: Agent<TInput, TOutput, TStream>,
|
|
140
|
-
context: AgentContext<any, any, any>
|
|
502
|
+
agent: Agent<TInput, TOutput, TStream, TConfig, TAppState>,
|
|
503
|
+
context: AgentContext<any, any, any, TConfig, TAppState>
|
|
141
504
|
) => Promise<void> | void
|
|
142
505
|
): void;
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Register an event listener for when the agent completes successfully.
|
|
509
|
+
*
|
|
510
|
+
* @param eventName - Must be 'completed'
|
|
511
|
+
* @param callback - Function called when agent execution completes
|
|
512
|
+
*
|
|
513
|
+
* @example
|
|
514
|
+
* ```typescript
|
|
515
|
+
* agent.addEventListener('completed', (eventName, agent, ctx) => {
|
|
516
|
+
* console.log(`${agent.metadata.name} completed successfully`);
|
|
517
|
+
* });
|
|
518
|
+
* ```
|
|
519
|
+
*/
|
|
143
520
|
addEventListener(
|
|
144
521
|
eventName: 'completed',
|
|
145
522
|
callback: (
|
|
146
523
|
eventName: 'completed',
|
|
147
|
-
agent: Agent<TInput, TOutput, TStream>,
|
|
148
|
-
context: AgentContext<any, any, any>
|
|
524
|
+
agent: Agent<TInput, TOutput, TStream, TConfig, TAppState>,
|
|
525
|
+
context: AgentContext<any, any, any, TConfig, TAppState>
|
|
149
526
|
) => Promise<void> | void
|
|
150
527
|
): void;
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Register an event listener for when the agent throws an error.
|
|
531
|
+
*
|
|
532
|
+
* @param eventName - Must be 'errored'
|
|
533
|
+
* @param callback - Function called when agent execution fails
|
|
534
|
+
*
|
|
535
|
+
* @example
|
|
536
|
+
* ```typescript
|
|
537
|
+
* agent.addEventListener('errored', (eventName, agent, ctx, error) => {
|
|
538
|
+
* console.error(`${agent.metadata.name} failed:`, error.message);
|
|
539
|
+
* });
|
|
540
|
+
* ```
|
|
541
|
+
*/
|
|
151
542
|
addEventListener(
|
|
152
543
|
eventName: 'errored',
|
|
153
544
|
callback: (
|
|
154
545
|
eventName: 'errored',
|
|
155
|
-
agent: Agent<TInput, TOutput, TStream>,
|
|
156
|
-
context: AgentContext<any, any, any>,
|
|
546
|
+
agent: Agent<TInput, TOutput, TStream, TConfig, TAppState>,
|
|
547
|
+
context: AgentContext<any, any, any, TConfig, TAppState>,
|
|
157
548
|
data: Error
|
|
158
549
|
) => Promise<void> | void
|
|
159
550
|
): void;
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Remove a previously registered 'started' event listener.
|
|
554
|
+
*
|
|
555
|
+
* @param eventName - Must be 'started'
|
|
556
|
+
* @param callback - The callback function to remove
|
|
557
|
+
*/
|
|
160
558
|
removeEventListener(
|
|
161
559
|
eventName: 'started',
|
|
162
560
|
callback: (
|
|
163
561
|
eventName: 'started',
|
|
164
|
-
agent: Agent<TInput, TOutput, TStream>,
|
|
165
|
-
context: AgentContext<any, any, any>
|
|
562
|
+
agent: Agent<TInput, TOutput, TStream, TConfig, TAppState>,
|
|
563
|
+
context: AgentContext<any, any, any, TConfig, TAppState>
|
|
166
564
|
) => Promise<void> | void
|
|
167
565
|
): void;
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Remove a previously registered 'completed' event listener.
|
|
569
|
+
*
|
|
570
|
+
* @param eventName - Must be 'completed'
|
|
571
|
+
* @param callback - The callback function to remove
|
|
572
|
+
*/
|
|
168
573
|
removeEventListener(
|
|
169
574
|
eventName: 'completed',
|
|
170
575
|
callback: (
|
|
171
576
|
eventName: 'completed',
|
|
172
|
-
agent: Agent<TInput, TOutput, TStream>,
|
|
173
|
-
context: AgentContext<any, any, any>
|
|
577
|
+
agent: Agent<TInput, TOutput, TStream, TConfig, TAppState>,
|
|
578
|
+
context: AgentContext<any, any, any, TConfig, TAppState>
|
|
174
579
|
) => Promise<void> | void
|
|
175
580
|
): void;
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Remove a previously registered 'errored' event listener.
|
|
584
|
+
*
|
|
585
|
+
* @param eventName - Must be 'errored'
|
|
586
|
+
* @param callback - The callback function to remove
|
|
587
|
+
*/
|
|
176
588
|
removeEventListener(
|
|
177
589
|
eventName: 'errored',
|
|
178
590
|
callback: (
|
|
179
591
|
eventName: 'errored',
|
|
180
|
-
agent: Agent<TInput, TOutput, TStream>,
|
|
181
|
-
context: AgentContext<any, any, any>,
|
|
592
|
+
agent: Agent<TInput, TOutput, TStream, TConfig, TAppState>,
|
|
593
|
+
context: AgentContext<any, any, any, TConfig, TAppState>,
|
|
182
594
|
data: Error
|
|
183
595
|
) => Promise<void> | void
|
|
184
596
|
): void;
|
|
@@ -196,6 +608,143 @@ type InferStreamOutput<TOutput, TStream extends boolean> = TStream extends true
|
|
|
196
608
|
? StandardSchemaV1.InferOutput<TOutput>
|
|
197
609
|
: void;
|
|
198
610
|
|
|
611
|
+
type SchemaInput<TSchema> = TSchema extends { input: infer I } ? I : undefined;
|
|
612
|
+
type SchemaOutput<TSchema> = TSchema extends { output: infer O } ? O : undefined;
|
|
613
|
+
type SchemaStream<TSchema> = TSchema extends { stream: infer S }
|
|
614
|
+
? S extends boolean
|
|
615
|
+
? S
|
|
616
|
+
: false
|
|
617
|
+
: false;
|
|
618
|
+
|
|
619
|
+
type SchemaHandlerReturn<TSchema> =
|
|
620
|
+
SchemaStream<TSchema> extends true
|
|
621
|
+
? SchemaOutput<TSchema> extends StandardSchemaV1
|
|
622
|
+
? ReadableStream<StandardSchemaV1.InferOutput<SchemaOutput<TSchema>>>
|
|
623
|
+
: ReadableStream<unknown>
|
|
624
|
+
: SchemaOutput<TSchema> extends StandardSchemaV1
|
|
625
|
+
? StandardSchemaV1.InferOutput<SchemaOutput<TSchema>>
|
|
626
|
+
: void;
|
|
627
|
+
|
|
628
|
+
// Handler signature based on schema + setup result (no self-reference)
|
|
629
|
+
type AgentHandlerFromConfig<TSchema, TSetupReturn, TAppState = AppState> =
|
|
630
|
+
SchemaInput<TSchema> extends infer I
|
|
631
|
+
? I extends StandardSchemaV1
|
|
632
|
+
? (
|
|
633
|
+
ctx: AgentContext<any, any, any, TSetupReturn, TAppState>,
|
|
634
|
+
input: StandardSchemaV1.InferOutput<I>
|
|
635
|
+
) => Promise<SchemaHandlerReturn<TSchema>> | SchemaHandlerReturn<TSchema>
|
|
636
|
+
: (
|
|
637
|
+
ctx: AgentContext<any, any, any, TSetupReturn, TAppState>
|
|
638
|
+
) => Promise<SchemaHandlerReturn<TSchema>> | SchemaHandlerReturn<TSchema>
|
|
639
|
+
: (
|
|
640
|
+
ctx: AgentContext<any, any, any, TSetupReturn, TAppState>
|
|
641
|
+
) => Promise<SchemaHandlerReturn<TSchema>> | SchemaHandlerReturn<TSchema>;
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Configuration object for creating an agent with automatic type inference.
|
|
645
|
+
*
|
|
646
|
+
* @template TSchema - Schema definition object containing optional input, output, and stream properties
|
|
647
|
+
* @template TConfig - Function type that returns agent-specific configuration from setup
|
|
648
|
+
*/
|
|
649
|
+
export interface CreateAgentConfig<
|
|
650
|
+
TSchema extends
|
|
651
|
+
| {
|
|
652
|
+
input?: StandardSchemaV1;
|
|
653
|
+
output?: StandardSchemaV1;
|
|
654
|
+
stream?: boolean;
|
|
655
|
+
}
|
|
656
|
+
| undefined = undefined,
|
|
657
|
+
TConfig extends (app: AppState) => any = any,
|
|
658
|
+
> {
|
|
659
|
+
/**
|
|
660
|
+
* Optional schema validation using Zod or any StandardSchemaV1 compatible library.
|
|
661
|
+
*
|
|
662
|
+
* @example
|
|
663
|
+
* ```typescript
|
|
664
|
+
* schema: {
|
|
665
|
+
* input: z.object({ name: z.string(), age: z.number() }),
|
|
666
|
+
* output: z.string(),
|
|
667
|
+
* stream: false
|
|
668
|
+
* }
|
|
669
|
+
* ```
|
|
670
|
+
*/
|
|
671
|
+
schema?: TSchema;
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Agent metadata visible in the Agentuity platform.
|
|
675
|
+
*
|
|
676
|
+
* @example
|
|
677
|
+
* ```typescript
|
|
678
|
+
* metadata: {
|
|
679
|
+
* name: 'Greeting Agent',
|
|
680
|
+
* description: 'Returns personalized greetings'
|
|
681
|
+
* }
|
|
682
|
+
* ```
|
|
683
|
+
*/
|
|
684
|
+
metadata: ExternalAgentMetadata;
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Optional async function called once on app startup to initialize agent-specific resources.
|
|
688
|
+
* The returned value is available in the handler via `ctx.config`.
|
|
689
|
+
*
|
|
690
|
+
* @param app - Application state from createApp setup function
|
|
691
|
+
* @returns Agent-specific configuration object
|
|
692
|
+
*
|
|
693
|
+
* @example
|
|
694
|
+
* ```typescript
|
|
695
|
+
* setup: async (app) => {
|
|
696
|
+
* const cache = new Map();
|
|
697
|
+
* const db = await connectDB();
|
|
698
|
+
* return { cache, db };
|
|
699
|
+
* }
|
|
700
|
+
* ```
|
|
701
|
+
*/
|
|
702
|
+
setup?: TConfig;
|
|
703
|
+
|
|
704
|
+
/**
|
|
705
|
+
* The main agent logic that processes requests.
|
|
706
|
+
* Receives AgentContext and validated input (if schema.input is defined), returns output or stream.
|
|
707
|
+
*
|
|
708
|
+
* @param ctx - Agent context with logger, storage, and other runtime services
|
|
709
|
+
* @param input - Validated input (only present if schema.input is defined)
|
|
710
|
+
* @returns Output matching schema.output type, or ReadableStream if schema.stream is true
|
|
711
|
+
*
|
|
712
|
+
* @example
|
|
713
|
+
* ```typescript
|
|
714
|
+
* handler: async (ctx, { name, age }) => {
|
|
715
|
+
* ctx.logger.info(`Processing for ${name}`);
|
|
716
|
+
* await ctx.kv.set('lastUser', name);
|
|
717
|
+
* return `Hello, ${name}! You are ${age} years old.`;
|
|
718
|
+
* }
|
|
719
|
+
* ```
|
|
720
|
+
*/
|
|
721
|
+
handler: AgentHandlerFromConfig<
|
|
722
|
+
TSchema,
|
|
723
|
+
TConfig extends (app: AppState) => infer R ? Awaited<R> : undefined,
|
|
724
|
+
AppState
|
|
725
|
+
>;
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Optional async cleanup function called on app shutdown.
|
|
729
|
+
* Use this to close connections, flush buffers, etc.
|
|
730
|
+
*
|
|
731
|
+
* @param app - Application state from createApp
|
|
732
|
+
* @param config - Agent config returned from setup function
|
|
733
|
+
*
|
|
734
|
+
* @example
|
|
735
|
+
* ```typescript
|
|
736
|
+
* shutdown: async (app, config) => {
|
|
737
|
+
* await config.db.close();
|
|
738
|
+
* config.cache.clear();
|
|
739
|
+
* }
|
|
740
|
+
* ```
|
|
741
|
+
*/
|
|
742
|
+
shutdown?: (
|
|
743
|
+
app: AppState,
|
|
744
|
+
config: TConfig extends (app: AppState) => infer R ? Awaited<R> : undefined
|
|
745
|
+
) => Promise<void> | void;
|
|
746
|
+
}
|
|
747
|
+
|
|
199
748
|
export interface AgentRunner<
|
|
200
749
|
TInput extends StandardSchemaV1 | undefined = any,
|
|
201
750
|
TOutput extends StandardSchemaV1 | undefined = any,
|
|
@@ -210,30 +759,33 @@ export interface AgentRunner<
|
|
|
210
759
|
}
|
|
211
760
|
|
|
212
761
|
// Will be populated at runtime with strongly typed agents
|
|
213
|
-
const agents = new Map<string, Agent
|
|
762
|
+
const agents = new Map<string, Agent<any, any, any, any, any>>();
|
|
214
763
|
|
|
215
764
|
// WeakMap to store event listeners for each agent instance (truly private)
|
|
216
765
|
const agentEventListeners = new WeakMap<
|
|
217
|
-
Agent<any, any, any>,
|
|
766
|
+
Agent<any, any, any, any, any>,
|
|
218
767
|
Map<AgentEventName, Set<AgentEventCallback<any>>>
|
|
219
768
|
>();
|
|
220
769
|
|
|
770
|
+
// Map to store agent configs returned from setup (keyed by agent name)
|
|
771
|
+
const agentConfigs = new Map<string, unknown>();
|
|
772
|
+
|
|
221
773
|
// Helper to fire event listeners sequentially, abort on first error
|
|
222
774
|
async function fireAgentEvent(
|
|
223
|
-
agent: Agent<any, any, any>,
|
|
775
|
+
agent: Agent<any, any, any, any, any>,
|
|
224
776
|
eventName: 'started' | 'completed',
|
|
225
|
-
context: AgentContext<any, any, any>
|
|
777
|
+
context: AgentContext<any, any, any, any, any>
|
|
226
778
|
): Promise<void>;
|
|
227
779
|
async function fireAgentEvent(
|
|
228
|
-
agent: Agent<any, any, any>,
|
|
780
|
+
agent: Agent<any, any, any, any, any>,
|
|
229
781
|
eventName: 'errored',
|
|
230
|
-
context: AgentContext<any, any, any>,
|
|
782
|
+
context: AgentContext<any, any, any, any, any>,
|
|
231
783
|
data: Error
|
|
232
784
|
): Promise<void>;
|
|
233
785
|
async function fireAgentEvent(
|
|
234
|
-
agent: Agent<any, any, any>,
|
|
786
|
+
agent: Agent<any, any, any, any, any>,
|
|
235
787
|
eventName: AgentEventName,
|
|
236
|
-
context: AgentContext<any, any, any>,
|
|
788
|
+
context: AgentContext<any, any, any, any, any>,
|
|
237
789
|
data?: Error
|
|
238
790
|
): Promise<void> {
|
|
239
791
|
// Fire agent-level listeners
|
|
@@ -278,63 +830,265 @@ export type AgentName = keyof AgentRegistry extends never ? string : keyof Agent
|
|
|
278
830
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
279
831
|
export interface AgentRegistry {}
|
|
280
832
|
|
|
281
|
-
export const registerAgent = (name: AgentName, agent: Agent): void => {
|
|
833
|
+
export const registerAgent = (name: AgentName, agent: Agent<any, any, any, any, any>): void => {
|
|
282
834
|
agents.set(name, agent);
|
|
283
835
|
};
|
|
284
836
|
|
|
285
|
-
export
|
|
837
|
+
export const setAgentConfig = (name: AgentName, config: unknown): void => {
|
|
838
|
+
agentConfigs.set(name, config);
|
|
839
|
+
};
|
|
840
|
+
|
|
841
|
+
export const getAgentConfig = (name: AgentName): unknown => {
|
|
842
|
+
return agentConfigs.get(name);
|
|
843
|
+
};
|
|
844
|
+
|
|
845
|
+
const ValidationError = StructuredError('ValidationError')<{
|
|
846
|
+
issues: readonly StandardSchemaV1.Issue[];
|
|
847
|
+
}>();
|
|
848
|
+
|
|
849
|
+
/**
|
|
850
|
+
* Configuration object for creating an agent with explicit type parameters.
|
|
851
|
+
*
|
|
852
|
+
* @template TInput - Input schema type (StandardSchemaV1 or undefined)
|
|
853
|
+
* @template TOutput - Output schema type (StandardSchemaV1 or undefined)
|
|
854
|
+
* @template TStream - Whether agent returns a stream (true/false)
|
|
855
|
+
* @template TConfig - Type returned by setup function
|
|
856
|
+
* @template TAppState - Custom app state type from createApp
|
|
857
|
+
*/
|
|
858
|
+
export interface CreateAgentConfigExplicit<
|
|
286
859
|
TInput extends StandardSchemaV1 | undefined = undefined,
|
|
287
860
|
TOutput extends StandardSchemaV1 | undefined = undefined,
|
|
288
861
|
TStream extends boolean = false,
|
|
289
|
-
|
|
862
|
+
TConfig = unknown,
|
|
863
|
+
TAppState = AppState,
|
|
864
|
+
> {
|
|
865
|
+
/**
|
|
866
|
+
* Optional schema validation.
|
|
867
|
+
*
|
|
868
|
+
* @example
|
|
869
|
+
* ```typescript
|
|
870
|
+
* schema: {
|
|
871
|
+
* input: z.object({ name: z.string() }),
|
|
872
|
+
* output: z.string(),
|
|
873
|
+
* stream: false
|
|
874
|
+
* }
|
|
875
|
+
* ```
|
|
876
|
+
*/
|
|
290
877
|
schema?: {
|
|
878
|
+
/** Input validation schema */
|
|
291
879
|
input?: TInput;
|
|
880
|
+
/** Output validation schema */
|
|
292
881
|
output?: TOutput;
|
|
882
|
+
/** Whether the agent returns a ReadableStream */
|
|
293
883
|
stream?: TStream;
|
|
294
884
|
};
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* Agent metadata.
|
|
888
|
+
*
|
|
889
|
+
* @example
|
|
890
|
+
* ```typescript
|
|
891
|
+
* metadata: {
|
|
892
|
+
* name: 'My Agent',
|
|
893
|
+
* description: 'Does something useful'
|
|
894
|
+
* }
|
|
895
|
+
* ```
|
|
896
|
+
*/
|
|
295
897
|
metadata: ExternalAgentMetadata;
|
|
898
|
+
|
|
899
|
+
/**
|
|
900
|
+
* Optional setup function receiving app state, returns agent config.
|
|
901
|
+
* The returned value is available in the handler via `ctx.config`.
|
|
902
|
+
*
|
|
903
|
+
* @param app - Application state from createApp
|
|
904
|
+
* @returns Agent-specific configuration
|
|
905
|
+
*
|
|
906
|
+
* @example
|
|
907
|
+
* ```typescript
|
|
908
|
+
* setup: async (app) => ({ cache: new Map() })
|
|
909
|
+
* ```
|
|
910
|
+
*/
|
|
911
|
+
setup?: (app: TAppState) => Promise<TConfig> | TConfig;
|
|
912
|
+
|
|
913
|
+
/**
|
|
914
|
+
* Optional cleanup function called on app shutdown.
|
|
915
|
+
*
|
|
916
|
+
* @param app - Application state from createApp
|
|
917
|
+
* @param config - Agent config returned from setup
|
|
918
|
+
*
|
|
919
|
+
* @example
|
|
920
|
+
* ```typescript
|
|
921
|
+
* shutdown: async (app, config) => {
|
|
922
|
+
* config.cache.clear();
|
|
923
|
+
* }
|
|
924
|
+
* ```
|
|
925
|
+
*/
|
|
926
|
+
shutdown?: (app: TAppState, config: TConfig) => Promise<void> | void;
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* Agent handler function.
|
|
930
|
+
* Type is automatically inferred based on schema definitions.
|
|
931
|
+
*
|
|
932
|
+
* @param ctx - Agent context
|
|
933
|
+
* @param input - Validated input (only present if schema.input is defined)
|
|
934
|
+
* @returns Output or ReadableStream based on schema
|
|
935
|
+
*
|
|
936
|
+
* @example
|
|
937
|
+
* ```typescript
|
|
938
|
+
* handler: async (ctx, input) => {
|
|
939
|
+
* return `Hello, ${input.name}!`;
|
|
940
|
+
* }
|
|
941
|
+
* ```
|
|
942
|
+
*/
|
|
296
943
|
handler: TInput extends StandardSchemaV1
|
|
297
944
|
? TStream extends true
|
|
298
945
|
? TOutput extends StandardSchemaV1
|
|
299
946
|
? (
|
|
300
|
-
c: AgentContext<any, any, any>,
|
|
947
|
+
c: AgentContext<any, any, any, TConfig, TAppState>,
|
|
301
948
|
input: StandardSchemaV1.InferOutput<TInput>
|
|
302
949
|
) =>
|
|
303
950
|
| Promise<ReadableStream<StandardSchemaV1.InferOutput<TOutput>>>
|
|
304
951
|
| ReadableStream<StandardSchemaV1.InferOutput<TOutput>>
|
|
305
952
|
: (
|
|
306
|
-
c: AgentContext<any, any, any>,
|
|
953
|
+
c: AgentContext<any, any, any, TConfig, TAppState>,
|
|
307
954
|
input: StandardSchemaV1.InferOutput<TInput>
|
|
308
955
|
) => Promise<ReadableStream<unknown>> | ReadableStream<unknown>
|
|
309
956
|
: TOutput extends StandardSchemaV1
|
|
310
957
|
? (
|
|
311
|
-
c: AgentContext<any, any, any>,
|
|
958
|
+
c: AgentContext<any, any, any, TConfig, TAppState>,
|
|
312
959
|
input: StandardSchemaV1.InferOutput<TInput>
|
|
313
960
|
) =>
|
|
314
961
|
| Promise<StandardSchemaV1.InferOutput<TOutput>>
|
|
315
962
|
| StandardSchemaV1.InferOutput<TOutput>
|
|
316
963
|
: (
|
|
317
|
-
c: AgentContext<any, any, any>,
|
|
964
|
+
c: AgentContext<any, any, any, TConfig, TAppState>,
|
|
318
965
|
input: StandardSchemaV1.InferOutput<TInput>
|
|
319
966
|
) => Promise<void> | void
|
|
320
967
|
: TStream extends true
|
|
321
968
|
? TOutput extends StandardSchemaV1
|
|
322
969
|
? (
|
|
323
|
-
c: AgentContext<any, any, any>
|
|
970
|
+
c: AgentContext<any, any, any, TConfig, TAppState>
|
|
324
971
|
) =>
|
|
325
972
|
| Promise<ReadableStream<StandardSchemaV1.InferOutput<TOutput>>>
|
|
326
973
|
| ReadableStream<StandardSchemaV1.InferOutput<TOutput>>
|
|
327
974
|
: (
|
|
328
|
-
c: AgentContext<any, any, any>
|
|
975
|
+
c: AgentContext<any, any, any, TConfig, TAppState>
|
|
329
976
|
) => Promise<ReadableStream<unknown>> | ReadableStream<unknown>
|
|
330
977
|
: TOutput extends StandardSchemaV1
|
|
331
978
|
? (
|
|
332
|
-
c: AgentContext<any, any, any>
|
|
979
|
+
c: AgentContext<any, any, any, TConfig, TAppState>
|
|
333
980
|
) =>
|
|
334
981
|
| Promise<StandardSchemaV1.InferOutput<TOutput>>
|
|
335
982
|
| StandardSchemaV1.InferOutput<TOutput>
|
|
336
|
-
: (c: AgentContext<any, any, any>) => Promise<void> | void;
|
|
337
|
-
}
|
|
983
|
+
: (c: AgentContext<any, any, any, TConfig, TAppState>) => Promise<void> | void;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
/**
|
|
987
|
+
* Creates an agent with schema validation and lifecycle hooks.
|
|
988
|
+
*
|
|
989
|
+
* This is the recommended way to create agents with automatic type inference from schemas.
|
|
990
|
+
*
|
|
991
|
+
* @template TSchema - Schema definition object containing optional input, output, and stream properties
|
|
992
|
+
* @template TConfig - Function type that returns agent-specific configuration from setup
|
|
993
|
+
*
|
|
994
|
+
* @param config - Agent configuration object
|
|
995
|
+
*
|
|
996
|
+
* @returns Agent instance that can be registered with the runtime
|
|
997
|
+
*
|
|
998
|
+
* @example
|
|
999
|
+
* ```typescript
|
|
1000
|
+
* const agent = createAgent({
|
|
1001
|
+
* metadata: {
|
|
1002
|
+
* name: 'Greeting Agent',
|
|
1003
|
+
* description: 'Returns personalized greetings'
|
|
1004
|
+
* },
|
|
1005
|
+
* schema: {
|
|
1006
|
+
* input: z.object({ name: z.string(), age: z.number() }),
|
|
1007
|
+
* output: z.string()
|
|
1008
|
+
* },
|
|
1009
|
+
* handler: async (ctx, { name, age }) => {
|
|
1010
|
+
* ctx.logger.info(`Processing greeting for ${name}`);
|
|
1011
|
+
* return `Hello, ${name}! You are ${age} years old.`;
|
|
1012
|
+
* }
|
|
1013
|
+
* });
|
|
1014
|
+
* ```
|
|
1015
|
+
*/
|
|
1016
|
+
export function createAgent<
|
|
1017
|
+
TSchema extends
|
|
1018
|
+
| {
|
|
1019
|
+
input?: StandardSchemaV1;
|
|
1020
|
+
output?: StandardSchemaV1;
|
|
1021
|
+
stream?: boolean;
|
|
1022
|
+
}
|
|
1023
|
+
| undefined = undefined,
|
|
1024
|
+
TConfig extends (app: AppState) => any = any,
|
|
1025
|
+
>(
|
|
1026
|
+
config: CreateAgentConfig<TSchema, TConfig>
|
|
1027
|
+
): Agent<
|
|
1028
|
+
SchemaInput<TSchema>,
|
|
1029
|
+
SchemaOutput<TSchema>,
|
|
1030
|
+
SchemaStream<TSchema>,
|
|
1031
|
+
TConfig extends (app: AppState) => infer R ? Awaited<R> : undefined,
|
|
1032
|
+
AppState
|
|
1033
|
+
>;
|
|
1034
|
+
|
|
1035
|
+
/**
|
|
1036
|
+
* Creates an agent with explicit generic type parameters.
|
|
1037
|
+
*
|
|
1038
|
+
* Use this overload when you need explicit control over types or working with custom app state.
|
|
1039
|
+
*
|
|
1040
|
+
* @template TInput - Input schema type (StandardSchemaV1 or undefined)
|
|
1041
|
+
* @template TOutput - Output schema type (StandardSchemaV1 or undefined)
|
|
1042
|
+
* @template TStream - Whether agent returns a stream (true/false)
|
|
1043
|
+
* @template TConfig - Type returned by setup function
|
|
1044
|
+
* @template TAppState - Custom app state type from createApp
|
|
1045
|
+
*
|
|
1046
|
+
* @param config - Agent configuration object
|
|
1047
|
+
*
|
|
1048
|
+
* @returns Agent instance with explicit types
|
|
1049
|
+
*
|
|
1050
|
+
* @example
|
|
1051
|
+
* ```typescript
|
|
1052
|
+
* interface MyAppState { db: Database }
|
|
1053
|
+
* interface MyConfig { cache: Map<string, any> }
|
|
1054
|
+
*
|
|
1055
|
+
* const agent = createAgent<
|
|
1056
|
+
* z.ZodObject<any>, // TInput
|
|
1057
|
+
* z.ZodString, // TOutput
|
|
1058
|
+
* false, // TStream
|
|
1059
|
+
* MyConfig, // TConfig
|
|
1060
|
+
* MyAppState // TAppState
|
|
1061
|
+
* >({
|
|
1062
|
+
* metadata: { name: 'Custom Agent' },
|
|
1063
|
+
* setup: async (app) => ({ cache: new Map() }),
|
|
1064
|
+
* handler: async (ctx, input) => {
|
|
1065
|
+
* const db = ctx.app.db;
|
|
1066
|
+
* const cache = ctx.config.cache;
|
|
1067
|
+
* return 'result';
|
|
1068
|
+
* }
|
|
1069
|
+
* });
|
|
1070
|
+
* ```
|
|
1071
|
+
*/
|
|
1072
|
+
export function createAgent<
|
|
1073
|
+
TInput extends StandardSchemaV1 | undefined = undefined,
|
|
1074
|
+
TOutput extends StandardSchemaV1 | undefined = undefined,
|
|
1075
|
+
TStream extends boolean = false,
|
|
1076
|
+
TConfig = unknown,
|
|
1077
|
+
TAppState = AppState,
|
|
1078
|
+
>(
|
|
1079
|
+
config: CreateAgentConfigExplicit<TInput, TOutput, TStream, TConfig, TAppState>
|
|
1080
|
+
): Agent<TInput, TOutput, TStream, TConfig, TAppState>;
|
|
1081
|
+
|
|
1082
|
+
// Implementation
|
|
1083
|
+
export function createAgent<
|
|
1084
|
+
TInput extends StandardSchemaV1 | undefined = undefined,
|
|
1085
|
+
TOutput extends StandardSchemaV1 | undefined = undefined,
|
|
1086
|
+
TStream extends boolean = false,
|
|
1087
|
+
TConfig = unknown,
|
|
1088
|
+
TAppState = AppState,
|
|
1089
|
+
>(
|
|
1090
|
+
config: CreateAgentConfigExplicit<TInput, TOutput, TStream, TConfig, TAppState>
|
|
1091
|
+
): Agent<TInput, TOutput, TStream, TConfig, TAppState> {
|
|
338
1092
|
const inputSchema = config.schema?.input;
|
|
339
1093
|
const outputSchema = config.schema?.output;
|
|
340
1094
|
|
|
@@ -348,14 +1102,15 @@ export function createAgent<
|
|
|
348
1102
|
if (inputSchema) {
|
|
349
1103
|
const inputResult = await inputSchema['~standard'].validate(input);
|
|
350
1104
|
if (inputResult.issues) {
|
|
351
|
-
throw new
|
|
352
|
-
|
|
353
|
-
|
|
1105
|
+
throw new ValidationError({
|
|
1106
|
+
issues: inputResult.issues,
|
|
1107
|
+
message: `Input validation failed: ${inputResult.issues.map((i: any) => i.message).join(', ')}`,
|
|
1108
|
+
});
|
|
354
1109
|
}
|
|
355
1110
|
validatedInput = inputResult.value;
|
|
356
1111
|
}
|
|
357
1112
|
|
|
358
|
-
const agentCtx = getAgentContext()
|
|
1113
|
+
const agentCtx = getAgentContext() as AgentContext<any, any, any, TConfig, TAppState>;
|
|
359
1114
|
|
|
360
1115
|
// Get the agent instance from the agents Map to fire events
|
|
361
1116
|
// The agent will be registered in the agents Map before the handler is called
|
|
@@ -376,9 +1131,10 @@ export function createAgent<
|
|
|
376
1131
|
if (outputSchema) {
|
|
377
1132
|
const outputResult = await outputSchema['~standard'].validate(result);
|
|
378
1133
|
if (outputResult.issues) {
|
|
379
|
-
throw new
|
|
380
|
-
|
|
381
|
-
|
|
1134
|
+
throw new ValidationError({
|
|
1135
|
+
issues: outputResult.issues,
|
|
1136
|
+
message: `Output validation failed: ${outputResult.issues.map((i: any) => i.message).join(', ')}`,
|
|
1137
|
+
});
|
|
382
1138
|
}
|
|
383
1139
|
validatedOutput = outputResult.value;
|
|
384
1140
|
}
|
|
@@ -501,6 +1257,8 @@ export function createAgent<
|
|
|
501
1257
|
metadata: config.metadata,
|
|
502
1258
|
evals: evalsArray,
|
|
503
1259
|
createEval,
|
|
1260
|
+
setup: config.setup,
|
|
1261
|
+
shutdown: config.shutdown,
|
|
504
1262
|
};
|
|
505
1263
|
|
|
506
1264
|
// Add event listener methods
|
|
@@ -627,9 +1385,10 @@ export function createAgent<
|
|
|
627
1385
|
const evalInputResult =
|
|
628
1386
|
await evalItem.inputSchema['~standard'].validate(validatedInput);
|
|
629
1387
|
if (evalInputResult.issues) {
|
|
630
|
-
throw new
|
|
631
|
-
|
|
632
|
-
|
|
1388
|
+
throw new ValidationError({
|
|
1389
|
+
issues: evalInputResult.issues,
|
|
1390
|
+
message: `Eval input validation failed: ${evalInputResult.issues.map((i: any) => i.message).join(', ')}`,
|
|
1391
|
+
});
|
|
633
1392
|
}
|
|
634
1393
|
evalValidatedInput = evalInputResult.value;
|
|
635
1394
|
}
|
|
@@ -640,9 +1399,10 @@ export function createAgent<
|
|
|
640
1399
|
const evalOutputResult =
|
|
641
1400
|
await evalItem.outputSchema['~standard'].validate(validatedOutput);
|
|
642
1401
|
if (evalOutputResult.issues) {
|
|
643
|
-
throw new
|
|
644
|
-
|
|
645
|
-
|
|
1402
|
+
throw new ValidationError({
|
|
1403
|
+
issues: evalOutputResult.issues,
|
|
1404
|
+
message: `Eval output validation failed: ${evalOutputResult.issues.map((i: any) => i.message).join(', ')}`,
|
|
1405
|
+
});
|
|
646
1406
|
}
|
|
647
1407
|
evalValidatedOutput = evalOutputResult.value;
|
|
648
1408
|
}
|
|
@@ -765,7 +1525,7 @@ export function createAgent<
|
|
|
765
1525
|
agent.stream = config.schema.stream;
|
|
766
1526
|
}
|
|
767
1527
|
|
|
768
|
-
return agent as Agent<TInput, TOutput, TStream>;
|
|
1528
|
+
return agent as Agent<TInput, TOutput, TStream, TConfig, TAppState>;
|
|
769
1529
|
}
|
|
770
1530
|
|
|
771
1531
|
const runWithSpan = async <
|
|
@@ -877,11 +1637,14 @@ export const populateAgentsRegistry = (ctx: Context): any => {
|
|
|
877
1637
|
return agentsObj;
|
|
878
1638
|
};
|
|
879
1639
|
|
|
880
|
-
export const createAgentMiddleware = (agentName: AgentName): MiddlewareHandler => {
|
|
1640
|
+
export const createAgentMiddleware = (agentName: AgentName | ''): MiddlewareHandler => {
|
|
881
1641
|
return async (ctx, next) => {
|
|
882
1642
|
// Populate agents object with strongly-typed keys
|
|
883
1643
|
const agentsObj = populateAgentsRegistry(ctx);
|
|
884
1644
|
|
|
1645
|
+
// Set agent registry on context for access via c.var.agent
|
|
1646
|
+
ctx.set('agent', agentsObj);
|
|
1647
|
+
|
|
885
1648
|
// Determine current and parent agents
|
|
886
1649
|
let currentAgent: AgentRunner | undefined;
|
|
887
1650
|
let parentAgent: AgentRunner | undefined;
|
|
@@ -910,22 +1673,28 @@ export const createAgentMiddleware = (agentName: AgentName): MiddlewareHandler =
|
|
|
910
1673
|
const sessionId = ctx.var.sessionId;
|
|
911
1674
|
const thread = ctx.var.thread;
|
|
912
1675
|
const session = ctx.var.session;
|
|
1676
|
+
const config = agentName ? getAgentConfig(agentName as AgentName) : undefined;
|
|
1677
|
+
const app = ctx.var.app;
|
|
913
1678
|
|
|
914
1679
|
const args: RequestAgentContextArgs<
|
|
915
1680
|
AgentRegistry,
|
|
916
1681
|
AgentRunner | undefined,
|
|
917
|
-
AgentRunner | undefined
|
|
1682
|
+
AgentRunner | undefined,
|
|
1683
|
+
unknown,
|
|
1684
|
+
unknown
|
|
918
1685
|
> = {
|
|
919
1686
|
agent: agentsObj,
|
|
920
1687
|
current: currentAgent,
|
|
921
1688
|
parent: parentAgent,
|
|
922
|
-
agentName,
|
|
1689
|
+
agentName: agentName as AgentName,
|
|
923
1690
|
logger: ctx.var.logger.child({ agent: agentName }),
|
|
924
1691
|
tracer: ctx.var.tracer,
|
|
925
1692
|
sessionId,
|
|
926
1693
|
session,
|
|
927
1694
|
thread,
|
|
928
1695
|
handler: ctx.var.waitUntilHandler,
|
|
1696
|
+
config: config || {},
|
|
1697
|
+
app: app || {},
|
|
929
1698
|
};
|
|
930
1699
|
|
|
931
1700
|
return runInAgentContext(ctx as unknown as Record<string, unknown>, args, next);
|
|
@@ -933,3 +1702,22 @@ export const createAgentMiddleware = (agentName: AgentName): MiddlewareHandler =
|
|
|
933
1702
|
};
|
|
934
1703
|
|
|
935
1704
|
export const getAgents = () => agents;
|
|
1705
|
+
|
|
1706
|
+
export const runAgentSetups = async (appState: AppState): Promise<void> => {
|
|
1707
|
+
for (const [name, agent] of agents.entries()) {
|
|
1708
|
+
if (agent.setup) {
|
|
1709
|
+
const config = await agent.setup(appState);
|
|
1710
|
+
setAgentConfig(name as AgentName, config);
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
await notifyReady();
|
|
1714
|
+
};
|
|
1715
|
+
|
|
1716
|
+
export const runAgentShutdowns = async (appState: AppState): Promise<void> => {
|
|
1717
|
+
for (const [name, agent] of agents.entries()) {
|
|
1718
|
+
if (agent.shutdown) {
|
|
1719
|
+
const config = getAgentConfig(name as AgentName);
|
|
1720
|
+
await agent.shutdown(appState, config);
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
};
|