File size: 2,543 Bytes
b30b7c5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// Configuración avanzada de proveedores externos (opt-in). Elffuss corre en
// LOCAL por defecto; esto solo se usa si el usuario lo activa a mano.
// Las claves viven en localStorage de SU navegador y nunca salen de aquí
// (las llamadas van directas del navegador al proveedor).
const KEY = 'elffusscode.providers';

// Plantillas de proveedores externos. `kind` decide el dialecto de API.
const DEFAULTS = {
  openai: {
    kind: 'openai', label: 'OpenAI', enabled: false,
    baseURL: 'https://api.openai.com/v1', model: 'gpt-4o-mini', apiKey: '',
    help: 'Tu clave sk-… Se queda en tu navegador. OpenAI permite llamadas directas (CORS).',
  },
  anthropic: {
    kind: 'anthropic', label: 'Anthropic (Claude)', enabled: false,
    baseURL: 'https://api.anthropic.com', model: 'claude-sonnet-5', apiKey: '',
    help: 'Tu clave sk-ant-… Se envía la cabecera de acceso directo desde navegador.',
  },
  ollama: {
    kind: 'openai', label: 'Ollama (local)', enabled: false,
    baseURL: 'http://localhost:11434/v1', model: 'llama3.2', apiKey: 'ollama',
    help: 'Ollama en tu máquina. Arráncalo con OLLAMA_ORIGINS=* para permitir el navegador.',
  },
  server: {
    kind: 'openai', label: 'Servidor Elffuss (Ornith 9B)', enabled: false,
    baseURL: 'https://elffuss-claw.utopiaia.com/v1', model: 'ornith-9b', apiKey: '',
    temperature: 1.0, top_p: 0.95, thinking: false,
    help: 'El modelo grande en el servidor de UtopiaIA. No es local: los mensajes salen de tu máquina.',
  },
};

function load() {
  let saved = {};
  try { saved = JSON.parse(localStorage.getItem(KEY) || '{}'); } catch { /* corrupto */ }
  const out = {};
  for (const [id, def] of Object.entries(DEFAULTS)) out[id] = { ...def, ...saved[id] };
  return out;
}

export function configs() { return load(); }
export function get(id) { return load()[id]; }

export function update(id, patch) {
  const all = load();
  all[id] = { ...all[id], ...patch };
  // no persistir los campos de ayuda estáticos
  const slim = {};
  for (const [k, v] of Object.entries(all))
    slim[k] = { enabled: v.enabled, baseURL: v.baseURL, model: v.model, apiKey: v.apiKey };
  localStorage.setItem(KEY, JSON.stringify(slim));
  return all[id];
}

// Externos habilitados → opciones del selector, como ext:<id>.
export function enabledExternals() {
  return Object.entries(load())
    .filter(([, c]) => c.enabled)
    .map(([id, c]) => ({ id: 'ext:' + id, label: c.label + (id === 'ollama' || c.baseURL.startsWith('http://localhost') ? ' · local' : ' · nube') }));
}