agency-lang 0.7.0 → 0.7.2

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 (182) hide show
  1. package/dist/lib/agents/agency-agent/agent.agency +169 -28
  2. package/dist/lib/agents/agency-agent/agent.js +579 -152
  3. package/dist/lib/agents/agency-agent/lib/attachments.js +2 -2
  4. package/dist/lib/agents/agency-agent/lib/config.agency +5 -0
  5. package/dist/lib/agents/agency-agent/lib/config.js +11 -0
  6. package/dist/lib/agents/agency-agent/lib/defaultPolicy.agency +106 -0
  7. package/dist/lib/agents/agency-agent/lib/defaultPolicy.js +764 -3
  8. package/dist/lib/agents/agency-agent/lib/modelFilters.js +1 -1
  9. package/dist/lib/agents/agency-agent/lib/resolution.js +4 -4
  10. package/dist/lib/agents/agency-agent/lib/search.js +3 -3
  11. package/dist/lib/agents/agency-agent/lib/settings.js +1 -1
  12. package/dist/lib/agents/agency-agent/lib/utils.js +1 -1
  13. package/dist/lib/agents/agency-agent/shared.agency +22 -0
  14. package/dist/lib/agents/agency-agent/shared.js +160 -3
  15. package/dist/lib/agents/agency-agent/subagents/code.js +1 -1
  16. package/dist/lib/agents/agency-agent/subagents/explorer.js +1 -1
  17. package/dist/lib/agents/agency-agent/subagents/oracle.js +1 -1
  18. package/dist/lib/agents/agency-agent/subagents/research.js +1 -1
  19. package/dist/lib/agents/agency-agent/subagents/review.js +4 -4
  20. package/dist/lib/agents/agency-agent/tests/agentTurn.js +1 -1
  21. package/dist/lib/agents/agency-agent/tests/attachments.js +1 -1
  22. package/dist/lib/agents/agency-agent/tests/attachmentsTurn.js +2 -2
  23. package/dist/lib/agents/agency-agent/tests/gitPolicy.js +3 -3
  24. package/dist/lib/agents/agency-agent/tests/oneShotRounds.agency +20 -0
  25. package/dist/lib/agents/agency-agent/tests/oneShotRounds.js +555 -0
  26. package/dist/lib/agents/agency-agent/tests/oneShotRounds.test.json +9 -0
  27. package/dist/lib/agents/review/agent.js +3 -3
  28. package/dist/lib/cli/doctor.d.ts +8 -0
  29. package/dist/lib/cli/doctor.js +21 -13
  30. package/dist/lib/cli/doctor.test.js +34 -0
  31. package/dist/lib/cli/help.js +1 -5
  32. package/dist/lib/cli/runBundledAgent.d.ts +17 -1
  33. package/dist/lib/cli/runBundledAgent.js +73 -2
  34. package/dist/lib/cli/runBundledAgent.test.d.ts +1 -0
  35. package/dist/lib/cli/runBundledAgent.test.js +96 -0
  36. package/dist/lib/config.d.ts +42 -33
  37. package/dist/lib/config.js +108 -6
  38. package/dist/lib/config.test.js +121 -2
  39. package/dist/lib/ir/prettyPrint.js +25 -4
  40. package/dist/lib/parseCache.js +8 -13
  41. package/dist/lib/parseCache.test.js +5 -8
  42. package/dist/lib/parser.js +5 -12
  43. package/dist/lib/preprocessors/typescriptPreprocessor.d.ts +0 -28
  44. package/dist/lib/preprocessors/typescriptPreprocessor.js +0 -245
  45. package/dist/lib/runtime/configOverrides.d.ts +17 -16
  46. package/dist/lib/runtime/configOverrides.js +27 -16
  47. package/dist/lib/runtime/configOverrides.test.js +116 -2
  48. package/dist/lib/runtime/prompt.js +7 -3
  49. package/dist/lib/runtime/runner.d.ts +2 -2
  50. package/dist/lib/runtime/runner.js +26 -7
  51. package/dist/lib/runtime/state/context.js +9 -2
  52. package/dist/lib/stdlib/llm.d.ts +1 -0
  53. package/dist/lib/stdlib/version.d.ts +1 -1
  54. package/dist/lib/stdlib/version.js +1 -1
  55. package/dist/scripts/agency.d.ts +2 -0
  56. package/dist/scripts/agency.js +55 -12
  57. package/dist/scripts/agency.test.js +73 -1
  58. package/package.json +1 -1
  59. package/stdlib/agency/eval.js +1 -1
  60. package/stdlib/agency.js +1 -1
  61. package/stdlib/agent.agency +9 -9
  62. package/stdlib/agent.js +5 -5
  63. package/stdlib/data/tech/hackernews.js +1 -1
  64. package/stdlib/index.js +15 -15
  65. package/stdlib/llm.agency +2 -1
  66. package/stdlib/llm.js +3 -3
  67. package/stdlib/markdown.js +1 -1
  68. package/stdlib/memory.js +2 -2
  69. package/stdlib/object.js +5 -5
  70. package/stdlib/policy.agency +21 -7
  71. package/stdlib/policy.js +45 -16
  72. package/stdlib/skills.js +1 -1
  73. package/stdlib/strategy.js +3 -3
  74. package/stdlib/thread.js +3 -3
  75. package/stdlib/ui/chart.js +2 -2
  76. package/stdlib/ui/cli.agency +1 -1
  77. package/stdlib/ui/cli.js +1 -1
  78. package/stdlib/ui/layout.js +3 -3
  79. package/stdlib/ui/table.js +2 -2
  80. package/stdlib/ui.js +3 -3
  81. package/dist/lib/agents/docs/cli/cli/agent.md +0 -16
  82. package/dist/lib/agents/docs/cli/cli/compile.md +0 -21
  83. package/dist/lib/agents/docs/cli/cli/coverage.md +0 -112
  84. package/dist/lib/agents/docs/cli/cli/debug.md +0 -41
  85. package/dist/lib/agents/docs/cli/cli/doc.md +0 -98
  86. package/dist/lib/agents/docs/cli/cli/editor-integration.md +0 -44
  87. package/dist/lib/agents/docs/cli/cli/eval-judge.md +0 -72
  88. package/dist/lib/agents/docs/cli/cli/eval.md +0 -194
  89. package/dist/lib/agents/docs/cli/cli/format.md +0 -23
  90. package/dist/lib/agents/docs/cli/cli/index.md +0 -7
  91. package/dist/lib/agents/docs/cli/cli/local.md +0 -92
  92. package/dist/lib/agents/docs/cli/cli/models.md +0 -63
  93. package/dist/lib/agents/docs/cli/cli/optimize.md +0 -338
  94. package/dist/lib/agents/docs/cli/cli/pack.md +0 -56
  95. package/dist/lib/agents/docs/cli/cli/policy.md +0 -23
  96. package/dist/lib/agents/docs/cli/cli/preprocess-and-ast.md +0 -21
  97. package/dist/lib/agents/docs/cli/cli/review.md +0 -16
  98. package/dist/lib/agents/docs/cli/cli/run.md +0 -79
  99. package/dist/lib/agents/docs/cli/cli/schedule.md +0 -89
  100. package/dist/lib/agents/docs/cli/cli/serve.md +0 -52
  101. package/dist/lib/agents/docs/cli/cli/test.md +0 -44
  102. package/dist/lib/agents/docs/cli/cli/trace-and-bundle.md +0 -75
  103. package/dist/lib/agents/docs/cli/cli/typecheck.md +0 -19
  104. package/dist/lib/agents/docs/guide/guide/advanced-types.md +0 -26
  105. package/dist/lib/agents/docs/guide/guide/agency-config-file.md +0 -212
  106. package/dist/lib/agents/docs/guide/guide/agency-packages.md +0 -54
  107. package/dist/lib/agents/docs/guide/guide/agency-stdlib.md +0 -14
  108. package/dist/lib/agents/docs/guide/guide/agency-vs-typescript.md +0 -33
  109. package/dist/lib/agents/docs/guide/guide/attachments.md +0 -56
  110. package/dist/lib/agents/docs/guide/guide/basic-syntax.md +0 -350
  111. package/dist/lib/agents/docs/guide/guide/blocks.md +0 -134
  112. package/dist/lib/agents/docs/guide/guide/build-integration.md +0 -99
  113. package/dist/lib/agents/docs/guide/guide/builtins.md +0 -84
  114. package/dist/lib/agents/docs/guide/guide/callbacks.md +0 -169
  115. package/dist/lib/agents/docs/guide/guide/checkpointing.md +0 -101
  116. package/dist/lib/agents/docs/guide/guide/cli-args.md +0 -190
  117. package/dist/lib/agents/docs/guide/guide/common-functions.md +0 -36
  118. package/dist/lib/agents/docs/guide/guide/compiling-and-running.md +0 -62
  119. package/dist/lib/agents/docs/guide/guide/concurrency.md +0 -108
  120. package/dist/lib/agents/docs/guide/guide/cross-thread-context.md +0 -226
  121. package/dist/lib/agents/docs/guide/guide/custom-providers.md +0 -195
  122. package/dist/lib/agents/docs/guide/guide/debugging.md +0 -67
  123. package/dist/lib/agents/docs/guide/guide/developer-tools.md +0 -90
  124. package/dist/lib/agents/docs/guide/guide/effects-and-raises.md +0 -137
  125. package/dist/lib/agents/docs/guide/guide/effects.md +0 -100
  126. package/dist/lib/agents/docs/guide/guide/error-handling.md +0 -161
  127. package/dist/lib/agents/docs/guide/guide/exercise-1.md +0 -32
  128. package/dist/lib/agents/docs/guide/guide/functions.md +0 -94
  129. package/dist/lib/agents/docs/guide/guide/getting-started.md +0 -35
  130. package/dist/lib/agents/docs/guide/guide/global-var-initialization.md +0 -70
  131. package/dist/lib/agents/docs/guide/guide/global-vs-static.md +0 -76
  132. package/dist/lib/agents/docs/guide/guide/guards.md +0 -134
  133. package/dist/lib/agents/docs/guide/guide/handlers.md +0 -196
  134. package/dist/lib/agents/docs/guide/guide/image-generation.md +0 -113
  135. package/dist/lib/agents/docs/guide/guide/imports-and-packages.md +0 -100
  136. package/dist/lib/agents/docs/guide/guide/interrupts-from-typescript.md +0 -84
  137. package/dist/lib/agents/docs/guide/guide/interrupts-part-2.md +0 -54
  138. package/dist/lib/agents/docs/guide/guide/interrupts.md +0 -139
  139. package/dist/lib/agents/docs/guide/guide/llm-part-2.md +0 -111
  140. package/dist/lib/agents/docs/guide/guide/llm.md +0 -109
  141. package/dist/lib/agents/docs/guide/guide/mcp.md +0 -295
  142. package/dist/lib/agents/docs/guide/guide/memory.md +0 -401
  143. package/dist/lib/agents/docs/guide/guide/message-threads.md +0 -111
  144. package/dist/lib/agents/docs/guide/guide/nodes.md +0 -50
  145. package/dist/lib/agents/docs/guide/guide/observability.md +0 -99
  146. package/dist/lib/agents/docs/guide/guide/partial-application.md +0 -96
  147. package/dist/lib/agents/docs/guide/guide/pattern-matching.md +0 -366
  148. package/dist/lib/agents/docs/guide/guide/policies.md +0 -67
  149. package/dist/lib/agents/docs/guide/guide/schema-parameter-injection.md +0 -101
  150. package/dist/lib/agents/docs/guide/guide/schemas.md +0 -99
  151. package/dist/lib/agents/docs/guide/guide/serving.md +0 -165
  152. package/dist/lib/agents/docs/guide/guide/state-isolation.md +0 -139
  153. package/dist/lib/agents/docs/guide/guide/streaming.md +0 -28
  154. package/dist/lib/agents/docs/guide/guide/tags.md +0 -72
  155. package/dist/lib/agents/docs/guide/guide/testing.md +0 -187
  156. package/dist/lib/agents/docs/guide/guide/troubleshooting.md +0 -86
  157. package/dist/lib/agents/docs/guide/guide/ts-helpers.md +0 -559
  158. package/dist/lib/agents/docs/guide/guide/ts-interop.md +0 -72
  159. package/dist/lib/agents/docs/guide/guide/type-validation.md +0 -187
  160. package/dist/lib/agents/docs/guide/guide/types.md +0 -181
  161. package/dist/lib/agents/docs/guide/guide/unused.md +0 -178
  162. package/dist/lib/agents/docs/guide/guide/unused2.md +0 -258
  163. package/dist/lib/agents/docs/guide/guide/value-parameterized-types.md +0 -186
  164. package/dist/lib/agents/docs/guide/guide/vscode-extension.md +0 -33
  165. package/dist/lib/agents/docs/guide/guide/why-agency.md +0 -323
  166. package/dist/lib/preprocessors/typescriptPreprocessor.config.test.js +0 -327
  167. package/stdlib/browser.js +0 -421
  168. package/stdlib/chart.js +0 -983
  169. package/stdlib/cli.js +0 -1116
  170. package/stdlib/email.js +0 -1104
  171. package/stdlib/imessage.js +0 -377
  172. package/stdlib/keyring.js +0 -803
  173. package/stdlib/layout.js +0 -3657
  174. package/stdlib/oauth.js +0 -862
  175. package/stdlib/schemas.js +0 -223
  176. package/stdlib/search.js +0 -629
  177. package/stdlib/sms.js +0 -419
  178. package/stdlib/table.js +0 -1419
  179. package/stdlib/threads.js +0 -1041
  180. package/stdlib/types.js +0 -222
  181. package/stdlib/validators.js +0 -1606
  182. /package/dist/lib/{preprocessors/typescriptPreprocessor.config.test.d.ts → cli/doctor.test.d.ts} +0 -0
@@ -86,15 +86,12 @@ describe("parseAgencyFileCached", () => {
86
86
  expect(_internal.stats.hits).toBe(0);
87
87
  expect(_internal.stats.misses).toBe(2);
88
88
  });
89
- test("bypasses the cache entirely when tarsecTraceHost is set", () => {
89
+ test("a stale tarsecTraceHost key no longer bypasses the cache", () => {
90
90
  const file = writeTempAgencyFile(VALID_PROGRAM);
91
- const traced = parseAgencyFileCached(file, { tarsecTraceHost: true });
92
- expect(traced.success).toBe(true);
93
- expect(_internal.stats.hits).toBe(0);
94
- expect(_internal.stats.misses).toBe(0);
95
- // The traced parse must not have stored an entry either.
96
- parseAgencyFileCached(file, {});
97
- expect(_internal.stats.hits).toBe(0);
91
+ parseAgencyFileCached(file, { tarsecTraceHost: "http://x" });
92
+ parseAgencyFileCached(file, { tarsecTraceHost: "http://x" });
93
+ // Old code: bypass → hits 0, misses 0 (nothing stored). New code: caches.
94
+ expect(_internal.stats.hits).toBe(1);
98
95
  expect(_internal.stats.misses).toBe(1);
99
96
  });
100
97
  test("failed parses are not cached", () => {
@@ -1,5 +1,4 @@
1
- import { buildLineTable, capture, eof, getErrorMessage, getRightmostFailure, many, map, offsetToPosition, or, resetMemos, seqC, set, setInputStr, setTraceHost, setTraceId, success, TarsecError, trace, } from "tarsec";
2
- import { nanoid } from "nanoid";
1
+ import { buildLineTable, capture, eof, getErrorMessage, getRightmostFailure, many, map, offsetToPosition, or, resetMemos, seqC, set, setInputStr, success, TarsecError, trace, } from "tarsec";
3
2
  import { lowerPatterns, PatternLoweringError } from "./lowering/patternLowering.js";
4
3
  import { LoweringError } from "./lowering/loweringError.js";
5
4
  import render from "./templates/backends/agency/template.js";
@@ -48,16 +47,10 @@ export function _parseAgency(input, config = {}) {
48
47
  // Clear memo caches so loc info derived from `setInputStr` in a previous
49
48
  // parse (which may have used a different source) doesn't leak through.
50
49
  resetMemos();
51
- // CAUTION (parse cache): `tarsecTraceHost` is currently the ONLY config
52
- // field the parse path reads, and lib/parseCache.ts relies on that — its
53
- // cache key deliberately excludes config (tracing is handled via a full
54
- // cache bypass). If you add any config-driven parse behavior here (e.g. a
55
- // syntax feature flag), you MUST add that field to the parseCache key, or
56
- // the cache will silently serve one config's AST to another.
57
- if (config.tarsecTraceHost) {
58
- setTraceHost("http://localhost:1465");
59
- setTraceId(nanoid());
60
- }
50
+ // NOTE (parse cache): the parse path reads NO field of `config`, so
51
+ // lib/parseCache.ts can key entries without config. If you ever add
52
+ // config-driven parse behavior here, you MUST add that field to the
53
+ // parseCache key, or the cache will serve one config's AST to another.
61
54
  const result = agencyParser(normalized);
62
55
  if (!result.success) {
63
56
  const betterMessage = getErrorMessage();
@@ -85,34 +85,6 @@ export declare class TypescriptPreprocessor {
85
85
  protected _insertAwaitPendingCalls(body: AgencyNode[], locationToVars: Record<string, string[]>, currentPath?: number[]): AgencyNode[];
86
86
  protected nodeHasBody(node: AgencyNode): node is FunctionDefinition | AgencyNode | IfElse | WhileLoop | MessageThread;
87
87
  protected _nodeUsesVariable(node: AgencyNode, varName: string): boolean;
88
- /**
89
- * Filter out nodes based on excludeNodeTypes config
90
- */
91
- protected filterExcludedNodeTypes(): void;
92
- /**
93
- * Recursively filter nodes by type, handling all node structures
94
- */
95
- protected filterNodesByType(nodes: AgencyNode[], excludeSet: Set<string>): AgencyNode[];
96
- /**
97
- * Filter out builtin function calls based on excludeBuiltinFunctions config
98
- */
99
- protected filterExcludedBuiltinFunctions(): void;
100
- /**
101
- * Recursively filter builtin function calls
102
- */
103
- protected filterBuiltinFunctionCalls(nodes: AgencyNode[], excludeSet: Set<string>): AgencyNode[];
104
- /**
105
- * Validate fetch calls against allowed/disallowed domains
106
- */
107
- protected validateFetchDomains(): void;
108
- /**
109
- * Validate a single fetch call's domain
110
- */
111
- protected _validateFetchCall(node: FunctionCall, effectiveAllowed: Set<string> | null, disallowedSet: Set<string>): void;
112
- /**
113
- * Extract domain from URL string
114
- */
115
- protected _extractDomain(url: string): string | null;
116
88
  /**
117
89
  * Validate that no async function calls appear inside loops.
118
90
  * Async calls inside loops can't be properly serialized for interrupt
@@ -272,9 +272,6 @@ export class TypescriptPreprocessor {
272
272
  injectSchemaArgsInProgram(this.program, this.functionDefinitions, this.importedFunctions);
273
273
  this.collectSkills();
274
274
  this.addAwaitPendingCalls();
275
- this.filterExcludedNodeTypes();
276
- this.filterExcludedBuiltinFunctions();
277
- this.validateFetchDomains();
278
275
  this.validateNoAsyncInLoops();
279
276
  this.resolveVariableScopes();
280
277
  return this.program;
@@ -729,248 +726,6 @@ export class TypescriptPreprocessor {
729
726
  }
730
727
  return false;
731
728
  }
732
- /**
733
- * Filter out nodes based on excludeNodeTypes config
734
- */
735
- filterExcludedNodeTypes() {
736
- if (!this.config.excludeNodeTypes ||
737
- this.config.excludeNodeTypes.length === 0) {
738
- return;
739
- }
740
- const excludeSet = new Set(this.config.excludeNodeTypes);
741
- this.program.nodes = this.filterNodesByType(this.program.nodes, excludeSet);
742
- }
743
- /**
744
- * Recursively filter nodes by type, handling all node structures
745
- */
746
- filterNodesByType(nodes, excludeSet) {
747
- const filteredNodes = [];
748
- for (const node of nodes) {
749
- // Skip nodes of excluded types
750
- if (excludeSet.has(node.type)) {
751
- continue;
752
- }
753
- // Recursively filter child nodes
754
- if (node.type === "function" || node.type === "graphNode") {
755
- node.body = this.filterNodesByType(node.body, excludeSet);
756
- }
757
- else if (node.type === "ifElse") {
758
- node.thenBody = this.filterNodesByType(node.thenBody, excludeSet);
759
- if (node.elseBody) {
760
- node.elseBody = this.filterNodesByType(node.elseBody, excludeSet);
761
- }
762
- }
763
- else if (node.type === "whileLoop") {
764
- node.body = this.filterNodesByType(node.body, excludeSet);
765
- }
766
- else if (node.type === "messageThread") {
767
- node.body = this.filterNodesByType(node.body, excludeSet);
768
- }
769
- else if (node.type === "handleBlock") {
770
- node.body = this.filterNodesByType(node.body, excludeSet);
771
- if (node.handler.kind === "inline") {
772
- node.handler.body = this.filterNodesByType(node.handler.body, excludeSet);
773
- }
774
- }
775
- else if (node.type === "withModifier") {
776
- const filtered = this.filterNodesByType([node.statement], excludeSet)[0];
777
- if (!filtered)
778
- continue;
779
- node.statement = filtered;
780
- }
781
- else if (node.type === "matchBlock") {
782
- // Case bodies are arrays of nodes, but this filter (filterNodesByType)
783
- // isn't wired up for match arms yet — mirrors pre-existing behavior.
784
- }
785
- else if (node.type === "assignment") {
786
- node.value = (this.filterNodesByType([node.value], excludeSet)[0] || node.value);
787
- }
788
- else if (node.type === "functionCall") {
789
- node.arguments = this.filterNodesByType(node.arguments, excludeSet);
790
- }
791
- else if (node.type === "agencyArray") {
792
- node.items = this.filterNodesByType(node.items, excludeSet);
793
- }
794
- else if (node.type === "agencyObject") {
795
- node.entries = node.entries.map((entry) => ({
796
- ...entry,
797
- value: (this.filterNodesByType([entry.value], excludeSet)[0] || entry.value),
798
- }));
799
- }
800
- filteredNodes.push(node);
801
- }
802
- return filteredNodes;
803
- }
804
- /**
805
- * Filter out builtin function calls based on excludeBuiltinFunctions config
806
- */
807
- filterExcludedBuiltinFunctions() {
808
- if (!this.config.excludeBuiltinFunctions ||
809
- this.config.excludeBuiltinFunctions.length === 0) {
810
- return;
811
- }
812
- const excludeSet = new Set(this.config.excludeBuiltinFunctions);
813
- this.program.nodes = this.filterBuiltinFunctionCalls(this.program.nodes, excludeSet);
814
- }
815
- /**
816
- * Recursively filter builtin function calls
817
- */
818
- filterBuiltinFunctionCalls(nodes, excludeSet) {
819
- const filteredNodes = [];
820
- for (const node of nodes) {
821
- // Skip excluded builtin function calls
822
- if (node.type === "functionCall" && excludeSet.has(node.functionName)) {
823
- continue;
824
- }
825
- // Skip assignments to excluded builtin function calls
826
- if (node.type === "assignment" &&
827
- node.value.type === "functionCall" &&
828
- excludeSet.has(node.value.functionName)) {
829
- continue;
830
- }
831
- // Recursively filter child nodes
832
- if (node.type === "function" || node.type === "graphNode") {
833
- node.body = this.filterBuiltinFunctionCalls(node.body, excludeSet);
834
- }
835
- else if (node.type === "ifElse") {
836
- node.thenBody = this.filterBuiltinFunctionCalls(node.thenBody, excludeSet);
837
- if (node.elseBody) {
838
- node.elseBody = this.filterBuiltinFunctionCalls(node.elseBody, excludeSet);
839
- }
840
- }
841
- else if (node.type === "whileLoop") {
842
- node.body = this.filterBuiltinFunctionCalls(node.body, excludeSet);
843
- }
844
- else if (node.type === "messageThread") {
845
- node.body = this.filterBuiltinFunctionCalls(node.body, excludeSet);
846
- }
847
- else if (node.type === "handleBlock") {
848
- node.body = this.filterBuiltinFunctionCalls(node.body, excludeSet);
849
- if (node.handler.kind === "inline") {
850
- node.handler.body = this.filterBuiltinFunctionCalls(node.handler.body, excludeSet);
851
- }
852
- }
853
- else if (node.type === "withModifier") {
854
- const filtered = this.filterBuiltinFunctionCalls([node.statement], excludeSet)[0];
855
- if (!filtered)
856
- continue;
857
- node.statement = filtered;
858
- }
859
- else if (node.type === "matchBlock") {
860
- node.cases = node.cases.map((caseItem) => {
861
- if (caseItem.type === "comment") {
862
- return caseItem;
863
- }
864
- if (caseItem.type === "newLine") {
865
- return caseItem;
866
- }
867
- return {
868
- ...caseItem,
869
- body: this.filterBuiltinFunctionCalls(caseItem.body, excludeSet),
870
- };
871
- });
872
- }
873
- else if (node.type === "functionCall") {
874
- // Filter arguments that are function calls
875
- node.arguments = this.filterBuiltinFunctionCalls(node.arguments, excludeSet);
876
- }
877
- else if (node.type === "agencyArray") {
878
- node.items = this.filterBuiltinFunctionCalls(node.items, excludeSet);
879
- }
880
- else if (node.type === "agencyObject") {
881
- node.entries = node.entries.map((entry) => {
882
- const filteredValues = this.filterBuiltinFunctionCalls([entry.value], excludeSet);
883
- return {
884
- ...entry,
885
- value: filteredValues[0] || entry.value,
886
- };
887
- });
888
- }
889
- filteredNodes.push(node);
890
- }
891
- return filteredNodes;
892
- }
893
- /**
894
- * Validate fetch calls against allowed/disallowed domains
895
- */
896
- validateFetchDomains() {
897
- const hasAllowed = this.config.allowedFetchDomains &&
898
- this.config.allowedFetchDomains.length > 0;
899
- const hasDisallowed = this.config.disallowedFetchDomains &&
900
- this.config.disallowedFetchDomains.length > 0;
901
- if (!hasAllowed && !hasDisallowed) {
902
- return; // No domain restrictions
903
- }
904
- // Compute the effective allowed domains
905
- let effectiveAllowed = null;
906
- if (hasAllowed) {
907
- effectiveAllowed = new Set(this.config.allowedFetchDomains);
908
- // If both allowed and disallowed are set, remove disallowed from allowed
909
- if (hasDisallowed) {
910
- for (const domain of this.config.disallowedFetchDomains) {
911
- effectiveAllowed.delete(domain);
912
- }
913
- }
914
- }
915
- const disallowedSet = hasDisallowed
916
- ? new Set(this.config.disallowedFetchDomains)
917
- : new Set();
918
- // Walk through all nodes and validate fetch calls
919
- for (const { node } of walkNodesArray(this.program.nodes)) {
920
- if (node.type === "functionCall" &&
921
- (node.functionName === "fetch" ||
922
- node.functionName === "fetchJSON" ||
923
- node.functionName === "fetchJson")) {
924
- this._validateFetchCall(node, effectiveAllowed, disallowedSet);
925
- }
926
- }
927
- }
928
- /**
929
- * Validate a single fetch call's domain
930
- */
931
- _validateFetchCall(node, effectiveAllowed, disallowedSet) {
932
- // Get the URL argument (first argument to fetch)
933
- if (node.arguments.length === 0) {
934
- return; // No URL provided, let it fail at runtime
935
- }
936
- const urlArg = node.arguments[0];
937
- let url = null;
938
- // Extract URL if it's a string literal
939
- if (urlArg.type === "string") {
940
- // Reconstruct the URL from segments
941
- url = urlArg.segments
942
- .map((seg) => (seg.type === "text" ? seg.value : ""))
943
- .join("");
944
- }
945
- if (!url) {
946
- return; // Can't validate variable URLs at compile time
947
- }
948
- // Extract domain from URL
949
- const domain = this._extractDomain(url);
950
- if (!domain) {
951
- return; // Can't extract domain, skip validation
952
- }
953
- // Check if domain is allowed
954
- if (effectiveAllowed !== null && !effectiveAllowed.has(domain)) {
955
- throw new Error(`Fetch to domain "${domain}" is not allowed. Allowed domains: ${Array.from(effectiveAllowed).join(", ")}`);
956
- }
957
- // Check if domain is disallowed
958
- if (disallowedSet.has(domain)) {
959
- throw new Error(`Fetch to domain "${domain}" is explicitly disallowed.`);
960
- }
961
- }
962
- /**
963
- * Extract domain from URL string
964
- */
965
- _extractDomain(url) {
966
- try {
967
- const urlObj = new URL(url);
968
- return urlObj.hostname;
969
- }
970
- catch {
971
- return null; // Invalid URL
972
- }
973
- }
974
729
  /**
975
730
  * Validate that no async function calls appear inside loops.
976
731
  * Async calls inside loops can't be properly serialized for interrupt
@@ -20,22 +20,23 @@ export type RuntimeContextConstructorArgs = {
20
20
  export declare function setRuntimeConfigOverrides(overrides: Partial<AgencyConfig> | undefined): void;
21
21
  export declare function getRuntimeConfigOverrides(): Partial<AgencyConfig> | undefined;
22
22
  /**
23
- * Apply runtime config overrides (set per-subprocess via
24
- * `setRuntimeConfigOverrides`) to the args used to construct a
25
- * `RuntimeContext`. `log.*` fields and the top-level `observability` flag flow
26
- * into the statelog config; `client.providerModules` and `maxCallDepth` are
27
- * forwarded explicitly (see below). Other `AgencyConfig` fields are ignored
28
- * because the runtime has its own pathways for them. If a new statelog-relevant
29
- * override field is added, it will be picked up automatically by the shallow
30
- * merge below.
23
+ * Apply runtime config overrides a `Partial<AgencyConfig>` — onto the args
24
+ * used to construct a `RuntimeContext`. This is THE single runtime merge; it
25
+ * serves two transports:
26
+ * subprocess IPC: the parent forwards `configOverrides` in the spawn
27
+ * message (`setRuntimeConfigOverrides` sets the active value).
28
+ * bundled agents / packed bundles: `AGENCY_CONFIG_OVERRIDES` in the env
29
+ * (`config.ts` `readConfigOverrides`), passed explicitly by the caller.
31
30
  *
32
- * `client.providerModules` is honored: `_run` forwards the parent's
33
- * (absolutized) provider-module paths here so a subprocess loads the same
34
- * custom/local providers the parent has, regardless of how the child was
35
- * compiled. They are merged with any baked-in `providerModules` on `args`;
36
- * `loadProviderModules` de-duplicates by resolved path at load time.
37
- *
38
- * `maxCallDepth` is honored so a subprocess inherits the parent's runaway-
39
- * recursion ceiling rather than falling back to the default.
31
+ * Fields honored (others are ignored — the runtime has its own pathways):
32
+ * `log.*` + `observability` statelogConfig
33
+ * `traceFile` / `traceDir` traceConfig (the `trace` boolean is only a
34
+ * marker set alongside them by applyCliFlags; the file/dir drive output).
35
+ * An override always wins over the baked traceConfig: a supplied `traceDir`
36
+ * clears any baked `traceFile` (which `resolveTraceFilePath` would otherwise
37
+ * prefer), so a per-run `--trace` dir actually takes effect.
38
+ * `client.providerModules` merged with baked modules (subprocess loads
39
+ * the same custom/local providers; de-duped at load time).
40
+ * • `maxCallDepth` → inherit the parent's runaway-recursion ceiling.
40
41
  */
41
42
  export declare function applyRuntimeConfigOverridesToContextArgs(args: RuntimeContextConstructorArgs, overrides?: Partial<AgencyConfig> | undefined): RuntimeContextConstructorArgs;
@@ -6,23 +6,24 @@ export function getRuntimeConfigOverrides() {
6
6
  return activeRuntimeConfigOverrides;
7
7
  }
8
8
  /**
9
- * Apply runtime config overrides (set per-subprocess via
10
- * `setRuntimeConfigOverrides`) to the args used to construct a
11
- * `RuntimeContext`. `log.*` fields and the top-level `observability` flag flow
12
- * into the statelog config; `client.providerModules` and `maxCallDepth` are
13
- * forwarded explicitly (see below). Other `AgencyConfig` fields are ignored
14
- * because the runtime has its own pathways for them. If a new statelog-relevant
15
- * override field is added, it will be picked up automatically by the shallow
16
- * merge below.
9
+ * Apply runtime config overrides a `Partial<AgencyConfig>` — onto the args
10
+ * used to construct a `RuntimeContext`. This is THE single runtime merge; it
11
+ * serves two transports:
12
+ * subprocess IPC: the parent forwards `configOverrides` in the spawn
13
+ * message (`setRuntimeConfigOverrides` sets the active value).
14
+ * bundled agents / packed bundles: `AGENCY_CONFIG_OVERRIDES` in the env
15
+ * (`config.ts` `readConfigOverrides`), passed explicitly by the caller.
17
16
  *
18
- * `client.providerModules` is honored: `_run` forwards the parent's
19
- * (absolutized) provider-module paths here so a subprocess loads the same
20
- * custom/local providers the parent has, regardless of how the child was
21
- * compiled. They are merged with any baked-in `providerModules` on `args`;
22
- * `loadProviderModules` de-duplicates by resolved path at load time.
23
- *
24
- * `maxCallDepth` is honored so a subprocess inherits the parent's runaway-
25
- * recursion ceiling rather than falling back to the default.
17
+ * Fields honored (others are ignored — the runtime has its own pathways):
18
+ * `log.*` + `observability` statelogConfig
19
+ * `traceFile` / `traceDir` traceConfig (the `trace` boolean is only a
20
+ * marker set alongside them by applyCliFlags; the file/dir drive output).
21
+ * An override always wins over the baked traceConfig: a supplied `traceDir`
22
+ * clears any baked `traceFile` (which `resolveTraceFilePath` would otherwise
23
+ * prefer), so a per-run `--trace` dir actually takes effect.
24
+ * `client.providerModules` merged with baked modules (subprocess loads
25
+ * the same custom/local providers; de-duped at load time).
26
+ * • `maxCallDepth` → inherit the parent's runaway-recursion ceiling.
26
27
  */
27
28
  export function applyRuntimeConfigOverridesToContextArgs(args, overrides = activeRuntimeConfigOverrides) {
28
29
  if (!overrides)
@@ -37,6 +38,16 @@ export function applyRuntimeConfigOverridesToContextArgs(args, overrides = activ
37
38
  ...args,
38
39
  statelogConfig: { ...args.statelogConfig, ...statelogOverrides },
39
40
  };
41
+ if (overrides.traceFile || overrides.traceDir) {
42
+ merged.traceConfig = {
43
+ ...(args.traceConfig ?? {}),
44
+ // Override wins over baked. An explicit file sets traceFile; a dir-only
45
+ // override clears any baked traceFile so the dir is honored (see above).
46
+ ...(overrides.traceFile
47
+ ? { traceFile: overrides.traceFile }
48
+ : { traceFile: undefined, traceDir: overrides.traceDir }),
49
+ };
50
+ }
40
51
  const overrideModules = overrides.client?.providerModules;
41
52
  if (overrideModules && overrideModules.length > 0) {
42
53
  merged.providerModules = [
@@ -1,5 +1,8 @@
1
- import { describe, expect, it } from "vitest";
2
- import { applyRuntimeConfigOverridesToContextArgs } from "./configOverrides.js";
1
+ import { afterEach, describe, expect, it } from "vitest";
2
+ import { applyRuntimeConfigOverridesToContextArgs, setRuntimeConfigOverrides, } from "./configOverrides.js";
3
+ import { CONFIG_OVERRIDES_ENV, serializeConfigOverrides, } from "../config.js";
4
+ import { RuntimeContext } from "./state/context.js";
5
+ import { agentConfigOverride } from "../cli/runBundledAgent.js";
3
6
  describe("runtime config overrides", () => {
4
7
  it("applies eval run statelog overrides without replacing existing fields", () => {
5
8
  const result = applyRuntimeConfigOverridesToContextArgs({
@@ -57,3 +60,114 @@ describe("runtime config overrides", () => {
57
60
  expect(result.providerModules).toEqual(["/baked/a.mjs"]);
58
61
  });
59
62
  });
63
+ describe("applyRuntimeConfigOverridesToContextArgs — trace overrides", () => {
64
+ const baseArgs = () => ({
65
+ statelogConfig: {
66
+ host: "https://kept",
67
+ apiKey: "",
68
+ projectId: "",
69
+ debugMode: true,
70
+ observability: false,
71
+ },
72
+ smoltalkDefaults: {},
73
+ dirname: "/project",
74
+ traceConfig: { program: "agent" },
75
+ });
76
+ it("folds an override traceFile and preserves traceConfig.program", () => {
77
+ const r = applyRuntimeConfigOverridesToContextArgs(baseArgs(), {
78
+ trace: true,
79
+ traceFile: "/t.agencytrace",
80
+ });
81
+ expect(r.traceConfig?.traceFile).toBe("/t.agencytrace");
82
+ expect(r.traceConfig?.program).toBe("agent");
83
+ });
84
+ it("folds an override traceDir", () => {
85
+ const r = applyRuntimeConfigOverridesToContextArgs(baseArgs(), {
86
+ trace: true,
87
+ traceDir: "/traces",
88
+ });
89
+ expect(r.traceConfig?.traceDir).toBe("/traces");
90
+ });
91
+ it("an override traceDir clears a baked traceFile so the dir takes effect", () => {
92
+ const baked = { ...baseArgs(), traceConfig: { program: "agent", traceFile: "baked.trace" } };
93
+ const r = applyRuntimeConfigOverridesToContextArgs(baked, {
94
+ trace: true,
95
+ traceDir: "/x",
96
+ });
97
+ expect(r.traceConfig?.traceFile).toBeUndefined();
98
+ expect(r.traceConfig?.traceDir).toBe("/x");
99
+ });
100
+ it("applies trace + statelog overrides together, keeping statelog siblings", () => {
101
+ const r = applyRuntimeConfigOverridesToContextArgs(baseArgs(), {
102
+ trace: true,
103
+ traceFile: "/t",
104
+ observability: true,
105
+ log: { logFile: "/l" },
106
+ });
107
+ expect(r.traceConfig?.traceFile).toBe("/t");
108
+ expect(r.statelogConfig.logFile).toBe("/l");
109
+ expect(r.statelogConfig.observability).toBe(true);
110
+ expect(r.statelogConfig.host).toBe("https://kept");
111
+ });
112
+ it("is a no-op when overrides are empty/undefined", () => {
113
+ expect(applyRuntimeConfigOverridesToContextArgs(baseArgs(), {}).traceConfig?.traceFile).toBeUndefined();
114
+ expect(applyRuntimeConfigOverridesToContextArgs(baseArgs(), undefined).traceConfig?.program).toBe("agent");
115
+ });
116
+ });
117
+ describe("RuntimeContext honors AGENCY_CONFIG_OVERRIDES at construction", () => {
118
+ const saved = { ...process.env };
119
+ afterEach(() => {
120
+ process.env = { ...saved };
121
+ });
122
+ it("reads the env override into statelogConfig", () => {
123
+ process.env[CONFIG_OVERRIDES_ENV] = serializeConfigOverrides({
124
+ observability: true,
125
+ log: { logFile: "/tmp/wired.jsonl" },
126
+ });
127
+ const ctx = new RuntimeContext({
128
+ statelogConfig: { host: "", apiKey: "", projectId: "", debugMode: false, observability: false },
129
+ smoltalkDefaults: {},
130
+ dirname: "/project",
131
+ });
132
+ const sc = ctx.statelogConfig;
133
+ expect(sc.logFile).toBe("/tmp/wired.jsonl");
134
+ expect(sc.observability).toBe(true);
135
+ });
136
+ it("still applies the env override when an IPC override is also present (both transports layer)", () => {
137
+ process.env[CONFIG_OVERRIDES_ENV] = serializeConfigOverrides({
138
+ observability: true,
139
+ log: { logFile: "/tmp/tree.jsonl" },
140
+ });
141
+ // A subprocess launched with explicit IPC overrides (e.g. an eval run) must
142
+ // NOT drop out of the env-based statelog tree.
143
+ setRuntimeConfigOverrides({ maxCallDepth: 7 });
144
+ try {
145
+ const ctx = new RuntimeContext({
146
+ statelogConfig: { host: "", apiKey: "", projectId: "", debugMode: false, observability: false },
147
+ smoltalkDefaults: {},
148
+ dirname: "/project",
149
+ });
150
+ const sc = ctx.statelogConfig;
151
+ expect(sc.logFile).toBe("/tmp/tree.jsonl");
152
+ expect(sc.observability).toBe(true);
153
+ }
154
+ finally {
155
+ setRuntimeConfigOverrides(undefined);
156
+ }
157
+ });
158
+ });
159
+ describe("writer→reader override contract", () => {
160
+ it("agentConfigOverride output applies cleanly through the runtime merge", () => {
161
+ const base = {
162
+ statelogConfig: { host: "", apiKey: "", projectId: "", debugMode: false, observability: false },
163
+ smoltalkDefaults: {},
164
+ dirname: "/p",
165
+ traceConfig: { program: "agent" },
166
+ };
167
+ // The exact object runBundledAgent serializes into AGENCY_CONFIG_OVERRIDES.
168
+ const overrides = agentConfigOverride(["--trace", "t.trace", "--log-file", "l.jsonl"]);
169
+ const r = applyRuntimeConfigOverridesToContextArgs(base, overrides);
170
+ expect(r.traceConfig?.traceFile).toBe("t.trace");
171
+ expect(r.statelogConfig.logFile).toBe("l.jsonl");
172
+ });
173
+ });
@@ -536,7 +536,11 @@ export async function runPrompt(args) {
536
536
  // `smoltalkDefaults` and the per-call options, so precedence is
537
537
  // baked agency.json < stack defaults < per-call `llm({...})`.
538
538
  const stackDefaults = stateStack?.other?.llmDefaults ?? {};
539
- const { maxToolResultChars: stackMaxToolResultChars, ...stackSmolDefaults } = stackDefaults;
539
+ const { maxToolResultChars: stackMaxToolResultChars, maxToolCallRounds: stackMaxToolCallRounds, ...stackSmolDefaults } = stackDefaults;
540
+ // maxToolCallRounds precedence: a branch default (setLlmOptions) overrides the
541
+ // baked per-call value (agency.json → codegen literal, default 10). Kept out
542
+ // of stackSmolDefaults above — it isn't a smoltalk config field.
543
+ const effectiveMaxToolCallRounds = stackMaxToolCallRounds ?? maxToolCallRounds;
540
544
  const clientConfig = ctx.getSmoltalkConfig({
541
545
  ...stackSmolDefaults,
542
546
  ...restClientConfig,
@@ -882,9 +886,9 @@ export async function runPrompt(args) {
882
886
  });
883
887
  return;
884
888
  }
885
- if (self.toolCallRound >= maxToolCallRounds) {
889
+ if (self.toolCallRound >= effectiveMaxToolCallRounds) {
886
890
  await b.step(`round.${round}.tool.${callSlug}.tooManyRounds`, async () => {
887
- messages.push(smoltalk.toolMessage(`Error: Maximum number of tool call rounds (${maxToolCallRounds}) exceeded. This tool call will not be executed.`, { tool_call_id: toolCall.id, name: toolCall.name }));
891
+ messages.push(smoltalk.toolMessage(`Error: Maximum number of tool call rounds (${effectiveMaxToolCallRounds}) exceeded. This tool call will not be executed.`, { tool_call_id: toolCall.id, name: toolCall.name }));
888
892
  });
889
893
  return;
890
894
  }
@@ -205,7 +205,7 @@ export declare class Runner {
205
205
  hook(id: number, bodyFn: () => Promise<void>): Promise<void>;
206
206
  debugger(id: number, label: string): Promise<void>;
207
207
  pipe(id: number, input: any, fn: (value: any) => any): Promise<any>;
208
- thread(id: number, method: "create" | "createSubthread", opts: ThreadStepOpts, callback: (runner: Runner) => Promise<void>): Promise<void>;
208
+ thread(id: number, method: "create" | "createSubthread", optsArg: ThreadStepOpts | (() => ThreadStepOpts | Promise<ThreadStepOpts>), callback: (runner: Runner) => Promise<void>): Promise<void>;
209
209
  handle(id: number, handlerFn: HandlerFn, callback: (runner: Runner) => Promise<void>): Promise<void>;
210
210
  ifElse(id: number, branches: {
211
211
  condition: () => boolean | Promise<boolean>;
@@ -213,7 +213,7 @@ export declare class Runner {
213
213
  }[], elseBranch?: (runner: Runner) => Promise<void>, opts?: {
214
214
  matchId?: number;
215
215
  }): Promise<void>;
216
- loop(id: number, items: any[] | Record<string, any>, callback: (item: any, second: any, runner: Runner) => Promise<void>): Promise<void>;
216
+ loop(id: number, items: any[] | Record<string, any> | (() => any[] | Record<string, any> | Promise<any[] | Record<string, any>>), callback: (item: any, second: any, runner: Runner) => Promise<void>): Promise<void>;
217
217
  whileLoop(id: number, condition: () => boolean | Promise<boolean>, callback: (runner: Runner) => Promise<void>): Promise<void>;
218
218
  branchStep(id: number, branchKey: string, callback: (runner: Runner) => Promise<void>): Promise<void>;
219
219
  /**