harnex 0.7.12 → 0.7.14
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +71 -0
- data/README.md +62 -17
- data/TECHNICAL.md +20 -1
- data/guides/01_dispatch.md +29 -9
- data/guides/04_monitoring.md +11 -5
- data/lib/harnex/adapters/base.rb +16 -0
- data/lib/harnex/adapters/codex.rb +4 -0
- data/lib/harnex/adapters/codex_appserver.rb +12 -0
- data/lib/harnex/adapters/pi.rb +46 -5
- data/lib/harnex/artifact_report.rb +522 -33
- data/lib/harnex/cli.rb +17 -0
- data/lib/harnex/commands/artifact_report.rb +94 -0
- data/lib/harnex/commands/orchestration.rb +170 -0
- data/lib/harnex/commands/run.rb +68 -5
- data/lib/harnex/commands/wait.rb +6 -1
- data/lib/harnex/commands/watch.rb +2 -0
- data/lib/harnex/context_telemetry.rb +104 -0
- data/lib/harnex/core.rb +2 -0
- data/lib/harnex/orchestration.rb +458 -0
- data/lib/harnex/runtime/session.rb +620 -30
- data/lib/harnex/terminal_status.rb +7 -0
- data/lib/harnex/version.rb +2 -2
- data/lib/harnex.rb +4 -0
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e50f27f3d17436e058126d656fdaeb3dfd58cbfdb0e565b8f221ae6b579f3507
|
|
4
|
+
data.tar.gz: 01f08ae4414ed2e6a5d4d4503888349c7e27b7aee348b805a435f393ba0f95ad
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f62483a74ed5651eecc43c2e30f5020ddd077b0038a17522309af411335c86b94a04d45eec39a2d33defcbb0d781b7ac1c3085c34bd24d0ab1f9baaeb5ebbc32
|
|
7
|
+
data.tar.gz: 896793c0dc92d82f62989105714be633fc3b4966752fa3049d7258529cc31fbad2ac0ef1ff36bec2c5b9ac1b2baf42ac325d96f3fe9228f8efbfd0b61bc0e906
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,77 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.7.14] - 2026-07-15 | 10:06 PM | IST
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `harnex run` now accepts opt-in orchestration metadata flags
|
|
10
|
+
(`--orchestration-run-id`, `--orchestration-generation-id`,
|
|
11
|
+
`--orchestration-role`, `--orchestration-session-id`, and
|
|
12
|
+
`--orchestration-rotation-reason`) and emits a top-level `orchestration`
|
|
13
|
+
block when present.
|
|
14
|
+
- New `harnex orchestration sample` / `harnex orchestration report` commands
|
|
15
|
+
ingest bounded external-primary samples and compute primary-versus-worker
|
|
16
|
+
queue rollups without storing prompts, transcripts, tool payloads, or secrets.
|
|
17
|
+
- New `harnex artifact-report init PATH` and `harnex artifact-report validate
|
|
18
|
+
PATH [--final]` commands provide a bounded v1 report skeleton and
|
|
19
|
+
machine-readable field diagnostics without echoing report payloads.
|
|
20
|
+
- `harnex run --require-artifact-report` makes fresh accepted/no-change report
|
|
21
|
+
proof part of the work verdict and exposes strict mode to workers through
|
|
22
|
+
`HARNEX_ARTIFACT_REPORT_REQUIRED=1`.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- Autonomous Codex app-server turns launched with `--context` now distinguish
|
|
27
|
+
provider turn completion from accepted work completion. Harnex requires
|
|
28
|
+
structured command/tool activity, a Git delta, or a fresh accepted/no-change
|
|
29
|
+
report before emitting `task_complete`; the classifier never parses final
|
|
30
|
+
prose and applies equally to flex and fast service tiers.
|
|
31
|
+
- Dispatch outcomes now include additive `class` and `report_status` fields,
|
|
32
|
+
and watch/wait/status/marker payloads preserve typed proof failures.
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
- Acknowledgment-only Codex turns now emit `completed_no_activity` and return a
|
|
37
|
+
non-zero work/auto-stop verdict instead of being reported as successful work.
|
|
38
|
+
- Strict report mode fails closed for missing, malformed, unsupported,
|
|
39
|
+
oversized, schema-incomplete, rejected, and unchanged stale sidecars. A valid
|
|
40
|
+
explicit `no_change` report remains an accepted proof path for intentional
|
|
41
|
+
no-delta work, while report-shaped JSON printed in final prose is ignored.
|
|
42
|
+
|
|
43
|
+
## [0.7.13] - 2026-07-15 | 12:24 PM | IST
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
|
|
47
|
+
- Dispatch summaries now include a stable additive `context` block with
|
|
48
|
+
terminal and peak active-context pressure, source/status provenance, bounded
|
|
49
|
+
sample counts, and explicit missing-sample handling. Pi RPC reports observed
|
|
50
|
+
`get_session_stats.contextUsage`; Codex app-server conservatively estimates
|
|
51
|
+
pressure from `tokenUsage.last` plus `modelContextWindow`; unsupported
|
|
52
|
+
adapters do not fabricate values.
|
|
53
|
+
- Dispatch summaries now include additive `usage`, `attribution`, `outcome`, and
|
|
54
|
+
per-session `attempt` blocks. `usage.status` distinguishes provider-observed,
|
|
55
|
+
explicit-zero, caller-estimated, unsupported, and missing values so nullable
|
|
56
|
+
cost/token fields are never mistaken for zero.
|
|
57
|
+
- `harnex run` accepts `--parent-dispatch-id`, `--parent-attempt-id`, and
|
|
58
|
+
`--attempt-kind` (`initial`, `retry`, `fix`, `review`, or `superseding`) to
|
|
59
|
+
preserve parent/child relationships while retaining separate raw effort rows.
|
|
60
|
+
- Terminal event streams now emit `attempt_started` / `attempt_finished` and
|
|
61
|
+
translate Pi internal retry notices into `attempt_retry_scheduled`; the
|
|
62
|
+
Session exposes an `attempt_fallback_switched` telemetry seam for recovery
|
|
63
|
+
and fallback owners.
|
|
64
|
+
- Bounded artifact reports can optionally record a semantic outcome
|
|
65
|
+
(`accepted`, `rejected`, `no_change`, or `unknown`). Final outcome blocks
|
|
66
|
+
retain git commit/path/LOC observations without claiming they prove authorship.
|
|
67
|
+
|
|
68
|
+
### Changed
|
|
69
|
+
|
|
70
|
+
- Dispatch telemetry documentation now distinguishes cumulative usage from
|
|
71
|
+
active context-window pressure and defines context sample/high-water/null
|
|
72
|
+
semantics alongside usage-cost provenance, strict attribution quality,
|
|
73
|
+
sidecar-backed outcomes, attempt linkage, and safe throughput/reliability
|
|
74
|
+
query examples.
|
|
75
|
+
|
|
5
76
|
## [0.7.12] - 2026-07-10 | 11:19 PM | IST
|
|
6
77
|
|
|
7
78
|
### Fixed
|
data/README.md
CHANGED
|
@@ -203,8 +203,14 @@ For file-change hooks, use `--watch-file PATH`. The older
|
|
|
203
203
|
`--watch PATH`/`--watch=PATH` form is still accepted for compatibility, while
|
|
204
204
|
bare `--watch` means babysitter mode.
|
|
205
205
|
|
|
206
|
-
For one-shot startup prompts, add `--auto-stop`. It requires `--context
|
|
207
|
-
|
|
206
|
+
For one-shot startup prompts, add `--auto-stop`. It requires `--context`.
|
|
207
|
+
A Codex app-server turn launched from `--context` only counts as accepted
|
|
208
|
+
autonomous work when structured command/tool activity, a Git delta, or a fresh
|
|
209
|
+
accepted/no-change artifact report proves activity. An acknowledgment-only turn emits
|
|
210
|
+
`outcome.class=completed_no_activity`, makes `watch --until done` return
|
|
211
|
+
non-zero, and auto-stops with a non-zero verdict instead of reporting success.
|
|
212
|
+
PTY adapters still stop on prompt return because they do not expose equivalent
|
|
213
|
+
structured activity signals.
|
|
208
214
|
|
|
209
215
|
## Completion and waiting
|
|
210
216
|
|
|
@@ -269,20 +275,35 @@ harnex run pi --meta '{"read_budget_lines":2000,"output_ceiling_lines":800}' ...
|
|
|
269
275
|
```
|
|
270
276
|
|
|
271
277
|
Workers can also write a small machine-readable proof sidecar while keeping the
|
|
272
|
-
canonical explanation in plain-text `koder/` files
|
|
278
|
+
canonical explanation in plain-text `koder/` files. Initialize the real schema
|
|
279
|
+
instead of asking a model to reproduce it from prose:
|
|
273
280
|
|
|
274
281
|
```bash
|
|
275
|
-
harnex
|
|
276
|
-
|
|
277
|
-
--
|
|
282
|
+
harnex artifact-report init .harnex/reports/pi-i-61.json
|
|
283
|
+
harnex run pi --id pi-i-61 \
|
|
284
|
+
--artifact-report .harnex/reports/pi-i-61.json \
|
|
285
|
+
--require-artifact-report \
|
|
286
|
+
--context 'Run validation, update the canonical koder artifact, finalize $HARNEX_ARTIFACT_REPORT_PATH, and validate it with harnex artifact-report validate "$HARNEX_ARTIFACT_REPORT_PATH" --final' \
|
|
278
287
|
--auto-stop
|
|
279
288
|
```
|
|
280
289
|
|
|
281
290
|
The sidecar schema is `harnex.artifact_report.v1`; harnex exposes the path as
|
|
282
|
-
`HARNEX_ARTIFACT_REPORT_PATH` / `HARNEX_VALIDATION_REPORT_PATH`,
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
291
|
+
`HARNEX_ARTIFACT_REPORT_PATH` / `HARNEX_VALIDATION_REPORT_PATH`, the schema as
|
|
292
|
+
`HARNEX_ARTIFACT_REPORT_SCHEMA`, and strict mode as
|
|
293
|
+
`HARNEX_ARTIFACT_REPORT_REQUIRED=1`. `harnex artifact-report validate PATH`
|
|
294
|
+
checks field shapes; add `--final` to require `status=pass`, an
|
|
295
|
+
`accepted`/`no_change` outcome with a summary, valid command exit codes, and
|
|
296
|
+
`validation.final_reported=true`. Diagnostics contain bounded field paths and
|
|
297
|
+
shape errors, not report payloads or transcripts.
|
|
298
|
+
|
|
299
|
+
Without `--require-artifact-report`, report defects remain fail-soft warning
|
|
300
|
+
telemetry. With it, a missing, malformed, unsupported, oversized,
|
|
301
|
+
contract-incomplete, rejected, or unchanged stale report makes the work verdict
|
|
302
|
+
non-zero. A fresh explicit `no_change` report can prove an intentional no-delta
|
|
303
|
+
task without fake edits. Harnex records compact `artifact_report`, `validation`,
|
|
304
|
+
and `artifacts` blocks plus `outcome.class` / `outcome.report_status`; Git
|
|
305
|
+
changes alone never imply semantic acceptance, and JSON printed in final prose
|
|
306
|
+
is never scraped as a sidecar.
|
|
286
307
|
|
|
287
308
|
Queue runners can pass first-class attribution without hiding it in prose:
|
|
288
309
|
|
|
@@ -293,13 +314,36 @@ harnex run pi --project-id harnex --queue-id queue-005 --entry-id SP-4 \
|
|
|
293
314
|
|
|
294
315
|
Soft budget metadata is copied into summary `meta`; queue/agent/reliability
|
|
295
316
|
metadata is copied into top-level `queue`, `agent`, and `reliability` summary
|
|
296
|
-
blocks.
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
`
|
|
301
|
-
|
|
302
|
-
`
|
|
317
|
+
blocks. Every terminal row also has `usage` (so null is distinguishable from
|
|
318
|
+
explicit zero or an estimate), `attribution`, `outcome`, and a joinable
|
|
319
|
+
per-session `attempt` block. Terminal summary `actual` records timing, exit
|
|
320
|
+
classification, token usage when the adapter can capture it, adapter-reported
|
|
321
|
+
`cost_usd` when reliably available, git deltas, task-completion state,
|
|
322
|
+
operational counters (`stalls`, `force_resumes`, `disconnections`,
|
|
323
|
+
`tool_calls`, `commands_executed`), output/event log paths, and rough volume
|
|
324
|
+
measurements such as `lines_changed`, `output_lines`, `output_bytes`, and
|
|
325
|
+
`event_records`.
|
|
326
|
+
|
|
327
|
+
Long queue runners can also opt into logical primary-orchestrator rollups:
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
harnex run pi --orchestration-run-id queue-005 --orchestration-generation-id gen-1 \
|
|
331
|
+
--orchestration-role worker --project-id harnex --queue-id queue-005 \
|
|
332
|
+
--entry-id SP-4 --phase implement --intent queue-work ...
|
|
333
|
+
|
|
334
|
+
harnex orchestration sample --out .harnex/orchestrator.jsonl \
|
|
335
|
+
--run-id queue-005 --generation-id primary-1 --session-id pi-primary-1 \
|
|
336
|
+
--context-tokens 64000 --context-window-tokens 200000 \
|
|
337
|
+
--usage-status observed --usage-total-tokens 129000 --tool-calls 31
|
|
338
|
+
|
|
339
|
+
harnex orchestration report --dispatch .harnex/dispatch.jsonl \
|
|
340
|
+
--samples .harnex/orchestrator.jsonl --run-id queue-005 --json
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
External samples use the bounded `harnex.orchestrator_sample.v1` schema. They
|
|
344
|
+
record ids, lifecycle/sample event names, aggregate usage/context counters,
|
|
345
|
+
tool-call counts, compactions, and rotation reasons only; prompts, transcripts,
|
|
346
|
+
tool arguments/results, secrets, and private payloads are out of scope.
|
|
303
347
|
Harnex records the data only; consumers decide whether to fail closed. See
|
|
304
348
|
[docs/dispatch-telemetry.md](docs/dispatch-telemetry.md) for the field
|
|
305
349
|
contract.
|
|
@@ -378,6 +422,7 @@ See [recipes/03_buddy.md](recipes/03_buddy.md) for the full pattern.
|
|
|
378
422
|
| `harnex events --id <id>` | Stream structured session events (`--snapshot` for non-blocking dump) |
|
|
379
423
|
| `harnex history` | List completed dispatches from `.harnex/dispatch.jsonl` |
|
|
380
424
|
| `harnex wait --id <id>` | Block until process exit by default; use `--until done` for unattended work completion or `--until task_complete` for exact structured turn completion |
|
|
425
|
+
| `harnex artifact-report init\|validate PATH` | Create or validate bounded `harnex.artifact_report.v1` proof; use `validate --final` before strict completion |
|
|
381
426
|
| `harnex doctor` | Run adapter dependency preflight checks; add `--sweep` for read-only session drift diagnostics |
|
|
382
427
|
| `harnex guide` | Getting started walkthrough |
|
|
383
428
|
| `harnex agents-guide` | Agent-facing dispatch, chain, buddy, monitoring, and naming guides |
|
data/TECHNICAL.md
CHANGED
|
@@ -28,10 +28,29 @@ harnex run codex -- --cd ~/other/repo
|
|
|
28
28
|
| `--preset NAME` | Watch preset (`impl`, `plan`, `gate`), requires `--watch` |
|
|
29
29
|
| `--watch-file PATH` | Auto-send a file-change hook (`--watch PATH`/`--watch=PATH` legacy) |
|
|
30
30
|
| `--context TXT` | Give the agent a task on startup |
|
|
31
|
-
| `--auto-stop` | With `--context`, stop after
|
|
31
|
+
| `--auto-stop` | With `--context`, stop after accepted task completion |
|
|
32
|
+
| `--artifact-report PATH` | Expose and ingest a bounded v1 proof sidecar |
|
|
33
|
+
| `--require-artifact-report` | Fail closed unless the sidecar is accepted final proof |
|
|
32
34
|
| `--fast` | For Codex, use `service_tier="fast"` instead of default `flex` |
|
|
33
35
|
| `--timeout SEC` | Wait budget for detached registration |
|
|
34
36
|
|
|
37
|
+
Codex app-server auto-stop rejects completion with no structured command/tool
|
|
38
|
+
activity, Git delta, or fresh accepted/no-change report as
|
|
39
|
+
`completed_no_activity`. Strict artifact-report mode works across transports
|
|
40
|
+
and returns non-zero for missing, invalid, rejected, or stale proof.
|
|
41
|
+
|
|
42
|
+
### `harnex artifact-report` — Initialize and validate proof
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
harnex artifact-report init .harnex/reports/worker.json
|
|
46
|
+
harnex artifact-report validate .harnex/reports/worker.json --final
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`init` writes a schema-valid in-progress skeleton (`--force` replaces an
|
|
50
|
+
existing file). `validate` emits bounded machine-readable field diagnostics;
|
|
51
|
+
`--final` additionally requires accepted/no-change final proof and successful
|
|
52
|
+
validation records.
|
|
53
|
+
|
|
35
54
|
### `harnex send` — Talk to a running agent
|
|
36
55
|
|
|
37
56
|
```bash
|
data/guides/01_dispatch.md
CHANGED
|
@@ -22,6 +22,9 @@ Inside a harnex-managed session, these environment variables are available:
|
|
|
22
22
|
| `HARNEX_SESSION_REPO_ROOT` | Repo root for the session |
|
|
23
23
|
| `HARNEX_SESSION_ID` | Internal harnex instance ID |
|
|
24
24
|
| `HARNEX_SPAWNER_PANE` | Tmux pane ID of the invoker |
|
|
25
|
+
| `HARNEX_ARTIFACT_REPORT_PATH` | Absolute configured proof-sidecar path |
|
|
26
|
+
| `HARNEX_ARTIFACT_REPORT_SCHEMA` | Required sidecar schema identifier |
|
|
27
|
+
| `HARNEX_ARTIFACT_REPORT_REQUIRED` | `1` when report proof is fail-closed |
|
|
25
28
|
|
|
26
29
|
Use `harnex send`, `harnex status`, `harnex wait`, `harnex pane`, and
|
|
27
30
|
`harnex logs` to coordinate with peers. If you are not inside harnex,
|
|
@@ -64,9 +67,14 @@ harnex run pi --id pi-i-NN --tmux pi-i-NN \
|
|
|
64
67
|
```
|
|
65
68
|
|
|
66
69
|
For one-shot context dispatches that should clean themselves up, add
|
|
67
|
-
`--auto-stop`. It requires `--context
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
`--auto-stop`. It requires `--context` and does not keep the session alive for
|
|
71
|
+
later reuse. On Codex app-server, a turn launched from `--context` is accepted
|
|
72
|
+
only after structured command/tool activity, Git delta, or fresh
|
|
73
|
+
accepted/no-change sidecar proof. A prose-only acknowledgment emits
|
|
74
|
+
`completed_no_activity`, is
|
|
75
|
+
visible as `task_failed` before teardown, and exits non-zero. This keeps
|
|
76
|
+
parallel orchestration compact without converting agent turn completion into
|
|
77
|
+
accepted work completion:
|
|
70
78
|
|
|
71
79
|
```bash
|
|
72
80
|
for i in 1 2 3; do
|
|
@@ -96,20 +104,32 @@ harnex run codex --cwd /tmp/leximaze_eval_run_001 \
|
|
|
96
104
|
child process cwd. Neither flag is a sandbox.
|
|
97
105
|
|
|
98
106
|
For queue closeout, ask workers to write a compact sidecar in addition to their
|
|
99
|
-
plain-text `koder/` artifact
|
|
107
|
+
plain-text `koder/` artifact. For blind/unattended work, initialize and require
|
|
108
|
+
the report so a normal final answer cannot bypass proof acceptance:
|
|
100
109
|
|
|
101
110
|
```bash
|
|
111
|
+
harnex artifact-report init .harnex/reports/pi-i-NN.json
|
|
102
112
|
harnex run pi --id pi-i-NN --tmux pi-i-NN \
|
|
103
113
|
--artifact-report .harnex/reports/pi-i-NN.json \
|
|
104
|
-
--
|
|
114
|
+
--require-artifact-report \
|
|
115
|
+
--context 'Update the canonical koder file, finalize $HARNEX_ARTIFACT_REPORT_PATH, then run harnex artifact-report validate "$HARNEX_ARTIFACT_REPORT_PATH" --final' \
|
|
105
116
|
--auto-stop
|
|
106
117
|
```
|
|
107
118
|
|
|
108
119
|
The worker should keep the full explanation in `koder/` and put only compact
|
|
109
|
-
machine-readable proof in the sidecar:
|
|
110
|
-
artifact summaries (`finding`,
|
|
111
|
-
confidence, and canonical refs.
|
|
112
|
-
|
|
120
|
+
machine-readable proof in the sidecar: an `accepted` or `no_change` outcome,
|
|
121
|
+
validation command/status/exit codes, typed artifact summaries (`finding`,
|
|
122
|
+
`review`, `gate`, `blocker`, etc.), evidence, confidence, and canonical refs.
|
|
123
|
+
`harnex artifact-report validate PATH` checks the schema without echoing report
|
|
124
|
+
payloads; `--final` additionally requires accepted final proof and
|
|
125
|
+
`validation.final_reported=true`.
|
|
126
|
+
|
|
127
|
+
Without `--require-artifact-report`, missing/malformed reports remain warning
|
|
128
|
+
telemetry. Strict mode fails closed for missing, malformed, unsupported,
|
|
129
|
+
oversized, schema-incomplete, rejected, or unchanged stale reports. JSON in the
|
|
130
|
+
agent's final prose does not count: only the configured sidecar path is read.
|
|
131
|
+
A fresh valid `no_change` report is the explicit proof path for intentional
|
|
132
|
+
no-delta work.
|
|
113
133
|
|
|
114
134
|
Queue runners should pass first-class attribution so dispatch rows can be grouped
|
|
115
135
|
without path/id heuristics:
|
data/guides/04_monitoring.md
CHANGED
|
@@ -23,9 +23,12 @@ For unattended monitors on existing visible/detached sessions, prefer
|
|
|
23
23
|
exits `0`, failed work exits non-zero, and wall-clock caps exit `124`. For
|
|
24
24
|
callers that need the lower-level primitive, `harnex wait --until done` exposes
|
|
25
25
|
the same work fence. For structured sessions (Pi RPC and Codex app-server),
|
|
26
|
-
`harnex wait --until task_complete` remains the exact
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
`harnex wait --until task_complete` remains the exact accepted-turn fence.
|
|
27
|
+
Codex acknowledgment-only auto-stop turns are typed
|
|
28
|
+
`completed_no_activity` and fail this fence without transcript parsing.
|
|
29
|
+
`--require-artifact-report` can additionally make sidecar shape/final-proof
|
|
30
|
+
acceptance part of the verdict. Harnex still does not judge semantic quality;
|
|
31
|
+
verify the expected artifact or tests afterward.
|
|
29
32
|
|
|
30
33
|
## Completion Test
|
|
31
34
|
|
|
@@ -103,8 +106,11 @@ harnex watch --id pi-i-NN --until done --max-wait 90m \
|
|
|
103
106
|
```
|
|
104
107
|
|
|
105
108
|
If that exits `124`, inspect the pane/logs/events and decide whether to nudge,
|
|
106
|
-
stop, or continue. If it exits any other non-zero code,
|
|
107
|
-
|
|
109
|
+
stop, or continue. If it exits any other non-zero code, inspect
|
|
110
|
+
`outcome_class` / `artifact_report_status` in the JSON or fail marker, treat the
|
|
111
|
+
work as failed, and do not continue polling the same task as though it were
|
|
112
|
+
still running. `completed_no_activity`, `report_missing`, `report_invalid`, and
|
|
113
|
+
`report_rejected` are work-acceptance failures rather than successful turns.
|
|
108
114
|
|
|
109
115
|
Recommended caps:
|
|
110
116
|
|
data/lib/harnex/adapters/base.rb
CHANGED
|
@@ -73,6 +73,22 @@ module Harnex
|
|
|
73
73
|
{}
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
+
# Whether this adapter has a supported source for token/cost telemetry.
|
|
77
|
+
# A supported source can still be missing for a particular run.
|
|
78
|
+
def usage_telemetry_supported?
|
|
79
|
+
false
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Whether this adapter exposes active context-window occupancy separately
|
|
83
|
+
# from cumulative usage. Supported sources can still yield no valid sample.
|
|
84
|
+
def context_telemetry_supported?
|
|
85
|
+
false
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def context_telemetry_source
|
|
89
|
+
nil
|
|
90
|
+
end
|
|
91
|
+
|
|
76
92
|
def send_wait_seconds(submit:, enter_only:)
|
|
77
93
|
0.0
|
|
78
94
|
end
|
|
@@ -74,6 +74,18 @@ module Harnex
|
|
|
74
74
|
"openai"
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
+
def usage_telemetry_supported?
|
|
78
|
+
true
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def context_telemetry_supported?
|
|
82
|
+
true
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def context_telemetry_source
|
|
86
|
+
"codex_thread_token_usage_last"
|
|
87
|
+
end
|
|
88
|
+
|
|
77
89
|
def base_command
|
|
78
90
|
["codex", "app-server"]
|
|
79
91
|
end
|
data/lib/harnex/adapters/pi.rb
CHANGED
|
@@ -31,6 +31,10 @@ module Harnex
|
|
|
31
31
|
@write_mutex = Mutex.new
|
|
32
32
|
@summary_mutex = Mutex.new
|
|
33
33
|
@session_summary = {}
|
|
34
|
+
@context_telemetry = ContextTelemetry.new(
|
|
35
|
+
status: "observed",
|
|
36
|
+
source: context_telemetry_source
|
|
37
|
+
)
|
|
34
38
|
@model = nil
|
|
35
39
|
@provider = nil
|
|
36
40
|
@session_stats_requested = false
|
|
@@ -49,6 +53,18 @@ module Harnex
|
|
|
49
53
|
@model
|
|
50
54
|
end
|
|
51
55
|
|
|
56
|
+
def usage_telemetry_supported?
|
|
57
|
+
true
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def context_telemetry_supported?
|
|
61
|
+
true
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def context_telemetry_source
|
|
65
|
+
"pi_get_session_stats"
|
|
66
|
+
end
|
|
67
|
+
|
|
52
68
|
def base_command
|
|
53
69
|
["pi", "--mode", "rpc"]
|
|
54
70
|
end
|
|
@@ -147,11 +163,17 @@ module Harnex
|
|
|
147
163
|
|
|
148
164
|
def request_session_stats_async
|
|
149
165
|
return if @closed
|
|
150
|
-
return if @session_stats_requested
|
|
151
166
|
|
|
152
|
-
|
|
167
|
+
should_request = @summary_mutex.synchronize do
|
|
168
|
+
next false if @session_stats_requested
|
|
169
|
+
|
|
170
|
+
@session_stats_requested = true
|
|
171
|
+
end
|
|
172
|
+
return unless should_request
|
|
173
|
+
|
|
153
174
|
write_line("type" => "get_session_stats")
|
|
154
175
|
rescue StandardError
|
|
176
|
+
clear_session_stats_request
|
|
155
177
|
nil
|
|
156
178
|
end
|
|
157
179
|
|
|
@@ -181,8 +203,10 @@ module Harnex
|
|
|
181
203
|
agent_session_id: @session_summary[:agent_session_id],
|
|
182
204
|
tool_calls: @session_summary[:tool_calls],
|
|
183
205
|
cost_usd: @session_summary[:cost_usd],
|
|
206
|
+
cost_source: @session_summary[:cost_source],
|
|
184
207
|
model: @session_summary[:model],
|
|
185
|
-
agent_provider: @session_summary[:agent_provider]
|
|
208
|
+
agent_provider: @session_summary[:agent_provider],
|
|
209
|
+
context: @context_telemetry.snapshot
|
|
186
210
|
}
|
|
187
211
|
end
|
|
188
212
|
end
|
|
@@ -263,8 +287,7 @@ module Harnex
|
|
|
263
287
|
end
|
|
264
288
|
|
|
265
289
|
def attempt_live_summary_refresh
|
|
266
|
-
|
|
267
|
-
absorb_session_stats(response)
|
|
290
|
+
request("type" => "get_session_stats")
|
|
268
291
|
rescue StandardError
|
|
269
292
|
nil
|
|
270
293
|
end
|
|
@@ -338,6 +361,8 @@ module Harnex
|
|
|
338
361
|
@state = :prompt
|
|
339
362
|
@last_completed_at = Time.now
|
|
340
363
|
request_session_stats_async
|
|
364
|
+
when "compaction_end"
|
|
365
|
+
request_session_stats_async
|
|
341
366
|
when "message_end"
|
|
342
367
|
absorb_model_from_message(message["message"])
|
|
343
368
|
end
|
|
@@ -362,6 +387,8 @@ module Harnex
|
|
|
362
387
|
return unless data.is_a?(Hash)
|
|
363
388
|
|
|
364
389
|
tokens = data["tokens"] || {}
|
|
390
|
+
context_usage = data["contextUsage"]
|
|
391
|
+
context_usage = {} unless context_usage.is_a?(Hash)
|
|
365
392
|
@summary_mutex.synchronize do
|
|
366
393
|
@session_summary[:input_tokens] = numeric_or_nil(tokens["input"])
|
|
367
394
|
@session_summary[:output_tokens] = numeric_or_nil(tokens["output"])
|
|
@@ -369,10 +396,24 @@ module Harnex
|
|
|
369
396
|
@session_summary[:total_tokens] = numeric_or_nil(tokens["total"])
|
|
370
397
|
@session_summary[:tool_calls] = numeric_or_nil(data["toolCalls"])
|
|
371
398
|
@session_summary[:cost_usd] = float_or_nil(data["cost"])
|
|
399
|
+
@session_summary[:cost_source] = "provider_reported" unless @session_summary[:cost_usd].nil?
|
|
372
400
|
@session_summary[:agent_session_id] = data["sessionId"] if data["sessionId"]
|
|
373
401
|
@session_summary[:model] = @model if @model
|
|
374
402
|
@session_summary[:agent_provider] = @provider if @provider
|
|
403
|
+
@context_telemetry.record(
|
|
404
|
+
tokens: context_usage["tokens"],
|
|
405
|
+
window_tokens: context_usage["contextWindow"],
|
|
406
|
+
percent: context_usage["percent"]
|
|
407
|
+
)
|
|
375
408
|
end
|
|
409
|
+
ensure
|
|
410
|
+
clear_session_stats_request
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
def clear_session_stats_request
|
|
414
|
+
@summary_mutex.synchronize { @session_stats_requested = false }
|
|
415
|
+
rescue StandardError
|
|
416
|
+
@session_stats_requested = false
|
|
376
417
|
end
|
|
377
418
|
|
|
378
419
|
def absorb_model_from_message(message)
|