Skip to content

Commit 223411a

Browse files
tusharmathautofix-ci[bot]forge-code-agent
authored
refactor: drop agents from workflow (tailcallhq#1483)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: ForgeCode <noreply@forgecode.dev>
1 parent aa2956c commit 223411a

39 files changed

Lines changed: 612 additions & 980 deletions

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ This document contains guidelines and best practices for AI agents working with
7575
assert_eq(actual.b, expected.b);
7676

7777
## Verification
78+
Always verify changes by running tests and linting the codebase
7879

7980
1. Run crate specific tests to ensure they pass.
8081

Cargo.lock

Lines changed: 0 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ humantime = "2.2.0"
113113
gray_matter = "0.3.2"
114114
num-format = "0.4"
115115

116+
116117
# Internal crates
117118
forge_api = { path = "crates/forge_api" }
118119
forge_app = { path = "crates/forge_app" }

crates/forge_api/src/api.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ pub trait API: Sync + Send {
2020

2121
/// Provides a list of models available in the current environment
2222
async fn models(&self) -> Result<Vec<Model>>;
23+
/// Provides a list of agents available in the current environment
24+
async fn get_agents(&self) -> Result<Vec<Agent>>;
2325

2426
/// Executes a chat request and returns a stream of responses
2527
async fn chat(&self, chat: ChatRequest) -> Result<MpscStream<Result<ChatResponse>>>;

crates/forge_api/src/forge_api.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ use std::sync::Arc;
44
use anyhow::{Context, Result};
55
use forge_app::dto::{AppConfig, InitAuth};
66
use forge_app::{
7-
AppConfigService, AuthService, ConversationService, EnvironmentService, FileDiscoveryService,
8-
ForgeApp, McpConfigManager, ProviderRegistry, ProviderService, Services, User, UserUsage,
9-
Walker, WorkflowService,
7+
AgentLoaderService, AppConfigService, AuthService, ConversationService, EnvironmentService,
8+
FileDiscoveryService, ForgeApp, McpConfigManager, ProviderRegistry, ProviderService, Services,
9+
User, UserUsage, Walker, WorkflowService,
1010
};
1111
use forge_domain::*;
1212
use forge_infra::ForgeInfra;
@@ -53,6 +53,9 @@ impl<A: Services, F: CommandInfra> API for ForgeAPI<A, F> {
5353
.models(self.provider().await.context("User is not logged in")?)
5454
.await?)
5555
}
56+
async fn get_agents(&self) -> Result<Vec<Agent>> {
57+
Ok(self.services.get_agents().await?)
58+
}
5659

5760
async fn chat(
5861
&self,
@@ -67,11 +70,14 @@ impl<A: Services, F: CommandInfra> API for ForgeAPI<A, F> {
6770
&self,
6871
workflow: W,
6972
) -> anyhow::Result<Conversation> {
70-
self.services.create_conversation(workflow.into()).await
73+
let agents = self.get_agents().await?;
74+
self.services
75+
.init_conversation(workflow.into(), agents)
76+
.await
7177
}
7278

7379
async fn upsert_conversation(&self, conversation: Conversation) -> anyhow::Result<()> {
74-
self.services.upsert(conversation).await
80+
self.services.upsert_conversation(conversation).await
7581
}
7682

7783
async fn compact_conversation(
@@ -112,7 +118,7 @@ impl<A: Services, F: CommandInfra> API for ForgeAPI<A, F> {
112118
&self,
113119
conversation_id: &ConversationId,
114120
) -> anyhow::Result<Option<Conversation>> {
115-
self.services.find(conversation_id).await
121+
self.services.find_conversation(conversation_id).await
116122
}
117123

118124
async fn execute_shell_command(

crates/forge_app/src/agent.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,6 @@ impl<T: Services> AgentService for T {
7373
}
7474

7575
async fn update(&self, conversation: Conversation) -> anyhow::Result<()> {
76-
self.upsert(conversation).await
76+
self.upsert_conversation(conversation).await
7777
}
7878
}

crates/forge_app/src/agent_executor.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use futures::StreamExt;
1010
use tokio::sync::RwLock;
1111

1212
use crate::error::Error;
13-
use crate::{ConversationService, Services, WorkflowService};
13+
use crate::{AgentLoaderService, ConversationService, Services, WorkflowService};
1414

1515
#[derive(Clone)]
1616
pub struct AgentExecutor<S> {
@@ -24,15 +24,14 @@ impl<S: Services> AgentExecutor<S> {
2424
}
2525

2626
/// Returns a list of tool definitions for all available agents.
27-
pub async fn tool_agents(&self) -> anyhow::Result<Vec<ToolDefinition>> {
27+
pub async fn agent_definitions(&self) -> anyhow::Result<Vec<ToolDefinition>> {
2828
if let Some(tool_agents) = self.tool_agents.read().await.clone() {
2929
return Ok(tool_agents);
3030
}
31-
let workflow = self.services.read_merged(None).await?;
32-
33-
let agents: Vec<ToolDefinition> = workflow.agents.into_iter().map(Into::into).collect();
34-
*self.tool_agents.write().await = Some(agents.clone());
35-
Ok(agents)
31+
let agents = self.services.get_agents().await?;
32+
let tools: Vec<ToolDefinition> = agents.into_iter().map(Into::into).collect();
33+
*self.tool_agents.write().await = Some(tools.clone());
34+
Ok(tools)
3635
}
3736

3837
/// Executes an agent tool call by creating a new chat request for the
@@ -54,8 +53,10 @@ impl<S: Services> AgentExecutor<S> {
5453

5554
// Create a new conversation for agent execution
5655
let workflow = self.services.read_merged(None).await?;
56+
let agents = self.services.get_agents().await?;
5757
let conversation =
58-
ConversationService::create_conversation(self.services.as_ref(), workflow).await?;
58+
ConversationService::init_conversation(self.services.as_ref(), workflow, agents)
59+
.await?;
5960

6061
// Execute the request through the ForgeApp
6162
let app = crate::ForgeApp::new(self.services.clone());
@@ -99,7 +100,7 @@ impl<S: Services> AgentExecutor<S> {
99100
}
100101

101102
pub async fn contains_tool(&self, tool_name: &ToolName) -> anyhow::Result<bool> {
102-
let agent_tools = self.tool_agents().await?;
103+
let agent_tools = self.agent_definitions().await?;
103104
Ok(agent_tools.iter().any(|tool| tool.name == *tool_name))
104105
}
105106
}

crates/forge_app/src/app.rs

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@ use crate::dto::InitAuth;
1111
use crate::orch::Orchestrator;
1212
use crate::services::{CustomInstructionsService, TemplateService};
1313
use crate::tool_registry::ToolRegistry;
14-
use crate::workflow_manager::WorkflowManager;
1514
use crate::{
1615
AppConfigService, AttachmentService, ConversationService, EnvironmentService,
17-
FileDiscoveryService, ProviderRegistry, ProviderService, Services, Walker,
16+
FileDiscoveryService, ProviderRegistry, ProviderService, Services, Walker, WorkflowService,
1817
};
1918

2019
/// ForgeApp handles the core chat functionality by orchestrating various
@@ -24,7 +23,6 @@ pub struct ForgeApp<S> {
2423
services: Arc<S>,
2524
tool_registry: ToolRegistry<S>,
2625
authenticator: Authenticator<S>,
27-
workflow_manager: WorkflowManager<S>,
2826
}
2927

3028
impl<S: Services> ForgeApp<S> {
@@ -33,7 +31,6 @@ impl<S: Services> ForgeApp<S> {
3331
Self {
3432
tool_registry: ToolRegistry::new(services.clone()),
3533
authenticator: Authenticator::new(services.clone()),
36-
workflow_manager: WorkflowManager::new(services.clone()),
3734
services,
3835
}
3936
}
@@ -48,7 +45,7 @@ impl<S: Services> ForgeApp<S> {
4845

4946
// Get the conversation for the chat request
5047
let conversation = services
51-
.find(&chat.conversation_id)
48+
.find_conversation(&chat.conversation_id)
5249
.await
5350
.unwrap_or_default()
5451
.expect("conversation for the request should've been created at this point.");
@@ -63,11 +60,7 @@ impl<S: Services> ForgeApp<S> {
6360
let models = services.models(provider).await?;
6461

6562
// Discover files using the discovery service
66-
let workflow = self
67-
.workflow_manager
68-
.read_merged(None)
69-
.await
70-
.unwrap_or_default();
63+
let workflow = self.services.read_merged(None).await.unwrap_or_default();
7164
let max_depth = workflow.max_walker_depth;
7265
let environment = services.get_environment();
7366

@@ -117,15 +110,13 @@ impl<S: Services> ForgeApp<S> {
117110
let stream = MpscStream::spawn(
118111
|tx: tokio::sync::mpsc::Sender<Result<ChatResponse, anyhow::Error>>| {
119112
async move {
120-
let tx = Arc::new(tx);
121-
122113
// Execute dispatch and always save conversation afterwards
123114
let mut orch = orch.sender(tx.clone());
124115
let dispatch_result = orch.chat(chat.event).await;
125116

126117
// Always save conversation using get_conversation()
127118
let conversation = orch.get_conversation().clone();
128-
let save_result = services.upsert(conversation).await;
119+
let save_result = services.upsert_conversation(conversation).await;
129120

130121
// Send any error to the stream (prioritize dispatch error over save error)
131122
#[allow(clippy::collapsible_if)]
@@ -153,7 +144,7 @@ impl<S: Services> ForgeApp<S> {
153144
// Get the conversation
154145
let mut conversation = self
155146
.services
156-
.find(conversation_id)
147+
.find_conversation(conversation_id)
157148
.await?
158149
.ok_or_else(|| anyhow::anyhow!("Conversation not found: {}", conversation_id))?;
159150

@@ -191,7 +182,7 @@ impl<S: Services> ForgeApp<S> {
191182
conversation.context = Some(compacted_context);
192183

193184
// Save the updated conversation
194-
self.services.upsert(conversation).await?;
185+
self.services.upsert_conversation(conversation).await?;
195186

196187
// Return the compaction metrics
197188
Ok(CompactionResult::new(
@@ -215,13 +206,13 @@ impl<S: Services> ForgeApp<S> {
215206
self.authenticator.logout().await
216207
}
217208
pub async fn read_workflow(&self, path: Option<&Path>) -> Result<Workflow> {
218-
self.workflow_manager.read_workflow(path).await
209+
self.services.read_workflow(path).await
219210
}
220211

221212
pub async fn read_workflow_merged(&self, path: Option<&Path>) -> Result<Workflow> {
222-
self.workflow_manager.read_merged(path).await
213+
self.services.read_merged(path).await
223214
}
224215
pub async fn write_workflow(&self, path: Option<&Path>, workflow: &Workflow) -> Result<()> {
225-
self.workflow_manager.write_workflow(path, workflow).await
216+
self.services.write_workflow(path, workflow).await
226217
}
227218
}

crates/forge_app/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ mod truncation;
1919
mod user;
2020
mod utils;
2121
mod walker;
22-
mod workflow_manager;
2322

2423
pub use agent::*;
2524
pub use app::*;

crates/forge_app/src/orch.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use tracing::{debug, info, warn};
1212

1313
use crate::agent::AgentService;
1414
use crate::compact::Compactor;
15-
pub type ArcSender = Arc<tokio::sync::mpsc::Sender<anyhow::Result<ChatResponse>>>;
1615

1716
#[derive(Clone, Setters)]
1817
#[setters(into, strip_option)]

0 commit comments

Comments
 (0)