forked from WHC/Hermit
Vendored sashidown, OpenAI-compatible env (OPENAI_*), and bootstrap scripts. Co-authored-by: Cursor <cursoragent@cursor.com>
103 lines
2.9 KiB
C
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;
|
|
}
|