@agentuity/cli 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.
- package/AGENTS.md +1 -1
- package/README.md +1 -1
- package/dist/cmd/ai/capabilities/show.d.ts.map +1 -1
- package/dist/cmd/ai/capabilities/show.js +0 -13
- package/dist/cmd/ai/capabilities/show.js.map +1 -1
- package/dist/cmd/ai/prompt/agent.js +1 -1
- package/dist/cmd/ai/prompt/api.js +1 -1
- package/dist/cmd/build/ast.d.ts +1 -2
- package/dist/cmd/build/ast.d.ts.map +1 -1
- package/dist/cmd/build/ast.js +261 -260
- package/dist/cmd/build/ast.js.map +1 -1
- package/dist/cmd/build/bundler.d.ts +4 -1
- package/dist/cmd/build/bundler.d.ts.map +1 -1
- package/dist/cmd/build/bundler.js +89 -6
- package/dist/cmd/build/bundler.js.map +1 -1
- package/dist/cmd/build/index.d.ts.map +1 -1
- package/dist/cmd/build/index.js +2 -1
- package/dist/cmd/build/index.js.map +1 -1
- package/dist/cmd/build/plugin.d.ts.map +1 -1
- package/dist/cmd/build/plugin.js +152 -414
- package/dist/cmd/build/plugin.js.map +1 -1
- package/dist/cmd/build/route-registry.d.ts +36 -0
- package/dist/cmd/build/route-registry.d.ts.map +1 -0
- package/dist/cmd/build/route-registry.js +151 -0
- package/dist/cmd/build/route-registry.js.map +1 -0
- package/dist/cmd/cloud/deploy.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.js +2 -0
- package/dist/cmd/cloud/deploy.js.map +1 -1
- package/dist/cmd/cloud/index.d.ts.map +1 -1
- package/dist/cmd/cloud/index.js +0 -2
- package/dist/cmd/cloud/index.js.map +1 -1
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/index.js +4 -3
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/cmd/dev/sync.d.ts.map +1 -1
- package/dist/cmd/dev/sync.js +0 -15
- package/dist/cmd/dev/sync.js.map +1 -1
- package/dist/cmd/dev/templates.d.ts.map +1 -1
- package/dist/cmd/dev/templates.js +11 -35
- package/dist/cmd/dev/templates.js.map +1 -1
- package/dist/cmd/profile/create.d.ts.map +1 -1
- package/dist/cmd/profile/create.js +0 -1
- package/dist/cmd/profile/create.js.map +1 -1
- package/dist/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/cmd/project/template-flow.js +64 -53
- package/dist/cmd/project/template-flow.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -3
- package/dist/config.js.map +1 -1
- package/dist/env-util.d.ts.map +1 -1
- package/dist/env-util.js +0 -3
- package/dist/env-util.js.map +1 -1
- package/dist/tui/box.d.ts +19 -0
- package/dist/tui/box.d.ts.map +1 -0
- package/dist/tui/box.js +160 -0
- package/dist/tui/box.js.map +1 -0
- package/dist/tui/colors.d.ts +20 -0
- package/dist/tui/colors.d.ts.map +1 -0
- package/dist/tui/colors.js +52 -0
- package/dist/tui/colors.js.map +1 -0
- package/dist/tui/group.d.ts +25 -0
- package/dist/tui/group.d.ts.map +1 -0
- package/dist/tui/group.js +32 -0
- package/dist/tui/group.js.map +1 -0
- package/dist/tui/prompt.d.ts +65 -0
- package/dist/tui/prompt.d.ts.map +1 -0
- package/dist/tui/prompt.js +377 -0
- package/dist/tui/prompt.js.map +1 -0
- package/dist/tui/symbols.d.ts +32 -0
- package/dist/tui/symbols.d.ts.map +1 -0
- package/dist/tui/symbols.js +52 -0
- package/dist/tui/symbols.js.map +1 -0
- package/dist/tui.d.ts +6 -0
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +6 -0
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts +0 -24
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -1
- package/dist/types.js.map +1 -1
- package/package.json +3 -3
- package/src/cmd/ai/capabilities/show.ts +0 -13
- package/src/cmd/ai/prompt/agent.ts +1 -1
- package/src/cmd/ai/prompt/api.ts +1 -1
- package/src/cmd/build/ast.ts +364 -334
- package/src/cmd/build/bundler.ts +123 -9
- package/src/cmd/build/index.ts +2 -1
- package/src/cmd/build/plugin.ts +171 -493
- package/src/cmd/build/route-registry.ts +198 -0
- package/src/cmd/cloud/deploy.ts +2 -0
- package/src/cmd/cloud/index.ts +0 -2
- package/src/cmd/dev/index.ts +4 -3
- package/src/cmd/dev/sync.ts +0 -28
- package/src/cmd/dev/templates.ts +11 -35
- package/src/cmd/profile/create.ts +0 -1
- package/src/cmd/project/template-flow.ts +77 -57
- package/src/config.ts +0 -3
- package/src/env-util.ts +0 -3
- package/src/tui/box.ts +202 -0
- package/src/tui/colors.ts +55 -0
- package/src/tui/group.ts +56 -0
- package/src/tui/prompt.ts +506 -0
- package/src/tui/symbols.ts +64 -0
- package/src/tui.ts +14 -0
- package/src/types.ts +0 -1
- package/dist/cmd/cloud/objectstore/delete-bucket.d.ts +0 -3
- package/dist/cmd/cloud/objectstore/delete-bucket.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/delete-bucket.js +0 -72
- package/dist/cmd/cloud/objectstore/delete-bucket.js.map +0 -1
- package/dist/cmd/cloud/objectstore/delete.d.ts +0 -3
- package/dist/cmd/cloud/objectstore/delete.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/delete.js +0 -65
- package/dist/cmd/cloud/objectstore/delete.js.map +0 -1
- package/dist/cmd/cloud/objectstore/get.d.ts +0 -3
- package/dist/cmd/cloud/objectstore/get.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/get.js +0 -75
- package/dist/cmd/cloud/objectstore/get.js.map +0 -1
- package/dist/cmd/cloud/objectstore/index.d.ts +0 -3
- package/dist/cmd/cloud/objectstore/index.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/index.js +0 -36
- package/dist/cmd/cloud/objectstore/index.js.map +0 -1
- package/dist/cmd/cloud/objectstore/list-buckets.d.ts +0 -3
- package/dist/cmd/cloud/objectstore/list-buckets.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/list-buckets.js +0 -46
- package/dist/cmd/cloud/objectstore/list-buckets.js.map +0 -1
- package/dist/cmd/cloud/objectstore/list-keys.d.ts +0 -3
- package/dist/cmd/cloud/objectstore/list-keys.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/list-keys.js +0 -58
- package/dist/cmd/cloud/objectstore/list-keys.js.map +0 -1
- package/dist/cmd/cloud/objectstore/put.d.ts +0 -3
- package/dist/cmd/cloud/objectstore/put.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/put.js +0 -66
- package/dist/cmd/cloud/objectstore/put.js.map +0 -1
- package/dist/cmd/cloud/objectstore/repl.d.ts +0 -3
- package/dist/cmd/cloud/objectstore/repl.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/repl.js +0 -224
- package/dist/cmd/cloud/objectstore/repl.js.map +0 -1
- package/dist/cmd/cloud/objectstore/url.d.ts +0 -3
- package/dist/cmd/cloud/objectstore/url.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/url.js +0 -64
- package/dist/cmd/cloud/objectstore/url.js.map +0 -1
- package/dist/cmd/cloud/objectstore/util.d.ts +0 -11
- package/dist/cmd/cloud/objectstore/util.d.ts.map +0 -1
- package/dist/cmd/cloud/objectstore/util.js +0 -18
- package/dist/cmd/cloud/objectstore/util.js.map +0 -1
- package/src/cmd/build/ast.test.ts +0 -418
- package/src/cmd/build/fix-duplicate-exports.test.ts +0 -387
- package/src/cmd/cloud/objectstore/delete-bucket.ts +0 -77
- package/src/cmd/cloud/objectstore/delete.ts +0 -67
- package/src/cmd/cloud/objectstore/get.ts +0 -77
- package/src/cmd/cloud/objectstore/index.ts +0 -36
- package/src/cmd/cloud/objectstore/list-buckets.ts +0 -51
- package/src/cmd/cloud/objectstore/list-keys.ts +0 -63
- package/src/cmd/cloud/objectstore/put.ts +0 -74
- package/src/cmd/cloud/objectstore/repl.ts +0 -239
- package/src/cmd/cloud/objectstore/url.ts +0 -67
- package/src/cmd/cloud/objectstore/util.ts +0 -29
- package/src/crypto/box.test.ts +0 -431
- package/src/env-util.test.ts +0 -194
package/src/cmd/build/plugin.ts
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
import type { BunPlugin } from 'bun';
|
|
2
|
-
import { dirname,
|
|
2
|
+
import { dirname, join, resolve } from 'node:path';
|
|
3
3
|
import { existsSync, writeFileSync, mkdirSync, unlinkSync } from 'node:fs';
|
|
4
4
|
import type { BuildMetadata } from '@agentuity/server';
|
|
5
5
|
import {
|
|
6
6
|
parseAgentMetadata,
|
|
7
|
-
parseRoute,
|
|
8
7
|
parseEvalMetadata,
|
|
8
|
+
parseRoute,
|
|
9
9
|
analyzeWorkbench,
|
|
10
|
-
checkRouteConflicts,
|
|
11
10
|
generateLifecycleTypes,
|
|
12
11
|
findCreateAppEndPosition,
|
|
13
12
|
} from './ast';
|
|
14
13
|
import { StructuredError, type WorkbenchConfig } from '@agentuity/core';
|
|
15
14
|
import { applyPatch, generatePatches } from './patch';
|
|
16
|
-
import { detectSubagent } from '../../utils/detectSubagent';
|
|
17
15
|
import { createLogger } from '@agentuity/server';
|
|
18
16
|
import type { LogLevel } from '../../types';
|
|
19
17
|
import { toCamelCase, toPascalCase } from '../../utils/string';
|
|
18
|
+
import { generateRouteRegistry, type RouteInfo } from './route-registry';
|
|
20
19
|
|
|
21
20
|
/**
|
|
22
21
|
* Setup lifecycle types by analyzing app.ts for setup() function
|
|
@@ -77,53 +76,21 @@ async function setupWorkbench(srcDir: string): Promise<WorkbenchConfig | null> {
|
|
|
77
76
|
|
|
78
77
|
const workbenchConfig = analysis.config;
|
|
79
78
|
|
|
80
|
-
// Check for route conflicts if workbench is being used
|
|
81
|
-
if (workbenchConfig?.route) {
|
|
82
|
-
const hasConflict = checkRouteConflicts(appContent, workbenchConfig.route);
|
|
83
|
-
if (hasConflict) {
|
|
84
|
-
const logger = createLogger((process.env.AGENTUITY_LOG_LEVEL as LogLevel) || 'info');
|
|
85
|
-
logger.error(`🚨 Route conflict detected!\n`);
|
|
86
|
-
logger.error(
|
|
87
|
-
` Workbench route '${workbenchConfig.route}' conflicts with existing application route`
|
|
88
|
-
);
|
|
89
|
-
logger.error(` Please use a different route or remove the conflicting route.\n`);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
79
|
return workbenchConfig;
|
|
94
80
|
}
|
|
95
81
|
|
|
96
82
|
const AgentIdentifierCollisionError = StructuredError('AgentIdentifierCollisionError');
|
|
97
|
-
const SubAgentNameCollisionError = StructuredError('SubAgentNameCollisionError');
|
|
98
83
|
|
|
99
84
|
function generateAgentRegistry(srcDir: string, agentInfo: Array<Record<string, string>>) {
|
|
100
|
-
// Separate parent agents and subagents
|
|
101
|
-
const parentAgents = agentInfo.filter((a) => !a.parent);
|
|
102
|
-
const subagents = agentInfo.filter((a) => a.parent);
|
|
103
|
-
|
|
104
|
-
// Group subagents by parent
|
|
105
|
-
const subagentsByParent = new Map<string, Array<Record<string, string>>>();
|
|
106
|
-
for (const subagent of subagents) {
|
|
107
|
-
const parentName = subagent.parent!;
|
|
108
|
-
if (!subagentsByParent.has(parentName)) {
|
|
109
|
-
subagentsByParent.set(parentName, []);
|
|
110
|
-
}
|
|
111
|
-
subagentsByParent.get(parentName)!.push(subagent);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
85
|
// Detect naming collisions in generated identifiers
|
|
115
|
-
// Naming strategy: parent + child names are combined as `${parent}_${name}` then converted to camelCase
|
|
116
|
-
// Example: parent="user", child="profile" → "user_profile" → "userProfile"
|
|
117
|
-
// Potential collision: parent="user_profile", child="info" and parent="user", child="profile_info" both → "userProfileInfo"
|
|
118
86
|
const generatedNames = new Set<string>();
|
|
119
87
|
const collisions: string[] = [];
|
|
120
88
|
|
|
121
89
|
for (const agent of agentInfo) {
|
|
122
|
-
const
|
|
123
|
-
const camelName = toCamelCase(fullName);
|
|
90
|
+
const camelName = toCamelCase(agent.name);
|
|
124
91
|
|
|
125
92
|
if (generatedNames.has(camelName)) {
|
|
126
|
-
collisions.push(`Identifier collision detected: "${camelName}" (from "${
|
|
93
|
+
collisions.push(`Identifier collision detected: "${camelName}" (from "${agent.name}")`);
|
|
127
94
|
}
|
|
128
95
|
generatedNames.add(camelName);
|
|
129
96
|
}
|
|
@@ -138,158 +105,45 @@ function generateAgentRegistry(srcDir: string, agentInfo: Array<Record<string, s
|
|
|
138
105
|
}
|
|
139
106
|
|
|
140
107
|
// Generate imports for all agents
|
|
108
|
+
// Registry is now in .agentuity/, so imports need to go up one level and into src/
|
|
141
109
|
const imports = agentInfo
|
|
142
|
-
.map(({ name, path
|
|
143
|
-
const
|
|
144
|
-
const
|
|
145
|
-
const relativePath = path.replace(/^\.\/agent\//, './');
|
|
110
|
+
.map(({ name, path }) => {
|
|
111
|
+
const camelName = toCamelCase(name);
|
|
112
|
+
const relativePath = path.replace(/^\.\/agent\//, '../src/agent/');
|
|
146
113
|
return `import ${camelName}Agent from '${relativePath}';`;
|
|
147
114
|
})
|
|
148
115
|
.join('\n');
|
|
149
116
|
|
|
150
|
-
//
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const children = subagentsByParent.get(parentAgent.name) || [];
|
|
158
|
-
for (const child of children) {
|
|
159
|
-
const childPropertyName = toCamelCase(child.name);
|
|
160
|
-
|
|
161
|
-
// Check for collision with reserved agent properties
|
|
162
|
-
if (reservedAgentProperties.includes(childPropertyName)) {
|
|
163
|
-
throw new SubAgentNameCollisionError({
|
|
164
|
-
message:
|
|
165
|
-
`Subagent property name collision detected: "${childPropertyName}" in parent "${parentAgent.name}"\n` +
|
|
166
|
-
`The child name "${child.name}" conflicts with a reserved agent property (${reservedAgentProperties.join(', ')}).\n` +
|
|
167
|
-
`Please rename the subagent to avoid this collision.`,
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Generate nested registry structure
|
|
174
|
-
const registryLines: string[] = [];
|
|
175
|
-
for (const parentAgent of parentAgents) {
|
|
176
|
-
const parentCamelName = toCamelCase(parentAgent.name);
|
|
177
|
-
const children = subagentsByParent.get(parentAgent.name) || [];
|
|
178
|
-
|
|
179
|
-
if (children.length === 0) {
|
|
180
|
-
// No subagents, simple assignment
|
|
181
|
-
registryLines.push(` ${parentCamelName}: ${parentCamelName}Agent,`);
|
|
182
|
-
} else {
|
|
183
|
-
// Has subagents, create nested structure using object spread (no mutation)
|
|
184
|
-
registryLines.push(` ${parentCamelName}: {`);
|
|
185
|
-
registryLines.push(` ...${parentCamelName}Agent,`);
|
|
186
|
-
for (const child of children) {
|
|
187
|
-
const childCamelName = toCamelCase(`${parentAgent.name}_${child.name}`);
|
|
188
|
-
registryLines.push(` ${toCamelCase(child.name)}: ${childCamelName}Agent,`);
|
|
189
|
-
}
|
|
190
|
-
registryLines.push(` },`);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
const registry = registryLines.join('\n');
|
|
117
|
+
// Generate flat registry structure (no subagents)
|
|
118
|
+
const registry = agentInfo
|
|
119
|
+
.map(({ name }) => {
|
|
120
|
+
const camelName = toCamelCase(name);
|
|
121
|
+
return ` ${camelName}: ${camelName}Agent,`;
|
|
122
|
+
})
|
|
123
|
+
.join('\n');
|
|
194
124
|
|
|
195
125
|
// Generate type exports for all agents
|
|
196
126
|
const typeExports = agentInfo
|
|
197
|
-
.map(({ name
|
|
198
|
-
const
|
|
199
|
-
const
|
|
200
|
-
const pascalName = toPascalCase(fullName);
|
|
127
|
+
.map(({ name }) => {
|
|
128
|
+
const camelName = toCamelCase(name);
|
|
129
|
+
const pascalName = toPascalCase(name);
|
|
201
130
|
return `export type ${pascalName}AgentRunner = AgentRunner<typeof ${camelName}Agent['inputSchema'], typeof ${camelName}Agent['outputSchema'], typeof ${camelName}Agent['stream'] extends true ? true : false>;`;
|
|
202
131
|
})
|
|
203
132
|
.join('\n');
|
|
204
133
|
|
|
205
|
-
// Generate
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
// No subagents
|
|
213
|
-
honoAgentTypeLines.push(
|
|
214
|
-
` ${parentCamelName}: AgentRunner<LocalAgentRegistry['${parentCamelName}']['inputSchema'], LocalAgentRegistry['${parentCamelName}']['outputSchema'], LocalAgentRegistry['${parentCamelName}']['stream'] extends true ? true : false>;`
|
|
215
|
-
);
|
|
216
|
-
} else {
|
|
217
|
-
// Has subagents - create intersection type
|
|
218
|
-
honoAgentTypeLines.push(
|
|
219
|
-
` ${parentCamelName}: AgentRunner<LocalAgentRegistry['${parentCamelName}']['inputSchema'], LocalAgentRegistry['${parentCamelName}']['outputSchema'], LocalAgentRegistry['${parentCamelName}']['stream'] extends true ? true : false> & {`
|
|
220
|
-
);
|
|
221
|
-
for (const child of children) {
|
|
222
|
-
const childCamelName = toCamelCase(child.name);
|
|
223
|
-
const fullChildName = toCamelCase(`${parentAgent.name}_${child.name}`);
|
|
224
|
-
honoAgentTypeLines.push(
|
|
225
|
-
` ${childCamelName}: AgentRunner<typeof ${fullChildName}Agent['inputSchema'], typeof ${fullChildName}Agent['outputSchema'], typeof ${fullChildName}Agent['stream'] extends true ? true : false>;`
|
|
226
|
-
);
|
|
227
|
-
}
|
|
228
|
-
honoAgentTypeLines.push(` };`);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
const honoAgentTypes = honoAgentTypeLines.join('\n');
|
|
232
|
-
|
|
233
|
-
// Generate agent type definitions for AgentRegistry interface augmentation
|
|
234
|
-
const runtimeAgentTypeLines: string[] = [];
|
|
235
|
-
for (const parentAgent of parentAgents) {
|
|
236
|
-
const parentCamelName = toCamelCase(parentAgent.name);
|
|
237
|
-
const children = subagentsByParent.get(parentAgent.name) || [];
|
|
238
|
-
|
|
239
|
-
if (children.length === 0) {
|
|
240
|
-
// No subagents - use typeof the imported agent
|
|
241
|
-
runtimeAgentTypeLines.push(
|
|
242
|
-
` ${parentCamelName}: AgentRunner<typeof ${parentCamelName}Agent['inputSchema'], typeof ${parentCamelName}Agent['outputSchema'], typeof ${parentCamelName}Agent['stream'] extends true ? true : false>;`
|
|
243
|
-
);
|
|
244
|
-
} else {
|
|
245
|
-
// Has subagents - create intersection type using typeof
|
|
246
|
-
runtimeAgentTypeLines.push(
|
|
247
|
-
` ${parentCamelName}: AgentRunner<typeof ${parentCamelName}Agent['inputSchema'], typeof ${parentCamelName}Agent['outputSchema'], typeof ${parentCamelName}Agent['stream'] extends true ? true : false> & {`
|
|
248
|
-
);
|
|
249
|
-
for (const child of children) {
|
|
250
|
-
const childCamelName = toCamelCase(child.name);
|
|
251
|
-
const fullChildName = toCamelCase(`${parentAgent.name}_${child.name}`);
|
|
252
|
-
runtimeAgentTypeLines.push(
|
|
253
|
-
` ${childCamelName}: AgentRunner<typeof ${fullChildName}Agent['inputSchema'], typeof ${fullChildName}Agent['outputSchema'], typeof ${fullChildName}Agent['stream'] extends true ? true : false>;`
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
runtimeAgentTypeLines.push(` };`);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
const runtimeAgentTypes = runtimeAgentTypeLines.join('\n');
|
|
260
|
-
|
|
261
|
-
// Generate React client types with nested structure
|
|
262
|
-
const clientAgentTypeLines: string[] = [];
|
|
263
|
-
for (const parentAgent of parentAgents) {
|
|
264
|
-
const parentCamelName = toCamelCase(parentAgent.name);
|
|
265
|
-
const children = subagentsByParent.get(parentAgent.name) || [];
|
|
266
|
-
|
|
267
|
-
if (children.length === 0) {
|
|
268
|
-
// No subagents
|
|
269
|
-
clientAgentTypeLines.push(
|
|
270
|
-
` '${parentAgent.name}': Agent<typeof ${parentCamelName}Agent['inputSchema'], typeof ${parentCamelName}Agent['outputSchema']>;`
|
|
271
|
-
);
|
|
272
|
-
} else {
|
|
273
|
-
// Has subagents - create nested type with subagent access via dot notation
|
|
274
|
-
clientAgentTypeLines.push(
|
|
275
|
-
` '${parentAgent.name}': Agent<typeof ${parentCamelName}Agent['inputSchema'], typeof ${parentCamelName}Agent['outputSchema']>;`
|
|
276
|
-
);
|
|
277
|
-
for (const child of children) {
|
|
278
|
-
const fullChildName = toCamelCase(`${parentAgent.name}_${child.name}`);
|
|
279
|
-
clientAgentTypeLines.push(
|
|
280
|
-
` '${parentAgent.name}.${child.name}': Agent<typeof ${fullChildName}Agent['inputSchema'], typeof ${fullChildName}Agent['outputSchema']>;`
|
|
281
|
-
);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
const reactAgentTypes = clientAgentTypeLines.join('\n');
|
|
134
|
+
// Generate flat agent type definitions for AgentRegistry interface augmentation
|
|
135
|
+
const runtimeAgentTypes = agentInfo
|
|
136
|
+
.map(({ name }) => {
|
|
137
|
+
const camelName = toCamelCase(name);
|
|
138
|
+
return ` ${camelName}: AgentRunner<typeof ${camelName}Agent['inputSchema'], typeof ${camelName}Agent['outputSchema'], typeof ${camelName}Agent['stream'] extends true ? true : false>;`;
|
|
139
|
+
})
|
|
140
|
+
.join('\n');
|
|
286
141
|
|
|
287
142
|
const generatedContent = `/// <reference types="hono" />
|
|
288
143
|
// Auto-generated by Agentuity - do not edit manually
|
|
289
|
-
${imports}
|
|
144
|
+
${imports}
|
|
290
145
|
import type { AgentRunner, Logger } from '@agentuity/runtime';
|
|
291
|
-
import type { KeyValueStorage,
|
|
292
|
-
import type { Agent } from '@agentuity/react';
|
|
146
|
+
import type { KeyValueStorage, StreamStorage, VectorStorage } from '@agentuity/core';
|
|
293
147
|
|
|
294
148
|
/**
|
|
295
149
|
* Registry of all agents in this application.
|
|
@@ -315,38 +169,20 @@ ${runtimeAgentTypes}
|
|
|
315
169
|
}
|
|
316
170
|
}
|
|
317
171
|
|
|
318
|
-
//
|
|
319
|
-
//
|
|
320
|
-
declare module "hono" {
|
|
321
|
-
interface Context {
|
|
322
|
-
agentName: LocalAgentName;
|
|
323
|
-
agent: {
|
|
324
|
-
${honoAgentTypes}
|
|
325
|
-
};
|
|
326
|
-
waitUntil: (promise: Promise<void> | (() => void | Promise<void>)) => void;
|
|
327
|
-
logger: Logger;
|
|
328
|
-
kv: KeyValueStorage;
|
|
329
|
-
objectstore: ObjectStorage;
|
|
330
|
-
stream: StreamStorage;
|
|
331
|
-
vector: VectorStorage;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// Augment @agentuity/react types with strongly-typed agents from this project
|
|
336
|
-
declare module '@agentuity/react' {
|
|
337
|
-
interface AgentRegistry {
|
|
338
|
-
${reactAgentTypes}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
172
|
+
// NOTE: Hono Context properties are accessed via c.var (e.g., c.var.logger, c.var.kv)
|
|
173
|
+
// The Variables interface in @agentuity/runtime defines all available context properties
|
|
341
174
|
`;
|
|
342
175
|
|
|
176
|
+
const projectRoot = join(srcDir, '..');
|
|
177
|
+
const agentuityDir = join(projectRoot, '.agentuity');
|
|
178
|
+
const registryPath = join(agentuityDir, 'registry.generated.ts');
|
|
179
|
+
|
|
343
180
|
const agentsDir = join(srcDir, 'agent');
|
|
344
|
-
const registryPath = join(agentsDir, 'registry.generated.ts');
|
|
345
181
|
const legacyTypesPath = join(agentsDir, 'types.generated.d.ts');
|
|
346
182
|
|
|
347
|
-
// Ensure
|
|
348
|
-
if (!existsSync(
|
|
349
|
-
mkdirSync(
|
|
183
|
+
// Ensure .agentuity directory exists
|
|
184
|
+
if (!existsSync(agentuityDir)) {
|
|
185
|
+
mkdirSync(agentuityDir, { recursive: true });
|
|
350
186
|
}
|
|
351
187
|
|
|
352
188
|
writeFileSync(registryPath, generatedContent, 'utf-8');
|
|
@@ -364,11 +200,9 @@ export function getBuildMetadata(): Partial<BuildMetadata> {
|
|
|
364
200
|
}
|
|
365
201
|
|
|
366
202
|
const AgentNameDuplicateError = StructuredError('AgentNameDuplicateError');
|
|
367
|
-
const MetadataMissingError = StructuredError('MetadataMissingError');
|
|
368
203
|
const MetadataPropertyMissingError = StructuredError('MetadataPropertyMissingError')<{
|
|
369
204
|
name: string;
|
|
370
205
|
}>();
|
|
371
|
-
const SubAgentMissingError = StructuredError('SubAgentMissingError');
|
|
372
206
|
|
|
373
207
|
const AgentuityBundler: BunPlugin = {
|
|
374
208
|
name: 'Agentuity Bundler',
|
|
@@ -389,69 +223,51 @@ const AgentuityBundler: BunPlugin = {
|
|
|
389
223
|
(build.config.define?.['process.env.NODE_ENV']
|
|
390
224
|
? JSON.parse(build.config.define['process.env.NODE_ENV'])
|
|
391
225
|
: 'production') === 'development';
|
|
392
|
-
const routes: Set<string> = new Set();
|
|
393
226
|
const agentInfo: Array<Record<string, string>> = [];
|
|
394
227
|
const agentMetadata: Map<string, Map<string, string>> = new Map<
|
|
395
228
|
string,
|
|
396
229
|
Map<string, string>
|
|
397
230
|
>();
|
|
398
231
|
const transpiler = new Bun.Transpiler({ loader: 'ts', target: 'bun' });
|
|
399
|
-
let routeDefinitions: BuildMetadata['routes'] = [];
|
|
400
|
-
|
|
401
|
-
build.onResolve({ filter: /\/route\.ts$/, namespace: 'file' }, async (args) => {
|
|
402
|
-
if (args.path.startsWith(srcDir)) {
|
|
403
|
-
const importPath = args.path
|
|
404
|
-
.replace(rootDir, '')
|
|
405
|
-
.replace('.ts', '')
|
|
406
|
-
.replace('/src/', './');
|
|
407
|
-
routes.add(importPath);
|
|
408
|
-
}
|
|
409
|
-
return args;
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
build.onLoad({ filter: /\/route\.ts$/, namespace: 'file' }, async (args) => {
|
|
413
|
-
if (args.path.startsWith(srcDir)) {
|
|
414
|
-
const importPath = args.path
|
|
415
|
-
.replace(rootDir, '')
|
|
416
|
-
.replace('.ts', '')
|
|
417
|
-
.replace('/src/', './');
|
|
418
|
-
routes.add(importPath);
|
|
419
|
-
}
|
|
420
|
-
// return undefined to let Bun handle loading normally
|
|
421
|
-
return;
|
|
422
|
-
});
|
|
423
232
|
|
|
424
|
-
|
|
233
|
+
// Scan ALL .ts files in src/agent directory for agents
|
|
234
|
+
build.onLoad({ filter: /\/agent\/.*\.ts$/, namespace: 'file' }, async (args) => {
|
|
425
235
|
let newsource = await Bun.file(args.path).text();
|
|
426
236
|
if (args.path.startsWith(srcDir)) {
|
|
427
237
|
const contents = transpiler.transformSync(newsource);
|
|
428
|
-
const
|
|
238
|
+
const result = await parseAgentMetadata(
|
|
429
239
|
rootDir,
|
|
430
240
|
args.path,
|
|
431
241
|
contents,
|
|
432
242
|
projectId,
|
|
433
243
|
deploymentId
|
|
434
244
|
);
|
|
435
|
-
newsource = ns;
|
|
436
245
|
|
|
437
|
-
//
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
246
|
+
// Skip files that don't have a createAgent export
|
|
247
|
+
if (result === undefined) {
|
|
248
|
+
return {
|
|
249
|
+
contents: newsource,
|
|
250
|
+
loader: 'ts',
|
|
251
|
+
};
|
|
442
252
|
}
|
|
443
253
|
|
|
444
|
-
const
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
254
|
+
const [ns, md] = result;
|
|
255
|
+
newsource = ns;
|
|
256
|
+
|
|
257
|
+
// Only process files that actually export an agent
|
|
258
|
+
if (md.has('name')) {
|
|
259
|
+
const newAgentName = md.get('name');
|
|
260
|
+
for (const [, kv] of agentMetadata) {
|
|
261
|
+
const found = kv.get('name');
|
|
262
|
+
if (newAgentName === found) {
|
|
263
|
+
throw new AgentNameDuplicateError({
|
|
264
|
+
message: `The agent in ${kv.get('filename')} and the agent in ${md.get('filename')} have the same name (${found}). Agent Names must be unique within a project.`,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
451
267
|
}
|
|
452
|
-
}
|
|
453
268
|
|
|
454
|
-
|
|
269
|
+
agentMetadata.set(md.get('name')!, md);
|
|
270
|
+
}
|
|
455
271
|
}
|
|
456
272
|
return {
|
|
457
273
|
contents: newsource,
|
|
@@ -509,121 +325,6 @@ const AgentuityBundler: BunPlugin = {
|
|
|
509
325
|
await args.defer();
|
|
510
326
|
|
|
511
327
|
const inserts: string[] = [];
|
|
512
|
-
const routeMapping: Record<string, string> = {};
|
|
513
|
-
|
|
514
|
-
for (const route of routes) {
|
|
515
|
-
const name = basename(dirname(route));
|
|
516
|
-
const agent = route.replace(/\/route$/, '/agent');
|
|
517
|
-
const hasAgent = existsSync(join(srcDir, agent + '.ts'));
|
|
518
|
-
|
|
519
|
-
// Detect if this is a subagent route using shared utility
|
|
520
|
-
const { isSubagent, parentName } = detectSubagent(route);
|
|
521
|
-
|
|
522
|
-
const agentPath = route.replace(/\/route$/, '/*').replace('./', '/');
|
|
523
|
-
const routePath = route
|
|
524
|
-
.replace(/\/route$/, '')
|
|
525
|
-
.replace('/web/', '/api/')
|
|
526
|
-
.replace('/web', '/api')
|
|
527
|
-
.replace('./', '/');
|
|
528
|
-
|
|
529
|
-
const definitions = await parseRoute(
|
|
530
|
-
rootDir,
|
|
531
|
-
join(srcDir, `${route}.ts`),
|
|
532
|
-
projectId,
|
|
533
|
-
deploymentId
|
|
534
|
-
);
|
|
535
|
-
|
|
536
|
-
let agentDetail: Record<string, string> = {};
|
|
537
|
-
|
|
538
|
-
if (hasAgent) {
|
|
539
|
-
const md = agentMetadata.get(name);
|
|
540
|
-
if (!md) {
|
|
541
|
-
throw new MetadataMissingError({
|
|
542
|
-
message: `Couldn't find agent metadata for ${route}`,
|
|
543
|
-
});
|
|
544
|
-
}
|
|
545
|
-
agentDetail = {
|
|
546
|
-
name,
|
|
547
|
-
id: md.get('id')!,
|
|
548
|
-
path: `.${agent}`,
|
|
549
|
-
filename: md.get('filename')!,
|
|
550
|
-
identifier: md.get('identifier')!,
|
|
551
|
-
description: md.get('description') ?? '',
|
|
552
|
-
agentId: md.get('agentId')!,
|
|
553
|
-
};
|
|
554
|
-
if (isSubagent && parentName) {
|
|
555
|
-
agentDetail.parent = parentName;
|
|
556
|
-
}
|
|
557
|
-
agentInfo.push(agentDetail);
|
|
558
|
-
for (const def of definitions) {
|
|
559
|
-
def.agentIds = [agentDetail.agentId, agentDetail.id];
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
// do this after handling the agent association (if any)
|
|
564
|
-
routeDefinitions = [...routeDefinitions, ...definitions];
|
|
565
|
-
|
|
566
|
-
let buffer = `await (async() => {
|
|
567
|
-
const { createAgentMiddleware, getRouter, registerAgent } = await import('@agentuity/runtime');
|
|
568
|
-
const router = getRouter()!;
|
|
569
|
-
const route = require('./src/${route}').default;`;
|
|
570
|
-
if (hasAgent) {
|
|
571
|
-
const agentRegistrationName =
|
|
572
|
-
isSubagent && parentName ? `${parentName}.${name}` : name;
|
|
573
|
-
// Build evals path from agent path (e.g., 'agent/eval/agent' -> 'agent/eval/eval.ts')
|
|
574
|
-
const agentDirPath = agent.replace(/\/agent$/, '');
|
|
575
|
-
const evalsPath = join(srcDir, agentDirPath, 'eval.ts');
|
|
576
|
-
const evalsImport = existsSync(evalsPath)
|
|
577
|
-
? `\n require('./src/${agentDirPath}/eval');`
|
|
578
|
-
: '';
|
|
579
|
-
buffer += `
|
|
580
|
-
const agent = require('./src/${agent}').default;
|
|
581
|
-
router.all("${agentPath}", createAgentMiddleware('${agentRegistrationName}'));
|
|
582
|
-
registerAgent("${agentRegistrationName}", agent);${evalsImport}`;
|
|
583
|
-
}
|
|
584
|
-
buffer += `
|
|
585
|
-
router.route("${routePath}", route);
|
|
586
|
-
})();`;
|
|
587
|
-
inserts.push(buffer);
|
|
588
|
-
|
|
589
|
-
for (const def of definitions) {
|
|
590
|
-
routeMapping[`${def.method} ${def.path}`] = def.id;
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
// Register standalone agents (agents without routes)
|
|
595
|
-
const routeAgentNames = new Set(
|
|
596
|
-
agentInfo
|
|
597
|
-
.filter((a) => {
|
|
598
|
-
// Check if this agent was added via a route (has a corresponding route file)
|
|
599
|
-
const agentPath = a.path.replace(/^\./, '').replace(/\/agent$/, '/route');
|
|
600
|
-
return routes.has(agentPath.replace(/^\/src\//, './'));
|
|
601
|
-
})
|
|
602
|
-
.map((a) => a.name)
|
|
603
|
-
);
|
|
604
|
-
|
|
605
|
-
for (const agentDetail of agentInfo) {
|
|
606
|
-
if (!routeAgentNames.has(agentDetail.name)) {
|
|
607
|
-
// This is a standalone agent - register it without a route
|
|
608
|
-
const agentPath = agentDetail.path;
|
|
609
|
-
const agentDirPath = agentPath.replace(/\/agent$/, '');
|
|
610
|
-
const evalsPath = join(srcDir, agentDirPath.replace(/^\./, ''), 'eval.ts');
|
|
611
|
-
const evalsImport = existsSync(evalsPath)
|
|
612
|
-
? `\n require('./src/${agentDirPath.replace(/^\.\//, '')}/eval');`
|
|
613
|
-
: '';
|
|
614
|
-
const isSubagent = !!agentDetail.parent;
|
|
615
|
-
const agentRegistrationName = isSubagent
|
|
616
|
-
? `${agentDetail.parent}.${agentDetail.name}`
|
|
617
|
-
: agentDetail.name;
|
|
618
|
-
|
|
619
|
-
const buffer = `await (async() => {
|
|
620
|
-
const { registerAgent } = await import('@agentuity/runtime');
|
|
621
|
-
const agent = require('./src${agentPath}').default;
|
|
622
|
-
registerAgent("${agentRegistrationName}", agent);${evalsImport}
|
|
623
|
-
})();`;
|
|
624
|
-
inserts.push(buffer);
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
328
|
|
|
628
329
|
const indexFile = join(srcDir, 'web', 'index.html');
|
|
629
330
|
|
|
@@ -677,39 +378,48 @@ import { readFileSync, existsSync } from 'node:fs';
|
|
|
677
378
|
})();`);
|
|
678
379
|
}
|
|
679
380
|
|
|
680
|
-
//
|
|
681
|
-
|
|
682
|
-
const
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
381
|
+
// Build agentInfo from all discovered agents and track directories
|
|
382
|
+
const agentDirs = new Set<string>();
|
|
383
|
+
for (const [_identifier, md] of agentMetadata) {
|
|
384
|
+
// md.get('filename') can be either absolute or relative to rootDir
|
|
385
|
+
const filename = md.get('filename')!;
|
|
386
|
+
const absolutePath = filename.startsWith('/') ? filename : join(rootDir, filename);
|
|
387
|
+
|
|
388
|
+
// Track which directories have agents
|
|
389
|
+
const dir = dirname(absolutePath);
|
|
390
|
+
agentDirs.add(dir);
|
|
391
|
+
|
|
392
|
+
// Convert to path relative to srcDir
|
|
393
|
+
// e.g., /path/to/src/agent/my-agent.ts -> ./agent/my-agent
|
|
394
|
+
const agentPath = absolutePath.replace(srcDir, '.').replace('.ts', '');
|
|
395
|
+
|
|
396
|
+
const agentDetail: Record<string, string> = {
|
|
397
|
+
name: md.get('name')!,
|
|
398
|
+
id: md.get('id')!,
|
|
399
|
+
path: agentPath,
|
|
400
|
+
filename: absolutePath,
|
|
401
|
+
description: md.get('description') ?? '',
|
|
402
|
+
agentId: md.get('agentId')!,
|
|
403
|
+
};
|
|
404
|
+
agentInfo.push(agentDetail);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Validate that all directories in src/agent have at least one agent
|
|
408
|
+
const agentBaseDir = join(srcDir, 'agent');
|
|
409
|
+
if (existsSync(agentBaseDir)) {
|
|
410
|
+
const { readdirSync, statSync } = await import('node:fs');
|
|
411
|
+
const subdirs = readdirSync(agentBaseDir).filter((name) => {
|
|
412
|
+
const fullPath = join(agentBaseDir, name);
|
|
413
|
+
return statSync(fullPath).isDirectory();
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
for (const subdir of subdirs) {
|
|
417
|
+
const fullPath = join(agentBaseDir, subdir);
|
|
418
|
+
if (!agentDirs.has(fullPath)) {
|
|
419
|
+
throw new Error(
|
|
420
|
+
`Directory ${subdir} in src/agent must contain at least one agent (a file with a createAgent export)`
|
|
421
|
+
);
|
|
711
422
|
}
|
|
712
|
-
agentInfo.push(agentDetail);
|
|
713
423
|
}
|
|
714
424
|
}
|
|
715
425
|
|
|
@@ -723,6 +433,72 @@ import { readFileSync, existsSync } from 'node:fs';
|
|
|
723
433
|
// Generate lifecycle types if setup() is present in app.ts
|
|
724
434
|
await setupLifecycleTypes(rootDir, outDir, srcDir, logger);
|
|
725
435
|
|
|
436
|
+
// Parse routes from src/api directory
|
|
437
|
+
const apiRoutesMetadata: BuildMetadata['routes'] = [];
|
|
438
|
+
const routeInfoList: RouteInfo[] = [];
|
|
439
|
+
const apiDir = join(srcDir, 'api');
|
|
440
|
+
if (existsSync(apiDir)) {
|
|
441
|
+
const { readdirSync, statSync } = await import('node:fs');
|
|
442
|
+
const apiFiles = readdirSync(apiDir)
|
|
443
|
+
.filter((name) => name.endsWith('.ts') && !name.endsWith('.generated.ts'))
|
|
444
|
+
.map((name) => join(apiDir, name));
|
|
445
|
+
|
|
446
|
+
for (const apiFile of apiFiles) {
|
|
447
|
+
if (statSync(apiFile).isFile()) {
|
|
448
|
+
try {
|
|
449
|
+
const routes = await parseRoute(rootDir, apiFile, projectId, deploymentId);
|
|
450
|
+
apiRoutesMetadata.push(...routes);
|
|
451
|
+
|
|
452
|
+
// Collect route info for RouteRegistry generation
|
|
453
|
+
for (const route of routes) {
|
|
454
|
+
routeInfoList.push({
|
|
455
|
+
method: route.method.toUpperCase(),
|
|
456
|
+
path: route.path,
|
|
457
|
+
filename: route.filename,
|
|
458
|
+
hasValidator: route.config?.hasValidator === true,
|
|
459
|
+
routeType: route.type || 'api',
|
|
460
|
+
agentVariable: route.config?.agentVariable as string | undefined,
|
|
461
|
+
agentImportPath: route.config?.agentImportPath as string | undefined,
|
|
462
|
+
inputSchemaVariable: route.config?.inputSchemaVariable as
|
|
463
|
+
| string
|
|
464
|
+
| undefined,
|
|
465
|
+
outputSchemaVariable: route.config?.outputSchemaVariable as
|
|
466
|
+
| string
|
|
467
|
+
| undefined,
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
} catch (error) {
|
|
471
|
+
// Skip files that don't have createRouter (they might be utilities)
|
|
472
|
+
if (
|
|
473
|
+
error instanceof Error &&
|
|
474
|
+
error.message.includes('could not find an proper createRouter')
|
|
475
|
+
) {
|
|
476
|
+
logger.trace(`Skipping ${apiFile}: no createRouter found`);
|
|
477
|
+
} else {
|
|
478
|
+
throw error;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Generate RouteRegistry for type-safe route access
|
|
486
|
+
if (routeInfoList.length > 0) {
|
|
487
|
+
logger.trace(`Generating RouteRegistry with ${routeInfoList.length} routes`);
|
|
488
|
+
generateRouteRegistry(srcDir, routeInfoList);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Auto-mount src/api/index.ts if it exists
|
|
492
|
+
const apiIndexPath = join(srcDir, 'api', 'index.ts');
|
|
493
|
+
if (existsSync(apiIndexPath)) {
|
|
494
|
+
inserts.push(`await (async() => {
|
|
495
|
+
const { getRouter } = await import('@agentuity/runtime');
|
|
496
|
+
const router = getRouter()!;
|
|
497
|
+
const api = require('./src/api/index').default;
|
|
498
|
+
router.route('/api', api);
|
|
499
|
+
})();`);
|
|
500
|
+
}
|
|
501
|
+
|
|
726
502
|
// Only create the workbench routes if workbench is actually configured
|
|
727
503
|
if (workbenchConfig) {
|
|
728
504
|
inserts.push(`await (async() => {
|
|
@@ -772,14 +548,11 @@ await (async() => {
|
|
|
772
548
|
|
|
773
549
|
// generate the build metadata
|
|
774
550
|
metadata = {
|
|
775
|
-
routes:
|
|
551
|
+
routes: apiRoutesMetadata,
|
|
776
552
|
agents: [],
|
|
777
553
|
};
|
|
778
554
|
|
|
779
|
-
//
|
|
780
|
-
const parentAgentMetadata = new Map<string, Map<string, string>>();
|
|
781
|
-
const subagentsByParent = new Map<string, Array<Map<string, string>>>();
|
|
782
|
-
|
|
555
|
+
// Validate required metadata properties and build agent metadata
|
|
783
556
|
for (const [, v] of agentMetadata) {
|
|
784
557
|
if (!v.has('filename')) {
|
|
785
558
|
throw new MetadataPropertyMissingError({
|
|
@@ -793,12 +566,6 @@ await (async() => {
|
|
|
793
566
|
message: 'agent metadata is missing expected id property',
|
|
794
567
|
});
|
|
795
568
|
}
|
|
796
|
-
if (!v.has('identifier')) {
|
|
797
|
-
throw new MetadataPropertyMissingError({
|
|
798
|
-
name: 'identifier',
|
|
799
|
-
message: 'agent metadata is missing expected identifier property',
|
|
800
|
-
});
|
|
801
|
-
}
|
|
802
569
|
if (!v.has('version')) {
|
|
803
570
|
throw new MetadataPropertyMissingError({
|
|
804
571
|
name: 'version',
|
|
@@ -817,45 +584,13 @@ await (async() => {
|
|
|
817
584
|
message: 'agent metadata is missing expected agentId property',
|
|
818
585
|
});
|
|
819
586
|
}
|
|
820
|
-
|
|
821
|
-
const parentName = v.get('parent');
|
|
822
|
-
if (parentName) {
|
|
823
|
-
// This is a subagent
|
|
824
|
-
if (!subagentsByParent.has(parentName)) {
|
|
825
|
-
subagentsByParent.set(parentName, []);
|
|
826
|
-
}
|
|
827
|
-
subagentsByParent.get(parentName)!.push(v);
|
|
828
|
-
} else {
|
|
829
|
-
// This is a parent or standalone agent
|
|
830
|
-
parentAgentMetadata.set(v.get('identifier')!, v);
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
// Validate that all subagents reference existing parent agents
|
|
835
|
-
for (const [parentName, subagents] of subagentsByParent) {
|
|
836
|
-
const parentExists = Array.from(parentAgentMetadata.values()).some(
|
|
837
|
-
(meta) => meta.get('name') === parentName || meta.get('identifier') === parentName
|
|
838
|
-
);
|
|
839
|
-
if (!parentExists) {
|
|
840
|
-
const subagentPaths = subagents.map((s) => s.get('filename')).join(', ');
|
|
841
|
-
throw new SubAgentMissingError({
|
|
842
|
-
message:
|
|
843
|
-
`Subagent(s) [${subagentPaths}] reference parent "${parentName}" which does not exist. ` +
|
|
844
|
-
`Ensure the parent agent is defined.`,
|
|
845
|
-
});
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
// Build metadata with nested subagents
|
|
850
|
-
for (const [_identifier, v] of parentAgentMetadata) {
|
|
851
587
|
const agentData: BuildMetadata['agents'][number] = {
|
|
852
588
|
filename: v.get('filename')!,
|
|
853
589
|
id: v.get('id')!,
|
|
854
|
-
identifier: v.get('identifier')!,
|
|
855
590
|
agentId: v.get('agentId')!,
|
|
856
591
|
version: v.get('version')!,
|
|
857
592
|
name: v.get('name')!,
|
|
858
|
-
description: v.get('description') ?? '
|
|
593
|
+
description: v.get('description') ?? '',
|
|
859
594
|
projectId,
|
|
860
595
|
};
|
|
861
596
|
|
|
@@ -889,66 +624,9 @@ await (async() => {
|
|
|
889
624
|
logger.trace(`[plugin] No evals found for agent ${agentData.name}`);
|
|
890
625
|
}
|
|
891
626
|
|
|
892
|
-
// Add subagents if any (check both name and identifier)
|
|
893
|
-
const subagents =
|
|
894
|
-
subagentsByParent.get(agentData.name) ||
|
|
895
|
-
subagentsByParent.get(agentData.identifier);
|
|
896
|
-
if (subagents && subagents.length > 0) {
|
|
897
|
-
agentData.subagents = subagents.map((sub) => {
|
|
898
|
-
const subagentData: BuildMetadata['agents'][number] = {
|
|
899
|
-
filename: sub.get('filename')!,
|
|
900
|
-
id: sub.get('id')!,
|
|
901
|
-
identifier: sub.get('identifier')!,
|
|
902
|
-
agentId: sub.get('agentId')!,
|
|
903
|
-
version: sub.get('version')!,
|
|
904
|
-
name: sub.get('name')!,
|
|
905
|
-
description: sub.get('description') ?? '<no description provided>',
|
|
906
|
-
projectId,
|
|
907
|
-
};
|
|
908
|
-
|
|
909
|
-
// Add evals for subagents if any
|
|
910
|
-
const subEvalsStr = sub.get('evals');
|
|
911
|
-
if (subEvalsStr) {
|
|
912
|
-
logger.trace(
|
|
913
|
-
`[plugin] Found evals string for subagent ${subagentData.name}, parsing...`
|
|
914
|
-
);
|
|
915
|
-
try {
|
|
916
|
-
const parsedSubEvals = JSON.parse(subEvalsStr) as Array<
|
|
917
|
-
Omit<
|
|
918
|
-
NonNullable<BuildMetadata['agents'][number]['evals']>[number],
|
|
919
|
-
'agentIdentifier' | 'projectId'
|
|
920
|
-
>
|
|
921
|
-
>;
|
|
922
|
-
subagentData.evals = parsedSubEvals.map((evalItem) => ({
|
|
923
|
-
...evalItem,
|
|
924
|
-
agentIdentifier: subagentData.agentId,
|
|
925
|
-
projectId,
|
|
926
|
-
}));
|
|
927
|
-
logger.trace(
|
|
928
|
-
`[plugin] Successfully parsed ${subagentData.evals?.length ?? 0} eval(s) for subagent ${subagentData.name}`
|
|
929
|
-
);
|
|
930
|
-
} catch (e) {
|
|
931
|
-
logger.trace(
|
|
932
|
-
`[plugin] Failed to parse evals for subagent ${subagentData.name}: ${e}`
|
|
933
|
-
);
|
|
934
|
-
console.warn(
|
|
935
|
-
`Failed to parse evals for subagent ${subagentData.name}: ${e}`
|
|
936
|
-
);
|
|
937
|
-
}
|
|
938
|
-
} else {
|
|
939
|
-
logger.trace(`[plugin] No evals found for subagent ${subagentData.name}`);
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
return subagentData;
|
|
943
|
-
});
|
|
944
|
-
}
|
|
945
|
-
|
|
946
627
|
metadata.agents!.push(agentData);
|
|
947
628
|
}
|
|
948
629
|
|
|
949
|
-
const routeMappingJSFile = Bun.file(join(outDir, '.routemapping.json'));
|
|
950
|
-
await routeMappingJSFile.write(JSON.stringify(routeMapping));
|
|
951
|
-
|
|
952
630
|
return {
|
|
953
631
|
contents,
|
|
954
632
|
loader: 'ts',
|