refactoring

different default system prompts for cli and audio
This commit is contained in:
2026-05-04 21:18:09 +02:00
parent 3d8975cfc1
commit 51b1123cf9
16 changed files with 80 additions and 45 deletions
Generated
+3 -2
View File
@@ -1665,7 +1665,7 @@ dependencies = [
[[package]] [[package]]
name = "own_assist" name = "own_assist"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"base64", "base64",
"clap", "clap",
@@ -1688,8 +1688,9 @@ dependencies = [
[[package]] [[package]]
name = "own_assist_common" name = "own_assist_common"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"log",
"serde", "serde",
"thiserror 2.0.18", "thiserror 2.0.18",
"toml", "toml",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "own_assist" name = "own_assist"
version = "0.1.0" version = "0.2.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
+1 -1
View File
@@ -20,7 +20,7 @@ name="..." # optional, otherwise provided server name or random server name is c
url="..." url="..."
authorization="..." #optional authorization="..." #optional
[audio-server] [audio.server]
url="..." url="..."
authoritation="..." # optional authoritation="..." # optional
``` ```
+8 -1
View File
@@ -24,10 +24,17 @@ dependencies = [
"hashbrown", "hashbrown",
] ]
[[package]]
name = "log"
version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]] [[package]]
name = "own_assist_common" name = "own_assist_common"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"log",
"serde", "serde",
"thiserror", "thiserror",
"toml", "toml",
+3 -2
View File
@@ -1,9 +1,10 @@
[package] [package]
name = "own_assist_common" name = "own_assist_common"
version = "0.1.0" version = "0.2.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
thiserror = "2.0.18" thiserror = "2.0.18"
toml = "1.1.2" toml = "1.1.2"
serde = "1.0.228" serde = "1.0.228"
log = "0.4.29"
+14
View File
@@ -0,0 +1,14 @@
use std::fmt::Display;
pub fn exit_with_error_message(error: impl Display, message: impl Display) {
log::error!("{message}: {error}");
eprintln!("{}", message); // makes sure that message is printed even if logging is deactivated
std::process::exit(1);
}
#[macro_export]
macro_rules! exit_msg {
($message:expr) => {
|e| own_assist_common::exit_with_error_message(e, $message)
};
}
+3
View File
@@ -1,2 +1,5 @@
pub mod config_loader; pub mod config_loader;
mod exit_error;
pub use config_loader::config_from_file; pub use config_loader::config_from_file;
pub use exit_error::exit_with_error_message;
+4 -2
View File
@@ -977,7 +977,7 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
[[package]] [[package]]
name = "mcp_server_collection" name = "mcp_server_collection"
version = "0.2.0" version = "0.2.1"
dependencies = [ dependencies = [
"axum", "axum",
"chrono", "chrono",
@@ -994,6 +994,7 @@ dependencies = [
"tokio-util", "tokio-util",
"toml", "toml",
"tower-http", "tower-http",
"tracing",
"tracing-subscriber", "tracing-subscriber",
"url", "url",
"uuid", "uuid",
@@ -1108,8 +1109,9 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
[[package]] [[package]]
name = "own_assist_common" name = "own_assist_common"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"log",
"serde", "serde",
"thiserror", "thiserror",
"toml", "toml",
+2 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "mcp_server_collection" name = "mcp_server_collection"
version = "0.2.0" version = "0.2.1"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
@@ -11,6 +11,7 @@ serde = { version = "1.0.228", features = ["derive"] }
tokio = { version = "1.51.0", features = ["full"] } tokio = { version = "1.51.0", features = ["full"] }
own_assist_common = { path = "../common" } own_assist_common = { path = "../common" }
tokio-util = "0.7.18" tokio-util = "0.7.18"
tracing = "0.1.44"
tracing-subscriber = { version = "0.3.23", features = ["env-filter"] } tracing-subscriber = { version = "0.3.23", features = ["env-filter"] }
url = { version = "2.5.8", features = ["serde"] } url = { version = "2.5.8", features = ["serde"] }
uuid = { version = "1.23.0", features = ["v4"], optional = true } uuid = { version = "1.23.0", features = ["v4"], optional = true }
+3 -1
View File
@@ -11,6 +11,8 @@ use rmcp::ErrorData;
use rmcp::model::ErrorCode; use rmcp::model::ErrorCode;
use thiserror::Error; use thiserror::Error;
use tower_http::auth::AddAuthorization; use tower_http::auth::AddAuthorization;
use tracing::event;
use tracing::Level;
use uuid::Uuid; use uuid::Uuid;
pub(crate) type AuthorizedCaldavClient = pub(crate) type AuthorizedCaldavClient =
@@ -111,7 +113,7 @@ pub(crate) async fn upload_components(
calendar: &FoundCollection, calendar: &FoundCollection,
components: Vec<impl Into<CalendarComponent>>, components: Vec<impl Into<CalendarComponent>>,
) -> Result<PutResourceResponse, CalendarError> { ) -> Result<PutResourceResponse, CalendarError> {
println!("uploading components to {}", calendar.href); event!(Level::INFO, "uploading components to {}", calendar.href);
let mut upload_calendar = Calendar::new(); let mut upload_calendar = Calendar::new();
for todo in components { for todo in components {
+11 -1
View File
@@ -52,7 +52,17 @@ impl DateTimeHandler {
annotations(read_only_hint = true) annotations(read_only_hint = true)
)] )]
fn get_weekday() -> String { fn get_weekday() -> String {
Local::now().weekday().to_string() use chrono::Weekday::*;
match Local::now().weekday() {
Mon => "Monday",
Tue => "Tuesday",
Wed => "Wednesday",
Thu => "Thursday",
Fri => "Friday",
Sat => "Saturday",
Sun => "Sunday",
}.to_string()
} }
} }
+11 -13
View File
@@ -6,6 +6,7 @@ pub mod datetime;
pub mod caldav; pub mod caldav;
mod server_handler; mod server_handler;
#[cfg(feature = "caldav")]
use crate::caldav::CalDavHandler; use crate::caldav::CalDavHandler;
use crate::config::{Config, ServerConfig}; use crate::config::{Config, ServerConfig};
#[cfg(feature = "datetime")] #[cfg(feature = "datetime")]
@@ -15,13 +16,17 @@ use axum::Router;
use axum::response::Json; use axum::response::Json;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tokio::main; use tokio::main;
use tracing::{event, Level};
use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt; use tracing_subscriber::util::SubscriberInitExt;
use own_assist_common::exit_msg;
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
#[non_exhaustive] #[non_exhaustive]
pub enum McpServiceType { pub enum McpServiceType {
#[cfg(feature = "datetime")]
DateTime, DateTime,
#[cfg(feature = "caldav")]
CalDav, CalDav,
} }
@@ -32,10 +37,12 @@ pub(crate) async fn mcp_router(
for config in server_configs { for config in server_configs {
router = match config.r#type { router = match config.r#type {
#[cfg(feature = "datetime")]
McpServiceType::DateTime => router.route_service( McpServiceType::DateTime => router.route_service(
config.path.as_str(), config.path.as_str(),
DateTimeHandler::mcp_service(config.additional_properties.clone()).await?, DateTimeHandler::mcp_service(config.additional_properties.clone()).await?,
), ),
#[cfg(feature = "caldav")]
McpServiceType::CalDav => router.route_service( McpServiceType::CalDav => router.route_service(
config.path.as_str(), config.path.as_str(),
CalDavHandler::mcp_service(config.additional_properties.clone()).await?, CalDavHandler::mcp_service(config.additional_properties.clone()).await?,
@@ -65,10 +72,7 @@ async fn main() {
.init(); .init();
let config = Config::from_file() let config = Config::from_file()
.inspect_err(|e| { .inspect_err(exit_msg!("Error loading config: {e}"))
eprintln!("Error loading config: {e}");
std::process::exit(1);
})
.unwrap(); .unwrap();
let routes = Json( let routes = Json(
@@ -82,24 +86,18 @@ async fn main() {
let router = mcp_router(&config.servers) let router = mcp_router(&config.servers)
.await .await
.inspect_err(|e| { .inspect_err(exit_msg!("Error handling server: {e}"))
eprintln!("Error loading config: {e}");
std::process::exit(1);
})
.unwrap() .unwrap()
.route("/", axum::routing::get(|| async { routes })); .route("/", axum::routing::get(|| async { routes }));
let bind_address = config let bind_address = config
.bind_address .bind_address
.unwrap_or(url::Url::parse("http://localhost:8000").unwrap()); .unwrap_or(url::Url::parse("http://localhost:8000").unwrap());
println!("binding address at {bind_address}"); event!(Level::INFO,"binding address at {bind_address}");
let tcp_listener = tokio::net::TcpListener::bind(bind_address_format(bind_address)) let tcp_listener = tokio::net::TcpListener::bind(bind_address_format(bind_address))
.await .await
.inspect_err(|e| { .inspect_err(exit_msg!("Error bind tcp listener: {e:#?}"))
eprintln!("Error bind tcp listener: {e:#?}");
std::process::exit(1);
})
.unwrap(); .unwrap();
let ct = tokio_util::sync::CancellationToken::new(); let ct = tokio_util::sync::CancellationToken::new();
+3 -1
View File
@@ -223,6 +223,8 @@ impl AgentChat {
// serialize structured content if it exists // serialize structured content if it exists
if let Some(structured_content) = result.clone().and_then(|result|result.structured_content) { if let Some(structured_content) = result.clone().and_then(|result|result.structured_content) {
log::debug!("structured content: {structured_content:#?}");
self.message_history.push(ChatMessage::tool(structured_content.to_string())); self.message_history.push(ChatMessage::tool(structured_content.to_string()));
} else { } else {
let contents = match result { let contents = match result {
@@ -234,7 +236,7 @@ impl AgentChat {
None => vec![String::from("Tool Permission Denied by the user")], None => vec![String::from("Tool Permission Denied by the user")],
}; };
log::debug!("contents: {:#?}", contents); log::debug!("contents: {contents:#?}");
self.message_history self.message_history
.push(ChatMessage::tool(contents.join("\n"))); .push(ChatMessage::tool(contents.join("\n")));
+2 -1
View File
@@ -1,6 +1,7 @@
{ {
"translations": { "translations": {
"system_prompt": "Du bist ein Assistent, der per Sprache bedient wird. Du erhälst die Transkription und dein Output wird per Sprache ausgegeben und sollte dementsprechend auch kurz sein und kein Markdown enthalten. Wichtiger als deine Antworten sind deine Aktionen. Nutze bitte die tools, falls du sie brauchst um Informationen zu bekommen (z.B. über das aktuelle Datum oder den aktuellen Wochentag). Du bist in einem Agent Loop und kannst mehrere Tools hintereinander nutzen. Falls der Nutzer das Nutzen eines Tools ablehnt, sag ihm bescheid, dass du es brauchst.", "system_prompt_cli": "Du bist ein Assistent. Wichtiger als deine Antworten sind deine Aktionen. Nutze bitte die tools, falls du sie brauchst um Informationen zu bekommen (z.B. über das aktuelle Datum oder den aktuellen Wochentag). Du bist in einem Agent Loop und kannst mehrere Tools hintereinander nutzen. Falls der Nutzer das Nutzen eines Tools ablehnt, sag ihm bescheid, dass du es brauchst.",
"system_prompt_audio": "Du bist ein Assistent, der per Sprache bedient wird. Du erhälst die Transkription und dein Output wird per Sprache ausgegeben und sollte dementsprechend auch kurz sein und kein Markdown enthalten. Wichtiger als deine Antworten sind deine Aktionen. Nutze bitte die tools, falls du sie brauchst um Informationen zu bekommen (z.B. über das aktuelle Datum oder den aktuellen Wochentag). Du bist in einem Agent Loop und kannst mehrere Tools hintereinander nutzen. Falls der Nutzer das Nutzen eines Tools ablehnt, sag ihm bescheid, dass du es brauchst.",
"you": "Du", "you": "Du",
"assistant": "Assistent", "assistant": "Assistent",
"username": "Nutzername", "username": "Nutzername",
+5 -16
View File
@@ -12,6 +12,7 @@ use clap::Parser;
use cpal::traits::HostTrait; use cpal::traits::HostTrait;
use own_mcp::AgentChat; use own_mcp::AgentChat;
use std::fmt::Display; use std::fmt::Display;
use own_assist_common::exit_msg;
/// partial mcp client with cli and voice interaction /// partial mcp client with cli and voice interaction
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@@ -84,7 +85,7 @@ async fn main() {
let ollama = config.ollama_instance(); let ollama = config.ollama_instance();
let model_name = &config.ollama_config().model.name; let model_name = &config.ollama_config().model.name;
create_model_from_config(&ollama, &config.ollama_config().model) create_model_from_config(&ollama, &config.ollama_config().model, &config.interface)
.await .await
.inspect_err(exit_msg!(format!( .inspect_err(exit_msg!(format!(
"failed creating ollama model `{model_name}`" "failed creating ollama model `{model_name}`"
@@ -123,7 +124,8 @@ async fn main() {
.expect("no default device"), .expect("no default device"),
) )
.await .await
.inspect_err(exit_msg!("failed creating audio client")).unwrap(); .inspect_err(exit_msg!("failed creating audio client"))
.unwrap();
chat_loop(human_interface, agent_chat).await; chat_loop(human_interface, agent_chat).await;
} }
@@ -133,17 +135,4 @@ async fn main() {
}; };
} }
}; };
} }
fn exit_with_error_message(error: impl Display, message: impl Display) {
log::error!("{message}: {error}");
eprintln!("{}", message); // makes sure that message is printed even if logging is deactivated
std::process::exit(1);
}
#[macro_export]
macro_rules! exit_msg {
($message:expr) => {
|e| exit_with_error_message(e, $message)
};
}
+6 -2
View File
@@ -1,4 +1,4 @@
use crate::config::OllamaModelConfig; use crate::config::{HumanInterface, OllamaModelConfig};
use crate::tlt; use crate::tlt;
use crate::translate; use crate::translate;
use ollama_rs::Ollama; use ollama_rs::Ollama;
@@ -9,6 +9,7 @@ use ollama_rs::models::create::{CreateModelRequest, CreateModelStatus};
pub async fn create_model_from_config( pub async fn create_model_from_config(
ollama: &Ollama, ollama: &Ollama,
config: &OllamaModelConfig, config: &OllamaModelConfig,
interface: &HumanInterface
) -> Result<CreateModelStatus, OllamaError> { ) -> Result<CreateModelStatus, OllamaError> {
let model_options = ModelOptions::default() let model_options = ModelOptions::default()
.num_ctx(config.context_size.unwrap_or(2048)) // 2048 is the ollama default. .num_ctx(config.context_size.unwrap_or(2048)) // 2048 is the ollama default.
@@ -17,7 +18,10 @@ pub async fn create_model_from_config(
let system_prompt = config let system_prompt = config
.system_prompt .system_prompt
.clone() .clone()
.unwrap_or(tlt!("system_prompt")); .unwrap_or(match interface {
HumanInterface::Cli => tlt!("system_prompt_cli"),
HumanInterface::Audio => tlt!("system_prompt_audio"),
});
// print message to warn user of long waiting times // print message to warn user of long waiting times
if let Ok(models) = ollama.list_local_models().await if let Ok(models) = ollama.list_local_models().await