diff --git a/index.ts b/index.ts index 3d161d2..cbe1e37 100644 --- a/index.ts +++ b/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)) { - 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}`) + // 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)! + 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") {