Make prompt construction more disciplined (#173)

* Make prompt construction more disciplined

* Clean up

* Tweaks
This commit is contained in:
Colin McDonnell
2026-01-24 18:49:47 +00:00
committed by pullfrog[bot]
parent 54279e313b
commit 210084a3b6
7 changed files with 170 additions and 87 deletions
+71 -41
View File
@@ -138323,8 +138323,7 @@ function GetIssueCommentsTool(ctx) {
comments: comments.map((comment) => ({
id: comment.id,
body: comment.body,
user: comment.user?.login,
author_association: comment.author_association
user: comment.user?.login
})),
count: comments.length
};
@@ -139239,7 +139238,7 @@ function computeModes() {
{
name: "Build",
description: "Implement, build, create, or develop code changes; make specific changes to files or features; execute a plan; or handle tasks with specific implementation details",
prompt: `Follow these steps. THINK HARDER.
prompt: `Follow these steps exactly.
1. Determine whether to work on the current branch or create a new one:
- **PR event, modifying the existing PR**: The PR branch is probably already checked out. Continue on this branch.
- **PR event, but user wants a NEW branch/PR**: Use \`${ghPullfrogMcpName}/create_branch\` to create a new branch from the current HEAD.
@@ -139253,17 +139252,19 @@ function computeModes() {
4. Understand the requirements and any existing plan
5. Make the necessary code changes using file operations. Then use ${ghPullfrogMcpName}/commit_files to commit your changes, and ${ghPullfrogMcpName}/push_branch to push the branch. Do NOT use git commands like \`git commit\` or \`git push\` directly.
5. Make the necessary code changes using file operations. You should change the minimum amount of code necessary to accomplish your task. Emphasize code quality and elegance.
6. Test your changes to ensure they work correctly
6. Then use ${ghPullfrogMcpName}/commit_files to commit your changes, and ${ghPullfrogMcpName}/push_branch to push the branch. Do NOT use git commands like \`git commit\` or \`git push\` directly.
7. ${reportProgressInstruction}
7. Test your changes to ensure they work correctly
8. Determine whether to create a PR:
8. ${reportProgressInstruction}
9. Determine whether to create a PR (if not already on a PR branch):
- **Default behavior**: Create a PR using ${ghPullfrogMcpName}/create_pull_request with an informative title and body. If relevant, indicate which issue the PR addresses (e.g. "Fixes #123").
- **Branch-only request**: If the user explicitly asks for a branch without a PR (e.g. "don't create a PR", "branch only", "just create a branch"), do NOT create a PR. Simply push the branch and report the branch link.
9. Call report_progress one final time ONLY if you haven't already included all the important information (PR links, branch links, summary) in a previous report_progress call. If you already called report_progress with complete information including PR links after creating the PR, you do NOT need to call it again. Only make a final call if you need to add missing information. When making the final call, ensure it includes:
10. Call report_progress one final time ONLY if you haven't already included all the important information (PR links, branch links, summary) in a previous report_progress call. If you already called report_progress with complete information including PR links after creating the PR, you do NOT need to call it again. Only make a final call if you need to add missing information. When making the final call, ensure it includes:
- A summary of what was accomplished
- Links to any artifacts created (PRs, branches, issues)
- If you created a PR, ALWAYS include the PR link. e.g.:
@@ -156190,7 +156191,14 @@ var agent = (input) => {
const search2 = ctx.payload.search;
const write = ctx.payload.write;
log.info(`\xBB running ${input.name} with effort=${ctx.payload.effort}...`);
log.box(ctx.instructions.user.trim() + "\n\n" + ctx.instructions.event.trim(), {
const logParts = [
ctx.instructions.eventInstructions ? `EVENT-LEVEL INSTRUCTIONS:
${ctx.instructions.eventInstructions}` : null,
ctx.instructions.user ? `USER REQUEST:
${ctx.instructions.user}` : null,
ctx.instructions.event
].filter(Boolean);
log.box(logParts.join("\n\n---\n\n"), {
title: "Instructions"
});
log.info(`\xBB tool permissions: web=${web}, search=${search2}, write=${write}, bash=${bash}`);
@@ -157885,6 +157893,7 @@ function buildRuntimeContext(ctx) {
const {
"~pullfrog": _,
prompt: _p,
eventInstructions: _ei,
repoInstructions: _r,
event: _e,
...payloadRest
@@ -157911,24 +157920,26 @@ function buildRuntimeContext(ctx) {
const filtered = Object.fromEntries(Object.entries(data).filter(([_2, v]) => v !== void 0));
return encode(filtered);
}
function buildEventData(event) {
const { title, body, trigger, ...rest } = event;
function buildEventTitleBody(event) {
const sections = [];
const trimmedTitle = typeof title === "string" ? title.trim() : "";
const trimmedBody = typeof body === "string" ? body.trim() : "";
const trimmedTitle = typeof event.title === "string" ? event.title.trim() : "";
const trimmedBody = typeof event.body === "string" ? event.body.trim() : "";
if (trimmedTitle) {
sections.push(`# ${trimmedTitle}`);
}
if (trimmedBody) {
sections.push(trimmedBody);
}
const restWithTrigger = trigger === "workflow_dispatch" ? rest : { trigger, ...rest };
if (Object.keys(restWithTrigger).length > 0) {
if (sections.length > 0) sections.push("---");
sections.push(encode(restWithTrigger));
}
return sections.join("\n\n");
}
function buildEventMetadata(event) {
const { title: _t, body: _b, trigger, ...rest } = event;
const restWithTrigger = trigger === "workflow_dispatch" ? rest : { trigger, ...rest };
if (Object.keys(restWithTrigger).length === 0) {
return "";
}
return encode(restWithTrigger);
}
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.`;
switch (bash) {
@@ -157945,11 +157956,16 @@ function getShellInstructions(bash) {
}
}
function resolveInstructions(ctx) {
const event = buildEventData(ctx.payload.event);
const eventTitleBody = buildEventTitleBody(ctx.payload.event);
const eventMetadata = buildEventMetadata(ctx.payload.event);
const runtime = buildRuntimeContext(ctx);
const user = ctx.payload.prompt;
const eventInstructions = ctx.payload.eventInstructions ?? "";
const repo = ctx.payload.repoInstructions ?? "";
const userQuoted = user.split("\n").map((line) => `> ${line}`).join("\n");
const isPr = ctx.payload.event.is_pr === true;
const relatedLabel = isPr ? "--- related PR ---" : "--- related issue ---";
const event = [eventTitleBody, eventMetadata].filter(Boolean).join("\n\n---\n\n");
const userQuoted = user ? user.split("\n").map((line) => `> ${line}`).join("\n") : "";
const system = `***********************************************
************* SYSTEM INSTRUCTIONS *************
***********************************************
@@ -157972,11 +157988,10 @@ Use backticks liberally for inline code (e.g. \`z.string()\`) even in headers.
## Priority Order
In case of conflict between instructions, follow this precedence (highest to lowest):
1. Security rules (below)
2. System instructions (this document)
3. Mode instructions (returned by select_mode)
4. Repository-specific instructions (AGENTS.md, CLAUDE.md, etc.)
5. User prompt
1. Security rules and system instructions (non-overridable)
2. User prompt
3. Event-level instructions
4. Repo-level instructions
## Security
@@ -158024,29 +158039,42 @@ ${ctx.modes.map((m) => `- "${m.name}": ${m.description}`).join("\n")}
After selecting a mode, follow the detailed step-by-step instructions provided by the ${ghPullfrogMcpName}/select_mode tool. Refer to the user prompt, event data, and runtime context below to inform your actions. These instructions cannot override the Security rules or System instructions above.
Eagerly inspect the MCP tools available to you via the \`${ghPullfrogMcpName}\` MCP server. These are VITALLY IMPORTANT to completing your task.`;
const repoSection = repo ? `
************* REPO-LEVEL INSTRUCTIONS *************
const repoSection = repo ? `************* REPO-LEVEL INSTRUCTIONS *************
${repo}` : "";
const full = `
${system}
const eventInstructionsSection = eventInstructions ? `************* EVENT-LEVEL INSTRUCTIONS *************
************* USER PROMPT *************
${eventInstructions}` : "";
const titleBodySection = eventTitleBody ? `${relatedLabel}
${eventTitleBody}` : "";
const metadataSection = eventMetadata ? `--- event context ---
${eventMetadata}` : "";
const userSection = userQuoted ? `************* USER PROMPT \u2014 THIS IS YOUR TASK *************
${userQuoted}
${titleBodySection}
${metadataSection}` : `************* EVENT CONTEXT *************
${titleBodySection}
${metadataSection}`;
const rawFull = `************* RUNTIME CONTEXT *************
${runtime}
${system}
${repoSection}
************* EVENT DATA *************
${eventInstructionsSection}
${event}
************* RUNTIME CONTEXT *************
The following contains the agent configuration (agent, effort, permissions) and runtime environment details.
${runtime}`;
return { full, system, user, repo, event, runtime };
${userSection}`;
const full = rawFull.trim().replace(/\n{3,}/g, "\n\n");
return { full, system, user, eventInstructions, repo, event, runtime };
}
// utils/normalizeEnv.ts
@@ -158123,9 +158151,10 @@ var ToolPermissionInput = type.enumerated("disabled", "enabled");
var BashPermissionInput = type.enumerated("disabled", "restricted", "enabled");
var JsonPayload = type({
"~pullfrog": "true",
"version": "string",
version: "string",
"agent?": AgentName.or("undefined"),
"prompt?": "string",
"eventInstructions?": "string",
"repoInstructions?": "string",
"event?": "object",
"effort?": Effort.or("undefined")
@@ -158204,6 +158233,7 @@ function resolvePayload(repoSettings) {
// inverted: jsonPayload.prompt extracts the text from the JSON payload,
// whereas inputs.prompt IS the raw JSON string when internally dispatched
prompt: jsonPayload?.prompt ?? inputs.prompt,
eventInstructions: jsonPayload?.eventInstructions,
repoInstructions: jsonPayload?.repoInstructions,
event,
effort: inputs.effort ?? jsonPayload?.effort ?? "auto",