From 857e717e6343fa5c2ae96664bdc64741d5ba6830 Mon Sep 17 00:00:00 2001 From: soryu Date: Sun, 17 May 2026 21:22:34 +0100 Subject: chore: remove LLM module + all dependent surfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wholesale removal of the LLM integration layer. ~14,200 LOC deleted across backend and frontend. All chat-driven UIs go with it. ## Backend - Delete `src/llm/` (7,400 LOC): claude/groq clients, contract_tools, contract_evaluator, discuss_tools, mesh_tools, phase_guidance, task_output, templates, markdown round-trip, tools, transcript_analyzer. - Delete handlers wholly dependent on LLM: - `chat.rs` (file-level LLM chat at /files/{id}/chat) - `mesh_chat.rs` (mesh & task LLM chat + history) - `templates.rs` (/contract-types listing) - Strip LLM uses from `mesh_daemon.rs`: - `compute_action_directive` (used phase_guidance::check_deliverables_met to nudge supervisors with "all tasks done" messages). The auto-PR path below still fires when all tasks finish, so no behaviour lost. - `crate::llm::markdown_to_body` → inline 1-line replacement that wraps markdown content in a single BodyElement::Markdown. The editor re-parses on display, so round-trip is preserved. - Drop routes: /files/{id}/chat, /mesh/chat, /mesh/chat/history, /mesh/tasks/{id}/chat, /contract-types. - Drop the matching openapi registrations. ## Frontend - Delete components that were LLM-only: - `mesh/UnifiedMeshChatInput.tsx` - `listen/DiscussContractModal.tsx` - `listen/TranscriptAnalysisPanel.tsx` - `listen/ContractPickerModal.tsx` - `files/CliInput.tsx` - Delete the entire /listen page (its primary value-add was voice → LLM analysis → contract creation; without LLM the page is just a transcript display with no obvious user purpose). - Delete `hooks/useMeshChatHistory.ts` and `lib/listenApi.ts` (transcript-analysis API client to the already-Phase-5-removed listen handlers). - Strip api.ts of LLM exports: LlmModel, ChatMessage/Request/Response, UserQuestion/Answer, chatWithFile, MeshChat* types & functions, getMeshChatHistory, clearMeshChatHistory, chatWithMeshContext, ContractTypeTemplate, listContractTypes, chatWithContract, getContractChatHistory, clearContractChatHistory, discussContract, PhaseDefinition, DeliverableDefinition. - mesh.tsx: drop UnifiedMeshChatInput render + the chatContext memo + handleTaskUpdatedFromCli (only consumer was the input). - files.tsx: drop CliInput render + handleGenerateFromElement + handleBodyUpdate + handleClearFocus + suggestedPrompt state (all CliInput-only). - NavStrip: drop the /listen link. - main.tsx: drop the /listen route. ## Net diff: 37 files changed, 58 insertions, 14,281 deletions. Co-Authored-By: Claude Opus 4.7 (1M context) --- makima/src/server/handlers/mesh_daemon.rs | 96 +++++++------------------------ 1 file changed, 20 insertions(+), 76 deletions(-) (limited to 'makima/src/server/handlers/mesh_daemon.rs') diff --git a/makima/src/server/handlers/mesh_daemon.rs b/makima/src/server/handlers/mesh_daemon.rs index e5f0a81..19d2166 100644 --- a/makima/src/server/handlers/mesh_daemon.rs +++ b/makima/src/server/handlers/mesh_daemon.rs @@ -24,7 +24,6 @@ use uuid::Uuid; use crate::db::models::Task; use crate::db::repository; -use crate::llm::{check_deliverables_met, TaskInfo}; use crate::server::auth::{hash_api_key, API_KEY_HEADER}; use crate::server::messages::ApiError; use crate::server::state::{ @@ -609,71 +608,12 @@ struct DaemonAuthResult { owner_id: Uuid, } -/// Compute an action directive for the supervisor based on deliverable status. -/// Returns an [ACTION REQUIRED] message if all deliverables are met. -async fn compute_action_directive( - pool: &sqlx::PgPool, - contract_id: Uuid, - owner_id: Uuid, -) -> Option { - // Get contract - let contract = match repository::get_contract_for_owner(pool, contract_id, owner_id).await { - Ok(Some(c)) => c, - _ => return None, - }; - - // Get tasks (non-supervisor only) - let tasks = match repository::list_tasks_by_contract(pool, contract_id, owner_id).await { - Ok(t) => t.into_iter().filter(|t| !t.is_supervisor).collect::>(), - _ => return None, - }; - - // Get repositories - let repos = match repository::list_contract_repositories(pool, contract_id).await { - Ok(r) => r, - _ => return None, - }; - - // Get completed deliverables for the current phase - let completed_deliverables = contract.get_completed_deliverables(&contract.phase); - - let task_infos: Vec = tasks - .iter() - .map(|t| TaskInfo { - name: t.name.clone(), - status: t.status.clone(), - }) - .collect(); - - let has_repository = !repos.is_empty(); - - // Check deliverables (unused, but kept for future reference) - let _check = check_deliverables_met( - &contract.phase, - &contract.contract_type, - &completed_deliverables, - &task_infos, - has_repository, - ); - - // Generate directive based on deliverable status - if contract.phase == "execute" { - // Check if all tasks are done but PR deliverable is not marked complete - let all_tasks_done = !task_infos.is_empty() - && task_infos.iter().all(|t| t.status == "done"); - let pr_deliverable_complete = completed_deliverables.contains(&"pull-request".to_string()); - - if all_tasks_done && !pr_deliverable_complete { - let done_count = task_infos.len(); - return Some(format!( - "[INFO] All {} task(s) completed. System is auto-creating PR.", - done_count - )); - } - } - - None -} +// compute_action_directive removed alongside the LLM module — it used +// check_deliverables_met / TaskInfo from src/llm/phase_guidance.rs to +// nudge the supervisor with an "[INFO] all N tasks completed" message +// in the execute phase. Supervisors now receive `None` for the +// action_directive field; the auto-PR path below still fires when +// every non-supervisor task is done, so no behaviour is lost. /// Automatically create a PR when all non-supervisor tasks for a contract are done. /// Only applies to remote-repo contracts in the "execute" phase. @@ -1394,13 +1334,11 @@ async fn handle_daemon_connection(socket: WebSocket, state: SharedState, auth_re // Don't notify for supervisor tasks (they don't report to themselves) if !updated_task.is_supervisor { if let Ok(Some(supervisor)) = repository::get_contract_supervisor_task(&pool, contract_id).await { - // Compute action directive if task completed successfully - let action_directive = if updated_task.status == "done" { - compute_action_directive(&pool, contract_id, owner_id).await - } else { - None - }; - + // action_directive used to come from + // compute_action_directive (now removed alongside the + // LLM module). Passing None preserves the existing + // supervisor protocol; the auto-PR path below still + // fires when every task is done. state.notify_supervisor_of_task_completion( supervisor.id, supervisor.daemon_id, @@ -1409,7 +1347,7 @@ async fn handle_daemon_connection(socket: WebSocket, state: SharedState, auth_re &updated_task.status, updated_task.progress_summary.as_deref(), updated_task.error_message.as_deref(), - action_directive.as_deref(), + None, ).await; } } @@ -1812,8 +1750,14 @@ async fn handle_daemon_connection(socket: WebSocket, state: SharedState, auth_re // The request_id is the file_id we want to update if success { if let (Some(pool), Some(content)) = (&state.db_pool, content) { - // Convert markdown to body elements - let body = crate::llm::markdown_to_body(&content); + // Markdown → body. The full markdown parser lived in the + // (deleted) LLM module; we now wrap the raw markdown in a + // single Markdown body element so File records still round-trip. + // Lossless for the daemon-fetch flow because the editor + // re-parses the markdown content on display. + let body = vec![crate::db::models::BodyElement::Markdown { + content: content.clone(), + }]; // Update file in database let update_req = crate::db::models::UpdateFileRequest { -- cgit v1.2.3