agency-lang 0.0.1

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 (76) hide show
  1. package/README.md +7 -0
  2. package/dist/backends/baseGenerator.js +194 -0
  3. package/dist/backends/graphGenerator.integration.test.js +119 -0
  4. package/dist/backends/graphGenerator.js +308 -0
  5. package/dist/backends/index.js +3 -0
  6. package/dist/backends/typescriptGenerator/builtins.js +46 -0
  7. package/dist/backends/typescriptGenerator/typeToString.js +36 -0
  8. package/dist/backends/typescriptGenerator/typeToZodSchema.js +54 -0
  9. package/dist/backends/typescriptGenerator.integration.test.js +119 -0
  10. package/dist/backends/typescriptGenerator.js +340 -0
  11. package/dist/backends/typescriptGenerator.test.js +763 -0
  12. package/dist/backends/utils.js +6 -0
  13. package/dist/generate-graph-file.js +25 -0
  14. package/dist/generate-ts-file.js +26 -0
  15. package/dist/index.js +3 -0
  16. package/dist/parser.js +38 -0
  17. package/dist/parser.test.js +306 -0
  18. package/dist/parsers/access.js +19 -0
  19. package/dist/parsers/access.test.js +929 -0
  20. package/dist/parsers/assignment.js +8 -0
  21. package/dist/parsers/body.test.js +106 -0
  22. package/dist/parsers/comment.js +6 -0
  23. package/dist/parsers/comment.test.js +100 -0
  24. package/dist/parsers/dataStructures.js +14 -0
  25. package/dist/parsers/dataStructures.test.js +660 -0
  26. package/dist/parsers/function.js +22 -0
  27. package/dist/parsers/function.test.js +591 -0
  28. package/dist/parsers/functionCall.js +10 -0
  29. package/dist/parsers/functionCall.test.js +119 -0
  30. package/dist/parsers/importStatement.js +3 -0
  31. package/dist/parsers/importStatement.test.js +290 -0
  32. package/dist/parsers/literals.js +12 -0
  33. package/dist/parsers/literals.test.js +639 -0
  34. package/dist/parsers/matchBlock.js +24 -0
  35. package/dist/parsers/matchBlock.test.js +506 -0
  36. package/dist/parsers/parserUtils.js +2 -0
  37. package/dist/parsers/returnStatement.js +8 -0
  38. package/dist/parsers/tools.js +3 -0
  39. package/dist/parsers/tools.test.js +170 -0
  40. package/dist/parsers/typeHints.js +59 -0
  41. package/dist/parsers/typeHints.test.js +2754 -0
  42. package/dist/parsers/utils.js +5 -0
  43. package/dist/parsers/whileLoop.test.js +342 -0
  44. package/dist/templates/backends/graphGenerator/builtinTools.js +36 -0
  45. package/dist/templates/backends/graphGenerator/conditionalEdge.js +10 -0
  46. package/dist/templates/backends/graphGenerator/edge.js +10 -0
  47. package/dist/templates/backends/graphGenerator/goToNode.js +9 -0
  48. package/dist/templates/backends/graphGenerator/graphNode.js +15 -0
  49. package/dist/templates/backends/graphGenerator/imports.js +47 -0
  50. package/dist/templates/backends/graphGenerator/node.js +18 -0
  51. package/dist/templates/backends/graphGenerator/promptNode.js +16 -0
  52. package/dist/templates/backends/graphGenerator/startNode.js +10 -0
  53. package/dist/templates/backends/typescriptGenerator/builtinFunctions/fetch.js +17 -0
  54. package/dist/templates/backends/typescriptGenerator/builtinFunctions/fetchJSON.js +17 -0
  55. package/dist/templates/backends/typescriptGenerator/builtinFunctions/input.js +21 -0
  56. package/dist/templates/backends/typescriptGenerator/builtinFunctions/read.js +13 -0
  57. package/dist/templates/backends/typescriptGenerator/builtinTools.js +36 -0
  58. package/dist/templates/backends/typescriptGenerator/functionDefinition.js +11 -0
  59. package/dist/templates/backends/typescriptGenerator/imports.js +25 -0
  60. package/dist/templates/backends/typescriptGenerator/promptFunction.js +76 -0
  61. package/dist/templates/backends/typescriptGenerator/tool.js +23 -0
  62. package/dist/templates/backends/typescriptGenerator/toolCall.js +35 -0
  63. package/dist/types/access.js +1 -0
  64. package/dist/types/dataStructures.js +1 -0
  65. package/dist/types/function.js +1 -0
  66. package/dist/types/graphNode.js +1 -0
  67. package/dist/types/importStatement.js +1 -0
  68. package/dist/types/literals.js +1 -0
  69. package/dist/types/matchBlock.js +1 -0
  70. package/dist/types/returnStatement.js +1 -0
  71. package/dist/types/tools.js +1 -0
  72. package/dist/types/typeHints.js +1 -0
  73. package/dist/types/whileLoop.js +1 -0
  74. package/dist/types.js +11 -0
  75. package/dist/utils.js +18 -0
  76. package/package.json +52 -0
package/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # Agency
2
+ Agent Definition Language
3
+
4
+ ## troubleshooting
5
+ ### Weird undefined error
6
+
7
+ A couple of times, I have tried to import a parser, and even though it exists, when I import it, the value that is `undefined`. This is due to a circular dependency issue. If I move that parser to its own file and then import it, it works.
@@ -0,0 +1,194 @@
1
+ export class BaseGenerator {
2
+ typeHints = {};
3
+ graphNodes = [];
4
+ generatedStatements = [];
5
+ generatedTypeAliases = [];
6
+ functionScopedVariables = [];
7
+ // collect tools for a prompt
8
+ toolsUsed = [];
9
+ typeAliases = {};
10
+ // collect functions used to see what builtin helpers to include
11
+ functionsUsed = new Set();
12
+ importStatements = [];
13
+ // collect function signatures so we can implement named args
14
+ functionSignatures = {};
15
+ constructor() { }
16
+ generate(program) {
17
+ // Pass 1: Collect all type aliases
18
+ for (const node of program.nodes) {
19
+ if (node.type === "typeAlias") {
20
+ this.processTypeAlias(node);
21
+ }
22
+ }
23
+ // Pass 2: Collect all type hints
24
+ for (const node of program.nodes) {
25
+ if (node.type === "typeHint") {
26
+ this.processTypeHint(node);
27
+ }
28
+ }
29
+ // Pass 3: Collect all node names
30
+ for (const node of program.nodes) {
31
+ if (node.type === "graphNode") {
32
+ this.processGraphNodeName(node);
33
+ }
34
+ }
35
+ // Pass 4: Generate code for tools
36
+ for (const node of program.nodes) {
37
+ if (node.type === "function") {
38
+ this.generatedStatements.push(this.processTool(node));
39
+ this.collectFunctionSignature(node);
40
+ }
41
+ }
42
+ // Pass 5: Process all nodes and generate code
43
+ for (const node of program.nodes) {
44
+ const result = this.processNode(node);
45
+ this.generatedStatements.push(result);
46
+ }
47
+ const output = [];
48
+ output.push(this.preprocess() + "\n");
49
+ output.push(this.importStatements.join("\n") + "\n");
50
+ output.push(this.generateImports() + "\n");
51
+ output.push(this.generateBuiltins() + "\n");
52
+ output.push("\n");
53
+ output.push(...this.generatedTypeAliases);
54
+ output.push(this.generatedStatements.join(""));
55
+ output.push(this.postprocess() + "\n");
56
+ return {
57
+ output: output.filter(Boolean).join("\n"),
58
+ };
59
+ }
60
+ generateBuiltins() {
61
+ return "";
62
+ }
63
+ processTypeAlias(node) {
64
+ // subclasses implement this
65
+ return "";
66
+ }
67
+ processTypeHint(node) {
68
+ // subclasses implement this
69
+ return "";
70
+ }
71
+ collectFunctionSignature(node) {
72
+ this.functionSignatures[node.functionName] = node.parameters;
73
+ }
74
+ processGraphNodeName(node) { }
75
+ processNode(node) {
76
+ switch (node.type) {
77
+ case "typeHint":
78
+ return this.processTypeHint(node);
79
+ case "typeAlias":
80
+ return this.processTypeAlias(node);
81
+ case "assignment":
82
+ return this.processAssignment(node);
83
+ case "function":
84
+ return this.processFunctionDefinition(node);
85
+ case "functionCall":
86
+ return this.processFunctionCall(node);
87
+ case "accessExpression":
88
+ return this.processAccessExpression(node);
89
+ case "comment":
90
+ return this.processComment(node);
91
+ case "matchBlock":
92
+ return this.processMatchBlock(node);
93
+ case "number":
94
+ case "string":
95
+ case "variableName":
96
+ case "prompt":
97
+ // Standalone literals at top level
98
+ return this.generateLiteral(node);
99
+ case "returnStatement":
100
+ return this.processReturnStatement(node);
101
+ case "agencyArray":
102
+ return this.processAgencyArray(node);
103
+ case "agencyObject":
104
+ return this.processAgencyObject(node);
105
+ case "graphNode":
106
+ return this.processGraphNode(node);
107
+ case "usesTool":
108
+ return this.processUsesTool(node);
109
+ case "importStatement":
110
+ this.importStatements.push(this.processImportStatement(node));
111
+ return "";
112
+ case "whileLoop":
113
+ return this.processWhileLoop(node);
114
+ default:
115
+ throw new Error(`Unhandled Agency node type: ${node.type}`);
116
+ }
117
+ }
118
+ processWhileLoop(node) {
119
+ return "processWhileLoop not implemented";
120
+ }
121
+ processImportStatement(node) {
122
+ return "processImportStatement not implemented";
123
+ }
124
+ processTool(node) {
125
+ return "processTool not implemented";
126
+ }
127
+ processUsesTool(node) {
128
+ return "processUsesTool not implemented";
129
+ }
130
+ processGraphNode(node) {
131
+ return "processGraphNode not implemented";
132
+ }
133
+ processAgencyObject(node) {
134
+ return "<processAgencyObject not implemented>";
135
+ }
136
+ processAgencyArray(node) {
137
+ return "<processAgencyArray not implemented>";
138
+ }
139
+ processComment(node) {
140
+ return "processComment not implemented";
141
+ }
142
+ processReturnStatement(node) {
143
+ return "processReturnStatement not implemented";
144
+ }
145
+ processAccessExpression(node) {
146
+ switch (node.expression.type) {
147
+ case "dotProperty":
148
+ return this.processDotProperty(node.expression);
149
+ case "indexAccess":
150
+ return this.processIndexAccess(node.expression);
151
+ case "dotFunctionCall":
152
+ return this.processDotFunctionCall(node.expression);
153
+ }
154
+ }
155
+ processMatchBlock(node) {
156
+ return "processMatchBlock not implemented";
157
+ }
158
+ processDotProperty(node) {
159
+ return "processDotProperty not implemented";
160
+ }
161
+ processDotFunctionCall(node) {
162
+ return "processDotFunctionCall not implemented";
163
+ }
164
+ processIndexAccess(node) {
165
+ return "processIndexAccess not implemented";
166
+ }
167
+ processAssignment(node) {
168
+ return "processAssignment not implemented";
169
+ }
170
+ processPromptLiteral(variableName, node) {
171
+ return "processPromptLiteral not implemented";
172
+ }
173
+ processFunctionDefinition(node) {
174
+ return "processFunctionDefinition not implemented";
175
+ }
176
+ processFunctionCall(node) {
177
+ return "processFunctionCall not implemented";
178
+ }
179
+ generateFunctionCallExpression(node) {
180
+ return "generateFunctionCallExpression not implemented";
181
+ }
182
+ generateLiteral(literal) {
183
+ return "generateLiteral not implemented";
184
+ }
185
+ generateImports() {
186
+ return "generateImports not implemented";
187
+ }
188
+ preprocess() {
189
+ return "";
190
+ }
191
+ postprocess() {
192
+ return "";
193
+ }
194
+ }
@@ -0,0 +1,119 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { parseAgency } from "../parser.js";
3
+ import { generateGraph } from "./graphGenerator.js";
4
+ import fs from "fs";
5
+ import path from "path";
6
+ /**
7
+ * Recursively discovers all .agency/.mts fixture pairs in a directory
8
+ */
9
+ function discoverFixtures(fixtureDir) {
10
+ const fixtures = [];
11
+ function scanDirectory(dir, relativePath = "") {
12
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
13
+ for (const entry of entries) {
14
+ const fullPath = path.join(dir, entry.name);
15
+ const relPath = relativePath
16
+ ? `${relativePath}/${entry.name}`
17
+ : entry.name;
18
+ if (entry.isDirectory()) {
19
+ // Recursively scan subdirectories
20
+ scanDirectory(fullPath, relPath);
21
+ }
22
+ else if (entry.isFile() && entry.name.endsWith(".agency")) {
23
+ // Found an Agency file - look for corresponding .mts
24
+ const baseName = entry.name.replace(".agency", "");
25
+ const mtsPath = path.join(dir, `${baseName}.mts`);
26
+ if (fs.existsSync(mtsPath)) {
27
+ const nameWithoutExt = relativePath
28
+ ? `${relativePath}/${baseName}`
29
+ : baseName;
30
+ try {
31
+ fixtures.push({
32
+ name: nameWithoutExt,
33
+ agencyPath: fullPath,
34
+ mtsPath: mtsPath,
35
+ agencyContent: fs.readFileSync(fullPath, "utf-8"),
36
+ expectedGraph: fs.readFileSync(mtsPath, "utf-8"),
37
+ });
38
+ }
39
+ catch (error) {
40
+ console.error(`Cannot read fixture ${fullPath}: ${error instanceof Error ? error.message : String(error)}`);
41
+ }
42
+ }
43
+ else {
44
+ console.warn(`Warning: No corresponding .mts file for ${fullPath}`);
45
+ }
46
+ }
47
+ }
48
+ }
49
+ scanDirectory(fixtureDir);
50
+ return fixtures.sort((a, b) => a.name.localeCompare(b.name));
51
+ }
52
+ /**
53
+ * Normalizes whitespace in generated code for comparison
54
+ * Handles cross-platform line endings and trailing whitespace
55
+ */
56
+ function normalizeWhitespace(code) {
57
+ return (code
58
+ // Normalize line endings to \n
59
+ .replace(/\r\n/g, "\n")
60
+ // Remove trailing whitespace from each line
61
+ .split("\n")
62
+ .map((line) => line.trimEnd())
63
+ .join("\n")
64
+ // Collapse multiple consecutive blank lines to single blank line
65
+ .replace(/\n\n\n+/g, "\n\n")
66
+ // Trim leading/trailing blank lines
67
+ .trim()
68
+ // Ensure single trailing newline
69
+ .concat("\n"));
70
+ }
71
+ const FIXTURES_DIR = path.resolve(__dirname, "../../tests/graphGenerator");
72
+ describe("Graph Generator Integration Tests", () => {
73
+ const fixtures = discoverFixtures(FIXTURES_DIR);
74
+ // Guard against no fixtures found
75
+ if (fixtures.length === 0) {
76
+ it("should find test fixtures", () => {
77
+ expect(fixtures.length).toBeGreaterThan(0);
78
+ });
79
+ }
80
+ describe.each(fixtures)("Fixture: $name", ({ name, agencyPath, mtsPath, agencyContent, expectedGraph }) => {
81
+ it("should generate correct graph output", () => {
82
+ // 1. Parse Agency
83
+ const parseResult = parseAgency(agencyContent);
84
+ // 2. Assert parsing succeeded
85
+ if (!parseResult.success) {
86
+ const errorMessage = [
87
+ `Failed to parse Agency fixture: ${name}`,
88
+ `File: ${agencyPath}`,
89
+ `Error: ${parseResult.message}`,
90
+ ``,
91
+ `Agency Content:`,
92
+ agencyContent,
93
+ ].join("\n");
94
+ throw new Error(errorMessage);
95
+ }
96
+ // 3. Generate graph code
97
+ let generatedGraph;
98
+ try {
99
+ generatedGraph = generateGraph(parseResult.result);
100
+ }
101
+ catch (error) {
102
+ const errorMessage = [
103
+ `Failed to generate graph code for fixture: ${name}`,
104
+ `File: ${agencyPath}`,
105
+ `Error: ${error instanceof Error ? error.message : String(error)}`,
106
+ ``,
107
+ `Parsed AST:`,
108
+ JSON.stringify(parseResult.result, null, 2),
109
+ ].join("\n");
110
+ throw new Error(errorMessage);
111
+ }
112
+ // 4. Normalize and compare
113
+ const normalizedGenerated = normalizeWhitespace(generatedGraph);
114
+ const normalizedExpected = normalizeWhitespace(expectedGraph);
115
+ // 5. Assert equality with helpful diff
116
+ expect(normalizedGenerated).toBe(normalizedExpected);
117
+ });
118
+ });
119
+ });
@@ -0,0 +1,308 @@
1
+ import * as renderConditionalEdge from "../templates/backends/graphGenerator/conditionalEdge.js";
2
+ import * as renderImports from "../templates/backends/graphGenerator/imports.js";
3
+ import * as renderStartNode from "../templates/backends/graphGenerator/startNode.js";
4
+ import * as graphNode from "../templates/backends/graphGenerator/graphNode.js";
5
+ import * as builtinTools from "../templates/backends/graphGenerator/builtinTools.js";
6
+ import * as goToNode from "../templates/backends/graphGenerator/goToNode.js";
7
+ import { TypeScriptGenerator } from "./typescriptGenerator.js";
8
+ import { mapFunctionName } from "./typescriptGenerator/builtins.js";
9
+ export class GraphGenerator extends TypeScriptGenerator {
10
+ typeHints = {};
11
+ generatedStatements = [];
12
+ generatedTypeAliases = [];
13
+ typeAliases = {};
14
+ functionsUsed = new Set();
15
+ adjacentNodes = {};
16
+ currentAdjacentNodes = [];
17
+ isInsideGraphNode = false;
18
+ constructor() {
19
+ super();
20
+ }
21
+ /*
22
+ protected generateBuiltins(): string {
23
+ return "";
24
+ }
25
+
26
+ protected processTypeAlias(node: TypeAlias): void {
27
+ // subclasses implement this
28
+ }
29
+
30
+ protected processTypeHint(node: TypeHint): void {
31
+ // subclasses implement this
32
+ }
33
+
34
+ protected processNode(node: AgencyNode): string {
35
+ switch (node.type) {
36
+ case "typeHint":
37
+ case "typeAlias":
38
+ return "";
39
+ case "assignment":
40
+ return this.processAssignment(node);
41
+ case "function":
42
+ return this.processFunctionDefinition(node);
43
+ case "functionCall":
44
+ return this.processFunctionCall(node);
45
+ case "accessExpression":
46
+ return this.processAccessExpression(node);
47
+ case "comment":
48
+ return this.processComment(node);
49
+ case "matchBlock":
50
+ return this.processMatchBlock(node);
51
+ case "number":
52
+ case "string":
53
+ case "variableName":
54
+ case "prompt":
55
+ // Standalone literals at top level
56
+ return this.generateLiteral(node);
57
+ case "returnStatement":
58
+ return this.processReturnStatement(node);
59
+ case "agencyArray":
60
+ return this.processAgencyArray(node);
61
+ case "agencyObject":
62
+ return this.processAgencyObject(node);
63
+ }
64
+ }
65
+
66
+ protected processAgencyObject(node: AgencyObject): string {
67
+ return "<processAgencyObject not implemented>";
68
+ }
69
+
70
+ protected processAgencyArray(node: AgencyArray): string {
71
+ return "<processAgencyArray not implemented>";
72
+ }
73
+
74
+ protected processComment(node: AgencyComment): string {
75
+ return "processComment not implemented";
76
+ }
77
+
78
+
79
+
80
+ protected processAccessExpression(node: AccessExpression): string {
81
+ switch (node.expression.type) {
82
+ case "dotProperty":
83
+ return this.processDotProperty(node.expression);
84
+ case "indexAccess":
85
+ return this.processIndexAccess(node.expression);
86
+ case "dotFunctionCall":
87
+ return this.processDotFunctionCall(node.expression);
88
+ }
89
+ }
90
+
91
+ protected processMatchBlock(node: MatchBlock): string {
92
+ return "processMatchBlock not implemented";
93
+ }
94
+
95
+ protected processDotProperty(node: DotProperty): string {
96
+ return "processDotProperty not implemented";
97
+ }
98
+
99
+ protected processDotFunctionCall(node: DotFunctionCall): string {
100
+ return "processDotFunctionCall not implemented";
101
+ }
102
+
103
+ protected processIndexAccess(node: IndexAccess): string {
104
+ return "processIndexAccess not implemented";
105
+ } */
106
+ /* protected processAssignment(node: Assignment): string {
107
+ switch (node.value.type) {
108
+ case "prompt":
109
+ return this.processPromptLiteral(node.variableName, node.value);
110
+ default:
111
+ return this.createNode(
112
+ node.variableName,
113
+ this.processNode(wrapInReturn(node.value))
114
+ );
115
+ }
116
+ }
117
+
118
+ protected createNode(name: string, body: string): string {
119
+ this.graphNodes.push(name);
120
+ return renderNode.default({
121
+ name,
122
+ body,
123
+ });
124
+ }
125
+
126
+ protected processPromptLiteral(
127
+ variableName: string,
128
+ node: PromptLiteral
129
+ ): string {
130
+ this.graphNodes.push(variableName);
131
+
132
+ // Validate all interpolated variables are in scope
133
+ const interpolatedVars = node.segments
134
+ .filter((s) => s.type === "interpolation")
135
+ .map((s) => (s as InterpolationSegment).variableName);
136
+
137
+ for (const varName of interpolatedVars) {
138
+ if (!this.graphNodes.includes(varName)) {
139
+ throw new Error(
140
+ `Variable '${varName}' used in prompt interpolation but not defined. ` +
141
+ `Referenced in assignment to '${variableName}'.`
142
+ );
143
+ }
144
+ }
145
+
146
+ const promptFunction = this.generatePromptFunction({
147
+ variableName,
148
+ functionArgs: interpolatedVars,
149
+ prompt: node,
150
+ });
151
+ const argsStr = interpolatedVars.join(", ");
152
+
153
+ return promptNode.default({
154
+ name: variableName,
155
+ promptFunction,
156
+ argsStr,
157
+ });
158
+ }
159
+
160
+ generatePromptFunction({
161
+ variableName,
162
+ functionArgs = [],
163
+ prompt,
164
+ }: {
165
+ variableName: string;
166
+ functionArgs: string[];
167
+ prompt: PromptLiteral;
168
+ }): string {
169
+ // Generate async function for prompt-based assignment
170
+ const variableType = this.typeHints[variableName] || {
171
+ type: "primitiveType" as const,
172
+ value: "string",
173
+ };
174
+
175
+ const zodSchema = mapTypeToZodSchema(variableType, this.typeAliases);
176
+ const typeString = variableTypeToString(variableType, this.typeAliases);
177
+
178
+ // Build prompt construction code
179
+ const promptCode = this.buildPromptString(prompt.segments, this.typeHints);
180
+ const argsStr = functionArgs
181
+ .map(
182
+ (arg) =>
183
+ `${arg}: ${variableTypeToString(
184
+ this.typeHints[arg] || { type: "primitiveType", value: "string" },
185
+ this.typeAliases
186
+ )}`
187
+ )
188
+ .join(", ");
189
+ return promptFunction.default({
190
+ variableName,
191
+ argsStr,
192
+ typeString,
193
+ promptCode,
194
+ zodSchema,
195
+ });
196
+ }
197
+ */
198
+ processReturnStatement(node) {
199
+ if (!this.isInsideGraphNode) {
200
+ return super.processReturnStatement(node);
201
+ }
202
+ else {
203
+ const returnCode = this.processNode(node.value);
204
+ if (node.value.type === "functionCall" &&
205
+ this.graphNodes.includes(node.value.functionName)) {
206
+ // we're going to return a goToNode call, so just return that directly
207
+ return `return ${returnCode}\n`;
208
+ }
209
+ return `return { ...state, data: ${returnCode}}\n`;
210
+ }
211
+ }
212
+ processGraphNodeName(node) {
213
+ this.graphNodes.push(node.nodeName);
214
+ }
215
+ processGraphNode(node) {
216
+ const { nodeName, body, parameters } = node;
217
+ if (parameters.length > 1) {
218
+ throw new Error(`Graph node '${nodeName}' has more than one parameter. Only one parameter is supported for now.`);
219
+ }
220
+ this.adjacentNodes[nodeName] = [];
221
+ this.currentAdjacentNodes = [];
222
+ this.functionScopedVariables = [];
223
+ this.isInsideGraphNode = true;
224
+ if (parameters.length > 0) {
225
+ this.functionScopedVariables.push(parameters[0]);
226
+ }
227
+ const bodyCode = [];
228
+ for (const stmt of body) {
229
+ bodyCode.push(this.processNode(stmt));
230
+ }
231
+ this.functionScopedVariables = [];
232
+ this.adjacentNodes[nodeName] = [...this.currentAdjacentNodes];
233
+ this.isInsideGraphNode = false;
234
+ return graphNode.default({
235
+ name: nodeName,
236
+ body: bodyCode.join("\n"),
237
+ hasParam: parameters.length > 0,
238
+ paramName: parameters[0] || "input",
239
+ });
240
+ }
241
+ processFunctionCall(node) {
242
+ if (this.graphNodes.includes(node.functionName)) {
243
+ this.currentAdjacentNodes.push(node.functionName);
244
+ this.functionsUsed.add(node.functionName);
245
+ const functionCallCode = this.generateNodeCallExpression(node);
246
+ return functionCallCode;
247
+ }
248
+ else {
249
+ return super.processFunctionCall(node);
250
+ }
251
+ }
252
+ generateNodeCallExpression(node) {
253
+ const functionName = mapFunctionName(node.functionName);
254
+ const args = node.arguments;
255
+ const parts = args.map((arg) => {
256
+ if (arg.type === "functionCall") {
257
+ this.functionsUsed.add(arg.functionName);
258
+ return this.generateFunctionCallExpression(arg);
259
+ }
260
+ else if (arg.type === "accessExpression") {
261
+ return this.processAccessExpression(arg);
262
+ }
263
+ else {
264
+ return this.generateLiteral(arg);
265
+ }
266
+ });
267
+ const argsString = parts.join(", ");
268
+ return goToNode.default({
269
+ nodeName: functionName,
270
+ data: argsString,
271
+ });
272
+ } /*
273
+
274
+ protected generateLiteral(literal: Literal): string {
275
+ return "generateLiteral not implemented";
276
+ } */
277
+ generateImports() {
278
+ let arr = [
279
+ renderImports.default({ nodes: JSON.stringify(this.graphNodes) }),
280
+ ];
281
+ arr.push(builtinTools.default({}));
282
+ return arr.join("\n");
283
+ }
284
+ postprocess() {
285
+ const lines = [];
286
+ Object.keys(this.adjacentNodes).forEach((node) => {
287
+ const adjacent = this.adjacentNodes[node];
288
+ if (adjacent.length === 0) {
289
+ return;
290
+ }
291
+ lines.push(renderConditionalEdge.default({
292
+ fromNode: node,
293
+ toNodes: JSON.stringify(adjacent),
294
+ }));
295
+ });
296
+ if (!this.graphNodes.includes("main")) {
297
+ throw new Error("No entrypoint found for agent: missing 'main' node. Please create a node named 'main'.");
298
+ }
299
+ lines.push(renderStartNode.default({
300
+ startNode: "main",
301
+ }));
302
+ return lines.join("\n");
303
+ }
304
+ }
305
+ export function generateGraph(program) {
306
+ const generator = new GraphGenerator();
307
+ return generator.generate(program).output;
308
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./baseGenerator.js";
2
+ export * from "./typescriptGenerator.js";
3
+ export * from "./graphGenerator.js";
@@ -0,0 +1,46 @@
1
+ import * as builtinFunctionsInput from "../../templates/backends/typescriptGenerator/builtinFunctions/input.js";
2
+ import * as builtinFunctionsRead from "../../templates/backends/typescriptGenerator/builtinFunctions/read.js";
3
+ import * as builtinFunctionsFetchJSON from "../../templates/backends/typescriptGenerator/builtinFunctions/fetchJSON.js";
4
+ import * as builtinFunctionsFetch from "../../templates/backends/typescriptGenerator/builtinFunctions/fetch.js";
5
+ /**
6
+ * Maps Agency built-in function names to TypeScript equivalents
7
+ */
8
+ export const BUILTIN_FUNCTIONS = {
9
+ print: "console.log",
10
+ input: "_builtinInput",
11
+ read: "_builtinRead",
12
+ write: "fs.writeFileSync",
13
+ fetch: "_builtinFetch",
14
+ fetchJSON: "_builtinFetchJSON",
15
+ fetchJson: "_builtinFetchJSON",
16
+ };
17
+ /**
18
+ * Maps an Agency function name to its TypeScript equivalent
19
+ * Returns the original name if not a built-in
20
+ */
21
+ export function mapFunctionName(functionName) {
22
+ return BUILTIN_FUNCTIONS[functionName] || functionName;
23
+ }
24
+ /**
25
+ * Generates helper functions for built-in Agency functions
26
+ */
27
+ export function generateBuiltinHelpers(functionsUsed) {
28
+ const inputFunc = builtinFunctionsInput.default({});
29
+ const readFunc = builtinFunctionsRead.default({});
30
+ const fetchJSONFunc = builtinFunctionsFetchJSON.default({});
31
+ const helpers = [];
32
+ if (functionsUsed.has("input")) {
33
+ helpers.push(inputFunc);
34
+ }
35
+ if (functionsUsed.has("read")) {
36
+ helpers.push(readFunc);
37
+ }
38
+ if (functionsUsed.has("fetchJSON") || functionsUsed.has("fetchJson")) {
39
+ helpers.push(fetchJSONFunc);
40
+ }
41
+ if (functionsUsed.has("fetch")) {
42
+ const fetchFunc = builtinFunctionsFetch.default({});
43
+ helpers.push(fetchFunc);
44
+ }
45
+ return helpers.join("\n\n");
46
+ }