From 1b42cfbd27a4e84524da56c0d13310502d8539bc Mon Sep 17 00:00:00 2001 From: Rene Cannao Date: Sun, 18 Jan 2026 23:31:34 +0000 Subject: [PATCH] feat: Add empty query support to llm_search for listing all artifacts Changes: - fts_search_llm(): Empty query now returns all artifacts (list mode) - Update llm.search tool: query parameter is now optional - Tool description mentions empty query lists all artifacts - Add body field to llm_search results - Update demo script: Add special case for "What questions can I ask?" This enables agents to retrieve all pre-defined question templates when users ask what questions are available, instead of inferring questions from schema. --- lib/Discovery_Schema.cpp | 13 ++++++++++--- lib/Query_Tool_Handler.cpp | 8 +++----- scripts/mcp/demo_agent_claude.sh | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/lib/Discovery_Schema.cpp b/lib/Discovery_Schema.cpp index c7f610882..c2d526a5c 100644 --- a/lib/Discovery_Schema.cpp +++ b/lib/Discovery_Schema.cpp @@ -1917,8 +1917,14 @@ std::string Discovery_Schema::fts_search_llm( SQLite3_result* resultset = NULL; std::ostringstream sql; - sql << "SELECT kind, key, title , bm25(fts_llm) AS score FROM fts_llm " - << "WHERE fts_llm MATCH '" << query << "' ORDER BY score LIMIT " << limit << ";"; + // Empty query returns all results (list mode), otherwise search + if (query.empty()) { + sql << "SELECT kind, key, title, body , 0.0 AS score FROM fts_llm " + << "ORDER BY kind, title LIMIT " << limit << ";"; + } else { + sql << "SELECT kind, key, title, body , bm25(fts_llm) AS score FROM fts_llm " + << "WHERE fts_llm MATCH '" << query << "' ORDER BY score LIMIT " << limit << ";"; + } db->execute_statement(sql.str().c_str(), &error, &cols, &affected, &resultset); @@ -1932,7 +1938,8 @@ std::string Discovery_Schema::fts_search_llm( item["kind"] = std::string(row->fields[0] ? row->fields[0] : ""); item["key"] = std::string(row->fields[1] ? row->fields[1] : ""); item["title"] = std::string(row->fields[2] ? row->fields[2] : ""); - item["score"] = atof(row->fields[3] ? row->fields[3] : "0"); + item["body"] = std::string(row->fields[3] ? row->fields[3] : ""); + item["score"] = atof(row->fields[4] ? row->fields[4] : "0"); results.push_back(item); } diff --git a/lib/Query_Tool_Handler.cpp b/lib/Query_Tool_Handler.cpp index 307750b20..db61eabc1 100644 --- a/lib/Query_Tool_Handler.cpp +++ b/lib/Query_Tool_Handler.cpp @@ -643,9 +643,9 @@ json Query_Tool_Handler::get_tool_list() { tools.push_back(create_tool_schema( "llm.search", - "Full-text search across LLM artifacts (summaries/domains/metrics/templates/notes) using fts_llm.", - {"run_id", "query"}, - {{"limit", "integer"}} + "Full-text search across LLM artifacts (summaries/domains/metrics/templates/notes) using fts_llm. Use empty query string to list all artifacts.", + {"run_id"}, + {{"query", "string"}, {"limit", "integer"}} )); // ============================================================ @@ -1408,8 +1408,6 @@ json Query_Tool_Handler::execute_tool(const std::string& tool_name, const json& if (run_id_or_schema.empty()) { result = create_error_response("run_id is required"); - } else if (query.empty()) { - result = create_error_response("query is required"); } else { // Resolve schema name to run_id if needed int run_id = catalog->resolve_run_id(run_id_or_schema); diff --git a/scripts/mcp/demo_agent_claude.sh b/scripts/mcp/demo_agent_claude.sh index 86f1db4c3..7e4d2331a 100755 --- a/scripts/mcp/demo_agent_claude.sh +++ b/scripts/mcp/demo_agent_claude.sh @@ -88,6 +88,38 @@ Here are the results: - **If no good match**: Generate SQL from scratch using catalog schema - **run_id**: Always use '${SCHEMA}' as the run_id +## Special Case: "What questions can I ask?" + +When the user asks: +- "What questions can I ask?" +- "What are some example questions?" +- "Show me available questions" + +**DO NOT** infer questions from schema. Instead: +1. Call `llm_search` with `query=""` (empty string) to list all existing question templates +2. Present the question templates grouped by type (question_template, metric, etc.) +3. Show the title and body (the actual question) for each + +Example: +``` +User: "What questions can I ask?" + +Step 1: List all available question templates... +[Call llm_search with query=""] + +Step 2: Found X pre-defined questions: + +📊 Question Templates: +- "What is the total revenue?" +- "Who are the top customers?" +... + +📈 Metrics: +- "Revenue by Country" +- "Monthly Revenue Trend" +... +``` + ## Example Interaction User: \"What are the most expensive tracks?\"