diff mrjunejune/inference_bridge.c @ 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 b401627fc49e
children
line wrap: on
line diff
--- a/mrjunejune/inference_bridge.c	Fri Aug 07 07:34:12 2026 -0700
+++ b/mrjunejune/inference_bridge.c	Fri Aug 07 10:50:30 2026 -0700
@@ -187,19 +187,38 @@
   return success;
 }
 
+static const char *Inference_Bridge_Profile_Name(
+    Inference_Prompt_Profile profile)
+{
+  switch (profile)
+  {
+    case INFERENCE_PROMPT_PROFILE_PUBLIC_VISITOR:
+      return "public_visitor";
+    case INFERENCE_PROMPT_PROFILE_INVITED_FRIEND:
+      return "invited_friend";
+    case INFERENCE_PROMPT_PROFILE_JUNE_ADMIN:
+      return "june_admin";
+  }
+  return NULL;
+}
+
 static boolean Inference_Bridge_Command(
     Inference_Bridge *p_bridge,
     const char *command,
     const char *request_id,
     const char *conversation_id,
-    const char *prompt)
+    const char *prompt,
+    const char *prompt_profile,
+    uint32 prompt_version,
+    uint32 knowledge_version)
 {
   if (!command || !request_id)
     return FALSE;
   size_t input_length =
       strlen(command) + strlen(request_id) +
       strlen(conversation_id ? conversation_id : "") +
-      strlen(prompt ? prompt : "");
+      strlen(prompt ? prompt : "") +
+      strlen(prompt_profile ? prompt_profile : "");
   if (input_length > (((size_t)-1) - 4096) / 12)
     return FALSE;
   Dowa_Arena *p_arena = Dowa_Arena_Create(input_length * 12 + 4096);
@@ -212,8 +231,12 @@
   char *escaped_prompt = prompt
       ? Dowa_JSON_Escape_String(prompt, 0, p_arena)
       : NULL;
+  char *escaped_profile = prompt_profile
+      ? Dowa_JSON_Escape_String(prompt_profile, 0, p_arena)
+      : NULL;
   if (!escaped_command || !escaped_request || !escaped_conversation ||
-      (prompt && !escaped_prompt))
+      (prompt && !escaped_prompt) ||
+      (prompt_profile && !escaped_profile))
   {
     Dowa_Arena_Free(p_arena);
     return FALSE;
@@ -221,24 +244,30 @@
   size_t capacity =
       strlen(escaped_command) + strlen(escaped_request) +
       strlen(escaped_conversation) +
-      (escaped_prompt ? strlen(escaped_prompt) : 0) + 160;
+      (escaped_prompt ? strlen(escaped_prompt) : 0) +
+      (escaped_profile ? strlen(escaped_profile) : 0) + 256;
   char *payload = Dowa_Arena_Allocate(p_arena, capacity);
   if (!payload)
   {
     Dowa_Arena_Free(p_arena);
     return FALSE;
   }
-  if (escaped_prompt)
+  if (escaped_prompt && escaped_profile)
   {
     snprintf(
         payload,
         capacity,
         "{\"command\":\"%s\",\"request_id\":\"%s\","
-        "\"conversation_id\":\"%s\",\"prompt\":\"%s\"}",
+        "\"conversation_id\":\"%s\",\"prompt\":\"%s\","
+        "\"prompt_profile\":\"%s\",\"prompt_version\":%u,"
+        "\"knowledge_version\":%u}",
         escaped_command,
         escaped_request,
         escaped_conversation,
-        escaped_prompt);
+        escaped_prompt,
+        escaped_profile,
+        prompt_version,
+        knowledge_version);
   }
   else
   {
@@ -304,7 +333,7 @@
     return;
   if (atomic_load(&p_bridge->running) && p_bridge->p_commands)
     Inference_Bridge_Command(
-        p_bridge, "shutdown", "server-shutdown", "", NULL);
+        p_bridge, "shutdown", "server-shutdown", "", NULL, NULL, 0, 0);
   if (p_bridge->p_commands)
   {
     fclose(p_bridge->p_commands);
@@ -465,10 +494,152 @@
     Inference_Bridge *p_bridge,
     const char *request_id,
     const char *conversation_id,
-    const char *prompt)
+    const char *prompt,
+    Inference_Prompt_Profile prompt_profile,
+    uint32 prompt_version,
+    uint32 knowledge_version,
+    const Inference_Bridge_History_Message *p_history,
+    uint32 history_count)
 {
-  return Inference_Bridge_Command(
-      p_bridge, "turn.start", request_id, conversation_id, prompt);
+  const char *profile_name = Inference_Bridge_Profile_Name(prompt_profile);
+  if (!profile_name || prompt_version == 0 || knowledge_version == 0)
+    return FALSE;
+  if (history_count > INFERENCE_BRIDGE_HISTORY_MAX)
+    return FALSE;
+  /* Validate every history entry before touching the wire. */
+  for (uint32 i = 0; i < history_count; i++)
+  {
+    const Inference_Bridge_History_Message *m = &p_history[i];
+    if (!m->role || !m->content)
+      return FALSE;
+    if (strcmp(m->role, "user") != 0 && strcmp(m->role, "assistant") != 0)
+      return FALSE;
+  }
+
+  if (!request_id)
+    return FALSE;
+
+  /* Compute raw byte total to size the arena (12x expansion factor). */
+  size_t input_length =
+      strlen("turn.start") + strlen(request_id) +
+      strlen(conversation_id ? conversation_id : "") +
+      strlen(prompt ? prompt : "") +
+      strlen(profile_name);
+  for (uint32 i = 0; i < history_count; i++)
+  {
+    input_length += strlen(p_history[i].role) + strlen(p_history[i].content);
+  }
+  if (input_length > (((size_t)-1) - 4096) / 12)
+    return FALSE;
+
+  Dowa_Arena *p_arena = Dowa_Arena_Create(input_length * 12 + 4096);
+  if (!p_arena)
+    return FALSE;
+
+  char *escaped_command = Dowa_JSON_Escape_String("turn.start", 0, p_arena);
+  char *escaped_request = Dowa_JSON_Escape_String(request_id, 0, p_arena);
+  char *escaped_conversation = Dowa_JSON_Escape_String(
+      conversation_id ? conversation_id : "", 0, p_arena);
+  char *escaped_prompt = prompt
+      ? Dowa_JSON_Escape_String(prompt, 0, p_arena)
+      : NULL;
+  char *escaped_profile = Dowa_JSON_Escape_String(profile_name, 0, p_arena);
+
+  if (!escaped_command || !escaped_request || !escaped_conversation ||
+      (prompt && !escaped_prompt) || !escaped_profile)
+  {
+    Dowa_Arena_Free(p_arena);
+    return FALSE;
+  }
+
+  /* Escape history roles and contents. */
+  char *escaped_hist_role[INFERENCE_BRIDGE_HISTORY_MAX];
+  char *escaped_hist_content[INFERENCE_BRIDGE_HISTORY_MAX];
+  for (uint32 i = 0; i < history_count; i++)
+  {
+    escaped_hist_role[i] =
+        Dowa_JSON_Escape_String(p_history[i].role, 0, p_arena);
+    escaped_hist_content[i] =
+        Dowa_JSON_Escape_String(p_history[i].content, 0, p_arena);
+    if (!escaped_hist_role[i] || !escaped_hist_content[i])
+    {
+      Dowa_Arena_Free(p_arena);
+      return FALSE;
+    }
+  }
+
+  /* Compute payload capacity. */
+  size_t capacity =
+      strlen(escaped_command) + strlen(escaped_request) +
+      strlen(escaped_conversation) +
+      (escaped_prompt ? strlen(escaped_prompt) : 0) +
+      strlen(escaped_profile) + 256;
+  for (uint32 i = 0; i < history_count; i++)
+  {
+    capacity +=
+        strlen(escaped_hist_role[i]) + strlen(escaped_hist_content[i]) + 32;
+  }
+
+  char *payload = Dowa_Arena_Allocate(p_arena, capacity);
+  if (!payload)
+  {
+    Dowa_Arena_Free(p_arena);
+    return FALSE;
+  }
+
+  /* Write the base turn.start fields. */
+  int written = snprintf(
+      payload,
+      capacity,
+      "{\"command\":\"%s\",\"request_id\":\"%s\","
+      "\"conversation_id\":\"%s\",\"prompt\":\"%s\","
+      "\"prompt_profile\":\"%s\",\"prompt_version\":%u,"
+      "\"knowledge_version\":%u,\"history\":[",
+      escaped_command,
+      escaped_request,
+      escaped_conversation,
+      escaped_prompt ? escaped_prompt : "",
+      escaped_profile,
+      prompt_version,
+      knowledge_version);
+  if (written <= 0 || (size_t)written >= capacity)
+  {
+    Dowa_Arena_Free(p_arena);
+    return FALSE;
+  }
+  size_t offset = (size_t)written;
+
+  /* Append history entries. */
+  for (uint32 i = 0; i < history_count; i++)
+  {
+    int entry_written = snprintf(
+        payload + offset,
+        capacity - offset,
+        "%s{\"role\":\"%s\",\"content\":\"%s\"}",
+        i == 0 ? "" : ",",
+        escaped_hist_role[i],
+        escaped_hist_content[i]);
+    if (entry_written <= 0 || offset + (size_t)entry_written >= capacity)
+    {
+      Dowa_Arena_Free(p_arena);
+      return FALSE;
+    }
+    offset += (size_t)entry_written;
+  }
+
+  /* Close the history array and the outer object. */
+  if (offset + 2 >= capacity)
+  {
+    Dowa_Arena_Free(p_arena);
+    return FALSE;
+  }
+  payload[offset++] = ']';
+  payload[offset++] = '}';
+  payload[offset]   = '\0';
+
+  boolean success = Inference_Bridge_Write(p_bridge, payload);
+  Dowa_Arena_Free(p_arena);
+  return success;
 }
 
 boolean Inference_Bridge_Abort_Turn(
@@ -477,7 +648,7 @@
     const char *conversation_id)
 {
   return Inference_Bridge_Command(
-      p_bridge, "turn.abort", request_id, conversation_id, NULL);
+      p_bridge, "turn.abort", request_id, conversation_id, NULL, NULL, 0, 0);
 }
 
 boolean Inference_Bridge_Delete_Conversation(
@@ -486,7 +657,14 @@
     const char *conversation_id)
 {
   return Inference_Bridge_Command(
-      p_bridge, "conversation.delete", request_id, conversation_id, NULL);
+      p_bridge,
+      "conversation.delete",
+      request_id,
+      conversation_id,
+      NULL,
+      NULL,
+      0,
+      0);
 }
 
 void Inference_Bridge_Destroy(Inference_Bridge *p_bridge)