@agentuity/cli 0.0.43 → 0.0.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/README.md +1 -1
- package/dist/api.d.ts +3 -3
- package/dist/api.d.ts.map +1 -1
- package/dist/auth.d.ts +10 -2
- package/dist/auth.d.ts.map +1 -1
- package/dist/banner.d.ts.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cmd/auth/api.d.ts +4 -4
- package/dist/cmd/auth/api.d.ts.map +1 -1
- package/dist/cmd/auth/index.d.ts.map +1 -1
- package/dist/cmd/auth/login.d.ts.map +1 -1
- package/dist/cmd/auth/signup.d.ts.map +1 -1
- package/dist/cmd/auth/ssh/add.d.ts +2 -0
- package/dist/cmd/auth/ssh/add.d.ts.map +1 -0
- package/dist/cmd/auth/ssh/api.d.ts +16 -0
- package/dist/cmd/auth/ssh/api.d.ts.map +1 -0
- package/dist/cmd/auth/ssh/delete.d.ts +2 -0
- package/dist/cmd/auth/ssh/delete.d.ts.map +1 -0
- package/dist/cmd/auth/ssh/index.d.ts +3 -0
- package/dist/cmd/auth/ssh/index.d.ts.map +1 -0
- package/dist/cmd/auth/ssh/list.d.ts +2 -0
- package/dist/cmd/auth/ssh/list.d.ts.map +1 -0
- package/dist/cmd/auth/whoami.d.ts.map +1 -1
- package/dist/cmd/bundle/ast.d.ts +14 -3
- package/dist/cmd/bundle/ast.d.ts.map +1 -1
- package/dist/cmd/bundle/ast.test.d.ts +2 -0
- package/dist/cmd/bundle/ast.test.d.ts.map +1 -0
- package/dist/cmd/bundle/bundler.d.ts +6 -1
- package/dist/cmd/bundle/bundler.d.ts.map +1 -1
- package/dist/cmd/bundle/file.d.ts.map +1 -1
- package/dist/cmd/bundle/fix-duplicate-exports.d.ts +2 -0
- package/dist/cmd/bundle/fix-duplicate-exports.d.ts.map +1 -0
- package/dist/cmd/bundle/fix-duplicate-exports.test.d.ts +2 -0
- package/dist/cmd/bundle/fix-duplicate-exports.test.d.ts.map +1 -0
- package/dist/cmd/bundle/plugin.d.ts +2 -0
- package/dist/cmd/bundle/plugin.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.d.ts.map +1 -1
- package/dist/cmd/cloud/domain.d.ts +17 -0
- package/dist/cmd/cloud/domain.d.ts.map +1 -0
- package/dist/cmd/cloud/index.d.ts.map +1 -1
- package/dist/cmd/cloud/resource/add.d.ts +2 -0
- package/dist/cmd/cloud/resource/add.d.ts.map +1 -0
- package/dist/cmd/cloud/resource/delete.d.ts +2 -0
- package/dist/cmd/cloud/resource/delete.d.ts.map +1 -0
- package/dist/cmd/cloud/resource/index.d.ts +3 -0
- package/dist/cmd/cloud/resource/index.d.ts.map +1 -0
- package/dist/cmd/cloud/resource/list.d.ts +2 -0
- package/dist/cmd/cloud/resource/list.d.ts.map +1 -0
- package/dist/cmd/cloud/scp/download.d.ts +2 -0
- package/dist/cmd/cloud/scp/download.d.ts.map +1 -0
- package/dist/cmd/cloud/scp/index.d.ts +3 -0
- package/dist/cmd/cloud/scp/index.d.ts.map +1 -0
- package/dist/cmd/cloud/scp/upload.d.ts +2 -0
- package/dist/cmd/cloud/scp/upload.d.ts.map +1 -0
- package/dist/cmd/cloud/ssh.d.ts +2 -0
- package/dist/cmd/cloud/ssh.d.ts.map +1 -0
- package/dist/cmd/dev/api.d.ts +18 -0
- package/dist/cmd/dev/api.d.ts.map +1 -0
- package/dist/cmd/dev/download.d.ts +11 -0
- package/dist/cmd/dev/download.d.ts.map +1 -0
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/templates.d.ts +3 -0
- package/dist/cmd/dev/templates.d.ts.map +1 -0
- package/dist/cmd/env/delete.d.ts.map +1 -1
- package/dist/cmd/env/get.d.ts.map +1 -1
- package/dist/cmd/env/import.d.ts.map +1 -1
- package/dist/cmd/env/list.d.ts.map +1 -1
- package/dist/cmd/env/pull.d.ts.map +1 -1
- package/dist/cmd/env/push.d.ts.map +1 -1
- package/dist/cmd/env/set.d.ts.map +1 -1
- package/dist/cmd/profile/show.d.ts.map +1 -1
- package/dist/cmd/project/create.d.ts.map +1 -1
- package/dist/cmd/project/delete.d.ts.map +1 -1
- package/dist/cmd/project/list.d.ts.map +1 -1
- package/dist/cmd/project/show.d.ts.map +1 -1
- package/dist/cmd/project/template-flow.d.ts +4 -0
- package/dist/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/cmd/secret/delete.d.ts.map +1 -1
- package/dist/cmd/secret/get.d.ts.map +1 -1
- package/dist/cmd/secret/import.d.ts.map +1 -1
- package/dist/cmd/secret/list.d.ts.map +1 -1
- package/dist/cmd/secret/pull.d.ts.map +1 -1
- package/dist/cmd/secret/push.d.ts.map +1 -1
- package/dist/cmd/secret/set.d.ts.map +1 -1
- package/dist/config.d.ts +9 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/crypto/box.d.ts +65 -0
- package/dist/crypto/box.d.ts.map +1 -0
- package/dist/crypto/box.test.d.ts +2 -0
- package/dist/crypto/box.test.d.ts.map +1 -0
- package/dist/download.d.ts.map +1 -1
- package/dist/steps.d.ts +4 -1
- package/dist/steps.d.ts.map +1 -1
- package/dist/terminal.d.ts.map +1 -1
- package/dist/tui.d.ts +31 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/types.d.ts +249 -126
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/detectSubagent.d.ts +15 -0
- package/dist/utils/detectSubagent.d.ts.map +1 -0
- package/dist/utils/zip.d.ts +7 -0
- package/dist/utils/zip.d.ts.map +1 -0
- package/package.json +11 -3
- package/src/api-errors.md +2 -2
- package/src/api.ts +12 -7
- package/src/auth.ts +116 -7
- package/src/banner.ts +13 -6
- package/src/cli.ts +695 -63
- package/src/cmd/auth/api.ts +10 -16
- package/src/cmd/auth/index.ts +2 -1
- package/src/cmd/auth/login.ts +24 -8
- package/src/cmd/auth/signup.ts +15 -11
- package/src/cmd/auth/ssh/add.ts +263 -0
- package/src/cmd/auth/ssh/api.ts +94 -0
- package/src/cmd/auth/ssh/delete.ts +102 -0
- package/src/cmd/auth/ssh/index.ts +10 -0
- package/src/cmd/auth/ssh/list.ts +74 -0
- package/src/cmd/auth/whoami.ts +13 -13
- package/src/cmd/bundle/ast.test.ts +565 -0
- package/src/cmd/bundle/ast.ts +457 -44
- package/src/cmd/bundle/bundler.ts +255 -57
- package/src/cmd/bundle/file.ts +6 -12
- package/src/cmd/bundle/fix-duplicate-exports.test.ts +387 -0
- package/src/cmd/bundle/fix-duplicate-exports.ts +204 -0
- package/src/cmd/bundle/index.ts +9 -9
- package/src/cmd/bundle/patch/aisdk.ts +1 -1
- package/src/cmd/bundle/plugin.ts +373 -53
- package/src/cmd/cloud/deploy.ts +300 -93
- package/src/cmd/cloud/domain.ts +92 -0
- package/src/cmd/cloud/index.ts +4 -1
- package/src/cmd/cloud/resource/add.ts +56 -0
- package/src/cmd/cloud/resource/delete.ts +120 -0
- package/src/cmd/cloud/resource/index.ts +11 -0
- package/src/cmd/cloud/resource/list.ts +69 -0
- package/src/cmd/cloud/scp/download.ts +59 -0
- package/src/cmd/cloud/scp/index.ts +9 -0
- package/src/cmd/cloud/scp/upload.ts +62 -0
- package/src/cmd/cloud/ssh.ts +68 -0
- package/src/cmd/dev/api.ts +46 -0
- package/src/cmd/dev/download.ts +111 -0
- package/src/cmd/dev/index.ts +360 -34
- package/src/cmd/dev/templates.ts +84 -0
- package/src/cmd/env/delete.ts +5 -20
- package/src/cmd/env/get.ts +5 -18
- package/src/cmd/env/import.ts +5 -20
- package/src/cmd/env/list.ts +5 -18
- package/src/cmd/env/pull.ts +10 -23
- package/src/cmd/env/push.ts +5 -23
- package/src/cmd/env/set.ts +5 -20
- package/src/cmd/index.ts +2 -2
- package/src/cmd/profile/show.ts +15 -6
- package/src/cmd/project/create.ts +7 -2
- package/src/cmd/project/delete.ts +75 -18
- package/src/cmd/project/download.ts +2 -2
- package/src/cmd/project/list.ts +8 -8
- package/src/cmd/project/show.ts +3 -7
- package/src/cmd/project/template-flow.ts +170 -72
- package/src/cmd/secret/delete.ts +5 -20
- package/src/cmd/secret/get.ts +5 -18
- package/src/cmd/secret/import.ts +5 -20
- package/src/cmd/secret/list.ts +5 -18
- package/src/cmd/secret/pull.ts +10 -23
- package/src/cmd/secret/push.ts +5 -23
- package/src/cmd/secret/set.ts +5 -20
- package/src/config.ts +224 -24
- package/src/crypto/box.test.ts +431 -0
- package/src/crypto/box.ts +477 -0
- package/src/download.ts +1 -0
- package/src/env-util.test.ts +1 -1
- package/src/steps.ts +65 -6
- package/src/terminal.ts +24 -23
- package/src/tui.ts +192 -61
- package/src/types.ts +291 -201
- package/src/utils/detectSubagent.ts +31 -0
- package/src/utils/zip.ts +38 -0
- package/dist/cmd/example/create-user.d.ts +0 -2
- package/dist/cmd/example/create-user.d.ts.map +0 -1
- package/dist/cmd/example/create.d.ts +0 -2
- package/dist/cmd/example/create.d.ts.map +0 -1
- package/dist/cmd/example/deploy.d.ts +0 -2
- package/dist/cmd/example/deploy.d.ts.map +0 -1
- package/dist/cmd/example/index.d.ts +0 -2
- package/dist/cmd/example/index.d.ts.map +0 -1
- package/dist/cmd/example/list.d.ts +0 -2
- package/dist/cmd/example/list.d.ts.map +0 -1
- package/dist/cmd/example/optional-auth.d.ts +0 -3
- package/dist/cmd/example/optional-auth.d.ts.map +0 -1
- package/dist/cmd/example/run-command.d.ts +0 -2
- package/dist/cmd/example/run-command.d.ts.map +0 -1
- package/dist/cmd/example/sound.d.ts +0 -3
- package/dist/cmd/example/sound.d.ts.map +0 -1
- package/dist/cmd/example/spinner.d.ts +0 -2
- package/dist/cmd/example/spinner.d.ts.map +0 -1
- package/dist/cmd/example/steps.d.ts +0 -2
- package/dist/cmd/example/steps.d.ts.map +0 -1
- package/dist/cmd/example/version.d.ts +0 -2
- package/dist/cmd/example/version.d.ts.map +0 -1
- package/src/cmd/example/create-user.ts +0 -38
- package/src/cmd/example/create.ts +0 -31
- package/src/cmd/example/deploy.ts +0 -36
- package/src/cmd/example/index.ts +0 -29
- package/src/cmd/example/list.ts +0 -32
- package/src/cmd/example/optional-auth.ts +0 -38
- package/src/cmd/example/run-command.ts +0 -45
- package/src/cmd/example/sound.ts +0 -14
- package/src/cmd/example/spinner.ts +0 -44
- package/src/cmd/example/steps.ts +0 -66
- package/src/cmd/example/version.ts +0 -13
package/src/cmd/bundle/plugin.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { BunPlugin } from 'bun';
|
|
2
|
-
import { dirname, basename, join } from 'node:path';
|
|
3
|
-
import { existsSync, writeFileSync } from 'node:fs';
|
|
4
|
-
import type { BuildMetadata } from '
|
|
5
|
-
import { parseAgentMetadata, parseRoute } from './ast';
|
|
2
|
+
import { dirname, basename, join, resolve } from 'node:path';
|
|
3
|
+
import { existsSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
4
|
+
import type { BuildMetadata } from '@agentuity/server';
|
|
5
|
+
import { parseAgentMetadata, parseRoute, parseEvalMetadata } from './ast';
|
|
6
6
|
import { applyPatch, generatePatches } from './patch';
|
|
7
|
+
import { detectSubagent } from '../../utils/detectSubagent';
|
|
8
|
+
import { createLogger } from '@agentuity/server';
|
|
9
|
+
import type { LogLevel } from '../../types';
|
|
7
10
|
|
|
8
11
|
function toCamelCase(str: string): string {
|
|
9
12
|
return str
|
|
@@ -17,31 +20,139 @@ function toPascalCase(str: string): string {
|
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
function generateAgentRegistry(srcDir: string, agentInfo: Array<Record<string, string>>) {
|
|
23
|
+
// Separate parent agents and subagents
|
|
24
|
+
const parentAgents = agentInfo.filter((a) => !a.parent);
|
|
25
|
+
const subagents = agentInfo.filter((a) => a.parent);
|
|
26
|
+
|
|
27
|
+
// Group subagents by parent
|
|
28
|
+
const subagentsByParent = new Map<string, Array<Record<string, string>>>();
|
|
29
|
+
for (const subagent of subagents) {
|
|
30
|
+
const parentName = subagent.parent!;
|
|
31
|
+
if (!subagentsByParent.has(parentName)) {
|
|
32
|
+
subagentsByParent.set(parentName, []);
|
|
33
|
+
}
|
|
34
|
+
subagentsByParent.get(parentName)!.push(subagent);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Detect naming collisions in generated identifiers
|
|
38
|
+
// Naming strategy: parent + child names are combined as `${parent}_${name}` then converted to camelCase
|
|
39
|
+
// Example: parent="user", child="profile" → "user_profile" → "userProfile"
|
|
40
|
+
// Potential collision: parent="user_profile", child="info" and parent="user", child="profile_info" both → "userProfileInfo"
|
|
41
|
+
const generatedNames = new Set<string>();
|
|
42
|
+
const collisions: string[] = [];
|
|
43
|
+
|
|
44
|
+
for (const agent of agentInfo) {
|
|
45
|
+
const fullName = agent.parent ? `${agent.parent}_${agent.name}` : agent.name;
|
|
46
|
+
const camelName = toCamelCase(fullName);
|
|
47
|
+
|
|
48
|
+
if (generatedNames.has(camelName)) {
|
|
49
|
+
collisions.push(`Identifier collision detected: "${camelName}" (from "${fullName}")`);
|
|
50
|
+
}
|
|
51
|
+
generatedNames.add(camelName);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (collisions.length > 0) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
`Agent identifier naming collisions detected:\n${collisions.join('\n')}\n\n` +
|
|
57
|
+
`This occurs when different agent names produce the same camelCase identifier.\n` +
|
|
58
|
+
`Please rename your agents to avoid this collision.`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Generate imports for all agents
|
|
20
63
|
const imports = agentInfo
|
|
21
|
-
.map(({ name, path }) => {
|
|
22
|
-
const
|
|
64
|
+
.map(({ name, path, parent }) => {
|
|
65
|
+
const fullName = parent ? `${parent}.${name}` : name;
|
|
66
|
+
const camelName = toCamelCase(fullName.replace('.', '_'));
|
|
23
67
|
const relativePath = path.replace(/^\.\/agents\//, './');
|
|
24
68
|
return `import ${camelName}Agent from '${relativePath}';`;
|
|
25
69
|
})
|
|
26
70
|
.join('\n');
|
|
27
71
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
72
|
+
// Evals are now imported in plugin.ts when agents are registered
|
|
73
|
+
// No need to import them in registry.generated.ts
|
|
74
|
+
const evalsImportsStr = '';
|
|
75
|
+
|
|
76
|
+
// Validate that child property names don't collide with parent agent properties
|
|
77
|
+
const reservedAgentProperties = ['metadata', 'run', 'inputSchema', 'outputSchema', 'stream'];
|
|
78
|
+
for (const parentAgent of parentAgents) {
|
|
79
|
+
const children = subagentsByParent.get(parentAgent.name) || [];
|
|
80
|
+
for (const child of children) {
|
|
81
|
+
const childPropertyName = toCamelCase(child.name);
|
|
82
|
+
|
|
83
|
+
// Check for collision with reserved agent properties
|
|
84
|
+
if (reservedAgentProperties.includes(childPropertyName)) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`Subagent property name collision detected: "${childPropertyName}" in parent "${parentAgent.name}"\n` +
|
|
87
|
+
`The child name "${child.name}" conflicts with a reserved agent property (${reservedAgentProperties.join(', ')}).\n` +
|
|
88
|
+
`Please rename the subagent to avoid this collision.`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Generate nested registry structure
|
|
95
|
+
const registryLines: string[] = [];
|
|
96
|
+
for (const parentAgent of parentAgents) {
|
|
97
|
+
const parentCamelName = toCamelCase(parentAgent.name);
|
|
98
|
+
const children = subagentsByParent.get(parentAgent.name) || [];
|
|
99
|
+
|
|
100
|
+
if (children.length === 0) {
|
|
101
|
+
// No subagents, simple assignment
|
|
102
|
+
registryLines.push(` ${parentCamelName}: ${parentCamelName}Agent,`);
|
|
103
|
+
} else {
|
|
104
|
+
// Has subagents, create nested structure using object spread (no mutation)
|
|
105
|
+
registryLines.push(` ${parentCamelName}: {`);
|
|
106
|
+
registryLines.push(` ...${parentCamelName}Agent,`);
|
|
107
|
+
for (const child of children) {
|
|
108
|
+
const childCamelName = toCamelCase(`${parentAgent.name}_${child.name}`);
|
|
109
|
+
registryLines.push(` ${toCamelCase(child.name)}: ${childCamelName}Agent,`);
|
|
110
|
+
}
|
|
111
|
+
registryLines.push(` },`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const registry = registryLines.join('\n');
|
|
34
115
|
|
|
116
|
+
// Generate type exports for all agents
|
|
35
117
|
const typeExports = agentInfo
|
|
36
|
-
.map(({ name }) => {
|
|
37
|
-
const
|
|
38
|
-
const
|
|
118
|
+
.map(({ name, parent }) => {
|
|
119
|
+
const fullName = parent ? `${parent}_${name}` : name;
|
|
120
|
+
const camelName = toCamelCase(fullName);
|
|
121
|
+
const pascalName = toPascalCase(fullName);
|
|
39
122
|
return `export type ${pascalName}AgentRunner = AgentRunner<typeof ${camelName}Agent['inputSchema'], typeof ${camelName}Agent['outputSchema'], typeof ${camelName}Agent['stream'] extends true ? true : false>;`;
|
|
40
123
|
})
|
|
41
124
|
.join('\n');
|
|
42
125
|
|
|
126
|
+
// Generate nested agent type definitions
|
|
127
|
+
const agentTypeLines: string[] = [];
|
|
128
|
+
for (const parentAgent of parentAgents) {
|
|
129
|
+
const parentCamelName = toCamelCase(parentAgent.name);
|
|
130
|
+
const children = subagentsByParent.get(parentAgent.name) || [];
|
|
131
|
+
|
|
132
|
+
if (children.length === 0) {
|
|
133
|
+
// No subagents
|
|
134
|
+
agentTypeLines.push(
|
|
135
|
+
` ${parentCamelName}: AgentRunner<AgentRegistry['${parentCamelName}']['inputSchema'], AgentRegistry['${parentCamelName}']['outputSchema'], AgentRegistry['${parentCamelName}']['stream'] extends true ? true : false>;`
|
|
136
|
+
);
|
|
137
|
+
} else {
|
|
138
|
+
// Has subagents - create intersection type
|
|
139
|
+
agentTypeLines.push(
|
|
140
|
+
` ${parentCamelName}: AgentRunner<AgentRegistry['${parentCamelName}']['inputSchema'], AgentRegistry['${parentCamelName}']['outputSchema'], AgentRegistry['${parentCamelName}']['stream'] extends true ? true : false> & {`
|
|
141
|
+
);
|
|
142
|
+
for (const child of children) {
|
|
143
|
+
const childCamelName = toCamelCase(child.name);
|
|
144
|
+
const fullChildName = toCamelCase(`${parentAgent.name}_${child.name}`);
|
|
145
|
+
agentTypeLines.push(
|
|
146
|
+
` ${childCamelName}: AgentRunner<typeof ${fullChildName}Agent['inputSchema'], typeof ${fullChildName}Agent['outputSchema'], typeof ${fullChildName}Agent['stream'] extends true ? true : false>;`
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
agentTypeLines.push(` };`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const agentTypes = agentTypeLines.join('\n');
|
|
153
|
+
|
|
43
154
|
const generatedContent = `// Auto-generated by Agentuity - do not edit manually
|
|
44
|
-
${imports}
|
|
155
|
+
${imports}${evalsImportsStr}
|
|
45
156
|
import type { AgentRunner, Logger } from '@agentuity/runtime';
|
|
46
157
|
import type { KeyValueStorage, ObjectStorage, StreamStorage, VectorStorage } from '@agentuity/core';
|
|
47
158
|
|
|
@@ -60,7 +171,7 @@ declare module "hono" {
|
|
|
60
171
|
interface Context {
|
|
61
172
|
agentName: AgentName;
|
|
62
173
|
agent: {
|
|
63
|
-
|
|
174
|
+
${agentTypes}
|
|
64
175
|
};
|
|
65
176
|
waitUntil: (promise: Promise<void> | (() => void | Promise<void>)) => void;
|
|
66
177
|
logger: Logger;
|
|
@@ -75,27 +186,55 @@ declare module "hono" {
|
|
|
75
186
|
const agentsDir = join(srcDir, 'agents');
|
|
76
187
|
const registryPath = join(agentsDir, 'registry.generated.ts');
|
|
77
188
|
|
|
189
|
+
// Ensure agents directory exists
|
|
190
|
+
if (!existsSync(agentsDir)) {
|
|
191
|
+
mkdirSync(agentsDir, { recursive: true });
|
|
192
|
+
}
|
|
193
|
+
|
|
78
194
|
writeFileSync(registryPath, generatedContent, 'utf-8');
|
|
79
195
|
|
|
196
|
+
// Generate React client types with nested structure
|
|
197
|
+
const clientImports = agentInfo
|
|
198
|
+
.map(({ name, path, parent }) => {
|
|
199
|
+
const fullName = parent ? `${parent}_${name}` : name;
|
|
200
|
+
const camelName = toCamelCase(fullName);
|
|
201
|
+
const relativePath = path.replace(/^\.\/agents\//, './');
|
|
202
|
+
return `import type ${camelName}Agent from '${relativePath}';`;
|
|
203
|
+
})
|
|
204
|
+
.join('\n');
|
|
205
|
+
|
|
206
|
+
const clientAgentTypeLines: string[] = [];
|
|
207
|
+
for (const parentAgent of parentAgents) {
|
|
208
|
+
const parentCamelName = toCamelCase(parentAgent.name);
|
|
209
|
+
const children = subagentsByParent.get(parentAgent.name) || [];
|
|
210
|
+
|
|
211
|
+
if (children.length === 0) {
|
|
212
|
+
// No subagents
|
|
213
|
+
clientAgentTypeLines.push(
|
|
214
|
+
` '${parentAgent.name}': Agent<typeof ${parentCamelName}Agent['inputSchema'], typeof ${parentCamelName}Agent['outputSchema']>;`
|
|
215
|
+
);
|
|
216
|
+
} else {
|
|
217
|
+
// Has subagents - create nested type with subagent access via dot notation
|
|
218
|
+
clientAgentTypeLines.push(
|
|
219
|
+
` '${parentAgent.name}': Agent<typeof ${parentCamelName}Agent['inputSchema'], typeof ${parentCamelName}Agent['outputSchema']>;`
|
|
220
|
+
);
|
|
221
|
+
for (const child of children) {
|
|
222
|
+
const fullChildName = toCamelCase(`${parentAgent.name}_${child.name}`);
|
|
223
|
+
clientAgentTypeLines.push(
|
|
224
|
+
` '${parentAgent.name}.${child.name}': Agent<typeof ${fullChildName}Agent['inputSchema'], typeof ${fullChildName}Agent['outputSchema']>;`
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
80
230
|
const clientTypesContent = `// Auto-generated by Agentuity - do not edit manually
|
|
81
231
|
// This file augments @agentuity/react with your project's agent types
|
|
82
|
-
${
|
|
83
|
-
.map(({ name, path }) => {
|
|
84
|
-
const camelName = toCamelCase(name);
|
|
85
|
-
const relativePath = path.replace(/^\.\/agents\//, './');
|
|
86
|
-
return `import type ${camelName}Agent from '${relativePath}';`;
|
|
87
|
-
})
|
|
88
|
-
.join('\n')}
|
|
232
|
+
${clientImports}
|
|
89
233
|
import type { Agent } from '@agentuity/react';
|
|
90
234
|
|
|
91
235
|
declare module '@agentuity/react' {
|
|
92
236
|
interface AgentRegistry {
|
|
93
|
-
${
|
|
94
|
-
.map(({ name }) => {
|
|
95
|
-
const camelName = toCamelCase(name);
|
|
96
|
-
return ` '${name}': Agent<typeof ${camelName}Agent['inputSchema'], typeof ${camelName}Agent['outputSchema']>;`;
|
|
97
|
-
})
|
|
98
|
-
.join('\n')}
|
|
237
|
+
${clientAgentTypeLines.join('\n')}
|
|
99
238
|
}
|
|
100
239
|
}
|
|
101
240
|
`;
|
|
@@ -104,11 +243,23 @@ ${agentInfo
|
|
|
104
243
|
writeFileSync(clientTypesPath, clientTypesContent, 'utf-8');
|
|
105
244
|
}
|
|
106
245
|
|
|
246
|
+
let metadata: Partial<BuildMetadata>;
|
|
247
|
+
|
|
248
|
+
export function getBuildMetadata(): Partial<BuildMetadata> {
|
|
249
|
+
return metadata;
|
|
250
|
+
}
|
|
251
|
+
|
|
107
252
|
const AgentuityBundler: BunPlugin = {
|
|
108
253
|
name: 'Agentuity Bundler',
|
|
109
254
|
setup(build) {
|
|
110
|
-
const rootDir = build.config.root ?? '.';
|
|
255
|
+
const rootDir = resolve(build.config.root ?? '.');
|
|
111
256
|
const srcDir = join(rootDir, 'src');
|
|
257
|
+
const projectId = build.config.define?.['process.env.AGENTUITY_CLOUD_PROJECT_ID']
|
|
258
|
+
? JSON.parse(build.config.define['process.env.AGENTUITY_CLOUD_PROJECT_ID'])
|
|
259
|
+
: '';
|
|
260
|
+
const deploymentId = build.config.define?.['process.env.AGENTUITY_CLOUD_DEPLOYMENT_ID']
|
|
261
|
+
? JSON.parse(build.config.define['process.env.AGENTUITY_CLOUD_DEPLOYMENT_ID'])
|
|
262
|
+
: '';
|
|
112
263
|
const routes: Set<string> = new Set();
|
|
113
264
|
const agentInfo: Array<Record<string, string>> = [];
|
|
114
265
|
const agentMetadata: Map<string, Map<string, string>> = new Map<
|
|
@@ -129,12 +280,38 @@ const AgentuityBundler: BunPlugin = {
|
|
|
129
280
|
return args;
|
|
130
281
|
});
|
|
131
282
|
|
|
283
|
+
build.onLoad({ filter: /\/route\.ts$/, namespace: 'file' }, async (args) => {
|
|
284
|
+
if (args.path.startsWith(srcDir)) {
|
|
285
|
+
const importPath = args.path
|
|
286
|
+
.replace(rootDir, '')
|
|
287
|
+
.replace('.ts', '')
|
|
288
|
+
.replace('/src/', './');
|
|
289
|
+
routes.add(importPath);
|
|
290
|
+
}
|
|
291
|
+
// return undefined to let Bun handle loading normally
|
|
292
|
+
return;
|
|
293
|
+
});
|
|
294
|
+
|
|
132
295
|
build.onLoad({ filter: /\/agent\.ts$/, namespace: 'file' }, async (args) => {
|
|
133
296
|
let newsource = await Bun.file(args.path).text();
|
|
134
297
|
if (args.path.startsWith(srcDir)) {
|
|
135
298
|
const contents = transpiler.transformSync(newsource);
|
|
136
|
-
const [ns, md] = parseAgentMetadata(
|
|
299
|
+
const [ns, md] = await parseAgentMetadata(
|
|
300
|
+
rootDir,
|
|
301
|
+
args.path,
|
|
302
|
+
contents,
|
|
303
|
+
projectId,
|
|
304
|
+
deploymentId
|
|
305
|
+
);
|
|
137
306
|
newsource = ns;
|
|
307
|
+
|
|
308
|
+
// Detect if this is a subagent by checking path structure
|
|
309
|
+
// Note: Path structure assumption - 4 segments: agents/parent/child/agent.ts
|
|
310
|
+
const { isSubagent, parentName } = detectSubagent(args.path, srcDir);
|
|
311
|
+
if (isSubagent && parentName) {
|
|
312
|
+
md.set('parent', parentName);
|
|
313
|
+
}
|
|
314
|
+
|
|
138
315
|
agentMetadata.set(md.get('identifier')!, md);
|
|
139
316
|
}
|
|
140
317
|
return {
|
|
@@ -143,6 +320,19 @@ const AgentuityBundler: BunPlugin = {
|
|
|
143
320
|
};
|
|
144
321
|
});
|
|
145
322
|
|
|
323
|
+
build.onLoad({ filter: /\/eval\.ts$/, namespace: 'file' }, async (args) => {
|
|
324
|
+
let newsource = await Bun.file(args.path).text();
|
|
325
|
+
if (args.path.startsWith(srcDir)) {
|
|
326
|
+
const contents = transpiler.transformSync(newsource);
|
|
327
|
+
const [ns] = parseEvalMetadata(rootDir, args.path, contents, projectId, deploymentId);
|
|
328
|
+
newsource = ns;
|
|
329
|
+
}
|
|
330
|
+
return {
|
|
331
|
+
contents: newsource,
|
|
332
|
+
loader: 'ts',
|
|
333
|
+
};
|
|
334
|
+
});
|
|
335
|
+
|
|
146
336
|
const patches = generatePatches();
|
|
147
337
|
for (const [, patch] of patches) {
|
|
148
338
|
let modulePath = join('node_modules', patch.module, '.*');
|
|
@@ -173,17 +363,23 @@ const AgentuityBundler: BunPlugin = {
|
|
|
173
363
|
namespace: 'file',
|
|
174
364
|
},
|
|
175
365
|
async (args) => {
|
|
366
|
+
const logger = createLogger((process.env.AGENTUITY_LOG_LEVEL as LogLevel) || 'info');
|
|
176
367
|
if (build.config.target !== 'bun') {
|
|
177
368
|
return;
|
|
178
369
|
}
|
|
179
370
|
await args.defer();
|
|
180
371
|
|
|
181
372
|
const inserts: string[] = [];
|
|
373
|
+
const routeMapping: Record<string, string> = {};
|
|
182
374
|
|
|
183
375
|
for (const route of routes) {
|
|
184
376
|
const name = basename(dirname(route));
|
|
185
377
|
const agent = route.replace(/\/route$/, '/agent');
|
|
186
378
|
const hasAgent = existsSync(join(srcDir, agent + '.ts'));
|
|
379
|
+
|
|
380
|
+
// Detect if this is a subagent route using shared utility
|
|
381
|
+
const { isSubagent, parentName } = detectSubagent(route);
|
|
382
|
+
|
|
187
383
|
const agentPath = route
|
|
188
384
|
.replace(/\/route$/, '/*')
|
|
189
385
|
.replace('/agents', '/agent')
|
|
@@ -196,7 +392,12 @@ const AgentuityBundler: BunPlugin = {
|
|
|
196
392
|
.replace('/agents', '/agent')
|
|
197
393
|
.replace('./', '/');
|
|
198
394
|
|
|
199
|
-
const definitions = await parseRoute(
|
|
395
|
+
const definitions = await parseRoute(
|
|
396
|
+
rootDir,
|
|
397
|
+
join(srcDir, `${route}.ts`),
|
|
398
|
+
projectId,
|
|
399
|
+
deploymentId
|
|
400
|
+
);
|
|
200
401
|
routeDefinitions = [...routeDefinitions, ...definitions];
|
|
201
402
|
|
|
202
403
|
let agentDetail: Record<string, string> = {};
|
|
@@ -213,23 +414,38 @@ const AgentuityBundler: BunPlugin = {
|
|
|
213
414
|
identifier: md.get('identifier')!,
|
|
214
415
|
description: md.get('description') ?? '',
|
|
215
416
|
};
|
|
417
|
+
if (isSubagent && parentName) {
|
|
418
|
+
agentDetail.parent = parentName;
|
|
419
|
+
}
|
|
216
420
|
agentInfo.push(agentDetail);
|
|
217
421
|
}
|
|
218
422
|
|
|
219
423
|
let buffer = `await (async() => {
|
|
220
|
-
const { createAgentMiddleware,
|
|
221
|
-
const
|
|
424
|
+
const { createAgentMiddleware, getRouter, registerAgent } = await import('@agentuity/runtime');
|
|
425
|
+
const router = getRouter()!;
|
|
222
426
|
const route = require('./src/${route}').default;`;
|
|
223
427
|
if (hasAgent) {
|
|
428
|
+
const agentRegistrationName =
|
|
429
|
+
isSubagent && parentName ? `${parentName}.${name}` : name;
|
|
430
|
+
// Build evals path from agent path (e.g., 'agents/eval/agent' -> 'agents/eval/eval.ts')
|
|
431
|
+
const agentDirPath = agent.replace(/\/agent$/, '');
|
|
432
|
+
const evalsPath = join(srcDir, agentDirPath, 'eval.ts');
|
|
433
|
+
const evalsImport = existsSync(evalsPath)
|
|
434
|
+
? `\n require('./src/${agentDirPath}/eval');`
|
|
435
|
+
: '';
|
|
224
436
|
buffer += `
|
|
225
437
|
const agent = require('./src/${agent}').default;
|
|
226
|
-
|
|
227
|
-
registerAgent("${
|
|
438
|
+
router.all("${agentPath}", createAgentMiddleware('${agentRegistrationName}'));
|
|
439
|
+
registerAgent("${agentRegistrationName}", agent);${evalsImport}`;
|
|
228
440
|
}
|
|
229
441
|
buffer += `
|
|
230
|
-
|
|
442
|
+
router.route("${routePath}", route);
|
|
231
443
|
})();`;
|
|
232
444
|
inserts.push(buffer);
|
|
445
|
+
|
|
446
|
+
for (const def of definitions) {
|
|
447
|
+
routeMapping[`${def.method} ${def.path}`] = def.id;
|
|
448
|
+
}
|
|
233
449
|
}
|
|
234
450
|
|
|
235
451
|
const indexFile = join(srcDir, 'web', 'index.html');
|
|
@@ -237,18 +453,25 @@ const AgentuityBundler: BunPlugin = {
|
|
|
237
453
|
if (existsSync(indexFile)) {
|
|
238
454
|
inserts.unshift(`await (async () => {
|
|
239
455
|
const { serveStatic } = require('hono/bun');
|
|
240
|
-
const {
|
|
241
|
-
const
|
|
242
|
-
const index = await Bun.file(import.meta.dir + '/web/index.
|
|
456
|
+
const { getRouter } = await import('@agentuity/runtime');
|
|
457
|
+
const router = getRouter()!;
|
|
458
|
+
const index = await Bun.file(import.meta.dir + '/web/index.html').text();
|
|
243
459
|
const webstatic = serveStatic({ root: import.meta.dir + '/web' });
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
460
|
+
router.get('/', (c) => c.html(index));
|
|
461
|
+
router.get('/web/chunk/*', webstatic);
|
|
462
|
+
router.get('/web/asset/*', webstatic);
|
|
463
|
+
router.get('/public/*', webstatic);
|
|
248
464
|
})();`);
|
|
249
465
|
}
|
|
250
466
|
|
|
251
|
-
|
|
467
|
+
// Only generate registry if there are agents
|
|
468
|
+
// Note: We don't import the registry here because:
|
|
469
|
+
// 1. Evals are already imported when agents are registered (see line 421-422)
|
|
470
|
+
// 2. The registry is for type definitions only, not runtime execution
|
|
471
|
+
// 3. Importing it causes bundler resolution issues since it's generated during build
|
|
472
|
+
if (agentInfo.length > 0) {
|
|
473
|
+
generateAgentRegistry(srcDir, agentInfo);
|
|
474
|
+
}
|
|
252
475
|
|
|
253
476
|
const file = Bun.file(args.path);
|
|
254
477
|
let contents = await file.text();
|
|
@@ -270,10 +493,15 @@ const AgentuityBundler: BunPlugin = {
|
|
|
270
493
|
}
|
|
271
494
|
|
|
272
495
|
// generate the build metadata
|
|
273
|
-
|
|
496
|
+
metadata = {
|
|
274
497
|
routes: routeDefinitions,
|
|
275
498
|
agents: [],
|
|
276
499
|
};
|
|
500
|
+
|
|
501
|
+
// Group agents by parent/child relationship
|
|
502
|
+
const parentAgentMetadata = new Map<string, Map<string, string>>();
|
|
503
|
+
const subagentsByParent = new Map<string, Array<Map<string, string>>>();
|
|
504
|
+
|
|
277
505
|
for (const [, v] of agentMetadata) {
|
|
278
506
|
if (!v.has('filename')) {
|
|
279
507
|
throw new Error('agent metadata is missing expected filename property');
|
|
@@ -290,20 +518,112 @@ const AgentuityBundler: BunPlugin = {
|
|
|
290
518
|
if (!v.has('name')) {
|
|
291
519
|
throw new Error('agent metadata is missing expected name property');
|
|
292
520
|
}
|
|
293
|
-
|
|
521
|
+
|
|
522
|
+
const parentName = v.get('parent');
|
|
523
|
+
if (parentName) {
|
|
524
|
+
// This is a subagent
|
|
525
|
+
if (!subagentsByParent.has(parentName)) {
|
|
526
|
+
subagentsByParent.set(parentName, []);
|
|
527
|
+
}
|
|
528
|
+
subagentsByParent.get(parentName)!.push(v);
|
|
529
|
+
} else {
|
|
530
|
+
// This is a parent or standalone agent
|
|
531
|
+
parentAgentMetadata.set(v.get('identifier')!, v);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// Validate that all subagents reference existing parent agents
|
|
536
|
+
for (const [parentName, subagents] of subagentsByParent) {
|
|
537
|
+
const parentExists = Array.from(parentAgentMetadata.values()).some(
|
|
538
|
+
(meta) => meta.get('name') === parentName || meta.get('identifier') === parentName
|
|
539
|
+
);
|
|
540
|
+
if (!parentExists) {
|
|
541
|
+
const subagentPaths = subagents.map((s) => s.get('filename')).join(', ');
|
|
542
|
+
throw new Error(
|
|
543
|
+
`Subagent(s) [${subagentPaths}] reference parent "${parentName}" which does not exist. ` +
|
|
544
|
+
`Ensure the parent agent is defined.`
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// Build metadata with nested subagents
|
|
550
|
+
for (const [_identifier, v] of parentAgentMetadata) {
|
|
551
|
+
const agentData: BuildMetadata['agents'][number] = {
|
|
294
552
|
filename: v.get('filename')!,
|
|
295
553
|
id: v.get('id')!,
|
|
296
554
|
identifier: v.get('identifier')!,
|
|
297
555
|
version: v.get('version')!,
|
|
298
556
|
name: v.get('name')!,
|
|
299
557
|
description: v.get('description') ?? '<no description provided>',
|
|
300
|
-
}
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
const evalsStr = v.get('evals');
|
|
561
|
+
if (evalsStr) {
|
|
562
|
+
logger.trace(
|
|
563
|
+
`[plugin] Found evals string for agent ${agentData.name}, parsing...`
|
|
564
|
+
);
|
|
565
|
+
try {
|
|
566
|
+
agentData.evals = JSON.parse(evalsStr);
|
|
567
|
+
logger.trace(
|
|
568
|
+
`[plugin] Successfully parsed ${agentData.evals?.length ?? 0} eval(s) for agent ${agentData.name}`
|
|
569
|
+
);
|
|
570
|
+
} catch (e) {
|
|
571
|
+
logger.trace(
|
|
572
|
+
`[plugin] Failed to parse evals for agent ${agentData.name}: ${e}`
|
|
573
|
+
);
|
|
574
|
+
console.warn(`Failed to parse evals for agent ${agentData.name}: ${e}`);
|
|
575
|
+
}
|
|
576
|
+
} else {
|
|
577
|
+
logger.trace(`[plugin] No evals found for agent ${agentData.name}`);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Add subagents if any (check both name and identifier)
|
|
581
|
+
const subagents =
|
|
582
|
+
subagentsByParent.get(agentData.name) ||
|
|
583
|
+
subagentsByParent.get(agentData.identifier);
|
|
584
|
+
if (subagents && subagents.length > 0) {
|
|
585
|
+
agentData.subagents = subagents.map((sub) => {
|
|
586
|
+
const subagentData: BuildMetadata['agents'][number] = {
|
|
587
|
+
filename: sub.get('filename')!,
|
|
588
|
+
id: sub.get('id')!,
|
|
589
|
+
identifier: sub.get('identifier')!,
|
|
590
|
+
version: sub.get('version')!,
|
|
591
|
+
name: sub.get('name')!,
|
|
592
|
+
description: sub.get('description') ?? '<no description provided>',
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
// Add evals for subagents if any
|
|
596
|
+
const subEvalsStr = sub.get('evals');
|
|
597
|
+
if (subEvalsStr) {
|
|
598
|
+
logger.trace(
|
|
599
|
+
`[plugin] Found evals string for subagent ${subagentData.name}, parsing...`
|
|
600
|
+
);
|
|
601
|
+
try {
|
|
602
|
+
subagentData.evals = JSON.parse(subEvalsStr);
|
|
603
|
+
logger.trace(
|
|
604
|
+
`[plugin] Successfully parsed ${subagentData.evals?.length ?? 0} eval(s) for subagent ${subagentData.name}`
|
|
605
|
+
);
|
|
606
|
+
} catch (e) {
|
|
607
|
+
logger.trace(
|
|
608
|
+
`[plugin] Failed to parse evals for subagent ${subagentData.name}: ${e}`
|
|
609
|
+
);
|
|
610
|
+
console.warn(
|
|
611
|
+
`Failed to parse evals for subagent ${subagentData.name}: ${e}`
|
|
612
|
+
);
|
|
613
|
+
}
|
|
614
|
+
} else {
|
|
615
|
+
logger.trace(`[plugin] No evals found for subagent ${subagentData.name}`);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
return subagentData;
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
metadata.agents!.push(agentData);
|
|
301
623
|
}
|
|
302
624
|
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
);
|
|
306
|
-
await metadataFilename.write(JSON.stringify(metadata));
|
|
625
|
+
const routeMappingJSFile = Bun.file(join(build.config.outdir!, '.routemapping.json'));
|
|
626
|
+
await routeMappingJSFile.write(JSON.stringify(routeMapping));
|
|
307
627
|
|
|
308
628
|
return {
|
|
309
629
|
contents,
|