Skip to content

Feature/cloudflare gateway connector - #13

Open
anassg-lago wants to merge 4 commits into
mainfrom
feature/cloudflare-gateway-connector
Open

Feature/cloudflare gateway connector#13
anassg-lago wants to merge 4 commits into
mainfrom
feature/cloudflare-gateway-connector

Conversation

@anassg-lago

Copy link
Copy Markdown
Collaborator

What

  • Cloudflare AI Gateway connector: live path (wrap() auto-detects a client pointed at gateway.ai.cloudflare.com, skips billing on cf-aig-cache-status: HIT, auto-primes Workers AI pricing) and backfill path (gateway.adapters.cloudflare_gateway extracts a Logs API entry and bills Cloudflare's own metered cost via emit(usd_cost=..., event_id=...), idempotent across re-runs).
  • Model-attribution fix: OpenAI/Anthropic/Gemini adapters now prefer the response's own resolved model over the requested alias — fixes mispriced/misattributed events for aliased model names (e.g. Mistral's -latest, Gemini resolving to a dated snapshot).
  • Mistral pricing: resolves -latest aliases against Mistral's own /v1/models (union-find over its mutually-aliasing shape) so OpenRouter price lookups hit the right dated model.
  • Lazy pricing warm-up: Cloudflare Workers AI and Mistral pricing are primed reactively on the first wrap()'d call, not eagerly at SDK init.
  • Queue reliability: split permanent (4xx) vs. transient send failures; bounded shutdown drain instead of silently dropping stranded events on exit.
  • verify_ssl config option for local dev against a self-signed Lago instance.
  • README: documented the gateway connector, trimmed redundant sections and roadmap/phase markers.

Testing

  • 443 unit tests passing, 23 skipped (require live credentials).
  • Live-verified against a real Cloudflare AI Gateway (Workers AI, Anthropic, Mistral passthrough) and a real Lago account — confirmed exact current_usage event counts before/after.

…hit bugs

- extract_openai_native/extract_anthropic_native now prefer the response's own
  model over the requested alias, matching what actually served the call.
- Wrapper cache-hit detection: skip billing when a gateway (e.g. Cloudflare)
  served the response from cache, via .with_raw_response.create(...).
- New lago_agent_sdk.gateway.adapters.cloudflare_gateway: extract_cloudflare_log()
  and resolve_subscription() for the log-extraction half of a standalone
  connector, verified live across all three of Cloudflare's ingress methods
  (REST /ai/run, Unified/compat, Native binding) and across native wraps for
  Anthropic, Gemini, and Mistral through their dedicated passthrough endpoints.
…queue reliability

Follow-on to 2bb89a0 (Cloudflare AI Gateway connector). Adds:

- Gemini adapter: prefer the response's resolved model over the requested
  alias, same fix already applied to OpenAI/Anthropic in the prior commit.
  Extracted the shared resolve_model() helper to adapters/_common.py.
- Mistral '-latest' alias resolution for OpenRouter pricing lookups, via
  union-find over Mistral's mutually-aliasing /v1/models shape.
- Selective/lazy pricing warm-up: Cloudflare Workers AI and Mistral pricing
  are primed reactively on the first wrap()'d call (via _auto_prime_pricing_for),
  not eagerly at SDK init — OpenRouter is still warmed eagerly.
- EventQueue: split permanent (4xx) vs. transient send failures, bounded
  shutdown drain instead of silently dropping stranded events on exit.
- Added verify_ssl config option for local dev against a self-signed Lago.
- README: documented the Cloudflare AI Gateway connector (live + backfill
  paths), removed stale references and roadmap/phase markers.
Workers AI cached tokens were billed twice. `provider="workers-ai"` was
missing from `_INPUT_INCLUDES_CACHE_READ`, but Workers AI is only ever
reached through Cloudflare's OpenAI-COMPATIBLE endpoint, so its
`prompt_tokens` already includes `prompt_tokens_details.cached_tokens`.
With the cached portion never subtracted, those tokens were charged at the
full input rate AND again at the cache-read rate, which Cloudflare's
catalog does publish (verified live for kimi-k2.6, kimi-k2.7-code and
glm-5.2). Measured +583% overbill against a real cached call (prompt
23233 / cached 23168) at live catalog rates.

Gateway-backfilled Gemini calls could never be priced. The adapter passed
Cloudflare's own provider vocabulary through verbatim; a real entry
reports provider="google-ai-studio", which matched no vendor in
_VENDOR_MAP, so lookup_openrouter missed every time (confirmed against the
live 400-model table: miss as google-ai-studio, hit as gemini). The same
miss kept it out of _INPUT_INCLUDES_CACHE_READ, so Gemini's cache_read — a
subset of its input — was billed on top of input rather than subtracted.

A model already carrying its vendor prefix never matched. A real REST-path
log reports model="anthropic/claude-opus-4.8" with provider="anthropic",
which built "anthropic/anthropic/claude-opus-4.8". Now stripped, but only
when the prefix agrees with the resolved vendor, so the lookup stays
vendor-gated: a model naming a different vendor is still a miss.

Also: `_parse_price` raised InvalidOperation instead of returning None for
values >= 1e16, because `.quantize()` sat outside the try. That escaped
into emit()'s catch-all and dropped the event as an unknown error rather
than taking the normal "no price" path. Returning None also matches what
the JS port returns for the same inputs.

All 10 distinct (provider, model) pairs across the real captured fixtures
now resolve to a live price; three previously missed. The shared golden
fixture gains a `precomputed_cases` section carrying verbatim costs from
real gateway log entries, plus an optional `provider` on `cases` so
per-provider token semantics are pinned cross-repo.
@anassg-lago
anassg-lago force-pushed the feature/cloudflare-gateway-connector branch from 0bb4207 to 7f3d7c0 Compare August 7, 2026 09:01
`ruff format --check` is a CI gate, and these two files have been failing it
since 9cfde77, the branch's first commit — `main` is clean. Both changes are
purely cosmetic line-length wraps at the configured 110-char limit; no
behavior changes.

Unrelated to the billing fixes in the preceding commit, but the PR cannot go
green without it.
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