swarm-orchestrator 13.1.5 → 13.1.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.
- package/CHANGELOG.md +54 -0
- package/README.md +25 -4
- package/dist/agent-run.js +45 -1
- package/dist/agent-run.js.map +1 -1
- package/dist/cli-options.js +9 -8
- package/dist/cli-options.js.map +1 -1
- package/dist/cli.js +218 -0
- package/dist/cli.js.map +1 -1
- package/dist/core/loop.js +4 -2
- package/dist/core/loop.js.map +1 -1
- package/dist/evidence/dag.js +24 -0
- package/dist/evidence/dag.js.map +1 -1
- package/dist/evidence/ledger-record.js +1 -0
- package/dist/evidence/ledger-record.js.map +1 -1
- package/dist/evidence/review-page.js +198 -0
- package/dist/evidence/review-page.js.map +1 -1
- package/dist/gates/git-workspace.js +8 -38
- package/dist/gates/git-workspace.js.map +1 -1
- package/dist/gates/scratch-index.js +50 -0
- package/dist/gates/scratch-index.js.map +1 -0
- package/dist/tui/key-dispatcher.js +44 -0
- package/dist/tui/key-dispatcher.js.map +1 -1
- package/dist/tui/plain-lines.js +4 -0
- package/dist/tui/plain-lines.js.map +1 -1
- package/dist/tui/screen-model.js +39 -0
- package/dist/tui/screen-model.js.map +1 -1
- package/dist/tui/screen.js +28 -2
- package/dist/tui/screen.js.map +1 -1
- package/dist/tui/session-interface.js +120 -4
- package/dist/tui/session-interface.js.map +1 -1
- package/dist/tui/session-store.js +6 -0
- package/dist/tui/session-store.js.map +1 -1
- package/dist/tui/session-view.js +3 -0
- package/dist/tui/session-view.js.map +1 -1
- package/dist/tui/verify-bundle.js +30 -6
- package/dist/tui/verify-bundle.js.map +1 -1
- package/dist/tui/view-state.js +95 -0
- package/dist/tui/view-state.js.map +1 -1
- package/docs/build-guide.md +1 -1
- package/docs/claims.md +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,59 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 13.1.7
|
|
4
|
+
|
|
5
|
+
Found by driving the session through a real terminal rather than a pipe.
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **Enter did not submit at the prompt.** A terminal hands over what it buffered in one read, so
|
|
10
|
+
the newline arrived inside a longer chunk with no key flag set, and the whole chunk including
|
|
11
|
+
the control character was typed into the task being composed. A pasted task arrives the same
|
|
12
|
+
way, so everything before the newline is now typed and the newline still means run it.
|
|
13
|
+
- **The screen still showed a plain `DONE` for a run that changed nothing.** The gate strip
|
|
14
|
+
cannot tell passes over work from passes over an empty diff, and a model answering in prose
|
|
15
|
+
stops for the honest reason `completed` having done nothing. It now reads `DONE, but no files
|
|
16
|
+
changed`. The plain path already said this above its gate table.
|
|
17
|
+
|
|
18
|
+
## 13.1.6
|
|
19
|
+
|
|
20
|
+
A session, and the evidence a person reads.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- **`swarm` with no task opens a session.** One process, one ledger, tasks typed one after
|
|
25
|
+
another, each continuing the conversation the last one left. The screen keeps what each
|
|
26
|
+
finished turn came to, so it does not forget between them. `swarm "task"` is unchanged.
|
|
27
|
+
- **Each turn is measured on its own.** A turn ends by recording where it left the tree, so the
|
|
28
|
+
next turn's gates see that turn's changes and not the ones before it. Without it the second
|
|
29
|
+
turn is charged with the first's diff and the file-set check calls the first turn's files
|
|
30
|
+
out-of-set.
|
|
31
|
+
- **The review page says what happened.** The header carries the tasks, the model, whether the
|
|
32
|
+
loop completed, how long it took and what it cost, above the identifiers it used to open with.
|
|
33
|
+
- **The gate table is in the bundle.** It was printed to a terminal and never written into the
|
|
34
|
+
page, where the gates had been indistinguishable cards among the model calls.
|
|
35
|
+
- **The change itself is recorded and shown.** Nothing recorded a patch, so the question the
|
|
36
|
+
page exists to answer, what did this do to my code, meant leaving the evidence and running git.
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- **A run that changed nothing reported `DONE`.** The gates run after the loop and each gate
|
|
41
|
+
event rewrote the status, so the last gate to pass over an empty diff became the last word on
|
|
42
|
+
a run that built nothing. The stop reason is now its own field, and a cycle that measured no
|
|
43
|
+
changed files says so before the table.
|
|
44
|
+
- **A second turn measured its own edits as deletions.** `git diff <base>` from the person's
|
|
45
|
+
index calls a file that is in the base and untracked here deleted. Changes are now measured
|
|
46
|
+
through a scratch index, which makes the comparison tree to tree and counts a file the agent
|
|
47
|
+
just wrote as added.
|
|
48
|
+
- **`q` did not leave the view.** It set a flag that three things read after the fact; nothing
|
|
49
|
+
unmounted the screen, which kept painting. It now comes down and the run reports the way it
|
|
50
|
+
does off a terminal.
|
|
51
|
+
- **A refused bundle named nothing.** The failing check was read off stderr and the verifier
|
|
52
|
+
reports through stdout, so every real refusal said "no detail given" at the one moment the
|
|
53
|
+
panel exists for.
|
|
54
|
+
- Six record types rendered as their own bare name on the page, including the one holding what
|
|
55
|
+
the run cost.
|
|
56
|
+
|
|
3
57
|
## 13.1.5
|
|
4
58
|
|
|
5
59
|
Three fixes, all found by running the tool rather than by reading it.
|
package/README.md
CHANGED
|
@@ -31,11 +31,11 @@ a workspace it had never seen, recorded in a real terminal:
|
|
|
31
31
|
|
|
32
32
|
npm install -g swarm-orchestrator
|
|
33
33
|
|
|
34
|
-
That is **13.1.
|
|
34
|
+
That is **13.1.7**, and it leaves `swarm` on your path.
|
|
35
35
|
|
|
36
36
|
Installing from a tag works too, but only into a project rather than globally:
|
|
37
37
|
|
|
38
|
-
npm install github:moonrunnerkc/swarm-orchestrator#v13.1.
|
|
38
|
+
npm install github:moonrunnerkc/swarm-orchestrator#v13.1.7
|
|
39
39
|
|
|
40
40
|
`dist/` is not committed, so a git ref builds itself on install and needs this package's
|
|
41
41
|
devDependencies to do it. npm does not install those when a git ref is installed with `-g`: it
|
|
@@ -55,6 +55,7 @@ option, so on anything older that measurement does not happen.
|
|
|
55
55
|
|
|
56
56
|
swarm "make slugify collapse whitespace and strip punctuation"
|
|
57
57
|
|
|
58
|
+
swarm # a session: type tasks, one after another
|
|
58
59
|
swarm gates # run the gates over a workspace, no model
|
|
59
60
|
swarm select # probe this machine, recommend a local model
|
|
60
61
|
swarm calibrate # measure candidate models on the golden set
|
|
@@ -83,6 +84,25 @@ what it has learned.
|
|
|
83
84
|
Settings live in one optional `swarm.toml`: providers and endpoints, gate definitions, budgets,
|
|
84
85
|
model pins, and the `[interface]`, `[theme]` and `[keys]` tables. Flags win over the file.
|
|
85
86
|
|
|
87
|
+
## A session, or a single task
|
|
88
|
+
|
|
89
|
+
Run `swarm` with no task and it opens a session: one process, one ledger, and tasks typed one
|
|
90
|
+
after another, each continuing the conversation the last one left.
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
› create calculator.js exporting add and multiply, and calculator.test.js covering both
|
|
94
|
+
8 gate(s) passed, 8 step(s)
|
|
95
|
+
|
|
96
|
+
› add a divide function that throws on division by zero, and cover both cases
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Each turn is measured on its own. A turn ends by recording where it left the tree, so the next
|
|
100
|
+
one's gates see that turn's changes and not the ones before it. Three turns of this, with the
|
|
101
|
+
bundle verified from outside and the page it produced, are in
|
|
102
|
+
[`session.md`](docs/evidence/2026-08-24/session.md).
|
|
103
|
+
|
|
104
|
+
`swarm "task"` still runs one task and exits, exactly as before.
|
|
105
|
+
|
|
86
106
|
## Watching it work
|
|
87
107
|
|
|
88
108
|
On a terminal, a run draws a single screen you can drive. Off one, it writes the same plain
|
|
@@ -108,8 +128,9 @@ j scroll enter expand tab pane / filter e evidence ? help q detach ctrl+c
|
|
|
108
128
|
```
|
|
109
129
|
|
|
110
130
|
`?` lists every key. `enter` expands a row to its whole payload and the ledger record it came
|
|
111
|
-
from. `q` leaves the view
|
|
112
|
-
|
|
131
|
+
from. `q` leaves the view: the screen comes down and the run keeps going, reporting the plain
|
|
132
|
+
lines it writes off a terminal. `ctrl+c` cancels the run. There is no progress bar, because an
|
|
133
|
+
agent run has no denominator.
|
|
113
134
|
|
|
114
135
|
When the run ends, the screen lists what it produced, says how many claims the harness
|
|
115
136
|
verified and how many it refused, and offers to open the review page. It says the bundle
|
package/dist/agent-run.js
CHANGED
|
@@ -2,6 +2,7 @@ import { resolve } from "node:path";
|
|
|
2
2
|
import { runAgentLoop } from "./core/loop.js";
|
|
3
3
|
import { runGatesEngine } from "./gates/engine.js";
|
|
4
4
|
import { createAmendFileSetTool, createDeclareFileSetTool } from "./gates/file-set-tool.js";
|
|
5
|
+
import { diffAgainstBase } from "./gates/scratch-index.js";
|
|
5
6
|
import { createToolChokepoint } from "./tools/chokepoint.js";
|
|
6
7
|
import { createLedgerChokepointRecorder } from "./tools/chokepoint-record.js";
|
|
7
8
|
import { createClaimTool } from "./tools/claim-tool.js";
|
|
@@ -85,7 +86,10 @@ export async function runAgentTask(options) {
|
|
|
85
86
|
maxOutputTokens: 8192,
|
|
86
87
|
retryPolicy: { attempts: 3, baseDelayMs: 500, maxJitterRatio: 0.5 },
|
|
87
88
|
};
|
|
88
|
-
const loop = await runAgentLoop(options.task,
|
|
89
|
+
const loop = await runAgentLoop(options.task, {
|
|
90
|
+
...loopDependencies,
|
|
91
|
+
...(options.history === undefined ? {} : { history: options.history }),
|
|
92
|
+
});
|
|
89
93
|
await options.evidence.record({
|
|
90
94
|
type: "session-stopped",
|
|
91
95
|
actor: "harness",
|
|
@@ -116,12 +120,52 @@ export async function runAgentTask(options) {
|
|
|
116
120
|
? {}
|
|
117
121
|
: { singleFileTestCommand: options.singleFileTestCommand }),
|
|
118
122
|
});
|
|
123
|
+
// Said to the screen as well as written down, because a gate strip of passes over a tree
|
|
124
|
+
// nothing touched looks exactly like a gate strip of passes over work.
|
|
125
|
+
options.emit({
|
|
126
|
+
type: "changes",
|
|
127
|
+
changedFiles: gates.outcome.finalCycle.measures.changedFiles ?? 0,
|
|
128
|
+
});
|
|
129
|
+
// What the task did to the tree, as a patch, recorded once the gates have settled so it is
|
|
130
|
+
// the state that was judged. Nothing else in the ledger answers "what did it change to my
|
|
131
|
+
// code?": the file-set record names files, the diff budget counts lines, and the tool calls
|
|
132
|
+
// hold fragments, so a reviewer had to leave the evidence and run git themselves.
|
|
133
|
+
await recordWorkspaceDiff(options);
|
|
119
134
|
return {
|
|
120
135
|
loop,
|
|
121
136
|
gates,
|
|
122
137
|
green: loop.stopReason === "completed" && gates.outcome.settled === "green",
|
|
123
138
|
};
|
|
124
139
|
}
|
|
140
|
+
/** A patch is only worth reading up to a point, past which it is a file to open, not a page to read. */
|
|
141
|
+
const diffCharacterCap = 200_000;
|
|
142
|
+
async function recordWorkspaceDiff(options) {
|
|
143
|
+
let patch;
|
|
144
|
+
try {
|
|
145
|
+
patch = await diffAgainstBase({
|
|
146
|
+
workspaceRoot: options.workspace,
|
|
147
|
+
baseRef: options.baseRef,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// A tree the diff cannot be taken from is a fact about the workspace, and one the gates
|
|
152
|
+
// have already reported on. It is not a reason to lose the run's evidence.
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const truncated = patch.length > diffCharacterCap;
|
|
156
|
+
await options.evidence.record({
|
|
157
|
+
type: "workspace-diff",
|
|
158
|
+
actor: "harness",
|
|
159
|
+
// The patch is the harness's reading of the tree, and the tree is what the model wrote.
|
|
160
|
+
provenance: ["model"],
|
|
161
|
+
payload: {
|
|
162
|
+
baseRef: options.baseRef,
|
|
163
|
+
truncated,
|
|
164
|
+
characters: patch.length,
|
|
165
|
+
patch: truncated ? `${patch.slice(0, diffCharacterCap)}\n... truncated` : patch,
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
}
|
|
125
169
|
/**
|
|
126
170
|
* One attempt at fixing what a gate reported. A fresh loop rather than a continued one: the
|
|
127
171
|
* gate output is the whole brief, and starting clean keeps an attempt from inheriting the
|
package/dist/agent-run.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-run.js","sourceRoot":"","sources":["../src/agent-run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAyB,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAQrE,OAAO,EAAuB,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExE,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAE5F,OAAO,EAA2B,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AACtF,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAElE,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,gEAAgE;IAChE,4EAA4E;IAC5E,qFAAqF;IACrF,4FAA4F;IAC5F,uEAAuE;IACvE,yEAAyE;IACzE,gGAAgG;IAChG,mDAAmD;IACnD,kGAAkG;IAClG,2FAA2F;IAC3F,mEAAmE;IACnE,+FAA+F;IAC/F,+FAA+F;IAC/F,mGAAmG;IACnG,gEAAgE;IAChE,6FAA6F;IAC7F,2FAA2F;IAC3F,4FAA4F;CAC7F,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"agent-run.js","sourceRoot":"","sources":["../src/agent-run.ts"],"names":[],"mappings":"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"}
|
package/dist/cli-options.js
CHANGED
|
@@ -2,7 +2,9 @@ import { resolve } from "node:path";
|
|
|
2
2
|
import { bundledShortlistKeyword } from "./select/shortlist-source.js";
|
|
3
3
|
export const usage = [
|
|
4
4
|
"swarm [--model <provider:id>] [--workspace <dir>] [--bundle <dir>] [--base <ref>]",
|
|
5
|
-
' [--attempts <n>] [--max-steps <n>] [--local-endpoint <url>] "<task>"',
|
|
5
|
+
' [--attempts <n>] [--max-steps <n>] [--local-endpoint <url>] ["<task>"]',
|
|
6
|
+
"",
|
|
7
|
+
" swarm a session: type tasks, one after another",
|
|
6
8
|
"",
|
|
7
9
|
" swarm gates [--workspace <dir>] [--base <ref>] run the gates, no model",
|
|
8
10
|
" swarm select [--shortlist <file|url|bundled>] probe this machine, recommend a model",
|
|
@@ -145,13 +147,7 @@ export function parseCommandLine(argv, context) {
|
|
|
145
147
|
bundleDirectory,
|
|
146
148
|
};
|
|
147
149
|
}
|
|
148
|
-
const
|
|
149
|
-
if (task.length === 0) {
|
|
150
|
-
throw new InvalidCommandLineError("nothing to do");
|
|
151
|
-
}
|
|
152
|
-
return {
|
|
153
|
-
command: "run",
|
|
154
|
-
task,
|
|
150
|
+
const shared = {
|
|
155
151
|
modelSpec: flags.get("model") ?? null,
|
|
156
152
|
workspace,
|
|
157
153
|
maxSteps: parseFlagCount(flags.get("max-steps"), "--max-steps"),
|
|
@@ -161,6 +157,11 @@ export function parseCommandLine(argv, context) {
|
|
|
161
157
|
localEndpoint: parseLocalEndpoint(flags.get("local-endpoint")),
|
|
162
158
|
interfaceFlags: parseInterfaceFlags(flags),
|
|
163
159
|
};
|
|
160
|
+
const task = words.join(" ").trim();
|
|
161
|
+
if (task.length === 0) {
|
|
162
|
+
return { command: "session", ...shared };
|
|
163
|
+
}
|
|
164
|
+
return { command: "run", task, ...shared };
|
|
164
165
|
}
|
|
165
166
|
/** Both halves of a pair named at once is a contradiction, so it is an error rather than an order. */
|
|
166
167
|
function parseInterfaceFlags(flags) {
|
package/dist/cli-options.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-options.js","sourceRoot":"","sources":["../src/cli-options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"cli-options.js","sourceRoot":"","sources":["../src/cli-options.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -22,6 +22,7 @@ import { createFileSetRegistry } from "./gates/file-set.js";
|
|
|
22
22
|
import { citedRecords, outstandingJustifications } from "./gates/gate-runner.js";
|
|
23
23
|
import { createNodeCommandRunner } from "./gates/node-command-runner.js";
|
|
24
24
|
import { summarizeRatchet } from "./gates/ratchet-summary.js";
|
|
25
|
+
import { recordTurnBaseline } from "./gates/turn-baseline.js";
|
|
25
26
|
import { localEndpointRecord, resolveLocalEndpoint, } from "./providers/endpoint-resolution.js";
|
|
26
27
|
import { discoverLocalEndpoints } from "./providers/local-discovery.js";
|
|
27
28
|
import { parseModelSpec } from "./providers/model-spec.js";
|
|
@@ -173,6 +174,186 @@ async function chooseModel(task, home, random) {
|
|
|
173
174
|
candidates: calibrated.candidates,
|
|
174
175
|
};
|
|
175
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* A session: one process, one ledger, many tasks, each typed rather than passed.
|
|
179
|
+
*
|
|
180
|
+
* Everything expensive is built once, which is the point of a session over repeated runs: the
|
|
181
|
+
* settings, the provider registry, the sandbox and its tool definitions, the evidence chain and
|
|
182
|
+
* the screen all outlive a turn. What is rebuilt per turn is what carries state that a second
|
|
183
|
+
* task must not inherit, and each of those is a decision rather than an oversight:
|
|
184
|
+
*
|
|
185
|
+
* - the abort controller, because a signal is one-shot and a reused aborted one would make
|
|
186
|
+
* the next turn stop before it started;
|
|
187
|
+
* - the file-set registry, because declaring a set twice is an error and the check walks the
|
|
188
|
+
* whole chain when it decides what was edited before it was authorised;
|
|
189
|
+
* - the base commit, because the previous turn's edits are still uncommitted, and measuring
|
|
190
|
+
* against the start of the session would charge this turn with the last one's diff;
|
|
191
|
+
* - the routed model, because routing reads the task, and a different task may deserve a
|
|
192
|
+
* different arm.
|
|
193
|
+
*
|
|
194
|
+
* The conversation is what carries across, so a follow-up can say "now make it throw" and mean
|
|
195
|
+
* the file the previous turn wrote.
|
|
196
|
+
*/
|
|
197
|
+
async function session(options) {
|
|
198
|
+
if (!statSync(options.workspace).isDirectory()) {
|
|
199
|
+
throw new Error(`${options.workspace} is not a directory to work in`);
|
|
200
|
+
}
|
|
201
|
+
const settings = await settingsFor(options.workspace, {
|
|
202
|
+
model: options.modelSpec,
|
|
203
|
+
maxSteps: options.maxSteps,
|
|
204
|
+
attempts: options.attempts,
|
|
205
|
+
localEndpoint: options.localEndpoint,
|
|
206
|
+
interfaceFlags: options.interfaceFlags,
|
|
207
|
+
});
|
|
208
|
+
const clock = createSystemClock();
|
|
209
|
+
const random = createSystemRandom();
|
|
210
|
+
const evidence = await openEvidenceSession({
|
|
211
|
+
root: defaultSessionRoot(homedir()),
|
|
212
|
+
sessionId: createSessionId(clock, random),
|
|
213
|
+
clock,
|
|
214
|
+
});
|
|
215
|
+
const ui = startInterface({ task: "", workspace: options.workspace, settings, clock });
|
|
216
|
+
let baseRef = options.baseRef;
|
|
217
|
+
let history = [];
|
|
218
|
+
let turns = 0;
|
|
219
|
+
let lastGreen = true;
|
|
220
|
+
try {
|
|
221
|
+
for (;;) {
|
|
222
|
+
const task = await ui.readTask();
|
|
223
|
+
if (task === null) {
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
turns += 1;
|
|
227
|
+
ui.beginTurn(task);
|
|
228
|
+
const outcome = await runOneTurn({
|
|
229
|
+
task,
|
|
230
|
+
history,
|
|
231
|
+
baseRef,
|
|
232
|
+
options,
|
|
233
|
+
settings,
|
|
234
|
+
evidence,
|
|
235
|
+
ui,
|
|
236
|
+
clock,
|
|
237
|
+
random,
|
|
238
|
+
});
|
|
239
|
+
history = outcome.messages;
|
|
240
|
+
lastGreen = outcome.green;
|
|
241
|
+
// Where this turn ended is where the next one starts being measured from. A repository
|
|
242
|
+
// with no commit yet has nothing to hang one off, and the base stays where it was.
|
|
243
|
+
const recorded = await recordTurnBaseline({
|
|
244
|
+
workspaceRoot: options.workspace,
|
|
245
|
+
label: `turn ${turns}`,
|
|
246
|
+
previousBase: baseRef,
|
|
247
|
+
});
|
|
248
|
+
if (recorded !== null) {
|
|
249
|
+
baseRef = recorded;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
finally {
|
|
254
|
+
if (turns > 0) {
|
|
255
|
+
const written = await writeBundle(evidence, options.bundleDirectory, clock, ui.note);
|
|
256
|
+
announceBundle(written.directory, ui.note);
|
|
257
|
+
}
|
|
258
|
+
await ui.stop();
|
|
259
|
+
taskReader?.close();
|
|
260
|
+
taskReader = null;
|
|
261
|
+
taskLines = null;
|
|
262
|
+
}
|
|
263
|
+
if (turns === 0) {
|
|
264
|
+
process.stdout.write("nothing was asked for, so nothing ran.\n");
|
|
265
|
+
return 0;
|
|
266
|
+
}
|
|
267
|
+
return lastGreen ? 0 : 1;
|
|
268
|
+
}
|
|
269
|
+
/** One turn of a session, from a typed task to a settled set of gates. */
|
|
270
|
+
async function runOneTurn(input) {
|
|
271
|
+
const { task, options, settings, evidence, ui, clock, random } = input;
|
|
272
|
+
const routed = settings.modelPinned
|
|
273
|
+
? {
|
|
274
|
+
modelSpec: null,
|
|
275
|
+
assignment: "pinned",
|
|
276
|
+
decision: null,
|
|
277
|
+
candidates: [],
|
|
278
|
+
}
|
|
279
|
+
: await chooseModel(task, homedir(), random);
|
|
280
|
+
const modelSpec = routed.modelSpec ?? settings.modelSpec;
|
|
281
|
+
const spec = parseModelSpec(modelSpec);
|
|
282
|
+
const localBackend = await resolveLocalBackend(settings, [spec]);
|
|
283
|
+
if (localBackend !== null) {
|
|
284
|
+
await evidence.record(localEndpointRecord(localBackend));
|
|
285
|
+
}
|
|
286
|
+
if (routed.decision !== null) {
|
|
287
|
+
await evidence.record(routingDecisionRecord(routed.decision));
|
|
288
|
+
}
|
|
289
|
+
const usable = spec.provider === "local" && localBackend !== null
|
|
290
|
+
? chooseUsableModel({
|
|
291
|
+
requested: modelSpec,
|
|
292
|
+
preflight: await preflightAll(evidence, localBackend.url, [modelSpec]),
|
|
293
|
+
keys: settings.providerKeys,
|
|
294
|
+
candidates: routed.candidates,
|
|
295
|
+
})
|
|
296
|
+
: { outcome: "as-requested", modelSpec, reason: "not a local model" };
|
|
297
|
+
if (usable.outcome === "substituted") {
|
|
298
|
+
ui.note(`model: ${usable.modelSpec} instead of ${usable.requested}, ${usable.reason}`);
|
|
299
|
+
}
|
|
300
|
+
const registry = createProviderRegistry(registrySettingsFrom(settings, localBackend));
|
|
301
|
+
const model = createRecordingModelClient(registry.create(parseModelSpec(usable.modelSpec)), evidence);
|
|
302
|
+
const fileSet = createFileSetRegistry(evidence);
|
|
303
|
+
const interruption = new AbortController();
|
|
304
|
+
const onInterrupt = () => {
|
|
305
|
+
interruption.abort();
|
|
306
|
+
};
|
|
307
|
+
process.on("SIGINT", onInterrupt);
|
|
308
|
+
void ui.cancelled().then(onInterrupt);
|
|
309
|
+
const startedAt = clock.now();
|
|
310
|
+
const gateOptions = gateOptionsFrom(settings);
|
|
311
|
+
const diffBudget = diffBudgetFrom(settings);
|
|
312
|
+
try {
|
|
313
|
+
const { loop, gates } = await runAgentTask({
|
|
314
|
+
task,
|
|
315
|
+
workspace: options.workspace,
|
|
316
|
+
baseRef: input.baseRef,
|
|
317
|
+
maxSteps: settings.maxSteps,
|
|
318
|
+
attempts: settings.attempts,
|
|
319
|
+
model,
|
|
320
|
+
evidence,
|
|
321
|
+
fileSet,
|
|
322
|
+
clock,
|
|
323
|
+
random,
|
|
324
|
+
emit: (event) => {
|
|
325
|
+
ui.emit(event);
|
|
326
|
+
},
|
|
327
|
+
confirm: ui.confirm,
|
|
328
|
+
abortSignal: interruption.signal,
|
|
329
|
+
homeDir: homedir(),
|
|
330
|
+
history: input.history,
|
|
331
|
+
...(gateOptions === undefined ? {} : { gateOptions }),
|
|
332
|
+
...(diffBudget === undefined ? {} : { diffBudget }),
|
|
333
|
+
});
|
|
334
|
+
reportGates(gates.outcome, evidence, ui.note);
|
|
335
|
+
await logReward({
|
|
336
|
+
evidence,
|
|
337
|
+
home: homedir(),
|
|
338
|
+
task,
|
|
339
|
+
modelSpec: usable.modelSpec,
|
|
340
|
+
assignment: routed.assignment,
|
|
341
|
+
ratchet: summarizeRatchet(gates.outcome),
|
|
342
|
+
changedFiles: gates.outcome.finalCycle.measures.changedFiles ?? null,
|
|
343
|
+
latencyMs: clock.now() - startedAt,
|
|
344
|
+
recordedAt: clock.now(),
|
|
345
|
+
cost: await priceTask(usable.modelSpec, evidence),
|
|
346
|
+
note: ui.note,
|
|
347
|
+
});
|
|
348
|
+
return {
|
|
349
|
+
messages: loop.messages,
|
|
350
|
+
green: loop.stopReason === "completed" && gates.outcome.settled === "green",
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
finally {
|
|
354
|
+
process.off("SIGINT", onInterrupt);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
176
357
|
/**
|
|
177
358
|
* Everything ambient the screen needs, gathered here so nothing below the composition root
|
|
178
359
|
* reads a terminal, an environment variable, or the clock (invariant 8).
|
|
@@ -201,11 +382,35 @@ function startInterface(input) {
|
|
|
201
382
|
}),
|
|
202
383
|
bindings: resolveKeyBindings(ui.keys),
|
|
203
384
|
...(isTty ? { askOnTerminal } : {}),
|
|
385
|
+
readLine: readTaskLine,
|
|
204
386
|
openEvidence: ui.openEvidence,
|
|
205
387
|
spawnOpen: spawnOpener,
|
|
206
388
|
platform: platform(),
|
|
207
389
|
});
|
|
208
390
|
}
|
|
391
|
+
/**
|
|
392
|
+
* One readline for the whole session, opened when the first task is asked for.
|
|
393
|
+
*
|
|
394
|
+
* Kept open rather than opened per question, because a fresh interface per line loses whatever
|
|
395
|
+
* is already buffered from a pipe, and a piped session is a list of tasks somebody wrote down.
|
|
396
|
+
* Null at end of input is what ends the session.
|
|
397
|
+
*/
|
|
398
|
+
let taskReader = null;
|
|
399
|
+
let taskLines = null;
|
|
400
|
+
async function readTaskLine(prompt) {
|
|
401
|
+
if (taskReader === null) {
|
|
402
|
+
taskReader = createInterface({ input: process.stdin, output: process.stderr });
|
|
403
|
+
taskLines = taskReader[Symbol.asyncIterator]();
|
|
404
|
+
}
|
|
405
|
+
if (process.stdin.isTTY === true) {
|
|
406
|
+
process.stderr.write(prompt);
|
|
407
|
+
}
|
|
408
|
+
const next = await taskLines?.next();
|
|
409
|
+
if (next === undefined || next.done === true) {
|
|
410
|
+
return null;
|
|
411
|
+
}
|
|
412
|
+
return next.value;
|
|
413
|
+
}
|
|
209
414
|
/** Readline, on the plain path only. Ink owns stdin whenever the screen is up. */
|
|
210
415
|
async function askOnTerminal(question) {
|
|
211
416
|
const prompt = createInterface({ input: process.stdin, output: process.stderr });
|
|
@@ -403,6 +608,16 @@ function describeCycle(cycle) {
|
|
|
403
608
|
}
|
|
404
609
|
/** Written through `note`, so an interactive screen holds them until it comes down. */
|
|
405
610
|
function reportGates(outcome, evidence, note) {
|
|
611
|
+
// Said before the gate table rather than after it, because a table of passes over a tree
|
|
612
|
+
// nothing touched is the most misleading thing this tool can print. A model that answered in
|
|
613
|
+
// prose, or emitted its tool calls as text the protocol never parsed, reaches here having
|
|
614
|
+
// done nothing, stops for the honest reason "completed", and every gate then passes over an
|
|
615
|
+
// empty diff. A task can legitimately change nothing, so this states the fact rather than
|
|
616
|
+
// calling it a failure.
|
|
617
|
+
if (outcome.finalCycle.measures.changedFiles === 0) {
|
|
618
|
+
note("\nno files were changed. The gates below measured an unchanged workspace, so they say " +
|
|
619
|
+
"nothing about work being done.");
|
|
620
|
+
}
|
|
406
621
|
note(`\ngates:\n${describeCycle(outcome.finalCycle)}`);
|
|
407
622
|
for (const attempt of outcome.attempts) {
|
|
408
623
|
note(`attempt ${attempt.attempt}: ${attempt.decision.accepted ? "accepted" : "REJECTED"} - ` +
|
|
@@ -882,6 +1097,9 @@ async function main() {
|
|
|
882
1097
|
if (options.command === "parallel") {
|
|
883
1098
|
return parallel(options);
|
|
884
1099
|
}
|
|
1100
|
+
if (options.command === "session") {
|
|
1101
|
+
return session(options);
|
|
1102
|
+
}
|
|
885
1103
|
return options.command === "gates" ? gates(options) : run(options);
|
|
886
1104
|
}
|
|
887
1105
|
main().then((code) => {
|