import { Router } from 'express' import { createOpencodeClient } from '@opencode-ai/sdk' const OPENCODE_URL = 'http://localhost:4096' async function getClient() { console.log('[OpenCode] Creating client for URL:', OPENCODE_URL) return createOpencodeClient({ baseUrl: OPENCODE_URL, }) } export function createOpencodeRoutes(): Router { const router = Router() router.get('/', async (req, res) => { const action = req.query.action as string | undefined try { const client = await getClient() if (action === 'list-sessions') { const response = await client.session.list() const sessions = (response.data || []).map((session: { id: string; title?: string; createdAt?: string }) => ({ id: session.id, title: session.title || 'New Chat', createdAt: session.createdAt ? new Date(session.createdAt).getTime() : Date.now(), })) res.json({ sessions }) return } res.status(400).json({ error: 'Unknown action' }) } catch (error: unknown) { console.error('API error:', error) const errorMessage = error instanceof Error ? error.message : 'Unknown error' res.status(500).json({ error: errorMessage }) } }) router.post('/', async (req, res) => { try { const body = req.body const { action, sessionId, title, text, attachments } = body console.log('[OpenCode] Received action:', action, 'sessionId:', sessionId) const client = await getClient() console.log('[OpenCode] Client created successfully') if (action === 'create-session') { try { const response = await client.session.create({ body: { title: title || 'New Chat' }, }) if (response.error) { res.status(500).json({ error: 'OpenCode error', details: response.error }) return } const sessionData = response.data as { id: string; title?: string; createdAt?: string } | undefined if (sessionData) { res.json({ session: { id: sessionData.id, title: sessionData.title, createdAt: sessionData.createdAt ? new Date(sessionData.createdAt).getTime() : Date.now(), }, }) return } res.status(500).json({ error: 'Failed to create session - no data' }) return } catch (e: unknown) { console.error('Create session exception:', e) const errorMessage = e instanceof Error ? e.message : 'Unknown error' res.status(500).json({ error: errorMessage, exception: true }) return } } if (action === 'delete-session') { const response = await client.session.delete({ path: { id: sessionId }, }) res.json({ success: response.data }) return } if (action === 'get-session') { const response = await client.session.get({ path: { id: sessionId }, }) if (response.data) { res.json({ title: response.data.title || 'New Chat', }) return } res.status(404).json({ error: 'Session not found' }) return } if (action === 'get-messages') { const limit = body.limit || 20 const response = await client.session.messages({ path: { id: sessionId }, query: { limit } }) const messages = (response.data || []).map((item: { info?: { id?: string; role?: string; content?: string; createdAt?: string }; content?: string; parts?: unknown[]; id?: string; role?: string }) => { let content = item.info?.content || item.content || '' const parts = item.parts as Array<{ type: string; text?: string }> | undefined if (parts && parts.length > 0) { const textParts = parts .filter((p) => p.type === 'text') .map((p) => p.text) .join('') if (textParts) { content = textParts } } return { id: item.info?.id || item.id, role: item.info?.role || item.role, content: content, parts: item.parts || [], createdAt: item.info?.createdAt, } }) const hasMore = messages.length >= limit res.json({ messages, hasMore }) return } if (action === 'prompt') { const parts: Array<{ type: 'text'; text: string } | { type: 'file'; url: string; name: string; mime: string }> = [] if (attachments && attachments.length > 0) { for (const att of attachments as Array<{ url: string; name: string; mediaType: string }>) { parts.push({ type: 'file', url: att.url, name: att.name, mime: att.mediaType, }) } } parts.push({ type: 'text', text }) try { const response = await client.session.prompt({ path: { id: sessionId }, body: { parts }, }) if (response.data) { res.json({ message: { id: (response.data.info as { id?: string })?.id || crypto.randomUUID(), role: (response.data.info as { role?: string })?.role || 'assistant', content: '', parts: response.data.parts || [], createdAt: new Date().toISOString(), }, }) return } res.status(500).json({ error: 'Failed to get response', details: response.error }) return } catch (e: unknown) { console.error('Prompt exception:', e) const errorMessage = e instanceof Error ? e.message : 'Unknown error' res.status(500).json({ error: errorMessage }) return } } if (action === 'summarize-session') { try { await client.session.summarize({ path: { id: sessionId }, }) const response = await client.session.get({ path: { id: sessionId }, }) if (response.data) { res.json({ title: response.data.title || 'New Chat', }) return } res.status(500).json({ error: 'Failed to get session' }) return } catch (e: unknown) { console.error('Summarize error:', e) const errorMessage = e instanceof Error ? e.message : 'Unknown error' res.status(500).json({ error: errorMessage }) return } } res.status(400).json({ error: 'Unknown action' }) } catch (error: unknown) { console.error('API error:', error) const errorMessage = error instanceof Error ? error.message : 'Unknown error' res.status(500).json({ error: errorMessage }) } }) return router }