fix(core): derive models.dev reasoning variants (#34726)
This commit is contained in:
parent
cfd35c9354
commit
140224b0fc
29 changed files with 457 additions and 119 deletions
|
|
@ -151,6 +151,7 @@ export type AgentListOutput = {
|
||||||
readonly id: string
|
readonly id: string
|
||||||
readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string }
|
readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string }
|
||||||
readonly request: {
|
readonly request: {
|
||||||
|
readonly settings: { readonly [x: string]: JsonValue }
|
||||||
readonly headers: { readonly [x: string]: string }
|
readonly headers: { readonly [x: string]: string }
|
||||||
readonly body: { readonly [x: string]: JsonValue }
|
readonly body: { readonly [x: string]: JsonValue }
|
||||||
}
|
}
|
||||||
|
|
@ -2192,12 +2193,14 @@ export type ModelListOutput = {
|
||||||
readonly output: ReadonlyArray<string>
|
readonly output: ReadonlyArray<string>
|
||||||
}
|
}
|
||||||
readonly request: {
|
readonly request: {
|
||||||
|
readonly settings: { readonly [x: string]: JsonValue }
|
||||||
readonly headers: { readonly [x: string]: string }
|
readonly headers: { readonly [x: string]: string }
|
||||||
readonly body: { readonly [x: string]: JsonValue }
|
readonly body: { readonly [x: string]: JsonValue }
|
||||||
readonly variant?: string
|
readonly variant?: string
|
||||||
}
|
}
|
||||||
readonly variants: ReadonlyArray<{
|
readonly variants: ReadonlyArray<{
|
||||||
readonly id: string
|
readonly id: string
|
||||||
|
readonly settings: { readonly [x: string]: JsonValue }
|
||||||
readonly headers: { readonly [x: string]: string }
|
readonly headers: { readonly [x: string]: string }
|
||||||
readonly body: { readonly [x: string]: JsonValue }
|
readonly body: { readonly [x: string]: JsonValue }
|
||||||
}>
|
}>
|
||||||
|
|
@ -2256,6 +2259,7 @@ export type ProviderListOutput = {
|
||||||
}
|
}
|
||||||
| { readonly type: "native"; readonly url?: string; readonly settings: { readonly [x: string]: JsonValue } }
|
| { readonly type: "native"; readonly url?: string; readonly settings: { readonly [x: string]: JsonValue } }
|
||||||
readonly request: {
|
readonly request: {
|
||||||
|
readonly settings: { readonly [x: string]: JsonValue }
|
||||||
readonly headers: { readonly [x: string]: string }
|
readonly headers: { readonly [x: string]: string }
|
||||||
readonly body: { readonly [x: string]: JsonValue }
|
readonly body: { readonly [x: string]: JsonValue }
|
||||||
}
|
}
|
||||||
|
|
@ -2289,6 +2293,7 @@ export type ProviderGetOutput = {
|
||||||
}
|
}
|
||||||
| { readonly type: "native"; readonly url?: string; readonly settings: { readonly [x: string]: JsonValue } }
|
| { readonly type: "native"; readonly url?: string; readonly settings: { readonly [x: string]: JsonValue } }
|
||||||
readonly request: {
|
readonly request: {
|
||||||
|
readonly settings: { readonly [x: string]: JsonValue }
|
||||||
readonly headers: { readonly [x: string]: string }
|
readonly headers: { readonly [x: string]: string }
|
||||||
readonly body: { readonly [x: string]: JsonValue }
|
readonly body: { readonly [x: string]: JsonValue }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,7 @@ const layer = Layer.effect(
|
||||||
? { ...model.api, settings: { ...provider.api.settings, ...model.api.settings } }
|
? { ...model.api, settings: { ...provider.api.settings, ...model.api.settings } }
|
||||||
: model.api
|
: model.api
|
||||||
const request = {
|
const request = {
|
||||||
|
settings: { ...provider.request.settings, ...model.request.settings },
|
||||||
headers: { ...provider.request.headers, ...model.request.headers },
|
headers: { ...provider.request.headers, ...model.request.headers },
|
||||||
body: { ...provider.request.body, ...model.request.body },
|
body: { ...provider.request.body, ...model.request.body },
|
||||||
variant: model.request.variant,
|
variant: model.request.variant,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import { define } from "../../plugin/internal"
|
||||||
import { Effect } from "effect"
|
import { Effect } from "effect"
|
||||||
import { Config } from "../../config"
|
import { Config } from "../../config"
|
||||||
import { ModelV2 } from "../../model"
|
import { ModelV2 } from "../../model"
|
||||||
import { ProviderV2 } from "../../provider"
|
|
||||||
|
|
||||||
export const Plugin = define({
|
export const Plugin = define({
|
||||||
id: "config-provider",
|
id: "config-provider",
|
||||||
|
|
@ -54,6 +53,7 @@ export const Plugin = define({
|
||||||
if (item.name !== undefined) provider.name = item.name
|
if (item.name !== undefined) provider.name = item.name
|
||||||
if (item.api !== undefined) provider.api = { ...item.api }
|
if (item.api !== undefined) provider.api = { ...item.api }
|
||||||
if (item.request !== undefined) {
|
if (item.request !== undefined) {
|
||||||
|
Object.assign(provider.request.settings, item.request.settings)
|
||||||
Object.assign(provider.request.headers, item.request.headers)
|
Object.assign(provider.request.headers, item.request.headers)
|
||||||
Object.assign(provider.request.body, item.request.body)
|
Object.assign(provider.request.body, item.request.body)
|
||||||
}
|
}
|
||||||
|
|
@ -71,6 +71,7 @@ export const Plugin = define({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (config.request !== undefined) {
|
if (config.request !== undefined) {
|
||||||
|
Object.assign(model.request.settings, config.request.settings)
|
||||||
Object.assign(model.request.headers, config.request.headers)
|
Object.assign(model.request.headers, config.request.headers)
|
||||||
Object.assign(model.request.body, config.request.body)
|
Object.assign(model.request.body, config.request.body)
|
||||||
if (config.request.variant !== undefined) model.request.variant = config.request.variant
|
if (config.request.variant !== undefined) model.request.variant = config.request.variant
|
||||||
|
|
@ -81,11 +82,13 @@ export const Plugin = define({
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
existing = {
|
existing = {
|
||||||
id: variant.id,
|
id: variant.id,
|
||||||
|
settings: {},
|
||||||
headers: {},
|
headers: {},
|
||||||
body: {},
|
body: {},
|
||||||
}
|
}
|
||||||
model.variants.push(existing)
|
model.variants.push(existing)
|
||||||
}
|
}
|
||||||
|
Object.assign(existing.settings, variant.settings)
|
||||||
Object.assign(existing.headers, variant.headers)
|
Object.assign(existing.headers, variant.headers)
|
||||||
Object.assign(existing.body, variant.body)
|
Object.assign(existing.body, variant.body)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { ProviderV2 } from "../provider"
|
||||||
import { ModelV2 } from "../model"
|
import { ModelV2 } from "../model"
|
||||||
|
|
||||||
export class Request extends Schema.Class<Request>("ConfigV2.Provider.Request")({
|
export class Request extends Schema.Class<Request>("ConfigV2.Provider.Request")({
|
||||||
|
settings: ProviderV2.Settings.pipe(Schema.optional),
|
||||||
headers: Schema.Record(Schema.String, Schema.String).pipe(Schema.optional),
|
headers: Schema.Record(Schema.String, Schema.String).pipe(Schema.optional),
|
||||||
body: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
|
body: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
|
||||||
}) {}
|
}) {}
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,13 @@ export type Api = Model.Api
|
||||||
export const Info = Model.Info
|
export const Info = Model.Info
|
||||||
export type Info = Model.Info
|
export type Info = Model.Info
|
||||||
|
|
||||||
export type MutableInfo = Omit<Types.DeepMutable<Info>, "api"> & {
|
export type MutableRequest = ProviderV2.MutableRequest & { variant?: string }
|
||||||
|
export type MutableVariant = ProviderV2.MutableRequest & { id: VariantID }
|
||||||
|
|
||||||
|
export type MutableInfo = Omit<Types.DeepMutable<Info>, "api" | "request" | "variants"> & {
|
||||||
api: ProviderV2.MutableApi<Api>
|
api: ProviderV2.MutableApi<Api>
|
||||||
|
request: MutableRequest
|
||||||
|
variants: MutableVariant[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parse(input: string): { providerID: ProviderV2.ID; modelID: ID } {
|
export function parse(input: string): { providerID: ProviderV2.ID; modelID: ID } {
|
||||||
|
|
|
||||||
|
|
@ -70,25 +70,73 @@ function mergeCost(base: ModelV2Info["cost"], override: ModelsDev.Model["cost"]
|
||||||
return [merge(baseDefault ?? { input: 0, output: 0, cache: { read: 0, write: 0 } }, nextDefault), ...tiers.values()]
|
return [merge(baseDefault ?? { input: 0, output: 0, cache: { read: 0, write: 0 } }, nextDefault), ...tiers.values()]
|
||||||
}
|
}
|
||||||
|
|
||||||
function reasoningVariants(model: ModelsDev.Model, packageName: string | undefined): ModelV2Info["variants"] {
|
const OPENAI_INCLUDE_ENCRYPTED_REASONING = ["reasoning.encrypted_content"]
|
||||||
const result = new Map<ModelV2.VariantID, ModelV2Info["variants"][number]>()
|
|
||||||
if (packageName === "@ai-sdk/openai" || packageName === "@ai-sdk/openai-compatible") {
|
function reasoningVariants(provider: ModelsDev.Provider, model: ModelsDev.Model): ModelV2Info["variants"] {
|
||||||
const option = model.reasoning_options?.find((option) => option.type === "effort")
|
const npm = model.provider?.npm ?? provider.npm
|
||||||
for (const value of option?.values ?? []) {
|
const options = model.reasoning_options ?? []
|
||||||
const id = value === null ? "none" : value
|
const effort = options.find((option) => option.type === "effort")
|
||||||
if (typeof id !== "string") continue
|
if (effort?.type === "effort") {
|
||||||
const variantID = ModelV2.VariantID.make(id)
|
return effort.values.flatMap((value) => {
|
||||||
result.set(variantID, {
|
const raw: unknown = value
|
||||||
id: variantID,
|
const id = raw === null ? "none" : typeof raw === "string" ? raw : undefined
|
||||||
headers: {},
|
if (id === undefined) return []
|
||||||
body:
|
const settings = settingsForEffort(npm, id)
|
||||||
packageName === "@ai-sdk/openai"
|
return settings ? [{ id, settings, headers: {}, body: {} }] : []
|
||||||
? { include: ["reasoning.encrypted_content"], reasoning: { effort: id, summary: "auto" } }
|
})
|
||||||
: { reasoning_effort: id },
|
}
|
||||||
})
|
|
||||||
|
const budget = options.find((option) => option.type === "budget_tokens")
|
||||||
|
if (budget?.type === "budget_tokens") return budgetVariants(npm, budget)
|
||||||
|
|
||||||
|
// Toggle-only reasoning is intentionally left for a follow-up because V1 has
|
||||||
|
// provider/model-specific behavior like MiniMax M3 adaptive thinking and
|
||||||
|
// Qwen/GLM enable_thinking request shapes in packages/opencode.
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
function settingsForEffort(npm: string | undefined, effort: string): ProviderV2.Settings | undefined {
|
||||||
|
if (npm === "@openrouter/ai-sdk-provider") return { reasoning: { effort } }
|
||||||
|
if (npm === "@ai-sdk/anthropic" || npm === "@ai-sdk/google-vertex/anthropic") {
|
||||||
|
return { thinking: { type: "adaptive", display: "summarized" }, effort }
|
||||||
|
}
|
||||||
|
if (npm === "@ai-sdk/google" || npm === "@ai-sdk/google-vertex") {
|
||||||
|
return { thinkingConfig: { includeThoughts: true, thinkingLevel: effort } }
|
||||||
|
}
|
||||||
|
if (npm === "@ai-sdk/azure") return { reasoningEffort: effort }
|
||||||
|
if (npm === "@ai-sdk/openai") {
|
||||||
|
return {
|
||||||
|
reasoningEffort: effort,
|
||||||
|
reasoningSummary: "auto",
|
||||||
|
include: OPENAI_INCLUDE_ENCRYPTED_REASONING,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [...result.values()]
|
if (npm === "@ai-sdk/openai-compatible") return { reasoningEffort: effort }
|
||||||
|
}
|
||||||
|
|
||||||
|
function budgetVariants(
|
||||||
|
npm: string | undefined,
|
||||||
|
option: Extract<NonNullable<ModelsDev.Model["reasoning_options"]>[number], { type: "budget_tokens" }>,
|
||||||
|
): ModelV2Info["variants"] {
|
||||||
|
const max = option.max
|
||||||
|
const high = option.max === undefined ? Math.max(option.min ?? 0, 16_000) : Math.min(Math.max(option.min ?? 0, 16_000), option.max)
|
||||||
|
return [
|
||||||
|
{ id: "high", budget: high },
|
||||||
|
...(max === undefined || max === high ? [] : [{ id: "max", budget: max }]),
|
||||||
|
].flatMap((item) => {
|
||||||
|
const settings = settingsForBudget(npm, item.budget)
|
||||||
|
return settings ? [{ id: item.id, settings, headers: {}, body: {} }] : []
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function settingsForBudget(npm: string | undefined, budget: number): ProviderV2.Settings | undefined {
|
||||||
|
if (npm === "@openrouter/ai-sdk-provider") return { reasoning: { max_tokens: budget } }
|
||||||
|
if (npm === "@ai-sdk/anthropic" || npm === "@ai-sdk/google-vertex/anthropic") {
|
||||||
|
return { thinking: { type: "enabled", budgetTokens: budget } }
|
||||||
|
}
|
||||||
|
if (npm === "@ai-sdk/google" || npm === "@ai-sdk/google-vertex") {
|
||||||
|
return { thinkingConfig: { includeThoughts: true, thinkingBudget: budget } }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function modeName(model: ModelsDev.Model, mode: string) {
|
function modeName(model: ModelsDev.Model, mode: string) {
|
||||||
|
|
@ -193,7 +241,7 @@ export const ModelsDevPlugin = define({
|
||||||
|
|
||||||
for (const model of Object.values(item.models)) {
|
for (const model of Object.values(item.models)) {
|
||||||
const baseCost = cost(model.cost)
|
const baseCost = cost(model.cost)
|
||||||
const variants = reasoningVariants(model, model.provider?.npm ?? item.npm)
|
const variants = reasoningVariants(item, model)
|
||||||
catalog.model.update(providerID, model.id, (draft) => applyModel(draft, model, { cost: baseCost, variants }))
|
catalog.model.update(providerID, model.id, (draft) => applyModel(draft, model, { cost: baseCost, variants }))
|
||||||
for (const [mode, options] of Object.entries(model.experimental?.modes ?? {})) {
|
for (const [mode, options] of Object.entries(model.experimental?.modes ?? {})) {
|
||||||
catalog.model.update(providerID, `${model.id}-${mode}`, (draft) =>
|
catalog.model.update(providerID, `${model.id}-${mode}`, (draft) =>
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ export const OpencodePlugin = define<HttpClient.HttpClient | EventV2.Service | S
|
||||||
const variantID = ModelV2.VariantID.make(id)
|
const variantID = ModelV2.VariantID.make(id)
|
||||||
let existing = model.variants.find((item) => item.id === variantID)
|
let existing = model.variants.find((item) => item.id === variantID)
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
existing = { id: variantID, headers: {}, body: {} }
|
existing = { id: variantID, settings: {}, headers: {}, body: {} }
|
||||||
model.variants.push(existing)
|
model.variants.push(existing)
|
||||||
}
|
}
|
||||||
Object.assign(existing.headers, options.headers)
|
Object.assign(existing.headers, options.headers)
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,8 @@ export function generate(model: ModelV2Info): ModelV2Info["variants"] {
|
||||||
if (!["glm-5.2", "glm-5-2", "glm-5p2"].some((name) => ids.includes(name))) return []
|
if (!["glm-5.2", "glm-5-2", "glm-5p2"].some((name) => ids.includes(name))) return []
|
||||||
return ["high", "max"].map((id) => ({
|
return ["high", "max"].map((id) => ({
|
||||||
id,
|
id,
|
||||||
|
settings: { reasoningEffort: id },
|
||||||
headers: {},
|
headers: {},
|
||||||
body: { reasoning_effort: id },
|
body: {},
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,15 @@ export type MutableApi<T extends Api = Api> = T extends Api
|
||||||
export const Request = Provider.Request
|
export const Request = Provider.Request
|
||||||
export type Request = Provider.Request
|
export type Request = Provider.Request
|
||||||
|
|
||||||
|
export const Settings = Provider.Settings
|
||||||
|
export type Settings = Provider.Settings
|
||||||
|
|
||||||
export const Info = Provider.Info
|
export const Info = Provider.Info
|
||||||
export type Info = Provider.Info
|
export type Info = Provider.Info
|
||||||
|
|
||||||
export type MutableInfo = Omit<Types.DeepMutable<Info>, "api"> & { api: MutableApi }
|
export type MutableRequest = Types.DeepMutable<Request>
|
||||||
|
|
||||||
|
export type MutableInfo = Omit<Types.DeepMutable<Info>, "api" | "request"> & {
|
||||||
|
api: MutableApi
|
||||||
|
request: MutableRequest
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -97,11 +97,20 @@ const withDefaults = (model: ModelV2.Info, route: AnyRoute) => {
|
||||||
provider: model.providerID,
|
provider: model.providerID,
|
||||||
endpoint: model.api.url === undefined ? undefined : { baseURL: model.api.url },
|
endpoint: model.api.url === undefined ? undefined : { baseURL: model.api.url },
|
||||||
headers: model.request.headers,
|
headers: model.request.headers,
|
||||||
|
providerOptions: providerOptions(model),
|
||||||
http: { body: httpBody },
|
http: { body: httpBody },
|
||||||
limits: { context: model.limit.context, output: model.limit.output },
|
limits: { context: model.limit.context, output: model.limit.output },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const providerOptions = (model: ModelV2.Info) => {
|
||||||
|
if (Object.keys(model.request.settings).length === 0) return undefined
|
||||||
|
if (model.api.type !== "aisdk") return undefined
|
||||||
|
if (model.api.package === "@ai-sdk/openai") return { openai: model.request.settings }
|
||||||
|
if (model.api.package === "@ai-sdk/anthropic") return { anthropic: model.request.settings }
|
||||||
|
if (model.api.package === "@ai-sdk/openai-compatible") return { openai: model.request.settings }
|
||||||
|
}
|
||||||
|
|
||||||
export const withVariant = (
|
export const withVariant = (
|
||||||
model: ModelV2.Info,
|
model: ModelV2.Info,
|
||||||
variantID: ModelV2.VariantID | undefined,
|
variantID: ModelV2.VariantID | undefined,
|
||||||
|
|
@ -119,6 +128,7 @@ export const withVariant = (
|
||||||
return Effect.succeed(
|
return Effect.succeed(
|
||||||
variant
|
variant
|
||||||
? produce(model, (draft) => {
|
? produce(model, (draft) => {
|
||||||
|
Object.assign(draft.request.settings, variant.settings)
|
||||||
Object.assign(draft.request.headers, variant.headers)
|
Object.assign(draft.request.headers, variant.headers)
|
||||||
Object.assign(draft.request.body, variant.body)
|
Object.assign(draft.request.body, variant.body)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
67
packages/core/test/plugin/fixtures/models-dev-reasoning.json
Normal file
67
packages/core/test/plugin/fixtures/models-dev-reasoning.json
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
{
|
||||||
|
"openai": {
|
||||||
|
"id": "openai",
|
||||||
|
"name": "OpenAI",
|
||||||
|
"env": ["OPENAI_API_KEY"],
|
||||||
|
"npm": "@ai-sdk/openai",
|
||||||
|
"api": "https://api.openai.com/v1",
|
||||||
|
"models": {
|
||||||
|
"gpt-reasoning": {
|
||||||
|
"id": "gpt-reasoning",
|
||||||
|
"name": "GPT Reasoning",
|
||||||
|
"release_date": "2026-01-01",
|
||||||
|
"attachment": false,
|
||||||
|
"reasoning": true,
|
||||||
|
"reasoning_options": [
|
||||||
|
{ "type": "effort", "values": ["low", "high"] },
|
||||||
|
{ "type": "budget_tokens", "min": 1024, "max": 64000 },
|
||||||
|
{ "type": "toggle" }
|
||||||
|
],
|
||||||
|
"temperature": true,
|
||||||
|
"tool_call": true,
|
||||||
|
"limit": { "context": 128000, "output": 8192 },
|
||||||
|
"experimental": {
|
||||||
|
"modes": {
|
||||||
|
"high": {
|
||||||
|
"provider": {
|
||||||
|
"headers": { "x-mode": "high" },
|
||||||
|
"body": { "service_tier": "priority" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"anthropic": {
|
||||||
|
"id": "anthropic",
|
||||||
|
"name": "Anthropic",
|
||||||
|
"env": ["ANTHROPIC_API_KEY"],
|
||||||
|
"npm": "@ai-sdk/anthropic",
|
||||||
|
"api": "https://api.anthropic.com/v1",
|
||||||
|
"models": {
|
||||||
|
"claude-budget": {
|
||||||
|
"id": "claude-budget",
|
||||||
|
"name": "Claude Budget",
|
||||||
|
"release_date": "2026-01-01",
|
||||||
|
"attachment": false,
|
||||||
|
"reasoning": true,
|
||||||
|
"reasoning_options": [{ "type": "budget_tokens", "min": 1024, "max": 64000 }],
|
||||||
|
"temperature": true,
|
||||||
|
"tool_call": true,
|
||||||
|
"limit": { "context": 128000, "output": 8192 }
|
||||||
|
},
|
||||||
|
"claude-effort": {
|
||||||
|
"id": "claude-effort",
|
||||||
|
"name": "Claude Effort",
|
||||||
|
"release_date": "2026-01-01",
|
||||||
|
"attachment": false,
|
||||||
|
"reasoning": true,
|
||||||
|
"reasoning_options": [{ "type": "effort", "values": ["low"] }],
|
||||||
|
"temperature": true,
|
||||||
|
"tool_call": true,
|
||||||
|
"limit": { "context": 128000, "output": 8192 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -288,7 +288,7 @@ function providerInfo(value: ProviderV2.MutableInfo) {
|
||||||
return {
|
return {
|
||||||
...value,
|
...value,
|
||||||
api: { ...value.api, settings: value.api.settings && { ...value.api.settings } },
|
api: { ...value.api, settings: value.api.settings && { ...value.api.settings } },
|
||||||
request: { headers: { ...value.request.headers }, body: { ...value.request.body } },
|
request: { settings: { ...value.request.settings }, headers: { ...value.request.headers }, body: { ...value.request.body } },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -303,11 +303,13 @@ function modelInfo(value: ModelV2.Info | ModelV2.MutableInfo) {
|
||||||
},
|
},
|
||||||
request: {
|
request: {
|
||||||
...value.request,
|
...value.request,
|
||||||
|
settings: { ...value.request.settings },
|
||||||
headers: { ...value.request.headers },
|
headers: { ...value.request.headers },
|
||||||
body: { ...value.request.body },
|
body: { ...value.request.body },
|
||||||
},
|
},
|
||||||
variants: value.variants.map((variant) => ({
|
variants: value.variants.map((variant) => ({
|
||||||
...variant,
|
...variant,
|
||||||
|
settings: { ...variant.settings },
|
||||||
headers: { ...variant.headers },
|
headers: { ...variant.headers },
|
||||||
body: { ...variant.body },
|
body: { ...variant.body },
|
||||||
})),
|
})),
|
||||||
|
|
|
||||||
|
|
@ -168,14 +168,14 @@ describe("ModelsDevPlugin", () => {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
it.effect("derives OpenAI reasoning variants from models.dev reasoning options", () =>
|
it.effect("converts reasoning options into settings variants", () =>
|
||||||
Effect.acquireUseRelease(
|
Effect.acquireUseRelease(
|
||||||
Effect.sync(() => {
|
Effect.sync(() => {
|
||||||
const previous = {
|
const previous = {
|
||||||
path: Flag.OPENCODE_MODELS_PATH,
|
path: Flag.OPENCODE_MODELS_PATH,
|
||||||
disabled: Flag.OPENCODE_DISABLE_MODELS_FETCH,
|
disabled: Flag.OPENCODE_DISABLE_MODELS_FETCH,
|
||||||
}
|
}
|
||||||
Flag.OPENCODE_MODELS_PATH = path.join(import.meta.dir, "fixtures", "models-dev.json")
|
Flag.OPENCODE_MODELS_PATH = path.join(import.meta.dir, "fixtures", "models-dev-reasoning.json")
|
||||||
Flag.OPENCODE_DISABLE_MODELS_FETCH = true
|
Flag.OPENCODE_DISABLE_MODELS_FETCH = true
|
||||||
return previous
|
return previous
|
||||||
}),
|
}),
|
||||||
|
|
@ -183,17 +183,6 @@ describe("ModelsDevPlugin", () => {
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const catalog = yield* Catalog.Service
|
const catalog = yield* Catalog.Service
|
||||||
const integrations = yield* Integration.Service
|
const integrations = yield* Integration.Service
|
||||||
yield* catalog.transform((catalog) => {
|
|
||||||
catalog.model.update(ProviderV2.ID.opencode, ModelV2.ID.make("gpt-5.5"), (model) => {
|
|
||||||
model.variants = [
|
|
||||||
{
|
|
||||||
id: ModelV2.VariantID.make("high"),
|
|
||||||
headers: { custom: "true" },
|
|
||||||
body: { custom: true },
|
|
||||||
},
|
|
||||||
]
|
|
||||||
})
|
|
||||||
})
|
|
||||||
yield* ModelsDevPlugin.effect(
|
yield* ModelsDevPlugin.effect(
|
||||||
host({
|
host({
|
||||||
catalog: catalogHost(catalog),
|
catalog: catalogHost(catalog),
|
||||||
|
|
@ -201,42 +190,67 @@ describe("ModelsDevPlugin", () => {
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
expect((yield* catalog.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("gpt-5.5")))?.variants).toEqual([
|
const model = yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-reasoning"))
|
||||||
{
|
expect(model?.variants.map((variant) => variant.id)).toEqual([
|
||||||
id: ModelV2.VariantID.make("none"),
|
ModelV2.VariantID.make("low"),
|
||||||
headers: {},
|
ModelV2.VariantID.make("high"),
|
||||||
body: {
|
|
||||||
include: ["reasoning.encrypted_content"],
|
|
||||||
reasoning: { effort: "none", summary: "auto" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "low",
|
|
||||||
body: {
|
|
||||||
include: ["reasoning.encrypted_content"],
|
|
||||||
reasoning: { effort: "low", summary: "auto" },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "medium",
|
|
||||||
body: {
|
|
||||||
include: ["reasoning.encrypted_content"],
|
|
||||||
reasoning: { effort: "medium", summary: "auto" },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "high",
|
|
||||||
headers: { custom: "true" },
|
|
||||||
body: { custom: true },
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "xhigh",
|
|
||||||
body: {
|
|
||||||
include: ["reasoning.encrypted_content"],
|
|
||||||
reasoning: { effort: "xhigh", summary: "auto" },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
])
|
])
|
||||||
|
expect(model?.variants).toContainEqual({
|
||||||
|
id: ModelV2.VariantID.make("low"),
|
||||||
|
settings: {
|
||||||
|
reasoningEffort: "low",
|
||||||
|
reasoningSummary: "auto",
|
||||||
|
include: ["reasoning.encrypted_content"],
|
||||||
|
},
|
||||||
|
headers: {},
|
||||||
|
body: {},
|
||||||
|
})
|
||||||
|
expect(model?.variants).toContainEqual({
|
||||||
|
id: ModelV2.VariantID.make("high"),
|
||||||
|
settings: {
|
||||||
|
reasoningEffort: "high",
|
||||||
|
reasoningSummary: "auto",
|
||||||
|
include: ["reasoning.encrypted_content"],
|
||||||
|
},
|
||||||
|
headers: {},
|
||||||
|
body: {},
|
||||||
|
})
|
||||||
|
|
||||||
|
const mode = yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-reasoning-high"))
|
||||||
|
expect(mode).toMatchObject({
|
||||||
|
id: "gpt-reasoning-high",
|
||||||
|
name: "GPT Reasoning High",
|
||||||
|
request: {
|
||||||
|
headers: { "x-mode": "high" },
|
||||||
|
body: { service_tier: "priority" },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
expect(mode?.variants.map((variant) => variant.id)).toEqual([
|
||||||
|
ModelV2.VariantID.make("low"),
|
||||||
|
ModelV2.VariantID.make("high"),
|
||||||
|
])
|
||||||
|
|
||||||
|
const budgetModel = yield* catalog.model.get(ProviderV2.ID.anthropic, ModelV2.ID.make("claude-budget"))
|
||||||
|
expect(budgetModel?.variants).toContainEqual({
|
||||||
|
id: ModelV2.VariantID.make("high"),
|
||||||
|
settings: { thinking: { type: "enabled", budgetTokens: 16000 } },
|
||||||
|
headers: {},
|
||||||
|
body: {},
|
||||||
|
})
|
||||||
|
expect(budgetModel?.variants).toContainEqual({
|
||||||
|
id: ModelV2.VariantID.make("max"),
|
||||||
|
settings: { thinking: { type: "enabled", budgetTokens: 64000 } },
|
||||||
|
headers: {},
|
||||||
|
body: {},
|
||||||
|
})
|
||||||
|
|
||||||
|
const anthropicEffortModel = yield* catalog.model.get(ProviderV2.ID.anthropic, ModelV2.ID.make("claude-effort"))
|
||||||
|
expect(anthropicEffortModel?.variants).toContainEqual({
|
||||||
|
id: ModelV2.VariantID.make("low"),
|
||||||
|
settings: { thinking: { type: "adaptive", display: "summarized" }, effort: "low" },
|
||||||
|
headers: {},
|
||||||
|
body: {},
|
||||||
|
})
|
||||||
}).pipe(Effect.provide(AppNodeBuilder.build(ModelsDev.node))),
|
}).pipe(Effect.provide(AppNodeBuilder.build(ModelsDev.node))),
|
||||||
(previous) =>
|
(previous) =>
|
||||||
Effect.sync(() => {
|
Effect.sync(() => {
|
||||||
|
|
@ -245,5 +259,4 @@ describe("ModelsDevPlugin", () => {
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,7 @@ describe("OpencodePlugin", () => {
|
||||||
model.variants = [
|
model.variants = [
|
||||||
{
|
{
|
||||||
id: ModelV2.VariantID.make("custom"),
|
id: ModelV2.VariantID.make("custom"),
|
||||||
|
settings: {},
|
||||||
headers: { "x-custom": "true" },
|
headers: { "x-custom": "true" },
|
||||||
body: { custom: true },
|
body: { custom: true },
|
||||||
},
|
},
|
||||||
|
|
@ -177,7 +178,7 @@ describe("OpencodePlugin", () => {
|
||||||
url: `${server.url.origin}/v1`,
|
url: `${server.url.origin}/v1`,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
expect(provider.request).toEqual({ headers: { "x-org-id": "org" }, body: { custom: "value" } })
|
expect(provider.request).toEqual({ settings: {}, headers: { "x-org-id": "org" }, body: { custom: "value" } })
|
||||||
expect(yield* (yield* Integration.Service).get(Integration.ID.make("remote"))).toBeUndefined()
|
expect(yield* (yield* Integration.Service).get(Integration.ID.make("remote"))).toBeUndefined()
|
||||||
|
|
||||||
const model = required(yield* catalog.model.get(ProviderV2.ID.make("remote"), ModelV2.ID.make("model")))
|
const model = required(yield* catalog.model.get(ProviderV2.ID.make("remote"), ModelV2.ID.make("model")))
|
||||||
|
|
@ -192,11 +193,13 @@ describe("OpencodePlugin", () => {
|
||||||
expect(model.variants).toEqual([
|
expect(model.variants).toEqual([
|
||||||
{
|
{
|
||||||
id: ModelV2.VariantID.make("custom"),
|
id: ModelV2.VariantID.make("custom"),
|
||||||
|
settings: {},
|
||||||
headers: { "x-custom": "true" },
|
headers: { "x-custom": "true" },
|
||||||
body: { custom: true },
|
body: { custom: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: ModelV2.VariantID.make("high"),
|
id: ModelV2.VariantID.make("high"),
|
||||||
|
settings: {},
|
||||||
headers: {},
|
headers: {},
|
||||||
body: { temperature: 0.2 },
|
body: { temperature: 0.2 },
|
||||||
},
|
},
|
||||||
|
|
@ -359,6 +362,7 @@ describe("OpencodePlugin", () => {
|
||||||
...ProviderV2.Info.empty(ProviderV2.ID.opencode),
|
...ProviderV2.Info.empty(ProviderV2.ID.opencode),
|
||||||
api: { type: "aisdk", package: "test-provider" },
|
api: { type: "aisdk", package: "test-provider" },
|
||||||
request: {
|
request: {
|
||||||
|
settings: {},
|
||||||
headers: {},
|
headers: {},
|
||||||
body: { apiKey: "configured" },
|
body: { apiKey: "configured" },
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,8 @@ describe("VariantPlugin", () => {
|
||||||
yield* VariantPlugin.Plugin.effect(host({ catalog: catalogHost(service) }))
|
yield* VariantPlugin.Plugin.effect(host({ catalog: catalogHost(service) }))
|
||||||
|
|
||||||
expect((yield* service.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("glm-5.2")))?.variants).toEqual([
|
expect((yield* service.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("glm-5.2")))?.variants).toEqual([
|
||||||
expect.objectContaining({ id: "high", body: { reasoning_effort: "high" } }),
|
expect.objectContaining({ id: "high", settings: { reasoningEffort: "high" } }),
|
||||||
expect.objectContaining({ id: "max", body: { reasoning_effort: "max" } }),
|
expect.objectContaining({ id: "max", settings: { reasoningEffort: "max" } }),
|
||||||
])
|
])
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
@ -53,14 +53,14 @@ describe("VariantPlugin", () => {
|
||||||
type: "aisdk",
|
type: "aisdk",
|
||||||
package: "@ai-sdk/openai-compatible",
|
package: "@ai-sdk/openai-compatible",
|
||||||
}
|
}
|
||||||
model.variants = [{ id: ModelV2.VariantID.make("high"), headers: { custom: "true" }, body: {} }]
|
model.variants = [{ id: ModelV2.VariantID.make("high"), settings: {}, headers: { custom: "true" }, body: {} }]
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
yield* VariantPlugin.Plugin.effect(host({ catalog: catalogHost(service) }))
|
yield* VariantPlugin.Plugin.effect(host({ catalog: catalogHost(service) }))
|
||||||
|
|
||||||
expect((yield* service.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("glm-5.2")))?.variants).toEqual([
|
expect((yield* service.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("glm-5.2")))?.variants).toEqual([
|
||||||
expect.objectContaining({ id: "high", headers: { custom: "true" } }),
|
expect.objectContaining({ id: "high", headers: { custom: "true" } }),
|
||||||
expect.objectContaining({ id: "max", body: { reasoning_effort: "max" } }),
|
expect.objectContaining({ id: "max", settings: { reasoningEffort: "max" } }),
|
||||||
])
|
])
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ const model = (api: Api, variants: ModelV2.Info["variants"] = []) =>
|
||||||
api: { id: ModelV2.ID.make("api-test-model"), ...api },
|
api: { id: ModelV2.ID.make("api-test-model"), ...api },
|
||||||
capabilities: { tools: true, input: ["text"], output: ["text"] },
|
capabilities: { tools: true, input: ["text"], output: ["text"] },
|
||||||
request: {
|
request: {
|
||||||
|
settings: {},
|
||||||
headers: { "x-test": "header" },
|
headers: { "x-test": "header" },
|
||||||
body: { apiKey: "secret", custom_extension: { enabled: true } },
|
body: { apiKey: "secret", custom_extension: { enabled: true } },
|
||||||
},
|
},
|
||||||
|
|
@ -83,7 +84,7 @@ describe("SessionRunnerModel", () => {
|
||||||
url: "https://compatible.example/v1",
|
url: "https://compatible.example/v1",
|
||||||
settings: { apiKey: "settings-secret", compatibility: "strict" },
|
settings: { apiKey: "settings-secret", compatibility: "strict" },
|
||||||
}),
|
}),
|
||||||
request: { headers: {}, body: {} },
|
request: { settings: {}, headers: {}, body: {} },
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
const request = LLM.request({ model: resolved, prompt: "Hello" })
|
const request = LLM.request({ model: resolved, prompt: "Hello" })
|
||||||
|
|
@ -100,17 +101,17 @@ describe("SessionRunnerModel", () => {
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
it.effect("overlays selected OpenAI Session variant bodies", () =>
|
it.effect("overlays selected OpenAI Session variant settings and bodies", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const catalog = model({ type: "aisdk", package: "@ai-sdk/openai", url: "https://openai.example/v1" }, [
|
const catalog = model({ type: "aisdk", package: "@ai-sdk/openai", url: "https://openai.example/v1" }, [
|
||||||
{
|
{
|
||||||
id: ModelV2.VariantID.make("high"),
|
id: ModelV2.VariantID.make("high"),
|
||||||
|
settings: { reasoningEffort: "high" },
|
||||||
headers: { "x-variant": "high" },
|
headers: { "x-variant": "high" },
|
||||||
body: {
|
body: {
|
||||||
store: false,
|
store: false,
|
||||||
service_tier: "priority",
|
service_tier: "priority",
|
||||||
temperature: 0.2,
|
temperature: 0.2,
|
||||||
reasoning: { effort: "high" },
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
@ -137,7 +138,9 @@ describe("SessionRunnerModel", () => {
|
||||||
store: false,
|
store: false,
|
||||||
service_tier: "priority",
|
service_tier: "priority",
|
||||||
temperature: 0.2,
|
temperature: 0.2,
|
||||||
reasoning: { effort: "high" },
|
})
|
||||||
|
expect(resolved.route.defaults.providerOptions).toEqual({
|
||||||
|
openai: { store: false, reasoningEffort: "high" },
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
@ -149,6 +152,7 @@ describe("SessionRunnerModel", () => {
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
id: ModelV2.VariantID.make("high"),
|
id: ModelV2.VariantID.make("high"),
|
||||||
|
settings: {},
|
||||||
headers: {},
|
headers: {},
|
||||||
body: { store: false, reasoning_effort: "high" },
|
body: { store: false, reasoning_effort: "high" },
|
||||||
},
|
},
|
||||||
|
|
@ -205,13 +209,14 @@ describe("SessionRunnerModel", () => {
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
it.effect("overlays selected Anthropic Session variant bodies", () =>
|
it.effect("overlays selected Anthropic Session variant settings", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const catalog = model({ type: "aisdk", package: "@ai-sdk/anthropic", url: "https://anthropic.example/v1" }, [
|
const catalog = model({ type: "aisdk", package: "@ai-sdk/anthropic", url: "https://anthropic.example/v1" }, [
|
||||||
{
|
{
|
||||||
id: ModelV2.VariantID.make("high"),
|
id: ModelV2.VariantID.make("high"),
|
||||||
|
settings: { thinking: { type: "enabled", budgetTokens: 12000 } },
|
||||||
headers: {},
|
headers: {},
|
||||||
body: { thinking: { type: "enabled", budget_tokens: 12000 } },
|
body: {},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
const session = SessionV2.Info.make({
|
const session = SessionV2.Info.make({
|
||||||
|
|
@ -229,7 +234,9 @@ describe("SessionRunnerModel", () => {
|
||||||
|
|
||||||
expect(resolved.route.defaults.http?.body).toEqual({
|
expect(resolved.route.defaults.http?.body).toEqual({
|
||||||
custom_extension: { enabled: true },
|
custom_extension: { enabled: true },
|
||||||
thinking: { type: "enabled", budget_tokens: 12000 },
|
})
|
||||||
|
expect(resolved.route.defaults.providerOptions).toEqual({
|
||||||
|
anthropic: { thinking: { type: "enabled", budgetTokens: 12000 } },
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
@ -252,7 +259,7 @@ describe("SessionRunnerModel", () => {
|
||||||
const resolved = yield* SessionRunnerModel.fromCatalogModel(
|
const resolved = yield* SessionRunnerModel.fromCatalogModel(
|
||||||
ModelV2.Info.make({
|
ModelV2.Info.make({
|
||||||
...model({ type: "aisdk", package: "@ai-sdk/openai", url: "https://openai.example/v1" }),
|
...model({ type: "aisdk", package: "@ai-sdk/openai", url: "https://openai.example/v1" }),
|
||||||
request: { headers: {}, body: {} },
|
request: { settings: {}, headers: {}, body: {} },
|
||||||
}),
|
}),
|
||||||
Credential.Key.make({ type: "key", key: "secret" }),
|
Credential.Key.make({ type: "key", key: "secret" }),
|
||||||
)
|
)
|
||||||
|
|
@ -275,7 +282,7 @@ describe("SessionRunnerModel", () => {
|
||||||
const resolved = yield* SessionRunnerModel.fromCatalogModel(
|
const resolved = yield* SessionRunnerModel.fromCatalogModel(
|
||||||
ModelV2.Info.make({
|
ModelV2.Info.make({
|
||||||
...model({ type: "aisdk", package: "@ai-sdk/openai", url: "https://openai.example/v1" }),
|
...model({ type: "aisdk", package: "@ai-sdk/openai", url: "https://openai.example/v1" }),
|
||||||
request: { headers: {}, body: { apiKey: "configured-secret" } },
|
request: { settings: {}, headers: {}, body: { apiKey: "configured-secret" } },
|
||||||
}),
|
}),
|
||||||
credential,
|
credential,
|
||||||
)
|
)
|
||||||
|
|
@ -297,7 +304,7 @@ describe("SessionRunnerModel", () => {
|
||||||
const resolved = yield* SessionRunnerModel.fromCatalogModel(
|
const resolved = yield* SessionRunnerModel.fromCatalogModel(
|
||||||
ModelV2.Info.make({
|
ModelV2.Info.make({
|
||||||
...model({ type: "aisdk", package: "@ai-sdk/openai", url: "https://openai.example/v1" }),
|
...model({ type: "aisdk", package: "@ai-sdk/openai", url: "https://openai.example/v1" }),
|
||||||
request: { headers: {}, body: {} },
|
request: { settings: {}, headers: {}, body: {} },
|
||||||
}),
|
}),
|
||||||
Credential.OAuth.make({
|
Credential.OAuth.make({
|
||||||
type: "oauth",
|
type: "oauth",
|
||||||
|
|
|
||||||
|
|
@ -148,9 +148,22 @@ const AnthropicToolChoice = Schema.Union([
|
||||||
Schema.Struct({ type: Schema.tag("tool"), name: Schema.String }),
|
Schema.Struct({ type: Schema.tag("tool"), name: Schema.String }),
|
||||||
])
|
])
|
||||||
|
|
||||||
const AnthropicThinking = Schema.Struct({
|
const AnthropicThinking = Schema.Union([
|
||||||
type: Schema.tag("enabled"),
|
Schema.Struct({
|
||||||
budget_tokens: Schema.Number,
|
type: Schema.tag("enabled"),
|
||||||
|
budget_tokens: Schema.Number,
|
||||||
|
}),
|
||||||
|
Schema.Struct({
|
||||||
|
type: Schema.tag("adaptive"),
|
||||||
|
display: Schema.optional(Schema.Literals(["summarized", "omitted"])),
|
||||||
|
}),
|
||||||
|
Schema.Struct({
|
||||||
|
type: Schema.tag("disabled"),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
|
||||||
|
const AnthropicOutputConfig = Schema.Struct({
|
||||||
|
effort: Schema.optional(Schema.String),
|
||||||
})
|
})
|
||||||
|
|
||||||
const AnthropicBodyFields = {
|
const AnthropicBodyFields = {
|
||||||
|
|
@ -166,6 +179,7 @@ const AnthropicBodyFields = {
|
||||||
top_k: Schema.optional(Schema.Number),
|
top_k: Schema.optional(Schema.Number),
|
||||||
stop_sequences: optionalArray(Schema.String),
|
stop_sequences: optionalArray(Schema.String),
|
||||||
thinking: Schema.optional(AnthropicThinking),
|
thinking: Schema.optional(AnthropicThinking),
|
||||||
|
output_config: Schema.optional(AnthropicOutputConfig),
|
||||||
}
|
}
|
||||||
const AnthropicMessagesBody = Schema.Struct(AnthropicBodyFields)
|
const AnthropicMessagesBody = Schema.Struct(AnthropicBodyFields)
|
||||||
export type AnthropicMessagesBody = Schema.Schema.Type<typeof AnthropicMessagesBody>
|
export type AnthropicMessagesBody = Schema.Schema.Type<typeof AnthropicMessagesBody>
|
||||||
|
|
@ -492,7 +506,16 @@ const anthropicOptions = (request: LLMRequest) => request.providerOptions?.anthr
|
||||||
|
|
||||||
const lowerThinking = Effect.fn("AnthropicMessages.lowerThinking")(function* (request: LLMRequest) {
|
const lowerThinking = Effect.fn("AnthropicMessages.lowerThinking")(function* (request: LLMRequest) {
|
||||||
const thinking = anthropicOptions(request)?.thinking
|
const thinking = anthropicOptions(request)?.thinking
|
||||||
if (!ProviderShared.isRecord(thinking) || thinking.type !== "enabled") return undefined
|
if (!ProviderShared.isRecord(thinking)) return undefined
|
||||||
|
if (thinking.type === "adaptive") {
|
||||||
|
const display = thinking.display
|
||||||
|
return {
|
||||||
|
type: "adaptive" as const,
|
||||||
|
...(display === "summarized" || display === "omitted" ? { display } : {}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (thinking.type === "disabled") return { type: "disabled" as const }
|
||||||
|
if (thinking.type !== "enabled") return undefined
|
||||||
const budget =
|
const budget =
|
||||||
typeof thinking.budgetTokens === "number"
|
typeof thinking.budgetTokens === "number"
|
||||||
? thinking.budgetTokens
|
? thinking.budgetTokens
|
||||||
|
|
@ -503,6 +526,11 @@ const lowerThinking = Effect.fn("AnthropicMessages.lowerThinking")(function* (re
|
||||||
return { type: "enabled" as const, budget_tokens: budget }
|
return { type: "enabled" as const, budget_tokens: budget }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const outputConfig = (request: LLMRequest) => {
|
||||||
|
const effort = anthropicOptions(request)?.effort
|
||||||
|
return typeof effort === "string" ? { effort } : undefined
|
||||||
|
}
|
||||||
|
|
||||||
const fromRequest = Effect.fn("AnthropicMessages.fromRequest")(function* (request: LLMRequest) {
|
const fromRequest = Effect.fn("AnthropicMessages.fromRequest")(function* (request: LLMRequest) {
|
||||||
const toolChoice = request.toolChoice ? yield* lowerToolChoice(request.toolChoice) : undefined
|
const toolChoice = request.toolChoice ? yield* lowerToolChoice(request.toolChoice) : undefined
|
||||||
const generation = request.generation
|
const generation = request.generation
|
||||||
|
|
@ -549,6 +577,7 @@ const fromRequest = Effect.fn("AnthropicMessages.fromRequest")(function* (reques
|
||||||
top_k: generation?.topK,
|
top_k: generation?.topK,
|
||||||
stop_sequences: generation?.stop,
|
stop_sequences: generation?.stop,
|
||||||
thinking: yield* lowerThinking(request),
|
thinking: yield* lowerThinking(request),
|
||||||
|
output_config: outputConfig(request),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -168,8 +168,6 @@ interface ParserState {
|
||||||
readonly lifecycle: Lifecycle.State
|
readonly lifecycle: Lifecycle.State
|
||||||
}
|
}
|
||||||
|
|
||||||
const invalid = ProviderShared.invalidRequest
|
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// Request Lowering
|
// Request Lowering
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
@ -333,8 +331,6 @@ const lowerMessages = Effect.fn("OpenAIChat.lowerMessages")(function* (request:
|
||||||
const lowerOptions = Effect.fn("OpenAIChat.lowerOptions")(function* (request: LLMRequest) {
|
const lowerOptions = Effect.fn("OpenAIChat.lowerOptions")(function* (request: LLMRequest) {
|
||||||
const store = OpenAIOptions.store(request)
|
const store = OpenAIOptions.store(request)
|
||||||
const reasoningEffort = OpenAIOptions.reasoningEffort(request)
|
const reasoningEffort = OpenAIOptions.reasoningEffort(request)
|
||||||
if (reasoningEffort && !OpenAIOptions.isReasoningEffort(reasoningEffort))
|
|
||||||
return yield* invalid(`OpenAI Chat does not support reasoning effort ${reasoningEffort}`)
|
|
||||||
return {
|
return {
|
||||||
...(store !== undefined ? { store } : {}),
|
...(store !== undefined ? { store } : {}),
|
||||||
...(reasoningEffort ? { reasoning_effort: reasoningEffort } : {}),
|
...(reasoningEffort ? { reasoning_effort: reasoningEffort } : {}),
|
||||||
|
|
|
||||||
|
|
@ -457,8 +457,6 @@ const lowerOptions = Effect.fn("OpenAIResponses.lowerOptions")(function* (reques
|
||||||
const store = OpenAIOptions.store(request)
|
const store = OpenAIOptions.store(request)
|
||||||
const promptCacheKey = OpenAIOptions.promptCacheKey(request)
|
const promptCacheKey = OpenAIOptions.promptCacheKey(request)
|
||||||
const effort = OpenAIOptions.reasoningEffort(request)
|
const effort = OpenAIOptions.reasoningEffort(request)
|
||||||
if (effort && !OpenAIOptions.isReasoningEffort(effort))
|
|
||||||
return yield* invalid(`OpenAI Responses does not support reasoning effort ${effort}`)
|
|
||||||
const summary = OpenAIOptions.reasoningSummary(request)
|
const summary = OpenAIOptions.reasoningSummary(request)
|
||||||
const include = OpenAIOptions.include(request)
|
const include = OpenAIOptions.include(request)
|
||||||
const verbosity = OpenAIOptions.textVerbosity(request)
|
const verbosity = OpenAIOptions.textVerbosity(request)
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
import { Schema } from "effect"
|
import { Schema } from "effect"
|
||||||
import type { LLMRequest, ReasoningEffort, TextVerbosity as TextVerbosityValue } from "../../schema"
|
import type { LLMRequest, TextVerbosity as TextVerbosityValue } from "../../schema"
|
||||||
import { ReasoningEfforts, TextVerbosity } from "../../schema"
|
import { ReasoningEfforts, TextVerbosity } from "../../schema"
|
||||||
|
|
||||||
export const OpenAIReasoningEfforts = ReasoningEfforts.filter(
|
export const OpenAIReasoningEfforts = ReasoningEfforts
|
||||||
(effort): effort is Exclude<ReasoningEffort, "max"> => effort !== "max",
|
export type OpenAIReasoningEffort = string
|
||||||
)
|
|
||||||
export type OpenAIReasoningEffort = (typeof OpenAIReasoningEfforts)[number]
|
|
||||||
|
|
||||||
// Mirrors OpenAI's `ResponseIncludable` union from the official SDK. Keep this
|
// Mirrors OpenAI's `ResponseIncludable` union from the official SDK. Keep this
|
||||||
// in lockstep with `openai-node/src/resources/responses/responses.ts`.
|
// in lockstep with `openai-node/src/resources/responses/responses.ts`.
|
||||||
|
|
@ -23,22 +21,16 @@ export type OpenAIResponseIncludable = (typeof OpenAIResponseIncludables)[number
|
||||||
export const OpenAIServiceTiers = ["auto", "default", "flex", "priority"] as const
|
export const OpenAIServiceTiers = ["auto", "default", "flex", "priority"] as const
|
||||||
export type OpenAIServiceTier = (typeof OpenAIServiceTiers)[number]
|
export type OpenAIServiceTier = (typeof OpenAIServiceTiers)[number]
|
||||||
|
|
||||||
const REASONING_EFFORTS = new Set<string>(ReasoningEfforts)
|
|
||||||
const OPENAI_REASONING_EFFORTS = new Set<string>(OpenAIReasoningEfforts)
|
|
||||||
const TEXT_VERBOSITY = new Set<string>(["low", "medium", "high"])
|
const TEXT_VERBOSITY = new Set<string>(["low", "medium", "high"])
|
||||||
const INCLUDABLES = new Set<string>(OpenAIResponseIncludables)
|
const INCLUDABLES = new Set<string>(OpenAIResponseIncludables)
|
||||||
const SERVICE_TIERS = new Set<string>(OpenAIServiceTiers)
|
const SERVICE_TIERS = new Set<string>(OpenAIServiceTiers)
|
||||||
|
|
||||||
export const OpenAIReasoningEffort = Schema.Literals(OpenAIReasoningEfforts)
|
export const OpenAIReasoningEffort = Schema.String
|
||||||
export const OpenAITextVerbosity = TextVerbosity
|
export const OpenAITextVerbosity = TextVerbosity
|
||||||
export const OpenAIResponseIncludable = Schema.Literals(OpenAIResponseIncludables)
|
export const OpenAIResponseIncludable = Schema.Literals(OpenAIResponseIncludables)
|
||||||
export const OpenAIServiceTier = Schema.Literals(OpenAIServiceTiers)
|
export const OpenAIServiceTier = Schema.Literals(OpenAIServiceTiers)
|
||||||
|
|
||||||
const isAnyReasoningEffort = (effort: unknown): effort is ReasoningEffort =>
|
export const isReasoningEffort = (effort: unknown): effort is OpenAIReasoningEffort => typeof effort === "string"
|
||||||
typeof effort === "string" && REASONING_EFFORTS.has(effort)
|
|
||||||
|
|
||||||
export const isReasoningEffort = (effort: unknown): effort is OpenAIReasoningEffort =>
|
|
||||||
typeof effort === "string" && OPENAI_REASONING_EFFORTS.has(effort)
|
|
||||||
|
|
||||||
const isTextVerbosity = (value: unknown): value is TextVerbosityValue =>
|
const isTextVerbosity = (value: unknown): value is TextVerbosityValue =>
|
||||||
typeof value === "string" && TEXT_VERBOSITY.has(value)
|
typeof value === "string" && TEXT_VERBOSITY.has(value)
|
||||||
|
|
@ -50,9 +42,9 @@ export const store = (request: LLMRequest): boolean | undefined => {
|
||||||
return typeof value === "boolean" ? value : undefined
|
return typeof value === "boolean" ? value : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export const reasoningEffort = (request: LLMRequest): ReasoningEffort | undefined => {
|
export const reasoningEffort = (request: LLMRequest): string | undefined => {
|
||||||
const value = options(request)?.reasoningEffort
|
const value = options(request)?.reasoningEffort
|
||||||
return isAnyReasoningEffort(value) ? value : undefined
|
return typeof value === "string" ? value : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export const reasoningSummary = (request: LLMRequest): "auto" | undefined =>
|
export const reasoningSummary = (request: LLMRequest): "auto" | undefined =>
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export const ToolCallID = Schema.String
|
||||||
export type ToolCallID = Schema.Schema.Type<typeof ToolCallID>
|
export type ToolCallID = Schema.Schema.Type<typeof ToolCallID>
|
||||||
|
|
||||||
export const ReasoningEfforts = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] as const
|
export const ReasoningEfforts = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] as const
|
||||||
export const ReasoningEffort = Schema.Literals(ReasoningEfforts)
|
export const ReasoningEffort = Schema.String
|
||||||
export type ReasoningEffort = Schema.Schema.Type<typeof ReasoningEffort>
|
export type ReasoningEffort = Schema.Schema.Type<typeof ReasoningEffort>
|
||||||
|
|
||||||
export const TextVerbosity = Schema.Literals(["low", "medium", "high"])
|
export const TextVerbosity = Schema.Literals(["low", "medium", "high"])
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,23 @@ describe("Anthropic Messages route", () => {
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
it.effect("lowers adaptive thinking settings with effort", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const prepared = yield* LLMClient.prepare<AnthropicMessages.AnthropicMessagesBody>(
|
||||||
|
LLM.updateRequest(request, {
|
||||||
|
providerOptions: {
|
||||||
|
anthropic: { thinking: { type: "adaptive", display: "summarized" }, effort: "low" },
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(prepared.body).toMatchObject({
|
||||||
|
thinking: { type: "adaptive", display: "summarized" },
|
||||||
|
output_config: { effort: "low" },
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
it.effect("lowers chronological system updates natively for Claude Opus 4.8 with cache hints", () =>
|
it.effect("lowers chronological system updates natively for Claude Opus 4.8 with cache hints", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const prepared = yield* LLMClient.prepare<AnthropicMessages.AnthropicMessagesBody>(
|
const prepared = yield* LLMClient.prepare<AnthropicMessages.AnthropicMessagesBody>(
|
||||||
|
|
|
||||||
|
|
@ -98,12 +98,26 @@ describe("OpenAI Chat route", () => {
|
||||||
LLM.request({
|
LLM.request({
|
||||||
model: OpenAI.configure({ baseURL: "https://api.openai.test/v1/", apiKey: "test" }).chat("gpt-4o-mini"),
|
model: OpenAI.configure({ baseURL: "https://api.openai.test/v1/", apiKey: "test" }).chat("gpt-4o-mini"),
|
||||||
prompt: "think",
|
prompt: "think",
|
||||||
providerOptions: { openai: { reasoningEffort: "low" } },
|
providerOptions: { openai: { reasoningEffort: "max" } },
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(prepared.body.store).toBe(false)
|
expect(prepared.body.store).toBe(false)
|
||||||
expect(prepared.body.reasoning_effort).toBe("low")
|
expect(prepared.body.reasoning_effort).toBe("max")
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
it.effect("passes through custom OpenAI-compatible reasoning effort strings", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const prepared = yield* LLMClient.prepare<OpenAIChat.OpenAIChatBody>(
|
||||||
|
LLM.request({
|
||||||
|
model,
|
||||||
|
prompt: "think",
|
||||||
|
providerOptions: { openai: { reasoningEffort: "experimental" } },
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(prepared.body.reasoning_effort).toBe("experimental")
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,16 @@ describe("OpenAI Responses route", () => {
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
it.effect("passes through custom OpenAI reasoning effort strings", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const prepared = yield* LLMClient.prepare<OpenAIResponses.OpenAIResponsesBody>(
|
||||||
|
LLM.updateRequest(request, { providerOptions: { openai: { reasoningEffort: "experimental" } } }),
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(prepared.body.reasoning).toEqual({ effort: "experimental" })
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
it.effect("omits unsupported semantic service tiers", () =>
|
it.effect("omits unsupported semantic service tiers", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const prepared = yield* LLMClient.prepare(
|
const prepared = yield* LLMClient.prepare(
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ export const Info = Schema.Struct({
|
||||||
empty: (id: ID) =>
|
empty: (id: ID) =>
|
||||||
schema.make({
|
schema.make({
|
||||||
id,
|
id,
|
||||||
request: { headers: {}, body: {} },
|
request: { settings: {}, headers: {}, body: {} },
|
||||||
mode: "all",
|
mode: "all",
|
||||||
hidden: false,
|
hidden: false,
|
||||||
permissions: [
|
permissions: [
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ export const Info = Schema.Struct({
|
||||||
name: modelID,
|
name: modelID,
|
||||||
api: { id: modelID, type: "native", settings: {} },
|
api: { id: modelID, type: "native", settings: {} },
|
||||||
capabilities: { tools: false, input: [], output: [] },
|
capabilities: { tools: false, input: [], output: [] },
|
||||||
request: { headers: {}, body: {} },
|
request: { settings: {}, headers: {}, body: {} },
|
||||||
variants: [],
|
variants: [],
|
||||||
time: { released: 0 },
|
time: { released: 0 },
|
||||||
cost: [],
|
cost: [],
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
export * as Provider from "./provider.js"
|
export * as Provider from "./provider.js"
|
||||||
|
|
||||||
import { Schema } from "effect"
|
import { Effect, Schema } from "effect"
|
||||||
import { optional } from "./schema.js"
|
import { optional } from "./schema.js"
|
||||||
import { Integration } from "./integration.js"
|
import { Integration } from "./integration.js"
|
||||||
import { statics } from "./schema.js"
|
import { statics } from "./schema.js"
|
||||||
|
|
@ -43,8 +43,12 @@ export const Api = Schema.Union([AISDK, Native])
|
||||||
.annotate({ identifier: "Provider.Api" })
|
.annotate({ identifier: "Provider.Api" })
|
||||||
export type Api = typeof Api.Type
|
export type Api = typeof Api.Type
|
||||||
|
|
||||||
|
export const Settings = Schema.Record(Schema.String, Schema.Unknown).annotate({ identifier: "Provider.Settings" })
|
||||||
|
export type Settings = typeof Settings.Type
|
||||||
|
|
||||||
export interface Request extends Schema.Schema.Type<typeof Request> {}
|
export interface Request extends Schema.Schema.Type<typeof Request> {}
|
||||||
export const Request = Schema.Struct({
|
export const Request = Schema.Struct({
|
||||||
|
settings: Settings.pipe(Schema.withConstructorDefault(Effect.succeed({}))),
|
||||||
headers: Schema.Record(Schema.String, Schema.String),
|
headers: Schema.Record(Schema.String, Schema.String),
|
||||||
body: Schema.Record(Schema.String, Schema.Json),
|
body: Schema.Record(Schema.String, Schema.Json),
|
||||||
}).annotate({ identifier: "Provider.Request" })
|
}).annotate({ identifier: "Provider.Request" })
|
||||||
|
|
@ -66,7 +70,7 @@ export const Info = Schema.Struct({
|
||||||
id,
|
id,
|
||||||
name: id,
|
name: id,
|
||||||
api: { type: "native", settings: {} },
|
api: { type: "native", settings: {} },
|
||||||
request: { headers: {}, body: {} },
|
request: { settings: {}, headers: {}, body: {} },
|
||||||
}),
|
}),
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -399,6 +399,8 @@ import type {
|
||||||
V2SessionSwitchAgentResponses,
|
V2SessionSwitchAgentResponses,
|
||||||
V2SessionSwitchModelErrors,
|
V2SessionSwitchModelErrors,
|
||||||
V2SessionSwitchModelResponses,
|
V2SessionSwitchModelResponses,
|
||||||
|
V2SessionSyntheticErrors,
|
||||||
|
V2SessionSyntheticResponses,
|
||||||
V2SessionWaitErrors,
|
V2SessionWaitErrors,
|
||||||
V2SessionWaitResponses,
|
V2SessionWaitResponses,
|
||||||
V2ShellCreateErrors,
|
V2ShellCreateErrors,
|
||||||
|
|
@ -5816,6 +5818,47 @@ export class Session3 extends HeyApiClient {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add synthetic message
|
||||||
|
*
|
||||||
|
* Append a synthetic message to a session and resume execution.
|
||||||
|
*/
|
||||||
|
public synthetic<ThrowOnError extends boolean = false>(
|
||||||
|
parameters: {
|
||||||
|
sessionID: string
|
||||||
|
text?: string
|
||||||
|
description?: string
|
||||||
|
metadata?: {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
},
|
||||||
|
options?: Options<never, ThrowOnError>,
|
||||||
|
) {
|
||||||
|
const params = buildClientParams(
|
||||||
|
[parameters],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
args: [
|
||||||
|
{ in: "path", key: "sessionID" },
|
||||||
|
{ in: "body", key: "text" },
|
||||||
|
{ in: "body", key: "description" },
|
||||||
|
{ in: "body", key: "metadata" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
return (options?.client ?? this.client).post<V2SessionSyntheticResponses, V2SessionSyntheticErrors, ThrowOnError>({
|
||||||
|
url: "/api/session/{sessionID}/synthetic",
|
||||||
|
...options,
|
||||||
|
...params,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...options?.headers,
|
||||||
|
...params.headers,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compact session
|
* Compact session
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -942,6 +942,9 @@ export type GlobalEvent = {
|
||||||
messageID: string
|
messageID: string
|
||||||
text: string
|
text: string
|
||||||
description?: string
|
description?: string
|
||||||
|
metadata?: {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
|
|
@ -3618,6 +3621,9 @@ export type SyncEventSessionNextSynthetic = {
|
||||||
messageID: string
|
messageID: string
|
||||||
text: string
|
text: string
|
||||||
description?: string
|
description?: string
|
||||||
|
metadata?: {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4091,7 +4097,12 @@ export type LocationInfo = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ProviderSettings = {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
|
||||||
export type ProviderRequest = {
|
export type ProviderRequest = {
|
||||||
|
settings: ProviderSettings
|
||||||
headers: {
|
headers: {
|
||||||
[key: string]: string
|
[key: string]: string
|
||||||
}
|
}
|
||||||
|
|
@ -4583,6 +4594,9 @@ export type SessionNextSynthetic = {
|
||||||
messageID: string
|
messageID: string
|
||||||
text: string
|
text: string
|
||||||
description?: string
|
description?: string
|
||||||
|
metadata?: {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5120,6 +5134,7 @@ export type ModelV2Info = {
|
||||||
api: ModelApi
|
api: ModelApi
|
||||||
capabilities: ModelCapabilities
|
capabilities: ModelCapabilities
|
||||||
request: {
|
request: {
|
||||||
|
settings: ProviderSettings
|
||||||
headers: {
|
headers: {
|
||||||
[key: string]: string
|
[key: string]: string
|
||||||
}
|
}
|
||||||
|
|
@ -5130,6 +5145,7 @@ export type ModelV2Info = {
|
||||||
}
|
}
|
||||||
variants: Array<{
|
variants: Array<{
|
||||||
id: string
|
id: string
|
||||||
|
settings: ProviderSettings
|
||||||
headers: {
|
headers: {
|
||||||
[key: string]: string
|
[key: string]: string
|
||||||
}
|
}
|
||||||
|
|
@ -6806,6 +6822,9 @@ export type EventSessionNextSynthetic = {
|
||||||
messageID: string
|
messageID: string
|
||||||
text: string
|
text: string
|
||||||
description?: string
|
description?: string
|
||||||
|
metadata?: {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -12284,6 +12303,47 @@ export type V2SessionSkillResponses = {
|
||||||
|
|
||||||
export type V2SessionSkillResponse = V2SessionSkillResponses[keyof V2SessionSkillResponses]
|
export type V2SessionSkillResponse = V2SessionSkillResponses[keyof V2SessionSkillResponses]
|
||||||
|
|
||||||
|
export type V2SessionSyntheticData = {
|
||||||
|
body: {
|
||||||
|
text: string
|
||||||
|
description?: string
|
||||||
|
metadata?: {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
path: {
|
||||||
|
sessionID: string
|
||||||
|
}
|
||||||
|
query?: never
|
||||||
|
url: "/api/session/{sessionID}/synthetic"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type V2SessionSyntheticErrors = {
|
||||||
|
/**
|
||||||
|
* InvalidRequestError
|
||||||
|
*/
|
||||||
|
400: InvalidRequestError
|
||||||
|
/**
|
||||||
|
* UnauthorizedError
|
||||||
|
*/
|
||||||
|
401: UnauthorizedError
|
||||||
|
/**
|
||||||
|
* SessionNotFoundError
|
||||||
|
*/
|
||||||
|
404: SessionNotFoundError
|
||||||
|
}
|
||||||
|
|
||||||
|
export type V2SessionSyntheticError = V2SessionSyntheticErrors[keyof V2SessionSyntheticErrors]
|
||||||
|
|
||||||
|
export type V2SessionSyntheticResponses = {
|
||||||
|
/**
|
||||||
|
* <No Content>
|
||||||
|
*/
|
||||||
|
204: void
|
||||||
|
}
|
||||||
|
|
||||||
|
export type V2SessionSyntheticResponse = V2SessionSyntheticResponses[keyof V2SessionSyntheticResponses]
|
||||||
|
|
||||||
export type V2SessionCompactData = {
|
export type V2SessionCompactData = {
|
||||||
body?: never
|
body?: never
|
||||||
path: {
|
path: {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue