Repository navigation
Description
Finding
bin/agy-proxy.mjs reports a failed agy run as a successful completion in most shapes:
- Stream mode — the
child.on('close', code => ...)handler (bin/agy-proxy.mjs:467) checkscodeonly for the resume-retry case (code !== 0 && !hasOutput && allowRetry && targetConvId, :471). Every other non-zero exit falls through to the unconditional success ending at :481-510: a chunk withfinish_reason: 'stop'plusdata: [DONE]. ThestderrBuffercollected at :463-465 is never read anywhere in the stream path, so the failure cause is discarded entirely. - Non-stream mode — the failure branch is gated on empty output (
if (code !== 0 && !responseText), :553), so a run that fails after producing a partial response returns HTTP 200 withfinish_reason: 'stop'and the truncated text. (This is the sighting noted for separate judgement in muse-proxy: a run that fails after producing partial output is reported as a successful 'stop' — failure is masked whenever any content exists #672; the stream half above was not covered there or anywhere else.)
This is the agy-proxy counterpart of the defects already fixed in the sibling bin/muse-proxy.mjs (#670, #672, #674) and bin/codex-proxy.mjs (#676): a failed run presented as a clean stop.
Evidence (reproduced on main 4b85ef69)
Ran bin/agy-proxy.mjs with a stub agy at $HOME/.local/bin/agy (the proxy's own binary resolution) whose behaviour keys on the requested --output-format:
- Stub prints
stub agy: auth expiredto stderr and exits 3, no stdout:- stream: HTTP 200, one chunk with
finish_reason: "stop", thendata: [DONE]— no error anywhere - non-stream: HTTP 502
{"error":"agy process exited with non-zero code","code":3,"stderr":"stub agy: auth expired"}(correct — the control case)
- stream: HTTP 200, one chunk with
- Stub emits one
step_updatetext delta (partial answer) /{"response":"partial answer"}, printsstub agy: run failed midwayto stderr, exits 3:- stream: HTTP 200, content chunk
partial answer, then afinish_reason: "stop"chunk +[DONE] - non-stream: HTTP 200,
content: "partial answer",finish_reason: "stop"
- stream: HTTP 200, content chunk
- Stub success case (delta +
resultevent /{"response":"full answer"}, exit 0) correctly returns 200 with the full text andstopin both modes.
Dedup: searches for "agy-proxy" / "agy" across open and closed issues return only #434/#435/#437/#483/#661/#672 — #672 notes the non-stream gate at :553 as "judge separately" and explicitly excludes it from its acceptance criteria; none covers the stream handler or failure detection in this proxy. Cross-repo: bin/agy-proxy.mjs exists only in this repo (no copy in developing-today/opencode, developing-today/openchamber, dezren39/nix).
Why it matters
OpenCode consumes this bridge in streaming mode as a provider. A failed agy run (expired auth, CLI crash, model rejection) presented as a clean stop with empty or truncated text is worse than an error: downstream code and users treat it as the complete answer, and an auth expiry presents as "the model said nothing" instead of a diagnosable failure. The two modes also disagree with each other — and with the proxy's own correct empty-output non-stream case (502 with stderr).
Acceptance criteria
- A child that exits non-zero (or is killed by a signal —
codeisnullthen) is reported as a failure in both modes, regardless of how much content was already produced: non-stream returns an error status (the existing 502 shape, with stderr, is fine) instead of 200/stop; stream mode emits adata:-framed error event naming the failure (last stderr line when present) followed bydata: [DONE], and no chunk claimsfinish_reason: "stop". - The resume-retry behaviour is preserved: a failed resume (
code !== 0, no output, a conversation was being resumed) still retries once as a fresh conversation before any failure is reported. - Successful runs (exit 0) are unchanged in both modes.
- A regression test with a stub
agy(fail-with-no-output and fail-after-partial-output cases, both modes — thebin/codex-proxy.test.mjs/bin/muse-proxy.test.mjsstub pattern; there is currently nobin/agy-proxy.test.mjs) passes; the existing proxy test suites still pass.
Activity
Merge pull request #679 from developing-today/creator/678-agy-proxy-f…