1b499c9b67
Antes, el runtime construia la ruta del system prompt como agents/<agent-id>/<file>, lo cual fallaba para agentes en agents/_specials/ (como Father Bot). Ahora: 1. config.Load() guarda el directorio del config en ConfigDir 2. llm.go usa ConfigDir para resolver rutas relativas Esto corrige que Father Bot operara sin su system prompt completo (369 lineas de instrucciones, pipeline, seguridad) usando solo la description de una linea como fallback. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
472 lines
21 KiB
Go
472 lines
21 KiB
Go
// Package config provides the configuration schema and loader for agents.
|
|
package config
|
|
|
|
import "time"
|
|
|
|
// AgentConfig is the root configuration for a single agent.
|
|
type AgentConfig struct {
|
|
Agent AgentMeta `yaml:"agent"`
|
|
Personality PersonalityCfg `yaml:"personality"`
|
|
LLM LLMCfg `yaml:"llm"`
|
|
Tools ToolsCfg `yaml:"tools"`
|
|
Matrix MatrixCfg `yaml:"matrix"`
|
|
SSH SSHCfg `yaml:"ssh"`
|
|
Security SecurityCfg `yaml:"security"`
|
|
Schedules []ScheduleCfg `yaml:"schedules"`
|
|
Storage StorageCfg `yaml:"storage"`
|
|
Memory MemoryCfg `yaml:"memory"`
|
|
Skills SkillsCfg `yaml:"skills"`
|
|
|
|
// ConfigDir is the directory containing the config file. Set by the loader
|
|
// at load time, not from YAML. Used to resolve relative paths like
|
|
// system_prompt_file correctly regardless of where the agent lives.
|
|
ConfigDir string `yaml:"-"`
|
|
}
|
|
|
|
// ── Identity ──────────────────────────────────────────────────────────────
|
|
|
|
type AgentMeta struct {
|
|
ID string `yaml:"id"`
|
|
Name string `yaml:"name"`
|
|
Version string `yaml:"version"`
|
|
Type string `yaml:"type"` // "agent" (default) or "robot" (command-only, no LLM)
|
|
Enabled bool `yaml:"enabled"`
|
|
Template bool `yaml:"template"` // if true, launcher will skip this agent
|
|
Description string `yaml:"description"`
|
|
Tags []string `yaml:"tags"`
|
|
}
|
|
|
|
// ── Personality ───────────────────────────────────────────────────────────
|
|
|
|
type PersonalityCfg struct {
|
|
// --- campos existentes (sin cambios) ---
|
|
Tone string `yaml:"tone"`
|
|
Verbosity string `yaml:"verbosity"`
|
|
Language string `yaml:"language"`
|
|
LanguagesSupported []string `yaml:"languages_supported"`
|
|
EmojiStyle string `yaml:"emoji_style"`
|
|
Prefix string `yaml:"prefix"`
|
|
ErrorStyle string `yaml:"error_style"`
|
|
Templates TemplatesCfg `yaml:"templates"`
|
|
Behavior BehaviorCfg `yaml:"behavior"`
|
|
|
|
// --- NUEVOS campos ---
|
|
// Identidad narrativa
|
|
Role string `yaml:"role"` // rol principal: "asistente general", "devops engineer", "analista de datos"
|
|
Backstory string `yaml:"backstory"` // breve historia/contexto del personaje (1-3 frases)
|
|
Expertise []string `yaml:"expertise"` // areas de experiencia: ["linux", "docker", "monitoring"]
|
|
Limitations []string `yaml:"limitations"` // que NO sabe o no debe intentar
|
|
|
|
// Estilo de comunicacion
|
|
Communication CommunicationCfg `yaml:"communication"`
|
|
|
|
// Directivas de comportamiento en texto libre
|
|
CustomDirectives []string `yaml:"custom_directives"` // instrucciones adicionales para el system prompt
|
|
}
|
|
|
|
type TemplatesCfg struct {
|
|
Greeting string `yaml:"greeting"`
|
|
UnknownCommand string `yaml:"unknown_command"`
|
|
PermissionDenied string `yaml:"permission_denied"`
|
|
Error string `yaml:"error"`
|
|
Success string `yaml:"success"`
|
|
Busy string `yaml:"busy"`
|
|
}
|
|
|
|
type BehaviorCfg struct {
|
|
Proactive bool `yaml:"proactive"`
|
|
AskConfirmation bool `yaml:"ask_confirmation"`
|
|
ShowReasoning bool `yaml:"show_reasoning"`
|
|
ThreadReplies bool `yaml:"thread_replies"`
|
|
TypingIndicator bool `yaml:"typing_indicator"`
|
|
AcknowledgeReceipt bool `yaml:"acknowledge_receipt"`
|
|
}
|
|
|
|
// CommunicationCfg define como se expresa el agente mas alla del tone basico.
|
|
type CommunicationCfg struct {
|
|
Formality string `yaml:"formality"` // formal | semiformal | casual | coloquial
|
|
Humor string `yaml:"humor"` // none | subtle | moderate | frequent
|
|
Personality string `yaml:"personality"` // analytical | creative | pragmatic | empathetic | assertive
|
|
ResponseStyle string `yaml:"response_style"` // structured | conversational | bullet_points | narrative
|
|
Quirks []string `yaml:"quirks"` // rasgos unicos: ["usa analogias de cocina", "cita a Linus Torvalds"]
|
|
AvoidTopics []string `yaml:"avoid_topics"` // temas que evita o redirige
|
|
Catchphrases []string `yaml:"catchphrases"` // frases tipicas que usa ocasionalmente
|
|
}
|
|
|
|
// ── LLM ───────────────────────────────────────────────────────────────────
|
|
|
|
type LLMCfg struct {
|
|
Primary LLMProviderCfg `yaml:"primary"`
|
|
Fallback LLMProviderCfg `yaml:"fallback"`
|
|
Reasoning LLMReasoningCfg `yaml:"reasoning"`
|
|
ToolUse LLMToolUseCfg `yaml:"tool_use"`
|
|
RateLimit LLMRateLimitCfg `yaml:"rate_limit"`
|
|
}
|
|
|
|
type LLMProviderCfg struct {
|
|
Provider string `yaml:"provider"`
|
|
Model string `yaml:"model"`
|
|
APIKeyEnv string `yaml:"api_key_env"`
|
|
BaseURL string `yaml:"base_url"`
|
|
MaxTokens int `yaml:"max_tokens"`
|
|
Temperature float64 `yaml:"temperature"`
|
|
|
|
// ClaudeCode holds configuration for the claude-code provider (claude -p).
|
|
ClaudeCode ClaudeCodeCfg `yaml:"claude_code"`
|
|
}
|
|
|
|
// ClaudeCodeCfg configures the claude -p subprocess provider.
|
|
type ClaudeCodeCfg struct {
|
|
Binary string `yaml:"binary"` // path to claude binary (default: "claude")
|
|
Timeout time.Duration `yaml:"timeout"` // subprocess timeout (default: 5m)
|
|
DisableTools bool `yaml:"disable_tools"` // pass --tools "" to disable all internal tools
|
|
AllowedTools []string `yaml:"allowed_tools"` // tools claude -p can use internally (e.g. Bash, Read, Edit)
|
|
DisallowedTools []string `yaml:"disallowed_tools"` // tools to block
|
|
WorkingDir string `yaml:"working_dir"` // working directory for claude -p
|
|
PermissionMode string `yaml:"permission_mode"` // default, acceptEdits, bypassPermissions, plan
|
|
Model string `yaml:"model"` // inner model: sonnet, opus, haiku, or full name
|
|
FallbackModel string `yaml:"fallback_model"` // fallback model if primary is overloaded
|
|
SessionID string `yaml:"session_id"` // fixed session ID for continuity
|
|
AddDirs []string `yaml:"add_dirs"` // additional directories accessible
|
|
Streaming bool `yaml:"streaming"` // use --output-format stream-json for realtime progress
|
|
ShowToolProgress bool `yaml:"show_tool_progress"` // edit Matrix message to show tool usage progress
|
|
}
|
|
|
|
type LLMReasoningCfg struct {
|
|
SystemPromptFile string `yaml:"system_prompt_file"`
|
|
ContextWindow int `yaml:"context_window"`
|
|
MemoryMessages int `yaml:"memory_messages"`
|
|
}
|
|
|
|
type LLMToolUseCfg struct {
|
|
Enabled bool `yaml:"enabled"`
|
|
MaxIterations int `yaml:"max_iterations"`
|
|
ParallelCalls bool `yaml:"parallel_calls"`
|
|
}
|
|
|
|
type LLMRateLimitCfg struct {
|
|
RequestsPerMinute int `yaml:"requests_per_minute"`
|
|
TokensPerMinute int `yaml:"tokens_per_minute"`
|
|
ConcurrentRequests int `yaml:"concurrent_requests"`
|
|
}
|
|
|
|
// ── Tools ─────────────────────────────────────────────────────────────────
|
|
|
|
type ToolsCfg struct {
|
|
SSH SSHToolCfg `yaml:"ssh"`
|
|
HTTP HTTPToolCfg `yaml:"http"`
|
|
Scripts ScriptsCfg `yaml:"scripts"`
|
|
FileOps FileOpsCfg `yaml:"file_ops"`
|
|
Matrix MatrixToolCfg `yaml:"matrix_send"`
|
|
MCP MCPToolCfg `yaml:"mcp"`
|
|
Memory MemoryToolCfg `yaml:"memory"`
|
|
Knowledge KnowledgeToolCfg `yaml:"knowledge"`
|
|
SharedKnowledge SharedKnowledgeToolCfg `yaml:"shared_knowledge"`
|
|
Skills SkillsToolCfg `yaml:"skills"`
|
|
IMDb IMDbToolCfg `yaml:"imdb"`
|
|
}
|
|
|
|
type MatrixToolCfg struct {
|
|
AllowedRooms []string `yaml:"allowed_rooms"` // if non-empty, only these room IDs can be targeted
|
|
}
|
|
|
|
type KnowledgeToolCfg struct {
|
|
Enabled bool `yaml:"enabled"`
|
|
Dir string `yaml:"dir"` // default: "./knowledge" (relative to agent dir)
|
|
}
|
|
|
|
type SharedKnowledgeToolCfg struct {
|
|
Enabled bool `yaml:"enabled"` // default false
|
|
Dir string `yaml:"dir"` // default "knowledges" (relative to project root)
|
|
DBPath string `yaml:"db_path"` // default "knowledges/data/knowledge.db"
|
|
}
|
|
|
|
type SSHToolCfg struct {
|
|
Enabled bool `yaml:"enabled"`
|
|
AllowedTargets []string `yaml:"allowed_targets"`
|
|
AllowedCommands []string `yaml:"allowed_commands"` // allowlist: if non-empty, only these command prefixes are permitted
|
|
ForbiddenCommands []string `yaml:"forbidden_commands"`
|
|
Timeout time.Duration `yaml:"timeout"`
|
|
MaxConcurrent int `yaml:"max_concurrent"`
|
|
RequireConfirmation []string `yaml:"require_confirmation"`
|
|
}
|
|
|
|
type HTTPToolCfg struct {
|
|
Enabled bool `yaml:"enabled"`
|
|
AllowedDomains []string `yaml:"allowed_domains"`
|
|
Timeout time.Duration `yaml:"timeout"`
|
|
MaxRetries int `yaml:"max_retries"`
|
|
}
|
|
|
|
type ScriptsCfg struct {
|
|
Enabled bool `yaml:"enabled"`
|
|
ScriptsDir string `yaml:"scripts_dir"`
|
|
Allowed []string `yaml:"allowed"`
|
|
Timeout time.Duration `yaml:"timeout"`
|
|
Sandbox bool `yaml:"sandbox"`
|
|
}
|
|
|
|
type FileOpsCfg struct {
|
|
Enabled bool `yaml:"enabled"`
|
|
AllowedPaths []string `yaml:"allowed_paths"`
|
|
ReadOnly bool `yaml:"read_only"`
|
|
}
|
|
|
|
type MCPToolCfg struct {
|
|
Enabled bool `yaml:"enabled"`
|
|
Servers []MCPServerCfg `yaml:"servers"`
|
|
Expose MCPExposeCfg `yaml:"expose"`
|
|
}
|
|
|
|
type MCPServerCfg struct {
|
|
Name string `yaml:"name"` // nombre logico del servidor
|
|
Transport string `yaml:"transport"` // "stdio" | "sse" (default: auto-detect)
|
|
Command string `yaml:"command"` // stdio: comando a ejecutar
|
|
Args []string `yaml:"args"` // stdio: argumentos del comando
|
|
Env map[string]string `yaml:"env"` // stdio: variables de entorno extra
|
|
URL string `yaml:"url"` // sse: URL del servidor
|
|
Headers map[string]string `yaml:"headers"` // sse: headers HTTP extra (auth, etc.)
|
|
Tools []string `yaml:"tools"` // filtro: solo exponer estas tools (vacio = todas)
|
|
Prefix string `yaml:"prefix"` // prefijo para nombres de tools (evitar colisiones)
|
|
Timeout time.Duration `yaml:"timeout"` // timeout por llamada (default: 30s)
|
|
}
|
|
|
|
type MCPExposeCfg struct {
|
|
Port int `yaml:"port"`
|
|
Tools []string `yaml:"tools"`
|
|
}
|
|
|
|
// ── Matrix ────────────────────────────────────────────────────────────────
|
|
|
|
type MatrixCfg struct {
|
|
Homeserver string `yaml:"homeserver"`
|
|
UserID string `yaml:"user_id"`
|
|
AccessTokenEnv string `yaml:"access_token_env"`
|
|
DeviceID string `yaml:"device_id"`
|
|
Encryption EncryptionCfg `yaml:"encryption"`
|
|
Rooms RoomsCfg `yaml:"rooms"`
|
|
Filters FiltersCfg `yaml:"filters"`
|
|
Threads ThreadsCfg `yaml:"threads"`
|
|
}
|
|
|
|
// ThreadsCfg controls Matrix thread support (m.thread).
|
|
type ThreadsCfg struct {
|
|
Enabled bool `yaml:"enabled"` // respond in threads when message is in a thread (default true)
|
|
AutoThread bool `yaml:"auto_thread"` // auto-create a thread for each new conversation (default false)
|
|
}
|
|
|
|
type EncryptionCfg struct {
|
|
Enabled bool `yaml:"enabled"`
|
|
StorePath string `yaml:"store_path"`
|
|
PickleKeyEnv string `yaml:"pickle_key_env"` // env var with hex-encoded 32-byte key
|
|
TrustMode string `yaml:"trust_mode"` // tofu | cross-signing | manual
|
|
RecoveryKeyEnv string `yaml:"recovery_key_env"` // env var with base58 SSSS recovery key for cross-signing
|
|
}
|
|
|
|
type RoomsCfg struct {
|
|
Listen []string `yaml:"listen"`
|
|
Respond []string `yaml:"respond"`
|
|
Admin []string `yaml:"admin"`
|
|
}
|
|
|
|
type FiltersCfg struct {
|
|
// CommandPrefix is the prefix required for commands (e.g. "!" means "!help").
|
|
// Set to "" (empty) to allow commands without prefix — useful for robots where
|
|
// every message is a potential command. When empty, "!help" still works for
|
|
// backward compatibility (the leading "!" is stripped automatically).
|
|
CommandPrefix string `yaml:"command_prefix"`
|
|
MentionRespond bool `yaml:"mention_respond"`
|
|
DMRespond bool `yaml:"dm_respond"`
|
|
IgnoreBots bool `yaml:"ignore_bots"`
|
|
IgnoreUsers []string `yaml:"ignore_users"`
|
|
// Deprecated: use security/ centralized groups instead. Kept for backward compatibility.
|
|
AllowedUsers []string `yaml:"allowed_users"`
|
|
UnauthorizedResponse string `yaml:"unauthorized_response"` // silent (default) | explicit
|
|
MinPowerLevel int `yaml:"min_power_level"`
|
|
}
|
|
|
|
// ── SSH Inventory ─────────────────────────────────────────────────────────
|
|
|
|
type SSHCfg struct {
|
|
Defaults SSHDefaultsCfg `yaml:"defaults"`
|
|
Targets map[string]SSHTargetCfg `yaml:"targets"`
|
|
}
|
|
|
|
type SSHDefaultsCfg struct {
|
|
User string `yaml:"user"`
|
|
Port int `yaml:"port"`
|
|
KeyFileEnv string `yaml:"key_file_env"`
|
|
KnownHosts string `yaml:"known_hosts"`
|
|
KeepaliveInterval time.Duration `yaml:"keepalive_interval"`
|
|
Timeout time.Duration `yaml:"timeout"`
|
|
}
|
|
|
|
type SSHTargetCfg struct {
|
|
Hosts []string `yaml:"hosts"`
|
|
User string `yaml:"user"`
|
|
Port int `yaml:"port"`
|
|
JumpHost string `yaml:"jump_host"`
|
|
KeyFileEnv string `yaml:"key_file_env"`
|
|
}
|
|
|
|
// ── Security ──────────────────────────────────────────────────────────────
|
|
|
|
type SecurityCfg struct {
|
|
// Deprecated: use security/ centralized groups instead (see security/user-groups.yaml, permissions.yaml).
|
|
// Kept for backward compatibility; will be removed in a future issue.
|
|
Roles map[string]RoleCfg `yaml:"roles"`
|
|
Audit AuditCfg `yaml:"audit"`
|
|
Secrets SecretsCfg `yaml:"secrets"`
|
|
Sanitize SanitizeCfg `yaml:"sanitize"`
|
|
ToolRateLimit ToolRateLimitCfg `yaml:"tool_rate_limit"`
|
|
}
|
|
|
|
// ToolRateLimitCfg controls per-room rate limiting of tool executions.
|
|
type ToolRateLimitCfg struct {
|
|
Enabled bool `yaml:"enabled"` // enable tool rate limiting (default false)
|
|
MaxCallsPerMin int `yaml:"max_calls_per_min"` // max tool calls per room per minute (default 10)
|
|
CleanupIntervalS int `yaml:"cleanup_interval_s"` // seconds between stale entry cleanup (default 60)
|
|
}
|
|
|
|
// SanitizeCfg controls prompt injection detection on incoming messages.
|
|
type SanitizeCfg struct {
|
|
Enabled bool `yaml:"enabled"` // enable sanitization (default false)
|
|
Mode string `yaml:"mode"` // warn | strip | reject (default warn)
|
|
MinSeverity string `yaml:"min_severity"` // low | medium | high (default medium)
|
|
DisabledPatterns []string `yaml:"disabled_patterns"` // pattern names to skip
|
|
}
|
|
|
|
type RoleCfg struct {
|
|
Users []string `yaml:"users"`
|
|
Actions []string `yaml:"actions"`
|
|
}
|
|
|
|
type AuditCfg struct {
|
|
Enabled bool `yaml:"enabled"`
|
|
LogFile string `yaml:"log_file"`
|
|
LogToRoom string `yaml:"log_to_room"`
|
|
Include []string `yaml:"include"`
|
|
}
|
|
|
|
type SecretsCfg struct {
|
|
Provider string `yaml:"provider"` // env | vault | sops
|
|
}
|
|
|
|
// ── Scheduling ────────────────────────────────────────────────────────────
|
|
|
|
type ScheduleCfg struct {
|
|
Name string `yaml:"name"`
|
|
Cron string `yaml:"cron"`
|
|
Action ScheduledAction `yaml:"action"`
|
|
OnFailure FailureAction `yaml:"on_failure"`
|
|
OutputRoom string `yaml:"output_room"`
|
|
}
|
|
|
|
type ScheduledAction struct {
|
|
Kind string `yaml:"kind"`
|
|
Target string `yaml:"target"`
|
|
Command string `yaml:"command"`
|
|
Script string `yaml:"script"`
|
|
|
|
// Phase 1: send_message and llm_prompt fields
|
|
Message string `yaml:"message"` // inline text for send_message
|
|
Template string `yaml:"template"` // path to .md file for send_message
|
|
Prompt string `yaml:"prompt"` // inline prompt text for llm_prompt
|
|
}
|
|
|
|
type FailureAction struct {
|
|
NotifyRoom string `yaml:"notify_room"`
|
|
EscalateTo string `yaml:"escalate_to"`
|
|
}
|
|
|
|
// ── Storage ───────────────────────────────────────────────────────────────
|
|
|
|
type StorageCfg struct {
|
|
BasePath string `yaml:"base_path"` // root for all data; default $AGENTS_DATA_DIR/<id> or agents/<id>/data
|
|
State StateStorageCfg `yaml:"state"`
|
|
Cache CacheStorageCfg `yaml:"cache"`
|
|
History HistoryStorageCfg `yaml:"history"`
|
|
}
|
|
|
|
type StateStorageCfg struct {
|
|
Backend string `yaml:"backend"` // sqlite | redis | file
|
|
Path string `yaml:"path"`
|
|
}
|
|
|
|
type CacheStorageCfg struct {
|
|
Enabled bool `yaml:"enabled"`
|
|
Backend string `yaml:"backend"` // memory | redis
|
|
TTL time.Duration `yaml:"ttl"`
|
|
MaxEntries int `yaml:"max_entries"`
|
|
}
|
|
|
|
type HistoryStorageCfg struct {
|
|
Backend string `yaml:"backend"`
|
|
Path string `yaml:"path"`
|
|
Retention time.Duration `yaml:"retention"`
|
|
}
|
|
|
|
// ── Memory ────────────────────────────────────────────────────────────────
|
|
|
|
type MemoryCfg struct {
|
|
Enabled bool `yaml:"enabled"`
|
|
WindowSize int `yaml:"window_size"` // sliding window size per room (default 20)
|
|
DBPath string `yaml:"db_path"` // SQLite path (default agents/<id>/data/memory.db)
|
|
}
|
|
|
|
type MemoryToolCfg struct {
|
|
Enabled bool `yaml:"enabled"`
|
|
}
|
|
|
|
// ── Skills ────────────────────────────────────────────────────────────────
|
|
|
|
type SkillsCfg struct {
|
|
Enabled bool `yaml:"enabled"` // enable skills system (default false)
|
|
SkillsPath string `yaml:"path"` // path to skills directory (default: "skills/")
|
|
Categories []string `yaml:"categories"` // filter: only load skills from these categories (empty = all)
|
|
Timeout time.Duration `yaml:"timeout"` // timeout for script execution (default: 60s)
|
|
}
|
|
|
|
type SkillsToolCfg struct {
|
|
AllowedInterpreters []string `yaml:"allowed_interpreters"` // allowlist for skill script execution (default: ["bash", "sh"])
|
|
}
|
|
|
|
type IMDbToolCfg struct {
|
|
Enabled bool `yaml:"enabled"`
|
|
APIKey string `yaml:"api_key"` // OMDb API key (get from http://www.omdbapi.com/)
|
|
APIKeyEnv string `yaml:"api_key_env"` // env var name for API key (e.g., "OMDB_API_KEY")
|
|
Timeout time.Duration `yaml:"timeout"` // timeout for API requests (default: 10s)
|
|
}
|
|
|
|
// ── Special Agents ────────────────────────────────────────────────────────
|
|
|
|
// SpecialConfig is the root configuration for a special agent (no Matrix identity).
|
|
type SpecialConfig struct {
|
|
Special SpecialMeta `yaml:"special"`
|
|
LLM LLMCfg `yaml:"llm"`
|
|
Orchestration OrchestrationCfg `yaml:"orchestration"`
|
|
}
|
|
|
|
// SpecialMeta identifies a special agent.
|
|
type SpecialMeta struct {
|
|
ID string `yaml:"id"`
|
|
Type string `yaml:"type"` // "orchestrator", "scheduler", etc.
|
|
Enabled bool `yaml:"enabled"`
|
|
Description string `yaml:"description"`
|
|
}
|
|
|
|
// OrchestrationCfg configures the multi-bot orchestrator.
|
|
type OrchestrationCfg struct {
|
|
MaxIterations int `yaml:"max_iterations"`
|
|
QualityThreshold float64 `yaml:"quality_threshold"`
|
|
DelegationTimeout time.Duration `yaml:"delegation_timeout"`
|
|
RepetitionThreshold float64 `yaml:"repetition_threshold"` // 0-1: similarity ratio to detect circular conversations
|
|
Rooms []OrchestratedRoomCfg `yaml:"rooms"`
|
|
}
|
|
|
|
// OrchestratedRoomCfg defines a room managed by the orchestrator.
|
|
type OrchestratedRoomCfg struct {
|
|
RoomID string `yaml:"room_id"`
|
|
Participants []string `yaml:"participants"` // bot IDs that participate in this room
|
|
}
|