import type { Message, Part } from "@opencode-ai/sdk/v2/client" import { useCallback } from "react" import { opencodeClient } from "@/lib/opencode/client" import { useDirectoryStore, useSyncDirectory } from "./sync-context" import { useSync } from "./use-sync" // --------------------------------------------------------------------------- // Ascending ID generator — monotonic timestamp + sequence counter // --------------------------------------------------------------------------- let counter = 0 function ascending(prefix: string): string { const now = Date.now() const seq = (counter++ % 1000).toString().padStart(3, "0") return `${prefix}_${now}${seq}` } // --------------------------------------------------------------------------- // Prompt submission with optimistic updates // Prompt submission with optimistic message insertion // --------------------------------------------------------------------------- export type SubmitInput = { sessionID: string text: string parts?: Part[] agent: string model: { providerID: string; modelID: string } variant?: string command?: { name: string; arguments: string } images?: Array<{ id?: string; type: "file"; mime: string; url: string; filename: string }> } export function usePromptSubmit() { const store = useDirectoryStore() const directory = useSyncDirectory() const sync = useSync() const submit = useCallback( async (input: SubmitInput) => { const messageID = ascending("message") // Build optimistic user message const message: Message = { id: messageID, sessionID: input.sessionID, role: "user", time: { created: Date.now() }, agent: input.agent, model: input.model, variant: input.variant, } as Message // Build optimistic parts const textPart: Part = { id: ascending("part"), sessionID: input.sessionID, messageID, type: "text", text: input.text, } as Part const optimisticParts: Part[] = [textPart, ...(input.parts ?? [])] // Set busy status optimistically store.setState((prev) => ({ ...prev, session_status: { ...prev.session_status, [input.sessionID]: { type: "busy" }, }, })) // Add optimistic message immediately sync.optimistic.add({ sessionID: input.sessionID, message, parts: optimisticParts, }) try { if (input.command) { // Slash command await opencodeClient.sendCommand({ id: input.sessionID, command: input.command?.name ?? "", arguments: input.command?.arguments ?? "", agent: input.agent, providerID: input.model.providerID, modelID: input.model.modelID, variant: input.variant, files: input.images, messageId: messageID, directory, }).then(() => undefined) } else { // Regular prompt await opencodeClient.sendMessage({ id: input.sessionID, agent: input.agent, providerID: input.model.providerID, modelID: input.model.modelID, messageId: messageID, text: input.text, files: input.images, variant: input.variant, directory, }).then(() => undefined) } return true } catch (error) { // Revert optimistic on failure sync.optimistic.remove({ sessionID: input.sessionID, messageID, }) // Reset status store.setState((prev) => ({ ...prev, session_status: { ...prev.session_status, [input.sessionID]: { type: "idle" }, }, })) throw error } }, [directory, store, sync], ) return submit }