use std::fmt;
use std::path::PathBuf;
#[derive(Debug, Clone)]
pub struct MicroResolveConfig {
pub data_dir: Option<PathBuf>,
pub default_threshold: f32,
pub languages: Vec<String>,
pub llm: Option<LlmConfig>,
pub server: Option<ServerConfig>,
}
impl Default for MicroResolveConfig {
fn default() -> Self {
Self {
data_dir: None,
default_threshold: 0.3,
languages: vec!["en".to_string()],
llm: None,
server: None,
}
}
}
#[derive(Debug, Clone)]
pub struct LlmConfig {
pub provider: String,
pub model: String,
pub api_key: String,
}
#[derive(Debug, Clone)]
pub struct ServerConfig {
pub url: String,
pub api_key: Option<String>,
pub subscribe: Vec<String>,
pub tick_interval_secs: u64,
pub log_buffer_max: usize,
}
impl Default for ServerConfig {
fn default() -> Self {
Self {
url: String::new(),
api_key: None,
subscribe: Vec::new(),
tick_interval_secs: 30,
log_buffer_max: 500,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct NamespaceConfig {
pub default_threshold: Option<f32>,
pub languages: Option<Vec<String>>,
pub llm_model: Option<String>,
pub description: String,
}
#[derive(Debug)]
pub enum Error {
IntentNotFound(String),
Io(std::io::Error),
Parse(String),
Persistence(String),
Connect(String),
ConnectMode,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::IntentNotFound(id) => write!(f, "intent not found: {}", id),
Error::Io(e) => write!(f, "I/O error: {}", e),
Error::Parse(s) => write!(f, "parse error: {}", s),
Error::Persistence(s) => write!(f, "persistence error: {}", s),
Error::Connect(s) => write!(f, "connect error: {}", s),
Error::ConnectMode => write!(
f,
"mutation not allowed in connected mode; use the server's HTTP API directly"
),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Io(e) => Some(e),
_ => None,
}
}
}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Error::Io(e)
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct IntentSource {
#[serde(rename = "type")]
pub source_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
}
impl IntentSource {
pub fn new(source_type: impl Into<String>) -> Self {
Self {
source_type: source_type.into(),
label: None,
url: None,
}
}
pub fn with_label(mut self, label: impl Into<String>) -> Self {
self.label = Some(label.into());
self
}
pub fn with_url(mut self, url: impl Into<String>) -> Self {
self.url = Some(url.into());
self
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct IntentTarget {
#[serde(rename = "type")]
pub target_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub model: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub handler: Option<String>,
}
impl IntentTarget {
pub fn new(target_type: impl Into<String>) -> Self {
Self {
target_type: target_type.into(),
url: None,
model: None,
handler: None,
}
}
pub fn with_url(mut self, url: impl Into<String>) -> Self {
self.url = Some(url.into());
self
}
pub fn with_model(mut self, model: impl Into<String>) -> Self {
self.model = Some(model.into());
self
}
pub fn with_handler(mut self, handler: impl Into<String>) -> Self {
self.handler = Some(handler.into());
self
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct NamespaceModel {
pub label: String,
pub model_id: String,
}
#[derive(Debug, Clone)]
pub struct PhraseCheckResult {
pub added: bool,
pub redundant: bool,
pub warning: Option<String>,
}
pub const MAX_PHRASES_PER_LANGUAGE: usize = 500;
pub enum IntentSeeds {
Mono(Vec<String>),
Multi(std::collections::HashMap<String, Vec<String>>),
}
impl From<&[&str]> for IntentSeeds {
fn from(s: &[&str]) -> Self {
IntentSeeds::Mono(s.iter().map(|x| x.to_string()).collect())
}
}
impl<const N: usize> From<&[&str; N]> for IntentSeeds {
fn from(s: &[&str; N]) -> Self {
IntentSeeds::Mono(s.iter().map(|x| x.to_string()).collect())
}
}
impl From<Vec<String>> for IntentSeeds {
fn from(s: Vec<String>) -> Self {
IntentSeeds::Mono(s)
}
}
impl From<Vec<&str>> for IntentSeeds {
fn from(s: Vec<&str>) -> Self {
IntentSeeds::Mono(s.into_iter().map(|x| x.to_string()).collect())
}
}
impl From<std::collections::HashMap<String, Vec<String>>> for IntentSeeds {
fn from(m: std::collections::HashMap<String, Vec<String>>) -> Self {
IntentSeeds::Multi(m)
}
}
#[derive(Debug, Clone)]
pub struct IntentInfo {
pub id: String,
pub description: String,
pub instructions: String,
pub persona: String,
pub source: Option<IntentSource>,
pub target: Option<IntentTarget>,
pub schema: Option<serde_json::Value>,
pub guardrails: Vec<String>,
pub training: std::collections::HashMap<String, Vec<String>>,
}
#[derive(Debug, Clone)]
pub struct NamespaceInfo {
pub name: String,
pub description: String,
pub default_threshold: Option<f32>,
pub default_min_voting_tokens: Option<u32>,
pub domain_descriptions: std::collections::HashMap<String, String>,
}
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
pub struct NamespaceEdit {
pub name: Option<String>,
pub description: Option<String>,
pub default_threshold: Option<Option<f32>>,
pub default_min_voting_tokens: Option<Option<u32>>,
pub domain_descriptions: Option<std::collections::HashMap<String, String>>,
}
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
pub struct IntentEdit {
pub description: Option<String>,
pub instructions: Option<String>,
pub persona: Option<String>,
pub source: Option<IntentSource>,
pub target: Option<IntentTarget>,
pub schema: Option<serde_json::Value>,
pub guardrails: Option<Vec<String>>,
}