Skip to content

feat: remaining gaps — shared context, cost per tool, validate-config#28

Merged
kienbui1995 merged 1 commit intomainfrom
feat/remaining-gaps
Apr 11, 2026
Merged

feat: remaining gaps — shared context, cost per tool, validate-config#28
kienbui1995 merged 1 commit intomainfrom
feat/remaining-gaps

Conversation

@kienbui1995
Copy link
Copy Markdown
Owner

@kienbui1995 kienbui1995 commented Apr 11, 2026

Subagent shared context (Tier 1)

Agents share results via SharedContext board. Each subagent's output is stored and injected into subsequent agents' system prompts.

Cost per tool (Tier 2)

/cost now shows tool call counts:

─── Tool call counts ─────
  bash: 5x
  read_file: 3x
  edit_file: 2x
──────────────────────────

--validate-config (Tier 3)

magic-code --validate-config
✅ Config valid: anthropic provider, model claude-sonnet-4-20250514
  MCP servers: 1
  Hooks: 0
  Tool permissions: {}

180 tests pass.

Summary by CodeRabbit

  • New Features
    • Added --validate-config CLI flag to validate configuration and exit without launching the interface.
    • Enhanced /cost command to display per-tool call counts for improved cost tracking.

- Subagent shared context: agents can see each other's results
  via SharedContext board injected into system prompt
- Cost per tool: /cost now shows tool call counts breakdown
- --validate-config: validate config and exit with summary
- tool_call_counts tracked per tool name in TUI
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 11, 2026

📝 Walkthrough

Walkthrough

This pull request introduces a shared context system for inter-task communication in subagents, adds per-tool call tracking to the TUI application, and implements a CLI flag for early configuration validation without starting the execution flow.

Changes

Cohort / File(s) Summary
CLI Configuration Validation
mc/crates/mc-cli/src/main.rs
Added --validate-config flag to validate configuration and exit early. Refactored config warning iteration to use a warnings collection, and updated tool call event handling to increment per-tool call counters.
Shared Context Infrastructure
mc/crates/mc-core/src/lib.rs, mc/crates/mc-core/src/subagent.rs
Introduced SharedContext struct backed by thread-safe Arc<Mutex<HashMap>> with methods to set, get, and summarize key/value pairs. Extended SubagentSpawner with shared_context field and updated run_task to enrich prompts with context summary and store task outputs.
Tool Call Tracking
mc/crates/mc-tui/src/app.rs, mc/crates/mc-tui/src/commands.rs
Added tool_call_counts: HashMap<String, u32> field to App struct to track per-tool invocation counts. Updated /cost command to display tool call counts sorted by frequency.

Sequence Diagram(s)

sequenceDiagram
    participant TUI
    participant SubagentSpawner
    participant SharedContext
    participant Agent
    
    TUI->>SubagentSpawner: run_task(task_prompt, system_prompt)
    activate SubagentSpawner
    SubagentSpawner->>SharedContext: summary()
    activate SharedContext
    SharedContext-->>SubagentSpawner: context_summary
    deactivate SharedContext
    SubagentSpawner->>SubagentSpawner: build enriched_prompt<br/>(system_prompt + context_summary)
    SubagentSpawner->>Agent: run_simple_agent(enriched_prompt)
    activate Agent
    Agent-->>SubagentSpawner: output/error
    deactivate Agent
    SubagentSpawner->>SharedContext: set(task_key, result)
    activate SharedContext
    SharedContext-->>SubagentSpawner: stored
    deactivate SharedContext
    SubagentSpawner-->>TUI: task_result
    deactivate SubagentSpawner
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 A context flows through tasks so bright,
Shared whispers guide the agent's flight,
Each tool now counted, tracked with care,
Config validates before we dare,
The burrow's work grows strong and fair! 🎯

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes all three major features added in the PR: shared context for agent communication, per-tool cost tracking, and the validate-config flag.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/remaining-gaps

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
mc/crates/mc-cli/src/main.rs (1)

382-382: ⚠️ Potential issue | 🟡 Minor

Multiple CI formatting failures throughout the file.

The CI reports formatting issues at lines 382, 790, 1109, 1419-1420, 1506, 1524, and 1531. Run cargo fmt to fix all formatting issues in this file.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@mc/crates/mc-cli/src/main.rs` at line 382, This file has multiple Rust
formatting failures; run `cargo fmt` in the workspace to auto-fix formatting
across mc-cli/src/main.rs (including the stated locations around the main
function and other blocks where stray spacing/indentation exists, e.g., near the
closing parenthesis/semicolon tokens shown in the diff) and commit the resulting
changes; ensure rustfmt is configured consistently (rustfmt.toml if used) so
subsequent CI runs pass.
🧹 Nitpick comments (1)
mc/crates/mc-core/src/subagent.rs (1)

24-28: Silent failure on lock poisoning in set().

If the mutex is poisoned (a panic occurred while holding the lock), set() silently discards the write. Consider logging when this happens.

🔧 Proposed fix to add logging
     pub fn set(&self, key: &str, value: &str) {
-        if let Ok(mut map) = self.entries.lock() {
-            map.insert(key.to_string(), value.to_string());
+        match self.entries.lock() {
+            Ok(mut map) => {
+                map.insert(key.to_string(), value.to_string());
+            }
+            Err(e) => {
+                tracing::warn!("SharedContext lock poisoned, recovering: {e}");
+                e.into_inner().insert(key.to_string(), value.to_string());
+            }
         }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@mc/crates/mc-core/src/subagent.rs` around lines 24 - 28, The set() method
currently ignores a poisoned mutex since it only handles Ok from
self.entries.lock(); change it to detect Err from entries.lock() and log an
error when the mutex is poisoned (including the key and a contextual message and
the lock error), then still attempt to recover if appropriate (e.g.,
lock.into_inner() or map access) or return early; update references to
entries.lock() and the map.insert(...) call in set() to include this logging so
silent failures are visible.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@mc/crates/mc-core/src/subagent.rs`:
- Around line 88-94: Replace the redundant format!("{system_prompt}") call when
building enriched_prompt: use system_prompt.to_string() for the empty-shared
branch and build the combined string without the unnecessary named-format
pattern (e.g., system_prompt.to_string() + &shared or format!("{}{}",
system_prompt, shared)) so the code uses system_prompt.to_string() in the if
branch and a simple concatenation/format for the else branch; key symbols:
shared_context.summary(), enriched_prompt, system_prompt.
- Around line 108-113: The current use of
task_prompt.chars().take(50).collect::<String>() as task_key risks collisions
for prompts that share prefixes; change task_key generation in subagent (where
task_key is created) to derive a unique identifier instead—e.g., compute a
stable hash (sha256/xxhash) of the full task_prompt or combine a truncated
prefix with a short hash of task_prompt, then use that as the key passed to
self.shared_context.set; ensure both the Ok(output) and Err(e) branches use the
new key so results don't overwrite each other for different contexts.

---

Outside diff comments:
In `@mc/crates/mc-cli/src/main.rs`:
- Line 382: This file has multiple Rust formatting failures; run `cargo fmt` in
the workspace to auto-fix formatting across mc-cli/src/main.rs (including the
stated locations around the main function and other blocks where stray
spacing/indentation exists, e.g., near the closing parenthesis/semicolon tokens
shown in the diff) and commit the resulting changes; ensure rustfmt is
configured consistently (rustfmt.toml if used) so subsequent CI runs pass.

---

Nitpick comments:
In `@mc/crates/mc-core/src/subagent.rs`:
- Around line 24-28: The set() method currently ignores a poisoned mutex since
it only handles Ok from self.entries.lock(); change it to detect Err from
entries.lock() and log an error when the mutex is poisoned (including the key
and a contextual message and the lock error), then still attempt to recover if
appropriate (e.g., lock.into_inner() or map access) or return early; update
references to entries.lock() and the map.insert(...) call in set() to include
this logging so silent failures are visible.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8e144df2-6ce0-43c7-ad66-aa12cb008476

📥 Commits

Reviewing files that changed from the base of the PR and between adc3ea3 and 16d3af7.

📒 Files selected for processing (5)
  • mc/crates/mc-cli/src/main.rs
  • mc/crates/mc-core/src/lib.rs
  • mc/crates/mc-core/src/subagent.rs
  • mc/crates/mc-tui/src/app.rs
  • mc/crates/mc-tui/src/commands.rs

Comment on lines +88 to +94
// Inject shared context from other agents
let shared = self.shared_context.summary();
let enriched_prompt = if shared.is_empty() {
format!("{system_prompt}")
} else {
format!("{system_prompt}{shared}")
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Redundant format! macro and formatting issue flagged by CI.

Line 91 uses format!("{system_prompt}") which is unnecessary—just use system_prompt.to_string(). This also addresses the CI formatting failure on line 42 (which appears to be a line number discrepancy in the CI output pointing to this format! call pattern).

🧹 Proposed fix
         // Inject shared context from other agents
         let shared = self.shared_context.summary();
         let enriched_prompt = if shared.is_empty() {
-            format!("{system_prompt}")
+            system_prompt.to_string()
         } else {
             format!("{system_prompt}{shared}")
         };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Inject shared context from other agents
let shared = self.shared_context.summary();
let enriched_prompt = if shared.is_empty() {
format!("{system_prompt}")
} else {
format!("{system_prompt}{shared}")
};
// Inject shared context from other agents
let shared = self.shared_context.summary();
let enriched_prompt = if shared.is_empty() {
system_prompt.to_string()
} else {
format!("{system_prompt}{shared}")
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@mc/crates/mc-core/src/subagent.rs` around lines 88 - 94, Replace the
redundant format!("{system_prompt}") call when building enriched_prompt: use
system_prompt.to_string() for the empty-shared branch and build the combined
string without the unnecessary named-format pattern (e.g.,
system_prompt.to_string() + &shared or format!("{}{}", system_prompt, shared))
so the code uses system_prompt.to_string() in the if branch and a simple
concatenation/format for the else branch; key symbols: shared_context.summary(),
enriched_prompt, system_prompt.

Comment on lines +108 to +113
// Store result in shared context for other agents
let task_key = task_prompt.chars().take(50).collect::<String>();
match &result {
Ok(output) => self.shared_context.set(&task_key, output),
Err(e) => self.shared_context.set(&task_key, &format!("error: {e}")),
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Task key collision risk with truncated keys.

Using the first 50 characters of task_prompt as the key can cause collisions when multiple tasks share common prefixes. Per the context snippet from runtime.rs:920-948, task prompts are constructed as "{task}\n\nContext:\n{context}", so tasks with the same initial text but different contexts will overwrite each other's results.

Consider using a hash or including a unique identifier.

🔧 Proposed fix using hash
+use std::collections::hash_map::DefaultHasher;
+use std::hash::{Hash, Hasher};

         // Store result in shared context for other agents
-        let task_key = task_prompt.chars().take(50).collect::<String>();
+        let task_key = {
+            let mut hasher = DefaultHasher::new();
+            task_prompt.hash(&mut hasher);
+            format!("task_{:x}", hasher.finish())
+        };
         match &result {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Store result in shared context for other agents
let task_key = task_prompt.chars().take(50).collect::<String>();
match &result {
Ok(output) => self.shared_context.set(&task_key, output),
Err(e) => self.shared_context.set(&task_key, &format!("error: {e}")),
}
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
// Store result in shared context for other agents
let task_key = {
let mut hasher = DefaultHasher::new();
task_prompt.hash(&mut hasher);
format!("task_{:x}", hasher.finish())
};
match &result {
Ok(output) => self.shared_context.set(&task_key, output),
Err(e) => self.shared_context.set(&task_key, &format!("error: {e}")),
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@mc/crates/mc-core/src/subagent.rs` around lines 108 - 113, The current use of
task_prompt.chars().take(50).collect::<String>() as task_key risks collisions
for prompts that share prefixes; change task_key generation in subagent (where
task_key is created) to derive a unique identifier instead—e.g., compute a
stable hash (sha256/xxhash) of the full task_prompt or combine a truncated
prefix with a short hash of task_prompt, then use that as the key passed to
self.shared_context.set; ensure both the Ok(output) and Err(e) branches use the
new key so results don't overwrite each other for different contexts.

@kienbui1995 kienbui1995 merged commit 39bb751 into main Apr 11, 2026
6 of 7 checks passed
@kienbui1995 kienbui1995 deleted the feat/remaining-gaps branch April 11, 2026 19:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant