package llm
// effortLevels records which output_config.effort levels each model accepts.
// It is a per-model table for the same reason prices and adaptiveThinking are:
// the answer differs by model and a wrong one is not a rounding error.
// claude-haiku-4-5 answers a request carrying any effort level with
//
// 400 invalid_request_error: This model does not support the effort parameter
//
// which kills the agent before its first turn — which is what a Haiku subagent
// spawned from a session set to high effort did on every spawn.
//
// xhigh is not universal either: it arrived with Opus 4.7, so the 4.6 family
// takes the other four and Opus 4.5 takes only the first three.
//
// Only ids confirmed to accept a level are listed, and an unlisted id — a
// gateway serving something this build has never heard of, a family released
// after it — is treated as taking none. The two mistakes are not symmetric:
// sending effort to a model that lacks it is a hard 400 that ends the run
// before any work happens, where omitting it costs the level and says so in
// the status line. The recoverable failure is the one to default to, which is
// the same reading SupportsAdaptiveThinking makes.
var effortLevels = map[string][]string{
"claude-fable-5-1": EffortLevels,
"claude-fable-5": EffortLevels,
"claude-mythos-5-1": EffortLevels,
"claude-mythos-5": EffortLevels,
"claude-opus-5": EffortLevels,
"claude-opus-4-8": EffortLevels,
"claude-opus-4-7": EffortLevels,
"claude-sonnet-5": EffortLevels,
"claude-opus-4-6": {"low", "medium", "high", "max"},
"claude-sonnet-4-6": {"low", "medium", "high", "max"},
"claude-opus-4-5": {"low", "medium", "high"},
}
// SupportsEffort reports whether model accepts this effort level. An empty
// level is the API's own default and is always safe: it means the request
// carries no output_config at all.
func SupportsEffort(model, level string) bool {
if level == "" {
return true
}
for _, l := range effortLevels[basePrice(model)] {
if l == level {
return true
}
}
return false
}