From 51b0dd8d455a7cc82ba1430e6bfa8111bb5b1869 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 25 Jun 2026 11:43:03 +0100 Subject: [PATCH] Add a Documents control to workflow agent nodes The agent-node panel gains a Documents section (All input docs / None / Choose upstream document variables) and a file-passing selector (auto / native / extract), writing the input_documents and file_passing config the engine consumes. Selections persist as bare state-variable names so they resolve against run state; the toggle, chosen docs, and file-passing mode re-derive from the stored config on reload. Reuses the existing multiselect, select, and upstream-variable enumeration. Known minor: an input_documents entry whose upstream variable was renamed or deleted is preserved in config but not shown as a removable chip in Choose mode. --- .../src/agents/workflow/WorkflowBuilder.tsx | 146 +++++++++++++++++- .../workflow/components/PromptTextArea.tsx | 4 +- .../agents/workflow/documentConfig.test.ts | 126 +++++++++++++++ .../src/agents/workflow/documentConfig.ts | 84 ++++++++++ 4 files changed, 357 insertions(+), 3 deletions(-) create mode 100644 frontend/src/agents/workflow/documentConfig.test.ts create mode 100644 frontend/src/agents/workflow/documentConfig.ts diff --git a/frontend/src/agents/workflow/WorkflowBuilder.tsx b/frontend/src/agents/workflow/WorkflowBuilder.tsx index b5649d2c..dfa4e532 100644 --- a/frontend/src/agents/workflow/WorkflowBuilder.tsx +++ b/frontend/src/agents/workflow/WorkflowBuilder.tsx @@ -75,7 +75,17 @@ import { validateCodeJsonSchema, } from './codeNodeConfig'; import MobileBlocker from './components/MobileBlocker'; -import PromptTextArea from './components/PromptTextArea'; +import PromptTextArea, { + extractUpstreamVariables, +} from './components/PromptTextArea'; +import { + documentsModeToInputDocuments, + FILE_PASSING_OPTIONS, + FilePassing, + getDocumentsMode, + normalizeFilePassing, + toDocumentVariableOptions, +} from './documentConfig'; import { AgentNode, CodeNode, @@ -104,6 +114,8 @@ interface AgentNodeConfig { chunks?: string; retriever?: string; json_schema?: Record; + input_documents?: string[]; + file_passing?: FilePassing; } interface UserTool { @@ -1455,6 +1467,13 @@ function WorkflowBuilderInner() { return selectedModel.supports_structured_output; }, [selectedNode, availableModels]); + const selectedAgentDocumentOptions = useMemo(() => { + if (!selectedNode || selectedNode.type !== 'agent') return []; + return toDocumentVariableOptions( + extractUpstreamVariables(nodes, edges, selectedNode.id), + ); + }, [selectedNode, nodes, edges]); + const selectedCodeJsonSchemaText = useMemo(() => { if (!selectedNode || selectedNode.type !== 'code') return ''; @@ -2191,6 +2210,131 @@ function WorkflowBuilderInner() { emptyText="No sources available" /> + {(() => { + const inputDocuments = + selectedNode.data.config?.input_documents; + const documentsMode = + getDocumentsMode(inputDocuments); + const chosenDocuments = + documentsMode === 'choose' + ? (inputDocuments ?? []) + : []; + const filePassing = normalizeFilePassing( + selectedNode.data.config?.file_passing, + ); + const setInputDocuments = ( + nextInputDocuments: string[], + ) => + handleUpdateNodeData({ + config: { + ...(selectedNode.data.config || {}), + input_documents: nextInputDocuments, + }, + }); + return ( + <> +
+ +
+ {( + [ + ['all', 'All input docs'], + ['none', 'None'], + ['choose', 'Choose…'], + ] as const + ).map(([mode, modeLabel]) => ( + + ))} +
+ {documentsMode === 'choose' && ( +
+ + setInputDocuments( + documentsModeToInputDocuments( + 'choose', + nextDocuments, + ), + ) + } + placeholder="Select documents..." + searchPlaceholder="Search variables..." + emptyText="No upstream documents" + /> +
+ )} +

+ Documents passed to this agent from + uploads or upstream nodes. +

+
+
+ + +

+ Auto: send native when the model + supports it, otherwise extract text. +

+
+ + ); + })()}