(content: string)
| 213 | // ================== |
| 214 | |
| 215 | const sendMessage = async (content: string) => { |
| 216 | if (!content.trim()) return; |
| 217 | |
| 218 | // 创建用户消息 |
| 219 | const userMessage: TextMessage = { |
| 220 | id: generateId("msg"), |
| 221 | type: "text", |
| 222 | role: "user", |
| 223 | content: { text: content }, |
| 224 | createdAt: Date.now(), |
| 225 | status: "pending", |
| 226 | }; |
| 227 | chatStore.addMessage(userMessage); |
| 228 | |
| 229 | // 创建助手消息占位符(使用 reactive 确保响应式) |
| 230 | const assistantMessage: TextMessage = reactive({ |
| 231 | id: generateId("msg"), |
| 232 | type: "text", |
| 233 | role: "assistant", |
| 234 | content: { text: "" }, |
| 235 | createdAt: Date.now(), |
| 236 | }) as TextMessage; |
| 237 | chatStore.addMessage(assistantMessage); |
| 238 | |
| 239 | chatStore.setTyping(true); |
| 240 | chatStore.updateAgentStatus("thinking"); |
| 241 | userMessage.status = "sent"; |
| 242 | chatStore.setCurrentInput(""); |
| 243 | |
| 244 | try { |
| 245 | if (isDemoMode) { |
| 246 | // Demo 模式 |
| 247 | await new Promise((resolve) => setTimeout(resolve, config.demoDelay ?? 800)); |
| 248 | (assistantMessage.content as { text: string }).text = pickDemoResponse(content); |
| 249 | assistantMessage.status = "sent"; |
| 250 | chatStore.setTyping(false); |
| 251 | chatStore.updateAgentStatus("idle"); |
| 252 | } else { |
| 253 | // WebSocket 流式模式 |
| 254 | const ws = getInstance(); |
| 255 | |
| 256 | if (ws && wsConnected.value) { |
| 257 | // 监听 WebSocket 消息 |
| 258 | const unsubscribe = ws.onMessage((message: any) => { |
| 259 | if (message.type === "text_delta" && message.payload?.text) { |
| 260 | // 使用批量更新优化性能 |
| 261 | chatStore.handleTextChunk(assistantMessage.id, message.payload.text); |
| 262 | } else if (message.type === "chat_complete") { |
| 263 | assistantMessage.status = "sent"; |
| 264 | chatStore.setTyping(false); |
| 265 | chatStore.updateAgentStatus("idle"); |
| 266 | unsubscribe(); |
| 267 | |
| 268 | // 触发回调 |
| 269 | if (config.onReceive) { |
| 270 | config.onReceive(assistantMessage); |
| 271 | } |
| 272 | } else if (message.type === "error") { |
no test coverage detected