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:
co-authored by
Claude Opus 4.6
parent
eaa2ddc75e
commit
6f54e2cb30
@@ -5,49 +5,58 @@ pub struct PredefinedRule {
|
||||
|
||||
pub const SYSTEM_DEFINED_RULE_PREFIX: &str = "System Defined Rule";
|
||||
|
||||
pub fn is_predefined_rule(name: &str) -> bool {
|
||||
PREDEFINED_RULES.iter().any(|r| r.name == name)
|
||||
|| name.starts_with(SYSTEM_DEFINED_RULE_PREFIX)
|
||||
}
|
||||
|
||||
pub fn predefined_rule_index(name: &str) -> Option<usize> {
|
||||
PREDEFINED_RULES.iter().position(|r| r.name == name)
|
||||
}
|
||||
|
||||
pub const PREDEFINED_RULES: &[PredefinedRule] = &[
|
||||
PredefinedRule {
|
||||
name: "System Defined Rule #1",
|
||||
name: "Correctness Over Speed",
|
||||
content: "Prioritize correctness, completeness, and reliability over speed.",
|
||||
},
|
||||
PredefinedRule {
|
||||
name: "System Defined Rule #2",
|
||||
name: "Never Guess",
|
||||
content: "Never guess. If uncertain, explicitly say so and verify before finalizing.",
|
||||
},
|
||||
PredefinedRule {
|
||||
name: "System Defined Rule #3",
|
||||
name: "Evidence-Based Claims",
|
||||
content: "Ground non-trivial claims in evidence (repo files, command output, tests, official documentation).",
|
||||
},
|
||||
PredefinedRule {
|
||||
name: "System Defined Rule #4",
|
||||
name: "Verify When Uncertain",
|
||||
content: "If confidence is not high, or if a claim depends on external/current behavior, perform web verification before answering; prioritize official docs and cross-check with at least one additional reliable source.",
|
||||
},
|
||||
PredefinedRule {
|
||||
name: "System Defined Rule #5",
|
||||
name: "Separate Facts From Assumptions",
|
||||
content: "Clearly separate facts, assumptions, and hypotheses.",
|
||||
},
|
||||
PredefinedRule {
|
||||
name: "System Defined Rule #6",
|
||||
name: "Ask When Ambiguous",
|
||||
content: "Ask clarifying questions when ambiguity could change the solution or implementation.",
|
||||
},
|
||||
PredefinedRule {
|
||||
name: "System Defined Rule #7",
|
||||
name: "Validate Code Changes",
|
||||
content: "For code changes, run relevant validations when available (tests, lint, typecheck, build) and report what was run, what passed/failed, and what was not run.",
|
||||
},
|
||||
PredefinedRule {
|
||||
name: "System Defined Rule #8",
|
||||
name: "Disclose Unvalidated Risks",
|
||||
content: "If validation cannot be run, state that explicitly and describe residual risk and recommended manual checks.",
|
||||
},
|
||||
PredefinedRule {
|
||||
name: "System Defined Rule #9",
|
||||
name: "Admit Unknowns",
|
||||
content: "Prefer \"I don't know yet\" over plausible speculation.",
|
||||
},
|
||||
PredefinedRule {
|
||||
name: "System Defined Rule #10",
|
||||
name: "Challenge Bad Ideas",
|
||||
content: "If the user's idea is wrong, incomplete, risky, or non-optimal, say so directly and respectfully; explain why it may fail and provide a better alternative that still achieves the user's goal.",
|
||||
},
|
||||
PredefinedRule {
|
||||
name: "System Defined Rule #11",
|
||||
name: "Surface Disagreement",
|
||||
content: "Do not hide uncertainty, and do not avoid technical disagreement when correctness is at stake.",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
use crate::cloud_object::{
|
||||
CloudObject, CloudObjectSyncStatus, GenericStringObjectFormat, JsonObjectType,
|
||||
};
|
||||
use crate::drive::CloudObjectTypeAndId;
|
||||
use crate::cloud_object::{CloudObject, CloudObjectSyncStatus};
|
||||
use crate::network::NetworkStatus;
|
||||
use crate::pane_group::focus_state::PaneFocusHandle;
|
||||
use crate::pane_group::{pane::view, BackingView, PaneConfiguration, PaneEvent};
|
||||
@@ -337,22 +334,12 @@ pub fn is_online(app: &AppContext) -> bool {
|
||||
NetworkStatus::as_ref(app).is_online()
|
||||
}
|
||||
|
||||
pub fn is_delete_allowed(ai_fact: CloudAIFact, app: &AppContext) -> bool {
|
||||
let cloud_object_type_and_id = CloudObjectTypeAndId::GenericStringObject {
|
||||
object_type: GenericStringObjectFormat::Json(JsonObjectType::AIFact),
|
||||
id: ai_fact.sync_id(),
|
||||
};
|
||||
is_online(app)
|
||||
&& cloud_object_type_and_id.has_server_id()
|
||||
&& !ai_fact.metadata().has_pending_online_only_change()
|
||||
pub fn is_delete_allowed(_ai_fact: CloudAIFact, _app: &AppContext) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn is_edit_allowed(ai_fact: CloudAIFact, app: &AppContext) -> bool {
|
||||
let cloud_object_type_and_id = CloudObjectTypeAndId::GenericStringObject {
|
||||
object_type: GenericStringObjectFormat::Json(JsonObjectType::AIFact),
|
||||
id: ai_fact.sync_id(),
|
||||
};
|
||||
is_online(app) || !cloud_object_type_and_id.has_server_id()
|
||||
pub fn is_edit_allowed(_ai_fact: CloudAIFact, _app: &AppContext) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn is_syncing(ai_fact: CloudAIFact, app: &AppContext) -> bool {
|
||||
|
||||
@@ -46,8 +46,12 @@ use markdown_parser::{
|
||||
use std::fmt::Debug;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::{is_edit_allowed, is_syncing, style, AIFact, CloudAIFact, CloudAIFactModel};
|
||||
use crate::ai::facts::predefined_rules::{PREDEFINED_RULES, SYSTEM_DEFINED_RULE_PREFIX};
|
||||
use super::{
|
||||
is_delete_allowed, is_edit_allowed, is_syncing, style, AIFact, CloudAIFact, CloudAIFactModel,
|
||||
};
|
||||
use crate::ai::facts::predefined_rules::{
|
||||
is_predefined_rule, predefined_rule_index, PREDEFINED_RULES,
|
||||
};
|
||||
use crate::ai::facts::AIMemory;
|
||||
|
||||
pub const HEADER_TEXT: &str = "Rules";
|
||||
@@ -56,7 +60,7 @@ const DESCRIPTION_TEXT: &str = "Rules enhance the agent by providing structured
|
||||
const SEARCH_PLACEHOLDER_TEXT: &str = "Search rules";
|
||||
const ZERO_STATE_TEXT: &str = "Once you add a rule, it will be shown here.";
|
||||
const ZERO_STATE_TEXT_PROJECT: &str =
|
||||
"Once you generate a WARP.md rules file for a project, it will appear here.";
|
||||
"Once you generate a GALAXY.md rules file for a project, it will appear here.";
|
||||
|
||||
const DISABLED_BANNER_TEXT: &str =
|
||||
"Your rules are disabled and won't be used as context in sessions. You can ";
|
||||
@@ -84,6 +88,7 @@ pub enum RuleViewAction {
|
||||
AddPredefinedRules,
|
||||
InitializeProject,
|
||||
Edit(SyncId),
|
||||
Delete(SyncId),
|
||||
OpenSettings,
|
||||
SelectScope(RuleScope),
|
||||
OpenFile(PathBuf),
|
||||
@@ -94,6 +99,7 @@ pub struct MouseStateHandles {
|
||||
pub hover: MouseStateHandle,
|
||||
pub sync_status_hover: MouseStateHandle,
|
||||
pub sync_status_icon: MouseStateHandle,
|
||||
pub delete_hover: MouseStateHandle,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -358,13 +364,37 @@ impl RuleView {
|
||||
.cloned()
|
||||
.collect()
|
||||
};
|
||||
self.global_rules = ai_rules
|
||||
let mut rows: Vec<CloudRuleRow> = ai_rules
|
||||
.into_iter()
|
||||
.map(|ai_fact| CloudRuleRow {
|
||||
fact: ai_fact,
|
||||
mouse_states: Default::default(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
rows.sort_by(|a, b| {
|
||||
let name_a = match &a.fact.model().string_model {
|
||||
AIFact::Memory(AIMemory { name, .. }) => name.clone().unwrap_or_default(),
|
||||
};
|
||||
let name_b = match &b.fact.model().string_model {
|
||||
AIFact::Memory(AIMemory { name, .. }) => name.clone().unwrap_or_default(),
|
||||
};
|
||||
let is_predefined_a = is_predefined_rule(&name_a);
|
||||
let is_predefined_b = is_predefined_rule(&name_b);
|
||||
|
||||
match (is_predefined_a, is_predefined_b) {
|
||||
(true, true) => {
|
||||
let idx_a = predefined_rule_index(&name_a).unwrap_or(usize::MAX);
|
||||
let idx_b = predefined_rule_index(&name_b).unwrap_or(usize::MAX);
|
||||
idx_a.cmp(&idx_b)
|
||||
}
|
||||
(true, false) => std::cmp::Ordering::Less,
|
||||
(false, true) => std::cmp::Ordering::Greater,
|
||||
(false, false) => std::cmp::Ordering::Equal,
|
||||
}
|
||||
});
|
||||
|
||||
self.global_rules = rows;
|
||||
ctx.notify();
|
||||
}
|
||||
|
||||
@@ -466,7 +496,7 @@ impl RuleView {
|
||||
.filter_map(|row| {
|
||||
let AIFact::Memory(AIMemory { ref name, .. }) = row.fact.model().string_model;
|
||||
let name = name.as_deref().unwrap_or_default();
|
||||
if name.starts_with(SYSTEM_DEFINED_RULE_PREFIX) {
|
||||
if is_predefined_rule(name) {
|
||||
Some((
|
||||
name.to_string(),
|
||||
(row.fact.sync_id(), row.fact.metadata().revision.clone()),
|
||||
@@ -870,7 +900,8 @@ impl RuleView {
|
||||
|
||||
let mut row = Flex::row()
|
||||
.with_main_axis_size(MainAxisSize::Max)
|
||||
.with_main_axis_alignment(MainAxisAlignment::SpaceBetween);
|
||||
.with_main_axis_alignment(MainAxisAlignment::SpaceBetween)
|
||||
.with_cross_axis_alignment(CrossAxisAlignment::Center);
|
||||
|
||||
if let Some(sync_status_icon) =
|
||||
self.render_sync_status_icon(ai_row.clone(), appearance, app)
|
||||
@@ -880,6 +911,45 @@ impl RuleView {
|
||||
|
||||
row.add_child(Expanded::new(1., fact_text).finish());
|
||||
|
||||
if is_delete_allowed(ai_row.fact.clone(), app) {
|
||||
let delete_sync_id = ai_row.fact.sync_id();
|
||||
let delete_button = Hoverable::new(
|
||||
ai_row.mouse_states.delete_hover.clone(),
|
||||
|state| {
|
||||
let mut container = Container::new(
|
||||
ConstrainedBox::new(
|
||||
Icon::Trash
|
||||
.to_galaxyui_icon(
|
||||
appearance
|
||||
.theme()
|
||||
.sub_text_color(appearance.theme().background()),
|
||||
)
|
||||
.finish(),
|
||||
)
|
||||
.with_width(16.)
|
||||
.with_height(16.)
|
||||
.finish(),
|
||||
)
|
||||
.with_uniform_padding(4.)
|
||||
.with_corner_radius(CornerRadius::with_all(
|
||||
galaxyui::elements::Radius::Pixels(4.),
|
||||
));
|
||||
if state.is_hovered() {
|
||||
container =
|
||||
container.with_background(appearance.theme().surface_2());
|
||||
}
|
||||
container.finish()
|
||||
},
|
||||
)
|
||||
.with_cursor(Cursor::PointingHand)
|
||||
.on_click(move |ctx, _, _| {
|
||||
ctx.dispatch_typed_action(RuleViewAction::Delete(delete_sync_id));
|
||||
})
|
||||
.finish();
|
||||
|
||||
row.add_child(delete_button);
|
||||
}
|
||||
|
||||
let mut hoverable = Hoverable::new(ai_row.mouse_states.hover.clone(), |state| {
|
||||
let mut bg_color = internal_colors::neutral_1(appearance.theme());
|
||||
if state.is_hovered() {
|
||||
@@ -904,6 +974,7 @@ impl RuleView {
|
||||
if is_edit_allowed(ai_row.fact.clone(), app) {
|
||||
hoverable = hoverable
|
||||
.with_cursor(Cursor::PointingHand)
|
||||
.with_defer_events_to_children()
|
||||
.on_click(move |ctx, _, _| {
|
||||
ctx.dispatch_typed_action(RuleViewAction::Edit(ai_row.fact.sync_id()));
|
||||
});
|
||||
@@ -1050,6 +1121,9 @@ impl TypedActionView for RuleView {
|
||||
RuleViewAction::Edit(sync_id) => {
|
||||
ctx.emit(RuleViewEvent::Edit(*sync_id));
|
||||
}
|
||||
RuleViewAction::Delete(sync_id) => {
|
||||
self.delete_ai_rule(*sync_id, ctx);
|
||||
}
|
||||
RuleViewAction::OpenSettings => {
|
||||
ctx.emit(RuleViewEvent::OpenSettings);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user