feat(ask_sb): Add support for queryParams to OpenAI compatible language model providers (#490)

This commit is contained in:
Brendan Kellam 2025-09-04 18:02:49 -04:00 committed by GitHub
parent c451a7c304
commit a74d070775
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 567 additions and 24 deletions

View file

@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [4.6.6] - 2025-09-04 ## [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 ### 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) - 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)

View file

@ -275,6 +275,15 @@ The OpenAI compatible provider allows you to use any model that is compatible wi
"displayName": "OPTIONAL_DISPLAY_NAME", "displayName": "OPTIONAL_DISPLAY_NAME",
"token": { "token": {
"env": "OPTIONAL_API_KEY" "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"
}
} }
} }
] ]

View file

@ -2361,6 +2361,50 @@
} }
}, },
"additionalProperties": false "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": [ "required": [
@ -3736,6 +3780,50 @@
} }
}, },
"additionalProperties": false "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": [ "required": [

View file

@ -1158,6 +1158,50 @@
} }
}, },
"additionalProperties": false "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": [ "required": [
@ -2533,6 +2577,50 @@
} }
}, },
"additionalProperties": false "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": [ "required": [

View file

@ -118,6 +118,50 @@
} }
}, },
"additionalProperties": false "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
} }
} }
} }

View file

@ -2360,6 +2360,50 @@ const schema = {
} }
}, },
"additionalProperties": false "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": [ "required": [
@ -3735,6 +3779,50 @@ const schema = {
} }
}, },
"additionalProperties": false "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": [ "required": [

View file

@ -881,6 +881,32 @@ export interface OpenAICompatibleLanguageModel {
*/ */
baseUrl: string; baseUrl: string;
headers?: LanguageModelHeaders; 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 { export interface OpenRouterLanguageModel {
/** /**

View file

@ -1157,6 +1157,50 @@ const schema = {
} }
}, },
"additionalProperties": false "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": [ "required": [
@ -2532,6 +2576,50 @@ const schema = {
} }
}, },
"additionalProperties": false "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": [ "required": [

View file

@ -452,6 +452,32 @@ export interface OpenAICompatibleLanguageModel {
*/ */
baseUrl: string; baseUrl: string;
headers?: LanguageModelHeaders; 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 { export interface OpenRouterLanguageModel {
/** /**

View file

@ -117,6 +117,50 @@ const schema = {
} }
}, },
"additionalProperties": false "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; } as const;

View file

@ -50,3 +50,16 @@ export interface LanguageModelHeaders {
*/ */
[k: string]: string | Token; [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;
}

View file

@ -21,13 +21,14 @@ import { createXai } from '@ai-sdk/xai';
import { createOpenRouter } from '@openrouter/ai-sdk-provider'; import { createOpenRouter } from '@openrouter/ai-sdk-provider';
import { getTokenFromConfig } from "@sourcebot/crypto"; import { getTokenFromConfig } from "@sourcebot/crypto";
import { ChatVisibility, OrgRole, Prisma, PrismaClient } from "@sourcebot/db"; 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 { loadConfig } from "@sourcebot/shared";
import { generateText, JSONValue } from "ai"; import { generateText, JSONValue } from "ai";
import fs from 'fs'; import fs from 'fs';
import { StatusCodes } from "http-status-codes"; import { StatusCodes } from "http-status-codes";
import path from 'path'; import path from 'path';
import { LanguageModelInfo, SBChatMessage } from "./types"; import { LanguageModelInfo, SBChatMessage } from "./types";
import { Token } from "@sourcebot/schemas/v3/shared.type";
export const createChat = async (domain: string) => sew(() => export const createChat = async (domain: string) => sew(() =>
withAuth((userId) => withAuth((userId) =>
@ -393,7 +394,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or
? await getTokenFromConfig(config.sessionToken, orgId, prisma) ? await getTokenFromConfig(config.sessionToken, orgId, prisma)
: env.AWS_SESSION_TOKEN, : env.AWS_SESSION_TOKEN,
headers: config.headers headers: config.headers
? await extractLanguageModelHeaders(config.headers, orgId, prisma) ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma)
: undefined, : undefined,
}); });
@ -408,7 +409,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or
? await getTokenFromConfig(config.token, orgId, prisma) ? await getTokenFromConfig(config.token, orgId, prisma)
: env.ANTHROPIC_API_KEY, : env.ANTHROPIC_API_KEY,
headers: config.headers headers: config.headers
? await extractLanguageModelHeaders(config.headers, orgId, prisma) ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma)
: undefined, : undefined,
}); });
@ -431,7 +432,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or
apiVersion: config.apiVersion, apiVersion: config.apiVersion,
resourceName: config.resourceName ?? env.AZURE_RESOURCE_NAME, resourceName: config.resourceName ?? env.AZURE_RESOURCE_NAME,
headers: config.headers headers: config.headers
? await extractLanguageModelHeaders(config.headers, orgId, prisma) ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma)
: undefined, : undefined,
}); });
@ -444,7 +445,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or
baseURL: config.baseUrl, baseURL: config.baseUrl,
apiKey: config.token ? (await getTokenFromConfig(config.token, orgId, prisma)) : env.DEEPSEEK_API_KEY, apiKey: config.token ? (await getTokenFromConfig(config.token, orgId, prisma)) : env.DEEPSEEK_API_KEY,
headers: config.headers headers: config.headers
? await extractLanguageModelHeaders(config.headers, orgId, prisma) ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma)
: undefined, : undefined,
}); });
@ -459,7 +460,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or
? await getTokenFromConfig(config.token, orgId, prisma) ? await getTokenFromConfig(config.token, orgId, prisma)
: env.GOOGLE_GENERATIVE_AI_API_KEY, : env.GOOGLE_GENERATIVE_AI_API_KEY,
headers: config.headers headers: config.headers
? await extractLanguageModelHeaders(config.headers, orgId, prisma) ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma)
: undefined, : undefined,
}); });
@ -477,7 +478,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or
} }
} : {}), } : {}),
headers: config.headers headers: config.headers
? await extractLanguageModelHeaders(config.headers, orgId, prisma) ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma)
: undefined, : undefined,
}); });
@ -503,7 +504,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or
} }
} : {}), } : {}),
headers: config.headers headers: config.headers
? await extractLanguageModelHeaders(config.headers, orgId, prisma) ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma)
: undefined, : undefined,
}); });
@ -518,7 +519,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or
? await getTokenFromConfig(config.token, orgId, prisma) ? await getTokenFromConfig(config.token, orgId, prisma)
: env.MISTRAL_API_KEY, : env.MISTRAL_API_KEY,
headers: config.headers headers: config.headers
? await extractLanguageModelHeaders(config.headers, orgId, prisma) ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma)
: undefined, : undefined,
}); });
@ -533,7 +534,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or
? await getTokenFromConfig(config.token, orgId, prisma) ? await getTokenFromConfig(config.token, orgId, prisma)
: env.OPENAI_API_KEY, : env.OPENAI_API_KEY,
headers: config.headers headers: config.headers
? await extractLanguageModelHeaders(config.headers, orgId, prisma) ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma)
: undefined, : undefined,
}); });
@ -554,7 +555,10 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or
? await getTokenFromConfig(config.token, orgId, prisma) ? await getTokenFromConfig(config.token, orgId, prisma)
: undefined, : undefined,
headers: config.headers 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, : undefined,
}); });
@ -569,7 +573,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or
? await getTokenFromConfig(config.token, orgId, prisma) ? await getTokenFromConfig(config.token, orgId, prisma)
: env.OPENROUTER_API_KEY, : env.OPENROUTER_API_KEY,
headers: config.headers headers: config.headers
? await extractLanguageModelHeaders(config.headers, orgId, prisma) ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma)
: undefined, : undefined,
}); });
@ -584,7 +588,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or
? await getTokenFromConfig(config.token, orgId, prisma) ? await getTokenFromConfig(config.token, orgId, prisma)
: env.XAI_API_KEY, : env.XAI_API_KEY,
headers: config.headers headers: config.headers
? await extractLanguageModelHeaders(config.headers, orgId, prisma) ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma)
: undefined, : undefined,
}); });
@ -595,26 +599,28 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or
} }
} }
const extractLanguageModelHeaders = async ( const extractLanguageModelKeyValuePairs = async (
headers: LanguageModelHeaders, pairs: {
[k: string]: string | Token;
},
orgId: number, orgId: number,
db: PrismaClient, db: PrismaClient,
): Promise<Record<string, string>> => { ): Promise<Record<string, string>> => {
const resolvedHeaders: Record<string, string> = {}; const resolvedPairs: Record<string, string> = {};
if (!headers) { if (!pairs) {
return resolvedHeaders; return resolvedPairs;
} }
for (const [headerName, headerValue] of Object.entries(headers)) { for (const [key, val] of Object.entries(pairs)) {
if (typeof headerValue === "string") { if (typeof val === "string") {
resolvedHeaders[headerName] = headerValue; resolvedPairs[key] = val;
continue; continue;
} }
const value = await getTokenFromConfig(headerValue, orgId, db); const value = await getTokenFromConfig(val, orgId, db);
resolvedHeaders[headerName] = value; resolvedPairs[key] = value;
} }
return resolvedHeaders; return resolvedPairs;
} }

View file

@ -422,6 +422,9 @@
}, },
"headers": { "headers": {
"$ref": "./shared.json#/definitions/LanguageModelHeaders" "$ref": "./shared.json#/definitions/LanguageModelHeaders"
},
"queryParams": {
"$ref": "./shared.json#/definitions/LanguageModelQueryParams"
} }
}, },
"required": [ "required": [

View file

@ -89,6 +89,23 @@
} }
}, },
"additionalProperties": false "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
} }
} }
} }