feat(context): tambah context::window::resolve
Satukan tiga salinan logika resolusi context_window (Action::Compact, spawn_turn, status bar) yang sempat melenceng satu sama lain. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
c219b6ec58
commit
059ca8ea24
@@ -11,3 +11,4 @@
|
|||||||
//! `TurnEvent::Compacted`.
|
//! `TurnEvent::Compacted`.
|
||||||
|
|
||||||
pub mod tokens;
|
pub mod tokens;
|
||||||
|
pub mod window;
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
//! Single source of truth for resolving the active model's context
|
||||||
|
//! window size, replacing three copies of the same lookup that had
|
||||||
|
//! drifted (`Action::Compact`, `spawn_turn`, and `view/status.rs` each
|
||||||
|
//! had their own inline version — the status bar's copy additionally
|
||||||
|
//! displayed "?" on no match instead of falling back like the other two,
|
||||||
|
//! an inconsistency this unifies away).
|
||||||
|
|
||||||
|
use crate::model::app_config::AppConfig;
|
||||||
|
use crate::model::settings::Settings;
|
||||||
|
|
||||||
|
/// Resolve the context-window size (in tokens) for the currently
|
||||||
|
/// configured provider/model.
|
||||||
|
///
|
||||||
|
/// Flow: find the `ModelRole` whose `provider`+`model` match
|
||||||
|
/// `settings` -> use its `context_window` if set -> otherwise fall back
|
||||||
|
/// to `app_config.default_context_window`.
|
||||||
|
///
|
||||||
|
/// Return: always a concrete token count, never "unknown".
|
||||||
|
pub fn resolve(app_config: &AppConfig, settings: &Settings) -> usize {
|
||||||
|
app_config.model_roles.values()
|
||||||
|
.find(|role| role.provider == settings.provider && role.model == settings.model)
|
||||||
|
.and_then(|role| role.context_window)
|
||||||
|
.unwrap_or(app_config.default_context_window) as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::model::app_config::ModelRole;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn resolves_context_window_from_matching_model_role() {
|
||||||
|
let mut app_config = AppConfig::default();
|
||||||
|
app_config.model_roles.insert("default".to_string(), ModelRole {
|
||||||
|
provider: "zen".to_string(),
|
||||||
|
model: "deepseek-v4-flash-free".to_string(),
|
||||||
|
max_tokens: None,
|
||||||
|
context_window: Some(128_000),
|
||||||
|
temperature: None,
|
||||||
|
});
|
||||||
|
let mut settings = Settings::default();
|
||||||
|
settings.provider = "zen".to_string();
|
||||||
|
settings.model = "deepseek-v4-flash-free".to_string();
|
||||||
|
|
||||||
|
assert_eq!(resolve(&app_config, &settings), 128_000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn falls_back_to_default_context_window_when_no_role_matches() {
|
||||||
|
let app_config = AppConfig::default();
|
||||||
|
let mut settings = Settings::default();
|
||||||
|
settings.provider = "nonexistent".to_string();
|
||||||
|
settings.model = "nonexistent-model".to_string();
|
||||||
|
|
||||||
|
assert_eq!(resolve(&app_config, &settings), app_config.default_context_window as usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn falls_back_to_default_when_matching_role_has_no_context_window_set() {
|
||||||
|
let mut app_config = AppConfig::default();
|
||||||
|
app_config.model_roles.insert("default".to_string(), ModelRole {
|
||||||
|
provider: "zen".to_string(),
|
||||||
|
model: "deepseek-v4-flash-free".to_string(),
|
||||||
|
max_tokens: None,
|
||||||
|
context_window: None,
|
||||||
|
temperature: None,
|
||||||
|
});
|
||||||
|
let mut settings = Settings::default();
|
||||||
|
settings.provider = "zen".to_string();
|
||||||
|
settings.model = "deepseek-v4-flash-free".to_string();
|
||||||
|
|
||||||
|
assert_eq!(resolve(&app_config, &settings), app_config.default_context_window as usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user