Reduce session logging and background churn

This commit is contained in:
Ryan Ward
2026-09-02 15:13:24 -05:00
parent 13cbb232ee
commit b115946534
29 changed files with 268 additions and 127 deletions
-7
View File
@@ -216,13 +216,6 @@ impl BedrockClient {
tools.len()
);
log::info!(
"[bedrock] Sending request payload to Bedrock:\nSystem Prompt: {:?}\nMessages: {:#?}\nTools: {:#?}",
system_prompt,
messages,
tools
);
let converted = build_converse_request(
messages.clone(),
system_prompt.clone(),
+21 -7
View File
@@ -269,11 +269,17 @@ impl CurrentPrompt {
if let Some(session) = session {
let buffer_text = editor.as_ref(ctx).buffer_text(ctx);
let mut should_notify = false;
for (kind, state) in me.states.iter_mut() {
state.should_render =
kind.should_render(&buffer_text, session.aliases());
let should_render = kind.should_render(&buffer_text, session.aliases());
if state.should_render != should_render {
state.should_render = should_render;
should_notify = true;
}
}
if should_notify {
ctx.notify();
}
ctx.notify();
}
}
}
@@ -321,7 +327,10 @@ impl CurrentPrompt {
}
fn update_chip_value(&mut self, chip_kind: &ContextChipKind, value: Option<ChipValue>) {
log::debug!("Updating prompt value of {chip_kind:?} to {value:?}");
log::trace!(
"Updating prompt value of {chip_kind:?}; has_value={}",
value.is_some()
);
if let Some(state) = self.states.get_mut(chip_kind) {
if state.last_computed_value != value {
state.last_computed_value = value;
@@ -332,14 +341,19 @@ impl CurrentPrompt {
}
fn update_on_click_value(&mut self, chip_kind: &ContextChipKind, value: Option<Vec<String>>) {
log::debug!("Updating prompt on_click value of {chip_kind:?} to {value:?}");
log::trace!(
"Updating prompt on_click value of {chip_kind:?}; item_count={}",
value.as_ref().map_or(0, Vec::len)
);
let filter_values = match chip_kind {
ContextChipKind::ShellGitBranch => self.filter_git_branch_on_click_values(value),
_ => value,
};
if let Some(state) = self.states.get_mut(chip_kind) {
state.last_on_click_values = filter_values;
let _ = self.update_tx.try_send(());
if state.last_on_click_values != filter_values {
state.last_on_click_values = filter_values;
let _ = self.update_tx.try_send(());
}
}
}
-1
View File
@@ -47,7 +47,6 @@ impl PromptSnapshot {
})
.collect_vec();
log::debug!("Current prompt snapshot: {chips:?}");
Self {
chips,
same_line_prompt_enabled: current_prompt.same_line_prompt_enabled(),
+4 -1
View File
@@ -492,7 +492,10 @@ impl EditorView {
self.stop_transcribing_voice_input(ctx);
match result {
Ok(transcribe_response) => {
log::debug!("Transcribed voice input: {transcribe_response:?}");
log::debug!(
"Transcribed voice input; characters={}",
transcribe_response.chars().count()
);
self.user_insert(&transcribe_response, ctx);
}
Err(e) => match e {
+2 -2
View File
@@ -2396,7 +2396,7 @@ pub(crate) fn app_callbacks(
// Persist the final app state before tearing down the writer.
// This ensures the latest session (tabs, CWD, conversations) is saved
// even if the termination bypassed individual window-close events.
ctx.dispatch_global_action("workspace:save_app", &());
workspace::save_app_urgently(ctx);
NotebookManager::handle(ctx).update(ctx, |manager, ctx| {
// Notebooks are only saved periodically, so ensure that any pending changes have
@@ -2634,7 +2634,7 @@ pub(crate) fn app_callbacks(
stack.handle_window_closed(window_data, ctx);
});
}
ctx.dispatch_global_action("workspace:save_app", &());
workspace::save_app_urgently(ctx);
})),
on_window_moved: Some(Box::new(move |ctx| {
ctx.dispatch_global_action("workspace:save_app", &());
+6 -6
View File
@@ -499,7 +499,7 @@ impl PaneContent for TerminalPane {
let ambient_model = ambient_model.as_ref(app);
let task_id = ambient_model.task_id();
log::info!("[session-save] pane=viewer/ambient task_id={task_id:?}");
log::trace!("[session-snapshot] pane=viewer/ambient task_id={task_id:?}");
return LeafContents::AmbientAgent(AmbientAgentPaneSnapshot {
uuid: self.uuid.clone(),
task_id,
@@ -507,7 +507,7 @@ impl PaneContent for TerminalPane {
}
let cwd = view.pwd_if_local(app);
log::info!("[session-save] pane=viewer cwd={cwd:?} is_active={is_active}");
log::trace!("[session-snapshot] pane=viewer cwd={cwd:?} is_active={is_active}");
LeafContents::Terminal(TerminalPaneSnapshot {
uuid: self.uuid.clone(),
cwd,
@@ -533,14 +533,14 @@ impl PaneContent for TerminalPane {
// can be restored via the ambient agent task if one exists.
let task_id = view.model.lock().ambient_agent_task_id();
if task_id.is_some() {
log::info!("[session-save] pane=transcript/ambient task_id={task_id:?}");
log::trace!("[session-snapshot] pane=transcript/ambient task_id={task_id:?}");
LeafContents::AmbientAgent(AmbientAgentPaneSnapshot {
uuid: self.uuid.clone(),
task_id,
})
} else {
let cwd = view.pwd_if_local(app);
log::info!("[session-save] pane=transcript cwd={cwd:?} is_active={is_active}");
log::trace!("[session-snapshot] pane=transcript cwd={cwd:?} is_active={is_active}");
LeafContents::Terminal(TerminalPaneSnapshot {
uuid: self.uuid.clone(),
cwd,
@@ -584,8 +584,8 @@ impl PaneContent for TerminalPane {
});
let cwd = view.pwd_if_local(app);
log::info!(
"[session-save] pane=terminal cwd={cwd:?} is_active={is_active} \
log::trace!(
"[session-snapshot] pane=terminal cwd={cwd:?} is_active={is_active} \
conversations={} active_conversation={active_conversation_id:?} \
has_shell_launch_data={} has_input_config=true",
conversation_ids_to_restore.len(),
+17 -1
View File
@@ -1000,7 +1000,7 @@ pub enum OpenAIProviderKind {
///
/// Multiple providers can be configured simultaneously. Each provider has its own endpoint,
/// credentials, and model list.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, schemars::JsonSchema)]
#[derive(Clone, Serialize, Deserialize, PartialEq, schemars::JsonSchema)]
#[schemars(description = "Configuration for a direct model provider endpoint.")]
pub struct OpenAIProviderConfig {
#[serde(default)]
@@ -1027,6 +1027,22 @@ pub struct OpenAIProviderConfig {
pub models: Vec<OpenAIModelConfig>,
}
impl std::fmt::Debug for OpenAIProviderConfig {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("OpenAIProviderConfig")
.field("kind", &self.kind)
.field("enabled", &self.enabled)
.field("name", &self.name)
.field("base_url", &self.base_url)
.field("api_key_configured", &self.api_key.is_some())
.field("project_id", &self.project_id)
.field("location", &self.location)
.field("models", &self.models)
.finish()
}
}
impl settings_value::SettingsValue for OpenAIProviderConfig {}
fn default_acp_agent_id() -> String {
+3
View File
@@ -391,6 +391,9 @@ fn native_provider_settings_roundtrip_with_vertex_configuration() {
}))
.expect("Native OpenAI provider settings should deserialize");
assert_eq!(native_openai.kind, OpenAIProviderKind::OpenAI);
let debug_output = format!("{native_openai:?}");
assert!(!debug_output.contains("sk-test"));
assert!(debug_output.contains("api_key_configured: true"));
}
#[test]
@@ -260,18 +260,19 @@ fn wire_up_terminal_view_session_sharing(
if *SessionSettings::as_ref(ctx).honor_ps1 {
return
}
let Some(network) = session_sharer_clone.borrow().clone() else {
return;
};
let prompt_snapshot = current_prompt.read(ctx, |current_prompt, ctx| {
PromptSnapshot::from_current_prompt(current_prompt, ctx)
});
if let Some(network) = session_sharer_clone.borrow().as_ref() {
let Ok(serialized_prompt) = serde_json::to_string(&prompt_snapshot) else {
log::error!("Failed to serialize prompt snapshot to send active prompt update to shared session server");
return
};
network.update(ctx, |network, _| {
network.send_active_prompt_update_if_changed(session_sharing_protocol::common::ActivePrompt::WarpPrompt(serialized_prompt))
});
}
let Ok(serialized_prompt) = serde_json::to_string(&prompt_snapshot) else {
log::error!("Failed to serialize prompt snapshot to send active prompt update to shared session server");
return
};
network.update(ctx, |network, _| {
network.send_active_prompt_update_if_changed(session_sharing_protocol::common::ActivePrompt::WarpPrompt(serialized_prompt))
});
});
let session_sharer_clone = session_sharer.clone();
@@ -264,11 +264,11 @@ fn add_local_machine_env(env: &mut BTreeMap<OsString, EnvEntry>) {
let Ok(value) = reg_value_to_string(&value, &name) else {
safe_info!(
safe: ("Unable to convert value for key {name:?}"),
full: ("Unable to convert value for key {name:?}: {:?}", value.bytes)
full: ("Unable to convert value for key {name:?}")
);
continue;
};
log::trace!("adding SYS env: {name:?} = {value:?}");
log::trace!("adding SYS env: {name:?}");
env.insert(
map_key(name.clone().into()),
EnvEntry {
@@ -289,7 +289,7 @@ fn add_user_env(env: &mut BTreeMap<OsString, EnvEntry>) {
let Ok(value) = reg_value_to_string(&value, &name) else {
safe_info!(
safe: ("Unable to convert value for key {name:?}"),
full: ("Unable to convert value for key {name:?}: {:?}", value.bytes)
full: ("Unable to convert value for key {name:?}")
);
continue;
};
@@ -309,7 +309,7 @@ fn add_user_env(env: &mut BTreeMap<OsString, EnvEntry>) {
value
};
log::trace!("adding USER env: {name:?} = {value:?}");
log::trace!("adding USER env: {name:?}");
env.insert(
map_key(name.clone().into()),
EnvEntry {
@@ -19,7 +19,10 @@ pub(super) fn parse_ansi_c_quoted_string(quoted_string: String) -> String {
if quoted_string.trim().is_empty() {
return quoted_string;
}
log::debug!("Attempting to parse the following ANSI C escaped shell output: {quoted_string}");
log::debug!(
"Attempting to parse ANSI-C escaped shell output; bytes={}",
quoted_string.len()
);
let Some(quoted_string_without_prefix) = quoted_string.strip_prefix("$\'") else {
log::warn!("Tried to parse ANSI-C quoted string but $\' prefix was not present");
+3 -9
View File
@@ -653,10 +653,7 @@ impl<'a, H: Handler + 'a, W: io::Write> Performer<'a, H, W> {
fn handle_decoded_data(&mut self, decoded_data: Result<Vec<u8>, hex::FromHexError>) {
match decoded_data {
Ok(decoded_data) => {
safe_debug!(
safe: ("Decoded payload"),
full: ("Decoded payload string: {:?}", std::str::from_utf8(&decoded_data))
);
log::debug!("Decoded shell hook payload; bytes={}", decoded_data.len());
let hook = serde_json::from_slice::<DProtoHook>(&decoded_data);
if let Ok(hook) = &hook {
@@ -691,10 +688,7 @@ impl<'a, H: Handler + 'a, W: io::Write> Performer<'a, H, W> {
return;
}
};
safe_debug!(
safe: ("Decoded payload"),
full: ("Decoded payload string: {:?}", serde_json::to_string(&hook))
);
log::debug!("Decoded key-value shell hook payload");
self.handle_decoded_hook(Ok(hook));
}
Some(&WARP_KV_ENTRY_BYTE) => {
@@ -888,7 +882,7 @@ where
.map(|parts| parts.join(";").trim().to_owned());
if let Ok(body) = body {
if !body.is_empty() {
log::info!("Received OSC 9 notification: {}", body);
log::info!("Received OSC 9 notification; bytes={}", body.len());
self.handler.pluggable_notification(None, body);
return;
}
-1
View File
@@ -3058,7 +3058,6 @@ impl BlockList {
if let Some(prompt_snapshot) = &block.prompt_snapshot {
if let Ok(prompt_snapshot) = serde_json::from_str(prompt_snapshot) {
log::debug!("Restored prompt: {prompt_snapshot:?}");
self.active_block_mut().set_prompt_snapshot(prompt_snapshot);
}
}
-1
View File
@@ -356,7 +356,6 @@ impl Sessions {
let session = Session::new(session_info.clone(), command_executor);
log::info!("Shell is bootstrapped with session_id {:?}", session.id());
log::debug!("Session details: {session:?}");
let session = Arc::new(session);
self.sessions.insert(session.id(), session.clone());
+108 -36
View File
@@ -1,14 +1,16 @@
use std::path::PathBuf;
use std::time::Duration;
use ::settings::ToggleableSetting;
use galaxy_core::execution_mode::AppExecutionMode;
use galaxy_graphql::mutations::create_anonymous_user::AnonymousUserType;
use galaxyui::r#async::{SpawnedFutureHandle, Timer};
use galaxyui::windowing::WindowManager;
use galaxyui::{AppContext, SingletonEntity, TypedActionView};
use galaxyui::{AppContext, Entity, ModelContext, SingletonEntity, TypedActionView};
use crate::ai::agent::conversation::AIConversationId;
use crate::ai::agent::AIAgentExchangeId;
use crate::app_state::get_app_state;
use crate::app_state::{get_app_state, AppState};
use crate::network::NetworkStatus;
use crate::persistence::ModelEvent;
use crate::root_view::OpenPath;
@@ -20,6 +22,102 @@ use crate::workspace::cross_window_tab_drag::CrossWindowTabDrag;
use crate::workspace::{Workspace, WorkspaceAction};
use crate::{auth, GlobalResourceHandlesProvider};
const SESSION_SAVE_DEBOUNCE: Duration = Duration::from_millis(250);
pub(crate) struct SessionSaveCoordinator {
last_enqueued_state: Option<AppState>,
pending_save: bool,
timer_generation: u64,
timer: Option<SpawnedFutureHandle>,
}
impl SessionSaveCoordinator {
pub(crate) fn new() -> Self {
Self {
last_enqueued_state: None,
pending_save: false,
timer_generation: 0,
timer: None,
}
}
fn request_save(&mut self, ctx: &mut ModelContext<Self>) {
if !session_save_is_enabled(ctx) {
return;
}
if self.timer.is_none() {
self.save_if_changed(ctx);
} else {
self.pending_save = true;
}
self.restart_timer(ctx);
}
fn save_urgently(&mut self, ctx: &mut ModelContext<Self>) {
self.timer_generation = self.timer_generation.wrapping_add(1);
if let Some(timer) = self.timer.take() {
timer.abort();
}
self.pending_save = false;
if session_save_is_enabled(ctx) {
self.save_if_changed(ctx);
}
}
fn restart_timer(&mut self, ctx: &mut ModelContext<Self>) {
if let Some(timer) = self.timer.take() {
timer.abort();
}
self.timer_generation = self.timer_generation.wrapping_add(1);
let generation = self.timer_generation;
self.timer = Some(ctx.spawn(
async move { Timer::after(SESSION_SAVE_DEBOUNCE).await },
move |coordinator, _, ctx| {
if coordinator.timer_generation != generation {
return;
}
coordinator.timer = None;
if std::mem::take(&mut coordinator.pending_save) {
coordinator.save_if_changed(ctx);
}
},
));
}
fn save_if_changed(&mut self, ctx: &mut ModelContext<Self>) {
let Some(model_event_sender) = GlobalResourceHandlesProvider::as_ref(ctx)
.get()
.model_event_sender
.clone()
else {
return;
};
let app_state = get_app_state(ctx);
if self.last_enqueued_state.as_ref() == Some(&app_state) {
return;
}
if let Err(err) = model_event_sender.send(ModelEvent::Snapshot(app_state.clone())) {
log::error!("Error trying to send model event {err:?}");
return;
}
self.last_enqueued_state = Some(app_state);
}
}
impl Entity for SessionSaveCoordinator {
type Event = ();
}
impl SingletonEntity for SessionSaveCoordinator {}
fn session_save_is_enabled(ctx: &AppContext) -> bool {
AppExecutionMode::as_ref(ctx).can_save_session()
&& *GeneralSettings::as_ref(ctx).restore_session
&& !CrossWindowTabDrag::as_ref(ctx).is_active()
}
/// Specifies where a forked conversation should be opened.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum ForkedConversationDestination {
@@ -130,41 +228,15 @@ fn toggle_focus_reporting(_: &(), ctx: &mut AppContext) {
}
fn save_app(_: &(), ctx: &mut AppContext) {
if !AppExecutionMode::as_ref(ctx).can_save_session() {
return;
}
SessionSaveCoordinator::handle(ctx).update(ctx, |coordinator, ctx| {
coordinator.request_save(ctx);
});
}
if !*GeneralSettings::as_ref(ctx).restore_session {
return;
}
// While a cross-window tab drag is active, the dragged tab's pane group
// is in flight between source and preview windows and `get_app_state`
// would produce a snapshot with zero windows. Persisting that snapshot
// wipes the on-disk session via `save_app_state`'s delete-then-insert
// transaction. `save_app` fires from window move / focus / resize /
// close callbacks (see `app_callbacks` in `lib.rs`), all of which run
// during a drag, so we have to short-circuit at this boundary. The
// first save after the drag finalizes will rewrite the snapshot.
if CrossWindowTabDrag::as_ref(ctx).is_active() {
return;
}
let Some(model_event_sender) = GlobalResourceHandlesProvider::as_ref(ctx)
.get()
.model_event_sender
.clone()
else {
return;
};
// Only compute the app state if we're definitely going to use it.
let app_state = get_app_state(ctx);
let event = ModelEvent::Snapshot(app_state);
if let Err(err) = model_event_sender.send(event) {
log::error!("Error trying to send model event {err:?}");
}
pub(crate) fn save_app_urgently(ctx: &mut AppContext) {
SessionSaveCoordinator::handle(ctx).update(ctx, |coordinator, ctx| {
coordinator.save_urgently(ctx);
});
}
fn toggle_debug_network_status(_: &(), ctx: &mut AppContext) {
+2
View File
@@ -30,6 +30,7 @@ pub use action::{
};
pub use active_session::ActiveSession;
use galaxy_core::context_flag::ContextFlag;
pub(crate) use global_actions::save_app_urgently;
pub use global_actions::{
ForkAIConversationParams, ForkFromExchange, ForkedConversationDestination,
};
@@ -78,6 +79,7 @@ use crate::workspace::view::{
pub fn init(app: &mut AppContext) {
app.add_singleton_model(|_| WorkspaceRegistry::new());
app.add_singleton_model(|_| cross_window_tab_drag::CrossWindowTabDrag::new());
app.add_singleton_model(|_| global_actions::SessionSaveCoordinator::new());
use galaxyui::keymap::macros::*;
app.register_binding_validator::<Workspace>(is_binding_pty_compliant);