diff --git a/actions/setup/js/handle_agent_failure.cjs b/actions/setup/js/handle_agent_failure.cjs
index a111588a7e6..4c2e59bf04b 100644
--- a/actions/setup/js/handle_agent_failure.cjs
+++ b/actions/setup/js/handle_agent_failure.cjs
@@ -888,18 +888,32 @@ function buildEffectiveTokensRateLimitErrorContext(hasEffectiveTokensRateLimitEr
};
const usageLine = effectiveTokens ? `\n- Effective tokens used: \`${formatEffectiveTokensForMessage(effectiveTokens)}\`` : "";
const budgetLine = maxEffectiveTokens ? `\n- Configured ET budget: \`${formatEffectiveTokensForMessage(maxEffectiveTokens)}\`` : "";
- const runLine = runUrl ? `\n- Run: ${runUrl}` : "";
+ const runLine = runUrl ? `\n- Run: [${runUrl}](${runUrl})` : "";
const etTableSection = buildETComputationTable(effectiveTokens, readTokenUsageMarkdown());
+ const templateName = "effective_tokens_rate_limit_error.md";
+ let templatePath = "";
+ try {
+ templatePath = getPromptPath(templateName);
+ } catch (error) {
+ throw new Error(`failed to resolve template path for ${templateName} (${getErrorMessage(error)}); ` + "ensure RUNNER_TEMP or GH_AW_PROMPTS_DIR is set and the template file exists");
+ }
- const etSpecLink = "https://github.github.com/gh-aw/reference/effective-tokens-specification/";
- const tokenOptLink = "https://github.com/github/gh-aw/blob/main/.github/aw/token-optimization.md";
-
- return (
- `\n**⛔ Effective Token Budget Exhausted**: The run failed due to effective-token budget/rate-limit enforcement in the API proxy. [What are effective tokens?](${etSpecLink})${usageLine}${budgetLine}${runLine}\n\n` +
- etTableSection +
- `You can tune this limit with \`max-effective-tokens\` in workflow frontmatter. To reduce token consumption, review the [token optimization guide](${tokenOptLink}).\n`
- );
+ try {
+ return (
+ "\n" +
+ renderTemplateFromFile(templatePath, {
+ et_spec_link: "https://github.github.com/gh-aw/reference/effective-tokens-specification/",
+ token_opt_link: "https://github.com/github/gh-aw/blob/main/.github/aw/token-optimization.md",
+ usage_line: usageLine,
+ budget_line: budgetLine,
+ run_line: runLine,
+ et_table_section: etTableSection,
+ })
+ );
+ } catch (error) {
+ throw new Error(`failed to render template at ${templatePath}: ${getErrorMessage(error)}; ` + "verify template syntax and required placeholders: " + "et_spec_link, token_opt_link, usage_line, budget_line, run_line, et_table_section");
+ }
}
/**
diff --git a/actions/setup/js/handle_agent_failure.test.cjs b/actions/setup/js/handle_agent_failure.test.cjs
index 85088c9193e..9c5bdc4ae82 100644
--- a/actions/setup/js/handle_agent_failure.test.cjs
+++ b/actions/setup/js/handle_agent_failure.test.cjs
@@ -2007,8 +2007,29 @@ describe("handle_agent_failure", () => {
describe("buildEffectiveTokensRateLimitErrorContext", () => {
let buildEffectiveTokensRateLimitErrorContext;
+ const fs = require("fs");
+ const os = require("os");
+ const path = require("path");
+ let tmpDir;
beforeEach(() => {
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "gh-aw-test-et-error-context-"));
+ const promptsDir = path.join(tmpDir, "gh-aw", "prompts");
+ fs.mkdirSync(promptsDir, { recursive: true });
+ fs.writeFileSync(
+ path.join(promptsDir, "effective_tokens_rate_limit_error.md"),
+ "**⛔ Effective Token Budget Exhausted**: The run failed due to effective-token budget/rate-limit enforcement in the API proxy.\n\n" +
+ "\n" +
+ "Why this happened and how to optimize
\n\n" +
+ "- Learn about [effective tokens]({et_spec_link}).\n" +
+ "{usage_line}{budget_line}{run_line}\n" +
+ "You can tune this limit with `max-effective-tokens` in workflow frontmatter.\n\n" +
+ "{et_table_section}\n" +
+ "- To optimize this workflow, follow the [token optimization instructions]({token_opt_link}).\n" +
+ " \n"
+ );
+ process.env.RUNNER_TEMP = tmpDir;
+
global.core = { info: vi.fn(), warning: vi.fn(), error: vi.fn(), debug: vi.fn(), setOutput: vi.fn(), setFailed: vi.fn() };
global.github = {};
global.context = { repo: { owner: "owner", repo: "repo" } };
@@ -2020,6 +2041,10 @@ describe("handle_agent_failure", () => {
delete global.core;
delete global.github;
delete global.context;
+ delete process.env.RUNNER_TEMP;
+ if (tmpDir && fs.existsSync(tmpDir)) {
+ fs.rmSync(tmpDir, { recursive: true, force: true });
+ }
});
it("formats effective token values in friendly compact form", () => {
@@ -2056,6 +2081,17 @@ describe("handle_agent_failure", () => {
expect(result).toContain("https://github.com/github/gh-aw/blob/main/.github/aw/token-optimization.md");
});
+ it("formats the run URL as a markdown link", () => {
+ const result = buildEffectiveTokensRateLimitErrorContext(true, "10000000", "25000000", "https://example.com/run/1");
+ expect(result).toContain("- Run: [https://example.com/run/1](https://example.com/run/1)");
+ });
+
+ it("wraps ET guidance in a collapsible details section", () => {
+ const result = buildEffectiveTokensRateLimitErrorContext(true, "10000000", "25000000", "https://example.com/run/1");
+ expect(result).toContain("Why this happened and how to optimize");
+ expect(result).toContain("token optimization instructions");
+ });
+
it("includes a collapsible details section for ET computation", () => {
const result = buildEffectiveTokensRateLimitErrorContext(true, "10000000", "25000000", "https://example.com/run/1");
expect(result).toContain("");
diff --git a/actions/setup/md/effective_tokens_rate_limit_error.md b/actions/setup/md/effective_tokens_rate_limit_error.md
new file mode 100644
index 00000000000..eba38e79d7f
--- /dev/null
+++ b/actions/setup/md/effective_tokens_rate_limit_error.md
@@ -0,0 +1,12 @@
+**⛔ Effective Token Budget Exhausted**: The run failed due to effective-token budget/rate-limit enforcement in the API proxy.
+
+
+Why this happened and how to optimize
+
+- Learn about [effective tokens]({et_spec_link}).
+{usage_line}{budget_line}{run_line}
+You can tune this limit with `max-effective-tokens` in workflow frontmatter.
+
+{et_table_section}
+- To optimize this workflow, follow the [token optimization instructions]({token_opt_link}).
+