From 1efecaef1f867cb218366e2b4ab4b901fdd2835f Mon Sep 17 00:00:00 2001 From: tanaka takashi Date: Sat, 4 Jul 2026 14:54:45 +0900 Subject: 途中経過コミット MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mcp/tools/search_messages.c | 134 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 132 insertions(+), 2 deletions(-) (limited to 'src/mcp/tools/search_messages.c') diff --git a/src/mcp/tools/search_messages.c b/src/mcp/tools/search_messages.c index 44db1ef..4b7f870 100644 --- a/src/mcp/tools/search_messages.c +++ b/src/mcp/tools/search_messages.c @@ -13,8 +13,31 @@ typedef struct result_item { const tiny_store_entry_t *entry; double score; + double content_score; + double summary_score; + double tag_score; } result_item_t; +static double +score_component(const char *query, const tiny_message_t *message, int component) +{ + tiny_message_t candidate = *message; + candidate.metadata.tags = NULL; + candidate.metadata.tag_count = 0; + candidate.metadata.summary = NULL; + if (component == 1) + { + candidate.content = message->metadata.summary ? message->metadata.summary : ""; + } + else if (component == 2) + { + candidate.content = ""; + candidate.metadata.tags = message->metadata.tags; + candidate.metadata.tag_count = message->metadata.tag_count; + } + return tiny_search_score(query, &candidate); +} + static int compare_results(const void *left, const void *right) { @@ -28,6 +51,22 @@ compare_results(const void *left, const void *right) { return 1; } + if (a->entry->message.metadata.importance > b->entry->message.metadata.importance) + { + return -1; + } + if (a->entry->message.metadata.importance < b->entry->message.metadata.importance) + { + return 1; + } + if (a->entry->message.updated_at_ms > b->entry->message.updated_at_ms) + { + return -1; + } + if (a->entry->message.updated_at_ms < b->entry->message.updated_at_ms) + { + return 1; + } if (a->entry->message.timestamp_ms > b->entry->message.timestamp_ms) { return -1; @@ -45,15 +84,27 @@ call_search_messages(const mcpc_tool_t *tool, mcpc_ucbr_t *result) tiny_mcp_tools_context_t *context = tiny_mcp_tools_context_current(); char *query = tiny_mcp_tool_get_string(tool, "query", TINY_QUERY_MAX); char *session = tiny_mcp_tool_get_string(tool, "session_id", TINY_SESSION_ID_MAX); + char *kind_text = tiny_mcp_tool_get_string(tool, "memory_kind", 24); + char *tier_text = tiny_mcp_tool_get_string(tool, "memory_tier", 16); + char *tag = tiny_mcp_tool_get_string(tool, "tag", TINY_TAG_MAX); int32_t requested_limit = 20; + int32_t minimum_importance = 0; mcpc_errcode_t limit_status = mcpc_tool_get_tpropval_i32(tool, (const char8_t *)"limit", &requested_limit); + mcpc_errcode_t importance_status + = mcpc_tool_get_tpropval_i32(tool, (const char8_t *)"min_importance", &minimum_importance); + tiny_memory_kind_t kind = TINY_KIND_CONVERSATION; + tiny_memory_tier_t tier = TINY_TIER_SHORT; size_t limit, index, count = 0, candidate_count = 0, *candidates = NULL; result_item_t *items = NULL; tiny_json_buffer_t json; bool valid = context && query && query[0] && (limit_status == MCPC_EC_0 || limit_status == MCPC_EC_ANYDATA_NOTFOUND) && requested_limit >= 1 && requested_limit <= 100; + valid = valid && minimum_importance >= 0 && minimum_importance <= 100 + && (importance_status == MCPC_EC_0 || importance_status == MCPC_EC_ANYDATA_NOTFOUND) + && (!kind_text || tiny_kind_parse(kind_text, &kind)) + && (!tier_text || tiny_tier_parse(tier_text, &tier)); if (!valid) { tiny_mcp_tool_add_error(result, "VALIDATION_ERROR", "query or limit is invalid"); @@ -90,11 +141,37 @@ call_search_messages(const mcpc_tool_t *tool, mcpc_ucbr_t *result) { continue; } + if ((kind_text && entry->message.metadata.memory_kind != kind) + || (tier_text && entry->message.metadata.memory_tier != tier) + || entry->message.metadata.importance < minimum_importance) + { + continue; + } + if (tag) + { + size_t tag_index; + for (tag_index = 0; tag_index < entry->message.metadata.tag_count; + ++tag_index) + { + if (strcmp(tag, entry->message.metadata.tags[tag_index]) == 0) + { + break; + } + } + if (tag_index == entry->message.metadata.tag_count) + { + continue; + } + } score = tiny_search_score(query, &entry->message); if (score > 0) { items[count].entry = entry; - items[count++].score = score; + items[count].score = score; + items[count].content_score = score_component(query, &entry->message, 0); + items[count].summary_score = score_component(query, &entry->message, 1); + items[count].tag_score = score_component(query, &entry->message, 2); + count++; } } qsort(items, count, sizeof(*items), compare_results); @@ -110,7 +187,47 @@ call_search_messages(const mcpc_tool_t *tool, mcpc_ucbr_t *result) { tiny_json_raw(&json, ","); } - tiny_mcp_tool_append_message(&json, &items[index].entry->message); + { + tiny_json_buffer_t item; + tiny_json_init(&item); + tiny_mcp_tool_append_message(&item, &items[index].entry->message); + if (item.length > 0) + { + item.length--; + item.data[item.length] = '\0'; + } + tiny_json_raw(&item, ",\"score\":"); + tiny_json_number(&item, items[index].score); + tiny_json_raw(&item, ",\"score_breakdown\":{\"content\":"); + tiny_json_number(&item, items[index].content_score); + tiny_json_raw(&item, ",\"summary\":"); + tiny_json_number(&item, items[index].summary_score); + tiny_json_raw(&item, ",\"tags\":"); + tiny_json_number(&item, items[index].tag_score); + tiny_json_raw(&item, ",\"importance\":0},\"matched_fields\":["); + { + bool matched = false; + if (items[index].content_score > 0) + { + tiny_json_raw(&item, "\"content\""); + matched = true; + } + if (items[index].summary_score > 0) + { + tiny_json_raw(&item, matched ? ",\"summary\"" : "\"summary\""); + matched = true; + } + if (items[index].tag_score > 0) + { + tiny_json_raw(&item, matched ? ",\"tags\"" : "\"tags\""); + } + } + tiny_json_raw(&item, "],\"relation_count\":"); + tiny_json_u64(&item, items[index].entry->message.metadata.relation_count); + tiny_json_raw(&item, "}"); + tiny_json_raw_n(&json, item.data, item.length); + tiny_json_free(&item); + } } tiny_json_raw(&json, "]}"); tiny_mcp_tool_add_json(result, &json); @@ -122,6 +239,9 @@ call_search_messages(const mcpc_tool_t *tool, mcpc_ucbr_t *result) free(candidates); free(query); free(session); + free(kind_text); + free(tier_text); + free(tag); } bool @@ -145,6 +265,16 @@ tiny_mcp_register_search_messages(mcpc_server_t *server) "Conversation session to search; omit to search across all sessions.", MCPC_U8STR, false) + && tiny_mcp_tool_add_property( + tool, "memory_kind", "Optional exact memory kind filter.", MCPC_U8STR, false) + && tiny_mcp_tool_add_property( + tool, "memory_tier", "Optional exact memory tier filter.", MCPC_U8STR, false) + && tiny_mcp_tool_add_property(tool, "tag", "Optional exact tag filter.", MCPC_U8STR, false) + && tiny_mcp_tool_add_property(tool, + "min_importance", + "Minimum importance from 0 to 100; defaults to 0.", + MCPC_I32, + false) && tiny_mcp_tool_add_property( tool, "limit", -- cgit v1.2.3