From f9e0500ef83e0d8037f11888aa8fdcdb73408509 Mon Sep 17 00:00:00 2001 From: msukkari Date: Mon, 28 Jul 2025 15:11:51 -0700 Subject: [PATCH] rename search context to search scope --- .../chat/[id]/components/chatThreadPanel.tsx | 32 +++++----- .../[domain]/chat/components/newChatPanel.tsx | 4 +- .../components/homepage/agenticSearch.tsx | 8 +-- .../homepage/askSourcebotDemoCards.tsx | 52 +++++++-------- .../web/src/app/api/(server)/chat/route.ts | 20 +++--- .../web/src/components/atMentionInfoCard.tsx | 15 +++++ .../src/components/searchScopeInfoCard.tsx | 12 ++-- .../chat/components/chatBox/chatBox.tsx | 18 +++--- .../components/chatBox/chatBoxToolbar.tsx | 29 ++------- ...xtSelector.tsx => searchScopeSelector.tsx} | 64 +++++++++---------- .../chat/components/chatThread/chatThread.tsx | 22 +++---- packages/web/src/features/chat/types.ts | 6 +- .../features/chat/useCreateNewChatThread.ts | 12 ++-- packages/web/src/features/chat/utils.ts | 4 +- packages/web/src/types.ts | 19 ++---- 15 files changed, 153 insertions(+), 164 deletions(-) create mode 100644 packages/web/src/components/atMentionInfoCard.tsx rename packages/web/src/features/chat/components/chatBox/{contextSelector.tsx => searchScopeSelector.tsx} (86%) diff --git a/packages/web/src/app/[domain]/chat/[id]/components/chatThreadPanel.tsx b/packages/web/src/app/[domain]/chat/[id]/components/chatThreadPanel.tsx index 48824d76..3653c049 100644 --- a/packages/web/src/app/[domain]/chat/[id]/components/chatThreadPanel.tsx +++ b/packages/web/src/app/[domain]/chat/[id]/components/chatThreadPanel.tsx @@ -8,7 +8,7 @@ import { CreateUIMessage } from 'ai'; import { useRouter, useSearchParams } from 'next/navigation'; import { useEffect, useState } from 'react'; import { useChatId } from '../../useChatId'; -import { ContextItem } from '@/features/chat/components/chatBox/contextSelector'; +import { SearchScopeItem } from '@/features/chat/components/chatBox/searchScopeSelector'; interface ChatThreadPanelProps { languageModels: LanguageModelInfo[]; @@ -37,9 +37,9 @@ export const ChatThreadPanel = ({ // Use the last user's last message to determine what repos and contexts we should select by default. const lastUserMessage = messages.findLast((message) => message.role === "user"); const defaultSelectedRepos = lastUserMessage?.metadata?.selectedRepos ?? []; - const defaultSelectedContexts = lastUserMessage?.metadata?.selectedContexts ?? []; + const defaultSelectedReposets = lastUserMessage?.metadata?.selectedReposets ?? []; - const [selectedItems, setSelectedItems] = useState([ + const [selectedItems, setSelectedItems] = useState([ ...defaultSelectedRepos.map(repoName => { const repoInfo = repos.find(r => r.repoName === repoName); return { @@ -49,13 +49,13 @@ export const ChatThreadPanel = ({ codeHostType: repoInfo?.codeHostType || '' }; }), - ...defaultSelectedContexts.map(contextName => { - const context = searchContexts.find(c => c.name === contextName); + ...defaultSelectedReposets.map(reposetName => { + const reposet = searchContexts.find(c => c.name === reposetName); return { - type: 'context' as const, - value: contextName, - name: contextName, - repoCount: context?.repoNames.length || 0 + type: 'reposet' as const, + value: reposetName, + name: reposetName, + repoCount: reposet?.repoNames.length || 0 }; }) ]); @@ -67,7 +67,7 @@ export const ChatThreadPanel = ({ } try { - const { inputMessage, selectedRepos, selectedContexts } = JSON.parse(setChatState) as SetChatStatePayload; + const { inputMessage, selectedRepos, selectedReposets } = JSON.parse(setChatState) as SetChatStatePayload; setInputMessage(inputMessage); setSelectedItems([ ...selectedRepos.map(repoName => { @@ -79,13 +79,13 @@ export const ChatThreadPanel = ({ codeHostType: repoInfo?.codeHostType || '' }; }), - ...selectedContexts.map(contextName => { - const context = searchContexts.find(c => c.name === contextName); + ...selectedReposets.map(reposetName => { + const reposet = searchContexts.find(c => c.name === reposetName); return { - type: 'context' as const, - value: contextName, - name: contextName, - repoCount: context?.repoNames.length || 0 + type: 'reposet' as const, + value: reposetName, + name: reposetName, + repoCount: reposet?.repoNames.length || 0 }; }) ]); diff --git a/packages/web/src/app/[domain]/chat/components/newChatPanel.tsx b/packages/web/src/app/[domain]/chat/components/newChatPanel.tsx index a2addcd4..190aff7c 100644 --- a/packages/web/src/app/[domain]/chat/components/newChatPanel.tsx +++ b/packages/web/src/app/[domain]/chat/components/newChatPanel.tsx @@ -10,7 +10,7 @@ import { RepositoryQuery, SearchContextQuery } from "@/lib/types"; import { useCallback, useState } from "react"; import { Descendant } from "slate"; import { useLocalStorage } from "usehooks-ts"; -import { ContextItem } from "@/features/chat/components/chatBox/contextSelector"; +import { SearchScopeItem } from "@/features/chat/components/chatBox/searchScopeSelector"; interface NewChatPanelProps { languageModels: LanguageModelInfo[]; @@ -25,7 +25,7 @@ export const NewChatPanel = ({ searchContexts, order, }: NewChatPanelProps) => { - const [selectedItems, setSelectedItems] = useLocalStorage("selectedContextItems", [], { initializeWithValue: false }); + const [selectedItems, setSelectedItems] = useLocalStorage("selectedContextItems", [], { initializeWithValue: false }); const { createNewChatThread, isLoading } = useCreateNewChatThread(); const [isContextSelectorOpen, setIsContextSelectorOpen] = useState(false); diff --git a/packages/web/src/app/[domain]/components/homepage/agenticSearch.tsx b/packages/web/src/app/[domain]/components/homepage/agenticSearch.tsx index c8bd472f..f3ccddfc 100644 --- a/packages/web/src/app/[domain]/components/homepage/agenticSearch.tsx +++ b/packages/web/src/app/[domain]/components/homepage/agenticSearch.tsx @@ -9,7 +9,7 @@ import { RepositoryQuery, SearchContextQuery } from "@/lib/types"; import { useState } from "react"; import { SearchModeSelector, SearchModeSelectorProps } from "./toolbar"; import { useLocalStorage } from "usehooks-ts"; -import { ContextItem } from "@/features/chat/components/chatBox/contextSelector"; +import { SearchScopeItem } from "@/features/chat/components/chatBox/searchScopeSelector"; import { DemoExamples } from "@/types"; import { AskSourcebotDemoCards } from "./askSourcebotDemoCards"; @@ -34,7 +34,7 @@ export const AgenticSearch = ({ demoExamples, }: AgenticSearchProps) => { const { createNewChatThread, isLoading } = useCreateNewChatThread(); - const [selectedItems, setSelectedItems] = useLocalStorage("selectedContextItems", [], { initializeWithValue: false }); + const [selectedItems, setSelectedItems] = useLocalStorage("selectedContextItems", [], { initializeWithValue: false }); const [isContextSelectorOpen, setIsContextSelectorOpen] = useState(false); return ( @@ -74,10 +74,6 @@ export const AgenticSearch = ({ {demoExamples && ( )} diff --git a/packages/web/src/app/[domain]/components/homepage/askSourcebotDemoCards.tsx b/packages/web/src/app/[domain]/components/homepage/askSourcebotDemoCards.tsx index 743a1fc6..61f64a14 100644 --- a/packages/web/src/app/[domain]/components/homepage/askSourcebotDemoCards.tsx +++ b/packages/web/src/app/[domain]/components/homepage/askSourcebotDemoCards.tsx @@ -6,7 +6,7 @@ import { Search, LibraryBigIcon, Code, Info } from "lucide-react"; import { Badge } from "@/components/ui/badge"; import { Card } from "@/components/ui/card"; import { CardContent } from "@/components/ui/card"; -import { DemoExamples, DemoSearchExample, DemoSearchContext } from "@/types"; +import { DemoExamples, DemoSearchExample, DemoSearchScope } from "@/types"; import { cn, getCodeHostIcon } from "@/lib/utils"; import useCaptureEvent from "@/hooks/useCaptureEvent"; import { SearchScopeInfoCard } from "@/components/searchScopeInfoCard"; @@ -19,7 +19,7 @@ export const AskSourcebotDemoCards = ({ demoExamples, }: AskSourcebotDemoCardsProps) => { const captureEvent = useCaptureEvent(); - const [selectedFilterContext, setSelectedFilterContext] = useState(null); + const [selectedFilterSearchScope, setSelectedFilterSearchScope] = useState(null); const handleExampleClick = (example: DemoSearchExample) => { captureEvent('wa_demo_search_example_card_pressed', { @@ -32,16 +32,16 @@ export const AskSourcebotDemoCards = ({ } } - const getContextIcon = (context: DemoSearchContext, size: number = 20, isSelected: boolean = false) => { + const getSearchScopeIcon = (searchScope: DemoSearchScope, size: number = 20, isSelected: boolean = false) => { const sizeClass = size === 12 ? "h-3 w-3" : "h-5 w-5"; const colorClass = isSelected ? "text-primary-foreground" : "text-muted-foreground"; - if (context.type === "set") { + if (searchScope.type === "reposet") { return ; } - if (context.codeHostType) { - const codeHostIcon = getCodeHostIcon(context.codeHostType); + if (searchScope.codeHostType) { + const codeHostIcon = getCodeHostIcon(searchScope.codeHostType); if (codeHostIcon) { // When selected, icons need to match the inverted badge colors // In light mode selected: light icon on dark bg (invert) @@ -53,7 +53,7 @@ export const AskSourcebotDemoCards = ({ return ( {`${context.codeHostType} - {/* Search Context Filter */} + {/* Search Scope Filter */}
@@ -102,30 +102,30 @@ export const AskSourcebotDemoCards = ({
- Search Context: + Search Scope:
{ - setSelectedFilterContext(null); + setSelectedFilterSearchScope(null); }} > All - {demoExamples.searchContexts.map((context) => ( + {demoExamples.searchScopes.map((searchScope) => ( { - setSelectedFilterContext(context.id); + setSelectedFilterSearchScope(searchScope.id); }} > - {getContextIcon(context, 12, selectedFilterContext === context.id)} - {context.displayName} + {getSearchScopeIcon(searchScope, 12, selectedFilterSearchScope === searchScope.id)} + {searchScope.displayName} ))} @@ -133,11 +133,11 @@ export const AskSourcebotDemoCards = ({
{demoExamples.searchExamples .filter((example) => { - if (selectedFilterContext === null) return true; - return example.searchContext.includes(selectedFilterContext); + if (selectedFilterSearchScope === null) return true; + return example.searchScopes.includes(selectedFilterSearchScope); }) .map((example) => { - const searchContexts = demoExamples.searchContexts.filter((context) => example.searchContext.includes(context.id)) + const searchScopes = demoExamples.searchScopes.filter((searchScope) => example.searchScopes.includes(searchScope.id)) return (
- {searchContexts.map((context) => ( - - {getContextIcon(context, 12)} - {context.displayName} + {searchScopes.map((searchScope) => ( + + {getSearchScopeIcon(searchScope, 12)} + {searchScope.displayName} ))}
diff --git a/packages/web/src/app/api/(server)/chat/route.ts b/packages/web/src/app/api/(server)/chat/route.ts index c52b9e18..ac040c06 100644 --- a/packages/web/src/app/api/(server)/chat/route.ts +++ b/packages/web/src/app/api/(server)/chat/route.ts @@ -64,12 +64,12 @@ export async function POST(req: Request) { return serviceErrorResponse(schemaValidationError(parsed.error)); } - const { messages, id, selectedRepos, selectedContexts, languageModelId } = parsed.data; + const { messages, id, selectedRepos, selectedReposets, languageModelId } = parsed.data; const response = await chatHandler({ messages, id, selectedRepos, - selectedContexts, + selectedReposets, languageModelId, }, domain); @@ -94,11 +94,11 @@ interface ChatHandlerProps { messages: SBChatMessage[]; id: string; selectedRepos: string[]; - selectedContexts?: string[]; + selectedReposets?: string[]; languageModelId: string; } -const chatHandler = ({ messages, id, selectedRepos, selectedContexts, languageModelId }: ChatHandlerProps, domain: string) => sew(async () => +const chatHandler = ({ messages, id, selectedRepos, selectedReposets, languageModelId }: ChatHandlerProps, domain: string) => sew(async () => withAuth((userId) => withOrgMembership(userId, domain, async ({ org }) => { const chat = await prisma.chat.findUnique({ @@ -190,23 +190,23 @@ const chatHandler = ({ messages, id, selectedRepos, selectedContexts, languageMo // Expand search contexts to repos let expandedRepos = [...selectedRepos]; - if (selectedContexts && selectedContexts.length > 0) { - const searchContexts = await prisma.searchContext.findMany({ + if (selectedReposets && selectedReposets.length > 0) { + const searchReposets = await prisma.searchContext.findMany({ where: { orgId: org.id, - name: { in: selectedContexts } + name: { in: selectedReposets } }, include: { repos: true } }); - const contextRepos = searchContexts.flatMap(context => - context.repos.map(repo => repo.name) + const reposetRepos = searchReposets.flatMap(reposet => + reposet.repos.map(repo => repo.name) ); // Combine and deduplicate repos - expandedRepos = Array.from(new Set([...selectedRepos, ...contextRepos])); + expandedRepos = Array.from(new Set([...selectedRepos, ...reposetRepos])); } const researchStream = await createAgentStream({ diff --git a/packages/web/src/components/atMentionInfoCard.tsx b/packages/web/src/components/atMentionInfoCard.tsx new file mode 100644 index 00000000..74424074 --- /dev/null +++ b/packages/web/src/components/atMentionInfoCard.tsx @@ -0,0 +1,15 @@ +import { AtSignIcon } from "lucide-react"; + +export const AtMentionInfoCard = () => { + return ( +
+
+ +

Mention

+
+
+ When asking Sourcebot a question, you can @ mention files to include them in the context of the search. +
+
+ ); +}; \ No newline at end of file diff --git a/packages/web/src/components/searchScopeInfoCard.tsx b/packages/web/src/components/searchScopeInfoCard.tsx index 84083548..633dcbbb 100644 --- a/packages/web/src/components/searchScopeInfoCard.tsx +++ b/packages/web/src/components/searchScopeInfoCard.tsx @@ -1,17 +1,17 @@ import Image from "next/image"; -import { LibraryBigIcon, Code, Layers } from "lucide-react"; +import { LibraryBigIcon, Code, ScanSearchIcon } from "lucide-react"; import { cn, getCodeHostIcon } from "@/lib/utils"; export const SearchScopeInfoCard = () => { return (
- -

Search Context

+ +

Search Scope

- When asking Sourcebot a question, you can select one or more search contexts to constrain its scope. There - are two different types of search contexts: + When asking Sourcebot a question, you can select one or more scopes to constrain the search. + There are two different types of search scopes:
{(() => { @@ -32,7 +32,7 @@ export const SearchScopeInfoCard = () => {
- Set: A set of repositories, indicated by the library icon. + Reposet: A set of repositories, indicated by the library icon.
diff --git a/packages/web/src/features/chat/components/chatBox/chatBox.tsx b/packages/web/src/features/chat/components/chatBox/chatBox.tsx index c33cbdf1..170aa62f 100644 --- a/packages/web/src/features/chat/components/chatBox/chatBox.tsx +++ b/packages/web/src/features/chat/components/chatBox/chatBox.tsx @@ -18,7 +18,7 @@ import { Suggestion } from "./types"; import { useSuggestionModeAndQuery } from "./useSuggestionModeAndQuery"; import { useSuggestionsData } from "./useSuggestionsData"; import { useToast } from "@/components/hooks/use-toast"; -import { ContextItem } from "./contextSelector"; +import { SearchScopeItem } from "./searchScopeSelector"; import { SearchContextQuery } from "@/lib/types"; interface ChatBoxProps { @@ -29,7 +29,7 @@ interface ChatBoxProps { isRedirecting?: boolean; isGenerating?: boolean; languageModels: LanguageModelInfo[]; - selectedItems: ContextItem[]; + selectedItems: SearchScopeItem[]; searchContexts: SearchContextQuery[]; onContextSelectorOpenChanged: (isOpen: boolean) => void; } @@ -58,10 +58,10 @@ export const ChatBox = ({ return [item.value]; } - if (item.type === 'context') { - const context = searchContexts.find((context) => context.name === item.value); - if (context) { - return context.repoNames; + if (item.type === 'reposet') { + const reposet = searchContexts.find((reposet) => reposet.name === item.value); + if (reposet) { + return reposet.repoNames; } } @@ -162,7 +162,7 @@ export const ChatBox = ({ if (isSubmitDisabled) { if (isSubmitDisabledReason === "no-repos-selected") { toast({ - description: "⚠️ You must select at least one search context", + description: "⚠️ You must select at least one search scope", variant: "destructive", }); onContextSelectorOpenChanged(true); @@ -284,7 +284,7 @@ export const ChatBox = ({ >
- You must select at least one search context + You must select at least one search scope
)} diff --git a/packages/web/src/features/chat/components/chatBox/chatBoxToolbar.tsx b/packages/web/src/features/chat/components/chatBox/chatBoxToolbar.tsx index e32daaa5..beb034e6 100644 --- a/packages/web/src/features/chat/components/chatBox/chatBoxToolbar.tsx +++ b/packages/web/src/features/chat/components/chatBox/chatBoxToolbar.tsx @@ -1,6 +1,5 @@ 'use client'; -import { KeyboardShortcutHint } from "@/app/components/keyboardShortcutHint"; import { Button } from "@/components/ui/button"; import { Separator } from "@/components/ui/separator"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; @@ -8,19 +7,19 @@ import { LanguageModelInfo } from "@/features/chat/types"; import { RepositoryQuery, SearchContextQuery } from "@/lib/types"; import { AtSignIcon } from "lucide-react"; import { useCallback } from "react"; -import { useHotkeys } from "react-hotkeys-hook"; import { ReactEditor, useSlate } from "slate-react"; import { useSelectedLanguageModel } from "../../useSelectedLanguageModel"; import { LanguageModelSelector } from "./languageModelSelector"; -import { ContextSelector, type ContextItem } from "./contextSelector"; +import { SearchScopeSelector, type SearchScopeItem } from "./searchScopeSelector"; import { SearchScopeInfoCard } from "@/components/searchScopeInfoCard"; +import { AtMentionInfoCard } from "@/components/atMentionInfoCard"; export interface ChatBoxToolbarProps { languageModels: LanguageModelInfo[]; repos: RepositoryQuery[]; searchContexts: SearchContextQuery[]; - selectedItems: ContextItem[]; - onSelectedItemsChange: (items: ContextItem[]) => void; + selectedItems: SearchScopeItem[]; + onSelectedItemsChange: (items: SearchScopeItem[]) => void; isContextSelectorOpen: boolean; onContextSelectorOpenChanged: (isOpen: boolean) => void; } @@ -41,15 +40,6 @@ export const ChatBoxToolbar = ({ ReactEditor.focus(editor); }, [editor]); - useHotkeys("alt+mod+p", (e) => { - e.preventDefault(); - onAddContext(); - }, { - enableOnFormTags: true, - enableOnContentEditable: true, - description: "Add context", - }); - const { selectedLanguageModel, setSelectedLanguageModel } = useSelectedLanguageModel({ initialLanguageModel: languageModels.length > 0 ? languageModels[0] : undefined, }); @@ -67,19 +57,14 @@ export const ChatBoxToolbar = ({ - - - - Add context + + - { +interface SearchScopeSelectorProps extends React.ButtonHTMLAttributes { repos: RepositoryQuery[]; searchContexts: SearchContextQuery[]; - selectedItems: ContextItem[]; - onSelectedItemsChange: (items: ContextItem[]) => void; + selectedItems: SearchScopeItem[]; + onSelectedItemsChange: (items: SearchScopeItem[]) => void; className?: string; isOpen: boolean; onOpenChanged: (isOpen: boolean) => void; } -export const ContextSelector = React.forwardRef< +export const SearchScopeSelector = React.forwardRef< HTMLButtonElement, - ContextSelectorProps + SearchScopeSelectorProps >( ( { @@ -87,7 +87,7 @@ export const ContextSelector = React.forwardRef< } }; - const toggleItem = (item: ContextItem) => { + const toggleItem = (item: SearchScopeItem) => { // Store current scroll position before state update if (scrollContainerRef.current) { scrollPosition.current = scrollContainerRef.current.scrollTop; @@ -99,13 +99,13 @@ export const ContextSelector = React.forwardRef< const isDemoMode = process.env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT === "demo"; - let newSelectedItems: ContextItem[]; + let newSelectedItems: SearchScopeItem[]; if (isSelected) { newSelectedItems = selectedItems.filter( (selected) => !(selected.type === item.type && selected.value === item.value) ); } else { - // Limit selected context to 1 in demo mode + // Limit selected search scope to 1 in demo mode if (isDemoMode) { newSelectedItems = [item]; } else { @@ -124,26 +124,26 @@ export const ContextSelector = React.forwardRef< onOpenChanged(!isOpen); }; - const allItems = React.useMemo(() => { - const contextItems: ContextItem[] = searchContexts.map(context => ({ - type: 'context' as const, + const allSearchScopeItems = React.useMemo(() => { + const repoSetSearchScopeItems: RepoSetSearchScopeItem[] = searchContexts.map(context => ({ + type: 'reposet' as const, value: context.name, name: context.name, repoCount: context.repoNames.length })); - const repoItems: ContextItem[] = repos.map(repo => ({ + const repoSearchScopeItems: RepoSearchScopeItem[] = repos.map(repo => ({ type: 'repo' as const, value: repo.repoName, name: repo.repoDisplayName || repo.repoName.split('/').pop() || repo.repoName, codeHostType: repo.codeHostType, })); - return [...contextItems, ...repoItems]; + return [...repoSetSearchScopeItems, ...repoSearchScopeItems]; }, [repos, searchContexts]); - const sortedItems = React.useMemo(() => { - return allItems + const sortedSearchScopeItems = React.useMemo(() => { + return allSearchScopeItems .map((item) => ({ item, isSelected: selectedItems.some( @@ -154,19 +154,19 @@ export const ContextSelector = React.forwardRef< // Selected items first if (a.isSelected && !b.isSelected) return -1; if (!a.isSelected && b.isSelected) return 1; - // Then contexts before repos - if (a.item.type === 'context' && b.item.type === 'repo') return -1; - if (a.item.type === 'repo' && b.item.type === 'context') return 1; + // Then reposets before repos + if (a.item.type === 'reposet' && b.item.type === 'repo') return -1; + if (a.item.type === 'repo' && b.item.type === 'reposet') return 1; return 0; }) - }, [allItems, selectedItems]); + }, [allSearchScopeItems, selectedItems]); // Restore scroll position after re-render React.useEffect(() => { if (scrollContainerRef.current && scrollPosition.current > 0) { scrollContainerRef.current.scrollTop = scrollPosition.current; } - }, [sortedItems]); + }, [sortedSearchScopeItems]); return (
- + { - selectedItems.length === 0 ? `Select context` : + selectedItems.length === 0 ? `Search scopes` : selectedItems.length === 1 ? selectedItems[0].name : `${selectedItems.length} selected` } @@ -205,13 +205,13 @@ export const ContextSelector = React.forwardRef< > No results found. - {sortedItems.map(({ item, isSelected }) => { + {sortedSearchScopeItems.map(({ item, isSelected }) => { return (
- {item.type === 'context' ? ( + {item.type === 'reposet' ? ( ) : ( // Render code host icon for repos @@ -253,7 +253,7 @@ export const ContextSelector = React.forwardRef< {item.name} - {item.type === 'context' && ( + {item.type === 'reposet' && ( void; + selectedItems: SearchScopeItem[]; + onSelectedItemsChange: (items: SearchScopeItem[]) => void; isChatReadonly: boolean; } @@ -62,10 +62,10 @@ export const ChatThread = ({ const router = useRouter(); const [isContextSelectorOpen, setIsContextSelectorOpen] = useState(false); - const { selectedRepos, selectedContexts } = useMemo(() => { + const { selectedRepos, selectedReposets } = useMemo(() => { const repos = selectedItems.filter(item => item.type === 'repo').map(item => item.value); - const contexts = selectedItems.filter(item => item.type === 'context').map(item => item.value); - return { selectedRepos: repos, selectedContexts: contexts }; + const reposets = selectedItems.filter(item => item.type === 'reposet').map(item => item.value); + return { selectedRepos: repos, selectedReposets: reposets }; }, [selectedItems]); // Initial state is from attachments that exist in in the chat history. @@ -123,11 +123,11 @@ export const ChatThread = ({ _sendMessage(message, { body: { selectedRepos, - selectedContexts, + selectedReposets, languageModelId: selectedLanguageModel.model, } satisfies AdditionalChatRequestParams, - }); - }, [_sendMessage, selectedLanguageModel, toast, selectedRepos, selectedContexts]); + }); + }, [_sendMessage, selectedLanguageModel, toast, selectedRepos, selectedReposets]); const messagePairs = useMessagePairs(messages); @@ -243,13 +243,13 @@ export const ChatThread = ({ const text = slateContentToString(children); const mentions = getAllMentionElements(children); - const message = createUIMessage(text, mentions.map(({ data }) => data), selectedRepos, selectedContexts); + const message = createUIMessage(text, mentions.map(({ data }) => data), selectedRepos, selectedReposets); sendMessage(message); setIsAutoScrollEnabled(true); resetEditor(editor); - }, [sendMessage, selectedRepos, selectedContexts]); + }, [sendMessage, selectedRepos, selectedReposets]); return ( <> diff --git a/packages/web/src/features/chat/types.ts b/packages/web/src/features/chat/types.ts index b4c6bc8d..24d70907 100644 --- a/packages/web/src/features/chat/types.ts +++ b/packages/web/src/features/chat/types.ts @@ -51,7 +51,7 @@ export const sbChatMessageMetadataSchema = z.object({ userId: z.string(), })).optional(), selectedRepos: z.array(z.string()).optional(), - selectedContexts: z.array(z.string()).optional(), + selectedReposets: z.array(z.string()).optional(), traceId: z.string().optional(), }); @@ -140,7 +140,7 @@ export const SET_CHAT_STATE_QUERY_PARAM = 'setChatState'; export type SetChatStatePayload = { inputMessage: CreateUIMessage; selectedRepos: string[]; - selectedContexts: string[]; + selectedReposets: string[]; } @@ -158,6 +158,6 @@ export type LanguageModelInfo = { export const additionalChatRequestParamsSchema = z.object({ languageModelId: z.string(), selectedRepos: z.array(z.string()), - selectedContexts: z.array(z.string()), + selectedReposets: z.array(z.string()), }); export type AdditionalChatRequestParams = z.infer; \ No newline at end of file diff --git a/packages/web/src/features/chat/useCreateNewChatThread.ts b/packages/web/src/features/chat/useCreateNewChatThread.ts index 54aaf14d..3c108446 100644 --- a/packages/web/src/features/chat/useCreateNewChatThread.ts +++ b/packages/web/src/features/chat/useCreateNewChatThread.ts @@ -11,7 +11,7 @@ import { createChat } from "./actions"; import { isServiceError } from "@/lib/utils"; import { createPathWithQueryParams } from "@/lib/utils"; import { SET_CHAT_STATE_QUERY_PARAM, SetChatStatePayload } from "./types"; -import { ContextItem } from "./components/chatBox/contextSelector"; +import { SearchScopeItem } from "./components/chatBox/searchScopeSelector"; export const useCreateNewChatThread = () => { const domain = useDomain(); @@ -19,15 +19,15 @@ export const useCreateNewChatThread = () => { const { toast } = useToast(); const router = useRouter(); - const createNewChatThread = useCallback(async (children: Descendant[], selectedItems: ContextItem[]) => { + const createNewChatThread = useCallback(async (children: Descendant[], selectedItems: SearchScopeItem[]) => { const text = slateContentToString(children); const mentions = getAllMentionElements(children); - // Extract repos and contexts from selectedItems + // Extract repos and reposets from selectedItems const selectedRepos = selectedItems.filter(item => item.type === 'repo').map(item => item.value); - const selectedContexts = selectedItems.filter(item => item.type === 'context').map(item => item.value); + const selectedReposets = selectedItems.filter(item => item.type === 'reposet').map(item => item.value); - const inputMessage = createUIMessage(text, mentions.map((mention) => mention.data), selectedRepos, selectedContexts); + const inputMessage = createUIMessage(text, mentions.map((mention) => mention.data), selectedRepos, selectedReposets); setIsLoading(true); const response = await createChat(domain); @@ -43,7 +43,7 @@ export const useCreateNewChatThread = () => { [SET_CHAT_STATE_QUERY_PARAM, JSON.stringify({ inputMessage, selectedRepos, - selectedContexts, + selectedReposets, } satisfies SetChatStatePayload)], ); diff --git a/packages/web/src/features/chat/utils.ts b/packages/web/src/features/chat/utils.ts index e2495664..36330ad3 100644 --- a/packages/web/src/features/chat/utils.ts +++ b/packages/web/src/features/chat/utils.ts @@ -172,7 +172,7 @@ export const addLineNumbers = (source: string, lineOffset = 1) => { return source.split('\n').map((line, index) => `${index + lineOffset}:${line}`).join('\n'); } -export const createUIMessage = (text: string, mentions: MentionData[], selectedRepos: string[], selectedContexts: string[]): CreateUIMessage => { +export const createUIMessage = (text: string, mentions: MentionData[], selectedRepos: string[], selectedReposets: string[]): CreateUIMessage => { // Converts applicable mentions into sources. const sources: Source[] = mentions .map((mention) => { @@ -206,7 +206,7 @@ export const createUIMessage = (text: string, mentions: MentionData[], selectedR ], metadata: { selectedRepos, - selectedContexts, + selectedReposets, }, } } diff --git a/packages/web/src/types.ts b/packages/web/src/types.ts index 5b55b9db..2ceb5d30 100644 --- a/packages/web/src/types.ts +++ b/packages/web/src/types.ts @@ -4,11 +4,11 @@ export const orgMetadataSchema = z.object({ anonymousAccessEnabled: z.boolean().optional(), }) -export const demoSearchContextSchema = z.object({ +export const demoSearchScopeSchema = z.object({ id: z.number(), displayName: z.string(), value: z.string(), - type: z.enum(["repo", "set"]), + type: z.enum(["repo", "reposet"]), codeHostType: z.string().optional(), }) @@ -16,22 +16,15 @@ export const demoSearchExampleSchema = z.object({ title: z.string(), description: z.string(), url: z.string(), - searchContext: z.array(z.number()) -}) - -export const demoSearchContextExampleSchema = z.object({ - searchContext: z.number(), - description: z.string(), + searchScopes: z.array(z.number()) }) export const demoExamplesSchema = z.object({ - searchContexts: demoSearchContextSchema.array(), + searchScopes: demoSearchScopeSchema.array(), searchExamples: demoSearchExampleSchema.array(), - searchContextExamples: demoSearchContextExampleSchema.array(), }) export type OrgMetadata = z.infer; export type DemoExamples = z.infer; -export type DemoSearchContext = z.infer; -export type DemoSearchExample = z.infer; -export type DemoSearchContextExample = z.infer; \ No newline at end of file +export type DemoSearchScope = z.infer; +export type DemoSearchExample = z.infer; \ No newline at end of file