sync
This commit is contained in:
parent
c57216f22d
commit
bbbffbf928
3 changed files with 32 additions and 34 deletions
|
|
@ -474,15 +474,7 @@ export namespace Config {
|
||||||
.extend({
|
.extend({
|
||||||
whitelist: z.array(z.string()).optional(),
|
whitelist: z.array(z.string()).optional(),
|
||||||
blacklist: z.array(z.string()).optional(),
|
blacklist: z.array(z.string()).optional(),
|
||||||
models: z
|
models: z.record(z.string(), ModelsDev.Model.partial()).optional(),
|
||||||
.record(
|
|
||||||
z.string(),
|
|
||||||
ModelsDev.Model.partial().refine(
|
|
||||||
(input) => input.id === undefined,
|
|
||||||
"The model.id field can no longer be specified. Use model.target to specify an alternate model id to use when calling the provider.",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.optional(),
|
|
||||||
options: z
|
options: z
|
||||||
.object({
|
.object({
|
||||||
apiKey: z.string().optional(),
|
apiKey: z.string().optional(),
|
||||||
|
|
|
||||||
|
|
@ -481,8 +481,14 @@ export namespace Provider {
|
||||||
function mergeProvider(providerID: string, provider: Partial<Info>) {
|
function mergeProvider(providerID: string, provider: Partial<Info>) {
|
||||||
const match = database[providerID]
|
const match = database[providerID]
|
||||||
if (!match) return
|
if (!match) return
|
||||||
// @ts-expect-error
|
const existing = providers[providerID]
|
||||||
providers[providerID] = mergeDeep(match, provider)
|
if (existing) {
|
||||||
|
// @ts-expect-error
|
||||||
|
providers[providerID] = mergeDeep(existing, provider)
|
||||||
|
} else {
|
||||||
|
// @ts-expect-error
|
||||||
|
providers[providerID] = mergeDeep(match, provider)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// extend database from config
|
// extend database from config
|
||||||
|
|
@ -494,7 +500,7 @@ export namespace Provider {
|
||||||
env: provider.env ?? existing?.env ?? [],
|
env: provider.env ?? existing?.env ?? [],
|
||||||
options: mergeDeep(existing?.options ?? {}, provider.options ?? {}),
|
options: mergeDeep(existing?.options ?? {}, provider.options ?? {}),
|
||||||
source: "config",
|
source: "config",
|
||||||
models: {},
|
models: existing?.models ?? {},
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [modelID, model] of Object.entries(provider.models ?? {})) {
|
for (const [modelID, model] of Object.entries(provider.models ?? {})) {
|
||||||
|
|
@ -520,18 +526,18 @@ export namespace Provider {
|
||||||
attachment: model.attachment ?? existing?.capabilities.attachment ?? false,
|
attachment: model.attachment ?? existing?.capabilities.attachment ?? false,
|
||||||
toolcall: model.tool_call ?? existing?.capabilities.toolcall ?? true,
|
toolcall: model.tool_call ?? existing?.capabilities.toolcall ?? true,
|
||||||
input: {
|
input: {
|
||||||
text: model.modalities?.input?.includes("text") ?? false,
|
text: model.modalities?.input?.includes("text") ?? existing?.capabilities.input.text ?? true,
|
||||||
audio: model.modalities?.input?.includes("audio") ?? false,
|
audio: model.modalities?.input?.includes("audio") ?? existing?.capabilities.input.audio ?? false,
|
||||||
image: model.modalities?.input?.includes("image") ?? false,
|
image: model.modalities?.input?.includes("image") ?? existing?.capabilities.input.image ?? false,
|
||||||
video: model.modalities?.input?.includes("video") ?? false,
|
video: model.modalities?.input?.includes("video") ?? existing?.capabilities.input.video ?? false,
|
||||||
pdf: model.modalities?.input?.includes("pdf") ?? false,
|
pdf: model.modalities?.input?.includes("pdf") ?? existing?.capabilities.input.pdf ?? false,
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
text: model.modalities?.output?.includes("text") ?? false,
|
text: model.modalities?.output?.includes("text") ?? existing?.capabilities.output.text ?? true,
|
||||||
audio: model.modalities?.output?.includes("audio") ?? false,
|
audio: model.modalities?.output?.includes("audio") ?? existing?.capabilities.output.audio ?? false,
|
||||||
image: model.modalities?.output?.includes("image") ?? false,
|
image: model.modalities?.output?.includes("image") ?? existing?.capabilities.output.image ?? false,
|
||||||
video: model.modalities?.output?.includes("video") ?? false,
|
video: model.modalities?.output?.includes("video") ?? existing?.capabilities.output.video ?? false,
|
||||||
pdf: model.modalities?.output?.includes("pdf") ?? false,
|
pdf: model.modalities?.output?.includes("pdf") ?? existing?.capabilities.output.pdf ?? false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
cost: {
|
cost: {
|
||||||
|
|
@ -638,12 +644,11 @@ export namespace Provider {
|
||||||
|
|
||||||
// load config
|
// load config
|
||||||
for (const [providerID, provider] of configProviders) {
|
for (const [providerID, provider] of configProviders) {
|
||||||
mergeProvider(providerID, {
|
const partial: Partial<Info> = { source: "config" }
|
||||||
source: "config",
|
if (provider.env) partial.env = provider.env
|
||||||
env: provider.env,
|
if (provider.name) partial.name = provider.name
|
||||||
name: provider.name,
|
if (provider.options) partial.options = provider.options
|
||||||
options: provider.options,
|
mergeProvider(providerID, partial)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [providerID, provider] of Object.entries(providers)) {
|
for (const [providerID, provider] of Object.entries(providers)) {
|
||||||
|
|
|
||||||
|
|
@ -634,7 +634,7 @@ test("getModel uses realIdByKey for aliased models", async () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
test("provider api field sets default baseURL", async () => {
|
test("provider api field sets model api.url", async () => {
|
||||||
await using tmp = await tmpdir({
|
await using tmp = await tmpdir({
|
||||||
init: async (dir) => {
|
init: async (dir) => {
|
||||||
await Bun.write(
|
await Bun.write(
|
||||||
|
|
@ -667,7 +667,8 @@ test("provider api field sets default baseURL", async () => {
|
||||||
directory: tmp.path,
|
directory: tmp.path,
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["custom-api"].options.baseURL).toBe("https://api.example.com/v1")
|
// api field is stored on model.api.url, used by getSDK to set baseURL
|
||||||
|
expect(providers["custom-api"].models["model-1"].api.url).toBe("https://api.example.com/v1")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -1122,8 +1123,8 @@ test("provider with multiple env var options only includes apiKey when single en
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["multi-env"]).toBeDefined()
|
expect(providers["multi-env"]).toBeDefined()
|
||||||
// When multiple env options exist, apiKey should NOT be auto-set
|
// When multiple env options exist, key should NOT be auto-set
|
||||||
expect(providers["multi-env"].options.apiKey).toBeUndefined()
|
expect(providers["multi-env"].key).toBeUndefined()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -1164,8 +1165,8 @@ test("provider with single env var includes apiKey automatically", async () => {
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
expect(providers["single-env"]).toBeDefined()
|
expect(providers["single-env"]).toBeDefined()
|
||||||
// Single env option should auto-set apiKey
|
// Single env option should auto-set key
|
||||||
expect(providers["single-env"].options.apiKey).toBe("my-api-key")
|
expect(providers["single-env"].key).toBe("my-api-key")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue