fix: parse actual event structure from logs
Реальная структура событий из логов: - session.text.delta: data.sessionID + data.delta (чанки текста) - session.text.ended: data.sessionID + data.text (полный текст) - session.reasoning.delta: data.delta (рассуждения) - session.reasoning.ended: data.text (полные рассуждения) Ранний парсинг не работал — искал в event.data.delta, но sessionID был в event.data.sessionID (не event.sessionID). Теперь: - session.text.delta → собираем data.delta по чанкам - session.text.ended → заменяем на data.text (полный) - session.reasoning.* → тоже собираем - resolve при первом тексте
This commit is contained in:
parent
9276de3c94
commit
76db8b5d36
96
index.ts
96
index.ts
|
|
@ -110,65 +110,21 @@ async function runPlugin(ctx: any, options: any, dataDir: string) {
|
|||
try {
|
||||
eventData = JSON.parse(event)
|
||||
} catch {
|
||||
// not JSON — log raw for debugging
|
||||
log(`Raw event (not JSON): ${event.slice(0, 200)}`)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
const eventType = eventData?.type || ""
|
||||
const sessionId = eventData?.sessionID || eventData?.session?.id || ""
|
||||
|
||||
// Log ALL session events for debugging
|
||||
if (eventType.includes("session") || sessionId) {
|
||||
const preview = JSON.stringify(eventData).slice(0, 500)
|
||||
log(`Event: type=${eventType}, session=${sessionId}, data=${preview}`)
|
||||
}
|
||||
|
||||
// Check if this event has response text for a pending prompt
|
||||
if (sessionId && pendingResponses.has(sessionId)) {
|
||||
// Session text delta — streaming text chunks
|
||||
// Structure: { type: "session.text.delta", data: { sessionID, delta: "text" } }
|
||||
if (eventType === "session.text.delta") {
|
||||
const sessionId = eventData?.data?.sessionID || ""
|
||||
const delta = eventData?.data?.delta || ""
|
||||
if (sessionId && delta && pendingResponses.has(sessionId)) {
|
||||
const pending = pendingResponses.get(sessionId)!
|
||||
|
||||
// Try multiple structures to extract assistant text
|
||||
let newText = ""
|
||||
|
||||
// 1. event.data.content[].text (assistant text parts)
|
||||
const parts = eventData?.data?.content || eventData?.content || eventData?.update?.content
|
||||
if (Array.isArray(parts)) {
|
||||
for (const part of parts) {
|
||||
if (part?.type === "text" && part?.text) {
|
||||
newText += part.text
|
||||
}
|
||||
}
|
||||
}
|
||||
// 2. event.data.text (direct text)
|
||||
if (!newText && typeof eventData?.data?.text === "string") {
|
||||
newText = eventData.data.text
|
||||
}
|
||||
// 3. event.data.message.text (message text)
|
||||
if (!newText && eventData?.data?.message?.text) {
|
||||
newText = eventData.data.message.text
|
||||
}
|
||||
// 4. event.payload.text (synthetic message)
|
||||
if (!newText && typeof eventData?.payload?.text === "string") {
|
||||
newText = eventData.payload.text
|
||||
}
|
||||
// 5. event.update.content (simple content update)
|
||||
if (!newText && typeof eventData?.update?.content === "string") {
|
||||
newText = eventData.update.content
|
||||
}
|
||||
// 6. event.delta (streaming delta)
|
||||
if (!newText && typeof eventData?.delta === "string") {
|
||||
newText = eventData.delta
|
||||
}
|
||||
// 7. event.content (direct content)
|
||||
if (!newText && typeof eventData?.content === "string") {
|
||||
newText = eventData.content
|
||||
}
|
||||
|
||||
if (newText) {
|
||||
pending.text += newText
|
||||
log(`Collected ${newText.length} chars, total: ${pending.text.length} chars for session ${sessionId}`)
|
||||
pending.text += delta
|
||||
log(`Collected delta: ${delta.length} chars, total: ${pending.text.length} chars for session ${sessionId}`)
|
||||
// Resolve immediately when we get any text
|
||||
const timer = (pending as any)._safetyTimer
|
||||
if (timer) clearTimeout(timer)
|
||||
|
|
@ -176,6 +132,42 @@ async function runPlugin(ctx: any, options: any, dataDir: string) {
|
|||
pending.resolve(pending.text)
|
||||
}
|
||||
}
|
||||
|
||||
// Session text ended — complete text available
|
||||
// Structure: { type: "session.text.ended", data: { sessionID, text: "full text" } }
|
||||
if (eventType === "session.text.ended") {
|
||||
const sessionId = eventData?.data?.sessionID || ""
|
||||
const fullText = eventData?.data?.text || ""
|
||||
if (sessionId && fullText && pendingResponses.has(sessionId)) {
|
||||
const pending = pendingResponses.get(sessionId)!
|
||||
pending.text = fullText
|
||||
log(`Collected ended text: ${fullText.length} chars for session ${sessionId}`)
|
||||
const timer = (pending as any)._safetyTimer
|
||||
if (timer) clearTimeout(timer)
|
||||
pendingResponses.delete(sessionId)
|
||||
pending.resolve(pending.text)
|
||||
}
|
||||
}
|
||||
|
||||
// Session reasoning delta — also collect (optional, for full response)
|
||||
if (eventType === "session.reasoning.delta") {
|
||||
const sessionId = eventData?.data?.sessionID || ""
|
||||
const delta = eventData?.data?.delta || ""
|
||||
if (sessionId && delta && pendingResponses.has(sessionId)) {
|
||||
const pending = pendingResponses.get(sessionId)!
|
||||
pending.text += delta
|
||||
}
|
||||
}
|
||||
|
||||
// Session reasoning ended — full reasoning text
|
||||
if (eventType === "session.reasoning.ended") {
|
||||
const sessionId = eventData?.data?.sessionID || ""
|
||||
const text = eventData?.data?.text || ""
|
||||
if (sessionId && text && pendingResponses.has(sessionId)) {
|
||||
const pending = pendingResponses.get(sessionId)!
|
||||
pending.text += text
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (String(err).includes("AbortError") || (err as { name?: string }).name === "AbortError") {
|
||||
|
|
|
|||
Loading…
Reference in New Issue