feat(FN-4017): add /new command alias for task creation in quick chat
Added a `/new` slash command alias across the chat interface, with interception in ChatView, support in the QuickChatFAB, corresponding tests, and documentation in the dashboard guide. Fusion-Task-Id: FN-4017
This commit is contained in:
@@ -1244,7 +1244,7 @@ export function ChatView({ projectId, addToast, experimentalFeatures }: ChatView
|
||||
const files = pendingAttachments.map((attachment) => attachment.file);
|
||||
if ((!trimmed && files.length === 0) || !activeSession) return;
|
||||
|
||||
if (trimmed === "/clear") {
|
||||
if (trimmed === "/clear" || trimmed === "/new") {
|
||||
clearComposerState();
|
||||
stopStreaming();
|
||||
clearPendingMessage();
|
||||
|
||||
@@ -1673,7 +1673,7 @@ export function QuickChatFAB({
|
||||
return;
|
||||
}
|
||||
|
||||
if (trimmed === "/clear") {
|
||||
if (trimmed === "/clear" || trimmed === "/new") {
|
||||
stopStreaming();
|
||||
clearPendingMessage();
|
||||
attachmentsToSend.forEach((attachment) => {
|
||||
@@ -2382,7 +2382,7 @@ export function QuickChatFAB({
|
||||
))}
|
||||
{helpMessageVisible && (
|
||||
<div className="quick-chat-panel-message quick-chat-panel-message--received" data-testid="quick-chat-help-message">
|
||||
{renderAssistantMessageContent("Available commands:\n- `/clear` — Clear conversation and start fresh\n- `/skill:{name}` — Use a specific skill\n- `/help` — Show this help")}
|
||||
{renderAssistantMessageContent("Available commands:\n- `/new` or `/clear` — Clear conversation and start fresh\n- `/skill:{name}` — Use a specific skill\n- `/help` — Show this help")}
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
@@ -2436,7 +2436,7 @@ export function QuickChatFAB({
|
||||
))}
|
||||
{helpMessageVisible && (
|
||||
<div className="quick-chat-panel-message quick-chat-panel-message--received" data-testid="quick-chat-help-message">
|
||||
{renderAssistantMessageContent("Available commands:\n- `/clear` — Clear conversation and start fresh\n- `/skill:{name}` — Use a specific skill\n- `/help` — Show this help")}
|
||||
{renderAssistantMessageContent("Available commands:\n- `/new` or `/clear` — Clear conversation and start fresh\n- `/skill:{name}` — Use a specific skill\n- `/help` — Show this help")}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -1093,6 +1093,51 @@ describe("ChatView", () => {
|
||||
expect(clearPendingMessage).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("intercepts exact /new and starts a fresh session instead of sending message", async () => {
|
||||
const sendMessage = vi.fn();
|
||||
const createSession = vi.fn().mockResolvedValue({ id: "session-new", agentId: "agent-001" });
|
||||
const stopStreaming = vi.fn();
|
||||
const clearPendingMessage = vi.fn();
|
||||
|
||||
setupMockChat({
|
||||
activeSession: activeSessionFixture,
|
||||
messages: [],
|
||||
sendMessage,
|
||||
createSession,
|
||||
stopStreaming,
|
||||
clearPendingMessage,
|
||||
});
|
||||
|
||||
render(<ChatView projectId="proj-123" addToast={vi.fn()} />);
|
||||
|
||||
const textarea = screen.getByTestId("chat-input");
|
||||
await userEvent.type(textarea, " /new {enter}");
|
||||
|
||||
expect(sendMessage).not.toHaveBeenCalled();
|
||||
expect(createSession).toHaveBeenCalledWith({ agentId: "agent-001" });
|
||||
expect(stopStreaming).toHaveBeenCalledTimes(1);
|
||||
expect(clearPendingMessage).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("does not intercept non-exact /new text", async () => {
|
||||
const sendMessage = vi.fn();
|
||||
const createSession = vi.fn();
|
||||
setupMockChat({
|
||||
activeSession: activeSessionFixture,
|
||||
messages: [],
|
||||
sendMessage,
|
||||
createSession,
|
||||
});
|
||||
|
||||
render(<ChatView projectId="proj-123" addToast={vi.fn()} />);
|
||||
|
||||
const textarea = screen.getByTestId("chat-input");
|
||||
await userEvent.type(textarea, "/new now{enter}");
|
||||
|
||||
expect(sendMessage).toHaveBeenCalledWith("/new now", []);
|
||||
expect(createSession).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not intercept non-exact /clear text", async () => {
|
||||
const sendMessage = vi.fn();
|
||||
const createSession = vi.fn();
|
||||
|
||||
@@ -231,6 +231,44 @@ describe("QuickChatFAB session-first UX", () => {
|
||||
expect(mockStreamChatResponse).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("intercepts exact /new and starts a fresh session for the active target", async () => {
|
||||
render(<QuickChatFAB addToast={vi.fn()} projectId="proj-1" />);
|
||||
fireEvent.click(screen.getByTestId("quick-chat-fab"));
|
||||
|
||||
const input = await screen.findByTestId("quick-chat-input");
|
||||
await waitFor(() => expect(input).not.toBeDisabled());
|
||||
fireEvent.change(input, { target: { value: " /new " } });
|
||||
fireEvent.click(screen.getByTestId("quick-chat-send"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockCreateChatSession).toHaveBeenCalledWith(
|
||||
{ agentId: "__fn_agent__", modelProvider: "openai", modelId: "gpt-4o" },
|
||||
"proj-1",
|
||||
);
|
||||
});
|
||||
expect(mockStreamChatResponse).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not intercept non-exact /new prompts", async () => {
|
||||
render(<QuickChatFAB addToast={vi.fn()} projectId="proj-1" />);
|
||||
fireEvent.click(screen.getByTestId("quick-chat-fab"));
|
||||
|
||||
const input = await screen.findByTestId("quick-chat-input");
|
||||
await waitFor(() => expect(input).not.toBeDisabled());
|
||||
fireEvent.change(input, { target: { value: "/new now" } });
|
||||
fireEvent.click(screen.getByTestId("quick-chat-send"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockStreamChatResponse).toHaveBeenCalledWith(
|
||||
"session-model",
|
||||
"/new now",
|
||||
expect.any(Object),
|
||||
[],
|
||||
"proj-1",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("does not intercept non-exact /clear prompts", async () => {
|
||||
render(<QuickChatFAB addToast={vi.fn()} projectId="proj-1" />);
|
||||
fireEvent.click(screen.getByTestId("quick-chat-fab"));
|
||||
@@ -312,7 +350,10 @@ describe("QuickChatFAB session-first UX", () => {
|
||||
fireEvent.change(input, { target: { value: "/help" } });
|
||||
fireEvent.click(screen.getByTestId("quick-chat-send"));
|
||||
|
||||
expect(await screen.findByTestId("quick-chat-help-message")).toBeInTheDocument();
|
||||
const helpMessage = await screen.findByTestId("quick-chat-help-message");
|
||||
expect(helpMessage).toBeInTheDocument();
|
||||
expect(helpMessage).toHaveTextContent("/new");
|
||||
expect(helpMessage).toHaveTextContent("/clear");
|
||||
expect(mockStreamChatResponse).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user