Dexter es un agente autónomo de investigación financiera que piensa, planifica y aprende mientras trabaja. Realiza análisis utilizando planificación de tareas, auto-reflexión y datos de mercado en tiempo real. Piensa en Claude Code, pero construido específicamente para investigación financiera.
Dexter toma preguntas financieras complejas y las convierte en planes de investigación claros y paso a paso. Ejecuta esas tareas utilizando datos de mercado en vivo, verifica su propio trabajo y refina los resultados hasta tener una respuesta confiable respaldada por datos.
Capacidades Clave:
- Planificación Inteligente de Tareas: Descompone automáticamente consultas complejas en pasos de investigación estructurados
- Ejecución Autónoma: Selecciona y ejecuta las herramientas correctas para recopilar datos financieros
- Auto-Validación: Verifica su propio trabajo e itera hasta que las tareas estén completas
- Datos Financieros en Tiempo Real: Acceso a estados de resultados, balances y estados de flujo de efectivo
- Características de Seguridad: Detección de bucles incorporada y límites de pasos para prevenir ejecución descontrolada
- Soporte para APIs Locales: Compatible con LM Studio, Ollama y otros servidores locales compatibles con OpenAI
Dexter utiliza una arquitectura multi-agente con componentes especializados que trabajan en conjunto para realizar investigación financiera completa. El sistema está diseñado con dos implementaciones: una en Python y otra en TypeScript, ambas compartiendo la misma filosofía arquitectónica pero adaptadas a sus respectivos ecosistemas.
- Función: Analiza la consulta del usuario y la descompone en una lista estructurada de tareas
- Implementación:
- Python:
plan_tasks()enagent.py - TypeScript:
TaskPlanner.planTasks()entask-planner.ts
- Python:
- Proceso:
- Recibe la consulta del usuario
- Analiza las herramientas disponibles (16 herramientas financieras + búsqueda)
- Genera tareas específicas, atómicas y secuenciales
- Retorna una lista de tareas con IDs y descripciones
- Función: Ejecuta las tareas planificadas utilizando herramientas financieras
- Implementación:
- Python: Loop principal en
agent.run()conask_for_actions()y_execute_tool() - TypeScript:
TaskExecutor.executeTasks()entask-executor.ts
- Python: Loop principal en
- Proceso:
- Para cada tarea, genera subtareas específicas (solo en TypeScript)
- Solicita al LLM qué herramienta usar y con qué parámetros
- Optimiza los argumentos de las herramientas antes de ejecutarlas
- Ejecuta las herramientas y guarda los resultados
- Valida si la tarea está completa antes de continuar
- Función: Verifica si las tareas están completas y si el objetivo principal se ha alcanzado
- Implementación:
- Python:
ask_if_done()yis_goal_achieved()enagent.py - TypeScript: Integrado en
TaskExecutor
- Python:
- Proceso:
- Evalúa si una tarea individual está completa
- Evalúa si el objetivo general de la consulta se ha cumplido
- Utiliza los resultados de las herramientas para tomar decisiones
- Función: Sintetiza todos los hallazgos en una respuesta comprensiva
- Implementación:
- Python:
_generate_answer()enagent.py - TypeScript:
AnswerGenerator.generateAnswer()enanswer-generator.ts
- Python:
- Proceso:
- Selecciona contextos relevantes de los archivos guardados
- Carga los contextos seleccionados
- Genera una respuesta completa basada en los datos recopilados
- Transmite la respuesta en tiempo real (streaming)
1. Usuario hace una consulta
↓
2. Agente de Planificación descompone la consulta en tareas
↓
3. Para cada tarea:
a. Agente de Ejecución pregunta al LLM qué hacer
b. LLM selecciona una herramienta y parámetros
c. Se optimizan los argumentos de la herramienta
d. Se ejecuta la herramienta
e. Se guarda el resultado en el sistema de archivos (ContextManager)
f. Se genera un resumen del resultado
g. Agente de Validación verifica si la tarea está completa
↓
4. Agente de Validación verifica si el objetivo general se alcanzó
↓
5. Generador de Respuestas:
a. Selecciona contextos relevantes usando LLM
b. Carga los contextos seleccionados
c. Genera respuesta final con streaming
Dexter utiliza LangChain como capa de abstracción para interactuar con múltiples proveedores de modelos de lenguaje. El sistema soporta tres proveedores principales:
-
OpenAI (por defecto)
- Modelos:
gpt-4.1,gpt-4,gpt-3.5-turbo, etc. - Clave API:
OPENAI_API_KEY - Implementación:
ChatOpenAIde LangChain
- Modelos:
-
Anthropic
- Modelos:
claude-sonnet-4.5,claude-3-opus, etc. - Clave API:
ANTHROPIC_API_KEY - Implementación:
ChatAnthropicde LangChain
- Modelos:
-
Google Gemini
- Modelos:
gemini-3,gemini-pro, etc. - Clave API:
GOOGLE_API_KEY - Implementación:
ChatGoogleGenerativeAIde LangChain
- Modelos:
Python (src/dexter/model.py):
def get_chat_model(model_name: str, temperature: float = 0, streaming: bool = False):
if model_name.startswith("claude-"):
return ChatAnthropic(model=model_name, ...)
elif model_name.startswith("gemini-"):
return ChatGoogleGenerativeAI(model=model_name, ...)
else:
return ChatOpenAI(model=model_name, ...)TypeScript (dexter-ts/src/model/llm.ts):
export function getChatModel(modelName: string, temperature: number = 0, streaming: boolean = false) {
const prefix = Object.keys(MODEL_PROVIDERS).find(p => modelName.startsWith(p));
const factory = prefix ? MODEL_PROVIDERS[prefix] : DEFAULT_PROVIDER;
return factory(modelName, { temperature, streaming });
}Dexter SÍ soporta endpoints locales como LM Studio, Ollama y otros servidores compatibles con la API de OpenAI. El sistema detecta automáticamente cuando se configura una URL base local y ajusta su comportamiento en consecuencia.
Para usar una API local (como LM Studio en http://localhost:1234), configura la variable de entorno OPENAI_BASE_URL:
# En tu archivo .env
OPENAI_BASE_URL=http://localhost:1234/v1
OPENAI_API_KEY=local-key-123 # Opcional para APIs locales sin autenticaciónNotas importantes:
- La URL base debe incluir
/v1al final (ejemplo:http://localhost:1234/v1) - LangChain añadirá automáticamente
/chat/completionsal hacer las peticiones - Si tu API local no requiere autenticación, puedes usar cualquier valor para
OPENAI_API_KEYo incluso omitirlo - El nombre del modelo debe coincidir exactamente con el que está cargado en tu servidor local
- Inicia LM Studio y carga un modelo (ej:
qwen3-vl-30b-a3b-thinking) - Asegúrate de que el servidor local esté corriendo en
http://localhost:1234 - Configura tu archivo
.env:OPENAI_BASE_URL=http://localhost:1234/v1 OPENAI_API_KEY=lm-studio # Cualquier valor funciona - Ejecuta Dexter normalmente:
uv run dexter-agent # Python # o bun run start # TypeScript
La API local debe ser compatible con el formato de OpenAI. El endpoint esperado es:
POST http://localhost:1234/v1/chat/completions
Con el siguiente formato de request (compatible con LM Studio):
{
"model": "lmstudio-community/qwen3-vl-30b-a3b-thinking",
"messages": [
{
"role": "system",
"content": "Always answer in rhymes. Today is Thursday"
},
{
"role": "user",
"content": "What day is it today?"
}
],
"temperature": 0.7,
"max_tokens": -1,
"stream": false
}LM Studio y otros servidores locales funcionan mejor con modelos que soportan function calling:
- Llama 3.1 (8B, 70B)
- Qwen2.5 / Qwen3
- Mistral
- Otros modelos que soporten OpenAI-compatible function calling
Nota: Algunos modelos pueden no soportar structured output perfectamente. En ese caso, el código hará fallback automático a respuestas regulares.
Python (src/dexter/model.py):
base_url = os.getenv("OPENAI_BASE_URL")
if base_url:
# Usa API local con LocalChatOpenAI
return LocalChatOpenAI(
model=model_name,
base_url=base_url,
api_key=api_key # Opcional para APIs locales
)TypeScript (dexter-ts/src/model/llm.ts):
const baseUrl = process.env.OPENAI_BASE_URL;
if (baseUrl) {
config.configuration = { baseURL: baseUrl };
// API key opcional para APIs locales
}Para más detalles sobre configuración de APIs locales, consulta el archivo API_LOCAL.md.
Dexter cuenta con 17 herramientas especializadas en investigación financiera, todas integradas con la API de Financial Datasets (https://api.financialdatasets.ai).
get_income_statements: Estados de resultados (ingresos, gastos, ganancias)get_balance_sheets: Balances (activos, pasivos, patrimonio)get_cash_flow_statements: Estados de flujo de efectivoget_all_financial_statements: Todos los estados financieros combinados
get_filings: Obtener todos los documentos regulatoriosget_10K_filing_items: Elementos específicos de formularios 10-K (informes anuales)get_10Q_filing_items: Elementos específicos de formularios 10-Q (informes trimestrales)get_8K_filing_items: Elementos específicos de formularios 8-K (eventos actuales)
get_financial_metrics_snapshot: Instantánea de métricas claveget_financial_metrics: Métricas financieras históricas
get_price_snapshot: Precio actual de una acciónget_prices: Precios históricos de acciones
get_news: Noticias financieras relacionadas con una empresaget_analyst_estimates: Estimaciones de analistas
get_segmented_revenues: Ingresos por segmento de negocio
search_google_news: Búsqueda de noticias en Google
Todas las herramientas financieras utilizan la misma función base para llamar a la API:
Python (src/dexter/tools/finance/api.py):
def call_api(endpoint: str, params: dict) -> dict:
base_url = "https://api.financialdatasets.ai"
url = f"{base_url}{endpoint}"
headers = {"x-api-key": financial_datasets_api_key}
response = requests.get(url, params=params, headers=headers)
response.raise_for_status()
return response.json()TypeScript (dexter-ts/src/tools/finance/api.ts):
export async function callApi(endpoint: string, params: Record<string, ...>): Promise<...> {
const url = new URL(`${BASE_URL}${endpoint}`);
// ... añade parámetros
const response = await fetch(url.toString(), {
headers: { 'x-api-key': FINANCIAL_DATASETS_API_KEY || '' }
});
return response.json();
}Dexter implementa un sistema sofisticado de gestión de contexto que guarda los resultados de las herramientas en el sistema de archivos para eficiencia de memoria.
El ContextManager es responsable de:
- Guardar Contextos: Cuando una herramienta se ejecuta, su resultado se guarda en un archivo JSON
- Generar Resúmenes: Usa el LLM para generar resúmenes breves de cada resultado
- Seleccionar Contextos Relevantes: Al generar la respuesta final, selecciona solo los contextos relevantes usando el LLM
- Cargar Contextos: Carga solo los contextos seleccionados cuando se necesita generar la respuesta
Los contextos se guardan en .dexter/context/ con nombres descriptivos:
- Formato:
{TICKER}_{tool_name}_{hash}.json - Ejemplo:
AAPL_get_income_statements_a1b2c3d4e5f6.json
Ejecución de Herramienta
↓
Resultado guardado en archivo JSON
↓
Generación de resumen con LLM
↓
Puntero guardado en memoria (ligero)
↓
[Durante generación de respuesta]
↓
LLM selecciona contextos relevantes
↓
Solo se cargan los archivos seleccionados
↓
Respuesta generada con contextos cargados
Python (src/dexter/utils/context.py):
save_context(): Guarda resultado y genera resumenselect_relevant_contexts(): Selecciona contextos usando LLMload_contexts(): Carga archivos seleccionados
TypeScript (dexter-ts/src/utils/context.ts):
- Misma funcionalidad adaptada a TypeScript
El proyecto contiene dos implementaciones completas:
src/dexter/
├── agent.py # Lógica principal de orquestación del agente
├── model.py # Interfaz LLM (multi-proveedor)
├── prompts.py # Prompts del sistema para cada componente
├── schemas.py # Modelos Pydantic para validación
├── cli.py # Punto de entrada CLI
├── tools/ # Herramientas disponibles
│ ├── __init__.py # Registro de todas las herramientas
│ ├── finance/ # 16 herramientas financieras
│ │ ├── api.py # Cliente base para Financial Datasets API
│ │ ├── fundamentals.py
│ │ ├── filings.py
│ │ ├── metrics.py
│ │ ├── prices.py
│ │ ├── news.py
│ │ ├── estimates.py
│ │ └── segments.py
│ └── search/ # Herramientas de búsqueda
│ └── google.py
└── utils/ # Utilidades
├── context.py # Gestión de contexto (offloading)
├── config.py # Persistencia de configuración
├── env.py # Gestión de API keys
├── logger.py # Sistema de logging
├── ui.py # Interfaz de usuario
└── model_selector.py # Selector de modelos
dexter-ts/src/
├── agent/ # Componentes del agente
│ ├── agent.ts # Orquestación principal
│ ├── task-planner.ts # Planificación de tareas y subtareas
│ ├── task-executor.ts # Ejecución de tareas con loops agenticos
│ ├── answer-generator.ts # Generación de respuestas
│ ├── prompts.ts # Prompts del sistema
│ └── schemas.ts # Esquemas Zod
├── components/ # Componentes React/Ink para UI
│ ├── AnswerBox.tsx # Visualización de respuestas con streaming
│ ├── Input.tsx # Entrada de usuario
│ ├── Intro.tsx # Pantalla de bienvenida
│ ├── ModelSelector.tsx # Selector de modelos
│ ├── TaskProgress.tsx # Progreso de tareas
│ └── TaskList.tsx # Lista de tareas
├── model/
│ └── llm.ts # Interfaz LLM (multi-proveedor)
├── tools/ # Herramientas (misma estructura que Python)
├── utils/
│ ├── context.ts # Gestión de contexto
│ ├── config.ts # Configuración persistente
│ └── env.ts # Gestión de API keys
├── hooks/
│ └── useQueryQueue.ts # Cola de consultas
├── cli.tsx # Componente CLI principal
└── index.tsx # Punto de entrada
- Python 3.10 o superior
- uv gestor de paquetes
- Clave API de OpenAI (obtener aquí)
- Clave API de Financial Datasets (obtener aquí)
- Bun runtime (v1.0 o superior)
- Clave API de OpenAI (obtener aquí)
- Clave API de Financial Datasets (obtener aquí)
Si no tienes Bun instalado:
macOS/Linux:
curl -fsSL https://bun.com/install | bashWindows:
powershell -c "irm bun.sh/install.ps1|iex"Verifica la instalación:
bun --version- Clona el repositorio:
git clone https://github.com/virattt/dexter.git
cd dexter- Instala las dependencias con uv:
uv sync- Configura las variables de entorno:
# Copia el archivo de ejemplo
cp env.example .env
# Edita .env y añade tus API keys
# OPENAI_API_KEY=tu-clave-openai
# OPENAI_BASE_URL=http://localhost:1234/v1 # Opcional: para usar APIs locales (LM Studio, Ollama, etc.)
# ANTHROPIC_API_KEY=tu-clave-anthropic (opcional)
# GOOGLE_API_KEY=tu-clave-google (opcional)
# FINANCIAL_DATASETS_API_KEY=tu-clave-financial-datasets- Clona el repositorio:
git clone https://github.com/virattt/dexter.git
cd dexter/dexter-ts- Instala las dependencias con Bun:
bun install- Configura las variables de entorno:
# Copia el archivo de ejemplo desde el directorio padre
cp ../env.example .env
# Edita .env y añade tus API keys
# OPENAI_API_KEY=tu-clave-openai
# OPENAI_BASE_URL=http://localhost:1234/v1 # Opcional: para usar APIs locales (LM Studio, Ollama, etc.)
# ANTHROPIC_API_KEY=tu-clave-anthropic (opcional)
# GOOGLE_API_KEY=tu-clave-google (opcional)
# FINANCIAL_DATASETS_API_KEY=tu-clave-financial-datasetsEjecuta Dexter en modo interactivo:
uv run dexter-agentEjecuta Dexter en modo interactivo:
bun run startO en modo desarrollo con watch:
bun run devEn ambas versiones, puedes cambiar el modelo escribiendo /model en la CLI. Esto te permitirá seleccionar entre:
- GPT 4.1 (OpenAI)
- Claude Sonnet 4.5 (Anthropic)
- Gemini 3 (Google)
Prueba preguntarle a Dexter cosas como:
- "¿Cuál fue el crecimiento de ingresos de Apple en los últimos 4 trimestres?"
- "Compara los márgenes operativos de Microsoft y Google para 2023"
- "Analiza las tendencias de flujo de efectivo de Tesla durante el año pasado"
- "¿Cuál es la relación deuda-capital de Amazon basada en estados financieros recientes?"
Dexter automáticamente:
- Descompone tu pregunta en tareas de investigación
- Obtiene los datos financieros necesarios
- Realiza cálculos y análisis
- Proporciona una respuesta comprensiva y rica en datos
Python:
from dexter.agent import Agent
agent = Agent(
max_steps=20, # Límite global de seguridad
max_steps_per_task=5, # Límite de iteraciones por tarea
model="gpt-4.1" # Modelo LLM a usar
)TypeScript:
import { Agent } from './agent/agent.js';
const agent = new Agent({
model: 'gpt-4.1', // Modelo LLM a usar
callbacks: { // Callbacks para observar ejecución
onUserQuery: (query) => console.log(query),
onTasksPlanned: (tasks) => console.log(tasks),
// ... más callbacks
}
});# API Local (LM Studio, Ollama, etc.)
OPENAI_BASE_URL=http://localhost:1234/v1 # URL base de tu API local
OPENAI_API_KEY=local-key-123 # Opcional para APIs sin autenticación
# LangSmith (para tracing y debugging)
LANGSMITH_API_KEY=tu-clave-langsmith
LANGSMITH_ENDPOINT=https://api.smith.langchain.com
LANGSMITH_PROJECT=dexter
LANGSMITH_TRACING=trueNota: Para más información sobre cómo configurar APIs locales como LM Studio, consulta el archivo API_LOCAL.md que incluye instrucciones detalladas, troubleshooting y ejemplos específicos.
Dexter incluye varias características de seguridad para prevenir ejecución descontrolada:
- Límite Global de Pasos: Previene loops infinitos con
max_steps - Límite por Tarea: Cada tarea tiene un límite de iteraciones (
max_steps_per_task) - Detección de Bucles: Detecta acciones repetitivas y aborta la ejecución
- Validación de Tareas: Verifica si las tareas están completas antes de continuar
- Validación Meta: Verifica si el objetivo general se ha alcanzado
- Arquitectura más simple y directa
- Loop secuencial de tareas
- Validación en dos niveles (tarea y meta)
- Gestión de contexto integrada
- Arquitectura híbrida con subtareas
- Ejecución paralela de tareas
- UI interactiva con React/Ink
- Cola de consultas para manejar múltiples preguntas
- Streaming de respuestas en tiempo real
- Haz fork del repositorio
- Crea una rama de características
- Realiza tus cambios
- Haz push a la rama
- Crea un Pull Request
Importante: Por favor mantén tus pull requests pequeños y enfocados. Esto facilitará la revisión y fusión.
Este proyecto está licenciado bajo la Licencia MIT.