Files
sovereign_browser/src/agent_conversations.h
T

145 lines
5.0 KiB
C

/*
* agent_conversations.h — Nostr conversation persistence for agent chat
*
* Saves and loads agent chat conversations as NIP-78 (kind 30078) addressable
* events. Each conversation is stored with:
* d-tag: "{uuid}" (no prefix — matches ai.html so conversations are
* shared between sovereign_browser and the client)
* t-tag: "client-ai-chat-v1"
*
* The event content is NIP-44 encrypted (self-to-self) JSON:
* { "schema": 1, "title": "...", "messages": [ {role, content, tool_calls, tool_call_id}, ... ] }
*
* Reuses the NIP-44 encryption + event signing + relay publishing patterns
* from settings_sync.c and bookmarks.c.
*
* See plans/cross-project-agent-sync.md (Workstream 3) for the full design.
*/
#ifndef AGENT_CONVERSATIONS_H
#define AGENT_CONVERSATIONS_H
#include <glib.h>
/* cJSON is in the vendored nostr_core_lib */
#include "../nostr_core_lib/cjson/cJSON.h"
/* nostr_signer_t is needed for init */
#include "nostr_core/nostr_signer.h"
#ifdef __cplusplus
extern "C" {
#endif
/* The Nostr kind for arbitrary custom app data (NIP-78). */
#define AGENT_CONV_KIND 30078
/* The t-tag that identifies these conversation events. Matches ai.html
* so conversations are shared between sovereign_browser and the client. */
#define AGENT_CONV_T_TAG "client-ai-chat-v1"
/* The prefix for the d-tag. Empty — the d-tag is just the UUID, matching
* ai.html's d:{conversation-id} format. Kept as a macro for compatibility
* with build_d_tag()/d_tag_to_id(). */
#define AGENT_CONV_D_PREFIX ""
/*
* Initialize the conversation persistence module. Stores the signer + pubkey
* references for save/load/delete operations.
*
* signer — the user's nostr_signer_t (NULL for read-only/no-login)
* pubkey_hex — the user's hex pubkey (64 chars, may be NULL)
*
* Call after login.
*/
void agent_conversations_init(nostr_signer_t *signer,
const char *pubkey_hex);
/*
* Update the signer reference (e.g. after switching identity).
*/
void agent_conversations_set_signer(nostr_signer_t *signer,
const char *pubkey_hex);
/*
* List all saved conversations from the local SQLite cache.
*
* Queries kind 30078 events by the user's pubkey that have the
* t-tag "client-ai-chat-v1". Extracts the conversation id
* (from the d-tag, which is just the UUID), title (from the
* decrypted content), and updated_at (from created_at).
*
* Returns a newly allocated cJSON array of summary objects:
* [{"id":"...", "title":"...", "updated_at":N}, ...]
* Returns an empty array on error or if no conversations exist.
* Caller must cJSON_Delete() the result.
*/
cJSON *agent_conversations_list(void);
/*
* Save the current agent chat session to Nostr as a kind 30078 event.
*
* conversation_id — the conversation id (UUID). If NULL, a new UUID is
* generated and the d-tag becomes just "{uuid}"
* (no prefix, matching ai.html).
* title — the conversation title. If NULL, derived from the
* first user message (truncated to 60 chars).
*
* Fetches the current session's messages via agent_chat_store, NIP-44
* encrypts them, builds a kind 30078 event with the d-tag and t-tag,
* signs it, publishes to bootstrap relays, and stores in SQLite.
*
* Returns a newly allocated string with the conversation id (caller must
* g_free), or NULL on error.
*/
char *agent_conversations_save(const char *conversation_id,
const char *title);
/*
* Load a conversation from Nostr (local SQLite cache) into the agent chat
* store as the current session.
*
* conversation_id — the conversation id (the UUID used as the d-tag).
*
* Fetches the kind 30078 event with d-tag "{id}", NIP-44 decrypts
* the content, parses the messages, creates a new agent chat session,
* and populates it with the parsed messages.
*
* Returns 0 on success, -1 on error.
*/
int agent_conversations_load(const char *conversation_id);
/*
* Rename a conversation — update its title in the local SQLite cache
* and re-publish the kind 30078 event with the new title.
*
* conversation_id — the conversation id (the UUID used as the d-tag).
* new_title — the new title (must be non-NULL and non-empty).
*
* Loads the existing event, decrypts the content, replaces the title,
* re-encrypts, signs a new kind 30078 event with the same d-tag, stores
* it in SQLite, and publishes to bootstrap relays.
*
* Returns 0 on success, -1 on error.
*/
int agent_conversations_rename(const char *conversation_id,
const char *new_title);
/*
* Delete a conversation from Nostr.
*
* conversation_id — the conversation id (the UUID used as the d-tag).
*
* Publishes a kind 5 deletion event referencing the kind 30078 event id,
* and removes the event from the local SQLite cache.
*
* Returns 0 on success, -1 on error.
*/
int agent_conversations_delete(const char *conversation_id);
#ifdef __cplusplus
}
#endif
#endif /* AGENT_CONVERSATIONS_H */