3.3: Modify Agent and ToolRegistry for multi-agent

Agent changes:
- Accept optional AgentConfig in __init__
- Add name property
- Filter tools via agent_config.tools whitelist in respond()
- Use agent-specific personality file when configured
- Pass agent name to skills registry for filtering

ToolRegistry changes:
- get_tools_schema() accepts filter_names parameter
- get_tools_description() accepts filter_names parameter
- When filter_names is None, all tools are returned (backward compat)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
cora-start
PeninsulaInd 2026-02-17 10:08:16 -06:00
parent 537e3bd528
commit 86511d5a0f
2 changed files with 38 additions and 11 deletions

View File

@ -9,7 +9,7 @@ import uuid
from collections.abc import Generator
from pathlib import Path
from .config import Config
from .config import AgentConfig, Config
from .db import Database
from .llm import LLMAdapter
from .router import build_system_prompt, format_messages_for_llm
@ -63,15 +63,26 @@ def _build_file_content_parts(files: list[str]) -> list[dict]:
class Agent:
def __init__(self, config: Config, db: Database, llm: LLMAdapter):
def __init__(
self,
config: Config,
db: Database,
llm: LLMAdapter,
agent_config: AgentConfig | None = None,
):
self.config = config
self.db = db
self.llm = llm
self.agent_config = agent_config or AgentConfig()
self.conv_id: str | None = None
self._memory = None # set by app after memory system init
self._tools = None # set by app after tool system init
self._skills_registry = None # set by app after skills init
@property
def name(self) -> str:
return self.agent_config.name
def set_memory(self, memory):
self._memory = memory
@ -104,18 +115,29 @@ class Agent:
if self._memory:
memory_context = self._memory.get_context(user_input)
# Apply tool whitelist from agent config
tool_filter = self.agent_config.tools
tools_schema = []
tools_description = ""
if self._tools:
tools_schema = self._tools.get_tools_schema()
tools_description = self._tools.get_tools_description()
tools_schema = self._tools.get_tools_schema(filter_names=tool_filter)
tools_description = self._tools.get_tools_description(filter_names=tool_filter)
skills_context = ""
if self._skills_registry:
skills_context = self._skills_registry.get_prompt_section()
skills_context = self._skills_registry.get_prompt_section(self.name)
# Use agent-specific personality file if configured
identity_dir = self.config.identity_dir
personality_file = self.agent_config.personality_file
if personality_file:
pf = Path(personality_file)
if pf.exists():
identity_dir = pf.parent
system_prompt = build_system_prompt(
identity_dir=self.config.identity_dir,
identity_dir=identity_dir,
memory_context=memory_context,
tools_description=tools_description,
skills_context=skills_context,

View File

@ -118,15 +118,20 @@ class ToolRegistry:
except Exception as e:
log.warning("Failed to load tool module %s: %s", module_name, e)
def get_tools_schema(self) -> list[dict]:
"""Get all tools in OpenAI function-calling format."""
return [t.to_openai_schema() for t in _TOOLS.values()]
def get_tools_schema(self, filter_names: list[str] | None = None) -> list[dict]:
"""Get tools in OpenAI function-calling format, optionally filtered."""
tools = _TOOLS.values()
if filter_names is not None:
tools = [t for t in tools if t.name in filter_names]
return [t.to_openai_schema() for t in tools]
def get_tools_description(self) -> str:
"""Human-readable tool list for system prompt."""
def get_tools_description(self, filter_names: list[str] | None = None) -> str:
"""Human-readable tool list for system prompt, optionally filtered."""
lines = []
by_cat: dict[str, list[ToolDef]] = {}
for t in _TOOLS.values():
if filter_names is not None and t.name not in filter_names:
continue
by_cat.setdefault(t.category, []).append(t)
for cat, tools in sorted(by_cat.items()):