Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions .jp/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,14 @@ opus6 = "anthropic/claude-opus-4-6"
haiku = "anthropic/claude-haiku-4-5"
zai = "cerebras/zai-glm-4.7"
# OpenAI aliases
openai = "openai/gpt-5.5"
chatgpt = "openai/gpt-5.5"
gpt = "openai/gpt-5.5"
gpt5 = "openai/gpt-5.5"
openai = "openai/gpt-5.6-sol"
chatgpt = "openai/gpt-5.6-sol"
gpt = "openai/gpt-5.6-sol"
gpt5 = "openai/gpt-5.6-sol"
gpt55 = "openai/gpt-5.5"
sol = "openai/gpt-5.6-sol"
terra = "openai/gpt-5.6-terra"
luna = "openai/gpt-5.6-luna"
gpt5-pro = "openai/gpt-5.5-pro"
gpt-pro = "openai/gpt-5.5-pro"
gpt5-mini = "openai/gpt-5.4-mini"
Expand Down
12 changes: 6 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 26 additions & 1 deletion crates/jp_llm/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,13 @@ impl ModelDetails {
medium,
high,
xhigh,
max,
}) => match config {
// Off, so disabled.
Some(ReasoningConfig::Off) => None,

// Auto configured, so use medium effort if the model supports
// it, otherwise high or low.
// it, otherwise the nearest supported level.
None | Some(ReasoningConfig::Auto) => Some(CustomReasoningConfig {
effort: if medium {
ReasoningEffort::Medium
Expand All @@ -162,6 +163,8 @@ impl ModelDetails {
ReasoningEffort::XHigh
} else if low {
ReasoningEffort::Low
} else if max {
ReasoningEffort::Max
} else {
ReasoningEffort::Xlow
},
Expand Down Expand Up @@ -262,6 +265,10 @@ pub enum ReasoningDetails {

/// Whether the model supports extremely high effort reasoning.
xhigh: bool,

/// Whether the model supports maximum effort reasoning, with no
/// constraints on token spending.
max: bool,
},

/// Adaptive reasoning support.
Expand Down Expand Up @@ -298,6 +305,7 @@ impl ReasoningDetails {
medium: bool,
high: bool,
xhigh: bool,
max: bool,
) -> Self {
Self::Leveled {
none,
Expand All @@ -306,6 +314,7 @@ impl ReasoningDetails {
medium,
high,
xhigh,
max,
}
}

Expand Down Expand Up @@ -352,6 +361,7 @@ impl ReasoningDetails {
medium,
high,
xhigh,
max,
} => {
if *none {
Some(ReasoningEffort::None)
Expand All @@ -365,6 +375,8 @@ impl ReasoningDetails {
Some(ReasoningEffort::High)
} else if *xhigh {
Some(ReasoningEffort::XHigh)
} else if *max {
Some(ReasoningEffort::Max)
} else {
None
}
Expand All @@ -373,6 +385,15 @@ impl ReasoningDetails {
}
}

/// Returns `true` if the model supports the `max` reasoning effort level.
#[must_use]
pub fn supports_max_effort(&self) -> bool {
matches!(
self,
Self::Leveled { max: true, .. } | Self::Adaptive { max: true, .. }
)
}

#[must_use]
pub fn is_unsupported(&self) -> bool {
matches!(self, Self::Unsupported)
Expand All @@ -393,3 +414,7 @@ impl ReasoningDetails {
matches!(self, Self::Adaptive { .. })
}
}

#[cfg(test)]
#[path = "model_tests.rs"]
mod tests;
43 changes: 43 additions & 0 deletions crates/jp_llm/src/model_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use jp_config::model::parameters::{ReasoningConfig, ReasoningEffort};

use super::{ModelDetails, ReasoningDetails};

mod custom_reasoning_config {
use super::*;

fn model(reasoning: ReasoningDetails) -> ModelDetails {
let mut details = ModelDetails::empty("openai/test-model".parse().unwrap());
details.reasoning = Some(reasoning);
details
}

/// A leveled model whose only supported level is `max` resolves `Auto` to
/// `max` instead of falling through to an unsupported level.
#[test]
fn auto_on_max_only_model_selects_max() {
let details = model(ReasoningDetails::leveled(
false, false, false, false, false, false, true,
));

let config = details
.custom_reasoning_config(Some(ReasoningConfig::Auto))
.unwrap();

assert_eq!(config.effort, ReasoningEffort::Max);
}

/// `max` is a last resort: any lower supported level wins in the `Auto`
/// selection.
#[test]
fn auto_prefers_lower_levels_over_max() {
let details = model(ReasoningDetails::leveled(
false, false, true, false, false, false, true,
));

let config = details
.custom_reasoning_config(Some(ReasoningConfig::Auto))
.unwrap();

assert_eq!(config.effort, ReasoningEffort::Low);
}
}
4 changes: 2 additions & 2 deletions crates/jp_llm/src/provider/cerebras.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ fn map_model(id: &str) -> Result<ModelDetails> {
context_window: Some(131_072),
max_output_tokens: Some(40_960),
reasoning: Some(ReasoningDetails::leveled(
false, false, true, true, true, false,
false, false, true, true, true, false, false,
)),
knowledge_cutoff: None,
deprecated: None,
Expand All @@ -242,7 +242,7 @@ fn map_model(id: &str) -> Result<ModelDetails> {
max_output_tokens: Some(40_960),
// Reasoning is enabled by default; only `none` disables it.
reasoning: Some(ReasoningDetails::leveled(
true, false, false, false, false, false,
true, false, false, false, false, false, false,
)),
knowledge_cutoff: None,
deprecated: None,
Expand Down
7 changes: 4 additions & 3 deletions crates/jp_llm/src/provider/google.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ fn create_request(
medium,
high,
xhigh: _,
max: _,
} => {
let level = config
.effort
Expand Down Expand Up @@ -408,7 +409,7 @@ fn map_model(model: types::Model) -> ModelDetails {
context_window,
max_output_tokens,
reasoning: Some(ReasoningDetails::leveled(
false, false, true, true, true, false,
false, false, true, true, true, false, false,
)),
knowledge_cutoff: Some(NaiveDate::from_ymd_opt(2025, 1, 1).unwrap()),
deprecated: Some(ModelDeprecation::Active),
Expand All @@ -422,7 +423,7 @@ fn map_model(model: types::Model) -> ModelDetails {
context_window,
max_output_tokens,
reasoning: Some(ReasoningDetails::leveled(
false, false, true, false, true, false,
false, false, true, false, true, false, false,
)),
knowledge_cutoff: Some(NaiveDate::from_ymd_opt(2025, 1, 1).unwrap()),
deprecated: Some(ModelDeprecation::Active),
Expand All @@ -435,7 +436,7 @@ fn map_model(model: types::Model) -> ModelDetails {
context_window,
max_output_tokens,
reasoning: Some(ReasoningDetails::leveled(
false, true, true, true, true, false,
false, true, true, true, true, false, false,
)),
knowledge_cutoff: Some(NaiveDate::from_ymd_opt(2025, 1, 1).unwrap()),
deprecated: Some(ModelDeprecation::Active),
Expand Down
Loading
Loading