From 20ac96e68dad99e795d2fbcc10ef036b19cde1a3 Mon Sep 17 00:00:00 2001 From: Thomas Kosiewski Date: Wed, 18 Mar 2026 14:25:38 +0100 Subject: [PATCH] feat(site): include chatId in editor deep links (#23214) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - include the current agent chat ID in VS Code and Cursor deep links opened from the agent detail page - extend `getVSCodeHref` so `chatId` is added only when provided - add focused tests for deep-link generation with and without `chatId` ## Testing - `pnpm -C site run format -- src/modules/apps/apps.ts src/modules/apps/apps.test.ts src/pages/AgentsPage/AgentDetail.tsx` - `pnpm -C site run check -- src/modules/apps/apps.ts src/modules/apps/apps.test.ts src/pages/AgentsPage/AgentDetail.tsx` - `pnpm -C site exec vitest run src/modules/apps/apps.test.ts` - `pnpm -C site run lint:types` --- _Generated with [`mux`](https://github.com/coder/mux) • Model: `openai:gpt-5.4` • Thinking: `high`_ --- site/src/modules/apps/apps.test.ts | 45 ++++++++++++++++++++++- site/src/modules/apps/apps.ts | 6 ++- site/src/pages/AgentsPage/AgentDetail.tsx | 1 + 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/site/src/modules/apps/apps.test.ts b/site/src/modules/apps/apps.test.ts index 96a1d1c686..c30e3bdbf9 100644 --- a/site/src/modules/apps/apps.test.ts +++ b/site/src/modules/apps/apps.test.ts @@ -3,7 +3,50 @@ import { MockWorkspaceAgent, MockWorkspaceApp, } from "testHelpers/entities"; -import { getAppHref, SESSION_TOKEN_PLACEHOLDER } from "./apps"; +import { getAppHref, getVSCodeHref, SESSION_TOKEN_PLACEHOLDER } from "./apps"; + +describe("getVSCodeHref", () => { + it("includes the chat ID when provided", () => { + const folder = "/workspace/test"; + const href = getVSCodeHref("vscode", { + owner: MockWorkspace.owner_name, + workspace: MockWorkspace.name, + token: "user-session-token", + agent: MockWorkspaceAgent.name, + folder, + chatId: "chat-123", + }); + const query = new URLSearchParams({ + owner: MockWorkspace.owner_name, + workspace: MockWorkspace.name, + url: location.origin, + token: "user-session-token", + openRecent: "true", + agent: MockWorkspaceAgent.name, + folder, + chatId: "chat-123", + }); + + expect(href).toBe(`vscode://coder.coder-remote/open?${query}`); + }); + + it("omits the chat ID when none is provided", () => { + const href = getVSCodeHref("cursor", { + owner: MockWorkspace.owner_name, + workspace: MockWorkspace.name, + token: "user-session-token", + }); + const query = new URLSearchParams({ + owner: MockWorkspace.owner_name, + workspace: MockWorkspace.name, + url: location.origin, + token: "user-session-token", + openRecent: "true", + }); + + expect(href).toBe(`cursor://coder.coder-remote/open?${query}`); + }); +}); describe("getAppHref", () => { it("returns the URL without changes when external app has regular URL", () => { diff --git a/site/src/modules/apps/apps.ts b/site/src/modules/apps/apps.ts index deabbc2753..da6df2432e 100644 --- a/site/src/modules/apps/apps.ts +++ b/site/src/modules/apps/apps.ts @@ -34,11 +34,12 @@ type GetVSCodeHrefParams = { token: string; agent?: string; folder?: string; + chatId?: string; }; export const getVSCodeHref = ( app: "vscode" | "vscode-insiders" | "cursor", - { owner, workspace, token, agent, folder }: GetVSCodeHrefParams, + { owner, workspace, token, agent, folder, chatId }: GetVSCodeHrefParams, ) => { const query = new URLSearchParams({ owner, @@ -53,6 +54,9 @@ export const getVSCodeHref = ( if (folder) { query.set("folder", folder); } + if (chatId) { + query.set("chatId", chatId); + } return `${app}://coder.coder-remote/open?${query}`; }; diff --git a/site/src/pages/AgentsPage/AgentDetail.tsx b/site/src/pages/AgentsPage/AgentDetail.tsx index 41d02eb464..226914eb68 100644 --- a/site/src/pages/AgentsPage/AgentDetail.tsx +++ b/site/src/pages/AgentsPage/AgentDetail.tsx @@ -781,6 +781,7 @@ const AgentDetail: FC = () => { token: key, agent: workspaceAgent.name, folder: workspaceAgent.expanded_directory, + chatId: agentId, }); }, onError: () => {