Skip to content

Commit 9485f63

Browse files
committed
feat(harness): integrate pi runtime into desktop app
1 parent 84dccb9 commit 9485f63

62 files changed

Lines changed: 2895 additions & 182 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/code/electron-builder.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ const config: Configuration = {
4949
".vite/build/plugins/posthog/**",
5050
".vite/build/codex-acp/**",
5151
".vite/build/grammars/**",
52+
".vite/build/rpc-host.js",
53+
".vite/build/rpc-host.js.map",
5254
...asarUnpackGlobs,
5355
],
5456

apps/code/electron.vite.config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
copyCodexAcpBinaries,
2323
copyDrizzleMigrations,
2424
copyEnricherGrammars,
25+
copyPiRpcHost,
2526
copyPosthogPlugin,
2627
fixFilenameCircularRef,
2728
getBuildDate,
@@ -93,6 +94,7 @@ export default defineConfig(({ mode }) => {
9394
autoServicesPlugin(path.join(__dirname, "src/main/services")),
9495
fixFilenameCircularRef(),
9596
copyClaudeExecutable(),
97+
copyPiRpcHost(),
9698
copyPosthogPlugin(isDev),
9799
copyDrizzleMigrations(),
98100
copyCodexAcpBinaries(),

apps/code/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@
152152
"reflect-metadata": "^0.2.2",
153153
"semver": "^7.8.1",
154154
"shadcn": "^4.1.2",
155+
"superjson": "catalog:",
155156
"smol-toml": "^1.6.1",
156157
"tailwindcss-scroll-mask": "^0.0.3",
157158
"tw-animate-css": "^1.4.0",

apps/code/src/main/di/container.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ import { OAUTH_CALLBACK_SERVER } from "@posthog/workspace-server/services/oauth-
184184
import { oauthCallbackModule } from "@posthog/workspace-server/services/oauth-callback/oauth-callback.module";
185185
import { onboardingImportModule } from "@posthog/workspace-server/services/onboarding-import/onboarding-import.module";
186186
import { osModule } from "@posthog/workspace-server/services/os/os.module";
187+
import { PI_SESSION_SERVICE } from "@posthog/workspace-server/services/pi-session/identifiers";
188+
import type { PiSessionService } from "@posthog/workspace-server/services/pi-session/pi-session";
189+
import { piSessionModule } from "@posthog/workspace-server/services/pi-session/pi-session.module";
187190
import { POSTHOG_PLUGIN_SERVICE } from "@posthog/workspace-server/services/posthog-plugin/identifiers";
188191
import { posthogPluginModule } from "@posthog/workspace-server/services/posthog-plugin/posthog-plugin.module";
189192
import { PROCESS_TRACKING_SERVICE } from "@posthog/workspace-server/services/process-tracking/identifiers";
@@ -356,6 +359,7 @@ container
356359
.bind(MAIN_DEFAULT_ADDITIONAL_DIRECTORY_REPOSITORY)
357360
.toService(DEFAULT_ADDITIONAL_DIRECTORY_REPOSITORY);
358361
container.load(agentModule);
362+
container.load(piSessionModule);
359363
container.bind(AGENT_SLEEP_COORDINATOR).toService(MAIN_SLEEP_SERVICE);
360364
container.bind(AGENT_MCP_APPS).toService(MCP_APPS_SERVICE);
361365
container.bind(AGENT_REPO_FILES).toService(MAIN_FS_SERVICE);
@@ -391,8 +395,12 @@ container.bind(MCP_PROXY_AUTH).toDynamicValue((ctx) => {
391395
});
392396
container.load(archiveModule);
393397
container.bind(ARCHIVE_SESSION_CANCELLER).toDynamicValue((ctx) => ({
394-
cancelSessionsByTaskId: (taskId: string) =>
395-
ctx.get<AgentService>(AGENT_SERVICE).cancelSessionsByTaskId(taskId),
398+
cancelSessionsByTaskId: async (taskId: string) => {
399+
await Promise.all([
400+
ctx.get<AgentService>(AGENT_SERVICE).cancelSessionsByTaskId(taskId),
401+
ctx.get<PiSessionService>(PI_SESSION_SERVICE).stop(taskId),
402+
]);
403+
},
396404
}));
397405
container.bind(ARCHIVE_FILE_WATCHER).toDynamicValue((ctx) => ({
398406
stopWatching: async (worktreePath: string) => {
@@ -403,8 +411,12 @@ container.bind(ARCHIVE_FILE_WATCHER).toDynamicValue((ctx) => ({
403411
}));
404412
container.load(suspensionModule);
405413
container.bind(SUSPENSION_SESSION_CANCELLER).toDynamicValue((ctx) => ({
406-
cancelSessionsByTaskId: (taskId: string) =>
407-
ctx.get<AgentService>(AGENT_SERVICE).cancelSessionsByTaskId(taskId),
414+
cancelSessionsByTaskId: async (taskId: string) => {
415+
await Promise.all([
416+
ctx.get<AgentService>(AGENT_SERVICE).cancelSessionsByTaskId(taskId),
417+
ctx.get<PiSessionService>(PI_SESSION_SERVICE).stop(taskId),
418+
]);
419+
},
408420
}));
409421
container.bind(SUSPENSION_FILE_WATCHER).toDynamicValue((ctx) => ({
410422
stopWatching: async (worktreePath: string) => {
@@ -675,7 +687,12 @@ container.load(workspaceModule);
675687
container.bind(WORKSPACE_AGENT).toDynamicValue((ctx): WorkspaceAgent => {
676688
const agent = ctx.get<AgentService>(AGENT_SERVICE);
677689
return {
678-
cancelSessionsByTaskId: (taskId) => agent.cancelSessionsByTaskId(taskId),
690+
cancelSessionsByTaskId: async (taskId) => {
691+
await Promise.all([
692+
agent.cancelSessionsByTaskId(taskId),
693+
ctx.get<PiSessionService>(PI_SESSION_SERVICE).stop(taskId),
694+
]);
695+
},
679696
onAgentFileActivity: (handler) =>
680697
agent.on(AgentServiceEvent.AgentFileActivity, handler),
681698
};

apps/code/src/main/trpc/router.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import { notificationRouter } from "@posthog/host-router/routers/notification.ro
3535
import { oauthRouter } from "@posthog/host-router/routers/oauth.router";
3636
import { onboardingImportRouter } from "@posthog/host-router/routers/onboarding-import.router";
3737
import { osRouter } from "@posthog/host-router/routers/os.router";
38+
import { piSessionRouter } from "@posthog/host-router/routers/pi-session.router";
3839
import { processTrackingRouter } from "@posthog/host-router/routers/process-tracking.router";
3940
import { provisioningRouter } from "@posthog/host-router/routers/provisioning.router";
4041
import { secureStoreRouter } from "@posthog/host-router/routers/secure-store.router";
@@ -93,6 +94,7 @@ export const trpcRouter = router({
9394
onboardingImport: onboardingImportRouter,
9495
logs: logsRouter,
9596
os: osRouter,
97+
piSession: piSessionRouter,
9698
processTracking: processTrackingRouter,
9799
provisioning: provisioningRouter,
98100
sleep: sleepRouter,

apps/code/src/renderer/di/bindings.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ import {
6565
GITHUB_CONNECT_CLIENT,
6666
type GithubConnectClient,
6767
} from "@posthog/core/onboarding/identifiers";
68+
import { PI_RUNNER } from "@posthog/core/pi-runtime/identifiers";
69+
import type { PiRunner } from "@posthog/core/pi-runtime/piRunner";
6870
import {
6971
type BundleLocalSkill,
7072
CLOUD_ARTIFACT_BUNDLE_LOCAL_SKILL,
@@ -276,6 +278,7 @@ export interface RendererBindings {
276278
[SHELL_PROCESS_READER]: ShellProcessReader;
277279
[ANALYTICS_TRACKER]: AnalyticsTracker;
278280
[TASK_CREATION_HOST]: ITaskCreationHost;
281+
[PI_RUNNER]: PiRunner;
279282
[TASK_CREATION_EFFECTS]: TaskCreationEffects;
280283
[RENDERER_TASK_SERVICE]: TaskService;
281284
[TASK_SERVICE]: TaskService;

apps/code/src/renderer/di/container.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import {
3030
import { LLM_GATEWAY_SERVICE } from "@posthog/core/llm-gateway/identifiers";
3131
import type { LlmGatewayService } from "@posthog/core/llm-gateway/llm-gateway";
3232
import type { LlmMessage } from "@posthog/core/llm-gateway/schemas";
33+
import { PI_RUNNER } from "@posthog/core/pi-runtime/identifiers";
34+
import type { PiRunner } from "@posthog/core/pi-runtime/piRunner";
3335
import {
3436
CLOUD_ARTIFACT_BUNDLE_LOCAL_SKILL,
3537
CLOUD_ARTIFACT_READ_FILE_AS_BASE64,
@@ -149,6 +151,7 @@ import { trpcClient } from "@renderer/trpc";
149151
import { hostTrpcClient } from "@renderer/trpc/client";
150152
import type { TRPCClient } from "@trpc/client";
151153
import { hostLog, logger } from "@utils/logger";
154+
import { TrpcPiRunner } from "../platform-adapters/trpc-pi-runner";
152155
import type { RendererBindings } from "./bindings";
153156
import { TASK_SERVICE as RENDERER_TASK_SERVICE, TRPC_CLIENT } from "./tokens";
154157

@@ -288,6 +291,7 @@ container
288291

289292
// Bind services
290293
container.bind<ITaskCreationHost>(TASK_CREATION_HOST).to(TrpcTaskCreationHost);
294+
container.bind<PiRunner>(PI_RUNNER).to(TrpcPiRunner);
291295
container.bind(TASK_CREATION_EFFECTS).toConstantValue(taskCreationEffects);
292296
container.bind<TaskService>(RENDERER_TASK_SERVICE).to(TaskService);
293297
container.bind<TaskService>(TASK_SERVICE).toService(RENDERER_TASK_SERVICE);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import type {
2+
PiResumeInput,
3+
PiRunInput,
4+
PiRunner,
5+
} from "@posthog/core/pi-runtime/piRunner";
6+
import { resolveService } from "@posthog/di/container";
7+
import {
8+
HOST_TRPC_CLIENT,
9+
type HostTrpcClient,
10+
} from "@posthog/host-router/client";
11+
12+
function hostClient(): HostTrpcClient {
13+
return resolveService<HostTrpcClient>(HOST_TRPC_CLIENT);
14+
}
15+
16+
export class TrpcPiRunner implements PiRunner {
17+
async create(input: PiRunInput): Promise<void> {
18+
await hostClient().piSession.start.mutate(input);
19+
}
20+
21+
resume(input: PiResumeInput): Promise<void> {
22+
return hostClient().piSession.resume.mutate(input);
23+
}
24+
25+
stop(taskId: string): Promise<void> {
26+
return hostClient().piSession.stop.mutate({ taskId });
27+
}
28+
}

apps/code/src/renderer/trpc/client.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,18 @@ import {
77
createTRPCOptionsProxy,
88
} from "@trpc/tanstack-react-query";
99
import { queryClient } from "@utils/queryClient";
10+
import superjson from "superjson";
1011
import type { TrpcRouter } from "../../main/trpc/router";
1112

1213
export const trpcClient = createTRPCClient<TrpcRouter>({
13-
links: [ipcInstrumentationLink<TrpcRouter>(), ipcLink()],
14+
links: [
15+
ipcInstrumentationLink<TrpcRouter>(),
16+
ipcLink({ transformer: superjson }),
17+
],
1418
});
1519

1620
export const hostTrpcClient = createTRPCClient<HostRouter>({
17-
links: [ipcLink()],
21+
links: [ipcLink({ transformer: superjson })],
1822
});
1923

2024
const context = createTRPCContext<TrpcRouter>();

apps/code/vite-main-plugins.mts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,29 @@ function copyClaudeSupportAssets(sourcePath: string, destDir: string): void {
163163
}
164164
}
165165

166+
export function copyPiRpcHost(): Plugin {
167+
return {
168+
name: "copy-pi-rpc-host",
169+
writeBundle() {
170+
const candidates = [
171+
join(__dirname, "node_modules/@posthog/agent/dist/pi/rpc-host.js"),
172+
join(
173+
__dirname,
174+
"../../node_modules/@posthog/agent/dist/pi/rpc-host.js",
175+
),
176+
join(__dirname, "../../packages/agent/dist/pi/rpc-host.js"),
177+
];
178+
const source = candidates.find((candidate) => existsSync(candidate));
179+
if (!source) {
180+
throw new Error(
181+
`[copy-pi-rpc-host] Unable to find Pi RPC host, required at runtime by createPiRpcClient. Build @posthog/agent first. Checked:\n ${candidates.join("\n ")}`,
182+
);
183+
}
184+
copyFileSync(source, join(__dirname, ".vite/build/rpc-host.js"));
185+
},
186+
};
187+
}
188+
166189
export function copyClaudeExecutable(): Plugin {
167190
return {
168191
name: "copy-claude-executable",

0 commit comments

Comments
 (0)