Files
CST-agent/tests/test_replay_starvation.c
WHCandCursor 1f1fcba7ad Initial CST-Agent: portable Linux/Termux/Windows coding agent.
Vendored sashidown, OpenAI-compatible env (OPENAI_*), and bootstrap scripts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-07 22:42:32 +08:00

103 lines
2.9 KiB
C

#include "ctl.h"
#include "cst_agent.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* 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;
}