diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ff1325cf..71195e18b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added +- Added optional `visibility` parameter to `/api/chat/blocking` endpoint and MCP `ask_codebase` tool to allow controlling chat session visibility in shared environments. [#903](https://github.com/sourcebot-dev/sourcebot/pull/903) + ## [4.11.1] - 2026-02-18 ### Changed diff --git a/packages/mcp/CHANGELOG.md b/packages/mcp/CHANGELOG.md index 698e6f847..1a5e07615 100644 --- a/packages/mcp/CHANGELOG.md +++ b/packages/mcp/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added +- Added optional `visibility` parameter to `ask_codebase` tool to allow controlling chat session visibility in shared environments. [#903](https://github.com/sourcebot-dev/sourcebot/pull/903) + ## [1.0.16] - 2026-02-10 ### Added diff --git a/packages/mcp/src/index.ts b/packages/mcp/src/index.ts index 198bc401e..a31cd2fbd 100644 --- a/packages/mcp/src/index.ts +++ b/packages/mcp/src/index.ts @@ -416,6 +416,8 @@ server.tool( Returns a detailed answer in markdown format with code references, plus a link to view the full research session (including all tool calls and reasoning) in the Sourcebot web UI. + When using this in shared environments (e.g., Slack), you can set the visibility parameter to 'PUBLIC' to ensure everyone can access the chat link. + This is a blocking operation that may take 30-60+ seconds for complex questions as the agent researches the codebase. `, askCodebaseRequestSchema.shape, diff --git a/packages/mcp/src/schemas.ts b/packages/mcp/src/schemas.ts index fe6e70087..4cbc7e574 100644 --- a/packages/mcp/src/schemas.ts +++ b/packages/mcp/src/schemas.ts @@ -381,6 +381,10 @@ export const askCodebaseRequestSchema = z.object({ .omit({ displayName: true }) .optional() .describe("The language model to use for answering the question. If not provided, defaults to the first model in the config. Use list_language_models to see available options."), + visibility: z + .enum(['PRIVATE', 'PUBLIC']) + .optional() + .describe("The visibility of the chat session. If not provided, defaults to PRIVATE for authenticated users and PUBLIC for anonymous users. Set to PUBLIC to make the chat viewable by anyone with the link."), }); export const sourceSchema = z.object({ diff --git a/packages/web/src/app/api/(server)/chat/blocking/route.ts b/packages/web/src/app/api/(server)/chat/blocking/route.ts index 66444a48f..66917dd06 100644 --- a/packages/web/src/app/api/(server)/chat/blocking/route.ts +++ b/packages/web/src/app/api/(server)/chat/blocking/route.ts @@ -33,6 +33,10 @@ const blockingChatRequestSchema = z.object({ languageModel: languageModelInfoSchema .optional() .describe("The language model to use for the chat. If not provided, the first configured model is used."), + visibility: z + .nativeEnum(ChatVisibility) + .optional() + .describe("The visibility of the chat session. If not provided, defaults to PRIVATE for authenticated users and PUBLIC for anonymous users. Set to PUBLIC to make the chat viewable by anyone with the link. Note: Anonymous users cannot create PRIVATE chats; any PRIVATE request from an unauthenticated user will be ignored and set to PUBLIC."), }); /** @@ -62,7 +66,7 @@ export const POST = apiHandler(async (request: NextRequest) => { return serviceErrorResponse(requestBodySchemaValidationError(parsed.error)); } - const { query, repos = [], languageModel: requestedLanguageModel } = parsed.data; + const { query, repos = [], languageModel: requestedLanguageModel, visibility: requestedVisibility } = parsed.data; const response: BlockingChatResponse | ServiceError = await sew(() => withOptionalAuthV2(async ({ org, user, prisma }) => { @@ -95,12 +99,18 @@ export const POST = apiHandler(async (request: NextRequest) => { const { model, providerOptions } = await _getAISDKLanguageModelAndOptions(languageModelConfig); const modelName = languageModelConfig.displayName ?? languageModelConfig.model; + // Determine visibility: anonymous users cannot create private chats (they would be inaccessible) + // Only use requested visibility if user is authenticated, otherwise always use PUBLIC + const chatVisibility = (requestedVisibility && user) + ? requestedVisibility + : (user ? ChatVisibility.PRIVATE : ChatVisibility.PUBLIC); + // Create a new chat session const chat = await prisma.chat.create({ data: { orgId: org.id, createdById: user?.id, - visibility: user ? ChatVisibility.PRIVATE : ChatVisibility.PUBLIC, + visibility: chatVisibility, messages: [] as unknown as Prisma.InputJsonValue, }, });