diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d3c24c0..61528abf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [4.6.6] - 2025-09-04 +### Added +- Added support for specifying query params for openai compatible language models. [#490](https://github.com/sourcebot-dev/sourcebot/pull/490) + ### Fixed - Fix issue where zoekt was failing to index repositories due to `HEAD` pointing to a branch that does not exist. [#488](https://github.com/sourcebot-dev/sourcebot/pull/488) diff --git a/docs/docs/configuration/language-model-providers.mdx b/docs/docs/configuration/language-model-providers.mdx index 44865e6d..606f4d31 100644 --- a/docs/docs/configuration/language-model-providers.mdx +++ b/docs/docs/configuration/language-model-providers.mdx @@ -275,6 +275,15 @@ The OpenAI compatible provider allows you to use any model that is compatible wi "displayName": "OPTIONAL_DISPLAY_NAME", "token": { "env": "OPTIONAL_API_KEY" + }, + // Optional query parameters can be passed in the request url as: + "queryParams": { + // raw string values + "optional-query-param": "foo", + // or as environment variables + "optional-query-param-secret": { + "env": "MY_SECRET_ENV_VAR" + } } } ] diff --git a/docs/snippets/schemas/v3/index.schema.mdx b/docs/snippets/schemas/v3/index.schema.mdx index 291cc3b2..d9914254 100644 --- a/docs/snippets/schemas/v3/index.schema.mdx +++ b/docs/snippets/schemas/v3/index.schema.mdx @@ -2361,6 +2361,50 @@ } }, "additionalProperties": false + }, + "queryParams": { + "type": "object", + "description": "Optional query parameters to include in the request url.", + "patternProperties": { + "^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$": { + "anyOf": [ + { + "type": "string" + }, + { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + ] + } + }, + "additionalProperties": false } }, "required": [ @@ -3736,6 +3780,50 @@ } }, "additionalProperties": false + }, + "queryParams": { + "type": "object", + "description": "Optional query parameters to include in the request url.", + "patternProperties": { + "^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$": { + "anyOf": [ + { + "type": "string" + }, + { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + ] + } + }, + "additionalProperties": false } }, "required": [ diff --git a/docs/snippets/schemas/v3/languageModel.schema.mdx b/docs/snippets/schemas/v3/languageModel.schema.mdx index c24c17ac..d90c4a76 100644 --- a/docs/snippets/schemas/v3/languageModel.schema.mdx +++ b/docs/snippets/schemas/v3/languageModel.schema.mdx @@ -1158,6 +1158,50 @@ } }, "additionalProperties": false + }, + "queryParams": { + "type": "object", + "description": "Optional query parameters to include in the request url.", + "patternProperties": { + "^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$": { + "anyOf": [ + { + "type": "string" + }, + { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + ] + } + }, + "additionalProperties": false } }, "required": [ @@ -2533,6 +2577,50 @@ } }, "additionalProperties": false + }, + "queryParams": { + "type": "object", + "description": "Optional query parameters to include in the request url.", + "patternProperties": { + "^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$": { + "anyOf": [ + { + "type": "string" + }, + { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + ] + } + }, + "additionalProperties": false } }, "required": [ diff --git a/docs/snippets/schemas/v3/shared.schema.mdx b/docs/snippets/schemas/v3/shared.schema.mdx index f31a0936..82ca9195 100644 --- a/docs/snippets/schemas/v3/shared.schema.mdx +++ b/docs/snippets/schemas/v3/shared.schema.mdx @@ -118,6 +118,50 @@ } }, "additionalProperties": false + }, + "LanguageModelQueryParams": { + "type": "object", + "description": "Optional query parameters to include in the request url.", + "patternProperties": { + "^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$": { + "anyOf": [ + { + "type": "string" + }, + { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + ] + } + }, + "additionalProperties": false } } } diff --git a/packages/schemas/src/v3/index.schema.ts b/packages/schemas/src/v3/index.schema.ts index efa924f6..9b912121 100644 --- a/packages/schemas/src/v3/index.schema.ts +++ b/packages/schemas/src/v3/index.schema.ts @@ -2360,6 +2360,50 @@ const schema = { } }, "additionalProperties": false + }, + "queryParams": { + "type": "object", + "description": "Optional query parameters to include in the request url.", + "patternProperties": { + "^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$": { + "anyOf": [ + { + "type": "string" + }, + { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + ] + } + }, + "additionalProperties": false } }, "required": [ @@ -3735,6 +3779,50 @@ const schema = { } }, "additionalProperties": false + }, + "queryParams": { + "type": "object", + "description": "Optional query parameters to include in the request url.", + "patternProperties": { + "^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$": { + "anyOf": [ + { + "type": "string" + }, + { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + ] + } + }, + "additionalProperties": false } }, "required": [ diff --git a/packages/schemas/src/v3/index.type.ts b/packages/schemas/src/v3/index.type.ts index ef225f46..f3ee3d2f 100644 --- a/packages/schemas/src/v3/index.type.ts +++ b/packages/schemas/src/v3/index.type.ts @@ -881,6 +881,32 @@ export interface OpenAICompatibleLanguageModel { */ baseUrl: string; headers?: LanguageModelHeaders; + queryParams?: LanguageModelQueryParams; +} +/** + * Optional query parameters to include in the request url. + */ +export interface LanguageModelQueryParams { + /** + * This interface was referenced by `LanguageModelQueryParams`'s JSON-Schema definition + * via the `patternProperty` "^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$". + */ + [k: string]: + | string + | ( + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + } + ); } export interface OpenRouterLanguageModel { /** diff --git a/packages/schemas/src/v3/languageModel.schema.ts b/packages/schemas/src/v3/languageModel.schema.ts index 2e8ec4bd..cd879e59 100644 --- a/packages/schemas/src/v3/languageModel.schema.ts +++ b/packages/schemas/src/v3/languageModel.schema.ts @@ -1157,6 +1157,50 @@ const schema = { } }, "additionalProperties": false + }, + "queryParams": { + "type": "object", + "description": "Optional query parameters to include in the request url.", + "patternProperties": { + "^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$": { + "anyOf": [ + { + "type": "string" + }, + { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + ] + } + }, + "additionalProperties": false } }, "required": [ @@ -2532,6 +2576,50 @@ const schema = { } }, "additionalProperties": false + }, + "queryParams": { + "type": "object", + "description": "Optional query parameters to include in the request url.", + "patternProperties": { + "^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$": { + "anyOf": [ + { + "type": "string" + }, + { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + ] + } + }, + "additionalProperties": false } }, "required": [ diff --git a/packages/schemas/src/v3/languageModel.type.ts b/packages/schemas/src/v3/languageModel.type.ts index 7de00803..803a6c17 100644 --- a/packages/schemas/src/v3/languageModel.type.ts +++ b/packages/schemas/src/v3/languageModel.type.ts @@ -452,6 +452,32 @@ export interface OpenAICompatibleLanguageModel { */ baseUrl: string; headers?: LanguageModelHeaders; + queryParams?: LanguageModelQueryParams; +} +/** + * Optional query parameters to include in the request url. + */ +export interface LanguageModelQueryParams { + /** + * This interface was referenced by `LanguageModelQueryParams`'s JSON-Schema definition + * via the `patternProperty` "^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$". + */ + [k: string]: + | string + | ( + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + } + ); } export interface OpenRouterLanguageModel { /** diff --git a/packages/schemas/src/v3/shared.schema.ts b/packages/schemas/src/v3/shared.schema.ts index 666e2262..5ecacd44 100644 --- a/packages/schemas/src/v3/shared.schema.ts +++ b/packages/schemas/src/v3/shared.schema.ts @@ -117,6 +117,50 @@ const schema = { } }, "additionalProperties": false + }, + "LanguageModelQueryParams": { + "type": "object", + "description": "Optional query parameters to include in the request url.", + "patternProperties": { + "^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$": { + "anyOf": [ + { + "type": "string" + }, + { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + ] + } + }, + "additionalProperties": false } } } as const; diff --git a/packages/schemas/src/v3/shared.type.ts b/packages/schemas/src/v3/shared.type.ts index 16f897e1..727de2be 100644 --- a/packages/schemas/src/v3/shared.type.ts +++ b/packages/schemas/src/v3/shared.type.ts @@ -50,3 +50,16 @@ export interface LanguageModelHeaders { */ [k: string]: string | Token; } +/** + * Optional query parameters to include in the request url. + * + * This interface was referenced by `Shared`'s JSON-Schema + * via the `definition` "LanguageModelQueryParams". + */ +export interface LanguageModelQueryParams { + /** + * This interface was referenced by `LanguageModelQueryParams`'s JSON-Schema definition + * via the `patternProperty` "^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$". + */ + [k: string]: string | Token; +} diff --git a/packages/web/src/features/chat/actions.ts b/packages/web/src/features/chat/actions.ts index b2449282..3f72e110 100644 --- a/packages/web/src/features/chat/actions.ts +++ b/packages/web/src/features/chat/actions.ts @@ -21,13 +21,14 @@ import { createXai } from '@ai-sdk/xai'; import { createOpenRouter } from '@openrouter/ai-sdk-provider'; import { getTokenFromConfig } from "@sourcebot/crypto"; import { ChatVisibility, OrgRole, Prisma, PrismaClient } from "@sourcebot/db"; -import { LanguageModel, LanguageModelHeaders } from "@sourcebot/schemas/v3/languageModel.type"; +import { LanguageModel } from "@sourcebot/schemas/v3/languageModel.type"; import { loadConfig } from "@sourcebot/shared"; import { generateText, JSONValue } from "ai"; import fs from 'fs'; import { StatusCodes } from "http-status-codes"; import path from 'path'; import { LanguageModelInfo, SBChatMessage } from "./types"; +import { Token } from "@sourcebot/schemas/v3/shared.type"; export const createChat = async (domain: string) => sew(() => withAuth((userId) => @@ -393,7 +394,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or ? await getTokenFromConfig(config.sessionToken, orgId, prisma) : env.AWS_SESSION_TOKEN, headers: config.headers - ? await extractLanguageModelHeaders(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) : undefined, }); @@ -408,7 +409,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or ? await getTokenFromConfig(config.token, orgId, prisma) : env.ANTHROPIC_API_KEY, headers: config.headers - ? await extractLanguageModelHeaders(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) : undefined, }); @@ -431,7 +432,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or apiVersion: config.apiVersion, resourceName: config.resourceName ?? env.AZURE_RESOURCE_NAME, headers: config.headers - ? await extractLanguageModelHeaders(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) : undefined, }); @@ -444,7 +445,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or baseURL: config.baseUrl, apiKey: config.token ? (await getTokenFromConfig(config.token, orgId, prisma)) : env.DEEPSEEK_API_KEY, headers: config.headers - ? await extractLanguageModelHeaders(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) : undefined, }); @@ -459,7 +460,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or ? await getTokenFromConfig(config.token, orgId, prisma) : env.GOOGLE_GENERATIVE_AI_API_KEY, headers: config.headers - ? await extractLanguageModelHeaders(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) : undefined, }); @@ -477,7 +478,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or } } : {}), headers: config.headers - ? await extractLanguageModelHeaders(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) : undefined, }); @@ -503,7 +504,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or } } : {}), headers: config.headers - ? await extractLanguageModelHeaders(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) : undefined, }); @@ -518,7 +519,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or ? await getTokenFromConfig(config.token, orgId, prisma) : env.MISTRAL_API_KEY, headers: config.headers - ? await extractLanguageModelHeaders(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) : undefined, }); @@ -533,7 +534,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or ? await getTokenFromConfig(config.token, orgId, prisma) : env.OPENAI_API_KEY, headers: config.headers - ? await extractLanguageModelHeaders(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) : undefined, }); @@ -554,7 +555,10 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or ? await getTokenFromConfig(config.token, orgId, prisma) : undefined, headers: config.headers - ? await extractLanguageModelHeaders(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) + : undefined, + queryParams: config.queryParams + ? await extractLanguageModelKeyValuePairs(config.queryParams, orgId, prisma) : undefined, }); @@ -569,7 +573,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or ? await getTokenFromConfig(config.token, orgId, prisma) : env.OPENROUTER_API_KEY, headers: config.headers - ? await extractLanguageModelHeaders(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) : undefined, }); @@ -584,7 +588,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or ? await getTokenFromConfig(config.token, orgId, prisma) : env.XAI_API_KEY, headers: config.headers - ? await extractLanguageModelHeaders(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) : undefined, }); @@ -595,26 +599,28 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or } } -const extractLanguageModelHeaders = async ( - headers: LanguageModelHeaders, +const extractLanguageModelKeyValuePairs = async ( + pairs: { + [k: string]: string | Token; + }, orgId: number, db: PrismaClient, ): Promise> => { - const resolvedHeaders: Record = {}; + const resolvedPairs: Record = {}; - if (!headers) { - return resolvedHeaders; + if (!pairs) { + return resolvedPairs; } - for (const [headerName, headerValue] of Object.entries(headers)) { - if (typeof headerValue === "string") { - resolvedHeaders[headerName] = headerValue; + for (const [key, val] of Object.entries(pairs)) { + if (typeof val === "string") { + resolvedPairs[key] = val; continue; } - const value = await getTokenFromConfig(headerValue, orgId, db); - resolvedHeaders[headerName] = value; + const value = await getTokenFromConfig(val, orgId, db); + resolvedPairs[key] = value; } - return resolvedHeaders; + return resolvedPairs; } diff --git a/schemas/v3/languageModel.json b/schemas/v3/languageModel.json index d362fac5..613eb87b 100644 --- a/schemas/v3/languageModel.json +++ b/schemas/v3/languageModel.json @@ -422,6 +422,9 @@ }, "headers": { "$ref": "./shared.json#/definitions/LanguageModelHeaders" + }, + "queryParams": { + "$ref": "./shared.json#/definitions/LanguageModelQueryParams" } }, "required": [ diff --git a/schemas/v3/shared.json b/schemas/v3/shared.json index 6721e3e7..baa6dae8 100644 --- a/schemas/v3/shared.json +++ b/schemas/v3/shared.json @@ -89,6 +89,23 @@ } }, "additionalProperties": false + }, + "LanguageModelQueryParams": { + "type": "object", + "description": "Optional query parameters to include in the request url.", + "patternProperties": { + "^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$": { + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/Token" + } + ] + } + }, + "additionalProperties": false } } } \ No newline at end of file