Skip to content

Commit 37bb07a

Browse files
committed
feat: add agent chat re-apply interaction for tool calls, groups, and diff batches
- Implemented in-place re-apply functionality in agent chat to allow users to re-run completed edit actions. - Added support for single tool call, whole tool-call group, and diff batch re-application. - Enhanced UI to show re-apply actions inline with appropriate success, conflict, and error states. - Updated ChatInput component to handle composition events for better input management. - Introduced ModelSelector component with search functionality for model selection. - Created use-agent-selected-model composable for persistent model selection across sessions. - Refactored write views to integrate selected model management. - Updated Vite configuration to streamline plugin usage and improve development experience. Signed-off-by: Innei <tukon479@gmail.com>
1 parent 4d586d5 commit 37bb07a

9 files changed

Lines changed: 1841 additions & 41 deletions

File tree

docs/superpowers/plans/2026-04-05-agent-chat-reapply.md

Lines changed: 1104 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 396 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,396 @@
1+
# Agent Chat Re-Apply Interaction
2+
3+
**Date**: 2026-04-05
4+
**Scope**: admin-vue3 repo only
5+
**Stack**: Vue 3 TSX (defineComponent + JSX), `@haklex/rich-agent-core`, Lexical editor integration in `RichEditorWithAgent.tsx`
6+
7+
## Overview
8+
9+
Add an in-place `re-apply` interaction to the agent chat so the user can re-run previously completed edit actions without creating a new chat flow.
10+
11+
The feature must support three replay targets:
12+
13+
1. **Single tool call** — replay one completed `ToolCallGroupItem`
14+
2. **Whole tool-call group** — replay all completed items in a `tool_call_group`
15+
3. **Diff batch** — re-apply one previously generated `ReviewBatch`
16+
17+
The user-selected interaction model is **Option A: direct in-place replay**:
18+
19+
- `Re-apply` appears directly on the existing bubble UI
20+
- replay runs from the current chat surface, not a tray and not a new bubble type
21+
- replay operates against the **current editor state**
22+
- when replay cannot safely target the current document, the UI shows **conflict** or **error** inline rather than silently falling back to a fresh agent run
23+
24+
## Goals
25+
26+
- Make replay feel like a local action on an existing result, not a new agent session
27+
- Keep the current chat layout and bubble model intact
28+
- Reuse existing editor-apply logic where possible, especially the current batch-accept flow
29+
- Surface replay progress and failure inline at the exact action origin
30+
- Allow partial success for group and batch replay
31+
32+
## Non-Goals
33+
34+
- No replay queue / tray
35+
- No new chat bubble type such as "Replay request"
36+
- No silent fallback to "ask the agent again"
37+
- No attempt to preserve the original document snapshot and fully reproduce historical output
38+
- No unrelated refactor of the agent loop architecture
39+
40+
## Interaction Model
41+
42+
### Single Tool Call
43+
44+
**File**: `src/components/editor/rich/agent-chat/bubbles/ToolCall.tsx`
45+
46+
Behavior:
47+
48+
- Add a hover-visible `Re-apply` action next to the existing copy affordance
49+
- Only show the action for replayable completed items
50+
- Clicking starts replay immediately
51+
- While replay is running:
52+
- disable the action
53+
- show spinner / running state inline
54+
- On success:
55+
- show a transient `Re-applied` success state inline
56+
- On compatibility failure:
57+
- show `Conflict` inline
58+
- expanding the item may show the reason text if needed
59+
- On execution failure:
60+
- show `Failed` inline with error details available in the expanded area
61+
62+
### Tool Call Group
63+
64+
**File**: `src/components/editor/rich/agent-chat/bubbles/ToolCallGroup.tsx`
65+
66+
Behavior:
67+
68+
- Add a group-level `Re-apply all` action in the group header
69+
- Keep per-item `Re-apply` actions available inside the expanded list
70+
- Group replay executes items in original order
71+
- Group completion is aggregated and displayed in the header:
72+
- `18/18 reapplied`
73+
- `12/18 reapplied, 6 conflicted`
74+
- `9/18 reapplied, 3 conflicted, 6 failed`
75+
- One conflicted item must not block all later items from attempting replay
76+
77+
### Diff Batch
78+
79+
**File**: `src/components/editor/rich/agent-chat/bubbles/DiffReviewBubble.tsx`
80+
81+
Behavior:
82+
83+
- Add a batch-level `Re-apply` action in the existing header action area
84+
- Keep `Accept` / `Reject` as the primary actions; `Re-apply` is visually weaker
85+
- Replay here means **apply this batch's entries to the current editor state again**
86+
- Batch replay returns aggregate result similar to group replay:
87+
- full success
88+
- partial success with conflicts
89+
- failed
90+
- If the current document drift makes some entries unsafe, show a warning / conflict state inline in the batch header
91+
92+
## Replay Semantics
93+
94+
Replay always targets the **current editor state**, not the historical snapshot from the original run.
95+
96+
### Why
97+
98+
- The user explicitly chose a hybrid/current-state-first model
99+
- The chat UI should help continue editing the current document, not restore history
100+
- Historical full reproduction would require storing and restoring older editor snapshots, which is outside this feature's scope
101+
102+
### Allowed Outcomes
103+
104+
Each replay target resolves to one of:
105+
106+
- `success` — operation applied cleanly to current state
107+
- `conflict` — target anchor no longer matches current state, so replay was intentionally skipped
108+
- `error` — replay attempted but failed due to runtime or parse/apply error
109+
110+
For groups and batches, the final result is aggregated from per-entry outcomes.
111+
112+
### No Silent Fallback
113+
114+
If replay cannot safely operate on the current document, the system must **not** silently:
115+
116+
- ask the model to regenerate the result
117+
- create a fresh agent run
118+
- mutate the original bubble history
119+
120+
Instead it should surface the conflict inline and preserve the original record as history.
121+
122+
## Compatibility Check
123+
124+
Compatibility check runs before each individual replay operation.
125+
126+
### Replace / Delete
127+
128+
- Use the original `blockId`
129+
- If the block is still present, replay may proceed
130+
- If the block is missing, mark the item as `conflict`
131+
132+
### Insert
133+
134+
- Re-resolve the insertion anchor from the original position metadata
135+
- Root-position insertions remain replayable by clamping the original index into the current root child range
136+
- Relative insertions (`before` / `after`) require the referenced block to still exist
137+
- Missing anchor becomes `conflict`
138+
139+
### Idempotency
140+
141+
Replay is intentionally a **re-execution** of the original operation, not an idempotent deduped apply.
142+
143+
Implications:
144+
145+
- replaying an `insert` may insert another block if its anchor still exists
146+
- replaying a previously accepted batch is allowed, but it may produce a different result than the first apply because the document has already changed
147+
- the system should report what happened; it should not silently suppress a valid second insertion just because a similar edit happened before
148+
149+
### Batch Entries
150+
151+
- Evaluate each batch entry independently
152+
- Some entries may succeed while others conflict
153+
- The batch-level result is only `success` when every entry succeeds
154+
155+
## Architecture and Boundaries
156+
157+
### Rendering Layer
158+
159+
**Files**:
160+
161+
- `src/components/editor/rich/agent-chat/ChatMessageList.tsx`
162+
- `src/components/editor/rich/agent-chat/bubbles/ToolCall.tsx`
163+
- `src/components/editor/rich/agent-chat/bubbles/ToolCallGroup.tsx`
164+
- `src/components/editor/rich/agent-chat/bubbles/DiffReviewBubble.tsx`
165+
166+
Responsibilities:
167+
168+
- Render replay actions
169+
- Render inline replay state: idle / running / success / conflict / error
170+
- Emit replay intents upward
171+
172+
The rendering layer must **not**:
173+
174+
- touch the Lexical editor directly
175+
- mutate agent store history
176+
- implement replay logic itself
177+
178+
### Orchestration Layer
179+
180+
**File**: `src/components/editor/rich/RichEditorWithAgent.tsx`
181+
182+
Responsibilities:
183+
184+
- own the unified replay entry points:
185+
- `handleReapplyItem(itemId | item)`
186+
- `handleReapplyGroup(groupId | items)`
187+
- `handleReapplyBatch(batchId)`
188+
- run compatibility checks
189+
- apply editor mutations
190+
- aggregate group and batch results
191+
- update replay UI state
192+
193+
Why this layer:
194+
195+
- it already owns editor access
196+
- it already applies accepted review batches
197+
- replay is an editor-side reapplication concern, not a model execution concern
198+
199+
### Agent Loop Composable
200+
201+
**File not targeted**: `src/components/editor/rich/agent-chat/composables/use-agent-loop.ts`
202+
203+
Do **not** move replay into the agent loop composable in this phase.
204+
205+
Reason:
206+
207+
- replay is not a fresh model inference flow
208+
- the existing `retry()` behavior already represents "send the last user message again"
209+
- mixing local replay and remote agent rerun inside the same abstraction would blur semantics
210+
211+
## State Model
212+
213+
Add a lightweight replay state map owned by `RichEditorWithAgent.tsx`.
214+
215+
Suggested shape:
216+
217+
```typescript
218+
type ReplayStatus = 'idle' | 'running' | 'success' | 'conflict' | 'error'
219+
220+
interface ReplayStateEntry {
221+
status: ReplayStatus
222+
message?: string
223+
finishedAt?: number
224+
summary?: {
225+
succeeded: number
226+
conflicted: number
227+
failed: number
228+
total: number
229+
}
230+
}
231+
232+
type ReplayStateMap = Record<string, ReplayStateEntry | undefined>
233+
```
234+
235+
Stable keys:
236+
237+
- `tool:<item.id>`
238+
- `group:<group.id>`
239+
- `batch:<batch.id>`
240+
241+
Rules:
242+
243+
- UI state is separate from bubble history
244+
- success may be transient and auto-clear after a short timeout
245+
- conflict and error should remain visible until replay is attempted again or the panel is rerendered
246+
- group and batch entries may store aggregate `summary`
247+
248+
## Replayability Rules
249+
250+
Only replay actions that are deterministic editor applications should expose `Re-apply`.
251+
252+
### Tool Calls
253+
254+
Replayable:
255+
256+
- completed edit-like tool calls that still map to a known operation payload
257+
258+
Not replayable:
259+
260+
- running items
261+
- errored items without valid operation payload
262+
- items that are display-only or lack sufficient data to reconstruct the operation
263+
264+
If some legacy tool-call items do not contain enough structured data to replay safely, hide `Re-apply` for those items.
265+
266+
### Groups
267+
268+
- `Re-apply all` should appear only if the group contains at least one replayable item
269+
- non-replayable items are skipped and counted separately only if needed in the final summary text
270+
271+
### Batches
272+
273+
- a batch is replayable when its `entries` are still available
274+
- replay works regardless of whether the batch was previously accepted or still pending
275+
276+
## Execution Flow
277+
278+
### Single Item Replay
279+
280+
1. User clicks `Re-apply`
281+
2. UI key `tool:<id>` becomes `running`
282+
3. Resolve the underlying operation payload
283+
4. Run compatibility check against current editor state
284+
5. If compatible, apply to Lexical editor
285+
6. Update entry to:
286+
- `success`, or
287+
- `conflict`, or
288+
- `error`
289+
290+
### Group Replay
291+
292+
1. User clicks `Re-apply all`
293+
2. UI key `group:<id>` becomes `running`
294+
3. Iterate items in original order
295+
4. Replay each item independently
296+
5. Record per-item states and aggregate group summary
297+
6. Update group-level state when all items finish
298+
299+
### Batch Replay
300+
301+
1. User clicks batch `Re-apply`
302+
2. UI key `batch:<id>` becomes `running`
303+
3. Iterate batch entries in order
304+
4. Run compatibility check per entry
305+
5. Apply compatible entries
306+
6. Aggregate final summary and expose inline result
307+
308+
## Error Handling
309+
310+
### Conflict
311+
312+
Conflict is a first-class outcome, not a generic error.
313+
314+
Typical causes:
315+
316+
- referenced block no longer exists
317+
- insert anchor disappeared
318+
- current document order changed enough that the original anchor no longer makes sense
319+
320+
UI treatment:
321+
322+
- inline `Conflict` state near the replay control
323+
- optional short message such as `Target block not found`
324+
- for group / batch: aggregate counts in header plus per-item local state when visible
325+
326+
### Error
327+
328+
Error means replay should have been possible but failed during execution.
329+
330+
Examples:
331+
332+
- node parse error
333+
- unexpected malformed operation payload
334+
- editor update error
335+
336+
UI treatment:
337+
338+
- inline `Failed` state
339+
- error details available in expanded content or local message
340+
341+
## Minimal File Changes
342+
343+
Expected touched files:
344+
345+
- `src/components/editor/rich/agent-chat/ChatMessageList.tsx`
346+
- `src/components/editor/rich/agent-chat/bubbles/ToolCall.tsx`
347+
- `src/components/editor/rich/agent-chat/bubbles/ToolCallGroup.tsx`
348+
- `src/components/editor/rich/agent-chat/bubbles/DiffReviewBubble.tsx`
349+
- `src/components/editor/rich/RichEditorWithAgent.tsx`
350+
351+
Optional helper extraction if implementation becomes too dense:
352+
353+
- `src/components/editor/rich/agent-chat/composables/use-agent-reapply.ts`
354+
355+
This helper is allowed only if it keeps `RichEditorWithAgent.tsx` smaller without moving replay semantics into the generic agent loop.
356+
357+
## Testing Strategy
358+
359+
Add focused tests around replay behavior instead of broad visual snapshot coverage.
360+
361+
Minimum automated coverage:
362+
363+
1. single-item replay succeeds when target block still exists
364+
2. single-item replay returns conflict when target block is missing
365+
3. group replay reports partial success when some items conflict
366+
4. batch replay applies compatible entries and reports incompatible ones
367+
368+
Manual verification:
369+
370+
1. hover a completed tool call and trigger `Re-apply`
371+
2. trigger `Re-apply all` on a group
372+
3. trigger `Re-apply` on a diff batch
373+
4. confirm inline running / success / conflict / failed states render at the original action location
374+
5. confirm no new chat bubble is created
375+
376+
## Implementation Notes
377+
378+
- Reuse the current editor-apply logic from the existing batch accept path where possible
379+
- Prefer shared helper functions for:
380+
- locating blocks
381+
- compatibility checking
382+
- applying insert / replace / delete
383+
- aggregating summaries
384+
- Keep comments minimal and only where replay edge cases are not obvious
385+
386+
## Final Decision Summary
387+
388+
The chosen design is:
389+
390+
- **direct, in-place replay UI**
391+
- **current-state-first replay semantics**
392+
- **inline conflict/error reporting**
393+
- **no tray**
394+
- **no new replay bubble type**
395+
- **no silent fallback to a fresh agent run**
396+

0 commit comments

Comments
 (0)