mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
## Summary - Adds a session-level `dry_run` flag that forces ALL tool calls (`run_block`, `run_agent`) in a copilot/autopilot session to use dry-run simulation mode - Stores the flag in a typed `ChatSessionMetadata` JSON model on the `ChatSession` DB row, accessed via `session.dry_run` property - Adds `dry_run` to the AutoPilot block Input schema so graph builders can create dry-run autopilot nodes - Refactors multiple copilot tools from `**kwargs` to explicit parameters for type safety ## Changes - **Prisma schema**: Added `metadata` JSON column to `ChatSession` model with migration - **Python models**: Added `ChatSessionMetadata` model with `dry_run` field, added `metadata` field to `ChatSessionInfo` and `ChatSession`, updated `from_db()`, `new()`, and `create_chat_session()` - **Session propagation**: `set_execution_context(user_id, session)` called from `baseline/service.py` so tool handlers can read session-level flags via `session.dry_run` - **Tool enforcement**: `run_block` and `run_agent` check `session.dry_run` and force `dry_run=True` when set; `run_agent` blocks scheduling in dry-run sessions - **AutoPilot block**: Added `dry_run` input field, passes it when creating sessions - **Chat API**: Added `CreateSessionRequest` model with `dry_run` field to `POST /sessions` endpoint; added `metadata` to session responses - **Frontend**: Updated `useChatSession.ts` to pass body to the create session mutation - **Tool refactoring**: Multiple copilot tools refactored from `**kwargs` to explicit named parameters (agent_browser, manage_folders, workspace_files, connect_integration, agent_output, bash_exec, etc.) for better type safety ## Test plan - [x] Unit tests for `ChatSession.new()` with dry_run parameter - [x] Unit tests for `RunBlockTool` session dry_run override - [x] Unit tests for `RunAgentTool` session dry_run override - [x] Unit tests for session dry_run blocks scheduling - [x] Existing dry_run tests still pass (12/12) - [x] Existing permissions tests still pass - [x] All pre-commit hooks pass (ruff, isort, pyright, tsc) - [ ] Manual: Create autopilot session with `dry_run=True`, verify run_block/run_agent calls use simulation --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
115 lines
3.6 KiB
Python
115 lines
3.6 KiB
Python
"""CreateAgentTool - Creates agents from pre-built JSON."""
|
|
|
|
import logging
|
|
import uuid
|
|
from typing import Any
|
|
|
|
from backend.copilot.model import ChatSession
|
|
|
|
from .agent_generator.pipeline import fetch_library_agents, fix_validate_and_save
|
|
from .base import BaseTool
|
|
from .models import ErrorResponse, ToolResponseBase
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class CreateAgentTool(BaseTool):
|
|
"""Tool for creating agents from pre-built JSON."""
|
|
|
|
@property
|
|
def name(self) -> str:
|
|
return "create_agent"
|
|
|
|
@property
|
|
def description(self) -> str:
|
|
return (
|
|
"Create a new agent from JSON (nodes + links). Validates, auto-fixes, and saves. "
|
|
"Before calling, search for existing agents with find_library_agent."
|
|
)
|
|
|
|
@property
|
|
def requires_auth(self) -> bool:
|
|
return True
|
|
|
|
@property
|
|
def parameters(self) -> dict[str, Any]:
|
|
return {
|
|
"type": "object",
|
|
"properties": {
|
|
"agent_json": {
|
|
"type": "object",
|
|
"description": "Agent graph with 'nodes' and 'links' arrays.",
|
|
},
|
|
"library_agent_ids": {
|
|
"type": "array",
|
|
"items": {"type": "string"},
|
|
"description": "Library agent IDs as building blocks.",
|
|
},
|
|
"save": {
|
|
"type": "boolean",
|
|
"description": "Save the agent (default: true). False for preview.",
|
|
"default": True,
|
|
},
|
|
"folder_id": {
|
|
"type": "string",
|
|
"description": "Folder ID to save into (default: root).",
|
|
},
|
|
},
|
|
"required": ["agent_json"],
|
|
}
|
|
|
|
async def _execute(
|
|
self,
|
|
user_id: str | None,
|
|
session: ChatSession,
|
|
agent_json: dict[str, Any] | None = None,
|
|
save: bool = True,
|
|
library_agent_ids: list[str] | None = None,
|
|
folder_id: str | None = None,
|
|
**kwargs,
|
|
) -> ToolResponseBase:
|
|
session_id = session.session_id if session else None
|
|
|
|
if not agent_json:
|
|
return ErrorResponse(
|
|
message=(
|
|
"Please provide agent_json with the complete agent graph. "
|
|
"Use find_block to discover blocks, then generate the JSON."
|
|
),
|
|
error="missing_agent_json",
|
|
session_id=session_id,
|
|
)
|
|
|
|
if library_agent_ids is None:
|
|
library_agent_ids = []
|
|
|
|
nodes = agent_json.get("nodes", [])
|
|
if not nodes:
|
|
return ErrorResponse(
|
|
message="The agent JSON has no nodes. An agent needs at least one block.",
|
|
error="empty_agent",
|
|
session_id=session_id,
|
|
)
|
|
|
|
# Ensure top-level fields
|
|
if "id" not in agent_json:
|
|
agent_json["id"] = str(uuid.uuid4())
|
|
if "version" not in agent_json:
|
|
agent_json["version"] = 1
|
|
if "is_active" not in agent_json:
|
|
agent_json["is_active"] = True
|
|
|
|
# Fetch library agents for AgentExecutorBlock validation
|
|
library_agents = await fetch_library_agents(user_id, library_agent_ids)
|
|
|
|
return await fix_validate_and_save(
|
|
agent_json,
|
|
user_id=user_id,
|
|
session_id=session_id,
|
|
save=save,
|
|
is_update=False,
|
|
default_name="Generated Agent",
|
|
library_agents=library_agents,
|
|
folder_id=folder_id,
|
|
)
|