diff --git a/server-rs/crates/platform-editor-agent/src/agent/prompt.rs b/server-rs/crates/platform-editor-agent/src/agent/prompt.rs index f9f498766..fc1bc4b41 100644 --- a/server-rs/crates/platform-editor-agent/src/agent/prompt.rs +++ b/server-rs/crates/platform-editor-agent/src/agent/prompt.rs @@ -81,3 +81,114 @@ pub fn generate_ui_design_tool_description() -> String { "仅用于生成完整可用的 UI 设计图或界面稿,包括 HUD、弹窗、面板、按钮组合和整页界面。不要用于提取图标、拆素材;{EXISTING_IMAGE_EDIT_POLICY}。UI 规范图、组件规范展板或视觉规范展板属于规范展板,{SPEC_BOARD_ROUTE_POLICY}。只能输出一张图" ) } + +#[cfg(test)] +mod tests { + use super::*; + use platform_agent_harness::prompt::build_tools_system_prompt; + use platform_llm::LlmMessageRole; + use shared_contracts::editor_agent::{ + EDITOR_AGENT_MESSAGES_DOCUMENT_VERSION, EditorAgentMessage, + }; + + #[test] + fn business_prompt_keeps_pending_confirmation_and_cancellation_policy() { + let prompt = editor_agent_system_prompt(); + + assert!(prompt.contains("pending confirmation/completed/cancelled")); + assert!(prompt.contains("用户界面工具消息的确认/取消按钮")); + assert!(prompt.contains("引导他使用确认/取消按钮")); + assert!(prompt.contains("禁止在对话中dump参数")); + } + + #[test] + fn business_prompt_allows_new_calls_after_cancelled_or_pending_calls() { + let prompt = editor_agent_system_prompt(); + + assert!(prompt.contains("已经被用户取消的工具调用是无法再次被确认的")); + assert!(prompt.contains("如果用户明确要修改, 请发起新工具调用")); + assert!(prompt.contains("一个等待确认的工具调用不影响另一个工具调用的发起")); + assert!(prompt.contains("不要因为尚未确认或完成就拒绝发起另一个")); + } + + #[test] + fn final_business_prompt_batches_independent_calls_but_keeps_serial_execution() { + let prompt = build_tools_system_prompt(editor_agent_system_prompt(), &[]); + + assert!(prompt.contains("尽可能多(无依赖)的工具调用")); + assert!(prompt.contains("尽量批量")); + assert!(prompt.contains("(sequentially inside)")); + assert!(prompt.contains("call them in a batch instead of one call per turn")); + } + + #[test] + fn prompt_memory_keeps_only_the_latest_window_before_history_end() { + let messages = (0..20) + .map(|index| EditorAgentMessage { + id: index, + client_message_id: None, + role: match index % 3 { + 0 => EditorAgentMessageRole::User, + 1 => EditorAgentMessageRole::Assistant, + _ => EditorAgentMessageRole::System, + }, + text: format!("message-{index}"), + attachments: Vec::new(), + tool_call: None, + created_at: format!("created-{index}"), + }) + .collect::>(); + let document = EditorAgentConversationMessagesDocument { + version: EDITOR_AGENT_MESSAGES_DOCUMENT_VERSION, + conversation_id: "conversation-1".to_string(), + messages, + }; + + let memory = build_prompt_memory(&document, 19); + + assert_eq!(memory.len(), EDITOR_AGENT_MAX_RECENT_PROMPT_MESSAGES); + for (offset, message) in memory.iter().enumerate() { + let source_index = offset + 1; + assert_eq!(message.content, format!("message-{source_index}")); + assert_eq!( + message.role, + match source_index % 3 { + 0 => LlmMessageRole::User, + 1 => LlmMessageRole::Assistant, + _ => LlmMessageRole::System, + } + ); + } + assert!(memory.iter().all(|message| message.content != "message-0")); + assert!(memory.iter().all(|message| message.content != "message-19")); + } + + #[test] + fn business_prompt_requests_a_new_reference_when_history_is_outside_the_window() { + let prompt = editor_agent_system_prompt(); + + assert!(prompt.contains("滑动窗口上下文有限")); + assert!(prompt.contains("可能被历史截断了")); + assert!(prompt.contains("请求用户重新引用")); + assert!(prompt.contains("但不是告诉你image_id")); + } + + #[test] + fn tool_descriptions_keep_edit_and_spec_board_routes_consistent() { + let edit_image = edit_image_tool_description(); + let generate_image = generate_image_tool_description(); + let character = generate_character_tool_description(); + let icons = generate_icon_spritesheet_tool_description(); + let ui = generate_ui_design_tool_description(); + + assert!(edit_image.contains(EXISTING_IMAGE_EDIT_POLICY)); + assert!(generate_image.contains(EXISTING_IMAGE_EDIT_POLICY)); + assert!(generate_image.contains(SPEC_BOARD_ROUTE_POLICY)); + assert!(generate_image.contains(SPEC_BOARD_CONTENT_POLICY)); + assert!(character.contains(EXISTING_IMAGE_EDIT_POLICY)); + assert!(character.contains(SPEC_BOARD_ROUTE_POLICY)); + assert!(icons.contains(SPEC_BOARD_ROUTE_POLICY)); + assert!(ui.contains(EXISTING_IMAGE_EDIT_POLICY)); + assert!(ui.contains(SPEC_BOARD_ROUTE_POLICY)); + } +}