Skip to content

Commit 76f1383

Browse files
authored
feat(cloud-agent): refine cloud PR publish policy (#1652)
1 parent 22f228c commit 76f1383

File tree

5 files changed

+329
-37
lines changed

5 files changed

+329
-37
lines changed

packages/agent/src/server/agent-server.test.ts

Lines changed: 140 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ interface TestableServer {
2020
detectAndAttachPrUrl(payload: unknown, update: unknown): void;
2121
detectedPrUrl: string | null;
2222
buildCloudSystemPrompt(prUrl?: string | null): string;
23+
buildDetectedPrContext(prUrl: string): string;
2324
}
2425

2526
// The Claude Agent SDK has an internal readMessages() loop that rejects with
@@ -380,14 +381,17 @@ describe("AgentServer HTTP Mode", () => {
380381
});
381382

382383
describe("buildCloudSystemPrompt", () => {
383-
it("returns PR-aware prompt when prUrl is provided", () => {
384+
it("returns review-first prompt for existing PRs on non-Slack runs", () => {
384385
const s = createServer();
385386
const prompt = (s as unknown as TestableServer).buildCloudSystemPrompt(
386387
"https://github.com/org/repo/pull/1",
387388
);
388-
expect(prompt).toContain("Do NOT create a new branch");
389+
expect(prompt).toContain("stop with local changes ready for review");
389390
expect(prompt).toContain("https://github.com/org/repo/pull/1");
390-
expect(prompt).toContain("gh pr checkout");
391+
expect(prompt).toContain(
392+
"Do NOT create new commits, push to the branch, or update the pull request unless the user explicitly asks.",
393+
);
394+
expect(prompt).not.toContain("gh pr checkout");
391395
expect(prompt).not.toContain("Create a draft pull request");
392396
expect(prompt).toContain("Generated-By: PostHog Code");
393397
expect(prompt).toContain("Task-Id: test-task-id");
@@ -396,25 +400,55 @@ describe("AgentServer HTTP Mode", () => {
396400
it("returns default prompt when no prUrl", () => {
397401
const s = createServer();
398402
const prompt = (s as unknown as TestableServer).buildCloudSystemPrompt();
399-
expect(prompt).toContain("posthog-code/");
400-
expect(prompt).toContain("Create a draft pull request");
401-
expect(prompt).toContain("gh pr create --draft");
403+
expect(prompt).toContain("stop with local changes ready for review");
404+
expect(prompt).toContain(
405+
"Do NOT create a branch, commit, push, or open a pull request unless the user explicitly asks.",
406+
);
402407
expect(prompt).toContain("Generated-By: PostHog Code");
403408
expect(prompt).toContain("Task-Id: test-task-id");
404-
expect(prompt).toContain("Created with [PostHog Code]");
409+
expect(prompt).not.toContain("gh pr create --draft");
405410
});
406411

407412
it("returns default prompt when prUrl is null", () => {
408413
const s = createServer();
409414
const prompt = (s as unknown as TestableServer).buildCloudSystemPrompt(
410415
null,
411416
);
417+
expect(prompt).toContain("stop with local changes ready for review");
418+
});
419+
420+
it("returns auto-PR prompt for Slack-origin runs", () => {
421+
process.env.POSTHOG_CODE_INTERACTION_ORIGIN = "slack";
422+
const s = createServer();
423+
const prompt = (s as unknown as TestableServer).buildCloudSystemPrompt();
412424
expect(prompt).toContain("posthog-code/");
413425
expect(prompt).toContain("Create a draft pull request");
414426
expect(prompt).toContain("gh pr create --draft");
427+
expect(prompt).toContain("Generated-By: PostHog Code");
428+
expect(prompt).toContain("Task-Id: test-task-id");
429+
expect(prompt).toContain("Created with [PostHog Code]");
430+
delete process.env.POSTHOG_CODE_INTERACTION_ORIGIN;
431+
});
432+
433+
it("returns PR-update prompt for existing PRs on Slack-origin runs", () => {
434+
process.env.POSTHOG_CODE_INTERACTION_ORIGIN = "slack";
435+
const s = createServer();
436+
const prompt = (s as unknown as TestableServer).buildCloudSystemPrompt(
437+
"https://github.com/org/repo/pull/1",
438+
);
439+
expect(prompt).toContain(
440+
"gh pr checkout https://github.com/org/repo/pull/1",
441+
);
442+
expect(prompt).toContain(
443+
"Stage and commit all changes with a clear commit message",
444+
);
445+
expect(prompt).toContain("Push to the existing PR branch");
446+
expect(prompt).not.toContain("Create a draft pull request");
447+
delete process.env.POSTHOG_CODE_INTERACTION_ORIGIN;
415448
});
416449

417450
it("includes --base flag when baseBranch is configured", () => {
451+
process.env.POSTHOG_CODE_INTERACTION_ORIGIN = "slack";
418452
server = new AgentServer({
419453
port,
420454
jwtPublicKey: TEST_PUBLIC_KEY,
@@ -433,13 +467,112 @@ describe("AgentServer HTTP Mode", () => {
433467
expect(prompt).toContain(
434468
"gh pr create --draft --base add-yolo-to-readme",
435469
);
470+
delete process.env.POSTHOG_CODE_INTERACTION_ORIGIN;
436471
});
437472

438473
it("omits --base flag when baseBranch is not configured", () => {
474+
process.env.POSTHOG_CODE_INTERACTION_ORIGIN = "slack";
439475
const s = createServer();
440476
const prompt = (s as unknown as TestableServer).buildCloudSystemPrompt();
441477
expect(prompt).toContain("gh pr create --draft`");
442478
expect(prompt).not.toContain("--base");
479+
delete process.env.POSTHOG_CODE_INTERACTION_ORIGIN;
480+
});
481+
482+
it("disables auto-publish for Slack-origin runs when createPr is false", () => {
483+
process.env.POSTHOG_CODE_INTERACTION_ORIGIN = "slack";
484+
server = new AgentServer({
485+
port,
486+
jwtPublicKey: TEST_PUBLIC_KEY,
487+
repositoryPath: repo.path,
488+
apiUrl: "http://localhost:8000",
489+
apiKey: "test-api-key",
490+
projectId: 1,
491+
mode: "interactive",
492+
taskId: "test-task-id",
493+
runId: "test-run-id",
494+
createPr: false,
495+
});
496+
const prompt = (
497+
server as unknown as TestableServer
498+
).buildCloudSystemPrompt();
499+
expect(prompt).toContain("stop with local changes ready for review");
500+
expect(prompt).not.toContain("gh pr create --draft");
501+
delete process.env.POSTHOG_CODE_INTERACTION_ORIGIN;
502+
});
503+
504+
it("disables auto-publish for existing PRs when createPr is false", () => {
505+
process.env.POSTHOG_CODE_INTERACTION_ORIGIN = "slack";
506+
server = new AgentServer({
507+
port,
508+
jwtPublicKey: TEST_PUBLIC_KEY,
509+
repositoryPath: repo.path,
510+
apiUrl: "http://localhost:8000",
511+
apiKey: "test-api-key",
512+
projectId: 1,
513+
mode: "interactive",
514+
taskId: "test-task-id",
515+
runId: "test-run-id",
516+
createPr: false,
517+
});
518+
const prompt = (
519+
server as unknown as TestableServer
520+
).buildCloudSystemPrompt("https://github.com/org/repo/pull/1");
521+
expect(prompt).toContain("stop with local changes ready for review");
522+
expect(prompt).not.toContain("gh pr checkout");
523+
expect(prompt).not.toContain("Push to the existing PR branch");
524+
delete process.env.POSTHOG_CODE_INTERACTION_ORIGIN;
525+
});
526+
});
527+
528+
describe("buildDetectedPrContext", () => {
529+
const prUrl = "https://github.com/org/repo/pull/1";
530+
531+
it("returns review-first PR context for non-Slack runs", () => {
532+
const s = createServer();
533+
const context = (s as unknown as TestableServer).buildDetectedPrContext(
534+
prUrl,
535+
);
536+
expect(context).toContain("stop with local changes ready for review");
537+
expect(context).toContain(
538+
"Do NOT create commits, push to the PR branch, update the pull request",
539+
);
540+
expect(context).not.toContain("gh pr checkout");
541+
});
542+
543+
it("returns auto-update PR context for Slack-origin runs", () => {
544+
process.env.POSTHOG_CODE_INTERACTION_ORIGIN = "slack";
545+
const s = createServer();
546+
const context = (s as unknown as TestableServer).buildDetectedPrContext(
547+
prUrl,
548+
);
549+
expect(context).toContain(`gh pr checkout ${prUrl}`);
550+
expect(context).toContain(
551+
"Make changes, commit, and push to that branch",
552+
);
553+
delete process.env.POSTHOG_CODE_INTERACTION_ORIGIN;
554+
});
555+
556+
it("returns review-first PR context when createPr is false", () => {
557+
process.env.POSTHOG_CODE_INTERACTION_ORIGIN = "slack";
558+
server = new AgentServer({
559+
port,
560+
jwtPublicKey: TEST_PUBLIC_KEY,
561+
repositoryPath: repo.path,
562+
apiUrl: "http://localhost:8000",
563+
apiKey: "test-api-key",
564+
projectId: 1,
565+
mode: "interactive",
566+
taskId: "test-task-id",
567+
runId: "test-run-id",
568+
createPr: false,
569+
});
570+
const context = (
571+
server as unknown as TestableServer
572+
).buildDetectedPrContext(prUrl);
573+
expect(context).toContain("stop with local changes ready for review");
574+
expect(context).not.toContain("gh pr checkout");
575+
delete process.env.POSTHOG_CODE_INTERACTION_ORIGIN;
443576
});
444577
});
445578
});

0 commit comments

Comments
 (0)