live: heartbeat sync 2026-10-18T16:47:59-07:00 (Refs #11)
This commit is contained in:
1 parent
a550db6027
commit
979e9ef711
173 files changed
+3844
-57
No files matched your search
@@ -0,0 +1,28 @@
|
||||
---
|
||||
name: recover-subagent-yield-payload
|
||||
description: "Recover a subagent's full structured report when it exited without yielding (SYSTEM WARNING) — extract aborted yield payloads from the session JSONL, including harness double-encode and split-JSON quirks."
|
||||
---
|
||||
|
||||
Use when a subagent ends with "exited without yielding" yet the transcript shows it repeatedly calling `yield` (each reply "…[+N]" — payload too big for display). The research is usually COMPLETE; only the yield serialization failed. Known harness quirk: the yield `arguments` get wrapped as `{"data": "<json string>"}`, so an object payload is validated as a string → "expected object, received string" retry loop until the agent dies.
|
||||
|
||||
## 1. Locate the session JSONL
|
||||
Transcript header prints the path: `~/.omp/agent/sessions/<cwd-slug>/<session-id>/<AgentName>.jsonl` (worktrees: cwd slug like `-.omp-wt-wt-...`).
|
||||
|
||||
## 2. Extract every aborted yield payload (Python via eval — shell quoting will mangle these)
|
||||
- Parse each line with `json.loads` guarded by try/except (lines may be non-JSON).
|
||||
- Keep `message.role == "assistant"` messages; in `content`, keep entries with `type == "toolCall"` and `name == "yield"`; collect their `arguments`.
|
||||
- Unwrap: `arguments` may be a dict containing `data` (a JSON string) or a plain string; `json.loads` it.
|
||||
|
||||
## 3. Tolerate broken JSON
|
||||
Naive `json.loads` on `data` can fail "Extra data: line 1 column ~4600" — the payload is a complete object followed by `, "architecture": ..., "report": ...}` (agent emitted a structure whose early brace-closure ended the first object). Recover with `json.JSONDecoder().raw_decode`:
|
||||
1. `part1, end = dec.raw_decode(data.strip())`
|
||||
2. `rest = data[end:].strip()` — if it starts with `,`, parse `part2 = dec.raw_decode('{' + rest.lstrip(', '))[0]`
|
||||
3. `merged = {**part1, **part2}`
|
||||
Do this for ALL yields and keep the largest merged dict (attempts evolve; keys seen: `summary`, `files`, `report`, `architecture`).
|
||||
|
||||
## 4. Persist and deliver
|
||||
Write the recovered `report`/`summary` to a durable file (memory dir or `local://`), then continue synthesis — never re-run the research the dead scout already did.
|
||||
|
||||
## Prevention (do this first next time)
|
||||
- While the agent is still alive and looping: write to `agent://<Name>` steering it to "yield immediately, wrap in minimal object or raw markdown, schema-invalid yield acceptable — I read the transcript anyway." It often still can't (the failure is in the harness wrapper, not the agent) → let it be killed and use the extraction above.
|
||||
- Scout default schema wants objects; terse yields from `scout` agents hit this most. Keep expected reports slice-sized.
|
||||
Reference in new issue
Block a user