Skip to content

fix(listener): bind API calls to session credentials - #3796

Draft
just-cameron wants to merge 1 commit into
mainfrom
overlord/fix-cloud-credential-project-mismatch
Draft

fix(listener): bind API calls to session credentials#3796
just-cameron wants to merge 1 commit into
mainfrom
overlord/fix-cloud-credential-project-mismatch

Conversation

@just-cameron

Copy link
Copy Markdown
Contributor

Summary

  • scope listener-dispatched API work to the credential that authenticated the active WebSocket session
  • apply that session credential to both SDK-backed and raw API request paths without copying the secret into the public runtime context
  • preserve explicit LETTA_API_KEY precedence

Root 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_KEY remains authoritative.

Validation

  • bun test src/websocket/listener/auth-lifecycle.test.ts
  • bun test src/websocket/listener/message-router.test.ts src/websocket/listener/commands/model-toolset.test.ts src/providers/connect-provider-service.test.ts
  • bun run check

The 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 set LETTA_API_KEY still 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_KEY present in the listener process remains authoritative by design.

The highest-risk surface is async credential scope leaking across concurrent listener sessions. AsyncLocalStorage confines 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

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