128 lines
4.3 KiB
TypeScript
128 lines
4.3 KiB
TypeScript
import type { PluginInput } from "@opencode-ai/plugin"
|
|
import type { ToolContext } from "@opencode-ai/plugin/tool"
|
|
import { log, promptSyncWithModelSuggestionRetry } from "../../shared"
|
|
import { extractLatestAssistantText } from "./assistant-message-extractor"
|
|
import { MULTIMODAL_LOOKER_AGENT } from "./constants"
|
|
import { READ_ENABLED, buildLookAtPrompt } from "./look-at-prompt"
|
|
import type { LookAtFilePart } from "./look-at-input-preparer"
|
|
import { resolveMultimodalLookerAgentMetadata } from "./multimodal-agent-metadata"
|
|
import { waitForLookAtSessionResult } from "./session-poller"
|
|
|
|
interface RunLookAtSessionInput {
|
|
ctx: PluginInput
|
|
toolContext: ToolContext
|
|
goal: string
|
|
filePart: LookAtFilePart
|
|
isBase64Input: boolean
|
|
}
|
|
|
|
export async function runLookAtSession({
|
|
ctx,
|
|
toolContext,
|
|
goal,
|
|
filePart,
|
|
isBase64Input,
|
|
}: RunLookAtSessionInput): Promise<string> {
|
|
const prompt = buildLookAtPrompt(goal, isBase64Input)
|
|
const { agentModel, agentVariant } = await resolveMultimodalLookerAgentMetadata(ctx)
|
|
|
|
log(`[look_at] Creating session with parent: ${toolContext.sessionID}`)
|
|
const parentSession = await ctx.client.session.get({
|
|
path: { id: toolContext.sessionID },
|
|
}).catch(() => null)
|
|
const parentDirectory = parentSession?.data?.directory ?? ctx.directory
|
|
|
|
const createResult = await ctx.client.session.create({
|
|
body: {
|
|
parentID: toolContext.sessionID,
|
|
title: `look_at: ${goal.substring(0, 50)}`,
|
|
},
|
|
query: { directory: parentDirectory },
|
|
})
|
|
|
|
if (createResult.error) {
|
|
log("[look_at] Session create error:", createResult.error)
|
|
const errorString = String(createResult.error)
|
|
if (errorString.toLowerCase().includes("unauthorized")) {
|
|
return `Error: Failed to create session (Unauthorized). This may be due to:
|
|
1. OAuth token restrictions (e.g., Claude Code credentials are restricted to Claude Code only)
|
|
2. Provider authentication issues
|
|
3. Session permission inheritance problems
|
|
|
|
Try using a different provider or API key authentication.
|
|
|
|
Original error: ${createResult.error}`
|
|
}
|
|
|
|
return `Error: Failed to create session: ${createResult.error}`
|
|
}
|
|
|
|
const sessionID = createResult.data.id
|
|
log(`[look_at] Created session: ${sessionID}`)
|
|
|
|
log(`[look_at] Sending prompt with ${isBase64Input ? "base64 image" : "file"} to session ${sessionID}`)
|
|
let promptFailed = false
|
|
try {
|
|
await promptSyncWithModelSuggestionRetry(ctx.client, {
|
|
path: { id: sessionID },
|
|
body: {
|
|
agent: MULTIMODAL_LOOKER_AGENT,
|
|
tools: {
|
|
task: false,
|
|
call_omo_agent: false,
|
|
look_at: false,
|
|
read: READ_ENABLED,
|
|
},
|
|
parts: [
|
|
{ type: "text", text: prompt },
|
|
filePart,
|
|
],
|
|
...(agentModel ? { model: { providerID: agentModel.providerID, modelID: agentModel.modelID } } : {}),
|
|
...(agentVariant ? { variant: agentVariant } : {}),
|
|
},
|
|
}, {
|
|
queueBehavior: "defer",
|
|
})
|
|
} catch (promptError) {
|
|
promptFailed = true
|
|
log("[look_at] Prompt error (ignored, will still fetch messages):", promptError)
|
|
}
|
|
|
|
let observedMessages: unknown[] | undefined
|
|
let observedText: string | undefined
|
|
if (typeof ctx.client.session.status === "function") {
|
|
const waitResult = await waitForLookAtSessionResult(ctx.client, sessionID, {
|
|
allowStableIdleWithoutActivity: true,
|
|
allowEmptyStableIdleWithoutActivity: promptFailed,
|
|
})
|
|
observedText = waitResult.outcome.text ?? undefined
|
|
if (observedText) {
|
|
observedMessages = waitResult.messages
|
|
}
|
|
}
|
|
|
|
let messages = observedMessages
|
|
if (!messages) {
|
|
log(`[look_at] Fetching messages from session ${sessionID}...`)
|
|
const messagesResult = await ctx.client.session.messages({
|
|
path: { id: sessionID },
|
|
})
|
|
|
|
if (messagesResult.error) {
|
|
log("[look_at] Messages error:", messagesResult.error)
|
|
return `Error: Failed to get messages: ${messagesResult.error}`
|
|
}
|
|
messages = messagesResult.data
|
|
}
|
|
log(`[look_at] Got ${messages.length} messages`)
|
|
|
|
const responseText = observedText ?? extractLatestAssistantText(messages)
|
|
if (!responseText) {
|
|
log("[look_at] No assistant message found")
|
|
return "Error: No response from multimodal-looker agent"
|
|
}
|
|
|
|
log(`[look_at] Got response, length: ${responseText.length}`)
|
|
return responseText
|
|
}
|