Skip to content

Commit 4fbb459

Browse files
Remove repositories from being a mentionable item, instead opting for using the selector as the source of truth. Plumbed repo selection to route.
1 parent 8a5c7e7 commit 4fbb459

File tree

13 files changed

+70
-215
lines changed

13 files changed

+70
-215
lines changed

packages/web/src/app/[domain]/chat/[id]/components/chatThreadPanel.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { CreateUIMessage } from 'ai';
1515
import { ChatBoxToolbarProps } from '@/features/chat/components/chatBox/chatBoxToolbar';
1616

1717
interface ChatThreadPanelProps {
18-
chatBoxToolbarProps: ChatBoxToolbarProps;
18+
chatBoxToolbarProps: Omit<ChatBoxToolbarProps, "selectedRepos" | "onSelectedReposChange">;
1919
order: number;
2020
}
2121

@@ -30,6 +30,7 @@ export const ChatThreadPanel = ({
3030
const router = useRouter();
3131
const searchParams = useSearchParams();
3232
const [inputMessage, setInputMessage] = useState<CreateUIMessage<SBChatMessage> | undefined>(undefined);
33+
const [selectedRepos, setSelectedRepos] = useState<string[]>([]);
3334

3435
const { data: messages, isPending, isError } = useQuery({
3536
queryKey: ['load-chat', chatId, domain],
@@ -50,8 +51,9 @@ export const ChatThreadPanel = ({
5051
}
5152

5253
try {
53-
const { inputMessage } = JSON.parse(setChatState) as SetChatStatePayload;
54+
const { inputMessage, selectedRepos } = JSON.parse(setChatState) as SetChatStatePayload;
5455
setInputMessage(inputMessage);
56+
setSelectedRepos(selectedRepos);
5557
} catch {
5658
console.error('Invalid message in URL');
5759
}
@@ -84,6 +86,8 @@ export const ChatThreadPanel = ({
8486
initialMessages={messages}
8587
inputMessage={inputMessage}
8688
chatBoxToolbarProps={chatBoxToolbarProps}
89+
selectedRepos={selectedRepos}
90+
onSelectedReposChange={setSelectedRepos}
8791
/>
8892
)}
8993
</div>

packages/web/src/app/[domain]/chat/components/newChatPanel.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,24 @@ import { ChatBox } from "@/features/chat/components/chatBox";
55
import { ChatBoxToolbar, ChatBoxToolbarProps } from "@/features/chat/components/chatBox/chatBoxToolbar";
66
import { CustomSlateEditor } from "@/features/chat/customSlateEditor";
77
import { useCreateNewChatThread } from "@/features/chat/useCreateNewChatThread";
8-
import { useCallback } from "react";
8+
import { useCallback, useState } from "react";
99
import { Descendant } from "slate";
1010

1111
interface NewChatPanelProps {
12-
chatBoxToolbarProps: ChatBoxToolbarProps;
12+
chatBoxToolbarProps: Omit<ChatBoxToolbarProps, "selectedRepos" | "onSelectedReposChange">;
1313
order: number;
1414
}
1515

1616
export const NewChatPanel = ({
1717
chatBoxToolbarProps,
1818
order,
1919
}: NewChatPanelProps) => {
20+
const [selectedRepos, setSelectedRepos] = useState<string[]>([]);
2021
const { createNewChatThread, isLoading } = useCreateNewChatThread();
2122

2223
const onSubmit = useCallback((children: Descendant[]) => {
23-
createNewChatThread(children);
24-
}, [createNewChatThread]);
24+
createNewChatThread(children, selectedRepos);
25+
}, [createNewChatThread, selectedRepos]);
2526

2627

2728
return (
@@ -43,6 +44,8 @@ export const NewChatPanel = ({
4344
<div className="w-full flex flex-row items-center bg-accent rounded-b-md px-2">
4445
<ChatBoxToolbar
4546
{...chatBoxToolbarProps}
47+
selectedRepos={selectedRepos}
48+
onSelectedReposChange={setSelectedRepos}
4649
/>
4750
</div>
4851
</CustomSlateEditor>

packages/web/src/app/[domain]/components/homepage/agenticSearch.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ const suggestions: Record<SuggestionType, {
7171

7272
interface AgenticSearchProps {
7373
searchModeSelectorProps: SearchModeSelectorProps;
74-
chatBoxToolbarProps: ChatBoxToolbarProps;
74+
chatBoxToolbarProps: Omit<ChatBoxToolbarProps, "selectedRepos" | "onSelectedReposChange">;
7575
}
7676

7777
export const AgenticSearch = ({
@@ -82,7 +82,8 @@ export const AgenticSearch = ({
8282
const { createNewChatThread, isLoading } = useCreateNewChatThread();
8383
const dropdownRef = useRef<HTMLDivElement>(null);
8484
const editor = useSlate();
85-
85+
const [selectedRepos, setSelectedRepos] = useState<string[]>([]);
86+
8687
const setSelectedSuggestionType = useCallback((type: SuggestionType | undefined) => {
8788
_setSelectedSuggestionType(type);
8889
if (type) {
@@ -111,7 +112,7 @@ export const AgenticSearch = ({
111112
>
112113
<ChatBox
113114
onSubmit={(children) => {
114-
createNewChatThread(children);
115+
createNewChatThread(children, selectedRepos);
115116
}}
116117
className="min-h-[50px]"
117118
isRedirecting={isLoading}
@@ -121,6 +122,8 @@ export const AgenticSearch = ({
121122
<div className="w-full flex flex-row items-center bg-accent rounded-b-md px-2">
122123
<ChatBoxToolbar
123124
{...chatBoxToolbarProps}
125+
selectedRepos={selectedRepos}
126+
onSelectedReposChange={setSelectedRepos}
124127
/>
125128
<SearchModeSelector
126129
{...searchModeSelectorProps}

packages/web/src/features/chat/agent.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ Your workflow has two distinct phases:
156156
</workflow>
157157
158158
<available_repositories>
159-
The following repositories are available for analysis:
159+
The user has selected the following repositories for analysis:
160160
${selectedRepos.map(repo => `- ${repo}`).join('\n')}
161161
</available_repositories>
162162

packages/web/src/features/chat/components/chatBox/chatBox.tsx

Lines changed: 6 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,18 @@ import { Button } from "@/components/ui/button";
55
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
66
import { CustomEditor, MentionElement, RenderElementPropsFor } from "@/features/chat/types";
77
import { insertMention, slateContentToString } from "@/features/chat/utils";
8-
import { cn, getCodeHostIcon, IS_MAC } from "@/lib/utils";
8+
import { cn, IS_MAC } from "@/lib/utils";
99
import { computePosition, flip, offset, shift, VirtualElement } from "@floating-ui/react";
10-
import { ArrowUp, BookIcon, Loader2, StopCircleIcon } from "lucide-react";
10+
import { ArrowUp, Loader2, StopCircleIcon } from "lucide-react";
1111
import { Fragment, KeyboardEvent, useCallback, useEffect, useMemo, useRef, useState } from "react";
1212
import { useHotkeys } from "react-hotkeys-hook";
1313
import { Descendant, insertText } from "slate";
1414
import { Editable, ReactEditor, RenderElementProps, RenderLeafProps, useFocused, useSelected, useSlate } from "slate-react";
15+
import { useSelectedLanguageModel } from "../../useSelectedLanguageModel";
1516
import { SuggestionBox } from "./suggestionsBox";
1617
import { Suggestion } from "./types";
1718
import { useSuggestionModeAndQuery } from "./useSuggestionModeAndQuery";
1819
import { useSuggestionsData } from "./useSuggestionsData";
19-
import Image from "next/image";
20-
import { useSelectedLanguageModel } from "../../useSelectedLanguageModel";
2120

2221
interface ChatBoxProps {
2322
onSubmit: (children: Descendant[], editor: CustomEditor) => void;
@@ -43,6 +42,8 @@ export const ChatBox = ({
4342
const { suggestions, isLoading } = useSuggestionsData({
4443
suggestionMode,
4544
suggestionQuery,
45+
// @todo: add selected repos.
46+
selectedRepos: [],
4647
});
4748
const { selectedLanguageModel } = useSelectedLanguageModel();
4849

@@ -104,19 +105,8 @@ export const ChatBox = ({
104105
revision: suggestion.revision,
105106
}, range);
106107
break;
107-
case 'repo':
108-
insertMention(editor, {
109-
type: 'repo',
110-
name: suggestion.name,
111-
displayName: suggestion.displayName,
112-
codeHostType: suggestion.codeHostType,
113-
}, range);
114-
break;
115108
case 'refine': {
116109
switch (suggestion.targetSuggestionMode) {
117-
case 'repo':
118-
insertText(editor, 'repo:');
119-
break;
120110
case 'file':
121111
insertText(editor, 'file:');
122112
break;
@@ -213,7 +203,7 @@ export const ChatBox = ({
213203
>
214204
<Editable
215205
className="w-full focus-visible:outline-none focus-visible:ring-0 bg-background text-base disabled:cursor-not-allowed disabled:opacity-50 md:text-sm"
216-
placeholder="Ask, plan, or search your codebase. @mention files and repos to refine your query."
206+
placeholder="Ask, plan, or search your codebase. @mention files to refine your query."
217207
renderElement={renderElement}
218208
renderLeaf={renderLeaf}
219209
onKeyDown={onKeyDown}
@@ -326,32 +316,4 @@ const MentionComponent = ({
326316
</Tooltip>
327317
)
328318
}
329-
else if (data.type === 'repo') {
330-
const icon = getCodeHostIcon(data.codeHostType);
331-
return (
332-
<span
333-
{...attributes}
334-
contentEditable={false}
335-
className={cn(
336-
"px-1.5 py-0.5 mr-1.5 mb-1 align-baseline inline-block rounded bg-muted text-xs font-mono",
337-
{
338-
"ring-2 ring-blue-300": selected && focused
339-
}
340-
)}
341-
>
342-
<span contentEditable={false} className="flex flex-row items-center select-none">
343-
{icon ? (
344-
<Image
345-
src={icon.src}
346-
alt={data.codeHostType}
347-
className={cn("w-3 h-3 mr-1", icon.className)}
348-
/>
349-
) : (
350-
<BookIcon className="w-3 h-3 mr-1" />
351-
)}
352-
{data.displayName ?? data.name}
353-
</span>
354-
</span>
355-
)
356-
}
357319
}

packages/web/src/features/chat/components/chatBox/chatBoxToolbar.tsx

Lines changed: 14 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,28 @@ import { KeyboardShortcutHint } from "@/app/components/keyboardShortcutHint";
44
import { Button } from "@/components/ui/button";
55
import { Separator } from "@/components/ui/separator";
66
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
7-
import { LanguageModelInfo, RepoMentionData } from "@/features/chat/types";
8-
import { insertMention, isMentionElement } from "@/features/chat/utils";
7+
import { LanguageModelInfo } from "@/features/chat/types";
98
import { RepositoryQuery } from "@/lib/types";
109
import { AtSignIcon } from "lucide-react";
1110
import { useCallback } from "react";
1211
import { useHotkeys } from "react-hotkeys-hook";
13-
import { Descendant, Transforms } from "slate";
1412
import { ReactEditor, useSlate } from "slate-react";
15-
import { useRepoMentions } from "../../useRepoMentions";
1613
import { useSelectedLanguageModel } from "../../useSelectedLanguageModel";
1714
import { LanguageModelSelector } from "./languageModelSelector";
1815
import { RepoSelector } from "./repoSelector";
1916

2017
export interface ChatBoxToolbarProps {
2118
languageModels: LanguageModelInfo[];
2219
repos: RepositoryQuery[];
20+
selectedRepos: string[];
21+
onSelectedReposChange: (repos: string[]) => void;
2322
}
2423

2524
export const ChatBoxToolbar = ({
2625
languageModels,
2726
repos,
27+
selectedRepos,
28+
onSelectedReposChange,
2829
}: ChatBoxToolbarProps) => {
2930
const editor = useSlate();
3031

@@ -42,35 +43,8 @@ export const ChatBoxToolbar = ({
4243
description: "Add context",
4344
});
4445

45-
const selectedRepos = useRepoMentions();
4646
const { selectedLanguageModel, setSelectedLanguageModel } = useSelectedLanguageModel();
4747

48-
const onSelectedReposChange = useCallback((repos: RepoMentionData[]) => {
49-
const addedRepos = repos.filter((repo) => !selectedRepos.some((selectedRepo) => selectedRepo.name === repo.name));
50-
const removedRepos = selectedRepos.filter((repo) => !repos.some((selectedRepo) => selectedRepo.name === repo.name));
51-
52-
addedRepos.forEach((repo) => {
53-
console.log('adding repo', repo);
54-
insertMention(editor, {
55-
type: 'repo',
56-
name: repo.name,
57-
displayName: repo.displayName,
58-
codeHostType: repo.codeHostType,
59-
})
60-
});
61-
62-
Transforms.removeNodes(editor, {
63-
at: [],
64-
match: (node) => {
65-
const descendant = node as Descendant;
66-
return isMentionElement(descendant) &&
67-
descendant.data.type === 'repo' &&
68-
removedRepos.some((repo) => repo.name === descendant.data.name);
69-
}
70-
});
71-
72-
}, [editor, selectedRepos]);
73-
7448
return (
7549
<>
7650
<Tooltip>
@@ -98,12 +72,7 @@ export const ChatBoxToolbar = ({
9872
<TooltipTrigger asChild>
9973
<RepoSelector
10074
className="bg-inherit w-fit h-6 min-h-6"
101-
repos={repos?.map((repo) => ({
102-
type: 'repo',
103-
name: repo.repoName,
104-
displayName: repo.repoDisplayName,
105-
codeHostType: repo.codeHostType,
106-
})) ?? []}
75+
repos={repos.map((repo) => repo.repoName)}
10776
selectedRepos={selectedRepos}
10877
onSelectedReposChange={onSelectedReposChange}
10978
/>
@@ -117,14 +86,16 @@ export const ChatBoxToolbar = ({
11786
<Separator orientation="vertical" className="h-3 ml-1 mr-2" />
11887
<Tooltip>
11988
<TooltipTrigger asChild>
120-
<LanguageModelSelector
121-
languageModels={languageModels}
122-
onSelectedModelChange={setSelectedLanguageModel}
123-
selectedModel={selectedLanguageModel}
124-
/>
89+
<div>
90+
<LanguageModelSelector
91+
languageModels={languageModels}
92+
onSelectedModelChange={setSelectedLanguageModel}
93+
selectedModel={selectedLanguageModel}
94+
/>
95+
</div>
12596
</TooltipTrigger>
12697
<TooltipContent side="bottom">
127-
<span>Configured language model</span>
98+
<span>Selected language model</span>
12899
</TooltipContent>
129100
</Tooltip>
130101
</>

packages/web/src/features/chat/components/chatBox/repoSelector.tsx

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,11 @@ import {
2323
CommandList,
2424
CommandSeparator,
2525
} from "@/components/ui/command";
26-
import { RepoMentionData } from "../../types";
2726

2827
interface RepoSelectorProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
29-
repos: RepoMentionData[];
30-
selectedRepos: RepoMentionData[];
31-
onSelectedReposChange: (repos: RepoMentionData[]) => void;
28+
repos: string[];
29+
selectedRepos: string[];
30+
onSelectedReposChange: (repos: string[]) => void;
3231
className?: string;
3332
}
3433

@@ -60,11 +59,11 @@ export const RepoSelector = React.forwardRef<
6059
}
6160
};
6261

63-
const toggleRepo = (repo: RepoMentionData) => {
64-
const newSelectedRepos = selectedRepos.some((selectedRepo) => selectedRepo.name === repo.name)
65-
? selectedRepos.filter((selectedRepo) => selectedRepo.name !== repo.name)
62+
const toggleRepo = (repo: string) => {
63+
const newSelectedValues = selectedRepos.includes(repo)
64+
? selectedRepos.filter((value) => value !== repo)
6665
: [...selectedRepos, repo];
67-
onSelectedReposChange(newSelectedRepos);
66+
onSelectedReposChange(newSelectedValues);
6867
};
6968

7069
const handleClear = () => {
@@ -100,7 +99,7 @@ export const RepoSelector = React.forwardRef<
10099
>
101100
{
102101
selectedRepos.length === 0 ? `${repos.length} repo${repos.length === 1 ? '' : 's'}` :
103-
selectedRepos.length === 1 ? `${selectedRepos[0].displayName ?? selectedRepos[0].name}` :
102+
selectedRepos.length === 1 ? `${selectedRepos[0].split('/').pop()}` :
104103
`${selectedRepos.length} repo${selectedRepos.length === 1 ? '' : 's'}`
105104
}
106105
</span>
@@ -123,10 +122,10 @@ export const RepoSelector = React.forwardRef<
123122
<CommandGroup>
124123

125124
{repos.map((repo) => {
126-
const isSelected = selectedRepos.some((selectedRepo) => selectedRepo.name === repo.name);
125+
const isSelected = selectedRepos.includes(repo);
127126
return (
128127
<CommandItem
129-
key={repo.name}
128+
key={repo}
130129
onSelect={() => toggleRepo(repo)}
131130
className="cursor-pointer"
132131
>
@@ -140,7 +139,7 @@ export const RepoSelector = React.forwardRef<
140139
>
141140
<CheckIcon className="h-4 w-4" />
142141
</div>
143-
<span>{repo.displayName ?? repo.name}</span>
142+
<span>{repo}</span>
144143
</CommandItem>
145144
);
146145
})}

0 commit comments

Comments
 (0)