diff --git a/site/src/pages/AgentsPage/AgentChatInput.tsx b/site/src/pages/AgentsPage/AgentChatInput.tsx index 74421f0826..b07e99f677 100644 --- a/site/src/pages/AgentsPage/AgentChatInput.tsx +++ b/site/src/pages/AgentsPage/AgentChatInput.tsx @@ -397,6 +397,9 @@ export const AgentChatInput = memo( } else if (isEditingHistoryMessage) { e.preventDefault(); handleCancelHistoryEdit(); + } else if (isStreaming && onInterrupt && !isInterruptPending) { + e.preventDefault(); + onInterrupt(); } return; } @@ -422,6 +425,9 @@ export const AgentChatInput = memo( handleSubmit, input, isEditingHistoryMessage, + isInterruptPending, + isStreaming, + onInterrupt, onPromoteQueuedMessage, queuedMessages, ], diff --git a/site/src/pages/AgentsPage/AgentsPage.tsx b/site/src/pages/AgentsPage/AgentsPage.tsx index 0ade6e5e2e..423260d599 100644 --- a/site/src/pages/AgentsPage/AgentsPage.tsx +++ b/site/src/pages/AgentsPage/AgentsPage.tsx @@ -52,6 +52,7 @@ import { getModelSelectorPlaceholder, hasConfiguredModelsInCatalog, } from "./modelOptions"; +import { useAgentsPageKeybindings } from "./useAgentsPageKeybindings"; const emptyInputStorageKey = "agents.empty-input"; const selectedWorkspaceIdStorageKey = "agents.selected-workspace-id"; @@ -338,6 +339,10 @@ const AgentsPage: FC = () => { document.title = pageTitle("Agents"); }, []); + useAgentsPageKeybindings({ + onNewAgent: handleNewAgent, + }); + useEffect(() => { if (!agentId) { setIsRightPanelOpen(false); diff --git a/site/src/pages/AgentsPage/useAgentsPageKeybindings.ts b/site/src/pages/AgentsPage/useAgentsPageKeybindings.ts new file mode 100644 index 0000000000..e6b72ddee6 --- /dev/null +++ b/site/src/pages/AgentsPage/useAgentsPageKeybindings.ts @@ -0,0 +1,35 @@ +import { useEffect } from "react"; + +/** + * Global keyboard shortcuts for the Agents page. + * + * - Ctrl+N / Cmd+N — Create a new agent. + */ +export function useAgentsPageKeybindings({ + onNewAgent, +}: { + onNewAgent: () => void; +}) { + useEffect(() => { + const handler = (event: KeyboardEvent) => { + // Ignore events originating from inputs / textareas / contenteditable + // so we don't hijack normal typing. + const target = event.target as HTMLElement | null; + if (target) { + const tag = target.tagName; + if (tag === "INPUT" || tag === "TEXTAREA" || target.isContentEditable) { + return; + } + } + + // Ctrl+N / Cmd+N — new agent + if (event.key === "n" && (event.metaKey || event.ctrlKey)) { + event.preventDefault(); + onNewAgent(); + } + }; + + document.addEventListener("keydown", handler); + return () => document.removeEventListener("keydown", handler); + }, [onNewAgent]); +}