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 collections.abc import Generator
from pathlib import Path from pathlib import Path
from .config import Config from .config import AgentConfig, Config
from .db import Database from .db import Database
from .llm import LLMAdapter from .llm import LLMAdapter
from .router import build_system_prompt, format_messages_for_llm 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: 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.config = config
self.db = db self.db = db
self.llm = llm self.llm = llm
self.agent_config = agent_config or AgentConfig()
self.conv_id: str | None = None self.conv_id: str | None = None
self._memory = None # set by app after memory system init self._memory = None # set by app after memory system init
self._tools = None # set by app after tool system init self._tools = None # set by app after tool system init
self._skills_registry = None # set by app after skills 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): def set_memory(self, memory):
self._memory = memory self._memory = memory
@ -104,18 +115,29 @@ class Agent:
if self._memory: if self._memory:
memory_context = self._memory.get_context(user_input) memory_context = self._memory.get_context(user_input)
# Apply tool whitelist from agent config
tool_filter = self.agent_config.tools
tools_schema = [] tools_schema = []
tools_description = "" tools_description = ""
if self._tools: if self._tools:
tools_schema = self._tools.get_tools_schema() tools_schema = self._tools.get_tools_schema(filter_names=tool_filter)
tools_description = self._tools.get_tools_description() tools_description = self._tools.get_tools_description(filter_names=tool_filter)
skills_context = "" skills_context = ""
if self._skills_registry: 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( system_prompt = build_system_prompt(
identity_dir=self.config.identity_dir, identity_dir=identity_dir,
memory_context=memory_context, memory_context=memory_context,
tools_description=tools_description, tools_description=tools_description,
skills_context=skills_context, skills_context=skills_context,

View File

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