@setoelkahfi / sigit / commits / 6bf9997

Add /reload command to re-sync session state in place

Logging in mid-session shouldn't require recreating the session. /reload re-applies the active backend from current credentials (picking up a fresh /login token), retries a failed startup model load, and pushes refreshed config options + available commands so the editor's UI reflects current state — all without a new session. Also: - Correct the /login message: it no longer claims sign-in "applies to your next session" (the backend swaps in-session); it now points to /models. - /logout drops back to the local backend when leaving a cloud tier. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Seto Elkahfi committed Jun 24, 2026 at 17:22 UTC 6bf9997f89dd9ddde22b0811e175ae8d9920ea5d
1 file changed +83 -2
src/main.rs
+83 -2
@@ -46,7 +46,8 @@ use onde::inference::SamplingConfig;
46
47 use agent_client_protocol::schema::{
48 AgentCapabilities, AuthMethod, AuthMethodAgent, AuthenticateRequest, AuthenticateResponse,
49 - AvailableCommand, AvailableCommandInput, AvailableCommandsUpdate, UnstructuredCommandInput,
49 + AvailableCommand, AvailableCommandInput, AvailableCommandsUpdate, ConfigOptionUpdate,
50 + UnstructuredCommandInput,
51 CancelNotification, ContentBlock, ContentChunk, EmbeddedResourceResource, ForkSessionRequest,
52 ForkSessionResponse, Implementation, InitializeRequest, InitializeResponse, LoadSessionRequest,
53 LoadSessionResponse, Meta, NewSessionRequest, NewSessionResponse, PromptRequest,
@@ -596,6 +597,7 @@ impl SiGitAgent {
597 with_hint("login", "Sign in to siGit Code Cloud", "<email> <password>"),
598 AvailableCommand::new("logout", "Sign out of siGit Code Cloud"),
599 AvailableCommand::new("whoami", "Show the signed-in account"),
600 + AvailableCommand::new("reload", "Re-sync sign-in and model state"),
601 AvailableCommand::new("clear", "Wipe the conversation history"),
602 AvailableCommand::new("status", "Show engine status"),
603 ];
@@ -1214,6 +1216,70 @@ impl SiGitAgent {
1216 *self.backend.lock().await = local_backend;
1217 }
1218
1219 + /// Re-attempt the lazy startup model load if the previous attempt failed.
1220 + /// Clears the one-shot guard so the next load runs; a healthy load is left
1221 + /// untouched so `/reload` doesn't needlessly reload a working model.
1222 + fn retry_startup_model_load_if_failed(&self) {
1223 + let had_error = self
1224 + .model_load_error
1225 + .lock()
1226 + .map(|guard| guard.is_some())
1227 + .unwrap_or(false);
1228 + if had_error {
1229 + self.startup_model_load_started
1230 + .store(false, Ordering::Release);
1231 + self.start_startup_model_load_if_needed();
1232 + }
1233 + }
1234 +
1235 + /// Re-sync session state in place — no new session needed. Re-applies the
1236 + /// active backend from current credentials (so a fresh `/login` token is
1237 + /// picked up), retries a failed model load, and pushes refreshed commands +
1238 + /// picker so the editor's UI reflects the current state.
1239 + async fn handle_reload(&self, cx: &ConnectionTo<Client>, session_id: SessionId) {
1240 + let signed_in = account::status_line().await;
1241 +
1242 + let on_cloud_tier = {
1243 + let guard = self.current_model.lock().unwrap();
1244 + guard
1245 + .model_id
1246 + .strip_prefix("sigit-cloud:")
1247 + .map(str::to_string)
1248 + };
1249 +
1250 + let backend_note = match on_cloud_tier {
1251 + Some(tier) => match self.switch_to_cloud_tier(&tier).await {
1252 + Some(name) => format!("Active: {name}."),
1253 + None => {
1254 + self.reset_to_local_backend().await;
1255 + "Signed out — back to on-device. Pick a model with /models.".to_string()
1256 + }
1257 + },
1258 + None => {
1259 + self.reset_to_local_backend().await;
1260 + self.retry_startup_model_load_if_failed();
1261 + let guard = self.current_model.lock().unwrap();
1262 + format!("Active: {}.", guard.display_name)
1263 + }
1264 + };
1265 +
1266 + // Push refreshed picker + commands so the editor reflects current state.
1267 + let config_options = {
1268 + let guard = self.current_model.lock().unwrap();
1269 + build_model_config_options(&guard)
1270 + };
1271 + self.send_tool_call_update(
1272 + cx,
1273 + session_id.clone(),
1274 + SessionUpdate::ConfigOptionUpdate(ConfigOptionUpdate::new(config_options)),
1275 + )
1276 + .ok();
1277 + self.advertise_commands(cx, session_id.clone());
1278 +
1279 + self.send_assistant_message(cx, session_id, format!("Reloaded. {signed_in} {backend_note}"))
1280 + .ok();
1281 + }
1282 +
1283 async fn handle_set_session_config_option(
1284 &self,
1285 cx: &ConnectionTo<Client>,
@@ -1609,6 +1675,8 @@ enum SlashCommand {
1675 Login(Option<String>),
1676 Logout,
1677 Whoami,
1678 + /// Re-sync session state (auth, backend, picker) without a new session.
1679 + Reload,
1680 Exit,
1681 Unknown(String),
1682 }
@@ -1629,6 +1697,7 @@ fn parse_slash(input: &str) -> Option<SlashCommand> {
1697 "/login" => SlashCommand::Login(argument.map(str::to_string)),
1698 "/logout" => SlashCommand::Logout,
1699 "/whoami" => SlashCommand::Whoami,
1700 + "/reload" => SlashCommand::Reload,
1701 "/exit" | "/quit" | "/q" => SlashCommand::Exit,
1702 other => SlashCommand::Unknown(other.to_string()),
1703 })
@@ -1722,6 +1791,7 @@ async fn exec_slash_acp(
1791 /login E P - sign in to siGit Code Cloud\n\
1792 /logout - sign out\n\
1793 /whoami - show the signed-in account\n\
1794 + /reload - re-sync sign-in and model state\n\
1795 /clear - wipe conversation history\n\
1796 /status - show engine status\n\
1797 /exit - end this turn",
@@ -1858,7 +1928,7 @@ async fn exec_slash_acp(
1928 let message = match argument.as_deref().and_then(account::parse_login_args) {
1929 Some((email, password)) => match account::authenticate(&email, &password).await {
1930 Ok(email) => format!(
1861 - "Signed in as {email}. siGit Code Cloud applies to your next session."
1931 + "Signed in as {email}. Pick a siGit Code Cloud tier in /models to use it."
1932 ),
1933 Err(error) => format!("Login failed: {error}"),
1934 },
@@ -1867,13 +1937,24 @@ async fn exec_slash_acp(
1937 agent.send_assistant_message(cx, session_id, message).ok();
1938 }
1939 SlashCommand::Logout => {
1940 + // If we're on a cloud tier, drop back to local — the token is gone.
1941 + let on_cloud = {
1942 + let guard = agent.current_model.lock().unwrap();
1943 + guard.model_id.starts_with("sigit-cloud:")
1944 + };
1945 let message = account::end_session().await;
1946 + if on_cloud {
1947 + agent.reset_to_local_backend().await;
1948 + }
1949 agent.send_assistant_message(cx, session_id, message).ok();
1950 }
1951 SlashCommand::Whoami => {
1952 let message = account::status_line().await;
1953 agent.send_assistant_message(cx, session_id, message).ok();
1954 }
1955 + SlashCommand::Reload => {
1956 + agent.handle_reload(cx, session_id).await;
1957 + }
1958 SlashCommand::Exit => {
1959 agent
1960 .send_assistant_message(