brass-runtime 1.19.2 → 1.21.0

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 (44) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/dist/agent/cli/main.cjs +265 -43
  3. package/dist/agent/cli/main.d.ts +99 -0
  4. package/dist/agent/cli/main.js +238 -16
  5. package/dist/agent/cli/main.mjs +238 -16
  6. package/dist/agent/index.cjs +18 -2
  7. package/dist/agent/index.d.ts +60 -482
  8. package/dist/agent/index.js +17 -1
  9. package/dist/agent/index.mjs +17 -1
  10. package/dist/{chunk-QAHW7S3Q.cjs → chunk-62IBGQOU.cjs} +6 -6
  11. package/dist/{chunk-6AGAZD32.js → chunk-6LF3M4JC.js} +2 -2
  12. package/dist/{chunk-5X3MPWTR.mjs → chunk-6NXQL3IC.mjs} +370 -10
  13. package/dist/{chunk-J4F5KC3U.js → chunk-AI3M6624.js} +1260 -45
  14. package/dist/{chunk-TWEHIAUE.cjs → chunk-BDTBIYAM.cjs} +13 -13
  15. package/dist/{chunk-IA6BDGXW.mjs → chunk-D53GY2SZ.mjs} +2 -2
  16. package/dist/{chunk-IHY2EJTT.cjs → chunk-EX4VEKUF.cjs} +1340 -125
  17. package/dist/{chunk-UOKXJQAI.cjs → chunk-LA2PAO7J.cjs} +378 -18
  18. package/dist/{chunk-ZXXOXB3T.mjs → chunk-OS4F5HZE.mjs} +1 -1
  19. package/dist/{chunk-HKLZJ5UK.js → chunk-POH2WZBI.js} +370 -10
  20. package/dist/{chunk-6BNZS2A4.mjs → chunk-Q57ENQUW.mjs} +1260 -45
  21. package/dist/{chunk-BHX4MD35.js → chunk-VXZIP3IU.js} +1 -1
  22. package/dist/{defaultClient-hyVSNzSJ.d.ts → defaultClient-DLOa3gdw.d.ts} +101 -3
  23. package/dist/http/index.cjs +69 -33
  24. package/dist/http/index.d.ts +67 -4
  25. package/dist/http/index.js +37 -1
  26. package/dist/http/index.mjs +37 -1
  27. package/dist/http/testing.cjs +4 -4
  28. package/dist/http/testing.d.ts +1 -1
  29. package/dist/http/testing.js +1 -1
  30. package/dist/http/testing.mjs +1 -1
  31. package/dist/nodeWorkspaceDiscovery-Ami1UkMt.d.ts +631 -0
  32. package/dist/observability/index.cjs +3 -3
  33. package/dist/observability/index.d.ts +3 -3
  34. package/dist/observability/index.js +2 -2
  35. package/dist/observability/index.mjs +2 -2
  36. package/dist/perf/cli.cjs +18 -18
  37. package/dist/perf/cli.js +3 -3
  38. package/dist/perf/cli.mjs +3 -3
  39. package/dist/perf/index.cjs +5 -5
  40. package/dist/perf/index.js +3 -3
  41. package/dist/perf/index.mjs +3 -3
  42. package/dist/{server-BKKuzAW9.d.ts → server-BGXOabjo.d.ts} +1 -1
  43. package/package.json +1 -1
  44. package/wasm/pkg/package.json +1 -1
@@ -15,6 +15,7 @@ var _chunkJKHBEWQAcjs = require('./chunk-JKHBEWQA.cjs');
15
15
 
16
16
 
17
17
 
18
+
18
19
  var _chunkMVGUEJ5Zcjs = require('./chunk-MVGUEJ5Z.cjs');
19
20
 
20
21
  // src/agent/core/state.ts
@@ -62,6 +63,187 @@ var reduceAgentState = (state, observation) => {
62
63
  };
63
64
  var isTerminal = (state) => state.phase === "done" || state.phase === "failed" || state.steps >= MAX_AGENT_STEPS;
64
65
 
66
+ // src/agent/core/contextBudget/armExtraction.ts
67
+ var FALLBACK_ARM_ID = "__fallback__";
68
+ var COMPOUND_EXTENSIONS = [
69
+ ".test.ts",
70
+ ".test.tsx",
71
+ ".test.js",
72
+ ".test.jsx",
73
+ ".spec.ts",
74
+ ".spec.tsx",
75
+ ".spec.js",
76
+ ".spec.jsx",
77
+ ".pbt.test.ts",
78
+ ".pbt.test.js",
79
+ ".d.ts",
80
+ ".d.mts",
81
+ ".d.cts",
82
+ ".config.ts",
83
+ ".config.js",
84
+ ".config.mjs",
85
+ ".config.cjs",
86
+ ".module.ts",
87
+ ".module.css",
88
+ ".stories.tsx",
89
+ ".stories.ts"
90
+ ];
91
+ var extractExtension = (filename) => {
92
+ const lower = filename.toLowerCase();
93
+ for (const ext of COMPOUND_EXTENSIONS) {
94
+ if (lower.endsWith(ext) && filename.length > ext.length) {
95
+ return filename.slice(filename.length - ext.length);
96
+ }
97
+ }
98
+ const dotIndex = filename.lastIndexOf(".");
99
+ if (dotIndex > 0 && dotIndex < filename.length - 1) {
100
+ return filename.slice(dotIndex);
101
+ }
102
+ return "";
103
+ };
104
+ var normalizePath = (filePath) => filePath.replace(/\\/g, "/");
105
+ var deriveArmId = (filePath) => {
106
+ try {
107
+ if (!filePath || typeof filePath !== "string") {
108
+ return FALLBACK_ARM_ID;
109
+ }
110
+ const normalized = normalizePath(filePath.trim());
111
+ if (!normalized) {
112
+ return FALLBACK_ARM_ID;
113
+ }
114
+ const lastSlash = normalized.lastIndexOf("/");
115
+ const directory = lastSlash >= 0 ? normalized.slice(0, lastSlash) : "";
116
+ const filename = lastSlash >= 0 ? normalized.slice(lastSlash + 1) : normalized;
117
+ if (!filename) {
118
+ return FALLBACK_ARM_ID;
119
+ }
120
+ const extension = extractExtension(filename);
121
+ if (!extension) {
122
+ return FALLBACK_ARM_ID;
123
+ }
124
+ const glob = `*${extension}`;
125
+ return directory ? `${directory}/${glob}` : glob;
126
+ } catch (e) {
127
+ return FALLBACK_ARM_ID;
128
+ }
129
+ };
130
+ var assignArm = (filePath) => {
131
+ const id = deriveArmId(filePath);
132
+ return { id, pattern: id };
133
+ };
134
+ var groupByArm = (candidates) => {
135
+ const map = /* @__PURE__ */ new Map();
136
+ for (const path of candidates) {
137
+ const arm = assignArm(path);
138
+ const existing = map.get(arm.id);
139
+ if (existing) {
140
+ existing.push(path);
141
+ } else {
142
+ map.set(arm.id, [path]);
143
+ }
144
+ }
145
+ return map;
146
+ };
147
+
148
+ // src/agent/core/contextBudget/banditEngine.ts
149
+ var defaultArmStats = () => ({
150
+ alpha: 1,
151
+ beta: 1,
152
+ pulls: 0,
153
+ lastPulledAt: 0
154
+ });
155
+ var sampleBeta = (alpha, beta, rng) => {
156
+ const a = Math.max(alpha, 1e-3);
157
+ const b = Math.max(beta, 1e-3);
158
+ const x = sampleGamma(a, rng);
159
+ const y = sampleGamma(b, rng);
160
+ if (x + y === 0) return 0.5;
161
+ return x / (x + y);
162
+ };
163
+ var sampleGamma = (shape, rng) => {
164
+ if (shape < 1) {
165
+ const sample = sampleGamma(shape + 1, rng);
166
+ const u = rng();
167
+ return sample * Math.pow(u === 0 ? 1e-10 : u, 1 / shape);
168
+ }
169
+ const d = shape - 1 / 3;
170
+ const c = 1 / Math.sqrt(9 * d);
171
+ for (; ; ) {
172
+ let x;
173
+ let v;
174
+ do {
175
+ const u1 = rng();
176
+ const u2 = rng();
177
+ x = Math.sqrt(-2 * Math.log(u1 === 0 ? 1e-10 : u1)) * Math.cos(2 * Math.PI * u2);
178
+ v = 1 + c * x;
179
+ } while (v <= 0);
180
+ v = v * v * v;
181
+ const u = rng();
182
+ if (u < 1 - 0.0331 * (x * x) * (x * x)) {
183
+ return d * v;
184
+ }
185
+ if (Math.log(u === 0 ? 1e-10 : u) < 0.5 * x * x + d * (1 - v + Math.log(v))) {
186
+ return d * v;
187
+ }
188
+ }
189
+ };
190
+ var selectArms = (state, candidateArms, rng) => {
191
+ if (candidateArms.length === 0) return [];
192
+ const sampled = candidateArms.map((arm) => {
193
+ const stats = _nullishCoalesce(state.arms[arm.id], () => ( defaultArmStats()));
194
+ const value = sampleBeta(stats.alpha, stats.beta, rng);
195
+ return { arm, value };
196
+ });
197
+ sampled.sort((a, b) => b.value - a.value);
198
+ return sampled.map((s) => s.arm);
199
+ };
200
+
201
+ // src/agent/core/contextBudget/integration.ts
202
+ var shouldApplyBandit = (state, contextEnabled, hasInitialPatch) => {
203
+ if (Object.keys(state.arms).length === 0) return false;
204
+ if (!contextEnabled) return false;
205
+ if (hasInitialPatch) return false;
206
+ return true;
207
+ };
208
+ var reorderCandidates = (candidates, state, rng) => {
209
+ try {
210
+ if (Object.keys(state.arms).length === 0) {
211
+ return candidates;
212
+ }
213
+ const armGroups = groupByArm(candidates);
214
+ const uniqueArms = [];
215
+ for (const armId of armGroups.keys()) {
216
+ uniqueArms.push({ id: armId, pattern: armId });
217
+ }
218
+ const prioritizedArms = selectArms(state, uniqueArms, rng);
219
+ const result = [];
220
+ const includedArmIds = /* @__PURE__ */ new Set();
221
+ for (const arm of prioritizedArms) {
222
+ const paths = armGroups.get(arm.id);
223
+ if (paths) {
224
+ for (const p of paths) {
225
+ result.push(p);
226
+ }
227
+ includedArmIds.add(arm.id);
228
+ }
229
+ }
230
+ for (const [armId, paths] of armGroups) {
231
+ if (!includedArmIds.has(armId)) {
232
+ for (const p of paths) {
233
+ result.push(p);
234
+ }
235
+ }
236
+ }
237
+ return result;
238
+ } catch (error) {
239
+ console.warn(
240
+ "[contextBudget] reorderCandidates failed, returning original order:",
241
+ error instanceof Error ? error.message : String(error)
242
+ );
243
+ return candidates;
244
+ }
245
+ };
246
+
65
247
  // src/agent/core/contextDiscovery.ts
66
248
  var DEFAULT_CONTEXT_GLOBS = [
67
249
  "*.ts",
@@ -359,7 +541,7 @@ var summarizeContextDiscovery = (state) => {
359
541
  remainingFileBudget
360
542
  };
361
543
  };
362
- var nextContextDiscoveryAction = (state) => {
544
+ var nextContextDiscoveryAction = (state, banditState) => {
363
545
  const config = configFor(state);
364
546
  if (!config.enabled) return void 0;
365
547
  if (_optionalChain([state, 'access', _22 => _22.goal, 'access', _23 => _23.initialPatch, 'optionalAccess', _24 => _24.trim, 'call', _25 => _25()])) return void 0;
@@ -367,8 +549,14 @@ var nextContextDiscoveryAction = (state) => {
367
549
  const readsRemaining = Math.max(0, config.maxFiles - contextFileReadCount(state));
368
550
  const directPaths = extractLikelyFilePaths(state);
369
551
  const resultPaths = pathsFromSearchResults(state, config.maxSearchResults);
552
+ const allCandidates = [...directPaths, ...resultPaths];
553
+ const orderedCandidates = banditState && shouldApplyBandit(
554
+ banditState,
555
+ config.enabled,
556
+ Boolean(_optionalChain([state, 'access', _26 => _26.goal, 'access', _27 => _27.initialPatch, 'optionalAccess', _28 => _28.trim, 'call', _29 => _29()]))
557
+ ) ? reorderCandidates(allCandidates, banditState, Math.random) : allCandidates;
370
558
  if (readsRemaining > 0) {
371
- const nextPath = [...directPaths, ...resultPaths].find(
559
+ const nextPath = orderedCandidates.find(
372
560
  (path) => path !== "package.json" && !alreadyRead(state, path) && !knownMissing(state, path)
373
561
  );
374
562
  if (nextPath) {
@@ -416,7 +604,7 @@ var parsePackageJson = (state) => {
416
604
  try {
417
605
  const parsed = JSON.parse(observation.content);
418
606
  return isRecord(parsed) ? parsed : void 0;
419
- } catch (e) {
607
+ } catch (e2) {
420
608
  return void 0;
421
609
  }
422
610
  };
@@ -430,7 +618,7 @@ var packageScripts = (pkg) => {
430
618
  };
431
619
  var markerExists = (state, path) => state.observations.some((obs) => obs.type === "fs.exists" && obs.path === path && obs.exists);
432
620
  var hasDependencyName = (pkg, dependency) => {
433
- const collections = [_optionalChain([pkg, 'optionalAccess', _26 => _26.dependencies]), _optionalChain([pkg, 'optionalAccess', _27 => _27.devDependencies]), _optionalChain([pkg, 'optionalAccess', _28 => _28.optionalDependencies])];
621
+ const collections = [_optionalChain([pkg, 'optionalAccess', _30 => _30.dependencies]), _optionalChain([pkg, 'optionalAccess', _31 => _31.devDependencies]), _optionalChain([pkg, 'optionalAccess', _32 => _32.optionalDependencies])];
434
622
  return collections.some((collection) => isRecord(collection) && typeof collection[dependency] === "string");
435
623
  };
436
624
  var hasAnyDependency = (pkg, dependencies) => dependencies.some((dependency) => hasDependencyName(pkg, dependency));
@@ -459,7 +647,7 @@ var discoverProjectProfile = (state, packageManager) => {
459
647
  if (desktopPresent) stacks.push("desktop");
460
648
  const bridgePresent = markerExists(state, "bridges") || markerExists(state, "bridges/whatsmeow-bridge/Cargo.toml") || markerExists(state, "bridges/whatsmeow-bridge/package.json") || scriptNames.some((name) => name.includes("bridge"));
461
649
  if (bridgePresent) stacks.push("bridge");
462
- const monorepoPresent = markerExists(state, "pnpm-workspace.yaml") || markerExists(state, "turbo.json") || markerExists(state, "nx.json") || markerExists(state, "apps") || markerExists(state, "packages") || markerExists(state, "bridges") || Array.isArray(_optionalChain([pkg, 'optionalAccess', _29 => _29.workspaces]));
650
+ const monorepoPresent = markerExists(state, "pnpm-workspace.yaml") || markerExists(state, "turbo.json") || markerExists(state, "nx.json") || markerExists(state, "apps") || markerExists(state, "packages") || markerExists(state, "bridges") || Array.isArray(_optionalChain([pkg, 'optionalAccess', _33 => _33.workspaces]));
463
651
  if (monorepoPresent) stacks.push("monorepo");
464
652
  const candidateValidationScripts = unique2([
465
653
  ...scriptNamesMatching(scripts, [
@@ -541,7 +729,7 @@ var parseProjectPackageJson = (state) => {
541
729
  try {
542
730
  const parsed = JSON.parse(observation.content);
543
731
  return isRecord2(parsed) ? parsed : void 0;
544
- } catch (e2) {
732
+ } catch (e3) {
545
733
  return void 0;
546
734
  }
547
735
  };
@@ -556,7 +744,7 @@ var packageScripts2 = (pkg) => {
556
744
  var hasFsExistsObservation = (state, path) => state.observations.some((obs) => obs.type === "fs.exists" && obs.path === path);
557
745
  var nextProjectProbeAction = (state) => {
558
746
  const project = state.goal.project;
559
- if (!_optionalChain([project, 'optionalAccess', _30 => _30.validationCommands]) && (!_optionalChain([project, 'optionalAccess', _31 => _31.packageManager]) || project.packageManager === "auto")) {
747
+ if (!_optionalChain([project, 'optionalAccess', _34 => _34.validationCommands]) && (!_optionalChain([project, 'optionalAccess', _35 => _35.packageManager]) || project.packageManager === "auto")) {
560
748
  for (const path of PROJECT_LOCKFILE_PROBES) {
561
749
  if (!hasFsExistsObservation(state, path)) return { type: "fs.exists", path };
562
750
  }
@@ -565,9 +753,9 @@ var nextProjectProbeAction = (state) => {
565
753
  return profileProbe ? { type: "fs.exists", path: profileProbe } : void 0;
566
754
  };
567
755
  var packageManagerFromPackageJson = (pkg) => {
568
- const raw = typeof _optionalChain([pkg, 'optionalAccess', _32 => _32.packageManager]) === "string" ? pkg.packageManager : void 0;
756
+ const raw = typeof _optionalChain([pkg, 'optionalAccess', _36 => _36.packageManager]) === "string" ? pkg.packageManager : void 0;
569
757
  if (!raw) return void 0;
570
- const name = _optionalChain([raw, 'access', _33 => _33.split, 'call', _34 => _34("@"), 'access', _35 => _35[0], 'optionalAccess', _36 => _36.trim, 'call', _37 => _37()]);
758
+ const name = _optionalChain([raw, 'access', _37 => _37.split, 'call', _38 => _38("@"), 'access', _39 => _39[0], 'optionalAccess', _40 => _40.trim, 'call', _41 => _41()]);
571
759
  if (name === "npm" || name === "pnpm" || name === "yarn" || name === "bun") return name;
572
760
  return void 0;
573
761
  };
@@ -580,7 +768,7 @@ var packageManagerFromLockfiles = (state) => {
580
768
  return void 0;
581
769
  };
582
770
  var discoverPackageManager = (state) => {
583
- const configured = _optionalChain([state, 'access', _38 => _38.goal, 'access', _39 => _39.project, 'optionalAccess', _40 => _40.packageManager]);
771
+ const configured = _optionalChain([state, 'access', _42 => _42.goal, 'access', _43 => _43.project, 'optionalAccess', _44 => _44.packageManager]);
584
772
  if (configured && configured !== "auto") return configured;
585
773
  return _nullishCoalesce(_nullishCoalesce(packageManagerFromPackageJson(parseProjectPackageJson(state)), () => ( packageManagerFromLockfiles(state))), () => ( "npm"));
586
774
  };
@@ -668,7 +856,7 @@ var commandForScript = (packageManager, scriptName) => {
668
856
  }
669
857
  };
670
858
  var configuredValidationCommands = (project) => {
671
- if (!_optionalChain([project, 'optionalAccess', _41 => _41.validationCommands])) return void 0;
859
+ if (!_optionalChain([project, 'optionalAccess', _45 => _45.validationCommands])) return void 0;
672
860
  return project.validationCommands.map((command) => splitCommand(command)).filter((command) => command.length > 0);
673
861
  };
674
862
  var discoverValidationCommands = (state) => {
@@ -693,7 +881,7 @@ var discoverValidationCommands = (state) => {
693
881
  const notes = [];
694
882
  const testScript = firstExistingScript(
695
883
  scripts,
696
- _nullishCoalesce(_optionalChain([project, 'optionalAccess', _42 => _42.testScriptNames]), () => ( DEFAULT_TEST_SCRIPT_NAMES)),
884
+ _nullishCoalesce(_optionalChain([project, 'optionalAccess', _46 => _46.testScriptNames]), () => ( DEFAULT_TEST_SCRIPT_NAMES)),
697
885
  { skipPlaceholderTest: true }
698
886
  );
699
887
  if (testScript) {
@@ -707,7 +895,7 @@ var discoverValidationCommands = (state) => {
707
895
  notes.push(`Selected project health script: ${healthScript}.`);
708
896
  }
709
897
  }
710
- const includeTypecheck = _optionalChain([project, 'optionalAccess', _43 => _43.includeTypecheck]) === true || goalMentionsAny(state.goal.text, ["typecheck", "type-check", "type check", "types", "tsc"]) || commands.length === 0;
898
+ const includeTypecheck = _optionalChain([project, 'optionalAccess', _47 => _47.includeTypecheck]) === true || goalMentionsAny(state.goal.text, ["typecheck", "type-check", "type check", "types", "tsc"]) || commands.length === 0;
711
899
  if (includeTypecheck) {
712
900
  const typecheckScript = firstExistingScript(scripts, TYPECHECK_SCRIPT_NAMES);
713
901
  if (typecheckScript) {
@@ -715,7 +903,7 @@ var discoverValidationCommands = (state) => {
715
903
  notes.push(`Selected typecheck script: ${typecheckScript}.`);
716
904
  }
717
905
  }
718
- const includeLint = _optionalChain([project, 'optionalAccess', _44 => _44.includeLint]) === true || goalMentionsAny(state.goal.text, ["lint", "eslint"]) || commands.length === 0;
906
+ const includeLint = _optionalChain([project, 'optionalAccess', _48 => _48.includeLint]) === true || goalMentionsAny(state.goal.text, ["lint", "eslint"]) || commands.length === 0;
719
907
  if (includeLint) {
720
908
  const lintScript = firstExistingScript(scripts, LINT_SCRIPT_NAMES);
721
909
  if (lintScript) {
@@ -727,7 +915,7 @@ var discoverValidationCommands = (state) => {
727
915
  commands.push(["cargo", "check"]);
728
916
  notes.push("Selected Cargo check because a root Cargo.toml was detected.");
729
917
  }
730
- const max = _nullishCoalesce(_optionalChain([project, 'optionalAccess', _45 => _45.maxValidationCommands]), () => ( 2));
918
+ const max = _nullishCoalesce(_optionalChain([project, 'optionalAccess', _49 => _49.maxValidationCommands]), () => ( 2));
731
919
  const validationCommands = dedupeCommands(commands).slice(0, Math.max(0, max));
732
920
  return {
733
921
  packageManager,
@@ -755,9 +943,9 @@ var clampNonNegativeInteger = (value, fallback) => {
755
943
  };
756
944
  var patchRepairAttemptsUsed = (state) => state.observations.filter((obs) => obs.type === "llm.response" && obs.purpose === "patch").length;
757
945
  var patchQualitySummary = (state) => {
758
- const enabled = _nullishCoalesce(_optionalChain([state, 'access', _46 => _46.goal, 'access', _47 => _47.patchQuality, 'optionalAccess', _48 => _48.enabled]), () => ( true));
946
+ const enabled = _nullishCoalesce(_optionalChain([state, 'access', _50 => _50.goal, 'access', _51 => _51.patchQuality, 'optionalAccess', _52 => _52.enabled]), () => ( true));
759
947
  const maxRepairAttempts = clampNonNegativeInteger(
760
- _optionalChain([state, 'access', _49 => _49.goal, 'access', _50 => _50.patchQuality, 'optionalAccess', _51 => _51.maxRepairAttempts]),
948
+ _optionalChain([state, 'access', _53 => _53.goal, 'access', _54 => _54.patchQuality, 'optionalAccess', _55 => _55.maxRepairAttempts]),
761
949
  DEFAULT_MAX_REPAIR_ATTEMPTS
762
950
  );
763
951
  const repairAttemptsUsed = patchRepairAttemptsUsed(state);
@@ -766,7 +954,7 @@ var patchQualitySummary = (state) => {
766
954
  maxRepairAttempts,
767
955
  repairAttemptsUsed,
768
956
  repairsRemaining: Math.max(0, maxRepairAttempts - repairAttemptsUsed),
769
- exactSuppliedPatch: Boolean(_optionalChain([state, 'access', _52 => _52.goal, 'access', _53 => _53.initialPatch, 'optionalAccess', _54 => _54.trim, 'call', _55 => _55()]))
957
+ exactSuppliedPatch: Boolean(_optionalChain([state, 'access', _56 => _56.goal, 'access', _57 => _57.initialPatch, 'optionalAccess', _58 => _58.trim, 'call', _59 => _59()]))
770
958
  };
771
959
  };
772
960
  var canRequestPatchRepair = (state) => {
@@ -808,26 +996,26 @@ var clampNonNegativeInteger2 = (value, fallback) => {
808
996
  var rollbackStrategy = (value) => value === "last" ? "last" : "all";
809
997
  var rollbackSafetySummary = (state) => {
810
998
  const rollback = state.goal.rollback;
811
- const enabled = _nullishCoalesce(_optionalChain([rollback, 'optionalAccess', _56 => _56.enabled]), () => ( true));
812
- const maxRollbackDepth = clampNonNegativeInteger2(_optionalChain([rollback, 'optionalAccess', _57 => _57.maxRollbackDepth]), DEFAULT_MAX_ROLLBACK_DEPTH);
999
+ const enabled = _nullishCoalesce(_optionalChain([rollback, 'optionalAccess', _60 => _60.enabled]), () => ( true));
1000
+ const maxRollbackDepth = clampNonNegativeInteger2(_optionalChain([rollback, 'optionalAccess', _61 => _61.maxRollbackDepth]), DEFAULT_MAX_ROLLBACK_DEPTH);
813
1001
  const rollbackCount = state.observations.filter((obs) => obs.type === "patch.rolledBack").length;
814
1002
  const appliedStackDepth = unappliedPatchStack(state).length;
815
1003
  return {
816
1004
  enabled,
817
- onFinalValidationFailure: _nullishCoalesce(_optionalChain([rollback, 'optionalAccess', _58 => _58.onFinalValidationFailure]), () => ( true)),
818
- strategy: rollbackStrategy(_optionalChain([rollback, 'optionalAccess', _59 => _59.strategy])),
1005
+ onFinalValidationFailure: _nullishCoalesce(_optionalChain([rollback, 'optionalAccess', _62 => _62.onFinalValidationFailure]), () => ( true)),
1006
+ strategy: rollbackStrategy(_optionalChain([rollback, 'optionalAccess', _63 => _63.strategy])),
819
1007
  maxRollbackDepth,
820
- runValidationAfterRollback: _nullishCoalesce(_optionalChain([rollback, 'optionalAccess', _60 => _60.runValidationAfterRollback]), () => ( true)),
821
- allowForSuppliedPatches: _nullishCoalesce(_optionalChain([rollback, 'optionalAccess', _61 => _61.allowForSuppliedPatches]), () => ( false)),
1008
+ runValidationAfterRollback: _nullishCoalesce(_optionalChain([rollback, 'optionalAccess', _64 => _64.runValidationAfterRollback]), () => ( true)),
1009
+ allowForSuppliedPatches: _nullishCoalesce(_optionalChain([rollback, 'optionalAccess', _65 => _65.allowForSuppliedPatches]), () => ( false)),
822
1010
  rollbackCount,
823
1011
  appliedStackDepth,
824
- exactSuppliedPatch: Boolean(_optionalChain([state, 'access', _62 => _62.goal, 'access', _63 => _63.initialPatch, 'optionalAccess', _64 => _64.trim, 'call', _65 => _65()]))
1012
+ exactSuppliedPatch: Boolean(_optionalChain([state, 'access', _66 => _66.goal, 'access', _67 => _67.initialPatch, 'optionalAccess', _68 => _68.trim, 'call', _69 => _69()]))
825
1013
  };
826
1014
  };
827
1015
  var unappliedPatchStack = (state) => {
828
1016
  const stack = [];
829
1017
  for (const [index, observation] of state.observations.entries()) {
830
- if (observation.type === "patch.applied" && _optionalChain([observation, 'access', _66 => _66.patch, 'optionalAccess', _67 => _67.trim, 'call', _68 => _68()])) {
1018
+ if (observation.type === "patch.applied" && _optionalChain([observation, 'access', _70 => _70.patch, 'optionalAccess', _71 => _71.trim, 'call', _72 => _72()])) {
831
1019
  stack.push({
832
1020
  index,
833
1021
  patch: observation.patch,
@@ -835,8 +1023,8 @@ var unappliedPatchStack = (state) => {
835
1023
  });
836
1024
  continue;
837
1025
  }
838
- if (observation.type === "patch.rolledBack" && _optionalChain([observation, 'access', _69 => _69.patch, 'optionalAccess', _70 => _70.trim, 'call', _71 => _71()])) {
839
- const existingIndex = [...stack].reverse().findIndex((entry) => entry.patch.trim() === _optionalChain([observation, 'access', _72 => _72.patch, 'optionalAccess', _73 => _73.trim, 'call', _74 => _74()]));
1026
+ if (observation.type === "patch.rolledBack" && _optionalChain([observation, 'access', _73 => _73.patch, 'optionalAccess', _74 => _74.trim, 'call', _75 => _75()])) {
1027
+ const existingIndex = [...stack].reverse().findIndex((entry) => entry.patch.trim() === _optionalChain([observation, 'access', _76 => _76.patch, 'optionalAccess', _77 => _77.trim, 'call', _78 => _78()]));
840
1028
  if (existingIndex >= 0) {
841
1029
  stack.splice(stack.length - 1 - existingIndex, 1);
842
1030
  }
@@ -855,7 +1043,7 @@ var canAutoRollback = (state) => {
855
1043
  var shouldContinueRollbackStack = (state) => {
856
1044
  const summary = rollbackSafetySummary(state);
857
1045
  const latest = state.observations.at(-1);
858
- return _optionalChain([latest, 'optionalAccess', _75 => _75.type]) === "patch.rolledBack" && summary.strategy === "all" && canAutoRollback(state);
1046
+ return _optionalChain([latest, 'optionalAccess', _79 => _79.type]) === "patch.rolledBack" && summary.strategy === "all" && canAutoRollback(state);
859
1047
  };
860
1048
  var commandsEqual3 = (a, b) => a.length === b.length && a.every((part, index) => part === b[index]);
861
1049
  var shellResultsForCommands2 = (commands, observations) => commands.flatMap(
@@ -947,12 +1135,12 @@ var DEFAULT_SECRET_PATTERNS = [
947
1135
  var toRegExp = (pattern) => {
948
1136
  try {
949
1137
  return new RegExp(pattern, "gi");
950
- } catch (e3) {
1138
+ } catch (e4) {
951
1139
  return void 0;
952
1140
  }
953
1141
  };
954
- var configuredPatterns = (config) => (_nullishCoalesce(_optionalChain([config, 'optionalAccess', _76 => _76.additionalPatterns]), () => ( []))).map(toRegExp).filter((pattern) => Boolean(pattern));
955
- var isRedactionEnabled = (config) => _nullishCoalesce(_optionalChain([config, 'optionalAccess', _77 => _77.enabled]), () => ( true));
1142
+ var configuredPatterns = (config) => (_nullishCoalesce(_optionalChain([config, 'optionalAccess', _80 => _80.additionalPatterns]), () => ( []))).map(toRegExp).filter((pattern) => Boolean(pattern));
1143
+ var isRedactionEnabled = (config) => _nullishCoalesce(_optionalChain([config, 'optionalAccess', _81 => _81.enabled]), () => ( true));
956
1144
  var redactText = (value, config) => {
957
1145
  if (!isRedactionEnabled(config) || !value) return value;
958
1146
  return [...DEFAULT_SECRET_PATTERNS, ...configuredPatterns(config)].reduce(
@@ -989,8 +1177,8 @@ var inferUserLanguage = (text) => {
989
1177
  return void 0;
990
1178
  };
991
1179
  var configuredLanguageName = (language) => {
992
- const response = _nullishCoalesce(_optionalChain([language, 'optionalAccess', _78 => _78.response]), () => ( "auto"));
993
- if (response === "custom") return _optionalChain([language, 'optionalAccess', _79 => _79.custom, 'optionalAccess', _80 => _80.trim, 'call', _81 => _81()]) || void 0;
1180
+ const response = _nullishCoalesce(_optionalChain([language, 'optionalAccess', _82 => _82.response]), () => ( "auto"));
1181
+ if (response === "custom") return _optionalChain([language, 'optionalAccess', _83 => _83.custom, 'optionalAccess', _84 => _84.trim, 'call', _85 => _85()]) || void 0;
994
1182
  if (response === "auto" || response === "match-user") return void 0;
995
1183
  return LANGUAGE_LABELS[response];
996
1184
  };
@@ -1018,6 +1206,343 @@ var describeLanguagePolicy = (goal) => {
1018
1206
  };
1019
1207
  var spanishLike = (goal) => responseLanguageName(goal) === "Spanish";
1020
1208
 
1209
+ // src/agent/core/patchStrategy/types.ts
1210
+ var PATCH_STRATEGIES = [
1211
+ "direct-patch",
1212
+ "multi-step-patch",
1213
+ "propose-then-refine"
1214
+ ];
1215
+ var DEFAULT_STRATEGY = "direct-patch";
1216
+
1217
+ // src/agent/core/patchStrategy/thompson.ts
1218
+ var initialThompsonState = () => ({
1219
+ algorithm: "thompson",
1220
+ arms: {
1221
+ "direct-patch": { alpha: 1, beta: 1 },
1222
+ "multi-step-patch": { alpha: 1, beta: 1 },
1223
+ "propose-then-refine": { alpha: 1, beta: 1 }
1224
+ }
1225
+ });
1226
+ var thompsonSelect = (state, rng) => {
1227
+ let bestArm = PATCH_STRATEGIES[0];
1228
+ let bestSample = -Infinity;
1229
+ for (const arm of PATCH_STRATEGIES) {
1230
+ const { alpha, beta } = state.arms[arm];
1231
+ const sample = rng.sampleBeta(alpha, beta);
1232
+ if (sample > bestSample) {
1233
+ bestSample = sample;
1234
+ bestArm = arm;
1235
+ }
1236
+ }
1237
+ return bestArm;
1238
+ };
1239
+ var thompsonUpdate = (state, arm, reward) => {
1240
+ const clampedReward = Math.max(0, Math.min(1, reward));
1241
+ const current = state.arms[arm];
1242
+ const newAlpha = Math.max(1, current.alpha + clampedReward);
1243
+ const newBeta = Math.max(1, current.beta + (1 - clampedReward));
1244
+ return {
1245
+ ...state,
1246
+ arms: {
1247
+ ...state.arms,
1248
+ [arm]: { alpha: newAlpha, beta: newBeta }
1249
+ }
1250
+ };
1251
+ };
1252
+ var thompsonStateFromHistory = (history) => {
1253
+ let state = initialThompsonState();
1254
+ for (const entry of history) {
1255
+ state = thompsonUpdate(state, entry.arm, entry.reward);
1256
+ }
1257
+ return state;
1258
+ };
1259
+
1260
+ // src/agent/core/patchStrategy/exp3.ts
1261
+ var K = 3;
1262
+ var initialEXP3State = (gamma = 0.3) => ({
1263
+ algorithm: "exp3",
1264
+ arms: {
1265
+ "direct-patch": { weight: 1 },
1266
+ "multi-step-patch": { weight: 1 },
1267
+ "propose-then-refine": { weight: 1 }
1268
+ },
1269
+ gamma: Math.max(0, Math.min(1, gamma)) || 0.3,
1270
+ totalRounds: 0
1271
+ });
1272
+ var exp3Probabilities = (state) => {
1273
+ const { arms, gamma } = state;
1274
+ let weightSum = 0;
1275
+ for (const arm of PATCH_STRATEGIES) {
1276
+ weightSum += arms[arm].weight;
1277
+ }
1278
+ const probs = {};
1279
+ let probSum = 0;
1280
+ for (const arm of PATCH_STRATEGIES) {
1281
+ const p = (1 - gamma) * (arms[arm].weight / weightSum) + gamma / K;
1282
+ probs[arm] = p;
1283
+ probSum += p;
1284
+ }
1285
+ for (const arm of PATCH_STRATEGIES) {
1286
+ probs[arm] /= probSum;
1287
+ }
1288
+ return probs;
1289
+ };
1290
+ var exp3Select = (state, rng) => {
1291
+ const probs = exp3Probabilities(state);
1292
+ const r = rng.random();
1293
+ let cumulative = 0;
1294
+ for (const arm of PATCH_STRATEGIES) {
1295
+ cumulative += probs[arm];
1296
+ if (r < cumulative) {
1297
+ return arm;
1298
+ }
1299
+ }
1300
+ return PATCH_STRATEGIES[PATCH_STRATEGIES.length - 1];
1301
+ };
1302
+ var exp3Update = (state, arm, reward) => {
1303
+ const clampedReward = Math.max(0, Math.min(1, reward));
1304
+ const probs = exp3Probabilities(state);
1305
+ const pSelected = probs[arm];
1306
+ const estimatedReward = clampedReward / pSelected;
1307
+ const currentWeight = state.arms[arm].weight;
1308
+ const newWeight = Math.min(
1309
+ currentWeight * Math.exp(state.gamma * estimatedReward / K),
1310
+ 1e100
1311
+ );
1312
+ return {
1313
+ ...state,
1314
+ arms: {
1315
+ ...state.arms,
1316
+ [arm]: { weight: newWeight }
1317
+ },
1318
+ totalRounds: state.totalRounds + 1
1319
+ };
1320
+ };
1321
+ var exp3StateFromHistory = (history, gamma = 0.3) => {
1322
+ let state = initialEXP3State(gamma);
1323
+ for (const entry of history) {
1324
+ state = exp3Update(state, entry.arm, entry.reward);
1325
+ }
1326
+ return state;
1327
+ };
1328
+
1329
+ // src/agent/core/patchStrategy/selector.ts
1330
+ var selectStrategy = (_signals, config, history, rng) => {
1331
+ if (_optionalChain([config, 'optionalAccess', _86 => _86.enabled]) === false) {
1332
+ return DEFAULT_STRATEGY;
1333
+ }
1334
+ if (history.length === 0) {
1335
+ return DEFAULT_STRATEGY;
1336
+ }
1337
+ const algorithm = _nullishCoalesce(_optionalChain([config, 'optionalAccess', _87 => _87.algorithm]), () => ( "thompson"));
1338
+ switch (algorithm) {
1339
+ case "thompson": {
1340
+ const state = thompsonStateFromHistory(history);
1341
+ return thompsonSelect(state, rng);
1342
+ }
1343
+ case "exp3": {
1344
+ const rawGamma = _nullishCoalesce(_optionalChain([config, 'optionalAccess', _88 => _88.gamma]), () => ( 0.3));
1345
+ const gamma = Math.max(Number.EPSILON, Math.min(1, rawGamma)) || 0.3;
1346
+ const state = exp3StateFromHistory(history, gamma);
1347
+ return exp3Select(state, rng);
1348
+ }
1349
+ default: {
1350
+ const state = thompsonStateFromHistory(history);
1351
+ return thompsonSelect(state, rng);
1352
+ }
1353
+ }
1354
+ };
1355
+
1356
+ // src/agent/core/patchStrategy/signalExtractor.ts
1357
+ var FILE_EXTENSIONS = [
1358
+ "tsx",
1359
+ "jsx",
1360
+ "mts",
1361
+ "cts",
1362
+ "mjs",
1363
+ "cjs",
1364
+ "json",
1365
+ "yaml",
1366
+ "html",
1367
+ "scss",
1368
+ "ts",
1369
+ "js",
1370
+ "md",
1371
+ "yml",
1372
+ "css"
1373
+ ];
1374
+ var ASCII_CASE_BIT = 32;
1375
+ var MAX_FILE_PATH_CANDIDATE_LENGTH = 512;
1376
+ var KEYWORDS = [
1377
+ "refactor",
1378
+ "rename",
1379
+ "bug",
1380
+ "fix",
1381
+ "add",
1382
+ "create",
1383
+ "move",
1384
+ "delete"
1385
+ ];
1386
+ var KEYWORD_PATTERNS = new Map(
1387
+ KEYWORDS.map((kw) => [kw, new RegExp(`\\b${kw}\\b`, "i")])
1388
+ );
1389
+ var categorizeGoalLength = (text) => {
1390
+ const len = text.length;
1391
+ if (len < 80) return "short";
1392
+ if (len <= 300) return "medium";
1393
+ return "long";
1394
+ };
1395
+ var isAsciiAlpha = (code) => code >= 65 && code <= 90 || code >= 97 && code <= 122;
1396
+ var isAsciiDigit = (code) => code >= 48 && code <= 57;
1397
+ var isPathCandidateChar = (code) => isAsciiAlpha(code) || isAsciiDigit(code) || code === 95 || // _
1398
+ code === 64 || // @
1399
+ code === 46 || // .
1400
+ code === 45 || // -
1401
+ code === 47 || // /
1402
+ code === 92 || // \
1403
+ code === 58;
1404
+ var matchesExtension = (text, start, end, extension) => {
1405
+ if (end - start !== extension.length) return false;
1406
+ for (let offset = 0; offset < extension.length; offset++) {
1407
+ const textCode = text.charCodeAt(start + offset) | ASCII_CASE_BIT;
1408
+ if (textCode !== extension.charCodeAt(offset)) {
1409
+ return false;
1410
+ }
1411
+ }
1412
+ return true;
1413
+ };
1414
+ var matchesKnownExtension = (text, start, end) => {
1415
+ for (const extension of FILE_EXTENSIONS) {
1416
+ if (matchesExtension(text, start, end, extension)) {
1417
+ return true;
1418
+ }
1419
+ }
1420
+ return false;
1421
+ };
1422
+ var stripTrailingPathPunctuation = (text, start, end) => {
1423
+ let currentEnd = end;
1424
+ while (currentEnd > start) {
1425
+ const code = text.charCodeAt(currentEnd - 1);
1426
+ if (code !== 46 && code !== 58) break;
1427
+ currentEnd--;
1428
+ }
1429
+ return currentEnd;
1430
+ };
1431
+ var stripLineSuffixes = (text, start, end) => {
1432
+ let currentEnd = end;
1433
+ for (let suffixCount = 0; suffixCount < 2; suffixCount++) {
1434
+ let cursor = currentEnd - 1;
1435
+ if (cursor < start || !isAsciiDigit(text.charCodeAt(cursor))) break;
1436
+ while (cursor >= start && isAsciiDigit(text.charCodeAt(cursor))) {
1437
+ cursor--;
1438
+ }
1439
+ if (cursor < start || text.charCodeAt(cursor) !== 58) break;
1440
+ currentEnd = cursor;
1441
+ }
1442
+ return currentEnd;
1443
+ };
1444
+ var findLastDot = (text, start, end) => {
1445
+ for (let index = end - 1; index >= start; index--) {
1446
+ if (text.charCodeAt(index) === 46) {
1447
+ return index;
1448
+ }
1449
+ }
1450
+ return -1;
1451
+ };
1452
+ var findFilenameStart = (text, start, dotIndex) => {
1453
+ let filenameStart = start;
1454
+ for (let index = start; index < dotIndex; index++) {
1455
+ const code = text.charCodeAt(index);
1456
+ if (code === 47 || code === 92) {
1457
+ filenameStart = index + 1;
1458
+ }
1459
+ }
1460
+ return filenameStart;
1461
+ };
1462
+ var isFilePathCandidate = (text, start, end) => {
1463
+ const punctuationEnd = stripTrailingPathPunctuation(text, start, end);
1464
+ const pathEnd = stripLineSuffixes(text, start, punctuationEnd);
1465
+ const dotIndex = findLastDot(text, start, pathEnd);
1466
+ if (dotIndex < 0 || dotIndex + 1 >= pathEnd) return false;
1467
+ if (!matchesKnownExtension(text, dotIndex + 1, pathEnd)) return false;
1468
+ return dotIndex > findFilenameStart(text, start, dotIndex);
1469
+ };
1470
+ var detectFilePaths = (text) => {
1471
+ let candidateStart = -1;
1472
+ let candidateTooLong = false;
1473
+ for (let index = 0; index <= text.length; index++) {
1474
+ const isCandidateChar = index < text.length && isPathCandidateChar(text.charCodeAt(index));
1475
+ if (isCandidateChar) {
1476
+ if (candidateStart < 0) {
1477
+ candidateStart = index;
1478
+ }
1479
+ if (index + 1 - candidateStart > MAX_FILE_PATH_CANDIDATE_LENGTH) {
1480
+ candidateTooLong = true;
1481
+ }
1482
+ continue;
1483
+ }
1484
+ if (candidateStart >= 0) {
1485
+ if (!candidateTooLong && isFilePathCandidate(text, candidateStart, index)) {
1486
+ return true;
1487
+ }
1488
+ candidateStart = -1;
1489
+ candidateTooLong = false;
1490
+ }
1491
+ }
1492
+ return false;
1493
+ };
1494
+ var detectKeywords = (text) => {
1495
+ const result = {};
1496
+ for (const kw of KEYWORDS) {
1497
+ result[kw] = KEYWORD_PATTERNS.get(kw).test(text);
1498
+ }
1499
+ return result;
1500
+ };
1501
+ var extractContextSignals = (observations) => {
1502
+ let hasProjectProfile = false;
1503
+ let searchResultCount = 0;
1504
+ let discoveredFileCount = 0;
1505
+ for (const obs of observations) {
1506
+ switch (obs.type) {
1507
+ case "fs.fileRead":
1508
+ discoveredFileCount++;
1509
+ if (obs.path.endsWith("package.json")) {
1510
+ hasProjectProfile = true;
1511
+ }
1512
+ break;
1513
+ case "fs.searchResult":
1514
+ searchResultCount += obs.matches.length;
1515
+ break;
1516
+ }
1517
+ }
1518
+ return {
1519
+ hasProjectProfile,
1520
+ searchResultCount,
1521
+ discoveredFileCount
1522
+ };
1523
+ };
1524
+ var extractSignals = (state) => {
1525
+ const goalText = state.goal.text;
1526
+ return {
1527
+ goalLengthCategory: categorizeGoalLength(goalText),
1528
+ hasFilePaths: detectFilePaths(goalText),
1529
+ keywords: detectKeywords(goalText),
1530
+ contextSignals: extractContextSignals(state.observations)
1531
+ };
1532
+ };
1533
+
1534
+ // src/agent/core/patchStrategy/promptStrategy.ts
1535
+ var strategyPromptFragment = (strategy) => {
1536
+ switch (strategy) {
1537
+ case "direct-patch":
1538
+ return "Produce a single focused patch in one response. Do not plan multiple steps. Emit one unified diff that addresses the goal directly.";
1539
+ case "multi-step-patch":
1540
+ return "You may produce multiple incremental patches across responses. Start with the most critical change, then refine iteratively based on validation feedback.";
1541
+ case "propose-then-refine":
1542
+ return "First propose a plan describing what changes are needed and why. Do NOT include a patch in this response. After validation feedback, produce the refined patch in a follow-up.";
1543
+ }
1544
+ };
1545
+
1021
1546
  // src/agent/core/decide.ts
1022
1547
  var hasObservation = (state, type) => state.observations.some((obs) => obs.type === type);
1023
1548
  var lastObservation = (state, type) => [...state.observations].reverse().find((obs) => obs.type === type);
@@ -1039,7 +1564,7 @@ var observationsAfterLatestWorkspaceChange = (state) => {
1039
1564
  var latestWorkspaceChange = (state) => {
1040
1565
  const index = latestWorkspaceChangeIndex(state);
1041
1566
  const observation = index < 0 ? void 0 : state.observations[index];
1042
- return _optionalChain([observation, 'optionalAccess', _82 => _82.type]) === "patch.applied" || _optionalChain([observation, 'optionalAccess', _83 => _83.type]) === "patch.rolledBack" ? observation : void 0;
1567
+ return _optionalChain([observation, 'optionalAccess', _89 => _89.type]) === "patch.applied" || _optionalChain([observation, 'optionalAccess', _90 => _90.type]) === "patch.rolledBack" ? observation : void 0;
1043
1568
  };
1044
1569
  var compactObservation = (obs) => {
1045
1570
  switch (obs.type) {
@@ -1102,13 +1627,13 @@ var causeMessage = (cause) => {
1102
1627
  try {
1103
1628
  const json = JSON.stringify(cause);
1104
1629
  if (json && json !== "{}") return json;
1105
- } catch (e4) {
1630
+ } catch (e5) {
1106
1631
  }
1107
1632
  }
1108
1633
  return String(cause);
1109
1634
  };
1110
1635
  var errorDetail = (state, cause) => redactForPrompt(state, causeMessage(cause)).slice(0, 2e3);
1111
- var buildPlanningPrompt = (state) => {
1636
+ var buildPlanningPrompt = (state, strategy) => {
1112
1637
  const discovery = discoverValidationCommands(state);
1113
1638
  return redactForPrompt(state, [
1114
1639
  "You are a coding agent running on brass-runtime.",
@@ -1119,6 +1644,7 @@ var buildPlanningPrompt = (state) => {
1119
1644
  "Only propose a patch when the observations are strong enough.",
1120
1645
  "Use the project command discovery summary as context, but do not invent commands that were not run.",
1121
1646
  describeLanguagePolicy(state.goal),
1647
+ strategy ? strategyPromptFragment(strategy) : "",
1122
1648
  "",
1123
1649
  `Goal: ${state.goal.text}`,
1124
1650
  `Workspace: ${state.goal.cwd}`,
@@ -1142,7 +1668,7 @@ ${result.stderr.slice(-8e3)}` : void 0
1142
1668
  var buildPatchRepairPrompt = (state, reason) => {
1143
1669
  const discovery = discoverValidationCommands(state);
1144
1670
  const quality = patchQualitySummary(state);
1145
- const latestPatchError = _optionalChain([lastObservation, 'call', _84 => _84(state, "agent.error"), 'optionalAccess', _85 => _85.error]);
1671
+ const latestPatchError = _optionalChain([lastObservation, 'call', _91 => _91(state, "agent.error"), 'optionalAccess', _92 => _92.error]);
1146
1672
  const latestPatch = lastMaterializedPatch(state);
1147
1673
  return redactForPrompt(state, [
1148
1674
  "You are repairing a generated patch for a coding agent running on brass-runtime.",
@@ -1168,7 +1694,7 @@ ${latestPatch.slice(-8e3)}` : "Latest materialized patch: none.",
1168
1694
  failedValidationLines(state).length > 0 ? `Failed validation after latest patch:
1169
1695
  ${failedValidationLines(state).join("\n\n")}` : "Failed validation after latest patch: none recorded.",
1170
1696
  "",
1171
- _optionalChain([latestPatchError, 'optionalAccess', _86 => _86._tag]) === "PatchError" ? `Latest patch error during ${latestPatchError.operation}: ${String(latestPatchError.cause)}` : "Latest patch error: none.",
1697
+ _optionalChain([latestPatchError, 'optionalAccess', _93 => _93._tag]) === "PatchError" ? `Latest patch error during ${latestPatchError.operation}: ${String(latestPatchError.cause)}` : "Latest patch error: none.",
1172
1698
  "",
1173
1699
  "Recent observations:",
1174
1700
  compactObservations(state) || "No observations yet."
@@ -1180,14 +1706,14 @@ var buildValidationSummary = (state) => {
1180
1706
  if (validationResults.length === 0) return void 0;
1181
1707
  const change = latestWorkspaceChange(state);
1182
1708
  const spanish = spanishLike(state.goal);
1183
- const label = _optionalChain([change, 'optionalAccess', _87 => _87.type]) === "patch.rolledBack" ? spanish ? "rollback" : "rollback" : spanish ? "aplicar patch" : "apply";
1709
+ const label = _optionalChain([change, 'optionalAccess', _94 => _94.type]) === "patch.rolledBack" ? spanish ? "rollback" : "rollback" : spanish ? "aplicar patch" : "apply";
1184
1710
  return [
1185
1711
  spanish ? `Validaci\xF3n despu\xE9s de ${label}:` : `Validation after latest ${label}:`,
1186
1712
  ...validationResults.map((result) => `- ${result.command.join(" ")} ${spanish ? "termin\xF3 con c\xF3digo" : "exited with"} ${result.exitCode}.`)
1187
1713
  ].join("\n");
1188
1714
  };
1189
1715
  var buildCompletionSummary = (state, patch) => {
1190
- const plan = _nullishCoalesce(_optionalChain([firstObservation, 'call', _88 => _88(state, "llm.response"), 'optionalAccess', _89 => _89.content, 'optionalAccess', _90 => _90.trim, 'call', _91 => _91()]), () => ( "No plan was generated."));
1716
+ const plan = _nullishCoalesce(_optionalChain([firstObservation, 'call', _95 => _95(state, "llm.response"), 'optionalAccess', _96 => _96.content, 'optionalAccess', _97 => _97.trim, 'call', _98 => _98()]), () => ( "No plan was generated."));
1191
1717
  const latestResponse = lastObservation(state, "llm.response");
1192
1718
  const patchApplied = lastObservation(state, "patch.applied");
1193
1719
  const patchRolledBack = lastObservation(state, "patch.rolledBack");
@@ -1195,7 +1721,7 @@ var buildCompletionSummary = (state, patch) => {
1195
1721
  const validation = buildValidationSummary(state);
1196
1722
  const spanish = spanishLike(state.goal);
1197
1723
  const lines = [plan];
1198
- if (_optionalChain([latestResponse, 'optionalAccess', _92 => _92.purpose]) === "patch" && latestResponse.content.trim()) {
1724
+ if (_optionalChain([latestResponse, 'optionalAccess', _99 => _99.purpose]) === "patch" && latestResponse.content.trim()) {
1199
1725
  lines.push("", spanish ? "\xDAltima respuesta de reparaci\xF3n del patch:" : "Latest patch repair response:", latestResponse.content.trim());
1200
1726
  }
1201
1727
  if (patchRolledBack) {
@@ -1219,14 +1745,14 @@ var buildCompletionSummary = (state, patch) => {
1219
1745
  return redactForPrompt(state, lines.join("\n").trim());
1220
1746
  };
1221
1747
  var buildErrorSummary = (state) => {
1222
- const latestError = _optionalChain([lastObservation, 'call', _93 => _93(state, "agent.error"), 'optionalAccess', _94 => _94.error]);
1748
+ const latestError = _optionalChain([lastObservation, 'call', _100 => _100(state, "agent.error"), 'optionalAccess', _101 => _101.error]);
1223
1749
  const spanish = spanishLike(state.goal);
1224
1750
  if (!latestError) return spanish ? "La ejecuci\xF3n del agente fall\xF3." : "Agent run failed.";
1225
1751
  switch (latestError._tag) {
1226
1752
  case "FsError":
1227
1753
  return spanish ? `El agente se detuvo por un error de filesystem durante ${latestError.operation}: ${errorDetail(state, latestError.cause)}` : `Agent stopped after a filesystem error during ${latestError.operation}: ${errorDetail(state, latestError.cause)}`;
1228
1754
  case "ShellError":
1229
- return spanish ? `El agente se detuvo por un error ejecutando ${_nullishCoalesce(_optionalChain([latestError, 'access', _95 => _95.command, 'optionalAccess', _96 => _96.join, 'call', _97 => _97(" ")]), () => ( latestError.operation))}: ${errorDetail(state, latestError.cause)}` : `Agent stopped after a shell error during ${_nullishCoalesce(_optionalChain([latestError, 'access', _98 => _98.command, 'optionalAccess', _99 => _99.join, 'call', _100 => _100(" ")]), () => ( latestError.operation))}: ${errorDetail(state, latestError.cause)}`;
1755
+ return spanish ? `El agente se detuvo por un error ejecutando ${_nullishCoalesce(_optionalChain([latestError, 'access', _102 => _102.command, 'optionalAccess', _103 => _103.join, 'call', _104 => _104(" ")]), () => ( latestError.operation))}: ${errorDetail(state, latestError.cause)}` : `Agent stopped after a shell error during ${_nullishCoalesce(_optionalChain([latestError, 'access', _105 => _105.command, 'optionalAccess', _106 => _106.join, 'call', _107 => _107(" ")]), () => ( latestError.operation))}: ${errorDetail(state, latestError.cause)}`;
1230
1756
  case "LLMError":
1231
1757
  return spanish ? `El agente se detuvo porque fall\xF3 la llamada al modelo: ${errorDetail(state, latestError.cause)}` : `Agent stopped because the model call failed: ${errorDetail(state, latestError.cause)}`;
1232
1758
  case "PatchError":
@@ -1274,7 +1800,7 @@ var latestLlmPatchCandidate = (state) => {
1274
1800
  var latestExtractedPatch = (state) => {
1275
1801
  for (let index = state.observations.length - 1; index >= 0; index -= 1) {
1276
1802
  const observation = state.observations[index];
1277
- if (_optionalChain([observation, 'optionalAccess', _101 => _101.type]) !== "llm.response") continue;
1803
+ if (_optionalChain([observation, 'optionalAccess', _108 => _108.type]) !== "llm.response") continue;
1278
1804
  const patch = extractUnifiedDiff(observation.content);
1279
1805
  if (patch) return patch;
1280
1806
  }
@@ -1283,8 +1809,8 @@ var latestExtractedPatch = (state) => {
1283
1809
  var lastMaterializedPatch = (state) => {
1284
1810
  for (let index = state.observations.length - 1; index >= 0; index -= 1) {
1285
1811
  const observation = state.observations[index];
1286
- if (_optionalChain([observation, 'optionalAccess', _102 => _102.type]) === "patch.proposed") return observation.patch;
1287
- if (_optionalChain([observation, 'optionalAccess', _103 => _103.type]) === "patch.applied") {
1812
+ if (_optionalChain([observation, 'optionalAccess', _109 => _109.type]) === "patch.proposed") return observation.patch;
1813
+ if (_optionalChain([observation, 'optionalAccess', _110 => _110.type]) === "patch.applied") {
1288
1814
  if (observation.patch) return observation.patch;
1289
1815
  const previousLlmPatch = state.observations.slice(0, index).reverse().find((obs) => obs.type === "llm.response" && Boolean(extractUnifiedDiff(obs.content)));
1290
1816
  return previousLlmPatch ? extractUnifiedDiff(previousLlmPatch.content) : state.goal.initialPatch;
@@ -1294,7 +1820,7 @@ var lastMaterializedPatch = (state) => {
1294
1820
  };
1295
1821
  var shouldRequestRepairAfterValidation = (state) => {
1296
1822
  if (!isWritableMode(state.goal.mode)) return false;
1297
- if (_optionalChain([latestWorkspaceChange, 'call', _104 => _104(state), 'optionalAccess', _105 => _105.type]) !== "patch.applied") return false;
1823
+ if (_optionalChain([latestWorkspaceChange, 'call', _111 => _111(state), 'optionalAccess', _112 => _112.type]) !== "patch.applied") return false;
1298
1824
  if (!canRequestPatchRepair(state)) return false;
1299
1825
  const commands = discoverValidationCommands(state).validationCommands;
1300
1826
  const status = patchValidationStatus(commands, observationsAfterPatch(state));
@@ -1302,7 +1828,7 @@ var shouldRequestRepairAfterValidation = (state) => {
1302
1828
  };
1303
1829
  var shouldAutoRollbackAfterFinalValidationFailure = (state) => {
1304
1830
  if (!isWritableMode(state.goal.mode)) return false;
1305
- if (_optionalChain([latestWorkspaceChange, 'call', _106 => _106(state), 'optionalAccess', _107 => _107.type]) !== "patch.applied") return false;
1831
+ if (_optionalChain([latestWorkspaceChange, 'call', _113 => _113(state), 'optionalAccess', _114 => _114.type]) !== "patch.applied") return false;
1306
1832
  if (canRequestPatchRepair(state)) return false;
1307
1833
  const summary = rollbackSafetySummary(state);
1308
1834
  if (!summary.onFinalValidationFailure) return false;
@@ -1315,7 +1841,7 @@ var shouldRequestRepairAfterPatchError = (state) => {
1315
1841
  if (!isWritableMode(state.goal.mode)) return false;
1316
1842
  if (!canRequestPatchRepair(state)) return false;
1317
1843
  const latest = state.observations.at(-1);
1318
- return _optionalChain([latest, 'optionalAccess', _108 => _108.type]) === "agent.error" && latest.error._tag === "PatchError";
1844
+ return _optionalChain([latest, 'optionalAccess', _115 => _115.type]) === "agent.error" && latest.error._tag === "PatchError";
1319
1845
  };
1320
1846
  var repairAction = (state, reason) => ({
1321
1847
  type: "llm.complete",
@@ -1352,8 +1878,11 @@ var initialPatchFlowAction = (state, suppliedPatch) => {
1352
1878
  };
1353
1879
  var decideNextAction = (state) => {
1354
1880
  const latest = state.observations.at(-1);
1355
- if (_optionalChain([latest, 'optionalAccess', _109 => _109.type]) === "agent.error") {
1881
+ if (_optionalChain([latest, 'optionalAccess', _116 => _116.type]) === "agent.error") {
1356
1882
  if (shouldRequestRepairAfterPatchError(state)) {
1883
+ if (state.goal.llmAvailable === false) {
1884
+ return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, { type: "agent.finish", summary: buildErrorSummary(state) });
1885
+ }
1357
1886
  return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, repairAction(state, "previous patch failed to apply"));
1358
1887
  }
1359
1888
  return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, { type: "agent.finish", summary: buildErrorSummary(state) });
@@ -1365,7 +1894,7 @@ var decideNextAction = (state) => {
1365
1894
  if (probeAction) {
1366
1895
  return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, probeAction);
1367
1896
  }
1368
- const suppliedPatch = _optionalChain([state, 'access', _110 => _110.goal, 'access', _111 => _111.initialPatch, 'optionalAccess', _112 => _112.trim, 'call', _113 => _113()]);
1897
+ const suppliedPatch = _optionalChain([state, 'access', _117 => _117.goal, 'access', _118 => _118.initialPatch, 'optionalAccess', _119 => _119.trim, 'call', _120 => _120()]);
1369
1898
  if (suppliedPatch) {
1370
1899
  const action = initialPatchFlowAction(state, suppliedPatch);
1371
1900
  if (action) return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, action);
@@ -1389,12 +1918,25 @@ var decideNextAction = (state) => {
1389
1918
  if (!planResponse) {
1390
1919
  const validationAction = nextValidationActionBeforePlanning(state);
1391
1920
  if (validationAction) return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, validationAction);
1392
- const contextAction = nextContextDiscoveryAction(state);
1921
+ const contextAction = nextContextDiscoveryAction(state, state.goal.banditState);
1393
1922
  if (contextAction) return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, contextAction);
1923
+ if (state.goal.llmAvailable === false) {
1924
+ return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, {
1925
+ type: "agent.finish",
1926
+ summary: "No LLM provider configured. Tool-only execution complete."
1927
+ });
1928
+ }
1929
+ const signals = extractSignals(state);
1930
+ const strategy = selectStrategy(
1931
+ signals,
1932
+ state.goal.patchStrategy,
1933
+ _nullishCoalesce(state.goal.rewardHistory, () => ( [])),
1934
+ { sampleBeta: (a, b) => sampleBeta(a, b, Math.random), random: Math.random }
1935
+ );
1394
1936
  return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, {
1395
1937
  type: "llm.complete",
1396
1938
  purpose: "plan",
1397
- prompt: buildPlanningPrompt(state)
1939
+ prompt: buildPlanningPrompt(state, strategy)
1398
1940
  });
1399
1941
  }
1400
1942
  if (isWritableMode(state.goal.mode)) {
@@ -1402,17 +1944,20 @@ var decideNextAction = (state) => {
1402
1944
  const rollbackAction = automaticRollbackAction(state, "continuing rollback of generated patch stack");
1403
1945
  if (rollbackAction) return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, rollbackAction);
1404
1946
  }
1405
- if (_optionalChain([latestWorkspaceChange, 'call', _114 => _114(state), 'optionalAccess', _115 => _115.type]) === "patch.rolledBack") {
1947
+ if (_optionalChain([latestWorkspaceChange, 'call', _121 => _121(state), 'optionalAccess', _122 => _122.type]) === "patch.rolledBack") {
1406
1948
  const summary = rollbackSafetySummary(state);
1407
1949
  if (summary.runValidationAfterRollback) {
1408
1950
  const validationAction = nextValidationActionAfterLatestWorkspaceChange(state);
1409
1951
  if (validationAction) return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, validationAction);
1410
1952
  }
1411
1953
  }
1412
- if (_optionalChain([latestWorkspaceChange, 'call', _116 => _116(state), 'optionalAccess', _117 => _117.type]) === "patch.applied") {
1954
+ if (_optionalChain([latestWorkspaceChange, 'call', _123 => _123(state), 'optionalAccess', _124 => _124.type]) === "patch.applied") {
1413
1955
  const validationAction = nextValidationActionAfterPatch(state);
1414
1956
  if (validationAction) return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, validationAction);
1415
1957
  if (shouldRequestRepairAfterValidation(state)) {
1958
+ if (state.goal.llmAvailable === false) {
1959
+ return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, { type: "agent.finish", summary: buildErrorSummary(state) });
1960
+ }
1416
1961
  return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, repairAction(state, "validation failed after applying the generated patch"));
1417
1962
  }
1418
1963
  if (shouldAutoRollbackAfterFinalValidationFailure(state)) {
@@ -1434,8 +1979,8 @@ var nowMillis = () => _chunkMVGUEJ5Zcjs.asyncEffect.call(void 0, (_env, cb) => {
1434
1979
  });
1435
1980
  var emitAgentEvent = (event) => _chunkMVGUEJ5Zcjs.asyncEffect.call(void 0, (env, cb) => {
1436
1981
  try {
1437
- _optionalChain([env, 'access', _118 => _118.events, 'optionalAccess', _119 => _119.emit, 'call', _120 => _120(event)]);
1438
- } catch (e5) {
1982
+ _optionalChain([env, 'access', _125 => _125.events, 'optionalAccess', _126 => _126.emit, 'call', _127 => _127(event)]);
1983
+ } catch (e6) {
1439
1984
  }
1440
1985
  cb({ _tag: "Success", value: void 0 });
1441
1986
  });
@@ -1632,13 +2177,22 @@ var actionToEffect = (action, state) => {
1632
2177
  )
1633
2178
  );
1634
2179
  case "llm.complete":
1635
- return _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0,
1636
- service("llm"),
1637
- (llm) => _chunkMVGUEJ5Zcjs.asyncMap.call(void 0,
2180
+ return _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0, service("llm"), (llm) => {
2181
+ if (!llm) {
2182
+ return _chunkMVGUEJ5Zcjs.asyncFail.call(void 0, {
2183
+ _tag: "LLMError",
2184
+ cause: "llm_unavailable: no LLM provider is configured"
2185
+ });
2186
+ }
2187
+ return _chunkMVGUEJ5Zcjs.asyncMap.call(void 0,
1638
2188
  llm.complete({ purpose: action.purpose, prompt: action.prompt }),
1639
- (response) => ({ type: "llm.response", purpose: action.purpose, content: response.content })
1640
- )
1641
- );
2189
+ (response) => ({
2190
+ type: "llm.response",
2191
+ purpose: action.purpose,
2192
+ content: response.content
2193
+ })
2194
+ );
2195
+ });
1642
2196
  case "patch.propose":
1643
2197
  return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, { type: "patch.proposed", patch: action.patch });
1644
2198
  case "patch.apply":
@@ -1721,11 +2275,11 @@ var defaultPolicyFor = (action) => {
1721
2275
  };
1722
2276
  var configuredPolicyFor = (action, overrides) => {
1723
2277
  const base = defaultPolicyFor(action);
1724
- const override = _optionalChain([overrides, 'optionalAccess', _121 => _121[action.type]]);
2278
+ const override = _optionalChain([overrides, 'optionalAccess', _128 => _128[action.type]]);
1725
2279
  return {
1726
2280
  ...base,
1727
- timeoutMs: _optionalChain([override, 'optionalAccess', _122 => _122.timeoutMs]) !== void 0 ? Math.max(1, Math.floor(override.timeoutMs)) : base.timeoutMs,
1728
- retries: _optionalChain([override, 'optionalAccess', _123 => _123.retries]) !== void 0 ? Math.max(0, Math.floor(override.retries)) : base.retries
2281
+ timeoutMs: _optionalChain([override, 'optionalAccess', _129 => _129.timeoutMs]) !== void 0 ? Math.max(1, Math.floor(override.timeoutMs)) : base.timeoutMs,
2282
+ retries: _optionalChain([override, 'optionalAccess', _130 => _130.retries]) !== void 0 ? Math.max(0, Math.floor(override.retries)) : base.retries
1729
2283
  };
1730
2284
  };
1731
2285
  var runAuthorizedAction = (action, state, scope) => _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0, _chunkMVGUEJ5Zcjs.asyncSync.call(void 0, (env) => env.toolPolicies), (toolPolicies) => {
@@ -1821,7 +2375,265 @@ var invokeAction = (action, state, scope) => _chunkMVGUEJ5Zcjs.asyncFlatMap.call
1821
2375
  })
1822
2376
  );
1823
2377
 
2378
+ // src/agent/core/llmBudget/config.ts
2379
+ var DEFAULTS = {
2380
+ overshootFraction: 0.1,
2381
+ enabled: true
2382
+ };
2383
+ var resolveBudgetConfig = (goalBudget, configBudget) => {
2384
+ if (goalBudget === void 0 && configBudget === void 0) {
2385
+ return void 0;
2386
+ }
2387
+ const merged = {
2388
+ ...configBudget,
2389
+ ...goalBudget
2390
+ };
2391
+ if (merged.tokenBudget === void 0) {
2392
+ return void 0;
2393
+ }
2394
+ return {
2395
+ tokenBudget: merged.tokenBudget,
2396
+ overshootFraction: _nullishCoalesce(merged.overshootFraction, () => ( DEFAULTS.overshootFraction)),
2397
+ enabled: _nullishCoalesce(merged.enabled, () => ( DEFAULTS.enabled)),
2398
+ modelTiers: merged.modelTiers
2399
+ };
2400
+ };
2401
+ var validateBudgetConfig = (config) => {
2402
+ if (!Number.isFinite(config.tokenBudget) || config.tokenBudget <= 0) {
2403
+ return `tokenBudget must be a positive finite number, got ${config.tokenBudget}`;
2404
+ }
2405
+ if (!Number.isFinite(config.overshootFraction) || config.overshootFraction < 0 || config.overshootFraction > 1) {
2406
+ return `overshootFraction must be between 0 and 1 inclusive, got ${config.overshootFraction}`;
2407
+ }
2408
+ return void 0;
2409
+ };
2410
+
2411
+ // src/agent/core/llmBudget/state.ts
2412
+ var initBudgetState = () => ({
2413
+ totalInputTokens: 0,
2414
+ totalOutputTokens: 0,
2415
+ totalTokens: 0,
2416
+ callCount: 0,
2417
+ calls: []
2418
+ });
2419
+ var updateBudgetState = (state, usage, tier, confidence, estimated) => {
2420
+ const totalInputTokens = state.totalInputTokens + usage.inputTokens;
2421
+ const totalOutputTokens = state.totalOutputTokens + usage.outputTokens;
2422
+ return {
2423
+ totalInputTokens,
2424
+ totalOutputTokens,
2425
+ totalTokens: totalInputTokens + totalOutputTokens,
2426
+ callCount: state.callCount + 1,
2427
+ calls: [
2428
+ ...state.calls,
2429
+ { usage, tier, confidence, estimated }
2430
+ ]
2431
+ };
2432
+ };
2433
+ var budgetStatus = (state, config) => {
2434
+ const { totalTokens } = state;
2435
+ const { tokenBudget, overshootFraction } = config;
2436
+ const hardCap = tokenBudget * (1 + overshootFraction);
2437
+ if (totalTokens <= tokenBudget) {
2438
+ return { type: "under" };
2439
+ }
2440
+ if (totalTokens <= hardCap) {
2441
+ return { type: "warning", overage: totalTokens - tokenBudget };
2442
+ }
2443
+ return { type: "exceeded", overage: totalTokens - tokenBudget };
2444
+ };
2445
+ var budgetAllowsCall = (state, config) => {
2446
+ return budgetStatus(state, config).type !== "exceeded";
2447
+ };
2448
+
2449
+ // src/agent/core/llmBudget/estimation.ts
2450
+ var estimateTokens = (promptLength, responseLength) => ({
2451
+ inputTokens: Math.ceil(promptLength / 4),
2452
+ outputTokens: Math.ceil(responseLength / 4)
2453
+ });
2454
+
2455
+ // src/agent/core/llmBudget/confidence.ts
2456
+ var HEDGING_PHRASES = [
2457
+ "i think",
2458
+ "maybe",
2459
+ "perhaps",
2460
+ "not sure",
2461
+ "might be",
2462
+ "could be"
2463
+ ];
2464
+ var hasDiffBlock = (response) => {
2465
+ if (response.includes("```diff")) return true;
2466
+ const lines = response.split("\n");
2467
+ return lines.some(
2468
+ (line) => line.startsWith("---") || line.startsWith("+++")
2469
+ );
2470
+ };
2471
+ var isConcise = (response) => response.length < 2e3;
2472
+ var referencesGoal = (response, goal) => {
2473
+ const words = goal.split(/\s+/).filter((w) => w.length >= 3).map((w) => w.toLowerCase());
2474
+ const responseLower = response.toLowerCase();
2475
+ return words.some((word) => responseLower.includes(word));
2476
+ };
2477
+ var referencesReadFiles = (response, readFiles) => {
2478
+ if (readFiles.length === 0) return false;
2479
+ return readFiles.some((filePath) => response.includes(filePath));
2480
+ };
2481
+ var countHedgingPhrases = (response) => {
2482
+ const responseLower = response.toLowerCase();
2483
+ let count = 0;
2484
+ for (const phrase of HEDGING_PHRASES) {
2485
+ let idx = 0;
2486
+ while (true) {
2487
+ const found = responseLower.indexOf(phrase, idx);
2488
+ if (found === -1) break;
2489
+ count++;
2490
+ idx = found + phrase.length;
2491
+ }
2492
+ }
2493
+ return count;
2494
+ };
2495
+ var extractConfidenceSignals = (response, goal, readFiles) => ({
2496
+ hasDiffBlock: hasDiffBlock(response),
2497
+ isConcise: isConcise(response),
2498
+ referencesGoal: referencesGoal(response, goal),
2499
+ referencesReadFiles: referencesReadFiles(response, readFiles),
2500
+ hedgingCount: countHedgingPhrases(response)
2501
+ });
2502
+ var estimateConfidence = (response, goal, readFiles) => {
2503
+ const signals = extractConfidenceSignals(response, goal, readFiles);
2504
+ let score = 0.35;
2505
+ if (signals.hasDiffBlock) score += 0.2;
2506
+ if (signals.isConcise) score += 0.15;
2507
+ if (signals.referencesGoal) score += 0.15;
2508
+ if (signals.referencesReadFiles) score += 0.15;
2509
+ const hedgingPenalty = Math.min(signals.hedgingCount * 0.1, 0.3);
2510
+ score -= hedgingPenalty;
2511
+ score = Math.max(0, Math.min(1, score));
2512
+ return { score, signals };
2513
+ };
2514
+
2515
+ // src/agent/core/llmBudget/router.ts
2516
+ var DEFAULT_THRESHOLDS = {
2517
+ goalLength: 500,
2518
+ filesRead: 5,
2519
+ searchMatches: 30,
2520
+ repairAttempts: 1
2521
+ };
2522
+ var extractComplexitySignals = (state) => {
2523
+ const observations = state.observations;
2524
+ const goalLength = state.goal.text.length;
2525
+ let filesRead = 0;
2526
+ let searchMatches2 = 0;
2527
+ let hasValidationErrors = false;
2528
+ let repairAttempts = 0;
2529
+ for (const obs of observations) {
2530
+ switch (obs.type) {
2531
+ case "fs.fileRead":
2532
+ filesRead++;
2533
+ break;
2534
+ case "fs.searchResult":
2535
+ searchMatches2 += obs.matches.length;
2536
+ break;
2537
+ case "shell.result":
2538
+ if (obs.exitCode !== 0) {
2539
+ hasValidationErrors = true;
2540
+ }
2541
+ break;
2542
+ case "llm.response":
2543
+ if (obs.purpose === "patch") {
2544
+ repairAttempts++;
2545
+ }
2546
+ break;
2547
+ }
2548
+ }
2549
+ return {
2550
+ goalLength,
2551
+ filesRead,
2552
+ searchMatches: searchMatches2,
2553
+ hasValidationErrors,
2554
+ repairAttempts
2555
+ };
2556
+ };
2557
+ var routeModel = (state, _budgetState, thresholds) => {
2558
+ const t = _nullishCoalesce(thresholds, () => ( DEFAULT_THRESHOLDS));
2559
+ const signals = extractComplexitySignals(state);
2560
+ if (signals.goalLength >= t.goalLength || signals.filesRead >= t.filesRead || signals.searchMatches >= t.searchMatches || signals.hasValidationErrors || signals.repairAttempts >= t.repairAttempts) {
2561
+ return "large";
2562
+ }
2563
+ return "small";
2564
+ };
2565
+
2566
+ // src/agent/core/llmBudget/events.ts
2567
+ var makeBudgetUsageEvent = (usage, cumulative, tier, remaining) => ({
2568
+ type: "budget.usage",
2569
+ usage,
2570
+ cumulative,
2571
+ tier,
2572
+ remaining,
2573
+ at: Date.now()
2574
+ });
2575
+ var makeBudgetRoutedEvent = (tier, signals, resolvedProvider) => ({
2576
+ type: "budget.routed",
2577
+ tier,
2578
+ signals,
2579
+ resolvedProvider,
2580
+ at: Date.now()
2581
+ });
2582
+ var makeBudgetConfidenceEvent = (score, signals, purpose) => ({
2583
+ type: "budget.confidence",
2584
+ score,
2585
+ signals,
2586
+ purpose,
2587
+ at: Date.now()
2588
+ });
2589
+ var makeBudgetWarningEvent = (totalTokens, tokenBudget) => ({
2590
+ type: "budget.warning",
2591
+ totalTokens,
2592
+ tokenBudget,
2593
+ at: Date.now()
2594
+ });
2595
+ var makeBudgetExceededEvent = (totalTokens, tokenBudget, overshootFraction, hardCap) => ({
2596
+ type: "budget.exceeded",
2597
+ totalTokens,
2598
+ tokenBudget,
2599
+ overshootFraction,
2600
+ hardCap,
2601
+ at: Date.now()
2602
+ });
2603
+
2604
+ // src/agent/core/llmBudget/persistence.ts
2605
+ var isValidRecord = (r) => {
2606
+ if (r === null || typeof r !== "object") return false;
2607
+ const rec = r;
2608
+ return typeof rec.goalId === "string" && typeof rec.totalTokens === "number" && typeof rec.callCount === "number" && (rec.tier === "small" || rec.tier === "large") && typeof rec.confidence === "number" && typeof rec.timestamp === "number";
2609
+ };
2610
+ var parseLearningStore = (json) => {
2611
+ try {
2612
+ const parsed = JSON.parse(json);
2613
+ if (parsed === null || typeof parsed !== "object") {
2614
+ return { records: [] };
2615
+ }
2616
+ if (!Array.isArray(parsed.records)) {
2617
+ return { records: [] };
2618
+ }
2619
+ const validRecords = parsed.records.filter(isValidRecord);
2620
+ return { records: validRecords };
2621
+ } catch (e7) {
2622
+ return { records: [] };
2623
+ }
2624
+ };
2625
+ var appendRunRecord = (store, record, maxRecords = 100) => {
2626
+ const updated = [...store.records, record];
2627
+ if (updated.length > maxRecords) {
2628
+ return { records: updated.slice(updated.length - maxRecords) };
2629
+ }
2630
+ return { records: updated };
2631
+ };
2632
+ var serializeLearningStore = (store) => JSON.stringify(store, null, 2);
2633
+
1824
2634
  // src/agent/core/runAgent.ts
2635
+ var _promises = require('fs/promises');
2636
+ var _path = require('path');
1825
2637
  var executeAction = (action, state, scope) => _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0,
1826
2638
  nowMillis(),
1827
2639
  (startedAt) => _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0,
@@ -1885,45 +2697,197 @@ var recordObservation = (next, observation) => _chunkMVGUEJ5Zcjs.asyncFlatMap.ca
1885
2697
  ];
1886
2698
  return emitAgentEvents(events);
1887
2699
  });
1888
- var runLoop = (state, scope, runStartedAt) => {
2700
+ var buildBudgetExhaustedSummary = (state) => {
2701
+ const observations = state.observations;
2702
+ const fileReads = observations.filter((o) => o.type === "fs.fileRead").length;
2703
+ const llmCalls = observations.filter((o) => o.type === "llm.response").length;
2704
+ if (state.phase === "planning") {
2705
+ const hasPlan = observations.some((o) => o.type === "llm.response");
2706
+ if (!hasPlan) {
2707
+ return "Budget exhausted before planning could complete. No plan was generated within the token budget.";
2708
+ }
2709
+ }
2710
+ if (state.phase === "validating") {
2711
+ return `Budget exhausted during validation. Completed ${state.steps} steps (${fileReads} file reads, ${llmCalls} LLM calls). In-progress non-LLM validation commands were allowed to complete.`;
2712
+ }
2713
+ return `Budget exhausted. Completed ${state.steps} steps (${fileReads} file reads, ${llmCalls} LLM calls) before reaching the token budget hard cap.`;
2714
+ };
2715
+ var extractReadFiles = (state) => state.observations.filter((o) => o.type === "fs.fileRead").map((o) => o.path);
2716
+ var LEARNING_STORE_PATH = ".brass/llm-budget.json";
2717
+ var persistLearningRecord = (state, budgetState) => _chunkMVGUEJ5Zcjs.asyncFold.call(void 0,
2718
+ _chunkMVGUEJ5Zcjs.asyncInterruptible.call(void 0, (_env, cb) => {
2719
+ const filePath = `${state.goal.cwd}/${LEARNING_STORE_PATH}`;
2720
+ const run = async () => {
2721
+ const lastCall = budgetState.calls[budgetState.calls.length - 1];
2722
+ const tier = _nullishCoalesce(_optionalChain([lastCall, 'optionalAccess', _131 => _131.tier]), () => ( "small"));
2723
+ const confidence = budgetState.callCount > 0 ? budgetState.calls.reduce((sum, c) => sum + c.confidence, 0) / budgetState.callCount : 0;
2724
+ const record = {
2725
+ goalId: state.goal.id,
2726
+ totalTokens: budgetState.totalTokens,
2727
+ callCount: budgetState.callCount,
2728
+ tier,
2729
+ confidence,
2730
+ timestamp: Date.now()
2731
+ };
2732
+ let existingJson = "";
2733
+ try {
2734
+ existingJson = await _promises.readFile.call(void 0, filePath, "utf8");
2735
+ } catch (e8) {
2736
+ }
2737
+ const store = parseLearningStore(existingJson);
2738
+ const updated = appendRunRecord(store, record);
2739
+ const serialized = serializeLearningStore(updated);
2740
+ await _promises.mkdir.call(void 0, _path.dirname.call(void 0, filePath), { recursive: true });
2741
+ await _promises.writeFile.call(void 0, filePath, serialized, "utf8");
2742
+ };
2743
+ run().then(
2744
+ () => cb({ _tag: "Success", value: void 0 }),
2745
+ (err) => cb({ _tag: "Failure", cause: { _tag: "Fail", error: { _tag: "FsError", operation: "persistLearningStore", cause: err } } })
2746
+ );
2747
+ }),
2748
+ // On failure: swallow the error silently (Requirement 7.4)
2749
+ () => _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, void 0),
2750
+ // On success: pass through
2751
+ () => _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, void 0)
2752
+ );
2753
+ var executeBudgetGatedLLMCall = (action, state, budgetState, budgetConfig, scope) => {
2754
+ if (!budgetAllowsCall(budgetState, budgetConfig)) {
2755
+ const hardCap = budgetConfig.tokenBudget * (1 + budgetConfig.overshootFraction);
2756
+ const exceededEvent = makeBudgetExceededEvent(
2757
+ budgetState.totalTokens,
2758
+ budgetConfig.tokenBudget,
2759
+ budgetConfig.overshootFraction,
2760
+ hardCap
2761
+ );
2762
+ return _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0, emitAgentEvent(exceededEvent), () => {
2763
+ const finishObservation = {
2764
+ type: "agent.done",
2765
+ summary: buildBudgetExhaustedSummary(state)
2766
+ };
2767
+ return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, { observation: finishObservation, budgetState });
2768
+ });
2769
+ }
2770
+ const tier = routeModel(state, budgetState);
2771
+ const signals = extractComplexitySignals(state);
2772
+ const resolvedProvider = _optionalChain([budgetConfig, 'access', _132 => _132.modelTiers, 'optionalAccess', _133 => _133[tier], 'optionalAccess', _134 => _134.provider]);
2773
+ const routedEvent = makeBudgetRoutedEvent(tier, signals, resolvedProvider);
2774
+ return _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0,
2775
+ emitAgentEvent(routedEvent),
2776
+ () => (
2777
+ // Execute the LLM call through the normal action execution path
2778
+ // We use the LLM service directly to capture the full LLMResponse with usage
2779
+ _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0, _chunkMVGUEJ5Zcjs.asyncSync.call(void 0, (env) => env.llm), (llm) => {
2780
+ if (!llm) {
2781
+ return _chunkMVGUEJ5Zcjs.asyncFail.call(void 0, {
2782
+ _tag: "LLMError",
2783
+ cause: "llm_unavailable: no LLM provider is configured"
2784
+ });
2785
+ }
2786
+ return _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0,
2787
+ llm.complete({ purpose: action.purpose, prompt: action.prompt }),
2788
+ (response) => {
2789
+ const usage = _nullishCoalesce(response.usage, () => ( estimateTokens(
2790
+ action.prompt.length,
2791
+ response.content.length
2792
+ )));
2793
+ const estimated = response.usage === void 0;
2794
+ const readFiles = extractReadFiles(state);
2795
+ const { score: confidence, signals: confidenceSignals } = estimateConfidence(
2796
+ response.content,
2797
+ state.goal.text,
2798
+ readFiles
2799
+ );
2800
+ const newBudgetState = updateBudgetState(budgetState, usage, tier, confidence, estimated);
2801
+ const remaining = Math.max(0, budgetConfig.tokenBudget - newBudgetState.totalTokens);
2802
+ const usageEvent = makeBudgetUsageEvent(
2803
+ usage,
2804
+ { totalTokens: newBudgetState.totalTokens, callCount: newBudgetState.callCount },
2805
+ tier,
2806
+ remaining
2807
+ );
2808
+ const confidenceEvent = makeBudgetConfidenceEvent(confidence, confidenceSignals, action.purpose);
2809
+ const events = [usageEvent, confidenceEvent];
2810
+ if (newBudgetState.totalTokens > budgetConfig.tokenBudget) {
2811
+ events.push(makeBudgetWarningEvent(newBudgetState.totalTokens, budgetConfig.tokenBudget));
2812
+ }
2813
+ return _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0, emitAgentEvents(events), () => {
2814
+ const observation = {
2815
+ type: "llm.response",
2816
+ purpose: action.purpose,
2817
+ content: response.content
2818
+ };
2819
+ return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, { observation, budgetState: newBudgetState });
2820
+ });
2821
+ }
2822
+ );
2823
+ })
2824
+ )
2825
+ );
2826
+ };
2827
+ var runLoop = (state, budgetState, budgetConfig, scope, runStartedAt) => {
1889
2828
  if (isTerminal(state)) {
2829
+ const persistEffect = budgetConfig !== void 0 && budgetState !== void 0 ? persistLearningRecord(state, budgetState) : _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, void 0);
1890
2830
  return _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0,
1891
- nowMillis(),
1892
- (at) => _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0,
1893
- emitAgentEvent({
1894
- type: "agent.run.completed",
1895
- goal: state.goal,
1896
- status: runStatusFor(state.phase),
1897
- phase: state.phase,
1898
- steps: state.steps,
1899
- durationMs: at - runStartedAt,
1900
- at
1901
- }),
1902
- () => _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, state)
2831
+ persistEffect,
2832
+ () => _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0,
2833
+ nowMillis(),
2834
+ (at) => _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0,
2835
+ emitAgentEvent({
2836
+ type: "agent.run.completed",
2837
+ goal: state.goal,
2838
+ status: runStatusFor(state.phase),
2839
+ phase: state.phase,
2840
+ steps: state.steps,
2841
+ durationMs: at - runStartedAt,
2842
+ at
2843
+ }),
2844
+ () => _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, state)
2845
+ )
1903
2846
  )
1904
2847
  );
1905
2848
  }
1906
- return _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0,
1907
- decideNextAction(state),
1908
- (action) => _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0, executeAction(action, state, scope), (observation) => {
2849
+ return _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0, decideNextAction(state), (action) => {
2850
+ if (action.type === "llm.complete" && budgetConfig !== void 0 && budgetState !== void 0) {
2851
+ return _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0,
2852
+ executeBudgetGatedLLMCall(action, state, budgetState, budgetConfig, scope),
2853
+ (result) => {
2854
+ const next = reduceAgentState(state, result.observation);
2855
+ return _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0,
2856
+ recordObservation(next, result.observation),
2857
+ () => runLoop(next, result.budgetState, budgetConfig, scope, runStartedAt)
2858
+ );
2859
+ }
2860
+ );
2861
+ }
2862
+ return _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0, executeAction(action, state, scope), (observation) => {
1909
2863
  const next = reduceAgentState(state, observation);
1910
2864
  return _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0,
1911
2865
  recordObservation(next, observation),
1912
- () => runLoop(next, scope, runStartedAt)
2866
+ () => runLoop(next, budgetState, budgetConfig, scope, runStartedAt)
1913
2867
  );
1914
- })
1915
- );
2868
+ });
2869
+ });
1916
2870
  };
1917
- var runAgent = (runtime, goal) => _chunkJKHBEWQAcjs.withScopeAsync.call(void 0,
1918
- runtime,
1919
- (scope) => _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0,
1920
- nowMillis(),
1921
- (startedAt) => _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0,
1922
- emitAgentEvent({ type: "agent.run.started", goal, at: startedAt }),
1923
- () => runLoop(initialAgentState(goal), scope, startedAt)
2871
+ var runAgent = (runtime, goal, configBudget) => {
2872
+ const budgetConfig = resolveBudgetConfig(goal.budget, configBudget);
2873
+ if (budgetConfig !== void 0) {
2874
+ const validationError = validateBudgetConfig(budgetConfig);
2875
+ if (validationError !== void 0) {
2876
+ return _chunkMVGUEJ5Zcjs.asyncFail.call(void 0, { _tag: "AgentLoopError", message: validationError });
2877
+ }
2878
+ }
2879
+ const budgetState = budgetConfig !== void 0 ? initBudgetState() : void 0;
2880
+ return _chunkJKHBEWQAcjs.withScopeAsync.call(void 0,
2881
+ runtime,
2882
+ (scope) => _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0,
2883
+ nowMillis(),
2884
+ (startedAt) => _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0,
2885
+ emitAgentEvent({ type: "agent.run.started", goal, at: startedAt }),
2886
+ () => runLoop(initialAgentState(goal), budgetState, budgetConfig, scope, startedAt)
2887
+ )
1924
2888
  )
1925
- )
1926
- );
2889
+ );
2890
+ };
1927
2891
 
1928
2892
  // src/agent/core/config.ts
1929
2893
  var isAgentConfigMode = (value) => value === "read-only" || value === "propose" || value === "write" || value === "autonomous";
@@ -1946,6 +2910,243 @@ var goalForAgentPreset = (preset) => {
1946
2910
  }
1947
2911
  };
1948
2912
 
2913
+ // src/agent/core/hostProfile.ts
2914
+ var deepFreeze = (obj) => {
2915
+ Object.freeze(obj);
2916
+ for (const name of Object.getOwnPropertyNames(obj)) {
2917
+ const value = obj[name];
2918
+ if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
2919
+ deepFreeze(value);
2920
+ }
2921
+ }
2922
+ return obj;
2923
+ };
2924
+
2925
+ // src/agent/core/hostSignals.ts
2926
+ var MAX_ENV_KEYS = 256;
2927
+ var collectHostSignals = (input) => {
2928
+ const signals = [];
2929
+ try {
2930
+ for (const arg of input.argv) {
2931
+ signals.push({ source: "argv", value: arg });
2932
+ }
2933
+ } catch (e9) {
2934
+ }
2935
+ try {
2936
+ const keys = Object.keys(input.env).sort();
2937
+ const limit = Math.min(keys.length, MAX_ENV_KEYS);
2938
+ for (let i = 0; i < limit; i++) {
2939
+ signals.push({ source: "env-key", value: keys[i] });
2940
+ }
2941
+ } catch (e10) {
2942
+ }
2943
+ try {
2944
+ signals.push({
2945
+ source: "stdio",
2946
+ value: input.stdoutIsTTY ? "stdout:tty" : "stdout:pipe"
2947
+ });
2948
+ signals.push({
2949
+ source: "stdio",
2950
+ value: input.stdinIsTTY ? "stdin:tty" : "stdin:pipe"
2951
+ });
2952
+ if (input.ttyColumns !== void 0) {
2953
+ signals.push({ source: "stdio", value: `columns:${input.ttyColumns}` });
2954
+ }
2955
+ } catch (e11) {
2956
+ }
2957
+ try {
2958
+ if (input.parentProcessName !== void 0) {
2959
+ signals.push({ source: "parent-process", value: input.parentProcessName });
2960
+ }
2961
+ } catch (e12) {
2962
+ }
2963
+ try {
2964
+ for (const marker of input.workspaceMarkers) {
2965
+ signals.push({ source: "workspace-marker", value: marker });
2966
+ }
2967
+ } catch (e13) {
2968
+ }
2969
+ try {
2970
+ if (input.stdinFirstLine !== void 0 && !input.stdinIsTTY) {
2971
+ signals.push({ source: "protocol-handshake", value: input.stdinFirstLine });
2972
+ }
2973
+ } catch (e14) {
2974
+ }
2975
+ try {
2976
+ for (const configPath of input.configPaths) {
2977
+ signals.push({ source: "config", value: configPath });
2978
+ }
2979
+ } catch (e15) {
2980
+ }
2981
+ return deepFreeze(signals);
2982
+ };
2983
+
2984
+ // src/agent/core/hostInference.ts
2985
+ var CI_INDICATORS = [
2986
+ "CI",
2987
+ "GITHUB_ACTIONS",
2988
+ "JENKINS_URL",
2989
+ "CIRCLECI",
2990
+ "TRAVIS",
2991
+ "GITLAB_CI",
2992
+ "BUILDKITE",
2993
+ "TF_BUILD"
2994
+ ];
2995
+ var inferTransport = (signals) => {
2996
+ const hasProtocolMcp = signals.some(
2997
+ (s) => s.source === "protocol-handshake" && s.value.toLowerCase().includes("mcp")
2998
+ );
2999
+ if (hasProtocolMcp) return "mcp";
3000
+ const extensionMarkers = [".vscode", ".cursor", ".kiro"];
3001
+ const hasExtensionMarker = signals.some(
3002
+ (s) => s.source === "workspace-marker" && extensionMarkers.some((m) => s.value.toLowerCase().includes(m))
3003
+ );
3004
+ const hasExtensionConfig = signals.some(
3005
+ (s) => s.source === "config" && extensionMarkers.some((m) => s.value.toLowerCase().includes(m))
3006
+ );
3007
+ if (hasExtensionMarker || hasExtensionConfig) return "extension";
3008
+ const hasCiEnv = signals.some(
3009
+ (s) => s.source === "env-key" && CI_INDICATORS.some((ci) => s.value === ci)
3010
+ );
3011
+ if (hasCiEnv) return "ci";
3012
+ const stdoutIsTty = signals.some(
3013
+ (s) => s.source === "stdio" && s.value === "stdout:tty"
3014
+ );
3015
+ if (stdoutIsTty) return "terminal";
3016
+ const stdoutIsPipe = signals.some(
3017
+ (s) => s.source === "stdio" && s.value === "stdout:pipe"
3018
+ );
3019
+ if (stdoutIsPipe) return "stdio";
3020
+ return "unknown";
3021
+ };
3022
+ var inferCapabilities = (signals, transport) => {
3023
+ const hasOwnLLM = signals.some(
3024
+ (s) => s.source === "env-key" && (s.value.toUpperCase().includes("LLM") || s.value.toUpperCase().includes("AI_API")) || s.source === "protocol-handshake" && s.value.toLowerCase().includes("llm")
3025
+ );
3026
+ const wantsJson = transport === "stdio" || transport === "mcp";
3027
+ const supportsStreamingEvents = transport === "terminal" || transport === "mcp" || transport === "extension";
3028
+ const supportsMcp = transport === "mcp";
3029
+ const stdinIsTty = signals.some(
3030
+ (s) => s.source === "stdio" && s.value === "stdin:tty"
3031
+ );
3032
+ const canAskApproval = stdinIsTty || transport === "extension" || transport === "mcp";
3033
+ const ttyColumnsSignal = signals.find(
3034
+ (s) => s.source === "stdio" && s.value.startsWith("columns:")
3035
+ );
3036
+ const ttyColumns = ttyColumnsSignal ? parseInt(ttyColumnsSignal.value.slice("columns:".length), 10) : void 0;
3037
+ const stdoutIsTty = signals.some(
3038
+ (s) => s.source === "stdio" && s.value === "stdout:tty"
3039
+ );
3040
+ const canRenderDiff = stdoutIsTty && ttyColumns !== void 0 && ttyColumns >= 80 || transport === "extension";
3041
+ const canApplyPatch = transport === "extension" || transport === "mcp";
3042
+ const interactiveTty = stdoutIsTty;
3043
+ return {
3044
+ hasOwnLLM,
3045
+ wantsJson,
3046
+ supportsStreamingEvents,
3047
+ supportsMcp,
3048
+ canAskApproval,
3049
+ canRenderDiff,
3050
+ canApplyPatch,
3051
+ interactiveTty
3052
+ };
3053
+ };
3054
+ var inferConstraints = (capabilities, transport) => {
3055
+ const readOnlyByDefault = transport === "ci";
3056
+ const patchPreviewRequired = capabilities.canRenderDiff === true && capabilities.canApplyPatch === false;
3057
+ const requireNoNetwork = false;
3058
+ return {
3059
+ readOnlyByDefault,
3060
+ patchPreviewRequired,
3061
+ requireNoNetwork
3062
+ };
3063
+ };
3064
+ var IDENTITY_PATTERNS = [
3065
+ {
3066
+ name: "cursor",
3067
+ match: (signals) => {
3068
+ if (signals.some((s) => s.source === "workspace-marker" && s.value.toLowerCase().includes(".cursor"))) {
3069
+ return 0.8;
3070
+ }
3071
+ return 0;
3072
+ }
3073
+ },
3074
+ {
3075
+ name: "vscode",
3076
+ match: (signals) => {
3077
+ if (signals.some((s) => s.source === "workspace-marker" && s.value.toLowerCase().includes(".vscode"))) {
3078
+ return 0.8;
3079
+ }
3080
+ return 0;
3081
+ }
3082
+ },
3083
+ {
3084
+ name: "kiro",
3085
+ match: (signals) => {
3086
+ if (signals.some((s) => s.source === "workspace-marker" && s.value.toLowerCase().includes(".kiro"))) {
3087
+ return 0.8;
3088
+ }
3089
+ if (signals.some((s) => s.source === "env-key" && s.value.startsWith("KIRO_"))) {
3090
+ return 0.7;
3091
+ }
3092
+ return 0;
3093
+ }
3094
+ },
3095
+ {
3096
+ name: "codex",
3097
+ match: (signals) => {
3098
+ if (signals.some((s) => s.source === "parent-process" && s.value.toLowerCase().includes("codex"))) {
3099
+ return 0.9;
3100
+ }
3101
+ if (signals.some((s) => s.source === "env-key" && s.value.startsWith("CODEX_"))) {
3102
+ return 0.7;
3103
+ }
3104
+ return 0;
3105
+ }
3106
+ },
3107
+ {
3108
+ name: "claude-code",
3109
+ match: (signals) => {
3110
+ if (signals.some((s) => s.source === "parent-process" && s.value.toLowerCase().includes("claude"))) {
3111
+ return 0.9;
3112
+ }
3113
+ return 0;
3114
+ }
3115
+ }
3116
+ ];
3117
+ var inferOptionalIdentity = (signals) => {
3118
+ let bestName;
3119
+ let bestConfidence = 0;
3120
+ for (const pattern of IDENTITY_PATTERNS) {
3121
+ const confidence = pattern.match(signals);
3122
+ if (confidence > bestConfidence) {
3123
+ bestConfidence = confidence;
3124
+ bestName = pattern.name;
3125
+ }
3126
+ }
3127
+ if (bestName === void 0 || bestConfidence <= 0) {
3128
+ return void 0;
3129
+ }
3130
+ return {
3131
+ name: bestName,
3132
+ confidence: Math.round(bestConfidence * 100) / 100
3133
+ };
3134
+ };
3135
+ var buildHostProfile = (input) => {
3136
+ const signals = collectHostSignals(input);
3137
+ const transport = inferTransport(signals);
3138
+ const capabilities = inferCapabilities(signals, transport);
3139
+ const constraints = inferConstraints(capabilities, transport);
3140
+ const identity = inferOptionalIdentity(signals);
3141
+ return deepFreeze({
3142
+ transport,
3143
+ capabilities,
3144
+ constraints,
3145
+ identity,
3146
+ evidence: signals
3147
+ });
3148
+ };
3149
+
1949
3150
  // src/agent/tools/permissions.ts
1950
3151
  var DEFAULT_SAFE_SHELL_PATTERNS = [
1951
3152
  "npm test",
@@ -2022,14 +3223,14 @@ var matchesPattern = (command, pattern) => {
2022
3223
  const re = new RegExp(`^${normalizedPattern.split("*").map(escapeRegExp).join(".*")}$`);
2023
3224
  return re.test(normalizedCommand);
2024
3225
  };
2025
- var matchAny = (command, patterns) => Boolean(_optionalChain([patterns, 'optionalAccess', _124 => _124.some, 'call', _125 => _125((pattern) => matchesPattern(command, pattern))]));
3226
+ var matchAny = (command, patterns) => Boolean(_optionalChain([patterns, 'optionalAccess', _135 => _135.some, 'call', _136 => _136((pattern) => matchesPattern(command, pattern))]));
2026
3227
  var allow = () => ({ type: "allow" });
2027
3228
  var deny = (reason) => ({ type: "deny", reason });
2028
3229
  var ask = (reason, risk, defaultAnswer = "reject") => ({ type: "ask", reason, risk, defaultAnswer });
2029
3230
  var describeCommand = (action) => action.type === "shell.exec" ? action.command.join(" ") : action.type;
2030
3231
  var shellAskRulePattern = (rule) => typeof rule === "string" ? rule : rule.pattern;
2031
3232
  var shellAskDecision = (command, rules) => {
2032
- const rule = _optionalChain([rules, 'optionalAccess', _126 => _126.find, 'call', _127 => _127((candidate) => matchesPattern(command, shellAskRulePattern(candidate)))]);
3233
+ const rule = _optionalChain([rules, 'optionalAccess', _137 => _137.find, 'call', _138 => _138((candidate) => matchesPattern(command, shellAskRulePattern(candidate)))]);
2033
3234
  if (!rule) return void 0;
2034
3235
  if (typeof rule === "string") {
2035
3236
  return ask(`Run command: ${shellCommandText(command)}`, "high", "reject");
@@ -2041,12 +3242,12 @@ var shellAskDecision = (command, rules) => {
2041
3242
  );
2042
3243
  };
2043
3244
  var configuredShellAllowPatterns = (config) => [
2044
- ..._optionalChain([config, 'optionalAccess', _128 => _128.inheritDefaults]) === false ? [] : DEFAULT_SAFE_SHELL_PATTERNS,
2045
- ..._nullishCoalesce(_optionalChain([config, 'optionalAccess', _129 => _129.allow]), () => ( []))
3245
+ ..._optionalChain([config, 'optionalAccess', _139 => _139.inheritDefaults]) === false ? [] : DEFAULT_SAFE_SHELL_PATTERNS,
3246
+ ..._nullishCoalesce(_optionalChain([config, 'optionalAccess', _140 => _140.allow]), () => ( []))
2046
3247
  ];
2047
3248
  var shellDecisionFromConfig = (command, config) => {
2048
- if (matchAny(command, _optionalChain([config, 'optionalAccess', _130 => _130.deny]))) return deny(`Command denied by policy: ${shellCommandText(command)}`);
2049
- const askDecision = shellAskDecision(command, _optionalChain([config, 'optionalAccess', _131 => _131.ask]));
3249
+ if (matchAny(command, _optionalChain([config, 'optionalAccess', _141 => _141.deny]))) return deny(`Command denied by policy: ${shellCommandText(command)}`);
3250
+ const askDecision = shellAskDecision(command, _optionalChain([config, 'optionalAccess', _142 => _142.ask]));
2050
3251
  if (askDecision) return askDecision;
2051
3252
  if (matchAny(command, configuredShellAllowPatterns(config))) return allow();
2052
3253
  return void 0;
@@ -2124,7 +3325,7 @@ var makeAutoDenyApprovals = (reason = "Approval denied by non-interactive policy
2124
3325
  // src/agent/node/nodeShell.ts
2125
3326
  var dynamicImport = new Function("specifier", "return import(specifier)");
2126
3327
  var chunkToString = (chunk) => {
2127
- const maybeToString = _optionalChain([chunk, 'optionalAccess', _132 => _132.toString]);
3328
+ const maybeToString = _optionalChain([chunk, 'optionalAccess', _143 => _143.toString]);
2128
3329
  return typeof maybeToString === "function" ? maybeToString.call(chunk, "utf8") : String(chunk);
2129
3330
  };
2130
3331
  var NodeShell = {
@@ -2154,10 +3355,10 @@ var NodeShell = {
2154
3355
  shell: false,
2155
3356
  stdio: ["pipe", "pipe", "pipe"]
2156
3357
  });
2157
- _optionalChain([child, 'access', _133 => _133.stdout, 'optionalAccess', _134 => _134.on, 'call', _135 => _135("data", (chunk) => {
3358
+ _optionalChain([child, 'access', _144 => _144.stdout, 'optionalAccess', _145 => _145.on, 'call', _146 => _146("data", (chunk) => {
2158
3359
  stdout += chunkToString(chunk);
2159
3360
  })]);
2160
- _optionalChain([child, 'access', _136 => _136.stderr, 'optionalAccess', _137 => _137.on, 'call', _138 => _138("data", (chunk) => {
3361
+ _optionalChain([child, 'access', _147 => _147.stderr, 'optionalAccess', _148 => _148.on, 'call', _149 => _149("data", (chunk) => {
2161
3362
  stderr += chunkToString(chunk);
2162
3363
  })]);
2163
3364
  child.on("error", (cause) => {
@@ -2186,9 +3387,9 @@ var NodeShell = {
2186
3387
  );
2187
3388
  });
2188
3389
  if (options.stdin !== void 0) {
2189
- _optionalChain([child, 'access', _139 => _139.stdin, 'optionalAccess', _140 => _140.end, 'call', _141 => _141(options.stdin)]);
3390
+ _optionalChain([child, 'access', _150 => _150.stdin, 'optionalAccess', _151 => _151.end, 'call', _152 => _152(options.stdin)]);
2190
3391
  } else {
2191
- _optionalChain([child, 'access', _142 => _142.stdin, 'optionalAccess', _143 => _143.end, 'call', _144 => _144()]);
3392
+ _optionalChain([child, 'access', _153 => _153.stdin, 'optionalAccess', _154 => _154.end, 'call', _155 => _155()]);
2192
3393
  }
2193
3394
  }).catch((cause) => {
2194
3395
  if (done) return;
@@ -2207,7 +3408,7 @@ var NodeShell = {
2207
3408
  return () => {
2208
3409
  if (done) return;
2209
3410
  done = true;
2210
- _optionalChain([child, 'optionalAccess', _145 => _145.kill, 'optionalCall', _146 => _146("SIGTERM")]);
3411
+ _optionalChain([child, 'optionalAccess', _156 => _156.kill, 'optionalCall', _157 => _157("SIGTERM")]);
2211
3412
  };
2212
3413
  })
2213
3414
  };
@@ -2221,8 +3422,8 @@ var parseRipgrep = (stdout) => stdout.split("\n").filter(Boolean).map((line) =>
2221
3422
  var makeNodeFileSystem = (shell) => ({
2222
3423
  readFile: (path) => _chunkJKHBEWQAcjs.fromPromiseAbortable.call(void 0,
2223
3424
  async (signal) => {
2224
- const { readFile } = await dynamicImport2("node:fs/promises");
2225
- return readFile(path, { encoding: "utf8", signal });
3425
+ const { readFile: readFile2 } = await dynamicImport2("node:fs/promises");
3426
+ return readFile2(path, { encoding: "utf8", signal });
2226
3427
  },
2227
3428
  (cause) => ({ _tag: "FsError", operation: "readFile", cause })
2228
3429
  ),
@@ -2234,7 +3435,7 @@ var makeNodeFileSystem = (shell) => ({
2234
3435
  try {
2235
3436
  await stat(path);
2236
3437
  return true;
2237
- } catch (e6) {
3438
+ } catch (e16) {
2238
3439
  return false;
2239
3440
  }
2240
3441
  },
@@ -2251,7 +3452,7 @@ var makeNodeFileSystem = (shell) => ({
2251
3452
  "never",
2252
3453
  "--max-count",
2253
3454
  "5",
2254
- ..._nullishCoalesce(_optionalChain([options, 'optionalAccess', _147 => _147.globs, 'optionalAccess', _148 => _148.flatMap, 'call', _149 => _149((glob) => ["--glob", glob])]), () => ( [])),
3455
+ ..._nullishCoalesce(_optionalChain([options, 'optionalAccess', _158 => _158.globs, 'optionalAccess', _159 => _159.flatMap, 'call', _160 => _160((glob) => ["--glob", glob])]), () => ( [])),
2255
3456
  "--",
2256
3457
  query,
2257
3458
  "."
@@ -2556,13 +3757,16 @@ var validateAgentConfig = (config, sourcePath) => {
2556
3757
  config.batch.goals.forEach((goal, index) => validateBatchGoal(goal, `config.batch.goals[${index}]`));
2557
3758
  }
2558
3759
  }
3760
+ if (config.budget !== void 0) {
3761
+ if (!isRecord3(config.budget)) throw new Error("config.budget must be an object.");
3762
+ }
2559
3763
  return config;
2560
3764
  };
2561
3765
  var isFile = async (path) => {
2562
3766
  const { stat } = await dynamicImport3("node:fs/promises");
2563
3767
  try {
2564
3768
  return (await stat(path)).isFile();
2565
- } catch (e7) {
3769
+ } catch (e17) {
2566
3770
  return false;
2567
3771
  }
2568
3772
  };
@@ -2580,8 +3784,8 @@ var findConfigPath = async (cwd) => {
2580
3784
  }
2581
3785
  };
2582
3786
  var readConfigFile = async (path) => {
2583
- const { readFile } = await dynamicImport3("node:fs/promises");
2584
- const raw = String(await readFile(path, "utf8")).replace(/^\uFEFF/, "");
3787
+ const { readFile: readFile2 } = await dynamicImport3("node:fs/promises");
3788
+ const raw = String(await readFile2(path, "utf8")).replace(/^\uFEFF/, "");
2585
3789
  try {
2586
3790
  return validateAgentConfig(JSON.parse(raw), path);
2587
3791
  } catch (error) {
@@ -2605,7 +3809,7 @@ var loadNodeAgentConfig = async (options) => {
2605
3809
  };
2606
3810
 
2607
3811
  // src/agent/llm/openAICompatible.ts
2608
- var extractText = (json) => _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(_optionalChain([json, 'optionalAccess', _150 => _150.choices, 'optionalAccess', _151 => _151[0], 'optionalAccess', _152 => _152.message, 'optionalAccess', _153 => _153.content]), () => ( _optionalChain([json, 'optionalAccess', _154 => _154.output_text]))), () => ( _optionalChain([json, 'optionalAccess', _155 => _155.content, 'optionalAccess', _156 => _156[0], 'optionalAccess', _157 => _157.text]))), () => ( JSON.stringify(json)));
3812
+ var extractText = (json) => _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(_optionalChain([json, 'optionalAccess', _161 => _161.choices, 'optionalAccess', _162 => _162[0], 'optionalAccess', _163 => _163.message, 'optionalAccess', _164 => _164.content]), () => ( _optionalChain([json, 'optionalAccess', _165 => _165.output_text]))), () => ( _optionalChain([json, 'optionalAccess', _166 => _166.content, 'optionalAccess', _167 => _167[0], 'optionalAccess', _168 => _168.text]))), () => ( JSON.stringify(json)));
2609
3813
  var makeOpenAICompatibleLLM = (config) => ({
2610
3814
  complete: (request) => _chunkJKHBEWQAcjs.fromPromiseAbortable.call(void 0,
2611
3815
  async (signal) => {
@@ -2673,18 +3877,18 @@ var makeRequestBody = (request, config) => {
2673
3877
  });
2674
3878
  };
2675
3879
  var extractGoogleText = (json) => {
2676
- const text = _optionalChain([json, 'access', _158 => _158.candidates, 'optionalAccess', _159 => _159.flatMap, 'call', _160 => _160((candidate) => _nullishCoalesce(_optionalChain([candidate, 'access', _161 => _161.content, 'optionalAccess', _162 => _162.parts]), () => ( []))), 'access', _163 => _163.map, 'call', _164 => _164((part) => _nullishCoalesce(part.text, () => ( ""))), 'access', _165 => _165.filter, 'call', _166 => _166(Boolean), 'access', _167 => _167.join, 'call', _168 => _168("\n"), 'access', _169 => _169.trim, 'call', _170 => _170()]);
3880
+ const text = _optionalChain([json, 'access', _169 => _169.candidates, 'optionalAccess', _170 => _170.flatMap, 'call', _171 => _171((candidate) => _nullishCoalesce(_optionalChain([candidate, 'access', _172 => _172.content, 'optionalAccess', _173 => _173.parts]), () => ( []))), 'access', _174 => _174.map, 'call', _175 => _175((part) => _nullishCoalesce(part.text, () => ( ""))), 'access', _176 => _176.filter, 'call', _177 => _177(Boolean), 'access', _178 => _178.join, 'call', _179 => _179("\n"), 'access', _180 => _180.trim, 'call', _181 => _181()]);
2677
3881
  if (text) return text;
2678
- const blockReason = _optionalChain([json, 'access', _171 => _171.promptFeedback, 'optionalAccess', _172 => _172.blockReason]);
3882
+ const blockReason = _optionalChain([json, 'access', _182 => _182.promptFeedback, 'optionalAccess', _183 => _183.blockReason]);
2679
3883
  if (blockReason) {
2680
- const message = _optionalChain([json, 'access', _173 => _173.promptFeedback, 'optionalAccess', _174 => _174.blockReasonMessage]);
3884
+ const message = _optionalChain([json, 'access', _184 => _184.promptFeedback, 'optionalAccess', _185 => _185.blockReasonMessage]);
2681
3885
  throw new Error(`Google Gemini blocked the prompt: ${blockReason}${message ? ` - ${message}` : ""}`);
2682
3886
  }
2683
- const finishReason = _optionalChain([json, 'access', _175 => _175.candidates, 'optionalAccess', _176 => _176[0], 'optionalAccess', _177 => _177.finishReason]);
3887
+ const finishReason = _optionalChain([json, 'access', _186 => _186.candidates, 'optionalAccess', _187 => _187[0], 'optionalAccess', _188 => _188.finishReason]);
2684
3888
  if (finishReason) {
2685
3889
  throw new Error(`Google Gemini returned no text. finishReason=${finishReason}`);
2686
3890
  }
2687
- if (_optionalChain([json, 'access', _178 => _178.error, 'optionalAccess', _179 => _179.message])) {
3891
+ if (_optionalChain([json, 'access', _189 => _189.error, 'optionalAccess', _190 => _190.message])) {
2688
3892
  throw new Error(`Google Gemini error: ${json.error.message}`);
2689
3893
  }
2690
3894
  return JSON.stringify(json);
@@ -2693,8 +3897,8 @@ var responseErrorMessage = async (res) => {
2693
3897
  const raw = await res.text();
2694
3898
  try {
2695
3899
  const json = JSON.parse(raw);
2696
- return _nullishCoalesce(_optionalChain([json, 'access', _180 => _180.error, 'optionalAccess', _181 => _181.message]), () => ( raw));
2697
- } catch (e8) {
3900
+ return _nullishCoalesce(_optionalChain([json, 'access', _191 => _191.error, 'optionalAccess', _192 => _192.message]), () => ( raw));
3901
+ } catch (e18) {
2698
3902
  return raw;
2699
3903
  }
2700
3904
  };
@@ -2737,7 +3941,7 @@ var makeFakeLLM = (options = {}) => ({
2737
3941
 
2738
3942
  // src/agent/node/nodeWorkspaceDiscovery.ts
2739
3943
  var _fs = require('fs');
2740
- var _path = require('path');
3944
+
2741
3945
  var WORKSPACE_MARKERS = [
2742
3946
  { name: ".brass-agent.json", kind: "file" },
2743
3947
  { name: "brass-agent.config.json", kind: "file" },
@@ -2751,7 +3955,7 @@ var markerExists2 = (path, kind) => {
2751
3955
  try {
2752
3956
  const stat = _fs.statSync.call(void 0, path);
2753
3957
  return kind === "directory" ? stat.isDirectory() : stat.isFile();
2754
- } catch (e9) {
3958
+ } catch (e19) {
2755
3959
  return false;
2756
3960
  }
2757
3961
  };
@@ -2880,4 +4084,15 @@ var discoverNodeWorkspaceRoot = (cwd, options = {}) => {
2880
4084
 
2881
4085
 
2882
4086
 
2883
- exports.initialAgentState = initialAgentState; exports.reduceAgentState = reduceAgentState; exports.isTerminal = isTerminal; exports.extractLikelyFilePaths = extractLikelyFilePaths; exports.deriveContextSearchQueries = deriveContextSearchQueries; exports.describeContextDiscovery = describeContextDiscovery; exports.summarizeContextDiscovery = summarizeContextDiscovery; exports.nextContextDiscoveryAction = nextContextDiscoveryAction; exports.PROJECT_PROFILE_PROBES = PROJECT_PROFILE_PROBES; exports.projectProfileProbePending = projectProfileProbePending; exports.discoverProjectProfile = discoverProjectProfile; exports.describeProjectProfile = describeProjectProfile; exports.PROJECT_LOCKFILE_PROBES = PROJECT_LOCKFILE_PROBES; exports.parseProjectPackageJson = parseProjectPackageJson; exports.nextProjectProbeAction = nextProjectProbeAction; exports.discoverPackageManager = discoverPackageManager; exports.splitCommand = splitCommand; exports.commandForScript = commandForScript; exports.discoverValidationCommands = discoverValidationCommands; exports.nextUnrunValidationCommand = nextUnrunValidationCommand; exports.describeCommandDiscovery = describeCommandDiscovery; exports.patchRepairAttemptsUsed = patchRepairAttemptsUsed; exports.patchQualitySummary = patchQualitySummary; exports.canRequestPatchRepair = canRequestPatchRepair; exports.patchValidationStatus = patchValidationStatus; exports.describePatchQuality = describePatchQuality; exports.rollbackSafetySummary = rollbackSafetySummary; exports.unappliedPatchStack = unappliedPatchStack; exports.latestUnappliedPatch = latestUnappliedPatch; exports.canAutoRollback = canAutoRollback; exports.shouldContinueRollbackStack = shouldContinueRollbackStack; exports.workspaceValidationStatus = workspaceValidationStatus; exports.describeRollbackSafety = describeRollbackSafety; exports.extractUnifiedDiff = extractUnifiedDiff; exports.extractPatchPaths = extractPatchPaths; exports.isRedactionEnabled = isRedactionEnabled; exports.redactText = redactText; exports.inferUserLanguage = inferUserLanguage; exports.responseLanguageName = responseLanguageName; exports.describeLanguagePolicy = describeLanguagePolicy; exports.spanishLike = spanishLike; exports.decideNextAction = decideNextAction; exports.nowMillis = nowMillis; exports.emitAgentEvent = emitAgentEvent; exports.emitAgentEvents = emitAgentEvents; exports.summarizeAgentAction = summarizeAgentAction; exports.summarizeAgentObservation = summarizeAgentObservation; exports.observationStatus = observationStatus; exports.errorEventFor = errorEventFor; exports.observationEventFor = observationEventFor; exports.runStatusFor = runStatusFor; exports.retry = retry; exports.sleep = sleep; exports.timeout = timeout; exports.invokeAction = invokeAction; exports.runAgent = runAgent; exports.isAgentConfigMode = isAgentConfigMode; exports.isAgentConfigApprovalMode = isAgentConfigApprovalMode; exports.isAgentConfigLLMProvider = isAgentConfigLLMProvider; exports.AGENT_CONFIG_FILE_NAMES = AGENT_CONFIG_FILE_NAMES; exports.isAgentPreset = isAgentPreset; exports.goalForAgentPreset = goalForAgentPreset; exports.makeConfiguredPermissions = makeConfiguredPermissions; exports.defaultPermissions = defaultPermissions; exports.autoApproveApprovals = autoApproveApprovals; exports.makeAutoDenyApprovals = makeAutoDenyApprovals; exports.NodeShell = NodeShell; exports.makeNodeFileSystem = makeNodeFileSystem; exports.makeNodePatchService = makeNodePatchService; exports.loadNodeAgentConfig = loadNodeAgentConfig; exports.makeOpenAICompatibleLLM = makeOpenAICompatibleLLM; exports.makeGoogleGenerativeAILLM = makeGoogleGenerativeAILLM; exports.makeFakeLLM = makeFakeLLM; exports.discoverNodeWorkspaceRoot = discoverNodeWorkspaceRoot;
4087
+
4088
+
4089
+
4090
+
4091
+
4092
+
4093
+
4094
+
4095
+
4096
+
4097
+
4098
+ exports.initialAgentState = initialAgentState; exports.reduceAgentState = reduceAgentState; exports.isTerminal = isTerminal; exports.sampleBeta = sampleBeta; exports.extractLikelyFilePaths = extractLikelyFilePaths; exports.deriveContextSearchQueries = deriveContextSearchQueries; exports.describeContextDiscovery = describeContextDiscovery; exports.summarizeContextDiscovery = summarizeContextDiscovery; exports.nextContextDiscoveryAction = nextContextDiscoveryAction; exports.PROJECT_PROFILE_PROBES = PROJECT_PROFILE_PROBES; exports.projectProfileProbePending = projectProfileProbePending; exports.discoverProjectProfile = discoverProjectProfile; exports.describeProjectProfile = describeProjectProfile; exports.PROJECT_LOCKFILE_PROBES = PROJECT_LOCKFILE_PROBES; exports.parseProjectPackageJson = parseProjectPackageJson; exports.nextProjectProbeAction = nextProjectProbeAction; exports.discoverPackageManager = discoverPackageManager; exports.splitCommand = splitCommand; exports.commandForScript = commandForScript; exports.discoverValidationCommands = discoverValidationCommands; exports.nextUnrunValidationCommand = nextUnrunValidationCommand; exports.describeCommandDiscovery = describeCommandDiscovery; exports.patchRepairAttemptsUsed = patchRepairAttemptsUsed; exports.patchQualitySummary = patchQualitySummary; exports.canRequestPatchRepair = canRequestPatchRepair; exports.patchValidationStatus = patchValidationStatus; exports.describePatchQuality = describePatchQuality; exports.rollbackSafetySummary = rollbackSafetySummary; exports.unappliedPatchStack = unappliedPatchStack; exports.latestUnappliedPatch = latestUnappliedPatch; exports.canAutoRollback = canAutoRollback; exports.shouldContinueRollbackStack = shouldContinueRollbackStack; exports.workspaceValidationStatus = workspaceValidationStatus; exports.describeRollbackSafety = describeRollbackSafety; exports.extractUnifiedDiff = extractUnifiedDiff; exports.extractPatchPaths = extractPatchPaths; exports.isRedactionEnabled = isRedactionEnabled; exports.redactText = redactText; exports.inferUserLanguage = inferUserLanguage; exports.responseLanguageName = responseLanguageName; exports.describeLanguagePolicy = describeLanguagePolicy; exports.spanishLike = spanishLike; exports.selectStrategy = selectStrategy; exports.extractSignals = extractSignals; exports.decideNextAction = decideNextAction; exports.nowMillis = nowMillis; exports.emitAgentEvent = emitAgentEvent; exports.emitAgentEvents = emitAgentEvents; exports.summarizeAgentAction = summarizeAgentAction; exports.summarizeAgentObservation = summarizeAgentObservation; exports.observationStatus = observationStatus; exports.errorEventFor = errorEventFor; exports.observationEventFor = observationEventFor; exports.runStatusFor = runStatusFor; exports.retry = retry; exports.sleep = sleep; exports.timeout = timeout; exports.invokeAction = invokeAction; exports.runAgent = runAgent; exports.isAgentConfigMode = isAgentConfigMode; exports.isAgentConfigApprovalMode = isAgentConfigApprovalMode; exports.isAgentConfigLLMProvider = isAgentConfigLLMProvider; exports.AGENT_CONFIG_FILE_NAMES = AGENT_CONFIG_FILE_NAMES; exports.isAgentPreset = isAgentPreset; exports.goalForAgentPreset = goalForAgentPreset; exports.deepFreeze = deepFreeze; exports.collectHostSignals = collectHostSignals; exports.CI_INDICATORS = CI_INDICATORS; exports.inferTransport = inferTransport; exports.inferCapabilities = inferCapabilities; exports.inferConstraints = inferConstraints; exports.inferOptionalIdentity = inferOptionalIdentity; exports.buildHostProfile = buildHostProfile; exports.makeConfiguredPermissions = makeConfiguredPermissions; exports.defaultPermissions = defaultPermissions; exports.autoApproveApprovals = autoApproveApprovals; exports.makeAutoDenyApprovals = makeAutoDenyApprovals; exports.NodeShell = NodeShell; exports.makeNodeFileSystem = makeNodeFileSystem; exports.makeNodePatchService = makeNodePatchService; exports.loadNodeAgentConfig = loadNodeAgentConfig; exports.makeOpenAICompatibleLLM = makeOpenAICompatibleLLM; exports.makeGoogleGenerativeAILLM = makeGoogleGenerativeAILLM; exports.makeFakeLLM = makeFakeLLM; exports.discoverNodeWorkspaceRoot = discoverNodeWorkspaceRoot;