From a27e8151b39da4c8759e8e922ef132212327e413 Mon Sep 17 00:00:00 2001 From: asepharyana Date: Fri, 28 Aug 2026 15:27:25 +0700 Subject: [PATCH] feat(agent): wire auto-review (review_enabled no-op -> nyata) review_enabled (default TRUE) selama ini no-op: tampil di TUI settings overlay ("Review: true"), bisa di-toggle via command, TAPI spawn_background_review tidak pernah dipanggil & Origin::Reviewer tidak pernah dikonstruksi. User melihat "Review: true" padahal auto-review setelah edit tak pernah jalan. Sekarang feature yang sudah dibangun penuh (subagent/auto/engine.rs: git diff -> LLM review -> auto-fix HIGH/MEDIUM) di-wire: - daemon/handler.rs: trigger setelah run_turn bila review_enabled; capture flag+creds SEBELUM api_key/provider_cfg di-move ke LlmClient. - tui/turn.rs: sama, gated by state.settings.flags.review_enabled. - ws/lib.rs: channel minimal tanpa settings -> review nyala tiap prompt (konsisten dgn default ON). Aman: review fire-and-forget (tokio::spawn), get_git_diff skip bila no-change, no-op bila bukan git repo (auto/engine). Creds dipakai = creds ter-resolve yg sama dgn komposisi turn. Verifikasi: check/clippy/fmt/test workspace hijau (0 error/warning/fail). --- Cargo.lock | 22 +++++++++++----------- apps/interfaces/daemon/src/handler.rs | 21 +++++++++++++++++++++ apps/interfaces/tui/src/turn.rs | 19 +++++++++++++++++++ apps/interfaces/ws/src/lib.rs | 18 ++++++++++++++++++ 4 files changed, 69 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6301f11..6179964 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4862,7 +4862,7 @@ dependencies = [ [[package]] name = "zesdex-api" -version = "1.21.0" +version = "1.21.1" dependencies = [ "anyhow", "argon2", @@ -4885,7 +4885,7 @@ dependencies = [ [[package]] name = "zesdex-application" -version = "1.21.0" +version = "1.21.1" dependencies = [ "anyhow", "base64", @@ -4903,7 +4903,7 @@ dependencies = [ [[package]] name = "zesdex-bootstrap" -version = "1.21.0" +version = "1.21.1" dependencies = [ "anyhow", "chrono", @@ -4920,7 +4920,7 @@ dependencies = [ [[package]] name = "zesdex-daemon" -version = "1.21.0" +version = "1.21.1" dependencies = [ "anyhow", "base64", @@ -4944,7 +4944,7 @@ dependencies = [ [[package]] name = "zesdex-domain" -version = "1.21.0" +version = "1.21.1" dependencies = [ "anyhow", "base64", @@ -4960,7 +4960,7 @@ dependencies = [ [[package]] name = "zesdex-gateway" -version = "1.21.0" +version = "1.21.1" dependencies = [ "anyhow", "axum", @@ -4987,7 +4987,7 @@ dependencies = [ [[package]] name = "zesdex-grpc" -version = "1.21.0" +version = "1.21.1" dependencies = [ "anyhow", "axum", @@ -5004,7 +5004,7 @@ dependencies = [ [[package]] name = "zesdex-infrastructure" -version = "1.21.0" +version = "1.21.1" dependencies = [ "anyhow", "argon2", @@ -5052,7 +5052,7 @@ dependencies = [ [[package]] name = "zesdex-tui" -version = "1.21.0" +version = "1.21.1" dependencies = [ "anyhow", "base64", @@ -5078,7 +5078,7 @@ dependencies = [ [[package]] name = "zesdex-web" -version = "1.21.0" +version = "1.21.1" dependencies = [ "anyhow", "axum", @@ -5098,7 +5098,7 @@ dependencies = [ [[package]] name = "zesdex-ws" -version = "1.21.0" +version = "1.21.1" dependencies = [ "anyhow", "axum", diff --git a/apps/interfaces/daemon/src/handler.rs b/apps/interfaces/daemon/src/handler.rs index f9b8217..7a01236 100644 --- a/apps/interfaces/daemon/src/handler.rs +++ b/apps/interfaces/daemon/src/handler.rs @@ -320,6 +320,18 @@ fn handle_submit_input(state: &mut AppStateRest, text: String) { api_base: provider_cfg.as_ref().map(|cfg| cfg.api_base.clone()), }; + // Capture state for the optional background auto-review so it can run + // with the same resolved provider. Done here, before `api_key` / + // `provider_cfg` are moved into the client below. The reviewer is + // fire-and-forget and skips itself when the workspace has no diff. + let review_enabled = state.settings.flags.review_enabled; + let review_key = api_key.clone(); + let review_model = + zesdex_domain::cms::resolve_effective_model(&state.settings, &state.app_config); + let review_base = provider_cfg.as_ref().map(|c| c.api_base.clone()); + let review_ws = params.workspace_roots.clone(); + let review_events = params.turn_events.clone(); + let client = std::sync::Arc::new(zesdex_infrastructure::llm::provider::LlmClient::new( api_key, zesdex_domain::cms::resolve_effective_model(&state.settings, &state.app_config), @@ -348,6 +360,15 @@ fn handle_submit_input(state: &mut AppStateRest, text: String) { use zesdex_application::agent::AgentTurnService; tokio::spawn(async move { let _ = turn_service.run_turn(params).await; + if review_enabled { + zesdex_infrastructure::subagent::auto::engine::spawn_background_review( + review_ws, + review_events, + review_key, + review_model, + review_base, + ); + } }); } diff --git a/apps/interfaces/tui/src/turn.rs b/apps/interfaces/tui/src/turn.rs index fddb205..7e1e091 100644 --- a/apps/interfaces/tui/src/turn.rs +++ b/apps/interfaces/tui/src/turn.rs @@ -110,6 +110,16 @@ pub fn spawn_agent_turn(state: &mut AppStateRest, text: String) { api_base: api_base.clone(), }; + // Capture for the optional background auto-review before `api_key` / + // `model` / `api_base` move into the client below. The reviewer is + // fire-and-forget and skips itself when the workspace has no diff. + let review_enabled = state.settings.flags.review_enabled; + let review_key = api_key.clone(); + let review_model = model.clone(); + let review_base = api_base.clone(); + let review_ws = workspace_roots.clone(); + let review_events = turn_events.clone(); + let client = std::sync::Arc::new(LlmClient::new(api_key, model, api_base)); let tool_ctx = ToolCtx::builder() @@ -127,6 +137,15 @@ pub fn spawn_agent_turn(state: &mut AppStateRest, text: String) { tokio::spawn(async move { let _ = turn_service.run_turn(params).await; + if review_enabled { + zesdex_infrastructure::subagent::auto::engine::spawn_background_review( + review_ws, + review_events, + review_key, + review_model, + review_base, + ); + } }); } diff --git a/apps/interfaces/ws/src/lib.rs b/apps/interfaces/ws/src/lib.rs index 46a2c27..2857a26 100644 --- a/apps/interfaces/ws/src/lib.rs +++ b/apps/interfaces/ws/src/lib.rs @@ -130,6 +130,17 @@ async fn handle_socket(mut socket: WebSocket, state: Arc) { api_base: None, }; + // Capture for the optional background auto-review + // before `api_key`/`model` move into the client. + // This minimal WS channel has no settings toggle, so + // review fires whenever a prompt runs (consistent + // with the default review_enabled=true). + let review_key = api_key.clone(); + let review_model = model.clone(); + let review_base = None; + let review_ws = workspace_roots.clone(); + let review_events = turn_events.clone(); + let client = std::sync::Arc::new( zesdex_infrastructure::llm::provider::LlmClient::new( api_key, model, None, @@ -159,6 +170,13 @@ async fn handle_socket(mut socket: WebSocket, state: Arc) { use zesdex_application::agent::AgentTurnService; tokio::spawn(async move { let _ = turn_service.run_turn(params).await; + zesdex_infrastructure::subagent::auto::engine::spawn_background_review( + review_ws, + review_events, + review_key, + review_model, + review_base, + ); }); let tx_clone = tx.clone();