dave: tweak search tool to include limit arg

So that dave can return single notes

Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
William Casarin
2025-03-29 10:09:40 -07:00
parent 418e08541d
commit 366827d335

View File

@@ -43,7 +43,7 @@ pub enum Message {
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SearchResponse { pub struct SearchResponse {
context: SearchContext, //context: SearchContext,
notes: Vec<u64>, notes: Vec<u64>,
} }
@@ -259,7 +259,8 @@ pub enum SearchContext {
#[derive(Debug, Deserialize, Serialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]
pub struct SearchCall { pub struct SearchCall {
context: SearchContext, //context: SearchContext,
limit: i32,
query: String, query: String,
} }
@@ -278,7 +279,7 @@ impl SearchCall {
} }
}; };
SearchResponse { SearchResponse {
context: self.context.clone(), //context: self.context.clone(),
notes, notes,
} }
} }
@@ -438,13 +439,16 @@ impl Dave {
fn search_call_ui(search_call: &SearchCall, ui: &mut egui::Ui) { fn search_call_ui(search_call: &SearchCall, ui: &mut egui::Ui) {
ui.add(search_icon(16.0, 16.0)); ui.add(search_icon(16.0, 16.0));
ui.add_space(8.0); ui.add_space(8.0);
let context = match search_call.context { //let context = match search_call.context {
SearchContext::Profile => "profile ", // SearchContext::Profile => "profile ",
SearchContext::Any => "", // SearchContext::Any => "",
SearchContext::Home => "home ", // SearchContext::Home => "home ",
}; //};
ui.label(format!("Searching {}for '{}'", context, search_call.query)); ui.label(format!(
"Searching for '{}'",
/*context,*/ search_call.query
));
} }
fn tool_call_ui(toolcalls: &[ToolCall], ui: &mut egui::Ui) { fn tool_call_ui(toolcalls: &[ToolCall], ui: &mut egui::Ui) {
@@ -497,13 +501,14 @@ impl Dave {
} }
fn send_user_message(&mut self, app_ctx: &AppContext, ctx: &egui::Context) { fn send_user_message(&mut self, app_ctx: &AppContext, ctx: &egui::Context) {
let messages = { let messages: Vec<ChatCompletionRequestMessage> = {
let txn = Transaction::new(app_ctx.ndb).expect("txn"); let txn = Transaction::new(app_ctx.ndb).expect("txn");
self.chat self.chat
.iter() .iter()
.map(|c| c.to_api_msg(&txn, app_ctx.ndb)) .map(|c| c.to_api_msg(&txn, app_ctx.ndb))
.collect() .collect()
}; };
tracing::debug!("sending messages, latest: {:?}", messages.last().unwrap());
let pubkey = self.pubkey.clone(); let pubkey = self.pubkey.clone();
let ctx = ctx.clone(); let ctx = ctx.clone();
let client = self.client.clone(); let client = self.client.clone();
@@ -574,7 +579,9 @@ impl Dave {
} }
if let Some(content) = &resp.content { if let Some(content) = &resp.content {
tx.send(DaveResponse::Token(content.to_owned())).unwrap(); if let Err(err) = tx.send(DaveResponse::Token(content.to_owned())) {
tracing::error!("failed to send dave response token to ui: {err}");
}
ctx.request_repaint(); ctx.request_repaint();
} }
} }
@@ -628,7 +635,7 @@ impl notedeck::App for Dave {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
enum ArgType { enum ArgType {
String, String,
//Number, Number,
Enum(Vec<&'static str>), Enum(Vec<&'static str>),
} }
@@ -636,7 +643,7 @@ impl ArgType {
pub fn type_string(&self) -> &'static str { pub fn type_string(&self) -> &'static str {
match self { match self {
Self::String => "string", Self::String => "string",
//Self::Number => "number", Self::Number => "number",
Self::Enum(_) => "string", Self::Enum(_) => "string",
} }
} }
@@ -648,6 +655,7 @@ struct ToolArg {
name: &'static str, name: &'static str,
required: bool, required: bool,
description: &'static str, description: &'static str,
default: Option<Value>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -685,6 +693,9 @@ impl Tool {
"type".to_string(), "type".to_string(),
Value::String(arg.typ.type_string().to_string()), Value::String(arg.typ.type_string().to_string()),
); );
if let Some(default) = &arg.default {
props.insert("default".to_string(), default.clone());
}
props.insert( props.insert(
"description".to_string(), "description".to_string(),
Value::String(arg.description.to_owned()), Value::String(arg.description.to_owned()),
@@ -726,13 +737,30 @@ fn search_tool() -> Tool {
Tool { Tool {
name: "search", name: "search",
parse_call: SearchCall::parse, parse_call: SearchCall::parse,
description: "Full-text search functionality. Used for finding individual notes with specific terms. Queries with multiple words will only return results with notes that have all of those words.", description: "Full-text search functionality. Used for finding individual notes with specific terms in the contents.",
arguments: vec![ arguments: vec![
ToolArg { ToolArg {
name: "query", name: "query",
typ: ArgType::String, typ: ArgType::String,
required: true, required: true,
description: "The search query", default: None,
description: "The fulltext search query. Queries with multiple words will only return results with notes that have all of those words. Don't include 'and', 'punctuation', etc if you don't need to.",
},
ToolArg {
name: "limit",
typ: ArgType::Number,
required: true,
default: Some(Value::Number(serde_json::Number::from_i128(10).unwrap())),
description: "The number of results to return.",
},
/*
ToolArg {
name: "kind",
typ: ArgType::Enum(vec!["microblog", "longform"]),
required: true,
description: "The kind of note. microblogs are short snippets of texts (aka tweets, this is what you want to search by default). Longform are blog posts/articles.",
}, },
ToolArg { ToolArg {
@@ -741,6 +769,7 @@ fn search_tool() -> Tool {
required: true, required: true,
description: "The context in which the search is occuring. valid options are 'home', 'profile', 'any'", description: "The context in which the search is occuring. valid options are 'home', 'profile', 'any'",
} }
*/
] ]
} }
} }