Files
galaxy/app/src/terminal/input/user_query/data_source.rs
T

86 lines
3.0 KiB
Rust

//! Data source for the user query menu.
use galaxyui::{AppContext, Entity, SingletonEntity};
use itertools::Itertools;
use ordered_float::OrderedFloat;
use crate::ai::agent::conversation::AIConversationId;
use crate::ai::agent::AIAgentExchangeId;
use crate::ai::blocklist::BlocklistAIHistoryModel;
use crate::search::data_source::{Query, QueryResult};
use crate::search::mixer::DataSourceRunErrorWrapper;
use crate::search::SyncDataSource;
use crate::terminal::input::user_query::search_item::UserQuerySearchItem;
/// Action emitted when a query is selected in the user query menu.
#[derive(Clone, Debug)]
pub struct SelectUserQuery {
pub exchange_id: AIAgentExchangeId,
}
pub struct UserQueryDataSource {
conversation_id: AIConversationId,
}
impl UserQueryDataSource {
pub fn new(conversation_id: AIConversationId) -> Self {
Self { conversation_id }
}
pub fn set_conversation_id(&mut self, conversation_id: AIConversationId) {
self.conversation_id = conversation_id;
}
}
impl SyncDataSource for UserQueryDataSource {
type Action = SelectUserQuery;
fn run_query(
&self,
query: &Query,
app: &AppContext,
) -> Result<Vec<QueryResult<Self::Action>>, DataSourceRunErrorWrapper> {
let history_model = BlocklistAIHistoryModel::as_ref(app);
let Some(conversation) = history_model.conversation(&self.conversation_id) else {
return Ok(vec![]);
};
let search_query = query.text.trim().to_lowercase();
if search_query.is_empty() {
// With no search, we just return all queries in chronological order (oldest first).
let results: Vec<QueryResult<Self::Action>> = conversation
.root_task_exchanges()
.filter(|exchange| exchange.has_user_query())
.map(|exchange| {
let query_text = exchange.format_input_for_copy();
QueryResult::from(UserQuerySearchItem::new(exchange.id, query_text))
})
.collect();
Ok(results)
} else {
// Filter by fuzzy matching and sort by score.
let results = conversation
.root_task_exchanges()
.filter(|exchange| exchange.has_user_query())
.filter_map(|exchange| {
let query_text = exchange.format_input_for_copy();
let match_result =
fuzzy_match::match_indices_case_insensitive(&query_text, &search_query)?;
Some(QueryResult::from(
UserQuerySearchItem::new(exchange.id, query_text)
.with_query_match_result(Some(match_result.clone()))
.with_score(OrderedFloat(match_result.score as f64)),
))
})
.sorted_by(|a, b| b.score().cmp(&a.score()))
.collect();
Ok(results)
}
}
}
impl Entity for UserQueryDataSource {
type Event = ();
}