feat(proxy): support per-user upstream LLM API key configuration - #970
Open
dong-frank wants to merge 1 commit into
Open
feat(proxy): support per-user upstream LLM API key configuration#970dong-frank wants to merge 1 commit into
dong-frank wants to merge 1 commit into
Conversation
Allow each signed-in user to bind their own upstream LLM API key from the panel, and have the proxy use that user's key (never the global/agent key) when forwarding to the upstream provider. - core: add 'llm' config module with 'api_key' param scoped to global/user - panel: add 'upstream LLM' tab in SettingsDialog to view/save/clear the key for the currently logged-in user (password field, per-user via config/user set) - proxy: resolve the caller's own upstream key via getUserUpstreamApiKey and inject it into both the primary and retry upstream auth headers; keep empty (passthrough) when unconfigured, never falling back to the global/agent key Signed-off-by: dong-frank <1057762929@qq.com>
Collaborator
|
Thank you for your attention and contribution! We will schedule an internal review of this PR, and we will share any feedback right here. |
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
Currently the proxy forwards each chat request to the upstream LLM using a single shared upstream
apiKey(global config or per-agent entry). This forces every user to share one key — a real problemwhen different users are billed against their own accounts, or when an org wants each member to bring
their own provider key.
This PR lets each signed-in user bind their own upstream LLM API key from the panel, and makes the
proxy use that user's key (never the global/agent key) when forwarding to the upstream provider. The
key is stored in the core config params (scoped to
user), read back dynamically at request time via anew
getUserUpstreamApiKeycall, and injected into the upstreamauthorizationheader on both the primaryand retry paths.
Security-wise, the lookup is authenticated with the caller's own user key (
x-tdai-user-key) and enforcedon the core side by
assertCallerIsOwner, so a user can only ever read their own key — no cross-user access.Problem
MemoryProxy/src/handler.tsresolves the upstream key solely fromconfig.upstream.apiKey/ the agententry, so there is no notion of a per-user key. Consequences:
with the shared one, or must rely on the client passing its own key and hope the proxy doesn't override it.
Fix
Three sides cooperate; the core config store is the single source of truth, the proxy reads it
dynamically at request time, and the panel exposes the configuration UI.
1. core — new
llm.api_keyconfig param (user-scoped)MemoryCore/src/metadata/config/metadata_config_params.json: added anllmmodule with anapi_keyparam (default
"",allowed_scopes: ["global", "user"]). User-scoped values are set via the existingconfig/user/setroute and automatically override the global value when read — no new storage logic.2. proxy — resolve and inject the caller's own key
MemoryProxy/src/handler.ts:userIdis resolvable and the user has a configured key, that key is used.resolvedApiKeystays""— the proxy does not fall back to theglobal/agent key, so the client's own key passes through and an upstream auth failure prompts the user
to configure theirs.
userIdcannot be resolved (e.g. auth disabled).MemoryProxy/src/tdai/client.ts: addedgetUserUpstreamApiKey(userKey, userId)which POSTs/v3/meta/config/user/getformodule:"llm", param_name:"api_key", authenticated with the caller's ownx-tdai-user-keyso core'sassertCallerIsOwnerrestricts reads to self. It is fail-open: on anynetwork/HTTP/envelope error it returns
""(never throws, never blocks forwarding).3. panel — "upstream LLM" configuration tab
MemoryPanel/web/src/components/SettingsDialog.tsx: added an 「上游 LLM / Upstream LLM」 tab thatreads the current logged-in user's
llm/api_key(config/user/get) and lets them save (config/user/set)or clear it, rendered as a
type="password"field. I18n keys added inen-US.ts/zh-CN.ts.Test Plan
value, saves/clears it correctly, and persists to the core config store.
authorization: Bearer <user key>into the upstream request on both the primary and retry paths.
empty (client key passthrough) instead of substituting the global/agent key.
git diffagainst the basefeat/server_teamconfirms the PR touches only the 6 intended files(config param, panel tab, 2 i18n files, proxy handler, proxy tdai client) with no unrelated changes.
Related Issues
None. No upstream issue exists for this capability; this is a direct contribution.
Contributor