2025-07-10 12:52:44 +08:00
import json
from typing import Optional , Dict , Any
from agentpress . tool import ToolResult , openapi_schema , xml_schema
from agentpress . thread_manager import ThreadManager
from . base_tool import AgentBuilderBaseTool
from utils . logger import logger
2025-07-12 04:42:23 +08:00
from agent . config_helper import build_unified_config
2025-07-10 12:52:44 +08:00
class AgentConfigTool ( AgentBuilderBaseTool ) :
def __init__ ( self , thread_manager : ThreadManager , db_connection , agent_id : str ) :
super ( ) . __init__ ( thread_manager , db_connection , agent_id )
@openapi_schema ( {
" type " : " function " ,
" function " : {
" name " : " update_agent " ,
" description " : " Update the agent ' s configuration including name, description, system prompt, tools, and MCP servers. Call this whenever the user wants to modify any aspect of the agent. " ,
" parameters " : {
" type " : " object " ,
" properties " : {
" name " : {
" type " : " string " ,
" description " : " The name of the agent. Should be descriptive and indicate the agent ' s purpose. "
} ,
" description " : {
" type " : " string " ,
" description " : " A brief description of what the agent does and its capabilities. "
} ,
" system_prompt " : {
" type " : " string " ,
" description " : " The system instructions that define the agent ' s behavior, expertise, and approach. This should be comprehensive and well-structured. "
} ,
" agentpress_tools " : {
" type " : " object " ,
" description " : " Configuration for AgentPress tools. Each key is a tool name, and the value is an object with ' enabled ' (boolean) and ' description ' (string) properties. " ,
" additionalProperties " : {
" type " : " object " ,
" properties " : {
" enabled " : { " type " : " boolean " } ,
" description " : { " type " : " string " }
}
}
} ,
" configured_mcps " : {
" type " : " array " ,
" description " : " List of configured MCP servers for external integrations. " ,
" items " : {
" type " : " object " ,
" properties " : {
" name " : { " type " : " string " } ,
" qualifiedName " : { " type " : " string " } ,
" config " : { " type " : " object " } ,
" enabledTools " : {
" type " : " array " ,
" items " : { " type " : " string " }
}
}
}
} ,
" avatar " : {
" type " : " string " ,
" description " : " Emoji to use as the agent ' s avatar. "
} ,
" avatar_color " : {
" type " : " string " ,
" description " : " Hex color code for the agent ' s avatar background. "
}
} ,
" required " : [ ]
}
}
} )
@xml_schema (
tag_name = " update-agent " ,
mappings = [
{ " param_name " : " name " , " node_type " : " attribute " , " path " : " . " , " required " : False } ,
{ " param_name " : " description " , " node_type " : " element " , " path " : " description " , " required " : False } ,
{ " param_name " : " system_prompt " , " node_type " : " element " , " path " : " system_prompt " , " required " : False } ,
{ " param_name " : " agentpress_tools " , " node_type " : " element " , " path " : " agentpress_tools " , " required " : False } ,
{ " param_name " : " configured_mcps " , " node_type " : " element " , " path " : " configured_mcps " , " required " : False } ,
{ " param_name " : " avatar " , " node_type " : " attribute " , " path " : " . " , " required " : False } ,
{ " param_name " : " avatar_color " , " node_type " : " attribute " , " path " : " . " , " required " : False }
] ,
example = '''
< function_calls >
< invoke name = " update_agent " >
< parameter name = " name " > Research Assistant < / parameter >
< parameter name = " description " > An AI assistant specialized in conducting research and providing comprehensive analysis < / parameter >
< parameter name = " system_prompt " > You are a research assistant with expertise in gathering , analyzing , and synthesizing information . Your approach is thorough and methodical . . . < / parameter >
< parameter name = " agentpress_tools " > { " web_search " : { " enabled " : true , " description " : " Search the web for information " } , " sb_files " : { " enabled " : true , " description " : " Read and write files " } } < / parameter >
< parameter name = " avatar " > 🔬 < / parameter >
< parameter name = " avatar_color " > #4F46E5</parameter>
< / invoke >
< / function_calls >
'''
)
async def update_agent (
self ,
name : Optional [ str ] = None ,
description : Optional [ str ] = None ,
system_prompt : Optional [ str ] = None ,
agentpress_tools : Optional [ Dict [ str , Dict [ str , Any ] ] ] = None ,
configured_mcps : Optional [ list ] = None ,
avatar : Optional [ str ] = None ,
avatar_color : Optional [ str ] = None
) - > ToolResult :
try :
client = await self . db . client
2025-07-12 04:42:23 +08:00
agent_result = await client . table ( ' agents ' ) . select ( ' * ' ) . eq ( ' agent_id ' , self . agent_id ) . execute ( )
if not agent_result . data :
return self . fail_response ( " Agent not found " )
current_agent = agent_result . data [ 0 ]
2025-07-23 00:11:10 +08:00
metadata = current_agent . get ( ' metadata ' , { } )
is_suna_default = metadata . get ( ' is_suna_default ' , False )
if is_suna_default :
restricted_fields = [ ]
if name is not None :
restricted_fields . append ( " name " )
if description is not None :
restricted_fields . append ( " description " )
if system_prompt is not None :
restricted_fields . append ( " system prompt " )
if agentpress_tools is not None :
restricted_fields . append ( " default tools " )
if restricted_fields :
return self . fail_response (
f " Cannot modify { ' , ' . join ( restricted_fields ) } for the default Suna agent. "
f " Suna ' s core identity is managed centrally. However, you can still add MCP integrations, "
f " create workflows, set up triggers, and customize other aspects of Suna. "
)
2025-07-12 04:42:23 +08:00
2025-07-24 02:45:53 +08:00
# Prepare fields for unified config
update_fields = { }
2025-07-10 12:52:44 +08:00
if name is not None :
2025-07-24 02:45:53 +08:00
update_fields [ " name " ] = name
2025-07-10 12:52:44 +08:00
if description is not None :
2025-07-24 02:45:53 +08:00
update_fields [ " description " ] = description
# Check if any configuration fields need to be updated
config_changed = ( system_prompt is not None or agentpress_tools is not None or
configured_mcps is not None or avatar is not None or avatar_color is not None )
if not update_fields and not config_changed :
return self . fail_response ( " No fields provided to update " )
# Get current config
current_config = current_agent . get ( ' config ' , { } )
# Extract current values from config
current_system_prompt = system_prompt if system_prompt is not None else current_config . get ( ' system_prompt ' , ' ' )
# Handle agentpress tools
2025-07-10 12:52:44 +08:00
if agentpress_tools is not None :
formatted_tools = { }
for tool_name , tool_config in agentpress_tools . items ( ) :
if isinstance ( tool_config , dict ) :
2025-07-24 02:45:53 +08:00
formatted_tools [ tool_name ] = tool_config . get ( " enabled " , False )
else :
formatted_tools [ tool_name ] = bool ( tool_config )
current_agentpress_tools = formatted_tools
else :
current_agentpress_tools = current_config . get ( ' tools ' , { } ) . get ( ' agentpress ' , { } )
# Handle configured MCPs
2025-07-10 12:52:44 +08:00
if configured_mcps is not None :
if isinstance ( configured_mcps , str ) :
configured_mcps = json . loads ( configured_mcps )
2025-07-24 02:45:53 +08:00
current_configured_mcps = configured_mcps
else :
current_configured_mcps = current_config . get ( ' tools ' , { } ) . get ( ' mcp ' , [ ] )
2025-07-20 22:46:59 +08:00
2025-07-24 02:45:53 +08:00
# Get custom MCPs from config
current_custom_mcps = current_config . get ( ' tools ' , { } ) . get ( ' custom_mcp ' , [ ] )
2025-07-20 22:46:59 +08:00
2025-07-24 02:45:53 +08:00
# Handle avatar from metadata
current_metadata = current_config . get ( ' metadata ' , { } )
current_avatar = avatar if avatar is not None else current_metadata . get ( ' avatar ' )
current_avatar_color = avatar_color if avatar_color is not None else current_metadata . get ( ' avatar_color ' )
2025-07-12 04:42:23 +08:00
2025-07-24 02:45:53 +08:00
# Build the updated config
2025-07-12 04:42:23 +08:00
unified_config = build_unified_config (
system_prompt = current_system_prompt ,
agentpress_tools = current_agentpress_tools ,
configured_mcps = current_configured_mcps ,
custom_mcps = current_custom_mcps ,
avatar = current_avatar ,
avatar_color = current_avatar_color
)
2025-07-24 02:45:53 +08:00
# Prepare final update data
update_data = update_fields . copy ( )
2025-07-12 04:42:23 +08:00
update_data [ " config " ] = unified_config
2025-07-10 12:52:44 +08:00
result = await client . table ( ' agents ' ) . update ( update_data ) . eq ( ' agent_id ' , self . agent_id ) . execute ( )
if not result . data :
return self . fail_response ( " Failed to update agent " )
return self . success_response ( {
" message " : " Agent updated successfully " ,
" updated_fields " : list ( update_data . keys ( ) ) ,
" agent " : result . data [ 0 ]
} )
except Exception as e :
return self . fail_response ( f " Error updating agent: { str ( e ) } " )
@openapi_schema ( {
" type " : " function " ,
" function " : {
" name " : " get_current_agent_config " ,
" description " : " Get the current configuration of the agent being edited. Use this to check what ' s already configured before making updates. " ,
" parameters " : {
" type " : " object " ,
" properties " : { } ,
" required " : [ ]
}
}
} )
@xml_schema (
tag_name = " get-current-agent-config " ,
mappings = [ ] ,
example = '''
< function_calls >
< invoke name = " get_current_agent_config " >
< / invoke >
< / function_calls >
'''
)
async def get_current_agent_config ( self ) - > ToolResult :
try :
agent = await self . _get_agent_data ( )
if not agent :
return self . fail_response ( " Agent not found " )
config_summary = {
" agent_id " : agent [ " agent_id " ] ,
" name " : agent . get ( " name " , " Untitled Agent " ) ,
" description " : agent . get ( " description " , " No description set " ) ,
" system_prompt " : agent . get ( " system_prompt " , " No system prompt set " ) ,
" avatar " : agent . get ( " avatar " , " 🤖 " ) ,
" avatar_color " : agent . get ( " avatar_color " , " #6B7280 " ) ,
" agentpress_tools " : agent . get ( " agentpress_tools " , { } ) ,
" configured_mcps " : agent . get ( " configured_mcps " , [ ] ) ,
" custom_mcps " : agent . get ( " custom_mcps " , [ ] ) ,
" created_at " : agent . get ( " created_at " ) ,
" updated_at " : agent . get ( " updated_at " )
}
tools_count = len ( [ t for t , cfg in config_summary [ " agentpress_tools " ] . items ( ) if cfg . get ( " enabled " ) ] )
mcps_count = len ( config_summary [ " configured_mcps " ] )
custom_mcps_count = len ( config_summary [ " custom_mcps " ] )
return self . success_response ( {
" summary " : f " Agent ' { config_summary [ ' name ' ] } ' has { tools_count } tools enabled, { mcps_count } MCP servers configured, and { custom_mcps_count } custom MCP integrations. " ,
" configuration " : config_summary
} )
except Exception as e :
return self . fail_response ( f " Error getting agent configuration: { str ( e ) } " )