- Add optional history parameter to Run/RunStream for conversation context - Add Reasoning/ReasoningDelta fields to completion and stream types - Update llama.cpp adapter to propagate reasoning content from responses - Default persona language now adapts to the user's language dynamically
590 lines
No EOL
20 KiB
Markdown
590 lines
No EOL
20 KiB
Markdown
# 🏗️ rony-llm-agent — Architecture
|
|
|
|
> 🌐 **Idioma:** [English](architecture.md) | [Español](README.es.md)
|
|
|
|
|
|
**Versión:** 1.0
|
|
**Autor:** Victor Hugo Vargas
|
|
**Fecha:** 2026-06-28
|
|
**Estado:** Especificación de arquitectura de la librería
|
|
|
|
> 📚 **Otros documentos:**
|
|
> - [`README.md`](./README.md) — Overview de la librería
|
|
> - [`components.md`](./components.md) — Referencia detallada por paquete
|
|
> - [`phase2.md`](./phase2.md) — Features avanzadas (MCP, RAG completo, Skills, etc.)
|
|
|
|
---
|
|
|
|
## 🎯 1. Visión de la Librería
|
|
|
|
### 1.1 ¿Qué es rony-llm-agent?
|
|
|
|
Una librería Go que provee toda la lógica **genérica y reusable** para construir agentes basados en LLMs. No es un producto final — es el cimiento sobre el cual se construyen productos específicos.
|
|
|
|
**Productos que la consumen:**
|
|
|
|
- [`VictorVargas/rony-harness`](https://github.com/VictorVargas/rony-harness) — AI agent harness para desarrollo de software (TUI CLI)
|
|
- [`VictorVargas/rony-chat-bot`](https://github.com/VictorVargas/rony-chat-bot) — Chatbot HTTP para portfolios y sitios web
|
|
|
|
### 1.2 Principios de diseño
|
|
|
|
- **Reusable, no opinionated.** No fuerza un tipo de UI, deployment, ni use case.
|
|
- **Hexagonal puro.** Ports & adapters — toda dependencia externa va detrás de una interfaz.
|
|
- **Streaming-first.** Usa `iter.Seq2` de Go 1.23+ para streaming natural sin callbacks.
|
|
- **Seguridad por defecto.** Sandbox de paths con `os.Root` (Go 1.24+) en filesystem.
|
|
- **Zero magic.** No reflection, no codegen, no DSLs. Go idiomático y explícito.
|
|
- **Configurable por YAML.** Sin surprises, todo lo que afecta comportamiento es declarativo.
|
|
|
|
### 1.3 Lo que NO es
|
|
|
|
- ❌ No es un CLI — eso es responsabilidad del producto (ej. `harness`)
|
|
- ❌ No es un servidor HTTP — eso es responsabilidad del producto (ej. `chat-bot`)
|
|
- ❌ No fuerza un modelo o provider específico — adapters intercambiables
|
|
- ❌ No tiene estado persistente propio — eso lo maneja cada producto
|
|
|
|
---
|
|
|
|
## 🏗️ 2. Arquitectura Hexagonal (Ports & Adapters)
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ Productos que consumen │
|
|
│ (harness, chat-bot, dealer-bot, etc.) │
|
|
└──────────────────────────┬──────────────────────────────────────┘
|
|
│ usan interfaces públicas
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ rony-llm-agent (pkg/ — API pública) │
|
|
│ │
|
|
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
|
│ │ agent │ │ llm │ │ persona │ │ tools │ ... │
|
|
│ └────┬────┘ └────┬────┘ └─────────┘ └─────────┘ │
|
|
│ │ │ │
|
|
│ │ usa ports (interfaces) │
|
|
│ ▼ ▼ │
|
|
│ ┌─────────────────────────────────────────────────────┐ │
|
|
│ │ PORTS (interfaces puras) │ │
|
|
│ │ LLMClient, VectorDB, Embedder, ToolRegistry, ... │ │
|
|
│ └──────────────────────┬───────────────────────────────┘ │
|
|
│ │ implementadas por adapters │
|
|
└──────────────────────────┼──────────────────────────────────────┘
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ Adapters (en pkg/*/internal/) │
|
|
│ • providers/anthropic, openai, ollama, llamacpp │
|
|
│ • backends/chroma, qdrant, sqlite │
|
|
│ • embeddings/ollama, onnx │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 2.1 Capas
|
|
|
|
**Ports (interfaces puras)**
|
|
- Definen QUÉ hace el dominio, no CÓMO
|
|
- Son contratos sin implementación
|
|
- Permiten sustituir adapters sin tocar lógica de negocio
|
|
|
|
**Domain (pkg/)**
|
|
- Contiene toda la lógica reusable
|
|
- NO depende de nada externo
|
|
- Solo importa interfaces de sus propios ports
|
|
|
|
**Adapters (internals de cada adapter)**
|
|
- Implementaciones concretas de los ports
|
|
- Aquí viven las dependencias externas (HTTP clients, filesystem, DB drivers)
|
|
|
|
---
|
|
|
|
## 🧠 3. Core Interfaces
|
|
|
|
### 3.1 LLMClient (`pkg/llm/`)
|
|
|
|
Abstracción multi-provider. Los productos nunca tocan un SDK de provider directamente — siempre pasan por esta interfaz.
|
|
|
|
```go
|
|
type LLMClient interface {
|
|
Generate(ctx context.Context, req CompletionRequest) (CompletionResponse, error)
|
|
Stream(ctx context.Context, req CompletionRequest) iter.Seq2[StreamChunk, error]
|
|
Name() string
|
|
Capabilities() ProviderCapabilities
|
|
}
|
|
|
|
type CompletionRequest struct {
|
|
Messages []Message
|
|
Tools []Tool
|
|
ToolChoice ToolChoice // "auto" | "required" | "none" | ToolRef
|
|
Model string
|
|
Temperature *float32
|
|
MaxTokens *int
|
|
Stop []string
|
|
Metadata map[string]string
|
|
}
|
|
|
|
type CompletionResponse struct {
|
|
ID string
|
|
Content string
|
|
ToolCalls []ToolCall
|
|
Usage TokenUsage
|
|
StopReason string // "end_turn" | "tool_use" | "max_tokens" | "stop_sequence"
|
|
}
|
|
|
|
type StreamChunk struct {
|
|
Delta string
|
|
ToolCalls []ToolCall // streamed incremental
|
|
FinishReason string
|
|
Usage TokenUsage // sólo en chunk final
|
|
}
|
|
|
|
type TokenUsage struct {
|
|
InputTokens int
|
|
OutputTokens int
|
|
TotalTokens int
|
|
}
|
|
|
|
type ProviderCapabilities struct {
|
|
SupportsTools bool
|
|
SupportsVision bool
|
|
SupportsJSON bool
|
|
MaxContextWindow int
|
|
}
|
|
```
|
|
|
|
**Ver detalles completos:** [`pkg/llm/README.md`](../pkg/llm/README.md)
|
|
|
|
### 3.2 Tool System (`pkg/tools/`)
|
|
|
|
Función invocable por el LLM con JSON Schema, permisos, y sandbox.
|
|
|
|
```go
|
|
type Tool struct {
|
|
Name string
|
|
Description string
|
|
InputSchema json.RawMessage // JSON Schema draft-07+
|
|
Required []string
|
|
Handler ToolHandler // func(ctx, args json.RawMessage) (Result, error)
|
|
Permission Permission // Allow | Ask | Deny
|
|
Examples []ToolExample // few-shot para el LLM
|
|
}
|
|
|
|
type ToolHandler func(ctx context.Context, args json.RawMessage) (ToolResult, error)
|
|
|
|
type ToolResult struct {
|
|
Content string
|
|
IsError bool
|
|
Metadata map[string]string
|
|
Artifacts []Artifact
|
|
}
|
|
|
|
type ToolCall struct {
|
|
ID string
|
|
Name string
|
|
Arguments json.RawMessage
|
|
Thought string // opcional: chain-of-thought
|
|
}
|
|
|
|
type Permission int
|
|
|
|
const (
|
|
Allow Permission = iota
|
|
Ask
|
|
Deny
|
|
)
|
|
|
|
type ToolRegistry interface {
|
|
Register(tool Tool) error
|
|
Get(name string) (Tool, bool)
|
|
List() []Tool
|
|
Filter(policy PermissionPolicy) []Tool
|
|
}
|
|
```
|
|
|
|
**Ver detalles completos:** [`pkg/tools/README.md`](../pkg/tools/README.md)
|
|
|
|
### 3.3 Agent Loop (`pkg/agent/`)
|
|
|
|
Bucle iterativo entre LLM y ejecución de tools. Es el "cerebro" que orquesta todo.
|
|
|
|
```go
|
|
type Loop interface {
|
|
Run(ctx context.Context, input string, history ...Message) (Response, error)
|
|
RunStream(ctx context.Context, input string, history ...Message) iter.Seq2[Chunk, error]
|
|
}
|
|
|
|
type Config struct {
|
|
LLM llm.LLMClient
|
|
Persona persona.Persona
|
|
Tools tools.Registry
|
|
Sandbox Sandbox
|
|
MaxIters int
|
|
Approver Approver // nil = auto-approve all
|
|
OnIteration func(Iteration) // observability hook
|
|
}
|
|
|
|
type Response struct {
|
|
Content string
|
|
ToolCalls []tools.Call
|
|
Iterations int
|
|
Duration time.Duration
|
|
TokenUsage llm.TokenUsage
|
|
}
|
|
```
|
|
|
|
**Algoritmo:**
|
|
|
|
```
|
|
function RunAgent(userMessage, session):
|
|
messages = append(session.Messages, userMessage)
|
|
iteration = 0
|
|
|
|
while iteration < MaxIterations:
|
|
iteration++
|
|
|
|
response = llm.Generate(messages, tools)
|
|
if no tool calls: return response
|
|
|
|
messages.append(assistantMsg(response))
|
|
|
|
for toolCall in response.ToolCalls:
|
|
tool = registry.Get(toolCall.Name)
|
|
|
|
# Approval gate
|
|
if tool.Permission == Ask && !session.AutoApprove:
|
|
if !cli.AskApproval(tool, toolCall):
|
|
messages.append(denialMessage(toolCall))
|
|
continue
|
|
|
|
# Sandbox validation
|
|
if err := sandbox.ValidateToolCall(tool, toolCall); err != nil {
|
|
messages.append(errorMessage(toolCall, err))
|
|
continue
|
|
|
|
# Execute
|
|
result, err := tool.Handler(ctx, toolCall.Arguments)
|
|
|
|
# Truncate if needed
|
|
result.Content = truncate(result.Content, MaxToolOutputBytes)
|
|
|
|
messages.append(toolResultMessage(toolCall, result))
|
|
|
|
return ErrorResponse("max_iterations_exceeded")
|
|
```
|
|
|
|
**Parámetros:**
|
|
|
|
| Parámetro | Default | Descripción |
|
|
|---|---|---|
|
|
| `MaxIterations` | 50 | Máximo de ciclos antes de cortar |
|
|
| `MaxTokensPerSession` | 1,000,000 | Hard cap de tokens consumidos |
|
|
| `MaxToolOutputBytes` | 50KB | Truncar outputs grandes |
|
|
| `ToolTimeout` | 30s | Default, overrideable por tool |
|
|
|
|
**Termination conditions:**
|
|
1. ✅ LLM devuelve respuesta sin `ToolCalls` (caso normal)
|
|
2. 🛑 `MaxIterations` alcanzado
|
|
3. 💰 `MaxTokensPerSession` excedido
|
|
4. ⏱️ Timeout global
|
|
5. 🚫 Usuario aborta (`Ctrl+C` o `/stop`)
|
|
|
|
**Ver detalles completos:** [`pkg/agent/README.md`](../pkg/agent/README.md)
|
|
|
|
### 3.4 Persona System (`pkg/persona/`)
|
|
|
|
Ensamblador de system prompts combinando base + persona YAML + AGENTS.md.
|
|
|
|
```go
|
|
type Persona struct {
|
|
ID string
|
|
Name string
|
|
Tone string
|
|
Style string
|
|
Language string
|
|
Constraints []string
|
|
FewShot []llm.Message
|
|
}
|
|
|
|
type Loader interface {
|
|
Load(ctx context.Context, configPath string) (Persona, error)
|
|
Discover(ctx context.Context, workdir string) (Persona, error)
|
|
}
|
|
```
|
|
|
|
**Cómo se construye el system prompt final:**
|
|
|
|
```
|
|
1. Base prompt (hardcoded en la librería)
|
|
2. Persona YAML (configurable)
|
|
3. AGENTS.md del proyecto (descubierto en árbol de directorios)
|
|
4. Working memory context (si hay compaction)
|
|
```
|
|
|
|
**AGENTS.md discovery:** Busca `./AGENTS.md`, sube al padre, etc., concatenando todos. También incluye `~/.config/rony/AGENTS.md` como default global.
|
|
|
|
**Ver detalles completos:** [`pkg/persona/README.md`](../pkg/persona/README.md)
|
|
|
|
### 3.5 Memory (`pkg/rag/`)
|
|
|
|
Retrieval-Augmented Generation: memoria persistente y búsqueda semántica.
|
|
|
|
```go
|
|
type Memory interface {
|
|
Add(ctx context.Context, fragment Fragment) error
|
|
Search(ctx context.Context, query string, topK int) ([]Fragment, error)
|
|
Forget(ctx context.Context, id string) error
|
|
}
|
|
|
|
type Fragment struct {
|
|
ID string
|
|
Content string
|
|
Vector []float32
|
|
Metadata map[string]string
|
|
Timestamp time.Time
|
|
ProjectID string
|
|
}
|
|
|
|
type Embedder interface {
|
|
Embed(ctx context.Context, text string) ([]float32, error)
|
|
Dimensions() int
|
|
}
|
|
```
|
|
|
|
**Tipos de memoria:**
|
|
|
|
| Tipo | Qué guarda | Persistencia |
|
|
|---|---|---|
|
|
| **Working** | Mensajes de la sesión actual | RAM |
|
|
| **Episodic** | Eventos pasados | Vector DB |
|
|
| **Semantic** | Conocimiento consolidado | Vector DB (curado) |
|
|
| **Procedural** | Patrones de uso | Vector DB (auto-aprendido) |
|
|
|
|
**Backends soportados:**
|
|
- ChromaDB embedded (default)
|
|
- Qdrant embedded
|
|
- SQLite + sqlite-vec
|
|
|
|
**Ver detalles completos:** [`pkg/rag/README.md`](../pkg/rag/README.md)
|
|
|
|
### 3.6 Sandbox (`pkg/tools/sandbox/`)
|
|
|
|
Sandbox de filesystem a nivel kernel usando `os.Root` (Go 1.24+).
|
|
|
|
```go
|
|
type Sandbox struct {
|
|
workspace *os.Root // Go 1.24+
|
|
configDir *os.Root // ~/.config/rony/
|
|
}
|
|
|
|
func (s *Sandbox) Open(path string) (*os.File, error)
|
|
func (s *Sandbox) Create(path string) (*os.File, error)
|
|
func (s *Sandbox) ReadFile(path string) ([]byte, error)
|
|
func (s *Sandbox) WriteFile(path string, data []byte, perm os.FileMode) error
|
|
```
|
|
|
|
**Por qué `os.Root` (Go 1.24+) es security-critical:**
|
|
|
|
| Vector de ataque | `strings.HasPrefix` (naive) | `os.Root` |
|
|
|---|---|---|
|
|
| `../../../etc/passwd` | Bloqueado si abs path no tiene prefix | Bloqueado por kernel |
|
|
| Symlink dentro de workspace → `/etc/passwd` | Bloqueado solo si resolvemos manualmente | Bloqueado nativamente |
|
|
| Race condition TOCTOU | Posible | Imposible (kernel-checked) |
|
|
| Path encoding (`%2e%2e`) | No detectado | Detectado por stdlib |
|
|
| Null bytes en path | Depende del OS | Manejado por stdlib |
|
|
|
|
> 🔒 Por eso la librería **requiere Go 1.26+** (ver [README §16.1.3.1](https://github.com/VictorVargas/rony-harness/blob/main/docs/architecture.md#16131)).
|
|
|
|
### 3.7 Configuration (`pkg/config/`)
|
|
|
|
Carga YAML con precedencia jerárquica.
|
|
|
|
```go
|
|
type Config struct {
|
|
Model string
|
|
Persona string
|
|
Provider ProviderConfig
|
|
Tools ToolPolicy
|
|
Logging LoggingConfig
|
|
Sandbox SandboxConfig
|
|
}
|
|
|
|
type Loader interface {
|
|
Load(ctx context.Context, workdir string) (Config, error)
|
|
}
|
|
```
|
|
|
|
**Orden de precedencia (mayor a menor):**
|
|
|
|
```
|
|
flags CLI > env vars > ./rony.yaml > ~/.config/rony/config.yaml > defaults
|
|
```
|
|
|
|
**Ver detalles completos:** [`pkg/config/README.md`](../pkg/config/README.md)
|
|
|
|
---
|
|
|
|
## 🔒 4. Modelo de Seguridad
|
|
|
|
### 4.1 Amenazas cubiertas
|
|
|
|
| Amenaza | Mitigación en la librería |
|
|
|---|---|
|
|
| Path traversal | `os.Root` sandbox |
|
|
| Command injection | Validación de comandos (delegado a productos que usan bash tool) |
|
|
| Resource exhaustion | `MaxIterations`, `MaxTokensPerSession`, `MaxToolOutputBytes` |
|
|
| Prompt injection | Wrap de contenido externo en tags `<untrusted_content>` (Phase 2) |
|
|
| Secret leakage | `Redact()` función para logs (Phase 2) |
|
|
| Tool misuse | Approval gates + permission policies |
|
|
|
|
### 4.2 Principio de mínimo privilegio
|
|
|
|
- Tools tienen `Permission: Allow | Ask | Deny`
|
|
- Default es `Allow` solo para tools read-only
|
|
- `Ask` para tools que mutan estado
|
|
- `Deny` es raro, usado para tools deshabilitados explícitamente
|
|
|
|
### 4.3 Capas de defensa (Defense in depth)
|
|
|
|
```
|
|
Capa 1: Permission policy → rechaza tools no autorizados
|
|
Capa 2: Approval gate (Ask) → usuario confirma antes de ejecutar
|
|
Capa 3: Sandbox validation → paths dentro de allowed roots
|
|
Capa 4: Kernel enforcement (os.Root) → garantía a nivel OS
|
|
Capa 5: Output truncation → no devuelve outputs enormes
|
|
Capa 6: Secret redaction → no expone secrets en logs/outputs
|
|
```
|
|
|
|
---
|
|
|
|
## 📐 5. Especificaciones Técnicas (SDD)
|
|
|
|
### 5.1 Requisitos Funcionales Core
|
|
|
|
| ID | Requisito | Implementación |
|
|
|---|---|---|
|
|
| LRF-001 | LLMClient interface | `pkg/llm/` |
|
|
| LRF-002 | Multi-provider (OpenAI, Anthropic, Ollama, llama.cpp) | `pkg/llm/providers/` |
|
|
| LRF-003 | Streaming nativo | `iter.Seq2` |
|
|
| LRF-004 | Tool calling con JSON Schema | `pkg/tools/` |
|
|
| LRF-005 | Agent loop con guardrails | `pkg/agent/` |
|
|
| LRF-006 | Persona system + AGENTS.md | `pkg/persona/` |
|
|
| LRF-007 | RAG memory | `pkg/rag/` |
|
|
| LRF-008 | Sandbox de filesystem (kernel) | `pkg/tools/sandbox/` |
|
|
| LRF-009 | Configuration con precedencia | `pkg/config/` |
|
|
| LRF-010 | Approval gates | `pkg/agent/` |
|
|
|
|
### 5.2 Requisitos No Funcionales
|
|
|
|
| ID | Categoría | Target |
|
|
|---|---|---|
|
|
| LRNF-001 | Go version mínimo | 1.26 (por os.Root) |
|
|
| LRNF-002 | Cobertura de tests | ≥80% |
|
|
| LRNF-003 | API stability | Semver estricto |
|
|
| LRNF-004 | Dependencies mínimas | Solo stdlib + SDKs de provider |
|
|
| LRNF-005 | Thread safety | Toda API pública es safe para uso concurrente |
|
|
| LRNF-006 | Context propagation | Toda llamada toma `context.Context` |
|
|
|
|
---
|
|
|
|
## 🧪 6. Testing
|
|
|
|
### 6.1 Mock LLM Server
|
|
|
|
Para tests deterministas, los productos pueden usar `pkg/llm/mock`:
|
|
|
|
```go
|
|
import "github.com/VictorVargas/rony-llm-agent/pkg/llm/mock"
|
|
|
|
mockClient := mock.New(mock.Responses{
|
|
{Match: "hola", Response: "¡Hola! ¿Cómo estás?"},
|
|
{Match: "*", Response: "default"},
|
|
})
|
|
```
|
|
|
|
### 6.2 Mock Memory
|
|
|
|
```go
|
|
import "github.com/VictorVargas/rony-llm-agent/pkg/rag/mock"
|
|
|
|
memory := mock.NewMemory([]rag.Fragment{
|
|
{Content: "doc1", ProjectID: "test"},
|
|
})
|
|
```
|
|
|
|
### 6.3 Tabla de tests críticos (toda la librería)
|
|
|
|
| Test | Paquete | Prioridad |
|
|
|---|---|---|
|
|
| `LLMClient.Generate` retorna respuesta válida | `pkg/llm/` | Alta |
|
|
| `LLMClient.Stream` emite chunks en orden | `pkg/llm/` | Alta |
|
|
| `ToolRegistry.Register/Get/List` | `pkg/tools/` | Alta |
|
|
| Agent loop termina sin tool calls | `pkg/agent/` | Alta |
|
|
| Agent loop termina en max iterations | `pkg/agent/` | Alta |
|
|
| Path sandbox rechaza `../../../etc/passwd` | `pkg/tools/sandbox/` | Alta |
|
|
| Persona loader desde YAML | `pkg/persona/` | Alta |
|
|
| AGENTS.md discovery (sube directorios) | `pkg/persona/` | Media |
|
|
| Config precedence (env > file > defaults) | `pkg/config/` | Alta |
|
|
| Memory Search retorna top-K por similitud | `pkg/rag/` | Alta |
|
|
|
|
---
|
|
|
|
## 📚 7. Convenciones de código
|
|
|
|
### 7.1 Naming
|
|
|
|
- **Packages:** lowercase, singular (`agent`, `tools`, `llm`)
|
|
- **Interfaces:** terminan en sustantivo o capability (`Loop`, `LLMClient`, `Embedder`)
|
|
- **Errors:** `ErrXXX` para sentinels, wrapped con `%w`
|
|
- **Constructors:** `New` para constructor principal, `NewXxx` para variantes
|
|
|
|
### 7.2 Errors
|
|
|
|
```go
|
|
// Sentinel errors
|
|
var (
|
|
ErrToolNotFound = errors.New("tool not found")
|
|
ErrSandboxViolation = errors.New("path outside allowed roots")
|
|
)
|
|
|
|
// Wrapping
|
|
if err != nil {
|
|
return fmt.Errorf("loading persona %s: %w", name, err)
|
|
}
|
|
```
|
|
|
|
### 7.3 Context
|
|
|
|
Toda función que pueda bloquear toma `ctx context.Context` como primer parámetro:
|
|
|
|
```go
|
|
func (l *Loop) Run(ctx context.Context, input string) (Response, error)
|
|
func (m *Memory) Search(ctx context.Context, query string, topK int) ([]Fragment, error)
|
|
```
|
|
|
|
---
|
|
|
|
## 🔄 8. Versionado
|
|
|
|
- **Semver estricto** (`vMAJOR.MINOR.PATCH`)
|
|
- **MAJOR:** breaking changes en `pkg/` (interfaces, signatures, tipos públicos)
|
|
- **MINOR:** nuevas features, nuevos paquetes, nuevos adapters
|
|
- **PATCH:** bugfixes
|
|
|
|
Los adapters privados (`pkg/llm/providers/openai/`) pueden cambiar sin bump de MAJOR si la interfaz `LLMClient` no cambia.
|
|
|
|
---
|
|
|
|
## 📖 9. Referencias
|
|
|
|
- **Go 1.26 release notes:** https://go.dev/doc/go1.26
|
|
- **`os.Root` documentation:** https://pkg.go.dev/os#Root
|
|
- **`iter.Seq2` documentation:** https://pkg.go.dev/iter
|
|
- **Hexagonal Architecture (Alistair Cockburn):** https://alistair.cockburn.us/hexagonal-architecture/
|
|
- **DDD (Eric Evans, 2003):** Domain-Driven Design
|
|
- **ReAct Pattern (Yao et al., 2022):** https://arxiv.org/abs/2210.03629
|
|
|
|
---
|
|
|
|
## 🔗 Documentos relacionados
|
|
|
|
- [`README.md`](./README.md) — Overview de la librería
|
|
- [`components.md`](./components.md) — Referencia detallada por paquete
|
|
- [`phase2.md`](./phase2.md) — Features avanzadas (MCP, RAG completo, Skills, etc.)
|
|
- [Productos que usan esta librería](https://github.com/VictorVargas) |