Skip to content

Commit

Permalink
feat(workflow): add Input node type and streamline node validation
Browse files Browse the repository at this point in the history
- Introduce new Input node type for direct text input in workflows
- Refactor CLI node validation to be more flexible
- Update workflow executor to handle Input node processing
- Add UI components for Input node in sidebar and property editor
- Streamline Preview node implementation
  • Loading branch information
PriNova committed Nov 5, 2024
1 parent eb18d1d commit 2931d67
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 11 deletions.
21 changes: 14 additions & 7 deletions vscode/src/workflow/workflow-executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,6 @@ export function topologicalSort(nodes: WorkflowNode[], edges: Edge[]): WorkflowN
}

async function executeCLINode(node: WorkflowNode): Promise<string> {
if (!node.data.command) {
throw new Error(`No command specified for CLI node ${node.id} with ${node.data.label}`)
}

// Check if shell is available and workspace is trusted
if (!vscode.env.shell || !vscode.workspace.isTrusted) {
throw new Error('Shell command is not supported in your current workspace.')
Expand All @@ -77,7 +73,7 @@ async function executeCLINode(node: WorkflowNode): Promise<string> {
const cwd = vscode.workspace.workspaceFolders?.[0]?.uri?.path

// Filter and sanitize command
const filteredCommand = node.data.command.replaceAll(/(\s~\/)/g, ` ${homeDir}${path.sep}`)
const filteredCommand = node.data.command?.replaceAll(/(\s~\/)/g, ` ${homeDir}${path.sep}`) || ''

// Check for disallowed commands (you'll need to define commandsNotAllowed array)
if (commandsNotAllowed.some(cmd => filteredCommand.startsWith(cmd))) {
Expand Down Expand Up @@ -154,7 +150,12 @@ async function executeLLMNode(node: WorkflowNode, chatClient: ChatClient): Promi
}
}

async function executePreviewNode(node: WorkflowNode, input: string): Promise<string> {
async function executePreviewNode(input: string): Promise<string> {
return input
}

async function executeInputNode(input: string): Promise<string> {
// Return the content directly as it's user input
return input
}

Expand Down Expand Up @@ -234,7 +235,13 @@ export async function executeWorkflow(
break
}
case 'preview': {
result = await executePreviewNode(node, combinedInput)
result = await executePreviewNode(combinedInput)
break
}
case 'input': {
const text =
node.data.content?.replace('${input}', sanitizeForPrompt(combinedInput)) || ''
result = await executeInputNode(text)
break
}
default:
Expand Down
3 changes: 0 additions & 3 deletions vscode/webviews/workflow/components/Flow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,6 @@ export const Flow: React.FC<{
const onExecute = useCallback(() => {
// Validate all nodes have required fields
const invalidNodes = nodes.filter(node => {
if (node.type === NodeType.CLI) {
return !node.data.command || node.data.command.trim() === ''
}
if (node.type === NodeType.LLM) {
return !node.data.prompt || node.data.prompt.trim() === ''
}
Expand Down
14 changes: 14 additions & 0 deletions vscode/webviews/workflow/components/PropertyEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,20 @@ export const PropertyEditor: React.FC<PropertyEditorProps> = ({ node, onUpdate }
/>
</div>
)}

{node.type === NodeType.INPUT && (
<div>
<Label htmlFor="node-input">Input Text</Label>
<Textarea
id="node-input"
value={node.data.content || ''}
onChange={(e: { target: { value: any } }) =>
onUpdate(node.id, { content: e.target.value })
}
placeholder="Enter input text..."
/>
</div>
)}
</div>
)
}
14 changes: 14 additions & 0 deletions vscode/webviews/workflow/components/WorkflowSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,20 @@ export const WorkflowSidebar: React.FC<WorkflowSidebarProps> = ({
</div>
</AccordionContent>
</AccordionItem>
<AccordionItem value="input">
<AccordionTrigger>Input Text</AccordionTrigger>
<AccordionContent>
<div className="tw-flex tw-flex-col tw-gap-2">
<Button
onClick={() => onNodeAdd('Input Text', NodeType.INPUT)}
className="tw-w-full"
variant="secondary"
>
Add Input Text
</Button>
</div>
</AccordionContent>
</AccordionItem>
</Accordion>

<div className="tw-my-4 tw-border-t tw-border-border" />
Expand Down
25 changes: 24 additions & 1 deletion vscode/webviews/workflow/components/nodes/Nodes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export enum NodeType {
CLI = 'cli',
LLM = 'llm',
PREVIEW = 'preview',
INPUT = 'input',
}

// Shared node props interface
Expand Down Expand Up @@ -102,7 +103,7 @@ export const PreviewNode: React.FC<BaseNodeProps> = ({ data, selected }) => (
<div className="tw-flex tw-flex-col tw-gap-2">
<span>{data.label}</span>
<textarea
className="tw-w-full tw-h-24 tw-p-2 tw-rounded nodrag tw-resize tw-border-2 tw-border-solid tw-border-[var(--xy-node-border-default)]"
className="tw-w-full tw-h-24 tw-p-2 tw-rounded nodrag tw-resize tw-border-2 tw-border-solid tw-border-[var(--xy-node-border-default)]"
style={{
color: 'var(--vscode-editor-foreground)',
backgroundColor: 'var(--vscode-input-background)',
Expand All @@ -117,6 +118,27 @@ export const PreviewNode: React.FC<BaseNodeProps> = ({ data, selected }) => (
</div>
)

export const InputNode: React.FC<BaseNodeProps> = ({ data, selected }) => (
<div style={getNodeStyle(NodeType.INPUT, data.moving, selected, data.executing, data.error)}>
<Handle type="target" position={Position.Top} />
<div className="tw-flex tw-flex-col tw-gap-2 tw-text-left">
<span>{data.label}</span>
<textarea
className="tw-w-full tw-h-24 tw-p-2 tw-rounded nodrag tw-resize tw-border-2 tw-border-solid tw-border-[var(--xy-node-border-default)]"
style={{
color: 'var(--vscode-editor-foreground)',
backgroundColor: 'var(--vscode-input-background)',
outline: 'none', // Add this line
}}
value={data.content || ''}
readOnly
placeholder="Enter your input text here..."
/>
</div>
<Handle type="source" position={Position.Bottom} />
</div>
)

// Node Components with shared base props
export const CLINode: React.FC<BaseNodeProps> = ({ data, selected }) => (
<div style={getNodeStyle(NodeType.CLI, data.moving, selected, data.executing, data.error)}>
Expand All @@ -142,4 +164,5 @@ export const nodeTypes = {
[NodeType.CLI]: CLINode,
[NodeType.LLM]: CodyLLMNode,
[NodeType.PREVIEW]: PreviewNode,
[NodeType.INPUT]: InputNode,
}

0 comments on commit 2931d67

Please sign in to comment.