diff --git a/apps/sim/app/api/copilot/auto-allowed-tools/route.ts b/apps/sim/app/api/copilot/auto-allowed-tools/route.ts index 24df8ff81ba..61343d7541b 100644 --- a/apps/sim/app/api/copilot/auto-allowed-tools/route.ts +++ b/apps/sim/app/api/copilot/auto-allowed-tools/route.ts @@ -6,7 +6,7 @@ import { env } from '@/lib/core/config/env' const logger = createLogger('CopilotAutoAllowedToolsAPI') -/** Headers for server-to-server calls to the Go copilot backend. */ +/** Headers for server-to-server calls to the copilot backend. */ function copilotHeaders(): Record { const headers: Record = { 'Content-Type': 'application/json', @@ -36,7 +36,7 @@ export async function GET() { ) if (!res.ok) { - logger.warn('Go backend returned error for list auto-allowed', { status: res.status }) + logger.warn('Copilot returned error for list auto-allowed', { status: res.status }) return NextResponse.json({ autoAllowedTools: [] }) } @@ -73,7 +73,7 @@ export async function POST(request: NextRequest) { }) if (!res.ok) { - logger.warn('Go backend returned error for add auto-allowed', { status: res.status }) + logger.warn('Copilot returned error for add auto-allowed', { status: res.status }) return NextResponse.json({ error: 'Failed to add tool' }, { status: 500 }) } @@ -113,7 +113,7 @@ export async function DELETE(request: NextRequest) { ) if (!res.ok) { - logger.warn('Go backend returned error for remove auto-allowed', { status: res.status }) + logger.warn('Copilot returned error for remove auto-allowed', { status: res.status }) return NextResponse.json({ error: 'Failed to remove tool' }, { status: 500 }) } diff --git a/apps/sim/app/api/copilot/chat/route.ts b/apps/sim/app/api/copilot/chat/route.ts index 1c2ac412fed..dc9c443fb70 100644 --- a/apps/sim/app/api/copilot/chat/route.ts +++ b/apps/sim/app/api/copilot/chat/route.ts @@ -176,7 +176,7 @@ export async function POST(req: NextRequest) { const workflowId = resolved.workflowId const workflowResolvedName = resolved.workflowName - // Resolve workspace from workflow so it can be sent as implicit context to the Go backend. + // Resolve workspace from workflow so it can be sent as implicit context to the copilot. let resolvedWorkspaceId: string | undefined try { const { getWorkflowById } = await import('@/lib/workflows/utils') diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/message-content.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/message-content.tsx index 757d57e9da3..d9091800814 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/message-content.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/message-content.tsx @@ -1,11 +1,21 @@ 'use client' -import { resolveToolDisplay } from '@/lib/copilot/store-utils' -import { ClientToolCallState } from '@/lib/copilot/tools/client/tool-display-registry' -import type { ContentBlock, OptionItem, SubagentName, ToolCallData } from '../../types' -import { SUBAGENT_LABELS, TOOL_UI_METADATA } from '../../types' -import type { AgentGroupItem } from './components' -import { AgentGroup, ChatContent, CircleStop, Options, PendingTagIndicator } from './components' +import type { AgentGroupItem } from '@/app/workspace/[workspaceId]/home/components/message-content/components' +import { + AgentGroup, + ChatContent, + CircleStop, + Options, + PendingTagIndicator, +} from '@/app/workspace/[workspaceId]/home/components/message-content/components' +import type { + ContentBlock, + MothershipToolName, + OptionItem, + SubagentName, + ToolCallData, +} from '@/app/workspace/[workspaceId]/home/types' +import { SUBAGENT_LABELS, TOOL_UI_METADATA } from '@/app/workspace/[workspaceId]/home/types' interface TextSegment { type: 'text' @@ -45,16 +55,8 @@ const SUBAGENT_DISPATCH_TOOLS: Record = { file_write: 'workspace_file', } -function formatToolName(name: string): string { - return name - .replace(/_v\d+$/, '') - .split('_') - .map((w) => w.charAt(0).toUpperCase() + w.slice(1)) - .join(' ') -} - function resolveAgentLabel(key: string): string { - return SUBAGENT_LABELS[key as SubagentName] ?? formatToolName(key) + return SUBAGENT_LABELS[key as SubagentName] ?? key } function isToolDone(status: ToolCallData['status']): boolean { @@ -65,41 +67,12 @@ function isDelegatingTool(tc: NonNullable): boolean { return tc.status === 'executing' } -function mapToolStatusToClientState( - status: ContentBlock['toolCall'] extends { status: infer T } ? T : string -) { - switch (status) { - case 'success': - return ClientToolCallState.success - case 'error': - return ClientToolCallState.error - case 'cancelled': - return ClientToolCallState.cancelled - default: - return ClientToolCallState.executing - } -} - -function getOverrideDisplayTitle(tc: NonNullable): string | undefined { - if (tc.name === 'read' || tc.name.endsWith('_respond')) { - return resolveToolDisplay(tc.name, mapToolStatusToClientState(tc.status), tc.id, tc.params) - ?.text - } - return undefined -} - function toToolData(tc: NonNullable): ToolCallData { - const overrideDisplayTitle = getOverrideDisplayTitle(tc) - const displayTitle = - overrideDisplayTitle || - tc.displayTitle || - TOOL_UI_METADATA[tc.name as keyof typeof TOOL_UI_METADATA]?.title || - formatToolName(tc.name) - return { id: tc.id, toolName: tc.name, - displayTitle, + displayTitle: + tc.displayTitle ?? TOOL_UI_METADATA[tc.name as MothershipToolName]?.title ?? tc.name, status: tc.status, params: tc.params, result: tc.result, diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/utils.ts b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/utils.ts index 6b5cf61448b..2ef81f298b4 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/utils.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/utils.ts @@ -23,34 +23,95 @@ import { } from '@/components/emcn' import { Table as TableIcon } from '@/components/emcn/icons' import { AgentIcon } from '@/components/icons' -import type { MothershipToolName, SubagentName } from '../../types' +import type { MothershipToolName, SubagentName } from '@/app/workspace/[workspaceId]/home/types' export type IconComponent = ComponentType> const TOOL_ICONS: Record = { mothership: Blimp, + // Workspace glob: FolderCode, grep: Search, read: File, + // Search search_online: Search, scrape_page: Search, get_page_contents: Search, search_library_docs: Library, - manage_mcp_tool: Settings, - manage_skill: Asterisk, - user_memory: Database, + crawl_website: Search, + // Execution function_execute: TerminalWindow, superagent: Blimp, - user_table: TableIcon, - workspace_file: File, + run_workflow: PlayOutline, + run_block: PlayOutline, + run_from_block: PlayOutline, + run_workflow_until_block: PlayOutline, + complete_job: PlayOutline, + get_execution_summary: ClipboardList, + get_job_logs: ClipboardList, + get_workflow_logs: ClipboardList, + get_workflow_data: Layout, + get_block_outputs: ClipboardList, + get_block_upstream_references: ClipboardList, + get_deployed_workflow_state: Rocket, + check_deployment_status: Rocket, + // Workflows & folders create_workflow: Layout, + delete_workflow: Layout, edit_workflow: Pencil, + rename_workflow: Pencil, + move_workflow: Layout, + create_folder: FolderCode, + delete_folder: FolderCode, + move_folder: FolderCode, + list_folders: FolderCode, + list_user_workspaces: Layout, + revert_to_version: Rocket, + get_deployment_version: Rocket, + open_resource: Eye, + // Files + workspace_file: File, + download_to_workspace_file: File, + materialize_file: File, + generate_image: File, + generate_visualization: File, + // Tables & knowledge + user_table: TableIcon, + knowledge_base: Database, + // Jobs + create_job: Calendar, + manage_job: Calendar, + update_job_history: Calendar, + // Management + manage_mcp_tool: Settings, + manage_skill: Asterisk, + manage_credential: Integration, + manage_custom_tool: Wrench, + update_workspace_mcp_server: Settings, + delete_workspace_mcp_server: Settings, + create_workspace_mcp_server: Settings, + list_workspace_mcp_servers: Settings, + oauth_get_auth_link: Integration, + oauth_request_access: Integration, + set_environment_variables: Settings, + set_global_workflow_variables: Settings, + get_platform_actions: Settings, + search_documentation: Library, + search_patterns: Search, + deploy_api: Rocket, + deploy_chat: Rocket, + deploy_mcp: Rocket, + redeploy: Rocket, + generate_api_key: Asterisk, + user_memory: Database, + context_write: Pencil, + context_compaction: Asterisk, + // Subagents build: Hammer, run: PlayOutline, deploy: Rocket, auth: Integration, knowledge: Database, - knowledge_base: Database, table: TableIcon, job: Calendar, agent: AgentIcon, @@ -60,8 +121,6 @@ const TOOL_ICONS: Record${block.content}` : '', + } + } + const mapped: ContentBlock = { type: block.type as ContentBlockType, content: block.content, @@ -1078,6 +1085,36 @@ export function useChat( } break } + case 'reasoning': { + const d = ( + parsed.data && typeof parsed.data === 'object' ? parsed.data : {} + ) as Record + const phase = d.phase as string | undefined + if (phase === 'start') { + const tb = ensureTextBlock() + tb.content = `${tb.content ?? ''}` + runningText += '' + streamingContentRef.current = runningText + flush() + } else if (phase === 'end') { + const tb = ensureTextBlock() + tb.content = `${tb.content ?? ''}` + runningText += '' + streamingContentRef.current = runningText + flush() + } else { + const chunk = + typeof d.data === 'string' ? d.data : (parsed.content as string | undefined) + if (chunk) { + const tb = ensureTextBlock() + tb.content = (tb.content ?? '') + chunk + runningText += chunk + streamingContentRef.current = runningText + flush() + } + } + break + } case 'tool_generating': case 'tool_call': { const id = parsed.toolCallId diff --git a/apps/sim/app/workspace/[workspaceId]/home/types.ts b/apps/sim/app/workspace/[workspaceId]/home/types.ts index 0ba5c32ec78..c7593eacdd7 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/types.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/types.ts @@ -73,13 +73,63 @@ export type MothershipToolName = | 'search_library_docs' | 'manage_mcp_tool' | 'manage_skill' + | 'manage_credential' + | 'manage_custom_tool' + | 'manage_job' | 'user_memory' | 'function_execute' | 'superagent' | 'user_table' | 'workspace_file' | 'create_workflow' + | 'delete_workflow' | 'edit_workflow' + | 'rename_workflow' + | 'move_workflow' + | 'run_workflow' + | 'run_block' + | 'run_from_block' + | 'run_workflow_until_block' + | 'create_folder' + | 'delete_folder' + | 'move_folder' + | 'list_folders' + | 'list_user_workspaces' + | 'create_job' + | 'complete_job' + | 'update_job_history' + | 'download_to_workspace_file' + | 'materialize_file' + | 'context_write' + | 'generate_image' + | 'generate_visualization' + | 'crawl_website' + | 'get_execution_summary' + | 'get_job_logs' + | 'get_deployment_version' + | 'revert_to_version' + | 'check_deployment_status' + | 'get_deployed_workflow_state' + | 'get_workflow_data' + | 'get_workflow_logs' + | 'get_block_outputs' + | 'get_block_upstream_references' + | 'set_global_workflow_variables' + | 'set_environment_variables' + | 'get_platform_actions' + | 'search_documentation' + | 'search_patterns' + | 'update_workspace_mcp_server' + | 'delete_workspace_mcp_server' + | 'create_workspace_mcp_server' + | 'list_workspace_mcp_servers' + | 'deploy_api' + | 'deploy_chat' + | 'deploy_mcp' + | 'redeploy' + | 'generate_api_key' + | 'oauth_get_auth_link' + | 'oauth_request_access' | 'build' | 'run' | 'deploy' @@ -237,132 +287,171 @@ export interface ToolUIMetadata { } /** - * Default UI metadata for tools observed in the SSE stream. - * The Go backend sends `ui` on some tool_call events; this map provides - * fallback metadata for tools that arrive via `tool_generating` without `ui`. + * Primary UI metadata for tools observed in the SSE stream. + * Maps tool IDs to human-readable display names shown in the chat. + * This is the single source of truth — server-sent `ui.title` values are not used. */ -export const TOOL_UI_METADATA: Partial> = { - glob: { - title: 'Searching files', - phaseLabel: 'Workspace', - phase: 'workspace', +export const TOOL_UI_METADATA: Record = { + // Workspace + glob: { title: 'Searching workspace', phaseLabel: 'Workspace', phase: 'workspace' }, + grep: { title: 'Searching workspace', phaseLabel: 'Workspace', phase: 'workspace' }, + read: { title: 'Reading file', phaseLabel: 'Workspace', phase: 'workspace' }, + // Search + search_online: { title: 'Searching online', phaseLabel: 'Search', phase: 'search' }, + scrape_page: { title: 'Reading webpage', phaseLabel: 'Search', phase: 'search' }, + get_page_contents: { title: 'Reading page', phaseLabel: 'Search', phase: 'search' }, + search_library_docs: { title: 'Searching docs', phaseLabel: 'Search', phase: 'search' }, + crawl_website: { title: 'Browsing website', phaseLabel: 'Search', phase: 'search' }, + // Execution + function_execute: { title: 'Running code', phaseLabel: 'Code', phase: 'execution' }, + superagent: { title: 'Taking action', phaseLabel: 'Action', phase: 'execution' }, + run_workflow: { title: 'Running workflow', phaseLabel: 'Execution', phase: 'execution' }, + run_block: { title: 'Running block', phaseLabel: 'Execution', phase: 'execution' }, + run_from_block: { title: 'Running from block', phaseLabel: 'Execution', phase: 'execution' }, + run_workflow_until_block: { + title: 'Running partial workflow', + phaseLabel: 'Execution', + phase: 'execution', }, - grep: { - title: 'Searching code', - phaseLabel: 'Workspace', - phase: 'workspace', + complete_job: { title: 'Completing job', phaseLabel: 'Execution', phase: 'execution' }, + get_execution_summary: { title: 'Checking results', phaseLabel: 'Execution', phase: 'execution' }, + get_job_logs: { title: 'Checking logs', phaseLabel: 'Execution', phase: 'execution' }, + get_workflow_logs: { title: 'Checking logs', phaseLabel: 'Execution', phase: 'execution' }, + get_workflow_data: { title: 'Loading workflow', phaseLabel: 'Execution', phase: 'execution' }, + get_block_outputs: { + title: 'Checking block outputs', + phaseLabel: 'Execution', + phase: 'execution', }, - read: { title: 'Reading file', phaseLabel: 'Workspace', phase: 'workspace' }, - search_online: { - title: 'Searching online', - phaseLabel: 'Search', - phase: 'search', + get_block_upstream_references: { + title: 'Checking references', + phaseLabel: 'Execution', + phase: 'execution', }, - scrape_page: { - title: 'Scraping page', - phaseLabel: 'Search', - phase: 'search', + get_deployed_workflow_state: { + title: 'Checking deployment', + phaseLabel: 'Execution', + phase: 'execution', }, - get_page_contents: { - title: 'Getting page contents', - phaseLabel: 'Search', - phase: 'search', + check_deployment_status: { + title: 'Checking deployment', + phaseLabel: 'Execution', + phase: 'execution', + }, + // Workflows & folders + create_workflow: { title: 'Creating workflow', phaseLabel: 'Resource', phase: 'resource' }, + delete_workflow: { title: 'Deleting workflow', phaseLabel: 'Resource', phase: 'resource' }, + edit_workflow: { title: 'Editing workflow', phaseLabel: 'Resource', phase: 'resource' }, + rename_workflow: { title: 'Renaming workflow', phaseLabel: 'Resource', phase: 'resource' }, + move_workflow: { title: 'Moving workflow', phaseLabel: 'Resource', phase: 'resource' }, + create_folder: { title: 'Creating folder', phaseLabel: 'Resource', phase: 'resource' }, + delete_folder: { title: 'Deleting folder', phaseLabel: 'Resource', phase: 'resource' }, + move_folder: { title: 'Moving folder', phaseLabel: 'Resource', phase: 'resource' }, + list_folders: { title: 'Browsing folders', phaseLabel: 'Resource', phase: 'resource' }, + list_user_workspaces: { title: 'Browsing workspaces', phaseLabel: 'Resource', phase: 'resource' }, + revert_to_version: { title: 'Restoring version', phaseLabel: 'Resource', phase: 'resource' }, + get_deployment_version: { + title: 'Checking deployment', + phaseLabel: 'Resource', + phase: 'resource', + }, + open_resource: { title: 'Opening resource', phaseLabel: 'Resource', phase: 'resource' }, + // Files + workspace_file: { title: 'Working with files', phaseLabel: 'Resource', phase: 'resource' }, + download_to_workspace_file: { + title: 'Downloading file', + phaseLabel: 'Resource', + phase: 'resource', }, - search_library_docs: { - title: 'Searching library docs', - phaseLabel: 'Search', - phase: 'search', + materialize_file: { title: 'Saving file', phaseLabel: 'Resource', phase: 'resource' }, + generate_image: { title: 'Generating image', phaseLabel: 'Resource', phase: 'resource' }, + generate_visualization: { + title: 'Generating visualization', + phaseLabel: 'Resource', + phase: 'resource', }, - manage_mcp_tool: { - title: 'Managing MCP tool', + // Tables & knowledge + user_table: { title: 'Editing table', phaseLabel: 'Resource', phase: 'resource' }, + knowledge_base: { title: 'Updating knowledge base', phaseLabel: 'Resource', phase: 'resource' }, + // Jobs + create_job: { title: 'Creating job', phaseLabel: 'Resource', phase: 'resource' }, + manage_job: { title: 'Updating job', phaseLabel: 'Management', phase: 'management' }, + update_job_history: { title: 'Updating job', phaseLabel: 'Management', phase: 'management' }, + // Management + manage_mcp_tool: { title: 'Updating integration', phaseLabel: 'Management', phase: 'management' }, + manage_skill: { title: 'Updating skill', phaseLabel: 'Management', phase: 'management' }, + manage_credential: { title: 'Connecting account', phaseLabel: 'Management', phase: 'management' }, + manage_custom_tool: { title: 'Updating tool', phaseLabel: 'Management', phase: 'management' }, + update_workspace_mcp_server: { + title: 'Updating MCP server', phaseLabel: 'Management', phase: 'management', }, - manage_skill: { - title: 'Managing skill', + delete_workspace_mcp_server: { + title: 'Removing MCP server', phaseLabel: 'Management', phase: 'management', }, - user_memory: { - title: 'Accessing memory', + create_workspace_mcp_server: { + title: 'Creating MCP server', phaseLabel: 'Management', phase: 'management', }, - function_execute: { - title: 'Running code', - phaseLabel: 'Code', - phase: 'execution', + list_workspace_mcp_servers: { + title: 'Browsing MCP servers', + phaseLabel: 'Management', + phase: 'management', }, - superagent: { - title: 'Executing action', - phaseLabel: 'Action', - phase: 'execution', + oauth_get_auth_link: { + title: 'Connecting account', + phaseLabel: 'Management', + phase: 'management', }, - user_table: { - title: 'Managing table', - phaseLabel: 'Resource', - phase: 'resource', + oauth_request_access: { + title: 'Connecting account', + phaseLabel: 'Management', + phase: 'management', }, - workspace_file: { - title: 'Managing file', - phaseLabel: 'Resource', - phase: 'resource', + set_environment_variables: { + title: 'Updating environment', + phaseLabel: 'Management', + phase: 'management', }, - create_workflow: { - title: 'Creating workflow', - phaseLabel: 'Resource', - phase: 'resource', + set_global_workflow_variables: { + title: 'Updating variables', + phaseLabel: 'Management', + phase: 'management', }, - edit_workflow: { - title: 'Editing workflow', - phaseLabel: 'Resource', - phase: 'resource', + get_platform_actions: { title: 'Loading actions', phaseLabel: 'Management', phase: 'management' }, + search_documentation: { title: 'Searching docs', phaseLabel: 'Search', phase: 'search' }, + search_patterns: { title: 'Searching patterns', phaseLabel: 'Search', phase: 'search' }, + deploy_api: { title: 'Deploying API', phaseLabel: 'Deploy', phase: 'management' }, + deploy_chat: { title: 'Deploying chat', phaseLabel: 'Deploy', phase: 'management' }, + deploy_mcp: { title: 'Deploying MCP', phaseLabel: 'Deploy', phase: 'management' }, + redeploy: { title: 'Redeploying', phaseLabel: 'Deploy', phase: 'management' }, + generate_api_key: { title: 'Generating API key', phaseLabel: 'Deploy', phase: 'management' }, + user_memory: { title: 'Updating memory', phaseLabel: 'Management', phase: 'management' }, + context_write: { title: 'Writing notes', phaseLabel: 'Management', phase: 'management' }, + context_compaction: { + title: 'Optimizing context', + phaseLabel: 'Management', + phase: 'management', }, + // Subagents build: { title: 'Building', phaseLabel: 'Build', phase: 'subagent' }, run: { title: 'Running', phaseLabel: 'Run', phase: 'subagent' }, deploy: { title: 'Deploying', phaseLabel: 'Deploy', phase: 'subagent' }, - auth: { - title: 'Connecting credentials', - phaseLabel: 'Auth', - phase: 'subagent', - }, - knowledge: { - title: 'Managing knowledge', - phaseLabel: 'Knowledge', - phase: 'subagent', - }, - knowledge_base: { - title: 'Managing knowledge base', - phaseLabel: 'Resource', - phase: 'resource', - }, - table: { title: 'Managing tables', phaseLabel: 'Table', phase: 'subagent' }, - job: { title: 'Managing jobs', phaseLabel: 'Job', phase: 'subagent' }, - agent: { title: 'Agent action', phaseLabel: 'Agent', phase: 'subagent' }, - custom_tool: { - title: 'Creating tool', - phaseLabel: 'Tool', - phase: 'subagent', - }, + auth: { title: 'Connecting integration', phaseLabel: 'Auth', phase: 'subagent' }, + knowledge: { title: 'Working with knowledge', phaseLabel: 'Knowledge', phase: 'subagent' }, + table: { title: 'Working with tables', phaseLabel: 'Table', phase: 'subagent' }, + job: { title: 'Working with jobs', phaseLabel: 'Job', phase: 'subagent' }, + agent: { title: 'Taking action', phaseLabel: 'Agent', phase: 'subagent' }, + custom_tool: { title: 'Creating tool', phaseLabel: 'Tool', phase: 'subagent' }, research: { title: 'Researching', phaseLabel: 'Research', phase: 'subagent' }, plan: { title: 'Planning', phaseLabel: 'Plan', phase: 'subagent' }, debug: { title: 'Debugging', phaseLabel: 'Debug', phase: 'subagent' }, edit: { title: 'Editing workflow', phaseLabel: 'Edit', phase: 'subagent' }, - fast_edit: { - title: 'Editing workflow', - phaseLabel: 'Edit', - phase: 'subagent', - }, - open_resource: { - title: 'Opening resource', - phaseLabel: 'Resource', - phase: 'resource', - }, - context_compaction: { - title: 'Compacted context', - phaseLabel: 'Context', - phase: 'management', - }, + fast_edit: { title: 'Editing workflow', phaseLabel: 'Edit', phase: 'subagent' }, } export interface SSEPayloadUI { diff --git a/apps/sim/lib/copilot/orchestrator/sse/handlers/handlers.ts b/apps/sim/lib/copilot/orchestrator/sse/handlers/handlers.ts index 0cb6dc452d2..1b242eef77a 100644 --- a/apps/sim/lib/copilot/orchestrator/sse/handlers/handlers.ts +++ b/apps/sim/lib/copilot/orchestrator/sse/handlers/handlers.ts @@ -78,7 +78,7 @@ function abortPendingToolIfStreamDead( } /** - * Extract the `ui` object from a Go SSE event. The Go backend enriches + * Extract the `ui` object from an SSE event. The server enriches * tool_call events with `ui: { requiresConfirmation, clientExecutable, ... }`. */ function getEventUI(event: SSEEvent): { @@ -206,7 +206,7 @@ function handleClientCompletion( /** * Emit a synthetic tool_result SSE event to the client after a client-executable - * tool completes. The Go backend's actual tool_result is skipped (markToolResultSeen), + * tool completes. The server's actual tool_result is skipped (markToolResultSeen), * so the client would never learn the outcome without this. */ async function emitSyntheticToolResult( @@ -580,7 +580,7 @@ export const sseHandlers: Record = { context.currentThinkingBlock.content = `${context.currentThinkingBlock.content || ''}${chunk}` }, content: (event, context) => { - // Go backend sends content as a plain string in event.data, not wrapped in an object. + // Server sends content as a plain string in event.data, not wrapped in an object. let chunk: string | undefined if (typeof event.data === 'string') { chunk = event.data @@ -639,7 +639,7 @@ export const subAgentHandlers: Record = { content: (event, context) => { const parentToolCallId = context.subAgentParentToolCallId if (!parentToolCallId || !event.data) return - // Go backend sends content as a plain string in event.data + // Server sends content as a plain string in event.data let chunk: string | undefined if (typeof event.data === 'string') { chunk = event.data diff --git a/apps/sim/lib/copilot/orchestrator/sse/handlers/tool-execution.ts b/apps/sim/lib/copilot/orchestrator/sse/handlers/tool-execution.ts index 48bcfe729f0..445075ef992 100644 --- a/apps/sim/lib/copilot/orchestrator/sse/handlers/tool-execution.ts +++ b/apps/sim/lib/copilot/orchestrator/sse/handlers/tool-execution.ts @@ -747,11 +747,11 @@ export async function executeToolAndReport( } // Fire-and-forget: notify the copilot backend that the tool completed. - // IMPORTANT: We must NOT await this — the Go backend may block on the + // IMPORTANT: We must NOT await this — the server may block on the // mark-complete handler until it can write back on the SSE stream, but // the SSE reader (our for-await loop) is paused while we're in this - // handler. Awaiting here would deadlock: sim waits for Go's response, - // Go waits for sim to drain the SSE stream. + // handler. Awaiting here would deadlock: sim waits for the server's response, + // the server waits for sim to drain the SSE stream. markToolComplete( toolCall.id, toolCall.name, diff --git a/apps/sim/lib/copilot/orchestrator/tool-executor/index.ts b/apps/sim/lib/copilot/orchestrator/tool-executor/index.ts index aa29e862bc6..c4fb11fac3e 100644 --- a/apps/sim/lib/copilot/orchestrator/tool-executor/index.ts +++ b/apps/sim/lib/copilot/orchestrator/tool-executor/index.ts @@ -864,7 +864,6 @@ async function generateOAuthLink( }, }) - // Use Better Auth's server-side API with the real request headers (session cookie). const { auth } = await import('@/lib/auth/auth') const { headers: getHeaders } = await import('next/headers') const reqHeaders = await getHeaders() @@ -1163,10 +1162,10 @@ const SIM_WORKFLOW_TOOL_HANDLERS: Record< /** * Check whether a tool can be executed on the Sim (TypeScript) side. * - * Tools that are only available on the Go backend (e.g. search_patterns) + * Tools that are only available server-side (e.g. search_patterns) * will return false. The subagent tool_call * handler uses this to decide whether to execute a tool locally or let the - * Go backend's own tool_result SSE event handle it. + * server's own tool_result SSE event handle it. */ export function isToolAvailableOnSimSide(toolName: string): boolean { if (SERVER_TOOLS.has(toolName)) return true diff --git a/apps/sim/lib/copilot/orchestrator/types.ts b/apps/sim/lib/copilot/orchestrator/types.ts index 18978eda207..55cc2ba6331 100644 --- a/apps/sim/lib/copilot/orchestrator/types.ts +++ b/apps/sim/lib/copilot/orchestrator/types.ts @@ -23,7 +23,7 @@ export type SSEEventType = export interface SSEEvent { type: SSEEventType - /** Authoritative tool call state set by the Go backend */ + /** Authoritative tool call state set by the server */ state?: string data?: Record /** Parent agent that produced this event */ diff --git a/apps/sim/lib/copilot/resources.ts b/apps/sim/lib/copilot/resources.ts index a703d615a88..d2aac2f391e 100644 --- a/apps/sim/lib/copilot/resources.ts +++ b/apps/sim/lib/copilot/resources.ts @@ -17,15 +17,13 @@ export type { const logger = createLogger('CopilotResources') -type ChatResource = MothershipResource - /** * Appends resources to a chat's JSONB resources column, deduplicating by type+id. * Updates the title of existing resources if the new title is more specific. */ export async function persistChatResources( chatId: string, - newResources: ChatResource[] + newResources: MothershipResource[] ): Promise { const toMerge = newResources.filter((r) => r.id !== 'streaming-file') if (toMerge.length === 0) return @@ -39,8 +37,8 @@ export async function persistChatResources( if (!chat) return - const existing = Array.isArray(chat.resources) ? (chat.resources as ChatResource[]) : [] - const map = new Map() + const existing = Array.isArray(chat.resources) ? (chat.resources as MothershipResource[]) : [] + const map = new Map() const GENERIC = new Set(['Table', 'File', 'Workflow', 'Knowledge Base']) for (const r of existing) { @@ -72,7 +70,10 @@ export async function persistChatResources( /** * Removes resources from a chat's JSONB resources column by type+id. */ -export async function removeChatResources(chatId: string, toRemove: ChatResource[]): Promise { +export async function removeChatResources( + chatId: string, + toRemove: MothershipResource[] +): Promise { if (toRemove.length === 0) return try { @@ -84,7 +85,7 @@ export async function removeChatResources(chatId: string, toRemove: ChatResource if (!chat) return - const existing = Array.isArray(chat.resources) ? (chat.resources as ChatResource[]) : [] + const existing = Array.isArray(chat.resources) ? (chat.resources as MothershipResource[]) : [] const removeKeys = new Set(toRemove.map((r) => `${r.type}:${r.id}`)) const filtered = existing.filter((r) => !removeKeys.has(`${r.type}:${r.id}`)) diff --git a/apps/sim/lib/copilot/tools/client/base-tool.ts b/apps/sim/lib/copilot/tools/client/base-tool.ts index 0ee28659c6d..7910aa207bd 100644 --- a/apps/sim/lib/copilot/tools/client/base-tool.ts +++ b/apps/sim/lib/copilot/tools/client/base-tool.ts @@ -1,39 +1,3 @@ -import type { LucideIcon } from 'lucide-react' - -export enum ClientToolCallState { - generating = 'generating', - pending = 'pending', - executing = 'executing', - aborted = 'aborted', - rejected = 'rejected', - success = 'success', - error = 'error', - cancelled = 'cancelled', - review = 'review', - background = 'background', -} - -export interface ClientToolDisplay { - text: string - icon: LucideIcon -} - -export interface BaseClientToolMetadata { - displayNames: Partial> - uiConfig?: Record - getDynamicText?: ( - params: Record, - state: ClientToolCallState - ) => string | undefined -} - -export type DynamicTextFormatter = ( - params: Record, - state: ClientToolCallState -) => string | undefined - -export const WORKFLOW_EXECUTION_TIMEOUT_MS = 10 * 60 * 1000 - /** Event detail for OAuth connect events dispatched by the copilot. */ export interface OAuthConnectEventDetail { providerName: string diff --git a/apps/sim/lib/copilot/workflow-tools.ts b/apps/sim/lib/copilot/workflow-tools.ts index 4991f088a6a..ecfba90cebf 100644 --- a/apps/sim/lib/copilot/workflow-tools.ts +++ b/apps/sim/lib/copilot/workflow-tools.ts @@ -5,7 +5,7 @@ export const WORKFLOW_TOOL_NAMES = [ 'run_from_block', ] as const -export const WORKFLOW_TOOL_NAME_SET = new Set(WORKFLOW_TOOL_NAMES) +const WORKFLOW_TOOL_NAME_SET = new Set(WORKFLOW_TOOL_NAMES) export function isWorkflowToolName(name: string): boolean { return WORKFLOW_TOOL_NAME_SET.has(name)