Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/apps/desktop/src/api/tool_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ async fn build_tool_context(workspace_path: Option<&str>) -> ToolUseContext {
session_id: None,
dialog_turn_id: None,
workspace,
unlocked_collapsed_tools: Vec::new(),
custom_data: HashMap::new(),
computer_use_host: None,
cancellation_token: None,
Expand Down
7 changes: 7 additions & 0 deletions src/crates/acp/src/client/tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ impl Tool for AcpAgentTool {
))
}

fn short_description(&self) -> String {
format!(
"Delegate a task to the external ACP agent '{}'.",
self.display_name()
)
}

fn input_schema(&self) -> Value {
json!({
"type": "object",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ impl AgenticMode {
"Grep".to_string(),
"Glob".to_string(),
"WebSearch".to_string(),
"WebFetch".to_string(),
"TodoWrite".to_string(),
"GenerativeUI".to_string(),
"Skill".to_string(),
"AskUserQuestion".to_string(),
"Git".to_string(),
"TerminalControl".to_string(),
"ControlHub".to_string(),
"InitMiniApp".to_string(),
],
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::agentic::agents::Agent;
use crate::agentic::agents::{Agent, AgentToolPolicyOverrides};
use crate::agentic::tools::framework::ToolExposure;
use async_trait::async_trait;

pub struct DeepResearchMode {
default_tools: Vec<String>,
tool_exposure_overrides: AgentToolPolicyOverrides,
}

impl Default for DeepResearchMode {
Expand All @@ -13,6 +15,9 @@ impl Default for DeepResearchMode {

impl DeepResearchMode {
pub fn new() -> Self {
let mut tool_exposure_overrides = AgentToolPolicyOverrides::default();
tool_exposure_overrides.insert("WebSearch".to_string(), ToolExposure::Expanded);
tool_exposure_overrides.insert("WebFetch".to_string(), ToolExposure::Expanded);
Self {
default_tools: vec![
"Task".to_string(),
Expand All @@ -30,6 +35,7 @@ impl DeepResearchMode {
"TodoWrite".to_string(),
"AskUserQuestion".to_string(),
],
tool_exposure_overrides,
}
}
}
Expand Down Expand Up @@ -60,6 +66,10 @@ impl Agent for DeepResearchMode {
self.default_tools.clone()
}

fn tool_exposure_overrides(&self) -> &AgentToolPolicyOverrides {
&self.tool_exposure_overrides
}

fn is_readonly(&self) -> bool {
false
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::agentic::agents::{Agent, RequestContextPolicy};
use crate::agentic::agents::{Agent, AgentToolPolicyOverrides, RequestContextPolicy};
use crate::agentic::tools::framework::ToolExposure;
use async_trait::async_trait;

pub struct ReviewFixerAgent {
default_tools: Vec<String>,
tool_exposure_overrides: AgentToolPolicyOverrides,
}

impl Default for ReviewFixerAgent {
Expand All @@ -13,6 +15,9 @@ impl Default for ReviewFixerAgent {

impl ReviewFixerAgent {
pub fn new() -> Self {
let mut tool_exposure_overrides = AgentToolPolicyOverrides::default();
tool_exposure_overrides.insert("GetFileDiff".to_string(), ToolExposure::Expanded);
tool_exposure_overrides.insert("Git".to_string(), ToolExposure::Expanded);
Self {
default_tools: vec![
"Read".to_string(),
Expand All @@ -26,6 +31,7 @@ impl ReviewFixerAgent {
"TodoWrite".to_string(),
"Git".to_string(),
],
tool_exposure_overrides,
}
}
}
Expand Down Expand Up @@ -60,6 +66,10 @@ impl Agent for ReviewFixerAgent {
RequestContextPolicy::instructions_only()
}

fn tool_exposure_overrides(&self) -> &AgentToolPolicyOverrides {
&self.tool_exposure_overrides
}

fn is_readonly(&self) -> bool {
false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,60 +3,75 @@ use crate::agentic::deep_review_policy::{
REVIEWER_FRONTEND_AGENT_TYPE, REVIEWER_PERFORMANCE_AGENT_TYPE, REVIEWER_SECURITY_AGENT_TYPE,
REVIEW_JUDGE_AGENT_TYPE,
};
use crate::define_readonly_subagent;
use crate::agentic::agents::AgentToolPolicyOverrides;
use crate::agentic::tools::framework::ToolExposure;
use crate::define_readonly_subagent_with_overrides;

define_readonly_subagent!(
fn reviewer_tool_exposure_overrides() -> AgentToolPolicyOverrides {
let mut overrides = AgentToolPolicyOverrides::default();
overrides.insert("GetFileDiff".to_string(), ToolExposure::Expanded);
overrides.insert("Git".to_string(), ToolExposure::Expanded);
overrides
}

define_readonly_subagent_with_overrides!(
BusinessLogicReviewerAgent,
REVIEWER_BUSINESS_LOGIC_AGENT_TYPE,
"Business Logic Reviewer",
r#"Independent read-only reviewer focused on workflow correctness, business rules, state transitions, data integrity, and edge-case handling in the review target. Use this when you need a fresh perspective on whether the change still does the right thing for real users."#,
"review_business_logic_agent",
&["Read", "Grep", "Glob", "LS", "GetFileDiff", "Git"]
&["Read", "Grep", "Glob", "LS", "GetFileDiff", "Git"],
reviewer_tool_exposure_overrides()
);

define_readonly_subagent!(
define_readonly_subagent_with_overrides!(
PerformanceReviewerAgent,
REVIEWER_PERFORMANCE_AGENT_TYPE,
"Performance Reviewer",
r#"Independent read-only reviewer focused on latency, hot-path efficiency, unnecessary allocations, N+1 patterns, blocking calls, over-fetching, and scale-sensitive regressions introduced by the review target."#,
"review_performance_agent",
&["Read", "Grep", "Glob", "LS", "GetFileDiff", "Git"]
&["Read", "Grep", "Glob", "LS", "GetFileDiff", "Git"],
reviewer_tool_exposure_overrides()
);

define_readonly_subagent!(
define_readonly_subagent_with_overrides!(
SecurityReviewerAgent,
REVIEWER_SECURITY_AGENT_TYPE,
"Security Reviewer",
r#"Independent read-only reviewer focused on security risks such as injection, auth gaps, data exposure, unsafe command/file handling, privilege escalation, and trust-boundary mistakes in the review target."#,
"review_security_agent",
&["Read", "Grep", "Glob", "LS", "GetFileDiff", "Git"]
&["Read", "Grep", "Glob", "LS", "GetFileDiff", "Git"],
reviewer_tool_exposure_overrides()
);

define_readonly_subagent!(
define_readonly_subagent_with_overrides!(
ArchitectureReviewerAgent,
REVIEWER_ARCHITECTURE_AGENT_TYPE,
"Architecture Reviewer",
r#"Independent read-only reviewer focused on structural and architectural issues such as module boundary violations, API contract design, abstraction integrity, dependency direction, and cross-cutting concern impact in the review target."#,
"review_architecture_agent",
&["Read", "Grep", "Glob", "LS", "GetFileDiff", "Git"]
&["Read", "Grep", "Glob", "LS", "GetFileDiff", "Git"],
reviewer_tool_exposure_overrides()
);

define_readonly_subagent!(
define_readonly_subagent_with_overrides!(
FrontendReviewerAgent,
REVIEWER_FRONTEND_AGENT_TYPE,
"Frontend Reviewer",
r#"Independent read-only reviewer focused on frontend-specific issues such as i18n key synchronization, frontend performance patterns (e.g., memoization, virtualization, effect/reactivity dependencies), accessibility, state management, frontend-backend API contract alignment, and platform boundary compliance in the review target."#,
"review_frontend_agent",
&["Read", "Grep", "Glob", "LS", "GetFileDiff", "Git"]
&["Read", "Grep", "Glob", "LS", "GetFileDiff", "Git"],
reviewer_tool_exposure_overrides()
);

define_readonly_subagent!(
define_readonly_subagent_with_overrides!(
ReviewJudgeAgent,
REVIEW_JUDGE_AGENT_TYPE,
"Review Quality Inspector",
r#"Independent third-party arbiter that validates reviewer reports for logical consistency and evidence quality. It spot-checks specific code locations only when a claim needs verification, rather than re-reviewing the codebase from scratch."#,
"review_quality_gate_agent",
&["Read", "Grep", "Glob", "LS", "GetFileDiff", "Git"]
&["Read", "Grep", "Glob", "LS", "GetFileDiff", "Git"],
reviewer_tool_exposure_overrides()
);

#[cfg(test)]
Expand Down
113 changes: 111 additions & 2 deletions src/crates/core/src/agentic/agents/definitions/shared/readonly.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::agentic::agents::{Agent, RequestContextPolicy};
use crate::agentic::agents::{Agent, AgentToolPolicyOverrides, RequestContextPolicy};
use async_trait::async_trait;

/// Internal helper that holds the common metadata and behaviour for
Expand All @@ -9,22 +9,42 @@ pub struct ReadonlySubagent {
description: &'static str,
prompt_template: &'static str,
default_tools: &'static [&'static str],
tool_exposure_overrides: AgentToolPolicyOverrides,
}

impl ReadonlySubagent {
pub const fn new(
pub fn new(
id: &'static str,
name: &'static str,
description: &'static str,
prompt_template: &'static str,
default_tools: &'static [&'static str],
) -> Self {
Self::with_overrides(
id,
name,
description,
prompt_template,
default_tools,
AgentToolPolicyOverrides::default(),
)
}

pub fn with_overrides(
id: &'static str,
name: &'static str,
description: &'static str,
prompt_template: &'static str,
default_tools: &'static [&'static str],
tool_exposure_overrides: AgentToolPolicyOverrides,
) -> Self {
Self {
id,
name,
description,
prompt_template,
default_tools,
tool_exposure_overrides,
}
}
}
Expand Down Expand Up @@ -59,6 +79,10 @@ impl Agent for ReadonlySubagent {
RequestContextPolicy::instructions_only()
}

fn tool_exposure_overrides(&self) -> &AgentToolPolicyOverrides {
&self.tool_exposure_overrides
}

fn is_readonly(&self) -> bool {
true
}
Expand Down Expand Up @@ -130,6 +154,91 @@ macro_rules! define_readonly_subagent {
self.inner.request_context_policy()
}

fn tool_exposure_overrides(
&self,
) -> &$crate::agentic::agents::AgentToolPolicyOverrides {
self.inner.tool_exposure_overrides()
}

fn is_readonly(&self) -> bool {
self.inner.is_readonly()
}
}
};
}

#[macro_export]
macro_rules! define_readonly_subagent_with_overrides {
(
$struct_name:ident,
$id:expr,
$name:literal,
$description:literal,
$prompt:literal,
$tools:expr,
$overrides:expr
) => {
pub struct $struct_name {
inner: $crate::agentic::agents::ReadonlySubagent,
}

impl Default for $struct_name {
fn default() -> Self {
Self::new()
}
}

impl $struct_name {
pub fn new() -> Self {
Self {
inner: $crate::agentic::agents::ReadonlySubagent::with_overrides(
$id,
$name,
$description,
$prompt,
$tools,
$overrides,
),
}
}
}

#[async_trait::async_trait]
impl $crate::agentic::agents::Agent for $struct_name {
fn as_any(&self) -> &dyn std::any::Any {
self
}

fn id(&self) -> &str {
self.inner.id()
}

fn name(&self) -> &str {
self.inner.name()
}

fn description(&self) -> &str {
self.inner.description()
}

fn prompt_template_name(&self, model_name: Option<&str>) -> &str {
self.inner.prompt_template_name(model_name)
}

fn default_tools(&self) -> Vec<String> {
self.inner.default_tools()
}

fn request_context_policy(&self) -> $crate::agentic::agents::RequestContextPolicy {
self.inner.request_context_policy()
}

fn tool_exposure_overrides(
&self,
) -> &$crate::agentic::agents::AgentToolPolicyOverrides {
self.inner.tool_exposure_overrides()
}

fn is_readonly(&self) -> bool {
self.inner.is_readonly()
}
Expand Down
Loading
Loading