diff --git a/actions/setup/js/check_daily_aic_workflow_guardrail.cjs b/actions/setup/js/check_daily_aic_workflow_guardrail.cjs index a61a5332309..a9dee892c27 100644 --- a/actions/setup/js/check_daily_aic_workflow_guardrail.cjs +++ b/actions/setup/js/check_daily_aic_workflow_guardrail.cjs @@ -17,6 +17,7 @@ const RATE_LIMIT_RESERVE = 100; const REQUEST_OVERHEAD_BUDGET = MAX_WORKFLOW_RUN_PAGES + 4; const ESTIMATED_API_OPERATIONS_PER_RUN = 2; const INTEGER_FORMATTER = new Intl.NumberFormat("en-US"); +const DAILY_AIC_GUARDRAIL_DOCS_URL = "https://github.github.com/gh-aw/reference/cost-management/"; /** * @returns {Promise} @@ -55,6 +56,15 @@ function logDailyGuardrail(message, details) { core.info(formatDailyGuardrailLogMessage(message, details)); } +/** + * @param {unknown} error + * @returns {boolean} + */ +function isMissingArtifactDownloadError(error) { + const message = getErrorMessage(error).toLowerCase(); + return message.includes("unable to download artifact") && message.includes("artifact not found"); +} + /** * @returns {boolean} */ @@ -285,16 +295,16 @@ async function appendDailyAICSummary(workflowName, actorLogin, threshold, counte * * Error handling: all GitHub API interactions after the initial guard checks are wrapped * in a top-level try-catch. Any unexpected error (network failure, permission error, etc.) - * is logged as a warning and the function returns cleanly with `daily_effective_workflow_exceeded` + * is logged as a warning and the function returns cleanly with `daily_ai_credits_exceeded` * left at its default value of `"false"`. This design ensures the step never fails the * activation job — a guardrail error results in a safe bypass (agent allowed to run) rather * than a confusing workflow failure that blocks the agent entirely. */ async function main() { - core.setOutput("daily_effective_workflow_exceeded", "false"); - core.setOutput("daily_effective_workflow_total_effective_tokens", ""); - core.setOutput("daily_effective_workflow_total_ai_credits", ""); - core.setOutput("daily_effective_workflow_threshold", ""); + core.setOutput("daily_ai_credits_exceeded", "false"); + core.setOutput("daily_ai_credits_total_effective_tokens", ""); + core.setOutput("daily_ai_credits_total_ai_credits", ""); + core.setOutput("daily_ai_credits_threshold", ""); const threshold = parsePositiveCompactNumber(process.env.GH_AW_MAX_DAILY_AI_CREDITS); if (threshold <= 0) { return; @@ -312,7 +322,7 @@ async function main() { // Wrap all GitHub API interactions in a top-level try-catch so that transient API // errors, permission failures, or unexpected exceptions never fail the activation - // job step. A failure here would leave `daily_effective_workflow_exceeded` at its + // job step. A failure here would leave `daily_ai_credits_exceeded` at its // default "false" value, which is the safe fallback: the agent is allowed to run // and the guardrail is effectively bypassed for this invocation rather than causing // a confusing workflow failure. @@ -445,13 +455,19 @@ async function main() { countedRunIds: countedRuns.map(item => item.id), }); } catch (error) { + if (isMissingArtifactDownloadError(error)) { + logDailyGuardrail("Skipping run because usage artifact was not found at download time", { + runId: run.id, + }); + continue; + } core.warning(`Failed to inspect token usage for run ${run.id}: ${getErrorMessage(error)}`); } } - core.setOutput("daily_effective_workflow_total_effective_tokens", String(totalAIC)); - core.setOutput("daily_effective_workflow_total_ai_credits", String(totalAIC)); - core.setOutput("daily_effective_workflow_threshold", String(threshold)); + core.setOutput("daily_ai_credits_total_effective_tokens", String(totalAIC)); + core.setOutput("daily_ai_credits_total_ai_credits", String(totalAIC)); + core.setOutput("daily_ai_credits_threshold", String(threshold)); /** @type {{candidateRunsCount:number,inspectedRunsCount:number,truncatedByRateLimit:boolean}} */ const summaryMeta = { @@ -490,9 +506,11 @@ async function main() { return; } - core.setOutput("daily_effective_workflow_exceeded", "true"); + core.setOutput("daily_ai_credits_exceeded", "true"); await appendDailyAICSummary(workflowName, actorLogin, threshold, countedRuns, rateLimit, summaryMeta); - core.warning(`Daily workflow AIC guardrail exceeded for ${workflowName}: ${totalAIC}/${threshold}.`); + const exceededMessage = `Daily workflow AIC guardrail exceeded for ${workflowName}: ${totalAIC}/${threshold}. See ${DAILY_AIC_GUARDRAIL_DOCS_URL}`; + core.error(exceededMessage); + core.setFailed(exceededMessage); } catch (error) { // Treat any unexpected error as a non-blocking skip so the step never fails the // activation job. The output stays at the default "false", allowing the agent to @@ -505,6 +523,7 @@ module.exports = { main, shouldSkipDailyAICGuardrail, matchesGuardrailArtifactName, + isMissingArtifactDownloadError, findJSONLFiles, sumAICFromUsageJSONLFiles, calculateDailyAICStats, diff --git a/actions/setup/js/check_daily_aic_workflow_guardrail.test.cjs b/actions/setup/js/check_daily_aic_workflow_guardrail.test.cjs index 4678888a504..27dc49d8bcc 100644 --- a/actions/setup/js/check_daily_aic_workflow_guardrail.test.cjs +++ b/actions/setup/js/check_daily_aic_workflow_guardrail.test.cjs @@ -42,6 +42,11 @@ describe("check_daily_aic_workflow_guardrail", () => { expect(exports.matchesGuardrailArtifactName("activation")).toBe(false); }); + it("recognizes artifact-not-found download errors as non-actionable", () => { + expect(exports.isMissingArtifactDownloadError(new Error("Unable to download artifact(s): Artifact not found for name: usage"))).toBe(true); + expect(exports.isMissingArtifactDownloadError(new Error("network timeout"))).toBe(false); + }); + it("sums AI Credits across multiple JSONL files and usage attributes", () => { const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "daily-guardrail-token-usage-")); const nestedDir = path.join(tmpDir, "nested"); @@ -173,7 +178,7 @@ describe("check_daily_aic_workflow_guardrail", () => { it("main() does not fail the step when GitHub API calls throw", async () => { // Simulate a scenario where the GitHub API throws during workflow run lookup. - // The step should catch the error and NOT rethrow it, keeping daily_effective_workflow_exceeded at "false". + // The step should catch the error and NOT rethrow it, keeping daily_ai_credits_exceeded at "false". const coreOutputs = {}; const coreWarnings = []; const mockCore = { @@ -219,7 +224,7 @@ describe("check_daily_aic_workflow_guardrail", () => { // Should resolve without throwing even though the API calls throw await expect(exports.main()).resolves.toBeUndefined(); // The default "false" output must be set - expect(coreOutputs["daily_effective_workflow_exceeded"]).toBe("false"); + expect(coreOutputs["daily_ai_credits_exceeded"]).toBe("false"); // A warning must be emitted describing the error expect(coreWarnings.some(w => /unexpected error.*skipped/i.test(w))).toBe(true); } finally { @@ -323,4 +328,110 @@ describe("check_daily_aic_workflow_guardrail", () => { delete process.env.GH_AW_GITHUB_TOKEN; } }); + + it("main() marks the step as failed with docs link when daily guardrail is exceeded", async () => { + const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "daily-guardrail-download-")); + fs.writeFileSync(path.join(tmpDir, "usage.jsonl"), JSON.stringify({ aic: 50 }), "utf8"); + + vi.resetModules(); + vi.doMock("@actions/artifact", () => ({ + DefaultArtifactClient: class { + async listArtifacts() { + return { artifacts: [{ id: 1, name: "usage" }] }; + } + async downloadArtifact() { + return { downloadPath: tmpDir }; + } + }, + })); + + const mod = await import("./check_daily_aic_workflow_guardrail.cjs"); + const guardrail = mod.default || mod; + + const coreOutputs = {}; + const coreErrors = []; + const coreFailures = []; + const mockCore = { + setOutput: (key, value) => { + coreOutputs[key] = value; + }, + info: () => {}, + warning: () => {}, + error: msg => coreErrors.push(msg), + setFailed: msg => coreFailures.push(msg), + summary: { + addDetails: function () { + return this; + }, + write: async () => {}, + }, + }; + + const mockGithub = { + rest: { + rateLimit: { + get: async () => ({ + data: { + resources: { + core: { limit: 5000, remaining: 4995, used: 5, reset: Math.floor(Date.now() / 1000) + 3600 }, + }, + }, + headers: {}, + }), + }, + actions: { + getWorkflowRun: async () => ({ + data: { + workflow_id: 777, + actor: { login: "octocat" }, + triggering_actor: { login: "octocat" }, + }, + headers: {}, + }), + listWorkflowRuns: async () => ({ + data: { + workflow_runs: [ + { + id: 1234, + html_url: "https://example.test/runs/1234", + created_at: new Date().toISOString(), + conclusion: "success", + }, + ], + }, + headers: {}, + }), + }, + }, + }; + + const mockContext = { + repo: { owner: "test-owner", repo: "test-repo" }, + runId: 99, + }; + + global.core = mockCore; + global.github = mockGithub; + global.context = mockContext; + + process.env.GH_AW_WORKFLOW_NAME = "N+1 Crusher"; + process.env.GH_AW_MAX_DAILY_AI_CREDITS = "10"; + process.env.GH_AW_GITHUB_TOKEN = "fake-token"; + + try { + await expect(guardrail.main()).resolves.toBeUndefined(); + expect(coreOutputs["daily_ai_credits_exceeded"]).toBe("true"); + expect(coreErrors[0]).toContain("Daily workflow AIC guardrail exceeded for N+1 Crusher: 50/10."); + expect(coreErrors[0]).toContain("https://github.github.com/gh-aw/reference/cost-management/"); + expect(coreFailures[0]).toBe(coreErrors[0]); + } finally { + vi.doUnmock("@actions/artifact"); + delete global.core; + delete global.github; + delete global.context; + delete process.env.GH_AW_WORKFLOW_NAME; + delete process.env.GH_AW_MAX_DAILY_AI_CREDITS; + delete process.env.GH_AW_GITHUB_TOKEN; + } + }); }); diff --git a/actions/setup/js/handle_agent_failure.cjs b/actions/setup/js/handle_agent_failure.cjs index c37ddcf4224..7c059abc8bb 100644 --- a/actions/setup/js/handle_agent_failure.cjs +++ b/actions/setup/js/handle_agent_failure.cjs @@ -199,7 +199,7 @@ function buildFailureMatchCategories(options) { if (options.hasAppTokenMintingFailed) categories.push("app_token_minting_failed"); if (options.hasLockdownCheckFailed) categories.push("lockdown_check_failed"); if (options.hasStaleLockFileFailed) categories.push("stale_lock_file_failed"); - if (options.hasDailyAICExceeded) categories.push("daily_effective_workflow_exceeded"); + if (options.hasDailyAICExceeded) categories.push("daily_ai_credits_exceeded"); if (options.agentConclusion === "failure" && !options.isTimedOut) { categories.push("agent_failure"); @@ -2323,9 +2323,9 @@ async function main() { // stored in the compiled .lock.yml no longer matches the source .md file. // The agent is skipped in this case; the conclusion job runs to surface remediation guidance. const hasStaleLockFileFailed = process.env.GH_AW_STALE_LOCK_FILE_FAILED === "true"; - const hasDailyAICExceeded = process.env.GH_AW_DAILY_EFFECTIVE_WORKFLOW_EXCEEDED === "true"; - const dailyAICTotal = process.env.GH_AW_DAILY_EFFECTIVE_WORKFLOW_TOTAL_EFFECTIVE_TOKENS || ""; - const dailyAICThreshold = process.env.GH_AW_DAILY_EFFECTIVE_WORKFLOW_THRESHOLD || ""; + const hasDailyAICExceeded = process.env.GH_AW_DAILY_AI_CREDITS_EXCEEDED === "true"; + const dailyAICTotal = process.env.GH_AW_DAILY_AI_CREDITS_TOTAL_EFFECTIVE_TOKENS || ""; + const dailyAICThreshold = process.env.GH_AW_DAILY_AI_CREDITS_THRESHOLD || ""; // Cache-memory availability flag — set when cache-memory is configured for the workflow. // Used to detect cache-miss misconfigurations reported by the agent. const cacheMemoryEnabled = process.env.GH_AW_CACHE_MEMORY_ENABLED === "true"; @@ -2827,7 +2827,7 @@ async function main() { app_token_minting_failed_context: appTokenMintingFailedContext, lockdown_check_failed_context: lockdownCheckFailedContext, stale_lock_file_failed_context: staleLockFileFailedContext, - daily_effective_workflow_exceeded_context: dailyAICExceededContext, + daily_ai_credits_exceeded_context: dailyAICExceededContext, }; // Render the comment template @@ -3054,7 +3054,7 @@ async function main() { app_token_minting_failed_context: appTokenMintingFailedContext, lockdown_check_failed_context: lockdownCheckFailedContext, stale_lock_file_failed_context: staleLockFileFailedContext, - daily_effective_workflow_exceeded_context: dailyAICExceededContext, + daily_ai_credits_exceeded_context: dailyAICExceededContext, }; // Render the issue template diff --git a/actions/setup/md/agent_failure_comment.md b/actions/setup/md/agent_failure_comment.md index 9ca9cc477d8..3ef927bc868 100644 --- a/actions/setup/md/agent_failure_comment.md +++ b/actions/setup/md/agent_failure_comment.md @@ -1,3 +1,3 @@ Agent job [{run_id}]({run_url}) failed. -{secret_verification_context}{credential_auth_error_context}{inference_access_error_context}{mcp_policy_error_context}{model_not_supported_error_context}{ai_credits_rate_limit_error_context}{app_token_minting_failed_context}{lockdown_check_failed_context}{stale_lock_file_failed_context}{daily_effective_workflow_exceeded_context}{assignment_errors_context}{assign_copilot_failure_context}{create_discussion_errors_context}{code_push_failure_context}{repo_memory_validation_context}{push_repo_memory_failure_context}{missing_data_context}{missing_tool_context}{permission_denied_context}{tool_denials_exceeded_context}{report_incomplete_context}{missing_safe_outputs_context}{engine_failure_context}{timeout_context}{fork_context} +{secret_verification_context}{credential_auth_error_context}{inference_access_error_context}{mcp_policy_error_context}{model_not_supported_error_context}{ai_credits_rate_limit_error_context}{app_token_minting_failed_context}{lockdown_check_failed_context}{stale_lock_file_failed_context}{daily_ai_credits_exceeded_context}{assignment_errors_context}{assign_copilot_failure_context}{create_discussion_errors_context}{code_push_failure_context}{repo_memory_validation_context}{push_repo_memory_failure_context}{missing_data_context}{missing_tool_context}{permission_denied_context}{tool_denials_exceeded_context}{report_incomplete_context}{missing_safe_outputs_context}{engine_failure_context}{timeout_context}{fork_context} diff --git a/actions/setup/md/agent_failure_issue.md b/actions/setup/md/agent_failure_issue.md index c3968011585..842fc64602e 100644 --- a/actions/setup/md/agent_failure_issue.md +++ b/actions/setup/md/agent_failure_issue.md @@ -4,7 +4,7 @@ **Branch:** {branch} **Run:** {run_url}{pull_request_info} -{secret_verification_context}{credential_auth_error_context}{inference_access_error_context}{mcp_policy_error_context}{model_not_supported_error_context}{ai_credits_rate_limit_error_context}{app_token_minting_failed_context}{lockdown_check_failed_context}{stale_lock_file_failed_context}{daily_effective_workflow_exceeded_context}{assignment_errors_context}{assign_copilot_failure_context}{create_discussion_errors_context}{code_push_failure_context}{repo_memory_validation_context}{push_repo_memory_failure_context}{missing_data_context}{missing_tool_context}{permission_denied_context}{tool_denials_exceeded_context}{report_incomplete_context}{missing_safe_outputs_context}{engine_failure_context}{timeout_context}{fork_context} +{secret_verification_context}{credential_auth_error_context}{inference_access_error_context}{mcp_policy_error_context}{model_not_supported_error_context}{ai_credits_rate_limit_error_context}{app_token_minting_failed_context}{lockdown_check_failed_context}{stale_lock_file_failed_context}{daily_ai_credits_exceeded_context}{assignment_errors_context}{assign_copilot_failure_context}{create_discussion_errors_context}{code_push_failure_context}{repo_memory_validation_context}{push_repo_memory_failure_context}{missing_data_context}{missing_tool_context}{permission_denied_context}{tool_denials_exceeded_context}{report_incomplete_context}{missing_safe_outputs_context}{engine_failure_context}{timeout_context}{fork_context} ### Action Required diff --git a/actions/setup/md/daily_workflow_aic_exceeded.md b/actions/setup/md/daily_workflow_aic_exceeded.md index 325ccb98113..00f597239b1 100644 --- a/actions/setup/md/daily_workflow_aic_exceeded.md +++ b/actions/setup/md/daily_workflow_aic_exceeded.md @@ -40,7 +40,7 @@ Commit and push the updated `.lock.yml` file. The `max-daily-ai-credits` frontmatter option sets a per-workflow spending cap measured in *AI Credits* across the 24-hour window before the current run. The cap is scoped to the repository and workflow — it aggregates usage across all runs of this workflow regardless of who triggered them. -When the aggregated AI Credits usage across all completed runs of this workflow in the last 24 hours exceeds the threshold, the activation job sets the `daily_effective_workflow_exceeded` output to `true` and the agent job is skipped for that run. The conclusion job still runs and creates this report. +When the aggregated AI Credits usage across all completed runs of this workflow in the last 24 hours exceeds the threshold, the activation job sets the `daily_ai_credits_exceeded` output to `true` and the agent job is skipped for that run. The conclusion job still runs and creates this report. The guardrail is evaluated at activation time, not retrospectively, so a single very large run that pushes usage over the threshold only blocks *subsequent* runs in the same window — it does not cancel a run that is already in progress. diff --git a/pkg/workflow/compiler_activation_job_builder.go b/pkg/workflow/compiler_activation_job_builder.go index 9abd86e8d5b..6f1b8969a99 100644 --- a/pkg/workflow/compiler_activation_job_builder.go +++ b/pkg/workflow/compiler_activation_job_builder.go @@ -197,9 +197,9 @@ func (c *Compiler) addActivationFeedbackAndValidationSteps(ctx *activationJobBui c.maybeAddActivationAppTokenMintStep(ctx) if hasMaxDailyAICGuardrail(data) { ctx.steps = append(ctx.steps, c.buildActivationDailyAICGuardrailStep(data)...) - ctx.outputs["daily_effective_workflow_exceeded"] = "${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_exceeded == 'true' }}" - ctx.outputs["daily_effective_workflow_total_effective_tokens"] = "${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_total_effective_tokens || '' }}" - ctx.outputs["daily_effective_workflow_threshold"] = "${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_threshold || '' }}" + ctx.outputs["daily_ai_credits_exceeded"] = "${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_exceeded == 'true' }}" + ctx.outputs["daily_ai_credits_total_effective_tokens"] = "${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_total_effective_tokens || '' }}" + ctx.outputs["daily_ai_credits_threshold"] = "${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_threshold || '' }}" } c.addActivationReactionStep(ctx) c.addActivationSecretValidationStep(ctx) diff --git a/pkg/workflow/compiler_main_job.go b/pkg/workflow/compiler_main_job.go index 13f7248332e..aabdbb5b3db 100644 --- a/pkg/workflow/compiler_main_job.go +++ b/pkg/workflow/compiler_main_job.go @@ -66,7 +66,7 @@ func (c *Compiler) buildMainJob(data *WorkflowData, activationJobCreated bool) ( // we keep the condition on the agent job } if activationJobCreated && hasMaxDailyAICGuardrail(data) { - guard := &ExpressionNode{Expression: fmt.Sprintf("needs.%s.outputs.daily_effective_workflow_exceeded != 'true'", constants.ActivationJobName)} + guard := &ExpressionNode{Expression: fmt.Sprintf("needs.%s.outputs.daily_ai_credits_exceeded != 'true'", constants.ActivationJobName)} if jobCondition == "" { jobCondition = RenderCondition(guard) } else { diff --git a/pkg/workflow/daily_aic_workflow_guardrail_test.go b/pkg/workflow/daily_aic_workflow_guardrail_test.go index 6d505a49c04..8605719cfe1 100644 --- a/pkg/workflow/daily_aic_workflow_guardrail_test.go +++ b/pkg/workflow/daily_aic_workflow_guardrail_test.go @@ -133,22 +133,22 @@ Guardrail test workflow` if !strings.Contains(lockStr, `GH_AW_MAX_DAILY_AI_CREDITS: "100000000"`) { t.Fatal("expected activation job env to include normalized guardrail threshold") } - if !strings.Contains(lockStr, "daily_effective_workflow_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_exceeded == 'true' }}") { - t.Fatal("expected activation job to expose daily_effective_workflow_exceeded output") + if !strings.Contains(lockStr, "daily_ai_credits_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_exceeded == 'true' }}") { + t.Fatal("expected activation job to expose daily_ai_credits_exceeded output") } - if !strings.Contains(lockStr, "daily_effective_workflow_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_total_effective_tokens || '' }}") { + if !strings.Contains(lockStr, "daily_ai_credits_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_total_effective_tokens || '' }}") { t.Fatal("expected activation job to expose the aggregated ET total output") } - if strings.Contains(lockStr, "daily_effective_workflow_issue_url") { + if strings.Contains(lockStr, "daily_ai_credits_issue_url") { t.Fatal("expected activation job to avoid surfacing a separate daily workflow ET issue URL") } - if !strings.Contains(lockStr, "if: needs.activation.outputs.daily_effective_workflow_exceeded != 'true'") { + if !strings.Contains(lockStr, "if: needs.activation.outputs.daily_ai_credits_exceeded != 'true'") { t.Fatal("expected the agent job to be skipped when the daily workflow ET guardrail is exceeded") } - if !strings.Contains(lockStr, "GH_AW_DAILY_EFFECTIVE_WORKFLOW_EXCEEDED: ${{ needs.activation.outputs.daily_effective_workflow_exceeded }}") { + if !strings.Contains(lockStr, "GH_AW_DAILY_AI_CREDITS_EXCEEDED: ${{ needs.activation.outputs.daily_ai_credits_exceeded }}") { t.Fatal("expected the conclusion job to receive the daily workflow ET guardrail output") } - if !strings.Contains(lockStr, "needs.activation.outputs.daily_effective_workflow_exceeded == 'true'") { + if !strings.Contains(lockStr, "needs.activation.outputs.daily_ai_credits_exceeded == 'true'") { t.Fatal("expected the conclusion job condition to allow activation guardrail failures through") } if !strings.Contains(activationSection, "actions: read") { @@ -199,7 +199,7 @@ No daily guardrail` if !strings.Contains(lockStr, "if: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }}") { t.Fatal("expected emitted daily ET guardrail step to be dynamically skipped when threshold is unset") } - if !strings.Contains(lockStr, "daily_effective_workflow_exceeded") { + if !strings.Contains(lockStr, "daily_ai_credits_exceeded") { t.Fatal("expected workflows to continue wiring daily ET outputs when guardrail step is emitted") } if !strings.Contains(lockStr, "safe-output-artifact-client: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }}") { diff --git a/pkg/workflow/notify_comment.go b/pkg/workflow/notify_comment.go index 854d58f5222..0839bc437c4 100644 --- a/pkg/workflow/notify_comment.go +++ b/pkg/workflow/notify_comment.go @@ -356,9 +356,9 @@ func (c *Compiler) buildConclusionJob(data *WorkflowData, mainJobName string, sa // expression evaluates to "" which handle_agent_failure treats as "not failed". agentFailureEnvVars = append(agentFailureEnvVars, fmt.Sprintf(" GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.%s.outputs.stale_lock_file_failed }}\n", string(constants.ActivationJobName))) if hasMaxDailyAICGuardrail(data) { - agentFailureEnvVars = append(agentFailureEnvVars, fmt.Sprintf(" GH_AW_DAILY_EFFECTIVE_WORKFLOW_EXCEEDED: ${{ needs.%s.outputs.daily_effective_workflow_exceeded }}\n", string(constants.ActivationJobName))) - agentFailureEnvVars = append(agentFailureEnvVars, fmt.Sprintf(" GH_AW_DAILY_EFFECTIVE_WORKFLOW_TOTAL_EFFECTIVE_TOKENS: ${{ needs.%s.outputs.daily_effective_workflow_total_effective_tokens }}\n", string(constants.ActivationJobName))) - agentFailureEnvVars = append(agentFailureEnvVars, fmt.Sprintf(" GH_AW_DAILY_EFFECTIVE_WORKFLOW_THRESHOLD: ${{ needs.%s.outputs.daily_effective_workflow_threshold }}\n", string(constants.ActivationJobName))) + agentFailureEnvVars = append(agentFailureEnvVars, fmt.Sprintf(" GH_AW_DAILY_AI_CREDITS_EXCEEDED: ${{ needs.%s.outputs.daily_ai_credits_exceeded }}\n", string(constants.ActivationJobName))) + agentFailureEnvVars = append(agentFailureEnvVars, fmt.Sprintf(" GH_AW_DAILY_AI_CREDITS_TOTAL_EFFECTIVE_TOKENS: ${{ needs.%s.outputs.daily_ai_credits_total_effective_tokens }}\n", string(constants.ActivationJobName))) + agentFailureEnvVars = append(agentFailureEnvVars, fmt.Sprintf(" GH_AW_DAILY_AI_CREDITS_THRESHOLD: ${{ needs.%s.outputs.daily_ai_credits_threshold }}\n", string(constants.ActivationJobName))) } // Pass custom messages config if present (JSON computed once above) @@ -552,7 +552,7 @@ func (c *Compiler) buildConclusionJob(data *WorkflowData, mainJobName string, sa activationGuardrailsFailed := BuildOr(lockdownCheckFailed, staleLockFileFailed) if hasMaxDailyAICGuardrail(data) { dailyAICWorkflowExceeded := BuildEquals( - BuildPropertyAccess(fmt.Sprintf("needs.%s.outputs.daily_effective_workflow_exceeded", string(constants.ActivationJobName))), + BuildPropertyAccess(fmt.Sprintf("needs.%s.outputs.daily_ai_credits_exceeded", string(constants.ActivationJobName))), BuildStringLiteral("true"), ) activationGuardrailsFailed = BuildOr(activationGuardrailsFailed, dailyAICWorkflowExceeded) diff --git a/pkg/workflow/testdata/TestWasmGolden_AllEngines/claude.golden b/pkg/workflow/testdata/TestWasmGolden_AllEngines/claude.golden index afb01f66621..66c4cc706ec 100644 --- a/pkg/workflow/testdata/TestWasmGolden_AllEngines/claude.golden +++ b/pkg/workflow/testdata/TestWasmGolden_AllEngines/claude.golden @@ -28,9 +28,9 @@ jobs: outputs: comment_id: "" comment_repo: "" - daily_effective_workflow_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_exceeded == 'true' }} - daily_effective_workflow_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_threshold || '' }} - daily_effective_workflow_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_total_effective_tokens || '' }} + daily_ai_credits_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_exceeded == 'true' }} + daily_ai_credits_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_threshold || '' }} + daily_ai_credits_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_total_effective_tokens || '' }} engine_id: ${{ steps.generate_aw_info.outputs.engine_id }} lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} model: ${{ steps.generate_aw_info.outputs.model }} @@ -283,7 +283,7 @@ jobs: agent: needs: activation - if: needs.activation.outputs.daily_effective_workflow_exceeded != 'true' + if: needs.activation.outputs.daily_ai_credits_exceeded != 'true' runs-on: ubuntu-latest permissions: contents: read diff --git a/pkg/workflow/testdata/TestWasmGolden_AllEngines/codex.golden b/pkg/workflow/testdata/TestWasmGolden_AllEngines/codex.golden index 29583cbcd81..593f1586ccb 100644 --- a/pkg/workflow/testdata/TestWasmGolden_AllEngines/codex.golden +++ b/pkg/workflow/testdata/TestWasmGolden_AllEngines/codex.golden @@ -28,9 +28,9 @@ jobs: outputs: comment_id: "" comment_repo: "" - daily_effective_workflow_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_exceeded == 'true' }} - daily_effective_workflow_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_threshold || '' }} - daily_effective_workflow_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_total_effective_tokens || '' }} + daily_ai_credits_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_exceeded == 'true' }} + daily_ai_credits_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_threshold || '' }} + daily_ai_credits_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_total_effective_tokens || '' }} engine_id: ${{ steps.generate_aw_info.outputs.engine_id }} lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} model: ${{ steps.generate_aw_info.outputs.model }} @@ -284,7 +284,7 @@ jobs: agent: needs: activation - if: needs.activation.outputs.daily_effective_workflow_exceeded != 'true' + if: needs.activation.outputs.daily_ai_credits_exceeded != 'true' runs-on: ubuntu-latest permissions: contents: read diff --git a/pkg/workflow/testdata/TestWasmGolden_AllEngines/copilot.golden b/pkg/workflow/testdata/TestWasmGolden_AllEngines/copilot.golden index 282d11cc1f6..38433d7703b 100644 --- a/pkg/workflow/testdata/TestWasmGolden_AllEngines/copilot.golden +++ b/pkg/workflow/testdata/TestWasmGolden_AllEngines/copilot.golden @@ -28,9 +28,9 @@ jobs: outputs: comment_id: "" comment_repo: "" - daily_effective_workflow_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_exceeded == 'true' }} - daily_effective_workflow_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_threshold || '' }} - daily_effective_workflow_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_total_effective_tokens || '' }} + daily_ai_credits_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_exceeded == 'true' }} + daily_ai_credits_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_threshold || '' }} + daily_ai_credits_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_total_effective_tokens || '' }} engine_id: ${{ steps.generate_aw_info.outputs.engine_id }} lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} model: ${{ steps.generate_aw_info.outputs.model }} @@ -283,7 +283,7 @@ jobs: agent: needs: activation - if: needs.activation.outputs.daily_effective_workflow_exceeded != 'true' + if: needs.activation.outputs.daily_ai_credits_exceeded != 'true' runs-on: ubuntu-latest permissions: contents: read diff --git a/pkg/workflow/testdata/TestWasmGolden_AllEngines/gemini.golden b/pkg/workflow/testdata/TestWasmGolden_AllEngines/gemini.golden index 158b18eb2ca..f29a75b5731 100644 --- a/pkg/workflow/testdata/TestWasmGolden_AllEngines/gemini.golden +++ b/pkg/workflow/testdata/TestWasmGolden_AllEngines/gemini.golden @@ -28,9 +28,9 @@ jobs: outputs: comment_id: "" comment_repo: "" - daily_effective_workflow_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_exceeded == 'true' }} - daily_effective_workflow_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_threshold || '' }} - daily_effective_workflow_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_total_effective_tokens || '' }} + daily_ai_credits_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_exceeded == 'true' }} + daily_ai_credits_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_threshold || '' }} + daily_ai_credits_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_total_effective_tokens || '' }} engine_id: ${{ steps.generate_aw_info.outputs.engine_id }} lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} model: ${{ steps.generate_aw_info.outputs.model }} @@ -281,7 +281,7 @@ jobs: agent: needs: activation - if: needs.activation.outputs.daily_effective_workflow_exceeded != 'true' + if: needs.activation.outputs.daily_ai_credits_exceeded != 'true' runs-on: ubuntu-latest permissions: contents: read diff --git a/pkg/workflow/testdata/TestWasmGolden_AllEngines/pi.golden b/pkg/workflow/testdata/TestWasmGolden_AllEngines/pi.golden index db89a23c936..3cbe4f0a7f3 100644 --- a/pkg/workflow/testdata/TestWasmGolden_AllEngines/pi.golden +++ b/pkg/workflow/testdata/TestWasmGolden_AllEngines/pi.golden @@ -28,9 +28,9 @@ jobs: outputs: comment_id: "" comment_repo: "" - daily_effective_workflow_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_exceeded == 'true' }} - daily_effective_workflow_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_threshold || '' }} - daily_effective_workflow_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_total_effective_tokens || '' }} + daily_ai_credits_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_exceeded == 'true' }} + daily_ai_credits_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_threshold || '' }} + daily_ai_credits_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_total_effective_tokens || '' }} engine_id: ${{ steps.generate_aw_info.outputs.engine_id }} lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} model: ${{ steps.generate_aw_info.outputs.model }} @@ -282,7 +282,7 @@ jobs: agent: needs: activation - if: needs.activation.outputs.daily_effective_workflow_exceeded != 'true' + if: needs.activation.outputs.daily_ai_credits_exceeded != 'true' runs-on: ubuntu-latest permissions: contents: read diff --git a/pkg/workflow/testdata/TestWasmGolden_CompileFixtures/basic-copilot.golden b/pkg/workflow/testdata/TestWasmGolden_CompileFixtures/basic-copilot.golden index a91dfe8c652..cb3e792eed3 100644 --- a/pkg/workflow/testdata/TestWasmGolden_CompileFixtures/basic-copilot.golden +++ b/pkg/workflow/testdata/TestWasmGolden_CompileFixtures/basic-copilot.golden @@ -28,9 +28,9 @@ jobs: outputs: comment_id: "" comment_repo: "" - daily_effective_workflow_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_exceeded == 'true' }} - daily_effective_workflow_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_threshold || '' }} - daily_effective_workflow_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_total_effective_tokens || '' }} + daily_ai_credits_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_exceeded == 'true' }} + daily_ai_credits_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_threshold || '' }} + daily_ai_credits_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_total_effective_tokens || '' }} engine_id: ${{ steps.generate_aw_info.outputs.engine_id }} lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} model: ${{ steps.generate_aw_info.outputs.model }} @@ -283,7 +283,7 @@ jobs: agent: needs: activation - if: needs.activation.outputs.daily_effective_workflow_exceeded != 'true' + if: needs.activation.outputs.daily_ai_credits_exceeded != 'true' runs-on: ubuntu-latest permissions: contents: read diff --git a/pkg/workflow/testdata/TestWasmGolden_CompileFixtures/playwright-cli-mode.golden b/pkg/workflow/testdata/TestWasmGolden_CompileFixtures/playwright-cli-mode.golden index c5c908e033f..a1527ecd1c9 100644 --- a/pkg/workflow/testdata/TestWasmGolden_CompileFixtures/playwright-cli-mode.golden +++ b/pkg/workflow/testdata/TestWasmGolden_CompileFixtures/playwright-cli-mode.golden @@ -28,9 +28,9 @@ jobs: outputs: comment_id: "" comment_repo: "" - daily_effective_workflow_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_exceeded == 'true' }} - daily_effective_workflow_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_threshold || '' }} - daily_effective_workflow_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_total_effective_tokens || '' }} + daily_ai_credits_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_exceeded == 'true' }} + daily_ai_credits_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_threshold || '' }} + daily_ai_credits_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_total_effective_tokens || '' }} engine_id: ${{ steps.generate_aw_info.outputs.engine_id }} lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} model: ${{ steps.generate_aw_info.outputs.model }} @@ -294,7 +294,7 @@ jobs: agent: needs: activation - if: needs.activation.outputs.daily_effective_workflow_exceeded != 'true' + if: needs.activation.outputs.daily_ai_credits_exceeded != 'true' runs-on: ubuntu-latest permissions: read-all env: diff --git a/pkg/workflow/testdata/TestWasmGolden_CompileFixtures/smoke-copilot.golden b/pkg/workflow/testdata/TestWasmGolden_CompileFixtures/smoke-copilot.golden index d880b655770..406e7e80d61 100644 --- a/pkg/workflow/testdata/TestWasmGolden_CompileFixtures/smoke-copilot.golden +++ b/pkg/workflow/testdata/TestWasmGolden_CompileFixtures/smoke-copilot.golden @@ -40,9 +40,9 @@ jobs: body: ${{ steps.sanitized.outputs.body }} comment_id: "" comment_repo: "" - daily_effective_workflow_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_exceeded == 'true' }} - daily_effective_workflow_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_threshold || '' }} - daily_effective_workflow_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_total_effective_tokens || '' }} + daily_ai_credits_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_exceeded == 'true' }} + daily_ai_credits_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_threshold || '' }} + daily_ai_credits_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_total_effective_tokens || '' }} engine_id: ${{ steps.generate_aw_info.outputs.engine_id }} lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} model: ${{ steps.generate_aw_info.outputs.model }} @@ -402,7 +402,7 @@ jobs: agent: needs: activation - if: needs.activation.outputs.daily_effective_workflow_exceeded != 'true' + if: needs.activation.outputs.daily_ai_credits_exceeded != 'true' runs-on: ubuntu-latest permissions: actions: read diff --git a/pkg/workflow/testdata/TestWasmGolden_CompileFixtures/with-imports.golden b/pkg/workflow/testdata/TestWasmGolden_CompileFixtures/with-imports.golden index 23e26a75101..cda7b18d431 100644 --- a/pkg/workflow/testdata/TestWasmGolden_CompileFixtures/with-imports.golden +++ b/pkg/workflow/testdata/TestWasmGolden_CompileFixtures/with-imports.golden @@ -28,9 +28,9 @@ jobs: outputs: comment_id: "" comment_repo: "" - daily_effective_workflow_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_exceeded == 'true' }} - daily_effective_workflow_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_threshold || '' }} - daily_effective_workflow_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_total_effective_tokens || '' }} + daily_ai_credits_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_exceeded == 'true' }} + daily_ai_credits_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_threshold || '' }} + daily_ai_credits_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_total_effective_tokens || '' }} engine_id: ${{ steps.generate_aw_info.outputs.engine_id }} lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} model: ${{ steps.generate_aw_info.outputs.model }} @@ -284,7 +284,7 @@ jobs: agent: needs: activation - if: needs.activation.outputs.daily_effective_workflow_exceeded != 'true' + if: needs.activation.outputs.daily_ai_credits_exceeded != 'true' runs-on: ubuntu-latest permissions: contents: read