agency-lang 0.0.52 → 0.0.54
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/lib/backends/agencyGenerator.d.ts +2 -0
- package/dist/lib/backends/agencyGenerator.js +7 -3
- package/dist/lib/backends/baseGenerator.d.ts +2 -1
- package/dist/lib/backends/baseGenerator.js +5 -2
- package/dist/lib/backends/graphGenerator.js +1 -1
- package/dist/lib/backends/typescriptGenerator.d.ts +7 -1
- package/dist/lib/backends/typescriptGenerator.js +68 -19
- package/dist/lib/cli/commands.d.ts +12 -0
- package/dist/lib/cli/commands.js +217 -0
- package/dist/lib/cli/evaluate.d.ts +1 -0
- package/dist/lib/cli/evaluate.js +204 -0
- package/dist/lib/cli/help.d.ts +1 -0
- package/dist/lib/cli/help.js +51 -0
- package/dist/lib/cli/test.d.ts +2 -0
- package/dist/lib/cli/test.js +166 -0
- package/dist/lib/cli/util.d.ts +19 -0
- package/dist/lib/cli/util.js +132 -0
- package/dist/lib/config.d.ts +1 -0
- package/dist/lib/config.js +1 -0
- package/dist/lib/parser.d.ts +2 -1
- package/dist/lib/parser.js +26 -17
- package/dist/lib/parsers/function.js +2 -1
- package/dist/lib/parsers/importStatement.js +4 -4
- package/dist/lib/parsers/importStatement.test.js +82 -35
- package/dist/lib/parsers/parserUtils.js +1 -1
- package/dist/lib/parsers/skill.d.ts +5 -0
- package/dist/lib/parsers/skill.js +20 -0
- package/dist/lib/parsers/skill.test.d.ts +1 -0
- package/dist/lib/parsers/skill.test.js +338 -0
- package/dist/lib/parsers/tools.d.ts +1 -1
- package/dist/lib/parsers/tools.js +2 -2
- package/dist/lib/parsers/tools.test.js +17 -12
- package/dist/lib/parsers/typeHints.js +2 -2
- package/dist/lib/parsers/typeHints.test.js +13 -1
- package/dist/lib/preprocessors/typescriptPreprocessor.core.test.js +3 -2
- package/dist/lib/preprocessors/typescriptPreprocessor.d.ts +5 -9
- package/dist/lib/preprocessors/typescriptPreprocessor.js +68 -213
- package/dist/lib/templates/backends/graphGenerator/graphNode.d.ts +1 -1
- package/dist/lib/templates/backends/graphGenerator/graphNode.js +4 -1
- package/dist/lib/templates/backends/graphGenerator/imports.d.ts +1 -1
- package/dist/lib/templates/backends/graphGenerator/imports.js +117 -19
- package/dist/lib/templates/backends/graphGenerator/runNodeFunction.d.ts +1 -1
- package/dist/lib/templates/backends/graphGenerator/runNodeFunction.js +5 -6
- package/dist/lib/templates/backends/graphGenerator/specialVar.d.ts +1 -1
- package/dist/lib/templates/backends/graphGenerator/specialVar.js +1 -1
- package/dist/lib/templates/backends/graphGenerator/startNode.d.ts +1 -1
- package/dist/lib/templates/backends/graphGenerator/startNode.js +4 -2
- package/dist/lib/templates/backends/typescriptGenerator/imports.d.ts +1 -1
- package/dist/lib/templates/backends/typescriptGenerator/imports.js +2 -2
- package/dist/lib/templates/backends/typescriptGenerator/promptFunction.d.ts +2 -1
- package/dist/lib/templates/backends/typescriptGenerator/promptFunction.js +9 -73
- package/dist/lib/templates/backends/typescriptGenerator/tool.d.ts +2 -1
- package/dist/lib/templates/backends/typescriptGenerator/tool.js +2 -1
- package/dist/lib/templates/backends/typescriptGenerator/toolCall.d.ts +1 -2
- package/dist/lib/templates/backends/typescriptGenerator/toolCall.js +5 -3
- package/dist/lib/templates/cli/evaluate.d.ts +9 -0
- package/dist/lib/templates/cli/evaluate.js +24 -0
- package/dist/lib/templates/prompts/skill.d.ts +6 -0
- package/dist/lib/templates/prompts/skill.js +14 -0
- package/dist/lib/types/literals.d.ts +2 -0
- package/dist/lib/types/skill.d.ts +5 -0
- package/dist/lib/types/skill.js +1 -0
- package/dist/lib/types.d.ts +2 -1
- package/dist/lib/utils/node.d.ts +10 -0
- package/dist/lib/utils/node.js +208 -0
- package/dist/scripts/agency.js +151 -369
- package/package.json +7 -3
|
@@ -15,6 +15,7 @@ import { WhileLoop } from "../types/whileLoop.js";
|
|
|
15
15
|
import { BaseGenerator } from "./baseGenerator.js";
|
|
16
16
|
import { AgencyConfig } from "../config.js";
|
|
17
17
|
import { MessageThread } from "../types/messageThread.js";
|
|
18
|
+
import { Skill } from "../types/skill.js";
|
|
18
19
|
export declare class AgencyGenerator extends BaseGenerator {
|
|
19
20
|
private indentLevel;
|
|
20
21
|
private indentSize;
|
|
@@ -64,5 +65,6 @@ export declare class AgencyGenerator extends BaseGenerator {
|
|
|
64
65
|
protected processAwaitStatement(node: AwaitStatement): string;
|
|
65
66
|
protected processNewLine(_node: NewLine): string;
|
|
66
67
|
protected processMessageThread(node: MessageThread): string;
|
|
68
|
+
protected processSkill(node: Skill): string;
|
|
67
69
|
}
|
|
68
70
|
export declare function generateAgency(program: AgencyProgram): string;
|
|
@@ -141,7 +141,10 @@ export class AgencyGenerator extends BaseGenerator {
|
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
result += '"""';
|
|
144
|
-
return result
|
|
144
|
+
return result
|
|
145
|
+
.split("\n")
|
|
146
|
+
.map((line) => this.indentStr(line))
|
|
147
|
+
.join("\n");
|
|
145
148
|
}
|
|
146
149
|
processPromptLiteral(variableName, variableType, node) {
|
|
147
150
|
// For agency code, prompts are just part of assignments
|
|
@@ -380,8 +383,6 @@ export class AgencyGenerator extends BaseGenerator {
|
|
|
380
383
|
return "";
|
|
381
384
|
}
|
|
382
385
|
processUsesTool(node) {
|
|
383
|
-
// Track tool usage but don't generate code
|
|
384
|
-
this.toolsUsed.push(...node.toolNames);
|
|
385
386
|
return this.indentStr(`uses ${node.toolNames.join(", ")}`);
|
|
386
387
|
}
|
|
387
388
|
processSpecialVar(node) {
|
|
@@ -408,6 +409,9 @@ export class AgencyGenerator extends BaseGenerator {
|
|
|
408
409
|
const threadType = node.subthread ? "subthread" : "thread";
|
|
409
410
|
return this.indentStr(`${threadType} {\n${bodyCodeStr}${this.indentStr("}")}`);
|
|
410
411
|
}
|
|
412
|
+
processSkill(node) {
|
|
413
|
+
return this.indentStr(`skill "${node.filepath}"`);
|
|
414
|
+
}
|
|
411
415
|
}
|
|
412
416
|
export function generateAgency(program) {
|
|
413
417
|
const generator = new AgencyGenerator();
|
|
@@ -14,6 +14,7 @@ import { UsesTool } from "../types/tools.js";
|
|
|
14
14
|
import { WhileLoop } from "../types/whileLoop.js";
|
|
15
15
|
import { AgencyConfig } from "../config.js";
|
|
16
16
|
import { MessageThread } from "../types/messageThread.js";
|
|
17
|
+
import { Skill } from "../types/skill.js";
|
|
17
18
|
type Scope = GlobalScope | FunctionScope | NodeScope;
|
|
18
19
|
type GlobalScope = {
|
|
19
20
|
type: "global";
|
|
@@ -34,7 +35,6 @@ export declare class BaseGenerator {
|
|
|
34
35
|
protected functionScopedVariables: string[];
|
|
35
36
|
protected globalScopedVariables: string[];
|
|
36
37
|
protected functionParameters: string[];
|
|
37
|
-
protected toolsUsed: string[];
|
|
38
38
|
protected typeAliases: Record<string, VariableType>;
|
|
39
39
|
protected functionsUsed: Set<string>;
|
|
40
40
|
protected importStatements: string[];
|
|
@@ -59,6 +59,7 @@ export declare class BaseGenerator {
|
|
|
59
59
|
protected collectFunctionSignature(node: FunctionDefinition): void;
|
|
60
60
|
protected processGraphNodeName(node: GraphNodeDefinition): void;
|
|
61
61
|
protected processNode(node: AgencyNode): string;
|
|
62
|
+
protected processSkill(node: Skill): string;
|
|
62
63
|
protected processMessageThread(node: MessageThread): string;
|
|
63
64
|
protected processNewLine(_node: NewLine): string;
|
|
64
65
|
protected processAwaitStatement(node: AwaitStatement): string;
|
|
@@ -7,8 +7,6 @@ export class BaseGenerator {
|
|
|
7
7
|
functionScopedVariables = [];
|
|
8
8
|
globalScopedVariables = [];
|
|
9
9
|
functionParameters = [];
|
|
10
|
-
// collect tools for a prompt
|
|
11
|
-
toolsUsed = [];
|
|
12
10
|
typeAliases = {};
|
|
13
11
|
// collect functions used to see what builtin helpers to include
|
|
14
12
|
functionsUsed = new Set();
|
|
@@ -175,10 +173,15 @@ export class BaseGenerator {
|
|
|
175
173
|
return node.value;
|
|
176
174
|
case "messageThread":
|
|
177
175
|
return this.processMessageThread(node);
|
|
176
|
+
case "skill":
|
|
177
|
+
return this.processSkill(node);
|
|
178
178
|
default:
|
|
179
179
|
throw new Error(`Unhandled Agency node type: ${node.type}`);
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
|
+
processSkill(node) {
|
|
183
|
+
return "processSkill not implemented";
|
|
184
|
+
}
|
|
182
185
|
processMessageThread(node) {
|
|
183
186
|
return "processMessageThread not implemented";
|
|
184
187
|
}
|
|
@@ -46,7 +46,7 @@ export class GraphGenerator extends TypeScriptGenerator {
|
|
|
46
46
|
return `return ${returnCode}\n`;
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
return `return {
|
|
49
|
+
return `return { messages: __self.messages_0, data: ${returnCode}}\n`;
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
processGraphNodeName(node) {
|
|
@@ -14,6 +14,7 @@ import { WhileLoop } from "../types/whileLoop.js";
|
|
|
14
14
|
import { BaseGenerator } from "./baseGenerator.js";
|
|
15
15
|
import { AgencyConfig } from "../config.js";
|
|
16
16
|
import { MessageThread } from "../types/messageThread.js";
|
|
17
|
+
import { Skill } from "../types/skill.js";
|
|
17
18
|
export declare class TypeScriptGenerator extends BaseGenerator {
|
|
18
19
|
protected currentMessageThreadNodeId: string[];
|
|
19
20
|
constructor(args?: {
|
|
@@ -51,7 +52,11 @@ export declare class TypeScriptGenerator extends BaseGenerator {
|
|
|
51
52
|
protected generateLiteral(literal: Literal): string;
|
|
52
53
|
protected getScopeReturnType(): VariableType | undefined;
|
|
53
54
|
protected generateImports(): string;
|
|
54
|
-
buildPromptString(segments
|
|
55
|
+
buildPromptString({ segments, typeHints, skills, }: {
|
|
56
|
+
segments: PromptSegment[];
|
|
57
|
+
typeHints: TypeHintMap;
|
|
58
|
+
skills: Skill[];
|
|
59
|
+
}): string;
|
|
55
60
|
generateStringLiteral(segments: PromptSegment[]): string;
|
|
56
61
|
/**
|
|
57
62
|
* Generates an async for prompt-based assignments
|
|
@@ -71,6 +76,7 @@ export declare class TypeScriptGenerator extends BaseGenerator {
|
|
|
71
76
|
protected processTimeBlock(node: TimeBlock, timingVarName: string): string;
|
|
72
77
|
protected processAwaitStatement(node: AwaitStatement): string;
|
|
73
78
|
protected processMessageThread(node: MessageThread, varName?: string): string;
|
|
79
|
+
protected processSkill(node: Skill): string;
|
|
74
80
|
protected processBodyAsParts(body: AgencyNode[]): string[];
|
|
75
81
|
}
|
|
76
82
|
export declare function generateTypeScript(program: AgencyProgram, config?: AgencyConfig): string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TYPES_THAT_DONT_TRIGGER_NEW_PART } from "../config.js";
|
|
1
|
+
import { BUILTIN_TOOLS, TYPES_THAT_DONT_TRIGGER_NEW_PART } from "../config.js";
|
|
2
2
|
import * as renderSpecialVar from "../templates/backends/graphGenerator/specialVar.js";
|
|
3
3
|
import * as renderTime from "../templates/backends/typescriptGenerator/builtinFunctions/time.js";
|
|
4
4
|
import * as builtinTools from "../templates/backends/typescriptGenerator/builtinTools.js";
|
|
@@ -10,12 +10,14 @@ import * as renderMessageThread from "../templates/backends/typescriptGenerator/
|
|
|
10
10
|
import * as promptFunction from "../templates/backends/typescriptGenerator/promptFunction.js";
|
|
11
11
|
import * as renderTool from "../templates/backends/typescriptGenerator/tool.js";
|
|
12
12
|
import * as renderToolCall from "../templates/backends/typescriptGenerator/toolCall.js";
|
|
13
|
+
import * as renderSkillPrompt from "../templates/prompts/skill.js";
|
|
13
14
|
import { escape, uniq } from "../utils.js";
|
|
14
15
|
import { BaseGenerator } from "./baseGenerator.js";
|
|
15
16
|
import { generateBuiltinHelpers, mapFunctionName, } from "./typescriptGenerator/builtins.js";
|
|
16
17
|
import { variableTypeToString } from "./typescriptGenerator/typeToString.js";
|
|
17
18
|
import { DEFAULT_SCHEMA, mapTypeToZodSchema, } from "./typescriptGenerator/typeToZodSchema.js";
|
|
18
19
|
import { TypescriptPreprocessor } from "../preprocessors/typescriptPreprocessor.js";
|
|
20
|
+
import path from "path";
|
|
19
21
|
const DEFAULT_PROMPT_NAME = "__promptVar";
|
|
20
22
|
export class TypeScriptGenerator extends BaseGenerator {
|
|
21
23
|
currentMessageThreadNodeId = ["0"];
|
|
@@ -220,15 +222,18 @@ export class TypeScriptGenerator extends BaseGenerator {
|
|
|
220
222
|
name: functionName,
|
|
221
223
|
description: node.docString?.value || "No description provided.",
|
|
222
224
|
schema: Object.keys(properties).length > 0 ? `{${schema}}` : "{}",
|
|
225
|
+
parameters: JSON.stringify(parameters.map((p) => p.name)),
|
|
223
226
|
});
|
|
224
227
|
}
|
|
225
228
|
processUsesTool(node) {
|
|
226
229
|
node.toolNames.forEach((toolName) => {
|
|
227
|
-
if (
|
|
230
|
+
if (BUILTIN_TOOLS.includes(toolName))
|
|
231
|
+
return;
|
|
232
|
+
if (!this.functionDefinitions[toolName] &&
|
|
233
|
+
!this.isImportedTool(toolName)) {
|
|
228
234
|
throw new Error(`Tool '${toolName}' is being used but no function definition found for it. Make sure to define a function for this tool.`);
|
|
229
235
|
}
|
|
230
236
|
});
|
|
231
|
-
this.toolsUsed.push(...node.toolNames);
|
|
232
237
|
return "";
|
|
233
238
|
}
|
|
234
239
|
/**
|
|
@@ -348,7 +353,7 @@ export class TypeScriptGenerator extends BaseGenerator {
|
|
|
348
353
|
arr.push(builtinTools.default({}));
|
|
349
354
|
return arr.join("\n");
|
|
350
355
|
}
|
|
351
|
-
buildPromptString(segments, typeHints) {
|
|
356
|
+
buildPromptString({ segments, typeHints, skills, }) {
|
|
352
357
|
const promptParts = [];
|
|
353
358
|
for (const segment of segments) {
|
|
354
359
|
if (segment.type === "text") {
|
|
@@ -368,6 +373,21 @@ export class TypeScriptGenerator extends BaseGenerator {
|
|
|
368
373
|
}
|
|
369
374
|
}
|
|
370
375
|
}
|
|
376
|
+
if (skills.length > 0) {
|
|
377
|
+
const skillsArr = skills.map((skill) => {
|
|
378
|
+
// strip the directory and extension from the filepath to get the skill name
|
|
379
|
+
const skillName = path.basename(skill.filepath, path.extname(skill.filepath));
|
|
380
|
+
if (skill.description) {
|
|
381
|
+
return `- ${skillName} (filepath: ${skill.filepath}): ${skill.description}`;
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
return `- ${skillName} (filepath: ${skill.filepath})`;
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
promptParts.push(renderSkillPrompt.default({
|
|
388
|
+
skills: skillsArr.join("\n"),
|
|
389
|
+
}));
|
|
390
|
+
}
|
|
371
391
|
return "`" + promptParts.join("") + "`";
|
|
372
392
|
}
|
|
373
393
|
generateStringLiteral(segments) {
|
|
@@ -397,28 +417,50 @@ export class TypeScriptGenerator extends BaseGenerator {
|
|
|
397
417
|
const zodSchema = mapTypeToZodSchema(_variableType, this.typeAliases);
|
|
398
418
|
const typeString = variableTypeToString(_variableType, this.typeAliases);
|
|
399
419
|
// Build prompt construction code
|
|
400
|
-
const promptCode = this.buildPromptString(
|
|
420
|
+
const promptCode = this.buildPromptString({
|
|
421
|
+
segments: prompt.segments,
|
|
422
|
+
typeHints: this.typeHints,
|
|
423
|
+
skills: prompt.skills || [],
|
|
424
|
+
});
|
|
401
425
|
const parts = functionArgs.map((arg) => `${arg.replace(".", "_")}: ${variableTypeToString(this.typeHints[arg] || { type: "primitiveType", value: "string" }, this.typeAliases)}`);
|
|
402
426
|
parts.push("__metadata?: Record<string, any>");
|
|
403
427
|
const argsStr = parts.join(", ");
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
.join(", ");
|
|
428
|
+
let _tools = "";
|
|
429
|
+
if (prompt.tools) {
|
|
430
|
+
_tools = prompt.tools.toolNames.map((name) => `__${name}Tool`).join(", ");
|
|
431
|
+
}
|
|
407
432
|
const tools = _tools.length > 0 ? `[${_tools}]` : "undefined";
|
|
408
|
-
|
|
433
|
+
/* What's going on here? This is a nine. We change all agency functions to take an array of arguments.
|
|
434
|
+
So, for example, `function add(a, b)` would get turned into `function add(arr)`.
|
|
435
|
+
Earlier, the arguments were getting converted into an object like `function add({a, b})` because LLMs
|
|
436
|
+
pass back an object of parameters for the function calls, so that made it easy to pass those arguments
|
|
437
|
+
straight to a function.
|
|
438
|
+
|
|
439
|
+
But that meant if a function was defined in another file, we would need to parse the contents of the file
|
|
440
|
+
to understand the names of the function parameters, hence the idea of an array. Unfortunately, the array
|
|
441
|
+
still doesn't solve the problem completely, because if what we get back from a tool call is an object
|
|
442
|
+
like `{a:1, b:2}`, we need to know how to convert it into an array. We need to know the order of the parameters.
|
|
443
|
+
|
|
444
|
+
So now, every function call generates a related tool definition, but it also generats an array of parameter names.
|
|
445
|
+
So if the user defines `add`, we'll generate `export const __addTool`, which is the tool definition,
|
|
446
|
+
and `export const __addToolParams`, which is an array of param names.
|
|
447
|
+
|
|
448
|
+
It's a mess and needs rethinking 🤮
|
|
449
|
+
|
|
450
|
+
This still doesn't work perfectly, because I can't introspect imported functions to see if they throw an interrupt,
|
|
451
|
+
so I have to always assume they do, which reduces some opportunity for parallelism. Maybe I just need to bite the bullet
|
|
452
|
+
and commit to having a preprocessed step where all the files get read.
|
|
453
|
+
I'll probably need to do that for supporting type checking anyway.
|
|
454
|
+
*/
|
|
455
|
+
const functionCalls = (prompt.tools || { type: "usesTool", toolNames: [] }).toolNames
|
|
456
|
+
.filter((t) => BUILTIN_TOOLS.includes(t))
|
|
409
457
|
.map((toolName) => {
|
|
410
|
-
|
|
411
|
-
|
|
458
|
+
if (!this.functionDefinitions[toolName] &&
|
|
459
|
+
!this.isImportedTool(toolName)) {
|
|
412
460
|
throw new Error(`Tool '${toolName}' is being used but no function definition found for it. Make sure to define a function for this tool.`);
|
|
413
461
|
}
|
|
414
|
-
const paramsStr = func.parameters
|
|
415
|
-
.map((param, index) => {
|
|
416
|
-
return `args["${param.name}"]`;
|
|
417
|
-
})
|
|
418
|
-
.join(", ");
|
|
419
462
|
return renderToolCall.default({
|
|
420
463
|
name: toolName,
|
|
421
|
-
paramsStr,
|
|
422
464
|
});
|
|
423
465
|
})
|
|
424
466
|
.join("\n");
|
|
@@ -426,7 +468,6 @@ export class TypeScriptGenerator extends BaseGenerator {
|
|
|
426
468
|
const metadataObj = `{
|
|
427
469
|
messages: __self.messages_${this.currentMessageThreadNodeId.at(-1)}.getMessages(),
|
|
428
470
|
}`;
|
|
429
|
-
this.toolsUsed = []; // reset after use
|
|
430
471
|
const scopedFunctionArgs = functionArgs.map((arg) => this.generateScopedVariableName(arg));
|
|
431
472
|
return promptFunction.default({
|
|
432
473
|
variableName,
|
|
@@ -442,6 +483,7 @@ export class TypeScriptGenerator extends BaseGenerator {
|
|
|
442
483
|
nodeContext: this.getCurrentScope().type === "node",
|
|
443
484
|
isStreaming: prompt.isStreaming || false,
|
|
444
485
|
isAsync: prompt.async || false,
|
|
486
|
+
messagesVar: `__self.messages_${this.currentMessageThreadNodeId.at(-1)}`,
|
|
445
487
|
});
|
|
446
488
|
}
|
|
447
489
|
processImportStatement(node) {
|
|
@@ -452,7 +494,11 @@ export class TypeScriptGenerator extends BaseGenerator {
|
|
|
452
494
|
}
|
|
453
495
|
processImportToolStatement(node) {
|
|
454
496
|
const importNames = node.importedTools
|
|
455
|
-
.map((toolName) => [
|
|
497
|
+
.map((toolName) => [
|
|
498
|
+
toolName,
|
|
499
|
+
`__${toolName}Tool`,
|
|
500
|
+
`__${toolName}ToolParams`,
|
|
501
|
+
])
|
|
456
502
|
.flat();
|
|
457
503
|
return `import { ${importNames.join(", ")} } from "${node.agencyFile.replace(/\.agency$/, ".ts")}";`;
|
|
458
504
|
}
|
|
@@ -530,6 +576,9 @@ export class TypeScriptGenerator extends BaseGenerator {
|
|
|
530
576
|
parentNodeId: node.parentNodeId || "0",
|
|
531
577
|
});
|
|
532
578
|
}
|
|
579
|
+
processSkill(node) {
|
|
580
|
+
return "";
|
|
581
|
+
}
|
|
533
582
|
/* This generates the body of a node or function separated into multiple parts.
|
|
534
583
|
You can think of a part as roughly corresponding to a single statement
|
|
535
584
|
(although some statements don't need their own parts, such as a newlines or type definitions).
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AgencyConfig } from "../config.js";
|
|
2
|
+
import { AgencyProgram } from "../index.js";
|
|
3
|
+
export declare function loadConfig(configPath?: string): AgencyConfig;
|
|
4
|
+
export declare function readStdin(): Promise<string>;
|
|
5
|
+
export declare function parse(contents: string, config: AgencyConfig): AgencyProgram;
|
|
6
|
+
export declare function readFile(inputFile: string): string;
|
|
7
|
+
export declare function renderGraph(contents: string, config: AgencyConfig): void;
|
|
8
|
+
export declare function getImports(program: AgencyProgram): string[];
|
|
9
|
+
export declare function compile(config: AgencyConfig, inputFile: string, _outputFile?: string): string | null;
|
|
10
|
+
export declare function run(config: AgencyConfig, inputFile: string, outputFile?: string): void;
|
|
11
|
+
export declare function format(contents: string, config: AgencyConfig): Promise<string>;
|
|
12
|
+
export declare function formatFile(inputPath: string, inPlace: boolean, config: AgencyConfig): void;
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { generateAgency } from "../backends/agencyGenerator.js";
|
|
2
|
+
import { generateGraph } from "../index.js";
|
|
3
|
+
import { TypescriptPreprocessor } from "../preprocessors/typescriptPreprocessor.js";
|
|
4
|
+
import { renderMermaidAscii } from "beautiful-mermaid";
|
|
5
|
+
import { spawn } from "child_process";
|
|
6
|
+
import * as fs from "fs";
|
|
7
|
+
import * as path from "path";
|
|
8
|
+
import { parseAgency } from "../parser.js";
|
|
9
|
+
// Load configuration from agency.json
|
|
10
|
+
export function loadConfig(configPath) {
|
|
11
|
+
let config = {};
|
|
12
|
+
// Determine config file path
|
|
13
|
+
const defaultConfigPath = path.join(process.cwd(), "agency.json");
|
|
14
|
+
const finalConfigPath = configPath || defaultConfigPath;
|
|
15
|
+
// Check if config file exists
|
|
16
|
+
if (fs.existsSync(finalConfigPath)) {
|
|
17
|
+
try {
|
|
18
|
+
const configContent = fs.readFileSync(finalConfigPath, "utf-8");
|
|
19
|
+
config = JSON.parse(configContent);
|
|
20
|
+
if (config.verbose) {
|
|
21
|
+
console.log(`Loaded config from ${finalConfigPath}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
console.error(`Error loading config from ${finalConfigPath}:`, error);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return config;
|
|
30
|
+
}
|
|
31
|
+
export function readStdin() {
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
let data = "";
|
|
34
|
+
process.stdin.setEncoding("utf-8");
|
|
35
|
+
process.stdin.on("data", (chunk) => {
|
|
36
|
+
data += chunk;
|
|
37
|
+
});
|
|
38
|
+
process.stdin.on("end", () => {
|
|
39
|
+
resolve(data);
|
|
40
|
+
});
|
|
41
|
+
process.stdin.on("error", (err) => {
|
|
42
|
+
reject(err);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
export function parse(contents, config) {
|
|
47
|
+
const verbose = config.verbose ?? false;
|
|
48
|
+
const parseResult = parseAgency(contents, verbose);
|
|
49
|
+
// Check if parsing was successful
|
|
50
|
+
if (!parseResult.success) {
|
|
51
|
+
console.error("Parse error:");
|
|
52
|
+
console.error(parseResult);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
return parseResult.result;
|
|
56
|
+
}
|
|
57
|
+
export function readFile(inputFile) {
|
|
58
|
+
// Validate input file
|
|
59
|
+
if (!fs.existsSync(inputFile)) {
|
|
60
|
+
console.error(`Error: Input file '${inputFile}' not found`);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
// Read and parse the Agency file
|
|
64
|
+
const contents = fs.readFileSync(inputFile, "utf-8");
|
|
65
|
+
return contents;
|
|
66
|
+
}
|
|
67
|
+
export function renderGraph(contents, config) {
|
|
68
|
+
const parsedProgram = parse(contents, config);
|
|
69
|
+
const preprocessor = new TypescriptPreprocessor(parsedProgram, config);
|
|
70
|
+
preprocessor.preprocess();
|
|
71
|
+
const mermaid = preprocessor.renderMermaid();
|
|
72
|
+
console.log("Program Mermaid Diagram:\n");
|
|
73
|
+
mermaid.forEach((subgraph) => {
|
|
74
|
+
const ascii = renderMermaidAscii(subgraph);
|
|
75
|
+
console.log(ascii);
|
|
76
|
+
});
|
|
77
|
+
console.log("==========");
|
|
78
|
+
mermaid.forEach((subgraph) => {
|
|
79
|
+
console.log(subgraph);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
export function getImports(program) {
|
|
83
|
+
const toolAndNodeImports = program.nodes
|
|
84
|
+
.filter((node) => node.type === "importNodeStatement" ||
|
|
85
|
+
node.type === "importToolStatement")
|
|
86
|
+
.map((node) => node.agencyFile.trim());
|
|
87
|
+
// this makes compile() try to parse non-agency files
|
|
88
|
+
const importStatements = program.nodes
|
|
89
|
+
.filter((node) => node.type === "importStatement" && node.modulePath.endsWith(".agency"))
|
|
90
|
+
.map((node) => node.modulePath.trim());
|
|
91
|
+
return [...toolAndNodeImports, ...importStatements];
|
|
92
|
+
}
|
|
93
|
+
const compiledFiles = new Set();
|
|
94
|
+
const dirSearched = new Set();
|
|
95
|
+
export function compile(config, inputFile, _outputFile) {
|
|
96
|
+
// Check if the input is a directory
|
|
97
|
+
const stats = fs.statSync(inputFile);
|
|
98
|
+
const verbose = config.verbose ?? false;
|
|
99
|
+
if (stats.isDirectory()) {
|
|
100
|
+
dirSearched.add(path.resolve(inputFile));
|
|
101
|
+
// Find all .agency files in the directory
|
|
102
|
+
const files = fs.readdirSync(inputFile);
|
|
103
|
+
const agencyFiles = files.filter((file) => file.endsWith(".agency"));
|
|
104
|
+
for (const file of agencyFiles) {
|
|
105
|
+
const fullPath = path.join(inputFile, file);
|
|
106
|
+
compile(config, fullPath, undefined);
|
|
107
|
+
}
|
|
108
|
+
// Find all subdirectories and compile their .agency files
|
|
109
|
+
const subdirs = files.filter((file) => {
|
|
110
|
+
const fullPath = path.join(inputFile, file);
|
|
111
|
+
return fs.statSync(fullPath).isDirectory();
|
|
112
|
+
});
|
|
113
|
+
for (const subdir of subdirs) {
|
|
114
|
+
const fullSubdirPath = path.join(inputFile, subdir);
|
|
115
|
+
const resolvedSubdirPath = path.resolve(fullSubdirPath);
|
|
116
|
+
if (!dirSearched.has(resolvedSubdirPath)) {
|
|
117
|
+
compile(config, fullSubdirPath, undefined);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
// Resolve the absolute path of the input file to avoid duplicates
|
|
123
|
+
const absoluteInputFile = path.resolve(inputFile);
|
|
124
|
+
let outputFile = _outputFile || inputFile.replace(".agency", ".ts");
|
|
125
|
+
if (config.outDir && !_outputFile) {
|
|
126
|
+
const outputDir = path.resolve(config.outDir);
|
|
127
|
+
if (!fs.existsSync(outputDir)) {
|
|
128
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
129
|
+
}
|
|
130
|
+
outputFile = path.join(outputDir, outputFile);
|
|
131
|
+
}
|
|
132
|
+
// Skip if already compiled
|
|
133
|
+
if (compiledFiles.has(absoluteInputFile)) {
|
|
134
|
+
return outputFile;
|
|
135
|
+
}
|
|
136
|
+
compiledFiles.add(absoluteInputFile);
|
|
137
|
+
const contents = readFile(inputFile);
|
|
138
|
+
const parsedProgram = parse(contents, config);
|
|
139
|
+
const imports = getImports(parsedProgram);
|
|
140
|
+
const inputDir = path.dirname(absoluteInputFile);
|
|
141
|
+
for (const importPath of imports) {
|
|
142
|
+
const absPath = path.resolve(inputDir, importPath);
|
|
143
|
+
compile(config, absPath, undefined);
|
|
144
|
+
}
|
|
145
|
+
// Update the import path in the AST to reference the new .ts file
|
|
146
|
+
parsedProgram.nodes.forEach((node) => {
|
|
147
|
+
if (node.type === "importStatement") {
|
|
148
|
+
node.modulePath = node.modulePath.replace(".agency", ".ts");
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
const generatedCode = generateGraph(parsedProgram, config);
|
|
152
|
+
fs.writeFileSync(outputFile, generatedCode, "utf-8");
|
|
153
|
+
console.log(`${inputFile} → ${outputFile}`);
|
|
154
|
+
return outputFile;
|
|
155
|
+
}
|
|
156
|
+
export function run(config, inputFile, outputFile) {
|
|
157
|
+
// Compile the file
|
|
158
|
+
const output = compile(config, inputFile, outputFile);
|
|
159
|
+
if (output === null) {
|
|
160
|
+
console.error("Error: No output file generated.");
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
// Run the generated TypeScript file with Node.js
|
|
164
|
+
console.log(`Running ${output}...`);
|
|
165
|
+
console.log("---");
|
|
166
|
+
const nodeProcess = spawn("node", [output], {
|
|
167
|
+
stdio: "inherit",
|
|
168
|
+
shell: false,
|
|
169
|
+
});
|
|
170
|
+
nodeProcess.on("error", (error) => {
|
|
171
|
+
console.error(`Failed to run ${output}:`, error);
|
|
172
|
+
process.exit(1);
|
|
173
|
+
});
|
|
174
|
+
nodeProcess.on("exit", (code) => {
|
|
175
|
+
if (code !== 0) {
|
|
176
|
+
process.exit(code || 1);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
export async function format(contents, config) {
|
|
181
|
+
const parsedProgram = parse(contents, config);
|
|
182
|
+
const generatedCode = generateAgency(parsedProgram);
|
|
183
|
+
return generatedCode;
|
|
184
|
+
}
|
|
185
|
+
export function formatFile(inputPath, inPlace, config) {
|
|
186
|
+
const stats = fs.statSync(inputPath);
|
|
187
|
+
if (stats.isDirectory()) {
|
|
188
|
+
// Format all .agency files in directory
|
|
189
|
+
const files = fs.readdirSync(inputPath);
|
|
190
|
+
const agencyFiles = files.filter((file) => file.endsWith(".agency"));
|
|
191
|
+
for (const file of agencyFiles) {
|
|
192
|
+
const fullPath = path.join(inputPath, file);
|
|
193
|
+
formatFile(fullPath, inPlace, config);
|
|
194
|
+
}
|
|
195
|
+
// Recursively format subdirectories
|
|
196
|
+
const subdirs = files.filter((file) => {
|
|
197
|
+
const fullPath = path.join(inputPath, file);
|
|
198
|
+
return fs.statSync(fullPath).isDirectory();
|
|
199
|
+
});
|
|
200
|
+
for (const subdir of subdirs) {
|
|
201
|
+
const fullSubdirPath = path.join(inputPath, subdir);
|
|
202
|
+
formatFile(fullSubdirPath, inPlace, config);
|
|
203
|
+
}
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
// Format single file
|
|
207
|
+
const contents = readFile(inputPath);
|
|
208
|
+
const parsedProgram = parse(contents, config);
|
|
209
|
+
const generatedCode = generateAgency(parsedProgram);
|
|
210
|
+
if (inPlace) {
|
|
211
|
+
fs.writeFileSync(inputPath, generatedCode, "utf-8");
|
|
212
|
+
console.log(`Formatted ${inputPath}`);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
console.log(generatedCode);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function evaluate(target?: string, argsFilePath?: string, resultsFilePath?: string): Promise<void>;
|