comparison mrjunejune/conversation_api.c @ 261:b401627fc49e

Add JRPG mock flows and interactive previews Add scripted mock SSE commands, custom event forwarding, animated chat turns, full-height message navigation, and a cyberpunk resume dossier. Co-authored-by: Copilot <[email protected]>
author MrJuneJune <mrjunejune@users.noreply.github.com>
date Wed, 05 Aug 2026 20:38:32 -0700
parents 1f9877b637e9
children 04fee26ecce0
comparison
equal deleted inserted replaced
260:1f9877b637e9 261:b401627fc49e
14 14
15 #define CONVERSATION_TITLE_MAX 200 15 #define CONVERSATION_TITLE_MAX 200
16 #define CONVERSATION_PROMPT_MAX (32 * 1024) 16 #define CONVERSATION_PROMPT_MAX (32 * 1024)
17 #define CONVERSATION_RESPONSE_MAX (256 * 1024) 17 #define CONVERSATION_RESPONSE_MAX (256 * 1024)
18 #define CONVERSATION_HISTORY_MAX (512 * 1024) 18 #define CONVERSATION_HISTORY_MAX (512 * 1024)
19 #define CONVERSATION_CUSTOM_EVENT_MAX (3 * 1024)
20 #define CONVERSATION_EVENT_NAME_MAX 64
19 #define CONVERSATION_ACTIVE_MAX 4 21 #define CONVERSATION_ACTIVE_MAX 4
20 #define CONVERSATION_TURNS_PER_MINUTE 60 22 #define CONVERSATION_TURNS_PER_MINUTE 60
21 23
22 static Conversation_Store *g_conversation_store = NULL; 24 static Conversation_Store *g_conversation_store = NULL;
23 static Inference_Bridge *g_inference_bridge = NULL; 25 static Inference_Bridge *g_inference_bridge = NULL;
42 char error_message[512]; 44 char error_message[512];
43 struct Pending_Turn *p_next; 45 struct Pending_Turn *p_next;
44 } Pending_Turn; 46 } Pending_Turn;
45 47
46 static Pending_Turn *g_pending_turns = NULL; 48 static Pending_Turn *g_pending_turns = NULL;
49
50 static boolean Conversation_API_Is_Handled_Event(const char *type)
51 {
52 return
53 strcmp(type, "ready") == 0 ||
54 strcmp(type, "turn.accepted") == 0 ||
55 strcmp(type, "assistant.delta") == 0 ||
56 strcmp(type, "assistant.completed") == 0 ||
57 strcmp(type, "assistant.usage") == 0 ||
58 strcmp(type, "turn.error") == 0 ||
59 strcmp(type, "turn.done") == 0;
60 }
61
62 static boolean Conversation_API_Is_Safe_Event_Name(const char *type)
63 {
64 if (!type || type[0] == '\0')
65 return FALSE;
66 size_t length = strlen(type);
67 if (length > CONVERSATION_EVENT_NAME_MAX)
68 return FALSE;
69 for (size_t i = 0; i < length; i++)
70 {
71 char character = type[i];
72 if (!(
73 (character >= 'a' && character <= 'z') ||
74 (character >= 'A' && character <= 'Z') ||
75 (character >= '0' && character <= '9') ||
76 character == '.' ||
77 character == '_' ||
78 character == '-'))
79 return FALSE;
80 }
81 return TRUE;
82 }
47 83
48 static boolean Conversation_API_Acquire_Turn_Slot(void) 84 static boolean Conversation_API_Acquire_Turn_Slot(void)
49 { 85 {
50 time_t now = time(NULL); 86 time_t now = time(NULL);
51 pthread_mutex_lock(&g_admission_mutex); 87 pthread_mutex_lock(&g_admission_mutex);
311 pthread_mutex_lock(&g_pending_mutex); 347 pthread_mutex_lock(&g_pending_mutex);
312 Pending_Turn *p_turn = Conversation_API_Find_Pending(p_event->request_id); 348 Pending_Turn *p_turn = Conversation_API_Find_Pending(p_event->request_id);
313 if (!p_turn) 349 if (!p_turn)
314 { 350 {
315 pthread_mutex_unlock(&g_pending_mutex); 351 pthread_mutex_unlock(&g_pending_mutex);
352 return;
353 }
354
355 if (!Conversation_API_Is_Handled_Event(p_event->type))
356 {
357 if (!Conversation_API_Is_Safe_Event_Name(p_event->type) ||
358 !p_event->raw_json ||
359 p_event->raw_json_length == 0 ||
360 p_event->raw_json_length > CONVERSATION_CUSTOM_EVENT_MAX)
361 {
362 p_turn->failed = TRUE;
363 snprintf(
364 p_turn->error_message,
365 sizeof(p_turn->error_message),
366 "Invalid custom inference event");
367 Conversation_API_Send_Event(
368 p_turn,
369 "turn.error",
370 "{\"code\":\"invalid_custom_event\","
371 "\"message\":\"Invalid custom inference event\"}");
372 Conversation_API_Finalize_Pending(p_turn);
373 }
374 else if (Conversation_API_Send_Event(
375 p_turn, p_event->type, p_event->raw_json) < 0)
376 {
377 p_turn->aborted = TRUE;
378 should_abort = TRUE;
379 snprintf(
380 abort_request_id,
381 sizeof(abort_request_id),
382 "%s",
383 p_turn->request_id);
384 snprintf(
385 abort_conversation_id,
386 sizeof(abort_conversation_id),
387 "%s",
388 p_turn->conversation_id);
389 }
390 pthread_mutex_unlock(&g_pending_mutex);
391 if (should_abort)
392 Inference_Bridge_Abort_Turn(
393 g_inference_bridge, abort_request_id, abort_conversation_id);
316 return; 394 return;
317 } 395 }
318 396
319 size_t event_text_length = 397 size_t event_text_length =
320 strlen(p_event->delta ? p_event->delta : "") + 398 strlen(p_event->delta ? p_event->delta : "") +