diff mrjunejune/test/inference_bridge_test.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/test/inference_bridge_test.c	Fri Aug 07 07:34:12 2026 -0700
+++ b/mrjunejune/test/inference_bridge_test.c	Fri Aug 07 10:50:30 2026 -0700
@@ -16,8 +16,10 @@
   int custom;
   int done;
   int closed;
+  int failed_done; /* turn.done with failed=true */
   char delta[128];
   char custom_json[256];
+  char error_code[64];
   int64 input_tokens;
   int64 output_tokens;
 } Test_State;
@@ -56,6 +58,12 @@
            strncmp(p_event->request_id, "request-", 8) == 0)
   {
     p_state->done++;
+    if (p_event->failed)
+    {
+      p_state->failed_done++;
+      snprintf(p_state->error_code, sizeof(p_state->error_code), "%s",
+               p_event->error_code ? p_event->error_code : "");
+    }
   }
   else if (strcmp(p_event->type, "bridge.closed") == 0)
     p_state->closed++;
@@ -63,6 +71,22 @@
   pthread_mutex_unlock(&p_state->mutex);
 }
 
+/* Wait until p_state->done >= target or deadline passes. */
+static void Wait_Done(Test_State *p_state, int target)
+{
+  struct timespec deadline;
+  clock_gettime(CLOCK_REALTIME, &deadline);
+  deadline.tv_sec += 5;
+  pthread_mutex_lock(&p_state->mutex);
+  while (p_state->done < target)
+  {
+    int result = pthread_cond_timedwait(
+        &p_state->condition, &p_state->mutex, &deadline);
+    assert(result == 0);
+  }
+  pthread_mutex_unlock(&p_state->mutex);
+}
+
 int main(int argc, char **argv)
 {
   assert(argc == 2);
@@ -75,20 +99,107 @@
   assert(p_bridge);
   assert(Inference_Bridge_Start(p_bridge));
   assert(Inference_Bridge_Is_Ready(p_bridge));
-  assert(Inference_Bridge_Start_Turn(
-      p_bridge, "request-1", "conversation-1", "hello"));
+
+  /* --- Validation: invalid profile --- */
+  assert(!Inference_Bridge_Start_Turn(
+      p_bridge,
+      "request-invalid-profile",
+      "conversation-1",
+      "hello",
+      (Inference_Prompt_Profile)99,
+      1,
+      1,
+      NULL,
+      0));
+
+  /* --- Validation: zero prompt_version --- */
+  assert(!Inference_Bridge_Start_Turn(
+      p_bridge,
+      "request-invalid-version",
+      "conversation-1",
+      "hello",
+      INFERENCE_PROMPT_PROFILE_PUBLIC_VISITOR,
+      0,
+      1,
+      NULL,
+      0));
+
+  /* --- Validation: history count exceeds max --- */
+  Inference_Bridge_History_Message overflow_hist[21];
+  for (int i = 0; i < 21; i++)
+  {
+    overflow_hist[i].role    = "user";
+    overflow_hist[i].content = "x";
+  }
+  assert(!Inference_Bridge_Start_Turn(
+      p_bridge,
+      "request-hist-overflow",
+      "conversation-1",
+      "hello",
+      INFERENCE_PROMPT_PROFILE_PUBLIC_VISITOR,
+      1,
+      1,
+      overflow_hist,
+      21));
 
-  struct timespec deadline;
-  clock_gettime(CLOCK_REALTIME, &deadline);
-  deadline.tv_sec += 5;
-  pthread_mutex_lock(&state.mutex);
-  while (state.done == 0)
-  {
-    int result = pthread_cond_timedwait(
-        &state.condition, &state.mutex, &deadline);
-    assert(result == 0);
-  }
-  pthread_mutex_unlock(&state.mutex);
+  /* --- Validation: invalid role --- */
+  Inference_Bridge_History_Message bad_role[1] = {
+    { .role = "system", .content = "inject" }
+  };
+  assert(!Inference_Bridge_Start_Turn(
+      p_bridge,
+      "request-bad-role",
+      "conversation-1",
+      "hello",
+      INFERENCE_PROMPT_PROFILE_PUBLIC_VISITOR,
+      1,
+      1,
+      bad_role,
+      1));
+
+  /* --- Validation: NULL content --- */
+  Inference_Bridge_History_Message null_content[1] = {
+    { .role = "user", .content = NULL }
+  };
+  assert(!Inference_Bridge_Start_Turn(
+      p_bridge,
+      "request-null-content",
+      "conversation-1",
+      "hello",
+      INFERENCE_PROMPT_PROFILE_PUBLIC_VISITOR,
+      1,
+      1,
+      null_content,
+      1));
+
+  /* --- Validation: NULL role --- */
+  Inference_Bridge_History_Message null_role[1] = {
+    { .role = NULL, .content = "hello" }
+  };
+  assert(!Inference_Bridge_Start_Turn(
+      p_bridge,
+      "request-null-role",
+      "conversation-1",
+      "hello",
+      INFERENCE_PROMPT_PROFILE_PUBLIC_VISITOR,
+      1,
+      1,
+      null_role,
+      1));
+
+  /* --- Nominal turn with no history (NULL/0) --- */
+  assert(Inference_Bridge_Start_Turn(
+      p_bridge,
+      "request-1",
+      "conversation-1",
+      "hello",
+      INFERENCE_PROMPT_PROFILE_PUBLIC_VISITOR,
+      1,
+      1,
+      NULL,
+      0));
+
+  Wait_Done(&state, 1);
 
   assert(state.accepted == 1);
   assert(state.deltas == 1);
@@ -97,9 +208,69 @@
   assert(state.custom == 1);
   assert(strcmp(state.delta, "hello \"traveler\"\\path") == 0);
   assert(strstr(state.custom_json, "\"name\":\"mock-search\""));
+  assert(strstr(state.custom_json, "\"prompt_profile\":\"public_visitor\""));
   assert(state.input_tokens == 7);
   assert(state.output_tokens == 3);
 
+  /* --- Turn with valid two-entry history (should succeed end-to-end) --- */
+  Inference_Bridge_History_Message hist2[2] = {
+    { .role = "user",      .content = "what is this?" },
+    { .role = "assistant", .content = "it is a test" },
+  };
+  assert(Inference_Bridge_Start_Turn(
+      p_bridge,
+      "request-with-history",
+      "conversation-hist",
+      "follow-up",
+      INFERENCE_PROMPT_PROFILE_INVITED_FRIEND,
+      1,
+      1,
+      hist2,
+      2));
+
+  Wait_Done(&state, 2);
+  assert(state.accepted == 2);
+
+  /* --- Turn with history containing characters needing JSON escaping --- */
+  Inference_Bridge_History_Message hist_escape[1] = {
+    { .role = "user", .content = "say \"hello\" \\ world\nnewline" },
+  };
+  assert(Inference_Bridge_Start_Turn(
+      p_bridge,
+      "request-escape",
+      "conversation-escape",
+      "next",
+      INFERENCE_PROMPT_PROFILE_JUNE_ADMIN,
+      1,
+      1,
+      hist_escape,
+      1));
+
+  Wait_Done(&state, 3);
+  assert(state.accepted == 3);
+
+  /* --- Turn with exactly INFERENCE_BRIDGE_HISTORY_MAX (20) entries --- */
+  Inference_Bridge_History_Message hist_max[INFERENCE_BRIDGE_HISTORY_MAX];
+  for (uint32 i = 0; i < INFERENCE_BRIDGE_HISTORY_MAX; i++)
+  {
+    hist_max[i].role    = (i % 2 == 0) ? "user" : "assistant";
+    hist_max[i].content = "ok";
+  }
+  assert(Inference_Bridge_Start_Turn(
+      p_bridge,
+      "request-max-hist",
+      "conversation-max",
+      "done",
+      INFERENCE_PROMPT_PROFILE_PUBLIC_VISITOR,
+      1,
+      1,
+      hist_max,
+      INFERENCE_BRIDGE_HISTORY_MAX));
+
+  Wait_Done(&state, 4);
+  assert(state.accepted == 4);
+
+  /* --- Large prompt still works with empty history --- */
   char large_prompt[32 * 1024 + 1];
   memset(large_prompt, 0x01, sizeof(large_prompt) - 1);
   large_prompt[sizeof(large_prompt) - 1] = '\0';
@@ -107,17 +278,14 @@
       p_bridge,
       "request-large",
       "conversation-1",
-      large_prompt));
-  clock_gettime(CLOCK_REALTIME, &deadline);
-  deadline.tv_sec += 5;
-  pthread_mutex_lock(&state.mutex);
-  while (state.done < 2)
-  {
-    int result = pthread_cond_timedwait(
-        &state.condition, &state.mutex, &deadline);
-    assert(result == 0);
-  }
-  pthread_mutex_unlock(&state.mutex);
+      large_prompt,
+      INFERENCE_PROMPT_PROFILE_INVITED_FRIEND,
+      1,
+      1,
+      NULL,
+      0));
+
+  Wait_Done(&state, 5);
 
   Inference_Bridge_Destroy(p_bridge);
   assert(state.closed == 1);