@agentuity/runtime 0.1.13 → 0.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/package.json +8 -8
  2. package/src/_config.ts +13 -0
  3. package/src/_standalone.ts +167 -19
  4. package/src/index.ts +1 -0
  5. package/dist/_config.d.ts +0 -90
  6. package/dist/_config.d.ts.map +0 -1
  7. package/dist/_config.js +0 -135
  8. package/dist/_config.js.map +0 -1
  9. package/dist/_context.d.ts +0 -76
  10. package/dist/_context.d.ts.map +0 -1
  11. package/dist/_context.js +0 -147
  12. package/dist/_context.js.map +0 -1
  13. package/dist/_events.d.ts +0 -64
  14. package/dist/_events.d.ts.map +0 -1
  15. package/dist/_events.js +0 -92
  16. package/dist/_events.js.map +0 -1
  17. package/dist/_idle.d.ts +0 -7
  18. package/dist/_idle.d.ts.map +0 -1
  19. package/dist/_idle.js +0 -10
  20. package/dist/_idle.js.map +0 -1
  21. package/dist/_metadata.d.ts +0 -117
  22. package/dist/_metadata.d.ts.map +0 -1
  23. package/dist/_metadata.js +0 -246
  24. package/dist/_metadata.js.map +0 -1
  25. package/dist/_process-protection.d.ts +0 -25
  26. package/dist/_process-protection.d.ts.map +0 -1
  27. package/dist/_process-protection.js +0 -65
  28. package/dist/_process-protection.js.map +0 -1
  29. package/dist/_server.d.ts +0 -46
  30. package/dist/_server.d.ts.map +0 -1
  31. package/dist/_server.js +0 -85
  32. package/dist/_server.js.map +0 -1
  33. package/dist/_services.d.ts +0 -21
  34. package/dist/_services.d.ts.map +0 -1
  35. package/dist/_services.js +0 -248
  36. package/dist/_services.js.map +0 -1
  37. package/dist/_standalone.d.ts +0 -168
  38. package/dist/_standalone.d.ts.map +0 -1
  39. package/dist/_standalone.js +0 -441
  40. package/dist/_standalone.js.map +0 -1
  41. package/dist/_tokens.d.ts +0 -12
  42. package/dist/_tokens.d.ts.map +0 -1
  43. package/dist/_tokens.js +0 -96
  44. package/dist/_tokens.js.map +0 -1
  45. package/dist/_util.d.ts +0 -16
  46. package/dist/_util.d.ts.map +0 -1
  47. package/dist/_util.js +0 -54
  48. package/dist/_util.js.map +0 -1
  49. package/dist/_validation.d.ts +0 -89
  50. package/dist/_validation.d.ts.map +0 -1
  51. package/dist/_validation.js +0 -29
  52. package/dist/_validation.js.map +0 -1
  53. package/dist/_waituntil.d.ts +0 -18
  54. package/dist/_waituntil.d.ts.map +0 -1
  55. package/dist/_waituntil.js +0 -97
  56. package/dist/_waituntil.js.map +0 -1
  57. package/dist/agent.d.ts +0 -1210
  58. package/dist/agent.d.ts.map +0 -1
  59. package/dist/agent.js +0 -903
  60. package/dist/agent.js.map +0 -1
  61. package/dist/app.d.ts +0 -322
  62. package/dist/app.d.ts.map +0 -1
  63. package/dist/app.js +0 -160
  64. package/dist/app.js.map +0 -1
  65. package/dist/bun-s3-patch.d.ts +0 -37
  66. package/dist/bun-s3-patch.d.ts.map +0 -1
  67. package/dist/bun-s3-patch.js +0 -139
  68. package/dist/bun-s3-patch.js.map +0 -1
  69. package/dist/cors.d.ts +0 -42
  70. package/dist/cors.d.ts.map +0 -1
  71. package/dist/cors.js +0 -117
  72. package/dist/cors.js.map +0 -1
  73. package/dist/devmode.d.ts +0 -3
  74. package/dist/devmode.d.ts.map +0 -1
  75. package/dist/devmode.js +0 -167
  76. package/dist/devmode.js.map +0 -1
  77. package/dist/eval.d.ts +0 -91
  78. package/dist/eval.d.ts.map +0 -1
  79. package/dist/eval.js +0 -16
  80. package/dist/eval.js.map +0 -1
  81. package/dist/handlers/cron.d.ts +0 -47
  82. package/dist/handlers/cron.d.ts.map +0 -1
  83. package/dist/handlers/cron.js +0 -49
  84. package/dist/handlers/cron.js.map +0 -1
  85. package/dist/handlers/index.d.ts +0 -5
  86. package/dist/handlers/index.d.ts.map +0 -1
  87. package/dist/handlers/index.js +0 -5
  88. package/dist/handlers/index.js.map +0 -1
  89. package/dist/handlers/sse.d.ts +0 -91
  90. package/dist/handlers/sse.d.ts.map +0 -1
  91. package/dist/handlers/sse.js +0 -213
  92. package/dist/handlers/sse.js.map +0 -1
  93. package/dist/handlers/stream.d.ts +0 -52
  94. package/dist/handlers/stream.d.ts.map +0 -1
  95. package/dist/handlers/stream.js +0 -116
  96. package/dist/handlers/stream.js.map +0 -1
  97. package/dist/handlers/websocket.d.ts +0 -49
  98. package/dist/handlers/websocket.d.ts.map +0 -1
  99. package/dist/handlers/websocket.js +0 -143
  100. package/dist/handlers/websocket.js.map +0 -1
  101. package/dist/index.d.ts +0 -71
  102. package/dist/index.d.ts.map +0 -1
  103. package/dist/index.js +0 -58
  104. package/dist/index.js.map +0 -1
  105. package/dist/logger/console.d.ts +0 -70
  106. package/dist/logger/console.d.ts.map +0 -1
  107. package/dist/logger/console.js +0 -274
  108. package/dist/logger/console.js.map +0 -1
  109. package/dist/logger/index.d.ts +0 -3
  110. package/dist/logger/index.d.ts.map +0 -1
  111. package/dist/logger/index.js +0 -3
  112. package/dist/logger/index.js.map +0 -1
  113. package/dist/logger/internal.d.ts +0 -79
  114. package/dist/logger/internal.d.ts.map +0 -1
  115. package/dist/logger/internal.js +0 -133
  116. package/dist/logger/internal.js.map +0 -1
  117. package/dist/logger/logger.d.ts +0 -41
  118. package/dist/logger/logger.d.ts.map +0 -1
  119. package/dist/logger/logger.js +0 -2
  120. package/dist/logger/logger.js.map +0 -1
  121. package/dist/logger/user.d.ts +0 -8
  122. package/dist/logger/user.d.ts.map +0 -1
  123. package/dist/logger/user.js +0 -7
  124. package/dist/logger/user.js.map +0 -1
  125. package/dist/logger/util.d.ts +0 -11
  126. package/dist/logger/util.d.ts.map +0 -1
  127. package/dist/logger/util.js +0 -77
  128. package/dist/logger/util.js.map +0 -1
  129. package/dist/middleware.d.ts +0 -112
  130. package/dist/middleware.d.ts.map +0 -1
  131. package/dist/middleware.js +0 -507
  132. package/dist/middleware.js.map +0 -1
  133. package/dist/otel/config.d.ts +0 -19
  134. package/dist/otel/config.d.ts.map +0 -1
  135. package/dist/otel/config.js +0 -26
  136. package/dist/otel/config.js.map +0 -1
  137. package/dist/otel/console.d.ts +0 -33
  138. package/dist/otel/console.d.ts.map +0 -1
  139. package/dist/otel/console.js +0 -86
  140. package/dist/otel/console.js.map +0 -1
  141. package/dist/otel/exporters/index.d.ts +0 -4
  142. package/dist/otel/exporters/index.d.ts.map +0 -1
  143. package/dist/otel/exporters/index.js +0 -4
  144. package/dist/otel/exporters/index.js.map +0 -1
  145. package/dist/otel/exporters/jsonl-log-exporter.d.ts +0 -36
  146. package/dist/otel/exporters/jsonl-log-exporter.d.ts.map +0 -1
  147. package/dist/otel/exporters/jsonl-log-exporter.js +0 -103
  148. package/dist/otel/exporters/jsonl-log-exporter.js.map +0 -1
  149. package/dist/otel/exporters/jsonl-metric-exporter.d.ts +0 -40
  150. package/dist/otel/exporters/jsonl-metric-exporter.d.ts.map +0 -1
  151. package/dist/otel/exporters/jsonl-metric-exporter.js +0 -104
  152. package/dist/otel/exporters/jsonl-metric-exporter.js.map +0 -1
  153. package/dist/otel/exporters/jsonl-trace-exporter.d.ts +0 -36
  154. package/dist/otel/exporters/jsonl-trace-exporter.d.ts.map +0 -1
  155. package/dist/otel/exporters/jsonl-trace-exporter.js +0 -111
  156. package/dist/otel/exporters/jsonl-trace-exporter.js.map +0 -1
  157. package/dist/otel/fetch.d.ts +0 -12
  158. package/dist/otel/fetch.d.ts.map +0 -1
  159. package/dist/otel/fetch.js +0 -82
  160. package/dist/otel/fetch.js.map +0 -1
  161. package/dist/otel/http.d.ts +0 -16
  162. package/dist/otel/http.d.ts.map +0 -1
  163. package/dist/otel/http.js +0 -44
  164. package/dist/otel/http.js.map +0 -1
  165. package/dist/otel/logger.d.ts +0 -37
  166. package/dist/otel/logger.d.ts.map +0 -1
  167. package/dist/otel/logger.js +0 -268
  168. package/dist/otel/logger.js.map +0 -1
  169. package/dist/otel/otel.d.ts +0 -65
  170. package/dist/otel/otel.d.ts.map +0 -1
  171. package/dist/otel/otel.js +0 -261
  172. package/dist/otel/otel.js.map +0 -1
  173. package/dist/router.d.ts +0 -100
  174. package/dist/router.d.ts.map +0 -1
  175. package/dist/router.js +0 -163
  176. package/dist/router.js.map +0 -1
  177. package/dist/services/evalrun/composite.d.ts +0 -21
  178. package/dist/services/evalrun/composite.d.ts.map +0 -1
  179. package/dist/services/evalrun/composite.js +0 -26
  180. package/dist/services/evalrun/composite.js.map +0 -1
  181. package/dist/services/evalrun/http.d.ts +0 -24
  182. package/dist/services/evalrun/http.d.ts.map +0 -1
  183. package/dist/services/evalrun/http.js +0 -86
  184. package/dist/services/evalrun/http.js.map +0 -1
  185. package/dist/services/evalrun/index.d.ts +0 -5
  186. package/dist/services/evalrun/index.d.ts.map +0 -1
  187. package/dist/services/evalrun/index.js +0 -5
  188. package/dist/services/evalrun/index.js.map +0 -1
  189. package/dist/services/evalrun/json.d.ts +0 -21
  190. package/dist/services/evalrun/json.d.ts.map +0 -1
  191. package/dist/services/evalrun/json.js +0 -38
  192. package/dist/services/evalrun/json.js.map +0 -1
  193. package/dist/services/evalrun/local.d.ts +0 -19
  194. package/dist/services/evalrun/local.d.ts.map +0 -1
  195. package/dist/services/evalrun/local.js +0 -22
  196. package/dist/services/evalrun/local.js.map +0 -1
  197. package/dist/services/local/_db.d.ts +0 -4
  198. package/dist/services/local/_db.d.ts.map +0 -1
  199. package/dist/services/local/_db.js +0 -123
  200. package/dist/services/local/_db.js.map +0 -1
  201. package/dist/services/local/_router.d.ts +0 -3
  202. package/dist/services/local/_router.d.ts.map +0 -1
  203. package/dist/services/local/_router.js +0 -28
  204. package/dist/services/local/_router.js.map +0 -1
  205. package/dist/services/local/_util.d.ts +0 -18
  206. package/dist/services/local/_util.d.ts.map +0 -1
  207. package/dist/services/local/_util.js +0 -44
  208. package/dist/services/local/_util.js.map +0 -1
  209. package/dist/services/local/index.d.ts +0 -7
  210. package/dist/services/local/index.d.ts.map +0 -1
  211. package/dist/services/local/index.js +0 -7
  212. package/dist/services/local/index.js.map +0 -1
  213. package/dist/services/local/keyvalue.d.ts +0 -17
  214. package/dist/services/local/keyvalue.d.ts.map +0 -1
  215. package/dist/services/local/keyvalue.js +0 -125
  216. package/dist/services/local/keyvalue.js.map +0 -1
  217. package/dist/services/local/stream.d.ts +0 -12
  218. package/dist/services/local/stream.d.ts.map +0 -1
  219. package/dist/services/local/stream.js +0 -262
  220. package/dist/services/local/stream.js.map +0 -1
  221. package/dist/services/local/vector.d.ts +0 -17
  222. package/dist/services/local/vector.d.ts.map +0 -1
  223. package/dist/services/local/vector.js +0 -303
  224. package/dist/services/local/vector.js.map +0 -1
  225. package/dist/services/sandbox/http.d.ts +0 -13
  226. package/dist/services/sandbox/http.d.ts.map +0 -1
  227. package/dist/services/sandbox/http.js +0 -130
  228. package/dist/services/sandbox/http.js.map +0 -1
  229. package/dist/services/sandbox/index.d.ts +0 -2
  230. package/dist/services/sandbox/index.d.ts.map +0 -1
  231. package/dist/services/sandbox/index.js +0 -2
  232. package/dist/services/sandbox/index.js.map +0 -1
  233. package/dist/services/session/composite.d.ts +0 -21
  234. package/dist/services/session/composite.d.ts.map +0 -1
  235. package/dist/services/session/composite.js +0 -26
  236. package/dist/services/session/composite.js.map +0 -1
  237. package/dist/services/session/http.d.ts +0 -34
  238. package/dist/services/session/http.d.ts.map +0 -1
  239. package/dist/services/session/http.js +0 -80
  240. package/dist/services/session/http.js.map +0 -1
  241. package/dist/services/session/index.d.ts +0 -5
  242. package/dist/services/session/index.d.ts.map +0 -1
  243. package/dist/services/session/index.js +0 -5
  244. package/dist/services/session/index.js.map +0 -1
  245. package/dist/services/session/json.d.ts +0 -22
  246. package/dist/services/session/json.d.ts.map +0 -1
  247. package/dist/services/session/json.js +0 -35
  248. package/dist/services/session/json.js.map +0 -1
  249. package/dist/services/session/local.d.ts +0 -19
  250. package/dist/services/session/local.d.ts.map +0 -1
  251. package/dist/services/session/local.js +0 -23
  252. package/dist/services/session/local.js.map +0 -1
  253. package/dist/services/thread/local.d.ts +0 -20
  254. package/dist/services/thread/local.d.ts.map +0 -1
  255. package/dist/services/thread/local.js +0 -158
  256. package/dist/services/thread/local.js.map +0 -1
  257. package/dist/session.d.ts +0 -734
  258. package/dist/session.d.ts.map +0 -1
  259. package/dist/session.js +0 -1139
  260. package/dist/session.js.map +0 -1
  261. package/dist/validator.d.ts +0 -142
  262. package/dist/validator.d.ts.map +0 -1
  263. package/dist/validator.js +0 -149
  264. package/dist/validator.js.map +0 -1
  265. package/dist/web.d.ts +0 -8
  266. package/dist/web.d.ts.map +0 -1
  267. package/dist/web.js +0 -66
  268. package/dist/web.js.map +0 -1
  269. package/dist/workbench.d.ts +0 -17
  270. package/dist/workbench.d.ts.map +0 -1
  271. package/dist/workbench.js +0 -507
  272. package/dist/workbench.js.map +0 -1
package/dist/agent.js DELETED
@@ -1,903 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { StructuredError, toCamelCase, } from '@agentuity/core';
3
- import { context, SpanStatusCode, trace } from '@opentelemetry/api';
4
- import { TraceState } from '@opentelemetry/core';
5
- import { validator } from 'hono/validator';
6
- import { AGENT_RUNTIME, INTERNAL_AGENT, CURRENT_AGENT, AGENT_IDS } from './_config';
7
- import { getAgentContext, inHTTPContext, getHTTPContext, setupRequestAgentContext, getAgentAsyncLocalStorage, } from './_context';
8
- import { internal } from './logger/internal';
9
- import { fireEvent } from './_events';
10
- import { privateContext } from './_server';
11
- import { generateId } from './session';
12
- import { getEvalRunEventProvider } from './_services';
13
- import * as runtimeConfig from './_config';
14
- import { validateSchema, formatValidationIssues } from './_validation';
15
- import { getAgentMetadataByName, getEvalMetadata } from './_metadata';
16
- // Will be populated at runtime with strongly typed agents
17
- const agents = new Map();
18
- // WeakMap to store event listeners for each agent instance (truly private)
19
- const agentEventListeners = new WeakMap();
20
- // Map to store agent configs returned from setup (keyed by agent name)
21
- const agentConfigs = new Map();
22
- /**
23
- * Get the global runtime state (for production use).
24
- * In tests, use TestAgentContext which has isolated runtime state.
25
- */
26
- export function getGlobalRuntimeState() {
27
- return {
28
- agents,
29
- agentConfigs,
30
- agentEventListeners,
31
- };
32
- }
33
- /**
34
- * Get the runtime state from an AgentContext.
35
- * @internal
36
- */
37
- export function getAgentRuntime(ctx) {
38
- return ctx[AGENT_RUNTIME];
39
- }
40
- async function fireAgentEvent(runtime, agent, eventName, context, data) {
41
- // Fire agent-level listeners
42
- const listeners = runtime.agentEventListeners.get(agent);
43
- if (listeners) {
44
- const callbacks = listeners.get(eventName);
45
- if (callbacks && callbacks.size > 0) {
46
- for (const callback of callbacks) {
47
- try {
48
- if (eventName === 'errored' && data) {
49
- await callback(eventName, agent, context, data);
50
- }
51
- else if (eventName === 'started' || eventName === 'completed') {
52
- await callback(eventName, agent, context);
53
- }
54
- }
55
- catch (error) {
56
- // Log but don't re-throw - event listener errors should not crash the server
57
- internal.error(`Error in agent event listener for '${eventName}':`, error);
58
- }
59
- }
60
- }
61
- }
62
- // Fire global app-level events
63
- if (eventName === 'errored' && data) {
64
- await fireEvent('agent.errored', agent, context, data);
65
- }
66
- else if (eventName === 'started') {
67
- await fireEvent('agent.started', agent, context);
68
- }
69
- else if (eventName === 'completed') {
70
- await fireEvent('agent.completed', agent, context);
71
- }
72
- }
73
- export const registerAgent = (name, agent) => {
74
- agents.set(name, agent);
75
- };
76
- export const setAgentConfig = (name, config) => {
77
- agentConfigs.set(name, config);
78
- };
79
- export const getAgentConfig = (name) => {
80
- return agentConfigs.get(name);
81
- };
82
- const ValidationError = StructuredError('ValidationError')();
83
- // Implementation
84
- export function createAgent(name, config) {
85
- const inputSchema = config.schema?.input;
86
- const outputSchema = config.schema?.output;
87
- // Initialize evals array before handler so it can be captured in closure
88
- // Evals should only be added via agent.createEval() after agent creation
89
- const evalsArray = [];
90
- const handler = async (input) => {
91
- let validatedInput = undefined;
92
- if (inputSchema) {
93
- const inputResult = await inputSchema['~standard'].validate(input);
94
- if (inputResult.issues) {
95
- throw new ValidationError({
96
- issues: inputResult.issues,
97
- message: `Input validation failed: ${inputResult.issues.map((i) => i.message).join(', ')}`,
98
- });
99
- }
100
- validatedInput = inputResult.value;
101
- }
102
- const agentCtx = getAgentContext();
103
- // Store current agent for telemetry (using Symbol to keep it internal)
104
- agentCtx[CURRENT_AGENT] = agent;
105
- // Expose current agent metadata on the context
106
- agentCtx.current = agent.metadata;
107
- const attrs = {
108
- '@agentuity/agentId': agent.metadata.id,
109
- '@agentuity/agentInstanceId': agent.metadata.agentId,
110
- '@agentuity/agentDescription': agent.metadata.description,
111
- '@agentuity/agentName': agent.metadata.name,
112
- '@agentuity/threadId': agentCtx.thread.id,
113
- };
114
- // Set agent attributes on the current active span
115
- const activeSpan = trace.getActiveSpan();
116
- if (activeSpan) {
117
- activeSpan.setAttributes(attrs);
118
- }
119
- if (inHTTPContext()) {
120
- const honoCtx = privateContext(getHTTPContext());
121
- if (honoCtx.var.agentIds) {
122
- if (agent.metadata.id)
123
- honoCtx.var.agentIds.add(agent.metadata.id);
124
- if (agent.metadata.agentId)
125
- honoCtx.var.agentIds.add(agent.metadata.agentId);
126
- }
127
- }
128
- else {
129
- // For standalone contexts, check for AGENT_IDS symbol
130
- const agentIds = agentCtx[AGENT_IDS];
131
- if (agentIds) {
132
- if (agent.metadata.id)
133
- agentIds.add(agent.metadata.id);
134
- if (agent.metadata.agentId)
135
- agentIds.add(agent.metadata.agentId);
136
- }
137
- }
138
- agentCtx.logger = agentCtx.logger.child(attrs);
139
- // Get the agent instance from the runtime state to fire events
140
- const runtime = getAgentRuntime(agentCtx);
141
- // Fire 'started' event
142
- await fireAgentEvent(runtime, agent, 'started', agentCtx);
143
- try {
144
- // Wrap agent execution with span tracking if tracer is available
145
- const result = await (async () => {
146
- if (agentCtx.tracer && inHTTPContext()) {
147
- const honoCtx = getHTTPContext();
148
- return runWithSpan(agentCtx.tracer, agent, honoCtx, async () => inputSchema
149
- ? await config.handler(agentCtx, validatedInput)
150
- : await config.handler(agentCtx));
151
- }
152
- else if (agent.metadata.id) {
153
- // For standalone contexts, wrap with agent context to set aid in trace state
154
- return runWithAgentContext(agent.metadata.id, () => inputSchema
155
- ? config.handler(agentCtx, validatedInput)
156
- : config.handler(agentCtx));
157
- }
158
- else {
159
- // No agent ID, invoke handler directly
160
- return inputSchema
161
- ? config.handler(agentCtx, validatedInput)
162
- : config.handler(agentCtx);
163
- }
164
- })();
165
- let validatedOutput = result;
166
- // Skip output validation for streaming agents (they return ReadableStream)
167
- if (outputSchema && !config.schema?.stream) {
168
- const outputResult = await outputSchema['~standard'].validate(result);
169
- if (outputResult.issues) {
170
- throw new ValidationError({
171
- issues: outputResult.issues,
172
- message: `Output validation failed: ${outputResult.issues.map((i) => i.message).join(', ')}`,
173
- });
174
- }
175
- validatedOutput = outputResult.value;
176
- }
177
- // Store validated input/output in context state for event listeners
178
- agentCtx.state.set('_evalInput', validatedInput);
179
- agentCtx.state.set('_evalOutput', validatedOutput);
180
- // Fire 'completed' event - evals will run via event listener
181
- await fireAgentEvent(runtime, agent, 'completed', agentCtx);
182
- return validatedOutput;
183
- }
184
- catch (error) {
185
- // Fire 'errored' event
186
- await fireAgentEvent(runtime, agent, 'errored', agentCtx, error);
187
- throw error;
188
- }
189
- };
190
- // Create createEval method that infers types from agent and automatically adds to agent
191
- const createEval = ((evalNameOrConfig, evalConfig) => {
192
- // Handle preset eval config (single argument with name property)
193
- if (typeof evalNameOrConfig !== 'string' && 'name' in evalNameOrConfig) {
194
- const presetConfig = evalNameOrConfig;
195
- const evalName = presetConfig.name;
196
- internal.debug(`createEval called for agent "${name || 'unknown'}": registering preset eval "${evalName}"`);
197
- const evalType = {
198
- metadata: {
199
- identifier: evalName,
200
- name: evalName,
201
- description: presetConfig.description || '',
202
- },
203
- handler: presetConfig.handler,
204
- };
205
- if (inputSchema) {
206
- evalType.inputSchema = inputSchema;
207
- }
208
- if (outputSchema) {
209
- evalType.outputSchema = outputSchema;
210
- }
211
- evalsArray.push(evalType);
212
- internal.debug(`Added preset eval "${evalName}" to agent "${name || 'unknown'}". Total evals: ${evalsArray.length}`);
213
- return evalType;
214
- }
215
- // Handle custom eval config (name + config)
216
- if (typeof evalNameOrConfig !== 'string' || !evalConfig) {
217
- throw new Error('Invalid arguments: expected (name: string, config) or (config: PresetEvalConfig)');
218
- }
219
- const evalName = evalNameOrConfig;
220
- // Trace log to verify evals file is imported
221
- internal.debug(`createEval called for agent "${name || 'unknown'}": registering eval "${evalName}"`);
222
- // Use build-time injected metadata if available (same pattern as agents)
223
- const evalMetadata = evalConfig.metadata || {};
224
- // Build eval metadata - merge injected metadata with defaults
225
- const evalType = {
226
- metadata: {
227
- // Use build-time injected metadata if available, otherwise fallback to empty/undefined
228
- id: evalMetadata.id || undefined,
229
- identifier: evalMetadata.identifier || undefined,
230
- version: evalMetadata.version || undefined,
231
- filename: evalMetadata.filename || '',
232
- name: evalName,
233
- description: evalConfig.description || '',
234
- },
235
- handler: evalConfig.handler,
236
- };
237
- if (inputSchema) {
238
- evalType.inputSchema = inputSchema;
239
- }
240
- if (outputSchema) {
241
- evalType.outputSchema = outputSchema;
242
- }
243
- // Automatically add eval to agent's evals array
244
- evalsArray.push(evalType);
245
- internal.debug(`Added eval "${evalName}" to agent "${name || 'unknown'}". Total evals: ${evalsArray.length}`);
246
- return evalType;
247
- });
248
- // Build metadata - merge user-provided metadata with defaults
249
- // The build plugin injects metadata via config.metadata during AST transformation
250
- let metadata = {
251
- // Defaults (used when running without build, e.g., dev mode)
252
- name,
253
- description: config.description,
254
- id: '',
255
- agentId: '',
256
- filename: '',
257
- version: '',
258
- inputSchemaCode: '',
259
- outputSchemaCode: '',
260
- // Merge in build-time injected metadata (overrides defaults)
261
- ...config.metadata,
262
- };
263
- // If id/agentId are empty, try to load from agentuity.metadata.json
264
- if (!metadata.id || !metadata.agentId) {
265
- const fileMetadata = getAgentMetadataByName(name);
266
- if (fileMetadata) {
267
- internal.info('[agent] loaded metadata for "%s" from file: id=%s, agentId=%s', name, fileMetadata.id, fileMetadata.agentId);
268
- metadata = {
269
- ...metadata,
270
- id: fileMetadata.id || metadata.id,
271
- agentId: fileMetadata.agentId || metadata.agentId,
272
- filename: fileMetadata.filename || metadata.filename,
273
- version: fileMetadata.version || metadata.version,
274
- };
275
- }
276
- }
277
- // Error if agent has no metadata IDs in production - this causes agent_ids to be empty in sessions
278
- // which affects analytics, billing attribution, and session filtering
279
- // Only enforce in production (when AGENTUITY_CLOUD_PROJECT_ID is set) to allow dev/test without metadata
280
- if (!metadata.id && !metadata.agentId && runtimeConfig.getProjectId()) {
281
- throw new Error(`Agent "${name}" has no metadata IDs (id and agentId are empty). ` +
282
- `This will result in empty agent_ids in session events. ` +
283
- `Ensure agentuity.metadata.json exists in the runtime directory ` +
284
- `(checked: ${process.cwd()}/agentuity.metadata.json and ${process.cwd()}/.agentuity/agentuity.metadata.json). ` +
285
- `Run 'agentuity build' to generate the metadata file.`);
286
- }
287
- const agent = {
288
- handler,
289
- metadata,
290
- evals: evalsArray,
291
- createEval,
292
- setup: config.setup,
293
- shutdown: config.shutdown,
294
- };
295
- // Add event listener methods
296
- agent.addEventListener = (eventName, callback) => {
297
- const agentForListeners = agent;
298
- const callbackForListeners = callback;
299
- let listeners = agentEventListeners.get(agentForListeners);
300
- if (!listeners) {
301
- listeners = new Map();
302
- agentEventListeners.set(agentForListeners, listeners);
303
- }
304
- let callbacks = listeners.get(eventName);
305
- if (!callbacks) {
306
- callbacks = new Set();
307
- listeners.set(eventName, callbacks);
308
- }
309
- callbacks.add(callbackForListeners);
310
- };
311
- // Automatically add event listener for 'completed' event to run evals
312
- agent.addEventListener('completed', async (_event, _agent, ctx) => {
313
- // Use the agent instance passed to event listener to access its evals array
314
- // This ensures we get evals that were added via agent.createEval() after agent creation
315
- const agentEvals = _agent?.evals || evalsArray;
316
- internal.debug(`Checking evals: agent=${_agent.metadata?.name}, evalsArray.length=${evalsArray?.length || 0}, agent.evals.length=${_agent?.evals?.length || 0}`);
317
- if (agentEvals && agentEvals.length > 0) {
318
- internal.info(`Executing ${agentEvals.length} eval(s) after agent run`);
319
- // Get validated input/output from context state
320
- const validatedInput = ctx.state.get('_evalInput');
321
- const validatedOutput = ctx.state.get('_evalOutput');
322
- // Capture agentRunSpanId synchronously before waitUntil (which may run outside AsyncLocalStorage)
323
- let agentRunSpanId;
324
- try {
325
- const httpCtx = getHTTPContext();
326
- const _httpCtx = privateContext(httpCtx);
327
- agentRunSpanId = _httpCtx.var.agentRunSpanId;
328
- }
329
- catch {
330
- // HTTP context may not be available, spanId will be undefined
331
- }
332
- // Execute each eval using waitUntil to avoid blocking the response
333
- for (const evalItem of agentEvals) {
334
- const evalName = evalItem.metadata.name || 'unnamed';
335
- const agentName = _agent?.metadata?.name || name;
336
- ctx.waitUntil((async () => {
337
- internal.info(`[EVALRUN] Starting eval run tracking for '${evalName}'`);
338
- const evalRunId = generateId('evalrun');
339
- // Look up eval metadata from agentuity.metadata.json by agent name and eval name
340
- internal.info(`[EVALRUN] Looking up eval metadata: agentName='${agentName}', evalName='${evalName}'`);
341
- const evalMeta = getEvalMetadata(agentName, evalName);
342
- internal.info(`[EVALRUN] Eval metadata lookup result:`, {
343
- found: !!evalMeta,
344
- identifier: evalMeta?.identifier,
345
- id: evalMeta?.id,
346
- filename: evalMeta?.filename,
347
- });
348
- // evalId = deployment-specific ID (evalid_...), evalIdentifier = stable (eval_...)
349
- const evalId = evalMeta?.id || '';
350
- const evalIdentifier = evalMeta?.identifier || '';
351
- internal.info(`[EVALRUN] Resolved evalId='${evalId}', evalIdentifier='${evalIdentifier}'`);
352
- // Log eval metadata using structured logging and tracing
353
- ctx.logger.debug('Starting eval run with metadata', {
354
- evalName,
355
- agentName,
356
- evalRunId,
357
- evalId,
358
- evalMetaFromFile: !!evalMeta,
359
- evalMetadata: evalItem.metadata,
360
- });
361
- // Add eval metadata to the active span for observability
362
- const activeSpan = ctx.tracer ? trace.getActiveSpan() : undefined;
363
- if (activeSpan) {
364
- activeSpan.setAttributes({
365
- 'eval.name': evalName,
366
- 'eval.id': evalId,
367
- 'eval.runId': evalRunId,
368
- 'eval.description': evalMeta?.description || evalItem.metadata.description || '',
369
- 'eval.filename': evalMeta?.filename || evalItem.metadata.filename || '',
370
- });
371
- }
372
- const orgId = runtimeConfig.getOrganizationId();
373
- const projectId = runtimeConfig.getProjectId();
374
- const devMode = runtimeConfig.isDevMode() ?? false;
375
- const evalRunEventProvider = getEvalRunEventProvider();
376
- // Only send events if we have required context (devmode flag will be set based on devMode)
377
- const shouldSendEvalRunEvents = orgId && projectId && evalId !== '' && evalIdentifier !== '';
378
- internal.info(`[EVALRUN] Checking conditions for eval '${evalName}':`, {
379
- orgId: orgId,
380
- projectId: projectId,
381
- evalId: evalId,
382
- evalIdentifier: evalIdentifier,
383
- devMode,
384
- hasEvalRunEventProvider: !!evalRunEventProvider,
385
- shouldSendEvalRunEvents,
386
- });
387
- if (!shouldSendEvalRunEvents) {
388
- const reasons = [];
389
- if (!orgId)
390
- reasons.push('missing orgId');
391
- if (!projectId)
392
- reasons.push('missing projectId');
393
- if (!evalId || evalId === '')
394
- reasons.push('empty evalId');
395
- if (!evalIdentifier || evalIdentifier === '')
396
- reasons.push('empty evalIdentifier');
397
- internal.info(`[EVALRUN] Skipping eval run events for '${evalName}': ${reasons.join(', ')}`);
398
- }
399
- try {
400
- internal.debug(`Executing eval: ${evalName}`);
401
- // Send eval run start event
402
- if (shouldSendEvalRunEvents && evalRunEventProvider) {
403
- internal.info(`[EVALRUN] Sending start event for eval '${evalName}' (id: ${evalRunId}, evalId: ${evalId})`);
404
- try {
405
- const deploymentId = runtimeConfig.getDeploymentId();
406
- // Use captured agentRunSpanId (may be undefined if HTTP context unavailable)
407
- if (!agentRunSpanId) {
408
- internal.warn(`[EVALRUN] agentRunSpanId not available for eval '${evalName}' (id: ${evalRunId}). This may occur if waitUntil runs outside AsyncLocalStorage context.`);
409
- }
410
- const startEvent = {
411
- id: evalRunId,
412
- sessionId: ctx.sessionId,
413
- evalId: evalId, // deployment-specific ID (evalid_...)
414
- evalIdentifier: evalIdentifier, // stable identifier (eval_...)
415
- orgId: orgId,
416
- projectId: projectId,
417
- devmode: Boolean(devMode),
418
- deploymentId: deploymentId || undefined,
419
- spanId: agentRunSpanId,
420
- };
421
- internal.debug('[EVALRUN] Start event payload: %s', JSON.stringify(startEvent, null, 2));
422
- await evalRunEventProvider.start(startEvent);
423
- internal.info(`[EVALRUN] Start event sent successfully for eval '${evalName}' (id: ${evalRunId})`);
424
- }
425
- catch (error) {
426
- internal.error(`[EVALRUN] Error sending eval run start event for '${evalName}' (id: ${evalRunId})`, {
427
- error,
428
- });
429
- // Don't throw - continue with eval execution even if start event fails
430
- }
431
- }
432
- else if (shouldSendEvalRunEvents && !evalRunEventProvider) {
433
- internal.warn(`[EVALRUN] Conditions met but no evalRunEventProvider available for '${evalName}'`);
434
- }
435
- else {
436
- internal.debug(`[EVALRUN] Not sending start event for '${evalName}': shouldSendEvalRunEvents=${shouldSendEvalRunEvents}, hasProvider=${!!evalRunEventProvider}`);
437
- }
438
- // Validate eval input if schema exists
439
- let evalValidatedInput = validatedInput;
440
- if (evalItem.inputSchema) {
441
- const evalInputResult = await evalItem.inputSchema['~standard'].validate(validatedInput);
442
- if (evalInputResult.issues) {
443
- throw new ValidationError({
444
- issues: evalInputResult.issues,
445
- message: `Eval input validation failed: ${evalInputResult.issues.map((i) => i.message).join(', ')}`,
446
- });
447
- }
448
- evalValidatedInput = evalInputResult.value;
449
- }
450
- // Validate eval output if schema exists
451
- let evalValidatedOutput = validatedOutput;
452
- if (evalItem.outputSchema) {
453
- const evalOutputResult = await evalItem.outputSchema['~standard'].validate(validatedOutput);
454
- if (evalOutputResult.issues) {
455
- throw new ValidationError({
456
- issues: evalOutputResult.issues,
457
- message: `Eval output validation failed: ${evalOutputResult.issues.map((i) => i.message).join(', ')}`,
458
- });
459
- }
460
- evalValidatedOutput = evalOutputResult.value;
461
- }
462
- // Create EvalContext (just an alias for AgentContext)
463
- const evalContext = ctx;
464
- // Execute the eval handler conditionally based on agent schema
465
- let handlerResult;
466
- if (inputSchema && outputSchema) {
467
- // Both input and output defined
468
- handlerResult = await evalItem.handler(evalContext, evalValidatedInput, evalValidatedOutput);
469
- }
470
- else if (inputSchema) {
471
- // Only input defined
472
- handlerResult = await evalItem.handler(evalContext, evalValidatedInput);
473
- }
474
- else if (outputSchema) {
475
- // Only output defined
476
- handlerResult = await evalItem.handler(evalContext, evalValidatedOutput);
477
- }
478
- else {
479
- // Neither defined
480
- handlerResult = await evalItem.handler(evalContext);
481
- }
482
- // Wrap handler result with success for catalyst
483
- const result = {
484
- success: true,
485
- ...handlerResult,
486
- };
487
- // Log the result
488
- if (result.score !== undefined) {
489
- internal.info(`Eval '${evalName}' pass: ${result.passed}, score: ${result.score}`, result.metadata);
490
- }
491
- else {
492
- internal.info(`Eval '${evalName}' pass: ${result.passed}`, result.metadata);
493
- }
494
- // Send eval run complete event
495
- if (shouldSendEvalRunEvents && evalRunEventProvider) {
496
- internal.info(`[EVALRUN] Sending complete event for eval '${evalName}' (id: ${evalRunId})`);
497
- try {
498
- await evalRunEventProvider.complete({
499
- id: evalRunId,
500
- result,
501
- });
502
- internal.info(`[EVALRUN] Complete event sent successfully for eval '${evalName}' (id: ${evalRunId})`);
503
- }
504
- catch (error) {
505
- internal.error(`[EVALRUN] Error sending eval run complete event for '${evalName}' (id: ${evalRunId})`, {
506
- error,
507
- });
508
- }
509
- }
510
- internal.debug(`Eval '${evalName}' completed successfully`);
511
- }
512
- catch (error) {
513
- const errorMessage = error instanceof Error ? error.message : String(error);
514
- internal.error(`Error executing eval '${evalName}'`, { error });
515
- // Send eval run complete event with error
516
- if (shouldSendEvalRunEvents && evalRunEventProvider) {
517
- internal.info(`[EVALRUN] Sending complete event (error) for eval '${evalName}' (id: ${evalRunId})`);
518
- try {
519
- await evalRunEventProvider.complete({
520
- id: evalRunId,
521
- error: errorMessage,
522
- result: {
523
- success: false,
524
- passed: false,
525
- error: errorMessage,
526
- metadata: {},
527
- },
528
- });
529
- internal.info(`[EVALRUN] Complete event (error) sent successfully for eval '${evalName}' (id: ${evalRunId})`);
530
- }
531
- catch (eventError) {
532
- internal.error(`[EVALRUN] Error sending eval run complete event (error) for '${evalName}' (id: ${evalRunId})`, { error: eventError });
533
- }
534
- }
535
- }
536
- })());
537
- }
538
- }
539
- });
540
- agent.removeEventListener = (eventName, callback) => {
541
- const agentForListeners = agent;
542
- const callbackForListeners = callback;
543
- const listeners = agentEventListeners.get(agentForListeners);
544
- if (!listeners)
545
- return;
546
- const callbacks = listeners.get(eventName);
547
- if (!callbacks)
548
- return;
549
- callbacks.delete(callbackForListeners);
550
- };
551
- if (inputSchema) {
552
- agent.inputSchema = inputSchema;
553
- }
554
- if (outputSchema) {
555
- agent.outputSchema = outputSchema;
556
- }
557
- if (config.schema?.stream) {
558
- agent.stream = config.schema.stream;
559
- }
560
- // Add validator method with overloads
561
- agent.validator = ((override) => {
562
- const effectiveInputSchema = override?.input ?? inputSchema;
563
- // Only use agent's output schema if no override was provided at all.
564
- // If override is provided (even with just input), don't auto-apply agent's output schema
565
- // unless the override explicitly includes output.
566
- const effectiveOutputSchema = override ? override.output : outputSchema;
567
- // Helper to build the standard Hono input validator so types flow
568
- const buildInputValidator = (schema) => validator('json', async (value, c) => {
569
- if (schema) {
570
- const result = await validateSchema(schema, value);
571
- if (!result.success) {
572
- return c.json({
573
- error: 'Validation failed',
574
- message: formatValidationIssues(result.issues),
575
- issues: result.issues,
576
- }, 400);
577
- }
578
- return result.data;
579
- }
580
- return value;
581
- });
582
- // If no output schema, preserve existing behavior: pure input validation
583
- if (!effectiveOutputSchema) {
584
- return buildInputValidator(effectiveInputSchema);
585
- }
586
- // Output validation middleware (runs after handler)
587
- const outputValidator = async (c, next) => {
588
- await next();
589
- const res = c.res;
590
- if (!res)
591
- return;
592
- // Skip output validation for streaming agents
593
- if (config.schema?.stream) {
594
- return;
595
- }
596
- // Only validate JSON responses
597
- const contentType = res.headers.get('Content-Type') ?? '';
598
- if (!contentType.toLowerCase().includes('application/json')) {
599
- return;
600
- }
601
- // Clone so we don't consume the body that will be sent
602
- let responseBody;
603
- try {
604
- const cloned = res.clone();
605
- responseBody = await cloned.json();
606
- }
607
- catch {
608
- const OutputValidationError = StructuredError('OutputValidationError')();
609
- throw new OutputValidationError({
610
- message: 'Output validation failed: response is not valid JSON',
611
- issues: [],
612
- });
613
- }
614
- const result = await validateSchema(effectiveOutputSchema, responseBody);
615
- if (!result.success) {
616
- const OutputValidationError = StructuredError('OutputValidationError')();
617
- throw new OutputValidationError({
618
- message: `Output validation failed: ${formatValidationIssues(result.issues)}`,
619
- issues: result.issues,
620
- });
621
- }
622
- // Replace response with validated/sanitized JSON
623
- c.res = new Response(JSON.stringify(result.data), {
624
- status: res.status,
625
- headers: res.headers,
626
- });
627
- };
628
- // If we have no input schema, we only do output validation
629
- if (!effectiveInputSchema) {
630
- return outputValidator;
631
- }
632
- // Compose: input validator → output validator
633
- const inputMiddleware = buildInputValidator(effectiveInputSchema);
634
- const composed = async (c, next) => {
635
- // Run the validator first; its next() runs the output validator,
636
- // whose next() runs the actual handler(s)
637
- const result = await inputMiddleware(c, async () => {
638
- await outputValidator(c, next);
639
- });
640
- // If inputMiddleware returned early (validation failed), return that response
641
- return result;
642
- };
643
- return composed;
644
- });
645
- // Register the agent for runtime use
646
- // @ts-expect-error - metadata might be incomplete until build plugin injects InternalAgentMetadata
647
- agents.set(name, agent);
648
- // Create and return AgentRunner
649
- const runner = {
650
- metadata: metadata,
651
- validator: agent.validator,
652
- inputSchema: inputSchema,
653
- outputSchema: outputSchema,
654
- stream: config.schema?.stream || false,
655
- createEval,
656
- addEventListener: agent.addEventListener,
657
- removeEventListener: agent.removeEventListener,
658
- run: inputSchema
659
- ? async (input) => {
660
- return await agent.handler(input);
661
- }
662
- : async () => {
663
- return await agent.handler();
664
- },
665
- [INTERNAL_AGENT]: agent, // Store reference to internal agent for testing
666
- };
667
- return runner;
668
- }
669
- /**
670
- * Run a handler with the agent identifier set in trace state.
671
- * Used for non-HTTP contexts (standalone) where we still want to propagate
672
- * the agent ID to downstream API calls.
673
- */
674
- const runWithAgentContext = async (agentId, handler) => {
675
- const currentContext = context.active();
676
- const activeSpan = trace.getSpan(currentContext);
677
- if (!activeSpan) {
678
- // No active span, just run the handler
679
- return handler();
680
- }
681
- const currentSpanContext = activeSpan.spanContext();
682
- const existingTraceState = currentSpanContext.traceState ?? new TraceState();
683
- const updatedTraceState = existingTraceState.set('aid', agentId);
684
- const contextWithAgentId = trace.setSpanContext(currentContext, {
685
- ...currentSpanContext,
686
- traceState: updatedTraceState,
687
- });
688
- return context.with(contextWithAgentId, handler);
689
- };
690
- const runWithSpan = async (tracer, agent, ctx, handler) => {
691
- const currentContext = context.active();
692
- const span = tracer.startSpan('agent.run', {}, currentContext);
693
- // Set agent attributes on the span immediately after creation
694
- span.setAttributes({
695
- '@agentuity/agentId': agent.metadata.id,
696
- '@agentuity/agentInstanceId': agent.metadata.agentId,
697
- '@agentuity/agentDescription': agent.metadata.description,
698
- '@agentuity/agentName': agent.metadata.name,
699
- '@agentuity/threadId': ctx.var.thread.id,
700
- });
701
- const spanId = span.spanContext().spanId;
702
- // Store span ID in PrivateVariables
703
- const _ctx = privateContext(ctx);
704
- _ctx.set('agentRunSpanId', spanId);
705
- try {
706
- // Create a new context with the span and updated trace state including agent id
707
- const spanContext = trace.setSpan(currentContext, span);
708
- // Update trace state with agent identifier (aid) so downstream API calls (e.g., sandbox)
709
- // can associate operations with this agent. The trace state is scoped to this execution,
710
- // so when the agent finishes, the parent context's trace state is automatically restored.
711
- const currentSpanContext = span.spanContext();
712
- const existingTraceState = currentSpanContext.traceState ?? new TraceState();
713
- const updatedTraceState = existingTraceState.set('aid', agent.metadata.id);
714
- // Create context with both the span and the updated trace state
715
- const contextWithAgentId = trace.setSpanContext(spanContext, {
716
- ...currentSpanContext,
717
- traceState: updatedTraceState,
718
- });
719
- return await context.with(contextWithAgentId, handler);
720
- }
721
- catch (error) {
722
- span.recordException(error);
723
- span.setStatus({ code: SpanStatusCode.ERROR });
724
- throw error;
725
- }
726
- finally {
727
- span.end();
728
- }
729
- };
730
- const createAgentRunner = (agent, ctx) => {
731
- const tracer = ctx.var.tracer;
732
- if (agent.inputSchema) {
733
- return {
734
- metadata: agent.metadata,
735
- run: async (input) => {
736
- return runWithSpan(tracer, agent, ctx, async () => await agent.handler(input));
737
- },
738
- };
739
- }
740
- else {
741
- return {
742
- metadata: agent.metadata,
743
- run: async () => {
744
- return runWithSpan(tracer, agent, ctx, async () => await agent.handler());
745
- },
746
- };
747
- }
748
- };
749
- /**
750
- * Populate the agents object with all registered agents
751
- * Keys are converted to camelCase to match the generated TypeScript types
752
- */
753
- export const populateAgentsRegistry = (ctx) => {
754
- const agentsObj = {};
755
- // Track ownership of camelCase keys to detect collisions between different raw names
756
- const ownershipMap = new Map();
757
- // Build flat registry of agents
758
- for (const [name, agentFn] of agents) {
759
- const runner = createAgentRunner(agentFn, ctx);
760
- const key = toCamelCase(name);
761
- // Validate key is non-empty
762
- if (!key) {
763
- internal.warn(`Agent name "${name}" converts to empty camelCase key. Skipping.`);
764
- continue;
765
- }
766
- // Detect collision on key - check ownership
767
- const existingOwner = ownershipMap.get(key);
768
- if (existingOwner && existingOwner !== name) {
769
- internal.error(`Agent registry collision: "${name}" conflicts with "${existingOwner}" (both map to camelCase key "${key}")`);
770
- throw new Error(`Agent registry collision detected for key "${key}"`);
771
- }
772
- agentsObj[key] = runner;
773
- // Record ownership
774
- ownershipMap.set(key, name);
775
- }
776
- return agentsObj;
777
- };
778
- export const createAgentMiddleware = (agentName) => {
779
- return async (ctx, next) => {
780
- // Populate agents object with strongly-typed keys
781
- const agentsObj = populateAgentsRegistry(ctx);
782
- // Track agent ID for session telemetry
783
- if (agentName) {
784
- const agentKey = toCamelCase(agentName);
785
- const agent = agentsObj[agentKey];
786
- const _ctx = privateContext(ctx);
787
- // we add both so that you can query by either
788
- if (agent?.metadata?.id) {
789
- _ctx.var.agentIds.add(agent.metadata.id);
790
- }
791
- if (agent?.metadata?.agentId) {
792
- _ctx.var.agentIds.add(agent.metadata.agentId);
793
- }
794
- }
795
- const sessionId = ctx.var.sessionId;
796
- const thread = ctx.var.thread;
797
- const session = ctx.var.session;
798
- const config = agentName ? getAgentConfig(agentName) : undefined;
799
- const app = ctx.var.app;
800
- const args = {
801
- agent: agentsObj,
802
- logger: ctx.var.logger,
803
- tracer: ctx.var.tracer,
804
- sessionId,
805
- session,
806
- thread,
807
- handler: ctx.var.waitUntilHandler,
808
- config: config || {},
809
- app: app || {},
810
- runtime: getGlobalRuntimeState(),
811
- auth: ctx.var.auth ?? null,
812
- };
813
- return setupRequestAgentContext(ctx, args, next);
814
- };
815
- };
816
- export const getAgents = () => agents;
817
- export const runAgentSetups = async (appState) => {
818
- for (const [name, agent] of agents.entries()) {
819
- if (agent.setup) {
820
- const config = await agent.setup(appState);
821
- setAgentConfig(name, config);
822
- }
823
- }
824
- // Note: Server readiness is managed by Vite (dev) or Bun.serve (prod)
825
- };
826
- export const runAgentShutdowns = async (appState) => {
827
- const runtime = getGlobalRuntimeState();
828
- for (const [name, agent] of runtime.agents.entries()) {
829
- if (agent.shutdown) {
830
- const config = runtime.agentConfigs.get(name);
831
- await agent.shutdown(appState, config);
832
- }
833
- }
834
- };
835
- /**
836
- * Run an agent within a specific AgentContext.
837
- * Sets up AsyncLocalStorage with the provided context and executes the agent.
838
- *
839
- * This is the recommended way to test agents in unit tests. It automatically:
840
- * - Registers the agent in the runtime state so event listeners fire
841
- * - Sets up AsyncLocalStorage so getAgentContext() works inside the agent
842
- * - Handles both agents with input and agents without input
843
- *
844
- * **Use cases:**
845
- * - Unit testing agents with TestAgentContext
846
- * - Running agents outside HTTP request flow
847
- * - Custom agent execution environments
848
- * - Testing event listeners and evaluations
849
- *
850
- * @template TInput - Type of the input parameter
851
- * @template TOutput - Type of the return value
852
- *
853
- * @param ctx - The AgentContext to use (typically TestAgentContext in tests)
854
- * @param agent - The AgentRunner to execute (returned from createAgent)
855
- * @param input - Input data (required if agent has input schema, omit otherwise)
856
- *
857
- * @returns Promise resolving to the agent's output
858
- *
859
- * @example
860
- * ```typescript
861
- * import { runInAgentContext, TestAgentContext } from '@agentuity/runtime/test';
862
- *
863
- * test('greeting agent', async () => {
864
- * const ctx = new TestAgentContext();
865
- * const result = await runInAgentContext(ctx, greetingAgent, {
866
- * name: 'Alice',
867
- * age: 30
868
- * });
869
- * expect(result).toBe('Hello, Alice! You are 30 years old.');
870
- * });
871
- *
872
- * test('no-input agent', async () => {
873
- * const ctx = new TestAgentContext();
874
- * const result = await runInAgentContext(ctx, statusAgent);
875
- * expect(result).toEqual({ status: 'ok' });
876
- * });
877
- * ```
878
- */
879
- export async function runInAgentContext(ctx, agent, input) {
880
- const storage = getAgentAsyncLocalStorage();
881
- // Register agent in runtime state so events fire (lookup by metadata.name)
882
- const agentName = agent.metadata.name;
883
- const runtime = getAgentRuntime(ctx);
884
- // Get internal agent from runner (stored via symbol) or global registry
885
- const internalAgent = agent[INTERNAL_AGENT] || agents.get(agentName);
886
- if (internalAgent && agentName) {
887
- runtime.agents.set(agentName, internalAgent);
888
- // Copy event listeners from global to context runtime
889
- const globalListeners = agentEventListeners.get(internalAgent);
890
- if (globalListeners) {
891
- runtime.agentEventListeners.set(internalAgent, globalListeners);
892
- }
893
- }
894
- return storage.run(ctx, async () => {
895
- if (input !== undefined) {
896
- return await agent.run(input);
897
- }
898
- else {
899
- return await agent.run();
900
- }
901
- });
902
- }
903
- //# sourceMappingURL=agent.js.map