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/write_message.c | 212 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 188 insertions(+), 24 deletions(-) (limited to 'src/mcp/tools/write_message.c') diff --git a/src/mcp/tools/write_message.c b/src/mcp/tools/write_message.c index 7df0058..3d7cb29 100644 --- a/src/mcp/tools/write_message.c +++ b/src/mcp/tools/write_message.c @@ -34,7 +34,9 @@ metadata_has_only_known_fields(const char *json, int length) } key[decoded] = '\0'; if (strcmp(key, "tool_call_id") != 0 && strcmp(key, "tags") != 0 - && strcmp(key, "memory_tier") != 0) + && strcmp(key, "memory_tier") != 0 && strcmp(key, "memory_kind") != 0 + && strcmp(key, "importance") != 0 && strcmp(key, "summary") != 0 + && strcmp(key, "relations") != 0 && strcmp(key, "source_message_ids") != 0) { return false; } @@ -42,14 +44,20 @@ metadata_has_only_known_fields(const char *json, int length) return true; } -static bool -parse_metadata(const char *json, tiny_message_t *message) +bool +tiny_mcp_parse_metadata(const char *json, tiny_message_t *message, tiny_metadata_mask_t *present) { - const char *tool_call = NULL, *tier = NULL, *tags = NULL; - int tool_call_len = 0, tier_len = 0, tags_len = 0; + const char *tool_call = NULL, *tier = NULL, *tags = NULL, *kind = NULL, *summary = NULL; + const char *relations = NULL, *sources = NULL; + int tool_call_len = 0, tier_len = 0, tags_len = 0, kind_len = 0, summary_len = 0; + int relations_len = 0, sources_len = 0; int offset = 0, key_offset, key_length, value_offset, value_length, value_type; int length = (int)strlen(json); int tool_call_type, tier_type, tags_type; + int kind_type, summary_type, importance_type; + int relations_type, sources_type; + double importance = 50; + tiny_metadata_mask_t fields = 0; if (strcmp(json, "{}") == 0) { return true; @@ -62,12 +70,176 @@ parse_metadata(const char *json, tiny_message_t *message) tool_call_type = mjson_find(json, length, "$.tool_call_id", &tool_call, &tool_call_len); tier_type = mjson_find(json, length, "$.memory_tier", &tier, &tier_len); tags_type = mjson_find(json, length, "$.tags", &tags, &tags_len); + kind_type = mjson_find(json, length, "$.memory_kind", &kind, &kind_len); + summary_type = mjson_find(json, length, "$.summary", &summary, &summary_len); + importance_type = mjson_find(json, length, "$.importance", NULL, NULL); + relations_type = mjson_find(json, length, "$.relations", &relations, &relations_len); + sources_type = mjson_find(json, length, "$.source_message_ids", &sources, &sources_len); if ((tool_call_type != MJSON_TOK_INVALID && tool_call_type != MJSON_TOK_STRING) || (tier_type != MJSON_TOK_INVALID && tier_type != MJSON_TOK_STRING) - || (tags_type != MJSON_TOK_INVALID && tags_type != MJSON_TOK_ARRAY)) + || (tags_type != MJSON_TOK_INVALID && tags_type != MJSON_TOK_ARRAY) + || (kind_type != MJSON_TOK_INVALID && kind_type != MJSON_TOK_STRING) + || (summary_type != MJSON_TOK_INVALID && summary_type != MJSON_TOK_STRING) + || (importance_type != MJSON_TOK_INVALID && importance_type != MJSON_TOK_NUMBER) + || (relations_type != MJSON_TOK_INVALID && relations_type != MJSON_TOK_ARRAY) + || (sources_type != MJSON_TOK_INVALID && sources_type != MJSON_TOK_ARRAY)) { return false; } + fields |= tool_call_type != MJSON_TOK_INVALID ? TINY_METADATA_TOOL_CALL_ID : 0; + fields |= tags_type != MJSON_TOK_INVALID ? TINY_METADATA_TAGS : 0; + fields |= tier_type != MJSON_TOK_INVALID ? TINY_METADATA_TIER : 0; + fields |= kind_type != MJSON_TOK_INVALID ? TINY_METADATA_KIND : 0; + fields |= importance_type != MJSON_TOK_INVALID ? TINY_METADATA_IMPORTANCE : 0; + fields |= summary_type != MJSON_TOK_INVALID ? TINY_METADATA_SUMMARY : 0; + fields |= relations_type != MJSON_TOK_INVALID ? TINY_METADATA_RELATIONS : 0; + fields |= sources_type != MJSON_TOK_INVALID ? TINY_METADATA_SOURCES : 0; + if (relations_type == MJSON_TOK_ARRAY) + { + offset = 0; + while ((offset = mjson_next(relations, + relations_len, + offset, + &key_offset, + &key_length, + &value_offset, + &value_length, + &value_type)) + != 0) + { + tiny_relation_t relation; + char type[24]; + int decoded_type, decoded_id; + tiny_relation_t *resized; + if (value_type != MJSON_TOK_OBJECT + || message->metadata.relation_count >= TINY_RELATION_COUNT_MAX) + { + return false; + } + decoded_type = mjson_get_string( + relations + value_offset, value_length, "$.type", type, sizeof(type)); + decoded_id = mjson_get_string(relations + value_offset, + value_length, + "$.message_id", + relation.message_id, + sizeof(relation.message_id)); + if (decoded_type <= 0 || decoded_type >= (int)sizeof(type) + || decoded_id != TINY_MESSAGE_ID_LENGTH) + { + return false; + } + type[decoded_type] = '\0'; + relation.message_id[decoded_id] = '\0'; + if (!tiny_relation_type_parse(type, &relation.type) + || !tiny_message_id_valid(relation.message_id)) + { + return false; + } + resized = realloc(message->metadata.relations, + (message->metadata.relation_count + 1) * sizeof(*resized)); + if (!resized) + { + return false; + } + message->metadata.relations = resized; + message->metadata.relations[message->metadata.relation_count++] = relation; + } + } + if (sources_type == MJSON_TOK_ARRAY) + { + offset = 0; + while ((offset = mjson_next(sources, + sources_len, + offset, + &key_offset, + &key_length, + &value_offset, + &value_length, + &value_type)) + != 0) + { + char *id; + char **resized; + int decoded; + if (value_type != MJSON_TOK_STRING + || message->metadata.source_count >= TINY_SOURCE_COUNT_MAX) + { + return false; + } + id = malloc(TINY_MESSAGE_ID_LENGTH + 1); + if (!id) + { + return false; + } + decoded = mjson_get_string( + sources + value_offset, value_length, "$", id, TINY_MESSAGE_ID_LENGTH + 1); + if (decoded != TINY_MESSAGE_ID_LENGTH) + { + free(id); + return false; + } + id[decoded] = '\0'; + if (!tiny_message_id_valid(id)) + { + free(id); + return false; + } + resized = realloc(message->metadata.source_message_ids, + (message->metadata.source_count + 1) * sizeof(*resized)); + if (!resized) + { + free(id); + return false; + } + message->metadata.source_message_ids = resized; + message->metadata.source_message_ids[message->metadata.source_count++] = id; + } + } + if (importance_type == MJSON_TOK_NUMBER + && mjson_get_number(json, length, "$.importance", &importance) > 0) + { + if (importance < 0 || importance > 100 || importance != (double)(uint8_t)importance) + { + return false; + } + message->metadata.importance = (uint8_t)importance; + } + if (kind_type == MJSON_TOK_STRING) + { + char value[24]; + int decoded = mjson_get_string(json, length, "$.memory_kind", value, sizeof(value)); + if (decoded <= 0 || decoded >= (int)sizeof(value)) + { + return false; + } + value[decoded] = '\0'; + if (!tiny_kind_parse(value, &message->metadata.memory_kind)) + { + return false; + } + } + if (summary_type == MJSON_TOK_STRING) + { + int decoded; + message->metadata.summary = malloc(TINY_SUMMARY_MAX + 1); + if (!message->metadata.summary) + { + return false; + } + decoded = mjson_get_string( + json, length, "$.summary", message->metadata.summary, TINY_SUMMARY_MAX + 1); + if (decoded < 0 || decoded > TINY_SUMMARY_MAX + || (decoded && !tiny_utf8_valid(message->metadata.summary, (size_t)decoded))) + { + return false; + } + message->metadata.summary[decoded] = '\0'; + if (decoded == 0) + { + free(message->metadata.summary); + message->metadata.summary = NULL; + } + } if (tool_call_type == MJSON_TOK_STRING) { int decoded; @@ -144,7 +316,11 @@ parse_metadata(const char *json, tiny_message_t *message) message->metadata.tags[message->metadata.tag_count++] = tag; } } - return true; + if (present) + { + *present = fields; + } + return tiny_metadata_valid(&message->metadata); } static void @@ -163,7 +339,7 @@ call_write_message(const mcpc_tool_t *tool, mcpc_ucbr_t *result) metadata = tiny_mcp_tool_get_string(tool, "metadata_json", TINY_CONTENT_MAX); bool valid = context && input.session_id && input.session_id[0] && role && input.content && input.content[0] && tiny_role_parse(role, &input.role) - && parse_metadata(metadata ? metadata : "{}", &input); + && tiny_mcp_parse_metadata(metadata ? metadata : "{}", &input, NULL); if (!valid) { tiny_mcp_tool_add_error(result, "VALIDATION_ERROR", "invalid write_message arguments"); @@ -178,21 +354,7 @@ call_write_message(const mcpc_tool_t *tool, mcpc_ucbr_t *result) } else { - if (context->search_index - && !tiny_search_index_add( - context->search_index, &written, tiny_store_entry_count(context->store) - 1)) - { - tiny_search_index_free(context->search_index); - context->search_index = NULL; - } - if (context->history_index - && !tiny_history_index_add(context->history_index, - context->store, - tiny_store_entry_count(context->store) - 1)) - { - tiny_history_index_free(context->history_index); - context->history_index = NULL; - } + tiny_mcp_tools_invalidate_indexes(context); tiny_json_init(&json); tiny_json_raw(&json, "{\"status\":\"OK\",\"message\":"); tiny_mcp_tool_append_message(&json, &written); @@ -225,7 +387,9 @@ tiny_mcp_register_write_message(mcpc_server_t *server) && tiny_mcp_tool_add_property(tool, "metadata_json", "Optional JSON object string containing tool_call_id, tags, " - "and/or memory_tier; defaults to {}.", + "memory_tier, memory_kind, importance, summary, relations, " + "and/or source_message_ids; " + "defaults to {}.", MCPC_U8STR, false) && mcpc_server_add_tool(server, tool) == MCPC_EC_0; -- cgit v1.2.3