revert: AuthenticationContext ambient primitive (#259)#260
Merged
Kamilbenkirane merged 1 commit intomainfrom Apr 15, 2026
Merged
revert: AuthenticationContext ambient primitive (#259)#260Kamilbenkirane merged 1 commit intomainfrom
Kamilbenkirane merged 1 commit intomainfrom
Conversation
This reverts commit ff60c19. Reverting per YAGNI + design error found in downstream analysis. The shipped AuthenticationContext was keyed per-Provider, assuming a single Authentication is bound to a provider. Downstream analysis in a multi-modal, multi-provider context revealed this collapses cases where a single provider legitimately exposes DIFFERENT auth for different (modality, operation) pairs — e.g. OAuth for one operation and API-key for another. A per-Provider AuthenticationContext cannot represent both in the same scope and silently drops one. Independent of that correctness gap, the primitive was not actually needed: primitive peer SDKs (openai-python, anthropic-sdk-python, google-genai) have no ambient auth state and handle multi-tenancy via per-request client construction. celeste-python's own create_client() already supports this natively — it returns a ModalityClient with the auth bound at construction, which is the primitive-tier "bind once, call many" pattern. An ambient ContextVar-backed primitive is a framework-tier idea grafted onto the primitive layer. No downstream consumer actually adopted the primitive, so the revert has zero external breakage. create_client(auth=...) remains the supported path for reusable, auth-bound clients.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Reverts #259 — the
AuthenticationContext/authentication_scope/resolve_authentication/MissingAuthenticationErrorprimitive — per YAGNI plus a design error surfaced during downstream integration.Why
1. Per-Provider keying collapses real-world divergent auth
The shipped shape was
AuthenticationContext.entries: Mapping[Provider, Authentication]— one authentication per provider, bound for the whole async scope. This assumed a single Authentication is sufficient per provider.Multi-modal integration analysis showed that's not always true: a single provider can legitimately expose different authentication mechanisms for different
(modality, operation)pairs. For example, a provider may use API-key auth for one operation and OAuth (bearer-token) auth for another — they're not the sameAuthenticationclass, not the same secret, and not interchangeable. A per-Provider scope can only hold one of them; the other is silently lost.Moving to per-
(modality, operation)keying would have been possible but leads to the next point.2. The primitive isn't needed —
create_client()already handles thisPrimitive-tier peers (
openai-python,anthropic-sdk-python,google-genai) have no ambient authentication state — not inContextVar, not inthreading.local, not anywhere. Their multi-tenant story is per-request client construction:OpenAI(api_key=...),Anthropic(api_key=...),genai.Client(api_key=...). Each request builds its own client; theapi_keybinds at the client level; subsequent calls on that client reuse it.celeste-python already supports the identical pattern via
create_client(), which returns aModalityClientwithmodel,auth,provider,protocol, andbase_urlbound at construction:This is the primitive-tier "bind once, call many" pattern. It handles divergent per-(modality, operation) auth naturally — callers simply construct one client per slot, each with its own
auth=.Ambient ContextVar-backed authentication is a framework-tier convention (Flask
g, structlogbind_contextvars, DSPydspy.context, LangChainRunnableConfig). celeste-python positions itself as a primitive, and none of its primitive peers do this.AuthenticationContextimported a framework-tier idea into a layer whose peers deliberately reject it.3. Zero downstream adoption
No consumer has actually wired
authentication_scope(...)around any run. The primitive shipped but was never exercised in a downstream integration, so reverting has no external-breakage surface.What this changes for users
Nothing. All pre-#259 APIs remain intact:
celeste.text.generate(prompt, model="...", auth=...)— per-call auth (unchanged)celeste.text.generate(prompt, model="...", api_key="...")— per-call api_key (unchanged)create_client(modality=..., operation=..., model=..., auth=...)— bound-auth client reuse (unchanged, and remains the recommended path)Authentication/AuthHeader/NoAuth/APIKey/register_auth/get_auth_class— all keptcredentials.get_auth(...)— unchangedWhat's removed (all introduced by #259, no other usage):
AuthenticationContextclassauthentication_scope(...)context managerresolve_authentication(provider)lookupMissingAuthenticationErrorexceptioncreate_client()(~2 lines)test_authentication_context.pytest coverage folded back intotest_auth.pyTest plan
uv sync --all-extrasuv run ruff check src tests— cleanuv run ruff format --check src tests— clean (394 files)uv run mypy src/celeste— clean (331 files, 0 issues)uv run pytest tests/unit_tests -q— 586 passed (0 failures)