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
+86
View File
@@ -90,6 +90,7 @@ use crate::ai::blocklist::inline_action::aws_bedrock_credentials_error::{
use crate::ai::blocklist::inline_action::search_codebase::{
SearchCodebaseView, SearchCodebaseViewEvent,
};
use crate::ai::blocklist::inline_action::summarization::SummarizationView;
use crate::ai::blocklist::inline_action::web_fetch::WebFetchView;
use crate::ai::blocklist::inline_action::web_search::WebSearchView;
use crate::ai::facts::{AIFact, AIMemory, CloudAIFactModel};
@@ -830,6 +831,9 @@ pub struct AIBlock {
/// Map from web fetch message IDs to their view handles.
web_fetch_views: HashMap<MessageId, ViewHandle<WebFetchView>>,
/// Map from summarization message IDs to their view handles.
summarization_views: HashMap<MessageId, ViewHandle<SummarizationView>>,
/// Map from todo list IDs to their states.
todo_list_states: HashMap<MessageId, TodoListElementState>,
@@ -1340,6 +1344,7 @@ impl AIBlock {
search_codebase_view: Default::default(),
web_search_views: Default::default(),
web_fetch_views: Default::default(),
summarization_views: Default::default(),
requested_commands_to_auto_collapse: Default::default(),
review_changes_button,
open_all_comments_button,
@@ -1801,6 +1806,9 @@ impl AIBlock {
self.handle_web_fetch_messages(&output.messages, ctx);
}
self.handle_summarization_messages(&output.messages, ctx);
self.maybe_create_summarization_view_from_input(ctx);
for action in output.actions() {
let new_action_ids: HashSet<AIAgentActionId> =
output.actions().map(|action| action.id.clone()).collect();
@@ -3489,6 +3497,84 @@ impl AIBlock {
}
}
fn handle_summarization_messages(
&mut self,
messages: &[AIAgentOutputMessage],
ctx: &mut ViewContext<Self>,
) {
use crate::ai::agent::SummarizationType;
for message in messages {
let AIAgentOutputMessageType::Summarization {
finished_duration,
summarization_type,
..
} = &message.message
else {
continue;
};
if !matches!(summarization_type, SummarizationType::ConversationSummary) {
continue;
}
if let Some(view) = self.summarization_views.get(&message.id) {
if finished_duration.is_some() {
view.update(ctx, |view, ctx| {
view.mark_finished();
ctx.notify();
});
}
} else {
let is_finished = finished_duration.is_some();
let view = ctx.add_view(|ctx| {
let mut v = SummarizationView::new(ctx);
if is_finished {
v.mark_finished();
}
v
});
self.summarization_views.insert(message.id.clone(), view);
ctx.notify();
}
}
}
/// Creates a SummarizationView when the exchange input is a SummarizeConversation.
/// This handles the Bedrock path where no Summarization output message is emitted.
fn maybe_create_summarization_view_from_input(&mut self, ctx: &mut ViewContext<Self>) {
let is_summarize_input = self
.model
.inputs_to_render(ctx)
.iter()
.any(|i| matches!(i, AIAgentInput::SummarizeConversation { .. }));
if !is_summarize_input {
return;
}
let key = MessageId::new("__summarization_inline_view__".to_string());
if self.summarization_views.contains_key(&key) {
// Already created — check if we should mark it finished
let is_complete = !self.model.status(ctx).is_streaming();
if is_complete {
if let Some(view) = self.summarization_views.get(&key) {
view.update(ctx, |view, ctx| {
if !view.is_finished {
view.mark_finished();
ctx.notify();
}
});
}
}
return;
}
let view = ctx.add_view(|ctx| SummarizationView::new(ctx));
self.summarization_views.insert(key, view);
ctx.notify();
}
/// Note this is called when the search codebase tool call definition finishes streaming, not when the search actually completes.
fn handle_search_codebase_complete(
&mut self,