diff --git a/crates/tui/src/core/engine/tests.rs b/crates/tui/src/core/engine/tests.rs index 05d29da0b..d6a8bc041 100644 --- a/crates/tui/src/core/engine/tests.rs +++ b/crates/tui/src/core/engine/tests.rs @@ -2594,7 +2594,6 @@ fn non_yolo_mode_retains_default_defer_policy() { assert!(!should_default_defer_tool("run_tests", &always_load)); assert!(!should_default_defer_tool("agent", &always_load)); assert!(!should_default_defer_tool("read_file", &always_load)); - assert!(!should_default_defer_tool("remember", &always_load)); assert!(!should_default_defer_tool( "wait_for_dev_server", &always_load @@ -2654,7 +2653,6 @@ fn model_tool_catalog_applies_native_and_mcp_deferral() { api_tool("write_file"), api_tool("exec_shell"), api_tool("edit_file"), - api_tool("remember"), api_tool("project_map"), ], vec![api_tool("list_mcp_resources"), api_tool("mcp_server_write")], @@ -2673,7 +2671,6 @@ fn model_tool_catalog_applies_native_and_mcp_deferral() { assert_eq!(defer_loading("write_file"), Some(false)); assert_eq!(defer_loading("exec_shell"), Some(false)); assert_eq!(defer_loading("edit_file"), Some(false)); - assert_eq!(defer_loading("remember"), Some(false)); assert_eq!(defer_loading("project_map"), Some(true)); assert_eq!(defer_loading("list_mcp_resources"), Some(false)); assert_eq!(defer_loading("mcp_server_write"), Some(true)); diff --git a/crates/tui/src/core/engine/tool_catalog.rs b/crates/tui/src/core/engine/tool_catalog.rs index f7b164b0a..49fc740f4 100644 --- a/crates/tui/src/core/engine/tool_catalog.rs +++ b/crates/tui/src/core/engine/tool_catalog.rs @@ -57,7 +57,6 @@ pub(super) const DEFAULT_ACTIVE_NATIVE_TOOLS: &[&str] = &[ "grep_files", "list_dir", "read_file", - "remember", "run_tests", "run_verifiers", "task_create", diff --git a/crates/tui/src/core/engine/tool_setup.rs b/crates/tui/src/core/engine/tool_setup.rs index 7898312fc..043283fc5 100644 --- a/crates/tui/src/core/engine/tool_setup.rs +++ b/crates/tui/src/core/engine/tool_setup.rs @@ -7,10 +7,6 @@ use crate::core::authority::shell_policy_for_mode; use crate::tools::AgentToolSurfaceOptions; use crate::worker_profile::ShellPolicy; -fn should_register_remember_tool(memory_enabled: bool, moraine_fallback: bool) -> bool { - memory_enabled && !moraine_fallback -} - impl Engine { pub(super) fn agent_tool_surface_options( &self, @@ -19,8 +15,6 @@ impl Engine { let mut options = AgentToolSurfaceOptions::new(shell_policy); options.apply_patch_enabled = self.config.features.enabled(Feature::ApplyPatch); options.web_search_enabled = self.config.features.enabled(Feature::WebSearch); - options.memory_tool_enabled = - should_register_remember_tool(self.config.memory_enabled, self.config.moraine_fallback); options.vision_config = if self.config.features.enabled(Feature::VisionModel) { self.config.vision_config.clone() } else { @@ -80,14 +74,6 @@ impl Engine { builder = builder.with_web_tools(); } - // Register the `remember` tool only when the user has opted in to - // user-memory (#489). Without that opt-in the tool would always - // fail; surfacing it would just waste catalog slots. - // TODO(v0.8.71): remove when Moraine recall stable; see #3490, #3495 - if should_register_remember_tool(self.config.memory_enabled, self.config.moraine_fallback) { - builder = builder.with_remember_tool(); - } - // Register image_analyze tool when vision_model is configured and feature enabled. if self.config.features.enabled(Feature::VisionModel) && let Some(ref vision_config) = self.config.vision_config @@ -111,15 +97,3 @@ impl Engine { builder } } - -#[cfg(test)] -mod tests { - use super::should_register_remember_tool; - - #[test] - fn remember_tool_registration_respects_moraine_fallback() { - assert!(should_register_remember_tool(true, false)); - assert!(!should_register_remember_tool(false, false)); - assert!(!should_register_remember_tool(true, true)); - } -} diff --git a/crates/tui/src/main.rs b/crates/tui/src/main.rs index b716920d7..9e7397fad 100644 --- a/crates/tui/src/main.rs +++ b/crates/tui/src/main.rs @@ -8319,7 +8319,6 @@ async fn build_direct_workflow_tool( let mut surface = AgentToolSurfaceOptions::new(shell_policy); surface.apply_patch_enabled = features.enabled(Feature::ApplyPatch); surface.web_search_enabled = features.enabled(Feature::WebSearch); - surface.memory_tool_enabled = config.memory_enabled() && !config.moraine_fallback(); surface.vision_config = features .enabled(Feature::VisionModel) .then(|| config.vision_model_config()) diff --git a/crates/tui/src/tools/mod.rs b/crates/tui/src/tools/mod.rs index 03d6137ac..57ddb8df5 100644 --- a/crates/tui/src/tools/mod.rs +++ b/crates/tui/src/tools/mod.rs @@ -38,7 +38,6 @@ pub mod plan; pub mod plugin; pub mod project; pub mod registry; -pub mod remember; pub mod revert_turn; pub mod review; pub mod rlm; diff --git a/crates/tui/src/tools/registry.rs b/crates/tui/src/tools/registry.rs index 92ab68a37..2c6b3db20 100644 --- a/crates/tui/src/tools/registry.rs +++ b/crates/tui/src/tools/registry.rs @@ -497,7 +497,6 @@ pub struct AgentToolSurfaceOptions { pub shell_policy: crate::worker_profile::ShellPolicy, pub apply_patch_enabled: bool, pub web_search_enabled: bool, - pub memory_tool_enabled: bool, pub vision_config: Option, pub speech_output_dir: Option, pub goal_state: Option, @@ -510,7 +509,6 @@ impl AgentToolSurfaceOptions { shell_policy, apply_patch_enabled: false, web_search_enabled: false, - memory_tool_enabled: false, vision_config: None, speech_output_dir: None, goal_state: None, @@ -897,16 +895,6 @@ impl ToolRegistryBuilder { self.with_tool(Arc::new(FimEditTool::new(client, model))) } - /// Include the `remember` tool — model-callable bullet-add into the - /// user memory file (#489). Only register when the user has opted - /// in to the memory feature; without that, the tool would surface - /// in the model's catalog but always fail with "memory disabled". - #[must_use] - pub fn with_remember_tool(self) -> Self { - use super::remember::RememberTool; - self.with_tool(Arc::new(RememberTool)) - } - /// Include the slop ledger tools (#2127) — durable tracking of /// unresolved architectural residue: append, query, update, export. /// Registered unconditionally; the ledger JSON file is auto-created @@ -1062,9 +1050,6 @@ impl ToolRegistryBuilder { if options.web_search_enabled { builder = builder.with_web_tools(); } - if options.memory_tool_enabled { - builder = builder.with_remember_tool(); - } if let Some(vision_config) = options.vision_config { builder = builder.with_vision_tools(vision_config); } diff --git a/crates/tui/src/tools/remember.rs b/crates/tui/src/tools/remember.rs deleted file mode 100644 index 05b6ff5dd..000000000 --- a/crates/tui/src/tools/remember.rs +++ /dev/null @@ -1,138 +0,0 @@ -//! `remember` tool — model-callable bullet-add into the user memory file. -//! -//! Lets the model itself notice a durable preference, convention, or fact -//! worth keeping across sessions and write it to the user's `memory.md`. -//! The tool is auto-approved and side-effecting only on the user-owned -//! memory file (`~/.deepseek/memory.md` by default), so it doesn't get -//! gated behind the same approval flow as shell or arbitrary file writes. -//! -//! Only registered when `[memory] enabled = true` (or -//! `DEEPSEEK_MEMORY=on`). When disabled, the tool isn't surfaced to the -//! model at all, so prompts that mention `remember` simply fall through. - -use async_trait::async_trait; -use serde_json::{Value, json}; - -use super::spec::{ - ApprovalRequirement, ToolCapability, ToolContext, ToolError, ToolResult, ToolSpec, required_str, -}; - -/// Tool that appends one bullet to the user memory file. -pub struct RememberTool; - -#[async_trait] -impl ToolSpec for RememberTool { - fn name(&self) -> &'static str { - "remember" - } - - fn description(&self) -> &'static str { - "Append a durable note to the user memory file so it surfaces in \ - future sessions. Use this when the user states a preference, a \ - convention they want enforced, or a fact about themselves or \ - their workflow that you should not have to relearn next time. \ - Keep notes terse (one sentence). Don't store secrets, transient \ - tasks, or reasoning scratch — those belong in a checklist or in \ - the conversation." - } - - fn input_schema(&self) -> Value { - json!({ - "type": "object", - "properties": { - "note": { - "type": "string", - "description": "The single-sentence durable note to remember." - } - }, - "required": ["note"] - }) - } - - fn capabilities(&self) -> Vec { - vec![ToolCapability::WritesFiles] - } - - fn approval_requirement(&self) -> ApprovalRequirement { - // Memory writes are scoped to the user's own memory file; gating - // them behind the standard shell/write approval would defeat the - // point of automatic memory. - ApprovalRequirement::Auto - } - - async fn execute(&self, input: Value, context: &ToolContext) -> Result { - let note = required_str(&input, "note")?; - let path = context.memory_path.as_ref().ok_or_else(|| { - ToolError::execution_failed( - "user memory is disabled — set `[memory] enabled = true` in config.toml or \ - `DEEPSEEK_MEMORY=on` in the environment to enable", - ) - })?; - - crate::memory::append_entry(path, note).map_err(|err| { - ToolError::execution_failed(format!("failed to append to {}: {err}", path.display())) - })?; - - Ok(ToolResult::success(format!( - "remembered: {}", - note.trim_start_matches('#').trim() - ))) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::path::PathBuf; - use tempfile::tempdir; - - fn ctx_with_memory(path: PathBuf) -> ToolContext { - let mut ctx = ToolContext::new(path.parent().unwrap_or_else(|| std::path::Path::new("."))); - ctx.memory_path = Some(path); - ctx - } - - #[tokio::test] - async fn returns_error_when_memory_disabled() { - let tmp = tempdir().unwrap(); - let mut ctx = ToolContext::new(tmp.path()); - ctx.memory_path = None; // explicitly disabled - - let tool = RememberTool; - let err = tool - .execute(json!({"note": "use 4 spaces for indentation"}), &ctx) - .await - .unwrap_err(); - assert!(err.to_string().contains("memory is disabled"), "{err}"); - } - - #[tokio::test] - async fn appends_bullet_to_memory_file() { - let tmp = tempdir().unwrap(); - let path = tmp.path().join("memory.md"); - let ctx = ctx_with_memory(path.clone()); - - let tool = RememberTool; - let result = tool - .execute(json!({"note": "use 4 spaces for indentation"}), &ctx) - .await - .expect("ok"); - assert!(result.success); - assert!(result.content.contains("4 spaces")); - - let body = std::fs::read_to_string(&path).expect("read"); - assert!(body.contains("4 spaces")); - assert!(body.starts_with("- ("), "{body}"); - } - - #[tokio::test] - async fn rejects_missing_note_field() { - let tmp = tempdir().unwrap(); - let path = tmp.path().join("memory.md"); - let ctx = ctx_with_memory(path); - - let tool = RememberTool; - let err = tool.execute(json!({}), &ctx).await.unwrap_err(); - assert!(err.to_string().to_lowercase().contains("note"), "{err}"); - } -} diff --git a/crates/tui/src/tools/subagent/tests.rs b/crates/tui/src/tools/subagent/tests.rs index 78488398a..2050406d6 100644 --- a/crates/tui/src/tools/subagent/tests.rs +++ b/crates/tui/src/tools/subagent/tests.rs @@ -2817,7 +2817,6 @@ fn enabled_agent_surface_options() -> AgentToolSurfaceOptions { let mut options = AgentToolSurfaceOptions::new(ShellPolicy::Full); options.apply_patch_enabled = true; options.web_search_enabled = true; - options.memory_tool_enabled = true; options.goal_state = Some(crate::tools::goal::new_shared_goal_state()); options } @@ -2895,7 +2894,6 @@ fn subagent_feature_gates_match_parent_agent_surface() { "fetch_url", "web.run", "wait_for_dev_server", - "remember", ] { assert!( !parent_names.contains(name),