Skip to content

Plan title duplicated: appears in plan card AND as separate agent response message #837

Description

@adolfousier

Bug Report

Reported by: @leshchenko1979 (Alexey), 2026-07-27

Problem

When an agent turn runs with an active plan, the plan title appears twice:

  1. Inside the persistent plan card message (correct, rendered by plan_card.rs:render_plan_card_html)
  2. As the first line of the agent's text response, sent as a separate message by deliver_final_response in delivery.rs

The user sees: plan card (with title + prose expandables + checklist) followed by a second message that starts with the plan title again and then the agent's actual response text.

Root Cause

After #580 and #621 moved plan chrome (title, prose, checklist) from the per-turn flow block to the persistent plan card:

  • flow_chrome.rs:713 correctly sets plan_title: None, prose: None, checklist: None in FlowSections
  • plan_card.rs:render_plan_card_html correctly renders the title + prose expandables + checklist in one persistent message
  • But delivery.rs:deliver_final_response sends the agent's raw response.content as a new message with NO stripping of plan title

The LLM's response includes the plan title because context.rs:870 injects [ACTIVE PLAN REMINDER] Plan: "{title}" into the system prompt, and the model echoes the title back in its output.

Evidence

Alexey's screenshot (2026-07-27 13:46-13:47):

  • Message 13:46: Plan card with expandable sections (Context, Implementation steps, Out of scope, Files touched) and title at top
  • Message 13:47: "Business Tinder Help System Upgrade" + agent text response as a separate message (title duplicated)

Affected Code Paths

  • src/channels/telegram/delivery.rs:38 (deliver_final_response) sends response.content without plan-title stripping
  • src/channels/telegram/handler.rs:3529 refresh_plan_card called mid-round
  • src/channels/telegram/handler.rs:4008 refresh_plan_card called at turn end
  • Agent text delivery happens between these two refresh calls

Proposed Fix

In deliver_final_response (or a helper it calls), after sanitization and before sending:

  1. Load the active plan title for the session
  2. Strip leading lines from response.content that match the plan title (with or without prefix / bold markup)
  3. Send the cleaned text

This ensures the plan card is the single surface carrying the title, matching the #580/#621 architecture intent.

Related

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions