agentgui 1.0.85 → 1.0.86
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/package.json +1 -1
- package/server.js +13 -10
- package/static/index.html +100 -0
- package/static/js/client.js +93 -0
- package/static/js/conversations.js +1 -0
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -65,13 +65,16 @@ const server = http.createServer(async (req, res) => {
|
|
|
65
65
|
const routePath = req.url.slice(BASE_URL.length) || '/';
|
|
66
66
|
|
|
67
67
|
try {
|
|
68
|
-
|
|
68
|
+
// Remove query parameters from routePath for matching
|
|
69
|
+
const pathOnly = routePath.split('?')[0];
|
|
70
|
+
|
|
71
|
+
if (pathOnly === '/api/conversations' && req.method === 'GET') {
|
|
69
72
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
70
73
|
res.end(JSON.stringify({ conversations: queries.getConversationsList() }));
|
|
71
74
|
return;
|
|
72
75
|
}
|
|
73
76
|
|
|
74
|
-
if (
|
|
77
|
+
if (pathOnly === '/api/conversations' && req.method === 'POST') {
|
|
75
78
|
const body = await parseBody(req);
|
|
76
79
|
const conversation = queries.createConversation(body.agentId, body.title);
|
|
77
80
|
queries.createEvent('conversation.created', { agentId: body.agentId }, conversation.id);
|
|
@@ -81,7 +84,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
81
84
|
return;
|
|
82
85
|
}
|
|
83
86
|
|
|
84
|
-
const convMatch =
|
|
87
|
+
const convMatch = pathOnly.match(/^\/api\/conversations\/([^/]+)$/);
|
|
85
88
|
if (convMatch) {
|
|
86
89
|
if (req.method === 'GET') {
|
|
87
90
|
const conv = queries.getConversation(convMatch[1]);
|
|
@@ -111,7 +114,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
111
114
|
}
|
|
112
115
|
}
|
|
113
116
|
|
|
114
|
-
const messagesMatch =
|
|
117
|
+
const messagesMatch = pathOnly.match(/^\/api\/conversations\/([^/]+)\/messages$/);
|
|
115
118
|
if (messagesMatch) {
|
|
116
119
|
if (req.method === 'GET') {
|
|
117
120
|
const url = new URL(req.url, 'http://localhost');
|
|
@@ -141,7 +144,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
141
144
|
}
|
|
142
145
|
}
|
|
143
146
|
|
|
144
|
-
const streamMatch =
|
|
147
|
+
const streamMatch = pathOnly.match(/^\/api\/conversations\/([^/]+)\/stream$/);
|
|
145
148
|
if (streamMatch && req.method === 'POST') {
|
|
146
149
|
const conversationId = streamMatch[1];
|
|
147
150
|
const body = await parseBody(req);
|
|
@@ -180,7 +183,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
180
183
|
return;
|
|
181
184
|
}
|
|
182
185
|
|
|
183
|
-
const messageMatch =
|
|
186
|
+
const messageMatch = pathOnly.match(/^\/api\/conversations\/([^/]+)\/messages\/([^/]+)$/);
|
|
184
187
|
if (messageMatch && req.method === 'GET') {
|
|
185
188
|
const msg = queries.getMessage(messageMatch[2]);
|
|
186
189
|
if (!msg || msg.conversationId !== messageMatch[1]) { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Not found' })); return; }
|
|
@@ -189,7 +192,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
189
192
|
return;
|
|
190
193
|
}
|
|
191
194
|
|
|
192
|
-
const sessionMatch =
|
|
195
|
+
const sessionMatch = pathOnly.match(/^\/api\/sessions\/([^/]+)$/);
|
|
193
196
|
if (sessionMatch && req.method === 'GET') {
|
|
194
197
|
const sess = queries.getSession(sessionMatch[1]);
|
|
195
198
|
if (!sess) { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Not found' })); return; }
|
|
@@ -199,8 +202,8 @@ const server = http.createServer(async (req, res) => {
|
|
|
199
202
|
return;
|
|
200
203
|
}
|
|
201
204
|
|
|
202
|
-
if (
|
|
203
|
-
const convId =
|
|
205
|
+
if (pathOnly.match(/^\/api\/conversations\/([^/]+)\/sessions\/latest$/) && req.method === 'GET') {
|
|
206
|
+
const convId = pathOnly.match(/^\/api\/conversations\/([^/]+)\/sessions\/latest$/)[1];
|
|
204
207
|
const latestSession = queries.getLatestSession(convId);
|
|
205
208
|
if (!latestSession) {
|
|
206
209
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
@@ -213,7 +216,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
213
216
|
return;
|
|
214
217
|
}
|
|
215
218
|
|
|
216
|
-
const executionMatch =
|
|
219
|
+
const executionMatch = pathOnly.match(/^\/api\/sessions\/([^/]+)\/execution$/);
|
|
217
220
|
if (executionMatch && req.method === 'GET') {
|
|
218
221
|
const sessionId = executionMatch[1];
|
|
219
222
|
const url = new URL(req.url, 'http://localhost');
|
package/static/index.html
CHANGED
|
@@ -359,6 +359,106 @@
|
|
|
359
359
|
font-size: 0.7rem;
|
|
360
360
|
}
|
|
361
361
|
|
|
362
|
+
/* Conversation display */
|
|
363
|
+
.conversation-header {
|
|
364
|
+
padding: 1rem;
|
|
365
|
+
border-bottom: 1px solid var(--color-border);
|
|
366
|
+
margin-bottom: 1rem;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
.conversation-header h2 {
|
|
370
|
+
margin: 0 0 0.5rem 0;
|
|
371
|
+
font-size: 1.5rem;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.conversation-header p {
|
|
375
|
+
margin: 0;
|
|
376
|
+
font-size: 0.875rem;
|
|
377
|
+
color: var(--color-text-secondary);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.conversation-messages {
|
|
381
|
+
padding: 1rem;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.message {
|
|
385
|
+
margin-bottom: 1rem;
|
|
386
|
+
padding: 1rem;
|
|
387
|
+
border-radius: 0.375rem;
|
|
388
|
+
background-color: var(--color-bg-secondary);
|
|
389
|
+
border-left: 3px solid var(--color-primary);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.message-user {
|
|
393
|
+
border-left-color: var(--color-primary);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.message-assistant {
|
|
397
|
+
border-left-color: var(--color-success);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.message-role {
|
|
401
|
+
font-weight: 600;
|
|
402
|
+
font-size: 0.75rem;
|
|
403
|
+
text-transform: uppercase;
|
|
404
|
+
color: var(--color-text-secondary);
|
|
405
|
+
margin-bottom: 0.5rem;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.message-content {
|
|
409
|
+
font-size: 0.9rem;
|
|
410
|
+
line-height: 1.5;
|
|
411
|
+
white-space: pre-wrap;
|
|
412
|
+
word-break: break-word;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.message-timestamp {
|
|
416
|
+
font-size: 0.75rem;
|
|
417
|
+
color: var(--color-text-secondary);
|
|
418
|
+
margin-top: 0.5rem;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.message-blocks {
|
|
422
|
+
display: flex;
|
|
423
|
+
flex-direction: column;
|
|
424
|
+
gap: 0.75rem;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.message-text {
|
|
428
|
+
line-height: 1.6;
|
|
429
|
+
word-break: break-word;
|
|
430
|
+
white-space: pre-wrap;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.message-code {
|
|
434
|
+
background-color: var(--color-bg-code);
|
|
435
|
+
border-radius: 0.375rem;
|
|
436
|
+
padding: 0.75rem;
|
|
437
|
+
overflow-x: auto;
|
|
438
|
+
margin: 0.5rem 0;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
.message-code pre {
|
|
442
|
+
margin: 0;
|
|
443
|
+
font-family: 'Courier New', monospace;
|
|
444
|
+
font-size: 0.85rem;
|
|
445
|
+
color: #e0e0e0;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.message-tool {
|
|
449
|
+
background-color: var(--color-primary);
|
|
450
|
+
color: white;
|
|
451
|
+
padding: 0.25rem 0.5rem;
|
|
452
|
+
border-radius: 0.25rem;
|
|
453
|
+
font-size: 0.75rem;
|
|
454
|
+
display: inline-block;
|
|
455
|
+
margin: 0.25rem 0;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.text-secondary {
|
|
459
|
+
color: var(--color-text-secondary);
|
|
460
|
+
}
|
|
461
|
+
|
|
362
462
|
/* Responsive */
|
|
363
463
|
@media (max-width: 768px) {
|
|
364
464
|
.layout-with-sidebar {
|
package/static/js/client.js
CHANGED
|
@@ -170,6 +170,11 @@ class AgentGUIClient {
|
|
|
170
170
|
|
|
171
171
|
// Listen for new conversation creation
|
|
172
172
|
window.addEventListener('create-new-conversation', () => this.createNewConversation());
|
|
173
|
+
|
|
174
|
+
// Listen for conversation selection
|
|
175
|
+
window.addEventListener('conversation-selected', (event) => {
|
|
176
|
+
this.loadConversationMessages(event.detail.conversationId);
|
|
177
|
+
});
|
|
173
178
|
}
|
|
174
179
|
|
|
175
180
|
/**
|
|
@@ -517,6 +522,94 @@ class AgentGUIClient {
|
|
|
517
522
|
}
|
|
518
523
|
}
|
|
519
524
|
|
|
525
|
+
/**
|
|
526
|
+
* Load and display conversation messages
|
|
527
|
+
*/
|
|
528
|
+
async loadConversationMessages(conversationId) {
|
|
529
|
+
try {
|
|
530
|
+
this.state.currentConversation = { id: conversationId };
|
|
531
|
+
|
|
532
|
+
// Fetch conversation details
|
|
533
|
+
const convResponse = await fetch(window.__BASE_URL + `/api/conversations/${conversationId}`);
|
|
534
|
+
const { conversation } = await convResponse.json();
|
|
535
|
+
|
|
536
|
+
// Fetch messages
|
|
537
|
+
const messagesResponse = await fetch(window.__BASE_URL + `/api/conversations/${conversationId}/messages`);
|
|
538
|
+
if (!messagesResponse.ok) {
|
|
539
|
+
throw new Error(`Failed to fetch messages: ${messagesResponse.status}`);
|
|
540
|
+
}
|
|
541
|
+
const messagesData = await messagesResponse.json();
|
|
542
|
+
|
|
543
|
+
// Clear output and display conversation header
|
|
544
|
+
const outputEl = document.getElementById('output');
|
|
545
|
+
if (outputEl) {
|
|
546
|
+
outputEl.innerHTML = `
|
|
547
|
+
<div class="conversation-header">
|
|
548
|
+
<h2>${this.escapeHtml(conversation.title || 'Conversation')}</h2>
|
|
549
|
+
<p class="text-secondary">${conversation.agentType || 'unknown'} • ${new Date(conversation.created_at).toLocaleDateString()}</p>
|
|
550
|
+
</div>
|
|
551
|
+
<div class="conversation-messages">
|
|
552
|
+
${this.renderMessages(messagesData.messages || [])}
|
|
553
|
+
</div>
|
|
554
|
+
`;
|
|
555
|
+
}
|
|
556
|
+
} catch (error) {
|
|
557
|
+
console.error('Failed to load conversation messages:', error);
|
|
558
|
+
this.showError('Failed to load conversation: ' + error.message);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Render messages for display
|
|
564
|
+
*/
|
|
565
|
+
renderMessages(messages) {
|
|
566
|
+
if (messages.length === 0) {
|
|
567
|
+
return '<p class="text-secondary">No messages in this conversation yet</p>';
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
return messages.map(msg => {
|
|
571
|
+
let contentHtml = '';
|
|
572
|
+
|
|
573
|
+
// Handle different content types
|
|
574
|
+
if (typeof msg.content === 'string') {
|
|
575
|
+
contentHtml = `<div class="message-text">${this.escapeHtml(msg.content)}</div>`;
|
|
576
|
+
} else if (msg.content && typeof msg.content === 'object' && msg.content.type === 'claude_execution') {
|
|
577
|
+
// Handle Claude execution blocks
|
|
578
|
+
contentHtml = '<div class="message-blocks">';
|
|
579
|
+
if (msg.content.blocks && Array.isArray(msg.content.blocks)) {
|
|
580
|
+
msg.content.blocks.forEach(block => {
|
|
581
|
+
if (block.type === 'text') {
|
|
582
|
+
contentHtml += `<div class="message-text">${this.escapeHtml(block.text)}</div>`;
|
|
583
|
+
} else if (block.type === 'code_block') {
|
|
584
|
+
contentHtml += `<div class="message-code"><pre>${this.escapeHtml(block.code)}</pre></div>`;
|
|
585
|
+
} else if (block.type === 'tool_use') {
|
|
586
|
+
contentHtml += `<div class="message-tool">[Tool: ${this.escapeHtml(block.name)}]</div>`;
|
|
587
|
+
}
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
contentHtml += '</div>';
|
|
591
|
+
} else {
|
|
592
|
+
contentHtml = `<div class="message-text">${this.escapeHtml(JSON.stringify(msg.content))}</div>`;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
return `
|
|
596
|
+
<div class="message message-${msg.role}">
|
|
597
|
+
<div class="message-role">${msg.role.charAt(0).toUpperCase() + msg.role.slice(1)}</div>
|
|
598
|
+
${contentHtml}
|
|
599
|
+
<div class="message-timestamp">${new Date(msg.created_at).toLocaleString()}</div>
|
|
600
|
+
</div>
|
|
601
|
+
`;
|
|
602
|
+
}).join('');
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Escape HTML to prevent XSS
|
|
607
|
+
*/
|
|
608
|
+
escapeHtml(text) {
|
|
609
|
+
const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' };
|
|
610
|
+
return text.replace(/[&<>"']/g, c => map[c]);
|
|
611
|
+
}
|
|
612
|
+
|
|
520
613
|
/**
|
|
521
614
|
* Show error message
|
|
522
615
|
*/
|
|
@@ -65,6 +65,7 @@ class ConversationManager {
|
|
|
65
65
|
createConversationItem(conv) {
|
|
66
66
|
const li = document.createElement('li');
|
|
67
67
|
li.className = 'conversation-item';
|
|
68
|
+
li.dataset.convId = conv.id;
|
|
68
69
|
if (conv.id === this.activeId) li.classList.add('active');
|
|
69
70
|
|
|
70
71
|
const title = conv.title || `Conversation ${conv.id.slice(0, 8)}`;
|