agency-lang 0.0.91 → 0.0.93

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 (177) hide show
  1. package/dist/lib/backends/agencyGenerator.d.ts +3 -0
  2. package/dist/lib/backends/agencyGenerator.js +83 -39
  3. package/dist/lib/backends/agencyGenerator.test.js +130 -0
  4. package/dist/lib/backends/typescriptBuilder.d.ts +11 -2
  5. package/dist/lib/backends/typescriptBuilder.integration.test.js +50 -0
  6. package/dist/lib/backends/typescriptBuilder.js +282 -103
  7. package/dist/lib/backends/typescriptGenerator/typeToString.js +2 -0
  8. package/dist/lib/backends/typescriptGenerator/typeToZodSchema.d.ts +9 -1
  9. package/dist/lib/backends/typescriptGenerator/typeToZodSchema.js +31 -20
  10. package/dist/lib/cli/bundle.test.js +32 -20
  11. package/dist/lib/cli/commands.js +8 -7
  12. package/dist/lib/cli/debug.js +16 -2
  13. package/dist/lib/cli/doc.js +96 -32
  14. package/dist/lib/cli/doc.test.js +106 -0
  15. package/dist/lib/cli/events.d.ts +1 -0
  16. package/dist/lib/cli/events.js +15 -0
  17. package/dist/lib/cli/events.test.js +95 -0
  18. package/dist/lib/cli/watch.d.ts +4 -0
  19. package/dist/lib/cli/watch.js +101 -0
  20. package/dist/lib/cli/watch.test.d.ts +1 -0
  21. package/dist/lib/cli/watch.test.js +120 -0
  22. package/dist/lib/config.d.ts +12 -0
  23. package/dist/lib/debugger/driver.js +9 -1
  24. package/dist/lib/debugger/driver.test.js +37 -28
  25. package/dist/lib/debugger/testHelpers.d.ts +1 -0
  26. package/dist/lib/debugger/testHelpers.js +1 -0
  27. package/dist/lib/debugger/trace.test.js +40 -5
  28. package/dist/lib/debugger/types.d.ts +3 -0
  29. package/dist/lib/debugger/ui.d.ts +5 -0
  30. package/dist/lib/debugger/ui.js +443 -32
  31. package/dist/lib/debugger/uiState.d.ts +1 -1
  32. package/dist/lib/debugger/uiState.js +2 -2
  33. package/dist/lib/ir/builders.d.ts +7 -2
  34. package/dist/lib/ir/builders.js +7 -4
  35. package/dist/lib/ir/fluent.d.ts +3 -1
  36. package/dist/lib/ir/fluent.js +2 -2
  37. package/dist/lib/ir/prettyPrint.js +7 -3
  38. package/dist/lib/ir/tsIR.d.ts +1 -0
  39. package/dist/lib/parsers/access.test.js +200 -0
  40. package/dist/lib/parsers/assignment.test.js +23 -0
  41. package/dist/lib/parsers/binop.test.js +292 -3
  42. package/dist/lib/parsers/expression.test.js +32 -0
  43. package/dist/lib/parsers/function.test.js +99 -0
  44. package/dist/lib/parsers/literals.test.js +5 -4
  45. package/dist/lib/parsers/multiLineComment.test.js +31 -3
  46. package/dist/lib/parsers/parsers.d.ts +5 -0
  47. package/dist/lib/parsers/parsers.js +160 -36
  48. package/dist/lib/parsers/returnStatement.test.js +5 -3
  49. package/dist/lib/parsers/typeHints.test.js +53 -2
  50. package/dist/lib/preprocessors/typescriptPreprocessor.core.test.js +212 -1
  51. package/dist/lib/preprocessors/typescriptPreprocessor.d.ts +1 -1
  52. package/dist/lib/preprocessors/typescriptPreprocessor.js +55 -35
  53. package/dist/lib/runtime/__tests__/testHelpers.d.ts +8 -0
  54. package/dist/lib/runtime/__tests__/testHelpers.js +46 -0
  55. package/dist/lib/runtime/checkpoint.test.js +2 -22
  56. package/dist/lib/runtime/classReviver.js +10 -4
  57. package/dist/lib/runtime/debugger.js +11 -5
  58. package/dist/lib/runtime/debugger.test.js +13 -31
  59. package/dist/lib/runtime/errors.d.ts +4 -0
  60. package/dist/lib/runtime/errors.js +15 -0
  61. package/dist/lib/runtime/errors.test.js +35 -1
  62. package/dist/lib/runtime/hooks.d.ts +3 -2
  63. package/dist/lib/runtime/hooks.js +9 -1
  64. package/dist/lib/runtime/index.d.ts +10 -6
  65. package/dist/lib/runtime/index.js +7 -5
  66. package/dist/lib/runtime/interrupts.d.ts +4 -8
  67. package/dist/lib/runtime/interrupts.js +37 -59
  68. package/dist/lib/runtime/isDebugger.test.js +4 -3
  69. package/dist/lib/runtime/node.d.ts +2 -1
  70. package/dist/lib/runtime/node.js +38 -10
  71. package/dist/lib/runtime/prompt.js +91 -65
  72. package/dist/lib/runtime/result.d.ts +4 -2
  73. package/dist/lib/runtime/result.js +8 -7
  74. package/dist/lib/runtime/result.test.js +5 -3
  75. package/dist/lib/runtime/revivers/baseReviver.d.ts +7 -0
  76. package/dist/lib/runtime/revivers/baseReviver.js +1 -0
  77. package/dist/lib/runtime/revivers/dateReviver.d.ts +8 -0
  78. package/dist/lib/runtime/revivers/dateReviver.js +21 -0
  79. package/dist/lib/runtime/revivers/errorReviver.d.ts +8 -0
  80. package/dist/lib/runtime/revivers/errorReviver.js +37 -0
  81. package/dist/lib/runtime/revivers/index.d.ts +2 -0
  82. package/dist/lib/runtime/revivers/index.js +44 -0
  83. package/dist/lib/runtime/revivers/mapReviver.d.ts +8 -0
  84. package/dist/lib/runtime/revivers/mapReviver.js +17 -0
  85. package/dist/lib/runtime/revivers/regExpReviver.d.ts +8 -0
  86. package/dist/lib/runtime/revivers/regExpReviver.js +17 -0
  87. package/dist/lib/runtime/revivers/setReviver.d.ts +8 -0
  88. package/dist/lib/runtime/revivers/setReviver.js +17 -0
  89. package/dist/lib/runtime/revivers/urlReviver.d.ts +8 -0
  90. package/dist/lib/runtime/revivers/urlReviver.js +17 -0
  91. package/dist/lib/runtime/rewind.js +3 -2
  92. package/dist/lib/runtime/runner.d.ts +1 -1
  93. package/dist/lib/runtime/runner.js +23 -11
  94. package/dist/lib/runtime/runner.test.js +3 -22
  95. package/dist/lib/runtime/schema.d.ts +9 -0
  96. package/dist/lib/runtime/schema.js +37 -0
  97. package/dist/lib/runtime/schema.test.d.ts +1 -0
  98. package/dist/lib/runtime/schema.test.js +82 -0
  99. package/dist/lib/runtime/state/checkpointStore.d.ts +3 -1
  100. package/dist/lib/runtime/state/checkpointStore.js +18 -10
  101. package/dist/lib/runtime/state/checkpointStore.test.js +1 -17
  102. package/dist/lib/runtime/state/context.d.ts +22 -3
  103. package/dist/lib/runtime/state/context.js +80 -3
  104. package/dist/lib/runtime/state/context.test.js +39 -0
  105. package/dist/lib/runtime/state/globalStore.js +2 -1
  106. package/dist/lib/runtime/state/stateStack.d.ts +2 -2
  107. package/dist/lib/runtime/state/stateStack.js +7 -7
  108. package/dist/lib/runtime/state/stateStack.test.js +2 -2
  109. package/dist/lib/runtime/streaming.js +54 -35
  110. package/dist/lib/runtime/trace/eventLog.d.ts +79 -0
  111. package/dist/lib/runtime/trace/eventLog.js +296 -0
  112. package/dist/lib/runtime/trace/eventLog.test.d.ts +1 -0
  113. package/dist/lib/runtime/trace/eventLog.test.js +944 -0
  114. package/dist/lib/runtime/trace/sinks.d.ts +18 -0
  115. package/dist/lib/runtime/trace/sinks.js +49 -0
  116. package/dist/lib/runtime/trace/sinks.test.d.ts +1 -0
  117. package/dist/lib/runtime/trace/sinks.test.js +79 -0
  118. package/dist/lib/runtime/trace/traceReader.test.js +57 -24
  119. package/dist/lib/runtime/trace/traceWriter.d.ts +19 -3
  120. package/dist/lib/runtime/trace/traceWriter.js +83 -12
  121. package/dist/lib/runtime/trace/traceWriter.test.js +73 -12
  122. package/dist/lib/runtime/trace/types.d.ts +15 -0
  123. package/dist/lib/runtime/utils.js +3 -2
  124. package/dist/lib/templates/backends/typescriptGenerator/imports.d.ts +1 -1
  125. package/dist/lib/templates/backends/typescriptGenerator/imports.js +2 -1
  126. package/dist/lib/typeChecker/checker.js +2 -2
  127. package/dist/lib/typeChecker/inference.js +1 -1
  128. package/dist/lib/types/access.d.ts +8 -0
  129. package/dist/lib/types/binop.d.ts +1 -1
  130. package/dist/lib/types/binop.js +13 -1
  131. package/dist/lib/types/function.d.ts +7 -1
  132. package/dist/lib/types/function.js +14 -1
  133. package/dist/lib/types/graphNode.d.ts +5 -2
  134. package/dist/lib/types/returnStatement.d.ts +1 -1
  135. package/dist/lib/types/schemaExpression.d.ts +6 -0
  136. package/dist/lib/types/schemaExpression.js +1 -0
  137. package/dist/lib/types/typeHints.d.ts +2 -0
  138. package/dist/lib/types.d.ts +7 -4
  139. package/dist/lib/types.js +1 -1
  140. package/dist/lib/utils/node.js +19 -2
  141. package/dist/lib/version.d.ts +1 -1
  142. package/dist/lib/version.js +1 -1
  143. package/dist/scripts/agency.js +29 -5
  144. package/package.json +4 -6
  145. package/stdlib/agent.js +6 -2
  146. package/stdlib/array.agency +1 -3
  147. package/stdlib/array.js +17 -26
  148. package/stdlib/consensus.js +129 -8
  149. package/stdlib/firstValid.js +132 -9
  150. package/stdlib/fs.js +6 -2
  151. package/stdlib/http.js +739 -0
  152. package/stdlib/index.js +2 -2
  153. package/stdlib/lib/syntax.js +75 -0
  154. package/stdlib/lib/ui.js +393 -0
  155. package/stdlib/math.js +6 -2
  156. package/stdlib/object.js +82 -94
  157. package/stdlib/path.js +6 -2
  158. package/stdlib/retry.js +144 -15
  159. package/stdlib/sample.js +128 -7
  160. package/stdlib/shell.js +6 -2
  161. package/stdlib/strategy.js +84 -92
  162. package/stdlib/system.js +6 -2
  163. package/stdlib/ui.agency +95 -0
  164. package/stdlib/ui.js +1716 -0
  165. package/stdlib/weather.js +6 -9
  166. package/dist/lib/agents/agency-agent/subagents/code.js +0 -628
  167. package/dist/lib/agents/agency-agent/subagents/plan.js +0 -445
  168. package/dist/lib/agents/agency-agent/subagents/task.js +0 -557
  169. package/dist/lib/templates/backends/typescriptGenerator/rewindCheckpoint.d.ts +0 -11
  170. package/dist/lib/templates/backends/typescriptGenerator/rewindCheckpoint.js +0 -32
  171. package/dist/lib/templates/backends/typescriptGenerator/traceSetup.d.ts +0 -7
  172. package/dist/lib/templates/backends/typescriptGenerator/traceSetup.js +0 -12
  173. package/dist/lib/types/sentinel.d.ts +0 -11
  174. package/stdlib/_utils.js +0 -51
  175. package/stdlib/lib/process.js +0 -29
  176. package/stdlib/lib/test.js +0 -3
  177. /package/dist/lib/{types/sentinel.js → cli/events.test.d.ts} +0 -0
@@ -82,6 +82,9 @@ export declare class AgencyGenerator {
82
82
  protected processDebuggerStatement(node: DebuggerStatement): string;
83
83
  protected processComment(node: AgencyComment): string;
84
84
  protected processMultiLineComment(node: AgencyMultiLineComment): string;
85
+ protected formatDocComment(node: {
86
+ docComment?: AgencyMultiLineComment;
87
+ }): string;
85
88
  protected processImportStatement(node: ImportStatement): string;
86
89
  protected processImportNameType(node: ImportNameType): string;
87
90
  protected processImportNodeStatement(node: ImportNodeStatement): string;
@@ -196,8 +196,10 @@ export class AgencyGenerator {
196
196
  return this.processClassDefinition(node);
197
197
  case "newExpression":
198
198
  return this.processNewExpression(node);
199
+ case "schemaExpression":
200
+ return `schema(${variableTypeToString(node.typeArg, this.typeAliases)})`;
199
201
  case "regex":
200
- return `/${node.pattern}/${node.flags}`;
202
+ return `re/${node.pattern}/${node.flags}`;
201
203
  default:
202
204
  throw new Error(`Unhandled Agency node type: ${node.type}`);
203
205
  }
@@ -205,6 +207,9 @@ export class AgencyGenerator {
205
207
  needsParensLeft(child, parentOp) {
206
208
  if (child.type !== "binOpExpression")
207
209
  return false;
210
+ // For right-associative ops like **, (2 ** 3) ** 4 needs parens on the left
211
+ if (parentOp === "**")
212
+ return PRECEDENCE[child.operator] <= PRECEDENCE[parentOp];
208
213
  return PRECEDENCE[child.operator] < PRECEDENCE[parentOp];
209
214
  }
210
215
  needsParensRight(child, parentOp) {
@@ -287,7 +292,8 @@ export class AgencyGenerator {
287
292
  this.typeAliases[node.aliasName] = node.aliasedType;
288
293
  const aliasedTypeStr = this.aliasedTypeToString(node.aliasedType);
289
294
  const exportPrefix = node.exported ? "export " : "";
290
- return this.indentStr(`${exportPrefix}type ${node.aliasName} = ${aliasedTypeStr}`);
295
+ return (this.formatDocComment(node) +
296
+ this.indentStr(`${exportPrefix}type ${node.aliasName} = ${aliasedTypeStr}`));
291
297
  }
292
298
  // Assignment and literals
293
299
  processAssignment(node) {
@@ -295,8 +301,9 @@ export class AgencyGenerator {
295
301
  const chainStr = node.accessChain
296
302
  ?.map((ce) => this.processAccessChainElement(ce))
297
303
  .join("") ?? "";
304
+ const bangSuffix = node.validated ? "!" : "";
298
305
  const varName = node.typeHint
299
- ? `${node.variableName}${chainStr}: ${variableTypeToString(node.typeHint, this.typeAliases)}`
306
+ ? `${node.variableName}${chainStr}: ${variableTypeToString(node.typeHint, this.typeAliases)}${bangSuffix}`
300
307
  : `${node.variableName}${chainStr}`;
301
308
  const sharedPrefix = node.shared ? "shared " : "";
302
309
  const declPrefix = node.declKind ? `${node.declKind} ` : "";
@@ -365,19 +372,22 @@ export class AgencyGenerator {
365
372
  : "";
366
373
  if (p.typeHint) {
367
374
  const typeStr = variableTypeToString(p.typeHint, this.typeAliases);
368
- return `${prefix}${p.name}: ${typeStr}${defaultSuffix}`;
375
+ const bang = p.validated ? "!" : "";
376
+ return `${prefix}${p.name}: ${typeStr}${bang}${defaultSuffix}`;
369
377
  }
370
378
  else {
371
379
  return `${prefix}${p.name}${defaultSuffix}`;
372
380
  }
373
381
  })
374
382
  .join(", ");
383
+ const returnTypeBang = node.returnTypeValidated ? "!" : "";
375
384
  const returnTypeStr = node.returnType
376
- ? ": " + variableTypeToString(node.returnType, this.typeAliases)
385
+ ? ": " + variableTypeToString(node.returnType, this.typeAliases) + returnTypeBang
377
386
  : "";
378
387
  let safePrefix = node.safe ? "safe " : "";
379
388
  const exportPrefix = node.exported ? "export " : "";
380
- let result = this.indentStr(`${exportPrefix}${safePrefix}def ${functionName}(${params})${returnTypeStr} {\n`);
389
+ const keyword = node.callback ? "callback" : "def";
390
+ let result = this.indentStr(`${exportPrefix}${safePrefix}${keyword} ${functionName}(${params})${returnTypeStr} {\n`);
381
391
  this.increaseIndent();
382
392
  if (node.docString) {
383
393
  const docLines = [`"""`, ...node.docString.value.split("\n"), `"""`];
@@ -395,7 +405,7 @@ export class AgencyGenerator {
395
405
  result += bodyCode;
396
406
  this.decreaseIndent();
397
407
  result += this.indentStr(`}`);
398
- return tags + result;
408
+ return this.formatDocComment(node) + tags + result;
399
409
  }
400
410
  processFunctionCall(node) {
401
411
  const tags = this.formatAttachedTags(node);
@@ -588,6 +598,8 @@ export class AgencyGenerator {
588
598
  return lines.join("");
589
599
  }
590
600
  processReturnStatement(node) {
601
+ if (!node.value)
602
+ return this.indentStr("return");
591
603
  const valueCode = this.processNode(node.value).trim();
592
604
  return this.indentStr(`return ${valueCode}`);
593
605
  }
@@ -599,8 +611,16 @@ export class AgencyGenerator {
599
611
  return this.indentStr(`//${node.content}`);
600
612
  }
601
613
  processMultiLineComment(node) {
614
+ if (node.isDoc) {
615
+ return this.indentStr(`/**${node.content}*/`);
616
+ }
602
617
  return this.indentStr(`/*${node.content}*/`);
603
618
  }
619
+ formatDocComment(node) {
620
+ if (!node.docComment)
621
+ return "";
622
+ return this.processMultiLineComment(node.docComment) + "\n";
623
+ }
604
624
  processImportStatement(node) {
605
625
  const importedNames = node.importedNames.map((name) => this.processImportNameType(name));
606
626
  const modulePath = node.modulePath.startsWith("std::")
@@ -649,16 +669,26 @@ export class AgencyGenerator {
649
669
  const tags = this.formatAttachedTags(node);
650
670
  const { nodeName, body, parameters } = node;
651
671
  const params = parameters
652
- .map((p) => p.typeHint
653
- ? `${p.name}: ${variableTypeToString(p.typeHint, this.typeAliases)}`
654
- : p.name)
672
+ .map((p) => {
673
+ if (p.typeHint) {
674
+ const bang = p.validated ? "!" : "";
675
+ return `${p.name}: ${variableTypeToString(p.typeHint, this.typeAliases)}${bang}`;
676
+ }
677
+ return p.name;
678
+ })
655
679
  .join(", ");
680
+ const returnTypeBang = node.returnTypeValidated ? "!" : "";
656
681
  const returnTypeStr = node.returnType
657
- ? ": " + variableTypeToString(node.returnType, this.typeAliases)
682
+ ? ": " + variableTypeToString(node.returnType, this.typeAliases) + returnTypeBang
658
683
  : "";
659
684
  const visibilityStr = this.visibilityToString(node.visibility);
660
685
  let result = this.indentStr(`${visibilityStr}node ${nodeName}(${params})${returnTypeStr} {\n`);
661
686
  this.increaseIndent();
687
+ if (node.docString) {
688
+ const docLines = [`"""`, ...node.docString.value.split("\n"), `"""`];
689
+ const docStr = docLines.map((line) => this.indentStr(line)).join("\n");
690
+ result += `${docStr}\n`;
691
+ }
662
692
  const lines = [];
663
693
  for (const stmt of body) {
664
694
  lines.push(this.processNode(stmt));
@@ -670,7 +700,7 @@ export class AgencyGenerator {
670
700
  result += bodyCode;
671
701
  this.decreaseIndent();
672
702
  result += this.indentStr(`}`);
673
- return tags + result;
703
+ return this.formatDocComment(node) + tags + result;
674
704
  }
675
705
  processClassDefinition(node) {
676
706
  const extendsStr = node.parentClass ? ` extends ${node.parentClass}` : "";
@@ -683,9 +713,13 @@ export class AgencyGenerator {
683
713
  // Methods (constructor is auto-generated, not formatted)
684
714
  for (const method of node.methods) {
685
715
  const params = method.parameters
686
- .map((p) => p.typeHint
687
- ? `${p.name}: ${variableTypeToString(p.typeHint, this.typeAliases)}`
688
- : p.name)
716
+ .map((p) => {
717
+ if (p.typeHint) {
718
+ const bang = p.validated ? "!" : "";
719
+ return `${p.name}: ${variableTypeToString(p.typeHint, this.typeAliases)}${bang}`;
720
+ }
721
+ return p.name;
722
+ })
689
723
  .join(", ");
690
724
  const returnTypeStr = `: ${variableTypeToString(method.returnType, this.typeAliases)}`;
691
725
  result +=
@@ -747,8 +781,9 @@ export class AgencyGenerator {
747
781
  .trimEnd() + "\n";
748
782
  let handlerStr;
749
783
  if (node.handler.kind === "inline") {
784
+ const handlerBang = node.handler.param.validated ? "!" : "";
750
785
  const paramStr = node.handler.param.typeHint
751
- ? `${node.handler.param.name}: ${variableTypeToString(node.handler.param.typeHint, this.typeAliases)}`
786
+ ? `${node.handler.param.name}: ${variableTypeToString(node.handler.param.typeHint, this.typeAliases)}${handlerBang}`
752
787
  : node.handler.param.name;
753
788
  this.increaseIndent();
754
789
  const handlerBodyCodes = [];
@@ -771,35 +806,44 @@ export class AgencyGenerator {
771
806
  return this.indentStr(`skill "${node.filepath}"`);
772
807
  }
773
808
  processBinOpExpression(node, assigned = false) {
774
- // Collect a chain of the same operator (e.g. a |> b |> c)
775
809
  const op = node.operator;
776
- const parts = [];
777
- let current = node;
778
- while (current.type === "binOpExpression" && current.operator === op) {
779
- parts.push(this.processNode(current.right).trim());
780
- current = current.left;
781
- }
782
- parts.push(this.processNode(current).trim());
783
- parts.reverse();
784
- const oneLine = parts.join(` ${op} `);
785
- const multiLine = oneLine.length <= 60
786
- ? oneLine
787
- : parts[0] +
788
- "\n" +
789
- parts
790
- .slice(1)
791
- .map((p) => this.indentStr(`${op} ${p}`))
792
- .join("\n");
793
- return assigned ? multiLine : this.indentStr(multiLine);
810
+ // Unary prefix operators: !x, typeof x, void x
811
+ if (op === "!" || op === "typeof" || op === "void") {
812
+ const operand = this.processNode(node.right).trim();
813
+ const sep = op === "!" ? "" : " ";
814
+ const result = `${op}${sep}${operand}`;
815
+ return assigned ? result : this.indentStr(result);
816
+ }
817
+ // Postfix operators: x++, x--
818
+ if (op === "++" || op === "--") {
819
+ const operand = this.processNode(node.left).trim();
820
+ const result = `${operand}${op}`;
821
+ return assigned ? result : this.indentStr(result);
822
+ }
823
+ const leftStr = this.processNode(node.left).trim();
824
+ const rightStr = this.processNode(node.right).trim();
825
+ const left = this.needsParensLeft(node.left, op) ? `(${leftStr})` : leftStr;
826
+ const right = this.needsParensRight(node.right, op) ? `(${rightStr})` : rightStr;
827
+ const result = `${left} ${op} ${right}`;
828
+ return assigned ? result : this.indentStr(result);
794
829
  }
795
830
  processAccessChainElement(node) {
831
+ const dot = node.optional ? "?." : ".";
796
832
  switch (node.kind) {
797
833
  case "property":
798
- return `.${node.name}`;
799
- case "index":
800
- return `[${this.processNode(node.index).trim()}]`;
834
+ return `${dot}${node.name}`;
835
+ case "index": {
836
+ const inner = this.processNode(node.index).trim();
837
+ return node.optional ? `?.[${inner}]` : `[${inner}]`;
838
+ }
839
+ case "slice": {
840
+ const start = node.start ? this.processNode(node.start).trim() : "";
841
+ const end = node.end ? this.processNode(node.end).trim() : "";
842
+ const inner = `${start}:${end}`;
843
+ return node.optional ? `?.[${inner}]` : `[${inner}]`;
844
+ }
801
845
  case "methodCall":
802
- return `.${this.generateFunctionCallExpression(node.functionCall, "valueAccess")}`;
846
+ return `${dot}${this.generateFunctionCallExpression(node.functionCall, "valueAccess")}`;
803
847
  default:
804
848
  throw new Error(`Unknown access chain element kind: ${node.kind}`);
805
849
  }
@@ -239,4 +239,134 @@ describe("AgencyGenerator - Class Definitions", () => {
239
239
  const output = formatAgency(input);
240
240
  expect(output).toContain("new Counter(0)");
241
241
  });
242
+ it("should format callback declarations with the callback keyword", () => {
243
+ const input = `callback onLLMCallEnd(data) {
244
+ log(data)
245
+ }`;
246
+ const output = formatAgency(input);
247
+ expect(output).toContain("callback onLLMCallEnd(data)");
248
+ expect(output).not.toContain("def onLLMCallEnd");
249
+ });
250
+ });
251
+ describe("AgencyGenerator - Doc Comments", () => {
252
+ function formatAgency(input) {
253
+ const parseResult = parseAgency(input, {}, false);
254
+ expect(parseResult.success).toBe(true);
255
+ if (!parseResult.success)
256
+ return "";
257
+ const generator = new AgencyGenerator();
258
+ return generator.generate(parseResult.result).output.trim();
259
+ }
260
+ it("should preserve /** syntax for doc comments", () => {
261
+ const input = `/** This is a doc comment */\ndef foo() {\n print("hi")\n}`;
262
+ const output = formatAgency(input);
263
+ expect(output).toContain("/** This is a doc comment */");
264
+ });
265
+ it("should preserve /* syntax for regular multi-line comments", () => {
266
+ const input = `/* This is a regular comment */\ndef foo() {\n print("hi")\n}`;
267
+ const output = formatAgency(input);
268
+ expect(output).toContain("/* This is a regular comment */");
269
+ expect(output).not.toContain("/**");
270
+ });
271
+ it("should preserve multi-line doc comments", () => {
272
+ const input = `/**\nThis is a multi-line\ndoc comment\n*/\ndef foo() {\n print("hi")\n}`;
273
+ const output = formatAgency(input);
274
+ expect(output).toContain("/**");
275
+ expect(output).toContain("This is a multi-line");
276
+ });
277
+ it("should round-trip node docstrings", () => {
278
+ const input = `node main() {\n """Main entry point."""\n print("hello")\n}`;
279
+ const output = formatAgency(input);
280
+ expect(output).toContain('"""');
281
+ expect(output).toContain("Main entry point.");
282
+ });
283
+ });
284
+ describe("AgencyGenerator - bang (!) validated type annotations", () => {
285
+ function formatAgency(input) {
286
+ const parseResult = parseAgency(input, {}, false);
287
+ expect(parseResult.success).toBe(true);
288
+ if (!parseResult.success)
289
+ return "";
290
+ const generator = new AgencyGenerator();
291
+ return generator.generate(parseResult.result).output.trim();
292
+ }
293
+ it("should preserve ! on assignment type annotations", () => {
294
+ const input = `node main() {\n const x: number! = 42\n}`;
295
+ const output = formatAgency(input);
296
+ expect(output).toContain("const x: number! = 42");
297
+ });
298
+ it("should preserve ! on function parameter types", () => {
299
+ const input = `def process(data: number!) {\n print(data)\n}`;
300
+ const output = formatAgency(input);
301
+ expect(output).toContain("data: number!");
302
+ });
303
+ it("should preserve ! on function return types", () => {
304
+ const input = `def process(x: number): string! {\n return x\n}`;
305
+ const output = formatAgency(input);
306
+ expect(output).toContain("): string!");
307
+ });
308
+ it("should preserve ! on node return types", () => {
309
+ const input = `node main(): number! {\n return 42\n}`;
310
+ const output = formatAgency(input);
311
+ expect(output).toContain("(): number!");
312
+ });
313
+ it("should not add ! when not present", () => {
314
+ const input = `node main() {\n const x: number = 42\n}`;
315
+ const output = formatAgency(input);
316
+ expect(output).toContain("const x: number = 42");
317
+ expect(output).not.toContain("number!");
318
+ });
319
+ });
320
+ describe("AgencyGenerator - Result type formatting", () => {
321
+ function formatAgency(input) {
322
+ const parseResult = parseAgency(input, {}, false);
323
+ expect(parseResult.success).toBe(true);
324
+ if (!parseResult.success)
325
+ return "";
326
+ const generator = new AgencyGenerator();
327
+ return generator.generate(parseResult.result).output.trim();
328
+ }
329
+ it("should format Result<Foo> with single type param", () => {
330
+ const input = `def check(): Result<number> {\n return success(42)\n}`;
331
+ const output = formatAgency(input);
332
+ expect(output).toContain("Result<number>");
333
+ expect(output).not.toContain("Result<number,");
334
+ });
335
+ it("should format bare Result without type params", () => {
336
+ const input = `def check(): Result {\n return success(42)\n}`;
337
+ const output = formatAgency(input);
338
+ expect(output).toContain(": Result");
339
+ expect(output).not.toContain("Result<");
340
+ });
341
+ it("should format Result<Foo, Bar> with non-default failure type", () => {
342
+ const input = `def check(): Result<number, number> {\n return success(42)\n}`;
343
+ const output = formatAgency(input);
344
+ expect(output).toContain("Result<number, number>");
345
+ });
346
+ it("should normalize Result<Foo, string> to Result<Foo>", () => {
347
+ const input = `def check(): Result<number, string> {\n return success(42)\n}`;
348
+ const output = formatAgency(input);
349
+ expect(output).toContain("Result<number>");
350
+ expect(output).not.toContain("Result<number, string>");
351
+ });
352
+ });
353
+ describe("AgencyGenerator - schema(Type) expressions", () => {
354
+ function formatAgency(input) {
355
+ const parseResult = parseAgency(input, {}, false);
356
+ expect(parseResult.success).toBe(true);
357
+ if (!parseResult.success)
358
+ return "";
359
+ const generator = new AgencyGenerator();
360
+ return generator.generate(parseResult.result).output.trim();
361
+ }
362
+ it("should format schema(number)", () => {
363
+ const input = `node main() {\n const s = schema(number)\n}`;
364
+ const output = formatAgency(input);
365
+ expect(output).toContain("schema(number)");
366
+ });
367
+ it("should format schema(Result<number>)", () => {
368
+ const input = `node main() {\n const s = schema(Result<number>)\n}`;
369
+ const output = formatAgency(input);
370
+ expect(output).toContain("schema(Result<number>)");
371
+ });
242
372
  });
@@ -24,7 +24,7 @@ export declare class TypeScriptBuilder {
24
24
  /** Tracks the current substep nesting path. Empty when at the top level
25
25
  * of a stepped body. Non-empty when inside a block (if/else, etc.) that
26
26
  * has been broken into substeps. Used to generate unique variable names
27
- * like __substep_3_1 for nested blocks. */
27
+ * like __substep_3.1 for nested blocks. */
28
28
  private _subStepPath;
29
29
  private _sourceMapBuilder;
30
30
  private programInfo;
@@ -49,6 +49,11 @@ export declare class TypeScriptBuilder {
49
49
  * emits a normal `lhs = rhs` assignment.
50
50
  */
51
51
  private scopedAssign;
52
+ /**
53
+ * arr[1:3] = [10, 20] → arr.splice(start, end - start, ...value)
54
+ * arr[2:] = [10] → arr.splice(start, arr.length - start, ...value)
55
+ */
56
+ private buildSliceAssignment;
52
57
  private currentScopeKey;
53
58
  /** Returns the name of the current scope (function, node, or block name, or empty string for global). */
54
59
  private currentScopeName;
@@ -63,6 +68,7 @@ export declare class TypeScriptBuilder {
63
68
  private isImpureImportedFunction;
64
69
  private containsImpureCall;
65
70
  private getScopeReturnType;
71
+ private getScopeReturnTypeValidated;
66
72
  private agencyFileToDefaultImportName;
67
73
  private needsParensLeft;
68
74
  private needsParensRight;
@@ -105,6 +111,7 @@ export declare class TypeScriptBuilder {
105
111
  private processPipeExpression;
106
112
  private processTryExpression;
107
113
  private processNewExpression;
114
+ private processSchemaExpression;
108
115
  /**
109
116
  * Check if a method name matches any method defined on any known Agency class.
110
117
  * Used to decide whether to inject __state into method calls.
@@ -157,8 +164,11 @@ export declare class TypeScriptBuilder {
157
164
  private processForkCall;
158
165
  private generateNodeCallExpression;
159
166
  private processGraphNode;
167
+ /** If the enclosing function/node has returnTypeValidated, wrap value in __validateType */
168
+ private maybeWrapReturnValidation;
160
169
  private processReturnStatement;
161
170
  private processAssignment;
171
+ private _processAssignmentInner;
162
172
  private buildAccessChain;
163
173
  private buildAssignmentLhs;
164
174
  /**
@@ -167,7 +177,6 @@ export declare class TypeScriptBuilder {
167
177
  * response format from type hints, and tools from config object.
168
178
  */
169
179
  private processLlmCall;
170
- private processSentinel;
171
180
  private processDebuggerStatement;
172
181
  private processMessageThread;
173
182
  private processBlockPlain;
@@ -213,3 +213,53 @@ ${safeKeyword}def ${funcName}(id: string, shouldSave: boolean, items: string[]):
213
213
  }
214
214
  });
215
215
  });
216
+ describe("schema(Type) expression", () => {
217
+ it("should compile schema(Type) for named type aliases", () => {
218
+ expect(() => generateWithBuilder(`
219
+ type Category = "bug" | "feature"
220
+ node main() {
221
+ const s = schema(Category)
222
+ }
223
+ `)).not.toThrow();
224
+ });
225
+ it("should compile schema(Type) for builtin types", () => {
226
+ expect(() => generateWithBuilder(`
227
+ node main() {
228
+ const s = schema(number)
229
+ }
230
+ `)).not.toThrow();
231
+ });
232
+ it("should compile schema(Result<number>)", () => {
233
+ expect(() => generateWithBuilder(`
234
+ node main() {
235
+ const s = schema(Result<number>)
236
+ }
237
+ `)).not.toThrow();
238
+ });
239
+ it("generated code contains new Schema(...)", () => {
240
+ const output = generateWithBuilder(`
241
+ type Category = "bug" | "feature"
242
+ node main() {
243
+ const s = schema(Category)
244
+ }
245
+ `);
246
+ expect(output).toContain("new Schema(");
247
+ });
248
+ });
249
+ import { mapTypeToValidationSchema } from "./typescriptGenerator/typeToZodSchema.js";
250
+ describe("mapTypeToValidationSchema", () => {
251
+ it("generates Result validation schema for bare Result", () => {
252
+ const schema = mapTypeToValidationSchema({ type: "resultType", successType: { type: "primitiveType", value: "any" }, failureType: { type: "primitiveType", value: "any" } }, {});
253
+ expect(schema).toContain("z.literal(true)");
254
+ expect(schema).toContain("z.literal(false)");
255
+ });
256
+ it("generates Result validation schema with typed success", () => {
257
+ const schema = mapTypeToValidationSchema({ type: "resultType", successType: { type: "primitiveType", value: "number" }, failureType: { type: "primitiveType", value: "string" } }, {});
258
+ expect(schema).toContain("z.number()");
259
+ expect(schema).toContain("z.literal(true)");
260
+ });
261
+ it("delegates non-Result types to mapTypeToZodSchema", () => {
262
+ const schema = mapTypeToValidationSchema({ type: "primitiveType", value: "number" }, {});
263
+ expect(schema).toBe("z.number()");
264
+ });
265
+ });