diff --git a/ui/src/components/task-chat/TaskChatComposer.test.tsx b/ui/src/components/task-chat/TaskChatComposer.test.tsx
index e82fa34f0be..b232298de6d 100644
--- a/ui/src/components/task-chat/TaskChatComposer.test.tsx
+++ b/ui/src/components/task-chat/TaskChatComposer.test.tsx
@@ -580,24 +580,53 @@ describe("TaskChatComposer", () => {
expect(editable().textContent).toBe(`[/deploy](${SLASH_HREF}) `);
});
- it("shows the assignee combobox only when reassign is enabled, with the current label", () => {
+ it("shows a searchable assignee combobox and selects a filtered assignee", async () => {
+ const onAdd = vi.fn().mockResolvedValue(undefined);
render();
expect(container.querySelector('[data-testid="task-chat-composer-assignee"]')).toBeNull();
render(
,
);
- const trigger = container.querySelector('[data-testid="task-chat-composer-assignee"]');
+ const trigger = container.querySelector('[data-testid="task-chat-composer-assignee"]');
expect(trigger?.textContent).toContain("Sam");
+
+ flushSync(() => trigger?.click());
+ await flushAsync();
+
+ const searchInput = document.body.querySelector('input[placeholder="Search assignees…"]');
+ expect(searchInput).not.toBeNull();
+ flushSync(() => {
+ Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set?.call(searchInput, "engineering");
+ searchInput!.dispatchEvent(new Event("input", { bubbles: true }));
+ });
+
+ const optionButtons = Array.from(document.body.querySelectorAll('button[type="button"]'));
+ const clippyOption = optionButtons.find((button) => button.textContent?.includes("Clippy"));
+ const samOption = optionButtons.find((button) => button.textContent?.includes("Sam") && button !== trigger);
+ expect(clippyOption).not.toBeUndefined();
+ expect(samOption).toBeUndefined();
+
+ flushSync(() => clippyOption?.click());
+ expect(trigger?.textContent).toContain("Clippy");
+
+ typeText("Please take this.");
+ pressKey("Enter", { metaKey: true });
+ await flushAsync();
+ expect(onAdd).toHaveBeenCalledWith(
+ "Please take this.",
+ undefined,
+ { assigneeAgentId: "a1", assigneeUserId: null },
+ );
});
describe("draft persistence", () => {
diff --git a/ui/src/components/task-chat/TaskChatComposer.tsx b/ui/src/components/task-chat/TaskChatComposer.tsx
index 72ffd24261d..2617c926f76 100644
--- a/ui/src/components/task-chat/TaskChatComposer.tsx
+++ b/ui/src/components/task-chat/TaskChatComposer.tsx
@@ -107,6 +107,9 @@ function shouldImplicitlyReopenComment(issueStatus: string | undefined, assignee
}
function parseAssigneeValue(value: string): CommentReassignment | undefined {
+ if (!value) {
+ return { assigneeAgentId: null, assigneeUserId: null };
+ }
if (value.startsWith("agent:")) {
const id = value.slice("agent:".length);
return id ? { assigneeAgentId: id, assigneeUserId: null } : undefined;