reconcile provider session state and settle stuck turns#2666
reconcile provider session state and settle stuck turns#2666justsomelegs wants to merge 17 commits into
Conversation
|
React Review found Copy prompt for agentReviewed by react-review for commit d2742fc. Configure here. |
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ApprovabilityVerdict: Needs human review This PR introduces new runtime behavior for reconciling provider session state on startup and automatically settling stuck turns. Changes to state machine transitions and startup recovery logic warrant human review. You can customize Macroscope's approvability policy. Learn more. |
|
@justsomelegs I've built and ran dist:desktop:dmg version and it still hangs on waiting, while the session on opencode is completed
but I am able to end a chat session now so I think your change only fixed a local state of event cycle ingestion
|
|
@eersnington it was subscribing to the wrong event stream as the client.subscribe.event() has been broken upstream and the current fix it to subscribe to the global.event.subscribe() method made the change and it should now work. |
|
tbh as its an upstream issue it will most likley be fixed as the client event stream seems to just drop after the |
This reverts commit 9b21444.
|
i've undone the event stream change as its an upstream provider issue so i assume the issue will get fixed by opencode. its out of scope for my PR and no point adding a temp workaround if its gonna be fixed |
@justsomelegs Apologies Mr Legs, but I've gotten bit busy while also looking into the issue myself. And yes they seemed to have change changed the event stream from a repo scoped event.stream to a global.events that has { directory, payload }. OpenCode itself moved its own CLI to client.global.event(), so client.event.subscribe() may be legacy. Will test out your change and compare it to mine at eersnington#1
Ig, but right now users with OpenCode >0.14.40 will not be able to use T3 code |
|
@eersnington no problem at all :)
yeah true but there is already a PR open (#2673) for it so felt best to keep this PR scoped to bad session recovery states |
I agree, which is also why I'm keeping that PR in my fork as I've ran into a bunch more issues with steering prompts, and stale recovery. That way I can use a local build version of this. |
|
#2673 is great but IMO, it should also handle the older /event stream consumption so that people on older versions of OpenCode (<=0.14.40) won't be majorly surprised when they update T3 Code and their adapter breaks. Due to this bug, a lot people within the issue threads have downgraded their OpenCode install too |
|
could be a good PR to submit 👀 not at my computer at the moment otherwise i would submit it as a PR |
I've went ahead and did it Mr Legs #2704 |


What Changed
Fixes several provider session / turn lifecycle cases where T3 Code could leave a thread in the wrong state after provider runtime events, interrupts, stop failures, or server restart.
Main changes:
Treat active
turn.completedevents as lifecycle-ending events:readyerroractiveTurnIdis clearedTreat active
turn.abortedevents as lifecycle-ending events:readyactiveTurnIdis clearedIgnore completion/abort events for non-active turns so auxiliary provider work, like OpenCode title generation, does not incorrectly stop the main running turn.
Reconcile projected running sessions on server startup:
Make
thread.session.stopnon-destructive on provider stop failure:lastErrorPreserve failed turn state in server and web projections:
errorsettle the latest running turn aserrorinterruptedFix OpenCode adapter interrupt handling:
readyturn.abortedeventWhy
A few different provider lifecycle paths were being treated too loosely.
The main symptom was that a thread could stay stuck as “working” even after the provider had already finished, aborted, or lost the active session. This was especially visible with OpenCode, but the underlying fixes are in shared provider orchestration and projection code, so they apply more broadly than just OpenCode.
This approach keeps the existing event model, but makes the lifecycle rules stricter:
Fixes #2644
Fixes #2633
Fixes #2573
UI Changes
No UI changes.
Testing
bun run test src/orchestration/Layers/ProviderRuntimeIngestion.test.ts src/orchestration/Layers/ProjectionPipeline.test.ts src/orchestration/Layers/ProviderCommandReactor.test.ts src/provider/Layers/OpenCodeAdapter.test.tsbun run test src/store.test.tsbun fmtbun lintbun typecheckbun lintpasses with existing unrelated warnings.Checklist
Note
Reconcile provider session state and settle stuck running turns on stop or error
lastError, while live ready sessions are mirrored and their latest turn settled.stopped,interrupted,error), the most recent running turn is now settled tointerruptedorerrorwithcompletedAtstamped fromsession.updatedAt, both in the server projection and the web UI store.turn.abortedprovider runtime events now mark the thread session asreadyand clear the active turn, consistent withturn.completedhandling.OpenCodeAdapter.sendTurnno longer emit a spuriousturn.abortedevent;interruptTurnnow reliably emitsturn.abortedfor the correct turn and immediately reflects session state as ready.provider.session.stop.failedactivity, preserve the running state, and surfacelastError.Macroscope summarized c497da5.