Skip to content

fix: interceptor sync bridge + async detection, example fixes#213

Merged
saurabhjain1592 merged 2 commits into
mainfrom
fix/2861-interceptor-sync-bridge-examples
Jul 9, 2026
Merged

fix: interceptor sync bridge + async detection, example fixes#213
saurabhjain1592 merged 2 commits into
mainfrom
fix/2861-interceptor-sync-bridge-examples

Conversation

@saurabhjain1592

Copy link
Copy Markdown
Member

Summary

Hostile-testing sweep TEST-SDK ahead of the BukuWarung integration — tracking getaxonflow/axonflow-enterprise#2861.

  • All 5 provider interceptors crashed inside a running event loop (async-adapter-bypass class). The sync wrap paths (openai, anthropic, bedrock, gemini, ollama) ran governance via loop.run_until_completeRuntimeError: This event loop is already running in FastAPI/Jupyter/any async app driving a sync provider client. Observed live: examples/openai_integration.py crashed with coroutine 'AxonFlow.proxy_llm_call' was never awaited. New shared run_coroutine_sync bridge (mirrors SyncAxonFlow._run_sync, but on ONE persistent daemon-thread loop — a throwaway-loop bridge breaks the second call with "Event loop is closed" because the httpx pool is loop-affine) blocks the call site until the verdict is in.
  • AsyncOpenAI clients were silently given the SYNC wrap path. openai>=1/anthropic decorate async create with a plain-def @required_args wrapper, so asyncio.iscoroutinefunction returns False. is_async_callable follows __wrapped__ — verified against real openai 2.44 (async detected, sync stays sync).
  • Examples pass on enterprise (JWT-validating) stacks. quickstart, gateway_mode, openai_integration read AXONFLOW_USER_TOKEN instead of hardcoded non-JWT literals (they 401'd on DEPLOYMENT_MODE=enterprise). gateway_mode's block demo now uses stacked SQLi (blocked on every posture; PII defaults to redact) and exits non-zero on unexpected approval; openai_integration prints its block-probe outcome instead of ending silently.

Version 8.5.0 → 8.5.1 + CHANGELOG.

Testing

  • New TestSyncWrapInsideRunningLoop (6 tests, one per provider + allowed path) — mutation-verified: fails with the pre-fix openai interceptor restored. New TestAsyncDetectionThroughDecorators.
  • New runtime-e2e/interceptor_sync_bridge/ against a LIVE enterprise stack (v9.6.1): REAL openai.OpenAI client (dummy key — provider never reached) wrapped and driven from inside asyncio.run AND from plain sync code → stacked-SQLi prompt blocked with PolicyViolationError both times, no RuntimeError; AsyncOpenAI detected async, wrapped create is a coroutine function, blocked verdict awaited on the caller's loop — PASS 5/5. (The plain-sync leg caught the "Event loop is closed" pool-affinity regression during development; the persistent-loop bridge fixes it.)
  • All 7 examples re-run green against the live enterprise stack (quickstart, gateway_mode, openai_integration incl. real governed OpenAI round-trip, explain_decision, indonesia_compliance, list_decisions, wcp_retry_idempotency).
  • Full pytest: 1047 passed, 29 skipped. ruff clean.

Related Issues

  • getaxonflow/axonflow-enterprise#2861

- shared run_coroutine_sync bridge (persistent background loop) replaces
  per-interceptor loop.run_until_complete which crashed inside running
  loops (async-adapter-bypass class) across all 5 provider interceptors
- is_async_callable follows __wrapped__ so AsyncOpenAI/AsyncAnthropic
  (decorator-wrapped async create) get the async wrap path again
- examples read AXONFLOW_USER_TOKEN; gateway_mode block demo uses stacked
  SQLi and exits non-zero on unexpected approval
- runtime-e2e/interceptor_sync_bridge: live-agent bridge + detection proof

Signed-off-by: Saurabh Jain <saurabhjain1592@gmail.com>
block_reason or-fallbacks in the 5 interceptors converted to explicit
is-not-None form; baseline refreshed (14 entries removed)

Signed-off-by: Saurabh Jain <saurabhjain1592@gmail.com>
@saurabhjain1592

Copy link
Copy Markdown
Member Author

The one red check (Live integration vs try.getaxonflow.com) is pre-existing: the same workflow has failed on main's scheduled runs since 2026-07-07 (three consecutive days), with error=LLM routing failed + SQLi arriving unblocked from the deployed community-saas service — server-side state on try.getaxonflow.com, untouched by this diff. Likely the deployed twin of getaxonflow/axonflow-enterprise#2871 (retired claude-sonnet-4-20250514 fallback); flagged there. Everything else is green (18/18).

@saurabhjain1592
saurabhjain1592 merged commit dcb3fc2 into main Jul 9, 2026
18 of 19 checks passed
@saurabhjain1592
saurabhjain1592 deleted the fix/2861-interceptor-sync-bridge-examples branch July 9, 2026 23:32
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.

1 participant