Skip to content

fix(openai): attribute dedicated Baseten Python endpoints - #541

Open
nik13 wants to merge 11 commits into
devfrom
fix/openai-python-baseten-dedicated
Open

nik13 wants to merge 11 commits into
devfrom
fix/openai-python-baseten-dedicated

Conversation

@nik13

@nik13 nik13 commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fix the remaining Baseten attribution gap in the maintained Python OpenAI instrumentor. Model APIs at inference.baseten.co already map to baseten; dedicated and regional model-*.api.baseten.co endpoints still map to openai on dev.

  • Add a bounded, single-label host match for dedicated and regional Baseten model endpoints. Preserve exact domain boundaries, the 63-character DNS label limit, and the unknown-host fallback.
  • Add real OpenAI SDK → Future AGI register() → loopback OTLP contracts for hosted/dedicated/regional endpoints, sync/async calls, Chat Completions/Responses/embeddings, completed streams, HTTP errors, content masking, credentials, model metadata, token usage, normalized/lookalike URLs, and mutable client endpoints. Each operation exports exactly one span.
  • Finalize shared sync/async stream spans on explicit close and async request/iteration cancellation. Preserve SDK cleanup, exception identity, cancellation propagation and existing privacy masking; repeated cleanup exports no duplicate spans.
  • Add a network-isolated CI matrix for the declared OpenAI floor (1.69.0) and registry latest, printing the resolved version and preserving the existing Model APIs recipe contracts.
  • Document the direct dedicated-client route in the shared package README. No new instrumentor, copied customer helper, runtime dependency, version bump, or public API change.

This is the Python companion to the separate TypeScript repair in #336, not a replacement or duplicate of it. No unfinished Python Baseten PR or branch was found. Current dev was merged normally before final validation.

Failing-first evidence

Against dev 045f5f0f2d024d61352a9ba5bdbbfe1ef60aa752, the initial regression matrix produced 70 failures and 52 passes on both OpenAI 1.69.0 and 3.42.1. All failures were dedicated/regional provider attribution. Hosted endpoints and negative controls already passed. The provider-mapping portion changes five production lines; the lifecycle follow-up below also repairs the shared request/stream wrappers. The final Baseten matrix includes 123 passing tests, including an additional mutable-client regression.

Official endpoint references:

Synthetic resource tests prove instrumentor coverage, not that every Baseten deployment exposes every OpenAI resource.

Validation

Every local executable check ran with outbound networking denied except loopback. Dependencies were installed separately. Only synthetic credentials and model responses were used.

  • Full OpenAI package suite using the built wheel and published fi-instrumentation-otel==1.2.2: 474 passed, 18 skips on OpenAI 1.69.0 and 490 passed, 2 optional-package skips on registry-latest 3.42.1. The floor skips 16 new alias-specific cases because that SDK does not expose AsyncStream.aclose(). Import paths confirmed the installed wheel/core were used. The skips are the separately installable Fireworks and vLLM migration integrations.
  • Existing Baseten Model APIs recipe: 58 passed on each SDK version.
  • Held docs example executed through real register() and a loopback /tracer/v1/traces receiver: 6 passing runs, three endpoint shapes on each SDK version. The latest example uses the SDK's native httpx2 transport; the floor uses httpx.
  • Held MDX compilation, wheel build, release-plan validation (129 packages), and git diff --check passed.

Review round 1 lifecycle follow-up

Both findings were reproduced as pre-existing shared-instrumentor defects, not regressions in the hostname matcher. Explicit early close lost the span; async request/stream cancellation bypassed Exception handlers.

  • Added 26 native-transport lifecycle contracts covering dedicated/regional endpoints, sync/async close before consumption/after partial consumption/after exhaustion, repeated cleanup, SDK close failures, actual task cancellation during requests/iteration/close, partial output preservation, and error-detail masking.
  • Failing-first installed-wheel runs: 22 failed, 4 passed on each of OpenAI 1.69.0 and 3.42.1. The four controls are exhausted streams. After the fix all 26 passed, included in the full 474 passed / 2 optional skips suite above.
  • Both the installed wheel with published core and the checkout with source core pass that full suite on both SDK versions. The independent reviewer's original 11 contracts now pass on each SDK version; the existing recipe remains 58 passing on each.
  • Python 3.10 also passes the full suite (474 passed, 2 optional skips). With the Poetry-locked core 1.1.0, 470 pass / 6 skip: four masking-only variants explicitly skip because that core predates the optional feature. All lifecycle behavior still runs; cancellation messages are checked at the awaiting task only on Python 3.11+, where the runtime propagates them. These compatibility adjustments resolve the first CI run's test-only failures.
  • The floor/latest CI matrix now includes lifecycle and existing context-manager regression tests. Base dev was refreshed and already contained in the branch; no force-push or duplicate PR was needed.

Review round 2 async close alias follow-up

The latest SDK's AsyncStream.aclose() alias bypassed the proxy's instrumented close(), so direct calls and contextlib.aclosing() closed HTTP responses without finishing early stream spans. This was another pre-existing lifecycle gap, not a provider-matcher regression.

  • Route aclose() through the same instrumented close path, retaining SDK response cleanup, exception/cancellation propagation and once-only span finalization.
  • Add 16 native-transport cases across dedicated/regional endpoints: direct alias and stdlib context cleanup before consumption, after partial consumption and after exhaustion; repeated mixed cleanup; alias cleanup failures; and actual cancellation during alias cleanup.
  • Failing-first latest-SDK installed wheel: 12 failed, 30 passed in the expanded lifecycle suite. Fixed latest lifecycle suite: 42 passed. Floor retains 26 passing lifecycle cases and explicitly skips the 16 alias-only cases.
  • Full fixed installed-wheel suite with published core 1.2.2: 474 passed / 18 skipped on floor and 490 passed / 2 skipped on latest. Independent review contracts: 11 passed / 6 alias skips on floor and 17 passed on latest. Existing Baseten recipes remain 58 passing on each SDK.
  • All executable local checks ran inside the outbound-denying sandbox. Registry latest was independently confirmed as 3.42.1. Release plan and whitespace checks passed; refreshed dev was already contained in the branch.

Review round 3 high-level stream helper follow-up

The SDK's high-level chat.completions.stream() and responses.stream() context managers close their HTTP response directly, bypassing raw stream close. Empty and partially consumed helpers therefore lost their spans despite the earlier raw-stream fixes. The review reproducer showed 8 failures / 4 exhausted-stream controls passing on each SDK version. A task-safe, per-response close observer now finalizes these spans without replacing the SDK's helpers or adding a second span; raw stream close and cancellation keep their previous error behavior. It also preserves user exceptions and FI_HIDE_ERROR_DETAILS masking on high-level context exits.

  • Added 40 standalone contracts across both SDK versions and dedicated/regional endpoints: high-level Chat Completions and Responses, sync/async, empty/partial/exhausted consumption, user exceptions, and masked errors.
  • Failing-first expanded matrix: 16 failures / 8 passing controls on OpenAI 3.42.1; after repair all 24 passing. Full source suite: 514 passed / 18 skipped on OpenAI 1.69.0 and 530 passed / 2 skipped on OpenAI 3.42.1. Baseten recipes remain 58 passing on each SDK. All executable checks ran in the outbound-denying sandbox with synthetic transports.
  • Merged the current dev base normally. Release plan and whitespace checks pass. GitHub CI for this head is still running; no force-push, merge, or release was performed.

Review round 2 synchronous request interruption follow-up

  • A KeyboardInterrupt inside the synchronous native HTTP request previously propagated before ending its active span. The sync wrapper now finalizes it as ERROR, records the exception through the existing privacy-aware span wrapper, and re-raises the original interruption.
  • Failing-first native mock transport regressions: 4 failures / 4 successful-request controls passing on each of OpenAI 1.69.0 and 3.42.1, covering dedicated/regional Baseten routes with and without error-detail masking. Final complete Python OpenAI suites after a normal origin/dev merge: 526 passed / 18 skipped on the floor and 542 passed / 2 skipped on latest. All executable tests used an outbound-denying sandbox and synthetic credentials. Release-plan check and frozen TypeScript lockfile installation passed.

Documentation and release boundaries

The docs-site page is held locally until a release contains the corrected provider mapping; the current published traceAI-openai is 0.1.12. No docs PR, registry publication, tag, merge, or issue closure is part of this change. The existing standalone Baseten recipe remains explicitly Model APIs-only; dedicated endpoints use the OpenAI client directly.

Live Baseten calls, Future AGI Cloud execution, full docs-site rendering, and product screenshots were not performed. Baseten's separate Performance Client and non-OpenAI protocols are outside this route. The regression checks preserve the existing model attribute semantics rather than changing those shared conventions in this attribution fix.

🤖 Generated with Claude Code

nik13 and others added 11 commits November 2, 2026 08:53
Recognize bounded dedicated and regional model hostnames without treating arbitrary Baseten subdomains as model endpoints. Pin host boundaries and real SDK-to-OTLP contracts on the declared OpenAI floor and registry latest.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Preserve SDK cleanup and cancellation propagation while ending each span
once. Cover native floor/latest transports, close failures, error privacy,
and repeated cleanup in Baseten CI contracts.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Keep all lifecycle assertions on Python 3.10 while matching cancellation
messages only where Task propagates them. Only error-masking variants
skip on the Poetry-locked core that predates that optional feature.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Route the SDK alias through instrumented close so early cleanup, close errors and cancellation finish the span once. Cover direct aclose and contextlib.aclosing on dedicated and regional Baseten streams.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>

This branch has not been deployed

No deployments
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