Skip to content

feat(desktop): configure OpenAI-compatible base URLs - #3798

Open
am423 wants to merge 3 commits into
block:mainfrom
am423:feat/openai-compat-base-url-ui
Open

feat(desktop): configure OpenAI-compatible base URLs#3798
am423 wants to merge 3 commits into
block:mainfrom
am423:feat/openai-compat-base-url-ui

Conversation

@am423

@am423 am423 commented Jul 30, 2026

Copy link
Copy Markdown

Summary

Add complete custom OpenAI-compatible endpoint configuration for the native Buzz Agent.

The current desktop flow exposes an API-key field for the OpenAI-compatible provider but does not expose the endpoint location. This PR adds the missing Base URL field and carries it through persistence, inheritance, native configuration, and requests.

Changes

  • Add an optional OpenAI-compatible Base URL field to global/default configuration, agent creation, and existing-agent editing.
  • Persist the canonical OPENAI_COMPAT_BASE_URL value through the existing env_vars maps.
  • Keep blank values backward-compatible with the native OpenAI default endpoint.
  • Validate non-empty values as http:// or https:// URLs and block invalid configuration.
  • Preserve global, persona, runtime-file, and build-layer inheritance behavior.
  • Hide structured API-key and Base URL variables from duplicate Advanced rows.
  • Resolve native endpoint precedence as:
    OPENAI_COMPAT_BASE_URL > OPENAI_BASE_URL > https://api.openai.com/v1.
  • Add desktop unit/E2E coverage, native Rust resolver coverage, and documentation.

Validation

Passed:

  • pnpm test — 3,853 passed, 0 failed
  • Focused endpoint/config tests — 42 passed
  • pnpm typecheck
  • Biome checks
  • Desktop file-size ratchet
  • cargo test -p buzz-agent — 383 unit tests plus integration suites passed
  • Repository pre-commit checks

just ci was rerun after installing the repository-documented Linux/Tauri prerequisites (libatk1.0-dev, libgdk-pixbuf-2.0-dev, libgtk-3-dev, WebKitGTK, Ayatana, audio, SVG, XDo, and related development packages). The Tauri/Rust and web stages passed. The gate then failed on one unrelated, reproducible pre-existing mobile test:

  • mobile/test/features/channels/channel_detail_page_test.dart:1053
  • ChannelDetailPage keeps follow mode off while a tall newest message stays visible
  • Expected no Newest live update widget, but one was found.

The failing test also fails when rerun in isolation. No changed file is involved.

Related work

No credentials or secrets are included.

am423 added 2 commits July 30, 2026 14:50
…back

Resolve OpenAI-compatible base URL with pure precedence:
non-blank OPENAI_COMPAT_BASE_URL (desktop canonical) >
non-blank OPENAI_BASE_URL (generic SDK) >
https://api.openai.com/v1.

Blank/whitespace values fall through so a empty native override cannot
block generic fallback or the default. Keeps default …/v1 path joining
and is_openai_host Auto→Responses routing intact.

Signed-off-by: mr-r0b0t <adam.manning@gmail.com>
Signed-off-by: mr-r0b0t <adam.manning@gmail.com>
@am423
am423 requested a review from a team as a code owner July 30, 2026 20:19

@tlongwell-block tlongwell-block left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at exact head 9d609993bfdead6f4d73d39b5fd490e586bfae2e in a fresh worktree, git rev-parse HEAD confirmed in the same shell as every run below.

Verified locally at this head:

  • pnpm test: 3,853 passed, 0 failed (matches PR body)
  • pnpm typecheck + pnpm check (Biome, file-size ratchet, px-text, pubkey guards): clean
  • cargo test -p buzz-agent: 383 unit + integration suites, 0 failed (matches PR body)
  • Rust resolver precedence, blank/whitespace fall-through, and is_openai_host default preservation all read correct

Blocking: your own new E2E test fails deterministically — this is the red Desktop Smoke E2E (2) check.

tests/e2e/edit-agent.spec.ts:281 ("openai-compatible base URL field persists and is hidden from Advanced") fails on the reopen assertion at line 342: getByTestId('persona-provider-base-url') — element not found. Reproduced locally at this exact head; it failed all 3 retries on both CI attempts.

Root cause: the e2e mock bridge's update_managed_agent handler (desktop/src/testing/e2eBridge.ts ~line 8176) echoes name/model/systemPrompt/envVars/respondTo into the mock store but ignores provider. On reopen the LLM provider reverts to unset ("Select a provider…" — visible in the failure screenshot), providerOwnsBaseUrlField returns false, and the base-URL field never renders. The real backend does persist provider (agent_config.rs), so this is a mock gap, not a product bug — but the check is red either way.

Minimal fix, verified to turn the test green locally:

// handleUpdateManagedAgent input type:
provider?: string | null;
// handler body:
if (args.input.provider !== undefined) {
  agent.provider = args.input.provider;
}

(Also update the mock-boundary caveat comment at the top of edit-agent.spec.ts, which currently documents that the handler ignores provider.)

Non-blocking findings:

  1. ~70 lines of dead exports in PersonaProviderStructuredEnvFields.tsx: renderPersonaProviderStructuredEnvFields and isOpenAiCompatBaseUrlOwned have zero callers anywhere in the repo. Notably, AgentInstanceEditDialog.tsx re-implements isOpenAiCompatBaseUrlOwned inline (baseUrlPersonaSatisfied) instead of calling it. Either wire them up or delete them.
  2. The README row for OPENAI_COMPAT_API was changed from \| to \\| — an untouched feature-wise line. GitHub renders both identically (verified via the markdown API), so this is pure churn; please revert.
  3. The Rust fallback commit substantially duplicates open PR #3705 (different author). You disclose the overlap, but two open PRs racing on the same lines needs a maintainer call — consider rebasing onto or superseding it explicitly rather than carrying a parallel implementation.
  4. Several unrelated blank-line deletions in AgentConfigFields.tsx add diff noise.

The core design is sound: the base-URL field mirrors the API-key field's layering (local > persona > global > build > file), blank stays backward-compatible, validation is scoped to non-empty values, and hiding structured keys from Advanced prevents duplicate rows. Fix the mock-bridge gap and this is close.

…ndings

Addresses @tlongwell-block's review on PR block#3798.

Blocking — e2e mock bridge gap (Desktop Smoke E2E (2)):
The update_managed_agent handler in e2eBridge.ts echoed
name/model/systemPrompt/envVars/respondTo into the mock store but ignored
provider. On dialog reopen the LLM provider reverted to unset,
providerOwnsBaseUrlField returned false, and the base-URL field never
rendered — failing edit-agent.spec.ts:281 at the reopen assertion. The
real backend persists provider (agent_config.rs Option<Option<String>>
tri-state) and the frontend sends it; this was purely a mock gap. Add
provider to the handler input type and echo it into the store. Update the
mock-boundary caveat comment in edit-agent.spec.ts accordingly.

Non-blocking:
- Delete dead renderPersonaProviderStructuredEnvFields export (65 lines,
  zero callers) from PersonaProviderStructuredEnvFields.tsx. Wire
  AgentInstanceEditDialog's inline baseUrlPersonaSatisfied duplicate to
  call the now-shared isOpenAiCompatBaseUrlOwned export.
- Revert README OPENAI_COMPAT_API row from \\| back to \| (cosmetic
  churn on an untouched feature line; GitHub renders both identically).
- Restore 3 unrelated blank-line deletions in AgentConfigFields.tsx that
  added diff noise.

Verified locally at 9d60999 + this commit:
- edit-agent.spec.ts:281 green (was deterministically red)
- pnpm test: 3,853 passed, 0 failed
- cargo test -p buzz-agent: 22 passed, 0 failed
- tsc --noEmit: clean
- biome check: clean

Signed-off-by: mr-r0b0t <adam.manning@gmail.com>
@amanning3390

Copy link
Copy Markdown
Contributor

Review resolution — 9d6099936c5b8893

Thanks @tlongwell-block for the thorough review. All findings addressed below; verified locally at the exact PR head plus this commit.

✅ Blocking — e2e mock bridge gap (Desktop Smoke E2E (2))

Fixed in desktop/src/testing/e2eBridge.ts. handleUpdateManagedAgent now accepts provider?: string | null and echoes it into the mock store:

// handler body:
if (args.input.provider !== undefined) {
  agent.provider = args.input.provider;
}

The RawManagedAgent type already had provider; only the handler dropped it. The mock-boundary caveat comment in edit-agent.spec.ts is updated to list provider.

Verified: edit-agent.spec.ts:281 green (was deterministically red — failed all 3 retries on both CI attempts). Reproduced the red at 9d609993, confirmed green at 6c5b8893.

✅ Non-blocking #1 — dead exports

  • Deleted renderPersonaProviderStructuredEnvFields (65 lines, zero callers) from PersonaProviderStructuredEnvFields.tsx.
  • Wired AgentInstanceEditDialog.tsx's inline baseUrlPersonaSatisfied duplicate to call the now-shared isOpenAiCompatBaseUrlOwned export (removing the byte-identical inline copy).

✅ Non-blocking #2 — README churn

Reverted the OPENAI_COMPAT_API row in crates/buzz-agent/README.md from \\| back to \| (cosmetic-only on an untouched feature line).

✅ Non-blocking #4 — blank-line noise

Restored the 3 unrelated blank-line deletions in AgentConfigFields.tsx.

⏭️ Non-blocking #3 — PR #3705 overlap

Left as-is per your note — needs a maintainer call. My Rust fallback commit (6ff0d740) and open PR #3705 (Chukwuebuka-2003) implement the same OPENAI_BASE_URL fallback in config.rs. Happy to rebase onto #3705 or supersede it explicitly if a maintainer prefers; I'll defer to that decision here.

Local verification at 6c5b8893

Check Result
edit-agent.spec.ts:281 (the red CI check) ✅ green
pnpm test (desktop unit) ✅ 3,853 passed, 0 failed
cargo test -p buzz-agent ✅ 22 passed, 0 failed
tsc --noEmit ✅ clean
biome check . ✅ clean (exit 0)

Note: file-size ratchet (pnpm check) is red on these files pre-existing at 9d609993 (the merge-base is stale, so the ratchet sees the full growth from your earlier commits). My changes don't add to it — the dead-code removal actually reduces sizes.

Diff: 6 files, +15 / −72.


Push note: the commit is currently on amanning3390/buzz:feat/openai-compat-base-url-ui (SHA 6c5b8893). My am423 credentials aren't in this environment, so I pushed to my other fork. A maintainer with push access to am423/buzz (or me once I auth am423) can fast-forward am423:feat/openai-compat-base-url-ui to 6c5b8893. Until then CI won't re-run against the PR head. Happy to re-push from the am423 account if preferred.

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.

3 participants