Skip to content

feat(chat): paste-to-secret modal, first-class API key creation, Credential Manager agent#4647

Open
vibegui wants to merge 1 commit into
mainfrom
vibegui/token-detect-secret-modal
Open

feat(chat): paste-to-secret modal, first-class API key creation, Credential Manager agent#4647
vibegui wants to merge 1 commit into
mainfrom
vibegui/token-detect-secret-modal

Conversation

@vibegui

@vibegui vibegui commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Brings nano-studio's "this looks like a secret" flow to Studio, plus first-class API-key creation in chat. Rebased on top of #4643 (API Key Manager) — the originally-planned "Credential Manager" agent was dropped in favor of extending that merged agent.

1. Paste-to-secret in chat. When a user pastes (or types) something that looks like an API key/token into the chat composer, it's heuristically detected and a modal offers to vault it as a secret, swapping the raw value for a {{secret:name}} reference so the token never enters chat history.

  • web/utils/secret-detect.ts — priority-ordered detection (anthropic/openai/openrouter/github/aws/google/slack/jwt/labeled/generic) + heuristic naming, ported verbatim from nano-studio with its test suite.
  • New Tiptap secretRef inline chip node (registered in the composer and the read-only message renderer) that serializes to {{secret:name}} via derivePartsFromTiptapDoc.
  • StoreSecretDialog saves through the existing SECRET_CREATE mutation (defaults to organization scope, editable name). Paste mode swaps in-draft; a submit-time safety net catches typed tokens.
  • Raw tokens the user chooses to keep render as masked, click-to-copy chips in the transcript (SensitiveText).
  • Grants secrets:manage to the built-in user role so every member can vault a token from chat (previously admin-only).

2. First-class API_KEY_CREATE rendering. The raw key is returned exactly once; the new tool-call renderer auto-opens a "shown only once" modal with the key + copy button (guarded per toolCallId via sessionStorage so history revisits don't re-pop it), leaving an inline summary card afterward.

3. Vault secrets + UI-aware instructions on the API Key Manager (#4643). Extends the merged API Key Manager agent with SECRET_CREATE/SECRET_LIST and vault-handling instructions ({{secret:name}} references, never echo values, SECRET_LIST-before-create). Also fixes two failure modes observed in prod: the instructions now tell the agent the key is rendered by the UI in a secure shown-once panel (instead of "copy the tool result"), forbid running API_KEY_CREATE through a subtask (nested tool outputs are hidden, so a subtask-created key is displayed to no one and unrecoverable), and cap confirmation at one round so it stops re-litigating explicitly confirmed requests. resolveEffectiveVirtualMcpForHarness resolves pack-agent tools/instructions from code at dispatch time, so existing orgs pick this up immediately — no install-version bump needed.

Testing

  • bun test — new unit suites (secret-detect.test.ts, secret-ref/replace.test.ts) pass; api-key-manager + mesh-sdk constants tests updated and green; chat suite green (360 pass).
  • bun run check (typecheck) and bun run lint pass; bun run fmt:check clean.
  • The studio-pack.integration.test.ts toolset assertion was extended with the two secrets tools; the suite requires a migrated test Postgres (fails in its shared beforeAll seed in this sandbox — pre-existing, unrelated).

Manual verification notes (for reviewer)

  • Paste sk-ant-… → modal ("Anthropic API key", anthropic_api_key, org scope) → Save & use reference → chip in composer → send → user message shows chip; Settings → Secrets lists it; wire text part contains {{secret:anthropic_api_key}}.
  • API Key Manager: "create an API key…" → confirm → shown-once modal with key + copy; reload thread → modal does not re-open, inline card remains. Ask it to store a token → SECRET_CREATE → {{secret:name}} reference in reply.

🤖 Generated with Claude Code


Update: root-caused the "won't give me the key" prod report

The prod repro (org owner asks the org's default agent to mint a wide-access key, agent delegates to the API Key Manager via subtask, key is created but never shown) turned out to have a real root cause, not just an annoying agent: nested tool-call results are never rendered to the user (SubtaskResultBody only ever shows the subagent's own final text report, never its intermediate tool outputs) — so our shown-once UI panel structurally cannot appear for a delegated run, and the agent's own "never reprint the key" instruction (mine) or "always print it once" instruction (main's independent fix in #4689, merged the same day) each solved only one half of the problem.

Rebasing onto main surfaced #4689's fix as a real conflict, which forced reconciling both: the merged instructions now branch on the one signal the model can reliably observe — its own identity prompt (SUBAGENT_IDENTITY_PROMPT from build-agent-system-prompt.ts, which literally tells a subagent "this report is all the parent agent sees"):

  • Top-level (no subagent identity prompt): rely on the UI panel, never reprint the raw key in text — preserves this PR's "raw secrets shouldn't sit in plaintext chat history" goal.
  • Delegated subtask: print the key once in a fenced code block in the final report — the only channel a nested tool result has to the user; omitting it (my original instruction) makes the key permanently unrecoverable.

Also folded in: API_KEY_CREATE must never itself be delegated to a further subagent (that hides the result even from the calling manager), and "confirm once, then act" so an explicitly-confirmed request doesn't get re-litigated (the second screenshot).

api-key-manager.test.ts gained tests locking in each of these five behaviors individually.

@vibegui
vibegui force-pushed the vibegui/token-detect-secret-modal branch 3 times, most recently from c2d6beb to 9ebc120 Compare July 18, 2026 17:38
…t secrets on API Key Manager

Detect API keys/tokens pasted (or typed) into the chat composer and offer to
vault them as a secret, swapping the raw value for a `{{secret:name}}`
reference so it never lands in chat history. Ported from nano-studio.

- New heuristic detection (`web/utils/secret-detect.ts`), Tiptap `secretRef`
  chip node + pure doc-swap helper, and a StoreSecretDialog that saves via the
  existing SECRET_CREATE flow (org scope default). Raw tokens the user keeps
  render as masked, click-to-copy chips in the transcript.
- Grant `secrets:manage` to the built-in user role so every member can vault
  a token from chat.
- First-class API_KEY_CREATE tool rendering: an auto-opening "shown once"
  modal with the key + copy, guarded per tool-call so history revisits don't
  re-pop it; inline summary card remains.
- Extend the API Key Manager studio-pack agent (#4643) with SECRET_CREATE /
  SECRET_LIST and vault-handling instructions, so credential storage is
  usable from chat alongside key management. Runtime resolves pack-agent
  tools/instructions from code, so existing orgs pick this up immediately.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vibegui
vibegui force-pushed the vibegui/token-detect-secret-modal branch from 9ebc120 to 6db6b50 Compare July 18, 2026 19:11
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