Skip to content

feat(bridge): add anthropic-compatible gateway surface#178

Merged
typelicious merged 8 commits into
mainfrom
codex/anthropic-bridge-plan
Mar 30, 2026
Merged

feat(bridge): add anthropic-compatible gateway surface#178
typelicious merged 8 commits into
mainfrom
codex/anthropic-bridge-plan

Conversation

@typelicious
Copy link
Copy Markdown
Collaborator

Summary

  • add a minimal Anthropic bridge scaffold with canonical request and response models
  • expose Anthropic messages and count_tokens through the existing Gate routing path
  • add an optional Claude Code routing hook plus config, docs, and a local smoke example

Testing

  • env PYTHONPATH=. ./.venv-check-313/bin/pytest -q tests/test_config.py tests/test_anthropic_api.py tests/test_anthropic_bridge.py tests/test_request_hooks.py
  • rtk ruff check faigate/config.py faigate/main.py tests/test_config.py tests/test_anthropic_api.py
  • bash -n docs/examples/anthropic-bridge-smoke.sh

Comment thread faigate/main.py
Comment on lines +134 to +140
{
"type": "error",
"error": {
"type": error_type,
"message": message,
},
},

Check warning

Code scanning / CodeQL

Information exposure through an exception Medium

Stack trace information
flows to this location and may be exposed to an external user.
Stack trace information
flows to this location and may be exposed to an external user.

Copilot Autofix

AI about 2 months ago

In general, the fix is to avoid returning raw exception messages to the client. Instead, log the detailed exception server-side and send the client a generic, non-sensitive message (or, at most, a high-level description that doesn’t include stack traces, paths, or provider internals).

Specifically here, two except AnthropicBridgeError as exc: blocks currently call _anthropic_error_response(str(exc), ...). We should change these to:

  • Log the exception (including stack trace if desired) using the existing logger.
  • Return a generic error message (for example “Invalid Anthropic messages request” / “Invalid Anthropic count_tokens request” or “Anthropic bridge request failed”) that does not depend on exc.

Concretely, in faigate/main.py:

  1. Around lines 3000–3005 (Anthropic messages bridge route), replace the call that returns _anthropic_error_response(str(exc), ...) with:

    • A logger.warning (or logger.error) including the exception object.
    • A call to _anthropic_error_response with a fixed message such as "Invalid Anthropic messages request" and the same error_type and status_code as before.
  2. Around lines 3085–3089 (Anthropic count_tokens route), do the same: log exc, and return _anthropic_error_response with a fixed, non-tainted message such as "Invalid Anthropic count_tokens request".

No new imports are needed; logger already exists. This preserves HTTP semantics and error types while preventing exception-derived content from reaching clients.

Suggested changeset 1
faigate/main.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/faigate/main.py b/faigate/main.py
--- a/faigate/main.py
+++ b/faigate/main.py
@@ -2998,8 +2998,9 @@
         canonical_request = _resolve_anthropic_requested_model(canonical_request)
         execution = await _execute_chat_completion_body(canonical_request.to_openai_body(), headers)
     except AnthropicBridgeError as exc:
+        logger.warning("Anthropic bridge messages request failed: %s", exc)
         return _anthropic_error_response(
-            str(exc),
+            "Invalid Anthropic messages request",
             error_type="invalid_request_error",
             status_code=400,
         )
@@ -3083,8 +3083,9 @@
     try:
         result, extra_headers = dispatch_anthropic_count_tokens(payload=body, headers=headers)
     except AnthropicBridgeError as exc:
+        logger.warning("Anthropic count_tokens request failed: %s", exc)
         return _anthropic_error_response(
-            str(exc),
+            "Invalid Anthropic count_tokens request",
             error_type="invalid_request_error",
             status_code=400,
         )
EOF
@@ -2998,8 +2998,9 @@
canonical_request = _resolve_anthropic_requested_model(canonical_request)
execution = await _execute_chat_completion_body(canonical_request.to_openai_body(), headers)
except AnthropicBridgeError as exc:
logger.warning("Anthropic bridge messages request failed: %s", exc)
return _anthropic_error_response(
str(exc),
"Invalid Anthropic messages request",
error_type="invalid_request_error",
status_code=400,
)
@@ -3083,8 +3083,9 @@
try:
result, extra_headers = dispatch_anthropic_count_tokens(payload=body, headers=headers)
except AnthropicBridgeError as exc:
logger.warning("Anthropic count_tokens request failed: %s", exc)
return _anthropic_error_response(
str(exc),
"Invalid Anthropic count_tokens request",
error_type="invalid_request_error",
status_code=400,
)
Copilot is powered by AI and may make mistakes. Always verify output.
@typelicious typelicious merged commit ee226c4 into main Mar 30, 2026
13 checks passed
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.

2 participants