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
@@ -486,7 +486,15 @@ export class Runner {
486
486
  return result;
487
487
  }
488
488
  // ── Specialized: thread ──
489
- async thread(id, method, opts, callback) {
489
+ async thread(id, method,
490
+ // Codegen emits opts as a thunk (`async () => (<opts>)`) so its value
491
+ // expressions are evaluated ONLY after the halt/skip guards below. If a
492
+ // preceding `return` halted the runner, the steps that assign the locals
493
+ // those expressions reference are skipped, so evaluating them eagerly here
494
+ // would dereference an unset local and throw. Evaluating lazily lets the
495
+ // early return win. A bare object is still accepted for direct runtime
496
+ // callers (tests); only a function means "thunk".
497
+ optsArg, callback) {
490
498
  // Single canonical signature; `prettyPrint.ts` always emits an
491
499
  // opts object (possibly empty) so there is no dual-form path to
492
500
  // support. Test harnesses pass `{}` explicitly when they don't
@@ -498,6 +506,7 @@ export class Runner {
498
506
  return;
499
507
  if (await this.maybeDebugHook(id))
500
508
  return;
509
+ const opts = typeof optsArg === "function" ? await optsArg() : optsArg;
501
510
  this.ctx.coverageCollector?.hit(this.moduleId, this.scopeName, this.stepPath(id));
502
511
  // Post-ALS migration the ThreadStore is captured on `this.threads`
503
512
  // (seeded by the constructor from explicit opts or the active
@@ -736,7 +745,16 @@ export class Runner {
736
745
  }
737
746
  }
738
747
  // ── Specialized: loop (for) ──
739
- async loop(id, items,
748
+ async loop(id,
749
+ // The iterable is a thunk (codegen emits `async () => <expr>`) so its
750
+ // expression is evaluated ONLY after the halt/skip guards below. If a
751
+ // preceding `return` halted the runner, the steps that would assign the
752
+ // iterable's backing locals are skipped, so eagerly evaluating the
753
+ // expression here would dereference an unset local and throw. Evaluating
754
+ // lazily lets the early return win. A bare value is still accepted for
755
+ // direct runtime callers (tests); only a function means "thunk", since an
756
+ // iterable can never legitimately be a function.
757
+ items,
740
758
  // Second arg is the numeric index for arrays, or the value for records.
741
759
  callback) {
742
760
  if (this.shouldSkip())
@@ -746,6 +764,7 @@ export class Runner {
746
764
  if (await this.maybeDebugHook(id))
747
765
  return;
748
766
  this.ctx.coverageCollector?.hit(this.moduleId, this.scopeName, this.stepPath(id));
767
+ const items_ = typeof items === "function" ? await items() : items;
749
768
  const iterKey = this.path.length === 0
750
769
  ? `__iteration_${id}`
751
770
  : `__iteration_${this.key()}.${id}`;
@@ -756,11 +775,11 @@ export class Runner {
756
775
  // simply do nothing rather than crash mid-flow.
757
776
  let iterable;
758
777
  let isRecord = false;
759
- if (Array.isArray(items)) {
760
- iterable = items;
778
+ if (Array.isArray(items_)) {
779
+ iterable = items_;
761
780
  }
762
- else if (items != null && typeof items === "object") {
763
- iterable = Object.keys(items);
781
+ else if (items_ != null && typeof items_ === "object") {
782
+ iterable = Object.keys(items_);
764
783
  isRecord = true;
765
784
  }
766
785
  else {
@@ -780,7 +799,7 @@ export class Runner {
780
799
  // numeric index; for records it is the value at the current key. The
781
800
  // first callback arg is the element (array) or the key (record).
782
801
  const item = iterable[i];
783
- const second = isRecord ? items[item] : i;
802
+ const second = isRecord ? items_[item] : i;
784
803
  await this.runInScope(() => callback(item, second, this));
785
804
  }
786
805
  finally {
@@ -14,7 +14,8 @@ import { getOrCreateStore } from "../memory/registry.js";
14
14
  import { GlobalStore } from "../state/globalStore.js";
15
15
  import { StateStack } from "../state/stateStack.js";
16
16
  import { TraceWriter } from "../trace/traceWriter.js";
17
- import { applyRuntimeConfigOverridesToContextArgs } from "../configOverrides.js";
17
+ import { applyRuntimeConfigOverridesToContextArgs, getRuntimeConfigOverrides, } from "../configOverrides.js";
18
+ import { readConfigOverrides } from "../../config.js";
18
19
  import { CheckpointStore, RESULT_ENTRY_LABEL } from "./checkpointStore.js";
19
20
  import { PendingPromiseStore } from "./pendingPromiseStore.js";
20
21
  /**
@@ -161,7 +162,13 @@ export class RuntimeContext {
161
162
  jsonMemoryConfig;
162
163
  memoryManagerCache = {};
163
164
  constructor(args) {
164
- args = applyRuntimeConfigOverridesToContextArgs(args);
165
+ // One runtime merge, applied for BOTH transports so a subprocess launched
166
+ // with explicit IPC overrides still inherits the env override (e.g. a
167
+ // tree-wide --log-file). Env first, then IPC on top: IPC (explicit,
168
+ // per-child) wins per field, env fills the rest. Sequential application
169
+ // also layers nested `log`/`trace` objects rather than clobbering them.
170
+ args = applyRuntimeConfigOverridesToContextArgs(args, readConfigOverrides());
171
+ args = applyRuntimeConfigOverridesToContextArgs(args, getRuntimeConfigOverrides());
165
172
  const statelogConfig = {
166
173
  ...args.statelogConfig,
167
174
  traceId: args.statelogConfig.traceId || nanoid(),
@@ -17,6 +17,7 @@ export type LlmDefaults = RetryConfig & {
17
17
  reasoningEffort?: "low" | "medium" | "high";
18
18
  maxTokens?: number;
19
19
  maxToolResultChars?: number;
20
+ maxToolCallRounds?: number;
20
21
  };
21
22
  /**
22
23
  * Merge `opts` into the ACTIVE branch stack's LLM defaults
@@ -1 +1 @@
1
- export declare const VERSION = "0.7.0";
1
+ export declare const VERSION = "0.7.2";
@@ -1 +1 @@
1
- export const VERSION = "0.7.0";
1
+ export const VERSION = "0.7.2";
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from "commander";
3
+ export declare function parsePositiveInt(value: string): number;
4
+ export declare function parseNonNegativeInt(value: string): number;
3
5
  type CliDependencies = {
4
6
  loadLspStartServer?: () => Promise<() => void>;
5
7
  loadMcpStartServer?: () => Promise<() => void>;
@@ -11,13 +11,14 @@ import { evalExtract } from "../lib/cli/evalExtract.js";
11
11
  import { evalJudge } from "../lib/cli/evalJudge.js";
12
12
  import { evalRun } from "../lib/cli/eval/run.js";
13
13
  import { evalOptimize } from "../lib/cli/eval/optimize.js";
14
+ import { applyCliFlags, redactConfigSecrets, } from "../lib/config.js";
14
15
  import * as path from "path";
15
16
  import { _parseAgency } from "../lib/parser.js";
16
17
  import { TypescriptPreprocessor } from "../lib/preprocessors/typescriptPreprocessor.js";
17
18
  import { buildCompilationUnit } from "../lib/compilationUnit.js";
18
19
  import { SymbolTable } from "../lib/symbolTable.js";
19
20
  import { formatErrors, typeCheck } from "../lib/typeChecker/index.js";
20
- import { Command } from "commander";
21
+ import { Command, InvalidArgumentError } from "commander";
21
22
  import * as fs from "fs";
22
23
  import { color } from "../lib/utils/termcolors.js";
23
24
  import { TarsecError } from "tarsec";
@@ -42,6 +43,26 @@ import { startServer } from "../lib/lsp/index.js";
42
43
  import { startMcpServer } from "../lib/mcp/server.js";
43
44
  import { pathToFileURL } from "url";
44
45
  import { serveMcp, serveHttp } from "../lib/cli/serve.js";
46
+ // commander option parsers. Match the WHOLE string against digits so
47
+ // `parseInt`'s silent truncation ("1.5"→1, "3abc"→3, "0x10"→16) can't sneak an
48
+ // invalid value through as a usable number.
49
+ function parseBoundedInt(value, min, label) {
50
+ if (!/^\d+$/.test(value)) {
51
+ throw new InvalidArgumentError(label);
52
+ }
53
+ const n = parseInt(value, 10);
54
+ if (n < min) {
55
+ throw new InvalidArgumentError(label);
56
+ }
57
+ return n;
58
+ }
59
+ export function parsePositiveInt(value) {
60
+ return parseBoundedInt(value, 1, "must be a positive integer");
61
+ }
62
+ // 0 allowed (e.g. to disable a cap).
63
+ export function parseNonNegativeInt(value) {
64
+ return parseBoundedInt(value, 0, "must be a non-negative integer");
65
+ }
45
66
  function defaultResolveMcpCommand() {
46
67
  return ["agency", "mcp"];
47
68
  }
@@ -71,14 +92,7 @@ export function createProgram(deps = {}) {
71
92
  return config;
72
93
  }
73
94
  function runWithOptions(input, options) {
74
- const config = getConfig();
75
- if (options.trace) {
76
- config.trace = true;
77
- config.traceFile =
78
- typeof options.trace === "string"
79
- ? options.trace
80
- : input.replace(/\.agency$/, ".trace");
81
- }
95
+ const config = applyCliFlags(getConfig(), options, input);
82
96
  run(config, input, undefined, options.resume);
83
97
  }
84
98
  program
@@ -88,8 +102,15 @@ export function createProgram(deps = {}) {
88
102
  .argument("<inputs...>", "Paths to .agency input files or directories")
89
103
  .option("--ts", "Output .ts files with // @no-check header")
90
104
  .option("-w, --watch", "Watch for changes and recompile")
105
+ .option("--strict", "Fail on any fatal type error (typechecker.strict)")
106
+ .option("--max-tool-call-rounds <n>", "Max LLM tool-call rounds before halting a tool loop (default 10; overrides agency.json)", parsePositiveInt)
107
+ .option("--max-tool-result-chars <n>", "Max chars of a single tool result fed back to the model (0 disables; default 100000; overrides agency.json)", parseNonNegativeInt)
91
108
  .action(async (inputs, opts) => {
92
- const config = getConfig();
109
+ const config = applyCliFlags(getConfig(), {
110
+ strict: opts.strict,
111
+ maxToolCallRounds: opts.maxToolCallRounds,
112
+ maxToolResultChars: opts.maxToolResultChars,
113
+ });
93
114
  if (opts.watch) {
94
115
  const close = await watchAndCompile(config, inputs, { ts: opts.ts });
95
116
  process.once("SIGINT", async () => {
@@ -121,7 +142,12 @@ export function createProgram(deps = {}) {
121
142
  function addRunOptions(cmd) {
122
143
  return cmd
123
144
  .option("--resume <statefile>", "Resume execution from a saved state file")
124
- .option("--trace [file]", "Write execution trace to file (default: <input>.trace)");
145
+ .option("--trace [file]", "Write execution trace to file (default: <input>.trace)")
146
+ .option("--log-file <path>", "Append statelog events (one JSON object per line) to this file for this run")
147
+ .option("--observability", "Enable statelog observability for this run (use with a configured host, or --log-file)")
148
+ .option("--strict", "Fail the run on any fatal type error (typechecker.strict)")
149
+ .option("--max-tool-call-rounds <n>", "Max LLM tool-call rounds before halting a tool loop (default 10; overrides agency.json)", parsePositiveInt)
150
+ .option("--max-tool-result-chars <n>", "Max chars of a single tool result fed back to the model (0 disables; default 100000; overrides agency.json)", parseNonNegativeInt);
125
151
  }
126
152
  addRunOptions(program
127
153
  .command("run")
@@ -674,9 +700,26 @@ export function createProgram(deps = {}) {
674
700
  .description("Diagnose problems with an Agency file using the agency agent")
675
701
  .argument("<file>", "Path to the .agency file to diagnose")
676
702
  .option("--symptom <text>", "Optional description of the problem you are seeing")
703
+ .option("--trace [file]", "Write an execution trace of the diagnosis to this file")
704
+ .option("--log-file <path>", "Append statelog events from the diagnosis to this file")
677
705
  .action((file, opts) => {
678
706
  const config = getConfig();
679
- doctor(config, file, opts);
707
+ doctor(config, file, {
708
+ symptom: opts.symptom,
709
+ trace: opts.trace,
710
+ logFile: opts.logFile,
711
+ });
712
+ });
713
+ const configCmd = program
714
+ .command("config")
715
+ .description("Inspect Agency configuration");
716
+ configCmd
717
+ .command("show")
718
+ .description("Print the resolved, merged agency.json config as JSON")
719
+ .option("--show-secrets", "Print API keys verbatim instead of masking them (avoid in shared logs / bug reports)")
720
+ .action((opts) => {
721
+ const config = getConfig();
722
+ console.log(JSON.stringify(opts.showSecrets ? config : redactConfigSecrets(config), null, 2));
680
723
  });
681
724
  program
682
725
  .command("review", { hidden: true })
@@ -2,7 +2,20 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
2
  import * as fs from "fs";
3
3
  import * as os from "os";
4
4
  import * as path from "path";
5
- import { createProgram, runCli } from "./agency.js";
5
+ import { execFile } from "child_process";
6
+ import { promisify } from "util";
7
+ import { createProgram, parseNonNegativeInt, parsePositiveInt, runCli, } from "./agency.js";
8
+ const execFileAsync = promisify(execFile);
9
+ // The CLI integration tests below shell out to the built dist/ to observe real
10
+ // process exit codes (compile calls process.exit, which would kill the vitest
11
+ // worker if run in-process). They are SKIPPED (with a visible reason) when dist
12
+ // isn't built, so `pnpm test` stays green on a clean checkout; they run in CI
13
+ // and after `make` / `pnpm run build`.
14
+ const CLI = path.resolve("dist/scripts/agency.js");
15
+ const HAS_BUILT_CLI = fs.existsSync(CLI);
16
+ if (!HAS_BUILT_CLI) {
17
+ console.warn(`Skipping CLI integration tests: ${CLI} not built (run \`make\` or \`pnpm run build\`).`);
18
+ }
6
19
  let tmpDir;
7
20
  beforeEach(() => {
8
21
  tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "agency-cli-test-"));
@@ -68,3 +81,62 @@ describe("agency CLI command tree", () => {
68
81
  .toBe("function");
69
82
  });
70
83
  });
84
+ describe.skipIf(!HAS_BUILT_CLI)("compile --strict (integration, requires build)", () => {
85
+ it("exits non-zero on a type error with --strict, zero without", async () => {
86
+ const cli = CLI;
87
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "strict-"));
88
+ const f = path.join(dir, "bad.agency");
89
+ fs.writeFileSync(f, 'node main() {\n let x: number = "hello"\n}\n');
90
+ await expect(execFileAsync("node", [cli, "compile", f])).resolves.toBeTruthy();
91
+ await expect(execFileAsync("node", [cli, "compile", "--strict", f])).rejects.toBeTruthy();
92
+ fs.rmSync(dir, { recursive: true, force: true });
93
+ });
94
+ });
95
+ describe.skipIf(!HAS_BUILT_CLI)("compile --max-tool-call-rounds (integration, requires build)", () => {
96
+ it("bakes the flag value into the generated runPrompt call (overriding the default 10)", async () => {
97
+ const cli = CLI;
98
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "mtcr-"));
99
+ const f = path.join(dir, "prog.agency");
100
+ const out = path.join(dir, "prog.ts");
101
+ fs.writeFileSync(f, 'node main() {\n const reply = llm("hi")\n}\n');
102
+ await execFileAsync("node", [cli, "compile", "--ts", "--max-tool-call-rounds", "3", f]);
103
+ const generated = fs.readFileSync(out, "utf-8");
104
+ expect(generated).toContain("maxToolCallRounds: 3");
105
+ expect(generated).not.toContain("maxToolCallRounds: 10");
106
+ // A positive integer is required.
107
+ await expect(execFileAsync("node", [cli, "compile", "--ts", "--max-tool-call-rounds", "0", f])).rejects.toBeTruthy();
108
+ fs.rmSync(dir, { recursive: true, force: true });
109
+ });
110
+ });
111
+ describe.skipIf(!HAS_BUILT_CLI)("config show (integration, requires build)", () => {
112
+ it("prints the resolved, merged config as JSON, with secrets masked by default", async () => {
113
+ const cli = CLI;
114
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "config-show-"));
115
+ fs.writeFileSync(path.join(dir, "agency.json"), JSON.stringify({ outDir: "./built", log: { apiKey: "sk-secret-1234" } }));
116
+ const cfg = path.join(dir, "agency.json");
117
+ const masked = await execFileAsync("node", [cli, "-c", cfg, "config", "show"]);
118
+ const maskedJson = JSON.parse(masked.stdout);
119
+ expect(maskedJson.outDir).toBe("./built");
120
+ expect(maskedJson.log.apiKey).toBe("•••1234");
121
+ expect(masked.stdout).not.toContain("sk-secret-1234");
122
+ const raw = await execFileAsync("node", [cli, "-c", cfg, "config", "show", "--show-secrets"]);
123
+ expect(JSON.parse(raw.stdout).log.apiKey).toBe("sk-secret-1234");
124
+ fs.rmSync(dir, { recursive: true, force: true });
125
+ });
126
+ });
127
+ describe("integer flag parsers reject parseInt footguns", () => {
128
+ it("parsePositiveInt accepts positive integers, rejects 0/floats/garbage/hex/negatives", () => {
129
+ expect(parsePositiveInt("5")).toBe(5);
130
+ expect(parsePositiveInt("100")).toBe(100);
131
+ for (const bad of ["0", "1.5", "3abc", "0x10", "-1", "", " ", "1e3"]) {
132
+ expect(() => parsePositiveInt(bad)).toThrow();
133
+ }
134
+ });
135
+ it("parseNonNegativeInt accepts 0 and positives, rejects floats/garbage/hex/negatives", () => {
136
+ expect(parseNonNegativeInt("0")).toBe(0);
137
+ expect(parseNonNegativeInt("42")).toBe(42);
138
+ for (const bad of ["1.5", "3abc", "0x10", "-1", "", "1e3"]) {
139
+ expect(() => parseNonNegativeInt(bad)).toThrow();
140
+ }
141
+ });
142
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agency-lang",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "description": "The Agency language",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -266,7 +266,7 @@ async function __evalRun_impl(compiled, inputs, node = __UNSET, runsDir = __UNSE
266
266
  await runner.step(3, async (runner2) => {
267
267
  __stack.locals.lastStatus = `success`;
268
268
  });
269
- await runner.loop(4, __stack.locals.state.inputs, async (input2, _, runner2) => {
269
+ await runner.loop(4, async () => __stack.locals.state.inputs, async (input2, _, runner2) => {
270
270
  await runner2.step(0, async (runner3) => {
271
271
  __self.__retryable = false;
272
272
  __stack.locals.prep = await __call(_prepareInput, {
package/stdlib/agency.js CHANGED
@@ -1812,7 +1812,7 @@ async function __walkAST_impl(ast, visitor) {
1812
1812
  return;
1813
1813
  }
1814
1814
  });
1815
- await runner.loop(2, __stack.locals.result.visits, async (visit, _, runner2) => {
1815
+ await runner.loop(2, async () => __stack.locals.result.visits, async (visit, _, runner2) => {
1816
1816
  await runner2.step(0, async (runner3) => {
1817
1817
  const __funcResult = await __call(__stack.args.visitor, {
1818
1818
  type: "positional",
@@ -171,8 +171,8 @@ let _firstEntry: Record<string, boolean> = {}
171
171
  * categories.
172
172
  *
173
173
  * When called, sets the module-level handoff target. The current
174
- * LLM call returns. `route` reads the target via `consumeHandoff`
175
- * and re-runs the user's original message in the new specialist's
174
+ * LLM call returns. `route` reads (and clears) the target and
175
+ * re-runs the user's original message in the new specialist's
176
176
  * thread. If `category` isn't in `validCategories`, the handoff is
177
177
  * rejected and the LLM sees an error string as the tool's result.
178
178
  * This keeps the LLM from accidentally handing off to itself or to
@@ -207,11 +207,10 @@ export safe def handoff(
207
207
 
208
208
  /**
209
209
  * Read and clear the pending handoff target. Used internally by
210
- * `route` after each LLM call. Exposed for tests and for advanced
211
- * users writing their own dispatch loop on top of `handoff`.
212
- * Returns `""` when no handoff was requested.
210
+ * `route` after each LLM call. Returns `""` when no handoff was
211
+ * requested.
213
212
  */
214
- export safe def consumeHandoff(): string {
213
+ safe def consumeHandoff(): string {
215
214
  """
216
215
  Read and clear the pending handoff target. Returns "" when no handoff
217
216
  was requested.
@@ -317,9 +316,10 @@ def runOneTurnPrompt(
317
316
  * its system message is seeded on first entry, memory is scoped
318
317
  * if requested, and `llm(userMsg, { tools: [...spec.tools,
319
318
  * handoff] })` runs.
320
- * 2. After the LLM call returns, check `consumeHandoff()`.
321
- * - Empty → done, return the LLM's reply.
322
- * - Non-emptyloop with the new category, up to `config.maxHops`
319
+ * 2. After the LLM call returns, check whether `handoff` was called
320
+ * during the turn.
321
+ * - Nodone, return the LLM's reply.
322
+ * - Yes → loop with the new category, up to `config.maxHops`
323
323
  * total iterations.
324
324
  * 3. If the hop cap is reached without a final answer, run one more
325
325
  * LLM call WITHOUT the `handoff` tool so the agent must answer.
package/stdlib/agent.js CHANGED
@@ -352,7 +352,7 @@ async function __todoUpdate_impl(id, status) {
352
352
  }
353
353
  });
354
354
  });
355
- await runner.loop(1, __globals().get("stdlib/agent.agency", "_todos"), async (todo, _, runner2) => {
355
+ await runner.loop(1, async () => __globals().get("stdlib/agent.agency", "_todos"), async (todo, _, runner2) => {
356
356
  await runner2.ifElse(0, [
357
357
  {
358
358
  condition: async () => __eq(todo.id, __stack.args.id),
@@ -1109,7 +1109,7 @@ const consumeHandoff = __AgencyFunction.create({
1109
1109
  schema: z.object({})
1110
1110
  },
1111
1111
  safe: true,
1112
- exported: true
1112
+ exported: false
1113
1113
  }, __toolRegistry);
1114
1114
  async function __runOneTurn_impl(category, userMsg, config, allowHandoff) {
1115
1115
  const __setupData = setupFunction();
@@ -1534,7 +1534,7 @@ async function __runOneTurnPrompt_impl(category, userMsg, config, allowHandoff)
1534
1534
  }
1535
1535
  }
1536
1536
  ]);
1537
- await runner.thread(4, "create", { label: __stack.args.category, summarize: true, session: __stack.args.category }, async (runner2) => {
1537
+ await runner.thread(4, "create", async () => ({ label: __stack.args.category, summarize: true, session: __stack.args.category }), async (runner2) => {
1538
1538
  await runner2.ifElse(0, [
1539
1539
  {
1540
1540
  condition: async () => __eq(__stack.locals.spec.memory, true),
@@ -1592,7 +1592,7 @@ async function __runOneTurnPrompt_impl(category, userMsg, config, allowHandoff)
1592
1592
  await runner3.step(0, async (runner4) => {
1593
1593
  __stack.locals.validTargets = [];
1594
1594
  });
1595
- await runner3.loop(1, await __call(keys, {
1595
+ await runner3.loop(1, async () => await __call(keys, {
1596
1596
  type: "positional",
1597
1597
  args: [__stack.args.config.agents]
1598
1598
  }), async (c, _, runner4) => {
@@ -1963,7 +1963,7 @@ const route = __AgencyFunction.create({
1963
1963
  exported: true
1964
1964
  }, __toolRegistry);
1965
1965
  var stdin_default = graph;
1966
- const __sourceMap = { "stdlib/agent.agency:todoAdd": { "1": { "line": 52, "col": 2 }, "2": { "line": 53, "col": 2 } }, "stdlib/agent.agency:todoUpdate": { "1": { "line": 63, "col": 2 }, "2": { "line": 69, "col": 2 }, "1.0.0": { "line": 65, "col": 6 }, "1.0": { "line": 64, "col": 4 } }, "stdlib/agent.agency:todoWrite": { "1": { "line": 76, "col": 2 }, "2": { "line": 77, "col": 2 } }, "stdlib/agent.agency:todoList": { "1": { "line": 84, "col": 2 } }, "stdlib/agent.agency:question": { "1": { "line": 97, "col": 2 }, "2": { "line": 100, "col": 2 } }, "stdlib/agent.agency:handoff": { "1": { "line": 199, "col": 2 }, "2": { "line": 203, "col": 2 }, "3": { "line": 204, "col": 2 }, "1.0": { "line": 200, "col": 4 }, "1.1": { "line": 201, "col": 4 } }, "stdlib/agent.agency:consumeHandoff": { "1": { "line": 218, "col": 2 }, "2": { "line": 219, "col": 2 }, "3": { "line": 220, "col": 2 } }, "stdlib/agent.agency:runOneTurn": { "1": { "line": 233, "col": 2 }, "2": { "line": 234, "col": 2 }, "2.0": { "line": 235, "col": 4 }, "2.1": { "line": 237, "col": 4 } }, "stdlib/agent.agency:runOneTurnAgent": { "1": { "line": 253, "col": 2 }, "2": { "line": 254, "col": 2 }, "3": { "line": 255, "col": 2 }, "4": { "line": 256, "col": 2 } }, "stdlib/agent.agency:runOneTurnPrompt": { "1": { "line": 270, "col": 2 }, "2": { "line": 271, "col": 2 }, "3": { "line": 272, "col": 2 }, "4": { "line": 281, "col": 2 }, "6": { "line": 305, "col": 2 }, "3.1": { "line": 279, "col": 4 }, "4.0.0": { "line": 283, "col": 6 }, "4.0": { "line": 282, "col": 4 }, "4.2.0": { "line": 286, "col": 6 }, "4.2.1": { "line": 288, "col": 6 }, "4.2": { "line": 285, "col": 4 }, "4.4": { "line": 290, "col": 4 }, "4.5.0": { "line": 292, "col": 6 }, "4.5.1.0.0": { "line": 295, "col": 10 }, "4.5.1.0": { "line": 294, "col": 8 }, "4.5.1": { "line": 293, "col": 6 }, "4.5.2": { "line": 298, "col": 6 }, "4.5": { "line": 291, "col": 4 }, "4.6": { "line": 300, "col": 4 } }, "stdlib/agent.agency:route": { "1": { "line": 347, "col": 2 }, "2": { "line": 350, "col": 2 }, "3": { "line": 351, "col": 2 }, "4": { "line": 352, "col": 2 }, "5": { "line": 353, "col": 2 }, "6": { "line": 354, "col": 2 }, "7": { "line": 364, "col": 2 }, "8": { "line": 368, "col": 2 }, "1.0": { "line": 348, "col": 4 }, "6.0": { "line": 355, "col": 4 }, "6.1": { "line": 356, "col": 4 }, "6.2.0": { "line": 358, "col": 6 }, "6.2.1": { "line": 360, "col": 6 }, "6.2.2": { "line": 361, "col": 6 }, "6.2": { "line": 357, "col": 4 }, "7.1": { "line": 366, "col": 4 } } };
1966
+ const __sourceMap = { "stdlib/agent.agency:todoAdd": { "1": { "line": 52, "col": 2 }, "2": { "line": 53, "col": 2 } }, "stdlib/agent.agency:todoUpdate": { "1": { "line": 63, "col": 2 }, "2": { "line": 69, "col": 2 }, "1.0.0": { "line": 65, "col": 6 }, "1.0": { "line": 64, "col": 4 } }, "stdlib/agent.agency:todoWrite": { "1": { "line": 76, "col": 2 }, "2": { "line": 77, "col": 2 } }, "stdlib/agent.agency:todoList": { "1": { "line": 84, "col": 2 } }, "stdlib/agent.agency:question": { "1": { "line": 97, "col": 2 }, "2": { "line": 100, "col": 2 } }, "stdlib/agent.agency:handoff": { "1": { "line": 199, "col": 2 }, "2": { "line": 203, "col": 2 }, "3": { "line": 204, "col": 2 }, "1.0": { "line": 200, "col": 4 }, "1.1": { "line": 201, "col": 4 } }, "stdlib/agent.agency:consumeHandoff": { "1": { "line": 217, "col": 2 }, "2": { "line": 218, "col": 2 }, "3": { "line": 219, "col": 2 } }, "stdlib/agent.agency:runOneTurn": { "1": { "line": 232, "col": 2 }, "2": { "line": 233, "col": 2 }, "2.0": { "line": 234, "col": 4 }, "2.1": { "line": 236, "col": 4 } }, "stdlib/agent.agency:runOneTurnAgent": { "1": { "line": 252, "col": 2 }, "2": { "line": 253, "col": 2 }, "3": { "line": 254, "col": 2 }, "4": { "line": 255, "col": 2 } }, "stdlib/agent.agency:runOneTurnPrompt": { "1": { "line": 269, "col": 2 }, "2": { "line": 270, "col": 2 }, "3": { "line": 271, "col": 2 }, "4": { "line": 280, "col": 2 }, "6": { "line": 304, "col": 2 }, "3.1": { "line": 278, "col": 4 }, "4.0.0": { "line": 282, "col": 6 }, "4.0": { "line": 281, "col": 4 }, "4.2.0": { "line": 285, "col": 6 }, "4.2.1": { "line": 287, "col": 6 }, "4.2": { "line": 284, "col": 4 }, "4.4": { "line": 289, "col": 4 }, "4.5.0": { "line": 291, "col": 6 }, "4.5.1.0.0": { "line": 294, "col": 10 }, "4.5.1.0": { "line": 293, "col": 8 }, "4.5.1": { "line": 292, "col": 6 }, "4.5.2": { "line": 297, "col": 6 }, "4.5": { "line": 290, "col": 4 }, "4.6": { "line": 299, "col": 4 } }, "stdlib/agent.agency:route": { "1": { "line": 347, "col": 2 }, "2": { "line": 350, "col": 2 }, "3": { "line": 351, "col": 2 }, "4": { "line": 352, "col": 2 }, "5": { "line": 353, "col": 2 }, "6": { "line": 354, "col": 2 }, "7": { "line": 364, "col": 2 }, "8": { "line": 368, "col": 2 }, "1.0": { "line": 348, "col": 4 }, "6.0": { "line": 355, "col": 4 }, "6.1": { "line": 356, "col": 4 }, "6.2.0": { "line": 358, "col": 6 }, "6.2.1": { "line": 360, "col": 6 }, "6.2.2": { "line": 361, "col": 6 }, "6.2": { "line": 357, "col": 4 }, "7.1": { "line": 366, "col": 4 } } };
1967
1967
  export {
1968
1968
  AgentSpec,
1969
1969
  PromptSpec,
@@ -2704,7 +2704,7 @@ async function __hydrateStories_impl(ids, limit) {
2704
2704
  await runner.step(1, async (runner2) => {
2705
2705
  __stack.locals.stories = [];
2706
2706
  });
2707
- await runner.loop(2, await __call(takeFirst, {
2707
+ await runner.loop(2, async () => await __call(takeFirst, {
2708
2708
  type: "positional",
2709
2709
  args: [__stack.args.ids, __stack.args.limit]
2710
2710
  }), async (id, _, runner2) => {
package/stdlib/index.js CHANGED
@@ -2129,7 +2129,7 @@ async function __map_impl(arr, func) {
2129
2129
  await runner.step(1, async (runner2) => {
2130
2130
  __stack.locals.newArr = [];
2131
2131
  });
2132
- await runner.loop(2, __stack.args.arr, async (item, _, runner2) => {
2132
+ await runner.loop(2, async () => __stack.args.arr, async (item, _, runner2) => {
2133
2133
  await runner2.step(0, async (runner3) => {
2134
2134
  await __callMethod(__stack.locals.newArr, "push", {
2135
2135
  type: "positional",
@@ -2274,7 +2274,7 @@ async function __filter_impl(arr, func) {
2274
2274
  await runner.step(1, async (runner2) => {
2275
2275
  __stack.locals.result = [];
2276
2276
  });
2277
- await runner.loop(2, __stack.args.arr, async (item, _, runner2) => {
2277
+ await runner.loop(2, async () => __stack.args.arr, async (item, _, runner2) => {
2278
2278
  await runner2.ifElse(0, [
2279
2279
  {
2280
2280
  condition: async () => await __call(__stack.args.func, {
@@ -2426,7 +2426,7 @@ async function __exclude_impl(arr, func) {
2426
2426
  await runner.step(1, async (runner2) => {
2427
2427
  __stack.locals.result = [];
2428
2428
  });
2429
- await runner.loop(2, __stack.args.arr, async (item, _, runner2) => {
2429
+ await runner.loop(2, async () => __stack.args.arr, async (item, _, runner2) => {
2430
2430
  await runner2.ifElse(0, [
2431
2431
  {
2432
2432
  condition: async () => __eq(await __call(__stack.args.func, {
@@ -2575,7 +2575,7 @@ async function __find_impl(arr, func) {
2575
2575
  }
2576
2576
  });
2577
2577
  });
2578
- await runner.loop(1, __stack.args.arr, async (item, _, runner2) => {
2578
+ await runner.loop(1, async () => __stack.args.arr, async (item, _, runner2) => {
2579
2579
  await runner2.ifElse(0, [
2580
2580
  {
2581
2581
  condition: async () => await __call(__stack.args.func, {
@@ -2723,7 +2723,7 @@ async function __findIndex_impl(arr, func) {
2723
2723
  }
2724
2724
  });
2725
2725
  });
2726
- await runner.loop(1, __stack.args.arr, async (item, index, runner2) => {
2726
+ await runner.loop(1, async () => __stack.args.arr, async (item, index, runner2) => {
2727
2727
  await runner2.ifElse(0, [
2728
2728
  {
2729
2729
  condition: async () => await __call(__stack.args.func, {
@@ -2880,7 +2880,7 @@ async function __reduce_impl(arr, initial, func) {
2880
2880
  await runner.step(1, async (runner2) => {
2881
2881
  __stack.locals.acc = __stack.args.initial;
2882
2882
  });
2883
- await runner.loop(2, __stack.args.arr, async (item, _, runner2) => {
2883
+ await runner.loop(2, async () => __stack.args.arr, async (item, _, runner2) => {
2884
2884
  await runner2.step(0, async (runner3) => {
2885
2885
  __stack.locals.acc = await __call(__stack.args.func, {
2886
2886
  type: "positional",
@@ -3034,7 +3034,7 @@ async function __flatMap_impl(arr, func) {
3034
3034
  await runner.step(1, async (runner2) => {
3035
3035
  __stack.locals.result = [];
3036
3036
  });
3037
- await runner.loop(2, __stack.args.arr, async (item, _, runner2) => {
3037
+ await runner.loop(2, async () => __stack.args.arr, async (item, _, runner2) => {
3038
3038
  await runner2.step(0, async (runner3) => {
3039
3039
  __stack.locals.mapped = await __call(__stack.args.func, {
3040
3040
  type: "positional",
@@ -3046,7 +3046,7 @@ async function __flatMap_impl(arr, func) {
3046
3046
  return;
3047
3047
  }
3048
3048
  });
3049
- await runner2.loop(1, __stack.locals.mapped, async (sub, _2, runner3) => {
3049
+ await runner2.loop(1, async () => __stack.locals.mapped, async (sub, _2, runner3) => {
3050
3050
  await runner3.step(0, async (runner4) => {
3051
3051
  await __callMethod(__stack.locals.result, "push", {
3052
3052
  type: "positional",
@@ -3186,7 +3186,7 @@ async function __every_impl(arr, func) {
3186
3186
  }
3187
3187
  });
3188
3188
  });
3189
- await runner.loop(1, __stack.args.arr, async (item, _, runner2) => {
3189
+ await runner.loop(1, async () => __stack.args.arr, async (item, _, runner2) => {
3190
3190
  await runner2.ifElse(0, [
3191
3191
  {
3192
3192
  condition: async () => __eq(await __call(__stack.args.func, {
@@ -3334,7 +3334,7 @@ async function __some_impl(arr, func) {
3334
3334
  }
3335
3335
  });
3336
3336
  });
3337
- await runner.loop(1, __stack.args.arr, async (item, _, runner2) => {
3337
+ await runner.loop(1, async () => __stack.args.arr, async (item, _, runner2) => {
3338
3338
  await runner2.ifElse(0, [
3339
3339
  {
3340
3340
  condition: async () => await __call(__stack.args.func, {
@@ -3485,7 +3485,7 @@ async function __count_impl(arr, func) {
3485
3485
  await runner.step(1, async (runner2) => {
3486
3486
  __stack.locals.n = 0;
3487
3487
  });
3488
- await runner.loop(2, __stack.args.arr, async (item, _, runner2) => {
3488
+ await runner.loop(2, async () => __stack.args.arr, async (item, _, runner2) => {
3489
3489
  await runner2.ifElse(0, [
3490
3490
  {
3491
3491
  condition: async () => await __call(__stack.args.func, {
@@ -3634,7 +3634,7 @@ async function __sortBy_impl(arr, func) {
3634
3634
  await runner.step(1, async (runner2) => {
3635
3635
  __stack.locals.result = [];
3636
3636
  });
3637
- await runner.loop(2, __stack.args.arr, async (item, _, runner2) => {
3637
+ await runner.loop(2, async () => __stack.args.arr, async (item, _, runner2) => {
3638
3638
  await runner2.step(0, async (runner3) => {
3639
3639
  await __callMethod(__stack.locals.result, "push", {
3640
3640
  type: "positional",
@@ -3817,7 +3817,7 @@ async function __unique_impl(arr, func) {
3817
3817
  await runner.step(2, async (runner2) => {
3818
3818
  __stack.locals.seen = [];
3819
3819
  });
3820
- await runner.loop(3, __stack.args.arr, async (item, _, runner2) => {
3820
+ await runner.loop(3, async () => __stack.args.arr, async (item, _, runner2) => {
3821
3821
  await runner2.step(0, async (runner3) => {
3822
3822
  __stack.locals.key = await __call(__stack.args.func, {
3823
3823
  type: "positional",
@@ -3832,7 +3832,7 @@ async function __unique_impl(arr, func) {
3832
3832
  await runner2.step(1, async (runner3) => {
3833
3833
  __stack.locals.found = false;
3834
3834
  });
3835
- await runner2.loop(2, __stack.locals.seen, async (s, _2, runner3) => {
3835
+ await runner2.loop(2, async () => __stack.locals.seen, async (s, _2, runner3) => {
3836
3836
  await runner3.ifElse(0, [
3837
3837
  {
3838
3838
  condition: async () => __eq(s, __stack.locals.key),
@@ -4003,7 +4003,7 @@ async function __groupBy_impl(arr, func) {
4003
4003
  args: [null]
4004
4004
  });
4005
4005
  });
4006
- await runner.loop(3, __stack.args.arr, async (item, _, runner2) => {
4006
+ await runner.loop(3, async () => __stack.args.arr, async (item, _, runner2) => {
4007
4007
  await runner2.step(0, async (runner3) => {
4008
4008
  __stack.locals.key = await __call(__stack.args.func, {
4009
4009
  type: "positional",
package/stdlib/llm.agency CHANGED
@@ -38,7 +38,8 @@ export type LlmDefaults = {
38
38
  temperature?: number;
39
39
  reasoningEffort?: "low" | "medium" | "high";
40
40
  maxTokens?: number;
41
- maxToolResultChars?: number
41
+ maxToolResultChars?: number;
42
+ maxToolCallRounds?: number
42
43
  }
43
44
 
44
45
  export def setLlmOptions(opts: LlmDefaults) {