Files
unibots/internal/config/schema_test.go
T
agent fc644ecd6e feat: import agents_and_robots platform as unibots (Matrix-out, unibus transport)
Reemplaza el scaffold del echobot por la plataforma completa de bots traida
desde ~/DataProyects/Github/agents_and_robots tras la operacion Matrix-out:
los bots ya no hablan por Matrix sino por el bus unibus (modelo todo-rooms +
E2E via shell/transportunibus sobre github.com/enmanuel/unibus/pkg/client).

- go.mod: replace de unibus -> ../unibus y de fn-registry -> ../../../.. (paths
  relativos reajustados a la nueva ubicacion dentro de fn_registry).
- app.md: bump a 0.2.0, descripcion + arquitectura + comandos + gotchas reales.
- modulo Go conservado como github.com/enmanuel/agents (sin reescribir imports).

agents_and_robots queda archivado como museo de la era Matrix.
2026-06-07 11:50:13 +02:00

212 lines
4.7 KiB
Go

package config
import (
"testing"
"gopkg.in/yaml.v3"
)
// TestAgentConfigParseMinimal verifies that a minimal config YAML (with only
// required fields) parses into AgentConfig without error.
func TestAgentConfigParseMinimal(t *testing.T) {
const minimalYAML = `
agent:
id: test-bot
name: Test Bot
enabled: true
bus:
nats_url: "nats://127.0.0.1:4250"
ctrl_url: "http://127.0.0.1:8470"
llm:
primary:
provider: openai
model: gpt-4o
`
var cfg AgentConfig
if err := yaml.Unmarshal([]byte(minimalYAML), &cfg); err != nil {
t.Fatalf("failed to parse minimal config: %v", err)
}
if cfg.Agent.ID != "test-bot" {
t.Errorf("expected agent.id=test-bot, got %q", cfg.Agent.ID)
}
if cfg.Bus.NatsURL != "nats://127.0.0.1:4250" {
t.Errorf("expected bus.nats_url, got %q", cfg.Bus.NatsURL)
}
if cfg.LLM.Primary.Provider != "openai" {
t.Errorf("expected provider=openai, got %q", cfg.LLM.Primary.Provider)
}
}
// TestAgentConfigIgnoresRemovedSections verifies that YAML containing the
// removed sections (agents, observability, resilience) still parses without
// error. yaml.v3 silently ignores unknown keys.
func TestAgentConfigIgnoresRemovedSections(t *testing.T) {
const yamlWithRemoved = `
agent:
id: legacy-bot
name: Legacy Bot
enabled: true
bus:
nats_url: "nats://127.0.0.1:4250"
ctrl_url: "http://127.0.0.1:8470"
llm:
primary:
provider: openai
model: gpt-4o
# These sections were removed from the schema but may still exist in old YAMLs.
agents:
peers:
- id: other-bot
capabilities: [general]
room: "!abc:server.com"
delegation:
enabled: false
protocol:
format: json
channel: matrix
observability:
logging:
level: info
format: json
metrics:
enabled: false
health:
enabled: true
port: 8080
tracing:
enabled: false
resilience:
circuit_breaker:
failure_threshold: 5
timeout: 30s
retry:
max_attempts: 2
backoff: exponential
shutdown:
timeout: 10s
queue:
enabled: true
max_size: 100
`
var cfg AgentConfig
if err := yaml.Unmarshal([]byte(yamlWithRemoved), &cfg); err != nil {
t.Fatalf("parsing config with removed sections should succeed, got: %v", err)
}
if cfg.Agent.ID != "legacy-bot" {
t.Errorf("expected agent.id=legacy-bot, got %q", cfg.Agent.ID)
}
}
// TestAgentConfigParseFull verifies that a config YAML with all active sections
// parses correctly, including personality with communication.
func TestAgentConfigParseFull(t *testing.T) {
const fullYAML = `
agent:
id: full-bot
name: Full Bot
version: "1.0.0"
enabled: true
description: "A fully configured bot"
tags: [test, full]
personality:
tone: friendly
verbosity: concise
language: es
role: "asistente general"
communication:
formality: semiformal
humor: subtle
personality: pragmatic
response_style: structured
quirks: ["usa analogias"]
avoid_topics: ["politica"]
catchphrases: ["interesante"]
llm:
primary:
provider: openai
model: gpt-4o
api_key_env: OPENAI_API_KEY
max_tokens: 4096
temperature: 0.7
tool_use:
enabled: true
max_iterations: 5
bus:
nats_url: "nats://127.0.0.1:4250"
ctrl_url: "http://127.0.0.1:8470"
handle: full
threads:
enabled: true
auto_thread: false
tools:
ssh:
enabled: false
http:
enabled: true
allowed_domains: ["api.example.com"]
timeout: 10s
security:
sanitize:
enabled: true
mode: warn
min_severity: medium
tool_rate_limit:
enabled: true
max_calls_per_min: 10
storage:
base_path: "/data/full-bot"
memory:
enabled: true
window_size: 30
skills:
enabled: true
path: "skills/"
categories: ["devops"]
timeout: 60s
`
var cfg AgentConfig
if err := yaml.Unmarshal([]byte(fullYAML), &cfg); err != nil {
t.Fatalf("failed to parse full config: %v", err)
}
// Verify key fields
if cfg.Agent.ID != "full-bot" {
t.Errorf("agent.id: got %q", cfg.Agent.ID)
}
if cfg.Personality.Communication.Humor != "subtle" {
t.Errorf("personality.communication.humor: got %q", cfg.Personality.Communication.Humor)
}
if len(cfg.Personality.Communication.Quirks) != 1 {
t.Errorf("personality.communication.quirks: expected 1, got %d", len(cfg.Personality.Communication.Quirks))
}
if !cfg.LLM.ToolUse.Enabled {
t.Error("llm.tool_use.enabled should be true")
}
if !cfg.Tools.HTTP.Enabled {
t.Error("tools.http.enabled should be true")
}
if cfg.Storage.BasePath != "/data/full-bot" {
t.Errorf("storage.base_path: got %q", cfg.Storage.BasePath)
}
if !cfg.Memory.Enabled {
t.Error("memory.enabled should be true")
}
if !cfg.Skills.Enabled {
t.Error("skills.enabled should be true")
}
if !cfg.Security.Sanitize.Enabled {
t.Error("security.sanitize.enabled should be true")
}
}