Skip to content

fix(conversations): clear closed agent status#2662

Open
janburzinski wants to merge 2 commits into
mainfrom
emdash/closed-agents-marked-running-wlnuo
Open

fix(conversations): clear closed agent status#2662
janburzinski wants to merge 2 commits into
mainfrom
emdash/closed-agents-marked-running-wlnuo

Conversation

@janburzinski

Copy link
Copy Markdown
Collaborator

Description

  • clears stale agent activity indicators when a closed conversation session is dehydrated
  • resets working and awaiting-input statuses to idle on session exit
  • keeps completed/error badges intact on unseen results

Screenshot/Recording (if applicable)

https://streamable.com/oett2n

Checklist
  • I kept this PR small and focused
  • I ran a self-review before opening this PR
  • I ran the relevant local checks or explained why not
  • I updated docs when behavior or setup changed
  • I added or updated tests when behavior changed, or explained why not
  • I only added comments where the logic is not obvious
  • I used Conventional Commits for commit
    messages and, when possible, the PR title

@greptile-apps

greptile-apps Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes stale agent activity indicators by making detachSession return a boolean indicating whether the agent was actually terminated, and wiring that signal through dehydrateConversation to conditionally emit agentSessionExitedChannel. It also broadens the status-reset logic in AgentHookService to cover awaiting-input in addition to working.

  • detachSession return type — both LocalConversationProvider and SshConversationProvider now return false for tmux-backed sessions and true for plain PTY sessions.
  • dehydrateConversation — the agentSessionExitedChannel emit is now conditional on terminatedAgent === true, preventing live tmux agents from having their status reset.
  • AgentHookServiceshouldResetAgentStatusOnSessionExit is extracted and exported, broadening the guard from === 'working' to a set that also includes 'awaiting-input', with accompanying unit tests.

Confidence Score: 5/5

Safe to merge — the change is tightly scoped and correctly addresses the stale-indicator bug without regressing tmux sessions.

The boolean return from detachSession cleanly encodes whether the agent was actually terminated, and dehydrateConversation gates the event emit on that signal. The tmux guard (return false) prevents any status reset for live tmux agents. The AgentHookService listener is idempotent, both implementation classes and the interface are consistently updated, and the new unit tests cover the critical conditional paths.

No files require special attention.

Important Files Changed

Filename Overview
apps/emdash-desktop/src/main/core/conversations/dehydrateConversation.ts Conditional emit of agentSessionExitedChannel based on detachSession return value; correctly avoids resetting live tmux agents.
apps/emdash-desktop/src/main/core/conversations/impl/local-conversation.ts detachSession now returns false for tmux paths, true for plain-PTY paths; logic is unchanged, only the return type and value differ.
apps/emdash-desktop/src/main/core/conversations/impl/ssh-conversation.ts Mirrors local-conversation.ts changes: detachSession returns boolean indicating whether the SSH agent was terminated.
apps/emdash-desktop/src/main/core/agent-hooks/agent-hook-service.ts Extracts shouldResetAgentStatusOnSessionExit helper and broadens the reset guard to cover awaiting-input in addition to working.
apps/emdash-desktop/src/main/core/conversations/types.ts Interface updated to reflect Promise return type for detachSession; correctly propagated.
apps/emdash-desktop/src/main/core/conversations/dehydrateConversation.test.ts New test file covering both the emit and no-emit paths for dehydrateConversation; thorough coverage of the conditional logic.
apps/emdash-desktop/src/main/core/agent-hooks/agent-hook-service.test.ts Tests for shouldResetAgentStatusOnSessionExit correctly assert that working/awaiting-input reset and idle/completed/error/null do not.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant UI as Renderer (tab close)
    participant DC as dehydrateConversation
    participant LP as LocalConversationProvider
    participant EV as events (agentSessionExitedChannel)
    participant AHS as AgentHookService

    UI->>DC: dehydrateConversation(projectId, taskId, convId)
    DC->>LP: detachSession(convId)
    alt tmux session
        LP-->>DC: false (agent still running in tmux)
        DC-->>UI: (no emit)
    else plain PTY
        LP->>LP: detachPty() to pty.kill()
        LP->>LP: knownSessionIds.delete() + supervisor.forget()
        LP-->>DC: true (agent terminated)
        DC->>EV: emit agentSessionExitedChannel
        EV->>AHS: listener fires
        AHS->>AHS: shouldResetAgentStatusOnSessionExit(status)?
        alt status is working or awaiting-input
            AHS->>AHS: UPDATE agentStatus to idle
            AHS->>EV: emit conversationAgentStatusChangedChannel idle
        else status is idle/completed/error/null
            AHS-->>AHS: no-op
        end
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant UI as Renderer (tab close)
    participant DC as dehydrateConversation
    participant LP as LocalConversationProvider
    participant EV as events (agentSessionExitedChannel)
    participant AHS as AgentHookService

    UI->>DC: dehydrateConversation(projectId, taskId, convId)
    DC->>LP: detachSession(convId)
    alt tmux session
        LP-->>DC: false (agent still running in tmux)
        DC-->>UI: (no emit)
    else plain PTY
        LP->>LP: detachPty() to pty.kill()
        LP->>LP: knownSessionIds.delete() + supervisor.forget()
        LP-->>DC: true (agent terminated)
        DC->>EV: emit agentSessionExitedChannel
        EV->>AHS: listener fires
        AHS->>AHS: shouldResetAgentStatusOnSessionExit(status)?
        alt status is working or awaiting-input
            AHS->>AHS: UPDATE agentStatus to idle
            AHS->>EV: emit conversationAgentStatusChangedChannel idle
        else status is idle/completed/error/null
            AHS-->>AHS: no-op
        end
    end
Loading

Reviews (2): Last reviewed commit: "fix(conversations): preserve tmux agent ..." | Re-trigger Greptile

Comment thread apps/emdash-desktop/src/main/core/conversations/dehydrateConversation.ts Outdated
@janburzinski

Copy link
Copy Markdown
Collaborator Author

@greptileai

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