ff0e9ac557
Add SDKMessage local interface for message type safety Replace any lambda params and message casts with SDKMessage Remove eslint-disable comments for no-explicit-any Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
87 lines
3.1 KiB
TypeScript
87 lines
3.1 KiB
TypeScript
import type { PluginInput } from "@opencode-ai/plugin"
|
|
import { log } from "../../shared"
|
|
import { consumeNewMessages } from "../../shared/session-cursor"
|
|
|
|
interface SDKMessage {
|
|
info?: { role?: string; time?: { created?: number } }
|
|
parts?: Array<{ type: string; text?: string; content?: string | Array<{ type: string; text?: string }> }>
|
|
}
|
|
|
|
export async function processMessages(
|
|
sessionID: string,
|
|
ctx: PluginInput
|
|
): Promise<string> {
|
|
const messagesResult = await ctx.client.session.messages({
|
|
path: { id: sessionID },
|
|
})
|
|
|
|
if (messagesResult.error) {
|
|
log(`[call_omo_agent] Messages error:`, messagesResult.error)
|
|
throw new Error(`Failed to get messages: ${messagesResult.error}`)
|
|
}
|
|
|
|
const messages = messagesResult.data
|
|
log(`[call_omo_agent] Got ${messages.length} messages`)
|
|
|
|
// Include both assistant messages AND tool messages
|
|
// Tool results (grep, glob, bash output) come from role "tool"
|
|
const relevantMessages = messages.filter(
|
|
(m: SDKMessage) => m.info?.role === "assistant" || m.info?.role === "tool"
|
|
)
|
|
|
|
if (relevantMessages.length === 0) {
|
|
log(`[call_omo_agent] No assistant or tool messages found`)
|
|
log(`[call_omo_agent] All messages:`, JSON.stringify(messages, null, 2))
|
|
throw new Error("No assistant or tool response found")
|
|
}
|
|
|
|
log(`[call_omo_agent] Found ${relevantMessages.length} relevant messages`)
|
|
|
|
// Sort by time ascending (oldest first) to process messages in order
|
|
const sortedMessages = [...relevantMessages].sort((a: SDKMessage, b: SDKMessage) => {
|
|
const timeA = a.info?.time?.created ?? 0
|
|
const timeB = b.info?.time?.created ?? 0
|
|
return timeA - timeB
|
|
})
|
|
|
|
const newMessages = consumeNewMessages(sessionID, sortedMessages)
|
|
|
|
if (newMessages.length === 0) {
|
|
return "No new output since last check."
|
|
}
|
|
|
|
// Extract content from ALL messages, not just the last one
|
|
// Tool results may be in earlier messages while the final message is empty
|
|
const extractedContent: string[] = []
|
|
|
|
for (const message of newMessages) {
|
|
for (const part of message.parts ?? []) {
|
|
// Handle both "text" and "reasoning" parts (thinking models use "reasoning")
|
|
if ((part.type === "text" || part.type === "reasoning") && part.text) {
|
|
extractedContent.push(part.text)
|
|
} else if ((part.type as string) === "tool_result") {
|
|
// Tool results contain the actual output from tool calls
|
|
const toolResult = part as { content?: string | Array<{ type: string; text?: string }> }
|
|
if (typeof toolResult.content === "string" && toolResult.content) {
|
|
extractedContent.push(toolResult.content)
|
|
} else if (Array.isArray(toolResult.content)) {
|
|
// Handle array of content blocks
|
|
for (const block of toolResult.content) {
|
|
if ((block.type === "text" || block.type === "reasoning") && block.text) {
|
|
extractedContent.push(block.text)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const responseText = extractedContent
|
|
.filter((text) => text.length > 0)
|
|
.join("\n\n")
|
|
|
|
log(`[call_omo_agent] Got response, length: ${responseText.length}`)
|
|
|
|
return responseText
|
|
}
|