@tangle-network/agent-runtime 0.79.2 → 0.79.3

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.
@@ -1620,10 +1620,129 @@ function errMessage(err) {
1620
1620
  return String(err);
1621
1621
  }
1622
1622
 
1623
+ // src/mcp/worktree.ts
1624
+ import { spawn } from "child_process";
1625
+ async function runGitAsync(args, cwd, runner) {
1626
+ if (runner) return runner(args, { cwd });
1627
+ return new Promise((resolve, reject) => {
1628
+ const proc = spawn("git", args, { cwd, stdio: "pipe" });
1629
+ let stdout = "";
1630
+ let stderr = "";
1631
+ proc.stdout?.on("data", (c) => {
1632
+ stdout += String(c);
1633
+ });
1634
+ proc.stderr?.on("data", (c) => {
1635
+ stderr += String(c);
1636
+ });
1637
+ proc.on("error", reject);
1638
+ proc.on("close", (code) => resolve({ stdout, stderr, exitCode: code ?? -1 }));
1639
+ });
1640
+ }
1641
+ function ensureGitOk(step, result) {
1642
+ if (result.exitCode !== 0) {
1643
+ throw new Error(
1644
+ `worktree: git ${step} failed (exit ${result.exitCode}): ${result.stderr.slice(0, 400)}`
1645
+ );
1646
+ }
1647
+ }
1648
+ async function createWorktree(options) {
1649
+ const variants = options.variantsDir ?? ".agent-worktrees";
1650
+ const baseRef = options.baseRef ?? "HEAD";
1651
+ const branch = `delegate/${options.runId}`;
1652
+ const path2 = `${options.repoRoot.replace(/\/+$/, "")}/${variants}/${options.runId}`;
1653
+ const headSha = await runGitAsync(["rev-parse", baseRef], options.repoRoot, options.runGit);
1654
+ ensureGitOk(`rev-parse ${baseRef}`, headSha);
1655
+ const add = await runGitAsync(
1656
+ ["worktree", "add", "-b", branch, path2, baseRef],
1657
+ options.repoRoot,
1658
+ options.runGit
1659
+ );
1660
+ ensureGitOk(`worktree add ${path2}`, add);
1661
+ return { path: path2, baseSha: headSha.stdout.trim(), branch };
1662
+ }
1663
+ async function captureWorktreeDiff(options) {
1664
+ const baseRef = options.baseRef ?? options.worktree.baseSha;
1665
+ await runGitAsync(["add", "-A"], options.worktree.path, options.runGit);
1666
+ const patch = await runGitAsync(
1667
+ ["diff", "--cached", baseRef],
1668
+ options.worktree.path,
1669
+ options.runGit
1670
+ );
1671
+ const shortstat = await runGitAsync(
1672
+ ["diff", "--cached", "--shortstat", baseRef],
1673
+ options.worktree.path,
1674
+ options.runGit
1675
+ );
1676
+ const stats = parseShortstat(shortstat.stdout);
1677
+ return { patch: patch.stdout, stats };
1678
+ }
1679
+ function parseShortstat(text) {
1680
+ const out = { filesChanged: 0, insertions: 0, deletions: 0 };
1681
+ const filesMatch = text.match(/(\d+)\s+files?\s+changed/);
1682
+ if (filesMatch?.[1]) out.filesChanged = Number(filesMatch[1]);
1683
+ const insertMatch = text.match(/(\d+)\s+insertions?/);
1684
+ if (insertMatch?.[1]) out.insertions = Number(insertMatch[1]);
1685
+ const deleteMatch = text.match(/(\d+)\s+deletions?/);
1686
+ if (deleteMatch?.[1]) out.deletions = Number(deleteMatch[1]);
1687
+ return out;
1688
+ }
1689
+ async function removeWorktree(options) {
1690
+ const force = options.force ?? true;
1691
+ const args = ["worktree", "remove"];
1692
+ if (force) args.push("--force");
1693
+ args.push(options.worktree.path);
1694
+ const result = await runGitAsync(args, options.repoRoot, options.runGit);
1695
+ if (result.exitCode !== 0 && !/not a working tree/.test(result.stderr)) {
1696
+ await runGitAsync(
1697
+ ["branch", "-D", options.worktree.branch],
1698
+ options.repoRoot,
1699
+ options.runGit
1700
+ ).catch(() => void 0);
1701
+ }
1702
+ await runGitAsync(
1703
+ ["branch", "-D", options.worktree.branch],
1704
+ options.repoRoot,
1705
+ options.runGit
1706
+ ).catch(() => void 0);
1707
+ }
1708
+
1623
1709
  // src/runtime/router-client.ts
1624
1710
  import { estimateCost, isModelPriced } from "@tangle-network/agent-eval";
1625
1711
 
1626
1712
  // src/runtime/tool-loop.ts
1713
+ function estimateConversationTokens(messages) {
1714
+ let chars = 0;
1715
+ for (const m of messages) {
1716
+ const content = m.content;
1717
+ chars += typeof content === "string" ? content.length : safeJsonLength(content);
1718
+ const calls = m.tool_calls;
1719
+ if (calls) for (const c of calls) chars += c.function?.arguments?.length ?? 0;
1720
+ }
1721
+ return Math.ceil(chars / 4);
1722
+ }
1723
+ function safeJsonLength(value) {
1724
+ if (value === void 0 || value === null) return 0;
1725
+ try {
1726
+ return JSON.stringify(value)?.length ?? 0;
1727
+ } catch {
1728
+ return String(value).length;
1729
+ }
1730
+ }
1731
+ async function maybeCompact(messages, c, turn) {
1732
+ const head = c.preserveHead !== void 0 && c.preserveHead > 0 ? c.preserveHead : 2;
1733
+ if (messages.length <= head + 1) return false;
1734
+ const estimate = c.estimateTokens ?? estimateConversationTokens;
1735
+ const before = estimate(messages);
1736
+ if (before <= c.thresholdTokens) return false;
1737
+ const digest = await c.distill([...messages]);
1738
+ messages.splice(head, messages.length - head, {
1739
+ role: "user",
1740
+ content: `[earlier work compacted to save context \u2014 progress so far]
1741
+ ${digest}`
1742
+ });
1743
+ c.onCompact?.({ turn, beforeTokens: before, afterTokens: estimate(messages) });
1744
+ return true;
1745
+ }
1627
1746
  async function runBrainLoop(opts) {
1628
1747
  const maxTurns = opts.maxTurns ?? 4;
1629
1748
  const messages = [...opts.initialMessages];
@@ -1634,6 +1753,7 @@ async function runBrainLoop(opts) {
1634
1753
  for (let turn = 1; turn <= maxTurns; turn += 1) {
1635
1754
  if (opts.hooks?.stopBefore?.(turn)) break;
1636
1755
  await opts.hooks?.beforeTurn?.(turn, messages);
1756
+ if (opts.compaction) await maybeCompact(messages, opts.compaction, turn);
1637
1757
  const r = await opts.chat(messages, opts.tools);
1638
1758
  if (r.usage) {
1639
1759
  usage.input += r.usage.input;
@@ -1821,92 +1941,6 @@ ${lines.join("\n")}`;
1821
1941
  };
1822
1942
  }
1823
1943
 
1824
- // src/mcp/worktree.ts
1825
- import { spawn } from "child_process";
1826
- async function runGitAsync(args, cwd, runner) {
1827
- if (runner) return runner(args, { cwd });
1828
- return new Promise((resolve, reject) => {
1829
- const proc = spawn("git", args, { cwd, stdio: "pipe" });
1830
- let stdout = "";
1831
- let stderr = "";
1832
- proc.stdout?.on("data", (c) => {
1833
- stdout += String(c);
1834
- });
1835
- proc.stderr?.on("data", (c) => {
1836
- stderr += String(c);
1837
- });
1838
- proc.on("error", reject);
1839
- proc.on("close", (code) => resolve({ stdout, stderr, exitCode: code ?? -1 }));
1840
- });
1841
- }
1842
- function ensureGitOk(step, result) {
1843
- if (result.exitCode !== 0) {
1844
- throw new Error(
1845
- `worktree: git ${step} failed (exit ${result.exitCode}): ${result.stderr.slice(0, 400)}`
1846
- );
1847
- }
1848
- }
1849
- async function createWorktree(options) {
1850
- const variants = options.variantsDir ?? ".agent-worktrees";
1851
- const baseRef = options.baseRef ?? "HEAD";
1852
- const branch = `delegate/${options.runId}`;
1853
- const path2 = `${options.repoRoot.replace(/\/+$/, "")}/${variants}/${options.runId}`;
1854
- const headSha = await runGitAsync(["rev-parse", baseRef], options.repoRoot, options.runGit);
1855
- ensureGitOk(`rev-parse ${baseRef}`, headSha);
1856
- const add = await runGitAsync(
1857
- ["worktree", "add", "-b", branch, path2, baseRef],
1858
- options.repoRoot,
1859
- options.runGit
1860
- );
1861
- ensureGitOk(`worktree add ${path2}`, add);
1862
- return { path: path2, baseSha: headSha.stdout.trim(), branch };
1863
- }
1864
- async function captureWorktreeDiff(options) {
1865
- const baseRef = options.baseRef ?? options.worktree.baseSha;
1866
- await runGitAsync(["add", "-A"], options.worktree.path, options.runGit);
1867
- const patch = await runGitAsync(
1868
- ["diff", "--cached", baseRef],
1869
- options.worktree.path,
1870
- options.runGit
1871
- );
1872
- const shortstat = await runGitAsync(
1873
- ["diff", "--cached", "--shortstat", baseRef],
1874
- options.worktree.path,
1875
- options.runGit
1876
- );
1877
- const stats = parseShortstat(shortstat.stdout);
1878
- return { patch: patch.stdout, stats };
1879
- }
1880
- function parseShortstat(text) {
1881
- const out = { filesChanged: 0, insertions: 0, deletions: 0 };
1882
- const filesMatch = text.match(/(\d+)\s+files?\s+changed/);
1883
- if (filesMatch?.[1]) out.filesChanged = Number(filesMatch[1]);
1884
- const insertMatch = text.match(/(\d+)\s+insertions?/);
1885
- if (insertMatch?.[1]) out.insertions = Number(insertMatch[1]);
1886
- const deleteMatch = text.match(/(\d+)\s+deletions?/);
1887
- if (deleteMatch?.[1]) out.deletions = Number(deleteMatch[1]);
1888
- return out;
1889
- }
1890
- async function removeWorktree(options) {
1891
- const force = options.force ?? true;
1892
- const args = ["worktree", "remove"];
1893
- if (force) args.push("--force");
1894
- args.push(options.worktree.path);
1895
- const result = await runGitAsync(args, options.repoRoot, options.runGit);
1896
- if (result.exitCode !== 0 && !/not a working tree/.test(result.stderr)) {
1897
- await runGitAsync(
1898
- ["branch", "-D", options.worktree.branch],
1899
- options.repoRoot,
1900
- options.runGit
1901
- ).catch(() => void 0);
1902
- }
1903
- await runGitAsync(
1904
- ["branch", "-D", options.worktree.branch],
1905
- options.repoRoot,
1906
- options.runGit
1907
- ).catch(() => void 0);
1908
- }
1909
-
1910
1944
  // src/runtime/supervise/worktree-cli-executor.ts
1911
1945
  import { randomUUID } from "crypto";
1912
1946
 
@@ -1943,7 +1977,7 @@ async function runWorktreeHarness(opts) {
1943
1977
  worktree,
1944
1978
  ...opts.runGit ? { runGit: opts.runGit } : {}
1945
1979
  });
1946
- const checks = await runChecks({
1980
+ const checks = await runWorktreeChecks({
1947
1981
  worktreePath: worktree.path,
1948
1982
  ...opts.testCmd !== void 0 ? { testCmd: opts.testCmd } : {},
1949
1983
  ...opts.typecheckCmd !== void 0 ? { typecheckCmd: opts.typecheckCmd } : {},
@@ -1973,10 +2007,11 @@ async function runWorktreeHarness(opts) {
1973
2007
  throw err;
1974
2008
  }
1975
2009
  }
1976
- async function runChecks(opts) {
2010
+ async function runWorktreeChecks(opts) {
1977
2011
  if (opts.testCmd === void 0 && opts.typecheckCmd === void 0) return void 0;
2012
+ const runCommand = opts.runCommand ?? defaultRunCommand;
1978
2013
  const run = async (command) => {
1979
- const res = await opts.runCommand({
2014
+ const res = await runCommand({
1980
2015
  command,
1981
2016
  cwd: opts.worktreePath,
1982
2017
  timeoutMs: opts.timeoutMs,
@@ -2052,6 +2087,7 @@ function createWorktreeCliExecutor(options) {
2052
2087
  ...options.typecheckCmd !== void 0 ? { typecheckCmd: options.typecheckCmd } : {},
2053
2088
  ...options.harnessTimeoutMs !== void 0 ? { harnessTimeoutMs: options.harnessTimeoutMs } : {},
2054
2089
  ...options.checkTimeoutMs !== void 0 ? { checkTimeoutMs: options.checkTimeoutMs } : {},
2090
+ ...options.checkOutputCap !== void 0 ? { checkOutputCap: options.checkOutputCap } : {},
2055
2091
  ...linked ? { signal: linked } : {},
2056
2092
  ...options.runGit ? { runGit: options.runGit } : {},
2057
2093
  ...options.runHarness ? { runHarness: options.runHarness } : {},
@@ -2651,6 +2687,7 @@ ${folded}` : folded;
2651
2687
  model: seam.model,
2652
2688
  stream: true,
2653
2689
  session_id: args.sessionId,
2690
+ ...seam.cwd ? { cwd: seam.cwd } : {},
2654
2691
  ...seam.agentProfile ? { agent_profile: seam.agentProfile } : {},
2655
2692
  messages
2656
2693
  }),
@@ -2767,11 +2804,182 @@ function parseSseFrame(frame) {
2767
2804
  if (typeof u?.cost === "number") out.cost = u.cost;
2768
2805
  return Object.keys(out).length > 0 ? out : void 0;
2769
2806
  }
2807
+ function bridgeWorktreeExecutor(spec, ctx, seam) {
2808
+ const bridge = seam.bridge;
2809
+ if (!bridge) {
2810
+ throw new ValidationError("cliWorktreeExecutor: bridge transport missing");
2811
+ }
2812
+ if (!bridge.bridgeUrl || !bridge.bridgeBearer) {
2813
+ throw new ValidationError(
2814
+ "cliWorktreeExecutor: bridge.bridgeUrl + bridge.bridgeBearer required"
2815
+ );
2816
+ }
2817
+ const runId = seam.runId ?? randomUUID2();
2818
+ const sessionId = bridge.sessionId ?? `bridge-worktree-${runId}`;
2819
+ const controller = new AbortController();
2820
+ const pending = [];
2821
+ let inner;
2822
+ let worktree;
2823
+ let removed = false;
2824
+ let artifact;
2825
+ const cleanupWorktree = async () => {
2826
+ if (!worktree || removed) return;
2827
+ const target = worktree;
2828
+ removed = true;
2829
+ worktree = void 0;
2830
+ await removeWorktree({
2831
+ worktree: target,
2832
+ repoRoot: seam.repoRoot,
2833
+ ...seam.runGit ? { runGit: seam.runGit } : {}
2834
+ }).catch(() => void 0);
2835
+ };
2836
+ const deliver = (msg) => {
2837
+ if (inner?.deliver) {
2838
+ inner.deliver(msg);
2839
+ return;
2840
+ }
2841
+ pending.push(msg);
2842
+ };
2843
+ return {
2844
+ runtime: "cli",
2845
+ budgetExempt: seam.budgetExempt ?? false,
2846
+ deliver,
2847
+ execute(_task, signal) {
2848
+ return (async function* bridgeWorktreeStream() {
2849
+ const started = Date.now();
2850
+ const linked = mergeAbortSignals(signal, controller.signal);
2851
+ let bridgeArtifact;
2852
+ try {
2853
+ worktree = await createWorktree({
2854
+ repoRoot: seam.repoRoot,
2855
+ runId,
2856
+ ...seam.baseRef ? { baseRef: seam.baseRef } : {},
2857
+ ...seam.runGit ? { runGit: seam.runGit } : {}
2858
+ });
2859
+ removed = false;
2860
+ const bridgeSeam = {
2861
+ bridgeUrl: bridge.bridgeUrl,
2862
+ bridgeBearer: bridge.bridgeBearer,
2863
+ model: resolveBridgeWorktreeModel(spec, bridge),
2864
+ cwd: worktree.path,
2865
+ sessionId,
2866
+ ...bridge.agentProfile ? { agentProfile: bridge.agentProfile } : { agentProfile: spec.profile },
2867
+ ...bridge.timeoutMs !== void 0 ? { timeoutMs: bridge.timeoutMs } : {},
2868
+ ...bridge.maxTurns !== void 0 ? { maxTurns: bridge.maxTurns } : {}
2869
+ };
2870
+ const bridgeCtx = {
2871
+ ...ctx,
2872
+ signal: linked,
2873
+ seams: { ...ctx.seams, [bridgeSeamKey]: bridgeSeam }
2874
+ };
2875
+ inner = bridgeExecutor(spec, bridgeCtx);
2876
+ for (const msg of pending.splice(0)) inner.deliver?.(msg);
2877
+ const run = inner.execute(seam.taskPrompt, linked);
2878
+ if (isAsyncIterable2(run)) {
2879
+ for await (const event of run) yield event;
2880
+ bridgeArtifact = inner.resultArtifact();
2881
+ } else {
2882
+ bridgeArtifact = await run;
2883
+ }
2884
+ const diff = await captureWorktreeDiff({
2885
+ worktree,
2886
+ ...seam.runGit ? { runGit: seam.runGit } : {}
2887
+ });
2888
+ const checks = await runWorktreeChecks({
2889
+ worktreePath: worktree.path,
2890
+ ...seam.testCmd !== void 0 ? { testCmd: seam.testCmd } : {},
2891
+ ...seam.typecheckCmd !== void 0 ? { typecheckCmd: seam.typecheckCmd } : {},
2892
+ timeoutMs: seam.checkTimeoutMs ?? seam.harnessTimeoutMs ?? bridge.timeoutMs ?? 5 * 60 * 1e3,
2893
+ cap: seam.checkOutputCap ?? 16e3,
2894
+ ...seam.runCommand ? { runCommand: seam.runCommand } : {},
2895
+ signal: linked
2896
+ });
2897
+ const result = {
2898
+ branch: worktree.branch,
2899
+ patch: diff.patch,
2900
+ stats: diff.stats,
2901
+ harness: {
2902
+ name: "bridge",
2903
+ exitCode: null,
2904
+ timedOut: false,
2905
+ killedBySignal: null,
2906
+ durationMs: bridgeArtifact.spent.ms || Date.now() - started,
2907
+ stdout: bridgeOutputText(bridgeArtifact.out),
2908
+ stderr: ""
2909
+ },
2910
+ ...checks ? { checks } : {}
2911
+ };
2912
+ const spent = {
2913
+ ...bridgeArtifact.spent,
2914
+ ms: bridgeArtifact.spent.ms || Date.now() - started
2915
+ };
2916
+ artifact = {
2917
+ outRef: contentRef("bridge-worktree", { sessionId, result }),
2918
+ out: result,
2919
+ spent
2920
+ };
2921
+ } catch (err) {
2922
+ controller.abort();
2923
+ await inner?.teardown("brutalKill").catch(() => void 0);
2924
+ await cleanupWorktree();
2925
+ throw err;
2926
+ }
2927
+ })();
2928
+ },
2929
+ async teardown(grace) {
2930
+ controller.abort();
2931
+ let destroyed = true;
2932
+ try {
2933
+ if (inner) {
2934
+ destroyed = (await inner.teardown(grace)).destroyed;
2935
+ }
2936
+ } finally {
2937
+ await cleanupWorktree();
2938
+ }
2939
+ return { destroyed };
2940
+ },
2941
+ resultArtifact() {
2942
+ if (!artifact) {
2943
+ throw new ValidationError(
2944
+ "cliWorktreeExecutor: bridge resultArtifact() read before stream drained"
2945
+ );
2946
+ }
2947
+ return artifact;
2948
+ }
2949
+ };
2950
+ }
2951
+ function resolveBridgeWorktreeModel(spec, bridge) {
2952
+ if (bridge.model) return bridge.model;
2953
+ const model = spec.profile.model?.default;
2954
+ if (typeof model === "string" && model.length > 0) return model;
2955
+ throw new ValidationError(
2956
+ "cliWorktreeExecutor: bridge.model or AgentProfile.model.default required"
2957
+ );
2958
+ }
2959
+ function bridgeOutputText(out) {
2960
+ if (typeof out === "string") return out;
2961
+ if (out && typeof out === "object") {
2962
+ const content = out.content;
2963
+ if (typeof content === "string") return content;
2964
+ }
2965
+ try {
2966
+ return JSON.stringify(out) ?? String(out);
2967
+ } catch {
2968
+ return String(out);
2969
+ }
2970
+ }
2971
+ function isAsyncIterable2(value) {
2972
+ return value !== null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function";
2973
+ }
2770
2974
  var cliWorktreeExecutor = (spec, ctx) => {
2771
2975
  const seam = readSeam(ctx, cliWorktreeSeamKey, "cli-worktree");
2772
- if (!seam.repoRoot || !seam.harness || !seam.taskPrompt) {
2976
+ if (!seam.repoRoot || !seam.taskPrompt) {
2977
+ throw new ValidationError("cliWorktreeExecutor: CliWorktreeSeam.repoRoot + taskPrompt required");
2978
+ }
2979
+ if (seam.bridge) return bridgeWorktreeExecutor(spec, ctx, seam);
2980
+ if (!seam.harness) {
2773
2981
  throw new ValidationError(
2774
- "cliWorktreeExecutor: CliWorktreeSeam.repoRoot + harness + taskPrompt required"
2982
+ "cliWorktreeExecutor: CliWorktreeSeam.harness required when bridge is not set"
2775
2983
  );
2776
2984
  }
2777
2985
  return createWorktreeCliExecutor({
@@ -2781,7 +2989,14 @@ var cliWorktreeExecutor = (spec, ctx) => {
2781
2989
  taskPrompt: seam.taskPrompt,
2782
2990
  ...seam.runId ? { runId: seam.runId } : {},
2783
2991
  ...seam.baseRef ? { baseRef: seam.baseRef } : {},
2784
- ...seam.harnessTimeoutMs !== void 0 ? { harnessTimeoutMs: seam.harnessTimeoutMs } : {}
2992
+ ...seam.harnessTimeoutMs !== void 0 ? { harnessTimeoutMs: seam.harnessTimeoutMs } : {},
2993
+ ...seam.testCmd !== void 0 ? { testCmd: seam.testCmd } : {},
2994
+ ...seam.typecheckCmd !== void 0 ? { typecheckCmd: seam.typecheckCmd } : {},
2995
+ ...seam.checkTimeoutMs !== void 0 ? { checkTimeoutMs: seam.checkTimeoutMs } : {},
2996
+ ...seam.checkOutputCap !== void 0 ? { checkOutputCap: seam.checkOutputCap } : {},
2997
+ ...seam.runGit ? { runGit: seam.runGit } : {},
2998
+ ...seam.runCommand ? { runCommand: seam.runCommand } : {},
2999
+ ...seam.budgetExempt !== void 0 ? { budgetExempt: seam.budgetExempt } : {}
2785
3000
  });
2786
3001
  };
2787
3002
  function createExecutor(config) {
@@ -3275,7 +3490,7 @@ function gateOnDeliverable(inner, deliverable) {
3275
3490
  ...inner.deliver ? { deliver: (m) => inner.deliver?.(m) } : {},
3276
3491
  execute(task, signal) {
3277
3492
  const r = inner.execute(task, signal);
3278
- if (isAsyncIterable2(r)) {
3493
+ if (isAsyncIterable3(r)) {
3279
3494
  return (async function* () {
3280
3495
  for await (const ev of r) yield ev;
3281
3496
  const art = inner.resultArtifact();
@@ -3295,7 +3510,7 @@ function gateOnDeliverable(inner, deliverable) {
3295
3510
  }
3296
3511
  };
3297
3512
  }
3298
- function isAsyncIterable2(v) {
3513
+ function isAsyncIterable3(v) {
3299
3514
  return v != null && typeof v[Symbol.asyncIterator] === "function";
3300
3515
  }
3301
3516
 
@@ -3953,6 +4168,18 @@ function createCoordinationTools(opts) {
3953
4168
  }
3954
4169
 
3955
4170
  // src/runtime/supervise/coordination-driver.ts
4171
+ var distillInstruction = "CONTEXT COMPACTION. Your detailed turn-by-turn history is about to be discarded to free your context window. Write a COMPLETE, compact handoff note for your future self so you can keep going without it. Cover: (1) what you have accomplished; (2) every worker you spawned and its current status/result; (3) what subtasks remain unfinished, failing, or unverified \u2014 be specific and exhaustive here, this is the part you must not lose; (4) your immediate next action. Do not call any tools; respond with the note only.";
4172
+ function summarizeRoster(view, settled) {
4173
+ if (view.nodes.length === 0) return "Workers in current live scope: none yet.";
4174
+ const settledById = new Map(settled.map((w) => [w.id, w]));
4175
+ const lines = view.nodes.map((node) => formatRosterNode(node, settledById.get(node.id)));
4176
+ return `Workers in current live scope (ground truth from the run, ${view.nodes.length} total, ${view.inFlight} in flight):
4177
+ ${lines.join("\n")}`;
4178
+ }
4179
+ function formatRosterNode(node, settled) {
4180
+ const result = settled?.status === "done" ? `, delivered=${settled.valid ?? false}${settled.score !== void 0 ? `, score=${settled.score}` : ""}${settled.outRef ? `, outRef=${settled.outRef}` : ""}` : settled?.status === "down" ? `, reason=${settled.reason ?? "unknown"}` : node.outRef ? `, outRef=${node.outRef}` : "";
4181
+ return `- ${node.id}: ${node.status}, label=${node.label}, runtime=${node.runtime}${result}`;
4182
+ }
3956
4183
  var runawayTripwireTurns = 2e3;
3957
4184
  function poolStarved(scope, perWorker) {
3958
4185
  const b = scope.budget;
@@ -3974,6 +4201,11 @@ function driverAgent(opts) {
3974
4201
  "driverAgent: extraTools requires executeExtraTool (how to run a work-tool call)"
3975
4202
  );
3976
4203
  }
4204
+ if ((opts.analyzeOnSettle?.length ?? 0) > 0 && !opts.analysts) {
4205
+ throw new ValidationError(
4206
+ "driverAgent: analyzeOnSettle requires analysts (the lens registry the kinds resolve against)"
4207
+ );
4208
+ }
3977
4209
  const reserved = new Set(coordinationVerbNames);
3978
4210
  for (const t of opts.extraTools ?? []) {
3979
4211
  if (reserved.has(t.name)) {
@@ -3997,7 +4229,9 @@ function driverAgent(opts) {
3997
4229
  blobs: opts.blobs,
3998
4230
  makeWorkerAgent: opts.makeWorkerAgent,
3999
4231
  perWorker: opts.perWorker,
4000
- ...opts.maxLiveWorkers !== void 0 ? { maxLiveWorkers: opts.maxLiveWorkers } : {}
4232
+ ...opts.maxLiveWorkers !== void 0 ? { maxLiveWorkers: opts.maxLiveWorkers } : {},
4233
+ ...opts.analysts ? { analysts: opts.analysts } : {},
4234
+ ...opts.analyzeOnSettle ? { analyzeOnSettle: opts.analyzeOnSettle } : {}
4001
4235
  });
4002
4236
  const byName = new Map(coord.tools.map((t) => [t.name, t]));
4003
4237
  const toolSpecs = [
@@ -4012,8 +4246,8 @@ function driverAgent(opts) {
4012
4246
  }))
4013
4247
  ];
4014
4248
  const system = typeof opts.systemPrompt === "function" ? opts.systemPrompt(task) : opts.systemPrompt;
4015
- let turn = 0;
4016
- const chat = async (messages, tools) => {
4249
+ let driverTurn = 0;
4250
+ const meteredBrain = async (messages, tools, detail) => {
4017
4251
  const res = await opts.brain(messages, tools);
4018
4252
  if (res.usage || res.costUsd !== void 0) {
4019
4253
  const turnSpend = {
@@ -4023,18 +4257,52 @@ function driverAgent(opts) {
4023
4257
  ms: 0
4024
4258
  };
4025
4259
  await scope.meter(turnSpend, {
4026
- kind: "driver-inference",
4027
4260
  driver: opts.name,
4028
- turn,
4029
- toolCalls: (res.toolCalls ?? []).map((c) => c.name)
4261
+ toolCalls: (res.toolCalls ?? []).map((c) => c.name),
4262
+ ...detail
4030
4263
  });
4031
4264
  }
4032
- turn += 1;
4033
4265
  return res;
4034
4266
  };
4267
+ const chat = async (messages, tools) => {
4268
+ const turn = driverTurn;
4269
+ const res = await meteredBrain(messages, tools, {
4270
+ kind: "driver-inference",
4271
+ turn
4272
+ });
4273
+ driverTurn += 1;
4274
+ return res;
4275
+ };
4276
+ const compaction = opts.compaction ? {
4277
+ thresholdTokens: opts.compaction.thresholdTokens,
4278
+ distill: opts.compaction.distill ?? (async (msgs) => {
4279
+ const roster = summarizeRoster(scope.view, coord.settled());
4280
+ try {
4281
+ const res = await meteredBrain(
4282
+ [...msgs, { role: "user", content: distillInstruction }],
4283
+ [],
4284
+ { kind: "driver-compaction", compactingTurn: driverTurn }
4285
+ );
4286
+ const narrative = (res.content ?? "").trim();
4287
+ return narrative ? `${roster}
4288
+
4289
+ ## Progress notes
4290
+ ${narrative}` : roster;
4291
+ } catch (e) {
4292
+ return `${roster}
4293
+
4294
+ ## Progress notes
4295
+ Summary unavailable: ${errMessage2(e)}`;
4296
+ }
4297
+ }),
4298
+ ...opts.compaction.onCompact ? { onCompact: opts.compaction.onCompact } : {},
4299
+ ...opts.compaction.preserveHead !== void 0 ? { preserveHead: opts.compaction.preserveHead } : {},
4300
+ ...opts.compaction.estimateTokens ? { estimateTokens: opts.compaction.estimateTokens } : {}
4301
+ } : void 0;
4035
4302
  await runBrainLoop({
4036
4303
  chat,
4037
4304
  tools: toolSpecs,
4305
+ ...compaction ? { compaction } : {},
4038
4306
  execute: async (name, args) => {
4039
4307
  if (opts.executeExtraTool) {
4040
4308
  const worked = await runExtraTool(opts.executeExtraTool, name, args);
@@ -4094,6 +4362,9 @@ function safeJson(v) {
4094
4362
  return String(v);
4095
4363
  }
4096
4364
  }
4365
+ function errMessage2(e) {
4366
+ return e instanceof Error ? e.message : String(e);
4367
+ }
4097
4368
 
4098
4369
  // src/mcp/feedback-store.ts
4099
4370
  var InMemoryFeedbackStore = class {
@@ -5093,7 +5364,10 @@ function supervise(profile, task, opts) {
5093
5364
  ...opts.driveHarness ? { driveHarness: opts.driveHarness } : {},
5094
5365
  ...opts.extraTools ? { extraTools: opts.extraTools } : {},
5095
5366
  ...opts.executeExtraTool ? { executeExtraTool: opts.executeExtraTool } : {},
5096
- ...opts.maxTurns !== void 0 ? { maxTurns: opts.maxTurns } : {}
5367
+ ...opts.analysts ? { analysts: opts.analysts } : {},
5368
+ ...opts.analyzeOnSettle ? { analyzeOnSettle: opts.analyzeOnSettle } : {},
5369
+ ...opts.maxTurns !== void 0 ? { maxTurns: opts.maxTurns } : {},
5370
+ ...opts.compaction ? { compaction: opts.compaction } : {}
5097
5371
  });
5098
5372
  return createSupervisor().run(agent, task, {
5099
5373
  budget: opts.budget,
@@ -6031,10 +6305,32 @@ async function serveCoordinationMcp(opts) {
6031
6305
  }
6032
6306
 
6033
6307
  // src/runtime/supervise/supervisor-agent.ts
6308
+ var defaultSupervisorPrompt = [
6309
+ "You are a supervisor accountable for DELIVERING the task \u2014 not for looking busy. You succeed only",
6310
+ 'when the deliverable is actually produced and verified, never on a worker reporting "done".',
6311
+ "",
6312
+ "Spawning a worker spends the shared, conserved budget \u2014 so delegate with intent, not by reflex:",
6313
+ "- Do small, sequential work YOURSELF when you have work tools; spawn a worker when a sub-task is",
6314
+ " large, independent (parallelizable), or needs a clean context the current one has filled.",
6315
+ "- Prefer the FEWEST workers that deliver. Over-spawning burns the budget and rarely helps.",
6316
+ "",
6317
+ "Manage the context lifecycle on long work: give each spawned worker a BOUNDED brief \u2014 the specific",
6318
+ "sub-task plus only the interfaces/state it needs \u2014 never your whole history. When one chapter is",
6319
+ "done, distill what the next chapter needs and spawn fresh, rather than steering one worker until",
6320
+ "its context fills and degrades.",
6321
+ "",
6322
+ "Wait on real signals (await a settle, answer a blocking question), integrate the result, and stop",
6323
+ "as soon as the deliverable is met."
6324
+ ].join("\n");
6034
6325
  function supervisorAgent(profile, deps) {
6035
6326
  const name = profile.name ?? "supervisor";
6036
- const systemPrompt = profile.systemPrompt ?? "";
6327
+ const systemPrompt = profile.systemPrompt ?? defaultSupervisorPrompt;
6037
6328
  const harness = profile.harness ?? null;
6329
+ if (harness !== null && deps.compaction) {
6330
+ throw new ValidationError(
6331
+ "supervisorAgent: compaction is only supported for router-brained supervisors (profile.harness null)"
6332
+ );
6333
+ }
6038
6334
  if (harness === null) {
6039
6335
  const brain = deps.brain ?? routerBrainFromProfile(profile, deps);
6040
6336
  return driverAgent({
@@ -6047,7 +6343,10 @@ function supervisorAgent(profile, deps) {
6047
6343
  ...deps.maxLiveWorkers !== void 0 ? { maxLiveWorkers: deps.maxLiveWorkers } : {},
6048
6344
  ...deps.extraTools ? { extraTools: deps.extraTools } : {},
6049
6345
  ...deps.executeExtraTool ? { executeExtraTool: deps.executeExtraTool } : {},
6050
- ...deps.maxTurns !== void 0 ? { maxTurns: deps.maxTurns } : {}
6346
+ ...deps.analysts ? { analysts: deps.analysts } : {},
6347
+ ...deps.analyzeOnSettle ? { analyzeOnSettle: deps.analyzeOnSettle } : {},
6348
+ ...deps.maxTurns !== void 0 ? { maxTurns: deps.maxTurns } : {},
6349
+ ...deps.compaction ? { compaction: deps.compaction } : {}
6051
6350
  });
6052
6351
  }
6053
6352
  const driveHarness = deps.driveHarness;
@@ -6064,7 +6363,9 @@ function supervisorAgent(profile, deps) {
6064
6363
  blobs: deps.blobs,
6065
6364
  makeWorkerAgent: deps.makeWorkerAgent,
6066
6365
  perWorker: deps.perWorker,
6067
- ...deps.maxLiveWorkers !== void 0 ? { maxLiveWorkers: deps.maxLiveWorkers } : {}
6366
+ ...deps.maxLiveWorkers !== void 0 ? { maxLiveWorkers: deps.maxLiveWorkers } : {},
6367
+ ...deps.analysts ? { analysts: deps.analysts } : {},
6368
+ ...deps.analyzeOnSettle ? { analyzeOnSettle: deps.analyzeOnSettle } : {}
6068
6369
  });
6069
6370
  try {
6070
6371
  await driveHarness({ profile, task, scope, coordinationMcpUrl: mcp.url });
@@ -6102,15 +6403,15 @@ export {
6102
6403
  createScope,
6103
6404
  settledToIteration,
6104
6405
  withDriverExecutor,
6406
+ createWorktree,
6407
+ captureWorktreeDiff,
6408
+ removeWorktree,
6409
+ runWorktreeHarness,
6105
6410
  routerChatWithUsage,
6106
6411
  routerChatWithTools,
6107
6412
  routerToolLoop,
6108
6413
  routerBrain,
6109
6414
  createInbox,
6110
- createWorktree,
6111
- captureWorktreeDiff,
6112
- removeWorktree,
6113
- runWorktreeHarness,
6114
6415
  createWorktreeCliExecutor,
6115
6416
  cliWorktreeExecutor,
6116
6417
  createExecutor,
@@ -6178,4 +6479,4 @@ export {
6178
6479
  createInProcessTransport,
6179
6480
  serveCoordinationMcp
6180
6481
  };
6181
- //# sourceMappingURL=chunk-TSDKBFZP.js.map
6482
+ //# sourceMappingURL=chunk-KRULXIWS.js.map