pub const STAGED_PLANNER_TOOL_CALL_REJECT_PREFIX: &str =
"### 规划轮约束提醒(code=PLANNER_TOOL_CALL_REJECTED)";
pub const OUTER_LOOP_BUILD_IDLE_ORCHESTRATION_PREFIX: &str = "【编排纠偏】";
pub const LONG_TERM_MEMORY_INJECTION_CONTENT_PREFIX: &str = "以下为与当前问题可能相关的长期记忆";
#[must_use]
pub fn is_long_term_memory_injected_user_content(s: &str) -> bool {
s.trim_start()
.starts_with(LONG_TERM_MEMORY_INJECTION_CONTENT_PREFIX)
}
#[must_use]
pub fn is_planner_tool_call_reject_injected_user_content(s: &str) -> bool {
s.trim_start()
.starts_with(STAGED_PLANNER_TOOL_CALL_REJECT_PREFIX)
}
#[must_use]
pub fn is_staged_patch_feedback_user_content(s: &str) -> bool {
s.trim_start().starts_with("### 分阶段规划 · 步级反馈")
}
#[must_use]
pub fn is_plan_rewrite_injected_user_content(s: &str) -> bool {
s.contains("你的最终回答缺少**结构化规划**")
|| s.contains("crabmate_plan_semantic_feedback")
|| s.contains("侧向校验认为你的 **agent_reply_plan**")
}
#[must_use]
pub fn user_message_should_hide_for_chat_display(s: &str) -> bool {
is_planner_tool_call_reject_injected_user_content(s)
|| is_staged_patch_feedback_user_content(s)
|| is_plan_rewrite_injected_user_content(s)
|| is_long_term_memory_injected_user_content(s)
|| s.trim_start()
.starts_with(OUTER_LOOP_BUILD_IDLE_ORCHESTRATION_PREFIX)
}
#[must_use]
pub fn is_server_injected_user_content_for_storage(s: &str) -> bool {
user_message_should_hide_for_chat_display(s)
}
#[cfg(test)]
mod tests {
use std::fs;
use std::path::PathBuf;
use super::*;
#[test]
fn display_hide_user_golden() {
let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let path = manifest.join("fixtures/display_hide_user_golden.jsonl");
let raw =
fs::read_to_string(&path).unwrap_or_else(|e| panic!("read {}: {e}", path.display()));
for (line_no, line) in raw.lines().enumerate() {
let t = line.trim();
if t.is_empty() || t.starts_with('#') {
continue;
}
let mut parts = t.splitn(3, '\t');
let label = parts.next().unwrap_or("?");
let body = parts
.next()
.unwrap_or_else(|| panic!("line {}: missing body", line_no + 1))
.replace("\\n", "\n");
let expect_hidden = parts
.next()
.unwrap_or_else(|| panic!("line {}: missing expect", line_no + 1));
let expect_hidden = match expect_hidden {
"hide" => true,
"show" => false,
other => panic!("line {} ({}): bad expect {other:?}", line_no + 1, label),
};
let got = user_message_should_hide_for_chat_display(body.as_str());
assert_eq!(got, expect_hidden, "line {} ({})", line_no + 1, label);
}
}
}