MCPcopy Create free account
hub / github.com/github/gh-aw / buildEngineFailureContext

Function buildEngineFailureContext

actions/setup/js/handle_agent_failure.cjs:2294–2493  ·  view source on GitHub ↗

* Extract terminal error messages from agent-stdio.log to surface engine failures. * First tries to match known error patterns (ERROR:, Error:, Fatal:, panic:, Reconnecting...). * Falls back to the last non-empty lines of the log when no patterns match, so that * even timeout or unexpected-termin

(options = {})

Source from the content-addressed store, hash-verified

2292 * @returns {string} Formatted context string, or empty string if no engine failure found
2293 */
2294function buildEngineFailureContext(options = {}) {
2295 const suppressEngineRateLimit429 = options.suppressEngineRateLimit429 === true;
2296 // Derive agent-stdio.log path from the agent output file path (same directory)
2297 const agentOutputFile = process.env.GH_AW_AGENT_OUTPUT;
2298 const stdioLogPath = agentOutputFile ? path.join(path.dirname(agentOutputFile), "agent-stdio.log") : "/tmp/gh-aw/agent-stdio.log";
2299
2300 // Include engine ID in failure messages when available (e.g. "copilot", "claude", "codex")
2301 const engineId = process.env.GH_AW_ENGINE_ID || "";
2302 const engineLabel = engineId ? ` \`${engineId}\`` : " AI";
2303
2304 try {
2305 if (!fs.existsSync(stdioLogPath)) {
2306 core.info(`agent-stdio.log not found at ${stdioLogPath}, skipping engine failure context`);
2307 return "";
2308 }
2309
2310 const logContent = fs.readFileSync(stdioLogPath, "utf8");
2311 if (!logContent.trim()) {
2312 return "";
2313 }
2314
2315 const lines = logContent.split("\n");
2316
2317 // Guard: if the agent completed successfully (terminal_reason: "completed"), the job
2318 // failure was caused by something other than the agent itself (e.g., post-processing
2319 // or infrastructure). Suppress the engine failure context to avoid false positive labels.
2320 // Use the already-loaded logContent directly to avoid a redundant file read.
2321 if (/"terminal_reason"[ ]?:[ ]?"completed"/.test(logContent)) {
2322 core.info("Agent completed successfully (terminal_reason: completed) — suppressing engine failure context");
2323 return "";
2324 }
2325
2326 if (!suppressEngineRateLimit429 && (hasEngineRateLimit429Signal(logContent) || hasEngineRateLimit429InOTELMirror())) {
2327 core.info("Detected engine HTTP 429/rate-limit signal — using dedicated context message");
2328 return buildEngineRateLimit429Context(engineLabel);
2329 }
2330
2331 if (hasEngineMaxRunsExceededSignal(logContent)) {
2332 core.info("Detected engine max-runs guardrail signal — using dedicated context message");
2333 return buildEngineMaxRunsExceededContext(engineLabel);
2334 }
2335
2336 const errorMessages = new Set();
2337
2338 for (const line of lines) {
2339 // Codex / generic CLI: "ERROR: <message>" at the start of a line
2340 const errorPrefixMatch = line.match(/^ERROR:\s*(.+)$/);
2341 if (errorPrefixMatch) {
2342 errorMessages.add(errorPrefixMatch[1].trim());
2343 continue;
2344 }
2345
2346 // Node.js / generic: "Error: <message>" at the start of a line
2347 const errorCapMatch = line.match(/^Error:\s*(.+)$/);
2348 if (errorCapMatch) {
2349 errorMessages.add(errorCapMatch[1].trim());
2350 continue;
2351 }

Callers 2

mainFunction · 0.85

Calls 11

getPromptPathFunction · 0.85
renderTemplateFromFileFunction · 0.85
detectAWFStartupSignalsFunction · 0.85
buildWarningAlertLineFunction · 0.85
getErrorMessageFunction · 0.70
addMethod · 0.45

Tested by

no test coverage detected