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.
This commit is contained in:
Alex committed 2026-06-25 11:52:26 +01:00
1 parent 51b0dd8d45
commit 542ceb4497
3 files changed
+59 -3

No files matched your search

@@ -85,6 +85,7 @@ import {
getDocumentsMode,
normalizeFilePassing,
toDocumentVariableOptions,
withChosenDocumentOptions,
} from './documentConfig';
import {
AgentNode,
@@ -2271,9 +2272,10 @@ function WorkflowBuilderInner() {
{documentsMode === 'choose' && (
<div className="mt-2">
<MultiSelect
options={
selectedAgentDocumentOptions
}
options={withChosenDocumentOptions(
selectedAgentDocumentOptions,
chosenDocuments,
)}
selected={chosenDocuments}
onChange={(nextDocuments) =>
setInputDocuments(
@@ -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,
);
});
});
@@ -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;
}