diff options
| author | tanaka takashi <isazaka@gmail.com> | 2026-07-04 14:54:45 +0900 |
|---|---|---|
| committer | tanaka takashi <isazaka@gmail.com> | 2026-07-04 14:54:45 +0900 |
| commit | 1efecaef1f867cb218366e2b4ab4b901fdd2835f (patch) | |
| tree | 3080a3d80a1a0671e8e82819d3f785465aace162 /src/mcp/tools/common | |
| parent | 34e00404e9561dcaf8d2d99df7470757a4fee915 (diff) | |
途中経過コミット
Diffstat (limited to 'src/mcp/tools/common')
| -rw-r--r-- | src/mcp/tools/common/common.c | 36 | ||||
| -rw-r--r-- | src/mcp/tools/common/common.h | 3 | ||||
| -rw-r--r-- | src/mcp/tools/common/context.c | 34 | ||||
| -rw-r--r-- | src/mcp/tools/common/context.h | 4 | ||||
| -rw-r--r-- | src/mcp/tools/common/history.c | 23 | ||||
| -rw-r--r-- | src/mcp/tools/common/history.h | 6 | ||||
| -rw-r--r-- | src/mcp/tools/common/memory_index.c | 219 | ||||
| -rw-r--r-- | src/mcp/tools/common/memory_index.h | 24 | ||||
| -rw-r--r-- | src/mcp/tools/common/registry.c | 5 | ||||
| -rw-r--r-- | src/mcp/tools/common/registry.h | 1 |
10 files changed, 352 insertions, 3 deletions
diff --git a/src/mcp/tools/common/common.c b/src/mcp/tools/common/common.c index d6669f8..62f507f 100644 --- a/src/mcp/tools/common/common.c +++ b/src/mcp/tools/common/common.c @@ -68,6 +68,10 @@ tiny_mcp_tool_append_message(tiny_json_buffer_t *json, const tiny_message_t *mes tiny_json_string(json, tiny_role_name(message->role)); tiny_json_raw(json, ",\"content\":"); tiny_json_string(json, message->content); + tiny_json_raw(json, ",\"revision\":"); + tiny_json_u64(json, message->revision); + tiny_json_raw(json, ",\"updated_at\":"); + tiny_json_i64(json, message->updated_at_ms); tiny_json_raw(json, ",\"metadata\":{"); if (message->metadata.tool_call_id) { @@ -86,6 +90,38 @@ tiny_mcp_tool_append_message(tiny_json_buffer_t *json, const tiny_message_t *mes } tiny_json_raw(json, "],\"memory_tier\":"); tiny_json_string(json, tiny_tier_name(message->metadata.memory_tier)); + tiny_json_raw(json, ",\"memory_kind\":"); + tiny_json_string(json, tiny_kind_name(message->metadata.memory_kind)); + tiny_json_raw(json, ",\"importance\":"); + tiny_json_u64(json, message->metadata.importance); + if (message->metadata.summary) + { + tiny_json_raw(json, ",\"summary\":"); + tiny_json_string(json, message->metadata.summary); + } + tiny_json_raw(json, ",\"relations\":["); + for (index = 0; index < message->metadata.relation_count; ++index) + { + if (index) + { + tiny_json_raw(json, ","); + } + tiny_json_raw(json, "{\"type\":"); + tiny_json_string(json, tiny_relation_type_name(message->metadata.relations[index].type)); + tiny_json_raw(json, ",\"message_id\":"); + tiny_json_string(json, message->metadata.relations[index].message_id); + tiny_json_raw(json, "}"); + } + tiny_json_raw(json, "],\"source_message_ids\":["); + for (index = 0; index < message->metadata.source_count; ++index) + { + if (index) + { + tiny_json_raw(json, ","); + } + tiny_json_string(json, message->metadata.source_message_ids[index]); + } + tiny_json_raw(json, "]"); tiny_json_raw(json, "}}"); } diff --git a/src/mcp/tools/common/common.h b/src/mcp/tools/common/common.h index 07caea1..741b2ce 100644 --- a/src/mcp/tools/common/common.h +++ b/src/mcp/tools/common/common.h @@ -3,12 +3,15 @@ #include "domain/message.h" #include "mcp/json.h" +#include "domain/message.h" #include <mcpc/mcpc.h> void tiny_mcp_tool_add_error(mcpc_ucbr_t *result, const char *code, const char *message); void tiny_mcp_tool_add_json(mcpc_ucbr_t *result, tiny_json_buffer_t *json); char *tiny_mcp_tool_get_string(const mcpc_tool_t *tool, const char *name, size_t maximum); void tiny_mcp_tool_append_message(tiny_json_buffer_t *json, const tiny_message_t *message); +bool +tiny_mcp_parse_metadata(const char *json, tiny_message_t *message, tiny_metadata_mask_t *present); mcpc_tool_t *tiny_mcp_tool_new(const char *name, const char *description, mcpc_tcallcb_t callback); bool tiny_mcp_tool_add_property(mcpc_tool_t *tool, diff --git a/src/mcp/tools/common/context.c b/src/mcp/tools/common/context.c index d79b5de..e833f70 100644 --- a/src/mcp/tools/common/context.c +++ b/src/mcp/tools/common/context.c @@ -43,10 +43,12 @@ tiny_mcp_tools_context_new(tiny_store_t *store) context->store = store; context->search_index = tiny_mcp_tools_build_search_index(store); context->history_index = tiny_history_index_build(store); - if (!context->search_index || !context->history_index) + context->memory_index = tiny_memory_index_build(store); + if (!context->search_index || !context->history_index || !context->memory_index) { tiny_search_index_free(context->search_index); tiny_history_index_free(context->history_index); + tiny_memory_index_free(context->memory_index); free(context); return NULL; } @@ -62,10 +64,40 @@ tiny_mcp_tools_context_free(tiny_mcp_tools_context_t *context) } tiny_search_index_free(context->search_index); tiny_history_index_free(context->history_index); + tiny_memory_index_free(context->memory_index); free(context); } bool +tiny_mcp_tools_ensure_memory_index(tiny_mcp_tools_context_t *context) +{ + if (!context) + { + return false; + } + if (!context->memory_index) + { + context->memory_index = tiny_memory_index_build(context->store); + } + return context->memory_index != NULL; +} + +void +tiny_mcp_tools_invalidate_indexes(tiny_mcp_tools_context_t *context) +{ + if (!context) + { + return; + } + tiny_search_index_free(context->search_index); + tiny_history_index_free(context->history_index); + tiny_memory_index_free(context->memory_index); + context->search_index = NULL; + context->history_index = NULL; + context->memory_index = NULL; +} + +bool tiny_mcp_tools_context_activate(tiny_mcp_tools_context_t *context) { if (!context || active_context) diff --git a/src/mcp/tools/common/context.h b/src/mcp/tools/common/context.h index 2a6650a..bd167f2 100644 --- a/src/mcp/tools/common/context.h +++ b/src/mcp/tools/common/context.h @@ -3,6 +3,7 @@ #include "domain/search.h" #include "mcp/tools/common/history.h" +#include "mcp/tools/common/memory_index.h" #include "storage/store.h" typedef struct tiny_mcp_tools_context @@ -10,6 +11,7 @@ typedef struct tiny_mcp_tools_context tiny_store_t *store; tiny_search_index_t *search_index; tiny_history_index_t *history_index; + tiny_memory_index_t *memory_index; } tiny_mcp_tools_context_t; tiny_mcp_tools_context_t *tiny_mcp_tools_context_new(tiny_store_t *store); @@ -19,5 +21,7 @@ void tiny_mcp_tools_context_deactivate(tiny_mcp_tools_context_t *context); tiny_mcp_tools_context_t *tiny_mcp_tools_context_current(void); tiny_search_index_t *tiny_mcp_tools_build_search_index(const tiny_store_t *store); bool tiny_mcp_tools_ensure_history_index(tiny_mcp_tools_context_t *context); +bool tiny_mcp_tools_ensure_memory_index(tiny_mcp_tools_context_t *context); +void tiny_mcp_tools_invalidate_indexes(tiny_mcp_tools_context_t *context); #endif diff --git a/src/mcp/tools/common/history.c b/src/mcp/tools/common/history.c index 6254d8c..9f08e84 100644 --- a/src/mcp/tools/common/history.c +++ b/src/mcp/tools/common/history.c @@ -284,3 +284,26 @@ tiny_history_index_session(const tiny_history_index_t *index, } return index && session_id; } + +size_t +tiny_history_index_session_count(const tiny_history_index_t *index) +{ + return index ? index->count : 0; +} + +bool +tiny_history_index_session_at(const tiny_history_index_t *index, + size_t position, + const char **session_id, + const size_t **entries, + size_t *count) +{ + if (!index || position >= index->count || !session_id || !entries || !count) + { + return false; + } + *session_id = index->buckets[position].session_id; + *entries = index->buckets[position].entries; + *count = index->buckets[position].count; + return true; +} diff --git a/src/mcp/tools/common/history.h b/src/mcp/tools/common/history.h index ac08d99..d6f5708 100644 --- a/src/mcp/tools/common/history.h +++ b/src/mcp/tools/common/history.h @@ -13,5 +13,11 @@ bool tiny_history_index_session(const tiny_history_index_t *index, const char *session_id, const size_t **entries, size_t *count); +size_t tiny_history_index_session_count(const tiny_history_index_t *index); +bool tiny_history_index_session_at(const tiny_history_index_t *index, + size_t position, + const char **session_id, + const size_t **entries, + size_t *count); #endif diff --git a/src/mcp/tools/common/memory_index.c b/src/mcp/tools/common/memory_index.c new file mode 100644 index 0000000..36e430b --- /dev/null +++ b/src/mcp/tools/common/memory_index.c @@ -0,0 +1,219 @@ +#include "mcp/tools/common/memory_index.h" + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "base/allocator.h" + +#define EMPTY_SLOT SIZE_MAX + +typedef struct memory_bucket +{ + uint64_t hash; + char message_id[TINY_MESSAGE_ID_LENGTH + 1]; + size_t entry_index; + tiny_relation_reference_t *incoming; + size_t incoming_count; + size_t incoming_capacity; +} memory_bucket_t; + +struct tiny_memory_index +{ + memory_bucket_t *buckets; + size_t count; + size_t *slots; + size_t slot_capacity; +}; + +static uint64_t +id_hash(const char *value) +{ + uint64_t hash = UINT64_C(1469598103934665603); + while (*value) + { + hash ^= (unsigned char)*value++; + hash *= UINT64_C(1099511628211); + } + return hash; +} + +static size_t +slot_start(uint64_t hash, size_t capacity) +{ + return (size_t)(hash ^ (hash >> 32)) & (capacity - 1); +} + +static memory_bucket_t * +find_bucket(const tiny_memory_index_t *index, const char *message_id) +{ + uint64_t hash; + size_t slot, bucket; + if (!index || !message_id || !index->slot_capacity) + { + return NULL; + } + hash = id_hash(message_id); + slot = slot_start(hash, index->slot_capacity); + while ((bucket = index->slots[slot]) != EMPTY_SLOT) + { + if (bucket >= index->count) + { + return NULL; + } + if (index->buckets[bucket].hash == hash + && strcmp(index->buckets[bucket].message_id, message_id) == 0) + { + return &index->buckets[bucket]; + } + slot = (slot + 1) & (index->slot_capacity - 1); + } + return NULL; +} + +static bool +add_incoming(memory_bucket_t *bucket, size_t source, tiny_relation_type_t type) +{ + tiny_relation_reference_t *resized; + size_t capacity; + if (bucket->incoming_count == bucket->incoming_capacity) + { + capacity = bucket->incoming_capacity ? bucket->incoming_capacity * 2 : 4; + if (capacity < bucket->incoming_capacity + || !(resized = realloc(bucket->incoming, capacity * sizeof(*resized)))) + { + return false; + } + bucket->incoming = resized; + bucket->incoming_capacity = capacity; + } + bucket->incoming[bucket->incoming_count].source_index = source; + bucket->incoming[bucket->incoming_count].type = type; + bucket->incoming_count++; + return true; +} + +tiny_memory_index_t * +tiny_memory_index_build(const tiny_store_t *store) +{ + tiny_memory_index_t *index; + size_t count = tiny_store_entry_count(store), capacity = 64, position; + if (!store || count > SIZE_MAX / sizeof(memory_bucket_t)) + { + return NULL; + } + while (count > (capacity / 10) * 7) + { + if (capacity > SIZE_MAX / 2) + { + return NULL; + } + capacity *= 2; + } + index = calloc(1, sizeof(*index)); + if (!index || (count && !(index->buckets = calloc(count, sizeof(*index->buckets)))) + || !(index->slots = malloc(capacity * sizeof(*index->slots)))) + { + tiny_memory_index_free(index); + return NULL; + } + index->count = count; + index->slot_capacity = capacity; + for (position = 0; position < capacity; ++position) + { + index->slots[position] = EMPTY_SLOT; + } + for (position = 0; position < count; ++position) + { + const tiny_store_entry_t *entry = tiny_store_entry(store, position); + memory_bucket_t *bucket = &index->buckets[position]; + size_t slot; + memcpy(bucket->message_id, entry->message.message_id, sizeof(bucket->message_id)); + bucket->hash = id_hash(bucket->message_id); + bucket->entry_index = position; + slot = slot_start(bucket->hash, capacity); + while (index->slots[slot] != EMPTY_SLOT) + { + slot = (slot + 1) & (capacity - 1); + } + index->slots[slot] = position; + } + for (position = 0; position < count; ++position) + { + const tiny_store_entry_t *entry = tiny_store_entry(store, position); + size_t relation; + if (entry->deleted) + { + continue; + } + for (relation = 0; relation < entry->message.metadata.relation_count; ++relation) + { + const tiny_relation_t *value = &entry->message.metadata.relations[relation]; + memory_bucket_t *target = find_bucket(index, value->message_id); + if (!target || !add_incoming(target, position, value->type)) + { + tiny_memory_index_free(index); + return NULL; + } + } + } + return index; +} + +void +tiny_memory_index_free(tiny_memory_index_t *index) +{ + size_t position; + if (!index) + { + return; + } + for (position = 0; position < index->count; ++position) + { + free(index->buckets[position].incoming); + } + free(index->buckets); + free(index->slots); + free(index); +} + +bool +tiny_memory_index_find(const tiny_memory_index_t *index, + const char *message_id, + size_t *entry_index) +{ + memory_bucket_t *bucket; + if (!entry_index) + { + return false; + } + *entry_index = 0; + bucket = find_bucket(index, message_id); + if (bucket) + { + *entry_index = bucket->entry_index; + } + return bucket != NULL; +} + +bool +tiny_memory_index_incoming(const tiny_memory_index_t *index, + const char *message_id, + const tiny_relation_reference_t **references, + size_t *count) +{ + memory_bucket_t *bucket; + if (!references || !count) + { + return false; + } + *references = NULL; + *count = 0; + bucket = find_bucket(index, message_id); + if (bucket) + { + *references = bucket->incoming; + *count = bucket->incoming_count; + } + return bucket != NULL; +} diff --git a/src/mcp/tools/common/memory_index.h b/src/mcp/tools/common/memory_index.h new file mode 100644 index 0000000..fbe43a7 --- /dev/null +++ b/src/mcp/tools/common/memory_index.h @@ -0,0 +1,24 @@ +#ifndef TINY_CONVMEM_MCP_TOOLS_MEMORY_INDEX_H +#define TINY_CONVMEM_MCP_TOOLS_MEMORY_INDEX_H + +#include "storage/store.h" + +typedef struct tiny_relation_reference +{ + size_t source_index; + tiny_relation_type_t type; +} tiny_relation_reference_t; + +typedef struct tiny_memory_index tiny_memory_index_t; + +tiny_memory_index_t *tiny_memory_index_build(const tiny_store_t *store); +void tiny_memory_index_free(tiny_memory_index_t *index); +bool tiny_memory_index_find(const tiny_memory_index_t *index, + const char *message_id, + size_t *entry_index); +bool tiny_memory_index_incoming(const tiny_memory_index_t *index, + const char *message_id, + const tiny_relation_reference_t **references, + size_t *count); + +#endif diff --git a/src/mcp/tools/common/registry.c b/src/mcp/tools/common/registry.c index 9aa1dff..1bdafc3 100644 --- a/src/mcp/tools/common/registry.c +++ b/src/mcp/tools/common/registry.c @@ -6,6 +6,7 @@ bool tiny_mcp_tools_register(mcpc_server_t *server) { return tiny_mcp_register_write_message(server) && tiny_mcp_register_read_messages(server) - && tiny_mcp_register_search_messages(server) && tiny_mcp_register_delete_message(server) - && tiny_mcp_register_rebuild_index(server) && tiny_mcp_register_get_system_health(server); + && tiny_mcp_register_search_messages(server) && tiny_mcp_register_update_message(server) + && tiny_mcp_register_delete_message(server) && tiny_mcp_register_rebuild_index(server) + && tiny_mcp_register_get_system_health(server); } diff --git a/src/mcp/tools/common/registry.h b/src/mcp/tools/common/registry.h index bbc68d0..451d300 100644 --- a/src/mcp/tools/common/registry.h +++ b/src/mcp/tools/common/registry.h @@ -4,6 +4,7 @@ #include <mcpc/mcpc.h> bool tiny_mcp_register_write_message(mcpc_server_t *server); +bool tiny_mcp_register_update_message(mcpc_server_t *server); bool tiny_mcp_register_read_messages(mcpc_server_t *server); bool tiny_mcp_register_search_messages(mcpc_server_t *server); bool tiny_mcp_register_delete_message(mcpc_server_t *server); |
