Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 5 additions & 57 deletions src/adapters/telegram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use tracing::{error, info, warn};

use crate::{
handler::MessageHandler,
journal::command::{DEFAULT_RECENT_LIMIT, JournalCommand, JournalCommandRequest},
journal::command::{JournalCommand, JournalCommandRequest},
journal::transfer::{TransferError, TransferService},
messages::{IncomingMessage, MessageSource},
tokens::TokenIssuer,
Expand Down Expand Up @@ -126,22 +126,12 @@ enum Command {
Start,
#[command(description = "show commands")]
Help,
#[command(description = "show latest entry")]
Last,
#[command(description = "delete latest entry")]
Undo,
#[command(description = "show recent entries (optionally how many)")]
Recent(String),
#[command(description = "show today's entries")]
Today,
#[command(description = "show daily review")]
DayReview,
#[command(description = "show last week's review")]
WeekReview,
#[command(description = "show journal stats")]
Stats,
#[command(description = "show bot status")]
Status,
#[command(description = "search entries by meaning")]
Search(String),
#[command(description = "create or rotate your MCP access token (/token revoke to disable)")]
Expand All @@ -168,29 +158,9 @@ fn dispatch_for(command: Command) -> Dispatch {
match command {
Command::Start => Dispatch::Journal(JournalCommand::Start),
Command::Help => Dispatch::Help,
Command::Last => Dispatch::Journal(JournalCommand::Last),
Command::Undo => Dispatch::Journal(JournalCommand::Undo),
Command::Recent(argument) => {
let argument = argument.trim();
let command = if argument.is_empty() {
JournalCommand::Recent {
requested_limit: DEFAULT_RECENT_LIMIT,
}
} else {
match argument.parse::<u32>() {
Ok(limit) if limit > 0 => JournalCommand::Recent {
requested_limit: limit,
},
_ => JournalCommand::RecentUsage,
}
};
Dispatch::Journal(command)
}
Command::Today => Dispatch::Journal(JournalCommand::Today),
Command::DayReview => Dispatch::Journal(JournalCommand::DayReviewLast),
Command::WeekReview => Dispatch::Journal(JournalCommand::WeekReviewLast),
Command::Stats => Dispatch::Journal(JournalCommand::Stats),
Command::Status => Dispatch::Journal(JournalCommand::Status),
Command::Search(query) => {
let query = query.trim();
let command = if query.is_empty() {
Expand Down Expand Up @@ -697,11 +667,7 @@ mod tests {
#[test]
fn parse_journal_commands() {
assert_eq!(journal("/start"), Some(JournalCommand::Start));
assert_eq!(journal("/last"), Some(JournalCommand::Last));
assert_eq!(journal("/undo"), Some(JournalCommand::Undo));
assert_eq!(journal("/today"), Some(JournalCommand::Today));
assert_eq!(journal("/stats"), Some(JournalCommand::Stats));
assert_eq!(journal("/status"), Some(JournalCommand::Status));
assert_eq!(journal("/day_review"), Some(JournalCommand::DayReviewLast));
assert_eq!(
journal("/week_review"),
Expand All @@ -711,11 +677,10 @@ mod tests {

#[test]
fn parse_strips_bot_name_suffix() {
assert_eq!(journal("/last@mybot"), Some(JournalCommand::Last));
assert_eq!(journal("/status@mybot"), Some(JournalCommand::Status));
assert_eq!(journal("/undo@mybot"), Some(JournalCommand::Undo));
assert_eq!(
journal("/recent@mybot 3"),
Some(JournalCommand::Recent { requested_limit: 3 })
journal("/day_review@mybot"),
Some(JournalCommand::DayReviewLast)
);
assert_eq!(
journal("/search@mybot something"),
Expand All @@ -725,23 +690,6 @@ mod tests {
);
}

#[test]
fn parse_recent_command_arguments() {
assert_eq!(
journal("/recent"),
Some(JournalCommand::Recent {
requested_limit: DEFAULT_RECENT_LIMIT
})
);
assert_eq!(
journal("/recent 5"),
Some(JournalCommand::Recent { requested_limit: 5 })
);
assert_eq!(journal("/recent abc"), Some(JournalCommand::RecentUsage));
assert_eq!(journal("/recent 0"), Some(JournalCommand::RecentUsage));
assert_eq!(journal("/recent -3"), Some(JournalCommand::RecentUsage));
}

#[test]
fn parse_search_command_arguments() {
assert_eq!(
Expand Down Expand Up @@ -796,7 +744,7 @@ mod tests {
registered.command
);
}
assert!(help.contains("/recent"));
assert!(help.contains("/search"));
assert!(help.contains("/token"));
assert!(help.contains("/export"));
}
Expand Down
15 changes: 2 additions & 13 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ use crate::{
},
search::SemanticSearchService,
service::JournalService,
status::EmbeddingStatusConfig,
week_review::{build_weekly_review_service, configure_weekly_review},
},
prompts::{PromptKey, PromptRepository, PromptSource},
Expand Down Expand Up @@ -253,7 +252,6 @@ pub(crate) fn build_journal_service(
pool: SqlitePool,
prompt_repository: &PromptRepository,
config: &ServeConfig,
delivery_configured: bool,
) -> Result<JournalService, Box<dyn Error>> {
let mut journal_service = JournalService::new(JournalRepository::new(pool.clone()));

Expand All @@ -278,14 +276,9 @@ pub(crate) fn build_journal_service(
config.weekly_review.clone(),
)?;

if delivery_configured {
journal_service = journal_service.with_daily_review_delivery_configured();
}

if let Some(api_key) = config.openai_api_key() {
let cfg = config.embedding.clone();
let embedder =
RigOpenAiEmbedder::from_optional_api_key(cfg.clone(), Some(api_key.to_string()))
RigOpenAiEmbedder::from_optional_api_key(config.embedding.clone(), Some(api_key.to_string()))
.map_err(|error| {
warn!(
error = %error,
Expand All @@ -300,7 +293,6 @@ pub(crate) fn build_journal_service(
crate::journal::review::embedding_repository::SqliteDailyReviewEmbeddingRepository::new(
pool.clone(),
);
let status_config = EmbeddingStatusConfig { model: cfg.model };
let search = SemanticSearchService::new(
embedding_repository.clone(),
Arc::clone(&embedder),
Expand All @@ -314,10 +306,7 @@ pub(crate) fn build_journal_service(

journal_service = journal_service.with_search(search);
journal_service = journal_service.with_daily_review_search(review_search);
journal_service =
journal_service.with_capture_embedding(embedding_repository.clone(), embedder);
journal_service = journal_service.with_embedding_status_config(status_config);
journal_service = journal_service.with_pending_embedding_counter(embedding_repository);
journal_service = journal_service.with_capture_embedding(embedding_repository, embedder);
} else {
warn!("OPENAI_API_KEY is not set; semantic search and embeddings are disabled");
}
Expand Down
9 changes: 0 additions & 9 deletions src/journal/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ use chrono::{DateTime, Utc};

use crate::messages::MessageSource;

pub const DEFAULT_RECENT_LIMIT: u32 = 10;
pub const MAX_RECENT_LIMIT: u32 = 50;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct JournalCommandRequest {
pub source: MessageSource,
Expand All @@ -16,13 +13,7 @@ pub struct JournalCommandRequest {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum JournalCommand {
Start,
Last,
Undo,
Recent { requested_limit: u32 },
RecentUsage,
Today,
Stats,
Status,
DayReviewLast,
WeekReviewLast,
Search { query: String },
Expand Down
7 changes: 0 additions & 7 deletions src/journal/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,3 @@ impl AsRef<JournalEntry> for StoredJournalEntry {
&self.entry
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct JournalStats {
pub total_entries: i64,
pub entries_today: i64,
pub latest_received_at: Option<DateTime<Utc>>,
}
1 change: 0 additions & 1 deletion src/journal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ pub(crate) mod responses;
pub mod review;
pub mod search;
pub mod service;
pub mod status;
pub mod store;
pub mod transfer;
pub mod week_review;
Expand Down
12 changes: 5 additions & 7 deletions src/journal/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,11 @@ impl JournalServiceRegistry {
let prompt_repository = PromptRepository::new(pool.clone());

// Build the JournalService for this pool
let service = crate::app::build_journal_service(
pool.clone(),
&prompt_repository,
&self.serve_config,
self.serve_config.daily_review_delivery.enabled,
)
.map_err(|e| -> Box<dyn std::error::Error + Send + Sync> { e.to_string().into() })?;
let service =
crate::app::build_journal_service(pool.clone(), &prompt_repository, &self.serve_config)
.map_err(|e| -> Box<dyn std::error::Error + Send + Sync> {
e.to_string().into()
})?;

guard.insert(chat_id.to_string(), service.clone());
Ok(service)
Expand Down
53 changes: 1 addition & 52 deletions src/journal/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use sqlx::{Row, SqlitePool, sqlite::SqliteRow};

use crate::messages::{IncomingMessage, MessageSource};

use super::entry::{JournalEntry, JournalStats, StoredJournalEntry};
use super::entry::{JournalEntry, StoredJournalEntry};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct JournalConversation {
Expand Down Expand Up @@ -152,32 +152,6 @@ impl JournalRepository {
.collect())
}

pub async fn fetch_last_for_conversation(
&self,
source: &MessageSource,
source_conversation_id: &str,
) -> Result<Option<StoredJournalEntry>, sqlx::Error> {
let row = sqlx::query(
r#"
SELECT id, raw_text, received_at
FROM journal_entries
WHERE source = ?
AND source_conversation_id = ?
ORDER BY received_at DESC, id DESC
LIMIT 1
"#,
)
.bind(source.to_string())
.bind(source_conversation_id)
.fetch_optional(&self.pool)
.await?;

Ok(row.map(|row| StoredJournalEntry {
id: row.get("id"),
entry: map_entry(row),
}))
}

pub async fn delete_last_for_conversation(
&self,
source: &MessageSource,
Expand Down Expand Up @@ -504,29 +478,4 @@ impl JournalRepository {
})
.collect())
}

pub async fn stats(&self, today: NaiveDate) -> Result<JournalStats, sqlx::Error> {
let start = Utc.from_utc_datetime(&today.and_hms_opt(0, 0, 0).unwrap());
let end = start + Duration::days(1);

let row = sqlx::query(
r#"
SELECT
COUNT(*) AS total_entries,
COALESCE(SUM(CASE WHEN received_at >= ? AND received_at < ? THEN 1 ELSE 0 END), 0) AS entries_today,
MAX(received_at) AS latest_received_at
FROM journal_entries
"#,
)
.bind(start)
.bind(end)
.fetch_one(&self.pool)
.await?;

Ok(JournalStats {
total_entries: row.get("total_entries"),
entries_today: row.get("entries_today"),
latest_received_at: row.get("latest_received_at"),
})
}
}
Loading
Loading