diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/components/markdown-renderer.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/components/markdown-renderer.tsx index dd9e45cfcc..dcc2dffd06 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/components/markdown-renderer.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/components/markdown-renderer.tsx @@ -326,8 +326,8 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend ), table: ({ children }: React.TableHTMLAttributes) => ( -
- +
+
{children}
@@ -346,12 +346,12 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend ), th: ({ children }: React.ThHTMLAttributes) => ( - + {children} ), td: ({ children }: React.TdHTMLAttributes) => ( - + {children} ), diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/components/thinking-block.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/components/thinking-block.tsx index e1bfda0baa..54c7042e75 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/components/thinking-block.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/components/thinking-block.tsx @@ -246,7 +246,7 @@ export function ThinkingBlock({ )} > {/* Render markdown during streaming with thinking text styling */} -
+
@@ -286,7 +286,7 @@ export function ThinkingBlock({ )} > {/* Use markdown renderer for completed content */} -
+
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/block-ring-utils.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/block-ring-utils.ts index 1490d6040b..634d28a86e 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/block-ring-utils.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/block-ring-utils.ts @@ -50,7 +50,7 @@ export function getBlockRingStyles(options: BlockRingOptions): { !isPending && !isDeletedBlock && diffStatus === 'new' && - 'ring-[var(--brand-tertiary)]', + 'ring-[var(--brand-tertiary-2)]', !isActive && !isPending && !isDeletedBlock && diff --git a/apps/sim/lib/copilot/tools/client/other/search-library-docs.ts b/apps/sim/lib/copilot/tools/client/other/search-library-docs.ts new file mode 100644 index 0000000000..7dcff295b2 --- /dev/null +++ b/apps/sim/lib/copilot/tools/client/other/search-library-docs.ts @@ -0,0 +1,50 @@ +import { BookOpen, Loader2, MinusCircle, XCircle } from 'lucide-react' +import { + BaseClientTool, + type BaseClientToolMetadata, + ClientToolCallState, +} from '@/lib/copilot/tools/client/base-tool' + +export class SearchLibraryDocsClientTool extends BaseClientTool { + static readonly id = 'search_library_docs' + + constructor(toolCallId: string) { + super(toolCallId, SearchLibraryDocsClientTool.id, SearchLibraryDocsClientTool.metadata) + } + + static readonly metadata: BaseClientToolMetadata = { + displayNames: { + [ClientToolCallState.generating]: { text: 'Reading docs', icon: Loader2 }, + [ClientToolCallState.pending]: { text: 'Reading docs', icon: Loader2 }, + [ClientToolCallState.executing]: { text: 'Reading docs', icon: Loader2 }, + [ClientToolCallState.success]: { text: 'Read docs', icon: BookOpen }, + [ClientToolCallState.error]: { text: 'Failed to read docs', icon: XCircle }, + [ClientToolCallState.aborted]: { text: 'Aborted reading docs', icon: XCircle }, + [ClientToolCallState.rejected]: { text: 'Skipped reading docs', icon: MinusCircle }, + }, + getDynamicText: (params, state) => { + const libraryName = params?.library_name + if (libraryName && typeof libraryName === 'string') { + switch (state) { + case ClientToolCallState.success: + return `Read ${libraryName} docs` + case ClientToolCallState.executing: + case ClientToolCallState.generating: + case ClientToolCallState.pending: + return `Reading ${libraryName} docs` + case ClientToolCallState.error: + return `Failed to read ${libraryName} docs` + case ClientToolCallState.aborted: + return `Aborted reading ${libraryName} docs` + case ClientToolCallState.rejected: + return `Skipped reading ${libraryName} docs` + } + } + return undefined + }, + } + + async execute(): Promise { + return + } +} diff --git a/apps/sim/stores/panel/copilot/store.ts b/apps/sim/stores/panel/copilot/store.ts index d4e926c91e..97b785177a 100644 --- a/apps/sim/stores/panel/copilot/store.ts +++ b/apps/sim/stores/panel/copilot/store.ts @@ -42,6 +42,7 @@ import { RememberDebugClientTool } from '@/lib/copilot/tools/client/other/rememb import { ResearchClientTool } from '@/lib/copilot/tools/client/other/research' import { SearchDocumentationClientTool } from '@/lib/copilot/tools/client/other/search-documentation' import { SearchErrorsClientTool } from '@/lib/copilot/tools/client/other/search-errors' +import { SearchLibraryDocsClientTool } from '@/lib/copilot/tools/client/other/search-library-docs' import { SearchOnlineClientTool } from '@/lib/copilot/tools/client/other/search-online' import { SearchPatternsClientTool } from '@/lib/copilot/tools/client/other/search-patterns' import { SleepClientTool } from '@/lib/copilot/tools/client/other/sleep' @@ -116,6 +117,7 @@ const CLIENT_TOOL_INSTANTIATORS: Record any> = { get_trigger_blocks: (id) => new GetTriggerBlocksClientTool(id), search_online: (id) => new SearchOnlineClientTool(id), search_documentation: (id) => new SearchDocumentationClientTool(id), + search_library_docs: (id) => new SearchLibraryDocsClientTool(id), search_patterns: (id) => new SearchPatternsClientTool(id), search_errors: (id) => new SearchErrorsClientTool(id), remember_debug: (id) => new RememberDebugClientTool(id), @@ -174,6 +176,7 @@ export const CLASS_TOOL_METADATA: Record()( // If already sending a message, queue this one instead if (isSendingMessage) { - get().addToQueue(message, { fileAttachments, contexts }) + get().addToQueue(message, { fileAttachments, contexts, messageId }) logger.info('[Copilot] Message queued (already sending)', { queueLength: get().messageQueue.length + 1, + originalMessageId: messageId, }) return } @@ -3161,8 +3165,12 @@ export const useCopilotStore = create()( // Process next message in queue if any const nextInQueue = get().messageQueue[0] if (nextInQueue) { + // Use originalMessageId if available (from edit/resend), otherwise use queue entry id + const messageIdToUse = nextInQueue.originalMessageId || nextInQueue.id logger.info('[Queue] Processing next queued message', { id: nextInQueue.id, + originalMessageId: nextInQueue.originalMessageId, + messageIdToUse, queueLength: get().messageQueue.length, }) // Remove from queue and send @@ -3173,7 +3181,7 @@ export const useCopilotStore = create()( stream: true, fileAttachments: nextInQueue.fileAttachments, contexts: nextInQueue.contexts, - messageId: nextInQueue.id, + messageId: messageIdToUse, }) }, 100) } @@ -3615,10 +3623,12 @@ export const useCopilotStore = create()( fileAttachments: options?.fileAttachments, contexts: options?.contexts, queuedAt: Date.now(), + originalMessageId: options?.messageId, } set({ messageQueue: [...get().messageQueue, queuedMessage] }) logger.info('[Queue] Message added to queue', { id: queuedMessage.id, + originalMessageId: options?.messageId, queueLength: get().messageQueue.length, }) }, @@ -3659,12 +3669,15 @@ export const useCopilotStore = create()( await new Promise((resolve) => setTimeout(resolve, 50)) } + // Use originalMessageId if available (from edit/resend), otherwise use queue entry id + const messageIdToUse = message.originalMessageId || message.id + // Send the message await get().sendMessage(message.content, { stream: true, fileAttachments: message.fileAttachments, contexts: message.contexts, - messageId: message.id, + messageId: messageIdToUse, }) }, diff --git a/apps/sim/stores/panel/copilot/types.ts b/apps/sim/stores/panel/copilot/types.ts index bf9b210d88..fbb6404aac 100644 --- a/apps/sim/stores/panel/copilot/types.ts +++ b/apps/sim/stores/panel/copilot/types.ts @@ -70,6 +70,8 @@ export interface QueuedMessage { fileAttachments?: MessageFileAttachment[] contexts?: ChatContext[] queuedAt: number + /** Original messageId to use when processing (for edit/resend flows) */ + originalMessageId?: string } // Contexts attached to a user message @@ -249,6 +251,8 @@ export interface CopilotActions { options?: { fileAttachments?: MessageFileAttachment[] contexts?: ChatContext[] + /** Original messageId to preserve (for edit/resend flows) */ + messageId?: string } ) => void removeFromQueue: (id: string) => void