use anyhow::Result;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[cfg(feature = "backend-lancedb")]
use arrow_array::{
Array, BinaryArray, Float32Array, Int32Array, Int64Array, RecordBatch, StringArray,
TimestampMillisecondArray, BooleanArray, FixedSizeListArray,
};
#[cfg(feature = "backend-lancedb")]
use arrow_schema::{DataType, Field, Schema as ArrowSchema, TimeUnit};
#[cfg(feature = "backend-lancedb")]
use std::sync::Arc;
#[cfg(feature = "backend-lancedb")]
const EMBEDDING_DIM: i32 = 1536;
#[cfg(feature = "backend-lancedb")]
pub fn user_schema() -> Arc<ArrowSchema> {
Arc::new(ArrowSchema::new(vec![
Field::new("id", DataType::Utf8, false),
Field::new("profile_name", DataType::Utf8, false),
Field::new("identity_type", DataType::Utf8, false),
Field::new("identity_public_key", DataType::Utf8, true),
Field::new("encryption_public_key", DataType::Utf8, true),
Field::new("signature_public_key", DataType::Utf8, true),
Field::new("node_signature_public_key", DataType::Utf8, true),
Field::new("node_encryption_public_key", DataType::Utf8, true),
Field::new("permission_type", DataType::Utf8, true),
Field::new("wallet_id", DataType::Utf8, true),
Field::new("metadata", DataType::Utf8, true), Field::new("created_at", DataType::Timestamp(TimeUnit::Millisecond, None), false),
Field::new("updated_at", DataType::Timestamp(TimeUnit::Millisecond, None), false),
Field::new("is_active", DataType::Boolean, false),
]))
}
#[cfg(feature = "backend-lancedb")]
pub fn tool_schema() -> Arc<ArrowSchema> {
Arc::new(ArrowSchema::new(vec![
Field::new("id", DataType::Utf8, false),
Field::new("name", DataType::Utf8, false),
Field::new("description", DataType::Utf8, true),
Field::new("version", DataType::Utf8, false),
Field::new("tool_type", DataType::Utf8, false), Field::new("parameters_schema", DataType::Utf8, true), Field::new("enabled", DataType::Boolean, false),
Field::new("config", DataType::Utf8, true), Field::new("usage_count", DataType::Int64, false),
Field::new("avg_execution_time_ms", DataType::Float32, true),
Field::new("last_used_at", DataType::Timestamp(TimeUnit::Millisecond, None), true),
Field::new("created_at", DataType::Timestamp(TimeUnit::Millisecond, None), false),
Field::new("updated_at", DataType::Timestamp(TimeUnit::Millisecond, None), false),
]))
}
#[cfg(feature = "backend-lancedb")]
pub fn agent_schema() -> Arc<ArrowSchema> {
Arc::new(ArrowSchema::new(vec![
Field::new("id", DataType::Utf8, false),
Field::new("name", DataType::Utf8, false),
Field::new("description", DataType::Utf8, true),
Field::new("model", DataType::Utf8, false),
Field::new("system_prompt", DataType::Utf8, true),
Field::new("temperature", DataType::Float32, true),
Field::new("max_tokens", DataType::Int32, true),
Field::new("tools", DataType::Utf8, true), Field::new("created_by", DataType::Utf8, false),
Field::new("is_public", DataType::Boolean, false),
Field::new("usage_count", DataType::Int64, false),
Field::new("created_at", DataType::Timestamp(TimeUnit::Millisecond, None), false),
Field::new("updated_at", DataType::Timestamp(TimeUnit::Millisecond, None), false),
]))
}
#[cfg(feature = "backend-lancedb")]
pub fn embedding_schema() -> Arc<ArrowSchema> {
Arc::new(ArrowSchema::new(vec![
Field::new("id", DataType::Utf8, false),
Field::new("content", DataType::Utf8, false),
Field::new("content_hash", DataType::Utf8, false),
Field::new(
"vector",
DataType::FixedSizeList(
Arc::new(Field::new("item", DataType::Float32, false)),
EMBEDDING_DIM,
),
false,
),
Field::new("model", DataType::Utf8, false),
Field::new("source_type", DataType::Utf8, false), Field::new("source_id", DataType::Utf8, true),
Field::new("metadata", DataType::Utf8, true), Field::new("created_at", DataType::Timestamp(TimeUnit::Millisecond, None), false),
]))
}
#[cfg(feature = "backend-lancedb")]
pub fn job_schema() -> Arc<ArrowSchema> {
Arc::new(ArrowSchema::new(vec![
Field::new("id", DataType::Utf8, false),
Field::new("job_type", DataType::Utf8, false),
Field::new("status", DataType::Utf8, false), Field::new("priority", DataType::Int32, false),
Field::new("payload", DataType::Utf8, false), Field::new("result", DataType::Utf8, true), Field::new("error", DataType::Utf8, true),
Field::new("created_by", DataType::Utf8, false),
Field::new("agent_id", DataType::Utf8, true),
Field::new("started_at", DataType::Timestamp(TimeUnit::Millisecond, None), true),
Field::new("completed_at", DataType::Timestamp(TimeUnit::Millisecond, None), true),
Field::new("created_at", DataType::Timestamp(TimeUnit::Millisecond, None), false),
Field::new("updated_at", DataType::Timestamp(TimeUnit::Millisecond, None), false),
]))
}
#[cfg(feature = "backend-lancedb")]
pub fn session_schema() -> Arc<ArrowSchema> {
Arc::new(ArrowSchema::new(vec![
Field::new("id", DataType::Utf8, false),
Field::new("user_id", DataType::Utf8, false),
Field::new("agent_id", DataType::Utf8, true),
Field::new("messages", DataType::Utf8, false), Field::new("context", DataType::Utf8, true), Field::new("token_count", DataType::Int64, false),
Field::new("cost", DataType::Float32, true),
Field::new("created_at", DataType::Timestamp(TimeUnit::Millisecond, None), false),
Field::new("updated_at", DataType::Timestamp(TimeUnit::Millisecond, None), false),
]))
}
#[cfg(feature = "multimodal")]
pub fn multimodal_schema() -> Arc<ArrowSchema> {
Arc::new(ArrowSchema::new(vec![
Field::new("id", DataType::Utf8, false),
Field::new("media_type", DataType::Utf8, false), Field::new("mime_type", DataType::Utf8, false),
Field::new("data", DataType::Binary, false), Field::new("thumbnail", DataType::Binary, true), Field::new("width", DataType::Int32, true),
Field::new("height", DataType::Int32, true),
Field::new("duration_ms", DataType::Int64, true), Field::new(
"embedding",
DataType::FixedSizeList(
Arc::new(Field::new("item", DataType::Float32, false)),
EMBEDDING_DIM,
),
true,
),
Field::new("text_content", DataType::Utf8, true), Field::new("metadata", DataType::Utf8, true), Field::new("created_by", DataType::Utf8, false),
Field::new("created_at", DataType::Timestamp(TimeUnit::Millisecond, None), false),
]))
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct User {
pub id: Uuid,
pub profile_name: String,
pub identity_type: String,
pub identity_public_key: Option<String>,
pub encryption_public_key: Option<String>,
pub signature_public_key: Option<String>,
pub node_signature_public_key: Option<String>,
pub node_encryption_public_key: Option<String>,
pub permission_type: Option<String>,
pub wallet_id: Option<String>,
pub metadata: Option<serde_json::Value>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub is_active: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Tool {
pub id: Uuid,
pub name: String,
pub description: Option<String>,
pub version: String,
pub tool_type: ToolType,
pub parameters_schema: Option<serde_json::Value>,
pub enabled: bool,
pub config: Option<serde_json::Value>,
pub usage_count: i64,
pub avg_execution_time_ms: Option<f32>,
pub last_used_at: Option<DateTime<Utc>>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ToolType {
Rust,
JavaScript,
Python,
MCP,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Agent {
pub id: Uuid,
pub name: String,
pub description: Option<String>,
pub model: String,
pub system_prompt: Option<String>,
pub temperature: Option<f32>,
pub max_tokens: Option<i32>,
pub tools: Vec<String>,
pub created_by: String,
pub is_public: bool,
pub usage_count: i64,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Embedding {
pub id: Uuid,
pub content: String,
pub content_hash: String,
pub vector: Vec<f32>,
pub model: String,
pub source_type: String,
pub source_id: Option<String>,
pub metadata: Option<serde_json::Value>,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Job {
pub id: Uuid,
pub job_type: String,
pub status: JobStatus,
pub priority: i32,
pub payload: serde_json::Value,
pub result: Option<serde_json::Value>,
pub error: Option<String>,
pub created_by: String,
pub agent_id: Option<String>,
pub started_at: Option<DateTime<Utc>>,
pub completed_at: Option<DateTime<Utc>>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum JobStatus {
Pending,
Running,
Completed,
Failed,
Cancelled,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Session {
pub id: Uuid,
pub user_id: String,
pub agent_id: Option<String>,
pub messages: Vec<Message>,
pub context: Option<serde_json::Value>,
pub token_count: i64,
pub cost: Option<f32>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Message {
pub role: String,
pub content: String,
pub timestamp: DateTime<Utc>,
pub tool_calls: Option<Vec<ToolCall>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolCall {
pub id: String,
pub name: String,
pub arguments: serde_json::Value,
pub result: Option<serde_json::Value>,
}
#[cfg(feature = "multimodal")]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MultimodalContent {
pub id: Uuid,
pub media_type: MediaType,
pub mime_type: String,
pub data: Vec<u8>,
pub thumbnail: Option<Vec<u8>>,
pub width: Option<i32>,
pub height: Option<i32>,
pub duration_ms: Option<i64>,
pub embedding: Option<Vec<f32>>,
pub text_content: Option<String>,
pub metadata: Option<serde_json::Value>,
pub created_by: String,
pub created_at: DateTime<Utc>,
}
#[cfg(feature = "multimodal")]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum MediaType {
Image,
Audio,
Video,
Document,
}
#[cfg(feature = "backend-lancedb")]
pub trait ToRecordBatch {
fn to_record_batch(&self) -> Result<RecordBatch>;
}
#[cfg(feature = "backend-lancedb")]
pub trait FromRecordBatch: Sized {
fn from_record_batch(batch: &RecordBatch, row: usize) -> Result<Self>;
}
#[cfg(all(test, feature = "backend-lancedb"))]
mod tests {
use super::*;
#[test]
fn test_user_schema() {
let schema = user_schema();
assert_eq!(schema.fields().len(), 14);
assert_eq!(schema.field(0).name(), "id");
assert_eq!(schema.field(0).data_type(), &DataType::Utf8);
}
#[test]
fn test_embedding_schema() {
let schema = embedding_schema();
let vector_field = schema.field(3);
assert_eq!(vector_field.name(), "vector");
if let DataType::FixedSizeList(_, size) = vector_field.data_type() {
assert_eq!(*size, EMBEDDING_DIM);
} else {
panic!("Expected FixedSizeList for vector field");
}
}
#[test]
fn test_tool_type_serialization() {
let tool_type = ToolType::JavaScript;
let json = serde_json::to_string(&tool_type).unwrap();
assert_eq!(json, r#""javascript""#);
let deserialized: ToolType = serde_json::from_str(&json).unwrap();
assert!(matches!(deserialized, ToolType::JavaScript));
}
#[test]
fn test_job_status_serialization() {
let status = JobStatus::Running;
let json = serde_json::to_string(&status).unwrap();
assert_eq!(json, r#""running""#);
let deserialized: JobStatus = serde_json::from_str(&json).unwrap();
assert!(matches!(deserialized, JobStatus::Running));
}
}