show model name in footer, drop pullfrog.com link (#484)

* show model name in footer, drop pullfrog.com link

add model slug to buildPullfrogFooter so every Pullfrog comment
displays the active model (e.g. "Using `Big Pickle` (free)" or
"Using `Claude Opus`"). remove the pullfrog.com link from all footers.

Made-with: Cursor

* reject <br/> tags in comment bodies, add prompt guidance

add runtime validation in addFooter that throws if <br/> is followed
by a non-blank line (breaks GitHub heading rendering). the agent sees
the error and retries with clean markdown. also update Summarize mode
prompt to explicitly forbid <br/> tags.

Made-with: Cursor

* fix <br/> guidance: move to event instructions, clarify blank line rule

the formatting rule belongs in DEFAULT_PR_SUMMARY_INSTRUCTIONS (event
instructions), not the Summarize mode prompt. clarify that <br/> must
always be followed by a blank line before headings.

Made-with: Cursor

* generalize block-level HTML rule in summary instructions

add a prominent top-level rule about requiring blank lines between ALL
block-level HTML elements and markdown syntax, not just <br/>.

Made-with: Cursor

* move model to toolState instead of threading through params

model is set once at startup and read everywhere — it belongs on
toolState, not threaded as a separate param through 8 call sites.
postCleanup runs without toolState so it just omits the model label.

Made-with: Cursor

* update models.dev snapshot (openai latest changed)

Made-with: Cursor

* add comment to models snapshot test explaining its purpose

Made-with: Cursor
This commit is contained in:
Colin McDonnell
2026-03-17 19:59:11 +00:00
committed by pullfrog[bot]
parent 30d68e53a7
commit c6a3ee0e9a
11 changed files with 247 additions and 42 deletions
+33 -19
View File
@@ -145015,6 +145015,11 @@ function GetCheckSuiteLogsTool(ctx) {
// utils/buildPullfrogFooter.ts
var PULLFROG_DIVIDER = "<!-- PULLFROG_DIVIDER_DO_NOT_REMOVE_PLZ -->";
var FROG_LOGO = `<a href="https://pullfrog.com"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pullfrog.com/logos/frog-white-full-18px.png"><img src="https://pullfrog.com/logos/frog-green-full-18px.png" width="9px" height="9px" style="vertical-align: middle; " alt="Pullfrog"></picture></a>`;
function formatModelLabel(slug) {
const alias = modelAliases.find((a) => a.slug === slug);
if (!alias) return `\`${slug}\``;
return alias.isFree ? `\`${alias.displayName}\` (free)` : `\`${alias.displayName}\``;
}
function buildPullfrogFooter(params) {
const parts = [];
if (params.customParts) {
@@ -145030,11 +145035,10 @@ function buildPullfrogFooter(params) {
if (params.triggeredBy) {
parts.push("Triggered by [Pullfrog](https://pullfrog.com)");
}
const allParts = [
...parts,
"[pullfrog.com](https://pullfrog.com)",
"[\u{1D54F}](https://x.com/pullfrogai)"
];
if (params.model) {
parts.push(`Using ${formatModelLabel(params.model)}`);
}
const allParts = [...parts, "[\u{1D54F}](https://x.com/pullfrogai)"];
return `
${PULLFROG_DIVIDER}
<sup>${FROG_LOGO}&nbsp;&nbsp;\uFF5C ${allParts.join(" \uFF5C ")}</sup>`;
@@ -145098,22 +145102,25 @@ async function buildCommentFooter(params) {
} catch {
}
}
const footerParams = {
return buildPullfrogFooter({
triggeredBy: true,
workflowRun: runId ? { owner: repoContext.owner, repo: repoContext.name, runId, jobId } : void 0
};
if (params.customParts && params.customParts.length > 0) {
return buildPullfrogFooter({ ...footerParams, customParts: params.customParts });
}
return buildPullfrogFooter(footerParams);
workflowRun: runId ? { owner: repoContext.owner, repo: repoContext.name, runId, jobId } : void 0,
customParts: params.customParts,
model: params.model
});
}
function buildImplementPlanLink(owner, repo, issueNumber, commentId) {
const apiUrl = getApiUrl();
return `[Implement plan \u2794](${apiUrl}/trigger/${owner}/${repo}/${issueNumber}?action=implement&comment_id=${commentId})`;
}
async function addFooter(ctx, body) {
if (/<br\s*\/?>[ \t]*\n(?!\s*\n)/i.test(body)) {
throw new Error(
"body contains <br/> followed by a non-blank line, which breaks GitHub markdown rendering. always add a blank line after <br/> tags."
);
}
const bodyWithoutFooter = stripExistingFooter(fixDoubleEscapedString(body));
const footer = await buildCommentFooter({ octokit: ctx.octokit });
const footer = await buildCommentFooter({ octokit: ctx.octokit, model: ctx.toolState?.model });
return `${bodyWithoutFooter}${footer}`;
}
var Comment = type({
@@ -145221,7 +145228,8 @@ async function reportProgress(ctx, params) {
const bodyWithoutFooter = stripExistingFooter(body);
const footer = await buildCommentFooter({
octokit: ctx.octokit,
customParts
customParts,
model: ctx.toolState.model
});
const bodyWithFooter = `${bodyWithoutFooter}${footer}`;
const result2 = await ctx.octokit.rest.issues.updateComment({
@@ -145247,7 +145255,8 @@ async function reportProgress(ctx, params) {
const bodyWithoutFooter = stripExistingFooter(body);
const footer = await buildCommentFooter({
octokit: ctx.octokit,
customParts
customParts,
model: ctx.toolState.model
});
const bodyWithFooter = `${bodyWithoutFooter}${footer}`;
const result2 = await ctx.octokit.rest.issues.updateComment({
@@ -145289,7 +145298,8 @@ async function reportProgress(ctx, params) {
const bodyWithoutFooter = stripExistingFooter(body);
const footer = await buildCommentFooter({
octokit: ctx.octokit,
customParts
customParts,
model: ctx.toolState.model
});
const bodyWithPlanLink = `${bodyWithoutFooter}${footer}`;
const updateResult = await ctx.octokit.rest.issues.updateComment({
@@ -146722,7 +146732,8 @@ var PullRequest = type({
function buildPrBodyWithFooter(ctx, body) {
const footer = buildPullfrogFooter({
triggeredBy: true,
workflowRun: ctx.runId ? { owner: ctx.repo.owner, repo: ctx.repo.name, runId: ctx.runId, jobId: ctx.jobId } : void 0
workflowRun: ctx.runId ? { owner: ctx.repo.owner, repo: ctx.repo.name, runId: ctx.runId, jobId: ctx.jobId } : void 0,
model: ctx.toolState.model
});
const bodyWithoutFooter = stripExistingFooter(fixDoubleEscapedString(body));
return `${bodyWithoutFooter}${footer}`;
@@ -147031,7 +147042,8 @@ async function createAndSubmitWithFooter(ctx, params, opts) {
}
const footer = buildPullfrogFooter({
workflowRun: ctx.runId ? { owner: ctx.repo.owner, repo: ctx.repo.name, runId: ctx.runId, jobId: ctx.jobId } : void 0,
customParts
customParts,
model: ctx.toolState.model
});
return ctx.octokit.rest.pulls.submitReview({
owner: params.owner,
@@ -149367,7 +149379,8 @@ ${ctx.error}` : ctx.error;
const footer = buildPullfrogFooter({
triggeredBy: true,
workflowRun: runId ? { owner: repoContext.owner, repo: repoContext.name, runId } : void 0,
customParts
customParts,
model: ctx.toolState.model
});
await octokit.rest.issues.updateComment({
owner: repoContext.owner,
@@ -150369,6 +150382,7 @@ async function main() {
const runContext = await resolveRunContextData({ octokit: initialOctokit, token: jobToken });
timer.checkpoint("runContextData");
const payload = resolvePayload(resolvedPromptInput, runContext.repoSettings);
toolState.model = payload.model;
const tokenRef = __using(_stack2, await resolveTokens({ push: payload.push }), true);
if (payload.shell !== "enabled") {
delete process.env.ACTIONS_ID_TOKEN_REQUEST_URL;