sync
This commit is contained in:
parent
8b1c55f9fa
commit
2dbb029472
16 changed files with 364 additions and 332 deletions
|
|
@ -456,9 +456,9 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
||||||
<img src={`https://models.dev/logos/${i.provider.id}.svg`} class="size-6 p-0.5 shrink-0" />
|
<img src={`https://models.dev/logos/${i.provider.id}.svg`} class="size-6 p-0.5 shrink-0" />
|
||||||
<div class="flex gap-x-3 items-baseline flex-[1_0_0]">
|
<div class="flex gap-x-3 items-baseline flex-[1_0_0]">
|
||||||
<span class="text-14-medium text-text-strong overflow-hidden text-ellipsis">{i.name}</span>
|
<span class="text-14-medium text-text-strong overflow-hidden text-ellipsis">{i.name}</span>
|
||||||
<Show when={i.release_date}>
|
<Show when={false}>
|
||||||
<span class="text-12-medium text-text-weak overflow-hidden text-ellipsis truncate min-w-0">
|
<span class="text-12-medium text-text-weak overflow-hidden text-ellipsis truncate min-w-0">
|
||||||
{DateTime.fromFormat(i.release_date, "yyyy-MM-dd").toFormat("LLL yyyy")}
|
{DateTime.fromFormat("unknown", "yyyy-MM-dd").toFormat("LLL yyyy")}
|
||||||
</span>
|
</span>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -224,6 +224,7 @@ export namespace Agent {
|
||||||
export async function generate(input: { description: string }) {
|
export async function generate(input: { description: string }) {
|
||||||
const defaultModel = await Provider.defaultModel()
|
const defaultModel = await Provider.defaultModel()
|
||||||
const model = await Provider.getModel(defaultModel.providerID, defaultModel.modelID)
|
const model = await Provider.getModel(defaultModel.providerID, defaultModel.modelID)
|
||||||
|
const language = await Provider.getLanguage(model)
|
||||||
const system = SystemPrompt.header(defaultModel.providerID)
|
const system = SystemPrompt.header(defaultModel.providerID)
|
||||||
system.push(PROMPT_GENERATE)
|
system.push(PROMPT_GENERATE)
|
||||||
const existing = await list()
|
const existing = await list()
|
||||||
|
|
@ -241,7 +242,7 @@ export namespace Agent {
|
||||||
content: `Create an agent configuration based on this request: \"${input.description}\".\n\nIMPORTANT: The following identifiers already exist and must NOT be used: ${existing.map((i) => i.name).join(", ")}\n Return ONLY the JSON object, no other text, do not wrap in backticks`,
|
content: `Create an agent configuration based on this request: \"${input.description}\".\n\nIMPORTANT: The following identifiers already exist and must NOT be used: ${existing.map((i) => i.name).join(", ")}\n Return ONLY the JSON object, no other text, do not wrap in backticks`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
model: model.language,
|
model: language,
|
||||||
schema: z.object({
|
schema: z.object({
|
||||||
identifier: z.string(),
|
identifier: z.string(),
|
||||||
whenToUse: z.string(),
|
whenToUse: z.string(),
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ export const ModelsCommand = cmd({
|
||||||
|
|
||||||
function printModels(providerID: string, verbose?: boolean) {
|
function printModels(providerID: string, verbose?: boolean) {
|
||||||
const provider = providers[providerID]
|
const provider = providers[providerID]
|
||||||
const sortedModels = Object.entries(provider.info.models).sort(([a], [b]) => a.localeCompare(b))
|
const sortedModels = Object.entries(provider.models).sort(([a], [b]) => a.localeCompare(b))
|
||||||
for (const [modelID, model] of sortedModels) {
|
for (const [modelID, model] of sortedModels) {
|
||||||
process.stdout.write(`${providerID}/${modelID}`)
|
process.stdout.write(`${providerID}/${modelID}`)
|
||||||
process.stdout.write(EOL)
|
process.stdout.write(EOL)
|
||||||
|
|
|
||||||
|
|
@ -9,63 +9,55 @@ export namespace ModelsDev {
|
||||||
const log = Log.create({ service: "models.dev" })
|
const log = Log.create({ service: "models.dev" })
|
||||||
const filepath = path.join(Global.Path.cache, "models.json")
|
const filepath = path.join(Global.Path.cache, "models.json")
|
||||||
|
|
||||||
export const Model = z
|
export const Model = z.object({
|
||||||
.object({
|
id: z.string(),
|
||||||
id: z.string(),
|
name: z.string(),
|
||||||
name: z.string(),
|
target: z.string(),
|
||||||
target: z.string(),
|
release_date: z.string(),
|
||||||
release_date: z.string(),
|
attachment: z.boolean(),
|
||||||
attachment: z.boolean(),
|
reasoning: z.boolean(),
|
||||||
reasoning: z.boolean(),
|
temperature: z.boolean(),
|
||||||
temperature: z.boolean(),
|
tool_call: z.boolean(),
|
||||||
tool_call: z.boolean(),
|
cost: z.object({
|
||||||
cost: z.object({
|
input: z.number(),
|
||||||
input: z.number(),
|
output: z.number(),
|
||||||
output: z.number(),
|
cache_read: z.number().optional(),
|
||||||
cache_read: z.number().optional(),
|
cache_write: z.number().optional(),
|
||||||
cache_write: z.number().optional(),
|
context_over_200k: z
|
||||||
context_over_200k: z
|
|
||||||
.object({
|
|
||||||
input: z.number(),
|
|
||||||
output: z.number(),
|
|
||||||
cache_read: z.number().optional(),
|
|
||||||
cache_write: z.number().optional(),
|
|
||||||
})
|
|
||||||
.optional(),
|
|
||||||
}),
|
|
||||||
limit: z.object({
|
|
||||||
context: z.number(),
|
|
||||||
output: z.number(),
|
|
||||||
}),
|
|
||||||
modalities: z
|
|
||||||
.object({
|
.object({
|
||||||
input: z.array(z.enum(["text", "audio", "image", "video", "pdf"])),
|
input: z.number(),
|
||||||
output: z.array(z.enum(["text", "audio", "image", "video", "pdf"])),
|
output: z.number(),
|
||||||
|
cache_read: z.number().optional(),
|
||||||
|
cache_write: z.number().optional(),
|
||||||
})
|
})
|
||||||
.optional(),
|
.optional(),
|
||||||
experimental: z.boolean().optional(),
|
}),
|
||||||
status: z.enum(["alpha", "beta", "deprecated"]).optional(),
|
limit: z.object({
|
||||||
options: z.record(z.string(), z.any()),
|
context: z.number(),
|
||||||
headers: z.record(z.string(), z.string()).optional(),
|
output: z.number(),
|
||||||
provider: z.object({ npm: z.string() }).optional(),
|
}),
|
||||||
})
|
modalities: z
|
||||||
.meta({
|
.object({
|
||||||
ref: "Model",
|
input: z.array(z.enum(["text", "audio", "image", "video", "pdf"])),
|
||||||
})
|
output: z.array(z.enum(["text", "audio", "image", "video", "pdf"])),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
experimental: z.boolean().optional(),
|
||||||
|
status: z.enum(["alpha", "beta", "deprecated"]).optional(),
|
||||||
|
options: z.record(z.string(), z.any()),
|
||||||
|
headers: z.record(z.string(), z.string()).optional(),
|
||||||
|
provider: z.object({ npm: z.string() }).optional(),
|
||||||
|
})
|
||||||
export type Model = z.infer<typeof Model>
|
export type Model = z.infer<typeof Model>
|
||||||
|
|
||||||
export const Provider = z
|
export const Provider = z.object({
|
||||||
.object({
|
api: z.string().optional(),
|
||||||
api: z.string().optional(),
|
name: z.string(),
|
||||||
name: z.string(),
|
env: z.array(z.string()),
|
||||||
env: z.array(z.string()),
|
id: z.string(),
|
||||||
id: z.string(),
|
npm: z.string().optional(),
|
||||||
npm: z.string().optional(),
|
models: z.record(z.string(), Model),
|
||||||
models: z.record(z.string(), Model),
|
})
|
||||||
})
|
|
||||||
.meta({
|
|
||||||
ref: "Provider",
|
|
||||||
})
|
|
||||||
|
|
||||||
export type Provider = z.infer<typeof Provider>
|
export type Provider = z.infer<typeof Provider>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import { createVertex } from "@ai-sdk/google-vertex"
|
||||||
import { createVertexAnthropic } from "@ai-sdk/google-vertex/anthropic"
|
import { createVertexAnthropic } from "@ai-sdk/google-vertex/anthropic"
|
||||||
import { createOpenAI } from "@ai-sdk/openai"
|
import { createOpenAI } from "@ai-sdk/openai"
|
||||||
import { createOpenAICompatible } from "@ai-sdk/openai-compatible"
|
import { createOpenAICompatible } from "@ai-sdk/openai-compatible"
|
||||||
import { createOpenRouter } from "@openrouter/ai-sdk-provider"
|
import { createOpenRouter, type LanguageModelV2 } from "@openrouter/ai-sdk-provider"
|
||||||
import { createOpenaiCompatible as createGitHubCopilotOpenAICompatible } from "./sdk/openai-compatible/src"
|
import { createOpenaiCompatible as createGitHubCopilotOpenAICompatible } from "./sdk/openai-compatible/src"
|
||||||
|
|
||||||
export namespace Provider {
|
export namespace Provider {
|
||||||
|
|
@ -43,14 +43,13 @@ export namespace Provider {
|
||||||
"@ai-sdk/github-copilot": createGitHubCopilotOpenAICompatible,
|
"@ai-sdk/github-copilot": createGitHubCopilotOpenAICompatible,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CustomModelLoader = (sdk: any, modelID: string, options?: Record<string, any>) => Promise<any>
|
||||||
type CustomLoader = (provider: Info) => Promise<{
|
type CustomLoader = (provider: Info) => Promise<{
|
||||||
autoload: boolean
|
autoload: boolean
|
||||||
getModel?: (sdk: any, modelID: string, options?: Record<string, any>) => Promise<any>
|
getModel?: CustomModelLoader
|
||||||
options?: Record<string, any>
|
options?: Record<string, any>
|
||||||
}>
|
}>
|
||||||
|
|
||||||
type Source = "env" | "config" | "custom" | "api"
|
|
||||||
|
|
||||||
const CUSTOM_LOADERS: Record<string, CustomLoader> = {
|
const CUSTOM_LOADERS: Record<string, CustomLoader> = {
|
||||||
async anthropic() {
|
async anthropic() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -314,20 +313,20 @@ export namespace Provider {
|
||||||
reasoning: z.boolean(),
|
reasoning: z.boolean(),
|
||||||
attachment: z.boolean(),
|
attachment: z.boolean(),
|
||||||
toolcall: z.boolean(),
|
toolcall: z.boolean(),
|
||||||
input: {
|
input: z.object({
|
||||||
text: z.boolean(),
|
text: z.boolean(),
|
||||||
audio: z.boolean(),
|
audio: z.boolean(),
|
||||||
image: z.boolean(),
|
image: z.boolean(),
|
||||||
video: z.boolean(),
|
video: z.boolean(),
|
||||||
pdf: z.boolean(),
|
pdf: z.boolean(),
|
||||||
},
|
}),
|
||||||
output: {
|
output: z.object({
|
||||||
text: z.boolean(),
|
text: z.boolean(),
|
||||||
audio: z.boolean(),
|
audio: z.boolean(),
|
||||||
image: z.boolean(),
|
image: z.boolean(),
|
||||||
video: z.boolean(),
|
video: z.boolean(),
|
||||||
pdf: z.boolean(),
|
pdf: z.boolean(),
|
||||||
},
|
}),
|
||||||
}),
|
}),
|
||||||
cost: z.object({
|
cost: z.object({
|
||||||
input: z.number(),
|
input: z.number(),
|
||||||
|
|
@ -433,7 +432,7 @@ export namespace Provider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function fromModelsDevProvider(provider: ModelsDev.Provider): Info {
|
export function fromModelsDevProvider(provider: ModelsDev.Provider): Info {
|
||||||
return {
|
return {
|
||||||
id: provider.id,
|
id: provider.id,
|
||||||
source: "custom",
|
source: "custom",
|
||||||
|
|
@ -444,11 +443,6 @@ export namespace Provider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ModelWithStuff = {
|
|
||||||
language: LanguageModel
|
|
||||||
info: Model
|
|
||||||
}
|
|
||||||
|
|
||||||
const state = Instance.state(async () => {
|
const state = Instance.state(async () => {
|
||||||
using _ = log.time("state")
|
using _ = log.time("state")
|
||||||
const config = await Config.get()
|
const config = await Config.get()
|
||||||
|
|
@ -464,7 +458,10 @@ export namespace Provider {
|
||||||
}
|
}
|
||||||
|
|
||||||
const providers: { [providerID: string]: Info } = {}
|
const providers: { [providerID: string]: Info } = {}
|
||||||
const models = new Map<string, ModelWithStuff>()
|
const languages = new Map<string, LanguageModelV2>()
|
||||||
|
const modelLoaders: {
|
||||||
|
[providerID: string]: CustomModelLoader
|
||||||
|
} = {}
|
||||||
const sdk = new Map<number, SDK>()
|
const sdk = new Map<number, SDK>()
|
||||||
|
|
||||||
log.info("init")
|
log.info("init")
|
||||||
|
|
@ -631,6 +628,7 @@ export namespace Provider {
|
||||||
if (disabled.has(providerID)) continue
|
if (disabled.has(providerID)) continue
|
||||||
const result = await fn(database[providerID])
|
const result = await fn(database[providerID])
|
||||||
if (result && (result.autoload || providers[providerID])) {
|
if (result && (result.autoload || providers[providerID])) {
|
||||||
|
if (result.getModel) modelLoaders[providerID] = result.getModel
|
||||||
mergeProvider(providerID, {
|
mergeProvider(providerID, {
|
||||||
source: "custom",
|
source: "custom",
|
||||||
options: result.options,
|
options: result.options,
|
||||||
|
|
@ -645,7 +643,6 @@ export namespace Provider {
|
||||||
env: provider.env,
|
env: provider.env,
|
||||||
name: provider.name,
|
name: provider.name,
|
||||||
options: provider.options,
|
options: provider.options,
|
||||||
// TODO: merge models
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -689,9 +686,10 @@ export namespace Provider {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
models,
|
models: languages,
|
||||||
providers,
|
providers,
|
||||||
sdk,
|
sdk,
|
||||||
|
modelLoaders,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -789,15 +787,7 @@ export namespace Provider {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getModel(providerID: string, modelID: string) {
|
export async function getModel(providerID: string, modelID: string) {
|
||||||
const key = `${providerID}/${modelID}`
|
|
||||||
const s = await state()
|
const s = await state()
|
||||||
if (s.models.has(key)) return s.models.get(key)!
|
|
||||||
|
|
||||||
log.info("getModel", {
|
|
||||||
providerID,
|
|
||||||
modelID,
|
|
||||||
})
|
|
||||||
|
|
||||||
const provider = s.providers[providerID]
|
const provider = s.providers[providerID]
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
const availableProviders = Object.keys(s.providers)
|
const availableProviders = Object.keys(s.providers)
|
||||||
|
|
@ -813,38 +803,29 @@ export namespace Provider {
|
||||||
const suggestions = matches.map((m) => m.target)
|
const suggestions = matches.map((m) => m.target)
|
||||||
throw new ModelNotFoundError({ providerID, modelID, suggestions })
|
throw new ModelNotFoundError({ providerID, modelID, suggestions })
|
||||||
}
|
}
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
|
||||||
const sdk = await getSDK(info)
|
export async function getLanguage(model: Model) {
|
||||||
|
const s = await state()
|
||||||
|
const key = `${model.providerID}/${model.id}`
|
||||||
|
if (s.models.has(key)) return s.models.get(key)!
|
||||||
|
|
||||||
|
const provider = s.providers[model.providerID]
|
||||||
|
const sdk = await getSDK(model)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const language = provider.getModel
|
const language = s.modelLoaders[model.providerID]
|
||||||
? await provider.getModel(sdk, info.api.id, provider.options)
|
? await s.modelLoaders[model.providerID](sdk, model.api.id, provider.options)
|
||||||
: sdk.languageModel(info.api.id)
|
: sdk.languageModel(model.api.id)
|
||||||
log.info("found", { providerID, modelID })
|
s.models.set(key, language)
|
||||||
const cached: ModelWithStuff = {
|
return language
|
||||||
info,
|
|
||||||
language,
|
|
||||||
}
|
|
||||||
s.models.set(key, {
|
|
||||||
providerID,
|
|
||||||
modelID,
|
|
||||||
info,
|
|
||||||
language,
|
|
||||||
npm,
|
|
||||||
})
|
|
||||||
return {
|
|
||||||
modelID,
|
|
||||||
providerID,
|
|
||||||
info,
|
|
||||||
language,
|
|
||||||
npm,
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof NoSuchModelError)
|
if (e instanceof NoSuchModelError)
|
||||||
throw new ModelNotFoundError(
|
throw new ModelNotFoundError(
|
||||||
{
|
{
|
||||||
modelID: modelID,
|
modelID: model.id,
|
||||||
providerID,
|
providerID: model.providerID,
|
||||||
},
|
},
|
||||||
{ cause: e },
|
{ cause: e },
|
||||||
)
|
)
|
||||||
|
|
@ -857,7 +838,7 @@ export namespace Provider {
|
||||||
const provider = s.providers[providerID]
|
const provider = s.providers[providerID]
|
||||||
if (!provider) return undefined
|
if (!provider) return undefined
|
||||||
for (const item of query) {
|
for (const item of query) {
|
||||||
for (const modelID of Object.keys(provider.info.models)) {
|
for (const modelID of Object.keys(provider.models)) {
|
||||||
if (modelID.includes(item))
|
if (modelID.includes(item))
|
||||||
return {
|
return {
|
||||||
providerID,
|
providerID,
|
||||||
|
|
@ -893,7 +874,7 @@ export namespace Provider {
|
||||||
priority = ["gpt-5-nano"]
|
priority = ["gpt-5-nano"]
|
||||||
}
|
}
|
||||||
for (const item of priority) {
|
for (const item of priority) {
|
||||||
for (const model of Object.keys(provider.info.models)) {
|
for (const model of Object.keys(provider.models)) {
|
||||||
if (model.includes(item)) return getModel(providerID, model)
|
if (model.includes(item)) return getModel(providerID, model)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -901,7 +882,7 @@ export namespace Provider {
|
||||||
|
|
||||||
// Check if opencode provider is available before using it
|
// Check if opencode provider is available before using it
|
||||||
const opencodeProvider = await state().then((state) => state.providers["opencode"])
|
const opencodeProvider = await state().then((state) => state.providers["opencode"])
|
||||||
if (opencodeProvider && opencodeProvider.info.models["gpt-5-nano"]) {
|
if (opencodeProvider && opencodeProvider.models["gpt-5-nano"]) {
|
||||||
return getModel("opencode", "gpt-5-nano")
|
return getModel("opencode", "gpt-5-nano")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -924,12 +905,12 @@ export namespace Provider {
|
||||||
|
|
||||||
const provider = await list()
|
const provider = await list()
|
||||||
.then((val) => Object.values(val))
|
.then((val) => Object.values(val))
|
||||||
.then((x) => x.find((p) => !cfg.provider || Object.keys(cfg.provider).includes(p.info.id)))
|
.then((x) => x.find((p) => !cfg.provider || Object.keys(cfg.provider).includes(p.id)))
|
||||||
if (!provider) throw new Error("no providers found")
|
if (!provider) throw new Error("no providers found")
|
||||||
const [model] = sort(Object.values(provider.info.models))
|
const [model] = sort(Object.values(provider.models))
|
||||||
if (!model) throw new Error("no models found")
|
if (!model) throw new Error("no models found")
|
||||||
return {
|
return {
|
||||||
providerID: provider.info.id,
|
providerID: provider.id,
|
||||||
modelID: model.id,
|
modelID: model.id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import type { APICallError, ModelMessage } from "ai"
|
import type { APICallError, ModelMessage } from "ai"
|
||||||
import { unique } from "remeda"
|
import { unique } from "remeda"
|
||||||
import type { JSONSchema } from "zod/v4/core"
|
import type { JSONSchema } from "zod/v4/core"
|
||||||
import type { ModelsDev } from "./models"
|
import type { Provider } from "./provider"
|
||||||
|
|
||||||
export namespace ProviderTransform {
|
export namespace ProviderTransform {
|
||||||
function normalizeMessages(msgs: ModelMessage[], providerID: string, model: ModelsDev.Model): ModelMessage[] {
|
function normalizeMessages(msgs: ModelMessage[], model: Provider.Model): ModelMessage[] {
|
||||||
if (model.target.includes("claude")) {
|
if (model.api.id.includes("claude")) {
|
||||||
return msgs.map((msg) => {
|
return msgs.map((msg) => {
|
||||||
if ((msg.role === "assistant" || msg.role === "tool") && Array.isArray(msg.content)) {
|
if ((msg.role === "assistant" || msg.role === "tool") && Array.isArray(msg.content)) {
|
||||||
msg.content = msg.content.map((part) => {
|
msg.content = msg.content.map((part) => {
|
||||||
|
|
@ -21,7 +21,7 @@ export namespace ProviderTransform {
|
||||||
return msg
|
return msg
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (providerID === "mistral" || model.target.toLowerCase().includes("mistral")) {
|
if (model.providerID === "mistral" || model.api.id.toLowerCase().includes("mistral")) {
|
||||||
const result: ModelMessage[] = []
|
const result: ModelMessage[] = []
|
||||||
for (let i = 0; i < msgs.length; i++) {
|
for (let i = 0; i < msgs.length; i++) {
|
||||||
const msg = msgs[i]
|
const msg = msgs[i]
|
||||||
|
|
@ -108,67 +108,68 @@ export namespace ProviderTransform {
|
||||||
return msgs
|
return msgs
|
||||||
}
|
}
|
||||||
|
|
||||||
export function message(msgs: ModelMessage[], providerID: string, model: ModelsDev.Model) {
|
export function message(msgs: ModelMessage[], model: Provider.Model) {
|
||||||
msgs = normalizeMessages(msgs, providerID, model)
|
msgs = normalizeMessages(msgs, model)
|
||||||
if (providerID === "anthropic" || model.target.includes("anthropic") || model.target.includes("claude")) {
|
if (model.providerID === "anthropic" || model.api.id.includes("anthropic") || model.api.id.includes("claude")) {
|
||||||
msgs = applyCaching(msgs, providerID)
|
msgs = applyCaching(msgs, model.providerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return msgs
|
return msgs
|
||||||
}
|
}
|
||||||
|
|
||||||
export function temperature(model: ModelsDev.Model) {
|
export function temperature(model: Provider.Model) {
|
||||||
if (model.target.toLowerCase().includes("qwen")) return 0.55
|
if (model.api.id.toLowerCase().includes("qwen")) return 0.55
|
||||||
if (model.target.toLowerCase().includes("claude")) return undefined
|
if (model.api.id.toLowerCase().includes("claude")) return undefined
|
||||||
if (model.target.toLowerCase().includes("gemini-3-pro")) return 1.0
|
if (model.api.id.toLowerCase().includes("gemini-3-pro")) return 1.0
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
export function topP(model: ModelsDev.Model) {
|
export function topP(model: Provider.Model) {
|
||||||
if (model.target.toLowerCase().includes("qwen")) return 1
|
if (model.api.id.toLowerCase().includes("qwen")) return 1
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export function options(
|
export function options(
|
||||||
providerID: string,
|
model: Provider.Model,
|
||||||
model: ModelsDev.Model,
|
|
||||||
npm: string,
|
|
||||||
sessionID: string,
|
sessionID: string,
|
||||||
providerOptions?: Record<string, any>,
|
providerOptions?: Record<string, any>,
|
||||||
): Record<string, any> {
|
): Record<string, any> {
|
||||||
const result: Record<string, any> = {}
|
const result: Record<string, any> = {}
|
||||||
|
|
||||||
// switch to providerID later, for now use this
|
// switch to providerID later, for now use this
|
||||||
if (npm === "@openrouter/ai-sdk-provider") {
|
if (model.api.npm === "@openrouter/ai-sdk-provider") {
|
||||||
result["usage"] = {
|
result["usage"] = {
|
||||||
include: true,
|
include: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (providerID === "openai" || providerOptions?.setCacheKey) {
|
if (model.providerID === "openai" || providerOptions?.setCacheKey) {
|
||||||
result["promptCacheKey"] = sessionID
|
result["promptCacheKey"] = sessionID
|
||||||
}
|
}
|
||||||
|
|
||||||
if (providerID === "google" || (providerID.startsWith("opencode") && model.target.includes("gemini-3"))) {
|
if (
|
||||||
|
model.providerID === "google" ||
|
||||||
|
(model.providerID.startsWith("opencode") && model.api.id.includes("gemini-3"))
|
||||||
|
) {
|
||||||
result["thinkingConfig"] = {
|
result["thinkingConfig"] = {
|
||||||
includeThoughts: true,
|
includeThoughts: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model.target.includes("gpt-5") && !model.target.includes("gpt-5-chat")) {
|
if (model.providerID.includes("gpt-5") && !model.api.id.includes("gpt-5-chat")) {
|
||||||
if (model.target.includes("codex")) {
|
if (model.providerID.includes("codex")) {
|
||||||
result["store"] = false
|
result["store"] = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!model.target.includes("codex") && !model.target.includes("gpt-5-pro")) {
|
if (!model.api.id.includes("codex") && !model.api.id.includes("gpt-5-pro")) {
|
||||||
result["reasoningEffort"] = "medium"
|
result["reasoningEffort"] = "medium"
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model.target.endsWith("gpt-5.1") && providerID !== "azure") {
|
if (model.api.id.endsWith("gpt-5.1") && model.providerID !== "azure") {
|
||||||
result["textVerbosity"] = "low"
|
result["textVerbosity"] = "low"
|
||||||
}
|
}
|
||||||
|
|
||||||
if (providerID.startsWith("opencode")) {
|
if (model.providerID.startsWith("opencode")) {
|
||||||
result["promptCacheKey"] = sessionID
|
result["promptCacheKey"] = sessionID
|
||||||
result["include"] = ["reasoning.encrypted_content"]
|
result["include"] = ["reasoning.encrypted_content"]
|
||||||
result["reasoningSummary"] = "auto"
|
result["reasoningSummary"] = "auto"
|
||||||
|
|
@ -177,17 +178,17 @@ export namespace ProviderTransform {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
export function smallOptions(input: { providerID: string; model: ModelsDev.Model }) {
|
export function smallOptions(model: Provider.Model) {
|
||||||
const options: Record<string, any> = {}
|
const options: Record<string, any> = {}
|
||||||
|
|
||||||
if (input.providerID === "openai" || input.model.target.includes("gpt-5")) {
|
if (model.providerID === "openai" || model.api.id.includes("gpt-5")) {
|
||||||
if (input.model.target.includes("5.1")) {
|
if (model.api.id.includes("5.1")) {
|
||||||
options["reasoningEffort"] = "low"
|
options["reasoningEffort"] = "low"
|
||||||
} else {
|
} else {
|
||||||
options["reasoningEffort"] = "minimal"
|
options["reasoningEffort"] = "minimal"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (input.providerID === "google") {
|
if (model.providerID === "google") {
|
||||||
options["thinkingConfig"] = {
|
options["thinkingConfig"] = {
|
||||||
thinkingBudget: 0,
|
thinkingBudget: 0,
|
||||||
}
|
}
|
||||||
|
|
@ -255,7 +256,7 @@ export namespace ProviderTransform {
|
||||||
return standardLimit
|
return standardLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
export function schema(providerID: string, model: ModelsDev.Model, schema: JSONSchema.BaseSchema) {
|
export function schema(model: Provider.Model, schema: JSONSchema.BaseSchema) {
|
||||||
/*
|
/*
|
||||||
if (["openai", "azure"].includes(providerID)) {
|
if (["openai", "azure"].includes(providerID)) {
|
||||||
if (schema.type === "object" && schema.properties) {
|
if (schema.type === "object" && schema.properties) {
|
||||||
|
|
@ -275,7 +276,7 @@ export namespace ProviderTransform {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Convert integer enums to string enums for Google/Gemini
|
// Convert integer enums to string enums for Google/Gemini
|
||||||
if (providerID === "google" || model.target.includes("gemini")) {
|
if (model.providerID === "google" || model.api.id.includes("gemini")) {
|
||||||
const sanitizeGemini = (obj: any): any => {
|
const sanitizeGemini = (obj: any): any => {
|
||||||
if (obj === null || typeof obj !== "object") {
|
if (obj === null || typeof obj !== "object") {
|
||||||
return obj
|
return obj
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import { proxy } from "hono/proxy"
|
||||||
import { Session } from "../session"
|
import { Session } from "../session"
|
||||||
import z from "zod"
|
import z from "zod"
|
||||||
import { Provider } from "../provider/provider"
|
import { Provider } from "../provider/provider"
|
||||||
import { mapValues } from "remeda"
|
import { mapValues, pipe } from "remeda"
|
||||||
import { NamedError } from "@opencode-ai/util/error"
|
import { NamedError } from "@opencode-ai/util/error"
|
||||||
import { ModelsDev } from "../provider/models"
|
import { ModelsDev } from "../provider/models"
|
||||||
import { Ripgrep } from "../file/ripgrep"
|
import { Ripgrep } from "../file/ripgrep"
|
||||||
|
|
@ -1025,7 +1025,7 @@ export namespace Server {
|
||||||
async (c) => {
|
async (c) => {
|
||||||
c.status(204)
|
c.status(204)
|
||||||
c.header("Content-Type", "application/json")
|
c.header("Content-Type", "application/json")
|
||||||
return stream(c, async (stream) => {
|
return stream(c, async () => {
|
||||||
const sessionID = c.req.valid("param").id
|
const sessionID = c.req.valid("param").id
|
||||||
const body = c.req.valid("json")
|
const body = c.req.valid("json")
|
||||||
SessionPrompt.prompt({ ...body, sessionID })
|
SessionPrompt.prompt({ ...body, sessionID })
|
||||||
|
|
@ -1231,7 +1231,7 @@ export namespace Server {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
schema: resolver(
|
schema: resolver(
|
||||||
z.object({
|
z.object({
|
||||||
providers: ModelsDev.Provider.array(),
|
providers: Provider.Info.array(),
|
||||||
default: z.record(z.string(), z.string()),
|
default: z.record(z.string(), z.string()),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|
@ -1242,7 +1242,7 @@ export namespace Server {
|
||||||
}),
|
}),
|
||||||
async (c) => {
|
async (c) => {
|
||||||
using _ = log.time("providers")
|
using _ = log.time("providers")
|
||||||
const providers = await Provider.list().then((x) => mapValues(x, (item) => item.info))
|
const providers = await Provider.list().then((x) => mapValues(x, (item) => item))
|
||||||
return c.json({
|
return c.json({
|
||||||
providers: Object.values(providers),
|
providers: Object.values(providers),
|
||||||
default: mapValues(providers, (item) => Provider.sort(Object.values(item.models))[0].id),
|
default: mapValues(providers, (item) => Provider.sort(Object.values(item.models))[0].id),
|
||||||
|
|
@ -1272,7 +1272,10 @@ export namespace Server {
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
async (c) => {
|
async (c) => {
|
||||||
const providers = await ModelsDev.get()
|
const providers = pipe(
|
||||||
|
await ModelsDev.get(),
|
||||||
|
mapValues((x) => Provider.fromModelsDevProvider(x)),
|
||||||
|
)
|
||||||
const connected = await Provider.list().then((x) => Object.keys(x))
|
const connected = await Provider.list().then((x) => Object.keys(x))
|
||||||
return c.json({
|
return c.json({
|
||||||
all: Object.values(providers),
|
all: Object.values(providers),
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import { MessageV2 } from "./message-v2"
|
||||||
import { SystemPrompt } from "./system"
|
import { SystemPrompt } from "./system"
|
||||||
import { Bus } from "../bus"
|
import { Bus } from "../bus"
|
||||||
import z from "zod"
|
import z from "zod"
|
||||||
import type { ModelsDev } from "../provider/models"
|
|
||||||
import { SessionPrompt } from "./prompt"
|
import { SessionPrompt } from "./prompt"
|
||||||
import { Flag } from "../flag/flag"
|
import { Flag } from "../flag/flag"
|
||||||
import { Token } from "../util/token"
|
import { Token } from "../util/token"
|
||||||
|
|
@ -29,7 +28,7 @@ export namespace SessionCompaction {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isOverflow(input: { tokens: MessageV2.Assistant["tokens"]; model: ModelsDev.Model }) {
|
export function isOverflow(input: { tokens: MessageV2.Assistant["tokens"]; model: Provider.Model }) {
|
||||||
if (Flag.OPENCODE_DISABLE_AUTOCOMPACT) return false
|
if (Flag.OPENCODE_DISABLE_AUTOCOMPACT) return false
|
||||||
const context = input.model.limit.context
|
const context = input.model.limit.context
|
||||||
if (context === 0) return false
|
if (context === 0) return false
|
||||||
|
|
@ -98,6 +97,7 @@ export namespace SessionCompaction {
|
||||||
auto: boolean
|
auto: boolean
|
||||||
}) {
|
}) {
|
||||||
const model = await Provider.getModel(input.model.providerID, input.model.modelID)
|
const model = await Provider.getModel(input.model.providerID, input.model.modelID)
|
||||||
|
const language = await Provider.getLanguage(model)
|
||||||
const system = [...SystemPrompt.compaction(model.providerID)]
|
const system = [...SystemPrompt.compaction(model.providerID)]
|
||||||
const msg = (await Session.updateMessage({
|
const msg = (await Session.updateMessage({
|
||||||
id: Identifier.ascending("message"),
|
id: Identifier.ascending("message"),
|
||||||
|
|
@ -126,8 +126,7 @@ export namespace SessionCompaction {
|
||||||
const processor = SessionProcessor.create({
|
const processor = SessionProcessor.create({
|
||||||
assistantMessage: msg,
|
assistantMessage: msg,
|
||||||
sessionID: input.sessionID,
|
sessionID: input.sessionID,
|
||||||
providerID: input.model.providerID,
|
model: model,
|
||||||
model: model.info,
|
|
||||||
abort: input.abort,
|
abort: input.abort,
|
||||||
})
|
})
|
||||||
const result = await processor.process({
|
const result = await processor.process({
|
||||||
|
|
@ -139,17 +138,13 @@ export namespace SessionCompaction {
|
||||||
// set to 0, we handle loop
|
// set to 0, we handle loop
|
||||||
maxRetries: 0,
|
maxRetries: 0,
|
||||||
providerOptions: ProviderTransform.providerOptions(
|
providerOptions: ProviderTransform.providerOptions(
|
||||||
model.npm,
|
model.api.npm,
|
||||||
model.providerID,
|
model.providerID,
|
||||||
pipe(
|
pipe({}, mergeDeep(ProviderTransform.options(model, input.sessionID)), mergeDeep(model.options)),
|
||||||
{},
|
|
||||||
mergeDeep(ProviderTransform.options(model.providerID, model.info, model.npm ?? "", input.sessionID)),
|
|
||||||
mergeDeep(model.info.options),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
headers: model.info.headers,
|
headers: model.headers,
|
||||||
abortSignal: input.abort,
|
abortSignal: input.abort,
|
||||||
tools: model.info.tool_call ? {} : undefined,
|
tools: model.capabilities.toolcall ? {} : undefined,
|
||||||
messages: [
|
messages: [
|
||||||
...system.map(
|
...system.map(
|
||||||
(x): ModelMessage => ({
|
(x): ModelMessage => ({
|
||||||
|
|
@ -183,7 +178,7 @@ export namespace SessionCompaction {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
model: wrapLanguageModel({
|
model: wrapLanguageModel({
|
||||||
model: model.language,
|
model: language,
|
||||||
middleware: [
|
middleware: [
|
||||||
{
|
{
|
||||||
async transformParams(args) {
|
async transformParams(args) {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import { Config } from "../config/config"
|
||||||
import { Flag } from "../flag/flag"
|
import { Flag } from "../flag/flag"
|
||||||
import { Identifier } from "../id/id"
|
import { Identifier } from "../id/id"
|
||||||
import { Installation } from "../installation"
|
import { Installation } from "../installation"
|
||||||
import type { ModelsDev } from "../provider/models"
|
|
||||||
import { Share } from "../share/share"
|
import { Share } from "../share/share"
|
||||||
import { Storage } from "../storage/storage"
|
import { Storage } from "../storage/storage"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
|
|
@ -17,6 +16,7 @@ import { fn } from "@/util/fn"
|
||||||
import { Command } from "../command"
|
import { Command } from "../command"
|
||||||
import { Snapshot } from "@/snapshot"
|
import { Snapshot } from "@/snapshot"
|
||||||
import { ShareNext } from "@/share/share-next"
|
import { ShareNext } from "@/share/share-next"
|
||||||
|
import { Provider } from "@/provider/provider"
|
||||||
|
|
||||||
export namespace Session {
|
export namespace Session {
|
||||||
const log = Log.create({ service: "session" })
|
const log = Log.create({ service: "session" })
|
||||||
|
|
@ -389,7 +389,7 @@ export namespace Session {
|
||||||
|
|
||||||
export const getUsage = fn(
|
export const getUsage = fn(
|
||||||
z.object({
|
z.object({
|
||||||
model: z.custom<ModelsDev.Model>(),
|
model: Provider.Model,
|
||||||
usage: z.custom<LanguageModelUsage>(),
|
usage: z.custom<LanguageModelUsage>(),
|
||||||
metadata: z.custom<ProviderMetadata>().optional(),
|
metadata: z.custom<ProviderMetadata>().optional(),
|
||||||
}),
|
}),
|
||||||
|
|
@ -420,16 +420,16 @@ export namespace Session {
|
||||||
}
|
}
|
||||||
|
|
||||||
const costInfo =
|
const costInfo =
|
||||||
input.model.cost?.context_over_200k && tokens.input + tokens.cache.read > 200_000
|
input.model.cost?.experimentalOver200K && tokens.input + tokens.cache.read > 200_000
|
||||||
? input.model.cost.context_over_200k
|
? input.model.cost.experimentalOver200K
|
||||||
: input.model.cost
|
: input.model.cost
|
||||||
return {
|
return {
|
||||||
cost: safe(
|
cost: safe(
|
||||||
new Decimal(0)
|
new Decimal(0)
|
||||||
.add(new Decimal(tokens.input).mul(costInfo?.input ?? 0).div(1_000_000))
|
.add(new Decimal(tokens.input).mul(costInfo?.input ?? 0).div(1_000_000))
|
||||||
.add(new Decimal(tokens.output).mul(costInfo?.output ?? 0).div(1_000_000))
|
.add(new Decimal(tokens.output).mul(costInfo?.output ?? 0).div(1_000_000))
|
||||||
.add(new Decimal(tokens.cache.read).mul(costInfo?.cache_read ?? 0).div(1_000_000))
|
.add(new Decimal(tokens.cache.read).mul(costInfo?.cache.read ?? 0).div(1_000_000))
|
||||||
.add(new Decimal(tokens.cache.write).mul(costInfo?.cache_write ?? 0).div(1_000_000))
|
.add(new Decimal(tokens.cache.write).mul(costInfo?.cache.write ?? 0).div(1_000_000))
|
||||||
// TODO: update models.dev to have better pricing model, for now:
|
// TODO: update models.dev to have better pricing model, for now:
|
||||||
// charge reasoning tokens at the same rate as output tokens
|
// charge reasoning tokens at the same rate as output tokens
|
||||||
.add(new Decimal(tokens.reasoning).mul(costInfo?.output ?? 0).div(1_000_000))
|
.add(new Decimal(tokens.reasoning).mul(costInfo?.output ?? 0).div(1_000_000))
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import type { ModelsDev } from "@/provider/models"
|
|
||||||
import { MessageV2 } from "./message-v2"
|
import { MessageV2 } from "./message-v2"
|
||||||
import { streamText } from "ai"
|
import { streamText } from "ai"
|
||||||
import { Log } from "@/util/log"
|
import { Log } from "@/util/log"
|
||||||
|
|
@ -11,6 +10,7 @@ import { SessionSummary } from "./summary"
|
||||||
import { Bus } from "@/bus"
|
import { Bus } from "@/bus"
|
||||||
import { SessionRetry } from "./retry"
|
import { SessionRetry } from "./retry"
|
||||||
import { SessionStatus } from "./status"
|
import { SessionStatus } from "./status"
|
||||||
|
import type { Provider } from "@/provider/provider"
|
||||||
|
|
||||||
export namespace SessionProcessor {
|
export namespace SessionProcessor {
|
||||||
const DOOM_LOOP_THRESHOLD = 3
|
const DOOM_LOOP_THRESHOLD = 3
|
||||||
|
|
@ -31,8 +31,7 @@ export namespace SessionProcessor {
|
||||||
export function create(input: {
|
export function create(input: {
|
||||||
assistantMessage: MessageV2.Assistant
|
assistantMessage: MessageV2.Assistant
|
||||||
sessionID: string
|
sessionID: string
|
||||||
providerID: string
|
model: Provider.Model
|
||||||
model: ModelsDev.Model
|
|
||||||
abort: AbortSignal
|
abort: AbortSignal
|
||||||
}) {
|
}) {
|
||||||
const toolcalls: Record<string, MessageV2.ToolPart> = {}
|
const toolcalls: Record<string, MessageV2.ToolPart> = {}
|
||||||
|
|
@ -341,7 +340,7 @@ export namespace SessionProcessor {
|
||||||
log.error("process", {
|
log.error("process", {
|
||||||
error: e,
|
error: e,
|
||||||
})
|
})
|
||||||
const error = MessageV2.fromError(e, { providerID: input.providerID })
|
const error = MessageV2.fromError(e, { providerID: input.sessionID })
|
||||||
const retry = SessionRetry.retryable(error)
|
const retry = SessionRetry.retryable(error)
|
||||||
if (retry !== undefined) {
|
if (retry !== undefined) {
|
||||||
attempt++
|
attempt++
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,6 @@ import { fn } from "@/util/fn"
|
||||||
import { SessionProcessor } from "./processor"
|
import { SessionProcessor } from "./processor"
|
||||||
import { TaskTool } from "@/tool/task"
|
import { TaskTool } from "@/tool/task"
|
||||||
import { SessionStatus } from "./status"
|
import { SessionStatus } from "./status"
|
||||||
import type { ModelsDev } from "@/provider/models"
|
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
globalThis.AI_SDK_LOG_WARNINGS = false
|
globalThis.AI_SDK_LOG_WARNINGS = false
|
||||||
|
|
@ -288,6 +287,7 @@ export namespace SessionPrompt {
|
||||||
})
|
})
|
||||||
|
|
||||||
const model = await Provider.getModel(lastUser.model.providerID, lastUser.model.modelID)
|
const model = await Provider.getModel(lastUser.model.providerID, lastUser.model.modelID)
|
||||||
|
const language = await Provider.getLanguage(model)
|
||||||
const task = tasks.pop()
|
const task = tasks.pop()
|
||||||
|
|
||||||
// pending subtask
|
// pending subtask
|
||||||
|
|
@ -311,7 +311,7 @@ export namespace SessionPrompt {
|
||||||
reasoning: 0,
|
reasoning: 0,
|
||||||
cache: { read: 0, write: 0 },
|
cache: { read: 0, write: 0 },
|
||||||
},
|
},
|
||||||
modelID: model.modelID,
|
modelID: model.id,
|
||||||
providerID: model.providerID,
|
providerID: model.providerID,
|
||||||
time: {
|
time: {
|
||||||
created: Date.now(),
|
created: Date.now(),
|
||||||
|
|
@ -408,7 +408,7 @@ export namespace SessionPrompt {
|
||||||
agent: lastUser.agent,
|
agent: lastUser.agent,
|
||||||
model: {
|
model: {
|
||||||
providerID: model.providerID,
|
providerID: model.providerID,
|
||||||
modelID: model.modelID,
|
modelID: model.id,
|
||||||
},
|
},
|
||||||
sessionID,
|
sessionID,
|
||||||
auto: task.auto,
|
auto: task.auto,
|
||||||
|
|
@ -421,7 +421,7 @@ export namespace SessionPrompt {
|
||||||
if (
|
if (
|
||||||
lastFinished &&
|
lastFinished &&
|
||||||
lastFinished.summary !== true &&
|
lastFinished.summary !== true &&
|
||||||
SessionCompaction.isOverflow({ tokens: lastFinished.tokens, model: model.info })
|
SessionCompaction.isOverflow({ tokens: lastFinished.tokens, model })
|
||||||
) {
|
) {
|
||||||
await SessionCompaction.create({
|
await SessionCompaction.create({
|
||||||
sessionID,
|
sessionID,
|
||||||
|
|
@ -455,7 +455,7 @@ export namespace SessionPrompt {
|
||||||
reasoning: 0,
|
reasoning: 0,
|
||||||
cache: { read: 0, write: 0 },
|
cache: { read: 0, write: 0 },
|
||||||
},
|
},
|
||||||
modelID: model.modelID,
|
modelID: model.id,
|
||||||
providerID: model.providerID,
|
providerID: model.providerID,
|
||||||
time: {
|
time: {
|
||||||
created: Date.now(),
|
created: Date.now(),
|
||||||
|
|
@ -463,21 +463,18 @@ export namespace SessionPrompt {
|
||||||
sessionID,
|
sessionID,
|
||||||
})) as MessageV2.Assistant,
|
})) as MessageV2.Assistant,
|
||||||
sessionID: sessionID,
|
sessionID: sessionID,
|
||||||
model: model.info,
|
model,
|
||||||
providerID: model.providerID,
|
|
||||||
abort,
|
abort,
|
||||||
})
|
})
|
||||||
const system = await resolveSystemPrompt({
|
const system = await resolveSystemPrompt({
|
||||||
providerID: model.providerID,
|
model,
|
||||||
model: model.info,
|
|
||||||
agent,
|
agent,
|
||||||
system: lastUser.system,
|
system: lastUser.system,
|
||||||
})
|
})
|
||||||
const tools = await resolveTools({
|
const tools = await resolveTools({
|
||||||
agent,
|
agent,
|
||||||
sessionID,
|
sessionID,
|
||||||
providerID: model.providerID,
|
model,
|
||||||
model: model.info,
|
|
||||||
tools: lastUser.tools,
|
tools: lastUser.tools,
|
||||||
processor,
|
processor,
|
||||||
})
|
})
|
||||||
|
|
@ -487,19 +484,19 @@ export namespace SessionPrompt {
|
||||||
{
|
{
|
||||||
sessionID: sessionID,
|
sessionID: sessionID,
|
||||||
agent: lastUser.agent,
|
agent: lastUser.agent,
|
||||||
model: model.info,
|
model: model,
|
||||||
provider,
|
provider,
|
||||||
message: lastUser,
|
message: lastUser,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
temperature: model.info.temperature
|
temperature: model.capabilities.temperature
|
||||||
? (agent.temperature ?? ProviderTransform.temperature(model.info))
|
? (agent.temperature ?? ProviderTransform.temperature(model))
|
||||||
: undefined,
|
: undefined,
|
||||||
topP: agent.topP ?? ProviderTransform.topP(model.info),
|
topP: agent.topP ?? ProviderTransform.topP(model),
|
||||||
options: pipe(
|
options: pipe(
|
||||||
{},
|
{},
|
||||||
mergeDeep(ProviderTransform.options(model.providerID, model.info, model.npm, sessionID, provider?.options)),
|
mergeDeep(ProviderTransform.options(model, sessionID, provider?.options)),
|
||||||
mergeDeep(model.info.options),
|
mergeDeep(model.options),
|
||||||
mergeDeep(agent.options),
|
mergeDeep(agent.options),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
@ -547,19 +544,19 @@ export namespace SessionPrompt {
|
||||||
"x-opencode-request": lastUser.id,
|
"x-opencode-request": lastUser.id,
|
||||||
}
|
}
|
||||||
: undefined),
|
: undefined),
|
||||||
...model.info.headers,
|
...model.headers,
|
||||||
},
|
},
|
||||||
// set to 0, we handle loop
|
// set to 0, we handle loop
|
||||||
maxRetries: 0,
|
maxRetries: 0,
|
||||||
activeTools: Object.keys(tools).filter((x) => x !== "invalid"),
|
activeTools: Object.keys(tools).filter((x) => x !== "invalid"),
|
||||||
maxOutputTokens: ProviderTransform.maxOutputTokens(
|
maxOutputTokens: ProviderTransform.maxOutputTokens(
|
||||||
model.providerID,
|
model.api.npm,
|
||||||
params.options,
|
params.options,
|
||||||
model.info.limit.output,
|
model.limit.output,
|
||||||
OUTPUT_TOKEN_MAX,
|
OUTPUT_TOKEN_MAX,
|
||||||
),
|
),
|
||||||
abortSignal: abort,
|
abortSignal: abort,
|
||||||
providerOptions: ProviderTransform.providerOptions(model.npm, model.providerID, params.options),
|
providerOptions: ProviderTransform.providerOptions(model.api.npm, model.providerID, params.options),
|
||||||
stopWhen: stepCountIs(1),
|
stopWhen: stepCountIs(1),
|
||||||
temperature: params.temperature,
|
temperature: params.temperature,
|
||||||
topP: params.topP,
|
topP: params.topP,
|
||||||
|
|
@ -586,9 +583,9 @@ export namespace SessionPrompt {
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
tools: model.info.tool_call === false ? undefined : tools,
|
tools: model.capabilities.toolcall === false ? undefined : tools,
|
||||||
model: wrapLanguageModel({
|
model: wrapLanguageModel({
|
||||||
model: model.language,
|
model: language,
|
||||||
middleware: [
|
middleware: [
|
||||||
{
|
{
|
||||||
async transformParams(args) {
|
async transformParams(args) {
|
||||||
|
|
@ -604,7 +601,7 @@ export namespace SessionPrompt {
|
||||||
// Transform the inputSchema for provider compatibility
|
// Transform the inputSchema for provider compatibility
|
||||||
return {
|
return {
|
||||||
...tool,
|
...tool,
|
||||||
inputSchema: ProviderTransform.schema(model.providerID, model.info, tool.inputSchema),
|
inputSchema: ProviderTransform.schema(model, tool.inputSchema),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If no inputSchema, return tool unchanged
|
// If no inputSchema, return tool unchanged
|
||||||
|
|
@ -639,13 +636,8 @@ export namespace SessionPrompt {
|
||||||
return Provider.defaultModel()
|
return Provider.defaultModel()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resolveSystemPrompt(input: {
|
async function resolveSystemPrompt(input: { system?: string; agent: Agent.Info; model: Provider.Model }) {
|
||||||
system?: string
|
let system = SystemPrompt.header(input.model.providerID)
|
||||||
agent: Agent.Info
|
|
||||||
providerID: string
|
|
||||||
model: ModelsDev.Model
|
|
||||||
}) {
|
|
||||||
let system = SystemPrompt.header(input.providerID)
|
|
||||||
system.push(
|
system.push(
|
||||||
...(() => {
|
...(() => {
|
||||||
if (input.system) return [input.system]
|
if (input.system) return [input.system]
|
||||||
|
|
@ -663,8 +655,7 @@ export namespace SessionPrompt {
|
||||||
|
|
||||||
async function resolveTools(input: {
|
async function resolveTools(input: {
|
||||||
agent: Agent.Info
|
agent: Agent.Info
|
||||||
providerID: string
|
model: Provider.Model
|
||||||
model: ModelsDev.Model
|
|
||||||
sessionID: string
|
sessionID: string
|
||||||
tools?: Record<string, boolean>
|
tools?: Record<string, boolean>
|
||||||
processor: SessionProcessor.Info
|
processor: SessionProcessor.Info
|
||||||
|
|
@ -675,9 +666,9 @@ export namespace SessionPrompt {
|
||||||
mergeDeep(await ToolRegistry.enabled(input.agent)),
|
mergeDeep(await ToolRegistry.enabled(input.agent)),
|
||||||
mergeDeep(input.tools ?? {}),
|
mergeDeep(input.tools ?? {}),
|
||||||
)
|
)
|
||||||
for (const item of await ToolRegistry.tools(input.providerID)) {
|
for (const item of await ToolRegistry.tools(input.model.providerID)) {
|
||||||
if (Wildcard.all(item.id, enabledTools) === false) continue
|
if (Wildcard.all(item.id, enabledTools) === false) continue
|
||||||
const schema = ProviderTransform.schema(input.providerID, input.model, z.toJSONSchema(item.parameters))
|
const schema = ProviderTransform.schema(input.model, z.toJSONSchema(item.parameters))
|
||||||
tools[item.id] = tool({
|
tools[item.id] = tool({
|
||||||
id: item.id as any,
|
id: item.id as any,
|
||||||
description: item.description,
|
description: item.description,
|
||||||
|
|
@ -1428,19 +1419,18 @@ export namespace SessionPrompt {
|
||||||
if (!isFirst) return
|
if (!isFirst) return
|
||||||
const small =
|
const small =
|
||||||
(await Provider.getSmallModel(input.providerID)) ?? (await Provider.getModel(input.providerID, input.modelID))
|
(await Provider.getSmallModel(input.providerID)) ?? (await Provider.getModel(input.providerID, input.modelID))
|
||||||
|
const language = await Provider.getLanguage(small)
|
||||||
const provider = await Provider.getProvider(small.providerID)
|
const provider = await Provider.getProvider(small.providerID)
|
||||||
const options = pipe(
|
const options = pipe(
|
||||||
{},
|
{},
|
||||||
mergeDeep(
|
mergeDeep(ProviderTransform.options(small, input.session.id, provider?.options)),
|
||||||
ProviderTransform.options(small.providerID, small.info, small.npm ?? "", input.session.id, provider?.options),
|
mergeDeep(ProviderTransform.smallOptions(small)),
|
||||||
),
|
mergeDeep(small.options),
|
||||||
mergeDeep(ProviderTransform.smallOptions({ providerID: small.providerID, model: small.info })),
|
|
||||||
mergeDeep(small.info.options),
|
|
||||||
)
|
)
|
||||||
await generateText({
|
await generateText({
|
||||||
// use higher # for reasoning models since reasoning tokens eat up a lot of the budget
|
// use higher # for reasoning models since reasoning tokens eat up a lot of the budget
|
||||||
maxOutputTokens: small.info.reasoning ? 3000 : 20,
|
maxOutputTokens: small.capabilities.reasoning ? 3000 : 20,
|
||||||
providerOptions: ProviderTransform.providerOptions(small.npm, small.providerID, options),
|
providerOptions: ProviderTransform.providerOptions(small.api.npm, small.providerID, options),
|
||||||
messages: [
|
messages: [
|
||||||
...SystemPrompt.title(small.providerID).map(
|
...SystemPrompt.title(small.providerID).map(
|
||||||
(x): ModelMessage => ({
|
(x): ModelMessage => ({
|
||||||
|
|
@ -1471,8 +1461,8 @@ export namespace SessionPrompt {
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
headers: small.info.headers,
|
headers: small.headers,
|
||||||
model: small.language,
|
model: language,
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
if (result.text)
|
if (result.text)
|
||||||
|
|
@ -1489,7 +1479,7 @@ export namespace SessionPrompt {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
log.error("failed to generate title", { error, model: small.info.id })
|
log.error("failed to generate title", { error, model: small.id })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,19 +76,20 @@ export namespace SessionSummary {
|
||||||
const small =
|
const small =
|
||||||
(await Provider.getSmallModel(assistantMsg.providerID)) ??
|
(await Provider.getSmallModel(assistantMsg.providerID)) ??
|
||||||
(await Provider.getModel(assistantMsg.providerID, assistantMsg.modelID))
|
(await Provider.getModel(assistantMsg.providerID, assistantMsg.modelID))
|
||||||
|
const language = await Provider.getLanguage(small)
|
||||||
|
|
||||||
const options = pipe(
|
const options = pipe(
|
||||||
{},
|
{},
|
||||||
mergeDeep(ProviderTransform.options(small.providerID, small.info, small.npm ?? "", assistantMsg.sessionID)),
|
mergeDeep(ProviderTransform.options(small, assistantMsg.sessionID)),
|
||||||
mergeDeep(ProviderTransform.smallOptions({ providerID: small.providerID, model: small.info })),
|
mergeDeep(ProviderTransform.smallOptions(small)),
|
||||||
mergeDeep(small.info.options),
|
mergeDeep(small.options),
|
||||||
)
|
)
|
||||||
|
|
||||||
const textPart = msgWithParts.parts.find((p) => p.type === "text" && !p.synthetic) as MessageV2.TextPart
|
const textPart = msgWithParts.parts.find((p) => p.type === "text" && !p.synthetic) as MessageV2.TextPart
|
||||||
if (textPart && !userMsg.summary?.title) {
|
if (textPart && !userMsg.summary?.title) {
|
||||||
const result = await generateText({
|
const result = await generateText({
|
||||||
maxOutputTokens: small.info.reasoning ? 1500 : 20,
|
maxOutputTokens: small.capabilities.reasoning ? 1500 : 20,
|
||||||
providerOptions: ProviderTransform.providerOptions(small.npm, small.providerID, options),
|
providerOptions: ProviderTransform.providerOptions(small.api.npm, small.providerID, options),
|
||||||
messages: [
|
messages: [
|
||||||
...SystemPrompt.title(small.providerID).map(
|
...SystemPrompt.title(small.providerID).map(
|
||||||
(x): ModelMessage => ({
|
(x): ModelMessage => ({
|
||||||
|
|
@ -106,8 +107,8 @@ export namespace SessionSummary {
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
headers: small.info.headers,
|
headers: small.headers,
|
||||||
model: small.language,
|
model: language,
|
||||||
})
|
})
|
||||||
log.info("title", { title: result.text })
|
log.info("title", { title: result.text })
|
||||||
userMsg.summary.title = result.text
|
userMsg.summary.title = result.text
|
||||||
|
|
@ -132,9 +133,9 @@ export namespace SessionSummary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const result = await generateText({
|
const result = await generateText({
|
||||||
model: small.language,
|
model: language,
|
||||||
maxOutputTokens: 100,
|
maxOutputTokens: 100,
|
||||||
providerOptions: ProviderTransform.providerOptions(small.npm, small.providerID, options),
|
providerOptions: ProviderTransform.providerOptions(small.api.npm, small.providerID, options),
|
||||||
messages: [
|
messages: [
|
||||||
...SystemPrompt.summarize(small.providerID).map(
|
...SystemPrompt.summarize(small.providerID).map(
|
||||||
(x): ModelMessage => ({
|
(x): ModelMessage => ({
|
||||||
|
|
@ -148,7 +149,7 @@ export namespace SessionSummary {
|
||||||
content: `Summarize the above conversation according to your system prompts.`,
|
content: `Summarize the above conversation according to your system prompts.`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
headers: small.info.headers,
|
headers: small.headers,
|
||||||
}).catch(() => {})
|
}).catch(() => {})
|
||||||
if (result) summary = result.text
|
if (result) summary = result.text
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import PROMPT_COMPACTION from "./prompt/compaction.txt"
|
||||||
import PROMPT_SUMMARIZE from "./prompt/summarize.txt"
|
import PROMPT_SUMMARIZE from "./prompt/summarize.txt"
|
||||||
import PROMPT_TITLE from "./prompt/title.txt"
|
import PROMPT_TITLE from "./prompt/title.txt"
|
||||||
import PROMPT_CODEX from "./prompt/codex.txt"
|
import PROMPT_CODEX from "./prompt/codex.txt"
|
||||||
import type { ModelsDev } from "@/provider/models"
|
import type { Provider } from "@/provider/provider"
|
||||||
|
|
||||||
export namespace SystemPrompt {
|
export namespace SystemPrompt {
|
||||||
export function header(providerID: string) {
|
export function header(providerID: string) {
|
||||||
|
|
@ -25,13 +25,13 @@ export namespace SystemPrompt {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
export function provider(model: ModelsDev.Model) {
|
export function provider(model: Provider.Model) {
|
||||||
if (model.target.includes("gpt-5")) return [PROMPT_CODEX]
|
if (model.api.id.includes("gpt-5")) return [PROMPT_CODEX]
|
||||||
if (model.target.includes("gpt-") || model.target.includes("o1") || model.target.includes("o3"))
|
if (model.api.id.includes("gpt-") || model.api.id.includes("o1") || model.api.id.includes("o3"))
|
||||||
return [PROMPT_BEAST]
|
return [PROMPT_BEAST]
|
||||||
if (model.target.includes("gemini-")) return [PROMPT_GEMINI]
|
if (model.api.id.includes("gemini-")) return [PROMPT_GEMINI]
|
||||||
if (model.target.includes("claude")) return [PROMPT_ANTHROPIC]
|
if (model.api.id.includes("claude")) return [PROMPT_ANTHROPIC]
|
||||||
if (model.target.includes("polaris-alpha")) return [PROMPT_POLARIS]
|
if (model.api.id.includes("polaris-alpha")) return [PROMPT_POLARIS]
|
||||||
return [PROMPT_ANTHROPIC_WITHOUT_TODO]
|
return [PROMPT_ANTHROPIC_WITHOUT_TODO]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { Bus } from "@/bus"
|
import { Bus } from "@/bus"
|
||||||
import { Config } from "@/config/config"
|
import { Config } from "@/config/config"
|
||||||
import { ulid } from "ulid"
|
import { ulid } from "ulid"
|
||||||
import type { ModelsDev } from "@/provider/models"
|
|
||||||
import { Provider } from "@/provider/provider"
|
import { Provider } from "@/provider/provider"
|
||||||
import { Session } from "@/session"
|
import { Session } from "@/session"
|
||||||
import { MessageV2 } from "@/session/message-v2"
|
import { MessageV2 } from "@/session/message-v2"
|
||||||
|
|
@ -36,7 +35,7 @@ export namespace ShareNext {
|
||||||
type: "model",
|
type: "model",
|
||||||
data: [
|
data: [
|
||||||
await Provider.getModel(evt.properties.info.model.providerID, evt.properties.info.model.modelID).then(
|
await Provider.getModel(evt.properties.info.model.providerID, evt.properties.info.model.modelID).then(
|
||||||
(m) => m.info,
|
(m) => m,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
@ -105,7 +104,7 @@ export namespace ShareNext {
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: "model"
|
type: "model"
|
||||||
data: ModelsDev.Model[]
|
data: SDK.Model[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const queue = new Map<string, { timeout: NodeJS.Timeout; data: Map<string, Data> }>()
|
const queue = new Map<string, { timeout: NodeJS.Timeout; data: Map<string, Data> }>()
|
||||||
|
|
@ -171,7 +170,7 @@ export namespace ShareNext {
|
||||||
messages
|
messages
|
||||||
.filter((m) => m.info.role === "user")
|
.filter((m) => m.info.role === "user")
|
||||||
.map((m) => (m.info as SDK.UserMessage).model)
|
.map((m) => (m.info as SDK.UserMessage).model)
|
||||||
.map((m) => Provider.getModel(m.providerID, m.modelID).then((m) => m.info)),
|
.map((m) => Provider.getModel(m.providerID, m.modelID).then((m) => m)),
|
||||||
)
|
)
|
||||||
await sync(sessionID, [
|
await sync(sessionID, [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ export const ReadTool = Tool.define("read", {
|
||||||
const modelID = ctx.extra["modelID"] as string
|
const modelID = ctx.extra["modelID"] as string
|
||||||
const model = await Provider.getModel(providerID, modelID).catch(() => undefined)
|
const model = await Provider.getModel(providerID, modelID).catch(() => undefined)
|
||||||
if (!model) return false
|
if (!model) return false
|
||||||
return model.info.modalities?.input?.includes("image") ?? false
|
return model.capabilities.input.image
|
||||||
})()
|
})()
|
||||||
if (isImage) {
|
if (isImage) {
|
||||||
if (!supportsImages) {
|
if (!supportsImages) {
|
||||||
|
|
|
||||||
|
|
@ -942,6 +942,76 @@ export type AgentConfig = {
|
||||||
| undefined
|
| undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ProviderConfig = {
|
||||||
|
api?: string
|
||||||
|
name?: string
|
||||||
|
env?: Array<string>
|
||||||
|
id?: string
|
||||||
|
npm?: string
|
||||||
|
models?: {
|
||||||
|
[key: string]: {
|
||||||
|
id?: string
|
||||||
|
name?: string
|
||||||
|
target?: string
|
||||||
|
release_date?: string
|
||||||
|
attachment?: boolean
|
||||||
|
reasoning?: boolean
|
||||||
|
temperature?: boolean
|
||||||
|
tool_call?: boolean
|
||||||
|
cost?: {
|
||||||
|
input: number
|
||||||
|
output: number
|
||||||
|
cache_read?: number
|
||||||
|
cache_write?: number
|
||||||
|
context_over_200k?: {
|
||||||
|
input: number
|
||||||
|
output: number
|
||||||
|
cache_read?: number
|
||||||
|
cache_write?: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
limit?: {
|
||||||
|
context: number
|
||||||
|
output: number
|
||||||
|
}
|
||||||
|
modalities?: {
|
||||||
|
input: Array<"text" | "audio" | "image" | "video" | "pdf">
|
||||||
|
output: Array<"text" | "audio" | "image" | "video" | "pdf">
|
||||||
|
}
|
||||||
|
experimental?: boolean
|
||||||
|
status?: "alpha" | "beta" | "deprecated"
|
||||||
|
options?: {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
headers?: {
|
||||||
|
[key: string]: string
|
||||||
|
}
|
||||||
|
provider?: {
|
||||||
|
npm: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
whitelist?: Array<string>
|
||||||
|
blacklist?: Array<string>
|
||||||
|
options?: {
|
||||||
|
apiKey?: string
|
||||||
|
baseURL?: string
|
||||||
|
/**
|
||||||
|
* GitHub Enterprise URL for copilot authentication
|
||||||
|
*/
|
||||||
|
enterpriseUrl?: string
|
||||||
|
/**
|
||||||
|
* Enable promptCacheKey for this provider (default false)
|
||||||
|
*/
|
||||||
|
setCacheKey?: boolean
|
||||||
|
/**
|
||||||
|
* Timeout in milliseconds for requests to this provider. Default is 300000 (5 minutes). Set to false to disable timeout.
|
||||||
|
*/
|
||||||
|
timeout?: number | false
|
||||||
|
[key: string]: unknown | string | boolean | (number | false) | undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export type McpLocalConfig = {
|
export type McpLocalConfig = {
|
||||||
/**
|
/**
|
||||||
* Type of MCP server connection
|
* Type of MCP server connection
|
||||||
|
|
@ -1100,75 +1170,7 @@ export type Config = {
|
||||||
* Custom provider configurations and model overrides
|
* Custom provider configurations and model overrides
|
||||||
*/
|
*/
|
||||||
provider?: {
|
provider?: {
|
||||||
[key: string]: {
|
[key: string]: ProviderConfig
|
||||||
api?: string
|
|
||||||
name?: string
|
|
||||||
env?: Array<string>
|
|
||||||
id?: string
|
|
||||||
npm?: string
|
|
||||||
models?: {
|
|
||||||
[key: string]: {
|
|
||||||
id?: string
|
|
||||||
name?: string
|
|
||||||
target?: string
|
|
||||||
release_date?: string
|
|
||||||
attachment?: boolean
|
|
||||||
reasoning?: boolean
|
|
||||||
temperature?: boolean
|
|
||||||
tool_call?: boolean
|
|
||||||
cost?: {
|
|
||||||
input: number
|
|
||||||
output: number
|
|
||||||
cache_read?: number
|
|
||||||
cache_write?: number
|
|
||||||
context_over_200k?: {
|
|
||||||
input: number
|
|
||||||
output: number
|
|
||||||
cache_read?: number
|
|
||||||
cache_write?: number
|
|
||||||
}
|
|
||||||
}
|
|
||||||
limit?: {
|
|
||||||
context: number
|
|
||||||
output: number
|
|
||||||
}
|
|
||||||
modalities?: {
|
|
||||||
input: Array<"text" | "audio" | "image" | "video" | "pdf">
|
|
||||||
output: Array<"text" | "audio" | "image" | "video" | "pdf">
|
|
||||||
}
|
|
||||||
experimental?: boolean
|
|
||||||
status?: "alpha" | "beta" | "deprecated"
|
|
||||||
options?: {
|
|
||||||
[key: string]: unknown
|
|
||||||
}
|
|
||||||
headers?: {
|
|
||||||
[key: string]: string
|
|
||||||
}
|
|
||||||
provider?: {
|
|
||||||
npm: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
whitelist?: Array<string>
|
|
||||||
blacklist?: Array<string>
|
|
||||||
options?: {
|
|
||||||
apiKey?: string
|
|
||||||
baseURL?: string
|
|
||||||
/**
|
|
||||||
* GitHub Enterprise URL for copilot authentication
|
|
||||||
*/
|
|
||||||
enterpriseUrl?: string
|
|
||||||
/**
|
|
||||||
* Enable promptCacheKey for this provider (default false)
|
|
||||||
*/
|
|
||||||
setCacheKey?: boolean
|
|
||||||
/**
|
|
||||||
* Timeout in milliseconds for requests to this provider. Default is 300000 (5 minutes). Set to false to disable timeout.
|
|
||||||
*/
|
|
||||||
timeout?: number | false
|
|
||||||
[key: string]: unknown | string | boolean | (number | false) | undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* MCP (Model Context Protocol) server configurations
|
* MCP (Model Context Protocol) server configurations
|
||||||
|
|
@ -1355,52 +1357,71 @@ export type Command = {
|
||||||
|
|
||||||
export type Model = {
|
export type Model = {
|
||||||
id: string
|
id: string
|
||||||
|
providerID: string
|
||||||
|
api: {
|
||||||
|
id: string
|
||||||
|
url: string
|
||||||
|
npm: string
|
||||||
|
}
|
||||||
name: string
|
name: string
|
||||||
target: string
|
capabilities: {
|
||||||
release_date: string
|
temperature: boolean
|
||||||
attachment: boolean
|
reasoning: boolean
|
||||||
reasoning: boolean
|
attachment: boolean
|
||||||
temperature: boolean
|
toolcall: boolean
|
||||||
tool_call: boolean
|
input: {
|
||||||
|
text: boolean
|
||||||
|
audio: boolean
|
||||||
|
image: boolean
|
||||||
|
video: boolean
|
||||||
|
pdf: boolean
|
||||||
|
}
|
||||||
|
output: {
|
||||||
|
text: boolean
|
||||||
|
audio: boolean
|
||||||
|
image: boolean
|
||||||
|
video: boolean
|
||||||
|
pdf: boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
cost: {
|
cost: {
|
||||||
input: number
|
input: number
|
||||||
output: number
|
output: number
|
||||||
cache_read?: number
|
cache: {
|
||||||
cache_write?: number
|
read: number
|
||||||
context_over_200k?: {
|
write: number
|
||||||
|
}
|
||||||
|
experimentalOver200K?: {
|
||||||
input: number
|
input: number
|
||||||
output: number
|
output: number
|
||||||
cache_read?: number
|
cache: {
|
||||||
cache_write?: number
|
read: number
|
||||||
|
write: number
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
limit: {
|
limit: {
|
||||||
context: number
|
context: number
|
||||||
output: number
|
output: number
|
||||||
}
|
}
|
||||||
modalities?: {
|
status: "alpha" | "beta" | "deprecated" | "active"
|
||||||
input: Array<"text" | "audio" | "image" | "video" | "pdf">
|
|
||||||
output: Array<"text" | "audio" | "image" | "video" | "pdf">
|
|
||||||
}
|
|
||||||
experimental?: boolean
|
|
||||||
status?: "alpha" | "beta" | "deprecated"
|
|
||||||
options: {
|
options: {
|
||||||
[key: string]: unknown
|
[key: string]: unknown
|
||||||
}
|
}
|
||||||
headers?: {
|
headers: {
|
||||||
[key: string]: string
|
[key: string]: string
|
||||||
}
|
}
|
||||||
provider?: {
|
|
||||||
npm: string
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Provider = {
|
export type Provider = {
|
||||||
api?: string
|
|
||||||
name: string
|
|
||||||
env: Array<string>
|
|
||||||
id: string
|
id: string
|
||||||
npm?: string
|
name: string
|
||||||
|
source: "env" | "config" | "custom" | "api"
|
||||||
|
env: Array<string>
|
||||||
|
key?: string
|
||||||
|
options: {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
models: {
|
models: {
|
||||||
[key: string]: Model
|
[key: string]: Model
|
||||||
}
|
}
|
||||||
|
|
@ -2667,7 +2688,56 @@ export type ProviderListResponses = {
|
||||||
* List of providers
|
* List of providers
|
||||||
*/
|
*/
|
||||||
200: {
|
200: {
|
||||||
all: Array<Provider>
|
all: Array<{
|
||||||
|
api?: string
|
||||||
|
name: string
|
||||||
|
env: Array<string>
|
||||||
|
id: string
|
||||||
|
npm?: string
|
||||||
|
models: {
|
||||||
|
[key: string]: {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
target: string
|
||||||
|
release_date: string
|
||||||
|
attachment: boolean
|
||||||
|
reasoning: boolean
|
||||||
|
temperature: boolean
|
||||||
|
tool_call: boolean
|
||||||
|
cost: {
|
||||||
|
input: number
|
||||||
|
output: number
|
||||||
|
cache_read?: number
|
||||||
|
cache_write?: number
|
||||||
|
context_over_200k?: {
|
||||||
|
input: number
|
||||||
|
output: number
|
||||||
|
cache_read?: number
|
||||||
|
cache_write?: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
limit: {
|
||||||
|
context: number
|
||||||
|
output: number
|
||||||
|
}
|
||||||
|
modalities?: {
|
||||||
|
input: Array<"text" | "audio" | "image" | "video" | "pdf">
|
||||||
|
output: Array<"text" | "audio" | "image" | "video" | "pdf">
|
||||||
|
}
|
||||||
|
experimental?: boolean
|
||||||
|
status?: "alpha" | "beta" | "deprecated"
|
||||||
|
options: {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
headers?: {
|
||||||
|
[key: string]: string
|
||||||
|
}
|
||||||
|
provider?: {
|
||||||
|
npm: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}>
|
||||||
default: {
|
default: {
|
||||||
[key: string]: string
|
[key: string]: string
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue