Run Pi agents through the installed Pi CLI (#1097)

* Run Pi through its RPC interface

Replace the embedded Pi runtime packages with a process-backed runtime that starts pi --mode rpc, keeps the runtime port thin, and leaves provider behavior in the Paseo session and mapper modules.

Add focused adapter and mapper tests plus real Pi E2E coverage for the installed binary path.

* Keep Pi provider code in one module

* Add Pi session imports

* Enable Paseo MCP tools in Pi agents

Route injected MCP servers through Pi's MCP adapter and make structured MCP results visible to model-only clients.

Normalize Pi MCP proxy calls so Paseo timelines show the underlying tool names.

* Fix Pi import symlink tests on Windows

Create directory links explicitly in symlink cwd fixtures so Windows server tests exercise the intended path-equivalence behavior.

* Use native realpath for import cwd matching

Resolve import cwd matchers with native realpath so Windows symlink and junction sessions compare against the same path shape used by persisted provider data.

* Fallback realpath for Windows import matching

Use plain realpath when native realpath cannot resolve a cwd so symlink-equivalent persisted sessions still match on Windows runners.

* Add daemon system prompt support for Pi

* Fix Windows realpath import matching

* Remove Pi RPC migration plan doc
This commit is contained in:
Mohamed Boudra
2026-05-19 23:56:07 +08:00
committed by GitHub
parent 0e1c590a3b
commit 4cf985c254
36 changed files with 4319 additions and 3784 deletions
+39 -2
View File
@@ -1,5 +1,16 @@
import { describe, expect, it } from "vitest";
import { resolveImportCwd } from "./import.js";
import { describe, expect, it, vi } from "vitest";
import { resolveImportCwd, runImportCommand } from "./import.js";
const importAgent = vi.fn();
const close = vi.fn();
vi.mock("../../utils/client.js", () => ({
connectToDaemon: vi.fn(async () => ({
importAgent,
close,
})),
getDaemonHost: vi.fn(() => "ws://127.0.0.1:6767"),
}));
describe("resolveImportCwd", () => {
it("uses the invoking process cwd when --cwd is omitted", () => {
@@ -19,4 +30,30 @@ describe("resolveImportCwd", () => {
}),
);
});
it("accepts pi as an import provider", async () => {
importAgent.mockResolvedValueOnce({
id: "agent-1",
status: "idle",
provider: "pi",
cwd: "/tmp/project",
title: "Imported Pi session",
});
const result = await runImportCommand(
"pi-session-1",
{
provider: "pi",
cwd: "/tmp/project",
},
{} as never,
);
expect(importAgent).toHaveBeenCalledWith({
provider: "pi",
sessionId: "pi-session-1",
cwd: "/tmp/project",
});
expect(result.data.provider).toBe("pi");
});
});
+5 -3
View File
@@ -5,13 +5,15 @@ import type { CommandError, CommandOptions, SingleResult } from "../../output/in
import { agentRunSchema, type AgentRunResult } from "./run.js";
import type { AgentSnapshotPayload } from "@getpaseo/server";
const IMPORT_PROVIDERS = new Set(["claude", "codex", "opencode", "acp"]);
const IMPORT_PROVIDER_LIST = ["claude", "codex", "opencode", "pi", "acp"] as const;
const IMPORT_PROVIDERS = new Set<string>(IMPORT_PROVIDER_LIST);
const IMPORT_PROVIDER_HELP = IMPORT_PROVIDER_LIST.join(", ");
export function addImportOptions(cmd: Command): Command {
return cmd
.description("Import an existing provider session as a Paseo agent")
.argument("<id>", "Provider session/thread ID to import")
.requiredOption("--provider <provider>", "Agent provider: claude, codex, opencode, or acp")
.requiredOption("--provider <provider>", `Agent provider: ${IMPORT_PROVIDER_HELP}`)
.option("--cwd <path>", "Working directory for providers that require it")
.option(
"--label <key=value>",
@@ -54,7 +56,7 @@ function parseImportProvider(provider: string | undefined): string {
throw {
code: "INVALID_PROVIDER",
message: `Unsupported provider: ${normalizedProvider}`,
details: "Supported providers: claude, codex, opencode, acp",
details: `Supported providers: ${IMPORT_PROVIDER_HELP}`,
} satisfies CommandError;
}