feat: enhance agent management with project-level support

- Added support for project-level agents, allowing agents to be created, updated, and deleted within a specified working directory.
- Introduced `getAgentScope` function to determine the scope of agents based on their existence in project or user directories.
- Updated `getAgentSources`, `createAgent`, `updateAgent`, and `deleteAgent` functions to handle project-level paths and configurations.
- Enhanced logging to provide clearer information about agent operations, including scope and working directory.
- Refactored configuration reading and writing to accommodate project-specific configurations alongside user-level settings.
This commit is contained in:
Bohdan Triapitsyn
2025-12-29 22:42:10 +02:00
parent 0adcba854b
commit c4b9c18c24
10 changed files with 2849 additions and 1323 deletions
+35 -14
View File
@@ -1190,18 +1190,27 @@ async fn handle_agent_route(
req: Request<Body>,
name: String,
) -> Result<Response<Body>, StatusCode> {
// Get working directory for project-level agent detection
let working_directory = state.opencode.get_working_directory();
match method {
Method::GET => {
match opencode_config::get_agent_sources(&name).await {
Ok(sources) => Ok(json_response(
StatusCode::OK,
ConfigMetadataResponse {
name,
is_built_in: !sources.md.exists && !sources.json.exists,
scope: None,
sources,
},
)),
match opencode_config::get_agent_sources(&name, Some(&working_directory)).await {
Ok(sources) => {
let scope = sources.md.scope.clone().map(|s| match s {
opencode_config::Scope::User => opencode_config::CommandScope::User,
opencode_config::Scope::Project => opencode_config::CommandScope::Project,
});
Ok(json_response(
StatusCode::OK,
ConfigMetadataResponse {
name,
is_built_in: !sources.md.exists && !sources.json.exists,
scope,
sources,
},
))
}
Err(err) => {
error!("[desktop:config] Failed to read agent sources: {}", err);
Ok(config_error_response(
@@ -1216,8 +1225,17 @@ async fn handle_agent_route(
Ok(data) => data,
Err(resp) => return Ok(resp),
};
// Extract scope from payload if present
let scope = payload.get("scope")
.and_then(|v| v.as_str())
.and_then(|s| match s {
"project" => Some(opencode_config::AgentScope::Project),
"user" => Some(opencode_config::AgentScope::User),
_ => None,
});
match opencode_config::create_agent(&name, &payload).await {
match opencode_config::create_agent(&name, &payload, Some(&working_directory), scope).await {
Ok(()) => {
if let Err(resp) =
refresh_opencode_after_config_change(state, "agent creation").await
@@ -1253,7 +1271,7 @@ async fn handle_agent_route(
Err(resp) => return Ok(resp),
};
match opencode_config::update_agent(&name, &payload).await {
match opencode_config::update_agent(&name, &payload, Some(&working_directory)).await {
Ok(()) => {
if let Err(resp) =
refresh_opencode_after_config_change(state, "agent update").await
@@ -1283,7 +1301,7 @@ async fn handle_agent_route(
}
}
}
Method::DELETE => match opencode_config::delete_agent(&name).await {
Method::DELETE => match opencode_config::delete_agent(&name, Some(&working_directory)).await {
Ok(()) => {
if let Err(resp) =
refresh_opencode_after_config_change(state, "agent deletion").await
@@ -1329,7 +1347,10 @@ async fn handle_command_route(
Method::GET => {
match opencode_config::get_command_sources(&name, Some(&working_directory)).await {
Ok(sources) => {
let scope = sources.md.scope.clone();
let scope = sources.md.scope.clone().map(|s| match s {
opencode_config::Scope::User => opencode_config::CommandScope::User,
opencode_config::Scope::Project => opencode_config::CommandScope::Project,
});
Ok(json_response(
StatusCode::OK,
ConfigMetadataResponse {
File diff suppressed because it is too large Load Diff