mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-04 23:44:41 +00:00
* feat(server): add background agents An agent can be created background in any workspace. It stays a durable, addressable agent, but default discovery, workspace status and attention leave it out. Effective background is agent.background || workspace.background. - Protocol: `create_agent_request.background` now marks the agent itself and stays the workspace intent for a workspace the request creates. Snapshots carry `background`. The daemon advertises `features.backgroundAgents`. Clients advertise the `background_agents` capability. - Daemon: the flag persists in the agent record, so restart and resume keep it. AgentDirectory owns visibility. Inclusive reads and subscriptions from sources without `background_agents` see only agents in background workspaces, because older apps would otherwise open a tab for each one. - Inheritance: omitted on agent-scoped creation, children and new workspaces take the caller agent's background. - MCP: create_agent accepts `background`. - SDK: placing a background agent in an existing workspace, or under a caller, fails fast with "Update the host to use background agents." on older hosts. - CLI: `ls -a` and `ls --background` add a BACKGROUND column. * feat(app): hide background agents from tabs, track and status * docs(plugins): point hidden helpers at background agents * fix: keep background agents hidden across cache reload and connected hosts * fix: keep remote creation working on older hosts and inherit foreign parents' background
49 lines
1.8 KiB
TypeScript
49 lines
1.8 KiB
TypeScript
import { expect, type Page } from "@playwright/test";
|
|
import { PARENT_AGENT_ID_LABEL } from "@getpaseo/protocol/agent-labels";
|
|
import type { SeededWorkspace } from "./seed-client";
|
|
|
|
/**
|
|
* Starts a background agent the way a plugin helper does: in the workspace, under a parent,
|
|
* streaming for about ten seconds. Resolves once the daemon reports it running.
|
|
*/
|
|
export async function startBackgroundAgent(
|
|
workspace: Pick<SeededWorkspace, "client" | "repoPath" | "workspaceId">,
|
|
input: { parentId: string; title: string },
|
|
): Promise<{ id: string }> {
|
|
const agent = await workspace.client.createAgent({
|
|
provider: "mock",
|
|
cwd: workspace.repoPath,
|
|
workspaceId: workspace.workspaceId,
|
|
title: input.title,
|
|
modeId: "load-test",
|
|
model: "ten-second-stream",
|
|
initialPrompt: "classify the last turn",
|
|
labels: { [PARENT_AGENT_ID_LABEL]: input.parentId },
|
|
background: true,
|
|
});
|
|
await workspace.client.waitForAgentUpsert(agent.id, (snapshot) => snapshot.status === "running");
|
|
return { id: agent.id };
|
|
}
|
|
|
|
/** Waits for the agent's turn to end and archives it, as the plugin does with a helper's reply. */
|
|
export async function finishAndArchiveAgent(
|
|
workspace: Pick<SeededWorkspace, "client">,
|
|
agentId: string,
|
|
): Promise<void> {
|
|
const finished = await workspace.client.waitForFinish(agentId, 60_000);
|
|
expect(finished.status).toBe("idle");
|
|
await workspace.client.archiveAgent(agentId);
|
|
}
|
|
|
|
export async function expectWorkspaceShownIdle(page: Page, workspaceName: string): Promise<void> {
|
|
const row = page.getByRole("button", {
|
|
name: new RegExp(`^${escapeRegExp(workspaceName)}(?:,|$)`),
|
|
});
|
|
await expect(row).toBeVisible({ timeout: 30_000 });
|
|
await expect(row.getByTestId("workspace-status-indicator-running")).toHaveCount(0);
|
|
}
|
|
|
|
function escapeRegExp(value: string): string {
|
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
}
|