Skip to content

feat(coding-agent): surface refinement status and outcomes - #447

Open
snimu wants to merge 35 commits into
mainfrom
feat/refinement-status-queue
Open

feat(coding-agent): surface refinement status and outcomes#447
snimu wants to merge 35 commits into
mainfrom
feat/refinement-status-queue

Conversation

@snimu

@snimu snimu commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Refinement (the continual-harness update that runs after a turn ends) was invisible in the transcript: the TUI literally ignored refine_complete, and nothing showed what a refinement changed. This PR persists a durable outcome message and shows a live loader for user-issued /refine.

What it does

After every refinement (manual /refine, agent refine.run, or auto-refine), a refinement_outcome custom message is persisted into the session transcript and rendered like the compaction/skill cards:

  • Collapsed: one boxed line — [refinement] <summary> · N edits applied with the shared Ctrl+O expand hint.
  • Expanded (same app.tools.expand toggle as compaction summaries and skill invocations): one row per harness edit — action, scope, kind, entry id, error for failed edits — plus exact before/after entry payloads as inline diffs.
  • Replays with the session, survives context rebuilds even when the session-file append fails (memory-fallback mirrors compaction_outcome), and is excluded from model context (convertToLlm).
  • The generic /refine result row is still persisted for branch topology but no longer displayed — the outcome message supersedes it.
  • Print/headless mode skips the outcome when selecting the terminal result, mirroring compaction_outcome.
  • A live "Refining continual harness state..." loader runs while a user-issued /refine executes — built entirely from existing edges (the /refine slash-command message at message_start, and the already-wire-visible refine_complete/refine_failed), reusing the compaction Loader. No new events or state.

Shared component skeleton extracted

Compaction, skill, and refinement cards each duplicated the same Box-subclass skeleton (expanded flag, setExpanded, invalidate, bold label). That skeleton now lives in ExpandableCustomMessageBox + customMessageLabel, and all three components sit on it — the compaction and skill components each shrank by ~20 LOC.

Deliberately NOT included

Earlier revisions plumbed refinement_start/refinement_end events and an isRefining flag through the daemon protocol, RPC state, agents-view status labels, and heartbeat deferral. The apply phase is sub-second and both loader edges already existed on the wire, so all of that was stripped. No protocol/schema changes (revision stays at 16).

Size

+574/−111 (src +353/−108): component 102 + shared base 33, message type/factory/validator ~60, agent-session ~40, loader + wiring ~74, minus ~57 removed from compaction/skill components.

Validation

  • tsgo + biome green; refinement-outcome-message, interactive-mode-status, interactive-mode-compaction, skills, export-html-skill-block, print-mode, and agent-session-queue suites green (320 tests).

Fixes ENG-5285 (https://linear.app/primeintellect/issue/ENG-5285)

Note

Add durable refinement_outcome transcript messages and live /refine loader

  • Each successful refinement now records a refinement_outcome custom message via _recordRefinementOutcome in agent-session.ts, rendered as an expandable card with per-edit diffs by RefinementOutcomeMessageComponent
  • Queued /refine hides its slash-command result row (display=false) and shows a live Refining continual harness state... loader; on planner failure it emits refine_failed
  • Generalizes the unpersisted-outcome buffer from compaction-only to any custom message (_unpersistedOutcomes), so refinement outcomes that fail to persist are merged back on context rebuilds
  • Refines outcome messages are excluded from LLM context (convertToLlm) and skipped by headless terminal result selection
  • Refactors CompactionSummaryMessageComponent and SkillInvocationMessageComponent onto a shared ExpandableCustomMessageBox base
  • Behavioral Change: _mergeUnpersistedOutcomes now handles both compaction and refinement outcomes; _appendDurableSessionCommandMessage accepts a display param that can persist hidden result rows

Macroscope summarized 6f101fd.


Note

Medium Risk
Touches session persistence, context rebuilds, and interactive event/loader wiring for refinements. Not auth-critical, but incorrect merge or loader settle logic could drop outcomes or leave a stuck status spinner.

Overview
Makes refinements visible in the transcript. After each successful refine (slash command, agent, or auto), the session now records a durable refinement_outcome custom message with summary, scope, and applied edits. Persistence failures keep the outcome in memory so context rebuilds still show it; the message is excluded from LLM context.

The TUI renders a boxed [refinement] card that collapses to a one-liner and expands (same tool-output toggle as compaction/skill) to per-edit rows with before/after diffs. The generic /refine result row stays for branch topology but is hidden. User /refine shows a “Refining continual harness state...” loader until the command result settles; refine_complete/refine_failed from background refines do not stop it.

Compaction and skill cards now share ExpandableCustomMessageBox. Headless/print mode skips trailing refinement outcomes when picking the terminal result.

Reviewed by Cursor Bugbot for commit 6f101fd. Bugbot is set up for automated code reviews on this repo. Configure here.

@snimu
snimu marked this pull request as ready for review July 16, 2026 20:05
snimu added 8 commits July 16, 2026 22:08
# Conflicts:
#	packages/coding-agent/CHANGELOG.md
# Conflicts:
#	packages/coding-agent/CHANGELOG.md
# Conflicts:
#	packages/coding-agent/CHANGELOG.md
#	packages/coding-agent/src/core/agent-session.ts
# Conflicts:
#	packages/coding-agent/CHANGELOG.md
# Conflicts:
#	packages/coding-agent/CHANGELOG.md
# Conflicts:
#	packages/coding-agent/CHANGELOG.md
Comment thread packages/coding-agent/src/core/agent-session.ts Outdated
Comment thread packages/coding-agent/src/core/agent-session.ts Outdated
# Conflicts:
#	packages/coding-agent/CHANGELOG.md
#	packages/coding-agent/src/cli/daemon-launch.ts
#	packages/coding-agent/src/modes/agents-view/agents-view-state.ts
#	packages/coding-agent/src/modes/rpc/rpc-mode.ts
Comment thread packages/coding-agent/src/core/agent-session.ts Outdated
@sethkarten sethkarten changed the title feat(coding-agent): surface refinement and queue prompts feat(coding-agent): surface refinement status and outcomes Aug 18, 2026
@macroscopeapp

macroscopeapp Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Macroscope has since reviewed this pull request. An earlier review was skipped by a cost limit; a review has now completed, so that notice no longer applies.

Comment thread packages/coding-agent/src/core/agent-session.ts Outdated
Comment thread packages/coding-agent/src/core/agent-session.ts
snimu added 2 commits August 19, 2026 13:23
Replace the bespoke checkmark rendering with the shared custom-message
pattern: a boxed bold [refinement] label on the customMessage background,
collapsed to a single summary line and expanded through the same
tool-output toggle (ctrl+o) that compaction summaries and skill
invocations use, instead of a separate edit-diff axis.
snimu added 2 commits August 19, 2026 22:58
The apply phase is sub-second, so a "Refining" loader, agents-view
status label, daemon status string, heartbeat deferral, and an
isRefining wire flag were all periphery for something users can barely
see. Drop refinement_start/end events and every isRefining touchpoint
(daemon protocol schema stays at 16 — no wire change at all), and slim
the outcome-message validator to the shallow envelope checks the
compaction outcome uses. The feature is now just the persisted
[refinement] transcript card.
No new events or state: start the loader when the /refine slash-command
message reaches the transcript and stop it on the already-wire-visible
refine_complete/refine_failed events, mirroring the compaction loader.
Comment thread packages/coding-agent/src/modes/interactive/interactive-mode.ts
snimu added 5 commits August 20, 2026 10:14
Compaction, skill, and now refinement cards each copied the same Box
subclass with an expanded flag, setExpanded, invalidate, and bold-label
formatting. Pull that into ExpandableCustomMessageBox + a
customMessageLabel helper and rebase all three components onto it, so
the refinement card only carries its edit-row/diff formatting.
…s-queue

# Conflicts:
#	packages/coding-agent/CHANGELOG.md
A failed /refine persisted its command-error row without emitting
refine_failed, so the TUI loader kept spinning. Emit it from the queued
command catch, matching the refine.run and auto-refine failure paths.
Collapsed card now renders the [refinement] label line above the
summary line, matching the compaction card structure. The refine loader
joins compaction/retry in the syncWorkingLoader ownership guard so
periodic reconcile paths (subagent updates, connection refreshes)
cannot clear it mid-refine.
…s-queue

# Conflicts:
#	packages/coding-agent/CHANGELOG.md
Comment thread packages/coding-agent/src/modes/interactive/interactive-mode.ts Outdated
Long summaries wrapped the collapsed line onto a second row. Render the
collapsed line through a width-aware component that ellipsizes the
summary while keeping the edit count and expand hint visible.
snimu added 3 commits August 20, 2026 12:10
…d line

A compaction that starts mid-refine owns the status container; on
compaction_end syncWorkingLoader now remounts the refine loader instead
of bailing on the ownership guard. The collapsed outcome line is also
clipped to the render width after assembly so extreme narrow viewports
cannot wrap it.
…s-queue

# Conflicts:
#	packages/coding-agent/CHANGELOG.md
Comment thread packages/coding-agent/src/modes/interactive/interactive-mode.ts
Comment thread packages/coding-agent/src/modes/interactive/interactive-mode.ts
…n teardown

refine_complete carries no request identity, so an agent or auto
refinement settling while a queued user /refine waited on it killed the
loader early. The /refine result row is the user refine's settle edge
(emitted after refine() returns, error row on failure), so the loader
stops there — and on refine_failed, which covers a failed result-row
append. Session switches and stop() now discard the loader timer, which
previously leaked when the view never received a settle event.
Comment thread packages/coding-agent/src/modes/interactive/interactive-mode.ts

@cursor cursor 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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 6f101fd. Configure here.

} catch (error) {
if (error instanceof CompactionSkippedError) return;
const commandError = error instanceof Error ? error : new Error(String(error));
if (input.command.name === "refine") this._emitRefineFailed(commandError);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Success path emits refine failure

Medium Severity

The queued /refine catch now always calls _emitRefineFailed, including when refine() already succeeded and only the hidden result-row persist fails. The transcript already has a refinement_outcome, but the UI still surfaces a refinement failure and may append a Command failed row, so a completed harness update is reported as failed.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 6f101fd. Configure here.

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.

2 participants