Skip to content

fix/active-prompt-agent-inspection - #239

Merged
omarluq merged 4 commits into
mainfrom
fix/active-prompt-agent-inspection
Jul 29, 2026
Merged

fix/active-prompt-agent-inspection#239
omarluq merged 4 commits into
mainfrom
fix/active-prompt-agent-inspection

Conversation

@omarluq

@omarluq omarluq commented Jul 29, 2026

Copy link
Copy Markdown
Owner

No description provided.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Enabled agent-task inspection routing while a parent prompt remains active.
    • Added session-view snapshot/restore so switching and returning preserves durable and transient UI state (transcripts, streaming, tools, composer, scroll/autocomplete).
  • Bug Fixes

    • Correctly delivers agent-task completion to the owning session view.
    • Improved Escape/Alt+Escape behavior during inspection, including safer interrupt/cancel logic and more accurate “working” UI rendering.
  • Tests

    • Expanded coverage for inspecting/leave/revisit flows, parent prompt interactions, completion routing, and session-view missing/availability handling.

Walkthrough

The terminal now preserves per-session UI state during agent-task inspection, routes prompt and completion events to owning sessions, supports inspection while a parent prompt runs, and applies read-only input and escape-key behavior with expanded coverage.

Changes

Prompt-aware inspection flow

Layer / File(s) Summary
Session view persistence
internal/terminal/app.go, internal/terminal/session_view.go, internal/terminal/session_view_internal_test.go
Session-scoped presentation state is saved, restored, cloned, and temporarily applied while processing events.
Agent-task session switching
internal/terminal/agent_tasks.go, internal/terminal/agent_tasks_behavior_internal_test.go
Inspection validates active prompts, preserves transient state across session changes, refreshes durable transcripts, and routes completion to the owning session.
Session-scoped async events
internal/terminal/async_events.go
Prompt lifecycle, stream, user-entry, and completion events use the relevant session view.
Read-only inspection input behavior
internal/terminal/input.go, internal/terminal/input_escape.go, internal/terminal/message_layout.go, internal/terminal/agent_tasks_behavior_internal_test.go
Priority keys, escape handling, autocomplete, interrupts, and working indicators now account for inspection during an active prompt.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Poem

I’m a rabbit hopping through session views,
Keeping prompt streams where each one belongs.
Escape twice, or Alt to leave,
Child tasks finish while parents weave—
UI state returns with carrots and songs.

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive No description was provided, so the PR summary can't be validated against it. Add a short description of the behavior changes and tests covered.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change: active prompt agent inspection behavior.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/active-prompt-agent-inspection

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.82759% with 44 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.72%. Comparing base (773eb84) to head (69dfafe).

Files with missing lines Patch % Lines
internal/terminal/agent_tasks.go 75.67% 18 Missing and 9 partials ⚠️
internal/terminal/input.go 82.25% 7 Missing and 4 partials ⚠️
internal/terminal/session_view.go 96.00% 2 Missing and 2 partials ⚠️
internal/terminal/input_escape.go 50.00% 0 Missing and 1 partial ⚠️
internal/terminal/message_layout.go 0.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #239      +/-   ##
==========================================
- Coverage   84.72%   84.72%   -0.01%     
==========================================
  Files         315      316       +1     
  Lines       29299    29550     +251     
==========================================
+ Hits        24825    25035     +210     
- Misses       3068     3096      +28     
- Partials     1406     1419      +13     
Flag Coverage Δ
unittests 84.72% <84.82%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/terminal/agent_tasks.go (1)

1631-1675: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

leaveAgentTaskSession's success path never refreshes the durable transcript.

messages is fetched via app.sessionMessages(ctx, parentSessionID) up front, but it's only consumed inside the if !app.restoreSessionView(parentSessionID) fallback branch. When restoreSessionView succeeds (the common case — the parent session was previously saved on the way into inspection), the freshly-fetched messages is discarded and the durable transcript relies entirely on whatever was captured in the in-memory sessionViews[parentSessionID] snapshot. Contrast with switchToAgentTaskSession's success branch (lines 1560-1577), which explicitly nulls app.transcript.History and re-appends fresh messages before restoring transient state. Any message persisted to the parent session's durable store through a path that doesn't route through withSessionView's save while the child is being inspected will not appear once the user returns to the parent — and this isn't covered by any existing test (TestRevisitAgentTaskSessionRefreshesDurableTranscript only exercises the equivalent refresh on the inspectAgentTask/switchToAgentTaskSession side).

🐛 Proposed fix to mirror switchToAgentTaskSession's refresh-on-restore behavior
 	app.stopAgentTaskWatches()
 	app.saveSessionView()
 	app.agentTaskSessionStack = app.agentTaskSessionStack[:last]
 
-	if !app.restoreSessionView(parentSessionID) {
+	if app.restoreSessionView(parentSessionID) {
+		promptHistory := app.promptHistory
+		promptHistoryDraft := app.promptHistoryDraft
+		promptHistoryIndex := app.promptHistoryIndex
+		app.transcript.History = nil
+		app.transcript.LineCache.reset()
+		app.appendSessionMessages(messages)
+		app.promptHistory = promptHistory
+		app.promptHistoryDraft = promptHistoryDraft
+		app.promptHistoryIndex = promptHistoryIndex
+	} else {
 		app.sessionID = parentSessionID
 		app.pendingParentID = nil
 		app.resetMessages()
 		app.resetStreamingBlocks()
 
 		if settingsFound {
 			app.applySessionSettings(&settings)
 		}
 
 		app.appendSessionMessages(messages)
 	}

Consider also adding a regression test mirroring TestRevisitAgentTaskSessionRefreshesDurableTranscript but for the leave-to-parent direction.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/terminal/agent_tasks.go` around lines 1631 - 1675, Update
leaveAgentTaskSession to refresh the durable parent transcript when
restoreSessionView(parentSessionID) succeeds, mirroring the refresh behavior in
switchToAgentTaskSession: clear the current transcript history and re-append the
freshly loaded messages before restoring transient session state. Preserve the
existing fallback behavior and add a regression test covering durable messages
added while inspecting the child before returning to the parent.
🧹 Nitpick comments (4)
internal/terminal/agent_tasks_behavior_internal_test.go (1)

1010-1183: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract shared setup for the new inspection/prompt tests.

TestActivePromptInspectionAllowsNestedTaskSelection, TestDoubleEscapeCancelsParentPromptWithoutLeavingInspection, TestAltEscapeLeavesInspectionWithoutCancelingParentPrompt, and TestActivePromptInspectionBlocksGlobalAndExtensionShortcuts all repeat the same ~15 lines of fixture/task/stub/app/activePrompt/inspectAgentTask setup nearly verbatim. Extracting a small helper (e.g. returning the fixture, app, and task with the parent prompt already active and the child already inspected) would cut duplication significantly with minimal effort.

As per coding guidelines, **/*_test.go should "Prefer table-driven tests for core behavior and regression tests for terminal rendering bugs" — a shared setup helper achieves most of the intended DRY benefit here since the individual assertions are too distinct to naturally tabulate.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/terminal/agent_tasks_behavior_internal_test.go` around lines 1010 -
1183, Extract the duplicated fixture, task, stub, runtime, active-prompt, and
inspectAgentTask setup from the four named tests into a focused test helper that
returns the fixture and initialized app (and task data if needed). Update each
test to call the helper while preserving its existing assertions, cleanup, and
test-specific configuration such as nested tasks or composer text.

Source: Coding guidelines

internal/terminal/session_view.go (1)

117-145: 🚀 Performance & Scalability | 🔵 Trivial | 🏗️ Heavy lift

Repeated full clone round-trip on every streamed event while inspecting a different session.

withSessionView fast-paths only when the target session matches the currently displayed one; whenever inspectingWhilePromptRuns() is true, every prompt delta/thinking-delta/tool event routed through handlePromptAsyncEvent (async_events.go) triggers a full saveSessionView + restoreSessionView + saveSessionView + restoreSessionView cycle, each doing multiple maps.Clone/slices.Clone/buffer clones. During active token streaming this could run many times per second. Given the project guideline to keep terminal code allocation-conscious, it's worth benchmarking this path before merge, or batching/coalescing the save/restore so it isn't paid per-delta.

Separately (minor): the doc comment on lines 117-119 sits directly above inspectingWhilePromptRuns (no blank line), but its content ("routes an event to its owning session...") documents withSessionView, not inspectingWhilePromptRuns. Consider moving it directly above withSessionView.

As per coding guidelines, "Keep the default render path hot and allocation-conscious; do not route default UI through Lua unless explicitly required and benchmarked."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/terminal/session_view.go` around lines 117 - 145, Reduce allocation
overhead in withSessionView for repeated streamed events while inspecting
another session by batching or coalescing the saveSessionView/restoreSessionView
round-trip, and benchmark the resulting prompt-event path to confirm
improvement. Move the existing routing comment directly above withSessionView,
leaving inspectingWhilePromptRuns without that unrelated documentation.

Source: Coding guidelines

internal/terminal/input.go (2)

103-103: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the duplicated read-only status string into a constant.

Static analysis flags "agent task inspection is read-only while the parent response runs" duplicated across lines 103, 136, and 260.

♻️ Proposed fix
+const readOnlyInspectionStatus = "agent task inspection is read-only while the parent response runs"
+
 func (app *App) handleModalPriorityKey(ctx context.Context, event *tcell.EventKey) keyHandlingResult {
   ...
-  app.setStatus("agent task inspection is read-only while the parent response runs")
+  app.setStatus(readOnlyInspectionStatus)
   ...
 }

Apply the same substitution at lines 136 and 260.

Also applies to: 136-136, 259-261

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/terminal/input.go` at line 103, Extract the duplicated status text
used by app.setStatus into a named package-level constant in the input handling
code, then replace the occurrences at the referenced status-update sites,
including the calls near lines 103, 136, and 260, with that constant while
preserving the exact message.

Source: Linters/SAST tools


87-139: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the unreachable read-only re-checks
handlePriorityKey() already consumes every inspectingWhilePromptRuns() path, so the guards in handleInlineListsAndExtensionKey() and handleInputKey() never fire. Fold the read-only status text into one helper to avoid keeping the same branch and message in three places.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/terminal/input.go` around lines 87 - 139, The read-only inspection
handling is duplicated and unreachable in downstream key handlers. Remove the
redundant inspectingWhilePromptRuns guards and status branches from
handleInlineListsAndExtensionKey and handleInputKey, and centralize the shared
read-only status behavior in handleReadOnlyInspectionPriorityKey while
preserving its existing inspection navigation handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/terminal/async_events.go`:
- Around line 262-273: The return value of withSessionView is ignored, allowing
events to be silently dropped when the owner view is missing. In
internal/terminal/async_events.go lines 262-273, check the result around
handlePromptLifecycleEvent and handlePromptStreamEvent and log or set a status
on failure; in internal/terminal/agent_tasks.go lines 961-963, update
deliverAgentTaskCompletion to surface failure via setStatus; and in
internal/terminal/agent_tasks.go lines 979-981, update
deliverAgentTaskCompletionEvent similarly while preserving its existing
unresolved-owner status handling.</code>

---

Outside diff comments:
In `@internal/terminal/agent_tasks.go`:
- Around line 1631-1675: Update leaveAgentTaskSession to refresh the durable
parent transcript when restoreSessionView(parentSessionID) succeeds, mirroring
the refresh behavior in switchToAgentTaskSession: clear the current transcript
history and re-append the freshly loaded messages before restoring transient
session state. Preserve the existing fallback behavior and add a regression test
covering durable messages added while inspecting the child before returning to
the parent.

---

Nitpick comments:
In `@internal/terminal/agent_tasks_behavior_internal_test.go`:
- Around line 1010-1183: Extract the duplicated fixture, task, stub, runtime,
active-prompt, and inspectAgentTask setup from the four named tests into a
focused test helper that returns the fixture and initialized app (and task data
if needed). Update each test to call the helper while preserving its existing
assertions, cleanup, and test-specific configuration such as nested tasks or
composer text.

In `@internal/terminal/input.go`:
- Line 103: Extract the duplicated status text used by app.setStatus into a
named package-level constant in the input handling code, then replace the
occurrences at the referenced status-update sites, including the calls near
lines 103, 136, and 260, with that constant while preserving the exact message.
- Around line 87-139: The read-only inspection handling is duplicated and
unreachable in downstream key handlers. Remove the redundant
inspectingWhilePromptRuns guards and status branches from
handleInlineListsAndExtensionKey and handleInputKey, and centralize the shared
read-only status behavior in handleReadOnlyInspectionPriorityKey while
preserving its existing inspection navigation handling.

In `@internal/terminal/session_view.go`:
- Around line 117-145: Reduce allocation overhead in withSessionView for
repeated streamed events while inspecting another session by batching or
coalescing the saveSessionView/restoreSessionView round-trip, and benchmark the
resulting prompt-event path to confirm improvement. Move the existing routing
comment directly above withSessionView, leaving inspectingWhilePromptRuns
without that unrelated documentation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b149d34b-35d3-4d4d-a864-04f4ddad9aff

📥 Commits

Reviewing files that changed from the base of the PR and between 773eb84 and 2f5ebda.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (9)
  • internal/terminal/agent_tasks.go
  • internal/terminal/agent_tasks_behavior_internal_test.go
  • internal/terminal/app.go
  • internal/terminal/async_events.go
  • internal/terminal/input.go
  • internal/terminal/input_escape.go
  • internal/terminal/message_layout.go
  • internal/terminal/session_view.go
  • internal/terminal/session_view_internal_test.go

Comment thread internal/terminal/async_events.go Outdated
@sonarqubecloud

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/terminal/input.go (1)

226-235: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Exclude Alt+Escape from autocomplete dismissal. This helper runs before handleAgentTaskSessionEscape, so when autocomplete is open Alt+Escape closes autocomplete instead of leaving inspection. Skip tcell.ModAlt here (or reorder the checks), and add a handleKey regression test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/terminal/input.go` around lines 226 - 235, The
handleInspectionAutocompleteEscape method should not dismiss autocomplete for
Alt+Escape, allowing handleAgentTaskSessionEscape to leave inspection instead.
Add a modifier check for tcell.ModAlt while preserving existing escape handling,
and add a handleKey regression test covering Alt+Escape with autocomplete
active.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@internal/terminal/input.go`:
- Around line 226-235: The handleInspectionAutocompleteEscape method should not
dismiss autocomplete for Alt+Escape, allowing handleAgentTaskSessionEscape to
leave inspection instead. Add a modifier check for tcell.ModAlt while preserving
existing escape handling, and add a handleKey regression test covering
Alt+Escape with autocomplete active.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 72b8eee4-efe0-401f-adbf-fc236a43347c

📥 Commits

Reviewing files that changed from the base of the PR and between 2f5ebda and 69dfafe.

📒 Files selected for processing (7)
  • internal/terminal/agent_tasks.go
  • internal/terminal/agent_tasks_behavior_internal_test.go
  • internal/terminal/async_events.go
  • internal/terminal/bench_terminal_internal_test.go
  • internal/terminal/input.go
  • internal/terminal/session_view.go
  • internal/terminal/session_view_internal_test.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • internal/terminal/session_view_internal_test.go
  • internal/terminal/async_events.go
  • internal/terminal/session_view.go
  • internal/terminal/agent_tasks.go
  • internal/terminal/agent_tasks_behavior_internal_test.go

@omarluq
omarluq merged commit 1947593 into main Jul 29, 2026
16 checks passed
@omarluq
omarluq deleted the fix/active-prompt-agent-inspection branch July 29, 2026 04:29
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