@agentuity/cli 0.0.69 → 0.0.70

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 (153) hide show
  1. package/AGENTS.md +1 -1
  2. package/README.md +1 -1
  3. package/dist/cmd/ai/capabilities/show.d.ts.map +1 -1
  4. package/dist/cmd/ai/capabilities/show.js +0 -13
  5. package/dist/cmd/ai/capabilities/show.js.map +1 -1
  6. package/dist/cmd/ai/prompt/agent.js +1 -1
  7. package/dist/cmd/ai/prompt/api.js +1 -1
  8. package/dist/cmd/build/ast.d.ts +1 -2
  9. package/dist/cmd/build/ast.d.ts.map +1 -1
  10. package/dist/cmd/build/ast.js +261 -260
  11. package/dist/cmd/build/ast.js.map +1 -1
  12. package/dist/cmd/build/bundler.d.ts +2 -1
  13. package/dist/cmd/build/bundler.d.ts.map +1 -1
  14. package/dist/cmd/build/bundler.js +11 -2
  15. package/dist/cmd/build/bundler.js.map +1 -1
  16. package/dist/cmd/build/index.js +1 -1
  17. package/dist/cmd/build/index.js.map +1 -1
  18. package/dist/cmd/build/plugin.d.ts.map +1 -1
  19. package/dist/cmd/build/plugin.js +152 -414
  20. package/dist/cmd/build/plugin.js.map +1 -1
  21. package/dist/cmd/build/route-registry.d.ts +36 -0
  22. package/dist/cmd/build/route-registry.d.ts.map +1 -0
  23. package/dist/cmd/build/route-registry.js +151 -0
  24. package/dist/cmd/build/route-registry.js.map +1 -0
  25. package/dist/cmd/cloud/deploy.d.ts.map +1 -1
  26. package/dist/cmd/cloud/deploy.js +1 -0
  27. package/dist/cmd/cloud/deploy.js.map +1 -1
  28. package/dist/cmd/cloud/index.d.ts.map +1 -1
  29. package/dist/cmd/cloud/index.js +0 -2
  30. package/dist/cmd/cloud/index.js.map +1 -1
  31. package/dist/cmd/dev/index.js +3 -3
  32. package/dist/cmd/dev/index.js.map +1 -1
  33. package/dist/cmd/dev/sync.d.ts.map +1 -1
  34. package/dist/cmd/dev/sync.js +0 -15
  35. package/dist/cmd/dev/sync.js.map +1 -1
  36. package/dist/cmd/dev/templates.d.ts.map +1 -1
  37. package/dist/cmd/dev/templates.js +11 -35
  38. package/dist/cmd/dev/templates.js.map +1 -1
  39. package/dist/cmd/profile/create.d.ts.map +1 -1
  40. package/dist/cmd/profile/create.js +0 -1
  41. package/dist/cmd/profile/create.js.map +1 -1
  42. package/dist/cmd/project/template-flow.d.ts.map +1 -1
  43. package/dist/cmd/project/template-flow.js +64 -53
  44. package/dist/cmd/project/template-flow.js.map +1 -1
  45. package/dist/config.d.ts.map +1 -1
  46. package/dist/config.js +0 -3
  47. package/dist/config.js.map +1 -1
  48. package/dist/tui/box.d.ts +19 -0
  49. package/dist/tui/box.d.ts.map +1 -0
  50. package/dist/tui/box.js +160 -0
  51. package/dist/tui/box.js.map +1 -0
  52. package/dist/tui/colors.d.ts +20 -0
  53. package/dist/tui/colors.d.ts.map +1 -0
  54. package/dist/tui/colors.js +52 -0
  55. package/dist/tui/colors.js.map +1 -0
  56. package/dist/tui/group.d.ts +25 -0
  57. package/dist/tui/group.d.ts.map +1 -0
  58. package/dist/tui/group.js +32 -0
  59. package/dist/tui/group.js.map +1 -0
  60. package/dist/tui/prompt.d.ts +65 -0
  61. package/dist/tui/prompt.d.ts.map +1 -0
  62. package/dist/tui/prompt.js +377 -0
  63. package/dist/tui/prompt.js.map +1 -0
  64. package/dist/tui/symbols.d.ts +32 -0
  65. package/dist/tui/symbols.d.ts.map +1 -0
  66. package/dist/tui/symbols.js +52 -0
  67. package/dist/tui/symbols.js.map +1 -0
  68. package/dist/tui.d.ts +6 -0
  69. package/dist/tui.d.ts.map +1 -1
  70. package/dist/tui.js +6 -0
  71. package/dist/tui.js.map +1 -1
  72. package/dist/types.d.ts +0 -24
  73. package/dist/types.d.ts.map +1 -1
  74. package/dist/types.js +0 -1
  75. package/dist/types.js.map +1 -1
  76. package/package.json +3 -3
  77. package/src/cmd/ai/capabilities/show.ts +0 -13
  78. package/src/cmd/ai/prompt/agent.ts +1 -1
  79. package/src/cmd/ai/prompt/api.ts +1 -1
  80. package/src/cmd/build/ast.ts +364 -334
  81. package/src/cmd/build/bundler.ts +16 -1
  82. package/src/cmd/build/index.ts +1 -1
  83. package/src/cmd/build/plugin.ts +171 -493
  84. package/src/cmd/build/route-registry.ts +198 -0
  85. package/src/cmd/cloud/deploy.ts +1 -0
  86. package/src/cmd/cloud/index.ts +0 -2
  87. package/src/cmd/dev/index.ts +3 -3
  88. package/src/cmd/dev/sync.ts +0 -28
  89. package/src/cmd/dev/templates.ts +11 -35
  90. package/src/cmd/profile/create.ts +0 -1
  91. package/src/cmd/project/template-flow.ts +77 -57
  92. package/src/config.ts +0 -3
  93. package/src/tui/box.ts +202 -0
  94. package/src/tui/colors.ts +55 -0
  95. package/src/tui/group.ts +56 -0
  96. package/src/tui/prompt.ts +506 -0
  97. package/src/tui/symbols.ts +64 -0
  98. package/src/tui.ts +14 -0
  99. package/src/types.ts +0 -1
  100. package/dist/cmd/cloud/objectstore/delete-bucket.d.ts +0 -3
  101. package/dist/cmd/cloud/objectstore/delete-bucket.d.ts.map +0 -1
  102. package/dist/cmd/cloud/objectstore/delete-bucket.js +0 -72
  103. package/dist/cmd/cloud/objectstore/delete-bucket.js.map +0 -1
  104. package/dist/cmd/cloud/objectstore/delete.d.ts +0 -3
  105. package/dist/cmd/cloud/objectstore/delete.d.ts.map +0 -1
  106. package/dist/cmd/cloud/objectstore/delete.js +0 -65
  107. package/dist/cmd/cloud/objectstore/delete.js.map +0 -1
  108. package/dist/cmd/cloud/objectstore/get.d.ts +0 -3
  109. package/dist/cmd/cloud/objectstore/get.d.ts.map +0 -1
  110. package/dist/cmd/cloud/objectstore/get.js +0 -75
  111. package/dist/cmd/cloud/objectstore/get.js.map +0 -1
  112. package/dist/cmd/cloud/objectstore/index.d.ts +0 -3
  113. package/dist/cmd/cloud/objectstore/index.d.ts.map +0 -1
  114. package/dist/cmd/cloud/objectstore/index.js +0 -36
  115. package/dist/cmd/cloud/objectstore/index.js.map +0 -1
  116. package/dist/cmd/cloud/objectstore/list-buckets.d.ts +0 -3
  117. package/dist/cmd/cloud/objectstore/list-buckets.d.ts.map +0 -1
  118. package/dist/cmd/cloud/objectstore/list-buckets.js +0 -46
  119. package/dist/cmd/cloud/objectstore/list-buckets.js.map +0 -1
  120. package/dist/cmd/cloud/objectstore/list-keys.d.ts +0 -3
  121. package/dist/cmd/cloud/objectstore/list-keys.d.ts.map +0 -1
  122. package/dist/cmd/cloud/objectstore/list-keys.js +0 -58
  123. package/dist/cmd/cloud/objectstore/list-keys.js.map +0 -1
  124. package/dist/cmd/cloud/objectstore/put.d.ts +0 -3
  125. package/dist/cmd/cloud/objectstore/put.d.ts.map +0 -1
  126. package/dist/cmd/cloud/objectstore/put.js +0 -66
  127. package/dist/cmd/cloud/objectstore/put.js.map +0 -1
  128. package/dist/cmd/cloud/objectstore/repl.d.ts +0 -3
  129. package/dist/cmd/cloud/objectstore/repl.d.ts.map +0 -1
  130. package/dist/cmd/cloud/objectstore/repl.js +0 -224
  131. package/dist/cmd/cloud/objectstore/repl.js.map +0 -1
  132. package/dist/cmd/cloud/objectstore/url.d.ts +0 -3
  133. package/dist/cmd/cloud/objectstore/url.d.ts.map +0 -1
  134. package/dist/cmd/cloud/objectstore/url.js +0 -64
  135. package/dist/cmd/cloud/objectstore/url.js.map +0 -1
  136. package/dist/cmd/cloud/objectstore/util.d.ts +0 -11
  137. package/dist/cmd/cloud/objectstore/util.d.ts.map +0 -1
  138. package/dist/cmd/cloud/objectstore/util.js +0 -18
  139. package/dist/cmd/cloud/objectstore/util.js.map +0 -1
  140. package/src/cmd/build/ast.test.ts +0 -418
  141. package/src/cmd/build/fix-duplicate-exports.test.ts +0 -387
  142. package/src/cmd/cloud/objectstore/delete-bucket.ts +0 -77
  143. package/src/cmd/cloud/objectstore/delete.ts +0 -67
  144. package/src/cmd/cloud/objectstore/get.ts +0 -77
  145. package/src/cmd/cloud/objectstore/index.ts +0 -36
  146. package/src/cmd/cloud/objectstore/list-buckets.ts +0 -51
  147. package/src/cmd/cloud/objectstore/list-keys.ts +0 -63
  148. package/src/cmd/cloud/objectstore/put.ts +0 -74
  149. package/src/cmd/cloud/objectstore/repl.ts +0 -239
  150. package/src/cmd/cloud/objectstore/url.ts +0 -67
  151. package/src/cmd/cloud/objectstore/util.ts +0 -29
  152. package/src/crypto/box.test.ts +0 -431
  153. package/src/env-util.test.ts +0 -194
@@ -81,6 +81,13 @@ function generateStableAgentId(projectId, name) {
81
81
  function generateStableEvalId(projectId, agentId, name) {
82
82
  return `evalid_${hashSHA1(projectId, agentId, name)}`.substring(0, 64);
83
83
  }
84
+ /**
85
+ * Type guard to check if an AST node is an ObjectExpression
86
+ */
87
+ function isObjectExpression(node) {
88
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
89
+ return typeof node === 'object' && node !== null && node.type === 'ObjectExpression';
90
+ }
84
91
  /**
85
92
  * Extract schema code from createAgent call arguments
86
93
  * Returns input and output schema code as strings
@@ -117,7 +124,7 @@ function extractSchemaCode(callargexp) {
117
124
  return { inputSchemaCode, outputSchemaCode };
118
125
  }
119
126
  const MetadataError = StructuredError('MetatadataNameMissingError')();
120
- function augmentAgentMetadataNode(projectId, id, identifier, rel, version, ast, propvalue, filename, inputSchemaCode, outputSchemaCode) {
127
+ function augmentAgentMetadataNode(projectId, id, rel, version, ast, propvalue, filename, inputSchemaCode, outputSchemaCode) {
121
128
  const metadata = parseObjectExpressionToMap(propvalue);
122
129
  if (!metadata.has('name')) {
123
130
  const location = ast.loc?.start?.line ? ` on line ${ast.loc.start.line}` : '';
@@ -128,19 +135,10 @@ function augmentAgentMetadataNode(projectId, id, identifier, rel, version, ast,
128
135
  });
129
136
  }
130
137
  const name = metadata.get('name');
131
- if (metadata.has('identifier') && identifier !== metadata.get('identifier')) {
132
- const location = ast.loc?.start?.line ? ` on line ${ast.loc.start.line}` : '';
133
- throw new MetadataError({
134
- filename,
135
- line: ast.loc?.start?.line,
136
- message: `metadata.identifier (${metadata.get('identifier')}) in ${filename}${location} is mismatched (${name}). This is an internal error.`,
137
- });
138
- }
139
138
  const descriptionNode = propvalue.properties.find((x) => x.key.name === 'description')?.value;
140
139
  const description = descriptionNode ? descriptionNode.value : '';
141
140
  const agentId = generateStableAgentId(projectId, name);
142
141
  metadata.set('version', version);
143
- metadata.set('identifier', identifier);
144
142
  metadata.set('filename', rel);
145
143
  metadata.set('id', id);
146
144
  metadata.set('agentId', agentId);
@@ -151,7 +149,7 @@ function augmentAgentMetadataNode(projectId, id, identifier, rel, version, ast,
151
149
  if (outputSchemaCode) {
152
150
  metadata.set('outputSchemaCode', outputSchemaCode);
153
151
  }
154
- propvalue.properties.push(createObjectPropertyNode('id', id), createObjectPropertyNode('agentId', agentId), createObjectPropertyNode('version', version), createObjectPropertyNode('identifier', name), createObjectPropertyNode('filename', rel), createObjectPropertyNode('description', description));
152
+ propvalue.properties.push(createObjectPropertyNode('id', id), createObjectPropertyNode('agentId', agentId), createObjectPropertyNode('version', version), createObjectPropertyNode('filename', rel), createObjectPropertyNode('description', description));
155
153
  if (inputSchemaCode) {
156
154
  propvalue.properties.push(createObjectPropertyNode('inputSchemaCode', inputSchemaCode));
157
155
  }
@@ -162,14 +160,21 @@ function augmentAgentMetadataNode(projectId, id, identifier, rel, version, ast,
162
160
  // Evals imports are now handled in registry.generated.ts
163
161
  return [newsource, metadata];
164
162
  }
165
- function createAgentMetadataNode(id, name, rel, version, ast, callargexp, _filename) {
163
+ function createAgentMetadataNode(id, name, rel, version, ast, callargexp, _filename, projectId, inputSchemaCode, outputSchemaCode) {
166
164
  const newmetadata = createNewMetadataNode();
165
+ const agentId = generateStableAgentId(projectId, name);
167
166
  const md = new Map();
168
167
  md.set('id', id);
168
+ md.set('agentId', agentId);
169
169
  md.set('version', version);
170
170
  md.set('name', name);
171
- md.set('identifier', name);
172
171
  md.set('filename', rel);
172
+ if (inputSchemaCode) {
173
+ md.set('inputSchemaCode', inputSchemaCode);
174
+ }
175
+ if (outputSchemaCode) {
176
+ md.set('outputSchemaCode', outputSchemaCode);
177
+ }
173
178
  for (const [key, value] of md) {
174
179
  newmetadata.value.properties.push(createObjectPropertyNode(key, value));
175
180
  }
@@ -178,118 +183,6 @@ function createAgentMetadataNode(id, name, rel, version, ast, callargexp, _filen
178
183
  // Evals imports are now handled in registry.generated.ts
179
184
  return [newsource, md];
180
185
  }
181
- function camelToKebab(str) {
182
- return str
183
- .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
184
- .replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')
185
- .toLowerCase();
186
- }
187
- function setLiteralValue(literal, value) {
188
- literal.value = value;
189
- if (literal.raw !== undefined) {
190
- literal.raw = JSON.stringify(value);
191
- }
192
- }
193
- function augmentEvalMetadataNode(projectId, agentId, id, name, rel, version, _ast, metadataObj, _filename) {
194
- const metadata = parseObjectExpressionToMap(metadataObj);
195
- // Name can come from metadata.name or variable name (already resolved in caller)
196
- // If metadata doesn't have name, we'll add it from the resolved name
197
- if (!metadata.has('name')) {
198
- metadataObj.properties.push(createObjectPropertyNode('name', name));
199
- }
200
- const descriptionNode = metadataObj.properties.find((x) => x.key.name === 'description')?.value;
201
- const description = descriptionNode ? descriptionNode.value : '';
202
- const effectiveAgentId = agentId || '';
203
- const _evalId = getEvalId(projectId, effectiveAgentId, rel, name, version); // Deployment-specific ID (not used, kept for potential future use)
204
- const stableEvalId = generateStableEvalId(projectId, effectiveAgentId, name);
205
- // Check if id, version, identifier, filename, evalId already exist
206
- const existingKeys = new Set();
207
- for (const prop of metadataObj.properties) {
208
- if (prop.key.type === 'Identifier') {
209
- existingKeys.add(prop.key.name);
210
- }
211
- }
212
- // Add or update metadata properties
213
- if (!existingKeys.has('id')) {
214
- metadataObj.properties.push(createObjectPropertyNode('id', id));
215
- }
216
- else {
217
- // Update existing id
218
- for (const prop of metadataObj.properties) {
219
- if (prop.key.type === 'Identifier' && prop.key.name === 'id') {
220
- if (prop.value.type === 'Literal') {
221
- setLiteralValue(prop.value, id);
222
- }
223
- break;
224
- }
225
- }
226
- }
227
- if (!existingKeys.has('version')) {
228
- metadataObj.properties.push(createObjectPropertyNode('version', version));
229
- }
230
- else {
231
- for (const prop of metadataObj.properties) {
232
- if (prop.key.type === 'Identifier' && prop.key.name === 'version') {
233
- if (prop.value.type === 'Literal') {
234
- setLiteralValue(prop.value, version);
235
- }
236
- break;
237
- }
238
- }
239
- }
240
- if (!existingKeys.has('identifier')) {
241
- metadataObj.properties.push(createObjectPropertyNode('identifier', name));
242
- }
243
- else {
244
- for (const prop of metadataObj.properties) {
245
- if (prop.key.type === 'Identifier' && prop.key.name === 'identifier') {
246
- if (prop.value.type === 'Literal') {
247
- setLiteralValue(prop.value, name);
248
- }
249
- break;
250
- }
251
- }
252
- }
253
- if (!existingKeys.has('filename')) {
254
- metadataObj.properties.push(createObjectPropertyNode('filename', rel));
255
- }
256
- else {
257
- for (const prop of metadataObj.properties) {
258
- if (prop.key.type === 'Identifier' && prop.key.name === 'filename') {
259
- if (prop.value.type === 'Literal') {
260
- setLiteralValue(prop.value, rel);
261
- }
262
- break;
263
- }
264
- }
265
- }
266
- if (!existingKeys.has('evalId')) {
267
- metadataObj.properties.push(createObjectPropertyNode('evalId', stableEvalId));
268
- }
269
- else {
270
- for (const prop of metadataObj.properties) {
271
- if (prop.key.type === 'Identifier' && prop.key.name === 'evalId') {
272
- if (prop.value.type === 'Literal') {
273
- setLiteralValue(prop.value, stableEvalId);
274
- }
275
- break;
276
- }
277
- }
278
- }
279
- if (!existingKeys.has('description')) {
280
- metadataObj.properties.push(createObjectPropertyNode('description', description));
281
- }
282
- else {
283
- for (const prop of metadataObj.properties) {
284
- if (prop.key.type === 'Identifier' && prop.key.name === 'description') {
285
- if (prop.value.type === 'Literal') {
286
- setLiteralValue(prop.value, description);
287
- }
288
- break;
289
- }
290
- }
291
- }
292
- }
293
186
  const DuplicateNameError = StructuredError('DuplicateNameError')();
294
187
  export function parseEvalMetadata(rootDir, filename, contents, projectId, deploymentId, agentId) {
295
188
  const logLevel = (process.env.AGENTUITY_LOG_LEVEL || 'info');
@@ -326,81 +219,54 @@ export function parseEvalMetadata(rootDir, filename, contents, projectId, deploy
326
219
  property.type === 'Identifier' &&
327
220
  property.name === 'createEval') {
328
221
  // Found agent.createEval() call
329
- if (call.arguments.length > 0) {
222
+ // New signature: agent.createEval(name, { description?, handler })
223
+ if (call.arguments.length >= 2) {
330
224
  const firstArg = call.arguments[0];
331
- if (firstArg.type === 'ObjectExpression') {
332
- const evalConfig = firstArg;
333
- let evalName;
334
- let evalDescription;
335
- let variableName;
336
- let metadataObj;
337
- // Capture variable name if available
338
- if (vardecl.id.type === 'Identifier') {
339
- variableName = vardecl.id.name;
340
- }
341
- // Extract metadata from the eval config
342
- for (const prop of evalConfig.properties) {
343
- if (prop.key.type === 'Identifier' && prop.key.name === 'metadata') {
344
- if (prop.value.type === 'ObjectExpression') {
345
- metadataObj = prop.value;
346
- for (const metaProp of metadataObj.properties) {
347
- if (metaProp.key.type === 'Identifier') {
348
- if (metaProp.key.name === 'name' &&
349
- metaProp.value.type === 'Literal') {
350
- evalName = metaProp.value.value;
351
- }
352
- else if (metaProp.key.name === 'description' &&
353
- metaProp.value.type === 'Literal') {
354
- evalDescription = metaProp.value.value;
355
- }
356
- }
357
- }
225
+ const secondArg = call.arguments[1];
226
+ let evalName;
227
+ let evalDescription;
228
+ let configObj;
229
+ // First argument should be a string literal (the name)
230
+ if (firstArg.type === 'Literal' &&
231
+ typeof firstArg.value === 'string') {
232
+ evalName = firstArg.value;
233
+ }
234
+ else {
235
+ throw new MetadataError({
236
+ filename,
237
+ line: body.loc?.start?.line,
238
+ message: 'agent.createEval() first argument must be a string literal name.',
239
+ });
240
+ }
241
+ // Second argument should be the config object
242
+ if (secondArg.type === 'ObjectExpression') {
243
+ configObj = secondArg;
244
+ // Extract description from config object
245
+ for (const prop of configObj.properties) {
246
+ if (prop.key.type === 'Identifier' &&
247
+ prop.key.name === 'description') {
248
+ if (prop.value.type === 'Literal') {
249
+ evalDescription = prop.value.value;
358
250
  }
359
251
  }
360
252
  }
361
- // Use metadata.name if provided, otherwise use variable name
362
- // Throw error if neither is available (should never happen)
363
- let finalName;
364
- if (evalName) {
365
- finalName = evalName;
366
- }
367
- else if (variableName) {
368
- finalName = camelToKebab(variableName);
369
- }
370
- else {
371
- throw new MetadataError({
372
- filename,
373
- line: body.loc?.start?.line,
374
- message: 'Eval is missing a name. Please provide metadata.name or use a named export.',
375
- });
376
- }
377
- logger.trace(`Found eval: ${finalName}${evalDescription ? ` - ${evalDescription}` : ''}`);
378
- const evalId = getEvalId(projectId, deploymentId, rel, finalName, version);
379
- // Inject metadata into AST if metadata object exists
380
- let stableEvalId;
381
- const effectiveAgentId = agentId || '';
382
- if (metadataObj) {
383
- augmentEvalMetadataNode(projectId, effectiveAgentId, evalId, finalName, rel, version, ast, metadataObj, filename);
384
- // Extract evalId from metadata after augmentation
385
- const metadata = parseObjectExpressionToMap(metadataObj);
386
- stableEvalId =
387
- metadata.get('evalId') ||
388
- generateStableEvalId(projectId, effectiveAgentId, finalName);
389
- }
390
- else {
391
- // If no metadata object, generate stable evalId
392
- stableEvalId = generateStableEvalId(projectId, effectiveAgentId, finalName);
393
- }
394
- evals.push({
395
- filename: rel,
396
- id: evalId,
397
- version,
398
- identifier: finalName,
399
- name: finalName,
400
- evalId: stableEvalId,
401
- description: evalDescription,
402
- });
403
253
  }
254
+ const finalName = evalName;
255
+ logger.trace(`Found eval: ${finalName}${evalDescription ? ` - ${evalDescription}` : ''}`);
256
+ const evalId = getEvalId(projectId, deploymentId, rel, finalName, version);
257
+ // Generate stable evalId
258
+ const effectiveAgentId = agentId || '';
259
+ const stableEvalId = generateStableEvalId(projectId, effectiveAgentId, finalName);
260
+ // Note: We no longer inject metadata into the AST since there's no metadata object
261
+ // The runtime will generate IDs from the name parameter
262
+ evals.push({
263
+ filename: rel,
264
+ id: evalId,
265
+ version,
266
+ name: finalName,
267
+ evalId: stableEvalId,
268
+ description: evalDescription,
269
+ });
404
270
  }
405
271
  }
406
272
  }
@@ -433,8 +299,11 @@ export function parseEvalMetadata(rootDir, filename, contents, projectId, deploy
433
299
  return [newsource, evals];
434
300
  }
435
301
  const InvalidExportError = StructuredError('InvalidExportError')();
436
- const InvalidCreateAgentError = StructuredError('InvalidCreateAgentError')();
437
302
  export async function parseAgentMetadata(rootDir, filename, contents, projectId, deploymentId) {
303
+ // Quick string search optimization - skip AST parsing if no createAgent call
304
+ if (!contents.includes('createAgent')) {
305
+ return undefined;
306
+ }
438
307
  const ast = acornLoose.parse(contents, {
439
308
  locations: true,
440
309
  ecmaVersion: 'latest',
@@ -452,42 +321,54 @@ export async function parseAgentMetadata(rootDir, filename, contents, projectId,
452
321
  if (body.declaration?.type === 'CallExpression') {
453
322
  const call = body.declaration;
454
323
  if (call.callee.name === 'createAgent') {
455
- for (const callarg of call.arguments) {
456
- const callargexp = callarg;
457
- // Extract schema code before processing metadata
458
- let inputSchemaCode;
459
- let outputSchemaCode;
460
- if (!schemaCodeExtracted) {
461
- const schemaCode = extractSchemaCode(callargexp);
462
- inputSchemaCode = schemaCode.inputSchemaCode;
463
- outputSchemaCode = schemaCode.outputSchemaCode;
464
- schemaCodeExtracted = true;
465
- }
466
- for (const prop of callargexp.properties) {
467
- if (prop.key.type === 'Identifier' && prop.key.name === 'metadata') {
468
- result = augmentAgentMetadataNode(projectId, id, name, rel, version, ast, prop.value, filename, inputSchemaCode, outputSchemaCode);
469
- break;
470
- }
471
- }
472
- if (!result) {
473
- result = createAgentMetadataNode(id, name, rel, version, ast, callargexp, filename);
324
+ // Enforce new API: createAgent('name', {config})
325
+ if (call.arguments.length < 2) {
326
+ throw new Error(`createAgent requires 2 arguments: createAgent('name', config) in ${filename}`);
327
+ }
328
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
329
+ const nameArg = call.arguments[0];
330
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
331
+ const configArg = call.arguments[1];
332
+ if (!nameArg || nameArg.type !== 'Literal' || typeof nameArg.value !== 'string') {
333
+ throw new Error(`createAgent first argument must be a string literal in ${filename}`);
334
+ }
335
+ if (!isObjectExpression(configArg)) {
336
+ throw new Error(`createAgent second argument must be a config object in ${filename}`);
337
+ }
338
+ const callargexp = configArg;
339
+ // Extract schema code before processing metadata
340
+ let inputSchemaCode;
341
+ let outputSchemaCode;
342
+ if (!schemaCodeExtracted) {
343
+ const schemaCode = extractSchemaCode(callargexp);
344
+ inputSchemaCode = schemaCode.inputSchemaCode;
345
+ outputSchemaCode = schemaCode.outputSchemaCode;
346
+ schemaCodeExtracted = true;
347
+ }
348
+ for (const prop of callargexp.properties) {
349
+ if (prop.key.type === 'Identifier' && prop.key.name === 'metadata') {
350
+ result = augmentAgentMetadataNode(projectId, id, rel, version, ast, prop.value, filename, inputSchemaCode, outputSchemaCode);
351
+ break;
474
352
  }
475
- break;
476
353
  }
354
+ if (!result) {
355
+ result = createAgentMetadataNode(id, name, rel, version, ast, callargexp, filename, projectId, inputSchemaCode, outputSchemaCode);
356
+ }
357
+ break;
477
358
  }
478
359
  }
479
- if (!result) {
480
- const identifier = body.declaration;
481
- exportName = identifier.name;
482
- break;
483
- }
360
+ }
361
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
362
+ if (!result && body.declaration?.type === 'Identifier') {
363
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
364
+ const identifier = body.declaration;
365
+ exportName = identifier.name;
366
+ break;
484
367
  }
485
368
  }
369
+ // If no default export or createAgent found, skip this file (it's not an agent)
486
370
  if (!result && !exportName) {
487
- throw new InvalidExportError({
488
- filename,
489
- message: `could not find default export for ${filename} using ${rootDir}`,
490
- });
371
+ return undefined;
491
372
  }
492
373
  if (!result) {
493
374
  for (const body of ast.body) {
@@ -499,29 +380,42 @@ export async function parseAgentMetadata(rootDir, filename, contents, projectId,
499
380
  if (vardecl.init?.type === 'CallExpression') {
500
381
  const call = vardecl.init;
501
382
  if (call.callee.name === 'createAgent') {
502
- for (const callarg of call.arguments) {
503
- const callargexp = callarg;
504
- // Extract schema code before processing metadata
505
- let inputSchemaCode;
506
- let outputSchemaCode;
507
- if (!schemaCodeExtracted) {
508
- const schemaCode = extractSchemaCode(callargexp);
509
- inputSchemaCode = schemaCode.inputSchemaCode;
510
- outputSchemaCode = schemaCode.outputSchemaCode;
511
- schemaCodeExtracted = true;
512
- }
513
- for (const prop of callargexp.properties) {
514
- if (prop.key.type === 'Identifier' &&
515
- prop.key.name === 'metadata') {
516
- result = augmentAgentMetadataNode(projectId, id, name, rel, version, ast, prop.value, filename, inputSchemaCode, outputSchemaCode);
517
- break;
518
- }
519
- }
520
- if (!result) {
521
- result = createAgentMetadataNode(id, name, rel, version, ast, callargexp, filename);
383
+ // Enforce new API: createAgent('name', {config})
384
+ if (call.arguments.length < 2) {
385
+ throw new Error(`createAgent requires 2 arguments: createAgent('name', config) in ${filename}`);
386
+ }
387
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
388
+ const nameArg = call.arguments[0];
389
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
390
+ const configArg = call.arguments[1];
391
+ if (!nameArg ||
392
+ nameArg.type !== 'Literal' ||
393
+ typeof nameArg.value !== 'string') {
394
+ throw new Error(`createAgent first argument must be a string literal in ${filename}`);
395
+ }
396
+ if (!isObjectExpression(configArg)) {
397
+ throw new Error(`createAgent second argument must be a config object in ${filename}`);
398
+ }
399
+ const callargexp = configArg;
400
+ // Extract schema code before processing metadata
401
+ let inputSchemaCode;
402
+ let outputSchemaCode;
403
+ if (!schemaCodeExtracted) {
404
+ const schemaCode = extractSchemaCode(callargexp);
405
+ inputSchemaCode = schemaCode.inputSchemaCode;
406
+ outputSchemaCode = schemaCode.outputSchemaCode;
407
+ schemaCodeExtracted = true;
408
+ }
409
+ for (const prop of callargexp.properties) {
410
+ if (prop.key.type === 'Identifier' && prop.key.name === 'metadata') {
411
+ result = augmentAgentMetadataNode(projectId, id, rel, version, ast, prop.value, filename, inputSchemaCode, outputSchemaCode);
412
+ break;
522
413
  }
523
- break;
524
414
  }
415
+ if (!result) {
416
+ result = createAgentMetadataNode(id, name, rel, version, ast, callargexp, filename, projectId, inputSchemaCode, outputSchemaCode);
417
+ }
418
+ break;
525
419
  }
526
420
  }
527
421
  }
@@ -530,11 +424,9 @@ export async function parseAgentMetadata(rootDir, filename, contents, projectId,
530
424
  }
531
425
  }
532
426
  }
427
+ // If no createAgent found after checking all declarations, skip this file
533
428
  if (!result) {
534
- throw new InvalidCreateAgentError({
535
- filename,
536
- message: `error parsing: ${filename}. could not find an proper createAgent defined in this file`,
537
- });
429
+ return undefined;
538
430
  }
539
431
  // Parse evals from eval.ts file in the same directory
540
432
  const logLevel = (process.env.AGENTUITY_LOG_LEVEL || 'info');
@@ -565,6 +457,69 @@ export async function parseAgentMetadata(rootDir, filename, contents, projectId,
565
457
  }
566
458
  const InvalidCreateRouterError = StructuredError('InvalidCreateRouterError')();
567
459
  const InvalidRouterConfigError = StructuredError('InvalidRouterConfigError')();
460
+ function hasValidatorCall(args) {
461
+ if (!args || args.length === 0)
462
+ return { hasValidator: false };
463
+ for (const arg of args) {
464
+ if (!arg || typeof arg !== 'object')
465
+ continue;
466
+ const node = arg;
467
+ // Check if this is a CallExpression with callee named 'validator'
468
+ if (node.type === 'CallExpression') {
469
+ const callExpr = node;
470
+ if (callExpr.callee.type === 'Identifier') {
471
+ const identifier = callExpr.callee;
472
+ if (identifier.name === 'validator') {
473
+ // Try to extract schema variables from validator({ input, output })
474
+ const schemas = extractValidatorSchemas(callExpr);
475
+ return { hasValidator: true, ...schemas };
476
+ }
477
+ }
478
+ // Check for agent.validator()
479
+ if (callExpr.callee.type === 'MemberExpression') {
480
+ const member = callExpr.callee;
481
+ if (member.property && member.property.name === 'validator') {
482
+ // Extract agent variable name (the object before .validator())
483
+ const agentVariable = member.object.type === 'Identifier'
484
+ ? member.object.name
485
+ : undefined;
486
+ return { hasValidator: true, agentVariable };
487
+ }
488
+ }
489
+ }
490
+ }
491
+ return { hasValidator: false };
492
+ }
493
+ /**
494
+ * Extract schema variable names from validator() call arguments
495
+ * Example: validator({ input: myInputSchema, output: myOutputSchema })
496
+ */
497
+ function extractValidatorSchemas(callExpr) {
498
+ const result = {};
499
+ // Check if validator has arguments
500
+ if (!callExpr.arguments || callExpr.arguments.length === 0) {
501
+ return result;
502
+ }
503
+ // First argument should be an object expression
504
+ const firstArg = callExpr.arguments[0];
505
+ if (!firstArg || firstArg.type !== 'ObjectExpression') {
506
+ return result;
507
+ }
508
+ const objExpr = firstArg;
509
+ for (const prop of objExpr.properties) {
510
+ const keyName = prop.key.name;
511
+ if ((keyName === 'input' || keyName === 'output') && prop.value.type === 'Identifier') {
512
+ const valueName = prop.value.name;
513
+ if (keyName === 'input') {
514
+ result.inputSchemaVariable = valueName;
515
+ }
516
+ else {
517
+ result.outputSchemaVariable = valueName;
518
+ }
519
+ }
520
+ }
521
+ return result;
522
+ }
568
523
  export async function parseRoute(rootDir, filename, projectId, deploymentId) {
569
524
  const contents = await Bun.file(filename).text();
570
525
  const version = hash(contents);
@@ -575,6 +530,26 @@ export async function parseRoute(rootDir, filename, projectId, deploymentId) {
575
530
  });
576
531
  let exportName;
577
532
  let variableName;
533
+ // Extract import statements to map variable names to their import sources
534
+ const importMap = new Map(); // Maps variable name to import path
535
+ for (const body of ast.body) {
536
+ if (body.type === 'ImportDeclaration') {
537
+ const importDecl = body;
538
+ const importPath = importDecl.source?.value;
539
+ if (importPath && importDecl.specifiers) {
540
+ for (const spec of importDecl.specifiers) {
541
+ if (spec.type === 'ImportDefaultSpecifier' && spec.local?.name) {
542
+ // import hello from '@agent/hello'
543
+ importMap.set(spec.local.name, importPath);
544
+ }
545
+ else if (spec.type === 'ImportSpecifier' && spec.local?.name) {
546
+ // import { hello } from './shared'
547
+ importMap.set(spec.local.name, importPath);
548
+ }
549
+ }
550
+ }
551
+ }
552
+ }
578
553
  for (const body of ast.body) {
579
554
  if (body.type === 'ExportDefaultDeclaration') {
580
555
  const identifier = body.declaration;
@@ -596,11 +571,20 @@ export async function parseRoute(rootDir, filename, projectId, deploymentId) {
596
571
  if (identifier.name === exportName) {
597
572
  if (vardecl.init?.type === 'CallExpression') {
598
573
  const call = vardecl.init;
574
+ // Support both createRouter() and new Hono()
599
575
  if (call.callee.name === 'createRouter') {
600
576
  variableName = identifier.name;
601
577
  break;
602
578
  }
603
579
  }
580
+ else if (vardecl.init?.type === 'NewExpression') {
581
+ const newExpr = vardecl.init;
582
+ // Support new Hono() pattern
583
+ if (newExpr.callee.name === 'Hono') {
584
+ variableName = identifier.name;
585
+ break;
586
+ }
587
+ }
604
588
  }
605
589
  }
606
590
  }
@@ -609,21 +593,17 @@ export async function parseRoute(rootDir, filename, projectId, deploymentId) {
609
593
  if (!variableName) {
610
594
  throw new InvalidCreateRouterError({
611
595
  filename,
612
- message: `error parsing: ${filename}. could not find an proper createRouter defined in this file`,
596
+ message: `error parsing: ${filename}. could not find an proper createRouter or new Hono() defined in this file`,
613
597
  });
614
598
  }
615
599
  const rel = relative(rootDir, filename);
616
600
  const dir = dirname(filename);
617
601
  const name = basename(dir);
618
- // Detect if this is a subagent route and build proper path
619
- const relativePath = relative(rootDir, dir)
620
- .replace(/^src\/agent\//, '')
621
- .replace(/^src\/web\//, '');
622
- const pathParts = relativePath.split('/').filter(Boolean);
623
- const isSubagent = pathParts.length === 2 && filename.includes('src/agent');
624
- const routeName = isSubagent ? pathParts.join('/') : name;
602
+ // For src/api/index.ts, we don't want to add the folder name since it's the root API router
603
+ const isRootApi = filename.includes('src/api/index.ts');
604
+ const routeName = isRootApi ? '' : name;
625
605
  const routes = [];
626
- const routePrefix = filename.includes('src/agent') ? '/agent' : '/api';
606
+ const routePrefix = '/api';
627
607
  try {
628
608
  for (const body of ast.body) {
629
609
  if (body.type === 'ExpressionStatement') {
@@ -744,6 +724,27 @@ export async function parseRoute(rootDir, filename, projectId, deploymentId) {
744
724
  .replaceAll(/\/{2,}/g, '/')
745
725
  .replaceAll(/\/$/g, '');
746
726
  const id = generateRouteId(projectId, deploymentId, type, method, rel, thepath, version);
727
+ // Check if this route uses validator middleware
728
+ const validatorInfo = hasValidatorCall(statement.expression.arguments);
729
+ // Store validator info in config if present
730
+ const routeConfig = config ? { ...config } : {};
731
+ if (validatorInfo.hasValidator) {
732
+ routeConfig.hasValidator = true;
733
+ if (validatorInfo.agentVariable) {
734
+ routeConfig.agentVariable = validatorInfo.agentVariable;
735
+ // Look up where this agent variable is imported from
736
+ const agentImportPath = importMap.get(validatorInfo.agentVariable);
737
+ if (agentImportPath) {
738
+ routeConfig.agentImportPath = agentImportPath;
739
+ }
740
+ }
741
+ if (validatorInfo.inputSchemaVariable) {
742
+ routeConfig.inputSchemaVariable = validatorInfo.inputSchemaVariable;
743
+ }
744
+ if (validatorInfo.outputSchemaVariable) {
745
+ routeConfig.outputSchemaVariable = validatorInfo.outputSchemaVariable;
746
+ }
747
+ }
747
748
  routes.push({
748
749
  id,
749
750
  method: method,
@@ -751,7 +752,7 @@ export async function parseRoute(rootDir, filename, projectId, deploymentId) {
751
752
  filename: rel,
752
753
  path: thepath,
753
754
  version,
754
- config,
755
+ config: Object.keys(routeConfig).length > 0 ? routeConfig : undefined,
755
756
  });
756
757
  }
757
758
  }