opencode-harness-kit 0.6.4 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +249 -1
- package/README.md +222 -5
- package/bin/oc-harness.mjs +85 -7
- package/dist/budget.d.ts +247 -0
- package/dist/config.d.ts +34 -1
- package/dist/effort.d.ts +12 -1
- package/dist/guard.d.ts +5 -0
- package/dist/health.d.ts +12 -1
- package/dist/index.js +556 -149
- package/dist/profile.d.ts +2 -1
- package/dist/prune.d.ts +22 -0
- package/dist/rules.d.ts +6 -2
- package/docs/EXIT-CODES.md +18 -4
- package/docs/REVIEW-VERDICT.md +73 -0
- package/eval/RESULTS.md +130 -7
- package/eval/ab.mjs +591 -68
- package/eval/compare.mjs +267 -0
- package/eval/verify.mjs +9 -0
- package/lanes.json +18 -9
- package/package.json +6 -2
- package/prompts/reviewer.md +24 -0
- package/src/budget.js +418 -0
- package/src/config.js +172 -6
- package/src/driver/run.mjs +780 -42
- package/src/effort.js +17 -3
- package/src/guard.ts +304 -1
- package/src/health.js +13 -1
- package/src/index.ts +23 -12
- package/src/profile.js +1 -1
- package/src/prune.ts +21 -1
- package/src/rules.js +145 -0
- package/src/tasks.js +31 -0
package/dist/profile.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export type Lane = {
|
|
|
12
12
|
steps?: number;
|
|
13
13
|
permission?: Record<string, any>;
|
|
14
14
|
prompt: string;
|
|
15
|
+
skills?: boolean;
|
|
15
16
|
};
|
|
16
17
|
export type Profile = {
|
|
17
18
|
id: string;
|
|
@@ -69,7 +70,7 @@ export type RetentionRecord = {
|
|
|
69
70
|
* @typedef {"zero-retention" | "retained" | "may-train" | "unknown"} Retention
|
|
70
71
|
* @typedef {string | null} EffortRequest
|
|
71
72
|
* @typedef {{ model: string, levels?: string[], chain?: string[] }} RoleModel
|
|
72
|
-
* @typedef {{ description: string, mode?: string, steps?: number, permission?: Record<string, any>, prompt: string }} Lane
|
|
73
|
+
* @typedef {{ description: string, mode?: string, steps?: number, permission?: Record<string, any>, prompt: string, skills?: boolean }} Lane
|
|
73
74
|
* @typedef {object} Profile
|
|
74
75
|
* @property {string} id
|
|
75
76
|
* @property {string} [title]
|
package/dist/prune.d.ts
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
import type { Plugin } from "./plugin.js";
|
|
2
|
+
interface StubStats {
|
|
3
|
+
stubbed: number;
|
|
4
|
+
kept: number;
|
|
5
|
+
bytesBefore: number;
|
|
6
|
+
bytesAfter: number;
|
|
7
|
+
}
|
|
2
8
|
export declare const PrunePlugin: Plugin;
|
|
9
|
+
/**
|
|
10
|
+
* Append one line to the project's prune log, and rotate it when the file
|
|
11
|
+
* outgrew `maxBytes`.
|
|
12
|
+
*
|
|
13
|
+
* Exported so the rotation can be driven directly in the tests: reaching it
|
|
14
|
+
* through the hook needs a 4MB fixture, which is not a fixture.
|
|
15
|
+
*
|
|
16
|
+
* @param {string} worktree the project the log belongs to
|
|
17
|
+
* @param {string} profileId the profile the prune ran under
|
|
18
|
+
* @param {StubStats & { saved: number, threshold: number }} stats
|
|
19
|
+
* @param {number} [maxBytes] rotate above this; the telemetry default
|
|
20
|
+
*/
|
|
21
|
+
export declare function logPrune(worktree: string, profileId: string, stats: StubStats & {
|
|
22
|
+
saved: number;
|
|
23
|
+
threshold: number;
|
|
24
|
+
}, maxBytes?: number): Promise<void>;
|
|
3
25
|
export declare const pruneMeta: {
|
|
4
26
|
note: string;
|
|
5
27
|
};
|
package/dist/rules.d.ts
CHANGED
|
@@ -75,8 +75,12 @@ export declare function shellPayload(segment: string): string | null;
|
|
|
75
75
|
export declare const ASK_GATED: RegExp[];
|
|
76
76
|
/** @type {Rule[]} */
|
|
77
77
|
export declare const BASH_RULES: Rule[];
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
export declare const WRITE_RULES: {
|
|
79
|
+
name: string;
|
|
80
|
+
test: RegExp;
|
|
81
|
+
unless: RegExp;
|
|
82
|
+
why: string;
|
|
83
|
+
}[];
|
|
80
84
|
/**
|
|
81
85
|
* The shared denylist, checked the way the rules are checked.
|
|
82
86
|
*
|
package/docs/EXIT-CODES.md
CHANGED
|
@@ -9,18 +9,32 @@ stdout gets the answer and nothing else.
|
|
|
9
9
|
## `oc-harness run`
|
|
10
10
|
|
|
11
11
|
The unattended loop. It walks `.space/tasks.md`, asks the agent for one task
|
|
12
|
-
at a time, and re-runs the task's own verify command before believing it.
|
|
12
|
+
at a time, and re-runs the task's own verify command before believing it. It
|
|
13
|
+
builds and verifies; it does not plan, commit or push. With `--review` it also
|
|
14
|
+
asks the reviewer lane for a schema'd verdict and stops unless that verdict
|
|
15
|
+
passes.
|
|
13
16
|
|
|
14
17
|
| Code | Meaning |
|
|
15
18
|
|---|---|
|
|
16
19
|
| 0 | Every task is done. |
|
|
17
20
|
| 1 | There is no task file. The loop needs a plan to walk. |
|
|
18
|
-
| 2 | Stopped early and a person is needed: a task is blocked, a task has no verify command, the round cap was reached, or the time budget ran out. |
|
|
19
|
-
| 3 | The agent itself failed. The reason is the agent's own last words, and the task is marked blocked with them. |
|
|
21
|
+
| 2 | Stopped early and a person is needed: a task is blocked, a task has no verify command or one that cannot fail (`true`, `echo ok`), a task file with no tasks in it, the agent changed files the task did not name, another run holds the lock, the round cap was reached, or the time budget ran out. |
|
|
22
|
+
| 3 | The agent itself failed. The reason is the agent's own last words, and the task is marked blocked with them. This includes the agent exiting 0 with an empty transcript: that is a spent or unreachable model route, not a change worth verifying, so no verify runs. |
|
|
20
23
|
| 4 | The verify command failed. The task is marked blocked and the real output is in `.space/tasks.md` - not in the exit code, which is no place for a stack trace. |
|
|
24
|
+
| 5 | The review did not pass: the reviewer failed, returned prose instead of a schema'd verdict, or returned `fail`. The task is marked blocked with the blockers and the verdict file is in `.space/review/`. |
|
|
21
25
|
|
|
22
26
|
Code 2 is the "asked for something impossible" code: nothing about it is a
|
|
23
|
-
bug, and the reason is printed. Codes 3 and
|
|
27
|
+
bug, and the reason is printed. Codes 3, 4 and 5 mean the work did not land.
|
|
28
|
+
|
|
29
|
+
A task's `files:` line is a scope, not a hint. When the agent changes a file
|
|
30
|
+
the line does not name, the loop marks the task blocked and stops rather than
|
|
31
|
+
letting the next task build on an unplanned edit. `--allow-extra-files` is
|
|
32
|
+
the deliberate way to say the task may go wider; it is also the only way to
|
|
33
|
+
run outside a git work tree, where the check has nothing to read.
|
|
34
|
+
|
|
35
|
+
A live lock is not cleared automatically. `--force-unlock` breaks one
|
|
36
|
+
explicitly, for the case where the recorded pid now belongs to an unrelated
|
|
37
|
+
process. Do not use it to start a second run alongside a real one.
|
|
24
38
|
|
|
25
39
|
## `oc-harness doctor`
|
|
26
40
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# The review verdict
|
|
2
|
+
|
|
3
|
+
`oc-harness run --review` asks the `reviewer` lane for a machine-readable
|
|
4
|
+
verdict. A verdict is accepted only when it matches this schema; anything else
|
|
5
|
+
is a failed review, never a pass.
|
|
6
|
+
|
|
7
|
+
The contract is deliberately narrow. A reviewer that writes prose, wraps the
|
|
8
|
+
object in a sentence, or omits a field is rejected, because a loop that parses
|
|
9
|
+
whatever it is given will eventually parse a compliment as a pass.
|
|
10
|
+
|
|
11
|
+
## Schema
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"schema": "oc-harness/review@1",
|
|
16
|
+
"verdict": "pass",
|
|
17
|
+
"blockers": [],
|
|
18
|
+
"notes": ""
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
| Field | Required | Rule |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| `schema` | yes | Exactly `oc-harness/review@1`. Bump the suffix to change the shape. |
|
|
25
|
+
| `verdict` | yes | `pass` or `fail`. |
|
|
26
|
+
| `blockers` | yes | An array. `pass` requires it empty; `fail` requires at least one. |
|
|
27
|
+
| `blockers[].file` | yes | A path from the repository root. |
|
|
28
|
+
| `blockers[].line` | yes | A non-negative integer. `0` is allowed for a file-level finding. |
|
|
29
|
+
| `blockers[].issue` | yes | What is wrong. |
|
|
30
|
+
| `blockers[].consequence` | yes | What breaks because of it. A finding with no consequence is a preference. |
|
|
31
|
+
| `notes` | no | A short string. |
|
|
32
|
+
|
|
33
|
+
The reviewer may output the object bare or inside one ` ```json ` fence. It
|
|
34
|
+
may not put a sentence before or after it.
|
|
35
|
+
|
|
36
|
+
## Where it is kept
|
|
37
|
+
|
|
38
|
+
The orchestrator validates the verdict and writes it to
|
|
39
|
+
`.space/review/<round>-<task-slug>.json`, atomically. A review that leaves no
|
|
40
|
+
file is a review nobody can audit, and the next run cannot tell it happened.
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"schema": "oc-harness/review@1",
|
|
45
|
+
"at": "2026-10-24T12:00:00.000Z",
|
|
46
|
+
"task": "Add the retry budget",
|
|
47
|
+
"round": 3,
|
|
48
|
+
"reviewer": "reviewer",
|
|
49
|
+
"verify": { "command": "npm test", "exit": 0, "seconds": 12 },
|
|
50
|
+
"verdict": "fail",
|
|
51
|
+
"blockers": [
|
|
52
|
+
{
|
|
53
|
+
"file": "src/retry.js",
|
|
54
|
+
"line": 41,
|
|
55
|
+
"issue": "the budget is decremented after the sleep",
|
|
56
|
+
"consequence": "a timed-out attempt is refunded, so the loop can run forever"
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"notes": ""
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## What the loop does with it
|
|
64
|
+
|
|
65
|
+
| Verdict | Outcome |
|
|
66
|
+
|---|---|
|
|
67
|
+
| `pass` | The task is marked `done`, and the task's `output:` records the verdict path. |
|
|
68
|
+
| `fail` | The task is marked `blocked` with the blockers, and the run stops with exit 5. |
|
|
69
|
+
| malformed | The task is marked `blocked`, and the run stops with exit 5. |
|
|
70
|
+
| reviewer crashed | The task is marked `blocked`, and the run stops with exit 5. |
|
|
71
|
+
|
|
72
|
+
Review runs after the task's own `verify:` has passed. A failed verify never
|
|
73
|
+
reaches the reviewer, because there is nothing yet worth reviewing.
|
package/eval/RESULTS.md
CHANGED
|
@@ -18,6 +18,16 @@ bottom runs the same task with and without the kit, ten times each, on both
|
|
|
18
18
|
arms at once - 120 agent runs, which is enough to be worth reading and not
|
|
19
19
|
enough to be worth trusting.
|
|
20
20
|
|
|
21
|
+
**One definition changed, and the tables are marked.** Until commit `8614d75`
|
|
22
|
+
the A/B added up `tokens.input` - the part of each request that was not in the
|
|
23
|
+
provider's prompt cache - and called it "input tokens". That is not what a
|
|
24
|
+
request costs: a cached step reports a few hundred tokens there against tens of
|
|
25
|
+
thousands in `cache.read`. The column is now called **uncached input**, and a
|
|
26
|
+
**context tokens** row was added where the streams still exist to re-read it.
|
|
27
|
+
Both are medians over the same runs; the context row is the one to compare
|
|
28
|
+
against the guard's budget, and the uncached row is the one to compare against
|
|
29
|
+
any table written before this note.
|
|
30
|
+
|
|
21
31
|
## Two measurements, and the difference between them
|
|
22
32
|
|
|
23
33
|
**`npm run measure` is an OBSERVATION about one install.** It compares the work
|
|
@@ -175,7 +185,7 @@ so it entered the medians as a fast, empty, wrong answer.
|
|
|
175
185
|
| narrow reads | 66.7% | 66.7% |
|
|
176
186
|
| grep/glob calls | 3 | 2 |
|
|
177
187
|
| steps | 9 | 6 |
|
|
178
|
-
| input
|
|
188
|
+
| uncached input | 56,205 | 10,540 |
|
|
179
189
|
| final context | 39,928 | 12,718 |
|
|
180
190
|
| wall seconds | 43 | 21 |
|
|
181
191
|
| paths written outside the target | 0 | 0 |
|
|
@@ -199,8 +209,10 @@ traffic - gave **55/60 against 54/60**, the other way. Two measurements
|
|
|
199
209
|
put the tie on either side of zero, which is what a tie looks like from
|
|
200
210
|
both ends.
|
|
201
211
|
|
|
202
|
-
**On everything else, the kit is a cost.** It spends **5.3x the input
|
|
203
|
-
tokens**
|
|
212
|
+
**On everything else, the kit is a cost.** It spends **5.3x the uncached input
|
|
213
|
+
tokens** (the streams for this run are gone, so the context total cannot be
|
|
214
|
+
re-derived; on the free route, where they survive, the same ratio is 6.4x) and
|
|
215
|
+
takes **twice as long**, and it makes **more** tool calls.
|
|
204
216
|
Those are the honest numbers.
|
|
205
217
|
|
|
206
218
|
**The previous conclusion was the grader's fault, and it is worth writing
|
|
@@ -255,6 +267,117 @@ one-file question following it is waste either way. A fleet that routes
|
|
|
255
267
|
each job to the model built for it is the other half of what the kit
|
|
256
268
|
offers, and this suite uses one model on both sides, so it cannot see that.
|
|
257
269
|
|
|
270
|
+
### The same suite on the free route, 3 reps per arm
|
|
271
|
+
|
|
272
|
+
node eval/ab.mjs --target <scratch>/self --suite eval/tasks-self.json \
|
|
273
|
+
--reps 3 --timeout 180 --out <scratch>/ab-self-02 --budget 2500000
|
|
274
|
+
|
|
275
|
+
Run after the budget work, on the route this install actually uses,
|
|
276
|
+
`opencode/deepseek-v4.1-flash-free`, with `--out` so a quota stop would
|
|
277
|
+
resume rather than restart. 36 runs, 33 scored: three hit the 180-second
|
|
278
|
+
ceiling (one on, two off) and are excluded rather than counted as wrong.
|
|
279
|
+
|
|
280
|
+
**The token rows were re-read after the counter was fixed.** Until then the
|
|
281
|
+
suite summed `tokens.input` - the part of the prompt that was not in the
|
|
282
|
+
provider's cache - and the table called it "input tokens". The cost of a
|
|
283
|
+
request is the whole context it reads. Re-running the same streams through the
|
|
284
|
+
corrected reader puts the medians at 252,054 and 39,180 - **6.4x**, not 4.7x:
|
|
285
|
+
|
|
286
|
+
node eval/ab.mjs --target <scratch>/self --suite eval/tasks-self.json \
|
|
287
|
+
--rescore <scratch>/ab-self-02
|
|
288
|
+
|
|
289
|
+
The context row is over the 12 runs per arm that can still be re-scored: the
|
|
290
|
+
six edit runs per arm cannot, because the per-run copy of the subject they
|
|
291
|
+
edited is gone and re-grading them would grade nothing. The uncached row is
|
|
292
|
+
over the 17 and 16 runs the live suite scored, because that is the number it
|
|
293
|
+
printed; it is kept because every table above it was written with that
|
|
294
|
+
definition. Neither row is comparable to the other's count, and both are
|
|
295
|
+
comparable between the arms.
|
|
296
|
+
|
|
297
|
+
| metric (median) | kit on | kit off |
|
|
298
|
+
| --- | --- | --- |
|
|
299
|
+
| **correct** | **15/17** | **16/16** |
|
|
300
|
+
| tool calls | 9 | 4 |
|
|
301
|
+
| steps | 7 | 4 |
|
|
302
|
+
| narrow reads | 60% | 83.4% |
|
|
303
|
+
| context tokens (12 runs/arm) | 252,054 | 39,180 |
|
|
304
|
+
| uncached input (17/16 runs) | 44,444 | 9,527 |
|
|
305
|
+
| final context | 43,823 | 11,236 |
|
|
306
|
+
| wall seconds | 53.8 | 18.6 |
|
|
307
|
+
|
|
308
|
+
Same shape as the 10-rep run, and a little worse for the kit: 6.4x the context
|
|
309
|
+
tokens, 2.9x the wall time, twice the tool calls, and the one task the kit
|
|
310
|
+
lost outright was `read-control` (1/3 against 3/3) - the smallest task in the
|
|
311
|
+
suite, where the kit's fixed overhead is the whole cost. Three reps per arm
|
|
312
|
+
is not enough to call a correctness difference; it is enough to say the cost
|
|
313
|
+
reproduces.
|
|
314
|
+
|
|
315
|
+
### What the skill list cost
|
|
316
|
+
|
|
317
|
+
The first request of a run is the clean place to measure fixed overhead: the
|
|
318
|
+
prompt, the tool schemas, and the task, before any conversation. It is also
|
|
319
|
+
nearly constant run to run, which makes a median over 20 runs meaningful to the
|
|
320
|
+
token.
|
|
321
|
+
|
|
322
|
+
| first request | kit on | kit off |
|
|
323
|
+
| --- | --- | --- |
|
|
324
|
+
| skills on (3-rep run) | 36,016 | 7,856 |
|
|
325
|
+
| skills off (10-rep run) | 10,865 | 7,867 |
|
|
326
|
+
|
|
327
|
+
`oc-harness use fleet-safe --no-skills` removed **25,151 tokens** from every
|
|
328
|
+
kit-on request - 70% of its fixed cost, and more than the whole off arm. The
|
|
329
|
+
spread across runs is ±20 tokens, so this is not sampling noise; the off arm
|
|
330
|
+
did not move because the flag only changes the lanes' prompt.
|
|
331
|
+
|
|
332
|
+
node -e 'for (const f of <dir>/*-on-*.json) { first step_finish }'
|
|
333
|
+
|
|
334
|
+
The residual 10,865 is the lane prompt, `GLOBAL.md` and the tool schemas. The
|
|
335
|
+
skill list was the single largest line item in the kit's overhead, and it was
|
|
336
|
+
paying for 219 skills that a lane with `tools.skill: false` could not open.
|
|
337
|
+
|
|
338
|
+
### The 10-rep run: 47 of 120, stopped by the window
|
|
339
|
+
|
|
340
|
+
node eval/ab.mjs --target <scratch>/self --suite eval/tasks-self.json \
|
|
341
|
+
--reps 10 --timeout 180 --out <scratch>/ab-self-10 --budget 12000000
|
|
342
|
+
|
|
343
|
+
It started 47 runs and then the account's free window ran out, which looks
|
|
344
|
+
like `opencode run` hanging rather than like an error - see the preflight note
|
|
345
|
+
in the README. 46 of the 47 produced a result: 40 were scored and six are
|
|
346
|
+
listed as not scored. The 47th was cut off mid-run and is in no number below.
|
|
347
|
+
The other 73 were never started. Three of the six tasks have runs at all, so
|
|
348
|
+
this is a partial set and **not** the headline number. It is here because the
|
|
349
|
+
direction is worth having and because the files it came from will not survive
|
|
350
|
+
forever:
|
|
351
|
+
|
|
352
|
+
node eval/ab.mjs --target <scratch>/self --suite eval/tasks-self.json \
|
|
353
|
+
--rescore <scratch>/ab-self-10
|
|
354
|
+
|
|
355
|
+
| metric | kit on | kit off |
|
|
356
|
+
| --- | --- | --- |
|
|
357
|
+
| correct, all three tasks | 18/19 | 22/22 |
|
|
358
|
+
| `read-control` | 9/10 | 10/10 |
|
|
359
|
+
| `read-multi-denylist` | 6/6 | 10/10 |
|
|
360
|
+
| `read-multi-gate` | 3/3 | 2/2 |
|
|
361
|
+
| context tokens (median) | 62,990 | 49,374 |
|
|
362
|
+
| wall seconds (median) | 30.6 | 29.3 |
|
|
363
|
+
| not scored | 5 | 1 |
|
|
364
|
+
|
|
365
|
+
`wall seconds` is the harness's own timer, not the last event in the stream:
|
|
366
|
+
four of the on runs were killed at 180s and their streams stop earlier, so a
|
|
367
|
+
stream-derived column made the killed arm look faster.
|
|
368
|
+
|
|
369
|
+
Five runs hit the 180-second ceiling: four of them are `read-multi-denylist`
|
|
370
|
+
on the kit, at 12, 12, 15 and 20 steps, so on that task the kit did not merely
|
|
371
|
+
answer worse, it did not finish four times in ten. The fifth is `read-multi-gate`
|
|
372
|
+
off. A sixth run, `read-multi-gate` on, produced no output at all and is not
|
|
373
|
+
scored either. The context ratio here (1.3x) is much smaller than the 3-rep
|
|
374
|
+
run's 6.4x and should not be read as a contradiction: the task mix is
|
|
375
|
+
different, and the unfinished runs are excluded from the median.
|
|
376
|
+
|
|
377
|
+
Resuming is `--out` plus the same command; a finished run is read from its
|
|
378
|
+
sidecar and not paid for again, and the sidecar's token count is re-read from
|
|
379
|
+
the stream so the cap counts the corrected number.
|
|
380
|
+
|
|
258
381
|
## The A/B on TypeScript, against a PUBLIC subject
|
|
259
382
|
|
|
260
383
|
node eval/prepare.mjs --clone https://github.com/typesense/typesense-js \
|
|
@@ -284,7 +407,7 @@ is the check that stops an ambiguous task.
|
|
|
284
407
|
| tool calls | 12 | 12 |
|
|
285
408
|
| read calls | 2 | 2 |
|
|
286
409
|
| narrow reads | 50% | 58.4% |
|
|
287
|
-
| input
|
|
410
|
+
| uncached input | 46,025 | 17,324 |
|
|
288
411
|
| final context | 45,455 | 18,962 |
|
|
289
412
|
| wall seconds | **31.4** | 34.4 |
|
|
290
413
|
| paths outside the target | 0 | 0 |
|
|
@@ -332,7 +455,7 @@ pristine subject file by file, and the answer is graded by citation.
|
|
|
332
455
|
| **correct** | **2/2** | **2/2** |
|
|
333
456
|
| tool calls | 47 | 46 |
|
|
334
457
|
| read calls | 12 | 18 |
|
|
335
|
-
| input
|
|
458
|
+
| uncached input | 78,280 | 37,171 |
|
|
336
459
|
| final context | 68,794 | 42,732 |
|
|
337
460
|
| wall seconds | 121.4 | 104.7 |
|
|
338
461
|
|
|
@@ -360,7 +483,7 @@ off and on:
|
|
|
360
483
|
| --- | --- | --- | --- |
|
|
361
484
|
| tool calls | 67.5 | 51 | **-24%** |
|
|
362
485
|
| read calls | 22.5 | 18.5 | -18% |
|
|
363
|
-
| input
|
|
486
|
+
| uncached input | 268,834 | 84,325 | **-69%** |
|
|
364
487
|
| final context | 48,637 | 75,705 | +56% |
|
|
365
488
|
| wall seconds | 307.5 | 123.5 | **-60%** |
|
|
366
489
|
|
|
@@ -401,7 +524,7 @@ task actually says, and the difference between the arms is the lane.
|
|
|
401
524
|
| **correct** | **2/2** | **2/2** |
|
|
402
525
|
| tool calls | 36 | 20 |
|
|
403
526
|
| read calls | 5.5 | 7 |
|
|
404
|
-
| input
|
|
527
|
+
| uncached input | 85,499 | 38,934 |
|
|
405
528
|
| wall seconds | 161.5 | 80.8 |
|
|
406
529
|
|
|
407
530
|
### What this says, and what it does not
|