Skip to content

Three diagnostics-and-defaults fixes in the stream and provider path - #780

Merged
yogthos merged 2 commits into
mainfrom
vpma-stream-provider
Aug 15, 2026
Merged

Three diagnostics-and-defaults fixes in the stream and provider path#780
yogthos merged 2 commits into
mainfrom
vpma-stream-provider

Conversation

@yogthos

@yogthos yogthos commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

The tool-call gap timeout reported the residual budget its last wait
happened to get, not how long the provider was actually silent. When the
gap window drained between iterations — an ordinary slow consumer, since
the generator sits parked at its yield while the clock runs — the wait
got the 1ms clamp and the message read "timed out after 0s ... the
harness narrows to 60s" in a single sentence. as_secs truncating made
even the normal case read 59s for a full 60s window. It now reports the
measured stall, rounded. The gap budget also moves onto the runtime
clock, which is the one that actually spends it; two clocks measuring
one window can only disagree.

The wire dump's reasoning flag was additional_params.is_some(), which is
true for a tool_choice gate or a metadata map with thinking off, so
turns got labelled reasoning-enabled while sending no reasoning params.
The params and the flag are now the same decision.

DeepSeek, GLM, Cerebras, OpenCode and Kimi each restated their default
endpoint as an unwrap_or at client construction, duplicating the
resolver's table. Four of the five were unreachable, so they were free
to drift; and had the resolver ever stopped answering, the stale copy
would have become the live endpoint silently. One table now, and a
missing endpoint fails the build naming the provider instead of
defaulting to rig's assumption — for the OpenAI-compatible clients, the
wrong host holding the wrong key.

Closes dirge-vpma.24, dirge-vpma.26, dirge-vpma.27

Yogthos added 2 commits August 14, 2026 19:37
The tool-call gap timeout reported the residual budget its last wait
happened to get, not how long the provider was actually silent. When the
gap window drained between iterations — an ordinary slow consumer, since
the generator sits parked at its yield while the clock runs — the wait
got the 1ms clamp and the message read "timed out after 0s ... the
harness narrows to 60s" in a single sentence. as_secs truncating made
even the normal case read 59s for a full 60s window. It now reports the
measured stall, rounded. The gap budget also moves onto the runtime
clock, which is the one that actually spends it; two clocks measuring
one window can only disagree.

The wire dump's reasoning flag was additional_params.is_some(), which is
true for a tool_choice gate or a metadata map with thinking off, so
turns got labelled reasoning-enabled while sending no reasoning params.
The params and the flag are now the same decision.

DeepSeek, GLM, Cerebras, OpenCode and Kimi each restated their default
endpoint as an unwrap_or at client construction, duplicating the
resolver's table. Four of the five were unreachable, so they were free
to drift; and had the resolver ever stopped answering, the stale copy
would have become the live endpoint silently. One table now, and a
missing endpoint fails the build naming the provider instead of
defaulting to rig's assumption — for the OpenAI-compatible clients, the
wrong host holding the wrong key.

Closes dirge-vpma.24, dirge-vpma.26, dirge-vpma.27
…r twice

Reported live: the final answer rendered twice with the dim
"repaired 0 input(s): ; 1 invalid" line between the copies. It looks
like the old scavenged-tool-call duplicate but is unrelated — it is a
render bug, and the repair line is what triggers it.

Renderer::stream is handed the WHOLE accumulated response every time
and replaces the open block at the buffer tail, but only while
`streaming`. write_line seals that block, and the repair-stats summary
is emitted once per run immediately before AgentEnd — only when a repair
fired or an input was invalid, which is why the duplicate tracks the
"N invalid" line. handle_done then re-streams the response to commit it
as one reflowable markdown block, takes the sealed branch, and pushes a
second block holding the whole answer.

The renderer now remembers the committed part of the current logical
stream and renders only the remainder, so a re-stream after a seal is a
no-op and text arriving after one appends. end_stream() seals and clears
that, wired where the response buffer is already cleared: done,
tool_call, interjected, error, context_overflow, the reasoning marker
and the notice path. Without it a turn repeating the previous answer
verbatim would render as nothing — which is the exact case this was
reported from, so there is a test for it.

Also from the review of #779: land the vpma.22 regression test (the one
fix that shipped without its discriminating test — verified here by
mutation, red with the fix reverted), correct the LoopConfig api_key /
get_api_key docs, which still advertise per-request OAuth resolution
that vpma.25 removed, and drop a redundant rebind in rig_stream.

Closes dirge-fw0p
@yogthos
yogthos merged commit 6d5e22e into main Aug 15, 2026
15 checks passed
@yogthos
yogthos deleted the vpma-stream-provider branch August 15, 2026 00:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant