Clean up prompts (#126)

* Clean up prompts

* Drop in-payload review comments
This commit is contained in:
Colin McDonnell
2026-01-20 00:13:55 +00:00
committed by pullfrog[bot]
parent 159e937d0d
commit ce123c9a57
4 changed files with 133 additions and 105 deletions
+46 -35
View File
@@ -119602,21 +119602,21 @@ function computeModes() {
2. ${dependencyInstallationStep}
3. Review the feedback provided. Understand each review comment and what changes are being requested.
- **EVENT DATA may contain review comment details**: If available, \`approved_comments\` are comments to address, \`unapproved_comments\` are for context only. The \`triggerer\` field indicates who initiated this action - prioritize their replies when deciding how to implement fixes.
- You can use ${ghPullfrogMcpName}/get_pull_request to get PR metadata if needed.
3. Fetch review comments using ${ghPullfrogMcpName}/get_review_comments with \`pull_number\` and \`review_id\` from EVENT DATA. This returns \`commentsPath\` - read that file for full comment details with diff context. If EVENT DATA contains a \`triggerer\` field (indicating who requested fixes), you can pass \`approved_by\` to filter to only comments they approved with \u{1F44D}.
4. If the request requires understanding the codebase structure or conventions, gather relevant context. Read AGENTS.md if it exists.
4. Review the feedback provided. Understand each review comment and what changes are being requested.
5. Make the necessary code changes to address the feedback. Work through each review comment systematically.
5. If the request requires understanding the codebase structure or conventions, gather relevant context. Read AGENTS.md if it exists.
6. **CRITICAL: Reply to EACH review comment individually.** After fixing each comment, use ${ghPullfrogMcpName}/reply_to_review_comment to reply directly to that comment thread. Keep replies extremely brief (1 sentence max, e.g., "Fixed by renaming to X" or "Added null check"). If suggesting a small, specific, self-contained code change, use GitHub's suggestion format with \`\`\`suggestion blocks.
6. Make the necessary code changes to address the feedback. Work through each review comment systematically.
7. Test your changes to ensure they work correctly.
7. **CRITICAL: Reply to EACH review comment individually.** After fixing each comment, use ${ghPullfrogMcpName}/reply_to_review_comment to reply directly to that comment thread. Keep replies extremely brief (1 sentence max, e.g., "Fixed by renaming to X" or "Added null check"). If suggesting a small, specific, self-contained code change, use GitHub's suggestion format with \`\`\`suggestion blocks.
8. When done, commit your changes with ${ghPullfrogMcpName}/commit_files, then push with ${ghPullfrogMcpName}/push_branch. The push will automatically go to the correct remote (including fork repos). Do not create a new branch or PR - you are updating an existing one.
8. Test your changes to ensure they work correctly.
9. ${reportProgressInstruction}
9. When done, commit your changes with ${ghPullfrogMcpName}/commit_files, then push with ${ghPullfrogMcpName}/push_branch. The push will automatically go to the correct remote (including fork repos). Do not create a new branch or PR - you are updating an existing one.
10. ${reportProgressInstruction}
**CRITICAL: Keep the progress comment extremely brief.** The summary should be 1-2 sentences max (e.g., "Fixed 3 review comments and pushed changes."). Almost all detail belongs in the individual reply_to_review_comment calls, NOT in the progress comment.`
},
@@ -138074,17 +138074,25 @@ ${ctx.error}` : ctx.error;
// utils/instructions.ts
import { execSync } from "node:child_process";
function buildRuntimeContext(ctx) {
const lines = [];
lines.push(`working_directory: ${process.cwd()}`);
lines.push(`log_level: ${process.env.LOG_LEVEL}`);
const {
"~pullfrog": _,
prompt: _p,
repoInstructions: _r,
event: _e,
...payloadRest
} = ctx.payload;
let gitStatus;
try {
const gitStatus = execSync("git status --short", { encoding: "utf-8", stdio: "pipe" }).trim();
lines.push(`git_status: ${gitStatus || "(clean)"}`);
gitStatus = execSync("git status --short", { encoding: "utf-8", stdio: "pipe" }).trim() || "(clean)";
} catch {
}
lines.push(`repo: ${ctx.repoData.owner}/${ctx.repoData.name}`);
lines.push(`default_branch: ${ctx.repoData.repo.default_branch}`);
const ghVars = {
const data = {
...payloadRest,
repo: `${ctx.repoData.owner}/${ctx.repoData.name}`,
default_branch: ctx.repoData.repo.default_branch,
working_directory: process.cwd(),
log_level: process.env.LOG_LEVEL,
git_status: gitStatus,
github_event_name: process.env.GITHUB_EVENT_NAME,
github_ref: process.env.GITHUB_REF,
github_sha: process.env.GITHUB_SHA?.slice(0, 7),
@@ -138092,12 +138100,25 @@ function buildRuntimeContext(ctx) {
github_run_id: process.env.GITHUB_RUN_ID,
github_workflow: process.env.GITHUB_WORKFLOW
};
for (const [key, value2] of Object.entries(ghVars)) {
if (value2) {
lines.push(`${key}: ${value2}`);
}
const filtered = Object.fromEntries(Object.entries(data).filter(([_2, v]) => v !== void 0));
return encode(filtered);
}
function buildEventData(event) {
const { title, body, ...rest } = event;
const sections = [];
const trimmedTitle = typeof title === "string" ? title.trim() : "";
const trimmedBody = typeof body === "string" ? body.trim() : "";
if (trimmedTitle) {
sections.push(`# ${trimmedTitle}`);
}
return lines.join("\n");
if (trimmedBody) {
sections.push(trimmedBody);
}
if (Object.keys(rest).length > 0) {
if (sections.length > 0) sections.push("---");
sections.push(encode(rest));
}
return sections.join("\n\n");
}
function getShellInstructions(bash) {
const backgroundInstructions = `For long-running processes (dev servers, watchers), use \`bash({ command, background: true })\` which returns a handle. Use \`${ghPullfrogMcpName}/kill_background\` to stop background processes by handle.`;
@@ -138115,17 +138136,7 @@ function getShellInstructions(bash) {
}
}
function resolveInstructions(ctx) {
const event = encode({
agent: ctx.payload.agent,
effort: ctx.payload.effort,
permissions: {
web: ctx.payload.web,
search: ctx.payload.search,
write: ctx.payload.write,
bash: ctx.payload.bash
},
event: ctx.payload.event
});
const event = buildEventData(ctx.payload.event);
const runtime = buildRuntimeContext(ctx);
const user = ctx.payload.prompt;
const repo = ctx.payload.repoInstructions ?? "";
@@ -138219,12 +138230,12 @@ ${repoSection}
************* EVENT DATA *************
The following is structured data about the context of this run (agent, effort level, permissions, and the GitHub event that triggered it). Use this context to understand the full situation.
${event}
************* RUNTIME CONTEXT *************
The following contains the agent configuration (agent, effort, permissions) and runtime environment details.
${runtime}`;
return { full, system, user, repo, event, runtime };
}
+28 -31
View File
@@ -69,17 +69,13 @@ interface BasePayloadEvent {
issue_number?: number;
is_pr?: boolean;
branch?: string;
pr_title?: string;
pr_body?: string | null;
issue_title?: string;
issue_body?: string | null;
/** title of the issue/PR (or contextual title for comments) */
title?: string;
/** primary content for this trigger (issue body, PR body, comment body, review body, etc.) */
body?: string | null;
comment_id?: number;
comment_body?: string;
review_id?: number;
review_body?: string | null;
review_state?: string;
review_comments?: any[];
context?: any;
thread?: any;
pull_request?: any;
check_suite?: {
@@ -102,8 +98,8 @@ interface PullRequestOpenedEvent extends BasePayloadEvent {
trigger: "pull_request_opened";
issue_number: number;
is_pr: true;
pr_title: string;
pr_body: string | null;
title: string;
body: string | null;
branch: string;
}
@@ -111,8 +107,8 @@ interface PullRequestReadyForReviewEvent extends BasePayloadEvent {
trigger: "pull_request_ready_for_review";
issue_number: number;
is_pr: true;
pr_title: string;
pr_body: string | null;
title: string;
body: string | null;
branch: string;
}
@@ -120,8 +116,8 @@ interface PullRequestReviewRequestedEvent extends BasePayloadEvent {
trigger: "pull_request_review_requested";
issue_number: number;
is_pr: true;
pr_title: string;
pr_body: string | null;
title: string;
body: string | null;
branch: string;
}
@@ -130,10 +126,9 @@ interface PullRequestReviewSubmittedEvent extends BasePayloadEvent {
issue_number: number;
is_pr: true;
review_id: number;
review_body: string | null;
/** review body is the primary content */
body: string | null;
review_state: string;
review_comments: any[];
context: any;
branch: string;
}
@@ -141,9 +136,10 @@ interface PullRequestReviewCommentCreatedEvent extends BasePayloadEvent {
trigger: "pull_request_review_comment_created";
issue_number: number;
is_pr: true;
pr_title: string;
title: string;
comment_id: number;
comment_body: string;
/** comment body is the primary content */
body: string;
thread?: any;
branch: string;
}
@@ -151,42 +147,42 @@ interface PullRequestReviewCommentCreatedEvent extends BasePayloadEvent {
interface IssuesOpenedEvent extends BasePayloadEvent {
trigger: "issues_opened";
issue_number: number;
issue_title: string;
issue_body: string | null;
title: string;
body: string | null;
}
interface IssuesAssignedEvent extends BasePayloadEvent {
trigger: "issues_assigned";
issue_number: number;
issue_title: string;
issue_body: string | null;
title: string;
body: string | null;
}
interface IssuesLabeledEvent extends BasePayloadEvent {
trigger: "issues_labeled";
issue_number: number;
issue_title: string;
issue_body: string | null;
title: string;
body: string | null;
}
interface IssueCommentCreatedEvent extends BasePayloadEvent {
trigger: "issue_comment_created";
comment_id: number;
comment_body: string;
/** comment body is the primary content */
body: string;
issue_number: number;
// PR-specific fields (only present when is_pr is true)
is_pr?: true;
branch?: string;
pr_title?: string;
pr_body?: string | null;
title?: string;
}
interface CheckSuiteCompletedEvent extends BasePayloadEvent {
trigger: "check_suite_completed";
issue_number: number;
is_pr: true;
pr_title: string;
pr_body: string | null;
title: string;
body: string | null;
pull_request: any;
branch: string;
check_suite: {
@@ -216,7 +212,8 @@ interface ImplementPlanEvent extends BasePayloadEvent {
trigger: "implement_plan";
issue_number: number;
plan_comment_id: number;
plan_content: string;
/** plan content is the primary content */
body: string;
}
interface UnknownEvent extends BasePayloadEvent {
+9 -9
View File
@@ -73,21 +73,21 @@ export function computeModes(): Mode[] {
2. ${dependencyInstallationStep}
3. Review the feedback provided. Understand each review comment and what changes are being requested.
- **EVENT DATA may contain review comment details**: If available, \`approved_comments\` are comments to address, \`unapproved_comments\` are for context only. The \`triggerer\` field indicates who initiated this action - prioritize their replies when deciding how to implement fixes.
- You can use ${ghPullfrogMcpName}/get_pull_request to get PR metadata if needed.
3. Fetch review comments using ${ghPullfrogMcpName}/get_review_comments with \`pull_number\` and \`review_id\` from EVENT DATA. This returns \`commentsPath\` - read that file for full comment details with diff context. If EVENT DATA contains a \`triggerer\` field (indicating who requested fixes), you can pass \`approved_by\` to filter to only comments they approved with 👍.
4. If the request requires understanding the codebase structure or conventions, gather relevant context. Read AGENTS.md if it exists.
4. Review the feedback provided. Understand each review comment and what changes are being requested.
5. Make the necessary code changes to address the feedback. Work through each review comment systematically.
5. If the request requires understanding the codebase structure or conventions, gather relevant context. Read AGENTS.md if it exists.
6. **CRITICAL: Reply to EACH review comment individually.** After fixing each comment, use ${ghPullfrogMcpName}/reply_to_review_comment to reply directly to that comment thread. Keep replies extremely brief (1 sentence max, e.g., "Fixed by renaming to X" or "Added null check"). If suggesting a small, specific, self-contained code change, use GitHub's suggestion format with \`\`\`suggestion blocks.
6. Make the necessary code changes to address the feedback. Work through each review comment systematically.
7. Test your changes to ensure they work correctly.
7. **CRITICAL: Reply to EACH review comment individually.** After fixing each comment, use ${ghPullfrogMcpName}/reply_to_review_comment to reply directly to that comment thread. Keep replies extremely brief (1 sentence max, e.g., "Fixed by renaming to X" or "Added null check"). If suggesting a small, specific, self-contained code change, use GitHub's suggestion format with \`\`\`suggestion blocks.
8. When done, commit your changes with ${ghPullfrogMcpName}/commit_files, then push with ${ghPullfrogMcpName}/push_branch. The push will automatically go to the correct remote (including fork repos). Do not create a new branch or PR - you are updating an existing one.
8. Test your changes to ensure they work correctly.
9. ${reportProgressInstruction}
9. When done, commit your changes with ${ghPullfrogMcpName}/commit_files, then push with ${ghPullfrogMcpName}/push_branch. The push will automatically go to the correct remote (including fork repos). Do not create a new branch or PR - you are updating an existing one.
10. ${reportProgressInstruction}
**CRITICAL: Keep the progress comment extremely brief.** The summary should be 1-2 sentences max (e.g., "Fixed 3 review comments and pushed changes."). Almost all detail belongs in the individual reply_to_review_comment calls, NOT in the progress comment.`,
},
+50 -30
View File
@@ -1,6 +1,6 @@
import { execSync } from "node:child_process";
import { encode as toonEncode } from "@toon-format/toon";
import { ghPullfrogMcpName } from "../external.ts";
import { ghPullfrogMcpName, type PayloadEvent } from "../external.ts";
import type { Mode } from "../modes.ts";
import type { ResolvedPayload } from "./payload.ts";
import type { RepoData } from "./repoData.ts";
@@ -12,22 +12,30 @@ interface InstructionsContext {
}
function buildRuntimeContext(ctx: InstructionsContext): string {
const lines: string[] = [];
lines.push(`working_directory: ${process.cwd()}`);
lines.push(`log_level: ${process.env.LOG_LEVEL}`);
// extract payload fields excluding prompt/repoInstructions/event
const {
"~pullfrog": _,
prompt: _p,
repoInstructions: _r,
event: _e,
...payloadRest
} = ctx.payload;
let gitStatus: string | undefined;
try {
const gitStatus = execSync("git status --short", { encoding: "utf-8", stdio: "pipe" }).trim();
lines.push(`git_status: ${gitStatus || "(clean)"}`);
gitStatus =
execSync("git status --short", { encoding: "utf-8", stdio: "pipe" }).trim() || "(clean)";
} catch {
// git not available or not in a repo
}
lines.push(`repo: ${ctx.repoData.owner}/${ctx.repoData.name}`);
lines.push(`default_branch: ${ctx.repoData.repo.default_branch}`);
const ghVars: Record<string, string | undefined> = {
const data: Record<string, unknown> = {
...payloadRest,
repo: `${ctx.repoData.owner}/${ctx.repoData.name}`,
default_branch: ctx.repoData.repo.default_branch,
working_directory: process.cwd(),
log_level: process.env.LOG_LEVEL,
git_status: gitStatus,
github_event_name: process.env.GITHUB_EVENT_NAME,
github_ref: process.env.GITHUB_REF,
github_sha: process.env.GITHUB_SHA?.slice(0, 7),
@@ -35,13 +43,36 @@ function buildRuntimeContext(ctx: InstructionsContext): string {
github_run_id: process.env.GITHUB_RUN_ID,
github_workflow: process.env.GITHUB_WORKFLOW,
};
for (const [key, value] of Object.entries(ghVars)) {
if (value) {
lines.push(`${key}: ${value}`);
}
// filter out undefined values
const filtered = Object.fromEntries(Object.entries(data).filter(([_, v]) => v !== undefined));
return toonEncode(filtered);
}
function buildEventData(event: PayloadEvent): string {
const { title, body, ...rest } = event;
const sections: string[] = [];
// render title + body as markdown
const trimmedTitle = typeof title === "string" ? title.trim() : "";
const trimmedBody = typeof body === "string" ? body.trim() : "";
if (trimmedTitle) {
sections.push(`# ${trimmedTitle}`);
}
return lines.join("\n");
if (trimmedBody) {
sections.push(trimmedBody);
}
// separator and toon-encoded remaining fields
if (Object.keys(rest).length > 0) {
if (sections.length > 0) sections.push("---");
sections.push(toonEncode(rest));
}
return sections.join("\n\n");
}
function getShellInstructions(bash: ResolvedPayload["bash"]): string {
@@ -71,18 +102,7 @@ export interface ResolvedInstructions {
}
export function resolveInstructions(ctx: InstructionsContext): ResolvedInstructions {
const event = toonEncode({
agent: ctx.payload.agent,
effort: ctx.payload.effort,
permissions: {
web: ctx.payload.web,
search: ctx.payload.search,
write: ctx.payload.write,
bash: ctx.payload.bash,
},
event: ctx.payload.event,
});
const event = buildEventData(ctx.payload.event);
const runtime = buildRuntimeContext(ctx);
// user prompt is constructed server-side (body if @pullfrog tagged + per-trigger instructions)
@@ -190,12 +210,12 @@ ${repoSection}
************* EVENT DATA *************
The following is structured data about the context of this run (agent, effort level, permissions, and the GitHub event that triggered it). Use this context to understand the full situation.
${event}
************* RUNTIME CONTEXT *************
The following contains the agent configuration (agent, effort, permissions) and runtime environment details.
${runtime}`;
return { full, system, user, repo, event, runtime };