@agentuity/runtime 0.0.43 → 0.0.44
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/AGENTS.md +11 -9
- package/README.md +4 -4
- package/dist/_context.d.ts +12 -4
- package/dist/_context.d.ts.map +1 -1
- package/dist/_server.d.ts +7 -4
- package/dist/_server.d.ts.map +1 -1
- package/dist/_services.d.ts +13 -2
- package/dist/_services.d.ts.map +1 -1
- package/dist/_util.d.ts +1 -1
- package/dist/_util.d.ts.map +1 -1
- package/dist/_waituntil.d.ts +1 -3
- package/dist/_waituntil.d.ts.map +1 -1
- package/dist/agent.d.ts +41 -14
- package/dist/agent.d.ts.map +1 -1
- package/dist/app.d.ts +90 -8
- package/dist/app.d.ts.map +1 -1
- package/dist/eval.d.ts +79 -0
- package/dist/eval.d.ts.map +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/io/email.d.ts +77 -0
- package/dist/io/email.d.ts.map +1 -0
- package/dist/logger/console.d.ts +7 -1
- package/dist/logger/console.d.ts.map +1 -1
- package/dist/logger/user.d.ts.map +1 -1
- package/dist/otel/config.d.ts +3 -1
- package/dist/otel/config.d.ts.map +1 -1
- package/dist/otel/console.d.ts +2 -1
- package/dist/otel/console.d.ts.map +1 -1
- package/dist/otel/exporters/index.d.ts +4 -0
- package/dist/otel/exporters/index.d.ts.map +1 -0
- package/dist/otel/exporters/jsonl-log-exporter.d.ts +36 -0
- package/dist/otel/exporters/jsonl-log-exporter.d.ts.map +1 -0
- package/dist/otel/exporters/jsonl-metric-exporter.d.ts +40 -0
- package/dist/otel/exporters/jsonl-metric-exporter.d.ts.map +1 -0
- package/dist/otel/exporters/jsonl-trace-exporter.d.ts +36 -0
- package/dist/otel/exporters/jsonl-trace-exporter.d.ts.map +1 -0
- package/dist/otel/http.d.ts.map +1 -1
- package/dist/otel/logger.d.ts +8 -6
- package/dist/otel/logger.d.ts.map +1 -1
- package/dist/otel/otel.d.ts +8 -2
- package/dist/otel/otel.d.ts.map +1 -1
- package/dist/router.d.ts +4 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/services/evalrun/composite.d.ts +21 -0
- package/dist/services/evalrun/composite.d.ts.map +1 -0
- package/dist/services/evalrun/http.d.ts +24 -0
- package/dist/services/evalrun/http.d.ts.map +1 -0
- package/dist/services/evalrun/index.d.ts +5 -0
- package/dist/services/evalrun/index.d.ts.map +1 -0
- package/dist/services/evalrun/json.d.ts +21 -0
- package/dist/services/evalrun/json.d.ts.map +1 -0
- package/dist/services/evalrun/local.d.ts +19 -0
- package/dist/services/evalrun/local.d.ts.map +1 -0
- package/dist/services/local/_db.d.ts +4 -0
- package/dist/services/local/_db.d.ts.map +1 -0
- package/dist/services/local/_router.d.ts +3 -0
- package/dist/services/local/_router.d.ts.map +1 -0
- package/dist/services/local/_util.d.ts +18 -0
- package/dist/services/local/_util.d.ts.map +1 -0
- package/dist/services/local/index.d.ts +8 -0
- package/dist/services/local/index.d.ts.map +1 -0
- package/dist/services/local/keyvalue.d.ts +10 -0
- package/dist/services/local/keyvalue.d.ts.map +1 -0
- package/dist/services/local/objectstore.d.ts +11 -0
- package/dist/services/local/objectstore.d.ts.map +1 -0
- package/dist/services/local/stream.d.ts +10 -0
- package/dist/services/local/stream.d.ts.map +1 -0
- package/dist/services/local/vector.d.ts +13 -0
- package/dist/services/local/vector.d.ts.map +1 -0
- package/dist/services/session/composite.d.ts +21 -0
- package/dist/services/session/composite.d.ts.map +1 -0
- package/dist/services/session/http.d.ts +23 -0
- package/dist/services/session/http.d.ts.map +1 -0
- package/dist/services/session/index.d.ts +5 -0
- package/dist/services/session/index.d.ts.map +1 -0
- package/dist/services/session/json.d.ts +22 -0
- package/dist/services/session/json.d.ts.map +1 -0
- package/dist/services/session/local.d.ts +19 -0
- package/dist/services/session/local.d.ts.map +1 -0
- package/dist/session.d.ts +70 -0
- package/dist/session.d.ts.map +1 -0
- package/package.json +10 -6
- package/src/_config.ts +1 -1
- package/src/_context.ts +19 -16
- package/src/_server.ts +284 -42
- package/src/_services.ts +147 -34
- package/src/_util.ts +2 -3
- package/src/_waituntil.ts +5 -153
- package/src/agent.ts +667 -65
- package/src/app.ts +159 -13
- package/src/eval.ts +95 -0
- package/src/index.ts +6 -1
- package/src/io/email.ts +173 -0
- package/src/logger/console.ts +196 -17
- package/src/logger/user.ts +7 -3
- package/src/otel/config.ts +7 -44
- package/src/otel/console.ts +8 -4
- package/src/otel/exporters/README.md +217 -0
- package/src/otel/exporters/index.ts +3 -0
- package/src/otel/exporters/jsonl-log-exporter.ts +113 -0
- package/src/otel/exporters/jsonl-metric-exporter.ts +120 -0
- package/src/otel/exporters/jsonl-trace-exporter.ts +121 -0
- package/src/otel/http.ts +3 -1
- package/src/otel/logger.ts +87 -37
- package/src/otel/otel.ts +43 -22
- package/src/router.ts +44 -4
- package/src/services/evalrun/composite.ts +34 -0
- package/src/services/evalrun/http.ts +112 -0
- package/src/services/evalrun/index.ts +4 -0
- package/src/services/evalrun/json.ts +46 -0
- package/src/services/evalrun/local.ts +28 -0
- package/src/services/local/README.md +1576 -0
- package/src/services/local/_db.ts +182 -0
- package/src/services/local/_router.ts +86 -0
- package/src/services/local/_util.ts +49 -0
- package/src/services/local/index.ts +7 -0
- package/src/services/local/keyvalue.ts +118 -0
- package/src/services/local/objectstore.ts +152 -0
- package/src/services/local/stream.ts +296 -0
- package/src/services/local/vector.ts +264 -0
- package/src/services/session/composite.ts +33 -0
- package/src/services/session/http.ts +64 -0
- package/src/services/session/index.ts +4 -0
- package/src/services/session/json.ts +42 -0
- package/src/services/session/local.ts +28 -0
- package/src/session.ts +284 -0
- package/dist/_unauthenticated.d.ts +0 -26
- package/dist/_unauthenticated.d.ts.map +0 -1
- package/src/_unauthenticated.ts +0 -126
package/src/agent.ts
CHANGED
|
@@ -1,16 +1,44 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import type {
|
|
3
|
-
StandardSchemaV1,
|
|
4
3
|
KeyValueStorage,
|
|
5
4
|
ObjectStorage,
|
|
5
|
+
StandardSchemaV1,
|
|
6
6
|
StreamStorage,
|
|
7
7
|
VectorStorage,
|
|
8
8
|
} from '@agentuity/core';
|
|
9
|
-
import {
|
|
10
|
-
|
|
9
|
+
import type { Tracer } from '@opentelemetry/api';
|
|
10
|
+
import { SpanStatusCode, context, trace } from '@opentelemetry/api';
|
|
11
11
|
import type { Context, MiddlewareHandler } from 'hono';
|
|
12
12
|
import { getAgentContext, runInAgentContext, type RequestAgentContextArgs } from './_context';
|
|
13
13
|
import type { Logger } from './logger';
|
|
14
|
+
import type {
|
|
15
|
+
Eval,
|
|
16
|
+
EvalContext,
|
|
17
|
+
EvalRunResult,
|
|
18
|
+
EvalMetadata,
|
|
19
|
+
EvalFunction,
|
|
20
|
+
ExternalEvalMetadata,
|
|
21
|
+
} from './eval';
|
|
22
|
+
import { internal } from './logger/internal';
|
|
23
|
+
import { getApp } from './app';
|
|
24
|
+
import type { Thread, Session } from './session';
|
|
25
|
+
import { privateContext } from './_server';
|
|
26
|
+
import { generateId } from './session';
|
|
27
|
+
import { getEvalRunEventProvider } from './_services';
|
|
28
|
+
import * as runtimeConfig from './_config';
|
|
29
|
+
import type { EvalRunStartEvent } from '@agentuity/core';
|
|
30
|
+
|
|
31
|
+
export type AgentEventName = 'started' | 'completed' | 'errored';
|
|
32
|
+
|
|
33
|
+
export type AgentEventCallback<TAgent extends Agent<any, any, any>> =
|
|
34
|
+
| ((eventName: 'started', agent: TAgent, context: AgentContext) => Promise<void> | void)
|
|
35
|
+
| ((eventName: 'completed', agent: TAgent, context: AgentContext) => Promise<void> | void)
|
|
36
|
+
| ((
|
|
37
|
+
eventName: 'errored',
|
|
38
|
+
agent: TAgent,
|
|
39
|
+
context: AgentContext,
|
|
40
|
+
data: Error
|
|
41
|
+
) => Promise<void> | void);
|
|
14
42
|
|
|
15
43
|
export interface AgentContext {
|
|
16
44
|
// email: () => Promise<Email | null>;
|
|
@@ -19,6 +47,7 @@ export interface AgentContext {
|
|
|
19
47
|
waitUntil: (promise: Promise<void> | (() => void | Promise<void>)) => void;
|
|
20
48
|
agent?: any; // Will be augmented by generated code
|
|
21
49
|
current?: any; // Will be augmented by generated code
|
|
50
|
+
parent?: any; // Will be augmented by generated code - reference to parent agent for subagents
|
|
22
51
|
agentName?: AgentName;
|
|
23
52
|
logger: Logger;
|
|
24
53
|
sessionId: string;
|
|
@@ -27,9 +56,12 @@ export interface AgentContext {
|
|
|
27
56
|
objectstore: ObjectStorage;
|
|
28
57
|
stream: StreamStorage;
|
|
29
58
|
vector: VectorStorage;
|
|
59
|
+
state: Map<string, unknown>;
|
|
60
|
+
thread: Thread;
|
|
61
|
+
session: Session;
|
|
30
62
|
}
|
|
31
63
|
|
|
32
|
-
|
|
64
|
+
type InternalAgentMetadata = {
|
|
33
65
|
/**
|
|
34
66
|
* the unique identifier for this agent and project
|
|
35
67
|
*/
|
|
@@ -38,14 +70,6 @@ interface AgentMetadata {
|
|
|
38
70
|
* the folder name for the agent
|
|
39
71
|
*/
|
|
40
72
|
identifier: string;
|
|
41
|
-
/**
|
|
42
|
-
* the human readable name for the agent (identifier is used if not specified)
|
|
43
|
-
*/
|
|
44
|
-
name: string;
|
|
45
|
-
/**
|
|
46
|
-
* the human readable description for the agent (empty if not provided)
|
|
47
|
-
*/
|
|
48
|
-
description: string;
|
|
49
73
|
/**
|
|
50
74
|
* the relative path to the agent from the root project directory
|
|
51
75
|
*/
|
|
@@ -54,7 +78,32 @@ interface AgentMetadata {
|
|
|
54
78
|
* a unique version for the agent. computed as the SHA256 contents of the file.
|
|
55
79
|
*/
|
|
56
80
|
version: string;
|
|
57
|
-
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
type ExternalAgentMetadata = {
|
|
84
|
+
/**
|
|
85
|
+
* the human readable name for the agent
|
|
86
|
+
*/
|
|
87
|
+
name: string;
|
|
88
|
+
/**
|
|
89
|
+
* the human readable description for the agent (empty if not provided)
|
|
90
|
+
*/
|
|
91
|
+
description: string;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
type AgentMetadata = InternalAgentMetadata & ExternalAgentMetadata;
|
|
95
|
+
|
|
96
|
+
// Type for createEval method
|
|
97
|
+
type CreateEvalMethod<
|
|
98
|
+
TInput extends StandardSchemaV1 | undefined = any,
|
|
99
|
+
TOutput extends StandardSchemaV1 | undefined = any,
|
|
100
|
+
> = (config: {
|
|
101
|
+
metadata?: Partial<ExternalEvalMetadata>;
|
|
102
|
+
handler: EvalFunction<
|
|
103
|
+
TInput extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<TInput> : undefined,
|
|
104
|
+
TOutput extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<TOutput> : undefined
|
|
105
|
+
>;
|
|
106
|
+
}) => Eval<TInput, TOutput>;
|
|
58
107
|
|
|
59
108
|
/**
|
|
60
109
|
* The Agent handler interface.
|
|
@@ -66,6 +115,58 @@ export type Agent<
|
|
|
66
115
|
> = {
|
|
67
116
|
metadata: AgentMetadata;
|
|
68
117
|
handler: (ctx: AgentContext, ...args: any[]) => any | Promise<any>;
|
|
118
|
+
evals?: Eval[];
|
|
119
|
+
createEval: CreateEvalMethod<TInput, TOutput>;
|
|
120
|
+
addEventListener(
|
|
121
|
+
eventName: 'started',
|
|
122
|
+
callback: (
|
|
123
|
+
eventName: 'started',
|
|
124
|
+
agent: Agent<TInput, TOutput, TStream>,
|
|
125
|
+
context: AgentContext
|
|
126
|
+
) => Promise<void> | void
|
|
127
|
+
): void;
|
|
128
|
+
addEventListener(
|
|
129
|
+
eventName: 'completed',
|
|
130
|
+
callback: (
|
|
131
|
+
eventName: 'completed',
|
|
132
|
+
agent: Agent<TInput, TOutput, TStream>,
|
|
133
|
+
context: AgentContext
|
|
134
|
+
) => Promise<void> | void
|
|
135
|
+
): void;
|
|
136
|
+
addEventListener(
|
|
137
|
+
eventName: 'errored',
|
|
138
|
+
callback: (
|
|
139
|
+
eventName: 'errored',
|
|
140
|
+
agent: Agent<TInput, TOutput, TStream>,
|
|
141
|
+
context: AgentContext,
|
|
142
|
+
data: Error
|
|
143
|
+
) => Promise<void> | void
|
|
144
|
+
): void;
|
|
145
|
+
removeEventListener(
|
|
146
|
+
eventName: 'started',
|
|
147
|
+
callback: (
|
|
148
|
+
eventName: 'started',
|
|
149
|
+
agent: Agent<TInput, TOutput, TStream>,
|
|
150
|
+
context: AgentContext
|
|
151
|
+
) => Promise<void> | void
|
|
152
|
+
): void;
|
|
153
|
+
removeEventListener(
|
|
154
|
+
eventName: 'completed',
|
|
155
|
+
callback: (
|
|
156
|
+
eventName: 'completed',
|
|
157
|
+
agent: Agent<TInput, TOutput, TStream>,
|
|
158
|
+
context: AgentContext
|
|
159
|
+
) => Promise<void> | void
|
|
160
|
+
): void;
|
|
161
|
+
removeEventListener(
|
|
162
|
+
eventName: 'errored',
|
|
163
|
+
callback: (
|
|
164
|
+
eventName: 'errored',
|
|
165
|
+
agent: Agent<TInput, TOutput, TStream>,
|
|
166
|
+
context: AgentContext,
|
|
167
|
+
data: Error
|
|
168
|
+
) => Promise<void> | void
|
|
169
|
+
): void;
|
|
69
170
|
} & (TInput extends StandardSchemaV1 ? { inputSchema: TInput } : { inputSchema?: never }) &
|
|
70
171
|
(TOutput extends StandardSchemaV1 ? { outputSchema: TOutput } : { outputSchema?: never }) &
|
|
71
172
|
(TStream extends true ? { stream: true } : { stream?: false });
|
|
@@ -96,6 +197,58 @@ export interface AgentRunner<
|
|
|
96
197
|
// Will be populated at runtime with strongly typed agents
|
|
97
198
|
const agents = new Map<string, Agent>();
|
|
98
199
|
|
|
200
|
+
// WeakMap to store event listeners for each agent instance (truly private)
|
|
201
|
+
const agentEventListeners = new WeakMap<
|
|
202
|
+
Agent<any, any, any>,
|
|
203
|
+
Map<AgentEventName, Set<AgentEventCallback<any>>>
|
|
204
|
+
>();
|
|
205
|
+
|
|
206
|
+
// Helper to fire event listeners sequentially, abort on first error
|
|
207
|
+
async function fireAgentEvent(
|
|
208
|
+
agent: Agent<any, any, any>,
|
|
209
|
+
eventName: 'started' | 'completed',
|
|
210
|
+
context: AgentContext
|
|
211
|
+
): Promise<void>;
|
|
212
|
+
async function fireAgentEvent(
|
|
213
|
+
agent: Agent<any, any, any>,
|
|
214
|
+
eventName: 'errored',
|
|
215
|
+
context: AgentContext,
|
|
216
|
+
data: Error
|
|
217
|
+
): Promise<void>;
|
|
218
|
+
async function fireAgentEvent(
|
|
219
|
+
agent: Agent<any, any, any>,
|
|
220
|
+
eventName: AgentEventName,
|
|
221
|
+
context: AgentContext,
|
|
222
|
+
data?: Error
|
|
223
|
+
): Promise<void> {
|
|
224
|
+
// Fire agent-level listeners
|
|
225
|
+
const listeners = agentEventListeners.get(agent);
|
|
226
|
+
if (listeners) {
|
|
227
|
+
const callbacks = listeners.get(eventName);
|
|
228
|
+
if (callbacks && callbacks.size > 0) {
|
|
229
|
+
for (const callback of callbacks) {
|
|
230
|
+
if (eventName === 'errored' && data) {
|
|
231
|
+
await (callback as any)(eventName, agent, context, data);
|
|
232
|
+
} else if (eventName === 'started' || eventName === 'completed') {
|
|
233
|
+
await (callback as any)(eventName, agent, context);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Fire app-level listeners
|
|
240
|
+
const app = getApp();
|
|
241
|
+
if (app) {
|
|
242
|
+
if (eventName === 'errored' && data) {
|
|
243
|
+
await app.fireEvent('agent.errored', agent, context, data);
|
|
244
|
+
} else if (eventName === 'started') {
|
|
245
|
+
await app.fireEvent('agent.started', agent, context);
|
|
246
|
+
} else if (eventName === 'completed') {
|
|
247
|
+
await app.fireEvent('agent.completed', agent, context);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
99
252
|
/**
|
|
100
253
|
* Union type of all registered agent names.
|
|
101
254
|
* Falls back to `string` when no agents are registered (before augmentation).
|
|
@@ -118,7 +271,7 @@ export function createAgent<
|
|
|
118
271
|
output?: TOutput;
|
|
119
272
|
stream?: TStream;
|
|
120
273
|
};
|
|
121
|
-
metadata?: Partial<
|
|
274
|
+
metadata?: Partial<ExternalAgentMetadata>;
|
|
122
275
|
handler: TInput extends StandardSchemaV1
|
|
123
276
|
? TStream extends true
|
|
124
277
|
? TOutput extends StandardSchemaV1
|
|
@@ -159,6 +312,10 @@ export function createAgent<
|
|
|
159
312
|
const inputSchema = config.schema?.input;
|
|
160
313
|
const outputSchema = config.schema?.output;
|
|
161
314
|
|
|
315
|
+
// Initialize evals array before handler so it can be captured in closure
|
|
316
|
+
// Evals should only be added via agent.createEval() after agent creation
|
|
317
|
+
const evalsArray: Eval[] = [];
|
|
318
|
+
|
|
162
319
|
const handler = async (_ctx: Context, input?: any) => {
|
|
163
320
|
let validatedInput: any = undefined;
|
|
164
321
|
|
|
@@ -174,25 +331,390 @@ export function createAgent<
|
|
|
174
331
|
|
|
175
332
|
const agentCtx = getAgentContext();
|
|
176
333
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
334
|
+
// Get the agent instance from the agents Map to fire events
|
|
335
|
+
// The agent will be registered in the agents Map before the handler is called
|
|
336
|
+
const agentName = agentCtx.agentName;
|
|
337
|
+
const registeredAgent = agentName ? agents.get(agentName) : undefined;
|
|
338
|
+
|
|
339
|
+
// Fire 'started' event (only if agent is registered)
|
|
340
|
+
if (registeredAgent) {
|
|
341
|
+
await fireAgentEvent(registeredAgent, 'started', agentCtx);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
try {
|
|
345
|
+
const result = inputSchema
|
|
346
|
+
? await (config.handler as any)(agentCtx, validatedInput)
|
|
347
|
+
: await (config.handler as any)(agentCtx);
|
|
348
|
+
|
|
349
|
+
let validatedOutput: any = result;
|
|
350
|
+
if (outputSchema) {
|
|
351
|
+
const outputResult = await outputSchema['~standard'].validate(result);
|
|
352
|
+
if (outputResult.issues) {
|
|
353
|
+
throw new Error(
|
|
354
|
+
`Output validation failed: ${outputResult.issues.map((i: any) => i.message).join(', ')}`
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
validatedOutput = outputResult.value;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Store validated input/output in context state for event listeners
|
|
361
|
+
agentCtx.state.set('_evalInput', validatedInput);
|
|
362
|
+
agentCtx.state.set('_evalOutput', validatedOutput);
|
|
363
|
+
|
|
364
|
+
// Fire 'completed' event - evals will run via event listener
|
|
365
|
+
if (registeredAgent) {
|
|
366
|
+
await fireAgentEvent(registeredAgent, 'completed', agentCtx);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return validatedOutput;
|
|
370
|
+
} catch (error) {
|
|
371
|
+
// Fire 'errored' event
|
|
372
|
+
if (registeredAgent) {
|
|
373
|
+
await fireAgentEvent(registeredAgent, 'errored', agentCtx, error as Error);
|
|
374
|
+
}
|
|
375
|
+
throw error;
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
// Infer input/output types from agent schema
|
|
380
|
+
type AgentInput = TInput extends StandardSchemaV1
|
|
381
|
+
? StandardSchemaV1.InferOutput<TInput>
|
|
382
|
+
: undefined;
|
|
383
|
+
type AgentOutput = TOutput extends StandardSchemaV1
|
|
384
|
+
? StandardSchemaV1.InferOutput<TOutput>
|
|
385
|
+
: undefined;
|
|
386
|
+
|
|
387
|
+
// Create createEval method that infers types from agent and automatically adds to agent
|
|
388
|
+
const createEval = (evalConfig: {
|
|
389
|
+
metadata?: Partial<Omit<EvalMetadata, 'id' | 'version'>>;
|
|
390
|
+
handler: EvalFunction<AgentInput, AgentOutput>;
|
|
391
|
+
}): Eval<TInput, TOutput> => {
|
|
392
|
+
const evalName = evalConfig.metadata?.name || 'unnamed';
|
|
393
|
+
// Trace log to verify evals file is imported
|
|
394
|
+
internal.debug(
|
|
395
|
+
`createEval called for agent "${config?.metadata?.name || 'unknown'}": registering eval "${evalName}"`
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
// Get filename (can be provided via __filename or set by bundler)
|
|
399
|
+
const filename = evalConfig.metadata?.filename || '';
|
|
400
|
+
|
|
401
|
+
// Derive identifier from filename if not provided
|
|
402
|
+
let identifier = evalConfig.metadata?.identifier || '';
|
|
403
|
+
if (!identifier && filename) {
|
|
404
|
+
const pathParts = filename.split(/[/\\]/);
|
|
405
|
+
const basename = pathParts[pathParts.length - 1] || '';
|
|
406
|
+
identifier = basename.replace(/\.(ts|tsx|js|jsx)$/, '') || '';
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Use name as identifier fallback
|
|
410
|
+
if (!identifier) {
|
|
411
|
+
identifier = evalName;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Generate eval ID and version at runtime (similar to build-time generation)
|
|
415
|
+
const projectId = runtimeConfig.getProjectId() || '';
|
|
416
|
+
const deploymentId = runtimeConfig.getDeploymentId() || '';
|
|
417
|
+
// Generate version from available metadata (deterministic hash)
|
|
418
|
+
// At build-time, version is hash of file contents; at runtime we use metadata
|
|
419
|
+
const versionHasher = new Bun.CryptoHasher('sha1');
|
|
420
|
+
versionHasher.update(identifier);
|
|
421
|
+
versionHasher.update(evalName);
|
|
422
|
+
versionHasher.update(filename);
|
|
423
|
+
const version = versionHasher.digest('hex');
|
|
424
|
+
// Generate eval ID using same logic as build-time (getEvalId)
|
|
425
|
+
// Format: eval_${hashSHA1(projectId, deploymentId, filename, name, version)}
|
|
426
|
+
const idHasher = new Bun.CryptoHasher('sha1');
|
|
427
|
+
idHasher.update(projectId);
|
|
428
|
+
idHasher.update(deploymentId);
|
|
429
|
+
idHasher.update(filename);
|
|
430
|
+
idHasher.update(evalName);
|
|
431
|
+
idHasher.update(version);
|
|
432
|
+
const evalId = `eval_${idHasher.digest('hex')}`;
|
|
433
|
+
|
|
434
|
+
const evalType: any = {
|
|
435
|
+
metadata: {
|
|
436
|
+
id: evalId,
|
|
437
|
+
version,
|
|
438
|
+
identifier,
|
|
439
|
+
name: evalConfig.metadata?.name || '',
|
|
440
|
+
description: evalConfig.metadata?.description || '',
|
|
441
|
+
filename,
|
|
442
|
+
},
|
|
443
|
+
handler: evalConfig.handler,
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
if (inputSchema) {
|
|
447
|
+
evalType.inputSchema = inputSchema;
|
|
448
|
+
}
|
|
180
449
|
|
|
181
450
|
if (outputSchema) {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
451
|
+
evalType.outputSchema = outputSchema;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Automatically add eval to agent's evals array
|
|
455
|
+
evalsArray.push(evalType);
|
|
456
|
+
internal.debug(
|
|
457
|
+
`Added eval "${evalName}" to agent "${config?.metadata?.name || 'unknown'}". Total evals: ${evalsArray.length}`
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
return evalType as Eval<TInput, TOutput>;
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
const agent: any = {
|
|
464
|
+
handler,
|
|
465
|
+
metadata: config.metadata,
|
|
466
|
+
evals: evalsArray,
|
|
467
|
+
createEval,
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
// Add event listener methods
|
|
471
|
+
agent.addEventListener = (eventName: AgentEventName, callback: any): void => {
|
|
472
|
+
const agentForListeners = agent as any as Agent<any, any, any>;
|
|
473
|
+
const callbackForListeners = callback as any as AgentEventCallback<any>;
|
|
474
|
+
let listeners = agentEventListeners.get(agentForListeners);
|
|
475
|
+
if (!listeners) {
|
|
476
|
+
listeners = new Map();
|
|
477
|
+
agentEventListeners.set(agentForListeners, listeners);
|
|
478
|
+
}
|
|
479
|
+
let callbacks = listeners.get(eventName);
|
|
480
|
+
if (!callbacks) {
|
|
481
|
+
callbacks = new Set();
|
|
482
|
+
listeners.set(eventName, callbacks);
|
|
483
|
+
}
|
|
484
|
+
callbacks.add(callbackForListeners);
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
// Automatically add event listener for 'completed' event to run evals
|
|
488
|
+
(agent as Agent).addEventListener('completed', async (_event, _agent, ctx) => {
|
|
489
|
+
// Get the agent instance from the agents Map to access its current evals array
|
|
490
|
+
// This ensures we get evals that were added via agent.createEval() after agent creation
|
|
491
|
+
const agentName = ctx.agentName;
|
|
492
|
+
const registeredAgent = agentName ? agents.get(agentName) : undefined;
|
|
493
|
+
const agentEvals = registeredAgent?.evals || evalsArray;
|
|
494
|
+
|
|
495
|
+
internal.debug(
|
|
496
|
+
`Checking evals: agentName=${agentName}, evalsArray.length=${evalsArray?.length || 0}, agent.evals.length=${registeredAgent?.evals?.length || 0}`
|
|
497
|
+
);
|
|
498
|
+
|
|
499
|
+
if (agentEvals && agentEvals.length > 0) {
|
|
500
|
+
internal.info(`Executing ${agentEvals.length} eval(s) after agent run`);
|
|
501
|
+
|
|
502
|
+
// Get validated input/output from context state
|
|
503
|
+
const validatedInput = ctx.state.get('_evalInput');
|
|
504
|
+
const validatedOutput = ctx.state.get('_evalOutput');
|
|
505
|
+
|
|
506
|
+
// Execute each eval using waitUntil to avoid blocking the response
|
|
507
|
+
for (const evalItem of agentEvals) {
|
|
508
|
+
const evalName = evalItem.metadata.name || 'unnamed';
|
|
509
|
+
|
|
510
|
+
ctx.waitUntil(
|
|
511
|
+
(async () => {
|
|
512
|
+
internal.info(`[EVALRUN] Starting eval run tracking for '${evalName}'`);
|
|
513
|
+
const evalRunId = generateId('evalrun');
|
|
514
|
+
const evalId = evalItem.metadata.id || '';
|
|
515
|
+
const orgId = runtimeConfig.getOrganizationId();
|
|
516
|
+
const projectId = runtimeConfig.getProjectId();
|
|
517
|
+
const devMode = runtimeConfig.isDevMode() ?? false;
|
|
518
|
+
const evalRunEventProvider = getEvalRunEventProvider();
|
|
519
|
+
|
|
520
|
+
// Only send events if we have required context (devmode flag will be set based on devMode)
|
|
521
|
+
const shouldSendEvalRunEvents = orgId && projectId && evalId !== '';
|
|
522
|
+
|
|
523
|
+
internal.info(`[EVALRUN] Checking conditions for eval '${evalName}':`, {
|
|
524
|
+
orgId: orgId,
|
|
525
|
+
projectId: projectId,
|
|
526
|
+
evalId: evalId,
|
|
527
|
+
devMode,
|
|
528
|
+
hasEvalRunEventProvider: !!evalRunEventProvider,
|
|
529
|
+
shouldSendEvalRunEvents,
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
if (!shouldSendEvalRunEvents) {
|
|
533
|
+
const reasons: string[] = [];
|
|
534
|
+
if (!orgId) reasons.push('missing orgId');
|
|
535
|
+
if (!projectId) reasons.push('missing projectId');
|
|
536
|
+
if (!evalId || evalId === '') reasons.push('empty evalId');
|
|
537
|
+
internal.info(
|
|
538
|
+
`[EVALRUN] Skipping eval run events for '${evalName}': ${reasons.join(', ')}`
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
try {
|
|
543
|
+
internal.debug(`Executing eval: ${evalName}`);
|
|
544
|
+
|
|
545
|
+
// Send eval run start event
|
|
546
|
+
if (shouldSendEvalRunEvents && evalRunEventProvider) {
|
|
547
|
+
internal.info(
|
|
548
|
+
`[EVALRUN] Sending start event for eval '${evalName}' (id: ${evalRunId}, evalId: ${evalId})`
|
|
549
|
+
);
|
|
550
|
+
try {
|
|
551
|
+
const startEvent: EvalRunStartEvent = {
|
|
552
|
+
id: evalRunId,
|
|
553
|
+
sessionId: ctx.sessionId,
|
|
554
|
+
evalId: evalId,
|
|
555
|
+
orgId: orgId!,
|
|
556
|
+
projectId: projectId!,
|
|
557
|
+
devmode: Boolean(devMode),
|
|
558
|
+
};
|
|
559
|
+
internal.debug(
|
|
560
|
+
'[EVALRUN] Start event payload: %s',
|
|
561
|
+
JSON.stringify(startEvent, null, 2)
|
|
562
|
+
);
|
|
563
|
+
await evalRunEventProvider.start(startEvent);
|
|
564
|
+
internal.info(
|
|
565
|
+
`[EVALRUN] Start event sent successfully for eval '${evalName}' (id: ${evalRunId})`
|
|
566
|
+
);
|
|
567
|
+
} catch (error) {
|
|
568
|
+
internal.error(
|
|
569
|
+
`[EVALRUN] Error sending eval run start event for '${evalName}' (id: ${evalRunId})`,
|
|
570
|
+
{
|
|
571
|
+
error,
|
|
572
|
+
}
|
|
573
|
+
);
|
|
574
|
+
// Don't throw - continue with eval execution even if start event fails
|
|
575
|
+
}
|
|
576
|
+
} else if (shouldSendEvalRunEvents && !evalRunEventProvider) {
|
|
577
|
+
internal.warn(
|
|
578
|
+
`[EVALRUN] Conditions met but no evalRunEventProvider available for '${evalName}'`
|
|
579
|
+
);
|
|
580
|
+
} else {
|
|
581
|
+
internal.debug(
|
|
582
|
+
`[EVALRUN] Not sending start event for '${evalName}': shouldSendEvalRunEvents=${shouldSendEvalRunEvents}, hasProvider=${!!evalRunEventProvider}`
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// Validate eval input if schema exists
|
|
587
|
+
let evalValidatedInput: any = validatedInput;
|
|
588
|
+
if (evalItem.inputSchema) {
|
|
589
|
+
const evalInputResult =
|
|
590
|
+
await evalItem.inputSchema['~standard'].validate(validatedInput);
|
|
591
|
+
if (evalInputResult.issues) {
|
|
592
|
+
throw new Error(
|
|
593
|
+
`Eval input validation failed: ${evalInputResult.issues.map((i: any) => i.message).join(', ')}`
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
evalValidatedInput = evalInputResult.value;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// Validate eval output if schema exists
|
|
600
|
+
let evalValidatedOutput: any = validatedOutput;
|
|
601
|
+
if (evalItem.outputSchema) {
|
|
602
|
+
const evalOutputResult =
|
|
603
|
+
await evalItem.outputSchema['~standard'].validate(validatedOutput);
|
|
604
|
+
if (evalOutputResult.issues) {
|
|
605
|
+
throw new Error(
|
|
606
|
+
`Eval output validation failed: ${evalOutputResult.issues.map((i: any) => i.message).join(', ')}`
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
evalValidatedOutput = evalOutputResult.value;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// Create EvalContext (just an alias for AgentContext)
|
|
613
|
+
const evalContext: EvalContext = ctx;
|
|
614
|
+
|
|
615
|
+
// Execute the eval handler conditionally based on agent schema
|
|
616
|
+
let result: EvalRunResult;
|
|
617
|
+
if (inputSchema && outputSchema) {
|
|
618
|
+
// Both input and output defined
|
|
619
|
+
result = await (evalItem.handler as any)(
|
|
620
|
+
evalContext,
|
|
621
|
+
evalValidatedInput,
|
|
622
|
+
evalValidatedOutput
|
|
623
|
+
);
|
|
624
|
+
} else if (inputSchema) {
|
|
625
|
+
// Only input defined
|
|
626
|
+
result = await (evalItem.handler as any)(evalContext, evalValidatedInput);
|
|
627
|
+
} else if (outputSchema) {
|
|
628
|
+
// Only output defined
|
|
629
|
+
result = await (evalItem.handler as any)(evalContext, evalValidatedOutput);
|
|
630
|
+
} else {
|
|
631
|
+
// Neither defined
|
|
632
|
+
result = await (evalItem.handler as any)(evalContext);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// Process the returned result
|
|
636
|
+
if (result.success) {
|
|
637
|
+
if ('passed' in result) {
|
|
638
|
+
internal.info(
|
|
639
|
+
`Eval '${evalName}' pass: ${result.passed}`,
|
|
640
|
+
result.metadata
|
|
641
|
+
);
|
|
642
|
+
} else if ('score' in result) {
|
|
643
|
+
internal.info(
|
|
644
|
+
`Eval '${evalName}' score: ${result.score}`,
|
|
645
|
+
result.metadata
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
} else {
|
|
649
|
+
internal.error(`Eval '${evalName}' failed: ${result.error}`);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// Send eval run complete event
|
|
653
|
+
if (shouldSendEvalRunEvents && evalRunEventProvider) {
|
|
654
|
+
internal.info(
|
|
655
|
+
`[EVALRUN] Sending complete event for eval '${evalName}' (id: ${evalRunId})`
|
|
656
|
+
);
|
|
657
|
+
try {
|
|
658
|
+
await evalRunEventProvider.complete({
|
|
659
|
+
id: evalRunId,
|
|
660
|
+
result: result.success ? result : undefined,
|
|
661
|
+
error: result.success ? undefined : result.error,
|
|
662
|
+
});
|
|
663
|
+
internal.info(
|
|
664
|
+
`[EVALRUN] Complete event sent successfully for eval '${evalName}' (id: ${evalRunId})`
|
|
665
|
+
);
|
|
666
|
+
} catch (error) {
|
|
667
|
+
internal.error(
|
|
668
|
+
`[EVALRUN] Error sending eval run complete event for '${evalName}' (id: ${evalRunId})`,
|
|
669
|
+
{
|
|
670
|
+
error,
|
|
671
|
+
}
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
internal.debug(`Eval '${evalName}' completed successfully`);
|
|
677
|
+
} catch (error) {
|
|
678
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
679
|
+
internal.error(`Error executing eval '${evalName}'`, { error });
|
|
680
|
+
|
|
681
|
+
// Send eval run complete event with error
|
|
682
|
+
if (shouldSendEvalRunEvents && evalRunEventProvider) {
|
|
683
|
+
internal.info(
|
|
684
|
+
`[EVALRUN] Sending complete event (error) for eval '${evalName}' (id: ${evalRunId})`
|
|
685
|
+
);
|
|
686
|
+
try {
|
|
687
|
+
await evalRunEventProvider.complete({
|
|
688
|
+
id: evalRunId,
|
|
689
|
+
error: errorMessage,
|
|
690
|
+
});
|
|
691
|
+
internal.info(
|
|
692
|
+
`[EVALRUN] Complete event (error) sent successfully for eval '${evalName}' (id: ${evalRunId})`
|
|
693
|
+
);
|
|
694
|
+
} catch (eventError) {
|
|
695
|
+
internal.error(
|
|
696
|
+
`[EVALRUN] Error sending eval run complete event (error) for '${evalName}' (id: ${evalRunId})`,
|
|
697
|
+
{ error: eventError }
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
})()
|
|
186
703
|
);
|
|
187
704
|
}
|
|
188
|
-
return outputResult.value;
|
|
189
705
|
}
|
|
706
|
+
});
|
|
190
707
|
|
|
191
|
-
|
|
708
|
+
agent.removeEventListener = (eventName: AgentEventName, callback: any): void => {
|
|
709
|
+
const agentForListeners = agent as any as Agent<any, any, any>;
|
|
710
|
+
const callbackForListeners = callback as any as AgentEventCallback<any>;
|
|
711
|
+
const listeners = agentEventListeners.get(agentForListeners);
|
|
712
|
+
if (!listeners) return;
|
|
713
|
+
const callbacks = listeners.get(eventName);
|
|
714
|
+
if (!callbacks) return;
|
|
715
|
+
callbacks.delete(callbackForListeners);
|
|
192
716
|
};
|
|
193
717
|
|
|
194
|
-
const agent: any = { handler, metadata: config.metadata };
|
|
195
|
-
|
|
196
718
|
if (inputSchema) {
|
|
197
719
|
agent.inputSchema = inputSchema;
|
|
198
720
|
}
|
|
@@ -208,6 +730,35 @@ export function createAgent<
|
|
|
208
730
|
return agent as Agent<TInput, TOutput, TStream>;
|
|
209
731
|
}
|
|
210
732
|
|
|
733
|
+
const runWithSpan = async <T>(
|
|
734
|
+
tracer: Tracer,
|
|
735
|
+
agent: Agent<any, any, any>,
|
|
736
|
+
handler: () => Promise<T>
|
|
737
|
+
): Promise<T> => {
|
|
738
|
+
const currentContext = context.active();
|
|
739
|
+
const span = tracer.startSpan(
|
|
740
|
+
'agent.run',
|
|
741
|
+
{
|
|
742
|
+
attributes: {
|
|
743
|
+
'@agentuity/agentName': agent.metadata?.name || '',
|
|
744
|
+
'@agentuity/agentId': agent.metadata?.id || '',
|
|
745
|
+
},
|
|
746
|
+
},
|
|
747
|
+
currentContext
|
|
748
|
+
);
|
|
749
|
+
|
|
750
|
+
try {
|
|
751
|
+
const spanContext = trace.setSpan(currentContext, span);
|
|
752
|
+
return await context.with(spanContext, handler);
|
|
753
|
+
} catch (error) {
|
|
754
|
+
span.recordException(error as Error);
|
|
755
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
756
|
+
throw error;
|
|
757
|
+
} finally {
|
|
758
|
+
span.end();
|
|
759
|
+
}
|
|
760
|
+
};
|
|
761
|
+
|
|
211
762
|
const createAgentRunner = <
|
|
212
763
|
TInput extends StandardSchemaV1 | undefined = any,
|
|
213
764
|
TOutput extends StandardSchemaV1 | undefined = any,
|
|
@@ -216,76 +767,127 @@ const createAgentRunner = <
|
|
|
216
767
|
agent: Agent<TInput, TOutput, TStream>,
|
|
217
768
|
ctx: Context
|
|
218
769
|
): AgentRunner<TInput, TOutput, TStream> => {
|
|
770
|
+
const tracer = ctx.var.tracer;
|
|
771
|
+
|
|
219
772
|
if (agent.inputSchema) {
|
|
220
773
|
return {
|
|
221
774
|
metadata: agent.metadata,
|
|
222
775
|
run: async (input: any) => {
|
|
223
|
-
return
|
|
776
|
+
return runWithSpan(tracer, agent as Agent<any, any, any>, () =>
|
|
777
|
+
agent.handler(ctx as unknown as AgentContext, input)
|
|
778
|
+
);
|
|
224
779
|
},
|
|
225
780
|
} as AgentRunner<TInput, TOutput, TStream>;
|
|
226
781
|
} else {
|
|
227
782
|
return {
|
|
228
783
|
metadata: agent.metadata,
|
|
229
784
|
run: async () => {
|
|
230
|
-
return
|
|
785
|
+
return runWithSpan(tracer, agent as Agent<any, any, any>, () =>
|
|
786
|
+
agent.handler(ctx as unknown as AgentContext)
|
|
787
|
+
);
|
|
231
788
|
},
|
|
232
789
|
} as AgentRunner<TInput, TOutput, TStream>;
|
|
233
790
|
}
|
|
234
791
|
};
|
|
235
792
|
|
|
793
|
+
/**
|
|
794
|
+
* Populate the agents object with all registered agents
|
|
795
|
+
*/
|
|
796
|
+
export const populateAgentsRegistry = (ctx: Context): any => {
|
|
797
|
+
const agentsObj: any = {};
|
|
798
|
+
|
|
799
|
+
// Convert kebab-case to camelCase
|
|
800
|
+
const toCamelCase = (str: string): string => {
|
|
801
|
+
return str
|
|
802
|
+
.replace(/[-_\s]+(.)?/g, (_, char) => (char ? char.toUpperCase() : ''))
|
|
803
|
+
.replace(/^(.)/, (char) => char.toLowerCase());
|
|
804
|
+
};
|
|
805
|
+
|
|
806
|
+
// Build nested structure for agents and subagents
|
|
807
|
+
for (const [name, agentFn] of agents) {
|
|
808
|
+
const runner = createAgentRunner(agentFn, ctx);
|
|
809
|
+
|
|
810
|
+
if (name.includes('.')) {
|
|
811
|
+
// Subagent: "parent.child"
|
|
812
|
+
const parts = name.split('.');
|
|
813
|
+
if (parts.length !== 2) {
|
|
814
|
+
internal.warn(`Invalid subagent name format: "${name}". Expected "parent.child".`);
|
|
815
|
+
continue;
|
|
816
|
+
}
|
|
817
|
+
const parentName = parts[0];
|
|
818
|
+
const childName = parts[1];
|
|
819
|
+
if (parentName && childName) {
|
|
820
|
+
if (!agentsObj[parentName]) {
|
|
821
|
+
// Ensure parent exists
|
|
822
|
+
const parentAgent = agents.get(parentName);
|
|
823
|
+
if (parentAgent) {
|
|
824
|
+
agentsObj[parentName] = createAgentRunner(parentAgent, ctx);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
// Attach subagent to parent using camelCase property name
|
|
828
|
+
const camelChildName = toCamelCase(childName);
|
|
829
|
+
if (agentsObj[parentName]) {
|
|
830
|
+
agentsObj[parentName][camelChildName] = runner;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
} else {
|
|
834
|
+
// Parent agent or standalone agent
|
|
835
|
+
agentsObj[name] = runner;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
return agentsObj;
|
|
840
|
+
};
|
|
841
|
+
|
|
236
842
|
export const createAgentMiddleware = (agentName: AgentName): MiddlewareHandler => {
|
|
237
843
|
return async (ctx, next) => {
|
|
238
|
-
// Detect websocket upgrade requests
|
|
239
|
-
const isWebSocket = ctx.req.header('upgrade')?.toLowerCase() === 'websocket';
|
|
240
|
-
|
|
241
844
|
// Populate agents object with strongly-typed keys
|
|
242
|
-
const agentsObj
|
|
243
|
-
|
|
244
|
-
|
|
845
|
+
const agentsObj = populateAgentsRegistry(ctx);
|
|
846
|
+
|
|
847
|
+
// Determine current and parent agents
|
|
848
|
+
let currentAgent: AgentRunner | undefined;
|
|
849
|
+
let parentAgent: AgentRunner | undefined;
|
|
850
|
+
|
|
851
|
+
if (agentName?.includes('.')) {
|
|
852
|
+
// This is a subagent
|
|
853
|
+
const parts = agentName.split('.');
|
|
854
|
+
const parentName = parts[0];
|
|
855
|
+
const childName = parts[1];
|
|
856
|
+
if (parentName && childName) {
|
|
857
|
+
currentAgent = agentsObj[parentName]?.[childName];
|
|
858
|
+
parentAgent = agentsObj[parentName];
|
|
859
|
+
}
|
|
860
|
+
} else if (agentName) {
|
|
861
|
+
// This is a parent or standalone agent
|
|
862
|
+
currentAgent = agentsObj[agentName];
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
const _ctx = privateContext(ctx);
|
|
866
|
+
if (currentAgent?.metadata?.id) {
|
|
867
|
+
_ctx.var.agentIds.add(currentAgent.metadata.id);
|
|
245
868
|
}
|
|
246
869
|
|
|
870
|
+
const sessionId = ctx.var.sessionId;
|
|
871
|
+
const thread = ctx.var.thread;
|
|
872
|
+
const session = ctx.var.session;
|
|
873
|
+
|
|
247
874
|
const args: Partial<RequestAgentContextArgs<AgentRegistry, any>> = {
|
|
248
875
|
agent: agentsObj,
|
|
249
|
-
current:
|
|
876
|
+
current: currentAgent,
|
|
877
|
+
parent: parentAgent,
|
|
250
878
|
agentName,
|
|
251
879
|
logger: ctx.var.logger.child({ agent: agentName }),
|
|
252
880
|
tracer: ctx.var.tracer,
|
|
253
|
-
|
|
881
|
+
sessionId,
|
|
882
|
+
session,
|
|
883
|
+
thread,
|
|
884
|
+
handler: ctx.var.waitUntilHandler,
|
|
254
885
|
};
|
|
255
886
|
|
|
256
|
-
const span = trace.getActiveSpan();
|
|
257
|
-
if (span?.spanContext) {
|
|
258
|
-
args.sessionId = span.spanContext().traceId;
|
|
259
|
-
} else {
|
|
260
|
-
args.sessionId = Bun.randomUUIDv7();
|
|
261
|
-
}
|
|
262
|
-
|
|
263
887
|
return runInAgentContext(
|
|
264
888
|
ctx as unknown as Record<string, unknown>,
|
|
265
889
|
args as RequestAgentContextArgs<any, any>,
|
|
266
|
-
next
|
|
267
|
-
isWebSocket
|
|
890
|
+
next
|
|
268
891
|
);
|
|
269
|
-
|
|
270
|
-
// FIXME
|
|
271
|
-
// ctx.email = async (): Promise<Email> => {
|
|
272
|
-
// return {
|
|
273
|
-
// address: 'test@example.com',
|
|
274
|
-
// name: 'Test User',
|
|
275
|
-
// html: '<p>Hello, world!</p>',
|
|
276
|
-
// text: 'Hello, world!',
|
|
277
|
-
// };
|
|
278
|
-
// };
|
|
279
|
-
// ctx.sms = async (): Promise<SMS> => {
|
|
280
|
-
// return {
|
|
281
|
-
// message: 'Hello, world!',
|
|
282
|
-
// number: '+1234567890',
|
|
283
|
-
// };
|
|
284
|
-
// };
|
|
285
|
-
// ctx.cron = async (): Promise<Cron> => {
|
|
286
|
-
// return {
|
|
287
|
-
// schedule: '0 0 * * *',
|
|
288
|
-
// };
|
|
289
|
-
// };
|
|
290
892
|
};
|
|
291
893
|
};
|