Skip to content

Commit 3425671

Browse files
feat(web): Add provider leads with first-class providers (#25753)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent f6a9315 commit 3425671

15 files changed

Lines changed: 220 additions & 119 deletions

File tree

‎apps/web/src/components/settings/AcpRegistrySearchStep.browser.test.tsx‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,12 @@ it("rechecks the grant before preparing an agent", async () => {
116116
expect(state.prepare).not.toHaveBeenCalled();
117117
expect(onPrepared).not.toHaveBeenCalled();
118118
});
119+
120+
it("leaves out Registry agents that T3 Code supports as their own providers", async () => {
121+
setup();
122+
state.result = { agents: [gemini, { ...gemini, id: "codex-acp", name: "Codex" }] };
123+
await using _screen = await render(<Step />);
124+
125+
expect(page.getByRole("button", { name: "Add Gemini CLI" }).query()).not.toBeNull();
126+
expect(page.getByRole("button", { name: "Add Codex" }).query()).toBeNull();
127+
});

‎apps/web/src/components/settings/AcpRegistrySearchStep.tsx‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";
2525
import { isConfiguredAcpRegistryAgent } from "./AddProviderInstanceDialog.logic";
2626
import { ProviderDriverKind } from "@t3tools/contracts";
2727
import { ProviderInstanceIcon } from "../chat/ProviderInstanceIcon";
28+
import { providerClients } from "./providerDriverMeta";
2829

2930
function errorMessage(error: unknown): string {
3031
return error instanceof Error && error.message.trim()
@@ -33,6 +34,9 @@ function errorMessage(error: unknown): string {
3334
}
3435

3536
const ACP_REGISTRY_SEARCH_DEBOUNCE_MS = 300;
37+
const FIRST_CLASS_REGISTRY_AGENT_IDS = new Set(
38+
providerClients.definitions.flatMap((definition) => definition.acpRegistryAgentIds ?? []),
39+
);
3640

3741
function applyAcpRegistryPrepareResult(
3842
agent: AcpRegistrySearchAgent,
@@ -144,7 +148,8 @@ export function AcpRegistrySearchStep({
144148
void registry.prepare(agent, onPrepared);
145149
};
146150

147-
const results = search.data?.agents ?? null;
151+
const results =
152+
search.data?.agents.filter((agent) => !FIRST_CLASS_REGISTRY_AGENT_IDS.has(agent.id)) ?? null;
148153
const isInitialSearch = search.isPending && results === null;
149154
const isRefreshing = search.isPending && results !== null;
150155
const resultCount = results?.length ?? 0;

‎apps/web/src/components/settings/AddProviderInstanceDialog.environment.browser.test.tsx‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ function button(label: string) {
114114
return found!;
115115
}
116116
const click = (label: string) => act(async () => button(label).click());
117+
const radio = (label: string) =>
118+
[...document.querySelectorAll<HTMLElement>('[role="radio"]')].find(
119+
(element) => element.textContent?.trim() === label,
120+
);
117121
const input = (selector: string) => {
118122
const found = document.querySelector<HTMLInputElement>(selector);
119123
expect(found, selector).not.toBeNull();
@@ -166,11 +170,32 @@ describe("AddProviderInstanceDialog environment routing", () => {
166170
});
167171
});
168172

173+
it("keeps fx and the ACP Registry under Show more", async () => {
174+
setup();
175+
await using _screen = await render(dialog());
176+
expect(radio("Codex")).toBeDefined();
177+
expect(radio("fx")).toBeUndefined();
178+
expect(document.body.textContent).not.toContain("Use Kilo Code");
179+
180+
await click("Show more");
181+
button("Use Kilo Code");
182+
await act(async () => radio("fx")!.click());
183+
await click("Next");
184+
await click("Next");
185+
await click("Add instance");
186+
expect(settingsHooks.mutate).toHaveBeenCalledWith({
187+
operation: "create",
188+
instanceId: "fx",
189+
instance: { driver: "fx", enabled: true, displayName: "fx" },
190+
});
191+
});
192+
169193
it("awaits an atomic create before closing and retains prepared ACP metadata", async () => {
170194
setup();
171195
const mutation = deferred<{ readonly _tag: "Success"; readonly value: unknown }>();
172196
settingsHooks.mutate.mockReturnValueOnce(mutation.promise);
173197
await using _screen = await render(dialog());
198+
await click("Show more");
174199
await click("Use Kilo Code");
175200

176201
expect(document.body.textContent).toContain("v4.2.0 · binary");
@@ -202,6 +227,7 @@ describe("AddProviderInstanceDialog environment routing", () => {
202227
it("creates a local command in the selected environment without a sign-in step", async () => {
203228
setup();
204229
await using _screen = await render(dialog());
230+
await click("Show more");
205231
await click("Use local command");
206232
await click("Next");
207233
expect(document.body.textContent).toContain("Executable is required.");

‎apps/web/src/components/settings/AddProviderInstanceDialog.tsx‎

Lines changed: 156 additions & 107 deletions
Large diffs are not rendered by default.

‎apps/web/src/components/settings/providerDriverMeta.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ export const providerClients = makeProviderClientRegistry([
1717
{
1818
driverKind: ProviderDriverKind.make("codex"),
1919
label: "Codex",
20+
acpRegistryAgentIds: ["codex-acp"],
2021
settingsSchema: CodexSettings,
2122
},
2223
{
2324
driverKind: ProviderDriverKind.make("claudeAgent"),
2425
label: "Claude",
26+
acpRegistryAgentIds: ["claude-acp"],
2527
settingsSchema: ClaudeSettings,
2628
},
2729
cursorClient,
@@ -31,6 +33,7 @@ export const providerClients = makeProviderClientRegistry([
3133
{
3234
driverKind: ProviderDriverKind.make("antigravity"),
3335
label: "Antigravity",
36+
acpRegistryAgentIds: ["antigravity-acp"],
3437
settingsSchema: AntigravitySettings,
3538
},
3639
museClient,

‎docs/user/providers-acp.md‎

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ T3 Code can run installed ACP commands or coding agents from the official
55
own models, tools, and sign-in, while T3 Code provides projects, threads, checkpoints, and task
66
delegation.
77

8-
Google Antigravity is available through its official `antigravity-acp` Registry entry. Add it like
9-
any other Registry agent; it does not need an Antigravity-specific T3 Code provider.
8+
Agents that T3 Code supports as their own providers, such as Codex, Claude, Cursor, Grok, OpenCode,
9+
Pi, and [Antigravity](./providers-antigravity.md), don't appear in the Registry list. Enable them in
10+
**Settings → Providers** instead.
1011

1112
T3 Code prefers the current ACP v2 preview protocol and uses its richer messages, usage, plans,
1213
configuration, compaction, and agent-terminal updates when the agent supports them. It also
13-
negotiates ACP v1 for Registry agents that have not migrated yet, so agents such as Pi continue to
14-
work through the same generic integration.
14+
negotiates ACP v1 for Registry agents that have not migrated yet, so they continue to work through
15+
the same generic integration.
1516

1617
Claude Agent uses the ACP v2 preview by default for Registry and local `claude-agent-acp`
1718
commands. If you encounter preview issues, set `CLAUDE_AGENT_ACP_EXPERIMENTAL_V2=0` in the
@@ -20,16 +21,16 @@ provider instance's environment overrides to use ACP v1.
2021
## Add an agent
2122

2223
1. Open **Settings → Providers**.
23-
2. Select **Add provider** and search the ACP Registry.
24-
3. Search for the agent and select **Add** on its result.
24+
2. Select **Add provider**, then **Show more**.
25+
3. Search the ACP Registry for the agent and select **Add** on its result.
2526
4. Confirm the name and instance ID, then complete the agent's sign-in step.
2627

2728
Search only shows agents that can run on the connected server. Registry agents are third-party
2829
code; review an agent's source and license before adding it.
2930

3031
## Add a local command
3132

32-
In **Settings → Providers → Add provider**, select **Local ACP command**. Enter the executable
33+
In **Settings → Providers → Add provider**, select **Show more**, then **Local ACP command**. Enter the executable
3334
name or path on the selected environment, add one literal argument per row, and choose a display
3435
name. For DeepSeek Harness, use `dsh` with arguments `--profile` and `acp`.
3536

‎docs/user/providers-muse.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Muse Code
22

3-
Muse Code is a beta integration and is disabled by default. Install
3+
Muse Code is disabled by default. Install
44
[Muse Code](https://dev.meta.ai/docs/muse-code) on the machine hosting your
55
environment, then run `muse login` as the account that runs T3 Code.
66

‎packages/client-runtime/src/state/server.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,8 +1305,8 @@ export function createServerEnvironmentAtoms<R, E>(
13051305
searchAcpRegistry: createEnvironmentRpcQueryAtomFamily(runtime, {
13061306
label: "environment-data:server:acp-registry:search",
13071307
tag: WS_METHODS.serverSearchAcpRegistry,
1308-
staleTimeMs: 0,
1309-
idleTtlMs: 0,
1308+
// Reopening Add provider reuses recent results; submitting the same search refreshes it.
1309+
staleTimeMs: 5 * 60_000,
13101310
}),
13111311
configProjection,
13121312
welcome,

‎packages/provider-core/src/client.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ export interface ProviderClientDefinition {
4040
readonly environmentFields?: ReadonlyArray<ProviderEnvironmentField>;
4141
readonly hasDefaultInstance?: boolean;
4242
readonly badgeLabel?: string;
43+
/** `false` lists the provider under Add provider's "Show more" instead of up front. */
44+
readonly featured?: boolean;
45+
/** ACP Registry entries for this same agent, left out of Add provider's Registry list. */
46+
readonly acpRegistryAgentIds?: ReadonlyArray<string>;
4347
}
4448

4549
export function defineProviderClient<const Definition extends ProviderClientDefinition>(

‎packages/provider-cursor/src/client.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { CursorSettings } from "./settings.ts";
66
export const cursorClient = defineProviderClient({
77
driverKind: ProviderDriverKind.make("cursor"),
88
label: "Cursor",
9+
acpRegistryAgentIds: ["cursor"],
910
settingsSchema: CursorSettings,
1011
environmentFields: [
1112
{

0 commit comments

Comments
 (0)