mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
## Summary Reduce CoPilot per-turn token overhead by systematically trimming tool descriptions, parameter schemas, and system prompt content. All 35 MCP tool schemas are passed on every SDK call — this PR reduces their size. ### Strategy 1. **Tool descriptions**: Trimmed verbose multi-sentence explanations to concise single-sentence summaries while preserving meaning 2. **Parameter schemas**: Shortened parameter descriptions to essential info, removed some `default` values (handled in code) 3. **System prompt**: Condensed `_SHARED_TOOL_NOTES` and storage supplement template in `prompting.py` 4. **Cross-tool references**: Removed duplicate workflow hints (e.g. "call find_block before run_block" appeared in BOTH tools — kept only in the dependent tool). Critical cross-tool references retained (e.g. `continue_run_block` in `run_block`, `fix_agent_graph` in `validate_agent`, `get_doc_page` in `search_docs`, `web_fetch` preference in `browser_navigate`) ### Token Impact | Metric | Before | After | Reduction | |--------|--------|-------|-----------| | System Prompt | ~865 tokens | ~497 tokens | 43% | | Tool Schemas | ~9,744 tokens | ~6,470 tokens | 34% | | **Grand Total** | **~10,609 tokens** | **~6,967 tokens** | **34%** | Saves **~3,642 tokens per conversation turn**. ### Key Decisions - **Mostly description changes**: Tool logic, parameters, and types unchanged. However, some schema-level `default` fields were removed (e.g. `save` in `customize_agent`) — these are machine-readable metadata, not just prose, and may affect LLM behavior. - **Quality preserved**: All descriptions still convey what the tool does and essential usage patterns - **Cross-references trimmed carefully**: Kept prerequisite hints in the dependent tool (run_block mentions find_block) but removed the reverse (find_block no longer mentions run_block). Critical cross-tool guidance retained where removal would degrade model behavior. - **`run_time` description fixed**: Added missing supported values (today, last 30 days, ISO datetime) per review feedback ### Future Optimization The SDK passes all 35 tools on every call. The MCP protocol's `list_tools()` handler supports dynamic tool registration — a follow-up PR could implement lazy tool loading (register core tools + a discovery meta-tool) to further reduce per-turn token cost. ### Changes - Trimmed descriptions across 25 tool files - Condensed `_SHARED_TOOL_NOTES` and `_build_storage_supplement` in `prompting.py` - Fixed `run_time` schema description in `agent_output.py` ### Checklist #### For code changes: - [x] I have clearly listed my changes in the PR description - [x] I have made a test plan - [x] I have tested my changes according to the test plan: - [x] All 273 copilot tests pass locally - [x] All 35 tools load and produce valid schemas - [x] Before/after token dumps compared - [x] Formatting passes (`poetry run format`) - [x] CI green
109 lines
3.3 KiB
Python
109 lines
3.3 KiB
Python
"""CustomizeAgentTool - Customizes marketplace/template agents."""
|
|
|
|
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 CustomizeAgentTool(BaseTool):
|
|
"""Tool for customizing marketplace/template agents."""
|
|
|
|
@property
|
|
def name(self) -> str:
|
|
return "customize_agent"
|
|
|
|
@property
|
|
def description(self) -> str:
|
|
return (
|
|
"Customize a marketplace/template agent. Validates, auto-fixes, and saves."
|
|
)
|
|
|
|
@property
|
|
def requires_auth(self) -> bool:
|
|
return True
|
|
|
|
@property
|
|
def parameters(self) -> dict[str, Any]:
|
|
return {
|
|
"type": "object",
|
|
"properties": {
|
|
"agent_json": {
|
|
"type": "object",
|
|
"description": "Customized agent JSON with nodes and links.",
|
|
},
|
|
"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,
|
|
**kwargs,
|
|
) -> ToolResponseBase:
|
|
agent_json: dict[str, Any] | None = kwargs.get("agent_json")
|
|
session_id = session.session_id if session else None
|
|
|
|
if not agent_json:
|
|
return ErrorResponse(
|
|
message=(
|
|
"Please provide agent_json with the complete customized agent graph."
|
|
),
|
|
error="missing_agent_json",
|
|
session_id=session_id,
|
|
)
|
|
|
|
save = kwargs.get("save", True)
|
|
library_agent_ids = kwargs.get("library_agent_ids", [])
|
|
folder_id: str | None = kwargs.get("folder_id")
|
|
|
|
nodes = agent_json.get("nodes", [])
|
|
if not nodes:
|
|
return ErrorResponse(
|
|
message="The agent JSON has no nodes.",
|
|
error="empty_agent",
|
|
session_id=session_id,
|
|
)
|
|
|
|
# Ensure top-level fields before the fixer pipeline
|
|
if "id" not in agent_json:
|
|
agent_json["id"] = str(uuid.uuid4())
|
|
agent_json.setdefault("version", 1)
|
|
agent_json.setdefault("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="Customized Agent",
|
|
library_agents=library_agents,
|
|
folder_id=folder_id,
|
|
)
|