From 35a2bee409d8e47dac7cfce3da065851bcd7bc62 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Fri, 2 Oct 2026 14:41:35 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=97=82=EF=B8=8F=20feat:=20Choose=20Conver?= =?UTF-8?q?sation=20Checkout=20Mode=20(#16679)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Choose the conversation checkout mode * fix: Preserve checkout choices across submission and recovery * test: Match checkout policy defaults and share mode enum * fix: Offer shared checkout and require deliberate transition modes * fix: Retain explicit mode when changing repository selection * test: Match repository menu accessible labels --- .../Chat/Input/CodeWorkspaceMenu.tsx | 228 ++++++++++++--- .../__tests__/CodeWorkspaceMenu.spec.tsx | 273 ++++++++++++++++++ .../__tests__/useCodeWorkspace.test.tsx | 63 ++++ client/src/hooks/Agents/useCodeWorkspace.ts | 23 +- client/src/locales/en/translation.json | 7 +- docs/workspace-checkouts.md | 54 ++++ packages/api/src/agents/execution.spec.ts | 11 + packages/api/src/agents/execution.ts | 1 + packages/api/src/code/capabilities.spec.ts | 73 ++++- packages/api/src/code/capabilities.ts | 24 +- packages/api/src/code/http.spec.ts | 42 ++- packages/api/src/code/http.ts | 18 +- .../data-provider/src/code/selection.spec.ts | 39 ++- packages/data-provider/src/code/workspace.ts | 26 +- packages/data-provider/src/config.spec.ts | 10 + packages/data-provider/src/config.ts | 3 + packages/data-provider/src/schemas.ts | 2 + .../src/methods/conversation.spec.ts | 18 ++ .../data-schemas/src/schema/defaults.spec.ts | 31 ++ packages/data-schemas/src/schema/defaults.ts | 8 +- 20 files changed, 888 insertions(+), 66 deletions(-) create mode 100644 docs/workspace-checkouts.md create mode 100644 packages/data-schemas/src/schema/defaults.spec.ts diff --git a/client/src/components/Chat/Input/CodeWorkspaceMenu.tsx b/client/src/components/Chat/Input/CodeWorkspaceMenu.tsx index 35638c973d..ccc64256e4 100644 --- a/client/src/components/Chat/Input/CodeWorkspaceMenu.tsx +++ b/client/src/components/Chat/Input/CodeWorkspaceMenu.tsx @@ -1,5 +1,6 @@ -import { useId, useState } from 'react'; +import { Fragment, useId, useState } from 'react'; import * as Ariakit from '@ariakit/react'; +import { isCodeWorkspaceCheckoutAvailable } from 'librechat-data-provider'; import { TooltipAnchor, composerControlClasses, useToastContext } from '@librechat/client'; import { Check, ChevronDown, Folder, FolderSync, FolderX, RefreshCw, Monitor } from 'lucide-react'; import type { CodeWorkspaceSelection, TConversation } from 'librechat-data-provider'; @@ -103,10 +104,11 @@ function describeTransition( /** A sole advertised workspace is the only valid pick, so it counts as chosen until changed. */ function chosenWorkspaceId( target: CodeWorkspaceEnvironmentResult, - choices: Record, + choices: Record, ): string | undefined { const choice = choices[target.environment.id]; - if (choice != null && target.workspaces.some(({ id }) => id === choice)) return choice; + if (choice != null && target.workspaces.some(({ id }) => id === choice.workspaceId)) + return choice.workspaceId; return target.workspaces.length === 1 ? target.workspaces[0].id : undefined; } @@ -118,6 +120,8 @@ function EnvironmentWorkspaces({ hideOnClick, isSelected, onSelect, + checkout, + allowCheckoutSelection = false, }: { environment: CodeWorkspaceEnvironmentResult['environment']; requiredBy?: CodeWorkspaceEnvironmentResult['requiredBy']; @@ -126,6 +130,8 @@ function EnvironmentWorkspaces({ hideOnClick: boolean; isSelected: (workspaceId: string) => boolean; onSelect: (selection: CodeWorkspaceSelection) => void; + checkout?: CodeWorkspaceSelection['checkout']; + allowCheckoutSelection?: boolean; }) { const localize = useLocalize(); return ( @@ -146,47 +152,106 @@ function EnvironmentWorkspaces({ {workspaces.map((descriptor) => { const selected = isSelected(descriptor.id); return ( - onSelect({ environmentId: environment.id, workspaceId: descriptor.id })} - className={menuItemClasses(selected)} - > -