diff --git a/crates/agentic-core/migrations/0002_add_placeholders.sql b/crates/agentic-core/migrations/0002_add_placeholders.sql new file mode 100644 index 0000000..849c3ed --- /dev/null +++ b/crates/agentic-core/migrations/0002_add_placeholders.sql @@ -0,0 +1,12 @@ +ALTER TABLE conversations ADD COLUMN tenant_id TEXT; +ALTER TABLE conversations ADD COLUMN metadata TEXT; + +ALTER TABLE items ADD COLUMN tenant_id TEXT; +ALTER TABLE items ADD COLUMN raw_tokens TEXT; + +ALTER TABLE responses ADD COLUMN tenant_id TEXT; +ALTER TABLE responses ADD COLUMN raw_tokens TEXT; + +CREATE INDEX IF NOT EXISTS idx_conversations_tenant_id ON conversations (tenant_id); +CREATE INDEX IF NOT EXISTS idx_items_tenant_id ON items (tenant_id); +CREATE INDEX IF NOT EXISTS idx_responses_tenant_id ON responses (tenant_id); diff --git a/crates/agentic-core/src/storage/models/conversation.rs b/crates/agentic-core/src/storage/models/conversation.rs index 21a70f6..4d9515a 100644 --- a/crates/agentic-core/src/storage/models/conversation.rs +++ b/crates/agentic-core/src/storage/models/conversation.rs @@ -12,6 +12,9 @@ pub struct Conversation { /// Unique conversation identifier. pub id: String, + /// Optional metadata as JSON string. + pub metadata: Option, + /// Creation timestamp as Unix timestamp in seconds. pub created_at: i64, } @@ -69,10 +72,12 @@ mod tests { fn test_conversation_basic() { let conversation = Conversation { id: "conv_1".to_string(), + metadata: None, created_at: 1_704_067_200, }; assert_eq!(conversation.id, "conv_1"); + assert!(conversation.metadata.is_none()); assert_eq!(conversation.created_at, 1_704_067_200); } } diff --git a/crates/agentic-core/src/storage/models/item.rs b/crates/agentic-core/src/storage/models/item.rs index 71640dc..c283200 100644 --- a/crates/agentic-core/src/storage/models/item.rs +++ b/crates/agentic-core/src/storage/models/item.rs @@ -1,5 +1,7 @@ //! Conversation history item stored in the database. +use tracing::warn; + use super::super::pool::{DbPool, DbResult, DbTransaction}; use super::super::types::item::InOutItem; use crate::types::io::{InputItem, OutputItem}; @@ -44,9 +46,14 @@ impl Item { /// Deserialize data column as either `InputItem` or `OutputItem`. #[must_use] pub fn as_inout(&self) -> Option { - self.as_input() - .map(InOutItem::Input) - .or_else(|| self.as_output().map(InOutItem::Output)) + match (self.as_input(), self.as_output()) { + (Some(input), _) if !matches!(input, InputItem::Unknown) => Some(InOutItem::Input(input)), + (_, Some(output)) if !matches!(output, OutputItem::Unknown) => Some(InOutItem::Output(output)), + _ => { + warn!(item_id = %self.id, "unrecognized item type in stored data"); + None + } + } } } diff --git a/crates/agentic-core/src/storage/types/conversation.rs b/crates/agentic-core/src/storage/types/conversation.rs index c4fbe82..55dc909 100644 --- a/crates/agentic-core/src/storage/types/conversation.rs +++ b/crates/agentic-core/src/storage/types/conversation.rs @@ -9,6 +9,8 @@ use super::super::models::Conversation as StorageDbConversation; pub struct ConversationData { /// Unique conversation identifier pub conversation_id: String, + /// Optional metadata as JSON string + pub metadata: Option, /// Creation timestamp as Unix timestamp in seconds pub created_at: i64, } @@ -17,6 +19,7 @@ impl From for ConversationData { fn from(row: StorageDbConversation) -> Self { Self { conversation_id: row.id, + metadata: row.metadata, created_at: row.created_at, } } @@ -26,6 +29,7 @@ impl From for StorageDbConversation { fn from(data: ConversationData) -> Self { Self { id: data.conversation_id, + metadata: data.metadata, created_at: data.created_at, } } @@ -39,6 +43,7 @@ mod tests { fn test_conversation_from_db_conversation() { let db_row = StorageDbConversation { id: "conv_123".to_string(), + metadata: None, created_at: 1_704_067_200, }; @@ -51,11 +56,13 @@ mod tests { fn test_conversation_roundtrip() { let data = ConversationData { conversation_id: "conv_456".to_string(), + metadata: Some(r#"{"key":"value"}"#.to_string()), created_at: 1_704_067_200, }; let db_row: StorageDbConversation = data.into(); assert_eq!(db_row.id, "conv_456"); + assert_eq!(db_row.metadata, Some(r#"{"key":"value"}"#.to_string())); assert_eq!(db_row.created_at, 1_704_067_200); } @@ -63,6 +70,7 @@ mod tests { fn test_conversation_data_clone() { let data = ConversationData { conversation_id: "conv_clone".to_string(), + metadata: None, created_at: 1_704_067_200, }; @@ -75,6 +83,7 @@ mod tests { fn test_conversation_data_debug_format() { let data = ConversationData { conversation_id: "conv_debug".to_string(), + metadata: None, created_at: 1_704_067_200, }; @@ -87,6 +96,7 @@ mod tests { fn test_conversation_bidirectional_conversion() { let original = ConversationData { conversation_id: "conv_bidir".to_string(), + metadata: None, created_at: 1_706_790_600, }; diff --git a/crates/agentic-core/src/types/io.rs b/crates/agentic-core/src/types/io.rs index 239a9ce..14fd7f9 100644 --- a/crates/agentic-core/src/types/io.rs +++ b/crates/agentic-core/src/types/io.rs @@ -51,6 +51,8 @@ pub enum InputItem { Message(InputMessage), #[serde(rename = "function_call_output")] FunctionCallOutput(FunctionToolResultMessage), + #[serde(other)] + Unknown, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -108,6 +110,8 @@ pub enum OutputItem { Message(OutputMessage), #[serde(rename = "function_call")] FunctionCall(FunctionToolCall), + #[serde(other)] + Unknown, } #[derive(Debug, Clone, Default, Serialize, Deserialize)]