Skip to content

Fix frontend settings API configuration - #33

Draft
cursor[bot] wants to merge 1 commit into
mainfrom
cursor/critical-bug-investigation-6c60
Draft

Fix frontend settings API configuration#33
cursor[bot] wants to merge 1 commit into
mainfrom
cursor/critical-bug-investigation-6c60

Conversation

@cursor

@cursor cursor Bot commented Jun 4, 2026

Copy link
Copy Markdown

Bug and impact

The frontend settings UI saved backend URLs under keys the shared API client never read (backend_base_url / agentnexus_backend_url vs api_url). Auth tokens entered in settings were also never connected to the API client after recent localStorage hardening. Users could save settings successfully but subsequent API requests still used the old backend URL and omitted Authorization headers, breaking protected flows such as executions and builder generation.

A second critical frontend blocker was found during validation: the resolved viem version did not export sendCallsSync / sendTransactionSync required by wagmi, causing the app build/dev UI to fail before rendering.

Root cause

Settings state and API request configuration diverged across three separate localStorage keys, and the token field became write-only when persistent token storage was removed. The modal also rendered inside the sticky/backdrop-filter navbar, which clipped fixed-position modal content in the browser.

Fix

  • Added a shared frontend API settings helper for backend URL resolution, legacy key migration, and memory-only auth tokens.
  • Wired the settings modal, settings page, and Axios request interceptors to the shared helper.
  • Portaled the settings modal to document.body and added scroll-safe sizing so all fields remain reachable.
  • Updated frontend viem to ^2.52.0 and aligned its override so wagmi imports resolve during build/dev.
  • Added focused Jest regression coverage for storage migration and modal save behavior.

Validation

  • pnpm --filter @agentnexus/frontend test -- --runTestsByPath src/lib/apiSettings.test.ts src/components/layout/SettingsModal.test.tsx
  • pnpm --filter @agentnexus/frontend type-check
  • Changed-file ESLint via temporary flat config ✅
  • pnpm --filter @agentnexus/frontend build
  • Browser walkthrough recording: app loads, settings modal shows both fields, URL persists after save, token field reopens blank ✅
  • python3 -m pytest

Known unrelated repo-wide gate failures observed: pnpm --filter @agentnexus/frontend test still lets Jest collect Playwright e2e specs and fails on missing TransformStream; ruff/bandit/mdformat fail on pre-existing Python/docs issues outside this frontend fix.

Open in Web View Automation 

Greptile Summary

This PR fixes a settings/API configuration split where three different localStorage keys were used across the settings modal, settings page, and Axios client — causing saved URLs and auth tokens to be silently ignored on actual requests. It introduces a shared apiSettings.ts helper that consolidates URL storage under a single api_url key with legacy key migration, stores auth tokens in memory only, and wires both settings surfaces and the Axios interceptors to this helper. The modal is also portaled to document.body to escape navbar clipping, and viem is bumped to ^2.52.0 to fix a missing export needed by wagmi.

  • URL consolidation & migration: apiSettings.ts reads from api_url, migrates backend_base_url/agentnexus_backend_url on first access, and removes the stale keys — ensuring the Axios interceptor's getApiBaseUrl() call always sees the user-configured URL without a page reload.
  • Memory-only auth token: setSessionAuthToken / getSessionAuthToken replace direct localStorage reads in the Axios auth interceptor, but both handleSave handlers call setSessionAuthToken(input?.value || '') unconditionally — so saving settings with a blank token field (the default every time the modal reopens) silently clears any previously-set in-memory token and breaks protected API calls until the token is re-entered.

Confidence Score: 3/5

The URL consolidation and legacy migration are solid, but both save handlers unconditionally overwrite the in-memory auth token with an empty value whenever the user saves settings without retyping their credential — this breaks protected API flows silently on every subsequent save.

The core settings-key fix is correct and the Axios interceptor wiring works. However, the unconditional setSessionAuthToken(input?.value || '') call in both SettingsModal.handleSave and settings/page.handleSave means that after a user sets a token and later reopens settings to adjust only the URL, clicking Save clears the credential they already entered. Protected endpoints (/executions, /builder/generate, etc.) will receive no Authorization header until the token is re-entered, which is a silent regression on exactly the protected flows this PR was meant to fix.

frontend/src/components/layout/SettingsModal.tsx and frontend/src/app/settings/page.tsx — both need the setSessionAuthToken call guarded so it only fires when the token field is non-empty.

Important Files Changed

Filename Overview
frontend/src/lib/apiSettings.ts New shared helper — URL migration logic, localStorage key consolidation, and memory-only token store are all correct; SSR guard via hasBrowserStorage() is properly applied throughout.
frontend/src/components/layout/SettingsModal.tsx Portal rendering and URL wiring are correct, but setSessionAuthToken is called unconditionally with a blank value on every save, silently clearing the in-memory auth token whenever the user saves without re-entering their credential.
frontend/src/app/settings/page.tsx Same unconditional `setSessionAuthToken(...
frontend/src/lib/api.ts Correctly delegates URL and auth-token resolution to apiSettings helpers; per-request interceptor overrides baseURL so no page reload is needed, and the removal of the localStorage auth-token read is correct.
frontend/src/lib/apiSettings.test.ts Good coverage of the key storage-migration paths and memory-only token behavior; trimming of whitespace is tested.
frontend/src/components/layout/SettingsModal.test.tsx Covers the happy-path save with a token, but is missing a test for re-saving without re-entering the token, which would expose the unconditional-clear bug.
frontend/package.json viem bumped to ^2.52.0 to satisfy wagmi's sendCallsSync/sendTransactionSync exports; @types/jest added as a dev dependency; override aligned to exact 2.52.0.

Sequence Diagram

sequenceDiagram
    participant UI as Settings Modal / Page
    participant AS as apiSettings.ts
    participant LS as localStorage
    participant AX as Axios interceptor
    participant BE as Backend API

    UI->>AS: saveApiBaseUrl(url)
    AS->>LS: setItem('api_url', url)
    AS->>LS: removeItem('backend_base_url')
    AS->>LS: removeItem('agentnexus_backend_url')

    UI->>AS: setSessionAuthToken(token or '')
    Note over AS: sessionAuthToken = token (in-memory)<br/>⚠️ empty string → sets null, clears token
    AS->>LS: removeItem('auth_token')

    AX->>AS: getApiBaseUrl()
    AS->>LS: getItem('api_url')
    AS-->>AX: resolved URL

    AX->>AS: getSessionAuthToken()
    AS-->>AX: sessionAuthToken (or null)
    AX->>BE: request with baseURL + optional Authorization header
Loading

Comments Outside Diff (1)

  1. frontend/src/components/layout/SettingsModal.test.tsx, line 82-101 (link)

    P2 Missing regression test for the "re-save without token clears credential" scenario

    The only test that exercises handleSave enters a token before clicking save. There is no test for: (1) set a token, (2) reopen the modal, (3) save with a blank token field — which is the exact flow that currently clears the in-memory token unexpectedly. Adding that case would have caught the conditional-update gap flagged above.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

    Fix in Codex Fix in Cursor

Fix All in Codex Fix All in Cursor

Reviews (1): Last reviewed commit: "fix: restore frontend settings API confi..." | Re-trigger Greptile

Greptile also left 2 inline comments on this PR.

Co-authored-by: up2itnow0822 <up2itnow0822@gmail.com>
const handleSave = () => {
persistBackendUrl(backendUrl);
saveApiBaseUrl(backendUrl);
setSessionAuthToken(apiKeyInputRef.current?.value || '');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Auth token silently cleared on every settings save without a new token

setSessionAuthToken(apiKeyInputRef.current?.value || '') is called unconditionally, but the token input is always reset to blank when the modal opens (line 20). So any subsequent save — e.g., a user who only wants to update the backend URL — calls setSessionAuthToken(''), which sets sessionAuthToken = null and removes the in-memory auth credential. All subsequent protected API calls (executionsAPI, builderAPI, etc.) will then be sent without an Authorization header. The token should only be updated when the user actually types a new value into the field.

The same issue is present in frontend/src/app/settings/page.tsx at the equivalent handleSave.

Fix in Codex Fix in Cursor

Comment on lines 19 to 22
const handleSave = () => {
persistBackendUrl(backendUrl);
saveApiBaseUrl(backendUrl);
setSessionAuthToken(apiKeyInputRef.current?.value || '');
alert('Settings saved. API keys are kept in memory only.');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Same unconditional setSessionAuthToken call here clears the in-memory auth token whenever the user saves any setting change without re-entering their token. Since the field always starts blank, any URL-only update wipes the credential.

Suggested change
const handleSave = () => {
persistBackendUrl(backendUrl);
saveApiBaseUrl(backendUrl);
setSessionAuthToken(apiKeyInputRef.current?.value || '');
alert('Settings saved. API keys are kept in memory only.');
const handleSave = () => {
saveApiBaseUrl(backendUrl);
const tokenValue = apiKeyInputRef.current?.value || '';
if (tokenValue) setSessionAuthToken(tokenValue);
alert('Settings saved. API keys are kept in memory only.');

Fix in Codex Fix in Cursor

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Duplicate draft — recommend close

Superseded by #35. Close after #35 merges.

Open in Web View Automation 

Sent by Cursor Automation: Untitled

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