Fix provider/model persistence and rewrite Aider runner for interactive mode

Rust groups.rs ProjectConfig was missing provider, model, and other optional
fields — serde silently dropped them on save, causing all projects to fall
back to claude/Opus on reload. Added all missing fields to both ProjectConfig
and GroupAgentConfig structs.

Rewrote aider-runner from one-shot --message mode to interactive stdin/stdout:
- Persistent aider process with multi-turn conversation support
- Pre-fetches btmsg inbox and bttask board before sending prompt to LLM
- Autonomous agent override prompt so LLM acts instead of asking for files
- Line-buffered output (no token-by-token fragments)
- Thinking block classification for DeepSeek R1
- Graceful /exit shutdown

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
DexterFromLab 2026-03-12 16:01:46 +01:00
parent e8555625ff
commit 862ddfcbb8
2 changed files with 290 additions and 99 deletions

View file

@ -25,6 +25,24 @@ pub struct ProjectConfig {
pub cwd: String,
pub profile: String,
pub enabled: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub provider: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub model: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub use_worktrees: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sandbox_enabled: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub anchor_budget_scale: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stall_threshold_min: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_agent: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub agent_role: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub system_prompt: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@ -34,6 +52,8 @@ pub struct GroupAgentConfig {
pub name: String,
pub role: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub provider: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub model: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cwd: Option<String>,
@ -42,6 +62,10 @@ pub struct GroupAgentConfig {
pub enabled: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub wake_interval_min: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub wake_strategy: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub wake_threshold: Option<f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]