Skip to content

fix(web): gate Finalize design package + trim handling reviewers asked for on #1649#1749

Closed
ecogsandbox wants to merge 1 commit into
nexu-io:mainfrom
ecogsandbox:local/fix-finalize-config-gate-1348
Closed

fix(web): gate Finalize design package + trim handling reviewers asked for on #1649#1749
ecogsandbox wants to merge 1 commit into
nexu-io:mainfrom
ecogsandbox:local/fix-finalize-config-gate-1348

Conversation

@ecogsandbox

Copy link
Copy Markdown

Why

Use case: Mirror PR #1649's gating fix for #1348, but include the one outstanding piece of reviewer feedback that PR #1649 has not yet incorporated: trim handling on apiKey / model.

Pain being addressed: Without trim handling, whitespace-only values (\" \") still pass the JS truthy check while the daemon route rejects them (!apiKey.trim() at apps/daemon/src/import-export-routes.ts:551). The user sees the same backend Bad request toast this fix is meant to prevent. This is the exact .trim() contract mismatch that closed PR #1367 (per @PerishCode review feedback) and that @Siri-Ray, @lefarcen, and the Codex bot are blocking #1649 on:

Happy to close this in favor of #1649 once @xxiaoxiong pushes the trim addition. Opening so reviewers can pull a verified branch in the meantime.

What users will see

  • "Finalize design package" button is disabled when `apiKey` or `model` is empty or whitespace-only; tooltip reads "Configure API key and model in Settings to enable finalization".
  • Defensive toast in `handleFinalize` covers programmatic triggers: "Cannot finalize: API key and model are required."
  • Trimmed values are passed into `finalize.trigger` so the UI gate matches the daemon's `apiKey.trim()` / `model.trim()` validation.

Surface area

  • UI — Finalize button disabled state, tooltip, defensive toast
  • Keyboard shortcut — no changes
  • CLI / env var — no changes
  • API / contract — no changes
  • Extension point — no changes
  • i18n keys — no changes (English-only tooltip, matches existing strings)
  • New top-level dependency — no changes
  • Default behavior change — gates an existing action

Screenshots

N/A — gating change. Disabled button + tooltip render via the native `disabled` attribute and `title`.

Bug fix verification

  1. Open a project with provider config empty (Local CLI mode or unconfigured BYOK).
  2. Before fix: Finalize is clickable; click → backend 400 → toast "Bad request — check the API key and model."
  3. After fix: Finalize is disabled; tooltip explains the prerequisite.
  4. Set apiKey + model in Settings; button re-enables; click finalizes normally.
  5. Edge case (this PR vs. fix: Gate Finalize design package when provider config is missing #1649): set apiKey to `" "` (whitespace only). Before this PR's trim handling, button is enabled and click still 400s; with trim handling, button stays disabled.

Validation

  • `pnpm guard` — green
  • `pnpm typecheck` — green
  • `pnpm --filter @open-design/web test` — 1189/1189 passed

Fixes #1348
References #1649, #1367


Generated with Claude Code

Carries upstream PR #1649 with the reviewer-requested trim handling that
PR #1649 has not yet incorporated. Disables the Finalize button when
config.apiKey or config.model is empty or whitespace-only, with a tooltip
that points users to Settings. Defense-in-depth toast in handleFinalize
for programmatic triggers. Trimmed values flow into finalize.trigger so
the UI gate matches the daemon's apiKey.trim()/model.trim() validation.

Bumps root package.json from 0.7.0 to 0.7.1.

Fixes: local "Bad request: set up API key first" toast on Finalize click.
References: nexu-io/open-design#1649, nexu-io/open-design#1348

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 28cdaadd6a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

baseUrl: config.baseUrl,
model: config.model,
model: config.model.trim(),
maxTokens: effectiveMaxTokens(config),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use the trimmed model for max-token defaults

When the saved model has leading/trailing whitespace, this path now correctly sends model: config.model.trim(), but effectiveMaxTokens(config) still looks up the untrimmed value. In that scenario, known models like claude-sonnet-4-5 miss their model-specific default and fall back to 8192 tokens, so finalization can be unnecessarily truncated even though the request uses the trimmed model. Compute the token cap from the same trimmed model that is sent to the daemon.

Useful? React with 👍 / 👎.

@lefarcen lefarcen requested a review from mrcfps May 15, 2026 00:54
@lefarcen lefarcen added size/S PR changes 20-100 lines risk/medium Medium risk: regular code changes type/bugfix Bug fix labels May 15, 2026

@lefarcen lefarcen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey @ecogsandbox! 👋 The trim-contract analysis here is precise — the mismatch between the JS truthy check and the daemon's apiKey.trim() at import-export-routes.ts:551 is exactly the gap reviewers flagged on #1649, and your bug-fix verification steps (especially edge case 5) show it end-to-end.

Heads-up: PR #1649 by @xxiaoxiong is also open against this area — both PRs touch FinalizeDesignButton.tsx and address the Finalize gating for #1348. This PR adds the .trim() handling that #1649 hasn't yet incorporated. The maintainer team will decide which one lands; sharing so neither effort goes to waste.

@mrcfps has been assigned to review. ✨

@mrcfps mrcfps left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the #1348 follow-up, @ecogsandbox — the main gate looks good, but I found one trim-path mismatch that still needs a small follow-up before the behavior fully lines up with the daemon validation.

🔁 Powered by Looper · runner=reviewer · agent=opencode · An autonomous AI dev team for your GitHub repos.

baseUrl: config.baseUrl,
model: config.model,
model: config.model.trim(),
maxTokens: effectiveMaxTokens(config),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

apps/web/src/components/ProjectView.tsx:2316 now trims config.model before calling finalize.trigger, but maxTokens is still computed from the untrimmed config object. When a saved model has leading or trailing whitespace and there is no explicit max-token override, effectiveMaxTokens(config) falls through to 8192 because apps/web/src/state/maxTokens.ts:96 looks up the raw model string, while the request is sent with the trimmed model id. That means a padded value like claude-sonnet-4-5 can still finalize with the fallback token cap and get unnecessarily truncated even though this PR is trying to normalize whitespace-only config issues. Please derive the trimmed values once, pass the trimmed model into effectiveMaxTokens, and add a regression in apps/web/tests/state/maxTokens.test.ts for a whitespace-padded known model id.

🔁 Powered by Looper · runner=reviewer · agent=opencode · An autonomous AI dev team for your GitHub repos.

@github-actions

Copy link
Copy Markdown
Contributor

@ecogsandbox friendly reminder: this PR has been waiting on an author response for more than 3 days after reviewer or maintainer feedback.

When you have a chance, please reply here or push an update. To keep the queue manageable, PRs with no author activity for more than 5 days after feedback may be closed automatically, but they can be reopened when work resumes.

@github-actions

Copy link
Copy Markdown
Contributor

Closing this PR for now because it has been waiting on an author response for more than 5 days after reviewer or maintainer feedback.

This is only a queue-management step, not a rejection of the work. If you would like to continue, please leave a comment or push an update and reopen the PR when ready.

@github-actions github-actions Bot closed this May 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk/medium Medium risk: regular code changes size/S PR changes 20-100 lines type/bugfix Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants