From 83f68e35ade76c220d05b089f9941a28c220cd0e Mon Sep 17 00:00:00 2001 From: Hare Date: Sun, 19 Apr 2026 08:51:04 +0900 Subject: [PATCH] =?UTF-8?q?compact:=20=E8=A6=81=E7=B4=84=E5=85=A5=E5=8A=9B?= =?UTF-8?q?=E3=81=8B=E3=82=89=20content/arguments/reasoning=20=E3=82=92?= =?UTF-8?q?=E9=99=A4=E3=81=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ToolCall.arguments, ToolResult.content, Reasoning は auto-read 側の責務。 要約は意思決定と意図のキャプチャに集中させ、コードや tool IO は持ち込まない。 --- crates/pod/src/pod.rs | 77 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 65 insertions(+), 12 deletions(-) diff --git a/crates/pod/src/pod.rs b/crates/pod/src/pod.rs index 4fbbb012..13006a88 100644 --- a/crates/pod/src/pod.rs +++ b/crates/pod/src/pod.rs @@ -1097,6 +1097,13 @@ impl From for PodRunResult { } /// Format conversation items into a text prompt for the summary Worker. +/// +/// The summary should capture decisions and user intent, not recreate code. +/// File contents and tool IO belong in auto-read / references, not in the +/// summary input. So this strips: +/// - `ToolCall.arguments` (keep only the tool name) +/// - `ToolResult.content` (keep only the summary line) +/// - `Reasoning` entirely (intermediate thought, superseded by decisions) fn build_summary_prompt(items: &[Item]) -> String { let mut lines = Vec::new(); for item in items { @@ -1114,20 +1121,13 @@ fn build_summary_prompt(items: &[Item]) -> String { .join(""); lines.push(format!("[{role_label}] {text}")); } - Item::ToolCall { - name, arguments, .. - } => { - lines.push(format!("[ToolCall] {name}({arguments})")); + Item::ToolCall { name, .. } => { + lines.push(format!("[ToolCall] {name}")); } - Item::ToolResult { - summary, content, .. - } => match content { - Some(c) => lines.push(format!("[ToolResult] {summary}\n{c}")), - None => lines.push(format!("[ToolResult] {summary}")), - }, - Item::Reasoning { text, .. } => { - lines.push(format!("[Reasoning] {text}")); + Item::ToolResult { summary, .. } => { + lines.push(format!("[ToolResult] {summary}")); } + Item::Reasoning { .. } => {} } } lines.join("\n\n") @@ -1197,3 +1197,56 @@ fn current_pwd() -> Result { source, }) } + +#[cfg(test)] +mod build_summary_prompt_tests { + use super::*; + + #[test] + fn strips_tool_call_arguments() { + let items = vec![Item::tool_call_json( + "call-1", + "read_file", + serde_json::json!({ "path": "src/main.rs" }), + )]; + let prompt = build_summary_prompt(&items); + assert_eq!(prompt, "[ToolCall] read_file"); + assert!(!prompt.contains("src/main.rs")); + } + + #[test] + fn strips_tool_result_content() { + let items = vec![Item::tool_result_with_content( + "call-1", + "read 3 lines", + "fn main() { println!(\"hello\"); }", + )]; + let prompt = build_summary_prompt(&items); + assert_eq!(prompt, "[ToolResult] read 3 lines"); + assert!(!prompt.contains("println")); + } + + #[test] + fn drops_reasoning_entirely() { + let items = vec![ + Item::user_message("hi"), + Item::reasoning("internal deliberation"), + Item::assistant_message("hello"), + ]; + let prompt = build_summary_prompt(&items); + assert!(prompt.contains("[User] hi")); + assert!(prompt.contains("[Assistant] hello")); + assert!(!prompt.contains("Reasoning")); + assert!(!prompt.contains("deliberation")); + } + + #[test] + fn keeps_user_and_assistant_messages() { + let items = vec![ + Item::user_message("fix the bug"), + Item::assistant_message("done"), + ]; + let prompt = build_summary_prompt(&items); + assert_eq!(prompt, "[User] fix the bug\n\n[Assistant] done"); + } +}