From 33da8ac4c5fd69e2af3a155a71f827548ad9b605 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 12 Dec 2025 21:06:12 +0000 Subject: [PATCH] Fix imix task execution hang by implementing Drop for Interpreter This change fixes a concurrency issue where imix tasks using the agent's transport would hang indefinitely upon completion. - Implemented `Drop` for `eldritch_core::Interpreter` to explicitly clear the environment values and parent reference. This breaks the reference cycles (e.g., Environment -> Value -> Function -> Environment) that prevented the underlying transport resources from being cleaned up. - Introduced `is_scope_owner` flag to `Interpreter` to distinguish between the root interpreter (which should cleanup the environment) and temporary interpreters used for `eval()` (which share the environment and should not clear it). - Updated `imixv2` tests to align with recent API changes in `claim_tasks`. --- implants/imixv2/src/tests/agent_trait_tests.rs | 2 +- .../eldritch-core/src/interpreter/core.rs | 13 +++++++++++++ .../eldritch-core/src/interpreter/eval.rs | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/implants/imixv2/src/tests/agent_trait_tests.rs b/implants/imixv2/src/tests/agent_trait_tests.rs index 0486dd4de..b57d3e57f 100644 --- a/implants/imixv2/src/tests/agent_trait_tests.rs +++ b/implants/imixv2/src/tests/agent_trait_tests.rs @@ -168,7 +168,7 @@ async fn test_imix_agent_claim_tasks() { let agent_clone = agent.clone(); std::thread::spawn(move || { - let _ = agent_clone.claim_tasks(c2::ClaimTasksRequest { beacon: None }); + let _ = agent_clone.claim_tasks(); }) .join() .unwrap(); diff --git a/implants/lib/eldritchv2/eldritch-core/src/interpreter/core.rs b/implants/lib/eldritchv2/eldritch-core/src/interpreter/core.rs index 46cfca9d7..d40d3bbb7 100644 --- a/implants/lib/eldritchv2/eldritch-core/src/interpreter/core.rs +++ b/implants/lib/eldritchv2/eldritch-core/src/interpreter/core.rs @@ -32,6 +32,18 @@ pub struct Interpreter { pub depth: usize, pub call_stack: Vec, pub current_func_name: String, + pub is_scope_owner: bool, +} + +impl Drop for Interpreter { + fn drop(&mut self) { + if self.is_scope_owner { + // Break reference cycles by clearing the environment values. + // This drops all variables including functions, which may hold references back to the environment. + self.env.write().values.clear(); + self.env.write().parent = None; + } + } } impl Default for Interpreter { @@ -59,6 +71,7 @@ impl Interpreter { depth: 0, call_stack: Vec::new(), current_func_name: "".to_string(), + is_scope_owner: true, }; interpreter.load_builtins(); diff --git a/implants/lib/eldritchv2/eldritch-core/src/interpreter/eval.rs b/implants/lib/eldritchv2/eldritch-core/src/interpreter/eval.rs index b1461857d..024c4eaf3 100644 --- a/implants/lib/eldritchv2/eldritch-core/src/interpreter/eval.rs +++ b/implants/lib/eldritchv2/eldritch-core/src/interpreter/eval.rs @@ -868,6 +868,7 @@ fn builtin_eval( depth: interp.depth + 1, call_stack: interp.call_stack.clone(), current_func_name: "".to_string(), + is_scope_owner: false, }; match temp_interp.interpret(&code) {