Mercurial
view infinite_canvas/agent_response.c @ 281:c57149ad216e default tip
Copilot-Session: f68442b1-fa8f-46a0-9689-81710613bbd4
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Tue, 18 Aug 2026 22:18:15 -0700 |
| parents | |
| children |
line wrap: on
line source
#include "infinite_canvas/agent_response.h" #include <math.h> #include <stdio.h> #include <string.h> static boolean Canvas_Agent_Entity_Type( const char *p_kind, Canvas_Entity_Type *p_type) { struct { const char *p_name; Canvas_Entity_Type type; } types[] = { {"text", CANVAS_ENTITY_TEXT}, {"button", CANVAS_ENTITY_BUTTON}, {"text_area", CANVAS_ENTITY_TEXT_AREA}, {"accordion", CANVAS_ENTITY_ACCORDION}, {"card", CANVAS_ENTITY_CARD}, {"calendar", CANVAS_ENTITY_CALENDAR}, {"table", CANVAS_ENTITY_TABLE}, {"notification", CANVAS_ENTITY_NOTIFICATION}, {"scroll_area", CANVAS_ENTITY_SCROLL_AREA}, {"image", CANVAS_ENTITY_IMAGE}, {"web_content", CANVAS_ENTITY_WEB_CONTENT}, }; for (size_t index = 0; index < sizeof(types) / sizeof(types[0]); index++) { if (strcmp(p_kind, types[index].p_name) == 0) { *p_type = types[index].type; return TRUE; } } return FALSE; } static boolean Canvas_Agent_JSON_Number( Dowa_JSON_Entry *p_object, const char *p_key, float *p_value, boolean *p_present) { Dowa_JSON_Value *p_json = Dowa_JSON_Get(p_object, p_key); *p_present = p_json ? TRUE : FALSE; if (!p_json) return TRUE; if (p_json->type != DOWA_JSON_NUMBER || !isfinite(p_json->num_val) || fabs(p_json->num_val) > 10000000.0) { return FALSE; } *p_value = (float)p_json->num_val; return TRUE; } static boolean Canvas_Agent_URL_Allowed(const char *p_value) { return !p_value[0] || strncmp(p_value, "https://", 8) == 0 || strncmp(p_value, "http://", 7) == 0; } boolean Canvas_Agent_Response_Parse( const char *p_json, Canvas_Agent_Response *p_response) { if (!p_json || !p_response) return FALSE; memset(p_response, 0, sizeof(*p_response)); Dowa_Arena *p_arena = Dowa_Arena_Create(128 * 1024); if (!p_arena) return FALSE; Dowa_JSON_Value root = Dowa_JSON_Parse( p_json, (int32)strlen(p_json), p_arena); if (root.type != DOWA_JSON_OBJECT) { Dowa_Arena_Free(p_arena); return FALSE; } Dowa_JSON_Entry *p_object = root.object_val; char *p_action = Dowa_JSON_Get_String(p_object, "action"); char *p_presentation = Dowa_JSON_Get_String(p_object, "presentation"); char *p_title = Dowa_JSON_Get_String(p_object, "title"); char *p_text = Dowa_JSON_Get_String(p_object, "response"); Dowa_JSON_Value *p_conversation = Dowa_JSON_Get(p_object, "conversation_id"); if (!p_action || (strcmp(p_action, "create") != 0 && strcmp(p_action, "append") != 0) || !p_presentation || (strcmp(p_presentation, "conversation") != 0 && strcmp(p_presentation, "action") != 0) || (strcmp(p_action, "append") == 0 && strcmp(p_presentation, "conversation") != 0) || !p_text || !p_conversation || p_conversation->type != DOWA_JSON_NUMBER || floor(p_conversation->num_val) != p_conversation->num_val || p_conversation->num_val < 0 || p_conversation->num_val > 4294967295.0) { Dowa_Arena_Free(p_arena); return FALSE; } snprintf( p_response->action, sizeof(p_response->action), "%s", p_action); snprintf( p_response->presentation, sizeof(p_response->presentation), "%s", p_presentation); snprintf( p_response->title, sizeof(p_response->title), "%s", p_title ? p_title : ""); snprintf( p_response->response, sizeof(p_response->response), "%s", p_text); p_response->conversation_id = (uint32)p_conversation->num_val; Dowa_JSON_Value *p_entities = Dowa_JSON_Get(p_object, "entities"); if (p_entities) { if (p_entities->type != DOWA_JSON_ARRAY || Dowa_Array_Length(p_entities->array_val) > CANVAS_AGENT_MAX_CREATED_ENTITIES) { Dowa_Arena_Free(p_arena); return FALSE; } for (size_t index = 0; index < Dowa_Array_Length(p_entities->array_val); index++) { Dowa_JSON_Value *p_value = &p_entities->array_val[index]; if (p_value->type != DOWA_JSON_OBJECT) { Dowa_Arena_Free(p_arena); return FALSE; } Dowa_JSON_Entry *p_entity_object = p_value->object_val; char *p_kind = Dowa_JSON_Get_String(p_entity_object, "kind"); Canvas_Agent_Entity_Spec *p_spec = &p_response->entities[p_response->entity_count]; if (!p_kind || !Canvas_Agent_Entity_Type(p_kind, &p_spec->type)) { Dowa_Arena_Free(p_arena); return FALSE; } char *p_label = Dowa_JSON_Get_String(p_entity_object, "label"); char *p_entity_text = Dowa_JSON_Get_String(p_entity_object, "text"); snprintf( p_spec->label, sizeof(p_spec->label), "%s", p_label ? p_label : ""); snprintf( p_spec->text, sizeof(p_spec->text), "%s", p_entity_text ? p_entity_text : ""); if ((p_spec->type == CANVAS_ENTITY_IMAGE || p_spec->type == CANVAS_ENTITY_WEB_CONTENT) && !Canvas_Agent_URL_Allowed(p_spec->text)) { Dowa_Arena_Free(p_arena); return FALSE; } float x = 0.0f; float y = 0.0f; boolean has_x = FALSE; boolean has_y = FALSE; if (!Canvas_Agent_JSON_Number( p_entity_object, "x", &x, &has_x) || !Canvas_Agent_JSON_Number( p_entity_object, "y", &y, &has_y)) { Dowa_Arena_Free(p_arena); return FALSE; } if (has_x != has_y) { Dowa_Arena_Free(p_arena); return FALSE; } if ((has_x && (fabsf(x) > 1000000.0f || fabsf(y) > 1000000.0f))) { Dowa_Arena_Free(p_arena); return FALSE; } p_spec->has_position = has_x && has_y; p_spec->position = (Vector2){x, y}; float width = 0.0f; float height = 0.0f; boolean has_width = FALSE; boolean has_height = FALSE; if (!Canvas_Agent_JSON_Number( p_entity_object, "width", &width, &has_width) || !Canvas_Agent_JSON_Number( p_entity_object, "height", &height, &has_height)) { Dowa_Arena_Free(p_arena); return FALSE; } if (has_width != has_height || (has_width && (width < 32.0f || height < 24.0f || width > 5000.0f || height > 5000.0f))) { Dowa_Arena_Free(p_arena); return FALSE; } p_spec->has_size = has_width && has_height; p_spec->size = (Vector2){width, height}; Dowa_JSON_Value *p_entity_value = Dowa_JSON_Get(p_entity_object, "value"); if (p_entity_value) { if (p_entity_value->type != DOWA_JSON_NUMBER || floor(p_entity_value->num_val) != p_entity_value->num_val || p_entity_value->num_val < -2147483648.0 || p_entity_value->num_val > 2147483647.0) { Dowa_Arena_Free(p_arena); return FALSE; } p_spec->value = (int32)p_entity_value->num_val; p_spec->has_value = TRUE; } p_response->entity_count++; } } Dowa_Arena_Free(p_arena); return TRUE; }