feat: inject global rules into AI system prompt and fix Rules UI seeding

- Load global rules (AIFact/AIMemory) from local CloudModel and inject
  them into the Bedrock/OpenAI system prompt as a '## Global Rules' section
  when memory is enabled.
- Fix rule seeding: always re-seed predefined rules when the CloudModel has
  none, regardless of the has_seeded_predefined_rules flag (handles case
  where flag was set but rules never persisted due to prior missing owner).
- Rename /context slash command to /copy-context: dumps the full context
  window (global rules, progressive summary, message history) to the
  clipboard for debugging.
This commit is contained in:
Ryan Ward
2026-07-16 12:25:56 -05:00
parent 66ef451115
commit 3d2d90fd4e
10 changed files with 188 additions and 15 deletions
+29
View File
@@ -152,6 +152,9 @@ pub struct RequestParams {
/// can store them back into the conversation for the next request cycle.
pub bedrock_messages_sent:
std::sync::Arc<std::sync::Mutex<Vec<crate::ai::bedrock::convert::ConversationMessage>>>,
/// Global rules (name, content) from the local CloudModel (AIFact/AIMemory).
/// Injected into the system prompt when `is_memory_enabled` is true.
pub global_rules: Vec<(String, String)>,
}
pub type Event = Result<warp_multi_agent_api::ResponseEvent, Arc<AIApiError>>;
@@ -216,6 +219,7 @@ impl RequestParams {
bedrock_progressive_summary: None,
bedrock_tool_result_archive: vec![],
bedrock_messages_sent: std::sync::Arc::new(std::sync::Mutex::new(vec![])),
global_rules: vec![],
}
}
@@ -421,6 +425,31 @@ impl RequestParams {
bedrock_progressive_summary: None,
bedrock_tool_result_archive: Vec::new(),
bedrock_messages_sent: std::sync::Arc::new(std::sync::Mutex::new(Vec::new())),
global_rules: if is_memory_enabled {
Self::load_global_rules(app)
} else {
vec![]
},
}
}
/// Load global rules (AIFact/AIMemory) from the local CloudModel.
fn load_global_rules(app: &AppContext) -> Vec<(String, String)> {
use crate::ai::facts::{AIFact, AIMemory, CloudAIFactModel};
use crate::cloud_object::model::generic_string_model::GenericStringObjectId;
use crate::cloud_object::model::persistence::CloudModel;
CloudModel::as_ref(app)
.get_all_objects_of_type::<GenericStringObjectId, CloudAIFactModel>()
.filter_map(|fact| {
let AIFact::Memory(AIMemory { name, content, .. }) =
fact.model().string_model.clone();
if content.is_empty() {
None
} else {
Some((name.unwrap_or_default(), content))
}
})
.collect()
}
}
+2
View File
@@ -150,6 +150,7 @@ pub async fn generate_multi_agent_output(
tool_result_archive: params.bedrock_tool_result_archive.clone(),
progressive_summary: params.bedrock_progressive_summary.clone(),
messages_sent: params.bedrock_messages_sent.clone(),
global_rules: params.global_rules.clone(),
};
match openai_translator::execute(translator_request, &mut request).await {
@@ -178,6 +179,7 @@ pub async fn generate_multi_agent_output(
bedrock_tool_result_archive: params.bedrock_tool_result_archive.clone(),
bedrock_progressive_summary: params.bedrock_progressive_summary.clone(),
bedrock_messages_sent: params.bedrock_messages_sent.clone(),
global_rules: params.global_rules.clone(),
};
match crate::ai::bedrock::translator::execute(translator_request, &mut request).await {