feat(F): F-TEST + F-DOC + F-UI-TRIG — Phase F complete!

- F-TEST: tests/test_phase_f_agents.py (1425 lines, 45 tests, all pass) — ReAct Loop, Permissions, Approvals, Skills, Context Builder, Data Policy, Transparency, Workstream, Budget
- F-DOC: docs/api-documentation.md (Phase F endpoints), docs/plugin-development-guide.md (Agent chapter 32), docs/test-strategy.md (Phase F test conventions)
- F-UI-TRIG: trigger_dispatcher dispatches agents on ui.*/context.* events (already implemented in F-PROACTIVE)
- Bug fix: approval.py metadata reserved attribute renamed to request_metadata
- PROGRESS.md: Phase F marked done, ~155/223 tasks done (70%)
This commit is contained in:
Agent Zero
2026-08-17 19:36:42 +02:00
parent ff08ea8012
commit 680557087e
7 changed files with 1693 additions and 11 deletions
+158
View File
@@ -2388,4 +2388,162 @@ Das Frontend nutzt die API-Client-Funktionen aus `importExport.ts`:
---
## 32. Agents (Phase F)
Phase F introduces a full agent system: agent definitions, a ReAct loop, a tool registry, a skill registry, a permission model, an approval workflow, and workstream integration. This chapter explains how plugins can contribute agents, tools, and skills.
### 32.1 Agent Definition
An agent is defined by an `AgentDefinition` record (automation plugin). Key fields:
- `name`, `description` — display and purpose.
- `llm_model`, `provider`, `api_key`, `api_base` — LLM configuration (secrets never exposed via API).
- `system_prompt` — the agent's base instructions.
- `max_steps`, `max_tokens`, `max_duration_seconds` — execution limits.
- `budget_limit_usd` — cumulative cost cap per agent.
- `tool_ids`, `skill_ids` — which tools and skills the agent may use.
- `mode``reactive` (manual/proactive trigger) or `proactive`.
- `trace_mode``standard` or `extended` (extended posts ReAct steps to the workstream).
- `ai_use_case_metadata` — allowed data categories for the data policy.
Create an agent via `POST /api/v1/agents` or directly in code:
```python
from app.plugins.builtins.automation.models import AgentDefinition
agent = AgentDefinition(
tenant_id=tenant_id,
name="Support Bot",
description="Answers support questions",
llm_model="gpt-4o",
system_prompt="You are a helpful support assistant.",
tool_ids=["mail_read", "contact_search"],
skill_ids=["support_skill"],
max_steps=10,
budget_limit_usd=5.0,
)
```
### 32.2 Registering Tools in the ToolRegistry
Tools are registered in the central `ToolRegistry` (ai_assistant plugin). A tool exposes an OpenAI-style function schema and a handler.
```python
from app.plugins.builtins.ai_assistant.contracts import get_tool_registry
from app.ai.agent_tools import AITool
async def _search_contacts_handler(args: dict, ctx: dict) -> dict:
# ... business logic ...
return {"results": [...]}
registry = get_tool_registry()
registry.register(AITool(
name="contact_search",
description="Search contacts by name or email",
parameters={
"type": "object",
"properties": {"query": {"type": "string"}},
"required": ["query"],
},
handler=_search_contacts_handler,
required_permission="contacts:read",
))
```
- `required_permission` gates the tool: a user only gets the tool if they hold that permission.
- The handler receives `(args, ctx)` where `ctx` contains `tenant_id`, `user_id`, `db`, and `agent_run_id`.
### 32.3 Registering Skills in the SkillRegistry
Skills bundle instructions and allowed tools. They are registered in the singleton `SkillRegistry`.
```python
from app.ai.skill_registry import SkillDefinition, get_skill_registry
skill = SkillDefinition(
name="support_skill",
description="Support workflow instructions",
instructions="Use contact_search then mail_read to answer support tickets.",
allowed_tool_ids=["contact_search", "mail_read"],
category="support",
)
get_skill_registry().register(skill)
```
- `get_by_names([...])` resolves skills and skips unknown names.
- A skill **never grants** a tool the user does not already have permission for — the effective tool set is the intersection of user, agent, skill, and tool permissions.
### 32.4 ReAct Loop
The ReAct loop (`app.ai.agent_loop.run_react_loop`) drives the agent:
1. Build context (system prompt + user message).
2. Call the LLM with the available tool schemas.
3. If the LLM returns a tool call, execute the tool handler and append the observation.
4. Repeat until a final answer, `max_steps`, timeout, or budget is reached.
```python
from app.ai.agent_loop import run_react_loop
result = await run_react_loop(
agent_definition=agent,
messages=[{"role": "user", "content": "Find the latest invoice"}],
tools=tool_schemas,
tool_registry=registry,
db=db,
tenant_id=tenant_id,
user_id=user_id,
agent_run_id=run_id,
max_steps=20,
timeout_seconds=300,
)
```
`result` is a `ReActResult` with `status`, `steps`, `final_content`, `total_cost_usd`, and `error`. Statuses: `completed`, `stopped_max_steps`, `stopped_timeout`, `stopped_error`, `budget_exceeded`.
### 32.5 Permission Model
Effective agent permissions are the **intersection** of four layers:
```
User permissions ∩ Agent tool_ids ∩ Skill allowed_tool_ids ∩ Tool required_permission
```
- `resolve_agent_permissions(db, tenant_id, user_id, agent)` returns an `AgentPermissionContext` with `effective_tool_ids` and `can_use_tool(name)`.
- System admins bypass the permission check and get all tools configured on the agent.
- `filter_visible_agents` respects `agents:read`; `check_agent_execute_permission` respects `agents:execute`.
- Optimistic locking: PATCH/DELETE on agents require a matching `version`; a mismatch returns `409 conflict`.
### 32.6 Approval Workflow
Tools that require human approval pause the loop and create an `ApprovalRequest` (`app.core.approval`).
- Status lifecycle: `pending``approved` | `rejected` | `expired`.
- Create: `create_approval_request(db, tenant_id, entity_type=..., entity_id=..., action=..., requested_by=..., metadata=...)`.
- Resolve: `resolve_approval_request(db, tenant_id, request_id, decision="approved"|"rejected", approver_id=..., comment=...)`.
- Expire: `expire_approval_request(db, tenant_id, request_id)`.
- API: `POST /api/v1/approvals`, `POST /api/v1/approvals/{id}/approve|reject`.
### 32.7 Workstream Integration
Agents post messages, steps, and results to the communication system (`app.ai.agent_workstream`):
- `post_agent_message` — text or block message, marked AI-generated.
- `post_agent_step` — ReAct step as an `action_card` (only in `extended` trace mode).
- `post_agent_result` — final result with `status`, `steps_taken`, `total_cost_usd`, `run_id`.
- `post_approval_request` — approval card.
All messages are marked with AI-generated transparency metadata.
### 32.8 Data Policy & Transparency
- `enforce_data_policy(db, tenant_id, messages, agent)` strips sensitive fields, enforces allowed data categories from `ai_use_case_metadata`, and checks provider compliance before content reaches the LLM.
- `mark_as_ai_generated(content, metadata)` adds `ai_generated: true` and `ai_metadata` to any outbound message.
### 32.9 Pre-Built Agents
LeoCRM ships pre-built agents in the automation plugin. Plugins can register additional agents at activation time by creating `AgentDefinition` records and registering their tools/skills in the registries.
---
*This document is authoritative for all plugin development at LeoCRM.*