Skip to content

[fix] Show the secret picker above the attach drawer and anchor the attach on the head revision - #6743

Merged
mmabrouk merged 6 commits into
release/v0.116.0from
fix/custom-secret-attach-drawer
Sep 10, 2026
Merged

[fix] Show the secret picker above the attach drawer and anchor the attach on the head revision#6743
mmabrouk merged 6 commits into
release/v0.116.0from
fix/custom-secret-attach-drawer

Conversation

@mmabrouk

@mmabrouk mmabrouk commented Sep 10, 2026

Copy link
Copy Markdown
Member

Context

Three bugs in the custom-secret attach flow that shipped in v0.115.4, all found in live use.

The Attach a secret drawer looked like it had no secrets. Clicking "Select a secret" opened the list with every text secret in it, but the list was drawn under the drawer. The drawer sits at zIndex 1000 so it stacks above the Advanced dialog, and the shared SelectContent portals its list to body at z-50. Nothing was visible, on both the desktop app and /m. Closes #6733.

The drawer and the Advanced section could also sit on "Loading secrets" forever. The vault hook reported loading while the one-time migration of legacy provider keys from browser local storage had not finished. A legacy payload that an older build wrote once instead of twice made that migration throw, it rolled back to "not migrated", and every secret picker stayed on Loading. It depends on what a browser holds for the origin, so it hits some people and not others. Found during manual QA of this branch.

Attaching from the chat card could fail with a raw 409 revision_conflict body, and Retry could never succeed. The commit sent base_revision_id equal to the revision the panel displayed. The server rejects any base that is not the variant head. The reporter's panel showed revision 106 while the head had been 107 for two days, so every attach failed with the same stale base. Closes #6734.

Changes

The picker draws above the drawer. AgentSecretAttachmentDrawer passes zIndex + 1 as an inline style to its SelectContent. SecretForm takes a new popupZIndex prop for the two selects in its JSON grid, and both the attach drawer (1000) and CreateSecretDrawer (1100) pass it. An inline style beats the z-50 class, and it follows the drawer's own zIndex prop instead of a second hard-coded number.

The drawer refetches the vault list when it opens. The vault query keeps a live subscriber for the whole page, so nothing ever refetched it. A secret created on the Settings page in another tab stayed invisible until a reload. The drawer now refetches in an effect keyed on open.

Loading no longer waits on the legacy migration. The migration accepts both encodings of the old local storage payload, backs up and clears a payload it cannot read, and always ends in the migrated state. The hook's loading flag is the query's pending state plus "migrating", nothing else.

The bindings commit anchors on the head. commitAgentCredentialsAtom reads the variant head first and builds the bindings-only revision on the head's data. The displayed revision names the variant, gates on unsaved edits, and supplies the attachments the user was looking at. Because both callers send the full attachment list, a head whose attachments differ from the displayed ones would be overwritten, so that case refuses with a plain message and the user reloads. That keeps the review rule from the design plan.

Before:

base_revision_id: <displayed revision>   -> 409 whenever the panel is not on the head

After:

head = retrieve(variant)                 -> falls back to the displayed revision if the read fails
head.attachments != displayed.attachments -> "This agent's secret attachments changed while you were editing them. Reload the configuration and attach again."
base_revision_id: head.id
on 409 revision_conflict: re-read once, retry once under the same rule

The lost-response recovery is unchanged. A 409 without the revision_conflict code stays a plain error. Edits typed during the request are carried to the adopted revision only when it was built on the displayed revision; copied onto a newer head they would revert the head's other fields locally. Adoption still keys on the displayed revision, because that is the revision the panel switches away from.

Tests

  • web/packages/agenta-entities/tests/unit/agent-credentials-commit.test.ts: 14 tests, eight new. They cover the head anchor when the panel is on an older revision, the fallback when the head read fails, the single re-read and retry on a race, the refusal when the head's attachments differ (before and after a race), a 409 without the conflict code, and the draft that must not be carried onto a newer head. The happy path asserts one head read.
  • web/packages/agenta-entities/tests/unit/vault-migration.test.ts: three tests for the migration, including an unreadable payload and a once-encoded payload.
  • vitest, tsc --noEmit and eslint in agenta-entities and agenta-entity-ui: green.
  • Two independent reviews (Codex at xhigh and a reviewer subagent) on the first commit found the attachment-overwrite path and the draft carry-over. The second commit addresses both.
  • Live on an isolated stack from this branch (http://144.76.237.122:8580, EE dev, fresh database):
    • Desktop and /m: the picker lists both seeded secrets on screen, layer 1001 above the drawer, and the two secrets were created after the tab had loaded, so the refetch on open is covered too.
    • Tab on revision 1, head moved to revision 2 through the API with an instruction edit, Attach from the tab: the commit landed as revision 3 with the API edit and the attachment, and the panel adopted it.
    • Tab on revision 3, head moved to revision 4 with different attachments, Attach: the drawer shows the reload message and no commit happens.
    • Loading: with an old-format key planted in local storage the section showed "Loading secrets" forever before the third commit, and lists the attachments after it.
    • Chat: the agent called request_secret, Configure opened the drawer with NPM_TOKEN prefilled, Create new saved a placeholder secret, Attach committed revision 5, the card settled as "NPM_TOKEN attached" and the run resumed.

Not touched: why the playground panel sat on an older revision in the first place. That is a separate question about how the chat picks its revision, and it no longer breaks the attach.

What to QA

Setup: a project with at least two text secrets in Settings → Secrets, and an agent with more than one revision.

  • Open the agent, Advanced → Custom secrets → Attach, click Select a secret. Every text secret is visible on screen in the list. Pick one, attach, and the row appears with its environment variable.
  • With the drawer closed, create a secret in Settings → Secrets in a second tab. Back in the first tab, open Attach again without reloading. The new secret is in the list.
  • Open Create new in the drawer, save a secret with a value and default variable. It is selected in the picker, and Attach commits it.
  • Open an older revision of the agent from the version history, then attach a secret from Advanced. It succeeds and the panel adopts a new revision on top of the latest one, with the newer edits intact.
  • Change the attachments in one tab, then attach from a second tab that still shows the old list. The drawer says the attachments changed and asks for a reload. Nothing is committed.
  • In the chat, let the agent call request_secret, click Configure, create or pick a secret, attach. The card settles and the conversation resumes.
  • Regression: the Create secret drawer from an MCP server setup. Its Format and JSON type selects open above the drawer.
  • In a browser that used an older Agenta build on the same origin, open Advanced, Custom secrets. The section and the drawer load instead of showing "Loading secrets".
  • Regression: remove an attachment from Advanced. The row goes away and the vault entry stays.

https://claude.ai/code/session_01AY886ajXX65KAa1Vc9JCXU

Mahmoud Mabrouk added 2 commits September 10, 2026 12:15
… attach on the head revision

The Attach a secret drawer sits at z-index 1000 above the Advanced dialog, and the
shared Select portals its option list to body at z-50, so the list painted under the
drawer and the picker looked empty. The drawer and the secret form now pass the layer
above the drawer to every SelectContent they render. The drawer also refetches the
vault list when it opens, because the vault query keeps a live subscriber for the
whole page and nothing else ever refetched it.

The bindings commit sent base_revision_id equal to the revision the panel displayed,
and the server rejects any base that is not the head, so every attach from a panel on
an older revision failed with a 409 and Retry resent the same stale base. The commit
now reads the variant head first and builds the bindings-only revision on the head's
data; on a real race it re-reads once and retries, then raises a plain message.

Closes #6733
Closes #6734

Claude-Session: https://claude.ai/code/session_01AY886ajXX65KAa1Vc9JCXU
… and keep drafts off a newer head

Review of the head-anchored commit found two data-loss paths. The callers send the full
attachment list from the revision the panel displays, so a commit on a head whose
attachments differ would silently drop the other change. The atom now compares the head's
attachments with the displayed ones before every attempt and asks for a reload when they
differ, which keeps the review rule from the design plan. Edits typed during the request
are carried to the adopted revision only when it was built on the displayed revision,
because copying them onto a newer head would revert the head's other fields locally.

The 409 check now requires the revision_conflict code, so a proxy 409 stays a plain error.
The vault refetch moved to its own effect keyed on open, because the refetch callback
changes identity on every fetch.

Claude-Session: https://claude.ai/code/session_01AY886ajXX65KAa1Vc9JCXU
@vercel

vercel Bot commented Sep 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
agenta-documentation Ready Ready Preview Sep 10, 2026 11:43am UTC

Request Review

@github-actions

github-actions Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

📘 Docs preview

Status ✅ Ready
Preview https://pr-6743-agenta-docs-preview.mahmoud-637.workers.dev/docs
Inspect Actions run
Commit 0e246df3db7724cc2ca6fec686fe9696d0784946

This comment updates in place on every push.

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


Mahmoud Mabrouk seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Advanced

Run ID: d2178ad0-1c94-4506-be89-e472860f1482

📥 Commits

Reviewing files that changed from the base of the PR and between aa4448b and 0e246df.

📒 Files selected for processing (2)
  • web/packages/agenta-entities/src/secret/state/atoms.ts
  • web/packages/agenta-entities/tests/unit/vault-migration.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • web/packages/agenta-entities/src/secret/state/atoms.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 4 remain after this review.


📝 Summary

Summary by CodeRabbit

  • Bug Fixes

    • Secret selection menus now appear above the attachment drawer.
    • Vault secrets refresh whenever the attachment drawer opens.
    • Legacy vault data migration safely handles encoded, invalid, or incomplete data.
    • Secret pickers are no longer blocked by failed migrations.
    • Agent credential updates target the latest revision while preserving unrelated changes.
    • Concurrent attachment changes are detected instead of overwritten.
    • Credential updates retry after revision conflicts and recover safely from lost responses.
  • Documentation

    • Updated design, QA, and status documentation with follow-up fixes and verification details.

Walkthrough

This PR improves legacy vault migration, refreshes vault secrets when the attachment drawer opens, fixes portaled selector layering, and anchors agent credential commits to the current workflow head with conflict handling.

Changes

Custom secret attachment flow

Layer / File(s) Summary
Vault migration completion and loading state
web/packages/agenta-entities/src/secret/state/atoms.ts, web/packages/agenta-entities/src/secret/state/useVaultSecret.ts, web/packages/agenta-entities/tests/unit/vault-migration.test.ts
Legacy vault payloads are validated entry by entry. Single- and double-encoded JSON are supported. Failed entries remain available for retry. Migration completes without blocking secret loading.
Secret picker refresh and popup layering
web/packages/agenta-entity-ui/src/secret/AgentSecretAttachmentDrawer.tsx, web/packages/agenta-entity-ui/src/secret/CreateSecretDrawer.tsx, web/packages/agenta-entity-ui/src/secret/SecretForm/SecretForm.tsx
The drawers refetch vault secrets on open. Select popups receive a z-index above their drawer.
Head-anchored credential commit
web/packages/agenta-entities/src/workflow/state/agentCredentials.ts, web/packages/agenta-entities/src/workflow/index.ts, web/packages/agenta-entities/tests/unit/agent-credentials-commit.test.ts
Credential commits use the variant head, preserve unrelated fields, retry one revision conflict, reject changed attachments with a shared message, and restrict lost-response recovery to matching data.
Follow-up specification and validation
docs/design/agent-custom-secrets/plan.md, docs/design/agent-custom-secrets/qa.md, docs/design/agent-custom-secrets/status.md
The design, QA, and status documents record the fixes and verification criteria.

Estimated code review effort: 4 (Complex) | ~45 minutes

Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant AttachmentDrawer
  participant CredentialCommit
  participant WorkflowAPI
  AttachmentDrawer->>CredentialCommit: Submit secret bindings
  CredentialCommit->>WorkflowAPI: Retrieve current variant head
  WorkflowAPI-->>CredentialCommit: Return head revision
  CredentialCommit->>WorkflowAPI: Commit bindings against head
  WorkflowAPI-->>CredentialCommit: Return committed revision or conflict
  CredentialCommit->>WorkflowAPI: Retrieve moved head and retry once
Loading

Merge Risk: ⚪ Minimal · up to 0e246

This change improves secret migration, picker refresh and layering, and concurrent credential attachment handling. No concrete merge-blocking risk remains in the supplied review context.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 60.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 9 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies both primary fixes: rendering the secret picker above the drawer and anchoring attachment commits on the head revision.
Description check ✅ Passed The description is directly related to the changes. It explains the picker, vault migration, revision anchoring, conflict handling, tests, and QA coverage.
Linked Issues check ✅ Passed The changes satisfy #6733 by rendering picker portals above the drawer and refetching vault secrets when the drawer opens. They satisfy #6734 by anchoring commits on the variant head, preserving newer…
Out of Scope Changes check ✅ Passed The changes remain within the custom-secret attachment flow. The migration handling, shared SecretForm popup fix, documentation, and tests support the picker and attachment behavior described by the l…
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/custom-secret-attach-drawer

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…e legacy key migration

The vault hook reported loading while the one-time localStorage migration had not
finished. A legacy payload that an older build wrote once instead of twice made the
migration throw, it rolled back to not-migrated, and every secret picker and the
Advanced section showed Loading secrets forever. The migration now accepts both
encodings, backs up and clears a payload it cannot read, and always ends migrated.
The loading flag no longer includes the migration state.

Claude-Session: https://claude.ai/code/session_01AY886ajXX65KAa1Vc9JCXU

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Advanced

Run ID: 7df89255-301c-4c83-9ceb-bf86ec884f2f

📥 Commits

Reviewing files that changed from the base of the PR and between 40f2263 and c7f38de.

📒 Files selected for processing (3)
  • web/packages/agenta-entities/src/secret/state/atoms.ts
  • web/packages/agenta-entities/src/secret/state/useVaultSecret.ts
  • web/packages/agenta-entities/tests/unit/vault-migration.test.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 5 remain after this review.

Comment thread web/packages/agenta-entities/src/secret/state/atoms.ts Outdated
@github-actions

github-actions Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Railway Preview Environment

Status Destroyed (PR closed)

Updated at 2026-09-10T12:07:05.958Z

…a bad one

CodeRabbit: a null entry in the legacy list threw inside the loop, which marked the
migration done without the backup and cleanup. The list now goes through a zod schema
via safeParseWithLogging, null entries drop out, a keyless entry is skipped, and one
entry that fails to save no longer stops the others. Backup and cleanup always run.

Claude-Session: https://claude.ai/code/session_01AY886ajXX65KAa1Vc9JCXU

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Advanced

Run ID: 22263dce-24e4-464a-8cbe-fdf0012de6f4

📥 Commits

Reviewing files that changed from the base of the PR and between c7f38de and aa4448b.

📒 Files selected for processing (2)
  • web/packages/agenta-entities/src/secret/state/atoms.ts
  • web/packages/agenta-entities/tests/unit/vault-migration.test.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 4 remain after this review.

Comment thread web/packages/agenta-entities/src/secret/state/atoms.ts
Comment thread web/packages/agenta-entities/src/secret/state/atoms.ts Outdated
…e entries one by one

Codex gate review: a legacy key whose save failed was cleared from storage with the
migration marked done, so a temporary API error lost it for good. The entries that
fail to save now stay in the active storage key in the canonical form, and the next
page load retries them. The list is also validated entry by entry, so one malformed
entry no longer rejects the valid ones beside it.

Claude-Session: https://claude.ai/code/session_01AY886ajXX65KAa1Vc9JCXU
@mmabrouk

Copy link
Copy Markdown
Member Author

Review rounds, for the record. Codex (xhigh) on the first commit found that a commit on the head with the displayed attachment list could drop an attachment added elsewhere, and that in-flight draft edits copied onto a newer head reverted its fields locally; commit 4e98fc3 closes both. CodeRabbit found that a null legacy entry threw inside the migration loop; commit aa4448b validates entries and isolates failures. Codex on the full branch then found that a failed save cleared the key for good and that whole-list validation rejected valid entries beside a bad one; commit 0e246df keeps failed entries for a retry on the next load and validates entry by entry. All three reviewers' findings are addressed, and every thread is resolved.

@mmabrouk
mmabrouk merged commit dc914e0 into release/v0.116.0 Sep 10, 2026
70 of 72 checks passed
@mmabrouk
mmabrouk deleted the fix/custom-secret-attach-drawer branch September 10, 2026 12:07
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.

2 participants