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
### 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)

View file

@ -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"
}
}
}
]

View file

@ -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": [

View file

@ -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": [

View file

@ -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
}
}
}

View file

@ -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": [

View file

@ -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 {
/**

View file

@ -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": [

View file

@ -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 {
/**

View file

@ -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;

View file

@ -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;
}

View file

@ -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<Record<string, string>> => {
const resolvedHeaders: Record<string, string> = {};
const resolvedPairs: Record<string, string> = {};
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;
}

View file

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

View file

@ -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
}
}
}