Arquitectura del Agente IA — Documentación técnica
100% local-first BYOK · sin backend apps/mobile/App.tsx

Grafo de funcionamiento

Nodos = pasos/decisiones, líneas = paso de datos. El ciclo lima discontinuo es el bucle agentic de uso de herramientas; la línea roja discontinua es la única llamada que sale a un servicio externo distinto del proveedor LLM.
no create_feature_issue reintenta con tool_result
Usuario (chat)
System promptGitHub AGENTS.md + caché local
Proveedor activoBYOK · 1 de 3 (is_active)
Llamada al modelostreaming SSE/XHR
¿Pide usar una herramienta?
handleToolCall()12 herramientas, 100% local
Respuesta finalal usuario, en streaming
AsyncStoragedieta · rutinas · medidas · memoria
GitHub Issues APIúnico destino externo
Flujo normal Bucle agentic (tool result → modelo) Llamada externa (no LLM)

Gymnasia Coach es el agente conversacional general de la app (pestaña Chat IA). Es un agente BYOK (Bring Your Own Key): el usuario configura su propia API key de OpenAI, Anthropic o Google, y la app llama directamente al proveedor elegido desde el dispositivo. No existe backend propio: toda la lógica de orquestación, herramientas y almacenamiento vive en App.tsx y en AsyncStorage local.

1 · Configuración y proveedor activo

Ajustes BYOK

El usuario guarda su API key

Una de las 3 keys (OpenAI / Anthropic / Google) se marca como is_active. Solo esa se usa para el chat general.

SecureStore / AsyncStorage
System prompt remoto

prompts/AGENTS.md en GitHub

Se descarga desde raw.githubusercontent.com/maximofn/gymnasia, se cachea localmente y cae a un prompt por defecto embebido si falla la red.

Editable sin publicar app

2 · Llamada al proveedor (uno activo)

OpenAI
Responses API · streaming SSE/XHR
Anthropic
Messages API · thinking habilitado
Google
Gemini generateContent

Cada proveedor tiene su propio adaptador de request/response (formatos de tools, streaming y bloques de contenido distintos), pero comparten el mismo bucle agentic descrito abajo.

3 · Bucle agentic (tool use)

Paso 1

Modelo responde

Texto en streaming y/o bloques tool_use / function_call.

Paso 2

handleToolCall()

Se ejecuta 100% en local contra el estado de la app (AsyncStorage, repos JSON).

Paso 3

Resultado → modelo

Se reinyecta como tool_result / function_call_output. Se repite hasta que no pide más tools.

4 · Herramientas disponibles (12)

🧠 Memoria personal
list_personal_data_keys
Lista las claves de datos personales guardadas del usuario.
read_field_description
Lee la descripción de un campo antes de interpretarlo.
read_field_value
Lee el valor de un campo concreto (ej. nombre, objetivo).
save_personal_data
Guarda/actualiza un array de campos {key, description, value}.
🍽️ Dieta
search_foods
Busca en el repositorio JSON de alimentos por nombre, categoría o rango de macros.
read_meal_foods
Lee los alimentos ya registrados en una comida/fecha.
add_meal_food
Añade un alimento (gramos + macros) a una comida y fecha concretas.
🏋️ Entrenamiento
search_exercises
Busca ejercicios por músculo, equipamiento o dificultad en el repo local.
read_routines
Lee las rutinas (templates) ya creadas por el usuario.
create_routine
Crea una rutina nueva; vincula imágenes de ejercicio por nombre exacto del repo.
📏 Medidas & meta
read_measurement / write_measurement
Lee o guarda medidas corporales (peso, % grasa, perímetros) por fecha.
create_feature_issue
Única herramienta que sale del dispositivo: crea un issue en GitHub (maximofn/gymnasia) cuando detecta una petición de mejora.

5 · Almacenamiento y salida

Sin base de datos

LocalStore (AsyncStorage)

Dieta, rutinas, medidas y datos personales viven en el dispositivo. Los repos de alimentos/ejercicios son JSON estáticos empaquetados con la app.

Excepción

GitHub Issues API

Único punto de salida a un servicio externo distinto del proveedor LLM: create_feature_issue.

Externo
Caveat de plataforma: en navegador (web), Anthropic requiere un proxy CORS local (apps/anthropic_proxy/cors-proxy.py) porque el navegador bloquea la llamada directa a api.anthropic.com. OpenAI y Google funcionan directo desde el navegador.

Grafo de funcionamiento

Nodos = pasos/decisiones, líneas = paso de datos. El ciclo lima discontinuo es el bucle agentic de uso de herramientas; la línea gris discontinua es la ruta alternativa sin foto.
no reintenta con tool_result alternativa sin foto
Usuario1–6 fotos + texto opcional
System promptFood Estimator (visión)
Selección por prioridadGoogle → OpenAI → Anthropic
Modelo analiza imágenes
¿Detecta código de barras?
scan_barcode()→ OpenFoodFacts API
Estimacióntexto libre o JSON si se pide
Confirmación usuariorequestStructuredNutritionJSON
add_meal_food()→ Dieta local (AsyncStorage)
MiniChat manualFOOD_AI_SYSTEM_PROMPT, sin fotos
Flujo normal Bucle agentic (tool result → modelo) Ruta alternativa

El Food Estimator es el sub-agente de visión que estima calorías y macros a partir de fotos de comida (pestaña Dieta → Estimación IA). Es independiente del chat general: tiene su propio system prompt, su propia herramienta y su propia política de selección de proveedor.

1 · Entrada

Input del usuario

1–6 fotos de la comida

Cámara o galería. También admite texto (preguntas de seguimiento sobre la estimación) reutilizando el contexto de la conversación.

2 · Selección de proveedor (por prioridad, no por proveedor activo)

A diferencia del chat general, aquí se prueba en orden hasta encontrar el primero con API key configurada:

1
Google
Gemini · visión
2
OpenAI
Responses API · visión
3
Anthropic
No admite imágenes en Web

3 · System prompt especializado

Nutricionista visual

Estima siempre: kcal, proteína (g), carbohidratos (g), grasa (g) y peso total (g). Da rangos si hay incertidumbre.

Clasificación

Determina si es producto_comercial, receta o alimento base genérico.

Salida estructurada

Si el usuario pide "Devuelve json", responde solo con JSON: dish_name, calories_kcal, protein_g, carbs_g, fat_g.

4 · Bucle agentic con herramienta de código de barras

Detección

¿Hay un código de barras en la foto?

El prompt obliga al modelo a usar la herramienta si detecta un EAN/UPC en cualquiera de las imágenes.

Única tool

scan_barcode(barcode)

Llama a OpenFoodFacts (API pública) con el código leído y devuelve datos nutricionales exactos del producto.

Externo · world.openfoodfacts.org

Producto comercial confirmado

Si se usó scan_barcode, la clasificación es siempre producto_comercial, con datos exactos en vez de estimados.

Igual que en el agente general, el resultado de la tool se reinyecta al modelo y el bucle se repite (máx. 5 rondas) hasta obtener una respuesta final.

5 · Persistencia del resultado

requestStructuredNutritionJSON

Confirmación del usuario

Cuando el usuario acepta la estimación, se pide el bloque JSON final y se parsea.

add_meal_food

Se añade a la dieta local del día/comida seleccionados (mismo store que usa el agente general).

Variante: estimación manual (sin foto)

MiniChat · FOOD_AI_SYSTEM_PROMPT

El usuario describe un alimento/receta por texto

Flujo conversacional: 1) el usuario nombra el alimento, 2) el modelo pregunta ingredientes/cantidades si faltan, 3) calcula valores por 100g/unidad, 4) el usuario confirma, 5) devuelve JSON para guardar en el repo de alimentos.

Sin herramientas · sin imágenes
Diseño clave: el Food Estimator prioriza el proveedor con mejor relación coste/calidad en visión (Google primero) en lugar de usar el proveedor "activo" del usuario, porque la estimación de fotos es la operación más frecuente y sensible a coste de la app.