From bf982c8c835b0435c0af465287c670e2dcf203c4 Mon Sep 17 00:00:00 2001 From: Devin Foley Date: Thu, 2 Jul 2026 21:32:50 -0700 Subject: [PATCH] Normalize adapter display labels (#8913) ## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Adapter names are part of the board-facing agent setup and management experience. > - The product now treats adapters as harnesses, while execution environments are modeled separately. > - Several built-in adapter labels still carried legacy local wording from the older harness-by-environment model. > - That wording makes the UI noisier and implies a distinction users no longer need to reason about. > - This pull request normalizes adapter display labels while keeping persisted adapter type identifiers unchanged. > - The benefit is clearer adapter selection and management copy without a database migration. ## Linked Issues or Issue Description No public GitHub issue was found for this exact cleanup. Related public PRs: - Supersedes #8910, an earlier branch for the same cleanup that did not include the later docs/gateway/Cursor alignment. - Refs #8819, which is related display-registry work for external multi-segment adapter labels, but not a duplicate of this built-in label cleanup. Feature request details: - Subsystem affected: Cross-cutting (`ui/`, `packages/adapters`, and docs). - Problem or motivation: user-facing adapter names include legacy local qualifiers even though adapters map to harnesses and environments are first-class elsewhere. - Proposed solution: remove the legacy local wording from built-in display labels, keep machine-readable adapter type ids unchanged, and keep gateway disambiguation where it is useful. - Alternatives considered: changing persisted adapter type ids was ruled out because it would create migration and compatibility risk; one-off UI replacements were ruled out because the display registry is already the correct central label boundary. - Roadmap alignment: this is small adapter UX polish, not a new roadmap-level core feature. ## What Changed - Updated the adapter display registry so known adapter labels are final and no built-in local adapter renders a legacy local suffix. - Preserved clean derived labels for unknown plugin local types while keeping gateway disambiguation for unknown gateway types. - Updated `AdapterManager` to prefer registry labels when the server reports raw adapter type ids for built-ins. - Removed legacy local wording from built-in adapter metadata labels in UI and adapter packages. - Aligned Cursor adapter metadata with the central display registry label. - Updated adapter docs and Storybook fixtures to match the new display names. - Added focused registry coverage for built-in labels and unknown plugin suffix behavior. ## Verification - `pnpm check:tokens` - `git diff --check origin/master...fix/adapter-display-labels` - Patch-addition scan for added secrets, private paths, and internal links: no matches. - GitHub duplicate search for open adapter-label/local-suffix issues and PRs; #8910 was identified as the older superseded public PR. - `pnpm exec vitest run ui/src/adapters/adapter-display-registry.test.ts` - `pnpm --filter @paperclipai/ui typecheck` - Stale-label scan found no remaining user-facing display-label suffixes; remaining local wording is operational/test terminology such as adapter ids, docs about running locally, and test descriptions. ## Risks Low risk. The change is display-label and documentation focused, and adapter type ids remain unchanged. The main risk is ambiguous gateway naming, mitigated by keeping explicit gateway labels where variants need disambiguation. ## Model Used OpenAI GPT-5 via Codex, tool-enabled coding agent in a local repository workspace. Context window size is not exposed by this environment. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip --- docs/adapters/claude-local.md | 2 +- docs/adapters/codex-local.md | 2 +- docs/adapters/creating-an-adapter.md | 2 +- docs/adapters/external-adapters.md | 2 +- docs/adapters/gemini-local.md | 2 +- docs/adapters/overview.md | 14 +++--- docs/deploy/environment-variables.md | 4 +- .../board-operator/creating-a-company.md | 4 +- docs/start/architecture.md | 2 +- packages/adapters/acpx-local/src/index.ts | 2 +- packages/adapters/claude-local/src/index.ts | 2 +- packages/adapters/codex-local/src/index.ts | 2 +- packages/adapters/cursor-local/src/index.ts | 2 +- packages/adapters/gemini-local/src/index.ts | 2 +- packages/adapters/grok-local/src/index.ts | 2 +- packages/adapters/opencode-local/src/index.ts | 2 +- packages/adapters/pi-local/src/index.ts | 2 +- ui/src/adapters/acpx-local/index.ts | 2 +- .../adapters/adapter-display-registry.test.ts | 47 ++++++++++++++++++ ui/src/adapters/adapter-display-registry.ts | 48 +++++++++++-------- ui/src/adapters/claude-local/index.ts | 2 +- ui/src/adapters/codex-local/index.ts | 2 +- ui/src/adapters/cursor/index.ts | 2 +- ui/src/adapters/gemini-local/index.ts | 2 +- ui/src/adapters/grok-local/index.ts | 2 +- ui/src/adapters/opencode-local/index.ts | 2 +- ui/src/adapters/pi-local/index.ts | 2 +- ui/src/pages/AdapterManager.tsx | 5 +- ui/storybook/.storybook/preview.tsx | 4 +- .../stories/agent-management.stories.tsx | 4 +- .../stories/dialogs-modals.stories.tsx | 8 ++-- .../stories/forms-editors.stories.tsx | 4 +- 32 files changed, 123 insertions(+), 63 deletions(-) create mode 100644 ui/src/adapters/adapter-display-registry.test.ts diff --git a/docs/adapters/claude-local.md b/docs/adapters/claude-local.md index 1cc39e219c..c61b8ca604 100644 --- a/docs/adapters/claude-local.md +++ b/docs/adapters/claude-local.md @@ -1,5 +1,5 @@ --- -title: Claude Local +title: Claude Code summary: Claude Code local adapter setup and configuration --- diff --git a/docs/adapters/codex-local.md b/docs/adapters/codex-local.md index fa4877b05a..e1bd06b17c 100644 --- a/docs/adapters/codex-local.md +++ b/docs/adapters/codex-local.md @@ -1,5 +1,5 @@ --- -title: Codex Local +title: Codex summary: OpenAI Codex local adapter setup and configuration --- diff --git a/docs/adapters/creating-an-adapter.md b/docs/adapters/creating-an-adapter.md index 2f4711aa15..c0f43ff8a2 100644 --- a/docs/adapters/creating-an-adapter.md +++ b/docs/adapters/creating-an-adapter.md @@ -54,7 +54,7 @@ my-adapter/ # external plugin ```ts export const type = "my_agent"; // snake_case, globally unique -export const label = "My Agent (local)"; +export const label = "My Agent"; export const models = [ { id: "model-a", label: "Model A" }, ]; diff --git a/docs/adapters/external-adapters.md b/docs/adapters/external-adapters.md index 522679f667..3a6b4ee6c7 100644 --- a/docs/adapters/external-adapters.md +++ b/docs/adapters/external-adapters.md @@ -116,7 +116,7 @@ The plugin loader calls `createServerAdapter()` from your package root. This fun ```ts export const type = "my_adapter"; // snake_case, globally unique -export const label = "My Agent (local)"; +export const label = "My Agent"; export const models = [ { id: "model-a", label: "Model A" }, diff --git a/docs/adapters/gemini-local.md b/docs/adapters/gemini-local.md index 51380b058d..a0458ec51d 100644 --- a/docs/adapters/gemini-local.md +++ b/docs/adapters/gemini-local.md @@ -1,5 +1,5 @@ --- -title: Gemini Local +title: Gemini CLI summary: Gemini CLI local adapter setup and configuration --- diff --git a/docs/adapters/overview.md b/docs/adapters/overview.md index a2f62b54bb..43a3963155 100644 --- a/docs/adapters/overview.md +++ b/docs/adapters/overview.md @@ -18,13 +18,13 @@ When a heartbeat fires, Paperclip: | Adapter | Type Key | Description | |---------|----------|-------------| -| [Claude Local](/adapters/claude-local) | `claude_local` | Runs Claude Code CLI locally | -| [Codex Local](/adapters/codex-local) | `codex_local` | Runs OpenAI Codex CLI locally | -| [Gemini Local](/adapters/gemini-local) | `gemini_local` | Runs Gemini CLI locally (experimental — adapter package exists, not yet in stable type enum) | -| OpenCode Local | `opencode_local` | Runs OpenCode CLI locally (multi-provider `provider/model`) | +| [Claude Code](/adapters/claude-local) | `claude_local` | Runs Claude Code CLI locally | +| [Codex](/adapters/codex-local) | `codex_local` | Runs OpenAI Codex CLI locally | +| [Gemini CLI](/adapters/gemini-local) | `gemini_local` | Runs Gemini CLI locally (experimental — adapter package exists, not yet in stable type enum) | +| OpenCode | `opencode_local` | Runs OpenCode CLI locally (multi-provider `provider/model`) | | Cursor | `cursor` | Runs Cursor in background mode | -| Pi Local | `pi_local` | Runs an embedded Pi agent locally | -| Hermes Local | `hermes_local` | Runs the local Hermes CLI through `@paperclipai/hermes-paperclip-adapter` | +| Pi | `pi_local` | Runs an embedded Pi agent locally | +| Hermes | `hermes_local` | Runs the local Hermes CLI through `@paperclipai/hermes-paperclip-adapter` | | Hermes Gateway | `hermes_gateway` | Calls an already-running Hermes API server through `@paperclipai/hermes-paperclip-adapter/gateway` | | OpenClaw Gateway | `openclaw_gateway` | Connects to an OpenClaw gateway endpoint | | [Process](/adapters/process) | `process` | Executes arbitrary shell commands | @@ -49,7 +49,7 @@ These adapters ship as standalone npm packages and are installed via the plugin | Adapter | Package | Type Key | Description | |---------|---------|----------|-------------| -| Droid Local | `@henkey/droid-paperclip-adapter` | `droid_local` | Runs Factory Droid locally | +| Droid | `@henkey/droid-paperclip-adapter` | `droid_local` | Runs Factory Droid locally | ## External Adapters diff --git a/docs/deploy/environment-variables.md b/docs/deploy/environment-variables.md index b5b6486dfb..b46dd64b1b 100644 --- a/docs/deploy/environment-variables.md +++ b/docs/deploy/environment-variables.md @@ -50,5 +50,5 @@ These are set automatically by the server when invoking agents: | Variable | Description | |----------|-------------| -| `ANTHROPIC_API_KEY` | Anthropic API key (for Claude Local adapter) | -| `OPENAI_API_KEY` | OpenAI API key (for Codex Local adapter) | +| `ANTHROPIC_API_KEY` | Anthropic API key (for Claude Code adapter) | +| `OPENAI_API_KEY` | OpenAI API key (for Codex adapter) | diff --git a/docs/guides/board-operator/creating-a-company.md b/docs/guides/board-operator/creating-a-company.md index fa437be8bb..cf71111f51 100644 --- a/docs/guides/board-operator/creating-a-company.md +++ b/docs/guides/board-operator/creating-a-company.md @@ -23,11 +23,11 @@ Go to the Goals section and create your top-level company goal. ## Step 3: Create the CEO Agent -The CEO is the first agent you create. Choose an adapter type (Claude Local is a good default) and configure: +The CEO is the first agent you create. Choose an adapter type (Claude Code is a good default) and configure: - **Name** — e.g. "CEO" - **Role** — `ceo` -- **Adapter** — how the agent runs (Claude Local, Codex Local, etc.) +- **Adapter** — how the agent runs (Claude Code, Codex, etc.) - **Prompt template** — instructions for what the CEO does on each heartbeat - **Budget** — monthly spend limit in cents diff --git a/docs/start/architecture.md b/docs/start/architecture.md index 27d72575e1..dd8839a51b 100644 --- a/docs/start/architecture.md +++ b/docs/start/architecture.md @@ -19,7 +19,7 @@ Paperclip is a monorepo with four main layers. │ Schema, migrations, embedded mode │ ├─────────────────────────────────────┤ │ Adapters │ -│ Claude Local, Codex Local, │ +│ Claude Code, Codex, │ │ Process, HTTP │ └─────────────────────────────────────┘ ``` diff --git a/packages/adapters/acpx-local/src/index.ts b/packages/adapters/acpx-local/src/index.ts index dcbba95354..ead70e617c 100644 --- a/packages/adapters/acpx-local/src/index.ts +++ b/packages/adapters/acpx-local/src/index.ts @@ -1,7 +1,7 @@ import type { AdapterModel } from "@paperclipai/adapter-utils"; export const type = "acpx_local"; -export const label = "ACPX (local)"; +export const label = "ACPX"; export const DEFAULT_ACPX_LOCAL_AGENT = "claude"; export const DEFAULT_ACPX_LOCAL_MODE = "persistent"; diff --git a/packages/adapters/claude-local/src/index.ts b/packages/adapters/claude-local/src/index.ts index 1370bd1113..3310bc8b3f 100644 --- a/packages/adapters/claude-local/src/index.ts +++ b/packages/adapters/claude-local/src/index.ts @@ -1,7 +1,7 @@ import type { AdapterModelProfileDefinition } from "@paperclipai/adapter-utils"; export const type = "claude_local"; -export const label = "Claude Code (local)"; +export const label = "Claude Code"; export const SANDBOX_INSTALL_COMMAND = "npm install -g @anthropic-ai/claude-code"; diff --git a/packages/adapters/codex-local/src/index.ts b/packages/adapters/codex-local/src/index.ts index dac11bbc76..3a38914972 100644 --- a/packages/adapters/codex-local/src/index.ts +++ b/packages/adapters/codex-local/src/index.ts @@ -1,7 +1,7 @@ import type { AdapterModelProfileDefinition } from "@paperclipai/adapter-utils"; export const type = "codex_local"; -export const label = "Codex (local)"; +export const label = "Codex"; export const SANDBOX_INSTALL_COMMAND = "npm install -g @openai/codex"; diff --git a/packages/adapters/cursor-local/src/index.ts b/packages/adapters/cursor-local/src/index.ts index f93928d85e..a576f503ca 100644 --- a/packages/adapters/cursor-local/src/index.ts +++ b/packages/adapters/cursor-local/src/index.ts @@ -1,7 +1,7 @@ import type { AdapterModelProfileDefinition } from "@paperclipai/adapter-utils"; export const type = "cursor"; -export const label = "Cursor CLI (local)"; +export const label = "Cursor"; // Cursor CLI is not distributed as an npm package — the official install // path is the upstream installer script at cursor.com/install. Other adapters diff --git a/packages/adapters/gemini-local/src/index.ts b/packages/adapters/gemini-local/src/index.ts index 72597a24f1..827fac3ef1 100644 --- a/packages/adapters/gemini-local/src/index.ts +++ b/packages/adapters/gemini-local/src/index.ts @@ -4,7 +4,7 @@ import { } from "@paperclipai/adapter-utils"; export const type = "gemini_local"; -export const label = "Gemini CLI (local)"; +export const label = "Gemini CLI"; export const SANDBOX_INSTALL_COMMAND = buildSandboxNpmInstallCommand("@google/gemini-cli"); diff --git a/packages/adapters/grok-local/src/index.ts b/packages/adapters/grok-local/src/index.ts index 7e12bd1d99..9e50feed8f 100644 --- a/packages/adapters/grok-local/src/index.ts +++ b/packages/adapters/grok-local/src/index.ts @@ -1,5 +1,5 @@ export const type = "grok_local"; -export const label = "Grok Build (local)"; +export const label = "Grok Build"; export const DEFAULT_GROK_LOCAL_MODEL = "grok-build"; diff --git a/packages/adapters/opencode-local/src/index.ts b/packages/adapters/opencode-local/src/index.ts index 77fe859c31..18c2df6740 100644 --- a/packages/adapters/opencode-local/src/index.ts +++ b/packages/adapters/opencode-local/src/index.ts @@ -1,7 +1,7 @@ import type { AdapterModelProfileDefinition } from "@paperclipai/adapter-utils"; export const type = "opencode_local"; -export const label = "OpenCode (local)"; +export const label = "OpenCode"; // Use OpenCode's official installer instead of `npm install -g opencode-ai`. // The npm package reifies four large Linux x64 prebuilt-binary subpackages diff --git a/packages/adapters/pi-local/src/index.ts b/packages/adapters/pi-local/src/index.ts index fef8bc2bed..57fb7daea6 100644 --- a/packages/adapters/pi-local/src/index.ts +++ b/packages/adapters/pi-local/src/index.ts @@ -1,7 +1,7 @@ import type { AdapterModelProfileDefinition } from "@paperclipai/adapter-utils"; export const type = "pi_local"; -export const label = "Pi (local)"; +export const label = "Pi"; export const SANDBOX_INSTALL_COMMAND = "npm install -g @earendil-works/pi-coding-agent@0.74.0"; diff --git a/ui/src/adapters/acpx-local/index.ts b/ui/src/adapters/acpx-local/index.ts index d8ae9675e0..4308d63522 100644 --- a/ui/src/adapters/acpx-local/index.ts +++ b/ui/src/adapters/acpx-local/index.ts @@ -4,7 +4,7 @@ import { SchemaConfigFields } from "../schema-config-fields"; export const acpxLocalUIAdapter: UIAdapterModule = { type: "acpx_local", - label: "ACPX (local)", + label: "ACPX", parseStdoutLine: parseAcpxStdoutLine, ConfigFields: SchemaConfigFields, buildAdapterConfig: buildAcpxLocalConfig, diff --git a/ui/src/adapters/adapter-display-registry.test.ts b/ui/src/adapters/adapter-display-registry.test.ts new file mode 100644 index 0000000000..8c32f162b7 --- /dev/null +++ b/ui/src/adapters/adapter-display-registry.test.ts @@ -0,0 +1,47 @@ +import { describe, expect, it } from "vitest"; + +import { getAdapterDisplay, getAdapterLabel, getAdapterLabels } from "./adapter-display-registry"; + +describe("adapter display registry", () => { + it("uses user-facing labels without the legacy local qualifier for built-in adapters", () => { + expect(getAdapterLabel("codex_local")).toBe("Codex"); + expect(getAdapterLabel("claude_local")).toBe("Claude Code"); + expect(getAdapterLabel("acpx_local")).toBe("ACPX"); + expect(getAdapterLabel("cursor")).toBe("Cursor"); + expect(getAdapterLabel("gemini_local")).toBe("Gemini CLI"); + expect(getAdapterLabel("grok_local")).toBe("Grok Build"); + expect(getAdapterLabel("hermes_local")).toBe("Hermes"); + expect(getAdapterLabel("hermes_gateway")).toBe("Hermes Gateway"); + expect(getAdapterLabel("opencode_local")).toBe("OpenCode"); + expect(getAdapterLabel("pi_local")).toBe("Pi"); + + expect(getAdapterLabels()).toMatchObject({ + codex_local: "Codex", + claude_local: "Claude Code", + acpx_local: "ACPX", + cursor: "Cursor", + gemini_local: "Gemini CLI", + grok_local: "Grok Build", + hermes_local: "Hermes", + hermes_gateway: "Hermes Gateway", + opencode_local: "OpenCode", + pi_local: "Pi", + }); + }); + + it("drops local suffixes for unknown plugin adapter labels", () => { + expect(getAdapterLabel("droid_local")).toBe("Droid"); + expect(getAdapterDisplay("droid_local")).toMatchObject({ + label: "Droid", + description: "External adapter", + }); + }); + + it("keeps a gateway suffix for unknown plugin adapter labels", () => { + expect(getAdapterLabel("droid_gateway")).toBe("Droid (gateway)"); + expect(getAdapterDisplay("droid_gateway")).toMatchObject({ + label: "Droid (gateway)", + description: "External gateway adapter", + }); + }); +}); diff --git a/ui/src/adapters/adapter-display-registry.ts b/ui/src/adapters/adapter-display-registry.ts index 17a20dca8f..032332d43e 100644 --- a/ui/src/adapters/adapter-display-registry.ts +++ b/ui/src/adapters/adapter-display-registry.ts @@ -21,13 +21,19 @@ import { OpenCodeLogoIcon } from "@/components/OpenCodeLogoIcon"; // Type suffix parsing // --------------------------------------------------------------------------- -const TYPE_SUFFIXES: Record = { - _local: "local", +// Suffixes stripped from type ids when deriving a human-readable label for +// unknown (plugin) adapter types. "_local" is a legacy qualifier from before +// first-class Environments and is never displayed; "_gateway" is re-appended +// as " (gateway)" to disambiguate gateway variants. Known adapters in +// `adapterDisplayMap` have final labels and never get a derived suffix. +const STRIPPED_TYPE_SUFFIXES = ["_local", "_gateway"] as const; + +const DISPLAY_SUFFIXES: Record = { _gateway: "gateway", }; function getTypeSuffix(type: string): string | null { - for (const [suffix, mode] of Object.entries(TYPE_SUFFIXES)) { + for (const [suffix, mode] of Object.entries(DISPLAY_SUFFIXES)) { if (type.endsWith(suffix)) return mode; } return null; @@ -55,57 +61,57 @@ export interface AdapterDisplayInfo { const adapterDisplayMap: Record = { acpx_local: { label: "ACPX", - description: "Experimental local ACPX multi-agent adapter", + description: "Experimental ACPX multi-agent harness", icon: Bot, experimental: true, hideFromVisualSelection: true, }, claude_local: { label: "Claude Code", - description: "Local Claude agent", + description: "Claude Code CLI harness", icon: Sparkles, recommended: true, }, codex_local: { label: "Codex", - description: "Local Codex agent", + description: "Codex CLI harness", icon: Code, recommended: true, }, gemini_local: { label: "Gemini CLI", - description: "Local Gemini agent", + description: "Gemini CLI harness", icon: Gem, }, grok_local: { label: "Grok Build", - description: "Local Grok Build agent", + description: "Grok Build harness", icon: Bot, }, hermes_gateway: { - label: "Hermes", + label: "Hermes Gateway", description: "Remote Hermes API server", icon: Bot, hideFromVisualSelection: true, }, hermes_local: { label: "Hermes", - description: "Local Hermes agent", + description: "Hermes harness", icon: Bot, }, opencode_local: { label: "OpenCode", - description: "Local multi-provider agent", + description: "OpenCode multi-provider harness", icon: OpenCodeLogoIcon, }, pi_local: { label: "Pi", - description: "Local Pi agent", + description: "Pi harness", icon: Terminal, }, cursor: { label: "Cursor", - description: "Local Cursor agent", + description: "Cursor CLI harness", icon: MousePointer2, }, cursor_cloud: { @@ -142,7 +148,7 @@ const adapterDisplayMap: Record = { function humanizeType(type: string): string { // Strip known type suffixes so "droid_local" → "Droid", not "Droid Local" let base = type; - for (const suffix of Object.keys(TYPE_SUFFIXES)) { + for (const suffix of STRIPPED_TYPE_SUFFIXES) { if (base.endsWith(suffix)) { base = base.slice(0, -suffix.length); break; @@ -152,16 +158,20 @@ function humanizeType(type: string): string { } export function getAdapterLabel(type: string): string { - const base = adapterDisplayMap[type]?.label ?? humanizeType(type); - return withSuffix(base, getTypeSuffix(type)); + // Known labels are final — only unknown (plugin) types get a derived + // suffix, so labels like "OpenClaw Gateway" don't become + // "OpenClaw Gateway (gateway)". + const known = adapterDisplayMap[type]; + if (known) return known.label; + return withSuffix(humanizeType(type), getTypeSuffix(type)); } export function getAdapterLabels(): Record { - const suffixed: Record = {}; + const labels: Record = {}; for (const [type, info] of Object.entries(adapterDisplayMap)) { - suffixed[type] = withSuffix(info.label, getTypeSuffix(type)); + labels[type] = info.label; } - return suffixed; + return labels; } export function getAdapterDisplay(type: string): AdapterDisplayInfo { diff --git a/ui/src/adapters/claude-local/index.ts b/ui/src/adapters/claude-local/index.ts index fc2904d014..5bb32eaa8c 100644 --- a/ui/src/adapters/claude-local/index.ts +++ b/ui/src/adapters/claude-local/index.ts @@ -5,7 +5,7 @@ import { buildClaudeLocalConfig } from "@paperclipai/adapter-claude-local/ui"; export const claudeLocalUIAdapter: UIAdapterModule = { type: "claude_local", - label: "Claude Code (local)", + label: "Claude Code", parseStdoutLine: parseClaudeStdoutLine, ConfigFields: ClaudeLocalConfigFields, buildAdapterConfig: buildClaudeLocalConfig, diff --git a/ui/src/adapters/codex-local/index.ts b/ui/src/adapters/codex-local/index.ts index 31a11bf3d5..0d9dd1a3dd 100644 --- a/ui/src/adapters/codex-local/index.ts +++ b/ui/src/adapters/codex-local/index.ts @@ -5,7 +5,7 @@ import { buildCodexLocalConfig } from "@paperclipai/adapter-codex-local/ui"; export const codexLocalUIAdapter: UIAdapterModule = { type: "codex_local", - label: "Codex (local)", + label: "Codex", parseStdoutLine: parseCodexStdoutLine, ConfigFields: CodexLocalConfigFields, buildAdapterConfig: buildCodexLocalConfig, diff --git a/ui/src/adapters/cursor/index.ts b/ui/src/adapters/cursor/index.ts index b80cff6e9b..9aa5ba0280 100644 --- a/ui/src/adapters/cursor/index.ts +++ b/ui/src/adapters/cursor/index.ts @@ -5,7 +5,7 @@ import { buildCursorLocalConfig } from "@paperclipai/adapter-cursor-local/ui"; export const cursorLocalUIAdapter: UIAdapterModule = { type: "cursor", - label: "Cursor CLI (local)", + label: "Cursor", parseStdoutLine: parseCursorStdoutLine, ConfigFields: CursorLocalConfigFields, buildAdapterConfig: buildCursorLocalConfig, diff --git a/ui/src/adapters/gemini-local/index.ts b/ui/src/adapters/gemini-local/index.ts index d4cb89e515..97a585d381 100644 --- a/ui/src/adapters/gemini-local/index.ts +++ b/ui/src/adapters/gemini-local/index.ts @@ -5,7 +5,7 @@ import { buildGeminiLocalConfig } from "@paperclipai/adapter-gemini-local/ui"; export const geminiLocalUIAdapter: UIAdapterModule = { type: "gemini_local", - label: "Gemini CLI (local)", + label: "Gemini CLI", parseStdoutLine: parseGeminiStdoutLine, ConfigFields: GeminiLocalConfigFields, buildAdapterConfig: buildGeminiLocalConfig, diff --git a/ui/src/adapters/grok-local/index.ts b/ui/src/adapters/grok-local/index.ts index 31b7ffe27e..ae08b64cac 100644 --- a/ui/src/adapters/grok-local/index.ts +++ b/ui/src/adapters/grok-local/index.ts @@ -5,7 +5,7 @@ import { GrokLocalConfigFields } from "./config-fields"; export const grokLocalUIAdapter: UIAdapterModule = { type: "grok_local", - label: "Grok Build (local)", + label: "Grok Build", parseStdoutLine: parseGrokStdoutLine, createStdoutParser: createGrokStdoutParser, ConfigFields: GrokLocalConfigFields, diff --git a/ui/src/adapters/opencode-local/index.ts b/ui/src/adapters/opencode-local/index.ts index b68f3ace00..97e5029b24 100644 --- a/ui/src/adapters/opencode-local/index.ts +++ b/ui/src/adapters/opencode-local/index.ts @@ -5,7 +5,7 @@ import { buildOpenCodeLocalConfig } from "@paperclipai/adapter-opencode-local/ui export const openCodeLocalUIAdapter: UIAdapterModule = { type: "opencode_local", - label: "OpenCode (local)", + label: "OpenCode", parseStdoutLine: parseOpenCodeStdoutLine, ConfigFields: OpenCodeLocalConfigFields, buildAdapterConfig: buildOpenCodeLocalConfig, diff --git a/ui/src/adapters/pi-local/index.ts b/ui/src/adapters/pi-local/index.ts index cfebf6698d..907bb148d3 100644 --- a/ui/src/adapters/pi-local/index.ts +++ b/ui/src/adapters/pi-local/index.ts @@ -5,7 +5,7 @@ import { buildPiLocalConfig } from "@paperclipai/adapter-pi-local/ui"; export const piLocalUIAdapter: UIAdapterModule = { type: "pi_local", - label: "Pi (local)", + label: "Pi", parseStdoutLine: parsePiStdoutLine, ConfigFields: PiLocalConfigFields, buildAdapterConfig: buildPiLocalConfig, diff --git a/ui/src/pages/AdapterManager.tsx b/ui/src/pages/AdapterManager.tsx index c55b66f17a..a90cc517f0 100644 --- a/ui/src/pages/AdapterManager.tsx +++ b/ui/src/pages/AdapterManager.tsx @@ -72,7 +72,10 @@ function AdapterRow({
- {adapter.label || getAdapterLabel(adapter.type)} + {/* The server reports label = raw type id, so prefer the display + registry's human label; keep a real self-reported label if an + external adapter ever provides one. */} + {adapter.label && adapter.label !== adapter.type ? adapter.label : getAdapterLabel(adapter.type)} {adapter.source === "external" ? "External" : "Built-in"} {adapter.source === "external" && ( diff --git a/ui/storybook/.storybook/preview.tsx b/ui/storybook/.storybook/preview.tsx index 011ec14b5b..552da835c2 100644 --- a/ui/storybook/.storybook/preview.tsx +++ b/ui/storybook/.storybook/preview.tsx @@ -104,7 +104,7 @@ function installStorybookApiFixtures() { return Response.json([ { type: "claude_local", - label: "Claude Local", + label: "Claude Code", source: "builtin", modelsCount: 2, loaded: true, @@ -119,7 +119,7 @@ function installStorybookApiFixtures() { }, { type: "codex_local", - label: "Codex Local", + label: "Codex", source: "builtin", modelsCount: 3, loaded: true, diff --git a/ui/storybook/stories/agent-management.stories.tsx b/ui/storybook/stories/agent-management.stories.tsx index c5a727fe37..2fdf2ef24b 100644 --- a/ui/storybook/stories/agent-management.stories.tsx +++ b/ui/storybook/stories/agent-management.stories.tsx @@ -298,7 +298,7 @@ const storybookSecrets: CompanySecret[] = [ const adapterFixtures: AdapterInfo[] = [ { type: "codex_local", - label: "Codex Local", + label: "Codex", source: "builtin", modelsCount: 3, loaded: true, @@ -313,7 +313,7 @@ const adapterFixtures: AdapterInfo[] = [ }, { type: "claude_local", - label: "Claude Local", + label: "Claude Code", source: "builtin", modelsCount: 2, loaded: true, diff --git a/ui/storybook/stories/dialogs-modals.stories.tsx b/ui/storybook/stories/dialogs-modals.stories.tsx index c0a7b7e2ef..24e25c74d2 100644 --- a/ui/storybook/stories/dialogs-modals.stories.tsx +++ b/ui/storybook/stories/dialogs-modals.stories.tsx @@ -373,7 +373,7 @@ function hydrateDialogQueries(queryClient: ReturnType) { queryClient.setQueryData(queryKeys.adapters.all, [ { type: "codex_local", - label: "Codex local", + label: "Codex", source: "builtin", modelsCount: 5, loaded: true, @@ -388,7 +388,7 @@ function hydrateDialogQueries(queryClient: ReturnType) { }, { type: "claude_local", - label: "Claude local", + label: "Claude Code", source: "builtin", modelsCount: 4, loaded: true, @@ -721,7 +721,7 @@ function useCheapLaneAdapterOverrides(variant: CheapLaneVariant) { queryClient.setQueryData(queryKeys.adapters.all, [ { type: "codex_local", - label: "Codex local", + label: "Codex", source: "builtin", modelsCount: 5, loaded: true, @@ -736,7 +736,7 @@ function useCheapLaneAdapterOverrides(variant: CheapLaneVariant) { }, { type: "opencode_local", - label: "OpenCode local", + label: "OpenCode", source: "builtin", modelsCount: 2, loaded: true, diff --git a/ui/storybook/stories/forms-editors.stories.tsx b/ui/storybook/stories/forms-editors.stories.tsx index 8c267fea90..8fa17c2071 100644 --- a/ui/storybook/stories/forms-editors.stories.tsx +++ b/ui/storybook/stories/forms-editors.stories.tsx @@ -121,7 +121,7 @@ const adapterSchema: JsonSchemaNode = { title: "Adapter name", description: "Human-readable name shown in the adapter manager.", minLength: 3, - default: "Codex local", + default: "Codex", }, mode: { type: "string", @@ -175,7 +175,7 @@ const adapterSchema: JsonSchemaNode = { const validAdapterValues = { ...getDefaultValues(adapterSchema), - adapterName: "Codex local", + adapterName: "Codex", mode: "implementation", apiKey: "secret:openai-api-key", concurrency: 2,