Skip to content

Commit 3b2dd51

Browse files
committed
rename everything to use search scope
1 parent f9e0500 commit 3b2dd51

File tree

14 files changed

+200
-225
lines changed

14 files changed

+200
-225
lines changed

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

Lines changed: 9 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22

33
import { ResizablePanel } from '@/components/ui/resizable';
44
import { ChatThread } from '@/features/chat/components/chatThread';
5-
import { LanguageModelInfo, SBChatMessage, SET_CHAT_STATE_QUERY_PARAM, SetChatStatePayload } from '@/features/chat/types';
5+
import { LanguageModelInfo, SBChatMessage, SearchScope, SET_CHAT_STATE_QUERY_PARAM, SetChatStatePayload } from '@/features/chat/types';
66
import { RepositoryQuery, SearchContextQuery } from '@/lib/types';
77
import { CreateUIMessage } from 'ai';
88
import { useRouter, useSearchParams } from 'next/navigation';
99
import { useEffect, useState } from 'react';
1010
import { useChatId } from '../../useChatId';
11-
import { SearchScopeItem } from '@/features/chat/components/chatBox/searchScopeSelector';
1211

1312
interface ChatThreadPanelProps {
1413
languageModels: LanguageModelInfo[];
@@ -33,62 +32,22 @@ export const ChatThreadPanel = ({
3332
const router = useRouter();
3433
const searchParams = useSearchParams();
3534
const [inputMessage, setInputMessage] = useState<CreateUIMessage<SBChatMessage> | undefined>(undefined);
36-
35+
3736
// Use the last user's last message to determine what repos and contexts we should select by default.
3837
const lastUserMessage = messages.findLast((message) => message.role === "user");
39-
const defaultSelectedRepos = lastUserMessage?.metadata?.selectedRepos ?? [];
40-
const defaultSelectedReposets = lastUserMessage?.metadata?.selectedReposets ?? [];
38+
const defaultSelectedSearchScopes = lastUserMessage?.metadata?.selectedSearchScopes ?? [];
39+
const [selectedSearchScopes, setSelectedSearchScopes] = useState<SearchScope[]>(defaultSelectedSearchScopes);
4140

42-
const [selectedItems, setSelectedItems] = useState<SearchScopeItem[]>([
43-
...defaultSelectedRepos.map(repoName => {
44-
const repoInfo = repos.find(r => r.repoName === repoName);
45-
return {
46-
type: 'repo' as const,
47-
value: repoName,
48-
name: repoInfo?.repoDisplayName || repoName.split('/').pop() || repoName,
49-
codeHostType: repoInfo?.codeHostType || ''
50-
};
51-
}),
52-
...defaultSelectedReposets.map(reposetName => {
53-
const reposet = searchContexts.find(c => c.name === reposetName);
54-
return {
55-
type: 'reposet' as const,
56-
value: reposetName,
57-
name: reposetName,
58-
repoCount: reposet?.repoNames.length || 0
59-
};
60-
})
61-
]);
62-
6341
useEffect(() => {
6442
const setChatState = searchParams.get(SET_CHAT_STATE_QUERY_PARAM);
6543
if (!setChatState) {
6644
return;
6745
}
6846

6947
try {
70-
const { inputMessage, selectedRepos, selectedReposets } = JSON.parse(setChatState) as SetChatStatePayload;
48+
const { inputMessage, selectedSearchScopes } = JSON.parse(setChatState) as SetChatStatePayload;
7149
setInputMessage(inputMessage);
72-
setSelectedItems([
73-
...selectedRepos.map(repoName => {
74-
const repoInfo = repos.find(r => r.repoName === repoName);
75-
return {
76-
type: 'repo' as const,
77-
value: repoName,
78-
name: repoInfo?.repoDisplayName || repoName.split('/').pop() || repoName,
79-
codeHostType: repoInfo?.codeHostType || ''
80-
};
81-
}),
82-
...selectedReposets.map(reposetName => {
83-
const reposet = searchContexts.find(c => c.name === reposetName);
84-
return {
85-
type: 'reposet' as const,
86-
value: reposetName,
87-
name: reposetName,
88-
repoCount: reposet?.repoNames.length || 0
89-
};
90-
})
91-
]);
50+
setSelectedSearchScopes(selectedSearchScopes);
9251
} catch {
9352
console.error('Invalid message in URL');
9453
}
@@ -97,7 +56,7 @@ export const ChatThreadPanel = ({
9756
const newSearchParams = new URLSearchParams(searchParams.toString());
9857
newSearchParams.delete(SET_CHAT_STATE_QUERY_PARAM);
9958
router.replace(`?${newSearchParams.toString()}`, { scroll: false });
100-
}, [searchParams, router, repos, searchContexts]);
59+
}, [searchParams, router]);
10160

10261
return (
10362
<ResizablePanel
@@ -113,8 +72,8 @@ export const ChatThreadPanel = ({
11372
languageModels={languageModels}
11473
repos={repos}
11574
searchContexts={searchContexts}
116-
selectedItems={selectedItems}
117-
onSelectedItemsChange={setSelectedItems}
75+
selectedSearchScopes={selectedSearchScopes}
76+
onSelectedSearchScopesChange={setSelectedSearchScopes}
11877
isChatReadonly={isChatReadonly}
11978
/>
12079
</div>

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

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@ import { ChatBox } from "@/features/chat/components/chatBox";
55
import { ChatBoxToolbar } from "@/features/chat/components/chatBox/chatBoxToolbar";
66
import { CustomSlateEditor } from "@/features/chat/customSlateEditor";
77
import { useCreateNewChatThread } from "@/features/chat/useCreateNewChatThread";
8-
import { LanguageModelInfo } from "@/features/chat/types";
8+
import { LanguageModelInfo, SearchScope } from "@/features/chat/types";
99
import { RepositoryQuery, SearchContextQuery } from "@/lib/types";
1010
import { useCallback, useState } from "react";
1111
import { Descendant } from "slate";
1212
import { useLocalStorage } from "usehooks-ts";
13-
import { SearchScopeItem } from "@/features/chat/components/chatBox/searchScopeSelector";
1413

1514
interface NewChatPanelProps {
1615
languageModels: LanguageModelInfo[];
@@ -25,13 +24,13 @@ export const NewChatPanel = ({
2524
searchContexts,
2625
order,
2726
}: NewChatPanelProps) => {
28-
const [selectedItems, setSelectedItems] = useLocalStorage<SearchScopeItem[]>("selectedContextItems", [], { initializeWithValue: false });
27+
const [selectedSearchScopes, setSelectedSearchScopes] = useLocalStorage<SearchScope[]>("selectedSearchScopes", [], { initializeWithValue: false });
2928
const { createNewChatThread, isLoading } = useCreateNewChatThread();
3029
const [isContextSelectorOpen, setIsContextSelectorOpen] = useState(false);
3130

3231
const onSubmit = useCallback((children: Descendant[]) => {
33-
createNewChatThread(children, selectedItems);
34-
}, [createNewChatThread, selectedItems]);
32+
createNewChatThread(children, selectedSearchScopes);
33+
}, [createNewChatThread, selectedSearchScopes]);
3534

3635

3736
return (
@@ -50,7 +49,7 @@ export const NewChatPanel = ({
5049
preferredSuggestionsBoxPlacement="bottom-start"
5150
isRedirecting={isLoading}
5251
languageModels={languageModels}
53-
selectedItems={selectedItems}
52+
selectedSearchScopes={selectedSearchScopes}
5453
searchContexts={searchContexts}
5554
onContextSelectorOpenChanged={setIsContextSelectorOpen}
5655
/>
@@ -59,8 +58,8 @@ export const NewChatPanel = ({
5958
languageModels={languageModels}
6059
repos={repos}
6160
searchContexts={searchContexts}
62-
selectedItems={selectedItems}
63-
onSelectedItemsChange={setSelectedItems}
61+
selectedSearchScopes={selectedSearchScopes}
62+
onSelectedSearchScopesChange={setSelectedSearchScopes}
6463
isContextSelectorOpen={isContextSelectorOpen}
6564
onContextSelectorOpenChanged={setIsContextSelectorOpen}
6665
/>

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

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@
33
import { Separator } from "@/components/ui/separator";
44
import { ChatBox } from "@/features/chat/components/chatBox";
55
import { ChatBoxToolbar } from "@/features/chat/components/chatBox/chatBoxToolbar";
6-
import { LanguageModelInfo } from "@/features/chat/types";
6+
import { LanguageModelInfo, SearchScope } from "@/features/chat/types";
77
import { useCreateNewChatThread } from "@/features/chat/useCreateNewChatThread";
88
import { RepositoryQuery, SearchContextQuery } from "@/lib/types";
99
import { useState } from "react";
1010
import { SearchModeSelector, SearchModeSelectorProps } from "./toolbar";
1111
import { useLocalStorage } from "usehooks-ts";
12-
import { SearchScopeItem } from "@/features/chat/components/chatBox/searchScopeSelector";
1312
import { DemoExamples } from "@/types";
1413
import { AskSourcebotDemoCards } from "./askSourcebotDemoCards";
1514

@@ -34,20 +33,20 @@ export const AgenticSearch = ({
3433
demoExamples,
3534
}: AgenticSearchProps) => {
3635
const { createNewChatThread, isLoading } = useCreateNewChatThread();
37-
const [selectedItems, setSelectedItems] = useLocalStorage<SearchScopeItem[]>("selectedContextItems", [], { initializeWithValue: false });
36+
const [selectedSearchScopes, setSelectedSearchScopes] = useLocalStorage<SearchScope[]>("selectedSearchScopes", [], { initializeWithValue: false });
3837
const [isContextSelectorOpen, setIsContextSelectorOpen] = useState(false);
3938

4039
return (
4140
<div className="flex flex-col items-center w-full">
4241
<div className="mt-4 w-full border rounded-md shadow-sm max-w-[800px]">
4342
<ChatBox
4443
onSubmit={(children) => {
45-
createNewChatThread(children, selectedItems);
44+
createNewChatThread(children, selectedSearchScopes);
4645
}}
4746
className="min-h-[50px]"
4847
isRedirecting={isLoading}
4948
languageModels={languageModels}
50-
selectedItems={selectedItems}
49+
selectedSearchScopes={selectedSearchScopes}
5150
searchContexts={searchContexts}
5251
onContextSelectorOpenChanged={setIsContextSelectorOpen}
5352
/>
@@ -58,8 +57,8 @@ export const AgenticSearch = ({
5857
languageModels={languageModels}
5958
repos={repos}
6059
searchContexts={searchContexts}
61-
selectedItems={selectedItems}
62-
onSelectedItemsChange={setSelectedItems}
60+
selectedSearchScopes={selectedSearchScopes}
61+
onSelectedSearchScopesChange={setSelectedSearchScopes}
6362
isContextSelectorOpen={isContextSelectorOpen}
6463
onContextSelectorOpenChanged={setIsContextSelectorOpen}
6564
/>

packages/web/src/app/api/(server)/chat/route.ts

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { sew, withAuth, withOrgMembership } from "@/actions";
22
import { env } from "@/env.mjs";
33
import { _getConfiguredLanguageModelsFull, updateChatMessages, updateChatName } from "@/features/chat/actions";
44
import { createAgentStream } from "@/features/chat/agent";
5-
import { additionalChatRequestParamsSchema, SBChatMessage } from "@/features/chat/types";
5+
import { additionalChatRequestParamsSchema, SBChatMessage, SearchScope } from "@/features/chat/types";
66
import { getAnswerPartFromAssistantMessage } from "@/features/chat/utils";
77
import { ErrorCode } from "@/lib/errorCodes";
88
import { notFound, schemaValidationError, serviceErrorResponse } from "@/lib/serviceError";
@@ -64,12 +64,11 @@ export async function POST(req: Request) {
6464
return serviceErrorResponse(schemaValidationError(parsed.error));
6565
}
6666

67-
const { messages, id, selectedRepos, selectedReposets, languageModelId } = parsed.data;
67+
const { messages, id, selectedSearchScopes, languageModelId } = parsed.data;
6868
const response = await chatHandler({
6969
messages,
7070
id,
71-
selectedRepos,
72-
selectedReposets,
71+
selectedSearchScopes,
7372
languageModelId,
7473
}, domain);
7574

@@ -93,12 +92,11 @@ const mergeStreamAsync = async (stream: StreamTextResult<any, any>, writer: UIMe
9392
interface ChatHandlerProps {
9493
messages: SBChatMessage[];
9594
id: string;
96-
selectedRepos: string[];
97-
selectedReposets?: string[];
95+
selectedSearchScopes: SearchScope[];
9896
languageModelId: string;
9997
}
10098

101-
const chatHandler = ({ messages, id, selectedRepos, selectedReposets, languageModelId }: ChatHandlerProps, domain: string) => sew(async () =>
99+
const chatHandler = ({ messages, id, selectedSearchScopes, languageModelId }: ChatHandlerProps, domain: string) => sew(async () =>
102100
withAuth((userId) =>
103101
withOrgMembership(userId, domain, async ({ org }) => {
104102
const chat = await prisma.chat.findUnique({
@@ -188,34 +186,38 @@ const chatHandler = ({ messages, id, selectedRepos, selectedReposets, languageMo
188186

189187
const startTime = new Date();
190188

191-
// Expand search contexts to repos
192-
let expandedRepos = [...selectedRepos];
193-
if (selectedReposets && selectedReposets.length > 0) {
194-
const searchReposets = await prisma.searchContext.findMany({
195-
where: {
196-
orgId: org.id,
197-
name: { in: selectedReposets }
198-
},
199-
include: {
200-
repos: true
189+
const expandedReposArrays = await Promise.all(selectedSearchScopes.map(async (scope) => {
190+
if (scope.type === 'repo') {
191+
return [scope.value];
192+
}
193+
194+
if (scope.type === 'reposet') {
195+
const reposet = await prisma.searchContext.findFirst({
196+
where: {
197+
orgId: org.id,
198+
name: scope.value
199+
},
200+
include: {
201+
repos: true
202+
}
203+
});
204+
205+
if (reposet) {
206+
return reposet.repos.map(repo => repo.name);
201207
}
202-
});
203-
204-
const reposetRepos = searchReposets.flatMap(reposet =>
205-
reposet.repos.map(repo => repo.name)
206-
);
208+
}
207209

208-
// Combine and deduplicate repos
209-
expandedRepos = Array.from(new Set([...selectedRepos, ...reposetRepos]));
210-
}
210+
return [];
211+
}));
212+
const expandedRepos = expandedReposArrays.flat();
211213

212214
const researchStream = await createAgentStream({
213215
model,
214216
providerOptions,
215217
headers,
216218
inputMessages: messageHistory,
217219
inputSources: sources,
218-
selectedRepos: expandedRepos,
220+
searchScopeRepoNames: expandedRepos,
219221
onWriteSource: (source) => {
220222
writer.write({
221223
type: 'data-source',
@@ -241,6 +243,7 @@ const chatHandler = ({ messages, id, selectedRepos, selectedReposets, languageMo
241243
totalOutputTokens: totalUsage.outputTokens,
242244
totalResponseTimeMs: new Date().getTime() - startTime.getTime(),
243245
modelName: languageModelConfig.displayName ?? languageModelConfig.model,
246+
selectedSearchScopes,
244247
traceId,
245248
}
246249
})

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ interface AgentOptions {
1616
model: LanguageModel;
1717
providerOptions?: ProviderOptions;
1818
headers?: Record<string, string>;
19-
selectedRepos: string[];
19+
searchScopeRepoNames: string[];
2020
inputMessages: ModelMessage[];
2121
inputSources: Source[];
2222
onWriteSource: (source: Source) => void;
@@ -35,12 +35,12 @@ export const createAgentStream = async ({
3535
headers,
3636
inputMessages,
3737
inputSources,
38-
selectedRepos,
38+
searchScopeRepoNames,
3939
onWriteSource,
4040
traceId,
4141
}: AgentOptions) => {
4242
const baseSystemPrompt = createBaseSystemPrompt({
43-
selectedRepos,
43+
searchScopeRepoNames,
4444
});
4545

4646
const stream = streamText({
@@ -50,7 +50,7 @@ export const createAgentStream = async ({
5050
system: baseSystemPrompt,
5151
messages: inputMessages,
5252
tools: {
53-
[toolNames.searchCode]: createCodeSearchTool(selectedRepos),
53+
[toolNames.searchCode]: createCodeSearchTool(searchScopeRepoNames),
5454
[toolNames.readFiles]: readFilesTool,
5555
[toolNames.findSymbolReferences]: findSymbolReferencesTool,
5656
[toolNames.findSymbolDefinitions]: findSymbolDefinitionsTool,
@@ -150,11 +150,11 @@ export const createAgentStream = async ({
150150
}
151151

152152
interface BaseSystemPromptOptions {
153-
selectedRepos: string[];
153+
searchScopeRepoNames: string[];
154154
}
155155

156156
export const createBaseSystemPrompt = ({
157-
selectedRepos,
157+
searchScopeRepoNames,
158158
}: BaseSystemPromptOptions) => {
159159
return `
160160
You are a powerful agentic AI code assistant built into Sourcebot, the world's best code-intelligence platform. Your job is to help developers understand and navigate their large codebases.
@@ -176,7 +176,7 @@ Your workflow has two distinct phases:
176176
177177
<available_repositories>
178178
The user has selected the following repositories for analysis:
179-
${selectedRepos.map(repo => `- ${repo}`).join('\n')}
179+
${searchScopeRepoNames.map(repo => `- ${repo}`).join('\n')}
180180
</available_repositories>
181181
182182
<research_phase_instructions>

0 commit comments

Comments
 (0)