Mercurial
view mrjunejune/conversation_store.h @ 265:056790c4fb0d
add role-aware Epi assistant prompts
Add verified June knowledge, guest/member/admin Copilot profiles, profile-isolated session recovery, animated Epi greetings, and a single authoritative runtime config workflow for inference.
Co-authored-by: Copilot <[email protected]>
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Fri, 07 Aug 2026 10:50:30 -0700 |
| parents | 04fee26ecce0 |
| children |
line wrap: on
line source
#ifndef MRJUNEJUNE_CONVERSATION_STORE_H #define MRJUNEJUNE_CONVERSATION_STORE_H #include "dowa/dowa.h" typedef struct Conversation_Store Conversation_Store; typedef enum { CONVERSATION_STORE_ERROR = -1, CONVERSATION_STORE_OK = 0, CONVERSATION_STORE_NOT_FOUND = 1, CONVERSATION_STORE_CONFLICT = 2, } Conversation_Store_Result; /* ------------------------------------------------------------------ */ /* Ownership types */ /* ------------------------------------------------------------------ */ typedef enum { CONVERSATION_OWNER_KIND_USER = 0, CONVERSATION_OWNER_KIND_GUEST = 1, CONVERSATION_OWNER_KIND_LEGACY = 2, } Conversation_Owner_Kind; /* * Owner identity for a conversation. * kind=USER/GUEST: id holds user_id or guest_id (UUID, 36 chars). * kind=LEGACY: id is empty; owned by no one. */ typedef struct { Conversation_Owner_Kind kind; char id[37]; /* user_id or guest_id; empty string for legacy */ } Conversation_Owner; /* * Lightweight summary returned by the listing endpoint. * All string pointers are arena-allocated. * last_message_preview is truncated to 200 chars (UTF-8 may split mid-char; * callers must not rely on it being valid UTF-8 at the boundary). */ typedef struct { char *id; char *title; char *status; int64 created_at; int64 updated_at; int64 turn_count; char *last_message_preview; /* at most 200 bytes + NUL */ } Conversation_Summary; /* ------------------------------------------------------------------ */ /* Turn and record types */ /* ------------------------------------------------------------------ */ typedef struct { int64 id; int64 sequence; char *role; char *content; char *status; char *request_id; char *error_message; int64 input_tokens; int64 output_tokens; int64 created_at; int64 completed_at; } Conversation_Turn; typedef struct { char *id; char *copilot_session_id; char *title; char *status; int64 created_at; int64 updated_at; Conversation_Turn *turns; } Conversation_Record; /* ------------------------------------------------------------------ */ /* Lifecycle */ /* ------------------------------------------------------------------ */ Conversation_Store *Conversation_Store_Create(const char *database_path); void Conversation_Store_Destroy(Conversation_Store *p_store); boolean Conversation_Store_Generate_UUID(char output[37]); /* ------------------------------------------------------------------ */ /* Owner-aware APIs (production HTTP handlers must use these) */ /* ------------------------------------------------------------------ */ /* * Create a conversation assigned to p_owner. * p_owner->kind must be USER or GUEST; LEGACY is rejected. */ Conversation_Store_Result Conversation_Store_Create_Owned( Conversation_Store *p_store, const char *title, const Conversation_Owner *p_owner, char output_id[37]); /* * Get a conversation; returns NOT_FOUND if the conversation does not belong * to p_owner (existence leaks prevented). */ Conversation_Store_Result Conversation_Store_Get_Owned( Conversation_Store *p_store, const char *conversation_id, const Conversation_Owner *p_owner, Conversation_Record *p_record, Dowa_Arena *p_arena); Conversation_Store_Result Conversation_Store_Update_Title_Owned( Conversation_Store *p_store, const char *conversation_id, const Conversation_Owner *p_owner, const char *title); Conversation_Store_Result Conversation_Store_Delete_Owned( Conversation_Store *p_store, const char *conversation_id, const Conversation_Owner *p_owner); Conversation_Store_Result Conversation_Store_Begin_Turn_Owned( Conversation_Store *p_store, const char *conversation_id, const Conversation_Owner *p_owner, const char *request_id, const char *prompt); /* * List conversations for an owner, ordered newest-first. * Legacy conversations are never listed (returns empty list for LEGACY owner). * * cursor_updated_at / cursor_id: pass 0 / NULL for the first page. * limit: capped to 50 internally; must be >= 1. * * *pp_summaries is arena-allocated; *p_count is the number of items. * A cursor for the next page (if *p_count == limit) can be derived from * (*pp_summaries)[*p_count - 1].{updated_at, id}. */ Conversation_Store_Result Conversation_Store_List( Conversation_Store *p_store, const Conversation_Owner *p_owner, int64 cursor_updated_at, const char *cursor_id, int32 limit, Conversation_Summary **pp_summaries, int32 *p_count, Dowa_Arena *p_arena); /* * Claim a legacy conversation: reassign it to user_id. * Returns NOT_FOUND if the conversation is not a legacy row (or does not * exist), preventing existence leaks. * Returns CONFLICT if the conversation is already owned by someone else. */ Conversation_Store_Result Conversation_Store_Claim_Legacy( Conversation_Store *p_store, const char *conversation_id, const char *user_id); /* * Atomically transfer all guest conversations to a user. * Idempotent: re-running with the same (guest_id, user_id) pair is safe. * Returns CONVERSATION_STORE_OK on success (including the no-op case). */ Conversation_Store_Result Conversation_Store_Transfer_Guest_To_User( Conversation_Store *p_store, const char *guest_id, const char *user_id); /* * Like Conversation_Store_Transfer_Guest_To_User but also clears outstanding * guest quota reservations atomically in the same transaction. * Use this on login: both the conversation transfer and quota cleanup commit * or roll back together. The quota tables must reside in the same SQLite * database file as the conversation tables (the shared mrjunejune.db). */ Conversation_Store_Result Conversation_Store_Transfer_Guest_To_User_Atomic( Conversation_Store *p_store, const char *guest_id, const char *user_id); /* ------------------------------------------------------------------ */ /* Legacy/internal APIs (kept only for migration-compatibility tests) */ /* Production HTTP handlers must not use these. */ /* ------------------------------------------------------------------ */ Conversation_Store_Result Conversation_Store_Create_Conversation( Conversation_Store *p_store, const char *title, char output_id[37]); Conversation_Store_Result Conversation_Store_Get( Conversation_Store *p_store, const char *conversation_id, Conversation_Record *p_record, Dowa_Arena *p_arena); Conversation_Store_Result Conversation_Store_Update_Title( Conversation_Store *p_store, const char *conversation_id, const char *title); Conversation_Store_Result Conversation_Store_Delete( Conversation_Store *p_store, const char *conversation_id); Conversation_Store_Result Conversation_Store_Begin_Turn( Conversation_Store *p_store, const char *conversation_id, const char *request_id, const char *prompt); Conversation_Store_Result Conversation_Store_Complete_Turn( Conversation_Store *p_store, const char *conversation_id, const char *request_id, const char *content, int64 input_tokens, int64 output_tokens); Conversation_Store_Result Conversation_Store_Fail_Turn( Conversation_Store *p_store, const char *conversation_id, const char *request_id, const char *error_message, boolean aborted); #endif