@tangle-network/agent-runtime 0.94.5 → 0.94.7

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 (72) hide show
  1. package/dist/agent.d.ts +1 -1
  2. package/dist/agent.js +4 -4
  3. package/dist/{agentic-generator-CL1q0H91.d.ts → agentic-generator-1g7GDba7.d.ts} +73 -6
  4. package/dist/analyst-loop.d.ts +1 -1
  5. package/dist/analyst-loop.js +2 -2
  6. package/dist/candidate-execution/index.d.ts +39 -4
  7. package/dist/candidate-execution/index.js +8 -2
  8. package/dist/{chunk-MZH4HORF.js → chunk-5BT2NMML.js} +689 -3
  9. package/dist/chunk-5BT2NMML.js.map +1 -0
  10. package/dist/{chunk-GKZ6DFDN.js → chunk-7HH22XN4.js} +105 -27
  11. package/dist/chunk-7HH22XN4.js.map +1 -0
  12. package/dist/{chunk-JMT5VYY3.js → chunk-7NCP74SL.js} +174 -48
  13. package/dist/chunk-7NCP74SL.js.map +1 -0
  14. package/dist/{chunk-WQA5Y6PD.js → chunk-EP6RVHMX.js} +3 -3
  15. package/dist/chunk-EP6RVHMX.js.map +1 -0
  16. package/dist/{chunk-LWNMCOEA.js → chunk-FRXDOBFP.js} +3 -3
  17. package/dist/chunk-GHXW56PO.js +526 -0
  18. package/dist/chunk-GHXW56PO.js.map +1 -0
  19. package/dist/{chunk-KHLE3C5G.js → chunk-HKMKUESZ.js} +169 -50
  20. package/dist/chunk-HKMKUESZ.js.map +1 -0
  21. package/dist/{chunk-63TIZHMI.js → chunk-KYPVUEJ4.js} +4 -4
  22. package/dist/{chunk-FVJ7M3DA.js → chunk-M22PL4GH.js} +1 -1
  23. package/dist/chunk-M22PL4GH.js.map +1 -0
  24. package/dist/{chunk-4VMRCEI6.js → chunk-MSUWXCHD.js} +2 -2
  25. package/dist/{chunk-ZQZX77MM.js → chunk-QDSOD7RC.js} +2 -2
  26. package/dist/{chunk-RNWDH5Z3.js → chunk-TNUBPPZA.js} +2 -2
  27. package/dist/{completion-gate-CfX2thvL.d.ts → completion-gate-tzwyyD-E.d.ts} +2 -2
  28. package/dist/{coordination-pOGZuYS7.d.ts → coordination-o0TzS7Ms.d.ts} +5 -5
  29. package/dist/environment-provider.d.ts +2 -2
  30. package/dist/{improve-Ciuvu2jh.d.ts → improve-DZeatcs7.d.ts} +19 -8
  31. package/dist/index.d.ts +22 -19
  32. package/dist/index.js +45 -22
  33. package/dist/index.js.map +1 -1
  34. package/dist/intelligence.d.ts +7 -7
  35. package/dist/intelligence.js +42 -18
  36. package/dist/intelligence.js.map +1 -1
  37. package/dist/knowledge.d.ts +7 -7
  38. package/dist/knowledge.js +4 -4
  39. package/dist/lifecycle.d.ts +3 -3
  40. package/dist/lifecycle.js +2 -2
  41. package/dist/{local-harness-CePtFrwu.d.ts → local-harness-ZLMkKdZc.d.ts} +1 -1
  42. package/dist/{loop-runner-bin-B4PwjVaF.d.ts → loop-runner-bin-iTSxSmpv.d.ts} +2 -2
  43. package/dist/loop-runner-bin.d.ts +6 -6
  44. package/dist/loop-runner-bin.js +6 -6
  45. package/dist/loops.d.ts +36 -23
  46. package/dist/loops.js +4 -4
  47. package/dist/mcp/bin.js +3 -3
  48. package/dist/mcp/index.d.ts +10 -10
  49. package/dist/mcp/index.js +5 -5
  50. package/dist/{mcp-serve-verifier-D7hCZIkT.d.ts → mcp-serve-verifier-BO4MEsR3.d.ts} +1 -1
  51. package/dist/{openai-tools-BMOu1t3A.d.ts → openai-tools-0wACz8f8.d.ts} +1 -1
  52. package/dist/{prepare-BKxAiUcH.d.ts → prepare-DIeVgQG3.d.ts} +1 -1
  53. package/dist/profiles.d.ts +1 -1
  54. package/dist/{sanitize-Dr3SliRC.d.ts → sanitize-Dcbjp0tU.d.ts} +1 -1
  55. package/dist/{supervise-Y3w878fN.d.ts → supervise-CRwaJIkd.d.ts} +4 -4
  56. package/dist/{types-Kjr5W6OF.d.ts → types-CKmyZ9TP.d.ts} +4 -7
  57. package/dist/{types-DHLXdLVN.d.ts → types-CogNCaw7.d.ts} +1 -1
  58. package/dist/{worktree-fanout-DmBvR-_O.d.ts → worktree-fanout-BJy24LYe.d.ts} +4 -4
  59. package/package.json +6 -4
  60. package/dist/chunk-4WWSICFY.js +0 -210
  61. package/dist/chunk-4WWSICFY.js.map +0 -1
  62. package/dist/chunk-FVJ7M3DA.js.map +0 -1
  63. package/dist/chunk-GKZ6DFDN.js.map +0 -1
  64. package/dist/chunk-JMT5VYY3.js.map +0 -1
  65. package/dist/chunk-KHLE3C5G.js.map +0 -1
  66. package/dist/chunk-MZH4HORF.js.map +0 -1
  67. package/dist/chunk-WQA5Y6PD.js.map +0 -1
  68. /package/dist/{chunk-LWNMCOEA.js.map → chunk-FRXDOBFP.js.map} +0 -0
  69. /package/dist/{chunk-63TIZHMI.js.map → chunk-KYPVUEJ4.js.map} +0 -0
  70. /package/dist/{chunk-4VMRCEI6.js.map → chunk-MSUWXCHD.js.map} +0 -0
  71. /package/dist/{chunk-ZQZX77MM.js.map → chunk-QDSOD7RC.js.map} +0 -0
  72. /package/dist/{chunk-RNWDH5Z3.js.map → chunk-TNUBPPZA.js.map} +0 -0
@@ -1,210 +0,0 @@
1
- import {
2
- runLocalHarness
3
- } from "./chunk-WQA5Y6PD.js";
4
-
5
- // src/improvement/agentic-generator.ts
6
- import { spawnSync } from "child_process";
7
- import { existsSync, readFileSync } from "fs";
8
- import { join } from "path";
9
- var RAW_TRACE_ANALYST_ID = "raw-trace-distiller";
10
- var RAW_TRACE_AREA = "raw-trace-context";
11
- var RAW_TRACE_DIAGNOSIS_PATH = ".improve/raw-trace-diagnosis.md";
12
- function agenticGenerator(opts = {}) {
13
- const harness = opts.harness ?? "claude";
14
- const buildPrompt = opts.buildPrompt ?? defaultBuildPrompt;
15
- const run = opts.runHarness ?? runLocalHarness;
16
- const dirty = opts.isDirty ?? worktreeDirty;
17
- const verify = opts.verify;
18
- return {
19
- kind: `agentic:${harness}`,
20
- // The seed repo + (in rawTraceContext mode) the raw-trace filesystem context
21
- // are the change signal — an agentic coder proposes from them even when the
22
- // distiller yielded zero findings. Without this, the improvementDriver's
23
- // empty-findings guard short-circuits and generates ZERO candidates on the
24
- // first (and, for a single-generation run, only) proposal round.
25
- proposesWithoutFindings: true,
26
- async generate({ worktreePath, report, findings, maxShots, signal }) {
27
- const basePrompt = buildPrompt({ report, findings });
28
- const needsRawTraceEvidence = requiresRawTraceEvidence(findings);
29
- const shots = Math.max(1, maxShots);
30
- let attemptNote = "";
31
- for (let shot = 0; shot < shots; shot++) {
32
- if (signal.aborted) break;
33
- await run({
34
- harness,
35
- cwd: worktreePath,
36
- taskPrompt: attemptNote ? `${basePrompt}
37
-
38
- ${attemptNote}` : basePrompt,
39
- // The candidate worktree is isolated and must be editable without an
40
- // interactive permission prompt. Other runLocalHarness callers remain
41
- // permission-safe by default.
42
- dangerouslySkipPermissions: harness === "claude",
43
- timeoutMs: opts.timeoutMs,
44
- signal
45
- });
46
- if (!dirty(worktreePath)) {
47
- attemptNote = EMPTY_TREE_NOTE;
48
- continue;
49
- }
50
- if (needsRawTraceEvidence) {
51
- const problem = rawTraceEvidenceProblem(worktreePath, findings);
52
- if (problem) {
53
- attemptNote = problem;
54
- continue;
55
- }
56
- }
57
- if (!verify) {
58
- return { applied: true, summary: summarize(findings) };
59
- }
60
- const result = await verify(worktreePath);
61
- if (result.ok) {
62
- return { applied: true, summary: summarize(findings) };
63
- }
64
- attemptNote = failureNote(result.feedback);
65
- }
66
- return { applied: false, summary: "" };
67
- }
68
- };
69
- }
70
- function defaultBuildPrompt(args) {
71
- const lines = [
72
- "You are improving this codebase based on an evaluation analysis.",
73
- "Make the smallest set of edits that addresses the findings below, then stop.",
74
- "Do not change unrelated code. Do not commit \u2014 leave changes in the working tree.",
75
- "",
76
- "Findings:"
77
- ];
78
- for (const f of args.findings) {
79
- const where = f.subject ? ` [${f.subject}]` : "";
80
- lines.push(`- (${f.severity})${where} ${f.claim}`);
81
- if (f.recommended_action) lines.push(` \u2192 ${f.recommended_action}`);
82
- }
83
- if (requiresRawTraceEvidence(args.findings)) {
84
- lines.push(
85
- "",
86
- "Raw trace evidence requirement:",
87
- `- Inspect at least one raw trace path named above before editing.`,
88
- `- Write ${RAW_TRACE_DIAGNOSIS_PATH} in this worktree.`,
89
- "- Include the exact trace path(s) inspected, the failure mechanism, and the code change made.",
90
- "- A candidate without this file, or with only this file changed, is discarded."
91
- );
92
- }
93
- return lines.join("\n");
94
- }
95
- var EMPTY_TREE_NOTE = "NOTE: your previous attempt left the working tree unchanged. Make the concrete file edits now.";
96
- function failureNote(feedback) {
97
- const detail = feedback?.trim();
98
- return [
99
- "NOTE: your edits are in the working tree but verification FAILED.",
100
- "Fix the problem in place \u2014 build on your existing edits, do not revert them.",
101
- detail ? `Verifier output:
102
- ${truncate(detail, 4e3)}` : "No verifier detail was captured."
103
- ].join("\n");
104
- }
105
- function rawTraceEvidenceProblem(worktreePath, findings) {
106
- const changedPaths = worktreeChangedPaths(worktreePath);
107
- const substantive = changedPaths.filter((path) => path !== RAW_TRACE_DIAGNOSIS_PATH);
108
- if (substantive.length === 0) {
109
- return [
110
- `NOTE: raw-trace mode requires a real code/config edit in addition to ${RAW_TRACE_DIAGNOSIS_PATH}.`,
111
- "Your previous attempt only changed the diagnosis artifact. Inspect the cited traces and make the causal code change."
112
- ].join("\n");
113
- }
114
- const diagnosisPath = join(worktreePath, RAW_TRACE_DIAGNOSIS_PATH);
115
- if (!existsSync(diagnosisPath)) {
116
- return [
117
- `NOTE: raw-trace mode requires ${RAW_TRACE_DIAGNOSIS_PATH}.`,
118
- "Before retrying, inspect at least one cited spans.jsonl/cached-result.json/artifact path, then write the diagnosis file with the exact path, failure mechanism, and code change."
119
- ].join("\n");
120
- }
121
- const body = readFileSync(diagnosisPath, "utf8");
122
- const evidencePaths = traceEvidencePaths(findings);
123
- if (evidencePaths.length > 0 && !evidencePaths.some((path) => body.includes(path))) {
124
- return [
125
- `${RAW_TRACE_DIAGNOSIS_PATH} exists, but it does not cite any exact raw trace path from the findings.`,
126
- `Cite at least one of these inspected paths exactly: ${evidencePaths.slice(0, 5).join(", ")}`
127
- ].join("\n");
128
- }
129
- return null;
130
- }
131
- function requiresRawTraceEvidence(findings) {
132
- return findings.some((finding) => {
133
- const f = finding;
134
- return f.analyst_id === RAW_TRACE_ANALYST_ID || f.area === RAW_TRACE_AREA;
135
- });
136
- }
137
- function traceEvidencePaths(findings) {
138
- const out = [];
139
- for (const finding of findings) {
140
- const refs = finding.evidence_refs;
141
- if (!Array.isArray(refs)) continue;
142
- for (const ref of refs) {
143
- if (!ref || typeof ref !== "object") continue;
144
- const uri = ref.uri;
145
- if (typeof uri === "string" && uri.length > 0) out.push(uri);
146
- }
147
- }
148
- return [...new Set(out)];
149
- }
150
- function commandVerifier(command, args = [], timeoutMs = 3e5) {
151
- return (worktreePath) => {
152
- const result = spawnSync(command, args, {
153
- cwd: worktreePath,
154
- encoding: "utf-8",
155
- timeout: timeoutMs
156
- });
157
- if (result.signal) {
158
- return {
159
- ok: false,
160
- feedback: `verifier '${command}' killed by ${result.signal} (likely timeout after ${timeoutMs}ms)`
161
- };
162
- }
163
- if (result.error) {
164
- const code = result.error.code;
165
- if (code === "ENOENT") {
166
- throw new Error(
167
- `commandVerifier: '${command}' not found in PATH (setup bug, not a failed candidate)`
168
- );
169
- }
170
- throw new Error(`commandVerifier: '${command}' failed to spawn: ${result.error.message}`);
171
- }
172
- if (result.status === 0) return { ok: true };
173
- const out = `${result.stdout ?? ""}${result.stderr ?? ""}`.trim();
174
- return { ok: false, feedback: out.length > 0 ? out : `exit ${result.status}` };
175
- };
176
- }
177
- function summarize(findings) {
178
- if (findings.length === 0) return "agentic improvement";
179
- if (findings.length === 1) return `agentic: ${truncate(findings[0].claim, 64)}`;
180
- return `agentic: ${findings.length} findings addressed`;
181
- }
182
- function truncate(s, n) {
183
- return s.length <= n ? s : `${s.slice(0, n - 1)}\u2026`;
184
- }
185
- function worktreeDirty(worktreePath) {
186
- return worktreeChangedPaths(worktreePath).length > 0;
187
- }
188
- function worktreeChangedPaths(worktreePath) {
189
- const result = spawnSync("git", ["status", "--porcelain", "--untracked-files=all"], {
190
- cwd: worktreePath,
191
- encoding: "utf-8"
192
- });
193
- if (result.error) {
194
- throw new Error(
195
- `agenticGenerator: git status failed to spawn in ${worktreePath}: ${result.error.message}`
196
- );
197
- }
198
- if (result.status !== 0) {
199
- throw new Error(
200
- `agenticGenerator: git status exited ${result.status} in ${worktreePath}: ${result.stderr.trim()}`
201
- );
202
- }
203
- return result.stdout.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => line.slice(3).trim());
204
- }
205
-
206
- export {
207
- agenticGenerator,
208
- commandVerifier
209
- };
210
- //# sourceMappingURL=chunk-4WWSICFY.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/improvement/agentic-generator.ts"],"sourcesContent":["/**\n *\n * `agenticGenerator` — the full-agentic `CandidateGenerator`: the\n * `shots=N, sandbox=on` setting of the one `improvementDriver`. It runs a real\n * coding harness (claude / codex / opencode) inside the candidate worktree the\n * driver already created, letting the agent read the codebase + the research\n * report and make the change in place. The driver then commits the worktree\n * into a `CodeSurface`.\n *\n * Mechanism: identical to the proven Phase-2.8 in-process executor — spawn the\n * harness as a subprocess with `cwd` = the worktree, on the same filesystem,\n * so edits land in place (no sandbox-mount round-trip). `runLocalHarness` is\n * the verified primitive. The OUTER sandbox is the improvement loop's own\n * execution context; the generator does not nest a second sandbox per\n * candidate (which would reintroduce a host↔sandbox worktree-transport\n * problem that does not need solving here).\n *\n * `maxShots` is the DEPTH dial — a multi-shot verify-in-session loop, NOT the\n * kernel `runLoop`. Each shot runs one full harness session in the (persistent)\n * worktree; between shots the loop refines based on what the last shot produced:\n * - empty tree → \"you changed nothing, make the edits\" → retry\n * - dirty + `verify` fails → feed the verifier's failure into the next shot\n * (the worktree persists, so the harness RESUMES atop its own failing\n * edits with the error in hand — no `--resume` session plumbing needed,\n * and harness-agnostic across claude/codex/opencode)\n * - dirty + `verify` ok (or no verifier configured) → return the candidate\n * A candidate that never verifies within `maxShots` is discarded (`applied:\n * false`), never shipped — if you configured a verifier, a non-passing tree is\n * not a candidate. With no verifier the legacy behavior holds: first dirty shot\n * is the candidate.\n *\n * @experimental\n */\n\nimport { spawnSync } from 'node:child_process'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { AnalystFinding } from '@tangle-network/agent-eval'\nimport { type LocalHarness, runLocalHarness } from '../mcp/local-harness'\nimport type { CandidateGenerator } from './improvement-driver'\n\nconst RAW_TRACE_ANALYST_ID = 'raw-trace-distiller'\nconst RAW_TRACE_AREA = 'raw-trace-context'\nconst RAW_TRACE_DIAGNOSIS_PATH = '.improve/raw-trace-diagnosis.md'\n\n/** Outcome of verifying a candidate worktree. `feedback` (compiler errors,\n * failing test output) is fed into the next shot when `ok` is false. */\nexport interface VerifyResult {\n ok: boolean\n feedback?: string\n}\n\n/** Verifies the edited worktree. Sync or async; throws only on a setup fault\n * (a candidate that fails verification returns `{ok:false}`, it does not\n * throw). */\nexport type Verifier = (worktreePath: string) => Promise<VerifyResult> | VerifyResult\n\nexport interface AgenticGeneratorOptions {\n /** Local coding harness to run in the worktree. Default `claude`. */\n harness?: LocalHarness\n /** Per-shot wall-clock timeout (ms). Default = `runLocalHarness` default (5m). */\n timeoutMs?: number\n /** Build the harness task prompt from the report + findings. Override for\n * domain phrasing; the default turns findings into a concrete coder task. */\n buildPrompt?: (args: { report: unknown; findings: AnalystFinding[] }) => string\n /** Verify the worktree after each dirtying shot. When set, a candidate that\n * fails verification is NOT returned — the failure feeds the next shot\n * (verify-in-session), up to `maxShots`; a candidate that never verifies is\n * discarded (`applied:false`), never shipped. Omitted ⇒ legacy behavior:\n * the first dirty shot is the candidate. See `commandVerifier`. */\n verify?: Verifier\n /** Test seam — inject the harness runner (defaults to `runLocalHarness`). */\n runHarness?: typeof runLocalHarness\n /** Test seam — inject the worktree-dirty check (defaults to `git status`). */\n isDirty?: (worktreePath: string) => boolean\n}\n\n/** Full-agentic `CandidateGenerator` (the `shots=N, sandbox=on` setting): run a real coding harness inside the candidate worktree so the agent makes the change in place. */\nexport function agenticGenerator(opts: AgenticGeneratorOptions = {}): CandidateGenerator {\n const harness = opts.harness ?? 'claude'\n const buildPrompt = opts.buildPrompt ?? defaultBuildPrompt\n const run = opts.runHarness ?? runLocalHarness\n const dirty = opts.isDirty ?? worktreeDirty\n const verify = opts.verify\n\n return {\n kind: `agentic:${harness}`,\n // The seed repo + (in rawTraceContext mode) the raw-trace filesystem context\n // are the change signal — an agentic coder proposes from them even when the\n // distiller yielded zero findings. Without this, the improvementDriver's\n // empty-findings guard short-circuits and generates ZERO candidates on the\n // first (and, for a single-generation run, only) proposal round.\n proposesWithoutFindings: true,\n async generate({ worktreePath, report, findings, maxShots, signal }) {\n const basePrompt = buildPrompt({ report, findings })\n const needsRawTraceEvidence = requiresRawTraceEvidence(findings)\n const shots = Math.max(1, maxShots)\n // Feedback appended to the base prompt for the NEXT shot — empty on shot 0.\n let attemptNote = ''\n\n for (let shot = 0; shot < shots; shot++) {\n if (signal.aborted) break\n await run({\n harness,\n cwd: worktreePath,\n taskPrompt: attemptNote ? `${basePrompt}\\n\\n${attemptNote}` : basePrompt,\n // The candidate worktree is isolated and must be editable without an\n // interactive permission prompt. Other runLocalHarness callers remain\n // permission-safe by default.\n dangerouslySkipPermissions: harness === 'claude',\n timeoutMs: opts.timeoutMs,\n signal,\n })\n\n // The worktree IS the signal: no edits ⇒ tell the next shot to act.\n if (!dirty(worktreePath)) {\n attemptNote = EMPTY_TREE_NOTE\n continue\n }\n\n if (needsRawTraceEvidence) {\n const problem = rawTraceEvidenceProblem(worktreePath, findings)\n if (problem) {\n attemptNote = problem\n continue\n }\n }\n\n // Dirty: with no verifier the diff IS the candidate (we trust the diff,\n // not the harness's stdout). With a verifier the candidate must pass it.\n if (!verify) {\n return { applied: true, summary: summarize(findings) }\n }\n const result = await verify(worktreePath)\n if (result.ok) {\n return { applied: true, summary: summarize(findings) }\n }\n // Dirty but failing — resume next shot atop these edits with the error.\n attemptNote = failureNote(result.feedback)\n }\n\n // Shots exhausted: no verified candidate (or, sans verifier, no edits).\n return { applied: false, summary: '' }\n },\n }\n}\n\n/** Turn the analyst's findings (+ optional report) into a concrete coder task. */\nfunction defaultBuildPrompt(args: { report: unknown; findings: AnalystFinding[] }): string {\n const lines: string[] = [\n 'You are improving this codebase based on an evaluation analysis.',\n 'Make the smallest set of edits that addresses the findings below, then stop.',\n 'Do not change unrelated code. Do not commit — leave changes in the working tree.',\n '',\n 'Findings:',\n ]\n for (const f of args.findings) {\n const where = f.subject ? ` [${f.subject}]` : ''\n lines.push(`- (${f.severity})${where} ${f.claim}`)\n if (f.recommended_action) lines.push(` → ${f.recommended_action}`)\n }\n if (requiresRawTraceEvidence(args.findings)) {\n lines.push(\n '',\n 'Raw trace evidence requirement:',\n `- Inspect at least one raw trace path named above before editing.`,\n `- Write ${RAW_TRACE_DIAGNOSIS_PATH} in this worktree.`,\n '- Include the exact trace path(s) inspected, the failure mechanism, and the code change made.',\n '- A candidate without this file, or with only this file changed, is discarded.',\n )\n }\n return lines.join('\\n')\n}\n\nconst EMPTY_TREE_NOTE =\n 'NOTE: your previous attempt left the working tree unchanged. Make the concrete file edits now.'\n\n/** Next-shot feedback when the worktree is dirty but failed verification. The\n * edits persist on disk, so the harness resumes atop them — tell it to fix in\n * place, not start over. Verifier detail is truncated to keep the prompt bounded. */\nfunction failureNote(feedback?: string): string {\n const detail = feedback?.trim()\n return [\n 'NOTE: your edits are in the working tree but verification FAILED.',\n 'Fix the problem in place — build on your existing edits, do not revert them.',\n detail ? `Verifier output:\\n${truncate(detail, 4000)}` : 'No verifier detail was captured.',\n ].join('\\n')\n}\n\nfunction rawTraceEvidenceProblem(worktreePath: string, findings: AnalystFinding[]): string | null {\n const changedPaths = worktreeChangedPaths(worktreePath)\n const substantive = changedPaths.filter((path) => path !== RAW_TRACE_DIAGNOSIS_PATH)\n if (substantive.length === 0) {\n return [\n `NOTE: raw-trace mode requires a real code/config edit in addition to ${RAW_TRACE_DIAGNOSIS_PATH}.`,\n 'Your previous attempt only changed the diagnosis artifact. Inspect the cited traces and make the causal code change.',\n ].join('\\n')\n }\n\n const diagnosisPath = join(worktreePath, RAW_TRACE_DIAGNOSIS_PATH)\n if (!existsSync(diagnosisPath)) {\n return [\n `NOTE: raw-trace mode requires ${RAW_TRACE_DIAGNOSIS_PATH}.`,\n 'Before retrying, inspect at least one cited spans.jsonl/cached-result.json/artifact path, then write the diagnosis file with the exact path, failure mechanism, and code change.',\n ].join('\\n')\n }\n\n const body = readFileSync(diagnosisPath, 'utf8')\n const evidencePaths = traceEvidencePaths(findings)\n if (evidencePaths.length > 0 && !evidencePaths.some((path) => body.includes(path))) {\n return [\n `${RAW_TRACE_DIAGNOSIS_PATH} exists, but it does not cite any exact raw trace path from the findings.`,\n `Cite at least one of these inspected paths exactly: ${evidencePaths.slice(0, 5).join(', ')}`,\n ].join('\\n')\n }\n\n return null\n}\n\nfunction requiresRawTraceEvidence(findings: AnalystFinding[]): boolean {\n return findings.some((finding) => {\n const f = finding as unknown as Record<string, unknown>\n return f.analyst_id === RAW_TRACE_ANALYST_ID || f.area === RAW_TRACE_AREA\n })\n}\n\nfunction traceEvidencePaths(findings: AnalystFinding[]): string[] {\n const out: string[] = []\n for (const finding of findings) {\n const refs = (finding as unknown as { evidence_refs?: unknown }).evidence_refs\n if (!Array.isArray(refs)) continue\n for (const ref of refs) {\n if (!ref || typeof ref !== 'object') continue\n const uri = (ref as { uri?: unknown }).uri\n if (typeof uri === 'string' && uri.length > 0) out.push(uri)\n }\n }\n return [...new Set(out)]\n}\n\n/** A `Verifier` that runs a command in the worktree: exit 0 ⇒ ok, any other\n * exit ⇒ failed with stdout+stderr as feedback. The common case — verify by\n * `tsc --noEmit`, `pnpm build`, or a test command. A timeout is treated as a\n * FAILED candidate (a change that hangs the build is a bad change); a missing\n * binary or spawn fault throws (a setup bug, not a failed candidate — no\n * silent fallback). */\nexport function commandVerifier(\n command: string,\n args: string[] = [],\n timeoutMs = 300_000,\n): Verifier {\n return (worktreePath: string): VerifyResult => {\n const result = spawnSync(command, args, {\n cwd: worktreePath,\n encoding: 'utf-8',\n timeout: timeoutMs,\n })\n if (result.signal) {\n return {\n ok: false,\n feedback: `verifier '${command}' killed by ${result.signal} (likely timeout after ${timeoutMs}ms)`,\n }\n }\n if (result.error) {\n const code = (result.error as NodeJS.ErrnoException).code\n if (code === 'ENOENT') {\n throw new Error(\n `commandVerifier: '${command}' not found in PATH (setup bug, not a failed candidate)`,\n )\n }\n throw new Error(`commandVerifier: '${command}' failed to spawn: ${result.error.message}`)\n }\n if (result.status === 0) return { ok: true }\n const out = `${result.stdout ?? ''}${result.stderr ?? ''}`.trim()\n return { ok: false, feedback: out.length > 0 ? out : `exit ${result.status}` }\n }\n}\n\n/** A one-line summary for the commit message, derived from the findings. */\nfunction summarize(findings: AnalystFinding[]): string {\n if (findings.length === 0) return 'agentic improvement'\n if (findings.length === 1) return `agentic: ${truncate(findings[0]!.claim, 64)}`\n return `agentic: ${findings.length} findings addressed`\n}\n\nfunction truncate(s: string, n: number): string {\n return s.length <= n ? s : `${s.slice(0, n - 1)}…`\n}\n\n/** Non-empty `git status --porcelain` ⇒ the harness changed the worktree.\n * Fails loud: the worktree is a fresh checkout, so a git error here means\n * something is genuinely broken (git missing, corrupt index, killed mid-run).\n * Folding that into `false` would silently discard a candidate and mask the\n * real failure — forbidden by the no-silent-fallbacks doctrine. */\nfunction worktreeDirty(worktreePath: string): boolean {\n return worktreeChangedPaths(worktreePath).length > 0\n}\n\nfunction worktreeChangedPaths(worktreePath: string): string[] {\n const result = spawnSync('git', ['status', '--porcelain', '--untracked-files=all'], {\n cwd: worktreePath,\n encoding: 'utf-8',\n })\n if (result.error) {\n throw new Error(\n `agenticGenerator: git status failed to spawn in ${worktreePath}: ${result.error.message}`,\n )\n }\n if (result.status !== 0) {\n throw new Error(\n `agenticGenerator: git status exited ${result.status} in ${worktreePath}: ${result.stderr.trim()}`,\n )\n }\n return result.stdout\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map((line) => line.slice(3).trim())\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/runtime/sandbox-events.ts"],"sourcesContent":["/**\n * Sandbox-event → runtime-event mapping.\n *\n * The sandbox SDK emits a polymorphic `SandboxEvent = { type, data, id? }`\n * whose `type` vocabulary is backend-determined (opencode, etc.) rather than\n * enumerated by the SDK. Two consumers project it:\n * - the loop kernel's cost ledger (`extractLlmCallEvent`) — sums usage off\n * every cost-bearing event, regardless of stream shape;\n * - the `AgentRuntime.act` streaming contract (`mapSandboxEvent`) — projects\n * incremental events to the `RuntimeStreamEvent` chat-UX vocabulary.\n *\n * Both live here so the empirically-observed `type` vocabulary has one home.\n */\n\nimport type { SandboxEvent } from '@tangle-network/sandbox'\nimport type { RuntimeStreamEvent } from '../types'\n\n/**\n * Extract a `RuntimeStreamEvent`-shaped `llm_call` from a sandbox event when\n * the event carries usage/cost data. Returns `undefined` for non-cost events\n * so the kernel can iterate the full stream without branching.\n *\n * Canonical cost-carrying types observed in the wild:\n * - `llm_call` — `data: { model, tokensIn, tokensOut, costUsd, ... }`\n * - `message.completed` / `result` — `data: { usage: { inputTokens,\n * outputTokens, totalCostUsd? } }`\n * - `cost.usage` / `usage` — same shape under a dedicated type\n *\n * Numeric coercion is strict: `Number.isFinite` gates every accumulator write\n * so a sentinel `NaN` from a misbehaving backend cannot poison the ledger.\n */\nexport function extractLlmCallEvent(\n event: SandboxEvent,\n agentRunName: string,\n): (RuntimeStreamEvent & { type: 'llm_call' }) | undefined {\n if (!event || typeof event !== 'object') return undefined\n const type = String(event.type ?? '')\n const data =\n event.data && typeof event.data === 'object'\n ? (event.data as Record<string, unknown>)\n : ({} as Record<string, unknown>)\n\n if (type === 'llm_call' || type === 'cost.usage' || type === 'usage') {\n return buildLlmCall(data, agentRunName)\n }\n if (type === 'message.completed' || type === 'result' || type === 'final') {\n const usage = data.usage as Record<string, unknown> | undefined\n if (!usage || typeof usage !== 'object') return undefined\n return buildLlmCall({ ...usage, model: data.model ?? usage.model }, agentRunName)\n }\n // sandbox 0.4.0 terminal event: `data = { tokenUsage: { inputTokens, outputTokens,\n // reasoningTokens, cacheReadInputTokens }, totalCostUsd }`. Usage lives under\n // `tokenUsage` (not `usage`) and the cost is top-level — neither matched the\n // branches above, so an in-process loopDispatch run reported {0,0} and the\n // backend-integrity guard misread a real run as a stub. Reasoning tokens are\n // billed output (reasoning models), so they fold into the output count.\n if (type === 'done') {\n const usage = data.tokenUsage as Record<string, unknown> | undefined\n if (!usage || typeof usage !== 'object') return undefined\n const out = pickFiniteNumber(usage, ['outputTokens', 'completion_tokens', 'tokensOut'])\n const reasoning = pickFiniteNumber(usage, ['reasoningTokens'])\n const mergedOut =\n out !== undefined || reasoning !== undefined ? (out ?? 0) + (reasoning ?? 0) : undefined\n return buildLlmCall(\n {\n inputTokens: usage.inputTokens,\n outputTokens: mergedOut,\n totalCostUsd: data.totalCostUsd,\n model: data.model ?? usage.model,\n },\n agentRunName,\n )\n }\n return undefined\n}\n\n/**\n * Sum the token usage + USD cost of a sandbox turn's events — the one honest way to meter an\n * `openSandboxRun` cell. Folds `extractLlmCallEvent` over the stream (which reads usage off EVERY backend\n * event shape), so a `runProfileMatrix` dispatch can report it to `ctx.cost`:\n *\n * const turn = await run.start(prompt)\n * const u = sumSandboxUsage(turn.events)\n * if (u.input || u.output) ctx.cost.observeTokens({ input: u.input, output: u.output })\n * if (u.costUsd) ctx.cost.observe(u.costUsd, 'sandbox-cell')\n *\n * Without this a cell reads `{tokens:0, cost:0}` and the backend-integrity guard correctly aborts the\n * matrix as a stub. `agentRunName` is the fallback model label for cost-only events (default `'agent'`).\n */\nexport function sumSandboxUsage(\n events: readonly SandboxEvent[],\n agentRunName = 'agent',\n): { input: number; output: number; costUsd: number } {\n let input = 0\n let output = 0\n let costUsd = 0\n for (const ev of events) {\n const call = extractLlmCallEvent(ev, agentRunName)\n if (!call) continue\n input += call.tokensIn ?? 0\n output += call.tokensOut ?? 0\n costUsd += call.costUsd ?? 0\n }\n return { input, output, costUsd }\n}\n\nfunction buildLlmCall(\n data: Record<string, unknown>,\n agentRunName: string,\n): (RuntimeStreamEvent & { type: 'llm_call' }) | undefined {\n const tokensIn = pickFiniteNumber(data, ['tokensIn', 'inputTokens', 'prompt_tokens'])\n const tokensOut = pickFiniteNumber(data, ['tokensOut', 'outputTokens', 'completion_tokens'])\n const costUsd = pickFiniteNumber(data, ['costUsd', 'totalCostUsd', 'cost_usd', 'cost'])\n if (tokensIn === undefined && tokensOut === undefined && costUsd === undefined) {\n return undefined\n }\n const model = typeof data.model === 'string' && data.model.length > 0 ? data.model : agentRunName\n const event: RuntimeStreamEvent & { type: 'llm_call' } = {\n type: 'llm_call',\n model,\n }\n if (tokensIn !== undefined) event.tokensIn = tokensIn\n if (tokensOut !== undefined) event.tokensOut = tokensOut\n if (costUsd !== undefined) event.costUsd = costUsd\n return event\n}\n\nfunction pickFiniteNumber(data: Record<string, unknown>, keys: string[]): number | undefined {\n for (const key of keys) {\n const value = data[key]\n if (typeof value === 'number' && Number.isFinite(value)) return value\n }\n return undefined\n}\n\n/**\n * Cross-event state for {@link mapSandboxToolEvent}. Sandbox backends emit a\n * tool invocation as MANY `message.part.updated` frames on the same call id\n * (pending → running → completed), so faithful projection needs per-call\n * status memory: one `tool_call` on first sighting, at most one `tool_result`\n * on the terminal transition, nothing on intermediate re-frames. Create one\n * state per turn via {@link createSandboxToolPartState}.\n *\n * @experimental\n */\nexport interface SandboxToolPartState {\n /** Last seen status per tool call id. A terminal status is sticky — later\n * frames on a settled call project to nothing. */\n statusByCall: Map<string, string>\n /** Sequence for synthesized call ids when an event carries none. */\n seq: number\n}\n\n/**\n * Fresh per-turn {@link SandboxToolPartState} for {@link mapSandboxToolEvent} — an\n * empty call-status map so each turn projects tool frames independently.\n *\n * @experimental\n */\nexport function createSandboxToolPartState(): SandboxToolPartState {\n return { statusByCall: new Map(), seq: 0 }\n}\n\n/** Terminal tool statuses that are failures (everything here settles the call). */\nconst TERMINAL_TOOL_FAILURE =\n /^(error|errored|failed|failure|cancelled|canceled|timeout|timed_out)$/i\n\n/**\n * Project one `SandboxEvent` onto the `tool_call` / `tool_result` variants of\n * `RuntimeStreamEvent` — the tool-part projection `mapSandboxEvent`\n * deliberately does NOT perform. Opt-in and additive: `mapSandboxEvent`'s\n * default vocabulary (text/reasoning deltas + `llm_call`) is unchanged;\n * consumers that need the tool surface (chat UIs rendering tool activity)\n * compose this projector alongside it — `streamAgentTurn` does exactly that\n * under its `preserveToolParts` option.\n *\n * Handled shapes (observed on the opencode / claude-code sandbox backends):\n * - `message.part.updated` with `part.type === 'tool'` — stateful: a\n * `tool_call` on the call id's first frame (args from `state.input` or\n * `state.metadata.input`), a `tool_result` when the status transitions to\n * `completed` (result from `state.output` / `metadata.output`) or to a\n * terminal failure (result is `{ error, status, output? }` — the error\n * surfaced in-band, never dropped).\n * - bare `tool*` event types (`tool.call`, `tool_result`, …) — stateless:\n * `*result*` types project to `tool_result`, the rest to `tool_call`.\n *\n * Returns `[]` for every non-tool event.\n *\n * @experimental\n */\nexport function mapSandboxToolEvent(\n event: SandboxEvent,\n state: SandboxToolPartState,\n): (RuntimeStreamEvent & { type: 'tool_call' | 'tool_result' })[] {\n if (!event || typeof event !== 'object') return []\n const type = String(event.type ?? '')\n const data =\n event.data && typeof event.data === 'object'\n ? (event.data as Record<string, unknown>)\n : ({} as Record<string, unknown>)\n\n if (type === 'message.part.updated') {\n const part =\n data.part && typeof data.part === 'object' ? (data.part as Record<string, unknown>) : {}\n if (String(part.type ?? '') !== 'tool') return []\n return projectToolPart(part, state, typeof event.id === 'string' ? event.id : undefined)\n }\n\n if (type.includes('tool')) {\n const callId =\n pickString(data, ['toolCallId', 'tool_use_id', 'id']) ??\n (typeof event.id === 'string' ? event.id : undefined) ??\n `sandbox-tool-${++state.seq}`\n const toolName = pickString(data, ['name', 'toolName', 'tool']) ?? 'sandbox_tool'\n if (type.includes('result')) {\n return [\n {\n type: 'tool_result',\n toolName,\n toolCallId: callId,\n result: data.output ?? data.result ?? data.content ?? data,\n },\n ]\n }\n return [\n { type: 'tool_call', toolName, toolCallId: callId, args: data.input ?? data.args ?? {} },\n ]\n }\n\n return []\n}\n\nfunction projectToolPart(\n part: Record<string, unknown>,\n state: SandboxToolPartState,\n eventId: string | undefined,\n): (RuntimeStreamEvent & { type: 'tool_call' | 'tool_result' })[] {\n const callId =\n pickString(part, ['callID', 'callId', 'toolCallId', 'id']) ??\n eventId ??\n `sandbox-tool-${++state.seq}`\n const toolName = pickString(part, ['tool', 'toolName', 'name']) ?? 'sandbox_tool'\n const toolState =\n part.state && typeof part.state === 'object' ? (part.state as Record<string, unknown>) : {}\n const metadata =\n toolState.metadata && typeof toolState.metadata === 'object'\n ? (toolState.metadata as Record<string, unknown>)\n : {}\n const status = pickString(toolState, ['status']) ?? 'updated'\n\n const previous = state.statusByCall.get(callId)\n const settled =\n previous === 'completed' || (previous !== undefined && TERMINAL_TOOL_FAILURE.test(previous))\n if (settled) return []\n\n const out: (RuntimeStreamEvent & { type: 'tool_call' | 'tool_result' })[] = []\n if (previous === undefined) {\n out.push({\n type: 'tool_call',\n toolName,\n toolCallId: callId,\n args: toolState.input ?? metadata.input ?? {},\n })\n }\n state.statusByCall.set(callId, status)\n\n if (status === 'completed') {\n out.push({\n type: 'tool_result',\n toolName,\n toolCallId: callId,\n result: toolState.output ?? metadata.output ?? '',\n })\n } else if (TERMINAL_TOOL_FAILURE.test(status)) {\n const message =\n pickString(toolState, ['error', 'message']) ??\n pickString(metadata, ['error', 'message']) ??\n `sandbox tool ended with status ${status}`\n const output = toolState.output ?? metadata.output\n out.push({\n type: 'tool_result',\n toolName,\n toolCallId: callId,\n result: { error: message, status, ...(output !== undefined ? { output } : {}) },\n })\n }\n return out\n}\n\nfunction pickString(data: Record<string, unknown>, keys: string[]): string | undefined {\n for (const key of keys) {\n const value = data[key]\n if (typeof value === 'string' && value.length > 0) return value\n }\n return undefined\n}\n\n/**\n * Project one `SandboxEvent` onto the `RuntimeStreamEvent` chat-UX vocabulary,\n * for runtimes that bridge a sandbox `streamPrompt` into the\n * `AgentRuntime.act` streaming contract. Returns `undefined` for events that\n * have no faithful projection — the raw stream is preserved separately for the\n * `OutputAdapter`, so an unmapped event never loses data.\n *\n * Mapped (the task-optional incremental variants — no synthesized task\n * lifecycle, no guessed tool-part shapes):\n * - `message.part.updated` text part → `text_delta`\n * - `message.part.updated` reasoning/thinking part → `reasoning_delta`\n * - cost-bearing events → `llm_call` (shared with the ledger extractor)\n *\n * Tool parts are deliberately NOT mapped here (unchanged default) — compose\n * {@link mapSandboxToolEvent} alongside when a consumer needs them.\n *\n * The opencode backend emits incremental text as\n * `{ type: 'message.part.updated', data: { part: { type, text }, delta } }`;\n * `delta` is the increment, `part.text` the running accumulation.\n */\nexport function mapSandboxEvent(\n event: SandboxEvent,\n opts: { agentRunName?: string } = {},\n): RuntimeStreamEvent | undefined {\n if (!event || typeof event !== 'object') return undefined\n const type = String(event.type ?? '')\n const data =\n event.data && typeof event.data === 'object'\n ? (event.data as Record<string, unknown>)\n : ({} as Record<string, unknown>)\n\n if (type === 'message.part.updated') {\n const part =\n data.part && typeof data.part === 'object' ? (data.part as Record<string, unknown>) : {}\n const partType = String(part.type ?? '')\n const delta = typeof data.delta === 'string' ? data.delta : undefined\n const text = delta ?? (typeof part.text === 'string' ? part.text : undefined)\n if (text === undefined) return undefined\n if (partType === 'text') return { type: 'text_delta', text }\n if (partType === 'reasoning' || partType === 'thinking')\n return { type: 'reasoning_delta', text }\n return undefined\n }\n\n return extractLlmCallEvent(event, opts.agentRunName ?? 'agent')\n}\n"],"mappings":"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","names":[]}