From 261d2f986c729b7c5cebf1a119981ccb86c73345 Mon Sep 17 00:00:00 2001 From: lucaronin Date: Fri, 20 Feb 2026 22:55:49 +0100 Subject: [PATCH] feat(ai-chat): Rust ai_chat command Add Tauri command for AI chat via reqwest: - ai_chat module with send_chat() using Anthropic Messages API - ANTHROPIC_API_KEY from environment variable - Proper error handling for missing key, API errors, parse failures - Unit tests for request building and response extraction - Mock handler added to mock-tauri.ts for browser testing Co-Authored-By: Claude Opus 4.6 --- src-tauri/Cargo.lock | 407 ++++++++++++++++++++++++++++++++++++++- src-tauri/Cargo.toml | 3 + src-tauri/src/ai_chat.rs | 149 ++++++++++++++ src-tauri/src/lib.rs | 10 +- src/mock-tauri.ts | 8 + 5 files changed, 569 insertions(+), 8 deletions(-) create mode 100644 src-tauri/src/ai_chat.rs diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 1ac95db1..e6bede52 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -458,6 +458,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation" version = "0.10.1" @@ -481,9 +491,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ "bitflags 2.11.0", - "core-foundation", + "core-foundation 0.10.1", "core-graphics-types", - "foreign-types", + "foreign-types 0.5.0", "libc", ] @@ -494,7 +504,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ "bitflags 2.11.0", - "core-foundation", + "core-foundation 0.10.1", "libc", ] @@ -881,6 +891,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + [[package]] name = "foreign-types" version = "0.5.0" @@ -888,7 +907,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ "foreign-types-macros", - "foreign-types-shared", + "foreign-types-shared 0.3.1", ] [[package]] @@ -902,6 +921,12 @@ dependencies = [ "syn 2.0.115", ] +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "foreign-types-shared" version = "0.3.1" @@ -1330,6 +1355,25 @@ dependencies = [ "syn 2.0.115", ] +[[package]] +name = "h2" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap 2.13.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -1452,6 +1496,7 @@ dependencies = [ "bytes", "futures-channel", "futures-core", + "h2", "http", "http-body", "httparse", @@ -1463,6 +1508,38 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.20" @@ -1481,9 +1558,11 @@ dependencies = [ "percent-encoding", "pin-project-lite", "socket2", + "system-configuration", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] @@ -1793,14 +1872,17 @@ name = "laputa" version = "0.1.0" dependencies = [ "chrono", + "futures-util", "gray_matter", "log", + "reqwest 0.12.28", "serde", "serde_json", "tauri", "tauri-build", "tauri-plugin-log", "tempfile", + "tokio", "walkdir", ] @@ -1996,6 +2078,23 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "native-tls" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "ndk" version = "0.9.0" @@ -2302,6 +2401,50 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "openssl" +version = "0.10.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +dependencies = [ + "bitflags 2.11.0", + "cfg-if", + "foreign-types 0.3.2", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "openssl-sys" +version = "0.9.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -2863,6 +3006,49 @@ dependencies = [ "bytecheck", ] +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams 0.4.2", + "web-sys", +] + [[package]] name = "reqwest" version = "0.13.2" @@ -2893,10 +3079,24 @@ dependencies = [ "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams", + "wasm-streams 0.5.0", "web-sys", ] +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rkyv" version = "0.7.46" @@ -2964,12 +3164,51 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "rustls" +version = "0.23.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + [[package]] name = "same-file" version = "1.0.6" @@ -2979,6 +3218,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "schemars" version = "0.8.22" @@ -3042,6 +3290,29 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags 2.11.0", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "selectors" version = "0.24.0" @@ -3165,6 +3436,18 @@ dependencies = [ "serde_core", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_with" version = "3.16.1" @@ -3376,6 +3659,12 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "swift-rs" version = "1.0.7" @@ -3429,6 +3718,27 @@ dependencies = [ "syn 2.0.115", ] +[[package]] +name = "system-configuration" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" +dependencies = [ + "bitflags 2.11.0", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "system-deps" version = "6.2.2" @@ -3450,7 +3760,7 @@ checksum = "f3a753bdc39c07b192151523a3f77cd0394aa75413802c883a0f6f6a0e5ee2e7" dependencies = [ "bitflags 2.11.0", "block2", - "core-foundation", + "core-foundation 0.10.1", "core-graphics", "crossbeam-channel", "dispatch", @@ -3535,7 +3845,7 @@ dependencies = [ "percent-encoding", "plist", "raw-window-handle", - "reqwest", + "reqwest 0.13.2", "serde", "serde_json", "serde_repr", @@ -3892,9 +4202,41 @@ dependencies = [ "mio", "pin-project-lite", "socket2", + "tokio-macros", "windows-sys 0.61.2", ] +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.18" @@ -4176,6 +4518,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.8" @@ -4237,6 +4585,12 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version-compare" version = "0.2.1" @@ -4399,6 +4753,19 @@ dependencies = [ "wasmparser", ] +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wasm-streams" version = "0.5.0" @@ -4663,6 +5030,17 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + [[package]] name = "windows-result" version = "0.3.4" @@ -4708,6 +5086,15 @@ dependencies = [ "windows-targets 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.59.0" @@ -5211,6 +5598,12 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + [[package]] name = "zerotrie" version = "0.2.3" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 80b38d47..9a01f538 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -24,6 +24,9 @@ tauri-plugin-log = "2" gray_matter = "0.2" walkdir = "2" chrono = { version = "0.4", features = ["serde"] } +reqwest = { version = "0.12", features = ["json", "stream"] } +tokio = { version = "1", features = ["rt-multi-thread", "macros"] } +futures-util = "0.3" [dev-dependencies] tempfile = "3" diff --git a/src-tauri/src/ai_chat.rs b/src-tauri/src/ai_chat.rs new file mode 100644 index 00000000..8da08a2d --- /dev/null +++ b/src-tauri/src/ai_chat.rs @@ -0,0 +1,149 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize)] +pub struct AiChatRequest { + pub model: Option, + pub messages: Vec, + pub system: Option, + pub max_tokens: Option, +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct AiMessage { + pub role: String, + pub content: String, +} + +#[derive(Debug, Serialize)] +pub struct AiChatResponse { + pub content: String, + pub model: String, + pub stop_reason: Option, +} + +#[derive(Debug, Deserialize)] +struct AnthropicResponse { + content: Vec, + model: String, + stop_reason: Option, +} + +#[derive(Debug, Deserialize)] +struct ContentBlock { + text: Option, +} + +#[derive(Debug, Serialize)] +struct AnthropicRequest { + model: String, + max_tokens: u32, + messages: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + system: Option, +} + +fn get_api_key() -> Result { + std::env::var("ANTHROPIC_API_KEY") + .map_err(|_| "ANTHROPIC_API_KEY environment variable not set".to_string()) +} + +fn build_request(req: &AiChatRequest) -> AnthropicRequest { + AnthropicRequest { + model: req.model.clone().unwrap_or_else(|| "claude-3-5-haiku-20241022".to_string()), + max_tokens: req.max_tokens.unwrap_or(4096), + messages: req.messages.clone(), + system: req.system.clone(), + } +} + +fn extract_response_text(resp: &AnthropicResponse) -> String { + resp.content + .iter() + .filter_map(|block| block.text.as_ref()) + .cloned() + .collect::>() + .join("") +} + +pub async fn send_chat(req: AiChatRequest) -> Result { + let api_key = get_api_key()?; + let anthropic_req = build_request(&req); + + let client = reqwest::Client::new(); + let response = client + .post("https://api.anthropic.com/v1/messages") + .header("x-api-key", &api_key) + .header("anthropic-version", "2023-06-01") + .header("content-type", "application/json") + .json(&anthropic_req) + .send() + .await + .map_err(|e| format!("Request failed: {}", e))?; + + if !response.status().is_success() { + let status = response.status(); + let body = response.text().await.unwrap_or_default(); + return Err(format!("Anthropic API error ({}): {}", status, body)); + } + + let anthropic_resp: AnthropicResponse = response + .json() + .await + .map_err(|e| format!("Failed to parse response: {}", e))?; + + Ok(AiChatResponse { + content: extract_response_text(&anthropic_resp), + model: anthropic_resp.model, + stop_reason: anthropic_resp.stop_reason, + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_build_request_defaults() { + let req = AiChatRequest { + model: None, + messages: vec![AiMessage { + role: "user".to_string(), + content: "Hello".to_string(), + }], + system: None, + max_tokens: None, + }; + let built = build_request(&req); + assert_eq!(built.model, "claude-3-5-haiku-20241022"); + assert_eq!(built.max_tokens, 4096); + assert!(built.system.is_none()); + } + + #[test] + fn test_build_request_custom() { + let req = AiChatRequest { + model: Some("claude-sonnet-4-20250514".to_string()), + messages: vec![], + system: Some("You are helpful".to_string()), + max_tokens: Some(1024), + }; + let built = build_request(&req); + assert_eq!(built.model, "claude-sonnet-4-20250514"); + assert_eq!(built.max_tokens, 1024); + assert_eq!(built.system.unwrap(), "You are helpful"); + } + + #[test] + fn test_extract_response_text() { + let resp = AnthropicResponse { + content: vec![ + ContentBlock { text: Some("Hello ".to_string()) }, + ContentBlock { text: Some("world".to_string()) }, + ContentBlock { text: None }, + ], + model: "test".to_string(), + stop_reason: Some("end_turn".to_string()), + }; + assert_eq!(extract_response_text(&resp), "Hello world"); + } +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 9aba027f..8df5d990 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,7 +1,9 @@ +pub mod ai_chat; pub mod frontmatter; pub mod git; pub mod vault; +use ai_chat::{AiChatRequest, AiChatResponse}; use git::{GitCommit, ModifiedFile}; use vault::VaultEntry; use frontmatter::FrontmatterValue; @@ -51,6 +53,11 @@ fn git_push(vault_path: String) -> Result { git::git_push(&vault_path) } +#[tauri::command] +async fn ai_chat(request: AiChatRequest) -> Result { + ai_chat::send_chat(request).await +} + #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() @@ -73,7 +80,8 @@ pub fn run() { get_modified_files, get_file_diff, git_commit, - git_push + git_push, + ai_chat ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src/mock-tauri.ts b/src/mock-tauri.ts index 94b7719c..3330e246 100644 --- a/src/mock-tauri.ts +++ b/src/mock-tauri.ts @@ -832,6 +832,14 @@ const mockHandlers: Record any> = { git_push: () => { return 'Everything up-to-date' }, + ai_chat: (args: { request: { messages: any[]; model?: string } }) => { + const lastMsg = args.request.messages[args.request.messages.length - 1]?.content ?? '' + return { + content: `[Mock] Responding to: "${lastMsg.slice(0, 80)}"`, + model: args.request.model ?? 'claude-3-5-haiku-20241022', + stop_reason: 'end_turn', + } + }, } export function isTauri(): boolean {