From 542ceb4497d32b6c9e163972f0b1f2945df26604 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 25 Jun 2026 11:52:26 +0100 Subject: [PATCH] Surface orphaned document selections as removable chips An input_documents entry with no matching upstream option (a renamed or deleted upstream output variable, or a literal ref) now appears as a removable chip in the agent node's Choose-mode document selector instead of silently vanishing, so the stored selection stays visible and editable. Adds withChosenDocumentOptions to merge stored selections into the multiselect options, with tests. --- .../src/agents/workflow/WorkflowBuilder.tsx | 8 +++-- .../agents/workflow/documentConfig.test.ts | 36 +++++++++++++++++++ .../src/agents/workflow/documentConfig.ts | 18 ++++++++++ 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/frontend/src/agents/workflow/WorkflowBuilder.tsx b/frontend/src/agents/workflow/WorkflowBuilder.tsx index dfa4e532..82c5f518 100644 --- a/frontend/src/agents/workflow/WorkflowBuilder.tsx +++ b/frontend/src/agents/workflow/WorkflowBuilder.tsx @@ -85,6 +85,7 @@ import { getDocumentsMode, normalizeFilePassing, toDocumentVariableOptions, + withChosenDocumentOptions, } from './documentConfig'; import { AgentNode, @@ -2271,9 +2272,10 @@ function WorkflowBuilderInner() { {documentsMode === 'choose' && (
setInputDocuments( diff --git a/frontend/src/agents/workflow/documentConfig.test.ts b/frontend/src/agents/workflow/documentConfig.test.ts index 4ded092c..320c645f 100644 --- a/frontend/src/agents/workflow/documentConfig.test.ts +++ b/frontend/src/agents/workflow/documentConfig.test.ts @@ -9,6 +9,7 @@ import { normalizeFilePassing, stripAgentPrefix, toDocumentVariableOptions, + withChosenDocumentOptions, } from './documentConfig'; describe('getDocumentsMode', () => { @@ -124,3 +125,38 @@ describe('toDocumentVariableOptions', () => { expect(options).toEqual([{ value: 'wire_doc', label: 'wire_doc' }]); }); }); + +describe('withChosenDocumentOptions', () => { + const base = [{ value: 'wire_doc', label: 'wire_doc' }]; + + it('keeps known options unchanged when all chosen are present', () => { + expect(withChosenDocumentOptions(base, ['wire_doc'])).toEqual(base); + }); + + it('appends an orphaned chosen name (renamed/deleted upstream var) as removable', () => { + expect( + withChosenDocumentOptions(base, ['wire_doc', 'renamed_doc']), + ).toEqual([ + { value: 'wire_doc', label: 'wire_doc' }, + { value: 'renamed_doc', label: 'renamed_doc' }, + ]); + }); + + it('surfaces a literal ref that has no upstream option', () => { + expect(withChosenDocumentOptions([], ['A1'])).toEqual([ + { value: 'A1', label: 'A1' }, + ]); + }); + + it('ignores blanks and the wildcard token', () => { + expect( + withChosenDocumentOptions(base, ['', ' ', ALL_INPUT_DOCUMENTS_TOKEN]), + ).toEqual(base); + }); + + it('does not duplicate an already-known chosen name', () => { + expect(withChosenDocumentOptions(base, ['wire_doc', 'wire_doc'])).toEqual( + base, + ); + }); +}); diff --git a/frontend/src/agents/workflow/documentConfig.ts b/frontend/src/agents/workflow/documentConfig.ts index daf57971..9cda0bcf 100644 --- a/frontend/src/agents/workflow/documentConfig.ts +++ b/frontend/src/agents/workflow/documentConfig.ts @@ -82,3 +82,21 @@ export function toDocumentVariableOptions( } return options; } + +/** Append stored chosen names lacking an upstream option so they stay visible and removable. */ +export function withChosenDocumentOptions( + options: { value: string; label: string }[], + chosen: string[], +): { value: string; label: string }[] { + const known = new Set(options.map((option) => option.value)); + const merged = [...options]; + for (const name of chosen) { + const value = name.trim(); + if (!value || value === ALL_INPUT_DOCUMENTS_TOKEN || known.has(value)) { + continue; + } + known.add(value); + merged.push({ value, label: value }); + } + return merged; +}