agentgui 1.0.105 → 1.0.107
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prd +0 -228
- package/package.json +1 -1
- package/static/index.html +47 -2
package/.prd
CHANGED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
# PRD: Real-time Streaming Architecture & HTML Response Rendering
|
|
2
|
-
|
|
3
|
-
## Vision
|
|
4
|
-
Transform agentgui from a "save-on-complete" model to a "stream-as-it-happens" model where:
|
|
5
|
-
1. Real-time stream chunks are persisted to DB immediately as they arrive
|
|
6
|
-
2. Client views always pull from persisted chunks (not ephemeral process output)
|
|
7
|
-
3. Conversation state survives page refresh and multi-tab viewing
|
|
8
|
-
4. Agent thoughts/responses rendered as beautiful semantic HTML (not JSON)
|
|
9
|
-
5. System remains the same whether viewing live stream or historical conversation
|
|
10
|
-
|
|
11
|
-
## Critical Problems Being Solved
|
|
12
|
-
|
|
13
|
-
### Problem 1: Conversation State Loss on Refresh
|
|
14
|
-
**Current**: Viewing live execution → refresh page → conversation disappears
|
|
15
|
-
**Why**: Stream chunks exist only in memory during execution, saved as single JSON when done
|
|
16
|
-
**Solution**: Persist each chunk to DB immediately as it arrives from stream
|
|
17
|
-
|
|
18
|
-
### Problem 2: Dual View Inconsistency
|
|
19
|
-
**Current**: Same conversation looks different when live vs after completion
|
|
20
|
-
**Why**: Live view shows individual streaming blocks, complete view shows condensed JSON
|
|
21
|
-
**Solution**: Single source of truth = DB chunks. No special handling for "done" state
|
|
22
|
-
|
|
23
|
-
### Problem 3: No Multi-Tab Support
|
|
24
|
-
**Current**: Can't view same conversation in two browser tabs simultaneously
|
|
25
|
-
**Why**: No persistent state, live process is ephemeral
|
|
26
|
-
**Solution**: DB persistence means any tab can view same chunks at any time
|
|
27
|
-
|
|
28
|
-
### Problem 4: HTML Output Not Distinguished from Files
|
|
29
|
-
**Current**: System prompt says "output HTML" but unclear if it means response HTML or file writes
|
|
30
|
-
**Why**: Ambiguous instruction in system prompt
|
|
31
|
-
**Solution**: Make explicit: Agent HTML responses ≠ file operations. Only HTML rendering for display
|
|
32
|
-
|
|
33
|
-
### Problem 5: Process Completion Creates Artifacts
|
|
34
|
-
**Current**: When execution finishes, entire thing re-saved as JSON blob
|
|
35
|
-
**Why**: Current architecture treats completion as "finalize and persist"
|
|
36
|
-
**Solution**: No special completion action. Streaming simply stops. DB already has everything.
|
|
37
|
-
|
|
38
|
-
## Architecture Changes Required
|
|
39
|
-
|
|
40
|
-
### 1. Stream Chunk Persistence (Core Change)
|
|
41
|
-
**Current Flow**:
|
|
42
|
-
```
|
|
43
|
-
Claude → Stream Event → In-Memory Buffer → On Complete: Save JSON → DB
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
**New Flow**:
|
|
47
|
-
```
|
|
48
|
-
Claude → Stream Event → Process → Save Chunk → DB → WebSocket to Clients
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
**Implementation**:
|
|
52
|
-
- Each `streaming_progress` event creates DB chunk immediately
|
|
53
|
-
- Each chunk has: `id`, `sessionId`, `conversationId`, `sequence`, `type`, `data`, `created_at`
|
|
54
|
-
- No buffering, no aggregation, no re-saving on completion
|
|
55
|
-
- Chunks table schema must support variable size chunks (BLOB or TEXT)
|
|
56
|
-
|
|
57
|
-
### 2. Client Rendering from DB Only
|
|
58
|
-
**Current**: Client renders from WebSocket stream events
|
|
59
|
-
**New**: Client renders from DB chunks via polling/WebSocket
|
|
60
|
-
**Benefit**: Same render path whether data is fresh or historical
|
|
61
|
-
|
|
62
|
-
**Implementation**:
|
|
63
|
-
- Add endpoint: `GET /api/conversations/:id/chunks?since=<timestamp>`
|
|
64
|
-
- Returns chunks in order (sequence number)
|
|
65
|
-
- Client polls every 100ms for new chunks
|
|
66
|
-
- WebSocket optimization: only notify "new chunk available", don't send chunk data
|
|
67
|
-
- Client always fetches from DB to keep rendering consistent
|
|
68
|
-
|
|
69
|
-
### 3. HTML Response Rendering (System Prompt Change)
|
|
70
|
-
**Current System Prompt**:
|
|
71
|
-
```
|
|
72
|
-
"Always write your responses in ripple-ui enhanced HTML"
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
**Problem**: Unclear if this is for file output or response rendering
|
|
76
|
-
**Solution**: Make explicit instruction:
|
|
77
|
-
```
|
|
78
|
-
For user-facing responses and thoughts: Always use semantic HTML with ripple-ui components
|
|
79
|
-
Do not treat this as file creation. HTML is for rendering in the UI, not saving to disk.
|
|
80
|
-
Block types (text, code, thinking, etc) in your message should render as beautiful semantic HTML
|
|
81
|
-
File operations (Read, Write, Edit) are separate - create actual files on disk when needed
|
|
82
|
-
Distinguish clearly: HTML response rendering ≠ file write operations
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### 4. Conversation URL State (Client Change)
|
|
86
|
-
**Current**: Conversations loaded from session, URL doesn't track state
|
|
87
|
-
**New**: URL contains conversation ID and session ID for deep linking
|
|
88
|
-
|
|
89
|
-
**Implementation**:
|
|
90
|
-
- Route: `/gm/?conversation=<conversationId>&session=<sessionId>`
|
|
91
|
-
- Page refresh loads same conversation from URL
|
|
92
|
-
- Each conversation maintains scroll position in localStorage
|
|
93
|
-
- Deep linking enables multi-tab viewing
|
|
94
|
-
|
|
95
|
-
### 5. Remove Post-Execution JSON Consolidation (Deletion)
|
|
96
|
-
**Current**: When execution completes, entire response saved as consolidated JSON
|
|
97
|
-
**New**: No action on completion. Stream already persisted.
|
|
98
|
-
|
|
99
|
-
**Implementation**:
|
|
100
|
-
- Delete code in `server.js` that creates final JSON blob on streaming_complete
|
|
101
|
-
- Keep the `streaming_complete` event for UI notifications ("Finished!")
|
|
102
|
-
- All message data comes from persisted chunks, not from completion blob
|
|
103
|
-
|
|
104
|
-
## Status: ✅ ALL WORK COMPLETE
|
|
105
|
-
|
|
106
|
-
**All 6 waves successfully executed, verified, and deployed.**
|
|
107
|
-
|
|
108
|
-
### Completed Deliverables
|
|
109
|
-
- ✅ Wave 1: Database schema with chunks table and indexes
|
|
110
|
-
- ✅ Wave 2: Backend stream persistence with exponential backoff retry logic
|
|
111
|
-
- ✅ Wave 3: Client chunk fetching with 100ms polling
|
|
112
|
-
- ✅ Wave 4: URL state management and multi-tab support
|
|
113
|
-
- ✅ Wave 5: Expanded SYSTEM_PROMPT with clear HTML/file distinction
|
|
114
|
-
- ✅ Wave 6: Comprehensive verification (7/7 tests passed)
|
|
115
|
-
|
|
116
|
-
### Verification Results
|
|
117
|
-
- ✓ Conversation persistence across refresh
|
|
118
|
-
- ✓ Multi-tab viewing with synchronized content
|
|
119
|
-
- ✓ Streaming chunks rendering consistency
|
|
120
|
-
- ✓ URL deep linking and parameter validation
|
|
121
|
-
- ✓ Data loss prevention (continuous sequences)
|
|
122
|
-
- ✓ Error recovery (chunks integrity maintained)
|
|
123
|
-
- ✓ System prompt clarity (HTML vs file operations)
|
|
124
|
-
|
|
125
|
-
### All Changes Committed and Pushed
|
|
126
|
-
- Branch: origin/main
|
|
127
|
-
- 6 commits successfully pushed
|
|
128
|
-
- Working tree clean
|
|
129
|
-
- Production ready
|
|
130
|
-
|
|
131
|
-
## Data Model
|
|
132
|
-
|
|
133
|
-
### New: chunks table
|
|
134
|
-
```sql
|
|
135
|
-
CREATE TABLE chunks (
|
|
136
|
-
id TEXT PRIMARY KEY,
|
|
137
|
-
sessionId TEXT NOT NULL,
|
|
138
|
-
conversationId TEXT NOT NULL,
|
|
139
|
-
sequence INTEGER NOT NULL,
|
|
140
|
-
type TEXT NOT NULL, -- "text", "code", "thinking", "tool_use", "tool_result", "bash", "system", "image"
|
|
141
|
-
data BLOB NOT NULL, -- full block data as JSON
|
|
142
|
-
created_at INTEGER NOT NULL,
|
|
143
|
-
FOREIGN KEY (sessionId) REFERENCES sessions(id),
|
|
144
|
-
FOREIGN KEY (conversationId) REFERENCES conversations(id)
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
CREATE INDEX idx_chunks_session ON chunks(sessionId, sequence);
|
|
148
|
-
CREATE INDEX idx_chunks_conversation ON chunks(conversationId, sequence);
|
|
149
|
-
CREATE UNIQUE INDEX idx_chunks_unique ON chunks(sessionId, sequence);
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
### Modified: messages table (optional cleanup)
|
|
153
|
-
- Keep as-is for message text
|
|
154
|
-
- Add `chunks_id` field to reference chunk sequence (future)
|
|
155
|
-
- Messages created from chunks summary, not vice versa
|
|
156
|
-
|
|
157
|
-
## API Changes
|
|
158
|
-
|
|
159
|
-
### New Endpoints
|
|
160
|
-
```
|
|
161
|
-
GET /api/conversations/:id/chunks?since=<timestamp>
|
|
162
|
-
Response: [{id, sessionId, conversationId, sequence, type, data, created_at}...]
|
|
163
|
-
|
|
164
|
-
GET /api/sessions/:id/chunks?since=<timestamp>
|
|
165
|
-
Response: Same as above, filtered by session
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
### Modified Endpoints
|
|
169
|
-
```
|
|
170
|
-
POST /api/conversations/:id/messages
|
|
171
|
-
- Still creates message (for conversation history)
|
|
172
|
-
- But also triggers chunk persistence for streaming blocks
|
|
173
|
-
- No change to request/response format
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
### Removed/Deprecated
|
|
177
|
-
```
|
|
178
|
-
The "save on completion" behavior in streaming_complete event
|
|
179
|
-
- Keep the event for UI ("execution finished")
|
|
180
|
-
- Just don't save aggregated JSON
|
|
181
|
-
- Chunks already in DB from streaming
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
## System Prompt Changes
|
|
185
|
-
|
|
186
|
-
### Current
|
|
187
|
-
```
|
|
188
|
-
Always write your responses in ripple-ui enhanced HTML. Avoid overriding
|
|
189
|
-
light/dark mode CSS variables. Use all the benefits of HTML to express
|
|
190
|
-
technical details with proper semantic markup, tables, code blocks, headings,
|
|
191
|
-
and lists. Write clean, well-structured HTML that respects the existing
|
|
192
|
-
design system.
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
### New (Clearer)
|
|
196
|
-
```
|
|
197
|
-
RESPONSE RENDERING:
|
|
198
|
-
Your thoughts and responses are rendered as semantic HTML in the UI using
|
|
199
|
-
ripple-ui components. Always structure responses with proper HTML:
|
|
200
|
-
- Use headings for sections (<h2>, <h3>)
|
|
201
|
-
- Use lists for sequences (<ul>, <ol>)
|
|
202
|
-
- Use tables for structured data
|
|
203
|
-
- Use code blocks with language tags
|
|
204
|
-
- Use semantic elements: <strong>, <em>, <code>, <pre>
|
|
205
|
-
- Never override CSS variables (use class names instead)
|
|
206
|
-
- Respect the design system
|
|
207
|
-
|
|
208
|
-
DISTINGUISH: HTML Response vs File Operations
|
|
209
|
-
- HTML above is for UI rendering, not file creation
|
|
210
|
-
- When you need to create files on disk: use Write, Edit, or Bash tools
|
|
211
|
-
- Message blocks (text, code, thinking, tool_use) render as HTML automatically
|
|
212
|
-
- File operations create actual files in the working directory
|
|
213
|
-
- Do not try to "output files" as HTML in your response
|
|
214
|
-
- File operations are explicit via tools, not implicit via response text
|
|
215
|
-
|
|
216
|
-
BLOCK TYPES:
|
|
217
|
-
Your assistant message will be parsed into blocks:
|
|
218
|
-
- text: Plain text with markdown support
|
|
219
|
-
- code: Code with language detection
|
|
220
|
-
- thinking: Internal reasoning (expandable)
|
|
221
|
-
- tool_use: Showing which tools you're calling
|
|
222
|
-
- tool_result: Tool output
|
|
223
|
-
- bash: Shell commands
|
|
224
|
-
- system: System information
|
|
225
|
-
- image: Image display
|
|
226
|
-
Each block renders with semantic HTML and proper styling.
|
|
227
|
-
```
|
|
228
|
-
|
package/package.json
CHANGED
package/static/index.html
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
--color-warning: #f59e0b;
|
|
27
27
|
--sidebar-width: 300px;
|
|
28
28
|
--header-height: 52px;
|
|
29
|
-
--msg-max-width:
|
|
29
|
+
--msg-max-width: 100%;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
html.dark {
|
|
@@ -318,10 +318,12 @@
|
|
|
318
318
|
max-width: var(--msg-max-width);
|
|
319
319
|
margin: 0 auto;
|
|
320
320
|
width: 100%;
|
|
321
|
-
padding: 1.5rem
|
|
321
|
+
padding: 1.5rem 2rem;
|
|
322
322
|
display: flex;
|
|
323
323
|
flex-direction: column;
|
|
324
324
|
min-height: 100%;
|
|
325
|
+
padding-left: calc(max(2rem, (100vw - 900px) / 2));
|
|
326
|
+
padding-right: calc(max(2rem, (100vw - 900px) / 2));
|
|
325
327
|
}
|
|
326
328
|
|
|
327
329
|
#output {
|
|
@@ -817,6 +819,49 @@
|
|
|
817
819
|
.agent-selector { display: none; }
|
|
818
820
|
}
|
|
819
821
|
|
|
822
|
+
/* ===== SCROLLBAR STYLING ===== */
|
|
823
|
+
::-webkit-scrollbar {
|
|
824
|
+
width: 10px;
|
|
825
|
+
height: 10px;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
::-webkit-scrollbar-track {
|
|
829
|
+
background: transparent;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
::-webkit-scrollbar-thumb {
|
|
833
|
+
background: #cbd5e1;
|
|
834
|
+
border-radius: 8px;
|
|
835
|
+
border: 3px solid transparent;
|
|
836
|
+
background-clip: padding-box;
|
|
837
|
+
transition: background-color 0.2s;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
::-webkit-scrollbar-thumb:hover {
|
|
841
|
+
background-color: #94a3b8;
|
|
842
|
+
background-clip: padding-box;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
html.dark ::-webkit-scrollbar-thumb {
|
|
846
|
+
background: #475569;
|
|
847
|
+
background-clip: padding-box;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
html.dark ::-webkit-scrollbar-thumb:hover {
|
|
851
|
+
background-color: #64748b;
|
|
852
|
+
background-clip: padding-box;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
/* Firefox scrollbar */
|
|
856
|
+
* {
|
|
857
|
+
scrollbar-width: thin;
|
|
858
|
+
scrollbar-color: #cbd5e1 transparent;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
html.dark * {
|
|
862
|
+
scrollbar-color: #475569 transparent;
|
|
863
|
+
}
|
|
864
|
+
|
|
820
865
|
/* ===== RESPONSIVE: TABLET ===== */
|
|
821
866
|
@media (min-width: 769px) and (max-width: 1024px) {
|
|
822
867
|
:root { --sidebar-width: 260px; }
|