feat: run tool by for a given agent [LET-6320] (#6386)
This commit is contained in:
committed by
Caren Thomas
parent
3a0bbe5495
commit
0fc86c4968
@@ -1915,7 +1915,7 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/letta__server__rest_api__routers__v1__tools__MCPToolExecuteRequest"
|
||||
"$ref": "#/components/schemas/letta__server__rest_api__routers__v1__tools__ToolExecuteRequest"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5254,6 +5254,74 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/agents/{agent_id}/tools/{tool_name}/run": {
|
||||
"post": {
|
||||
"tags": ["agents"],
|
||||
"summary": "Run Tool For Agent",
|
||||
"description": "Trigger a tool by name on a specific agent, providing the necessary arguments.\n\nThis endpoint executes a tool that is attached to the agent, using the agent's\nstate and environment variables for execution context.",
|
||||
"operationId": "run_tool_for_agent",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "agent_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"minLength": 42,
|
||||
"maxLength": 42,
|
||||
"pattern": "^agent-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
|
||||
"description": "The ID of the agent in the format 'agent-<uuid4>'",
|
||||
"examples": ["agent-123e4567-e89b-42d3-8456-426614174000"],
|
||||
"title": "Agent Id"
|
||||
},
|
||||
"description": "The ID of the agent in the format 'agent-<uuid4>'"
|
||||
},
|
||||
{
|
||||
"name": "tool_name",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"title": "Tool Name"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/letta__schemas__mcp_server__ToolExecuteRequest",
|
||||
"default": {
|
||||
"args": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ToolExecutionResult"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/agents/{agent_id}/sources/attach/{source_id}": {
|
||||
"patch": {
|
||||
"tags": ["agents"],
|
||||
@@ -11791,7 +11859,7 @@
|
||||
"post": {
|
||||
"tags": ["mcp-servers"],
|
||||
"summary": "Run Mcp Tool",
|
||||
"description": "Execute a specific MCP tool\n\nThe request body should contain the tool arguments in the MCPToolExecuteRequest format.",
|
||||
"description": "Execute a specific MCP tool\n\nThe request body should contain the tool arguments in the ToolExecuteRequest format.",
|
||||
"operationId": "mcp_run_tool",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -11817,7 +11885,7 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/letta__schemas__mcp_server__MCPToolExecuteRequest",
|
||||
"$ref": "#/components/schemas/letta__schemas__mcp_server__ToolExecuteRequest",
|
||||
"default": {
|
||||
"args": {}
|
||||
}
|
||||
@@ -39480,19 +39548,19 @@
|
||||
"title": "UpdateStreamableHTTPMCPServer",
|
||||
"description": "Update a Streamable HTTP MCP server"
|
||||
},
|
||||
"letta__schemas__mcp_server__MCPToolExecuteRequest": {
|
||||
"letta__schemas__mcp_server__ToolExecuteRequest": {
|
||||
"properties": {
|
||||
"args": {
|
||||
"additionalProperties": true,
|
||||
"type": "object",
|
||||
"title": "Args",
|
||||
"description": "Arguments to pass to the MCP tool"
|
||||
"description": "Arguments to pass to the tool"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"title": "MCPToolExecuteRequest",
|
||||
"description": "Request to execute an MCP tool by IDs."
|
||||
"title": "ToolExecuteRequest",
|
||||
"description": "Request to execute a tool."
|
||||
},
|
||||
"letta__schemas__mcp_server__UpdateSSEMCPServer": {
|
||||
"properties": {
|
||||
@@ -40082,17 +40150,17 @@
|
||||
],
|
||||
"title": "ToolSchema"
|
||||
},
|
||||
"letta__server__rest_api__routers__v1__tools__MCPToolExecuteRequest": {
|
||||
"letta__server__rest_api__routers__v1__tools__ToolExecuteRequest": {
|
||||
"properties": {
|
||||
"args": {
|
||||
"additionalProperties": true,
|
||||
"type": "object",
|
||||
"title": "Args",
|
||||
"description": "Arguments to pass to the MCP tool"
|
||||
"description": "Arguments to pass to the tool"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"title": "MCPToolExecuteRequest"
|
||||
"title": "ToolExecuteRequest"
|
||||
},
|
||||
"openai__types__chat__chat_completion_message_function_tool_call__Function": {
|
||||
"properties": {
|
||||
|
||||
@@ -259,10 +259,10 @@ class MCPServerResyncResult(LettaBase):
|
||||
added: List[str] = Field(default_factory=list, description="List of added tool names")
|
||||
|
||||
|
||||
class MCPToolExecuteRequest(LettaBase):
|
||||
"""Request to execute an MCP tool by IDs."""
|
||||
class ToolExecuteRequest(LettaBase):
|
||||
"""Request to execute a tool."""
|
||||
|
||||
args: Dict[str, Any] = Field(default_factory=dict, description="Arguments to pass to the MCP tool")
|
||||
args: Dict[str, Any] = Field(default_factory=dict, description="Arguments to pass to the tool")
|
||||
|
||||
|
||||
# Wrapper models for API requests with discriminated unions
|
||||
|
||||
@@ -43,6 +43,7 @@ from letta.schemas.letta_message_content import TextContent
|
||||
from letta.schemas.letta_request import LettaAsyncRequest, LettaRequest, LettaStreamingRequest
|
||||
from letta.schemas.letta_response import LettaResponse, LettaStreamingResponse
|
||||
from letta.schemas.letta_stop_reason import StopReasonType
|
||||
from letta.schemas.mcp_server import ToolExecuteRequest
|
||||
from letta.schemas.memory import (
|
||||
ArchivalMemorySearchResponse,
|
||||
ArchivalMemorySearchResult,
|
||||
@@ -55,6 +56,7 @@ from letta.schemas.passage import Passage
|
||||
from letta.schemas.run import Run as PydanticRun, RunUpdate
|
||||
from letta.schemas.source import BaseSource, Source
|
||||
from letta.schemas.tool import BaseTool, Tool
|
||||
from letta.schemas.tool_execution_result import ToolExecutionResult
|
||||
from letta.schemas.user import User
|
||||
from letta.serialize_schemas.pydantic_agent_schema import AgentSchema
|
||||
from letta.server.rest_api.dependencies import HeaderParams, get_headers, get_letta_server
|
||||
@@ -598,6 +600,72 @@ async def modify_approval_for_tool(
|
||||
return await server.agent_manager.get_agent_by_id_async(agent_id=agent_id, actor=actor)
|
||||
|
||||
|
||||
@router.post("/{agent_id}/tools/{tool_name}/run", response_model=ToolExecutionResult, operation_id="run_tool_for_agent")
|
||||
async def run_tool_for_agent(
|
||||
agent_id: AgentId,
|
||||
tool_name: str,
|
||||
request: ToolExecuteRequest = Body(default=ToolExecuteRequest()),
|
||||
server: "SyncServer" = Depends(get_letta_server),
|
||||
headers: HeaderParams = Depends(get_headers),
|
||||
):
|
||||
"""
|
||||
Trigger a tool by name on a specific agent, providing the necessary arguments.
|
||||
|
||||
This endpoint executes a tool that is attached to the agent, using the agent's
|
||||
state and environment variables for execution context.
|
||||
"""
|
||||
actor = await server.user_manager.get_actor_or_default_async(actor_id=headers.actor_id)
|
||||
|
||||
# Get agent with tools and environment variables
|
||||
agent = await server.agent_manager.get_agent_by_id_async(
|
||||
agent_id=agent_id,
|
||||
actor=actor,
|
||||
include_relationships=["tools", "tool_exec_environment_variables"],
|
||||
)
|
||||
|
||||
# Find the tool by name among attached tools
|
||||
tool = None
|
||||
if agent.tools:
|
||||
for t in agent.tools:
|
||||
if t.name == tool_name:
|
||||
tool = t
|
||||
break
|
||||
|
||||
if tool is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Tool '{tool_name}' not found or not attached to agent '{agent_id}'",
|
||||
)
|
||||
|
||||
# Build environment variables dict from agent secrets
|
||||
sandbox_env_vars = {}
|
||||
if agent.tool_exec_environment_variables:
|
||||
for env_var in agent.tool_exec_environment_variables:
|
||||
sandbox_env_vars[env_var.key] = env_var.value
|
||||
|
||||
# Create tool execution manager and execute the tool
|
||||
from letta.services.tool_executor.tool_execution_manager import ToolExecutionManager
|
||||
|
||||
tool_execution_manager = ToolExecutionManager(
|
||||
agent_state=agent,
|
||||
message_manager=server.message_manager,
|
||||
agent_manager=server.agent_manager,
|
||||
block_manager=server.block_manager,
|
||||
run_manager=server.run_manager,
|
||||
passage_manager=server.passage_manager,
|
||||
actor=actor,
|
||||
sandbox_env_vars=sandbox_env_vars,
|
||||
)
|
||||
|
||||
tool_execution_result = await tool_execution_manager.execute_tool_async(
|
||||
function_name=tool_name,
|
||||
function_args=request.args,
|
||||
tool=tool,
|
||||
)
|
||||
|
||||
return tool_execution_result
|
||||
|
||||
|
||||
@router.patch("/{agent_id}/sources/attach/{source_id}", response_model=AgentState, operation_id="attach_source_to_agent", deprecated=True)
|
||||
async def attach_source(
|
||||
source_id: SourceId,
|
||||
|
||||
@@ -10,7 +10,7 @@ from letta.schemas.letta_message import ToolReturnMessage
|
||||
from letta.schemas.mcp_server import (
|
||||
CreateMCPServerRequest,
|
||||
MCPServerUnion,
|
||||
MCPToolExecuteRequest,
|
||||
ToolExecuteRequest,
|
||||
UpdateMCPServerRequest,
|
||||
convert_generic_to_union,
|
||||
convert_update_to_internal,
|
||||
@@ -164,12 +164,12 @@ async def run_mcp_tool(
|
||||
tool_id: str,
|
||||
server: SyncServer = Depends(get_letta_server),
|
||||
headers: HeaderParams = Depends(get_headers),
|
||||
request: MCPToolExecuteRequest = Body(default=MCPToolExecuteRequest()),
|
||||
request: ToolExecuteRequest = Body(default=ToolExecuteRequest()),
|
||||
):
|
||||
"""
|
||||
Execute a specific MCP tool
|
||||
|
||||
The request body should contain the tool arguments in the MCPToolExecuteRequest format.
|
||||
The request body should contain the tool arguments in the ToolExecuteRequest format.
|
||||
"""
|
||||
actor = await server.user_manager.get_actor_or_default_async(actor_id=headers.actor_id)
|
||||
|
||||
|
||||
@@ -757,15 +757,15 @@ async def generate_json_schema(
|
||||
|
||||
|
||||
# TODO: @jnjpng move this and other models above to appropriate file for schemas
|
||||
class MCPToolExecuteRequest(BaseModel):
|
||||
args: Dict[str, Any] = Field(default_factory=dict, description="Arguments to pass to the MCP tool")
|
||||
class ToolExecuteRequest(BaseModel):
|
||||
args: Dict[str, Any] = Field(default_factory=dict, description="Arguments to pass to the tool")
|
||||
|
||||
|
||||
@router.post("/mcp/servers/{mcp_server_name}/tools/{tool_name}/execute", operation_id="execute_mcp_tool")
|
||||
async def execute_mcp_tool(
|
||||
mcp_server_name: str,
|
||||
tool_name: str,
|
||||
request: MCPToolExecuteRequest = Body(...),
|
||||
request: ToolExecuteRequest = Body(...),
|
||||
server: SyncServer = Depends(get_letta_server),
|
||||
headers: HeaderParams = Depends(get_headers),
|
||||
):
|
||||
|
||||
Reference in New Issue
Block a user