Merge pull request #1165 from escapade-mckv/fix-agent-builder-2a

fix agent builder functionality
This commit is contained in:
Bobbie 2025-08-01 02:16:58 +05:30 committed by GitHub
commit 0250e786cd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 149 additions and 72 deletions

View File

@ -58,16 +58,18 @@ class ToolManager:
self.thread_id = thread_id
def register_all_tools(self):
self.thread_manager.add_tool(ExpandMessageTool, thread_id=self.thread_id, thread_manager=self.thread_manager)
self.thread_manager.add_tool(MessageTool)
self.thread_manager.add_tool(SandboxShellTool, project_id=self.project_id, thread_manager=self.thread_manager)
self.thread_manager.add_tool(SandboxFilesTool, project_id=self.project_id, thread_manager=self.thread_manager)
self.thread_manager.add_tool(SandboxBrowserTool, project_id=self.project_id, thread_id=self.thread_id, thread_manager=self.thread_manager)
self.thread_manager.add_tool(SandboxDeployTool, project_id=self.project_id, thread_manager=self.thread_manager)
self.thread_manager.add_tool(SandboxExposeTool, project_id=self.project_id, thread_manager=self.thread_manager)
self.thread_manager.add_tool(ExpandMessageTool, thread_id=self.thread_id, thread_manager=self.thread_manager)
self.thread_manager.add_tool(MessageTool)
self.thread_manager.add_tool(SandboxWebSearchTool, project_id=self.project_id, thread_manager=self.thread_manager)
self.thread_manager.add_tool(SandboxVisionTool, project_id=self.project_id, thread_id=self.thread_id, thread_manager=self.thread_manager)
self.thread_manager.add_tool(SandboxImageEditTool, project_id=self.project_id, thread_id=self.thread_id, thread_manager=self.thread_manager)
if config.RAPID_API_KEY:
self.thread_manager.add_tool(DataProvidersTool)
@ -203,10 +205,10 @@ class PromptManager:
sample_response = file.read()
default_system_content = default_system_content + "\n\n <sample_assistant_response>" + sample_response + "</sample_assistant_response>"
if agent_config and agent_config.get('system_prompt'):
system_content = agent_config['system_prompt'].strip()
elif is_agent_builder:
if is_agent_builder:
system_content = get_agent_builder_prompt()
elif agent_config and agent_config.get('system_prompt'):
system_content = agent_config['system_prompt'].strip()
else:
system_content = default_system_content

View File

@ -322,6 +322,7 @@ class CredentialProfileTool(AgentBuilderBaseTool):
try:
from uuid import UUID
account_id = await self._get_current_account_id()
client = await self.db.client
profile = await profile_service.get_profile(UUID(account_id), UUID(profile_id))
if not profile:
@ -329,26 +330,69 @@ class CredentialProfileTool(AgentBuilderBaseTool):
if not profile.is_connected:
return self.fail_response("Profile is not connected yet. Please connect the profile first.")
# Simplified implementation - agent profile tools are now handled elsewhere
result = {
'success': True,
'enabled_tools': enabled_tools,
'total_tools': len(enabled_tools),
'version_name': 'simplified'
}
if not result.get("success", False):
return self.fail_response("Failed to update agent profile tools")
agent_result = await client.table('agents').select('current_version_id').eq('agent_id', self.agent_id).execute()
if not agent_result.data or not agent_result.data[0].get('current_version_id'):
return self.fail_response("Agent configuration not found")
version_msg = f"Profile '{profile.profile_name.value if hasattr(profile.profile_name, 'value') else str(profile.profile_name)}' updated with {len(enabled_tools)} tools"
version_result = await client.table('agent_versions')\
.select('config')\
.eq('version_id', agent_result.data[0]['current_version_id'])\
.maybe_single()\
.execute()
if not version_result.data or not version_result.data.get('config'):
return self.fail_response("Agent version configuration not found")
current_config = version_result.data['config']
current_tools = current_config.get('tools', {})
current_custom_mcps = current_tools.get('custom_mcp', [])
app_slug = profile.app_slug.value if hasattr(profile.app_slug, 'value') else str(profile.app_slug)
new_mcp_config = {
'name': display_name or profile.display_name,
'type': 'pipedream',
'config': {
'url': 'https://remote.mcp.pipedream.net',
'headers': {
'x-pd-app-slug': app_slug
},
'profile_id': profile_id
},
'enabledTools': enabled_tools
}
updated_mcps = [mcp for mcp in current_custom_mcps
if mcp.get('config', {}).get('profile_id') != profile_id]
updated_mcps.append(new_mcp_config)
current_tools['custom_mcp'] = updated_mcps
current_config['tools'] = current_tools
from agent.versioning.version_service import get_version_service
version_service = await get_version_service()
new_version = await version_service.create_version(
agent_id=self.agent_id,
user_id=account_id,
system_prompt=current_config.get('system_prompt', ''),
configured_mcps=current_config.get('tools', {}).get('mcp', []),
custom_mcps=updated_mcps,
agentpress_tools=current_config.get('tools', {}).get('agentpress', {}),
change_description=f"Configured {display_name or profile.display_name} with {len(enabled_tools)} tools"
)
profile_name = profile.profile_name.value if hasattr(profile.profile_name, 'value') else str(profile.profile_name)
return self.success_response({
"message": version_msg,
"enabled_tools": result.get("enabled_tools", []),
"total_tools": result.get("total_tools", 0),
"version_id": result.get("version_id"),
"version_name": result.get("version_name")
"message": f"Profile '{profile_name}' updated with {len(enabled_tools)} tools",
"enabled_tools": enabled_tools,
"total_tools": len(enabled_tools),
"version_id": new_version.version_id,
"version_name": new_version.version_name
})
except Exception as e:
logger.error(f"Error configuring profile for agent: {e}", exc_info=True)
return self.fail_response(f"Error configuring profile for agent: {str(e)}")
@openapi_schema({
@ -409,12 +453,11 @@ class CredentialProfileTool(AgentBuilderBaseTool):
version_service = await get_version_service()
await version_service.create_version(
agent_id=self.agent_id,
user_id=self.account_id,
user_id=account_id,
system_prompt=current_config.get('system_prompt', ''),
configured_mcps=current_config.get('tools', {}).get('mcp', []),
custom_mcps=updated_mcps,
agentpress_tools=current_config.get('tools', {}).get('agentpress', {}),
version_name="Removed credential profile",
change_description=f"Deleted credential profile {profile.display_name}"
)
except Exception as e:

View File

@ -120,7 +120,7 @@ export function ConfigurationTab({
<div className="bg-muted rounded-xl h-10 w-10 flex items-center justify-center transition-all duration-300 group-hover:scale-105">
<Settings className="h-5 w-5 text-muted-foreground" />
</div>
<div className="absolute -top-1 -right-1 w-3 h-3 bg-primary rounded-full opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
</div>
<div className="text-left flex-1">
<h4 className="font-semibold text-base text-foreground mb-1 group-hover:text-primary transition-colors duration-300">System Prompt</h4>
@ -163,7 +163,7 @@ export function ConfigurationTab({
<div className="bg-muted rounded-xl h-10 w-10 flex items-center justify-center transition-all duration-300 group-hover:scale-105">
<Wrench className="h-5 w-5 text-muted-foreground" />
</div>
<div className="absolute -top-1 -right-1 w-3 h-3 bg-primary rounded-full opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
</div>
<div className="text-left flex-1">
<h4 className="font-semibold text-base text-foreground mb-1 group-hover:text-primary transition-colors duration-300">Default Tools</h4>
@ -202,7 +202,7 @@ export function ConfigurationTab({
<div className="bg-muted rounded-xl h-10 w-10 flex items-center justify-center transition-all duration-300 group-hover:scale-105">
<Server className="h-5 w-5 text-muted-foreground" />
</div>
<div className="absolute -top-1 -right-1 w-3 h-3 bg-primary rounded-full opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
</div>
<div className="text-left flex-1">
<h4 className="font-semibold text-base text-foreground mb-1 group-hover:text-primary transition-colors duration-300">Integrations</h4>
@ -248,7 +248,7 @@ export function ConfigurationTab({
<div className="bg-muted rounded-xl h-10 w-10 flex items-center justify-center transition-all duration-300 group-hover:scale-105">
<BookOpen className="h-5 w-5 text-muted-foreground" />
</div>
<div className="absolute -top-1 -right-1 w-3 h-3 bg-primary rounded-full opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
</div>
<div className="text-left flex-1">
<h4 className="font-semibold text-base text-foreground mb-1 group-hover:text-primary transition-colors duration-300">Knowledge Base</h4>
@ -284,7 +284,7 @@ export function ConfigurationTab({
<div className="bg-muted rounded-xl h-10 w-10 flex items-center justify-center transition-all duration-300 group-hover:scale-105">
<Workflow className="h-5 w-5 text-muted-foreground" />
</div>
<div className="absolute -top-1 -right-1 w-3 h-3 bg-primary rounded-full opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
</div>
<div className="text-left flex-1">
<h4 className="font-semibold text-base text-foreground mb-1 group-hover:text-primary transition-colors duration-300">Workflows</h4>
@ -320,7 +320,7 @@ export function ConfigurationTab({
<div className="bg-muted rounded-xl h-10 w-10 flex items-center justify-center transition-all duration-300 group-hover:scale-105">
<Zap className="h-5 w-5 text-muted-foreground" />
</div>
<div className="absolute -top-1 -right-1 w-3 h-3 bg-primary rounded-full opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
</div>
<div className="text-left flex-1">
<h4 className="font-semibold text-base text-foreground mb-1 group-hover:text-primary transition-colors duration-300">Triggers</h4>

View File

@ -311,6 +311,7 @@ export interface ThreadContentProps {
agentName?: string;
agentAvatar?: React.ReactNode;
emptyStateComponent?: React.ReactNode; // Add custom empty state component prop
threadMetadata?: any; // Add thread metadata prop
}
export const ThreadContent: React.FC<ThreadContentProps> = ({
@ -333,6 +334,7 @@ export const ThreadContent: React.FC<ThreadContentProps> = ({
agentName = 'Suna',
agentAvatar = <KortixLogo size={16} />,
emptyStateComponent,
threadMetadata,
}) => {
const messagesEndRef = useRef<HTMLDivElement>(null);
const messagesContainerRef = useRef<HTMLDivElement>(null);
@ -351,6 +353,66 @@ export const ThreadContent: React.FC<ThreadContentProps> = ({
// In playback mode, we use visibleMessages instead of messages
const displayMessages = readOnly && visibleMessages ? visibleMessages : messages;
// Helper function to get agent info robustly
const getAgentInfo = useCallback(() => {
// First check thread metadata for is_agent_builder flag
if (threadMetadata?.is_agent_builder) {
return {
name: 'Agent Builder',
avatar: (
<div className="h-5 w-5 flex items-center justify-center rounded text-xs">
<span className="text-lg">🤖</span>
</div>
)
};
}
// Then check recent messages for agent info
const recentAssistantWithAgent = [...displayMessages].reverse().find(msg =>
msg.type === 'assistant' && (msg.agents?.avatar || msg.agents?.avatar_color || msg.agents?.name)
);
if (recentAssistantWithAgent?.agents?.name === 'Agent Builder') {
return {
name: 'Agent Builder',
avatar: (
<div className="h-5 w-5 flex items-center justify-center rounded text-xs">
<span className="text-lg">🤖</span>
</div>
)
};
}
if (recentAssistantWithAgent?.agents?.name) {
const isSunaAgent = recentAssistantWithAgent.agents.name === 'Suna';
const avatar = recentAssistantWithAgent.agents.avatar ? (
<>
{isSunaAgent ? (
<div className="h-5 w-5 flex items-center justify-center rounded text-xs">
<KortixLogo size={16} />
</div>
) : (
<div className="h-5 w-5 flex items-center justify-center rounded text-xs">
<span className="text-lg">{recentAssistantWithAgent.agents.avatar}</span>
</div>
)}
</>
) : (
<div className="h-5 w-5 flex items-center justify-center rounded text-xs">
<KortixLogo size={16} />
</div>
);
return {
name: recentAssistantWithAgent.agents.name,
avatar
};
}
return {
name: agentName || 'Suna',
avatar: agentAvatar
};
}, [threadMetadata, displayMessages, agentName, agentAvatar]);
const handleScroll = () => {
if (!messagesContainerRef.current) return;
const { scrollTop, scrollHeight, clientHeight } = messagesContainerRef.current;
@ -624,44 +686,10 @@ export const ThreadContent: React.FC<ThreadContentProps> = ({
<div className="flex flex-col gap-2">
<div className="flex items-center">
<div className="rounded-md flex items-center justify-center relative">
{(() => {
const firstAssistantWithAgent = group.messages.find(msg =>
msg.type === 'assistant' && (msg.agents?.avatar || msg.agents?.avatar_color)
);
const isSunaAgent = firstAssistantWithAgent?.agents?.name === 'Suna';
if (firstAssistantWithAgent?.agents?.avatar) {
const avatar = firstAssistantWithAgent.agents.avatar;
return (
<>
{isSunaAgent ? (
<div className="h-5 w-5 flex items-center justify-center rounded text-xs">
<KortixLogo size={16} />
</div>
) : (
<div
className="h-5 w-5 flex items-center justify-center rounded text-xs"
>
<span className="text-lg">{avatar}</span>
</div>
)}
</>
);
}
return <KortixLogo size={16} />;
})()}
{getAgentInfo().avatar}
</div>
<p className='ml-2 text-sm text-muted-foreground'>
{(() => {
const firstAssistantWithAgent = group.messages.find(msg =>
msg.type === 'assistant' && msg.agents?.name
);
if (firstAssistantWithAgent?.agents?.name) {
return firstAssistantWithAgent.agents.name;
}
return 'Suna';
})()}
{getAgentInfo().name}
</p>
</div>
@ -887,9 +915,11 @@ export const ThreadContent: React.FC<ThreadContentProps> = ({
{/* Logo positioned above the loader */}
<div className="flex items-center">
<div className="rounded-md flex items-center justify-center">
{agentAvatar}
{getAgentInfo().avatar}
</div>
<p className='ml-2 text-sm text-muted-foreground'>{agentName || 'Suna'}</p>
<p className='ml-2 text-sm text-muted-foreground'>
{getAgentInfo().name}
</p>
</div>
{/* Loader content */}
@ -899,17 +929,17 @@ export const ThreadContent: React.FC<ThreadContentProps> = ({
</div>
</div>
)}
{/* For playback mode - Show tool call animation if active */}
{readOnly && currentToolCall && (
<div ref={latestMessageRef}>
<div className="flex flex-col gap-2">
{/* Logo positioned above the tool call */}
<div className="flex justify-start">
<div className="rounded-md flex items-center justify-center">
{agentAvatar}
{getAgentInfo().avatar}
</div>
<p className='ml-2 text-sm text-muted-foreground'>{agentName || 'Suna'}</p>
<p className='ml-2 text-sm text-muted-foreground'>
{getAgentInfo().name}
</p>
</div>
{/* Tool call content */}
@ -932,9 +962,11 @@ export const ThreadContent: React.FC<ThreadContentProps> = ({
{/* Logo positioned above the streaming indicator */}
<div className="flex justify-start">
<div className="rounded-md flex items-center justify-center">
{agentAvatar}
{getAgentInfo().avatar}
</div>
<p className='ml-2 text-sm text-muted-foreground'>{agentName || 'Suna'}</p>
<p className='ml-2 text-sm text-muted-foreground'>
{getAgentInfo().name}
</p>
</div>
{/* Streaming indicator content */}