Skip to content

[Bug]: Claude thread's send button stays disabled after a completed turn — provider_session_runtime.activeTurnId not cleared on turn.completed #14428

Description

@eli-jordan

Summary

After a Claude Agent turn completed normally, the thread's composer send button stayed disabled. The thread projection shows the turn as completed and the session as ready, but the persisted provider runtime still records the finished turn as active.

Version / environment

  • T3 Code 0.0.43-nightly.20260929.2428 (Electron, Windows 10 Pro 19045)
  • Provider: claudeAgent, model claude-sonnet-5 (effort medium, context 200k), runtime mode full-access
  • Thread in a T3 worktree; 3 turns, all completed without error

What happened

  1. Sent the 3rd message in the thread (turn c7d3b361…, sent 13:01:18Z).
  2. The turn streamed and finished normally; the provider log shows result (subtype: success, stopReason: end_turn), then turn.completed (13:02:14.353Z), then command_lifecycle: completed.
  3. The send button then stayed disabled. There were no pending approvals, user-input requests or actionable plans (all counts 0), and no lastError.

Persisted state afterwards (state.sqlite)

Table State
projection_turns (turn c7d3b361…) state: completed, completed_at: 13:02:14.349Z, checkpoint ready
projection_thread_sessions status: ready, active_turn_id: null, last_error: null
projection_threads latest_turn_id: c7d3b361…, pending_approval_count: 0, pending_user_input_count: 0
provider_session_runtime status: running, runtime_payload_json.activeTurnId: "c7d3b361…", lastRuntimeEvent: "provider.sendTurn", lastRuntimeEventAt: 13:01:18.719Z, last_seen_at: 13:02:14.351Z

last_seen_at was updated at completion time, but activeTurnId and lastRuntimeEvent still hold the values from when the turn was sent. It looks like the runtime payload isn't updated on turn.completed, or a later write overwrites it with a stale copy.

Of the 27 threads with a runtime row, this was the only one where the projection said ready and the runtime still had an activeTurnId. The other rows were either stopped with no active turn, or running with a turn that really was in progress.

Expected

On turn.completed, clear activeTurnId in the persisted runtime payload (and in any in-memory copy) so the thread accepts new messages.

Workaround

With T3 Code running, I set runtime_payload_json.activeTurnId to null for that thread, after backing up the database. The in-memory server state is presumably still stale, so restarting the app is probably also needed. I didn't want to restart because another thread had a turn in progress.

Possibly related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions