Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,16 @@ export function useAgentSurface(

const harness = acpHarnessForPreset(binding?.agentId);
const agent =
harness && binding?.agentId && binding.agentSessionId && !binding.endedAt
? { id: binding.agentId, sessionId: binding.agentSessionId }
harness &&
binding?.agentId &&
(binding.agentSessionId || binding.chatSessionId) &&
!binding.endedAt
? {
id: binding.agentId,
...(binding.agentSessionId
? { sessionId: binding.agentSessionId }
: {}),
}
: undefined;
return {
surface: "cli",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ export type {
AgentSurface,
AgentSurfaceSwitch,
} from "./useAgentSurfaceSwitch";
export { useAgentSurfaceSwitch } from "./useAgentSurfaceSwitch";
export {
chatPaneDataForTerminal,
useAgentSurfaceSwitch,
} from "./useAgentSurfaceSwitch";
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { describe, expect, it } from "bun:test";
import { chatPaneDataForTerminal } from "./useAgentSurfaceSwitch";

describe("chatPaneDataForTerminal", () => {
const agent = { id: "claude", sessionId: "agent-session" };

it("attaches to the chat already running on the terminal", () => {
expect(
chatPaneDataForTerminal({
terminalId: "terminal-1",
agent,
binding: { chatSessionId: "chat-1" },
}),
).toEqual({ terminalId: "terminal-1", sessionId: "chat-1", agent });
Comment on lines +7 to +14

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 No-kill behavior remains untested

These tests check only chatPaneDataForTerminal, so they would still pass if switchSurface killed a chat-bound terminal. Add a test that calls switchSurface with a chat binding and checks that it preserves the session without calling killSession. Also cover a binding without agentSessionId, since this PR now offers the toggle in that case.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/AgentTerminalPane/hooks/useAgentSurfaceSwitch/useAgentSurfaceSwitch.test.ts
Line: 7-14

Comment:
**No-kill behavior remains untested**

These tests check only `chatPaneDataForTerminal`, so they would still pass if `switchSurface` killed a chat-bound terminal. Add a test that calls `switchSurface` with a chat binding and checks that it preserves the session without calling `killSession`. Also cover a binding without `agentSessionId`, since this PR now offers the toggle in that case.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

});

it("starts a chat for a terminal agent", () => {
expect(
chatPaneDataForTerminal({
terminalId: "terminal-1",
agent,
binding: {},
}),
).toEqual({ terminalId: "terminal-1", sessionId: null, agent });
expect(
chatPaneDataForTerminal({
terminalId: "terminal-1",
agent,
binding: undefined,
}),
).toEqual({ terminalId: "terminal-1", sessionId: null, agent });
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import type { CreatePaneInput, RendererContext } from "@superset/panes";
import { toast } from "@superset/ui/sonner";
import { workspaceTrpc } from "@superset/workspace-client";
import { useCallback, useMemo } from "react";
import {
type TerminalAgentBinding,
useTerminalAgentBindings,
} from "renderer/hooks/host-service/useTerminalAgentBindings";
import { useTerminalAppearance } from "renderer/hooks/useTerminalAppearance";
import { terminalQueryColors } from "renderer/lib/terminal/terminal-query-colors";
import { terminalRuntimeRegistry } from "renderer/lib/terminal/terminal-runtime-registry";
Expand Down Expand Up @@ -34,9 +38,31 @@ export type AgentSurfaceSwitch = {
stopChat(sessionId: string): Promise<boolean>;
};

/**
* The chat pane that replaces a terminal pane. A terminal id that already runs
* a chat (an automation run, a host-started chat) keeps that session: a pane
* with no session id starts a second agent on the same conversation.
*/
export function chatPaneDataForTerminal({
terminalId,
agent,
binding,
}: {
terminalId: string;
agent: AgentIdentity;
binding: Pick<TerminalAgentBinding, "chatSessionId"> | undefined;
}): ChatPaneData {
return {
terminalId,
sessionId: binding?.chatSessionId ?? null,
agent,
};
}

export function useAgentSurfaceSwitch(workspaceId: string): AgentSurfaceSwitch {
const { t } = useLingui();
const wiring = useChatWiring();
const bindings = useTerminalAgentBindings(workspaceId);
const killTerminal = workspaceTrpc.terminal.killSession.useMutation();
const runAgent = workspaceTrpc.agents.run.useMutation();
const appearance = useTerminalAppearance();
Expand Down Expand Up @@ -75,24 +101,23 @@ export function useAgentSurfaceSwitch(workspaceId: string): AgentSurfaceSwitch {
if (surface === "acp") {
if (ctx.pane.kind !== "terminal" || !agent) return;
const { terminalId } = ctx.pane.data as TerminalPaneData;
const binding = bindings.get(terminalId);
terminalRuntimeRegistry.dispose(terminalId);
try {
await killTerminal.mutateAsync({ terminalId, workspaceId });
} catch (error) {
console.warn("[acp-chat] could not stop the terminal", error);
toast.error(t({ message: "Couldn't stop the agent's terminal" }));
return;
if (!binding?.chatSessionId) {
try {
await killTerminal.mutateAsync({ terminalId, workspaceId });
} catch (error) {
console.warn("[acp-chat] could not stop the terminal", error);
toast.error(t({ message: "Couldn't stop the agent's terminal" }));
return;
}
}
replaceWith({
kind: "chat-v3",
...(ctx.pane.titleOverride
? { titleOverride: ctx.pane.titleOverride }
: {}),
data: {
terminalId,
sessionId: null,
agent,
} satisfies ChatPaneData,
data: chatPaneDataForTerminal({ terminalId, agent, binding }),
});
return;
}
Expand Down Expand Up @@ -134,7 +159,15 @@ export function useAgentSurfaceSwitch(workspaceId: string): AgentSurfaceSwitch {
});
}
},
[killTerminal, runAgent, stopChat, workspaceId, t, appearance.theme],
[
bindings,
killTerminal,
runAgent,
stopChat,
workspaceId,
t,
appearance.theme,
],
);

return useMemo(
Expand Down
Loading