Skip to content

Commit 891737e

Browse files
wip
1 parent 97f2810 commit 891737e

File tree

27 files changed

+188
-64
lines changed

27 files changed

+188
-64
lines changed

packages/mcp/src/client.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export const search = async (request: SearchRequest) => {
3535
method: 'POST',
3636
headers: {
3737
'Content-Type': 'application/json',
38+
'X-Sourcebot-Client-Source': 'mcp',
3839
...(env.SOURCEBOT_API_KEY ? { 'X-Sourcebot-Api-Key': env.SOURCEBOT_API_KEY } : {})
3940
},
4041
body: JSON.stringify(request)
@@ -56,6 +57,7 @@ export const listRepos = async (queryParams: ListReposQueryParams = {}) => {
5657
method: 'GET',
5758
headers: {
5859
'Content-Type': 'application/json',
60+
'X-Sourcebot-Client-Source': 'mcp',
5961
...(env.SOURCEBOT_API_KEY ? { 'X-Sourcebot-Api-Key': env.SOURCEBOT_API_KEY } : {})
6062
},
6163
});
@@ -76,6 +78,7 @@ export const getFileSource = async (request: FileSourceRequest) => {
7678
const response = await fetch(url, {
7779
method: 'GET',
7880
headers: {
81+
'X-Sourcebot-Client-Source': 'mcp',
7982
...(env.SOURCEBOT_API_KEY ? { 'X-Sourcebot-Api-Key': env.SOURCEBOT_API_KEY } : {})
8083
},
8184
});
@@ -95,6 +98,7 @@ export const listCommits = async (queryParams: ListCommitsQueryParamsSchema) =>
9598
method: 'GET',
9699
headers: {
97100
'X-Org-Domain': '~',
101+
'X-Sourcebot-Client-Source': 'mcp',
98102
...(env.SOURCEBOT_API_KEY ? { 'X-Sourcebot-Api-Key': env.SOURCEBOT_API_KEY } : {})
99103
},
100104
});
@@ -103,3 +107,27 @@ export const listCommits = async (queryParams: ListCommitsQueryParamsSchema) =>
103107
const totalCount = parseInt(response.headers.get('X-Total-Count') ?? '0', 10);
104108
return { commits, totalCount };
105109
}
110+
<<<<<<< Updated upstream
111+
=======
112+
113+
/**
114+
* Asks a natural language question about the codebase using the Sourcebot AI agent.
115+
* This is a blocking call that runs the full agent loop and returns when complete.
116+
*
117+
* @param request - The question and optional repo filters
118+
* @returns The agent's answer, chat URL, sources, and metadata
119+
*/
120+
export const askCodebase = async (request: AskCodebaseRequest): Promise<AskCodebaseResponse> => {
121+
const response = await fetch(`${env.SOURCEBOT_HOST}/api/chat/blocking`, {
122+
method: 'POST',
123+
headers: {
124+
'Content-Type': 'application/json',
125+
'X-Sourcebot-Client-Source': 'mcp',
126+
...(env.SOURCEBOT_API_KEY ? { 'X-Sourcebot-Api-Key': env.SOURCEBOT_API_KEY } : {})
127+
},
128+
body: JSON.stringify(request),
129+
});
130+
131+
return parseResponse(response, askCodebaseResponseSchema);
132+
}
133+
>>>>>>> Stashed changes

packages/mcp/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ server.tool(
101101
contextLines: env.DEFAULT_CONTEXT_LINES,
102102
isRegexEnabled: useRegex,
103103
isCaseSensitivityEnabled: caseSensitive,
104-
source: 'mcp',
105104
});
106105

107106
if (response.files.length === 0) {

packages/mcp/src/schemas.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ export const searchOptionsSchema = z.object({
3131

3232
export const searchRequestSchema = z.object({
3333
query: z.string(), // The zoekt query to execute.
34-
source: z.string().optional(), // The source of the search request.
3534
...searchOptionsSchema.shape,
3635
});
3736

packages/web/src/app/[domain]/components/searchBar/useSuggestionsData.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ export const useSuggestionsData = ({
6161
query: `file:${suggestionQuery}`,
6262
matches: 15,
6363
contextLines: 1,
64-
source: 'search-bar-file-suggestions'
6564
}),
6665
select: (data): Suggestion[] => {
6766
if (isServiceError(data)) {
@@ -82,7 +81,6 @@ export const useSuggestionsData = ({
8281
query: `sym:${suggestionQuery.length > 0 ? suggestionQuery : ".*"}`,
8382
matches: 15,
8483
contextLines: 1,
85-
source: 'search-bar-symbol-suggestions'
8684
}),
8785
select: (data): Suggestion[] => {
8886
if (isServiceError(data)) {

packages/web/src/app/[domain]/search/useStreamedSearch.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ export const useStreamedSearch = ({ query, matches, contextLines, whole, isRegex
121121
method: 'POST',
122122
headers: {
123123
'Content-Type': 'application/json',
124+
'X-Sourcebot-Client-Source': 'sourcebot-web-client',
124125
},
125126
body: JSON.stringify({
126127
query,
@@ -129,7 +130,6 @@ export const useStreamedSearch = ({ query, matches, contextLines, whole, isRegex
129130
whole,
130131
isRegexEnabled,
131132
isCaseSensitivityEnabled,
132-
source: 'sourcebot-web-client'
133133
} satisfies SearchRequest),
134134
signal: abortControllerRef.current.signal,
135135
});

packages/web/src/app/api/(client)/client.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const search = async (body: SearchRequest): Promise<SearchResponse | Serv
2525
method: "POST",
2626
headers: {
2727
"Content-Type": "application/json",
28+
"X-Sourcebot-Client-Source": "sourcebot-web-client",
2829
},
2930
body: JSON.stringify(body),
3031
}).then(response => response.json());
@@ -44,6 +45,9 @@ export const getFileSource = async (queryParams: FileSourceRequest): Promise<Fil
4445

4546
const result = await fetch(url, {
4647
method: "GET",
48+
headers: {
49+
"X-Sourcebot-Client-Source": "sourcebot-web-client",
50+
}
4751
}).then(response => response.json());
4852

4953
return result as FileSourceResponse | ServiceError;
@@ -59,6 +63,7 @@ export const listRepos = async (queryParams: ListReposQueryParams): Promise<List
5963
method: "GET",
6064
headers: {
6165
"Content-Type": "application/json",
66+
"X-Sourcebot-Client-Source": "sourcebot-web-client",
6267
},
6368
}).then(response => response.json());
6469

@@ -70,6 +75,7 @@ export const getVersion = async (): Promise<GetVersionResponse> => {
7075
method: "GET",
7176
headers: {
7277
"Content-Type": "application/json",
78+
"X-Sourcebot-Client-Source": "sourcebot-web-client",
7379
},
7480
}).then(response => response.json());
7581
return result as GetVersionResponse;
@@ -78,6 +84,9 @@ export const getVersion = async (): Promise<GetVersionResponse> => {
7884
export const findSearchBasedSymbolReferences = async (body: FindRelatedSymbolsRequest): Promise<FindRelatedSymbolsResponse | ServiceError> => {
7985
const result = await fetch("/api/find_references", {
8086
method: "POST",
87+
headers: {
88+
"X-Sourcebot-Client-Source": "sourcebot-web-client",
89+
},
8190
body: JSON.stringify(body),
8291
}).then(response => response.json());
8392
return result as FindRelatedSymbolsResponse | ServiceError;
@@ -86,6 +95,9 @@ export const findSearchBasedSymbolReferences = async (body: FindRelatedSymbolsRe
8695
export const findSearchBasedSymbolDefinitions = async (body: FindRelatedSymbolsRequest): Promise<FindRelatedSymbolsResponse | ServiceError> => {
8796
const result = await fetch("/api/find_definitions", {
8897
method: "POST",
98+
headers: {
99+
"X-Sourcebot-Client-Source": "sourcebot-web-client",
100+
},
89101
body: JSON.stringify(body),
90102
}).then(response => response.json());
91103
return result as FindRelatedSymbolsResponse | ServiceError;
@@ -94,6 +106,9 @@ export const findSearchBasedSymbolDefinitions = async (body: FindRelatedSymbolsR
94106
export const getTree = async (body: GetTreeRequest): Promise<GetTreeResponse | ServiceError> => {
95107
const result = await fetch("/api/tree", {
96108
method: "POST",
109+
headers: {
110+
"X-Sourcebot-Client-Source": "sourcebot-web-client",
111+
},
97112
body: JSON.stringify(body),
98113
}).then(response => response.json());
99114
return result as GetTreeResponse | ServiceError;
@@ -102,6 +117,9 @@ export const getTree = async (body: GetTreeRequest): Promise<GetTreeResponse | S
102117
export const getFiles = async (body: GetFilesRequest): Promise<GetFilesResponse | ServiceError> => {
103118
const result = await fetch("/api/files", {
104119
method: "POST",
120+
headers: {
121+
"X-Sourcebot-Client-Source": "sourcebot-web-client",
122+
},
105123
body: JSON.stringify(body),
106124
}).then(response => response.json());
107125
return result as GetFilesResponse | ServiceError;

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { _getConfiguredLanguageModelsFull, _getAISDKLanguageModelAndOptions, upd
33
import { createAgentStream } from "@/features/chat/agent";
44
import { additionalChatRequestParamsSchema, LanguageModelInfo, SBChatMessage, SearchScope } from "@/features/chat/types";
55
import { getAnswerPartFromAssistantMessage, getLanguageModelKey } from "@/features/chat/utils";
6+
import { apiHandler } from "@/lib/apiHandler";
67
import { ErrorCode } from "@/lib/errorCodes";
78
import { notFound, requestBodySchemaValidationError, serviceErrorResponse } from "@/lib/serviceError";
89
import { isServiceError } from "@/lib/utils";
@@ -22,6 +23,7 @@ import {
2223
} from "ai";
2324
import { randomUUID } from "crypto";
2425
import { StatusCodes } from "http-status-codes";
26+
import { NextRequest } from "next/server";
2527
import { z } from "zod";
2628

2729
const logger = createLogger('chat-api');
@@ -33,7 +35,7 @@ const chatRequestSchema = z.object({
3335
...additionalChatRequestParamsSchema.shape,
3436
})
3537

36-
export async function POST(req: Request) {
38+
export const POST = apiHandler(async (req: NextRequest) => {
3739
const requestBody = await req.json();
3840
const parsed = await chatRequestSchema.safeParseAsync(requestBody);
3941
if (!parsed.success) {
@@ -102,7 +104,7 @@ export async function POST(req: Request) {
102104
}
103105

104106
return response;
105-
}
107+
});
106108

107109
// eslint-disable-next-line @typescript-eslint/no-explicit-any
108110
const mergeStreamAsync = async (stream: StreamTextResult<any, any>, writer: UIMessageStreamWriter<SBChatMessage>, options: UIMessageStreamOptions<SBChatMessage> = {}) => {

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { listCommits } from "@/features/git";
2+
import { apiHandler } from "@/lib/apiHandler";
23
import { buildLinkHeader } from "@/lib/pagination";
34
import { serviceErrorResponse, queryParamsSchemaValidationError } from "@/lib/serviceError";
45
import { isServiceError } from "@/lib/utils";
@@ -16,7 +17,7 @@ const listCommitsQueryParamsSchema = z.object({
1617
perPage: z.coerce.number().int().positive().max(100).default(50),
1718
});
1819

19-
export const GET = async (request: NextRequest): Promise<Response> => {
20+
export const GET = apiHandler(async (request: NextRequest): Promise<Response> => {
2021
const rawParams = Object.fromEntries(
2122
Object.keys(listCommitsQueryParamsSchema.shape).map(key => [
2223
key,
@@ -61,4 +62,4 @@ export const GET = async (request: NextRequest): Promise<Response> => {
6162
if (linkHeader) headers.set('Link', linkHeader);
6263

6364
return new Response(JSON.stringify(commits), { status: 200, headers });
64-
}
65+
});

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
'use server';
22

33
import { fetchAuditRecords } from "@/ee/features/audit/actions";
4+
import { apiHandler } from "@/lib/apiHandler";
45
import { ErrorCode } from "@/lib/errorCodes";
56
import { serviceErrorResponse } from "@/lib/serviceError";
67
import { isServiceError } from "@/lib/utils";
78
import { getEntitlements } from "@sourcebot/shared";
89
import { StatusCodes } from "http-status-codes";
910

10-
export const GET = async () => {
11+
export const GET = apiHandler(async () => {
1112
const entitlements = getEntitlements();
1213
if (!entitlements.includes('audit')) {
1314
return serviceErrorResponse({
@@ -22,4 +23,4 @@ export const GET = async () => {
2223
return serviceErrorResponse(result);
2324
}
2425
return Response.json(result);
25-
};
26+
});

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
'use server';
22

3+
import { getAuditService } from "@/ee/features/audit/factory";
4+
import { apiHandler } from "@/lib/apiHandler";
5+
import { ErrorCode } from "@/lib/errorCodes";
6+
import { serviceErrorResponse, missingQueryParam, notFound } from "@/lib/serviceError";
7+
import { isServiceError } from "@/lib/utils";
38
import { withAuthV2, withMinimumOrgRole } from "@/withAuthV2";
49
import { OrgRole } from "@sourcebot/db";
5-
import { isServiceError } from "@/lib/utils";
6-
import { serviceErrorResponse, missingQueryParam, notFound } from "@/lib/serviceError";
710
import { createLogger } from "@sourcebot/shared";
8-
import { NextRequest } from "next/server";
911
import { StatusCodes } from "http-status-codes";
10-
import { ErrorCode } from "@/lib/errorCodes";
11-
import { getAuditService } from "@/ee/features/audit/factory";
12+
import { NextRequest } from "next/server";
1213

1314
const logger = createLogger('ee-user-api');
1415
const auditService = getAuditService();
1516

16-
export const DELETE = async (request: NextRequest) => {
17+
export const DELETE = apiHandler(async (request: NextRequest) => {
1718
const url = new URL(request.url);
1819
const userId = url.searchParams.get('userId');
1920

@@ -89,5 +90,5 @@ export const DELETE = async (request: NextRequest) => {
8990
}
9091

9192
return Response.json(result, { status: StatusCodes.OK });
92-
};
93+
});
9394

0 commit comments

Comments
 (0)