1 VOXAgent
jfabian edited this page 2026-08-13 11:15:47 -03:00

VOXAgent

File: vox/agents/base.py

An agent is a self-contained execution unit with a unique identity, mounted capabilities, and loaded roles. It is the "I" in the VOX system — every decision, command, and message originates from or is addressed to an agent. Agents are declarative: configuration lives in agent.yml, behavior in roles/*.py, and I/O is capability-gated (no implicit filesystem magic).

Declaration (agent.yml)

The manifest schema is validated by AgentLoader.MANIFEST_SCHEMA:

name: "<agent_name>"          # required, str
id: "<agent_uuid>"            # required, str
master_id: ""                 # optional; empty = root agent
autostart: true               # optional; start on orchestrator boot
conversational: true          # optional; allow free-form LLM conversation
roles: ["chat"]               # optional; explicit role allow-list
personality:                  # optional; consumed by roles
  rules: |
    You are a helpful assistant.
  messages:
    on_boot: "Ready."
rate_limit_max_calls: 30      # optional; events per rate-limit window
rate_limit_window: 60         # optional; window in seconds

Capabilities are not declared in agent.yml. They are derived from role REQUIRES declarations (discovered by static AST analysis of the role files) plus the agent's system capabilities (e.g. comm.gateway). Unknown manifest fields produce warnings; wrong types are rejected.

Bootstrap Flow

Load agent.yml       →  validate schema, extract config
Load .env            →  optional per-agent environment overrides
Load roles           →  import roles/*.py, find VOXRole subclasses
Discover capabilities→  AST-scan REQUIRES in role files + system capabilities
Mount capabilities   →  bind each as a VOXBoundCapability proxy
Inject vault secrets →  for SENSITIVE_PARAMS
Validate REQUIRES    →  missing capability → role disabled, agent DEGRADED
Ready                →  agent object exists (IDLE)
Boot (async)         →  cap.initialize() + cap.boot() on each, emit on_boot → ACTIVE

Hierarchy

Each agent has a master_id pointing to its parent. The orchestrator enforces creation order: root first, then children.

describe() embeds direct subordinates recursively in the "subordinates" field — each child's full describe() dict appears nested inside its parent. This produces a clean tree: root agents at the top, with subordinates: [...] containing their children, grandchildren, etc.

Key Members

Member Purpose
self.id Agent UUID
self.name Agent display name
self.master_id Parent UUID (empty for root)
self.capabilities {cap_id: VOXBoundCapability} — mounted capabilities (e.g. self.capabilities["ai.llm"])
self.roles {role_name: VOXRole}
self.commands Set of all registered command names
self.events Set of all registered event names
self.orchestrator Reference to the runtime orchestrator (may be None)
self.memory VOXAgentMemory — append-only forensic ledger
self.store VOXAgentStore — operational asset storage
self.get_safe_path(sub_dir, filename) Sandboxed path resolution (raises on escape)
self.emit(event, **kwargs) Dispatch an event to registered role handlers
self.boot() Transition to ACTIVE
self.pause() / self.resume() / self.stop() / self.shutdown() Lifecycle operations

Agents access subordinates via self.orchestrator.get_children(id). Command discovery for delegation goes through get_command_map() (own commands) and the orchestrator's command registry.

Note: there is no cap_llm / cap_telegram attribute sugar and no self.messaging bus in the current API. Capabilities live in the self.capabilities dict; inter-agent traffic flows through VOXMessage envelopes, agent.emit(), and orchestrator.dispatch_inbound_message().

Outbound messaging

Roles send messages through the mounted comm.gateway capability with an explicit channel and recipient:

await self.agent.capabilities["comm.gateway"].send_text(
    "telegram", recipient_id, text  # channel, recipient, text
)

Lifecycle States

VOX uses a nine-state machine (BOOTING, IDLE, ACTIVE, PAUSING, PAUSED, RESUMING, STOPPING, STOPPED, FAILED) with validated transitions. See Agent Lifecycle.

Degradation

An agent is flagged DEGRADED when:

  • no active roles are loaded,
  • a role's required capability is unavailable or missing secrets,
  • a capability is missing required params (None-defaulted param unset).

Degraded agents are tracked separately by the orchestrator and surfaced in the fleet snapshot.