fix(desktop): disambiguate provider API key labels and annotate mint key - #4406
Merged
Conversation
… key
Credential fields across Agent Defaults, agent edit, and agent create
dialogs previously used a hardcoded ternary that rendered any non-Anthropic
provider as 'OpenAI API Key'. OpenRouter's field was mislabeled; users
configuring an OpenRouter agent saw 'OpenAI API Key', which is misleading
and unrelated to the OPENAI_COMPAT_API_KEY it actually writes. The same
root cause made OPENAI_COMPAT_API_KEY and OPENAI_API_KEY visually
indistinguishable in the UI, contributing to the confusion reported in the
trading cards flow.
Add apiKeyLabel to PROVIDER_CREDENTIAL_CONFIG (single source of truth
alongside secretEnvVar and requiredEnvKeys) and expose
getProviderApiKeyLabel(providerId) next to getProviderApiKeyEnvVar. All
three ternaries in AgentConfigFields, AgentInstanceEditDialog, and
AgentDefinitionDialog are replaced with the helper. OpenRouter now reads
'OpenRouter API Key'; Anthropic reads 'Anthropic API Key'; OpenAI/compat
read 'OpenAI API Key'.
Add an optional envVarName prop to PersonaProviderApiKeyField that renders
the backing env var name as a muted monospace hint beneath the label. All
three call sites pass the secretEnvVar they already hold. A user who saw
OPENAI_API_KEY in the mint dialog can now tell at a glance that this field
is OPENAI_COMPAT_API_KEY, not the card-minting key.
Add an optional keyAnnotations prop to EnvVarsEditor. When a required or
user-managed row's key appears in the map, a muted one-line note renders
beneath it. AgentConfigFields passes { OPENAI_API_KEY: 'Used for minting
agent trading cards' } — the reciprocal signpost to the mint dialog's
pointer at Agent Defaults.
All ratcheted files stay within the 1000-line limit. 14 new tests added:
8 for getProviderApiKeyLabel, 4 for keyAnnotations lookup invariants, 2
for PersonaProviderApiKeyField export shape.
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
…oral tests Finding 1 — label collision: rename openai->'OpenAI Runtime API Key' and openai-compat->'OpenAI-compatible Runtime API Key' so the runtime credential field and the mint dialog never present different OPENAI_* vars under the same human label. Update personaModelDiscoveryStatus.ts to name the compat key explicitly (OPENAI_COMPAT_API_KEY) in the warning copy; pin the new text in its test. ProviderCredentialConfig is now a discriminated union so secretEnvVar and apiKeyLabel are always either both present or both absent — a future provider cannot ship a secret with no label. Finding 2 — signpost visible at the decision point: export CARD_MINT_KEY_ANNOTATIONS from agentConfigOptions.tsx (single source, no per-file duplication). Pass keyAnnotations to all three generic env editors: both EnvVarsEditor branches in AgentConfigFields, EditAgentAdvancedFields, and PersonaAdvancedFields. Add CardMintKeyCue — an always-visible muted cue beneath the Advanced toggle that fires when OPENAI_API_KEY is set in global env (Advanced is collapsed by default, so the per-row annotation is invisible on Will's exact databricks_v2 path until the cue guides the user to open it). Finding 3 — ratchet: AgentConfigFields.tsx at 994 (<=996); AgentInstanceEditDialog at 1228 (<=1228); AgentDefinitionDialog at 1045 (<=1047). Finding 4 — behavioral tests: PersonaProviderApiKeyField renders semantic label, env-var hint, and aria-describedby wiring; omitted-prop case verified. EnvVarsEditor render confirms annotation on matching row only. Playwright: stale 'OpenAI API Key' selectors in persona-env-vars.spec.ts updated; new card-mint-key-cue-visible-and-annotation-in-advanced test covers Will's exact path (databricks_v2 global provider + saved OPENAI_API_KEY -> cue visible before opening Advanced -> annotation present after). MINOR (a): ProviderCredentialConfig is now a discriminated union. MINOR (b): PR description updated — rationale uses independent endpoint namespaces rather than 'minting calls real OpenAI'. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
…ent duplicate IDs in nested dialogs Hardcoded 'persona-provider-api-key' / 'persona-provider-api-key-hint' IDs caused duplicate-ID collisions when AgentInstanceEditDialog mounted its credential field while its nested AgentDefaultsDialog was also open. The nested input's aria-describedby resolved to the parent field's hint paragraph, announcing the wrong env-var name to assistive technology. Generate both inputId and hintId from React.useId() so each instance gets a unique suffix. data-testid stays fixed for E2E selectors. Test: adds two-instance rendering test asserting unique hint IDs and that each input's aria-describedby resolves to its own hint, rendered inside a single React root (the accurate model of the nested-dialog DOM). Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
…iKeyField - Rewrite extractAllAttrs to use String.matchAll instead of re.exec in a while-assignment, resolving noAssignInExpressions lint violation - Apply Biome formatter to split the hintId ternary across lines Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Member
Author
Screenshots1. OpenAI Runtime API Key — relabeled field with
|
Contributor
|
yeah the repeated "openai api key" label on non-openai providers was confusing — calling out mint-key vs provider key separately should help. |
wpfleger96
added a commit
that referenced
this pull request
Aug 3, 2026
…int dialog (#4140) Fixes a write-once dead-end in the card mint dialog where a user with an expired OpenAI key had no way to replace it. **Source-aware key status (Rust + TypeScript).** `card_mint_key_status` returns a layer discriminant (`"none" | "global" | "persona" | "agent" | "process"`) instead of a boolean. A pure `resolve_key_layer()` helper in `card.rs` owns the classification logic; `card_mint_key_status` delegates to it, so the production path is under direct test with no duplicate logic. **Mint form always reachable.** The key panel replaces the mint form only for `none` (first-time setup) or when the user explicitly opens the edit panel (`editingKey`). Keys from agent/persona/process layers show an inline provenance row on the mint form with a "Why?" affordance; clicking it shows the read-only redirect in a panel with a Cancel button that returns to the mint form — never a terminal state. **Precise auth-error matching.** The 401 handling in `cardMintStore.ts` matches `startsWith("Card mint failed (HTTP 401 ")` plus the specific `Incorrect API key` text, so avatar-fetch 401 errors pass through unchanged. **Tri-state key status row.** "Using your saved OpenAI key · Update" renders only when `keyLayer === "global"` (confirmed writable key). Query pending or errored hides the row without asserting key existence. **Real tests.** Panel visibility derivations live in `cardMintKeyUtils.ts`, which `AgentCardMintDialog.tsx` imports directly. Tests cover all layers including the mint-reachability invariant (Mint reachable for every resolved layer; only `none` gates setup). - `card.rs` — new `resolve_key_layer()` pure helper; `card_mint_key_status` delegates to it; 999 lines (under the 1000-line ratchet) - `card/tests.rs` — precedence test calls `resolve_key_layer()` directly (no test-local closure); adds process-layer and blank-value cases - `tauriPersonas.ts` — `CardMintKeyLayer` type; updated `cardMintKeyStatus` signature - `cardMintKeyUtils.ts` — `showKeyPanel`, `showReadOnlyRow`, `showCancelButton`, `keyPanelTitle`, and helpers; component imports all of them - `AgentCardMintDialog.tsx` — inline provenance rows for all key sources; key panel only for setup/edit; no unused variables - `cardMintStore.ts` — precise 401 prefix matching - `e2eBridge.ts` — `card_mint_key_status` stub returns `"global"` (not boolean) - Tests: 3959 JS passing, 2089 Rust passing, `tsc --noEmit` clean Related: [#4406](#4406) --------- Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Co-authored-by: npub1ng3jzsaqxdhrfq22dg85j3lpr0zsh3jp7g2h9jyxl59wraayapnsu6kvfg <9a232143a0336e34814a6a0f4947e11bc50bc641f21572c886fd0ae1f7a4e867@buzz.block.builderlab.xyz>
tlongwell-block
pushed a commit
that referenced
this pull request
Aug 3, 2026
The pre-push branch-skew hook correctly refused a tree CI will never test: origin/main advanced over desktop/src/testing/e2eBridge.ts, which this branch also carries via its base. Merging the PR's own base rather than origin/main directly: 4c257c8 already contains current main (5e0efb0) AND Max's resolution of that exact e2eBridge.ts overlap, certified with Desktop Smoke E2E (1) green. Re-resolving main's conflict here would duplicate that work and risk diverging from it. Merge-only, no rebase, no force. merge-tree reported 0 conflicts. Co-authored-by: npub17jjz49l9jjmhhk7cac63j8yt9z555n9cw8vk7v5jz4vzw4ppld5qgj57cc <f4a42a97e594b77bdbd8ee35191c8b28a94a4cb871d96f32921558275421fb68@buzz.block.builderlab.xyz> Signed-off-by: npub17jjz49l9jjmhhk7cac63j8yt9z555n9cw8vk7v5jz4vzw4ppld5qgj57cc <f4a42a97e594b77bdbd8ee35191c8b28a94a4cb871d96f32921558275421fb68@buzz.block.builderlab.xyz> * origin/max/tui-renderer: fix(desktop): disambiguate provider API key labels and annotate mint key (#4406) fix(desktop): make OpenAI key re-enterable after first save in card mint dialog (#4140) fix(config-bridge): add harness-definition env tier and fix equal-value model override (#3580) test(desktop): prove channel repair boundary Polish mobile composer and messaging UI (#3918) ci(linux): enable mesh-llm feature in Linux release and canary builds (#4524) test(desktop): arm validation error before read test(desktop): atomically start channel validation fix(desktop): retain terminal focus on viewport click test(desktop): isolate deferred channel read fix(desktop): stop the terminal fade clobbering the app surface's compositor hint Revert "Merge PR #4523: close channel validation latch race" test(desktop): close channel validation latch race
wpfleger96
pushed a commit
that referenced
this pull request
Aug 3, 2026
…ed-unread * origin/main: (44 commits) chore(release): release Buzz Desktop version 0.5.4 (#4562) test(mobile): assert follow boundary semantics (#4559) docs(release): align desktop handoff instructions (#3988) fix: report agent usage per provider round, not once per turn (#4545) fix(desktop): harden Windows installs against Defender block and orphaned Node (#4382) feat(desktop): improve channel template discovery (#4549) fix(desktop): save key backups to authorized path (#4022) Add channel activity hover menu (#3935) feat(desktop): show saved Run on settings when editing an agent (#4539) fix(desktop): disambiguate provider API key labels and annotate mint key (#4406) fix(desktop): make OpenAI key re-enterable after first save in card mint dialog (#4140) fix(config-bridge): add harness-definition env tier and fix equal-value model override (#3580) Polish mobile composer and messaging UI (#3918) ci(linux): enable mesh-llm feature in Linux release and canary builds (#4524) fix(desktop): stop the create-agent provider config probe from erasing keystrokes (#4411) fix(mobile): recover and pace live subscriptions (#3053) feat(acp): deliver system prompt via _meta.systemPrompt for claude-agent-acp (#4395) fix(security): bump nostr crates for RUSTSEC-2026-0225..0232 + default sprig image to published digest (#4392) fix(desktop): back/forward via keyboard chords, mouse X1/X2 buttons, and swipe gestures (#3778) feat(k8s): Kubernetes backend plugin + desktop deploy path (#4289) ... Signed-off-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
wpfleger96
added a commit
that referenced
this pull request
Aug 3, 2026
Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com> * origin/main: (40 commits) fix(mobile): recover stale relay sessions (#4372) chore(release): release Buzz Desktop version 0.5.4 (#4562) test(mobile): assert follow boundary semantics (#4559) docs(release): align desktop handoff instructions (#3988) fix: report agent usage per provider round, not once per turn (#4545) fix(desktop): harden Windows installs against Defender block and orphaned Node (#4382) feat(desktop): improve channel template discovery (#4549) fix(desktop): save key backups to authorized path (#4022) Add channel activity hover menu (#3935) feat(desktop): show saved Run on settings when editing an agent (#4539) fix(desktop): disambiguate provider API key labels and annotate mint key (#4406) fix(desktop): make OpenAI key re-enterable after first save in card mint dialog (#4140) fix(config-bridge): add harness-definition env tier and fix equal-value model override (#3580) Polish mobile composer and messaging UI (#3918) ci(linux): enable mesh-llm feature in Linux release and canary builds (#4524) fix(desktop): stop the create-agent provider config probe from erasing keystrokes (#4411) fix(mobile): recover and pace live subscriptions (#3053) feat(acp): deliver system prompt via _meta.systemPrompt for claude-agent-acp (#4395) fix(security): bump nostr crates for RUSTSEC-2026-0225..0232 + default sprig image to published digest (#4392) fix(desktop): back/forward via keyboard chords, mouse X1/X2 buttons, and swipe gestures (#3778) ...
wpfleger96
added a commit
that referenced
this pull request
Aug 3, 2026
Syncs Cargo.lock and ci.yml updates from origin/main via the umbrella, which resolves the RUSTSEC-2026-0225..0229 nostr advisory failures in the Security gate. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com> * commit 'ad9ae1dbb0c2d9b6839c1e18d6fd6a78238b61fb': (40 commits) fix(mobile): recover stale relay sessions (#4372) chore(release): release Buzz Desktop version 0.5.4 (#4562) test(mobile): assert follow boundary semantics (#4559) docs(release): align desktop handoff instructions (#3988) fix: report agent usage per provider round, not once per turn (#4545) fix(desktop): harden Windows installs against Defender block and orphaned Node (#4382) feat(desktop): improve channel template discovery (#4549) fix(desktop): save key backups to authorized path (#4022) Add channel activity hover menu (#3935) feat(desktop): show saved Run on settings when editing an agent (#4539) fix(desktop): disambiguate provider API key labels and annotate mint key (#4406) fix(desktop): make OpenAI key re-enterable after first save in card mint dialog (#4140) fix(config-bridge): add harness-definition env tier and fix equal-value model override (#3580) Polish mobile composer and messaging UI (#3918) ci(linux): enable mesh-llm feature in Linux release and canary builds (#4524) fix(desktop): stop the create-agent provider config probe from erasing keystrokes (#4411) fix(mobile): recover and pace live subscriptions (#3053) feat(acp): deliver system prompt via _meta.systemPrompt for claude-agent-acp (#4395) fix(security): bump nostr crates for RUSTSEC-2026-0225..0232 + default sprig image to published digest (#4392) fix(desktop): back/forward via keyboard chords, mouse X1/X2 buttons, and swipe gestures (#3778) ...
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.





Two different credentials were presented under the same name throughout the app. The top-level credential field for non-Anthropic providers (OpenAI, OpenAI-compatible, OpenRouter) was labeled "OpenAI API Key" via a hardcoded binary ternary repeated in three dialogs. The card-minting key (
OPENAI_API_KEY) and the runtime credential (OPENAI_COMPAT_API_KEY) have independent endpoint namespaces and consumers (OPENAI_COMPAT_BASE_URL/OPENAI_COMPAT_API_KEYfor runtime,OPENAI_BASE_URL/OPENAI_API_KEYfor minting) and must remain separate — either may require a different credential. This PR makes them impossible to confuse in the UI.Changes
Provider-accurate labels from the credential table.
PROVIDER_CREDENTIAL_CONFIGentries now carry anapiKeyLabelpaired withsecretEnvVaras a discriminated union (both present or neither — a future provider cannot ship a secret field with no label).getProviderApiKeyLabel(providerId)is the single source of truth. The three hardcoded ternaries inAgentConfigFields,AgentInstanceEditDialog, andAgentDefinitionDialogare replaced by this helper. Labels:openai→ "OpenAI Runtime API Key",openai-compat→ "OpenAI-compatible Runtime API Key",openrouter→ "OpenRouter API Key" (was incorrectly "OpenAI API Key"),anthropic→ "Anthropic API Key" (unchanged).Field names its backing env var.
PersonaProviderApiKeyFieldrenders the env var name as a monospace hint beneath the label witharia-describedbywiring. All three call sites pass theirsecretEnvVar. A user who seesOPENAI_API_KEYin the mint dialog can now confirm at a glance that the credential field showsOPENAI_COMPAT_API_KEY— a different key.Signpost visible at the decision point.
CARD_MINT_KEY_ANNOTATIONSis exported fromagentConfigOptions.tsx(single source) and passed askeyAnnotationsto all three generic env editors: bothEnvVarsEditorbranches in Agent Defaults,EditAgentAdvancedFields, andPersonaAdvancedFields.CardMintKeyCue— a new small component — renders an always-visible muted cue beneath the Advanced toggle whenOPENAI_API_KEYis present in global env (Advanced is collapsed by default, so the per-row annotation is invisible until the cue guides the user to open it).Model discovery error copy. The
OPENAI_COMPAT_API_KEY requiredmessage now reads "Enter an OpenAI runtime API key (OPENAI_COMPAT_API_KEY) to load OpenAI models." — naming the env var explicitly so it cannot be confused with the mint key.Tests
getProviderApiKeyLabelhelper: pinned correct label per provider including the new distinct labels foropenaiandopenai-compatPersonaProviderApiKeyFieldrender: semantic label present; env-var hint rendered whenenvVarNameprovided;aria-describedbywired to hint id; hint and describedby absent when prop omittedEnvVarsEditorrender: annotation appears exactly once on the matching row; absent for non-matching rowspersonaModelDiscoveryStatus: pinned new copy namingOPENAI_COMPAT_API_KEYexplicitly"OpenAI API Key"selectors updated; newcard-mint-key-cue-visible-and-annotation-in-advancedtest covers Will's exact path (databricks_v2 global provider + savedOPENAI_API_KEY→ cue visible before opening Advanced → annotation present after opening)File sizes (post-format)
AgentConfigFields.tsxAgentInstanceEditDialog.tsxAgentDefinitionDialog.tsxRelated: #4140