@agentuity/cli 0.0.78 → 0.0.80
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/dist/cmd/build/ast.d.ts +2 -2
- package/dist/cmd/build/ast.d.ts.map +1 -1
- package/dist/cmd/build/ast.js +229 -24
- package/dist/cmd/build/ast.js.map +1 -1
- package/dist/cmd/build/bundler.d.ts +3 -1
- package/dist/cmd/build/bundler.d.ts.map +1 -1
- package/dist/cmd/build/bundler.js +18 -17
- 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 +5 -2
- 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 +29 -31
- package/dist/cmd/build/plugin.js.map +1 -1
- package/dist/cmd/build/{workbench-templates.d.ts → workbench.d.ts} +3 -1
- package/dist/cmd/build/workbench.d.ts.map +1 -0
- package/dist/cmd/build/{workbench-templates.js → workbench.js} +13 -1
- package/dist/cmd/build/workbench.js.map +1 -0
- package/dist/cmd/cloud/deploy.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.js +0 -1
- package/dist/cmd/cloud/deploy.js.map +1 -1
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/index.js +11 -2
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/cmd/project/template-flow.js +13 -2
- package/dist/cmd/project/template-flow.js.map +1 -1
- package/dist/sound.d.ts.map +1 -1
- package/dist/sound.js +1 -16
- package/dist/sound.js.map +1 -1
- package/package.json +5 -4
- package/src/cmd/build/ast.ts +322 -38
- package/src/cmd/build/bundler.ts +20 -17
- package/src/cmd/build/index.ts +5 -2
- package/src/cmd/build/plugin.ts +45 -41
- package/src/cmd/build/{workbench-templates.ts → workbench.ts} +13 -0
- package/src/cmd/cloud/deploy.ts +0 -1
- package/src/cmd/dev/index.ts +13 -2
- package/src/cmd/project/template-flow.ts +14 -2
- package/src/sound.ts +1 -17
- package/dist/cmd/build/workbench-templates.d.ts.map +0 -1
- package/dist/cmd/build/workbench-templates.js.map +0 -1
package/src/cmd/build/ast.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as acornLoose from 'acorn-loose';
|
|
2
|
-
import { dirname, relative } from 'node:path';
|
|
2
|
+
import { dirname, relative, join, basename } from 'node:path';
|
|
3
3
|
import { parse as parseCronExpression } from '@datasert/cronjs-parser';
|
|
4
4
|
import { generate } from 'astring';
|
|
5
5
|
import type { BuildMetadata } from '../../types';
|
|
@@ -7,7 +7,7 @@ import { createLogger } from '@agentuity/server';
|
|
|
7
7
|
import * as ts from 'typescript';
|
|
8
8
|
import { StructuredError, type WorkbenchConfig } from '@agentuity/core';
|
|
9
9
|
import type { LogLevel } from '../../types';
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
import { existsSync, mkdirSync } from 'node:fs';
|
|
12
12
|
import JSON5 from 'json5';
|
|
13
13
|
import { formatSchemaCode } from './format-schema';
|
|
@@ -152,7 +152,7 @@ function getEvalId(
|
|
|
152
152
|
name: string,
|
|
153
153
|
version: string
|
|
154
154
|
): string {
|
|
155
|
-
return `
|
|
155
|
+
return `evalid_${hashSHA1(projectId, deploymentId, filename, name, version)}`;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
function generateRouteId(
|
|
@@ -172,7 +172,7 @@ function generateStableAgentId(projectId: string, name: string): string {
|
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
function generateStableEvalId(projectId: string, agentId: string, name: string): string {
|
|
175
|
-
return `
|
|
175
|
+
return `eval_${hashSHA1(projectId, agentId, name)}`.substring(0, 64);
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
/**
|
|
@@ -328,24 +328,135 @@ function createAgentMetadataNode(
|
|
|
328
328
|
|
|
329
329
|
const DuplicateNameError = StructuredError('DuplicateNameError')<{ filename: string }>();
|
|
330
330
|
|
|
331
|
-
|
|
331
|
+
function injectEvalMetadata(
|
|
332
|
+
configObj: ASTObjectExpression,
|
|
333
|
+
evalId: string,
|
|
334
|
+
stableEvalId: string,
|
|
335
|
+
version: string,
|
|
336
|
+
filename: string,
|
|
337
|
+
agentId?: string
|
|
338
|
+
): void {
|
|
339
|
+
// Create metadata object with eval IDs and version
|
|
340
|
+
const properties = [
|
|
341
|
+
createObjectPropertyNode('id', evalId),
|
|
342
|
+
createObjectPropertyNode('evalId', stableEvalId),
|
|
343
|
+
createObjectPropertyNode('version', version),
|
|
344
|
+
createObjectPropertyNode('filename', filename),
|
|
345
|
+
];
|
|
346
|
+
|
|
347
|
+
// Add agentId if available
|
|
348
|
+
if (agentId) {
|
|
349
|
+
properties.push(createObjectPropertyNode('agentId', agentId));
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const metadataObj: ASTPropertyNode = {
|
|
353
|
+
type: 'Property',
|
|
354
|
+
kind: 'init',
|
|
355
|
+
key: {
|
|
356
|
+
type: 'Identifier',
|
|
357
|
+
name: 'metadata',
|
|
358
|
+
},
|
|
359
|
+
value: {
|
|
360
|
+
type: 'ObjectExpression',
|
|
361
|
+
properties,
|
|
362
|
+
} as ASTObjectExpression,
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
// Add metadata to the config object
|
|
366
|
+
configObj.properties.push(metadataObj);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function findAgentVariableAndImport(
|
|
370
|
+
ast: ASTProgram
|
|
371
|
+
): { varName: string; importPath: string } | undefined {
|
|
372
|
+
// First, find what variable is being used in agent.createEval() calls
|
|
373
|
+
let agentVarName: string | undefined;
|
|
374
|
+
|
|
375
|
+
for (const node of ast.body) {
|
|
376
|
+
if (node.type === 'ExportNamedDeclaration') {
|
|
377
|
+
const exportDecl = node as {
|
|
378
|
+
declaration?: { type: string; declarations?: Array<ASTVariableDeclarator> };
|
|
379
|
+
};
|
|
380
|
+
if (exportDecl.declaration?.type === 'VariableDeclaration') {
|
|
381
|
+
const variableDeclaration = exportDecl.declaration as {
|
|
382
|
+
declarations: Array<ASTVariableDeclarator>;
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
for (const vardecl of variableDeclaration.declarations) {
|
|
386
|
+
if (
|
|
387
|
+
vardecl.type === 'VariableDeclarator' &&
|
|
388
|
+
vardecl.init?.type === 'CallExpression'
|
|
389
|
+
) {
|
|
390
|
+
const call = vardecl.init as ASTCallExpression;
|
|
391
|
+
if (call.callee.type === 'MemberExpression') {
|
|
392
|
+
const memberExpr = call.callee as ASTMemberExpression;
|
|
393
|
+
const object = memberExpr.object as ASTNodeIdentifier;
|
|
394
|
+
const property = memberExpr.property as ASTNodeIdentifier;
|
|
395
|
+
if (
|
|
396
|
+
object.type === 'Identifier' &&
|
|
397
|
+
property.type === 'Identifier' &&
|
|
398
|
+
property.name === 'createEval'
|
|
399
|
+
) {
|
|
400
|
+
agentVarName = object.name;
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
if (agentVarName) break;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (!agentVarName) return undefined;
|
|
412
|
+
|
|
413
|
+
// Now find the import for this variable
|
|
414
|
+
for (const node of ast.body) {
|
|
415
|
+
if (node.type === 'ImportDeclaration') {
|
|
416
|
+
const importDecl = node as unknown as {
|
|
417
|
+
source: ASTLiteral;
|
|
418
|
+
specifiers: Array<{
|
|
419
|
+
type: string;
|
|
420
|
+
local: ASTNodeIdentifier;
|
|
421
|
+
}>;
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
// Find default import specifier that matches our variable
|
|
425
|
+
for (const spec of importDecl.specifiers) {
|
|
426
|
+
if (spec.type === 'ImportDefaultSpecifier' && spec.local.name === agentVarName) {
|
|
427
|
+
const importPath = importDecl.source.value;
|
|
428
|
+
if (typeof importPath === 'string') {
|
|
429
|
+
return { varName: agentVarName, importPath };
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
return undefined;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
export async function parseEvalMetadata(
|
|
332
440
|
rootDir: string,
|
|
333
441
|
filename: string,
|
|
334
442
|
contents: string,
|
|
335
443
|
projectId: string,
|
|
336
444
|
deploymentId: string,
|
|
337
|
-
agentId?: string
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
445
|
+
agentId?: string,
|
|
446
|
+
agentMetadata?: Map<string, Map<string, string>>
|
|
447
|
+
): Promise<
|
|
448
|
+
[
|
|
449
|
+
string,
|
|
450
|
+
Array<{
|
|
451
|
+
filename: string;
|
|
452
|
+
id: string;
|
|
453
|
+
version: string;
|
|
454
|
+
name: string;
|
|
455
|
+
evalId: string;
|
|
456
|
+
description?: string;
|
|
457
|
+
}>,
|
|
458
|
+
]
|
|
459
|
+
> {
|
|
349
460
|
const logLevel = (process.env.AGENTUITY_LOG_LEVEL || 'info') as
|
|
350
461
|
| 'trace'
|
|
351
462
|
| 'debug'
|
|
@@ -370,6 +481,47 @@ export function parseEvalMetadata(
|
|
|
370
481
|
description?: string;
|
|
371
482
|
}> = [];
|
|
372
483
|
|
|
484
|
+
// Try to find the corresponding agent to get the agentId
|
|
485
|
+
let resolvedAgentId = agentId;
|
|
486
|
+
if (!resolvedAgentId && agentMetadata) {
|
|
487
|
+
const agentInfo = findAgentVariableAndImport(ast);
|
|
488
|
+
if (agentInfo) {
|
|
489
|
+
logger.trace(
|
|
490
|
+
`[EVAL METADATA] Found agent variable '${agentInfo.varName}' imported from '${agentInfo.importPath}'`
|
|
491
|
+
);
|
|
492
|
+
|
|
493
|
+
// Resolve the import path to actual file path
|
|
494
|
+
let resolvedPath = agentInfo.importPath;
|
|
495
|
+
if (resolvedPath.startsWith('./') || resolvedPath.startsWith('../')) {
|
|
496
|
+
// Convert relative path to match the format in agentMetadata
|
|
497
|
+
const baseDir = dirname(filename);
|
|
498
|
+
resolvedPath = join(baseDir, resolvedPath);
|
|
499
|
+
// Normalize and ensure .ts extension
|
|
500
|
+
if (!resolvedPath.endsWith('.ts')) {
|
|
501
|
+
resolvedPath += '.ts';
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Find the agent metadata from the passed agentMetadata map
|
|
506
|
+
for (const [agentFile, metadata] of agentMetadata) {
|
|
507
|
+
// Check if this agent file matches the resolved import path
|
|
508
|
+
if (agentFile.includes(basename(resolvedPath)) && metadata.has('agentId')) {
|
|
509
|
+
resolvedAgentId = metadata.get('agentId');
|
|
510
|
+
logger.trace(
|
|
511
|
+
`[EVAL METADATA] Resolved agentId from agent metadata: ${resolvedAgentId} (file: ${agentFile})`
|
|
512
|
+
);
|
|
513
|
+
break;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if (!resolvedAgentId) {
|
|
518
|
+
logger.warn(
|
|
519
|
+
`[EVAL METADATA] Could not find agent metadata for import path: ${resolvedPath}`
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
373
525
|
// Find all exported agent.createEval() calls
|
|
374
526
|
for (const body of ast.body) {
|
|
375
527
|
let variableDeclaration: { declarations: Array<ASTVariableDeclarator> } | undefined;
|
|
@@ -451,16 +603,25 @@ export function parseEvalMetadata(
|
|
|
451
603
|
);
|
|
452
604
|
const evalId = getEvalId(projectId, deploymentId, rel, finalName, version);
|
|
453
605
|
|
|
454
|
-
// Generate stable evalId
|
|
455
|
-
const effectiveAgentId =
|
|
606
|
+
// Generate stable evalId using resolved agentId
|
|
607
|
+
const effectiveAgentId = resolvedAgentId || '';
|
|
456
608
|
const stableEvalId = generateStableEvalId(
|
|
457
609
|
projectId,
|
|
458
610
|
effectiveAgentId,
|
|
459
611
|
finalName
|
|
460
612
|
);
|
|
461
613
|
|
|
462
|
-
//
|
|
463
|
-
|
|
614
|
+
// Inject eval metadata into the AST (same pattern as agents)
|
|
615
|
+
if (configObj) {
|
|
616
|
+
injectEvalMetadata(
|
|
617
|
+
configObj,
|
|
618
|
+
evalId,
|
|
619
|
+
stableEvalId,
|
|
620
|
+
version,
|
|
621
|
+
rel,
|
|
622
|
+
resolvedAgentId
|
|
623
|
+
);
|
|
624
|
+
}
|
|
464
625
|
|
|
465
626
|
evals.push({
|
|
466
627
|
filename: rel,
|
|
@@ -740,13 +901,14 @@ export async function parseAgentMetadata(
|
|
|
740
901
|
const transpiler = new Bun.Transpiler({ loader: 'ts', target: 'bun' });
|
|
741
902
|
const evalsContents = transpiler.transformSync(evalsSource);
|
|
742
903
|
const agentId = result[1].get('agentId') || '';
|
|
743
|
-
const [, evals] = parseEvalMetadata(
|
|
904
|
+
const [, evals] = await parseEvalMetadata(
|
|
744
905
|
rootDir,
|
|
745
906
|
evalsPath,
|
|
746
907
|
evalsContents,
|
|
747
908
|
projectId,
|
|
748
909
|
deploymentId,
|
|
749
|
-
agentId
|
|
910
|
+
agentId,
|
|
911
|
+
new Map() // Empty map since we already have agentId
|
|
750
912
|
);
|
|
751
913
|
if (evals.length > 0) {
|
|
752
914
|
logger.trace(`Adding ${evals.length} eval(s) to agent metadata for ${name}`);
|
|
@@ -1777,11 +1939,17 @@ export * from '${runtimeImportPath}/src/index';
|
|
|
1777
1939
|
*/
|
|
1778
1940
|
export function analyzeWorkbench(content: string): WorkbenchAnalysis {
|
|
1779
1941
|
try {
|
|
1942
|
+
if (!content.includes('@agentuity/workbench')) {
|
|
1943
|
+
return {
|
|
1944
|
+
hasWorkbench: false,
|
|
1945
|
+
config: null,
|
|
1946
|
+
};
|
|
1947
|
+
}
|
|
1780
1948
|
const sourceFile = ts.createSourceFile('app.ts', content, ts.ScriptTarget.Latest, true);
|
|
1781
1949
|
|
|
1782
1950
|
let hasImport = false;
|
|
1783
|
-
|
|
1784
|
-
let
|
|
1951
|
+
const workbenchVariables = new Map<string, WorkbenchConfig>();
|
|
1952
|
+
let usedInServices = false;
|
|
1785
1953
|
|
|
1786
1954
|
function visitNode(node: ts.Node): void {
|
|
1787
1955
|
// Check for import declarations with createWorkbench
|
|
@@ -1795,18 +1963,55 @@ export function analyzeWorkbench(content: string): WorkbenchAnalysis {
|
|
|
1795
1963
|
}
|
|
1796
1964
|
}
|
|
1797
1965
|
|
|
1798
|
-
//
|
|
1799
|
-
if (
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1966
|
+
// Track variables assigned from createWorkbench() calls
|
|
1967
|
+
if (
|
|
1968
|
+
ts.isVariableDeclaration(node) &&
|
|
1969
|
+
node.initializer &&
|
|
1970
|
+
ts.isCallExpression(node.initializer) &&
|
|
1971
|
+
ts.isIdentifier(node.initializer.expression) &&
|
|
1972
|
+
node.initializer.expression.text === 'createWorkbench'
|
|
1973
|
+
) {
|
|
1974
|
+
// Extract variable name
|
|
1975
|
+
if (ts.isIdentifier(node.name)) {
|
|
1803
1976
|
// Extract configuration from the first argument (if any)
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1977
|
+
let varConfig: WorkbenchConfig;
|
|
1978
|
+
if (node.initializer.arguments.length > 0) {
|
|
1979
|
+
const configArg = node.initializer.arguments[0];
|
|
1980
|
+
varConfig = parseConfigObject(configArg) || { route: '/workbench' };
|
|
1807
1981
|
} else {
|
|
1808
1982
|
// Default config if no arguments provided
|
|
1809
|
-
|
|
1983
|
+
varConfig = { route: '/workbench' };
|
|
1984
|
+
}
|
|
1985
|
+
workbenchVariables.set(node.name.text, varConfig);
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1989
|
+
// Check if workbench variable is used in createApp's services config
|
|
1990
|
+
if (
|
|
1991
|
+
ts.isCallExpression(node) &&
|
|
1992
|
+
ts.isIdentifier(node.expression) &&
|
|
1993
|
+
node.expression.text === 'createApp' &&
|
|
1994
|
+
node.arguments.length > 0
|
|
1995
|
+
) {
|
|
1996
|
+
const configArg = node.arguments[0];
|
|
1997
|
+
if (ts.isObjectLiteralExpression(configArg)) {
|
|
1998
|
+
// Find the services property
|
|
1999
|
+
for (const prop of configArg.properties) {
|
|
2000
|
+
if (
|
|
2001
|
+
ts.isPropertyAssignment(prop) &&
|
|
2002
|
+
ts.isIdentifier(prop.name) &&
|
|
2003
|
+
prop.name.text === 'services'
|
|
2004
|
+
) {
|
|
2005
|
+
// Check if any workbench variable is referenced in services
|
|
2006
|
+
const foundVariableName = checkForWorkbenchUsage(
|
|
2007
|
+
prop.initializer,
|
|
2008
|
+
workbenchVariables
|
|
2009
|
+
);
|
|
2010
|
+
if (foundVariableName) {
|
|
2011
|
+
usedInServices = true;
|
|
2012
|
+
}
|
|
2013
|
+
break;
|
|
2014
|
+
}
|
|
1810
2015
|
}
|
|
1811
2016
|
}
|
|
1812
2017
|
}
|
|
@@ -1815,15 +2020,94 @@ export function analyzeWorkbench(content: string): WorkbenchAnalysis {
|
|
|
1815
2020
|
ts.forEachChild(node, visitNode);
|
|
1816
2021
|
}
|
|
1817
2022
|
|
|
2023
|
+
// Helper function to check if workbench variable is used in services config
|
|
2024
|
+
// Returns the variable name if found, otherwise null
|
|
2025
|
+
function checkForWorkbenchUsage(
|
|
2026
|
+
node: ts.Node,
|
|
2027
|
+
variables: Map<string, WorkbenchConfig>
|
|
2028
|
+
): string | null {
|
|
2029
|
+
let foundVar: string | null = null;
|
|
2030
|
+
|
|
2031
|
+
function visit(n: ts.Node): void {
|
|
2032
|
+
if (foundVar) return; // Already found
|
|
2033
|
+
|
|
2034
|
+
// Check for identifier references
|
|
2035
|
+
if (ts.isIdentifier(n) && variables.has(n.text)) {
|
|
2036
|
+
foundVar = n.text;
|
|
2037
|
+
return;
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
// Check for property shorthand: { workbench } in services
|
|
2041
|
+
if (ts.isShorthandPropertyAssignment(n) && variables.has(n.name.text)) {
|
|
2042
|
+
foundVar = n.name.text;
|
|
2043
|
+
return;
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
// Check for property value: { workbench: workbench } in services
|
|
2047
|
+
if (
|
|
2048
|
+
ts.isPropertyAssignment(n) &&
|
|
2049
|
+
n.initializer &&
|
|
2050
|
+
ts.isIdentifier(n.initializer) &&
|
|
2051
|
+
variables.has(n.initializer.text)
|
|
2052
|
+
) {
|
|
2053
|
+
foundVar = n.initializer.text;
|
|
2054
|
+
return;
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
ts.forEachChild(n, visit);
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
visit(node);
|
|
2061
|
+
return foundVar;
|
|
2062
|
+
}
|
|
2063
|
+
|
|
1818
2064
|
visitNode(sourceFile);
|
|
1819
2065
|
|
|
1820
|
-
//
|
|
1821
|
-
|
|
1822
|
-
|
|
2066
|
+
// Get the config from the first used workbench variable
|
|
2067
|
+
let config: WorkbenchConfig | null = null;
|
|
2068
|
+
if (hasImport && usedInServices) {
|
|
2069
|
+
// Re-check which variable was used
|
|
2070
|
+
const ast = sourceFile;
|
|
2071
|
+
for (const [varName, varConfig] of workbenchVariables.entries()) {
|
|
2072
|
+
// Simple check: walk through and find if this variable is used in services
|
|
2073
|
+
let used = false;
|
|
2074
|
+
function checkUsage(node: ts.Node): void {
|
|
2075
|
+
if (
|
|
2076
|
+
ts.isCallExpression(node) &&
|
|
2077
|
+
ts.isIdentifier(node.expression) &&
|
|
2078
|
+
node.expression.text === 'createApp' &&
|
|
2079
|
+
node.arguments.length > 0
|
|
2080
|
+
) {
|
|
2081
|
+
const configArg = node.arguments[0];
|
|
2082
|
+
if (ts.isObjectLiteralExpression(configArg)) {
|
|
2083
|
+
for (const prop of configArg.properties) {
|
|
2084
|
+
if (
|
|
2085
|
+
ts.isPropertyAssignment(prop) &&
|
|
2086
|
+
ts.isIdentifier(prop.name) &&
|
|
2087
|
+
prop.name.text === 'services'
|
|
2088
|
+
) {
|
|
2089
|
+
const foundVar = checkForWorkbenchUsage(
|
|
2090
|
+
prop.initializer,
|
|
2091
|
+
workbenchVariables
|
|
2092
|
+
);
|
|
2093
|
+
if (foundVar === varName) {
|
|
2094
|
+
used = true;
|
|
2095
|
+
config = varConfig;
|
|
2096
|
+
}
|
|
2097
|
+
break;
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
ts.forEachChild(node, checkUsage);
|
|
2103
|
+
}
|
|
2104
|
+
checkUsage(ast);
|
|
2105
|
+
if (used) break;
|
|
2106
|
+
}
|
|
1823
2107
|
}
|
|
1824
2108
|
|
|
1825
2109
|
return {
|
|
1826
|
-
hasWorkbench: hasImport &&
|
|
2110
|
+
hasWorkbench: hasImport && usedInServices,
|
|
1827
2111
|
config: config,
|
|
1828
2112
|
};
|
|
1829
2113
|
} catch (error) {
|
package/src/cmd/build/bundler.ts
CHANGED
|
@@ -11,8 +11,8 @@ import { getVersion } from '../../version';
|
|
|
11
11
|
import type { Project } from '../../types';
|
|
12
12
|
import { fixDuplicateExportsInDirectory } from './fix-duplicate-exports';
|
|
13
13
|
import type { Logger } from '../../types';
|
|
14
|
-
import { generateWorkbenchMainTsx, generateWorkbenchIndexHtml } from './workbench
|
|
15
|
-
import { analyzeWorkbench } from './ast';
|
|
14
|
+
import { generateWorkbenchMainTsx, generateWorkbenchIndexHtml } from './workbench';
|
|
15
|
+
import { analyzeWorkbench, type WorkbenchAnalysis } from './ast';
|
|
16
16
|
import { type DeployOptions } from '../../schemas/deploy';
|
|
17
17
|
|
|
18
18
|
const minBunVersion = '>=1.3.3';
|
|
@@ -64,6 +64,7 @@ export interface BundleOptions extends DeployOptions {
|
|
|
64
64
|
outDir?: string;
|
|
65
65
|
region: string;
|
|
66
66
|
logger: Logger;
|
|
67
|
+
workbench?: WorkbenchAnalysis;
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
type BuildResult = Awaited<ReturnType<typeof Bun.build>>;
|
|
@@ -116,6 +117,7 @@ export async function bundle({
|
|
|
116
117
|
env,
|
|
117
118
|
region,
|
|
118
119
|
logger,
|
|
120
|
+
workbench,
|
|
119
121
|
}: BundleOptions): Promise<{ output: string[] }> {
|
|
120
122
|
const output: string[] = [];
|
|
121
123
|
|
|
@@ -305,10 +307,12 @@ export async function bundle({
|
|
|
305
307
|
format: 'esm',
|
|
306
308
|
banner: `// Generated file. DO NOT EDIT`,
|
|
307
309
|
// Disable minify for server bundle (keep code readable for debugging)
|
|
308
|
-
|
|
309
|
-
minify: false,
|
|
310
|
+
minify: !dev,
|
|
310
311
|
drop: isProd ? ['debugger'] : undefined,
|
|
311
|
-
splitting
|
|
312
|
+
// Disable splitting - causes module initialization issues with externalized packages
|
|
313
|
+
// The chunk helper functions (__commonJS, __esm, etc.) don't properly handle
|
|
314
|
+
// CommonJS packages in node_modules that require() other modules
|
|
315
|
+
splitting: false,
|
|
312
316
|
conditions: [isProd ? 'production' : 'development', 'bun'],
|
|
313
317
|
external,
|
|
314
318
|
naming: {
|
|
@@ -322,9 +326,6 @@ export async function bundle({
|
|
|
322
326
|
if (!buildResult.success) {
|
|
323
327
|
handleBuildFailure(buildResult);
|
|
324
328
|
}
|
|
325
|
-
// Fix duplicate exports caused by Bun splitting bug
|
|
326
|
-
// See: https://github.com/oven-sh/bun/issues/5344
|
|
327
|
-
await fixDuplicateExportsInDirectory(outDir, false);
|
|
328
329
|
})();
|
|
329
330
|
|
|
330
331
|
const buildmetadata = getBuildMetadata();
|
|
@@ -468,13 +469,15 @@ export async function bundle({
|
|
|
468
469
|
|
|
469
470
|
// Bundle workbench app if detected via setupWorkbench
|
|
470
471
|
if (existsSync(appFile)) {
|
|
471
|
-
|
|
472
|
-
|
|
472
|
+
if (!workbench) {
|
|
473
|
+
const appContent = await Bun.file(appFile).text();
|
|
474
|
+
workbench = analyzeWorkbench(appContent);
|
|
475
|
+
}
|
|
473
476
|
|
|
474
|
-
if (
|
|
477
|
+
if (workbench.hasWorkbench) {
|
|
475
478
|
// Create workbench config with proper defaults
|
|
476
479
|
const defaultConfig = { route: '/workbench', headers: {}, port: port || 3500 };
|
|
477
|
-
const config = { ...defaultConfig, ...
|
|
480
|
+
const config = { ...defaultConfig, ...workbench.config };
|
|
478
481
|
try {
|
|
479
482
|
// Generate workbench files on the fly instead of using files from package
|
|
480
483
|
const tempWorkbenchDir = join(outDir, 'temp-workbench');
|
|
@@ -486,19 +489,19 @@ export async function bundle({
|
|
|
486
489
|
await Bun.write(workbenchIndexFile, generateWorkbenchIndexHtml());
|
|
487
490
|
|
|
488
491
|
// Bundle workbench using generated files
|
|
489
|
-
//
|
|
490
|
-
// Bun needs to resolve @agentuity/* packages from the project's node_modules
|
|
492
|
+
// Disable splitting to avoid CommonJS/ESM module resolution conflicts
|
|
491
493
|
const workbenchBuildConfig: Bun.BuildConfig = {
|
|
492
494
|
entrypoints: [workbenchIndexFile],
|
|
493
495
|
outdir: join(outDir, 'workbench'),
|
|
494
496
|
sourcemap: dev ? 'inline' : 'linked',
|
|
495
|
-
plugins: [AgentuityBundler], // i dont think we need this plugin here
|
|
496
497
|
target: 'browser',
|
|
497
498
|
format: 'esm',
|
|
498
499
|
banner: `// Generated file. DO NOT EDIT`,
|
|
499
|
-
minify: !dev,
|
|
500
|
-
|
|
500
|
+
minify: !dev,
|
|
501
|
+
drop: isProd ? ['debugger'] : undefined,
|
|
502
|
+
splitting: false,
|
|
501
503
|
packages: 'bundle',
|
|
504
|
+
conditions: ['browser', 'import', 'default'],
|
|
502
505
|
naming: {
|
|
503
506
|
entry: '[dir]/[name].[ext]',
|
|
504
507
|
chunk: 'workbench/chunk/[name]-[hash].[ext]',
|
package/src/cmd/build/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { resolve, join } from 'node:path';
|
|
2
|
+
import { resolve, join, relative } from 'node:path';
|
|
3
3
|
import { getServiceUrls } from '@agentuity/server';
|
|
4
4
|
import { createCommand } from '../../types';
|
|
5
5
|
import { bundle } from './bundler';
|
|
@@ -47,7 +47,10 @@ export const command = createCommand({
|
|
|
47
47
|
const outDir = opts.outdir ? resolve(opts.outdir) : join(absoluteProjectDir, '.agentuity');
|
|
48
48
|
|
|
49
49
|
try {
|
|
50
|
-
|
|
50
|
+
const rel = outDir.startsWith(absoluteProjectDir)
|
|
51
|
+
? relative(absoluteProjectDir, outDir)
|
|
52
|
+
: outDir;
|
|
53
|
+
tui.info(`Bundling project at ${absoluteProjectDir} to ${rel}`);
|
|
51
54
|
|
|
52
55
|
const env: Map<string, string> = new Map();
|
|
53
56
|
|
package/src/cmd/build/plugin.ts
CHANGED
|
@@ -236,38 +236,55 @@ const AgentuityBundler: BunPlugin = {
|
|
|
236
236
|
let newsource = await Bun.file(args.path).text();
|
|
237
237
|
if (args.path.startsWith(srcDir)) {
|
|
238
238
|
const contents = transpiler.transformSync(newsource);
|
|
239
|
-
const result = await parseAgentMetadata(
|
|
240
|
-
rootDir,
|
|
241
|
-
args.path,
|
|
242
|
-
contents,
|
|
243
|
-
projectId,
|
|
244
|
-
deploymentId
|
|
245
|
-
);
|
|
246
239
|
|
|
247
|
-
//
|
|
248
|
-
if (
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
240
|
+
// Check if this is an eval file (eval.ts)
|
|
241
|
+
if (args.path.endsWith('/eval.ts')) {
|
|
242
|
+
// parseEvalMetadata will find the agent from the import statement
|
|
243
|
+
const [ns] = await parseEvalMetadata(
|
|
244
|
+
rootDir,
|
|
245
|
+
args.path,
|
|
246
|
+
contents,
|
|
247
|
+
projectId,
|
|
248
|
+
deploymentId,
|
|
249
|
+
undefined, // No agentId - will be resolved from import
|
|
250
|
+
agentMetadata
|
|
251
|
+
);
|
|
252
|
+
newsource = ns;
|
|
253
|
+
} else {
|
|
254
|
+
// Handle regular agent files
|
|
255
|
+
const result = await parseAgentMetadata(
|
|
256
|
+
rootDir,
|
|
257
|
+
args.path,
|
|
258
|
+
contents,
|
|
259
|
+
projectId,
|
|
260
|
+
deploymentId
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
// Skip files that don't have a createAgent export
|
|
264
|
+
if (result === undefined) {
|
|
265
|
+
return {
|
|
266
|
+
contents: newsource,
|
|
267
|
+
loader: 'ts',
|
|
268
|
+
};
|
|
269
|
+
}
|
|
254
270
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
271
|
+
const [ns, md] = result;
|
|
272
|
+
newsource = ns;
|
|
273
|
+
|
|
274
|
+
// Only process files that actually export an agent
|
|
275
|
+
if (md.has('name')) {
|
|
276
|
+
const newAgentName = md.get('name');
|
|
277
|
+
for (const [, kv] of agentMetadata) {
|
|
278
|
+
const found = kv.get('name');
|
|
279
|
+
if (newAgentName === found) {
|
|
280
|
+
throw new AgentNameDuplicateError({
|
|
281
|
+
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.`,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
267
284
|
}
|
|
268
|
-
}
|
|
269
285
|
|
|
270
|
-
|
|
286
|
+
agentMetadata.set(md.get('name')!, md);
|
|
287
|
+
}
|
|
271
288
|
}
|
|
272
289
|
}
|
|
273
290
|
return {
|
|
@@ -276,19 +293,6 @@ const AgentuityBundler: BunPlugin = {
|
|
|
276
293
|
};
|
|
277
294
|
});
|
|
278
295
|
|
|
279
|
-
build.onLoad({ filter: /\/eval\.ts$/, namespace: 'file' }, async (args) => {
|
|
280
|
-
let newsource = await Bun.file(args.path).text();
|
|
281
|
-
if (args.path.startsWith(srcDir)) {
|
|
282
|
-
const contents = transpiler.transformSync(newsource);
|
|
283
|
-
const [ns] = parseEvalMetadata(rootDir, args.path, contents, projectId, deploymentId);
|
|
284
|
-
newsource = ns;
|
|
285
|
-
}
|
|
286
|
-
return {
|
|
287
|
-
contents: newsource,
|
|
288
|
-
loader: 'ts',
|
|
289
|
-
};
|
|
290
|
-
});
|
|
291
|
-
|
|
292
296
|
const patches = generatePatches();
|
|
293
297
|
for (const [, patch] of patches) {
|
|
294
298
|
let modulePath = join('node_modules', patch.module, '.*');
|