mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
c513ad22d7
- move chat controller, state, protocol, history, and websocket logic into a dedicated chat feature module - improve chat reconnection, session hydration, and send gating based on actual websocket state - preserve gateway status during transient SSE disconnects and update stop state immediately - generate wss websocket URLs behind HTTPS proxies and add backend tests for forwarded proto handling
82 lines
1.9 KiB
TypeScript
82 lines
1.9 KiB
TypeScript
import { normalizeUnixTimestamp } from "@/features/chat/state"
|
|
import { updateChatStore } from "@/store/chat"
|
|
|
|
export interface PicoMessage {
|
|
type: string
|
|
id?: string
|
|
session_id?: string
|
|
timestamp?: number | string
|
|
payload?: Record<string, unknown>
|
|
}
|
|
|
|
export function handlePicoMessage(
|
|
message: PicoMessage,
|
|
expectedSessionId: string,
|
|
) {
|
|
if (message.session_id && message.session_id !== expectedSessionId) {
|
|
return
|
|
}
|
|
|
|
const payload = message.payload || {}
|
|
|
|
switch (message.type) {
|
|
case "message.create": {
|
|
const content = (payload.content as string) || ""
|
|
const messageId = (payload.message_id as string) || `pico-${Date.now()}`
|
|
const timestamp =
|
|
message.timestamp !== undefined &&
|
|
Number.isFinite(Number(message.timestamp))
|
|
? normalizeUnixTimestamp(Number(message.timestamp))
|
|
: Date.now()
|
|
|
|
updateChatStore((prev) => ({
|
|
messages: [
|
|
...prev.messages,
|
|
{
|
|
id: messageId,
|
|
role: "assistant",
|
|
content,
|
|
timestamp,
|
|
},
|
|
],
|
|
isTyping: false,
|
|
}))
|
|
break
|
|
}
|
|
|
|
case "message.update": {
|
|
const content = (payload.content as string) || ""
|
|
const messageId = payload.message_id as string
|
|
if (!messageId) {
|
|
break
|
|
}
|
|
|
|
updateChatStore((prev) => ({
|
|
messages: prev.messages.map((msg) =>
|
|
msg.id === messageId ? { ...msg, content } : msg,
|
|
),
|
|
}))
|
|
break
|
|
}
|
|
|
|
case "typing.start":
|
|
updateChatStore({ isTyping: true })
|
|
break
|
|
|
|
case "typing.stop":
|
|
updateChatStore({ isTyping: false })
|
|
break
|
|
|
|
case "error":
|
|
console.error("Pico error:", payload)
|
|
updateChatStore({ isTyping: false })
|
|
break
|
|
|
|
case "pong":
|
|
break
|
|
|
|
default:
|
|
console.log("Unknown pico message type:", message.type)
|
|
}
|
|
}
|