| 59 | |
| 60 | // Render messages |
| 61 | function renderMessages(messages) { |
| 62 | if (!messagesContainer) return |
| 63 | |
| 64 | messagesContainer.innerHTML = '' |
| 65 | |
| 66 | messages.forEach((message) => { |
| 67 | const messageDiv = document.createElement('div') |
| 68 | messageDiv.className = `message ${message.role}` |
| 69 | |
| 70 | if (message.role === 'user') { |
| 71 | // Extract text content from parts |
| 72 | const textParts = message.parts.filter((p) => p.type === 'text') |
| 73 | const content = textParts.map((p) => p.content).join('') |
| 74 | |
| 75 | messageDiv.innerHTML = ` |
| 76 | <div class="message-content">${escapeHtml(content)}</div> |
| 77 | ` |
| 78 | } else if (message.role === 'assistant') { |
| 79 | // Render parts in their original order (maintains chronological flow) |
| 80 | const partsHtml = message.parts |
| 81 | .map((part) => { |
| 82 | if (part.type === 'thinking') { |
| 83 | return `<div class="thinking">${escapeHtml(part.content)}</div>` |
| 84 | } else if (part.type === 'text') { |
| 85 | return `<div class="message-content">${escapeHtml(part.content)}</div>` |
| 86 | } else if (part.type === 'tool-call') { |
| 87 | return ` |
| 88 | <div class="tool-call"> |
| 89 | <div> |
| 90 | <span class="tool-name">${escapeHtml(part.name)}</span> |
| 91 | <span class="tool-state">${escapeHtml(part.state)}</span> |
| 92 | </div> |
| 93 | <pre class="tool-args">${escapeHtml(part.arguments)}</pre> |
| 94 | ${part.output ? `<pre class="tool-output">${escapeHtml(JSON.stringify(part.output, null, 2))}</pre>` : ''} |
| 95 | </div> |
| 96 | ` |
| 97 | } else if (part.type === 'tool-result') { |
| 98 | return ` |
| 99 | <div class="tool-result"> |
| 100 | <div class="tool-result-label">Tool Result:</div> |
| 101 | <pre class="tool-result-content">${escapeHtml(part.content)}</pre> |
| 102 | </div> |
| 103 | ` |
| 104 | } |
| 105 | return '' |
| 106 | }) |
| 107 | .join('') |
| 108 | |
| 109 | messageDiv.innerHTML = partsHtml |
| 110 | } |
| 111 | |
| 112 | messagesContainer.appendChild(messageDiv) |
| 113 | }) |
| 114 | |
| 115 | // Scroll to bottom |
| 116 | messagesContainer.scrollTop = messagesContainer.scrollHeight |
| 117 | } |
| 118 | |