sync
parent
a844eb2429
commit
8b1c55f9fa
|
|
@ -470,6 +470,50 @@ export namespace Config {
|
|||
})
|
||||
export type Layout = z.infer<typeof Layout>
|
||||
|
||||
export const Provider = ModelsDev.Provider.partial()
|
||||
.extend({
|
||||
whitelist: z.array(z.string()).optional(),
|
||||
blacklist: z.array(z.string()).optional(),
|
||||
models: z
|
||||
.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
|
||||
.object({
|
||||
apiKey: z.string().optional(),
|
||||
baseURL: z.string().optional(),
|
||||
enterpriseUrl: z.string().optional().describe("GitHub Enterprise URL for copilot authentication"),
|
||||
setCacheKey: z.boolean().optional().describe("Enable promptCacheKey for this provider (default false)"),
|
||||
timeout: z
|
||||
.union([
|
||||
z
|
||||
.number()
|
||||
.int()
|
||||
.positive()
|
||||
.describe(
|
||||
"Timeout in milliseconds for requests to this provider. Default is 300000 (5 minutes). Set to false to disable timeout.",
|
||||
),
|
||||
z.literal(false).describe("Disable timeout for this provider entirely."),
|
||||
])
|
||||
.optional()
|
||||
.describe(
|
||||
"Timeout in milliseconds for requests to this provider. Default is 300000 (5 minutes). Set to false to disable timeout.",
|
||||
),
|
||||
})
|
||||
.catchall(z.any())
|
||||
.optional(),
|
||||
})
|
||||
.strict()
|
||||
.meta({
|
||||
ref: "ProviderConfig",
|
||||
})
|
||||
export type Provider = z.infer<typeof Provider>
|
||||
|
||||
export const Info = z
|
||||
.object({
|
||||
$schema: z.string().optional().describe("JSON schema reference for configuration validation"),
|
||||
|
|
@ -536,51 +580,7 @@ export namespace Config {
|
|||
.optional()
|
||||
.describe("Agent configuration, see https://opencode.ai/docs/agent"),
|
||||
provider: z
|
||||
.record(
|
||||
z.string(),
|
||||
ModelsDev.Provider.partial()
|
||||
.extend({
|
||||
whitelist: z.array(z.string()).optional(),
|
||||
blacklist: z.array(z.string()).optional(),
|
||||
models: z
|
||||
.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
|
||||
.object({
|
||||
apiKey: z.string().optional(),
|
||||
baseURL: z.string().optional(),
|
||||
enterpriseUrl: z.string().optional().describe("GitHub Enterprise URL for copilot authentication"),
|
||||
setCacheKey: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Enable promptCacheKey for this provider (default false)"),
|
||||
timeout: z
|
||||
.union([
|
||||
z
|
||||
.number()
|
||||
.int()
|
||||
.positive()
|
||||
.describe(
|
||||
"Timeout in milliseconds for requests to this provider. Default is 300000 (5 minutes). Set to false to disable timeout.",
|
||||
),
|
||||
z.literal(false).describe("Disable timeout for this provider entirely."),
|
||||
])
|
||||
.optional()
|
||||
.describe(
|
||||
"Timeout in milliseconds for requests to this provider. Default is 300000 (5 minutes). Set to false to disable timeout.",
|
||||
),
|
||||
})
|
||||
.catchall(z.any())
|
||||
.optional(),
|
||||
})
|
||||
.strict(),
|
||||
)
|
||||
.record(z.string(), Provider)
|
||||
.optional()
|
||||
.describe("Custom provider configurations and model overrides"),
|
||||
mcp: z.record(z.string(), Mcp).optional().describe("MCP (Model Context Protocol) server configurations"),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import z from "zod"
|
||||
import fuzzysort from "fuzzysort"
|
||||
import { Config } from "../config/config"
|
||||
import { entries, mapValues, mergeDeep, pipe, sortBy } from "remeda"
|
||||
import { mapValues, mergeDeep, sortBy } from "remeda"
|
||||
import { NoSuchModelError, type LanguageModel, type Provider as SDK } from "ai"
|
||||
import { Log } from "../util/log"
|
||||
import { BunProc } from "../bun"
|
||||
|
|
@ -360,20 +360,25 @@ export namespace Provider {
|
|||
})
|
||||
export type Model = z.infer<typeof Model>
|
||||
|
||||
export const Info = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
source: z.enum(["env", "config", "custom", "api"]),
|
||||
env: z.string().array(),
|
||||
key: z.string().optional(),
|
||||
options: z.record(z.string(), z.any()),
|
||||
models: z.record(z.string(), Model),
|
||||
})
|
||||
export const Info = z
|
||||
.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
source: z.enum(["env", "config", "custom", "api"]),
|
||||
env: z.string().array(),
|
||||
key: z.string().optional(),
|
||||
options: z.record(z.string(), z.any()),
|
||||
models: z.record(z.string(), Model),
|
||||
})
|
||||
.meta({
|
||||
ref: "Provider",
|
||||
})
|
||||
export type Info = z.infer<typeof Info>
|
||||
|
||||
function fromModelsDevModel(provider: ModelsDev.Provider, model: ModelsDev.Model): Model {
|
||||
return {
|
||||
id: model.id,
|
||||
providerID: provider.id,
|
||||
name: model.name,
|
||||
api: {
|
||||
id: model.id,
|
||||
|
|
@ -483,16 +488,16 @@ export namespace Provider {
|
|||
providers[providerID] = mergeDeep(match, provider)
|
||||
}
|
||||
|
||||
// TODO: load config
|
||||
// extend database from config
|
||||
for (const [providerID, provider] of configProviders) {
|
||||
const existing = database[providerID]
|
||||
const parsed: ModelsDev.Provider = {
|
||||
const parsed: Info = {
|
||||
id: providerID,
|
||||
npm: provider.npm ?? existing?.npm,
|
||||
name: provider.name ?? existing?.name ?? providerID,
|
||||
env: provider.env ?? existing?.env ?? [],
|
||||
api: provider.api ?? existing?.api,
|
||||
models: existing?.models ?? {},
|
||||
options: mergeDeep(existing?.options ?? {}, provider.options ?? {}),
|
||||
source: "config",
|
||||
models: {},
|
||||
}
|
||||
|
||||
for (const [modelID, model] of Object.entries(provider.models ?? {})) {
|
||||
|
|
@ -504,44 +509,51 @@ export namespace Provider {
|
|||
})
|
||||
const parsedModel: Model = {
|
||||
id: modelID,
|
||||
apiID: model.target ?? existing?.target ?? modelID,
|
||||
status: model.status ?? existing?.status ?? "alpha",
|
||||
api: {
|
||||
id: model.id ?? existing?.api.id ?? modelID,
|
||||
npm: model.provider?.npm ?? provider.npm ?? existing?.api.npm ?? providerID,
|
||||
url: provider?.api ?? existing?.api.url,
|
||||
},
|
||||
status: model.status ?? existing?.status ?? "active",
|
||||
name,
|
||||
providerID,
|
||||
npm: model.provider?.npm ?? existing?.provider?.npm ?? provider.npm ?? providerID,
|
||||
support: {
|
||||
temperature: model.temperature ?? existing?.temperature ?? false,
|
||||
reasoning: model.reasoning ?? existing?.reasoning ?? false,
|
||||
attachment: model.attachment ?? existing?.attachment ?? false,
|
||||
toolcall: model.tool_call ?? existing?.tool_call ?? true,
|
||||
capabilities: {
|
||||
temperature: model.temperature ?? existing?.capabilities.temperature ?? false,
|
||||
reasoning: model.reasoning ?? existing?.capabilities.reasoning ?? false,
|
||||
attachment: model.attachment ?? existing?.capabilities.attachment ?? false,
|
||||
toolcall: model.tool_call ?? existing?.capabilities.toolcall ?? true,
|
||||
input: {
|
||||
text: model.modalities?.input?.includes("text") ?? false,
|
||||
audio: model.modalities?.input?.includes("audio") ?? false,
|
||||
image: model.modalities?.input?.includes("image") ?? false,
|
||||
video: model.modalities?.input?.includes("video") ?? false,
|
||||
pdf: model.modalities?.input?.includes("pdf") ?? false,
|
||||
},
|
||||
output: {
|
||||
text: model.modalities?.output?.includes("text") ?? false,
|
||||
audio: model.modalities?.output?.includes("audio") ?? false,
|
||||
image: model.modalities?.output?.includes("image") ?? false,
|
||||
video: model.modalities?.output?.includes("video") ?? false,
|
||||
pdf: model.modalities?.output?.includes("pdf") ?? false,
|
||||
},
|
||||
},
|
||||
cost: {
|
||||
input: model?.cost?.input ?? existing?.cost?.input ?? 0,
|
||||
output: model?.cost?.output ?? existing?.cost?.output ?? 0,
|
||||
cache: {
|
||||
read: model?.cost?.cache_read ?? existing?.cost?.cache_read ?? 0,
|
||||
write: model?.cost?.cache_write ?? existing?.cost?.cache_write ?? 0,
|
||||
read: model?.cost?.cache_read ?? existing?.cost?.cache.read ?? 0,
|
||||
write: model?.cost?.cache_write ?? existing?.cost?.cache.write ?? 0,
|
||||
},
|
||||
},
|
||||
options: {
|
||||
...existing?.options,
|
||||
...model.options,
|
||||
options: mergeDeep(existing?.options ?? {}, model.options ?? {}),
|
||||
limit: {
|
||||
context: model.limit?.context ?? existing?.limit?.context ?? 0,
|
||||
output: model.limit?.output ?? existing?.limit?.output ?? 0,
|
||||
},
|
||||
limit: model.limit ??
|
||||
existing?.limit ?? {
|
||||
context: 0,
|
||||
output: 0,
|
||||
},
|
||||
modalities: model.modalities ??
|
||||
existing?.modalities ?? {
|
||||
input: ["text"],
|
||||
output: ["text"],
|
||||
},
|
||||
headers: model.headers ?? {},
|
||||
headers: mergeDeep(existing?.headers ?? {}, model.headers ?? {}),
|
||||
}
|
||||
parsed.models[modelID] = parsedModel
|
||||
}
|
||||
|
||||
database[providerID] = parsed
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue