@agentuity/runtime 0.0.69 → 0.0.71

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 (100) hide show
  1. package/AGENTS.md +88 -10
  2. package/README.md +0 -2
  3. package/dist/_config.d.ts +16 -0
  4. package/dist/_config.d.ts.map +1 -1
  5. package/dist/_config.js +16 -0
  6. package/dist/_config.js.map +1 -1
  7. package/dist/_context.d.ts +17 -15
  8. package/dist/_context.d.ts.map +1 -1
  9. package/dist/_context.js +17 -8
  10. package/dist/_context.js.map +1 -1
  11. package/dist/_server.d.ts.map +1 -1
  12. package/dist/_server.js +44 -21
  13. package/dist/_server.js.map +1 -1
  14. package/dist/_services.d.ts.map +1 -1
  15. package/dist/_services.js +4 -32
  16. package/dist/_services.js.map +1 -1
  17. package/dist/_tokens.d.ts +1 -0
  18. package/dist/_tokens.d.ts.map +1 -1
  19. package/dist/_tokens.js +1 -0
  20. package/dist/_tokens.js.map +1 -1
  21. package/dist/_validation.d.ts +3 -3
  22. package/dist/_validation.d.ts.map +1 -1
  23. package/dist/_validation.js.map +1 -1
  24. package/dist/agent.d.ts +289 -107
  25. package/dist/agent.d.ts.map +1 -1
  26. package/dist/agent.js +206 -149
  27. package/dist/agent.js.map +1 -1
  28. package/dist/app.d.ts +6 -18
  29. package/dist/app.d.ts.map +1 -1
  30. package/dist/app.js +1 -1
  31. package/dist/app.js.map +1 -1
  32. package/dist/eval.d.ts +4 -4
  33. package/dist/eval.d.ts.map +1 -1
  34. package/dist/index.d.ts +2 -1
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +1 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/otel/config.d.ts.map +1 -1
  39. package/dist/otel/config.js +5 -2
  40. package/dist/otel/config.js.map +1 -1
  41. package/dist/otel/console.d.ts +10 -6
  42. package/dist/otel/console.d.ts.map +1 -1
  43. package/dist/otel/console.js +31 -13
  44. package/dist/otel/console.js.map +1 -1
  45. package/dist/otel/logger.d.ts.map +1 -1
  46. package/dist/otel/logger.js +0 -19
  47. package/dist/otel/logger.js.map +1 -1
  48. package/dist/otel/otel.d.ts +2 -1
  49. package/dist/otel/otel.d.ts.map +1 -1
  50. package/dist/otel/otel.js +28 -15
  51. package/dist/otel/otel.js.map +1 -1
  52. package/dist/services/local/_db.d.ts.map +1 -1
  53. package/dist/services/local/_db.js +1 -22
  54. package/dist/services/local/_db.js.map +1 -1
  55. package/dist/services/local/_router.d.ts.map +1 -1
  56. package/dist/services/local/_router.js +0 -32
  57. package/dist/services/local/_router.js.map +1 -1
  58. package/dist/services/local/index.d.ts +0 -1
  59. package/dist/services/local/index.d.ts.map +1 -1
  60. package/dist/services/local/index.js +0 -1
  61. package/dist/services/local/index.js.map +1 -1
  62. package/dist/session.d.ts +2 -2
  63. package/dist/validator.d.ts +140 -0
  64. package/dist/validator.d.ts.map +1 -0
  65. package/dist/validator.js +146 -0
  66. package/dist/validator.js.map +1 -0
  67. package/dist/workbench.d.ts.map +1 -1
  68. package/dist/workbench.js +38 -29
  69. package/dist/workbench.js.map +1 -1
  70. package/package.json +7 -6
  71. package/src/_config.ts +19 -0
  72. package/src/_context.ts +25 -31
  73. package/src/_server.ts +49 -22
  74. package/src/_services.ts +2 -31
  75. package/src/_tokens.ts +1 -0
  76. package/src/_validation.ts +3 -7
  77. package/src/agent.ts +555 -348
  78. package/src/app.ts +5 -18
  79. package/src/eval.ts +6 -6
  80. package/src/index.ts +2 -1
  81. package/src/otel/config.ts +5 -2
  82. package/src/otel/console.ts +34 -20
  83. package/src/otel/logger.ts +0 -18
  84. package/src/otel/otel.ts +43 -29
  85. package/src/services/local/_db.ts +1 -27
  86. package/src/services/local/_router.ts +0 -46
  87. package/src/services/local/index.ts +0 -1
  88. package/src/session.ts +2 -2
  89. package/src/validator.ts +277 -0
  90. package/src/workbench.ts +38 -32
  91. package/dist/agent.validator.test.d.ts +0 -2
  92. package/dist/agent.validator.test.d.ts.map +0 -1
  93. package/dist/agent.validator.test.js +0 -508
  94. package/dist/agent.validator.test.js.map +0 -1
  95. package/dist/services/local/objectstore.d.ts +0 -19
  96. package/dist/services/local/objectstore.d.ts.map +0 -1
  97. package/dist/services/local/objectstore.js +0 -117
  98. package/dist/services/local/objectstore.js.map +0 -1
  99. package/src/agent.validator.test.ts +0 -587
  100. package/src/services/local/objectstore.ts +0 -177
@@ -0,0 +1,277 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { StructuredError, type InferOutput, type StandardSchemaV1 } from '@agentuity/core';
3
+ import type { Context, MiddlewareHandler } from 'hono';
4
+ import type { Handler } from 'hono/types';
5
+ import { validator as honoValidator } from 'hono/validator';
6
+ import { validateSchema, formatValidationIssues } from './_validation';
7
+
8
+ /**
9
+ * Route validator for standard HTTP routes (non-agent routes).
10
+ * Provides input and output validation with full type safety.
11
+ *
12
+ * **Input validation behavior by HTTP method:**
13
+ * - **GET**: Validates query parameters (accessible via `c.req.valid('query')`)
14
+ * - **POST/PUT/PATCH/DELETE**: Validates JSON body (accessible via `c.req.valid('json')`)
15
+ *
16
+ * **Output validation:**
17
+ * - Validates response JSON body before sending
18
+ * - Throws 500 Internal Server Error if validation fails
19
+ *
20
+ * @template TInput - Input schema type (query params for GET, body for POST/PUT/PATCH/DELETE)
21
+ * @template TOutput - Output schema type for response validation
22
+ *
23
+ * @example GET route with output validation only
24
+ * ```typescript
25
+ * router.get('/users',
26
+ * validator({ output: z.array(UserSchema) }),
27
+ * async (c) => {
28
+ * return c.json([{ id: '1', name: 'Alice' }]);
29
+ * }
30
+ * );
31
+ * ```
32
+ *
33
+ * @example GET route with query param validation
34
+ * ```typescript
35
+ * router.get('/users/:id',
36
+ * validator({
37
+ * input: z.object({ id: z.string() }),
38
+ * output: UserSchema
39
+ * }),
40
+ * async (c) => {
41
+ * const { id } = c.req.valid('query'); // Fully typed!
42
+ * return c.json({ id, name: 'Alice' });
43
+ * }
44
+ * );
45
+ * ```
46
+ *
47
+ * @example POST route with body and output validation
48
+ * ```typescript
49
+ * router.post('/users',
50
+ * validator({
51
+ * input: z.object({ name: z.string(), email: z.string().email() }),
52
+ * output: UserSchema
53
+ * }),
54
+ * async (c) => {
55
+ * const data = c.req.valid('json'); // Fully typed!
56
+ * return c.json({ id: '1', ...data });
57
+ * }
58
+ * );
59
+ * ```
60
+ */
61
+ export interface RouteValidator {
62
+ /**
63
+ * Output-only validation (no input validation).
64
+ * Useful for GET routes without query parameters.
65
+ *
66
+ * @template TOutput - Output schema type
67
+ * @param options - Configuration object with output schema
68
+ * @returns Hono middleware handler
69
+ */
70
+ <TOutput extends StandardSchemaV1>(options: {
71
+ output: TOutput;
72
+ }): Handler<
73
+ any,
74
+ any,
75
+ {
76
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
77
+ in: {};
78
+ out: { json: InferOutput<TOutput> };
79
+ }
80
+ >;
81
+
82
+ /**
83
+ * Input and output validation.
84
+ * - GET: validates query parameters
85
+ * - POST/PUT/PATCH/DELETE: validates JSON body
86
+ *
87
+ * @template TInput - Input schema type
88
+ * @template TOutput - Optional output schema type
89
+ * @param options - Configuration object with input and optional output schemas
90
+ * @returns Hono middleware handler with type inference
91
+ */
92
+ <
93
+ TInput extends StandardSchemaV1,
94
+ TOutput extends StandardSchemaV1 | undefined = undefined,
95
+ >(options: {
96
+ input: TInput;
97
+ output?: TOutput;
98
+ }): Handler<
99
+ any,
100
+ any,
101
+ {
102
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
103
+ in: {};
104
+ out: {
105
+ json: InferOutput<TInput>;
106
+ query: InferOutput<TInput>;
107
+ };
108
+ }
109
+ >;
110
+ }
111
+
112
+ /**
113
+ * Create a route validator middleware with input and/or output validation.
114
+ *
115
+ * Automatically handles different validation targets based on HTTP method:
116
+ * - GET requests: validates query parameters (if input schema provided)
117
+ * - POST/PUT/PATCH/DELETE: validates JSON body (if input schema provided)
118
+ * - All methods: validates JSON response (if output schema provided)
119
+ *
120
+ * @param options - Validation configuration
121
+ * @param options.input - Input schema (query params for GET, body for POST/PUT/PATCH/DELETE)
122
+ * @param options.output - Output schema for response validation
123
+ * @returns Hono middleware handler
124
+ *
125
+ * @example GET with query validation
126
+ * ```typescript
127
+ * import { validator } from '@agentuity/runtime';
128
+ *
129
+ * router.get('/search',
130
+ * validator({
131
+ * input: z.object({ q: z.string(), limit: z.number().optional() }),
132
+ * output: z.array(SearchResultSchema)
133
+ * }),
134
+ * async (c) => {
135
+ * const { q, limit } = c.req.valid('query'); // Typed!
136
+ * const results = await search(q, limit);
137
+ * return c.json(results);
138
+ * }
139
+ * );
140
+ * ```
141
+ *
142
+ * @example POST with body validation
143
+ * ```typescript
144
+ * router.post('/users',
145
+ * validator({
146
+ * input: z.object({ name: z.string() }),
147
+ * output: UserSchema
148
+ * }),
149
+ * async (c) => {
150
+ * const data = c.req.valid('json'); // Typed!
151
+ * const user = await createUser(data);
152
+ * return c.json(user);
153
+ * }
154
+ * );
155
+ * ```
156
+ */
157
+ export const validator: RouteValidator = ((options: {
158
+ input?: StandardSchemaV1;
159
+ output?: StandardSchemaV1;
160
+ }) => {
161
+ const { input: inputSchema, output: outputSchema } = options;
162
+
163
+ // Helper to build input validator that detects HTTP method
164
+ const buildInputValidator = (schema: StandardSchemaV1): MiddlewareHandler => {
165
+ return async (c: Context, next) => {
166
+ const method = c.req.method.toUpperCase();
167
+
168
+ // GET requests validate query parameters
169
+ if (method === 'GET') {
170
+ const queryValidator = honoValidator('query', async (value, c) => {
171
+ const result = await validateSchema(schema, value);
172
+ if (!result.success) {
173
+ return c.json(
174
+ {
175
+ error: 'Validation failed',
176
+ message: formatValidationIssues(result.issues),
177
+ issues: result.issues,
178
+ },
179
+ 400
180
+ );
181
+ }
182
+ return result.data;
183
+ });
184
+ return await queryValidator(c, next);
185
+ }
186
+
187
+ // POST/PUT/PATCH/DELETE validate JSON body
188
+ const jsonValidator = honoValidator('json', async (value, c) => {
189
+ const result = await validateSchema(schema, value);
190
+ if (!result.success) {
191
+ return c.json(
192
+ {
193
+ error: 'Validation failed',
194
+ message: formatValidationIssues(result.issues),
195
+ issues: result.issues,
196
+ },
197
+ 400
198
+ );
199
+ }
200
+ return result.data;
201
+ });
202
+ return await jsonValidator(c, next);
203
+ };
204
+ };
205
+
206
+ // Output validation middleware (runs after handler)
207
+ const outputValidator: MiddlewareHandler = async (c, next) => {
208
+ await next();
209
+
210
+ if (!outputSchema) return;
211
+
212
+ const res = c.res;
213
+ if (!res) return;
214
+
215
+ // Only validate JSON responses
216
+ const contentType = res.headers.get('Content-Type') ?? '';
217
+ if (!contentType.toLowerCase().includes('application/json')) {
218
+ return;
219
+ }
220
+
221
+ // Clone so we don't consume the body that will be sent
222
+ let responseBody: unknown;
223
+ try {
224
+ const cloned = res.clone();
225
+ responseBody = await cloned.json();
226
+ } catch {
227
+ const OutputValidationError = StructuredError('OutputValidationError')<{
228
+ issues: any[];
229
+ }>();
230
+ throw new OutputValidationError({
231
+ message: 'Output validation failed: response is not valid JSON',
232
+ issues: [],
233
+ });
234
+ }
235
+
236
+ const result = await validateSchema(outputSchema, responseBody);
237
+ if (!result.success) {
238
+ const OutputValidationError = StructuredError('OutputValidationError')<{
239
+ issues: any[];
240
+ }>();
241
+ throw new OutputValidationError({
242
+ message: `Output validation failed: ${formatValidationIssues(result.issues)}`,
243
+ issues: result.issues,
244
+ });
245
+ }
246
+
247
+ // Replace response with validated/sanitized JSON
248
+ c.res = new Response(JSON.stringify(result.data), {
249
+ status: res.status,
250
+ headers: res.headers,
251
+ });
252
+ };
253
+
254
+ // If no input schema, only do output validation
255
+ if (!inputSchema) {
256
+ return outputValidator as unknown as Handler;
257
+ }
258
+
259
+ // If no output schema, only do input validation
260
+ if (!outputSchema) {
261
+ return buildInputValidator(inputSchema) as unknown as Handler;
262
+ }
263
+
264
+ // Compose: input validator → output validator
265
+ const inputMiddleware = buildInputValidator(inputSchema);
266
+
267
+ const composed: MiddlewareHandler = async (c, next) => {
268
+ // Run input validator first, then output validator, then handler
269
+ const result = await inputMiddleware(c, async () => {
270
+ await outputValidator(c, next);
271
+ });
272
+ // If inputMiddleware returned early (validation failed), return that response
273
+ return result;
274
+ };
275
+
276
+ return composed as unknown as Handler;
277
+ }) as RouteValidator;
package/src/workbench.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  import { z } from 'zod';
2
2
  import type { Context, Handler } from 'hono';
3
+ import { s } from '@agentuity/schema';
3
4
  import { timingSafeEqual } from 'node:crypto';
4
5
  import { getAgents, createAgentMiddleware } from './agent';
5
6
  import { createRouter } from './router';
6
7
  import type { WebSocketConnection } from './router';
8
+ import { privateContext } from './_server';
7
9
 
8
10
  export const createWorkbenchExecutionRoute = (): Handler => {
9
11
  const authHeader = process.env.AGENTUITY_WORKBENCH_APIKEY
@@ -39,12 +41,12 @@ export const createWorkbenchExecutionRoute = (): Handler => {
39
41
  }
40
42
 
41
43
  // Get agents registry and find the agent
42
- const agents = getAgents();
44
+ const allAgents = getAgents();
43
45
 
44
46
  let agentObj;
45
47
  let agentName;
46
48
 
47
- for (const [name, agent] of agents) {
49
+ for (const [name, agent] of allAgents) {
48
50
  if (agent.metadata.id === agentId) {
49
51
  agentObj = agent;
50
52
  agentName = name;
@@ -56,37 +58,23 @@ export const createWorkbenchExecutionRoute = (): Handler => {
56
58
  return ctx.text('Agent not found', { status: 404 });
57
59
  }
58
60
 
59
- // Validate input if schema exists
60
- let validatedInput = input;
61
- if (agentObj.inputSchema) {
62
- const inputResult = await agentObj.inputSchema['~standard'].validate(input);
63
- if (inputResult.issues) {
64
- return ctx.json(
65
- {
66
- error: 'Validation failed',
67
- issues: inputResult.issues,
68
- },
69
- { status: 400 }
70
- );
71
- }
72
- validatedInput = inputResult.value;
73
- console.log('✅ [Workbench] Input validation passed');
74
- } else {
75
- console.log('ℹ️ [Workbench] No input schema, skipping validation');
61
+ // Track agent ID for telemetry (otelMiddleware sets up agentIds)
62
+ const _ctx = privateContext(ctx);
63
+ if (agentObj.metadata?.id) {
64
+ _ctx.var.agentIds.add(agentObj.metadata.id);
65
+ _ctx.var.agentIds.add(agentObj.metadata.agentId);
76
66
  }
77
67
 
78
- // Get agent runner from context.var.agent (should be available via middleware)
79
- const agentRunner = ctx.var.agent[agentName];
80
- if (!agentRunner) {
81
- return ctx.text('Agent runner not found', { status: 404 });
82
- }
83
-
84
- // Execute the agent
68
+ // Execute the agent handler directly
69
+ // The agentMiddleware has already set up the AsyncLocalStorage context
70
+ // so the handler can access it via getAgentContext()
85
71
  let result;
86
72
  if (agentObj.inputSchema) {
87
- result = await agentRunner.run(validatedInput);
73
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
74
+ result = await (agentObj as any).handler(input);
88
75
  } else {
89
- result = await agentRunner.run();
76
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
77
+ result = await (agentObj as any).handler();
90
78
  }
91
79
 
92
80
  // Handle cases where result might be undefined/null
@@ -147,6 +135,25 @@ export const createWorkbenchRouter = () => {
147
135
  return router;
148
136
  };
149
137
 
138
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
139
+ const toJSONSchema = (schema: any) => {
140
+ // Check if it's an Agentuity schema via StandardSchemaV1 vendor
141
+ if (schema?.['~standard']?.vendor === 'agentuity') {
142
+ return s.toJSONSchema(schema);
143
+ }
144
+ // Check if it's a Zod schema
145
+ if (schema?._def?.typeName) {
146
+ try {
147
+ return z.toJSONSchema(schema);
148
+ } catch {
149
+ return {};
150
+ }
151
+ }
152
+ // TODO: this is going to only work for zod schema for now. need a way to handle others
153
+ // Unknown schema type
154
+ return {};
155
+ };
156
+
150
157
  export const createWorkbenchMetadataRoute = (): Handler => {
151
158
  const authHeader = process.env.AGENTUITY_WORKBENCH_APIKEY
152
159
  ? `Bearer ${process.env.AGENTUITY_WORKBENCH_APIKEY}`
@@ -169,20 +176,19 @@ export const createWorkbenchMetadataRoute = (): Handler => {
169
176
  }
170
177
  }
171
178
  const schemas: { agents: Record<string, unknown> } = { agents: {} };
172
- // TODO: this is going to only work for zod schema for now. need a way to handle others
173
179
  for (const [, agent] of agents) {
174
- schemas.agents[agent.metadata.identifier] = {
180
+ schemas.agents[agent.metadata.id] = {
175
181
  schema: {
176
182
  input: agent.inputSchema
177
183
  ? {
178
184
  code: agent.metadata.inputSchemaCode || undefined,
179
- json: z.toJSONSchema(agent.inputSchema),
185
+ json: toJSONSchema(agent.inputSchema),
180
186
  }
181
187
  : undefined,
182
188
  output: agent.outputSchema
183
189
  ? {
184
190
  code: agent.metadata.outputSchemaCode || undefined,
185
- json: z.toJSONSchema(agent.outputSchema),
191
+ json: toJSONSchema(agent.outputSchema),
186
192
  }
187
193
  : undefined,
188
194
  },
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=agent.validator.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"agent.validator.test.d.ts","sourceRoot":"","sources":["../src/agent.validator.test.ts"],"names":[],"mappings":""}