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.
Files changed (67) hide show
  1. package/dist/lib/backends/agencyGenerator.d.ts +2 -0
  2. package/dist/lib/backends/agencyGenerator.js +7 -3
  3. package/dist/lib/backends/baseGenerator.d.ts +2 -1
  4. package/dist/lib/backends/baseGenerator.js +5 -2
  5. package/dist/lib/backends/graphGenerator.js +1 -1
  6. package/dist/lib/backends/typescriptGenerator.d.ts +7 -1
  7. package/dist/lib/backends/typescriptGenerator.js +68 -19
  8. package/dist/lib/cli/commands.d.ts +12 -0
  9. package/dist/lib/cli/commands.js +217 -0
  10. package/dist/lib/cli/evaluate.d.ts +1 -0
  11. package/dist/lib/cli/evaluate.js +204 -0
  12. package/dist/lib/cli/help.d.ts +1 -0
  13. package/dist/lib/cli/help.js +51 -0
  14. package/dist/lib/cli/test.d.ts +2 -0
  15. package/dist/lib/cli/test.js +166 -0
  16. package/dist/lib/cli/util.d.ts +19 -0
  17. package/dist/lib/cli/util.js +132 -0
  18. package/dist/lib/config.d.ts +1 -0
  19. package/dist/lib/config.js +1 -0
  20. package/dist/lib/parser.d.ts +2 -1
  21. package/dist/lib/parser.js +26 -17
  22. package/dist/lib/parsers/function.js +2 -1
  23. package/dist/lib/parsers/importStatement.js +4 -4
  24. package/dist/lib/parsers/importStatement.test.js +82 -35
  25. package/dist/lib/parsers/parserUtils.js +1 -1
  26. package/dist/lib/parsers/skill.d.ts +5 -0
  27. package/dist/lib/parsers/skill.js +20 -0
  28. package/dist/lib/parsers/skill.test.d.ts +1 -0
  29. package/dist/lib/parsers/skill.test.js +338 -0
  30. package/dist/lib/parsers/tools.d.ts +1 -1
  31. package/dist/lib/parsers/tools.js +2 -2
  32. package/dist/lib/parsers/tools.test.js +17 -12
  33. package/dist/lib/parsers/typeHints.js +2 -2
  34. package/dist/lib/parsers/typeHints.test.js +13 -1
  35. package/dist/lib/preprocessors/typescriptPreprocessor.core.test.js +3 -2
  36. package/dist/lib/preprocessors/typescriptPreprocessor.d.ts +5 -9
  37. package/dist/lib/preprocessors/typescriptPreprocessor.js +68 -213
  38. package/dist/lib/templates/backends/graphGenerator/graphNode.d.ts +1 -1
  39. package/dist/lib/templates/backends/graphGenerator/graphNode.js +4 -1
  40. package/dist/lib/templates/backends/graphGenerator/imports.d.ts +1 -1
  41. package/dist/lib/templates/backends/graphGenerator/imports.js +117 -19
  42. package/dist/lib/templates/backends/graphGenerator/runNodeFunction.d.ts +1 -1
  43. package/dist/lib/templates/backends/graphGenerator/runNodeFunction.js +5 -6
  44. package/dist/lib/templates/backends/graphGenerator/specialVar.d.ts +1 -1
  45. package/dist/lib/templates/backends/graphGenerator/specialVar.js +1 -1
  46. package/dist/lib/templates/backends/graphGenerator/startNode.d.ts +1 -1
  47. package/dist/lib/templates/backends/graphGenerator/startNode.js +4 -2
  48. package/dist/lib/templates/backends/typescriptGenerator/imports.d.ts +1 -1
  49. package/dist/lib/templates/backends/typescriptGenerator/imports.js +2 -2
  50. package/dist/lib/templates/backends/typescriptGenerator/promptFunction.d.ts +2 -1
  51. package/dist/lib/templates/backends/typescriptGenerator/promptFunction.js +9 -73
  52. package/dist/lib/templates/backends/typescriptGenerator/tool.d.ts +2 -1
  53. package/dist/lib/templates/backends/typescriptGenerator/tool.js +2 -1
  54. package/dist/lib/templates/backends/typescriptGenerator/toolCall.d.ts +1 -2
  55. package/dist/lib/templates/backends/typescriptGenerator/toolCall.js +5 -3
  56. package/dist/lib/templates/cli/evaluate.d.ts +9 -0
  57. package/dist/lib/templates/cli/evaluate.js +24 -0
  58. package/dist/lib/templates/prompts/skill.d.ts +6 -0
  59. package/dist/lib/templates/prompts/skill.js +14 -0
  60. package/dist/lib/types/literals.d.ts +2 -0
  61. package/dist/lib/types/skill.d.ts +5 -0
  62. package/dist/lib/types/skill.js +1 -0
  63. package/dist/lib/types.d.ts +2 -1
  64. package/dist/lib/utils/node.d.ts +10 -0
  65. package/dist/lib/utils/node.js +208 -0
  66. package/dist/scripts/agency.js +151 -369
  67. 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 { ...state, data: ${returnCode}}\n`;
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: PromptSegment[], typeHints: TypeHintMap): string;
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 (!this.functionDefinitions[toolName]) {
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(prompt.segments, this.typeHints);
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
- const _tools = this.toolsUsed
405
- .map((toolName) => `__${toolName}Tool`)
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
- const functionCalls = this.toolsUsed
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
- const func = this.functionDefinitions[toolName];
411
- if (!func) {
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) => [toolName, `__${toolName}Tool`])
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>;