feat(I): I-APPR-LOOP — agent loop human-in-the-loop approval integration (require_approval + approval_tools params, ApprovalRequest creation, workstream notification, pause loop), 8 tests passing

This commit is contained in:
Agent Zero
2026-08-19 00:20:36 +02:00
parent 610af39f75
commit dc1321c78b
2 changed files with 66 additions and 0 deletions
+40
View File
@@ -149,6 +149,8 @@ async def run_react_loop(
trace_id: str | None = None,
on_step: Callable | None = None,
dry_run: bool = False,
require_approval: bool = False,
approval_tools: list[str] | None = None,
) -> ReActResult:
"""Execute a ReAct loop: LLM reasoning → tool execution → repeat.
@@ -371,6 +373,44 @@ async def run_react_loop(
"arguments": args,
}
)
elif require_approval and (approval_tools is None or tool_name in (approval_tools or [])):
# I-APPR-LOOP: Human-in-the-Loop Approval
# Create an ApprovalRequest and pause the loop
try:
from app.core.approval import create_approval_request
from app.ai.agent_workstream import post_approval_request
approval = await create_approval_request(
db=db,
tenant_id=tenant_id,
entity_type="agent_run",
entity_id=agent_run_id or uuid.uuid4(),
action=f"tool:{tool_name}",
requested_by=user_id,
requested_by_type="agent",
)
# Post approval request to workstream
if agent_run_id:
await post_approval_request(
db=db,
tenant_id=tenant_id,
agent_id=getattr(agent_definition, "id", uuid.uuid4()),
approval_id=approval.id,
action=f"Tool '{tool_name}' requires approval",
details={"tool_name": tool_name, "arguments": args},
)
# Pause the loop — return with waiting_for_approval status
result.status = "waiting_for_approval"
result.error = f"Tool '{tool_name}' requires human approval (request_id: {approval.id})"
result.steps_taken = step_num
result.final_content = f"I need approval to execute tool '{tool_name}'. Approval request {approval.id} has been created."
logger.info("Agent loop paused for approval on tool '%s' (request: %s)", tool_name, approval.id)
return result
except Exception as e:
logger.warning("Failed to create approval request for tool '%s': %s", tool_name, e)
observation = json.dumps({"error": f"Approval required but failed to create request: {e}"})
else:
observation = await _execute_tool(tool_registry, tool_name, args, tool_context)
observations.append(observation)