Correct what a switch actually does to a running session
Every one of these said a switch leaves running sessions alone - that they keep talking to the old provider until restarted. That is wrong, and reassuring in exactly the wrong direction: a switch breaks them. The static half of the config does behave as described. Base URL, model ids and the env block are read once at startup and a running session keeps what it started with. The credential is not. It comes from running apiKeyHelper, which Claude Code re-invokes on a timer - CLAUDE_CODE_API_KEY_HELPER_TTL_MS is present in the 2.1.251 binary - and claude-key-helper.sh answers for whatever state.json says at that moment. So the switch reaches into a live session through the one part that was never cached. Into anthropic, the helper returns nothing by design and the next refresh comes back with no credential; into another provider, it hands over the new key while the session is still pointed at the old base URL, which rejects it. Either way the session starts failing calls whenever the TTL happens to expire, mid-turn as easily as between turns. One case does survive, and is now stated rather than glossed: switching between two presets of the same provider that share a keyRef keeps the same key and the same endpoint, so the session carries on with the model ids it started with. The claim in "Restarting sessions" predates this work - it came in with the Windows build - but it is wrong for the same reason and is corrected too.
This commit is contained in:
@@ -48,10 +48,12 @@ Panel {
|
||||
|
||||
// ---- Switch flow
|
||||
//
|
||||
// A switch is not one action. It rewrites settings.json, which every future
|
||||
// session reads and no running session re-reads, so two things have to be
|
||||
// settled before the write: whether the target can actually serve requests,
|
||||
// and what should happen to the sessions still talking to the old one.
|
||||
// A switch is not one action. It rewrites settings.json, and two things have
|
||||
// to be settled before the write: whether the target can actually serve
|
||||
// requests, and what should happen to the sessions already running - which a
|
||||
// switch breaks rather than leaves alone, because their credential is
|
||||
// re-fetched on a timer and resolves to the new mode while their endpoint
|
||||
// stays the old one.
|
||||
//
|
||||
// list -> preflight -> blocked
|
||||
// -> sessions -> confirm -> switch -> list
|
||||
@@ -848,10 +850,15 @@ Panel {
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
// Not "they will keep using the old provider". Their endpoint and model
|
||||
// ids are fixed at startup, but the key is re-fetched on a timer and
|
||||
// will resolve to the new mode, which the old endpoint refuses - so
|
||||
// they fail rather than carry on.
|
||||
Text {
|
||||
width: parent.width
|
||||
text: "Claude Code reads its settings once, at startup, so these keep "
|
||||
+ Modes.title(root.mode) + " until they are restarted."
|
||||
text: "They keep pointing at " + Modes.title(root.mode) + ", but their key is "
|
||||
+ "re-fetched on a timer and will switch under them. Their calls start "
|
||||
+ "failing from that moment, not at a clean stop."
|
||||
color: Color.muted
|
||||
wrapMode: Text.WordWrap
|
||||
lineHeight: 1.2
|
||||
@@ -863,8 +870,8 @@ Panel {
|
||||
width: parent.width
|
||||
visible: parent.busyCount > 0
|
||||
text: parent.busyCount === 1
|
||||
? "One is working right now and will lose that turn."
|
||||
: parent.busyCount + " are working right now and will lose those turns."
|
||||
? "One is working right now and will break mid-turn."
|
||||
: parent.busyCount + " are working right now and will break mid-turn."
|
||||
color: root.urgentColor
|
||||
wrapMode: Text.WordWrap
|
||||
font.family: root.bar ? root.bar.fontFamily : Style.font.family
|
||||
|
||||
Reference in New Issue
Block a user