summaryrefslogtreecommitdiff
path: root/makima/src/llm/claude.rs
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-05-17 21:22:34 +0100
committersoryu <soryu@soryu.co>2026-05-17 21:22:34 +0100
commit857e717e6343fa5c2ae96664bdc64741d5ba6830 (patch)
tree0f3898d9e2e2a3c312358dbf70c44f4ab1cf3648 /makima/src/llm/claude.rs
parentce29ae801bcc5a0ba76d5a8d1565242ab267a47d (diff)
downloadsoryu-857e717e6343fa5c2ae96664bdc64741d5ba6830.tar.gz
soryu-857e717e6343fa5c2ae96664bdc64741d5ba6830.zip
chore: remove LLM module + all dependent surfacesremove-llm
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) <noreply@anthropic.com>
Diffstat (limited to 'makima/src/llm/claude.rs')
-rw-r--r--makima/src/llm/claude.rs304
1 files changed, 0 insertions, 304 deletions
diff --git a/makima/src/llm/claude.rs b/makima/src/llm/claude.rs
deleted file mode 100644
index f475acd..0000000
--- a/makima/src/llm/claude.rs
+++ /dev/null
@@ -1,304 +0,0 @@
-//! Claude API client for LLM tool calling.
-
-use serde::{Deserialize, Serialize};
-use thiserror::Error;
-
-use super::tools::{Tool, ToolCall};
-
-const CLAUDE_API_URL: &str = "https://api.anthropic.com/v1/messages";
-const ANTHROPIC_VERSION: &str = "2023-06-01";
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum ClaudeModel {
- Opus,
- Sonnet,
-}
-
-impl ClaudeModel {
- pub fn model_id(&self) -> &'static str {
- match self {
- ClaudeModel::Opus => "claude-opus-4-5-20251101",
- ClaudeModel::Sonnet => "claude-sonnet-4-5-20250929",
- }
- }
-}
-
-impl Default for ClaudeModel {
- fn default() -> Self {
- ClaudeModel::Opus
- }
-}
-
-#[derive(Debug, Error)]
-pub enum ClaudeError {
- #[error("HTTP request failed: {0}")]
- Request(#[from] reqwest::Error),
- #[error("API error: {0}")]
- Api(String),
- #[error("Missing API key")]
- MissingApiKey,
-}
-
-#[derive(Debug, Clone)]
-pub struct ClaudeClient {
- api_key: String,
- client: reqwest::Client,
- model: ClaudeModel,
-}
-
-// Request types
-#[derive(Debug, Serialize)]
-struct ClaudeRequest {
- model: String,
- max_tokens: u32,
- messages: Vec<Message>,
- #[serde(skip_serializing_if = "Option::is_none")]
- tools: Option<Vec<ToolDefinition>>,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct Message {
- pub role: String,
- pub content: MessageContent,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-#[serde(untagged)]
-pub enum MessageContent {
- Text(String),
- Blocks(Vec<ContentBlock>),
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-#[serde(tag = "type")]
-pub enum ContentBlock {
- #[serde(rename = "text")]
- Text { text: String },
- #[serde(rename = "tool_use")]
- ToolUse {
- id: String,
- name: String,
- input: serde_json::Value,
- },
- #[serde(rename = "tool_result")]
- ToolResult {
- tool_use_id: String,
- content: String,
- },
-}
-
-#[derive(Debug, Serialize)]
-struct ToolDefinition {
- name: String,
- description: String,
- input_schema: serde_json::Value,
-}
-
-// Response types
-#[derive(Debug, Deserialize)]
-struct ClaudeResponse {
- content: Vec<ResponseContentBlock>,
- stop_reason: Option<String>,
-}
-
-#[derive(Debug, Clone, Deserialize)]
-#[serde(tag = "type")]
-pub enum ResponseContentBlock {
- #[serde(rename = "text")]
- Text { text: String },
- #[serde(rename = "tool_use")]
- ToolUse {
- id: String,
- name: String,
- input: serde_json::Value,
- },
-}
-
-#[derive(Debug)]
-pub struct ChatResult {
- pub content: Option<String>,
- pub tool_calls: Vec<ToolCall>,
- /// Raw tool use blocks for including in subsequent messages
- pub raw_tool_uses: Vec<ResponseContentBlock>,
- pub stop_reason: String,
-}
-
-impl ClaudeClient {
- pub fn new(api_key: String, model: ClaudeModel) -> Self {
- Self {
- api_key,
- client: reqwest::Client::new(),
- model,
- }
- }
-
- pub fn from_env(model: ClaudeModel) -> Result<Self, ClaudeError> {
- let api_key = std::env::var("ANTHROPIC_API_KEY").map_err(|_| ClaudeError::MissingApiKey)?;
- Ok(Self::new(api_key, model))
- }
-
- pub async fn chat_with_tools(
- &self,
- messages: Vec<Message>,
- tools: &[Tool],
- ) -> Result<ChatResult, ClaudeError> {
- let tool_definitions: Vec<ToolDefinition> = tools
- .iter()
- .map(|t| ToolDefinition {
- name: t.name.clone(),
- description: t.description.clone(),
- input_schema: t.parameters.clone(),
- })
- .collect();
-
- let request = ClaudeRequest {
- model: self.model.model_id().to_string(),
- max_tokens: 4096,
- messages,
- tools: Some(tool_definitions),
- };
-
- let response = self
- .client
- .post(CLAUDE_API_URL)
- .header("x-api-key", &self.api_key)
- .header("anthropic-version", ANTHROPIC_VERSION)
- .header("Content-Type", "application/json")
- .json(&request)
- .send()
- .await?;
-
- if !response.status().is_success() {
- let error_text = response.text().await.unwrap_or_default();
- return Err(ClaudeError::Api(error_text));
- }
-
- let claude_response: ClaudeResponse = response.json().await?;
-
- let stop_reason = claude_response.stop_reason.unwrap_or_else(|| "end_turn".to_string());
-
- // Extract text content and tool uses from content blocks
- let mut text_parts: Vec<String> = Vec::new();
- let mut raw_tool_uses: Vec<ResponseContentBlock> = Vec::new();
-
- for block in &claude_response.content {
- match block {
- ResponseContentBlock::Text { text } => {
- if !text.is_empty() {
- text_parts.push(text.clone());
- }
- }
- ResponseContentBlock::ToolUse { .. } => {
- raw_tool_uses.push(block.clone());
- }
- }
- }
-
- let content = if text_parts.is_empty() {
- None
- } else {
- Some(text_parts.join("\n"))
- };
-
- // Convert tool uses to ToolCalls
- let tool_calls: Vec<ToolCall> = raw_tool_uses
- .iter()
- .filter_map(|block| {
- if let ResponseContentBlock::ToolUse { id, name, input } = block {
- Some(ToolCall {
- id: id.clone(),
- name: name.clone(),
- arguments: input.clone(),
- })
- } else {
- None
- }
- })
- .collect();
-
- Ok(ChatResult {
- content,
- tool_calls,
- raw_tool_uses,
- stop_reason,
- })
- }
-}
-
-/// Helper to convert Groq-style messages to Claude messages
-pub fn groq_messages_to_claude(messages: &[super::groq::Message]) -> Vec<Message> {
- let mut claude_messages: Vec<Message> = Vec::new();
-
- for msg in messages {
- match msg.role.as_str() {
- "system" => {
- // Claude handles system prompts as first user message
- if let Some(ref content) = msg.content {
- claude_messages.push(Message {
- role: "user".to_string(),
- content: MessageContent::Text(format!("[System Instructions]: {}", content)),
- });
- // Add assistant acknowledgment to maintain conversation structure
- claude_messages.push(Message {
- role: "assistant".to_string(),
- content: MessageContent::Text("Understood. I'll follow these instructions.".to_string()),
- });
- }
- }
- "user" => {
- if let Some(ref content) = msg.content {
- claude_messages.push(Message {
- role: "user".to_string(),
- content: MessageContent::Text(content.clone()),
- });
- }
- }
- "assistant" => {
- let mut blocks: Vec<ContentBlock> = Vec::new();
-
- // Add text content if present
- if let Some(ref content) = msg.content {
- if !content.is_empty() {
- blocks.push(ContentBlock::Text { text: content.clone() });
- }
- }
-
- // Add tool uses if present
- if let Some(ref tool_calls) = msg.tool_calls {
- for tc in tool_calls {
- let input: serde_json::Value =
- serde_json::from_str(&tc.function.arguments).unwrap_or_default();
- blocks.push(ContentBlock::ToolUse {
- id: tc.id.clone(),
- name: tc.function.name.clone(),
- input,
- });
- }
- }
-
- if !blocks.is_empty() {
- claude_messages.push(Message {
- role: "assistant".to_string(),
- content: MessageContent::Blocks(blocks),
- });
- }
- }
- "tool" => {
- // Tool results in Claude go in a user message with tool_result blocks
- if let Some(ref content) = msg.content {
- let tool_use_id = msg.tool_call_id.clone().unwrap_or_default();
- claude_messages.push(Message {
- role: "user".to_string(),
- content: MessageContent::Blocks(vec![ContentBlock::ToolResult {
- tool_use_id,
- content: content.clone(),
- }]),
- });
- }
- }
- _ => {}
- }
- }
-
- claude_messages
-}