logancyang_obsidian-copilot/docs/TODO-composer-tool-redesign.md
Logan Yang b128b25558
Agent UIUX Improvements (#2149)
* Use openrouter openai embedding small as default embedding model

* Increase agent max iterations to 16 and add 5-minute loop timeout

- Raise max tool call iterations limit from 8 to 16
- Add AGENT_LOOP_TIMEOUT_MS constant (5 minutes) to prevent runaway loops
- Update slider max in settings UI to match new limit
- Show appropriate message when loop exits due to timeout vs max iterations

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Update agent reasoning spinner to sigma shape with smooth animation

- Change from 9-dot diamond to 7-dot sigma (Σ) pattern
- Animation traces sigma shape: top-right → top-left → center → bottom
- Use ease-in-out timing and gradual opacity transitions for smooth motion
- Adjust size to 13.5px for better alignment with text

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Improve agent reasoning step summaries and fix composer tool UX

- Add meaningful summaries for writeToFile/replaceInFile tools
  (e.g., "Writing to filename" instead of "Calling writeToFile")
- Show "Edit rejected" when user rejects changes in diff view
- Fix "Changes applied successfully" notice showing on reject
- Extract model's intermediate reasoning as finding summaries
- Add TODO doc for composer tool redesign to address 30s feedback gap

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add self-host mode eligibility gating and permanent validation

- Increase tool timeout from 60s to 120s
- Show self-host mode section only to Believer/Supporter plan users
- Add permanent validation after 3 consecutive successful checks
- Add useIsSelfHostEligible hook for offline-friendly eligibility check
- Preserve permanent validation status when re-enabling self-host mode

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix self-host validation to require 14-day intervals between count increments

- Only increment validation count when 14+ days have passed since last check
- Document need for structured ComposerTools results in TODO doc
- Add TODO for no-op case handling in AgentReasoningState

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix self-host validation timer and offline re-enable issues

- Don't reset timestamp when < 14 days (preserves interval countdown)
- Allow permanently validated users to see section even if toggle is off
- Supports offline re-enable for users with 3+ successful validations

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Wire refreshSelfHostModeValidation into plugin startup

Enables the 14-day periodic validation to actually increment the count
toward permanent self-host mode (3 successful checks).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Improve self-host mode validation with offline support and documentation

- Add grace period check in validateSelfHostMode for offline re-enable
- Change grace period from 14 to 15 days
- Add comprehensive documentation explaining validation flow
- Fix offline re-enable for users within grace period

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 17:10:28 -08:00

4.4 KiB

TODO: Composer Tool Redesign for Faster Feedback

Date: 2026-02-04 Assignee: @wenzhengjiang Status: TODO

Problem

The writeToFile and replaceInFile composer tools have a significant UX issue: there's a 30+ second gap between the initial reasoning step and any meaningful feedback about what the agent intends to do.

Root Cause

The current flow requires the model to generate the entire modified file content in a single tool call:

User: "Remove all the headings"
         ↓
Model receives prompt + full file content
         ↓
Model generates ENTIRE modified file (30+ seconds)
         ↓
Tool call emitted with full content
         ↓
UI finally shows "Writing to filename..."

During those 30+ seconds, the user has no idea what the agent is planning to do.

Current Tool Schema

writeToFile({
  path: string,
  content: string | object, // ← ENTIRE file content generated upfront
  confirmation: boolean,
});

Proposed Solution: Multi-Step Tool Design

Split the composer operation into two phases:

Phase 1: Intent Declaration (Fast)

A lightweight tool call that declares intent without generating content:

declareEditIntent({
  path: string,
  operation: "rewrite" | "modify" | "create",
  description: string, // e.g., "Remove all headings from the document"
});

This would return almost immediately (1-2 seconds) because the model only needs to decide WHAT to do, not generate the full content.

UI shows: "Planning to remove all headings from Daily-AI-Digest.md..."

Phase 2: Content Generation (Slow but expected)

After intent is confirmed, the full content generation happens:

executeEdit({
  path: string,
  content: string | object,
});

UI shows: "Generating changes..." → "Writing to filename..."

Benefits

  1. Immediate feedback: User knows the intent within 1-2 seconds
  2. Opportunity to cancel: User can abort before expensive generation
  3. Better UX: Progress feels natural (planning → executing)
  4. Clearer reasoning steps: Each phase has distinct, meaningful steps

Additional Requirements

Diff History Cache for Reliable Revert

Cache the last N diffs per file to enable reliable undo/revert functionality:

  • Store diffs (not full file snapshots) to minimize storage
  • Keep last N changes (e.g., N=10) per file path
  • Enable "Revert last change" and "Revert to version X" actions
  • Clear old diffs when limit exceeded (FIFO)
interface DiffHistoryEntry {
  timestamp: number;
  path: string;
  diff: Change[]; // from 'diff' library
  description: string; // e.g., "Remove all headings"
}

Dedicated "Apply" Model

Consider using a separate small, fast, and cheap model specifically for applying diffs:

  • Main model: Generates the intent and edit description (Phase 1)
  • Apply model: Executes the actual file transformation (Phase 2)

Benefits:

  • Faster execution for Phase 2 (smaller model = faster inference)
  • Lower cost (cheap model for mechanical transformation)
  • Main model focuses on understanding, apply model focuses on execution
  • Could use a fine-tuned model optimized for code/text transformations

Candidates: Gemini Flash Lite or comparable models.

Structured Tool Results

Currently, ComposerTools returns plain strings for errors/no-ops, making result parsing fragile:

// Current: Plain strings (fragile)
return `File is too small to use this tool...`;
return `Search text not found in file ${path}...`;
return `No changes made to ${path}...`;

The reasoning UI (AgentReasoningState.ts) uses string matching to detect these cases, which breaks if messages change.

Proposed: Return structured results:

interface ComposerToolResult {
  status: "success" | "rejected" | "no-op" | "error";
  message: string;
  path?: string;
}

This enables reliable status detection in the reasoning UI without fragile string matching.

  • src/tools/ComposerTools.ts - Current tool implementations
  • src/LLMProviders/chainRunner/AutonomousAgentChainRunner.ts - ReAct loop
  • src/LLMProviders/chainRunner/utils/AgentReasoningState.ts - Reasoning UI state

Next Steps

  1. Design the multi-step tool API
  2. Prototype with writeToFile first
  3. Update reasoning UI to handle two-phase operations
  4. Test with various file sizes and operations
  5. Roll out to replaceInFile