Mercurial
diff 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 |
line wrap: on
line diff
--- a/mrjunejune/conversation_api.c Wed Aug 05 09:19:41 2026 -0700 +++ b/mrjunejune/conversation_api.c Wed Aug 05 20:38:32 2026 -0700 @@ -16,6 +16,8 @@ #define CONVERSATION_PROMPT_MAX (32 * 1024) #define CONVERSATION_RESPONSE_MAX (256 * 1024) #define CONVERSATION_HISTORY_MAX (512 * 1024) +#define CONVERSATION_CUSTOM_EVENT_MAX (3 * 1024) +#define CONVERSATION_EVENT_NAME_MAX 64 #define CONVERSATION_ACTIVE_MAX 4 #define CONVERSATION_TURNS_PER_MINUTE 60 @@ -45,6 +47,40 @@ static Pending_Turn *g_pending_turns = NULL; +static boolean Conversation_API_Is_Handled_Event(const char *type) +{ + return + strcmp(type, "ready") == 0 || + strcmp(type, "turn.accepted") == 0 || + strcmp(type, "assistant.delta") == 0 || + strcmp(type, "assistant.completed") == 0 || + strcmp(type, "assistant.usage") == 0 || + strcmp(type, "turn.error") == 0 || + strcmp(type, "turn.done") == 0; +} + +static boolean Conversation_API_Is_Safe_Event_Name(const char *type) +{ + if (!type || type[0] == '\0') + return FALSE; + size_t length = strlen(type); + if (length > CONVERSATION_EVENT_NAME_MAX) + return FALSE; + for (size_t i = 0; i < length; i++) + { + char character = type[i]; + if (!( + (character >= 'a' && character <= 'z') || + (character >= 'A' && character <= 'Z') || + (character >= '0' && character <= '9') || + character == '.' || + character == '_' || + character == '-')) + return FALSE; + } + return TRUE; +} + static boolean Conversation_API_Acquire_Turn_Slot(void) { time_t now = time(NULL); @@ -316,6 +352,48 @@ return; } + if (!Conversation_API_Is_Handled_Event(p_event->type)) + { + if (!Conversation_API_Is_Safe_Event_Name(p_event->type) || + !p_event->raw_json || + p_event->raw_json_length == 0 || + p_event->raw_json_length > CONVERSATION_CUSTOM_EVENT_MAX) + { + p_turn->failed = TRUE; + snprintf( + p_turn->error_message, + sizeof(p_turn->error_message), + "Invalid custom inference event"); + Conversation_API_Send_Event( + p_turn, + "turn.error", + "{\"code\":\"invalid_custom_event\"," + "\"message\":\"Invalid custom inference event\"}"); + Conversation_API_Finalize_Pending(p_turn); + } + else if (Conversation_API_Send_Event( + p_turn, p_event->type, p_event->raw_json) < 0) + { + p_turn->aborted = TRUE; + should_abort = TRUE; + snprintf( + abort_request_id, + sizeof(abort_request_id), + "%s", + p_turn->request_id); + snprintf( + abort_conversation_id, + sizeof(abort_conversation_id), + "%s", + p_turn->conversation_id); + } + pthread_mutex_unlock(&g_pending_mutex); + if (should_abort) + Inference_Bridge_Abort_Turn( + g_inference_bridge, abort_request_id, abort_conversation_id); + return; + } + size_t event_text_length = strlen(p_event->delta ? p_event->delta : "") + strlen(p_event->content ? p_event->content : "") +