Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions actions/setup/js/handle_agent_failure.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -608,16 +608,9 @@ function buildTimeoutContext(isTimedOut, timeoutMinutes) {
const currentMinutes = parseInt(timeoutMinutes || "20", 10);
const suggestedMinutes = currentMinutes + 10;

let ctx = "\n**⏱️ Agent Timed Out**: The agent job exceeded the maximum allowed execution time";
ctx += ` (${currentMinutes} minutes).`;
ctx += "\n\nTo increase the timeout, add or update the `timeout-minutes` setting in your workflow's frontmatter:\n\n";
ctx += "```yaml\n";
ctx += "---\n";
ctx += `timeout-minutes: ${suggestedMinutes}\n`;
ctx += "---\n";
ctx += "```\n\n";

return ctx;
const templatePath = `${process.env.RUNNER_TEMP}/gh-aw/prompts/agent_timeout.md`;
const template = fs.readFileSync(templatePath, "utf8");
return "\n" + renderTemplate(template, { current_minutes: currentMinutes, suggested_minutes: suggestedMinutes });
}

Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buildTimeoutContext() behavior changed to load and render agent_timeout.md, but actions/setup/js/handle_agent_failure.test.cjs currently doesn’t cover this path (it covers other context builders). To prevent regressions (missing template, placeholder mismatch, wrong path), add a unit test that stubs fs.readFileSync for agent_timeout.md and asserts the rendered output includes the expected current_minutes / suggested_minutes values. Since buildTimeoutContext isn’t exported today, consider exporting it (non-breaking) similar to the other context builders so it can be tested directly.

Suggested change
module.exports.buildTimeoutContext = buildTimeoutContext;

Copilot uses AI. Check for mistakes.
/**
Expand Down Expand Up @@ -1169,4 +1162,4 @@ async function main() {
}
}

module.exports = { main, buildCodePushFailureContext, buildPushRepoMemoryFailureContext, buildAppTokenMintingFailedContext, buildLockdownCheckFailedContext };
module.exports = { main, buildCodePushFailureContext, buildPushRepoMemoryFailureContext, buildAppTokenMintingFailedContext, buildLockdownCheckFailedContext, buildTimeoutContext };
53 changes: 53 additions & 0 deletions actions/setup/js/handle_agent_failure.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -389,4 +389,57 @@ describe("handle_agent_failure", () => {
expect(result).toContain("gh aw compile --strict");
});
});

// ──────────────────────────────────────────────────────
// buildTimeoutContext
// ──────────────────────────────────────────────────────

describe("buildTimeoutContext", () => {
let buildTimeoutContext;
const fs = require("fs");
const path = require("path");
const templateContent = fs.readFileSync(path.join(__dirname, "../md/agent_timeout.md"), "utf8");
const originalReadFileSync = fs.readFileSync.bind(fs);

beforeEach(() => {
vi.resetModules();
// Stub readFileSync so the runtime path resolves to the source-tree template
fs.readFileSync = (filePath, encoding) => {
if (typeof filePath === "string" && filePath.includes("agent_timeout.md")) {
return templateContent;
}
return originalReadFileSync(filePath, encoding);
};
({ buildTimeoutContext } = require("./handle_agent_failure.cjs"));
});

afterEach(() => {
fs.readFileSync = originalReadFileSync;
});

it("returns empty string when not timed out", () => {
expect(buildTimeoutContext(false, "20")).toBe("");
expect(buildTimeoutContext(false, "")).toBe("");
});

it("returns formatted error message when timed out", () => {
const result = buildTimeoutContext(true, "20");
expect(result).toContain("Agent Timed Out");
expect(result).toContain("20");
expect(result).toContain("30");
expect(result).toContain("timeout-minutes");
});

it("uses default of 20 minutes when timeoutMinutes is empty", () => {
const result = buildTimeoutContext(true, "");
expect(result).toContain("20");
expect(result).toContain("30");
});

it("suggests current + 10 minutes", () => {
const result = buildTimeoutContext(true, "45");
expect(result).toContain("45");
expect(result).toContain("55");
});
});
});
9 changes: 9 additions & 0 deletions actions/setup/md/agent_timeout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
**⏱️ Agent Timed Out**: The agent job exceeded the maximum allowed execution time ({current_minutes} minutes).

To increase the timeout, add or update the `timeout-minutes` setting in your workflow's frontmatter:

```yaml
---
timeout-minutes: {suggested_minutes}
---
```
Loading