Detach subagents without archiving them (#1612)
* Add detach action for subagents * Translate detached subagent connection error * Address subagent detach review feedback * Fix subagent integration test import * Focus detached subagents as tabs
This commit is contained in:
@@ -2,6 +2,8 @@ import { describe, expect, test } from "vitest";
|
||||
import {
|
||||
FileExplorerRequestSchema,
|
||||
PaseoWorktreeArchiveRequestSchema,
|
||||
parseServerInfoStatusPayload,
|
||||
SessionInboundMessageSchema,
|
||||
SessionOutboundMessageSchema,
|
||||
} from "./messages.js";
|
||||
|
||||
@@ -131,6 +133,51 @@ describe("workspace descriptor message compatibility", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("agent detach RPC", () => {
|
||||
test("parses the namespaced detach request", () => {
|
||||
const parsed = SessionInboundMessageSchema.parse({
|
||||
type: "agent.detach.request",
|
||||
agentId: "child-agent",
|
||||
requestId: "req-detach",
|
||||
});
|
||||
|
||||
expect(parsed).toEqual({
|
||||
type: "agent.detach.request",
|
||||
agentId: "child-agent",
|
||||
requestId: "req-detach",
|
||||
});
|
||||
});
|
||||
|
||||
test("parses the namespaced detach response", () => {
|
||||
const parsed = SessionOutboundMessageSchema.parse({
|
||||
type: "agent.detach.response",
|
||||
payload: {
|
||||
requestId: "req-detach",
|
||||
agentId: "child-agent",
|
||||
accepted: true,
|
||||
error: null,
|
||||
},
|
||||
});
|
||||
|
||||
expect(parsed.type).toBe("agent.detach.response");
|
||||
});
|
||||
|
||||
test("parses the agentDetach server feature gate", () => {
|
||||
const parsed = parseServerInfoStatusPayload({
|
||||
status: "server_info",
|
||||
serverId: "srv-test",
|
||||
features: {
|
||||
agentDetach: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!parsed) {
|
||||
throw new Error("Expected server info payload to parse");
|
||||
}
|
||||
expect(parsed.features?.agentDetach).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("file explorer request compatibility", () => {
|
||||
test("acceptBinary is optional for old clients and accepted for new clients", () => {
|
||||
expect(
|
||||
|
||||
@@ -1308,6 +1308,17 @@ export const SetAgentFeatureResponseMessageSchema = z.object({
|
||||
payload: AgentActionResponsePayloadSchema,
|
||||
});
|
||||
|
||||
export const AgentDetachRequestMessageSchema = z.object({
|
||||
type: z.literal("agent.detach.request"),
|
||||
agentId: z.string(),
|
||||
requestId: z.string(),
|
||||
});
|
||||
|
||||
export const AgentDetachResponseMessageSchema = z.object({
|
||||
type: z.literal("agent.detach.response"),
|
||||
payload: AgentActionResponsePayloadSchema,
|
||||
});
|
||||
|
||||
export const AgentRewindModeSchema = z.enum(["conversation", "files", "both"]);
|
||||
|
||||
export const AgentRewindRequestMessageSchema = z.object({
|
||||
@@ -2021,6 +2032,7 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
|
||||
SetAgentModelRequestMessageSchema,
|
||||
SetAgentThinkingRequestMessageSchema,
|
||||
SetAgentFeatureRequestMessageSchema,
|
||||
AgentDetachRequestMessageSchema,
|
||||
AgentRewindRequestMessageSchema,
|
||||
AgentPermissionResponseMessageSchema,
|
||||
CheckoutStatusRequestSchema,
|
||||
@@ -2280,6 +2292,8 @@ export const ServerInfoStatusPayloadSchema = z
|
||||
projectRemove: z.boolean().optional(),
|
||||
// COMPAT(worktreeRestore): added in v0.1.97, drop the gate when floor >= v0.1.97
|
||||
worktreeRestore: z.boolean().optional(),
|
||||
// COMPAT(agentDetach): added in v0.1.98, remove gate after 2026-12-19 once daemon floor >= v0.1.98.
|
||||
agentDetach: z.boolean().optional(),
|
||||
})
|
||||
.optional(),
|
||||
})
|
||||
@@ -4019,6 +4033,7 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
|
||||
SetAgentModelResponseMessageSchema,
|
||||
SetAgentThinkingResponseMessageSchema,
|
||||
SetAgentFeatureResponseMessageSchema,
|
||||
AgentDetachResponseMessageSchema,
|
||||
AgentRewindResponseMessageSchema,
|
||||
UpdateAgentResponseMessageSchema,
|
||||
ProjectRenameResponseSchema,
|
||||
@@ -4166,6 +4181,7 @@ export type SetAgentModeResponseMessage = z.infer<typeof SetAgentModeResponseMes
|
||||
export type SetAgentModelResponseMessage = z.infer<typeof SetAgentModelResponseMessageSchema>;
|
||||
export type SetAgentThinkingResponseMessage = z.infer<typeof SetAgentThinkingResponseMessageSchema>;
|
||||
export type SetAgentFeatureResponseMessage = z.infer<typeof SetAgentFeatureResponseMessageSchema>;
|
||||
export type AgentDetachResponseMessage = z.infer<typeof AgentDetachResponseMessageSchema>;
|
||||
export type AgentRewindResponseMessage = z.infer<typeof AgentRewindResponseMessageSchema>;
|
||||
export type UpdateAgentResponseMessage = z.infer<typeof UpdateAgentResponseMessageSchema>;
|
||||
export type ProjectRenameResponse = z.infer<typeof ProjectRenameResponseSchema>;
|
||||
@@ -4299,6 +4315,7 @@ export type SetAgentModeRequestMessage = z.infer<typeof SetAgentModeRequestMessa
|
||||
export type SetAgentModelRequestMessage = z.infer<typeof SetAgentModelRequestMessageSchema>;
|
||||
export type SetAgentThinkingRequestMessage = z.infer<typeof SetAgentThinkingRequestMessageSchema>;
|
||||
export type SetAgentFeatureRequestMessage = z.infer<typeof SetAgentFeatureRequestMessageSchema>;
|
||||
export type AgentDetachRequestMessage = z.infer<typeof AgentDetachRequestMessageSchema>;
|
||||
export type AgentPermissionResponseMessage = z.infer<typeof AgentPermissionResponseMessageSchema>;
|
||||
export type CheckoutStatusRequest = z.infer<typeof CheckoutStatusRequestSchema>;
|
||||
export type CheckoutStatusResponse = z.infer<typeof CheckoutStatusResponseSchema>;
|
||||
|
||||
Reference in New Issue
Block a user