From e731bc821734836634c1fffc35bc923bd6ef2bdb Mon Sep 17 00:00:00 2001 From: "Dhanji R. Prasanna" Date: Sun, 11 Jan 2026 06:49:45 +0800 Subject: [PATCH] Make remember tool instructions more imperative in system prompts - Change 'call remember' to 'you MUST call remember' in native prompt - Change 'IF you discovered' to 'ALWAYS...when you discovered' - Add explicit list of trigger tools (code_search, rg, grep, find, read_file) - Add reminder to Response Guidelines section - Add remember tool and Project Memory section to non-native prompt - Remove redundant console output from remember tool - Fix test compilation errors (missing summary parameter, temporary borrow) --- .../g3-cli/tests/streaming_markdown_test.rs | 3 +- crates/g3-core/src/prompts.rs | 30 ++++++++++++++++--- crates/g3-core/src/session_continuation.rs | 3 ++ crates/g3-core/src/tools/memory.rs | 3 -- .../tests/test_session_continuation.rs | 13 ++++++++ 5 files changed, 44 insertions(+), 8 deletions(-) diff --git a/crates/g3-cli/tests/streaming_markdown_test.rs b/crates/g3-cli/tests/streaming_markdown_test.rs index 46d1573..36586a8 100644 --- a/crates/g3-cli/tests/streaming_markdown_test.rs +++ b/crates/g3-cli/tests/streaming_markdown_test.rs @@ -840,7 +840,8 @@ fn test_table_empty_line_then_header() { for ch in input.chars() { let out = fmt.process(&ch.to_string()); if !out.is_empty() { - eprintln!("After '{}': {:?}", if ch == '\n' { "\\n" } else { &ch.to_string() }, out); + let ch_display = if ch == '\n' { "\\n".to_string() } else { ch.to_string() }; + eprintln!("After '{}': {:?}", ch_display, out); } full_output.push_str(&out); } diff --git a/crates/g3-core/src/prompts.rs b/crates/g3-core/src/prompts.rs index 802b67b..bd074da 100644 --- a/crates/g3-core/src/prompts.rs +++ b/crates/g3-core/src/prompts.rs @@ -104,28 +104,30 @@ Do not explain what you're going to do - just do it by calling the tools. Project memory (if available) is automatically loaded at startup alongside README.md and AGENTS.md. It contains feature locations, patterns, and entry points discovered in previous sessions. -**IMPORTANT**: After completing a task where you discovered code locations, call the **`remember`** tool to save them. This helps avoid re-discovering the same code in future sessions. +**IMPORTANT**: After completing a task where you discovered code locations, you MUST call the **`remember`** tool to save them. This helps avoid re-discovering the same code in future sessions. ## Memory Format Use this format when calling `remember`: +``` ### - `` [..] - `()`, `` -## Patterns - ### 1. Step one 2. Step two +``` ## When to Remember -Call `remember` at the end of your turn IF you discovered: +**ALWAYS** call `remember` at the END of your turn when you discovered: - A feature's location (file + char range + function/struct names) - A useful pattern or workflow - An entry point for a subsystem +This applies whenever you use search tools like `code_search`, `rg`, `grep`, `find`, or `read_file` to locate code. + Do NOT save duplicates - check the Project Memory section (loaded at startup) to see what's already known. ## Example @@ -139,6 +141,7 @@ After discovering where WebDriver tools live: - Use Markdown formatting for all responses except tool calls. - Whenever taking actions, use the pronoun 'I' - Use quick and clever humor when appropriate. +- After discovering code locations via search tools, call `remember` to save them. "; pub const SYSTEM_PROMPT_FOR_NATIVE_TOOL_USE: &'static str = SYSTEM_NATIVE_TOOL_CALLS; @@ -216,6 +219,11 @@ Short description for providers without native calling specs: - Example: {\"tool\": \"research\", \"args\": {\"query\": \"Best Rust HTTP client libraries for async/await\"}} - Use for researching APIs, SDKs, libraries, approaches, bugs, or any topic requiring web research +- **remember**: Save discovered code locations to project memory + - Format: {\"tool\": \"remember\", \"args\": {\"notes\": \"markdown notes\"}} + - Example: {\"tool\": \"remember\", \"args\": {\"notes\": \"### Feature Name\\n- `file.rs` [0..100] - `function_name()`\"}} + - Use at the END of your turn after discovering code locations via search tools + # Instructions 1. Analyze the request and break down into smaller tasks if appropriate @@ -315,10 +323,24 @@ Skip TODO tools for simple single-step tasks: If you can complete it with 1-2 tool calls, skip TODO. +# Project Memory + +Project memory (if available) is automatically loaded at startup. It contains feature locations and patterns discovered in previous sessions. + +**ALWAYS** call `remember` at the END of your turn when you discovered: +- A feature's location (file + char range + function/struct names) +- A useful pattern or workflow +- An entry point for a subsystem + +This applies whenever you use search tools like `code_search`, `rg`, `grep`, `find`, or `read_file` to locate code. + +Do NOT save duplicates - check the Project Memory section (loaded at startup) to see what's already known. + # Response Guidelines - Use Markdown formatting for all responses except tool calls. - Whenever taking actions, use the pronoun 'I' +- After discovering code locations via search tools, call `remember` to save them. "; pub const SYSTEM_PROMPT_FOR_NON_NATIVE_TOOL_USE: &'static str = SYSTEM_NON_NATIVE_TOOL_USE; diff --git a/crates/g3-core/src/session_continuation.rs b/crates/g3-core/src/session_continuation.rs index edce8aa..200c169 100644 --- a/crates/g3-core/src/session_continuation.rs +++ b/crates/g3-core/src/session_continuation.rs @@ -481,6 +481,7 @@ mod tests { None, "test_session_123".to_string(), Some("Task completed successfully".to_string()), + None, "/path/to/session.json".to_string(), 45.0, Some("- [x] Task 1\n- [ ] Task 2".to_string()), @@ -499,6 +500,7 @@ mod tests { None, "test".to_string(), None, + None, "path".to_string(), 50.0, None, @@ -521,6 +523,7 @@ mod tests { Some("fowler".to_string()), "test".to_string(), None, + None, "path".to_string(), 50.0, Some("- [x] Done\n- [ ] Not done".to_string()), diff --git a/crates/g3-core/src/tools/memory.rs b/crates/g3-core/src/tools/memory.rs index c13263c..8f5d561 100644 --- a/crates/g3-core/src/tools/memory.rs +++ b/crates/g3-core/src/tools/memory.rs @@ -68,9 +68,6 @@ pub async fn execute_remember( // Write back std::fs::write(&memory_path, &final_content)?; - ctx.ui_writer - .println(&format!("💾 Memory updated ({})", format_size(final_content.len()))); - Ok(format!("Memory updated. Size: {}", format_size(final_content.len()))) } diff --git a/crates/g3-core/tests/test_session_continuation.rs b/crates/g3-core/tests/test_session_continuation.rs index c057820..5479f89 100644 --- a/crates/g3-core/tests/test_session_continuation.rs +++ b/crates/g3-core/tests/test_session_continuation.rs @@ -33,6 +33,7 @@ fn test_session_continuation_creation() { // This test doesn't need file system access let continuation = SessionContinuation::new(false, None, "test_session_123".to_string(), + None, Some("Task completed successfully".to_string()), "/path/to/session.json".to_string(), 45.0, @@ -66,6 +67,7 @@ fn test_can_restore_full_context_threshold() { let continuation = SessionContinuation::new(false, None, "test".to_string(), None, + None, "path".to_string(), percentage, None, @@ -87,6 +89,7 @@ fn test_save_and_load_continuation() { let original = SessionContinuation::new(false, None, "save_load_test".to_string(), + None, Some("Test summary content".to_string()), "/logs/g3_session_save_load_test.json".to_string(), 35.5, @@ -134,6 +137,7 @@ fn test_find_incomplete_agent_session() { true, // is_agent_mode Some("fowler".to_string()), // agent_name "fowler_session_1".to_string(), + None, Some("Working on task".to_string()), "/path/to/session.json".to_string(), 50.0, @@ -172,6 +176,7 @@ fn test_find_incomplete_agent_session_ignores_complete_todos() { true, Some("fowler".to_string()), "fowler_complete".to_string(), + None, Some("All done".to_string()), "/path/to/session.json".to_string(), 50.0, @@ -204,6 +209,7 @@ fn test_find_incomplete_agent_session_ignores_non_agent_mode() { None, "regular_session".to_string(), None, + None, "/path/to/session.json".to_string(), 50.0, Some("- [ ] Incomplete task".to_string()), @@ -238,6 +244,7 @@ fn test_clear_continuation() { // Create and save a continuation let continuation = SessionContinuation::new(false, None, "clear_test".to_string(), + None, Some("Will be cleared".to_string()), "/path/to/session.json".to_string(), 50.0, @@ -293,6 +300,7 @@ fn test_has_valid_continuation_with_missing_session_log() { // Create a continuation pointing to a non-existent session log let continuation = SessionContinuation::new(false, None, "invalid_test".to_string(), + None, Some("Summary".to_string()), "/nonexistent/path/session.json".to_string(), 30.0, @@ -321,6 +329,7 @@ fn test_has_valid_continuation_with_existing_session_log() { // Create a continuation pointing to the existing session log let continuation = SessionContinuation::new(false, None, "valid_test".to_string(), + None, Some("Summary".to_string()), session_log_path.to_string_lossy().to_string(), 30.0, @@ -342,6 +351,7 @@ fn test_continuation_serialization_format() { let continuation = SessionContinuation::new(false, None, "format_test".to_string(), + None, Some("Test summary".to_string()), "/path/to/session.json".to_string(), 42.5, @@ -376,6 +386,7 @@ fn test_multiple_saves_update_symlink() { // Save first continuation let first = SessionContinuation::new(false, None, "first_session".to_string(), + None, Some("First summary".to_string()), "/path/first.json".to_string(), 20.0, @@ -392,6 +403,7 @@ fn test_multiple_saves_update_symlink() { // Save second continuation (should update symlink) let second = SessionContinuation::new(false, None, "second_session".to_string(), + None, Some("Second summary".to_string()), "/path/second.json".to_string(), 60.0, @@ -437,6 +449,7 @@ fn test_symlink_migration_from_old_directory() { // Save a new continuation - this should migrate the old directory to a symlink let continuation = SessionContinuation::new(false, None, "new_session".to_string(), + None, Some("New summary".to_string()), "/path/to/session.json".to_string(), 50.0,