2026-07-20 16:29:32 +07:00
|
|
|
//! TUI agent turn interface adapter — delegates execution to `zesdex_infrastructure::agent`.
|
2026-07-20 10:55:09 +07:00
|
|
|
|
2026-07-20 16:29:32 +07:00
|
|
|
use std::sync::atomic::Ordering;
|
|
|
|
|
use tracing::info;
|
2026-07-20 10:55:09 +07:00
|
|
|
|
|
|
|
|
use zesdex_domain::core::ChatMessage;
|
2026-07-20 16:29:32 +07:00
|
|
|
use zesdex_infrastructure::agent::{spawn_agent_turn as backend_spawn_agent_turn, AgentTurnParams};
|
2026-07-20 10:55:09 +07:00
|
|
|
use crate::state::AppStateRest;
|
|
|
|
|
|
2026-07-20 16:29:32 +07:00
|
|
|
/// Spawn an agent turn on a background thread by delegating to `zesdex-infrastructure`.
|
2026-07-20 15:53:20 +07:00
|
|
|
#[tracing::instrument(skip(state))]
|
2026-07-20 10:55:09 +07:00
|
|
|
pub fn spawn_agent_turn(state: &mut AppStateRest, text: String) {
|
2026-07-20 13:52:20 +07:00
|
|
|
// compare_exchange: only mark in-flight if not already running
|
2026-07-20 16:29:32 +07:00
|
|
|
if state
|
|
|
|
|
.turn_in_flight_flag
|
2026-07-20 13:52:20 +07:00
|
|
|
.compare_exchange(false, true, Ordering::SeqCst, Ordering::Relaxed)
|
|
|
|
|
.is_err()
|
|
|
|
|
{
|
|
|
|
|
return; // already running
|
2026-07-20 10:55:09 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let turn_events = state.turn_events.clone();
|
|
|
|
|
let in_flight = state.turn_in_flight_flag.clone();
|
|
|
|
|
let abort = state.abort_flag.clone();
|
|
|
|
|
let session_dir = state.session_dir.clone();
|
|
|
|
|
let workspace_roots = state.workspace_roots.clone();
|
|
|
|
|
|
2026-07-20 14:30:36 +07:00
|
|
|
// Resolve LLM provider configuration from settings
|
|
|
|
|
let provider_name = &state.settings.provider;
|
|
|
|
|
let provider_cfg = state.app_config.providers.get(provider_name).cloned();
|
2026-07-20 16:29:32 +07:00
|
|
|
|
2026-07-20 14:30:36 +07:00
|
|
|
let mut api_key = String::new();
|
|
|
|
|
if let Some(key) = state.settings.api_keys.get(provider_name) {
|
|
|
|
|
api_key = key.clone();
|
|
|
|
|
} else if let Some(ref cfg) = provider_cfg {
|
|
|
|
|
if let Some(ref default_key) = cfg.default_api_key {
|
|
|
|
|
api_key = default_key.clone();
|
|
|
|
|
}
|
|
|
|
|
if api_key.is_empty() {
|
|
|
|
|
if let Some(ref env_name) = cfg.api_key_env {
|
|
|
|
|
if let Ok(val) = std::env::var(env_name) {
|
|
|
|
|
api_key = val;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let model = state.settings.model.clone();
|
|
|
|
|
let api_base = provider_cfg.map(|cfg| cfg.api_base.clone());
|
|
|
|
|
|
2026-07-20 10:55:09 +07:00
|
|
|
let mut messages: Vec<ChatMessage> = state
|
|
|
|
|
.session_runtime
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|rt| rt.messages.clone())
|
|
|
|
|
.unwrap_or_default();
|
|
|
|
|
messages.push(ChatMessage::user(text));
|
|
|
|
|
|
|
|
|
|
if let Some(ref mut rt) = state.session_runtime {
|
|
|
|
|
rt.messages = messages.clone();
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-20 16:29:32 +07:00
|
|
|
info!("delegating agent turn to infrastructure engine (model: {})", model);
|
2026-07-20 10:55:09 +07:00
|
|
|
|
2026-07-20 16:29:32 +07:00
|
|
|
let params = AgentTurnParams {
|
|
|
|
|
messages,
|
|
|
|
|
session_dir,
|
|
|
|
|
workspace_roots,
|
|
|
|
|
turn_events,
|
|
|
|
|
in_flight,
|
|
|
|
|
abort,
|
|
|
|
|
api_key,
|
|
|
|
|
model,
|
|
|
|
|
api_base,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
backend_spawn_agent_turn(params);
|
2026-07-20 10:55:09 +07:00
|
|
|
}
|