Refactor subagent and workflow domain models; migrate access tiers and events to domain module
- Moved `AccessTier` and `SubagentEvent` enums to `zesdex_domain::subagent`. - Consolidated workflow-related types into `zesdex_domain::workflow`. - Updated references across the codebase to use the new domain models. - Refactored tool execution logic to utilize a new `ToolExecutor` trait. - Enhanced `AgentTurnService` to handle tool calls and events more effectively. - Adjusted API handlers and state management to align with new domain structure.
This commit is contained in:
@@ -25,11 +25,9 @@ use zesdex_domain::core::ChatMessage;
|
||||
|
||||
const REVIEW_AGENT_ID: &str = "auto-review";
|
||||
|
||||
/// Spawn a background thread that reviews changes and auto-fixes issues.
|
||||
/// Spawn a background task that reviews changes and auto-fixes issues.
|
||||
///
|
||||
/// Everything runs synchronously on the background thread — no tokio
|
||||
/// runtime is created, avoiding the nested-runtime panic from
|
||||
/// reqwest::blocking inside block_on in tokio >= 1.38.
|
||||
/// Runs asynchronously using tokio::spawn.
|
||||
#[instrument(skip(turn_events))]
|
||||
pub fn spawn_background_review(
|
||||
workspace_roots: Vec<PathBuf>,
|
||||
@@ -41,7 +39,7 @@ pub fn spawn_background_review(
|
||||
let agent_id = REVIEW_AGENT_ID.to_string();
|
||||
let agent_name = "Auto-Review".to_string();
|
||||
|
||||
std::thread::spawn(move || {
|
||||
tokio::spawn(async move {
|
||||
let root = match workspace_roots.first() {
|
||||
Some(r) => r.clone(),
|
||||
None => {
|
||||
@@ -140,8 +138,6 @@ pub fn spawn_background_review(
|
||||
};
|
||||
|
||||
// 5. Call LLM to review the diff and suggest fixes.
|
||||
// No tokio runtime needed — LlmClient uses reqwest::blocking
|
||||
// internally, which is fine on a plain thread.
|
||||
let system_msg = ChatMessage::system(
|
||||
"You are an auto-review subagent. Your ONLY job:\n\
|
||||
1. Review the git diff below for:\n\
|
||||
@@ -171,8 +167,7 @@ pub fn spawn_background_review(
|
||||
"Review and fix this git diff:\n\n```diff\n{truncated_diff}\n```"
|
||||
));
|
||||
|
||||
// This is a sync call — no tokio runtime required on this thread.
|
||||
let response = run_llm_review(&client, &[system_msg, user_msg]);
|
||||
let response = run_llm_review(&client, &[system_msg, user_msg]).await;
|
||||
|
||||
let response_text = match response {
|
||||
Ok(text) => text,
|
||||
@@ -232,10 +227,10 @@ pub fn spawn_background_review(
|
||||
});
|
||||
}
|
||||
|
||||
/// Run the LLM review call synchronously using reqwest::blocking.
|
||||
fn run_llm_review(client: &LlmClient, messages: &[ChatMessage]) -> Result<String, String> {
|
||||
// Direct LLM call — no tokio, no tool calls, just Q&A.
|
||||
match client.chat_with_tools_non_streaming(messages, None, Some(1024), Some(0.3), None) {
|
||||
/// Run the LLM review call asynchronously using ProviderService.
|
||||
async fn run_llm_review(client: &LlmClient, messages: &[ChatMessage]) -> Result<String, String> {
|
||||
use zesdex_application::ports::ProviderService;
|
||||
match client.chat(messages, None, Some(1024), Some(0.3)).await {
|
||||
Ok((msg, _)) => Ok(msg.content.unwrap_or_default()),
|
||||
Err(e) => Err(e.to_string()),
|
||||
}
|
||||
|
||||
@@ -6,19 +6,7 @@
|
||||
|
||||
use crate::tools::Tool;
|
||||
|
||||
/// Access tier for subagent tool permissions.
|
||||
///
|
||||
/// Tiers are cumulative: `Write` includes everything in `Read`, and `Full`
|
||||
/// includes everything in `Write`.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum AccessTier {
|
||||
/// Read-only: search, read, glob, utility tools (no mutations).
|
||||
Read,
|
||||
/// Read + Write: above plus write, edit, delete, git, memory.
|
||||
Write,
|
||||
/// Full: above plus bash, shell, LSP, workflow, plan tools.
|
||||
Full,
|
||||
}
|
||||
pub use zesdex_domain::subagent::AccessTier;
|
||||
|
||||
/// Filter the available tools to match the given access tier.
|
||||
///
|
||||
|
||||
@@ -67,13 +67,13 @@ pub async fn run_agent(
|
||||
|
||||
// Limited iteration loop so we don't run forever
|
||||
for iteration in 0..MAX_ITERATIONS {
|
||||
let (response_msg, _usage) = client.chat_with_tools_non_streaming(
|
||||
use zesdex_application::ports::ProviderService;
|
||||
let (response_msg, _usage) = client.chat(
|
||||
&messages,
|
||||
Some(defs.clone()),
|
||||
Some(4096),
|
||||
None,
|
||||
None,
|
||||
)?;
|
||||
).await?;
|
||||
|
||||
let content = response_msg.content.clone().unwrap_or_default();
|
||||
let tool_calls = response_msg.tool_calls.unwrap_or_default();
|
||||
|
||||
@@ -1,27 +1,3 @@
|
||||
//! Subagent event types — events emitted during subagent execution.
|
||||
|
||||
/// Events emitted by a running subagent.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SubagentEvent {
|
||||
Started {
|
||||
agent_id: String,
|
||||
directive: String,
|
||||
},
|
||||
ToolCall {
|
||||
agent_id: String,
|
||||
tool_name: String,
|
||||
},
|
||||
ToolResult {
|
||||
agent_id: String,
|
||||
tool_name: String,
|
||||
output: String,
|
||||
},
|
||||
Completed {
|
||||
agent_id: String,
|
||||
output: String,
|
||||
},
|
||||
Failed {
|
||||
agent_id: String,
|
||||
error: String,
|
||||
},
|
||||
}
|
||||
pub use zesdex_domain::subagent::SubagentEvent;
|
||||
|
||||
@@ -35,12 +35,14 @@ impl SubagentProvider {
|
||||
///
|
||||
/// Use this for a plain text-in/text-out conversation.
|
||||
#[tracing::instrument(skip(self, messages))]
|
||||
pub fn chat(
|
||||
pub async fn chat(
|
||||
&self,
|
||||
messages: &[ChatMessage],
|
||||
) -> Result<(ChatMessage, Option<(u64, u64)>)> {
|
||||
use zesdex_application::ports::ProviderService;
|
||||
self.client
|
||||
.chat_with_tools_non_streaming(messages, None, Some(4096), None, None)
|
||||
.chat(messages, None, Some(4096), None)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Send messages with available tool definitions.
|
||||
@@ -48,14 +50,16 @@ impl SubagentProvider {
|
||||
/// Automatically converts the `&[Box<dyn Tool>]` slice to
|
||||
/// `Vec<ToolDef>` before passing to the underlying client.
|
||||
#[tracing::instrument(skip(self, messages, tools))]
|
||||
pub fn chat_with_tools(
|
||||
pub async fn chat_with_tools(
|
||||
&self,
|
||||
messages: &[ChatMessage],
|
||||
tools: &[Box<dyn Tool>],
|
||||
) -> Result<(ChatMessage, Option<(u64, u64)>)> {
|
||||
let defs = tool_defs(tools);
|
||||
use zesdex_application::ports::ProviderService;
|
||||
self.client
|
||||
.chat_with_tools_non_streaming(messages, Some(defs), Some(4096), None, None)
|
||||
.chat(messages, Some(defs), Some(4096), None)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user