Skip to content

fix(opencode2): keep the hidden child after a settled provider error - #482

Closed
qoole wants to merge 2 commits into
cortexkit:masterfrom
qoole:fix/opencode2-hidden-child-reuse-after-provider-error
Closed

qoole wants to merge 2 commits into
cortexkit:masterfrom
qoole:fix/opencode2-hidden-child-reuse-after-provider-error

Conversation

@qoole

@qoole qoole commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Fixes #481.

When every historian model fails with a provider error (for example the Go pool at its weekly quota and the Zen free tier refusing plugin requests), each failed run retired its hidden child and the next run created a new one. In practice that meant one new Magic Context historian session per trigger: 114 sessions in about 2.5 hours.

Change (packages/plugin/src/v2/hidden-completion.ts)

  • close() keeps the child when a run failed only on settled provider errors, i.e. rows the host persisted with error set, which surface as Hidden completion provider error: ….
  • open() reuses an active child whose newest assistant row is a settled provider error, in addition to a successful one. This is safe because the hidden-child hook replaces the whole draft (system, messages, tools) on every hidden prompt, so the error row never reaches a model again.
  • Unchanged: every other failure still retires the child — a thrown prompt dispatch, a refusal, a timeout, an abort. The existing test "retires an overall failed run and creates a fresh child next time" still holds.

Tests

Two new tests in hidden-completion.test.ts:

  • five runs failing on both the primary and the fallback model with provider-error rows, then a successful run: one child in total, no retired children;
  • a restarted executor reuses a child whose newest assistant is a settled provider error.

Reverting either half of the change makes both new tests fail. tsc --noEmit and biome check pass. bun test src/v2 fails the same 2 TUI-loader tests with and without this change; those need a built dist/.

A backoff so the historian stops retrying a quota-exhausted pool on every trigger would be a separate change.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Fixes #481. Previously, a historian run that failed only on settled provider errors retired its hidden child, so each trigger created a new session; with a provider at its quota, that meant one new session per trigger (114 in ~2.5 hours). Now such a child is kept and reused: the run's own failure record decides, since the caller always reports promptSettled=false after a failed attempt. This is safe because every hidden prompt replaces the child's whole draft, so the error row is never sent again. Dispatch errors, refusals, timeouts, and aborts still retire the child.

Written for commit bd99b86. Summary will update on new commits.

Review in cubic

RetriggerConfidence Score: 5/5

The PR appears safe to merge; the revised lifecycle logic fixes the provider-error reuse path while preserving retirement for unsettled failures.

Summary

The PR prevents repeated hidden-session creation when historian attempts fail exclusively with persisted provider errors.

  • Tracks whether a run encountered any genuinely unsettled failure.
  • Retains and reuses children whose latest assistant row contains a settled provider error.
  • Updates regression tests to exercise the production promptSettled: false behavior.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Hidden completion attempt] --> B{Result}
    B -->|Completion| C[Keep child]
    B -->|Persisted provider-error row| D[failed = true<br/>unsettledFailure = false]
    B -->|Dispatch, refusal, timeout, or abort| E[unsettledFailure = true]
    D --> F[Close retains child]
    E --> G[Close retires child]
    F --> H[Next open reuses child]
Loading

Reviews (2) · Last reviewed commit: "fix(opencode2): reuse the child whatever..."

A historian run that failed only on provider errors persisted as settled
assistant rows (quota, rate limit, refused request) retired its child,
and the next open() retired it again as not reusable, so a pool at its
quota produced a new hidden session per historian trigger (114 in 2.5 h
observed). The hidden-child hook replaces the child's whole draft on
every prompt, so an error row is never sent again: such a child is
reused. Dispatch failures, refusals, timeouts and aborts still retire it.

Fixes cortexkit#481
Comment thread packages/plugin/src/v2/hidden-completion.ts Outdated
…vider errors

The historian caller reports promptSettled=false after any failed
attempt, so requiring it kept every provider-error run retiring its
child in real use (observed after deploying the first version). The
run's own record that every failure was a persisted provider error row
decides; the tests now close as the caller does.
@qoole

qoole commented Sep 19, 2026

Copy link
Copy Markdown
Contributor Author

Follow-up commit bd99b86: in real use the historian caller reports promptSettled: false after any failed attempt, so the first version (which also required promptSettled) still retired the child on every provider-error run. I only found this after deploying it. The run's own record, that every failure was a persisted provider error row, now decides on its own. The two new tests now close the run the way the caller does (promptSettled: false), and they fail against the first version.

@qoole

qoole commented Sep 20, 2026

Copy link
Copy Markdown
Contributor Author

Landed on main in 991a3ad as part of the issue 481 merge, reimplemented on top of that work with a typed HiddenProviderError and a finish check on the settled predicate, rather than this branch's message-prefix check. Closing — thanks for folding it in.

For anyone hitting this before the next release: 0.42.6 is the latest on npm and still retires the hidden child on every provider error, so the sessions keep piling up until the fix ships.

@qoole qoole closed this Sep 20, 2026
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.

OpenCode 2: every failed historian run leaves a new hidden session behind (114 in 2.5 h with a quota-exhausted provider)

1 participant