type ChatCompletionResponse = { choices?: Array<{ message?: { content?: string; }; }>; }; function envValue(name: string) { const value = process.env[name]; if (!value) { return undefined; } const trimmed = value.trim(); return trimmed.length > 0 ? trimmed : undefined; } const DEFAULT_MODEL = 'zeroclaw'; function fallbackResponse(prompt: string) { const clipped = prompt.split('\n').slice(0, 6).join(' ').slice(0, 260); return [ 'OpenClaw fallback mode is active (missing OPENCLAW_BASE_URL or OPENCLAW_API_KEY).', 'Thesis: Portfolio remains analyzable with local heuristics until live model access is configured.', 'Risk scan: Concentration and filing sentiment should be monitored after each sync cycle.', `Context digest: ${clipped}` ].join('\n\n'); } export function getOpenClawConfig() { return { baseUrl: envValue('OPENCLAW_BASE_URL'), apiKey: envValue('OPENCLAW_API_KEY'), model: envValue('OPENCLAW_MODEL') ?? DEFAULT_MODEL }; } export function isOpenClawConfigured() { const config = getOpenClawConfig(); return Boolean(config.baseUrl && config.apiKey); } export async function runOpenClawAnalysis(prompt: string, systemPrompt?: string) { const config = getOpenClawConfig(); if (!config.baseUrl || !config.apiKey) { return { provider: 'local-fallback', model: config.model, text: fallbackResponse(prompt) }; } const response = await fetch(`${config.baseUrl}/v1/chat/completions`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${config.apiKey}` }, body: JSON.stringify({ model: config.model, temperature: 0.2, messages: [ systemPrompt ? { role: 'system', content: systemPrompt } : null, { role: 'user', content: prompt } ].filter(Boolean) }), cache: 'no-store' }); if (!response.ok) { const body = await response.text(); throw new Error(`OpenClaw request failed (${response.status}): ${body.slice(0, 220)}`); } const payload = await response.json() as ChatCompletionResponse; const text = payload.choices?.[0]?.message?.content?.trim(); if (!text) { throw new Error('OpenClaw returned an empty response'); } return { provider: 'openclaw', model: config.model, text }; }