Capítulo IA de la guía Neblla — neblla.ai.prompt(), presets, rutas de pago y entrega diferida. El contrato base está en core.txt; el criterio de cuándo usar Neblla, en empezar.txt. # IA integrada Llamadas a la IA desde la app sin montar servidor propio, sin gestionar claves en backend, sin rate limiting manual. El proveedor lo eliges tú: **Claude** (por defecto), **OpenAI** o **DeepSeek**; `neblla.ai.prompt()` funciona igual con los tres. ```javascript const res = await neblla.ai.prompt('Estoy en una sala oscura con una puerta cerrada. ¿Qué hago?', { preset: 'pista' }); console.log(res.text); ``` Firma: `neblla.ai.prompt(text, { preset?, model?, provider?, userToken? })` **(CLIENT)** — devuelve `Promise<{ text, usage, quota }>`. ## Proveedores y modelos `ai.provider` elige el proveedor de la app: `'claude'` (por defecto), `'openai'` o `'deepseek'`, en Config > IA o con `neblla_update_app({ ai: { provider, model, ... } })` (el objeto `ai` se reemplaza entero). Cada uno con sus modelos: - **Claude:** `opus-latest`, `sonnet-latest` (por defecto), `haiku-latest`. - **OpenAI:** `gpt-5`, `gpt-5-mini` (por defecto), `gpt-5-nano`. - **DeepSeek:** `deepseek-chat` (por defecto), `deepseek-reasoner`. Cuando pagas tú, Neblla usa tu clave **de ese proveedor**: la de Claude se guarda en tu cuenta (Cuenta > Claude), las de OpenAI y DeepSeek en su tarjeta de Config > IA; todas cifradas. Sin clave guardada, la llamada responde `no_developer_key`. Los errores del proveedor llegan como `claude_error:`, `openai_error:` o `deepseek_error:`. El `provider` de la llamada solo vale cuando paga el usuario (con su propia clave de ese proveedor); con tu clave, otro proveedor que el de la app se rechaza con `provider_not_allowed`. ## Presets Los `preset` son prompts que el desarrollador configura en el dashboard (p. ej. el preset `pista` lleva el prefijo "Eres el narrador de una aventura. Da una pista sutil sin desvelar la solución..."). Editables en el dashboard sin redeploy. ```javascript // ❌ Mal — el prompt completo en cliente: neblla.ai.prompt('Eres el narrador de una aventura. Da una pista... ' + userQuestion); // ✅ Bien — preset en el dashboard, solo la pregunta del usuario: neblla.ai.prompt(userQuestion, { preset: 'pista' }); ``` El preset prefix se aplica server-side (en rutas con clave del dev) y queda privado. ## Las tres rutas Neblla elige la ruta según **un solo** ajuste de la app, `ai.userTokenMode`, no por cómo se llame a `neblla.ai.prompt()`. Vía MCP es `neblla_update_app` con `ai: { userTokenMode: 'off' | 'browser' | 'server' }`. Lee bien los valores — `'off'` es el que paga el **dev**: 1. **Browser-directo** (`userTokenMode: 'browser'`) — el usuario aporta su propia clave; la llamada sale del navegador al proveedor (Anthropic u OpenAI) directamente, sin pasar por Neblla. DeepSeek no se llama desde el navegador: con DeepSeek, las claves de los usuarios van por el modo `server` (pedir `browser` con DeepSeek responde `invalid_ai_browser_provider`). El dev no paga tokens, no consume cuota de Neblla, no requiere login. El preset prefix queda visible en el bundle del cliente. 2. **Servidor con clave del dev** (`userTokenMode: 'off'` — el valor por defecto; "off" significa sin token DEL USUARIO, o sea que se usa la clave del dev) — la llamada va por el servidor de Neblla con la clave de API del dev. Cada usuario tiene una cuota diaria de tokens, encendida por defecto (`limitsEnabled`, 10.000 tokens al día con `tokensPerDay`; pasarse responde `quota_exceeded`): así un usuario no te vacía la clave. Se apaga con `limitsEnabled: false`. Requiere login. El modelo del panel (`ai.model`) es el tope: el `model` de la llamada puede ser ese o uno más barato del mismo proveedor (Haiku < Sonnet < Opus; nano < mini < gpt-5; deepseek-chat < deepseek-reasoner); uno más caro se rechaza con `model_not_allowed`, sin llamar al proveedor. 3. **Servidor con clave del usuario** (`userTokenMode: 'server'`) — el usuario aporta su clave (se pasa en el `userToken` del call), pero la llamada va por el servidor de Neblla para que el preset prefix quede privado. El dev no paga tokens. Requiere login. En `browser` y `server` paga el usuario: una llamada sin `userToken` se rechaza con `missing_user_token` y nunca cae en la clave del dev. En esos modos el usuario elige el proveedor y el modelo, porque lo paga él. ## Coste en cuota Cada llamada por servidor consume 500 unidades de la cuota diaria de la app (los tokens del proveedor se facturan aparte, contra la clave del dev o del usuario). El modo `browser` no consume cuota. Tabla completa de cuotas en publicar.txt. ## El consumo, a la vista El panel (Funciones › IA y Dinero › Plan y uso) y `neblla_get_app` (en `aiUsage`) enseñan lo que lleva gastado la IA de la app: hoy, este mes (UTC) y los últimos 30 días, y día a día en el panel. Para cada periodo: `calls` (llamadas que respondió el proveedor), `tokensIn` y `tokensOut`, `refused` (rechazadas antes de llegar al proveedor, sin coste: `refusedBy` dice por qué, p. ej. `quota_exceeded`, `no_developer_key`, `model_not_allowed`, `login_required`), `failed` (el proveedor respondió un error; ya pagó su coste fijo: `failedBy`) y `credits` (lo que costó en la cuota de la app). Separa lo que va con tu clave (`dev`), con la clave de cada usuario a través de Neblla (`user`) y la revisión con IA de la comunidad (`prescreen`, también con tu clave). `lifetime` da los tokens y llamadas de siempre que contó la cuota, y `creditsPerCall` lo que cuesta una llamada. `ai` dice el proveedor (`provider`, `providerName`) y si tienes guardada tu propia clave para él (`ownKey`, nunca la clave): con ella el panel pone «Tu IA · OpenAI» (o el proveedor que sea); sin ella, «Falta tu clave de OpenAI» (no hay una clave de Neblla para la IA de una app: las llamadas responden `no_developer_key`); y si paga la clave de cada usuario (`userTokenMode` `server` o `browser`), «Clave de cada usuario · OpenAI». Lo que cobra Neblla es solo eso: los créditos de la cuota de la app, y `euroPerCredit` / `eurosPerCall` su precio en euros al precio del paquete de cuota (14.000 créditos por 10 €). A eso súmale lo que te cobre tu proveedor de IA por los tokens, en la clave que pagó: la tuya o la de cada usuario (`ai.userTokenMode`). Neblla no lleva una tabla de precios de los proveedores: mira la suya. El asistente de crear una app y «+ Añadir funciones» enseñan la misma cuenta en la tarjeta de la IA (`POST /api/backend/ai-price`, sin app: `{ creditsPerCall, euroPerCredit, eurosPerCall, eurosPer1000Calls, currency, pack }`). El modo `browser` no pasa por Neblla y no se cuenta. Los días se guardan 90 días; un borrador (pre) cuenta para su app. Por HTTP, con la sesión del panel: `POST /api/backend/apps//ai-usage` con `{ days? }` (1–90, 30 por defecto). ## Entrega diferida Si la conexión se cae mientras la IA piensa, la respuesta se entrega cuando el usuario reconecta (dentro de 24h). El resultado llega por `neblla.ai.on('reply', cb)` **(CLIENT)**, sin código especial. Una consecuencia que conviene conocer: un `await neblla.ai.prompt(...)` que tarde más de 120 segundos ya ha rechazado con `ai_timeout` cuando llega la respuesta tardía, y esa respuesta se entrega **solo** por `neblla.ai.on('reply')`. Si tu app puede quedarse esperando dos minutos, escucha el evento además de hacer `await`.