v1.4.0: Auto-compact streaming, Bedrock summarization support, subagent orchestration, and Galaxy rebrand continuation

Major features:
- Auto-compact: triggers conversation summarization when context window >= 85%,
  compacts Bedrock message history to a summary pair, and tracks live context tokens
- Bedrock summarization: plumbs `is_summarization` flag through translator/client/response
  pipeline, handles SummarizeConversation input type, and marks `summarized` in metadata
- Session restore: rebuilds bedrock_message_history from persisted task messages via
  newly-public `convert_proto_message`, preventing empty history on reconnect
- Subagent orchestration: adds SubagentQuestion/Answer/CompletionSummary event types,
  parent-child question routing with depth limits, retry counting, and drain methods
- Summarization UI: inline SummarizationView in AI blocks with progress/finished states

Refactors:
- Rename WarpTheme → GalaxyTheme across ~100 files (rebrand continuation)
- Rename warp_home_config_dir → galaxy_home_config_dir and related path functions
- Predefined rules: replace "System Defined Rule #N" with descriptive names
  (e.g. "Correctness Over Speed", "Never Guess") and add lookup helpers
- Usage view: replace cumulative input/output token display with live context tokens,
  cache hit rate calculation, and separate cache read/write stats
- Telemetry: remove verbose doc comments, simplify trait definitions
- Facts view: simplify delete permission check (always allow local deletion)
- Remove warp_managed_paths_watcher.rs (dead code)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ryan Ward
2026-05-21 11:59:37 -05:00
co-authored by Claude Opus 4.6
parent eaa2ddc75e
commit 6f54e2cb30
229 changed files with 2506 additions and 2634 deletions
+76 -3
View File
@@ -30,7 +30,7 @@ use galaxy_core::features::FeatureFlag;
use galaxy_core::send_telemetry_from_ctx;
use galaxy_core::ui::appearance::Appearance;
use galaxy_core::ui::theme::color::internal_colors;
use galaxy_core::ui::theme::WarpTheme;
use galaxy_core::ui::theme::GalaxyTheme;
use galaxyui::color::ColorU;
use galaxyui::{EntityId, ModelContext, SingletonEntity};
use uuid::Uuid;
@@ -235,6 +235,19 @@ pub struct AIConversation {
/// tool calls, and tool results sent to/received from Bedrock across all
/// request cycles. This is the source of truth for what Bedrock sees.
bedrock_message_history: Vec<crate::ai::bedrock::convert::ConversationMessage>,
/// Live context token count from the most recent Bedrock response.
/// This is the actual input_tokens reported by Bedrock — represents the current
/// context window size, NOT a cumulative total.
current_context_tokens: u32,
/// Guards against repeated auto-compact triggers within the same high-usage window.
/// Set to true when auto-compact fires; reset when summarization completes.
has_pending_auto_compact: bool,
/// Number of times this child agent conversation has been automatically
/// restarted after a transient error. Capped at MAX_SUBAGENT_RETRIES.
subagent_retry_count: u8,
}
pub(crate) fn artifact_from_fork_proto(
@@ -287,6 +300,9 @@ impl AIConversation {
is_remote_child: false,
last_event_sequence: None,
bedrock_message_history: Vec::new(),
current_context_tokens: 0,
has_pending_auto_compact: false,
subagent_retry_count: 0,
}
}
@@ -314,6 +330,20 @@ impl AIConversation {
.cmp(depths.get(a.as_str()).unwrap_or(&0))
});
// Collect all task messages for rebuilding bedrock_message_history on restore.
// We must do this before consuming the tasks into exchanges.
let all_task_messages: Vec<&api::Message> = api_tasks_by_id
.values()
.flat_map(|task| task.messages.iter())
.collect();
let bedrock_message_history: Vec<crate::ai::bedrock::convert::ConversationMessage> =
all_task_messages
.iter()
.filter_map(|msg| {
crate::ai::bedrock::request_translator::convert_proto_message(msg)
})
.collect();
let mut api_tasks_and_exchanges_by_id: HashMap<_, _> = api_tasks_by_id
.into_iter()
.map(|(id, task)| {
@@ -469,7 +499,10 @@ impl AIConversation {
parent_conversation_id,
is_remote_child: false,
last_event_sequence,
bedrock_message_history: Vec::new(),
bedrock_message_history,
current_context_tokens: 0,
has_pending_auto_compact: false,
subagent_retry_count: 0,
})
}
@@ -521,6 +554,26 @@ impl AIConversation {
self.conversation_usage_metadata.context_window_usage
}
pub fn set_context_window_usage(&mut self, value: f32) {
self.conversation_usage_metadata.context_window_usage = value;
}
pub fn current_context_tokens(&self) -> u32 {
self.current_context_tokens
}
pub fn set_current_context_tokens(&mut self, tokens: u32) {
self.current_context_tokens = tokens;
}
pub fn has_pending_auto_compact(&self) -> bool {
self.has_pending_auto_compact
}
pub fn set_has_pending_auto_compact(&mut self, value: bool) {
self.has_pending_auto_compact = value;
}
pub fn credits_spent(&self) -> f32 {
(self.conversation_usage_metadata.credits_spent * 10.0).round() / 10.0
}
@@ -859,6 +912,14 @@ impl AIConversation {
self.is_remote_child = true;
}
pub fn subagent_retry_count(&self) -> u8 {
self.subagent_retry_count
}
pub fn increment_subagent_retry_count(&mut self) {
self.subagent_retry_count = self.subagent_retry_count.saturating_add(1);
}
/// Returns a flat list of linearized messages across all tasks, interpolating subtask messages
/// in between subagent tool calls and results, effectively corresponding to the order in which
/// the messages were created and added to the conversation.
@@ -1566,6 +1627,17 @@ impl AIConversation {
if was_user_initiated_request {
self.last_block_token_usage_by_model.clear();
}
// Update live context token count from this response's input tokens.
// This represents the actual current context window size (not cumulative).
let live_input: u32 = token_usage
.iter()
.map(|u| u.total_input + u.input_cache_read + u.input_cache_write)
.sum();
if live_input > 0 {
self.current_context_tokens = live_input;
}
for usage in token_usage.into_iter() {
let entry = self
.total_token_usage_by_model
@@ -1666,6 +1738,7 @@ impl AIConversation {
// so we only update the summarized flag if it's going from false to true.
if usage_metadata.summarized && !self.conversation_usage_metadata.was_summarized {
self.conversation_usage_metadata.was_summarized = usage_metadata.summarized;
self.has_pending_auto_compact = false;
}
}
Ok(())
@@ -3844,7 +3917,7 @@ impl ConversationStatus {
}
}
pub fn status_icon_and_color(&self, theme: &WarpTheme) -> (Icon, ColorU) {
pub fn status_icon_and_color(&self, theme: &GalaxyTheme) -> (Icon, ColorU) {
match self {
ConversationStatus::InProgress => (Icon::ClockLoader, theme.ansi_fg_magenta()),
ConversationStatus::Success => (Icon::Check, theme.ansi_fg_green()),