summaryrefslogtreecommitdiff
path: root/src/domain/message.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/domain/message.c')
-rw-r--r--src/domain/message.c176
1 files changed, 174 insertions, 2 deletions
diff --git a/src/domain/message.c b/src/domain/message.c
index b1db3e1..ec019c4 100644
--- a/src/domain/message.c
+++ b/src/domain/message.c
@@ -33,6 +33,9 @@ tiny_message_init(tiny_message_t *message)
}
memset(message, 0, sizeof(*message));
message->metadata.memory_tier = TINY_TIER_SHORT;
+ message->metadata.memory_kind = TINY_KIND_CONVERSATION;
+ message->metadata.importance = 50;
+ message->revision = 1;
}
void
@@ -46,11 +49,18 @@ tiny_message_free(tiny_message_t *message)
free(message->session_id);
free(message->content);
free(message->metadata.tool_call_id);
+ free(message->metadata.summary);
for (index = 0; index < message->metadata.tag_count; ++index)
{
free(message->metadata.tags[index]);
}
free(message->metadata.tags);
+ free(message->metadata.relations);
+ for (index = 0; index < message->metadata.source_count; ++index)
+ {
+ free(message->metadata.source_message_ids[index]);
+ }
+ free(message->metadata.source_message_ids);
tiny_message_init(message);
}
@@ -59,8 +69,7 @@ tiny_message_copy(tiny_message_t *destination, const tiny_message_t *source)
{
size_t index;
if (destination == NULL || source == NULL || destination == source || source->session_id == NULL
- || source->content == NULL
- || (source->metadata.tag_count != 0 && source->metadata.tags == NULL))
+ || source->content == NULL || !tiny_metadata_valid(&source->metadata))
{
return -1;
}
@@ -69,12 +78,56 @@ tiny_message_copy(tiny_message_t *destination, const tiny_message_t *source)
destination->timestamp_ms = source->timestamp_ms;
destination->role = source->role;
destination->metadata.memory_tier = source->metadata.memory_tier;
+ destination->metadata.memory_kind = source->metadata.memory_kind;
+ destination->metadata.importance = source->metadata.importance;
+ destination->revision = source->revision;
+ destination->updated_at_ms = source->updated_at_ms;
destination->session_id = duplicate_string(source->session_id);
destination->content = duplicate_string(source->content);
if (destination->session_id == NULL || destination->content == NULL)
{
return copy_failed(destination);
}
+ if (source->metadata.summary != NULL)
+ {
+ destination->metadata.summary = duplicate_string(source->metadata.summary);
+ if (destination->metadata.summary == NULL)
+ {
+ return copy_failed(destination);
+ }
+ }
+ if (source->metadata.relation_count > 0)
+ {
+ destination->metadata.relations
+ = malloc(source->metadata.relation_count * sizeof(*destination->metadata.relations));
+ if (destination->metadata.relations == NULL)
+ {
+ return copy_failed(destination);
+ }
+ memcpy(destination->metadata.relations,
+ source->metadata.relations,
+ source->metadata.relation_count * sizeof(*destination->metadata.relations));
+ destination->metadata.relation_count = source->metadata.relation_count;
+ }
+ if (source->metadata.source_count > 0)
+ {
+ destination->metadata.source_message_ids
+ = calloc(source->metadata.source_count, sizeof(char *));
+ if (destination->metadata.source_message_ids == NULL)
+ {
+ return copy_failed(destination);
+ }
+ for (index = 0; index < source->metadata.source_count; ++index)
+ {
+ destination->metadata.source_message_ids[index]
+ = duplicate_string(source->metadata.source_message_ids[index]);
+ if (destination->metadata.source_message_ids[index] == NULL)
+ {
+ return copy_failed(destination);
+ }
+ destination->metadata.source_count++;
+ }
+ }
if (source->metadata.tool_call_id != NULL)
{
destination->metadata.tool_call_id = duplicate_string(source->metadata.tool_call_id);
@@ -103,6 +156,70 @@ tiny_message_copy(tiny_message_t *destination, const tiny_message_t *source)
return 0;
}
+bool
+tiny_metadata_valid(const tiny_metadata_t *metadata)
+{
+ size_t index, other;
+ if (!metadata || metadata->memory_tier < TINY_TIER_SHORT
+ || metadata->memory_tier > TINY_TIER_DISCARD || metadata->memory_kind < TINY_KIND_CONVERSATION
+ || metadata->memory_kind > TINY_KIND_SUMMARY || metadata->importance > 100
+ || metadata->tag_count > TINY_TAG_COUNT_MAX || (metadata->tag_count && !metadata->tags)
+ || metadata->relation_count > TINY_RELATION_COUNT_MAX
+ || (metadata->relation_count && !metadata->relations)
+ || metadata->source_count > TINY_SOURCE_COUNT_MAX
+ || (metadata->source_count && !metadata->source_message_ids))
+ {
+ return false;
+ }
+ if (metadata->summary
+ && (strlen(metadata->summary) > TINY_SUMMARY_MAX
+ || !tiny_utf8_valid(metadata->summary, strlen(metadata->summary))))
+ {
+ return false;
+ }
+ for (index = 0; index < metadata->tag_count; ++index)
+ {
+ if (!metadata->tags[index] || !metadata->tags[index][0]
+ || strlen(metadata->tags[index]) > TINY_TAG_MAX)
+ {
+ return false;
+ }
+ }
+ for (index = 0; index < metadata->relation_count; ++index)
+ {
+ const tiny_relation_t *relation = &metadata->relations[index];
+ if (relation->type < TINY_RELATION_DEPENDS_ON || relation->type > TINY_RELATION_RELATED_TO
+ || !tiny_message_id_valid(relation->message_id))
+ {
+ return false;
+ }
+ for (other = 0; other < index; ++other)
+ {
+ if (relation->type == metadata->relations[other].type
+ && strcmp(relation->message_id, metadata->relations[other].message_id) == 0)
+ {
+ return false;
+ }
+ }
+ }
+ for (index = 0; index < metadata->source_count; ++index)
+ {
+ if (!metadata->source_message_ids[index]
+ || !tiny_message_id_valid(metadata->source_message_ids[index]))
+ {
+ return false;
+ }
+ for (other = 0; other < index; ++other)
+ {
+ if (strcmp(metadata->source_message_ids[index], metadata->source_message_ids[other]) == 0)
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
const char *
tiny_role_name(tiny_role_t role)
{
@@ -193,6 +310,61 @@ tiny_tier_parse(const char *value, tiny_memory_tier_t *tier)
return true;
}
+const char *
+tiny_kind_name(tiny_memory_kind_t kind)
+{
+ static const char *names[]
+ = { "unknown", "conversation", "episode", "semantic", "procedure", "preference", "summary" };
+ return kind >= TINY_KIND_CONVERSATION && kind <= TINY_KIND_SUMMARY ? names[kind] : names[0];
+}
+
+bool
+tiny_kind_parse(const char *value, tiny_memory_kind_t *kind)
+{
+ tiny_memory_kind_t candidate;
+ if (value == NULL || kind == NULL)
+ {
+ return false;
+ }
+ for (candidate = TINY_KIND_CONVERSATION; candidate <= TINY_KIND_SUMMARY; ++candidate)
+ {
+ if (strcmp(value, tiny_kind_name(candidate)) == 0)
+ {
+ *kind = candidate;
+ return true;
+ }
+ }
+ return false;
+}
+
+const char *
+tiny_relation_type_name(tiny_relation_type_t type)
+{
+ static const char *names[]
+ = { "unknown", "depends_on", "derived_from", "supersedes", "related_to" };
+ return type >= TINY_RELATION_DEPENDS_ON && type <= TINY_RELATION_RELATED_TO ? names[type]
+ : names[0];
+}
+
+bool
+tiny_relation_type_parse(const char *value, tiny_relation_type_t *type)
+{
+ tiny_relation_type_t candidate;
+ if (value == NULL || type == NULL)
+ {
+ return false;
+ }
+ for (candidate = TINY_RELATION_DEPENDS_ON; candidate <= TINY_RELATION_RELATED_TO; ++candidate)
+ {
+ if (strcmp(value, tiny_relation_type_name(candidate)) == 0)
+ {
+ *type = candidate;
+ return true;
+ }
+ }
+ return false;
+}
+
bool
tiny_utf8_valid(const char *value, size_t length)
{