diff --git a/.github/workflows/daily-team-evolution-insights.lock.yml b/.github/workflows/daily-team-evolution-insights.lock.yml index eec68dcb541..4edc6082a3e 100644 --- a/.github/workflows/daily-team-evolution-insights.lock.yml +++ b/.github/workflows/daily-team-evolution-insights.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"2d0f779aaf8f7164d73363bd00b226c0ffb9138298fa71e22f4d4f95107f0bf0","body_hash":"1572e54b8a5340cd1eca0454a579e520b856fac10d8826f3eadd3cc63d1fb376","strict":true,"agent_id":"goose","agent_model":"copilot/claude-sonnet-4.5","engine_versions":{"goose":"1.45.0"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"2d0f779aaf8f7164d73363bd00b226c0ffb9138298fa71e22f4d4f95107f0bf0","body_hash":"1572e54b8a5340cd1eca0454a579e520b856fac10d8826f3eadd3cc63d1fb376","agent_id":"goose","agent_model":"copilot/claude-sonnet-4.5","engine_versions":{"goose":"1.45.0"}} # gh-aw-manifest: {"version":1,"secrets":["GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.28.1","digest":"sha256:5e3f6ee27eeae07195838b97ac4aa2f8aea42a7c55f1c0d3e17d8e88e294ad0d","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.28.1@sha256:5e3f6ee27eeae07195838b97ac4aa2f8aea42a7c55f1c0d3e17d8e88e294ad0d"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.28.1","digest":"sha256:288e7d2a12d5b430500d739f9c16e20bb1ed51b91f986f3f3eccde189f489f5c","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.28.1@sha256:288e7d2a12d5b430500d739f9c16e20bb1ed51b91f986f3f3eccde189f489f5c"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.28.1","digest":"sha256:9d428af47899bf18ef2d5618075777d76ef344c91e76c1f44ec1aaa0ee347e5f","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.28.1@sha256:9d428af47899bf18ef2d5618075777d76ef344c91e76c1f44ec1aaa0ee347e5f"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.9","digest":"sha256:e5a1569aeaf41820fa7bdee3e94468cae448133cdbf00119ad24f5b74db1ab9f","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.9@sha256:e5a1569aeaf41820fa7bdee3e94468cae448133cdbf00119ad24f5b74db1ab9f"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196","pinned_image":"ghcr.io/github/gh-aw-node@sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196"},{"image":"ghcr.io/github/github-mcp-server:v1.9.0","digest":"sha256:881b53d6f75f69bdbc1b5b10fc2f1361717c19054143b3a8529fb5c32061a50e","pinned_image":"ghcr.io/github/github-mcp-server:v1.9.0@sha256:881b53d6f75f69bdbc1b5b10fc2f1361717c19054143b3a8529fb5c32061a50e"}]} # This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # @@ -153,7 +153,7 @@ jobs: GH_AW_INFO_FIREWALL_TYPE: "squid" GH_AW_INFO_AGENT_RUNTIME: "" GH_AW_INFO_FRONTMATTER_EMOJI: "📊" - GH_AW_COMPILED_STRICT: "true" + GH_AW_COMPILED_STRICT: "false" GH_AW_INFO_FEATURES: '{"gh-aw-detection":true}' uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: @@ -162,6 +162,11 @@ jobs: setupGlobals(core, github, context, exec, io, getOctokit); const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs'); await main(core, context); + - name: Enforce strict mode policy + if: ${{ vars.GH_AW_POLICY_STRICT == 'true' }} + run: | + echo "::error::GH_AW_POLICY_STRICT=true but this workflow was not compiled in strict mode. Recompile with --strict or strict: true." + exit 1 - name: Restore daily AIC usage cache id: restore-daily-aic-cache if: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }} diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml index ad799555f5c..9557d8df63d 100644 --- a/.github/workflows/mcp-inspector.lock.yml +++ b/.github/workflows/mcp-inspector.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"059f9e679f1a5a2bd3e7ad1308a9c25e36ad9c93f4db2a618ea6aca1280af00a","body_hash":"42daae928c8295891472e702ddec1ad8479ca526a291e5a9db7f7f89037a8b94","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.80","copilot-sdk":"1.0.11"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"059f9e679f1a5a2bd3e7ad1308a9c25e36ad9c93f4db2a618ea6aca1280af00a","body_hash":"42daae928c8295891472e702ddec1ad8479ca526a291e5a9db7f7f89037a8b94","agent_id":"copilot","engine_versions":{"copilot":"1.0.80","copilot-sdk":"1.0.11"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","DD_API_KEY","DD_APPLICATION_KEY","DD_APP_KEY","DD_SITE","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN","SENTRY_ACCESS_TOKEN","SENTRY_OPENAI_API_KEY","SLACK_BOT_TOKEN","TAVILY_API_KEY"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"b7ad1dad31e06c5925ef5d2fc7ad053ef454303e","version":"v7.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"docker/build-push-action","sha":"53b7df96c91f9c12dcc8a07bcb9ccacbed38856a","version":"v7.3.0"},{"repo":"docker/setup-buildx-action","sha":"bb05f3f5519dd87d3ba754cc423b652a5edd6d2c","version":"v4.2.0"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.28.1","digest":"sha256:5e3f6ee27eeae07195838b97ac4aa2f8aea42a7c55f1c0d3e17d8e88e294ad0d","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.28.1@sha256:5e3f6ee27eeae07195838b97ac4aa2f8aea42a7c55f1c0d3e17d8e88e294ad0d"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.28.1","digest":"sha256:288e7d2a12d5b430500d739f9c16e20bb1ed51b91f986f3f3eccde189f489f5c","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.28.1@sha256:288e7d2a12d5b430500d739f9c16e20bb1ed51b91f986f3f3eccde189f489f5c"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.28.1","digest":"sha256:9d428af47899bf18ef2d5618075777d76ef344c91e76c1f44ec1aaa0ee347e5f","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.28.1@sha256:9d428af47899bf18ef2d5618075777d76ef344c91e76c1f44ec1aaa0ee347e5f"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.9","digest":"sha256:e5a1569aeaf41820fa7bdee3e94468cae448133cdbf00119ad24f5b74db1ab9f","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.9@sha256:e5a1569aeaf41820fa7bdee3e94468cae448133cdbf00119ad24f5b74db1ab9f"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196","pinned_image":"ghcr.io/github/gh-aw-node@sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196"},{"image":"ghcr.io/github/github-mcp-server:v1.9.0","digest":"sha256:881b53d6f75f69bdbc1b5b10fc2f1361717c19054143b3a8529fb5c32061a50e","pinned_image":"ghcr.io/github/github-mcp-server:v1.9.0@sha256:881b53d6f75f69bdbc1b5b10fc2f1361717c19054143b3a8529fb5c32061a50e"},{"image":"ghcr.io/oraios/serena:latest","digest":"sha256:0944b2ffe66dbcddeed531694b6819d7f9efd8125b442b282a1cc863f570a03e","pinned_image":"ghcr.io/oraios/serena:latest@sha256:0944b2ffe66dbcddeed531694b6819d7f9efd8125b442b282a1cc863f570a03e"},{"image":"node:lts-alpine","digest":"sha256:d32cdf619f63fe0471182d08996dd516c6275bb5fd31ae06e55a570bd9e1ad43","pinned_image":"node:lts-alpine@sha256:d32cdf619f63fe0471182d08996dd516c6275bb5fd31ae06e55a570bd9e1ad43"}]} # This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # @@ -178,7 +178,7 @@ jobs: GH_AW_INFO_AGENT_RUNTIME: "cloud-hypervisor" GH_AW_INFO_CACHE_MEMORY: "true" GH_AW_INFO_FRONTMATTER_EMOJI: "🔍" - GH_AW_COMPILED_STRICT: "true" + GH_AW_COMPILED_STRICT: "false" GH_AW_INFO_FEATURES: '{"gh-aw-detection":true}' uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: @@ -187,6 +187,11 @@ jobs: setupGlobals(core, github, context, exec, io, getOctokit); const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs'); await main(core, context); + - name: Enforce strict mode policy + if: ${{ vars.GH_AW_POLICY_STRICT == 'true' }} + run: | + echo "::error::GH_AW_POLICY_STRICT=true but this workflow was not compiled in strict mode. Recompile with --strict or strict: true." + exit 1 - name: Restore daily AIC usage cache id: restore-daily-aic-cache if: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }} diff --git a/actions/setup/js/copilot_harness.test.cjs b/actions/setup/js/copilot_harness.test.cjs index 6792210f84f..f92c4f93538 100644 --- a/actions/setup/js/copilot_harness.test.cjs +++ b/actions/setup/js/copilot_harness.test.cjs @@ -170,6 +170,33 @@ describe("copilot_harness.cjs", () => { expect(isCAPIQuotaExceededError("Authentication failed")).toBe(false); expect(isCAPIQuotaExceededError("")).toBe(false); }); + + it("matches the Copilot CLI's own retry-exhaustion message without a CAPIError: prefix (429)", () => { + const output = + "Failed to get response from the AI model; retried 5 times (total retry wait time: 380.35 seconds) " + + "(Request-ID AC21:F5CEC:33A719:40DD88:6A83AA27) Last error: 429 Too Many Requests\nChanges +0 -0"; + expect(isCAPIQuotaExceededError(output)).toBe(true); + }); + + it("matches the Copilot CLI's own retry-exhaustion message for 5xx statuses (503)", () => { + const output = "Failed to get response from the AI model; retried 5 times (total retry wait time: 300 seconds) Last error: 503 Service Unavailable"; + expect(isCAPIQuotaExceededError(output)).toBe(true); + }); + + it("does not retry a zero-progress attempt that exhausted the CLI's own 429 retries", () => { + const output = + "Failed to get response from the AI model; retried 5 times (total retry wait time: 380.35 seconds) " + + "(Request-ID AC21:F5CEC:33A719:40DD88:6A83AA27) Last error: 429 Too Many Requests"; + expect( + shouldRetryFailedExecution({ + exitCode: 1, + hasOutput: true, + output, + attempt: 0, + maxRetries: 3, + }) + ).toBe(false); + }); }); it("matches CAPIError: 400 with various spacing", () => { diff --git a/actions/setup/js/detect_agent_errors.cjs b/actions/setup/js/detect_agent_errors.cjs index c565769f495..0c7fcaf4368 100644 --- a/actions/setup/js/detect_agent_errors.cjs +++ b/actions/setup/js/detect_agent_errors.cjs @@ -25,9 +25,12 @@ * response (for example "Response status code does not indicate success: 400 (Bad Request)"). * - capi_quota_exceeded_error: The Copilot CAPI quota has been exhausted * or rate-limited (e.g., "CAPIError: 429 429 quota exceeded", - * "CAPIError: Too Many Requests"). All matched forms are treated as - * non-retryable because the Copilot SDK has already retried internally - * before surfacing the error. + * "CAPIError: Too Many Requests", or the Copilot CLI's own + * retry-exhaustion message "Failed to get response from the AI model; + * retried N times ... Last error: 429/5xx" which carries no "CAPIError:" + * prefix). All matched forms are treated as non-retryable because the + * Copilot CLI/SDK has already retried internally before surfacing the + * error. * - invocation_cap_exceeded: The per-run pooled LLM invocation cap is * fully exhausted (e.g., "CAPIError: 429 Maximum LLM invocations exceeded (N/N)" * or `"type":"max_runs_exceeded"`). This is more specific than generic @@ -165,9 +168,13 @@ const MISSING_MODEL_PRICING_PATTERN = /Model\s+"([^"]+)"\s+has no AI credits pri // "CAPIError: 429 429 quota exceeded" (original observed form) // "CAPIError: 429 Too Many Requests" (HTTP 429 form) // "CAPIError: Too Many Requests" (no status code in message) -// All forms are treated as non-retryable; the Copilot SDK has already retried -// internally before surfacing this error (evidenced by "retried 5 times" context). -const CAPI_QUOTA_EXCEEDED_PATTERN = /CAPIError:\s*(?:429\s+)?(?:429\s+quota exceeded|Too Many Requests)/i; +// "Failed to get response from the AI model; retried 5 times ... Last error: 429 Too Many Requests" +// (Copilot CLI's own retry-exhaustion message, no "CAPIError:" prefix — seen with both +// 429 and 5xx terminal statuses, e.g. "Last error: 503 Service Unavailable") +// All forms are treated as non-retryable; the Copilot CLI/SDK has already retried +// internally before surfacing this error (evidenced by "retried N times" context). +const CAPI_QUOTA_EXCEEDED_PATTERN = + /CAPIError:\s*(?:429\s+)?(?:429\s+quota exceeded|Too Many Requests)|Failed to get response from the AI model;\s*retried\s+\d+\s+times[^\n]{0,300}?Last error:\s*(?:429|5\d{2})\b/i; /** * Build a case-insensitive merged RegExp from literal/regex patterns. diff --git a/actions/setup/js/detect_agent_errors.test.cjs b/actions/setup/js/detect_agent_errors.test.cjs index f026f15be08..b6061a1c8a0 100644 --- a/actions/setup/js/detect_agent_errors.test.cjs +++ b/actions/setup/js/detect_agent_errors.test.cjs @@ -221,6 +221,22 @@ describe("detect_agent_errors.cjs", () => { // it should NOT match the CAPI quota pattern. expect(isCAPIQuotaExceededError("CAPIError: 429 Maximum LLM invocations exceeded (25/25)")).toBe(false); }); + + it("matches the Copilot CLI's own retry-exhaustion message with no CAPIError: prefix (429)", () => { + const message = + "Failed to get response from the AI model; retried 5 times (total retry wait time: 380.35 seconds) " + + "(Request-ID AC21:F5CEC:33A719:40DD88:6A83AA27) Last error: 429 Too Many Requests"; + expect(isCAPIQuotaExceededError(message)).toBe(true); + }); + + it("matches the Copilot CLI's own retry-exhaustion message for 5xx statuses (503)", () => { + const message = "Failed to get response from the AI model; retried 5 times (total retry wait time: 300 seconds) Last error: 503 Service Unavailable"; + expect(isCAPIQuotaExceededError(message)).toBe(true); + }); + + it("does not match a 'Failed to get response' message without retry-exhaustion context", () => { + expect(isCAPIQuotaExceededError("Failed to get response from the AI model due to a network error")).toBe(false); + }); }); describe("INVOCATION_CAP_EXCEEDED_PATTERN / isInvocationCapExceededError", () => {