update formatting

restructure project
add cancellation token to cancel mcp server collection from serving
This commit is contained in:
2026-05-24 21:12:15 +02:00
parent 8085b43b1c
commit de0e665f57
15 changed files with 53 additions and 29 deletions
+1 -1
View File
@@ -3,5 +3,5 @@
assist.toml assist.toml
server.toml server.toml
temporary_audio temporary_audio
src/human_interface/.AUTH_HEADER cli/src/human_interface/.AUTH_HEADER
.idea .idea
+2 -1
View File
@@ -1921,7 +1921,7 @@ dependencies = [
] ]
[[package]] [[package]]
name = "own_assist" name = "own_assist_cli"
version = "0.3.0" version = "0.3.0"
dependencies = [ dependencies = [
"base64", "base64",
@@ -1940,6 +1940,7 @@ dependencies = [
"serde", "serde",
"thiserror 2.0.18", "thiserror 2.0.18",
"tokio", "tokio",
"tokio-util",
"url", "url",
] ]
+6 -5
View File
@@ -1,5 +1,5 @@
[package] [package]
name = "own_assist" name = "own_assist_cli"
version = "0.3.0" version = "0.3.0"
edition = "2024" edition = "2024"
@@ -10,9 +10,9 @@ rmcp = { version = "1.3.0", features = ["client"] }
log = { version = "0.4.29" } log = { version = "0.4.29" }
serde = { version = "1.0.228", features = ["derive"] } serde = { version = "1.0.228", features = ["derive"] }
url = "2.5.8" url = "2.5.8"
own_mcp = { path = "own_mcp" } own_mcp = { path = "../own_mcp" }
own_assist_common = { path = "common" } own_assist_common = { path = "../common" }
mcp_server_collection = { path = "mcp_server_collection", optional = true} mcp_server_collection = { path = "../mcp_server_collection", optional = true}
thiserror = "2.0.18" thiserror = "2.0.18"
dialoguer = "0.12.0" dialoguer = "0.12.0"
indicatif = "0.18.4" indicatif = "0.18.4"
@@ -21,7 +21,8 @@ clap = { version = "4.6.0", features = ["derive"] }
base64 = "0.22.1" base64 = "0.22.1"
cpal = "0.17.3" cpal = "0.17.3"
rodio = "0.22.2" rodio = "0.22.2"
tokio-util = { version = "0.7.18", optional = true }
[features] [features]
default = ["built-in-mcp-collection"] default = ["built-in-mcp-collection"]
built-in-mcp-collection = ["dep:mcp_server_collection"] built-in-mcp-collection = ["dep:mcp_server_collection", "dep:tokio-util"]
View File
+2 -1
View File
@@ -14,6 +14,7 @@ use own_assist_common::config_loader::ConfigLoadingError;
use own_assist_common::{exit_msg, init_tracing_subscriber}; use own_assist_common::{exit_msg, init_tracing_subscriber};
use own_mcp::AgentChat; use own_mcp::AgentChat;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use tokio_util::sync::CancellationToken;
/// partial mcp client with cli and voice interaction /// partial mcp client with cli and voice interaction
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@@ -67,7 +68,7 @@ async fn chat_loop(mut human_interface: impl HumanInterface, mut agent_chat: Age
} }
#[cfg(feature = "built-in-mcp-collection")] #[cfg(feature = "built-in-mcp-collection")]
fn launch_mcp_server() -> Result<JoinHandle<()>, ConfigLoadingError> { fn launch_mcp_server() -> Result<JoinHandle<CancellationToken>, ConfigLoadingError> {
let config = mcp_server_collection::config::Config::from_file()?; let config = mcp_server_collection::config::Config::from_file()?;
let handle = tokio::task::spawn(mcp_server_collection::serve(config)); let handle = tokio::task::spawn(mcp_server_collection::serve(config));
View File
+24 -12
View File
@@ -1,12 +1,12 @@
use tracing::Level;
use chrono::{Duration, Local};
use crate::caldav::client::{ use crate::caldav::client::{
AuthorizedCaldavClient, find_calendars, get_caldav_client, get_components, upload_components, AuthorizedCaldavClient, find_calendars, get_caldav_client, get_components, upload_components,
}; };
use crate::caldav::event::McpEvent;
use crate::caldav::todo::McpTodo; use crate::caldav::todo::McpTodo;
use crate::server_handler::{ use crate::server_handler::{
McpServerHandler, McpServerHandlerError, get_additional_property, get_property_as_string, McpServerHandler, McpServerHandlerError, get_additional_property, get_property_as_string,
}; };
use chrono::{Duration, Local};
use http::Uri; use http::Uri;
use icalendar::{Event, EventLike, Todo}; use icalendar::{Event, EventLike, Todo};
use libdav::dav::FoundCollection; use libdav::dav::FoundCollection;
@@ -19,7 +19,7 @@ use serde::Deserialize;
use std::str::FromStr; use std::str::FromStr;
use toml::Value; use toml::Value;
use toml::map::Map; use toml::map::Map;
use crate::caldav::event::McpEvent; use tracing::Level;
mod client; mod client;
mod datetime_conversion; mod datetime_conversion;
@@ -193,7 +193,10 @@ impl CalDavHandler {
} }
#[tool(description = "gets events of next 7 days")] #[tool(description = "gets events of next 7 days")]
async fn get_upcoming_events(&self, parameters: Parameters<GetCalendarComponentParameters>) -> Result<CallToolResult, ErrorData> { async fn get_upcoming_events(
&self,
parameters: Parameters<GetCalendarComponentParameters>,
) -> Result<CallToolResult, ErrorData> {
const DAYS_DELTA: Duration = Duration::days(7); const DAYS_DELTA: Duration = Duration::days(7);
const RECURRENCE_LIMIT: u16 = 10; const RECURRENCE_LIMIT: u16 = 10;
@@ -212,28 +215,37 @@ impl CalDavHandler {
match recurrence { match recurrence {
Ok(recurrence) => { Ok(recurrence) => {
let recurrence_result = recurrence.after(lower_bound).before(upper_bound).all(RECURRENCE_LIMIT); let recurrence_result = recurrence
.after(lower_bound)
.before(upper_bound)
.all(RECURRENCE_LIMIT);
for date in recurrence_result.dates { for date in recurrence_result.dates {
let mut event_instance = event.clone(); let mut event_instance = event.clone();
event_instance.start = Some(date.with_timezone(&Local{})); event_instance.start = Some(date.with_timezone(&Local {}));
if let Some(start) = event.start && let Some(end) = event.end { if let Some(start) = event.start
let event_duration = end-start; && let Some(end) = event.end
event_instance.end = Some(event_instance.start.unwrap() + event_duration); {
let event_duration = end - start;
event_instance.end =
Some(event_instance.start.unwrap() + event_duration);
} }
events.push(event_instance); events.push(event_instance);
} }
}, }
Err(error) => { Err(error) => {
tracing::event!(Level::INFO, "recurrence error occured. Event '{event:?}' is ignored: {error}"); tracing::event!(
Level::INFO,
"recurrence error occured. Event '{event:?}' is ignored: {error}"
);
} }
} }
} }
} }
events.sort_by_key(|event|event.start); events.sort_by_key(|event| event.start);
Ok(CallToolResult::structured(serde_json::json!(events))) Ok(CallToolResult::structured(serde_json::json!(events)))
} }
+11 -4
View File
@@ -16,6 +16,8 @@ use axum::Router;
use axum::response::Json; use axum::response::Json;
use own_assist_common::exit_msg; use own_assist_common::exit_msg;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tokio::select;
use tokio_util::sync::CancellationToken;
use tracing::{Level, event}; use tracing::{Level, event};
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
@@ -58,7 +60,7 @@ fn bind_address_format(url: url::Url) -> String {
) )
} }
pub async fn serve(config: Config) { pub async fn serve(config: Config) -> CancellationToken {
let routes = Json( let routes = Json(
config config
.servers .servers
@@ -84,12 +86,17 @@ pub async fn serve(config: Config) {
.inspect_err(exit_msg!("Error bind tcp listener: {e:#?}")) .inspect_err(exit_msg!("Error bind tcp listener: {e:#?}"))
.unwrap(); .unwrap();
let ct = tokio_util::sync::CancellationToken::new(); let cancellation_token = CancellationToken::new();
let cloned_cancellation_token = cancellation_token.clone();
let _ = axum::serve(tcp_listener, router) let _ = axum::serve(tcp_listener, router)
.with_graceful_shutdown(async move { .with_graceful_shutdown(async move {
tokio::signal::ctrl_c().await.unwrap(); select! {
ct.cancel(); _ = cloned_cancellation_token.cancelled() => (),
_ = tokio::signal::ctrl_c() => (),
}
}) })
.await; .await;
cancellation_token
} }
+1 -1
View File
@@ -1,7 +1,7 @@
use mcp_server_collection::config::Config; use mcp_server_collection::config::Config;
use mcp_server_collection::serve; use mcp_server_collection::serve;
use own_assist_common::{exit_msg, init_tracing_subscriber}; use own_assist_common::{exit_msg, init_tracing_subscriber};
use tokio::main; use tokio::{main};
#[main] #[main]
async fn main() { async fn main() {
+4 -2
View File
@@ -3,12 +3,12 @@ use ollama_rs::Ollama;
use ollama_rs::error::OllamaError; use ollama_rs::error::OllamaError;
use ollama_rs::generation::chat::ChatMessage; use ollama_rs::generation::chat::ChatMessage;
use ollama_rs::generation::chat::request::ChatMessageRequest; use ollama_rs::generation::chat::request::ChatMessageRequest;
use ollama_rs::generation::completion::request::GenerationRequest;
use ollama_rs::generation::tools::ToolInfo; use ollama_rs::generation::tools::ToolInfo;
use rmcp::ServiceError; use rmcp::ServiceError;
use rmcp::model::{CallToolRequestParams, CallToolResult}; use rmcp::model::{CallToolRequestParams, CallToolResult};
use serde::Deserialize; use serde::Deserialize;
use std::collections::HashMap; use std::collections::HashMap;
use ollama_rs::generation::completion::request::GenerationRequest;
use thiserror::Error; use thiserror::Error;
#[derive(Debug, Copy, Clone, Default, Deserialize, PartialEq)] #[derive(Debug, Copy, Clone, Default, Deserialize, PartialEq)]
@@ -118,7 +118,9 @@ impl AgentChat {
let ollama_client_clone = ollama_client.clone(); let ollama_client_clone = ollama_client.clone();
let model_clone = model.clone(); let model_clone = model.clone();
tokio::spawn(async move { tokio::spawn(async move {
let _ = ollama_client_clone.generate(GenerationRequest::new(model_clone, "")).await; let _ = ollama_client_clone
.generate(GenerationRequest::new(model_clone, ""))
.await;
}); });
Ok(Self { Ok(Self {