diff --git a/index.ts b/index.ts index 09912b0..dd2ffc5 100644 --- a/index.ts +++ b/index.ts @@ -93,10 +93,11 @@ async function runPlugin(ctx: any, options: any, dataDir: string) { // Track Matrix context per OpenCode session const sessionContextMap = new Map() - // Pending prompt responses — maps sessionID -> { resolve, reject } + // Pending prompt responses — maps sessionID -> { resolve, reject, reasoning } const pendingResponses = new Map void reject: (err: any) => void + reasoning: string }>() // V2 Event subscription — waits for response completion signals @@ -112,21 +113,41 @@ async function runPlugin(ctx: any, options: any, dataDir: string) { const eventType = eventData?.type || "" const sessionId = eventData?.data?.sessionID || "" + // Session reasoning delta — streaming reasoning chunks + if (eventType === "session.reasoning.delta" && sessionId && pendingResponses.has(sessionId)) { + const delta = eventData?.data?.delta || "" + pendingResponses.get(sessionId)!.reasoning += delta + continue + } + + // Session reasoning ended — full reasoning text + if (eventType === "session.reasoning.ended" && sessionId && pendingResponses.has(sessionId)) { + const text = eventData?.data?.text || "" + pendingResponses.get(sessionId)!.reasoning = text + continue + } + // Response text complete — full assembled text available // Structure: { type: "session.text.ended", data: { sessionID, text: "full text" } } if (eventType === "session.text.ended" && sessionId && pendingResponses.has(sessionId)) { const fullText = eventData?.data?.text || "" const pending = pendingResponses.get(sessionId)! - log(`Response ready: ${fullText.length} chars for session ${sessionId}`) pendingResponses.delete(sessionId) - pending.resolve(fullText) + + // Combine reasoning (in spoiler) + main text + let responseText = fullText + if (pending.reasoning) { + responseText = `
\nThinking\n\n${pending.reasoning}\n\n
\n\n---\n\n${fullText}` + } + + log(`Response ready: ${responseText.length} chars (${pending.reasoning ? 'with reasoning' : 'no reasoning'}) for session ${sessionId}`) + pending.resolve(responseText) continue } // Execution failed — session errored if (eventType === "session.execution.failed" && sessionId && pendingResponses.has(sessionId)) { const pending = pendingResponses.get(sessionId)! - log(`Session ${sessionId} execution failed`) pendingResponses.delete(sessionId) pending.reject(new Error("Session execution failed")) continue @@ -135,7 +156,6 @@ async function runPlugin(ctx: any, options: any, dataDir: string) { // Execution interrupted — session was interrupted if (eventType === "session.execution.interrupted" && sessionId && pendingResponses.has(sessionId)) { const pending = pendingResponses.get(sessionId)! - log(`Session ${sessionId} execution interrupted`) pendingResponses.delete(sessionId) pending.reject(new Error("Session execution interrupted")) continue @@ -222,7 +242,7 @@ async function runPlugin(ctx: any, options: any, dataDir: string) { // Resolved by: session.text.ended (success) // Rejected by: session.execution.failed / session.execution.interrupted const responsePromise = new Promise((resolve, reject) => { - pendingResponses.set(opencodeSessionId, { resolve, reject }) + pendingResponses.set(opencodeSessionId, { resolve, reject, reasoning: "" }) }) const responseText = await responsePromise