#include "ctl.h" #include "cst_agent.h" #include #include #include /* * Starvation replay: same logical tool call, cut at several prefixes. * CTL+CST should never execute on incomplete prefixes; JSON-buffer fails to * parse (cannot execute). When the full stream is present, both succeed. */ typedef struct { int n_ready; size_t peak; } ctl_stats_t; static void on_ev(const ctl_event_t *ev, void *ud) { ctl_stats_t *s = ud; if (ev->type == CTL_EV_CALL_READY) s->n_ready++; } static int ctl_ready_on_prefix(const char *full, size_t ncut, size_t *peak) { ctl_stats_t st = {0}; ctl_parser_t *p = ctl_parser_create(on_ev, &st); ctl_parser_feed(p, full, ncut); /* do not finish — simulate stream stall / truncation mid-turn */ *peak = ctl_parser_pending_peak(p); int ready = st.n_ready; ctl_parser_destroy(p); return ready; } int main(void) { const char *ctl = "call x1 read_file\n" "arg path 5\n" "a.txt" "end\n"; const char *json = "{\"name\":\"read_file\",\"arguments\":{\"path\":\"a.txt\"}}"; size_t ctl_len = strlen(ctl); size_t json_len = strlen(json); int ctl_premature = 0, json_ok_full = 0, ctl_ok_full = 0; int json_fail_trunc = 0, ctl_safe_trunc = 0; /* full streams */ { size_t peak = 0; ctl_stats_t st = {0}; ctl_parser_t *p = ctl_parser_create(on_ev, &st); ctl_parser_feed(p, ctl, ctl_len); ctl_parser_finish(p); peak = ctl_parser_pending_peak(p); ctl_ok_full = (st.n_ready == 1); printf("CTL full: ready=%d peak=%zu\n", st.n_ready, peak); ctl_parser_destroy(p); } { cst_json_tool_t t; json_ok_full = cst_json_try_parse_tool(json, json_len, &t); printf("JSON full: ok=%d name=%s\n", json_ok_full, t.name); } /* truncate at 50% and 80% */ size_t cuts[] = {ctl_len / 2, (ctl_len * 4) / 5, ctl_len - 2}; for (size_t i = 0; i < sizeof(cuts) / sizeof(cuts[0]); i++) { size_t peak = 0; int ready = ctl_ready_on_prefix(ctl, cuts[i], &peak); printf("CTL cut %zu/%zu: ready=%d peak=%zu\n", cuts[i], ctl_len, ready, peak); if (ready) ctl_premature++; else ctl_safe_trunc++; } size_t jcuts[] = {json_len / 2, (json_len * 4) / 5, json_len - 2}; for (size_t i = 0; i < sizeof(jcuts) / sizeof(jcuts[0]); i++) { cst_json_tool_t t; int ok = cst_json_try_parse_tool(json, jcuts[i], &t); printf("JSON cut %zu/%zu: ok=%d\n", jcuts[i], json_len, ok); if (!ok) json_fail_trunc++; } printf("\n=== summary ===\n"); printf("CTL full success: %s\n", ctl_ok_full ? "yes" : "no"); printf("JSON full success: %s\n", json_ok_full ? "yes" : "no"); printf("CTL premature executes on trunc: %d (want 0)\n", ctl_premature); printf("CTL safe truncations: %d\n", ctl_safe_trunc); printf("JSON trunc failures: %d\n", json_fail_trunc); if (!ctl_ok_full || !json_ok_full || ctl_premature != 0) return 1; printf("replay_starvation: OK\n"); return 0; }