fix(provider): type default model failures (#28881)
This commit is contained in:
@@ -69,7 +69,7 @@ export interface Interface {
|
|||||||
whenToUse: string
|
whenToUse: string
|
||||||
systemPrompt: string
|
systemPrompt: string
|
||||||
},
|
},
|
||||||
Provider.ModelNotFoundError
|
Provider.DefaultModelError
|
||||||
>
|
>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { EOL } from "os"
|
import { EOL } from "os"
|
||||||
import { basename } from "path"
|
import { basename } from "path"
|
||||||
import { Effect } from "effect"
|
import { Cause, Effect } from "effect"
|
||||||
import { Agent } from "../../../agent/agent"
|
import { Agent } from "../../../agent/agent"
|
||||||
import { Provider } from "@/provider/provider"
|
import { Provider } from "@/provider/provider"
|
||||||
import { Session } from "@/session/session"
|
import { Session } from "@/session/session"
|
||||||
@@ -80,7 +80,21 @@ const run = Effect.fn("Cli.debug.agent.body")(function* (
|
|||||||
const getAvailableTools = Effect.fn("Cli.debug.agent.getAvailableTools")(function* (agent: Agent.Info) {
|
const getAvailableTools = Effect.fn("Cli.debug.agent.getAvailableTools")(function* (agent: Agent.Info) {
|
||||||
const provider = yield* Provider.Service
|
const provider = yield* Provider.Service
|
||||||
const registry = yield* ToolRegistry.Service
|
const registry = yield* ToolRegistry.Service
|
||||||
const model = agent.model ?? (yield* provider.defaultModel())
|
const model =
|
||||||
|
agent.model ??
|
||||||
|
(yield* provider.defaultModel().pipe(
|
||||||
|
Effect.matchCauseEffect({
|
||||||
|
onSuccess: Effect.succeed,
|
||||||
|
onFailure: (cause) => {
|
||||||
|
const error = Cause.squash(cause) as Provider.DefaultModelError
|
||||||
|
if (error instanceof Provider.ModelNotFoundError) {
|
||||||
|
return fail(`Model not found: ${error.providerID}/${error.modelID}`)
|
||||||
|
}
|
||||||
|
if (error instanceof Provider.NoModelsError) return fail(`No models found for provider ${error.providerID}`)
|
||||||
|
return fail("No providers found")
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
))
|
||||||
return yield* registry.tools({ ...model, agent })
|
return yield* registry.tools({ ...model, agent })
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -133,7 +147,19 @@ const createToolContext = Effect.fn("Cli.debug.agent.createToolContext")(functio
|
|||||||
? agent.model
|
? agent.model
|
||||||
: yield* Effect.gen(function* () {
|
: yield* Effect.gen(function* () {
|
||||||
const provider = yield* Provider.Service
|
const provider = yield* Provider.Service
|
||||||
return yield* provider.defaultModel()
|
return yield* provider.defaultModel().pipe(
|
||||||
|
Effect.matchCauseEffect({
|
||||||
|
onSuccess: Effect.succeed,
|
||||||
|
onFailure: (cause) => {
|
||||||
|
const error = Cause.squash(cause) as Provider.DefaultModelError
|
||||||
|
if (error instanceof Provider.ModelNotFoundError) {
|
||||||
|
return fail(`Model not found: ${error.providerID}/${error.modelID}`)
|
||||||
|
}
|
||||||
|
if (error instanceof Provider.NoModelsError) return fail(`No models found for provider ${error.providerID}`)
|
||||||
|
return fail("No providers found")
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
const now = Date.now()
|
const now = Date.now()
|
||||||
const message: MessageV2.Assistant = {
|
const message: MessageV2.Assistant = {
|
||||||
|
|||||||
@@ -994,7 +994,22 @@ export class InitError extends Schema.TaggedErrorClass<InitError>()("ProviderIni
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Error = ModelNotFoundError | InitError
|
export class NoProvidersError extends Schema.TaggedErrorClass<NoProvidersError>()("ProviderNoProvidersError", {}) {
|
||||||
|
static isInstance(input: unknown): input is NoProvidersError {
|
||||||
|
return input instanceof NoProvidersError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NoModelsError extends Schema.TaggedErrorClass<NoModelsError>()("ProviderNoModelsError", {
|
||||||
|
providerID: ProviderID,
|
||||||
|
}) {
|
||||||
|
static isInstance(input: unknown): input is NoModelsError {
|
||||||
|
return input instanceof NoModelsError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DefaultModelError = ModelNotFoundError | NoProvidersError | NoModelsError
|
||||||
|
export type Error = ModelNotFoundError | InitError | NoProvidersError | NoModelsError
|
||||||
|
|
||||||
export interface Interface {
|
export interface Interface {
|
||||||
readonly list: () => Effect.Effect<Record<ProviderID, Info>>
|
readonly list: () => Effect.Effect<Record<ProviderID, Info>>
|
||||||
@@ -1006,7 +1021,7 @@ export interface Interface {
|
|||||||
query: string[],
|
query: string[],
|
||||||
) => Effect.Effect<{ providerID: ProviderID; modelID: string } | undefined>
|
) => Effect.Effect<{ providerID: ProviderID; modelID: string } | undefined>
|
||||||
readonly getSmallModel: (providerID: ProviderID) => Effect.Effect<Model | undefined>
|
readonly getSmallModel: (providerID: ProviderID) => Effect.Effect<Model | undefined>
|
||||||
readonly defaultModel: () => Effect.Effect<{ providerID: ProviderID; modelID: ModelID }>
|
readonly defaultModel: () => Effect.Effect<{ providerID: ProviderID; modelID: ModelID }, DefaultModelError>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
@@ -1821,9 +1836,9 @@ export const layer = Layer.effect(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const provider = Object.values(s.providers).find((p) => !cfg.provider || Object.keys(cfg.provider).includes(p.id))
|
const provider = Object.values(s.providers).find((p) => !cfg.provider || Object.keys(cfg.provider).includes(p.id))
|
||||||
if (!provider) throw new Error("no providers found")
|
if (!provider) return yield* new NoProvidersError()
|
||||||
const [model] = sort(Object.values(provider.models))
|
const [model] = sort(Object.values(provider.models))
|
||||||
if (!model) throw new Error("no models found")
|
if (!model) return yield* new NoModelsError({ providerID: provider.id })
|
||||||
return {
|
return {
|
||||||
providerID: provider.id,
|
providerID: provider.id,
|
||||||
modelID: model.id,
|
modelID: model.id,
|
||||||
|
|||||||
@@ -682,7 +682,7 @@ export const layer = Layer.effect(
|
|||||||
.findMessage(sessionID, (m) => m.info.role === "user" && !!m.info.model)
|
.findMessage(sessionID, (m) => m.info.role === "user" && !!m.info.model)
|
||||||
.pipe(Effect.orDie)
|
.pipe(Effect.orDie)
|
||||||
if (Option.isSome(match) && match.value.info.role === "user") return match.value.info.model
|
if (Option.isSome(match) && match.value.info.role === "user") return match.value.info.model
|
||||||
return yield* provider.defaultModel()
|
return yield* provider.defaultModel().pipe(Effect.orDie)
|
||||||
})
|
})
|
||||||
|
|
||||||
const createUserMessage = Effect.fn("SessionPrompt.createUserMessage")(function* (input: PromptInput) {
|
const createUserMessage = Effect.fn("SessionPrompt.createUserMessage")(function* (input: PromptInput) {
|
||||||
|
|||||||
@@ -351,6 +351,16 @@ it.instance(
|
|||||||
{ config: { model: "anthropic/claude-sonnet-4-20250514" } },
|
{ config: { model: "anthropic/claude-sonnet-4-20250514" } },
|
||||||
)
|
)
|
||||||
|
|
||||||
|
it.instance(
|
||||||
|
"defaultModel returns a typed error when config excludes every provider",
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const error = yield* Provider.use.defaultModel().pipe(Effect.flip)
|
||||||
|
expect(error).toBeInstanceOf(Provider.NoProvidersError)
|
||||||
|
expect(error._tag).toBe("ProviderNoProvidersError")
|
||||||
|
}),
|
||||||
|
{ config: { enabled_providers: [] } },
|
||||||
|
)
|
||||||
|
|
||||||
it.instance(
|
it.instance(
|
||||||
"provider with baseURL from config",
|
"provider with baseURL from config",
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
|
|||||||
Reference in New Issue
Block a user