diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/wand-prompt-bar/wand-prompt-bar.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/wand-prompt-bar/wand-prompt-bar.tsx index 9bde88bd9..16c3fc928 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/wand-prompt-bar/wand-prompt-bar.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/wand-prompt-bar/wand-prompt-bar.tsx @@ -81,15 +81,15 @@ export function WandPromptBar({
-
+
{ @@ -111,11 +111,6 @@ export function WandPromptBar({ disabled={isLoading || isStreaming} autoFocus={!isStreaming} /> - {isStreaming && ( -
-
-
- )}
) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/code.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/code.tsx index da6e16d47..e28bf62c1 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/code.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/code.tsx @@ -404,10 +404,8 @@ IMPORTANT FORMATTING RULES:
e.preventDefault()} onDrop={handleDrop} > @@ -419,7 +417,7 @@ IMPORTANT FORMATTING RULES: onClick={isPromptVisible ? hidePromptInline : showPromptInline} disabled={isAiLoading || isAiStreaming} aria-label='Generate code with AI' - className='h-8 w-8 rounded-full border border-transparent bg-muted/80 text-muted-foreground shadow-sm transition-all duration-200 hover:border-primary/20 hover:bg-muted hover:text-primary hover:shadow' + className='h-8 w-8 rounded-full border border-transparent bg-muted/80 text-muted-foreground shadow-sm transition-all duration-200 hover:border-primary/20 hover:bg-muted hover:text-foreground hover:shadow' > diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/long-input.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/long-input.tsx index 71e5f12fd..02ee1ebb9 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/long-input.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/long-input.tsx @@ -426,7 +426,7 @@ export function LongInput({ } disabled={wandHook.isLoading || wandHook.isStreaming || disabled} aria-label='Generate content with AI' - className='h-8 w-8 rounded-full border border-transparent bg-muted/80 text-muted-foreground shadow-sm transition-all duration-200 hover:border-primary/20 hover:bg-muted hover:text-primary hover:shadow' + className='h-8 w-8 rounded-full border border-transparent bg-muted/80 text-muted-foreground shadow-sm transition-all duration-200 hover:border-primary/20 hover:bg-muted hover:text-foreground hover:shadow' > diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/short-input.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/short-input.tsx index fc1aacbf9..d5f25077b 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/short-input.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/short-input.tsx @@ -436,7 +436,7 @@ export function ShortInput({ } disabled={wandHook.isLoading || wandHook.isStreaming || disabled} aria-label='Generate content with AI' - className='h-8 w-8 rounded-full border border-transparent bg-muted/80 text-muted-foreground shadow-sm transition-all duration-200 hover:border-primary/20 hover:bg-muted hover:text-primary hover:shadow' + className='h-8 w-8 rounded-full border border-transparent bg-muted/80 text-muted-foreground shadow-sm transition-all duration-200 hover:border-primary/20 hover:bg-muted hover:text-foreground hover:shadow' > diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/code-editor/code-editor.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/code-editor/code-editor.tsx index b6c2fb397..9ace40ebc 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/code-editor/code-editor.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/code-editor/code-editor.tsx @@ -6,6 +6,7 @@ import 'prismjs/components/prism-json' import 'prismjs/themes/prism.css' import { Wand2 } from 'lucide-react' import Editor from 'react-simple-code-editor' +import { Button } from '@/components/ui/button' import { cn } from '@/lib/utils' interface CodeEditorProps { @@ -213,19 +214,16 @@ export function CodeEditor({ )} > {showWandButton && onWandClick && ( - + )} {!showWandButton && code.split('\n').length > 5 && ( diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/custom-tool-modal/custom-tool-modal.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/custom-tool-modal/custom-tool-modal.tsx index f72bfad48..8b97b388a 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/custom-tool-modal/custom-tool-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/custom-tool-modal/custom-tool-modal.tsx @@ -1,5 +1,5 @@ import { useEffect, useMemo, useRef, useState } from 'react' -import { Code, FileJson, Trash2, X } from 'lucide-react' +import { AlertTriangle, Code, FileJson, Trash2, X } from 'lucide-react' import { useParams } from 'next/navigation' import { AlertDialog, @@ -934,11 +934,18 @@ try { + {schemaError && + !schemaGeneration.isStreaming && ( // Hide schema error while streaming + + + + + +

Invalid JSON

+
+
+ )}
- {schemaError && - !schemaGeneration.isStreaming && ( // Hide schema error while streaming -
{schemaError}
- )}
{ } expect(() => connectionResolver.resolveInputs(testBlock, contextWithConnections)).toThrow( - /Available connected blocks:.*Agent Block.*agent-1.*start/ + /Available connected blocks:.*Agent Block.*Start/ ) }) diff --git a/apps/sim/executor/resolver/resolver.ts b/apps/sim/executor/resolver/resolver.ts index 33ed2040d..a5bc9c6b3 100644 --- a/apps/sim/executor/resolver/resolver.ts +++ b/apps/sim/executor/resolver/resolver.ts @@ -463,10 +463,18 @@ export class InputResolver { const blockMatches = value.match(/<([^>]+)>/g) if (!blockMatches) return value - // If we're in an API block body, check each match to see if it looks like XML rather than a reference + // Filter out patterns that are clearly not variable references (e.g., comparison operators) + const validBlockMatches = blockMatches.filter((match) => this.isValidVariableReference(match)) + + // If no valid matches found after filtering, return original value + if (validBlockMatches.length === 0) { + return value + } + + // If we're in an API block body, check each valid match to see if it looks like XML rather than a reference if ( currentBlock.metadata?.id === 'api' && - blockMatches.some((match) => { + validBlockMatches.some((match) => { const innerContent = match.slice(1, -1) // Patterns that suggest this is XML, not a block reference: return ( @@ -490,7 +498,7 @@ export class InputResolver { value.includes('}') && value.includes('`') - for (const match of blockMatches) { + for (const match of validBlockMatches) { // Skip variables - they've already been processed if (match.startsWith(' is actually a variable reference. + * Valid variable references must: + * - Have no space after the opening < + * - Contain a dot (.) + * - Have no spaces until the closing > + * - Not be comparison operators or HTML tags + * + * @param match - The matched string including < and > + * @returns Whether this is a valid variable reference + */ + private isValidVariableReference(match: string): boolean { + const innerContent = match.slice(1, -1) + + if (!innerContent.includes('.')) { + return false + } + + const dotIndex = innerContent.indexOf('.') + const beforeDot = innerContent.substring(0, dotIndex) + const afterDot = innerContent.substring(dotIndex + 1) + + if (afterDot.includes(' ')) { + return false + } + + if ( + beforeDot.match(/^\s*[<>=!]+\s*$/) || + beforeDot.match(/\s[<>=!]+\s/) || + beforeDot.match(/^[<>=!]+\s/) + ) { + return false + } + + if (innerContent.startsWith(' ')) { + return false + } + + if (innerContent.match(/^[a-zA-Z][a-zA-Z0-9]*$/) && !innerContent.includes('.')) { + return false + } + + if (innerContent.match(/^[<>=!]+\s/)) { + return false + } + + if (beforeDot.match(/[+*/=<>!]/)) { + return false + } + + if (afterDot.match(/[+\-*/=<>!]/)) { + return false + } + + return true + } + /** * Determines if a string contains a properly formatted environment variable reference. * Valid references are either: @@ -1145,6 +1210,24 @@ export class InputResolver { return [...new Set(names)] // Remove duplicates } + /** + * Gets user-friendly block names for error messages. + * Only returns the actual block names that users see in the UI. + */ + private getAccessibleBlockNamesForError(currentBlockId: string): string[] { + const accessibleBlockIds = this.getAccessibleBlocks(currentBlockId) + const names: string[] = [] + + for (const blockId of accessibleBlockIds) { + const block = this.blockById.get(blockId) + if (block?.metadata?.name) { + names.push(block.metadata.name) + } + } + + return [...new Set(names)] // Remove duplicates + } + /** * Checks if a block reference could potentially be valid without throwing errors. * Used to filter out non-block patterns like from block reference resolution. @@ -1197,7 +1280,7 @@ export class InputResolver { } if (!sourceBlock) { - const accessibleNames = this.getAccessibleBlockNames(currentBlockId) + const accessibleNames = this.getAccessibleBlockNamesForError(currentBlockId) return { isValid: false, errorMessage: `Block "${blockRef}" was not found. Available connected blocks: ${accessibleNames.join(', ')}`, @@ -1207,7 +1290,7 @@ export class InputResolver { // Check if block is accessible (connected) const accessibleBlocks = this.getAccessibleBlocks(currentBlockId) if (!accessibleBlocks.has(sourceBlock.id)) { - const accessibleNames = this.getAccessibleBlockNames(currentBlockId) + const accessibleNames = this.getAccessibleBlockNamesForError(currentBlockId) return { isValid: false, errorMessage: `Block "${blockRef}" is not connected to this block. Available connected blocks: ${accessibleNames.join(', ')}`,