Cache-safe request assembly: append-only turn context and declared cache semantics (#11022)

This commit is contained in:
filip
2026-08-06 20:08:49 -07:00
committed by GitHub
parent ca52cce628
commit 66051ec7d2
39 changed files with 1589 additions and 1231 deletions
@@ -224,7 +224,7 @@ impl AdversaryInspector {
messages
.iter()
.rev()
.filter(|m| m.role == rmcp::model::Role::User)
.filter(|m| m.role == rmcp::model::Role::User && !m.is_turn_context())
.filter_map(|m| {
let text: String = m
.content
@@ -250,7 +250,7 @@ impl AdversaryInspector {
fn extract_original_task(messages: &[Message]) -> String {
for msg in messages {
if msg.role == rmcp::model::Role::User {
if msg.role == rmcp::model::Role::User && !msg.is_turn_context() {
let text: String = msg
.content
.iter()
@@ -720,4 +720,39 @@ mod tests {
.unwrap();
assert!(results.is_empty());
}
#[test]
fn user_context_extraction_skips_turn_context_events() {
use crate::conversation::message::MessageMetadata;
let turn_context = |text: &str| {
Message::user()
.with_text(text)
.with_metadata(MessageMetadata::agent_only().with_turn_context())
};
let messages = vec![
turn_context("turn context before any prompt"),
Message::user().with_text("never delete files outside the repo"),
turn_context("turn context for turn one"),
Message::assistant().with_text("understood"),
Message::user().with_text("first task"),
turn_context("turn context for turn two"),
Message::assistant().with_text("done"),
Message::user().with_text("second task"),
turn_context("turn context for turn three"),
];
let recent = AdversaryInspector::extract_recent_user_messages(&messages, 4);
assert_eq!(
recent,
vec![
"never delete files outside the repo",
"first task",
"second task"
]
);
let original = AdversaryInspector::extract_original_task(&messages);
assert_eq!(original, "never delete files outside the repo");
}
}
+30
View File
@@ -354,6 +354,7 @@ impl PromptInjectionScanner {
.rev()
.filter(|m| {
crate::conversation::effective_role(m) == crate::conversation::EffectiveRole::User
&& !m.is_turn_context()
})
.take(limit)
.map(|m| {
@@ -460,4 +461,33 @@ mod tests {
assert!(result.is_malicious);
}
#[test]
fn extract_user_messages_skips_turn_context_events() {
use crate::conversation::message::MessageMetadata;
let scanner = PromptInjectionScanner::new();
let turn_context = |text: &str| {
Message::user()
.with_text(text)
.with_metadata(MessageMetadata::agent_only().with_turn_context())
};
let messages = vec![
Message::user().with_text("oldest prompt"),
turn_context("turn context one"),
Message::assistant().with_text("ok"),
Message::user().with_text("middle prompt"),
turn_context("turn context two"),
Message::assistant().with_text("done"),
Message::user().with_text("newest prompt"),
turn_context("turn context three"),
];
let extracted = scanner.extract_user_messages(&messages, 3);
assert_eq!(
extracted,
vec!["newest prompt", "middle prompt", "oldest prompt"]
);
}
}