feat(chat): add agent orchestration system with plan_and_execute

Introduces TaskPlanner and AgentSpec so Pyra can decompose multi-step
tasks into sequential steps, each executed with a focused sub-agent
context rather than the full conversation history.

- plugins/base.py: AgentSpec dataclass + agent_spec() on Protocol/BasePlugin
- plugins/registry.py: register_builtin, get_agent, list_agents
- chat/planner.py: TaskPlanner with plan approval, per-step tool-use loop,
  verification call, and agent-aware routing
- chat/session.py: wires plan_and_execute as a built-in tool after load_all
- chat/history.py: planning hint in system prompt + dynamic agents listing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
curo1305
2026-05-17 21:03:42 +02:00
parent 72dae1e048
commit ad024807bc
5 changed files with 295 additions and 1 deletions
+33
View File
@@ -14,9 +14,11 @@ from pyra.chat.renderer import (
render_system,
render_text_response,
)
from pyra.chat.planner import TaskPlanner
from pyra.config.manager import load_config
from pyra.config.schema import PyraConfig
from pyra.memory.reader import list_memories
from pyra.plugins.base import Tool
from pyra.plugins.executor import ToolExecutor
from pyra.plugins.registry import PluginRegistry
from pyra.security.injection import scan_response
@@ -44,6 +46,37 @@ def start_chat() -> None:
registry = PluginRegistry.instance()
registry.load_all(pyra_home() / "plugins", cfg.plugins.enabled)
executor = ToolExecutor(registry, console)
planner = TaskPlanner(cfg, registry, executor)
registry.register_builtin(Tool(
name="plan_and_execute",
description=(
"Decompose a multi-step task into sequential steps and execute each with "
"a focused sub-agent. Use when the request has multiple distinct phases. "
"Specify 'agent' per step to route to a specialized agent."
),
parameters={
"type": "object",
"properties": {
"task": {"type": "string", "description": "Overall task description."},
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"description": {"type": "string", "description": "What this step should accomplish."},
"agent": {"type": "string", "description": "Optional agent name to handle this step."},
},
"required": ["description"],
},
"minItems": 1,
"description": "Ordered steps. Each step optionally routes to a named agent.",
},
},
"required": ["task", "steps"],
},
handler=planner.make_tool_handler(),
requires_approval=False,
))
history = ConversationHistory(cfg, registry)
session: PromptSession = PromptSession(