Add slash commands for ending and restarting agents (#1034)

* Add slash commands for ending agents

* Stabilize slash command e2e submit

* Unslop client slash command draft setup

* Fix slash commands while agent is running

* Fix slash command submit race

* Reshape client slash command execution

* Fix slash command tab cleanup
This commit is contained in:
Mohamed Boudra
2026-05-16 17:03:59 +08:00
committed by GitHub
parent 667f441cc0
commit 4b02daed8a
19 changed files with 934 additions and 53 deletions
+48 -2
View File
@@ -48,9 +48,11 @@ import {
deriveRouteBottomAnchorRequest,
} from "@/screens/agent/agent-ready-screen-bottom-anchor";
import { useCreateFlowStore } from "@/stores/create-flow-store";
import { buildDraftStoreKey } from "@/stores/draft-keys";
import { buildDraftStoreKey, generateDraftId } from "@/stores/draft-keys";
import { usePanelStore } from "@/stores/panel-store";
import { type Agent, useSessionStore } from "@/stores/session-store";
import { useWorkspaceLayoutStore } from "@/stores/workspace-layout-store";
import { buildWorkspaceTabPersistenceKey } from "@/stores/workspace-tabs-store";
import type { Theme } from "@/styles/theme";
import { SubagentsSection, useArchiveSubagent, useSubagentsForParent } from "@/subagents";
import type { PendingPermission } from "@/types/shared";
@@ -60,6 +62,7 @@ import { derivePendingPermissionKey, normalizeAgentSnapshot } from "@/utils/agen
import { mergePendingCreateImages } from "@/utils/pending-create-images";
import { navigateToAgent } from "@/utils/navigate-to-agent";
import { deriveSidebarStateBucket } from "@/utils/sidebar-agent-state";
import { buildDraftAgentSetup, type ClientSlashCommand } from "@/client-slash-commands";
interface ChatAgentStateShape {
serverId: string | null;
@@ -1257,7 +1260,11 @@ function ActiveAgentComposer({
const insets = useSafeAreaInsets();
const isCompact = useIsCompactFormFactor();
const paneContext = usePaneContext();
const { workspaceId } = paneContext;
const { workspaceId, tabId, retargetCurrentTab } = paneContext;
const { archiveAgent } = useArchiveAgent();
const closeWorkspaceTab = useWorkspaceLayoutStore((state) => state.closeTab);
const hideWorkspaceAgent = useWorkspaceLayoutStore((state) => state.hideAgent);
const unpinWorkspaceAgent = useWorkspaceLayoutStore((state) => state.unpinAgent);
const subagentRows = useSubagentsForParent({
serverId,
parentAgentId: agentId,
@@ -1305,6 +1312,44 @@ function ActiveAgentComposer({
[isCompact, openFileExplorerForCheckout, serverId, setExplorerTabForCheckout],
);
const handleClientSlashCommand = useCallback(
async (command: ClientSlashCommand) => {
const agent = resolveChatAgentFromSession(useSessionStore.getState(), serverId, agentId);
if (!agent) {
throw new Error("Agent not found");
}
const workspaceKey = buildWorkspaceTabPersistenceKey({ serverId, workspaceId });
if (workspaceKey) {
unpinWorkspaceAgent(workspaceKey, agentId);
hideWorkspaceAgent(workspaceKey, agentId);
}
if (command.kind === "replace-agent-with-draft") {
retargetCurrentTab({
kind: "draft",
draftId: generateDraftId(),
setup: buildDraftAgentSetup(agent),
});
} else if (workspaceKey) {
closeWorkspaceTab(workspaceKey, tabId);
}
await archiveAgent({ serverId, agentId });
},
[
agentId,
archiveAgent,
closeWorkspaceTab,
hideWorkspaceAgent,
retargetCurrentTab,
serverId,
tabId,
unpinWorkspaceAgent,
workspaceId,
],
);
const inputAreaStyle = useMemo(
() => [styles.inputAreaWrapper, { paddingBottom: insets.bottom }],
[insets.bottom],
@@ -1336,6 +1381,7 @@ function ActiveAgentComposer({
onAddImages={onAddImages}
onComposerHeightChange={onComposerHeightChange}
onMessageSent={onMessageSent}
onClientSlashCommand={handleClientSlashCommand}
/>
</View>
);
+1
View File
@@ -56,6 +56,7 @@ function DraftPanel() {
workspaceId={workspaceId}
tabId={tabId}
draftId={target.draftId}
initialSetup={target.setup}
isPaneFocused={isInteractive}
onOpenWorkspaceFile={handleOpenWorkspaceFile}
onCreated={handleCreated}