import { recordEarning, recordSpending } from './governance.js'; import { initVeniceWallet, walletInference, checkBalance, type VeniceBalance } from './venice-x402.js'; const VENICE_API_KEY = process.env.VENICE_API_KEY ?? ''; const VENICE_BASE_URL = 'https://api.venice.ai/api/v1'; // Venice's house model — cheapest and always available const VENICE_MODEL = process.env.VENICE_MODEL ?? 'venice-uncensored'; const EARN_PER_QUERY = 0.01; const COST_PER_QUERY = 0.002; // Venice pricing per 1M tokens (approximate) const MODEL_PRICING: Record = { 'venice-uncensored': { input: 0.10, output: 0.25 }, 'llama-3.3-70b': { input: 0.15, output: 0.60 }, 'kimi-k2-5': { input: 0.50, output: 1.50 }, 'deepseek-v3.2': { input: 0.15, output: 0.75 }, 'qwen3-coder-480b-a35b-instruct': { input: 0.15, output: 0.75 }, }; function calculateInferenceCost(model: string, promptTokens: number, completionTokens: number): number { const pricing = MODEL_PRICING[model] ?? { input: 0.10, output: 0.25 }; return (promptTokens * pricing.input + completionTokens * pricing.output) / 1_000_000; } // Inference mode: 'x402' (wallet auth, self-funding) or 'api_key' (Bearer token) let inferenceMode: 'x402' | 'api_key' | 'none' = 'none'; let lastBalanceCheck: VeniceBalance | null = null; export function configureAgent(privateKey: string, address: string): void { initVeniceWallet(privateKey, address); inferenceMode = 'x402'; console.log(`[Agent] Inference mode: x402 wallet auth (self-funding)`); } export function configureApiKey(): void { if (VENICE_API_KEY) { inferenceMode = 'api_key'; console.log(`[Agent] Inference mode: API key (Bearer)`); } } // ── Venice Inference ──────────────────────────────────── async function callVenice(content: string): Promise<{ content: string; cost: number }> { const systemPrompt = 'You are a concise summarizer. Summarize the following web page content in 2-3 sentences.'; if (inferenceMode === 'x402') { try { const text = await walletInference(VENICE_MODEL, systemPrompt, content, 200); const estPrompt = Math.ceil(content.length / 4); const estCompletion = Math.ceil(text.length / 4); return { content: text, cost: calculateInferenceCost(VENICE_MODEL, estPrompt, estCompletion) }; } catch (err) { console.log(`[Agent] x402 inference failed, trying API key fallback: ${err}`); if (!VENICE_API_KEY) throw err; // Fall through to API key } } if (VENICE_API_KEY) { const res = await fetch(`${VENICE_BASE_URL}/chat/completions`, { method: 'POST', headers: { 'Authorization': `Bearer ${VENICE_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: VENICE_MODEL, messages: [ { role: 'system', content: systemPrompt }, { role: 'user', content }, ], max_tokens: 200, }), }); if (!res.ok) { const text = await res.text(); throw new Error(`Venice API error: ${res.status} ${text}`); } const data = await res.json() as any; const usage = data.usage ?? {}; const cost = calculateInferenceCost(VENICE_MODEL, usage.prompt_tokens ?? 0, usage.completion_tokens ?? 0); return { content: data.choices?.[0]?.message?.content ?? 'No summary generated.', cost }; } throw new Error('No Venice inference configured.'); } // ── Public API ────────────────────────────────────────── export async function summarizeUrl(url: string): Promise<{ summary: string; inferenceMode: string; veniceBalance?: VeniceBalance; cost: { earned: number; inference: number; profit: number }; }> { // Fetch URL content let content: string; try { const res = await fetch(url, { headers: { 'User-Agent': 'SpendOS-Agent/1.0' }, signal: AbortSignal.timeout(10000), }); const text = await res.text(); content = text.slice(0, 4000); } catch (err) { content = `Failed to fetch URL: ${url}. Error: ${err}`; } // Call Venice let summary: string; let actualCost = 0; try { const result = await callVenice(content); summary = result.content; actualCost = result.cost; } catch (err) { summary = `Summarization failed: ${err}`; } // Check Venice balance (best-effort, for dashboard display) if (inferenceMode === 'x402') { try { lastBalanceCheck = await checkBalance(); } catch { /* non-critical */ } } // Track P&L with REAL inference cost recordEarning(EARN_PER_QUERY); recordSpending(actualCost); return { summary, inferenceMode, veniceBalance: lastBalanceCheck ?? undefined, cost: { earned: EARN_PER_QUERY, inference: COST_PER_QUERY, profit: EARN_PER_QUERY - COST_PER_QUERY, }, }; } export function getVeniceBalance(): VeniceBalance | null { return lastBalanceCheck; } export function getInferenceMode(): string { return inferenceMode; }