feat: edit coding agent profiles (#453)

* edit profiles.json

* move default crate configuration to a default_profiles.json

button to open mcp config in editor

initialse empty mcp config files

fix test

new JSON structure

remove editor buttons

fmt and types

* feat: add profile field to follow-up attempt (#442)

* move default crate configuration to a default_profiles.json

* new JSON structure

* feat: add profile field to follow-up attempt; fix follow ups using wrong session id at 2nd+ follow up

fmt

Profile selection (vibe-kanban cf714482)

Right now in the frontend, when viewing a task card, we show the base_coding_agent from the task attempt. We should also show the currently selected profile there in the same way

feat: add watchkill support to CommandBuilder and integrate with Claude executor

feat: refactor profile handling to use ProfileVariant across executors and requests

feat: restructure command modes in default_profiles.json for clarity and consistency

update profile handling to use ProfileVariant across components and add mode selection

fmt

feat: refactor profile handling to use variants instead of modes across components and update related structures

Fix frontend

* Refactor coding agent representation in task and task attempt models

- Changed `base_coding_agent` field to `profile` in `TaskWithAttemptStatus` and `TaskAttempt` structs.
- Updated SQL queries and data handling to reflect the new `profile` field.
- Modified related API endpoints and request/response structures to use `profile` instead of `base_coding_agent`.
- Adjusted frontend API calls and components to align with the updated data structure.
- Removed unused `BaseCodingAgent` enum and related type guards from the frontend.
- Enhanced MCP server configuration handling to utilize the new profile-based approach.

feat: Introduce MCP configuration management

- Added `McpConfig` struct for managing MCP server configurations.
- Implemented reading and writing of agent config files in JSON and TOML formats.
- Refactored MCP server handling in the `McpServers` component to utilize the new configuration structure.
- Removed deprecated `agent_config.rs` and updated related imports.
- Enhanced error handling for MCP server operations.
- Updated frontend strategies to accommodate the new MCP configuration structure.

feat: Introduce MCP configuration management

- Added `McpConfig` struct for managing MCP server configurations.
- Implemented reading and writing of agent config files in JSON and TOML formats.
- Refactored MCP server handling in the `McpServers` component to utilize the new configuration structure.
- Removed deprecated `agent_config.rs` and updated related imports.
- Enhanced error handling for MCP server operations.
- Updated frontend strategies to accommodate the new MCP configuration structure.

Best effort migration; add missing feature flag

feat: refactor execution process handling and introduce profile variant extraction

feat: add default follow-up variant handling in task details context

feat: enhance profile variant selection with dropdown menus in onboarding and task sections

fmt, types

* refactor: rename ProfileVariant to ProfileVariantLabel; Modified AgentProfile to wrap AgentProfileVariant

Fmt, clippy

* Fix rebase issues

* refactor: replace OnceLock with RwLock for AgentProfiles caching; update profile retrieval in executors and routes

---------

Co-authored-by: Gabriel Gordon-Hall <ggordonhall@gmail.com>

Fmt

Fix tests

refactor: clean up unused imports and default implementations in executor modules

Move profiles to profiles.rs

* rename profile to profile_variant_label for readability

rename AgentProfile to ProfileConfig, AgentProfileVariant to VariantAgentConfig

* remove duplicated profile state

* Amp yolo

---------

Co-authored-by: Alex Netsch <alex@bloop.ai>
This commit is contained in:
Gabriel Gordon-Hall
2025-08-14 17:33:33 +01:00
committed by GitHub
parent 2e07aa1a49
commit 9b4ca9dc45
64 changed files with 2086 additions and 1434 deletions

View File

@@ -0,0 +1,81 @@
//! Utilities for reading and writing external agent config files (not the server's own config).
//!
//! These helpers abstract over JSON vs TOML formats used by different agents.
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use tokio::fs;
use ts_rs::TS;
use crate::executors::ExecutorError;
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
pub struct McpConfig {
servers: HashMap<String, serde_json::Value>,
pub servers_path: Vec<String>,
pub template: serde_json::Value,
pub vibe_kanban: serde_json::Value,
pub is_toml_config: bool,
}
impl McpConfig {
pub fn new(
servers_path: Vec<String>,
template: serde_json::Value,
vibe_kanban: serde_json::Value,
is_toml_config: bool,
) -> Self {
Self {
servers: HashMap::new(),
servers_path,
template,
vibe_kanban,
is_toml_config,
}
}
pub fn set_servers(&mut self, servers: HashMap<String, serde_json::Value>) {
self.servers = servers;
}
}
/// Read an agent's external config file (JSON or TOML) and normalize it to serde_json::Value.
pub async fn read_agent_config(
config_path: &std::path::Path,
mcp_config: &McpConfig,
) -> Result<Value, ExecutorError> {
if let Ok(file_content) = fs::read_to_string(config_path).await {
if mcp_config.is_toml_config {
// Parse TOML then convert to JSON Value
if file_content.trim().is_empty() {
return Ok(serde_json::json!({}));
}
let toml_val: toml::Value = toml::from_str(&file_content)?;
let json_string = serde_json::to_string(&toml_val)?;
Ok(serde_json::from_str(&json_string)?)
} else {
Ok(serde_json::from_str(&file_content)?)
}
} else {
Ok(mcp_config.template.clone())
}
}
/// Write an agent's external config (as serde_json::Value) back to disk in the agent's format (JSON or TOML).
pub async fn write_agent_config(
config_path: &std::path::Path,
mcp_config: &McpConfig,
config: &Value,
) -> Result<(), ExecutorError> {
if mcp_config.is_toml_config {
// Convert JSON Value back to TOML
let toml_value: toml::Value = serde_json::from_str(&serde_json::to_string(config)?)?;
let toml_content = toml::to_string_pretty(&toml_value)?;
fs::write(config_path, toml_content).await?;
} else {
let json_content = serde_json::to_string_pretty(config)?;
fs::write(config_path, json_content).await?;
}
Ok(())
}