Skip to content

Fix Pi Anthropic routing through the firewall - #58313

Merged
pelikhan merged 5 commits into
mainfrom
copilot/fix-anthropic-model-path-issues
Sep 4, 2026
Merged

Fix Pi Anthropic routing through the firewall#58313
pelikhan merged 5 commits into
mainfrom
copilot/fix-anthropic-model-path-issues

Conversation

Copilot AI commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Pi routed Anthropic models through OpenAI Chat Completions, producing invalid upstream paths and disabling prompt caching. Failed inference-only sessions could then exit successfully without reporting useful output.

  • Native Anthropic routing

    • Configure firewall-backed Anthropic models with anthropic-messages.
    • Target /v1/messages, restoring native prompt-cache accounting.
  • Failure propagation

    • Track provider requests and successful responses.
    • Emit report_incomplete through the trusted safe-outputs CLI and exit nonzero when every request fails.
  • Regression coverage

    • Cover Anthropic model configuration, request URL resolution, all-request failure, and recovery after a successful response.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix Anthropic models under firewall to use correct path Fix Pi Anthropic routing through the firewall Sep 3, 2026
Copilot AI requested a review from pelikhan September 3, 2026 21:45
@pelikhan
pelikhan marked this pull request as ready for review September 3, 2026 21:48
Copilot AI balanced review requested due to automatic review settings September 3, 2026 21:48
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

⚠️ Security scanning failed for Ponytail Reviewer. Review the logs for details.

Lean already. Ship.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • ab.chatgpt.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"

See Network Configuration for more information.

Generated by Ponytail Reviewer for #58313

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check. See the comment below for the result and any generated ADR draft.

No ADR enforcement needed: PR does not have the 'implementation' label and has <=100 new lines of code in business logic directories.

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • github.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "github.com"

See Network Configuration for more information.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

Test Quality Sentinel skipped because pre-fetch PR data was unavailable: unable to fetch test file diff

🧪 Test quality analysis by Test Quality Sentinel

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Stream failures can still be counted as successful responses, preventing the required nonzero exit.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Routes Pi Anthropic traffic through the native Messages API and adds provider-failure detection.

Changes:

  • Uses anthropic-messages with /v1/messages.
  • Tracks provider outcomes and reports incomplete runs.
  • Adds routing and failure-path regression tests.
File summaries
File Description
actions/setup/js/pi_provider.test.cjs Tests routing and request outcomes.
actions/setup/js/pi_provider.cjs Adds routing diagnostics and provider failure handling.
actions/setup/js/pi_models_json.test.cjs Verifies Anthropic model configuration.
actions/setup/js/pi_models_json.cjs Selects the native Anthropic protocol.
Review details

Suppressed comments (2)

actions/setup/js/pi_provider.cjs:401

  • Setting process.exitCode here does not make the actual Pi command fail. This engine invokes the pinned Pi CLI with --print --mode json; Pi v0.84.3's JSON print mode returns 0 for an assistant error, and its main function then calls process.exit(exitCode), so that explicit 0 overrides this value. Propagate the all-requests-failed result into Pi's returned status or a checked wrapper marker; otherwise the job still exits successfully.
      process.exitCode = 1;

actions/setup/js/pi_provider.cjs:400

  • This end-of-run gate does not make the tested failure-then-success path recover successfully in production. A failed assistant turn also fires the existing message_end handler, which immediately emits report_incomplete while outputs are empty; handle_agent_failure.cjs:3564-3580 later treats that signal as a failure even if a subsequent request returns 2xx. Defer that emission until agent_end after evaluating these counters (and exercise message_end in the recovery test) so transient failures can actually recover.
    if (providerRequestCount > 0 && successfulProviderResponseCount === 0) {
      emitInfrastructureIncompleteIfNoSafeOutputs(`All ${providerRequestCount} Pi provider requests failed before safe outputs were emitted.`, log);
  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread actions/setup/js/pi_provider.cjs Outdated
Comment on lines +325 to +326
if (event.status >= 200 && event.status < 300) {
successfulProviderResponseCount += 1;
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Comment Memory

reviewed_at: 2026-09-03T21:57:30.759+00:00
review_event: REQUEST_CHANGES
top_themes:
  - anthropic route compatibility break
files_reviewed:
  - actions/setup/js/pi_models_json.cjs
  - actions/setup/js/pi_models_json.test.cjs
  - actions/setup/js/pi_provider.cjs
  - actions/setup/js/pi_provider.test.cjs
comment_count: 1

Note

This comment is managed by comment memory.

It stores persistent context for this thread in the code block at the top of this comment.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • github.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "github.com"

See Network Configuration for more information.

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt54 · 31.4 AIC · ⌖ 7.39 AIC · ⊞ 23.5K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Requesting changes

This patch fixes one Anthropic routing bug, but it also introduces a compatibility break on the provider path rewrite.

Blocking theme
  • The Anthropic request target now unconditionally switches from /messages to /v1/messages for every configured Anthropic base URL, with no compatibility gate or fallback. That can break existing non-firewall or older proxy endpoints immediately.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • github.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "github.com"

See Network Configuration for more information.

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt54 · 31.4 AIC · ⌖ 7.39 AIC · ⊞ 23.5K
Comment /review to run again

case "anthropic":
case "anthropic-messages":
return { api, method, url: joinApiUrl(baseUrl, "/messages") };
return { api, method, url: joinApiUrl(baseUrl, "/v1/messages") };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This change hard-switches Anthropic requests from /messages to /v1/messages for every anthropic and anthropic-messages base URL, so any existing proxy or custom base URL that still exposes the previous route will start returning hard failures.

💡 Why this blocks merge The PR description talks about fixing the firewall proxy, but the code here changes the request path globally in `resolveProviderRequestTarget` with no compatibility check or fallback. That means this is not just a firewall-only fix: any environment using `ANTHROPIC_BASE_URL` or another non-firewall endpoint that still implements the old `/messages` route will break immediately. A 404/405 here kills every Anthropic request, so this needs either an explicit capability gate for the firewall path or a backward-compatible fallback.

Suggested shape:

case "anthropic":
case "anthropic-messages":
  return { api, method, url: joinApiUrl(baseUrl, supportsV1 ? "/v1/messages" : "/messages") };

Or retry /messages when /v1/messages gets a route-level failure.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Skills-Based Review 🧠

Applied /diagnosing-bugs and /tdd — this is a targeted, well-tested bug fix (native Anthropic /v1/messages routing + failure propagation via report_incomplete). Requesting changes on one correctness risk; the rest is minor.

📋 Key Themes & Highlights

Key Themes

  • Possible duplicate report_incomplete emission: the new all-requests-failed check in agent_end and the existing per-message check in message_end can both fire for the same root cause, and the file-existence pre-check that's supposed to prevent double-emission doesn't see writes made through the CLI channel (see inline comment on pi_provider.cjs:401).
  • Minor test gap: no explicit case for zero responses ever recorded before agent_end (see inline comment on pi_provider.test.cjs).

Positive Highlights

  • ✅ Root cause is well-diagnosed: routes Anthropic through its native Messages API (/v1/messages) instead of the OpenAI-style gateway path, restoring prompt caching — a real, specific fix rather than a workaround.
  • ✅ Solid regression coverage: model API resolution, request URL resolution, all-request-failure, and recovery-after-failure are all exercised with descriptive test names.
  • ✅ Doc comment above resolvePiApiForProvider was updated to match the new behavior instead of going stale.

Applied via automated PR review (Matt Pocock skills reviewer).

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · copilot · sonnet50 · 42.9 AIC · ⌖ 14.9 AIC · ⊞ 10.3K
Comment /matt to run again


if (providerRequestCount > 0 && successfulProviderResponseCount === 0) {
emitInfrastructureIncompleteIfNoSafeOutputs(`All ${providerRequestCount} Pi provider requests failed before safe outputs were emitted.`, log);
process.exitCode = 1;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/diagnosing-bugs] This all-requests-failed check can double-emit report_incomplete for the same underlying failure, because the "already recorded" guard it relies on can't see prior emissions made through the CLI channel.

💡 Why this can duplicate

emitInfrastructureIncompleteIfNoSafeOutputs pre-checks for existing output by reading GH_AW_SAFE_OUTPUTS from the local filesystem (line 167). But per the docstring above it (lines 148-153), in the AWF sandbox that path is mounted read-only and the real write goes through the safeoutputs CLI to a different process — so the local file the pre-check reads never reflects a write that already happened via that CLI channel.

Concretely: if a request fails mid-session, message_end (line 349) already calls emitInfrastructureIncompleteIfNoSafeOutputs(...) and emits via the CLI. If that's also the last successful-response count staying at 0 by agent_end, the new check at line 399-401 fires again with a different details string ("All N Pi provider requests failed..."), and the local pre-check won't catch it because the CLI-written output isn't visible locally. Net effect: two report_incomplete safe outputs for one root cause.

Suggest tracking emission state in-memory within piProviderExtension (e.g. an incompleteEmitted flag set by both call sites) rather than relying solely on the file-existence pre-check, so the agent_end fallback only fires when message_end didn't already report it.

@copilot please address this.

await handlers.after_provider_response({ type: "after_provider_response", status: 200, headers: {} }, ctx);
await handlers.agent_end();

expect(process.exitCode).toBe(originalExitCode);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/tdd] Good regression coverage for the all-failed and recovery-after-failure paths, but there's no test for the case where after_provider_response never fires at all (e.g. the process errors out before a response, which is exactly the scenario message_end's connection-error test already exercises separately).

💡 Suggested edge case

Consider adding a case where before_provider_request fires once, no after_provider_response ever fires, then agent_end runs directly. That path is currently only implicitly covered (since successfulProviderResponseCount stays 0), but an explicit test would pin the intended semantics distinctly from the "one failed response" test at line 122, and guard against a future refactor accidentally requiring a response event to be recorded before this branch triggers.

@copilot please address this.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the Anthropic routing fix (backend-only, no UI surface — Impeccable modes not applicable).

  • resolvePiApiForProvider now correctly routes anthropic to anthropic-messages; verified against Go-side log fixtures (pkg/cli/token_usage_test.go) that confirm /v1/messages is the real firewall proxy path.
  • joinApiUrl(baseUrl, "/v1/messages") is safe since baseUrl is always a bare origin (via endpointBaseUrl/URL(...).origin), so no double /v1 prefix risk.
  • New failure-tracking (providerRequestCount/successfulProviderResponseCount) correctly emits report_incomplete only when all requests fail, and resets state properly on any success — matches the two new regression tests.

No blocking or actionable issues found.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • registry.npmjs.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "registry.npmjs.org"

See Network Configuration for more information.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · copilot · sonnet50 · 51 AIC · ⌖ 13.3 AIC · ⊞ 8.3K

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot This PR still has unresolved review feedback.

Please address these review outcomes and then run the pr-finisher skill:

  • copilot-pull-request-reviewer: failed provider requests can still be emitted as success paths, so the run may not exit nonzero after all-request failure.
  • github-actions: unconditionally rewriting Anthropic requests to /v1/messages can break existing non-firewall or older proxy endpoints without a compatibility gate or fallback.
  • mattpocock-skills-reviewer: defer failure emission until final agent evaluation so transient failures can recover cleanly without premature report_incomplete.

Also refresh the branch if needed after applying fixes.

Generated by 👨🍳 PR Sous Chef

Generated by 👨‍🍳 PR Sous Chef · pi · gpt54 · 32.7 AIC · ⌖ 9.85 AIC · ⊞ 9.2K ·
Comment /souschef to run again

Copilot AI and others added 2 commits September 3, 2026 23:46
Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

@copilot This PR still has unresolved review feedback.

Please address these review outcomes and then run the pr-finisher skill:...

Confirmed the current branch includes the requested fixes: stream-error accounting invalidates provisional 2xx success, report_incomplete is deferred to agent_end so recovery can succeed without duplicate emission, and Anthropic routing preserves /messages for legacy anthropic while using /v1/messages for native anthropic-messages. The provider regression suite passes: 15 tests, including stream failure, recovery, and no-response connection-error paths.

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
@pelikhan
pelikhan merged commit 08991e9 into main Sep 4, 2026
@pelikhan
pelikhan deleted the copilot/fix-anthropic-model-path-issues branch September 4, 2026 00:00
Copilot stopped work on behalf of gh-aw-bot due to an error September 4, 2026 00:00
Copilot AI requested a review from gh-aw-bot September 4, 2026 00:00
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.88.4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pi engine: Anthropic models are unusable under the firewall — gateway path lacks /v1, then the cache-miss guard aborts the run

4 participants