@arcteninc/core 0.0.22 → 0.0.24
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/package.json +1 -1
- package/scripts/cli-extract-types-auto.ts +226 -25
package/package.json
CHANGED
|
@@ -57,11 +57,142 @@ async function findToolUsageFiles(projectRoot: string): Promise<string[]> {
|
|
|
57
57
|
return files;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Extract tool names from an expression (handles arrays, variables, useMemo, etc.)
|
|
62
|
+
*/
|
|
63
|
+
function extractToolNamesFromExpression(
|
|
64
|
+
expr: ts.Expression,
|
|
65
|
+
sourceFile: ts.SourceFile,
|
|
66
|
+
variableMap: Map<string, ts.Expression>
|
|
67
|
+
): Set<string> {
|
|
68
|
+
const toolNames = new Set<string>();
|
|
69
|
+
const visited = new Set<ts.Node>();
|
|
70
|
+
|
|
71
|
+
function extractFromExpr(node: ts.Node): void {
|
|
72
|
+
if (visited.has(node)) return;
|
|
73
|
+
visited.add(node);
|
|
74
|
+
|
|
75
|
+
// Direct array literal: [tool1, tool2]
|
|
76
|
+
if (ts.isArrayLiteralExpression(node)) {
|
|
77
|
+
for (const element of node.elements) {
|
|
78
|
+
if (ts.isSpreadElement(element)) {
|
|
79
|
+
// Handle spread: [...someArray]
|
|
80
|
+
extractFromExpr(element.expression);
|
|
81
|
+
} else {
|
|
82
|
+
const name = element.getText(sourceFile).trim();
|
|
83
|
+
// Remove any object property access (e.g., tools.getOrders -> getOrders)
|
|
84
|
+
const simpleName = name.split('.').pop() || name;
|
|
85
|
+
if (simpleName && simpleName !== 'undefined' && simpleName !== 'null') {
|
|
86
|
+
toolNames.add(simpleName);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Variable reference: toolsList or function name: generateReport
|
|
94
|
+
if (ts.isIdentifier(node)) {
|
|
95
|
+
const varName = node.getText(sourceFile);
|
|
96
|
+
const varExpr = variableMap.get(varName);
|
|
97
|
+
if (varExpr) {
|
|
98
|
+
extractFromExpr(varExpr);
|
|
99
|
+
} else {
|
|
100
|
+
// If not in variableMap, it might be a function declaration name
|
|
101
|
+
// Add it directly as a tool name (findFunctionDefinition will find it later)
|
|
102
|
+
if (varName && varName !== 'undefined' && varName !== 'null') {
|
|
103
|
+
toolNames.add(varName);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Property access: wrappedTools.getRAGInfo
|
|
110
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
111
|
+
const propName = node.name.getText(sourceFile);
|
|
112
|
+
toolNames.add(propName);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// useMemo(() => [...], [])
|
|
117
|
+
if (ts.isCallExpression(node)) {
|
|
118
|
+
const callExpr = node.expression;
|
|
119
|
+
if (ts.isIdentifier(callExpr)) {
|
|
120
|
+
const funcName = callExpr.getText(sourceFile);
|
|
121
|
+
if (funcName === 'useMemo' && node.arguments.length > 0) {
|
|
122
|
+
const firstArg = node.arguments[0];
|
|
123
|
+
// Arrow function: () => [...]
|
|
124
|
+
if (ts.isArrowFunction(firstArg) && firstArg.body) {
|
|
125
|
+
if (ts.isBlock(firstArg.body)) {
|
|
126
|
+
// Block body: () => { return [...] }
|
|
127
|
+
for (const stmt of firstArg.body.statements) {
|
|
128
|
+
if (ts.isReturnStatement(stmt) && stmt.expression) {
|
|
129
|
+
extractFromExpr(stmt.expression);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
// Expression body: () => [...]
|
|
134
|
+
extractFromExpr(firstArg.body);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Regular function call: useMemo(fn, [])
|
|
138
|
+
else if (ts.isFunctionExpression(firstArg) || ts.isArrowFunction(firstArg)) {
|
|
139
|
+
// Can't easily extract from function body without more analysis
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Parenthesized: (toolsList)
|
|
147
|
+
if (ts.isParenthesizedExpression(node)) {
|
|
148
|
+
extractFromExpr(node.expression);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
extractFromExpr(expr);
|
|
154
|
+
return toolNames;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Build a map of variable declarations in the file
|
|
159
|
+
*/
|
|
160
|
+
function buildVariableMap(sourceFile: ts.SourceFile): Map<string, ts.Expression> {
|
|
161
|
+
const variableMap = new Map<string, ts.Expression>();
|
|
162
|
+
|
|
163
|
+
function visit(node: ts.Node) {
|
|
164
|
+
// const toolsList = [...] or const { tools } = something
|
|
165
|
+
if (ts.isVariableStatement(node)) {
|
|
166
|
+
for (const declaration of node.declarationList.declarations) {
|
|
167
|
+
if (ts.isIdentifier(declaration.name)) {
|
|
168
|
+
const varName = declaration.name.getText(sourceFile);
|
|
169
|
+
if (declaration.initializer) {
|
|
170
|
+
variableMap.set(varName, declaration.initializer);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// Handle destructuring: const { tools } = something
|
|
174
|
+
else if (ts.isObjectBindingPattern(declaration.name)) {
|
|
175
|
+
// For now, skip destructuring - can be enhanced later
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
ts.forEachChild(node, visit);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
visit(sourceFile);
|
|
184
|
+
return variableMap;
|
|
185
|
+
}
|
|
186
|
+
|
|
60
187
|
/**
|
|
61
188
|
* Extract tool names from ArctenAgent or useAgent usage
|
|
62
189
|
*/
|
|
63
|
-
function extractToolNamesFromFile(
|
|
190
|
+
function extractToolNamesFromFile(
|
|
191
|
+
sourceFile: ts.SourceFile,
|
|
192
|
+
program?: ts.Program
|
|
193
|
+
): ToolUsage[] {
|
|
64
194
|
const usages: ToolUsage[] = [];
|
|
195
|
+
const variableMap = buildVariableMap(sourceFile);
|
|
65
196
|
|
|
66
197
|
function visit(node: ts.Node) {
|
|
67
198
|
// Check for <ArctenAgent tools={[...]} safeTools={[...]} />
|
|
@@ -82,13 +213,9 @@ function extractToolNamesFromFile(sourceFile: ts.SourceFile): ToolUsage[] {
|
|
|
82
213
|
if (attrName === 'tools' || attrName === 'safeTools') {
|
|
83
214
|
if (attr.initializer && ts.isJsxExpression(attr.initializer)) {
|
|
84
215
|
const expr = attr.initializer.expression;
|
|
85
|
-
if (expr
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
// Remove any object property access (e.g., tools.getOrders -> getOrders)
|
|
89
|
-
const simpleName = name.split('.').pop() || name;
|
|
90
|
-
toolNames.add(simpleName);
|
|
91
|
-
}
|
|
216
|
+
if (expr) {
|
|
217
|
+
const extracted = extractToolNamesFromExpression(expr, sourceFile, variableMap);
|
|
218
|
+
extracted.forEach(name => toolNames.add(name));
|
|
92
219
|
}
|
|
93
220
|
}
|
|
94
221
|
}
|
|
@@ -118,13 +245,12 @@ function extractToolNamesFromFile(sourceFile: ts.SourceFile): ToolUsage[] {
|
|
|
118
245
|
if (ts.isPropertyAssignment(prop)) {
|
|
119
246
|
const propName = prop.name.getText(sourceFile);
|
|
120
247
|
if (propName === 'tools' || propName === 'safeTools') {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
248
|
+
const extracted = extractToolNamesFromExpression(
|
|
249
|
+
prop.initializer,
|
|
250
|
+
sourceFile,
|
|
251
|
+
variableMap
|
|
252
|
+
);
|
|
253
|
+
extracted.forEach(name => toolNames.add(name));
|
|
128
254
|
}
|
|
129
255
|
}
|
|
130
256
|
}
|
|
@@ -155,16 +281,38 @@ function findFunctionDefinition(
|
|
|
155
281
|
functionName: string,
|
|
156
282
|
sourceFile: ts.SourceFile,
|
|
157
283
|
program: ts.Program
|
|
158
|
-
): { sourceFile: ts.SourceFile; node: ts.FunctionDeclaration } | null {
|
|
284
|
+
): { sourceFile: ts.SourceFile; node: ts.FunctionDeclaration | ts.VariableDeclaration } | null {
|
|
159
285
|
// First, check if it's defined in the current file
|
|
160
|
-
let foundNode: ts.FunctionDeclaration | null = null;
|
|
286
|
+
let foundNode: ts.FunctionDeclaration | ts.VariableDeclaration | null = null;
|
|
161
287
|
|
|
162
288
|
function visitForDefinition(node: ts.Node) {
|
|
289
|
+
// Function declaration: function generateReport() {}
|
|
163
290
|
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
164
291
|
if (node.name.getText(sourceFile) === functionName) {
|
|
165
292
|
foundNode = node;
|
|
166
293
|
}
|
|
167
294
|
}
|
|
295
|
+
|
|
296
|
+
// Variable declaration with arrow function: const addFilter = async () => {}
|
|
297
|
+
// or function expression: const addFilter = async function() {}
|
|
298
|
+
if (ts.isVariableStatement(node)) {
|
|
299
|
+
for (const declaration of node.declarationList.declarations) {
|
|
300
|
+
if (ts.isIdentifier(declaration.name)) {
|
|
301
|
+
const varName = declaration.name.getText(sourceFile);
|
|
302
|
+
if (varName === functionName && declaration.initializer) {
|
|
303
|
+
// Check if it's an arrow function or function expression
|
|
304
|
+
if (
|
|
305
|
+
ts.isArrowFunction(declaration.initializer) ||
|
|
306
|
+
ts.isFunctionExpression(declaration.initializer)
|
|
307
|
+
) {
|
|
308
|
+
foundNode = declaration;
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
168
316
|
if (!foundNode) {
|
|
169
317
|
ts.forEachChild(node, visitForDefinition);
|
|
170
318
|
}
|
|
@@ -382,16 +530,46 @@ function serializeType(
|
|
|
382
530
|
* Extract metadata from a function
|
|
383
531
|
*/
|
|
384
532
|
function extractFunctionMetadata(
|
|
385
|
-
node: ts.FunctionDeclaration,
|
|
533
|
+
node: ts.FunctionDeclaration | ts.VariableDeclaration,
|
|
386
534
|
checker: ts.TypeChecker,
|
|
387
535
|
sourceFile: ts.SourceFile
|
|
388
536
|
): FunctionMetadata | null {
|
|
389
|
-
|
|
537
|
+
let functionNode: ts.FunctionDeclaration | ts.ArrowFunction | ts.FunctionExpression | null = null;
|
|
538
|
+
let functionName: string;
|
|
539
|
+
|
|
540
|
+
// Handle FunctionDeclaration: function generateReport() {}
|
|
541
|
+
if (ts.isFunctionDeclaration(node)) {
|
|
542
|
+
if (!node.name) {
|
|
543
|
+
return null;
|
|
544
|
+
}
|
|
545
|
+
functionNode = node;
|
|
546
|
+
functionName = node.name.getText(sourceFile);
|
|
547
|
+
}
|
|
548
|
+
// Handle VariableDeclaration: const addFilter = async () => {}
|
|
549
|
+
else if (ts.isVariableDeclaration(node)) {
|
|
550
|
+
if (!ts.isIdentifier(node.name)) {
|
|
551
|
+
return null;
|
|
552
|
+
}
|
|
553
|
+
functionName = node.name.getText(sourceFile);
|
|
554
|
+
|
|
555
|
+
if (node.initializer) {
|
|
556
|
+
if (ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer)) {
|
|
557
|
+
functionNode = node.initializer;
|
|
558
|
+
} else {
|
|
559
|
+
return null;
|
|
560
|
+
}
|
|
561
|
+
} else {
|
|
562
|
+
return null;
|
|
563
|
+
}
|
|
564
|
+
} else {
|
|
390
565
|
return null;
|
|
391
566
|
}
|
|
392
567
|
|
|
393
|
-
|
|
568
|
+
if (!functionNode) {
|
|
569
|
+
return null;
|
|
570
|
+
}
|
|
394
571
|
|
|
572
|
+
// Extract JSDoc comments
|
|
395
573
|
const jsDocTags = ts.getJSDocTags(node);
|
|
396
574
|
const jsDocComments = ts.getJSDocCommentsAndTags(node);
|
|
397
575
|
|
|
@@ -418,9 +596,24 @@ function extractFunctionMetadata(
|
|
|
418
596
|
|
|
419
597
|
const properties: Record<string, JsonSchemaProperty> = {};
|
|
420
598
|
const required: string[] = [];
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
599
|
+
|
|
600
|
+
// Check if async - works for both function declarations and arrow functions
|
|
601
|
+
const isAsync =
|
|
602
|
+
(ts.isFunctionDeclaration(node) && node.modifiers?.some(m => m.kind === ts.SyntaxKind.AsyncKeyword)) ||
|
|
603
|
+
(ts.isVariableDeclaration(node) && node.initializer && ts.isArrowFunction(node.initializer) &&
|
|
604
|
+
(node.initializer.modifiers?.some(m => m.kind === ts.SyntaxKind.AsyncKeyword) || false)) ||
|
|
605
|
+
(ts.isVariableDeclaration(node) && node.initializer && ts.isFunctionExpression(node.initializer) &&
|
|
606
|
+
(node.initializer.modifiers?.some(m => m.kind === ts.SyntaxKind.AsyncKeyword) || false)) ||
|
|
607
|
+
false;
|
|
608
|
+
|
|
609
|
+
// Extract parameters from the function node
|
|
610
|
+
const parameters = ts.isFunctionDeclaration(node)
|
|
611
|
+
? node.parameters
|
|
612
|
+
: (ts.isArrowFunction(functionNode) || ts.isFunctionExpression(functionNode))
|
|
613
|
+
? functionNode.parameters
|
|
614
|
+
: [];
|
|
615
|
+
|
|
616
|
+
for (const param of parameters) {
|
|
424
617
|
const paramName = param.name.getText(sourceFile);
|
|
425
618
|
const hasDefault = param.initializer !== undefined;
|
|
426
619
|
|
|
@@ -461,8 +654,16 @@ function extractFunctionMetadata(
|
|
|
461
654
|
}
|
|
462
655
|
|
|
463
656
|
let returnType = 'any';
|
|
464
|
-
if (node.type) {
|
|
657
|
+
if (ts.isFunctionDeclaration(node) && node.type) {
|
|
465
658
|
returnType = node.type.getText(sourceFile);
|
|
659
|
+
} else if (
|
|
660
|
+
ts.isVariableDeclaration(node) &&
|
|
661
|
+
node.initializer &&
|
|
662
|
+
(ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer))
|
|
663
|
+
) {
|
|
664
|
+
if (node.initializer.type) {
|
|
665
|
+
returnType = node.initializer.type.getText(sourceFile);
|
|
666
|
+
}
|
|
466
667
|
}
|
|
467
668
|
|
|
468
669
|
return {
|
|
@@ -512,7 +713,7 @@ async function autoDiscoverAndExtract(projectRoot: string, outputPath: string) {
|
|
|
512
713
|
for (const file of files) {
|
|
513
714
|
const sourceFile = program.getSourceFile(file);
|
|
514
715
|
if (sourceFile) {
|
|
515
|
-
const usages = extractToolNamesFromFile(sourceFile);
|
|
716
|
+
const usages = extractToolNamesFromFile(sourceFile, program);
|
|
516
717
|
if (usages.length > 0) {
|
|
517
718
|
allToolUsages.push(...usages);
|
|
518
719
|
usages.forEach(u => u.toolNames.forEach(name => allToolNames.add(name)));
|