fix(tui): repaint the header context window on a /model switch
After `/model`, the header kept the previous model's window ("15K /
1.0M" on a 262K model) until the next turn or a restart. The pager
caches the window inside its context snapshot (streaming `totalTokens`
updates refresh it from the catalog) and nothing refreshed the cache
when the session's model changed. Comparing cached numbers against
catalog windows cannot tell a catalog-derived total from a shell
effective limit (KIGI_DEBUG_CONTEXT_WINDOW, header upgrades), so the
shell, which installs the effective window, now reports it:
- kigi-shell: `handle_set_session_model` returns the installed window;
`model_switch::apply` stamps it as `totalContextTokens` in the
`session/set_model` response meta and carries it on the
`ModelChanged` broadcast (`context_window`, serde-default: old pagers
ignore it, old leaders omit it). The response meta previously
serialized the actor's inner `Result` and reported success on an
actor failure; that error now propagates.
- kigi-tui: `Effect::SwitchModel` reads the meta; `SwitchModelComplete`
carries `Ok(Option<u64>)`; the completion handler and the follower
`ModelChanged` arm call `AgentView::apply_context_window`, which
re-derives the snapshot (pct, free tokens) and reports whether it
changed so a follower redraws on a window-only change.
- Tests: the bare `/model <name>` dispatch path asserts the snapshot and
the drawn header; follower with/without the field; same-model new
window redraw; actor returns the window; serde round trip.
Claude-Session: https://claude.ai/code/session_01RUqV8HVGXcAETyYbZ2tPQ4
This commit is contained in:
1 parent
ff92a00fea
commit
b957e12370
16 files changed
+288
-27
No files matched your search
@@ -1518,6 +1518,9 @@ mod load_user_prompts_tests;
|
||||
#[path = "acp_session_tests/memory_config_tests.rs"]
|
||||
mod memory_config_tests;
|
||||
#[cfg(test)]
|
||||
#[path = "acp_session_tests/model_switch_window_tests.rs"]
|
||||
mod model_switch_window_tests;
|
||||
#[cfg(test)]
|
||||
#[path = "acp_session_tests/parallel_dispatch_tests.rs"]
|
||||
mod parallel_dispatch_tests;
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -10,7 +10,7 @@ impl SessionActor {
|
||||
apply_prompt_override: bool,
|
||||
skip_prompt_rewrite: bool,
|
||||
auto_compact_threshold_percent: u8,
|
||||
) -> Result<acp::ModelId, acp::Error> {
|
||||
) -> Result<(acp::ModelId, std::num::NonZeroU64), acp::Error> {
|
||||
let model_id = acp::ModelId::new(sampling_config.model.clone());
|
||||
// H4: record the picker's catalog KEY as this SESSION's own selection.
|
||||
// `sampling_config.model` is the ambiguous bare slug; the key is what
|
||||
@@ -120,7 +120,7 @@ impl SessionActor {
|
||||
agent_name: Some(agent_name),
|
||||
reasoning_effort: Some(sampling_config.reasoning_effort),
|
||||
});
|
||||
Ok(model_id)
|
||||
Ok((model_id, new_context_window))
|
||||
}
|
||||
/// Handle [`SessionCommand::RebuildAgentForDefinition`].
|
||||
///
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
//! `handle_set_session_model` reports the session's effective context
|
||||
//! window so clients repaint their header without waiting for a turn.
|
||||
use super::support::*;
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn set_session_model_returns_the_effective_context_window() {
|
||||
let local = tokio::task::LocalSet::new();
|
||||
local
|
||||
.run_until(async {
|
||||
let (actor, _rx) = build_actor().await;
|
||||
let cfg = kigi_sampler::SamplerConfig {
|
||||
model: "narrow".to_string(),
|
||||
context_window: 128_000,
|
||||
..Default::default()
|
||||
};
|
||||
let (model_id, window) = actor
|
||||
.handle_set_session_model(cfg, None, false, false, true, 85)
|
||||
.await
|
||||
.expect("model switch");
|
||||
assert_eq!(model_id.0.as_ref(), "narrow");
|
||||
assert_eq!(window.get(), 128_000);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
@@ -173,7 +173,9 @@ pub enum SessionCommand {
|
||||
/// `compaction.threshold_percent` (which is `Cell<u8>` so it can
|
||||
/// update without `&mut self`).
|
||||
auto_compact_threshold_percent: u8,
|
||||
responds_to: oneshot::Sender<Result<acp::ModelId, acp::Error>>,
|
||||
/// Ok: the applied model id and the session's effective context
|
||||
/// window, which clients repaint from without waiting for a turn.
|
||||
responds_to: oneshot::Sender<Result<(acp::ModelId, std::num::NonZeroU64), acp::Error>>,
|
||||
},
|
||||
/// Zero-turn harness rebuild: build a brand-new `Agent` from the
|
||||
/// session's `AgentRebuildSpec` and the new `AgentDefinition`,
|
||||
|
||||
Reference in new issue
Block a user