fix(listener): bind API calls to session credentials - #3796
Draft
just-cameron wants to merge 1 commit into
Draft
Conversation
Keep listener-triggered SDK and raw API requests on the credential that authenticated the active socket, while preserving LETTA_API_KEY precedence when explicitly set. 👾 Generated with [Letta Code](https://letta.com) Co-Authored-By: Letta Code <noreply@letta.com>
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
LETTA_API_KEYprecedenceRoot cause
The listener resolved a credential when opening its WebSocket, but command handlers later resolved credentials again from process settings and credential caches. If saved credentials changed while the socket remained active, listener-triggered model/provider requests could target a different Cloud project than the session that delivered the command.
The listener now carries the credential selected during connection setup into its message-dispatch async context. API client creation and raw API request configuration consult that context before saved settings or cached credentials. Explicit
LETTA_API_KEYremains authoritative.Validation
bun test src/websocket/listener/auth-lifecycle.test.tsbun test src/websocket/listener/message-router.test.ts src/websocket/listener/commands/model-toolset.test.ts src/providers/connect-provider-service.test.tsbun run checkThe listener lifecycle regression opens a real WebSocket, changes the saved API key without reconnecting, dispatches
list_models, and verifies both SDK-backed model requests and raw provider requests retain the socket credential. It also verifies a subsequently setLETTA_API_KEYstill overrides the session credential.Limits and risk
This changes credential selection only for API work spawned from an authenticated listener message. TUI and other non-listener callers retain their existing resolution behavior. It does not add a separate project-mismatch warning, and a
LETTA_API_KEYpresent in the listener process remains authoritative by design.The highest-risk surface is async credential scope leaking across concurrent listener sessions.
AsyncLocalStorageconfines the value to each message-dispatch chain, and the credential is stored separately from the runtime snapshot to keep it out of tool context and diagnostics. Rollback is limited to removing the listener credential scope and the two API-resolution lookups.Addresses #3781.
AI disclosure
Implemented by Overlord (
agent-c2adbf5c-8419-4211-8cd8-3740db164974) with Letta Code. Cameron Pfiffer directed the work and is responsible for review and submission.👾 Generated with Letta Code