(params: AskCodebaseParams)
| 44 | }; |
| 45 | |
| 46 | export const askCodebase = (params: AskCodebaseParams): Promise<AskCodebaseResult | ServiceError> => |
| 47 | sew(() => |
| 48 | withOptionalAuth(async ({ org, user, prisma }) => { |
| 49 | // Ask Sourcebot is a paid feature. askCodebase() is the single choke point |
| 50 | // for the programmatic ask path (the MCP `ask_codebase` tool and the |
| 51 | // /api/chat/blocking route both wrap it), so gating here covers both without |
| 52 | // double-gating at the tool-registration layer. |
| 53 | const askEntitlementError = await checkAskEntitlement(); |
| 54 | if (askEntitlementError) { |
| 55 | return askEntitlementError; |
| 56 | } |
| 57 | |
| 58 | const { query, repos = [], languageModel: requestedLanguageModel, visibility: requestedVisibility, source } = params; |
| 59 | |
| 60 | const configuredModels = await getConfiguredLanguageModels(); |
| 61 | if (configuredModels.length === 0) { |
| 62 | return { |
| 63 | statusCode: StatusCodes.BAD_REQUEST, |
| 64 | errorCode: ErrorCode.INVALID_REQUEST_BODY, |
| 65 | message: "No language models are configured. Please configure at least one language model. See: https://docs.sourcebot.dev/docs/configuration/language-model-providers", |
| 66 | } satisfies ServiceError; |
| 67 | } |
| 68 | |
| 69 | let languageModelConfig = configuredModels[0]; |
| 70 | if (requestedLanguageModel) { |
| 71 | const matchingModel = configuredModels.find( |
| 72 | (m) => getLanguageModelKey(m) === getLanguageModelKey(requestedLanguageModel) |
| 73 | ); |
| 74 | if (!matchingModel) { |
| 75 | return { |
| 76 | statusCode: StatusCodes.BAD_REQUEST, |
| 77 | errorCode: ErrorCode.INVALID_REQUEST_BODY, |
| 78 | message: `Language model '${requestedLanguageModel.provider}/${requestedLanguageModel.model}' is not configured.`, |
| 79 | } satisfies ServiceError; |
| 80 | } |
| 81 | languageModelConfig = matchingModel; |
| 82 | } |
| 83 | |
| 84 | const { model, providerOptions, temperature } = await getAISDKLanguageModelAndOptions(languageModelConfig); |
| 85 | const modelName = languageModelConfig.displayName ?? languageModelConfig.model; |
| 86 | |
| 87 | const chatVisibility = (requestedVisibility && user) |
| 88 | ? requestedVisibility |
| 89 | : (user ? ChatVisibility.PRIVATE : ChatVisibility.PUBLIC); |
| 90 | |
| 91 | const chat = await prisma.chat.create({ |
| 92 | data: { |
| 93 | orgId: org.id, |
| 94 | createdById: user?.id, |
| 95 | visibility: chatVisibility, |
| 96 | messages: [] as unknown as Prisma.InputJsonValue, |
| 97 | }, |
| 98 | }); |
| 99 | |
| 100 | await captureEvent('ask_thread_created', { |
| 101 | chatId: chat.id, |
| 102 | isAnonymous: !user, |
| 103 | source, |
no test coverage detected