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>
This commit is contained in:
WHC
2026-09-07 22:42:32 +08:00
co-authored by Cursor
commit 1f1fcba7ad
75 changed files with 14940 additions and 0 deletions
+156
View File
@@ -0,0 +1,156 @@
#include "ctl.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int n_open;
int n_arg;
int n_ready;
int n_text;
int n_error;
char last_name[CTL_MAX_NAME];
char last_id[CTL_MAX_ID];
char last_path[512];
size_t text_bytes;
} sink_t;
static void on_ev(const ctl_event_t *ev, void *ud) {
sink_t *s = ud;
switch (ev->type) {
case CTL_EV_CALL_OPEN:
s->n_open++;
snprintf(s->last_id, sizeof(s->last_id), "%s", ev->call->id);
snprintf(s->last_name, sizeof(s->last_name), "%s", ev->call->name);
break;
case CTL_EV_ARG:
s->n_arg++;
if (ev->call->nargs > 0) {
const ctl_arg_t *a = &ev->call->args[ev->call->nargs - 1];
if (strcmp(a->key, "path") == 0 && a->value)
snprintf(s->last_path, sizeof(s->last_path), "%s", a->value);
}
break;
case CTL_EV_CALL_READY:
s->n_ready++;
break;
case CTL_EV_TEXT:
s->n_text++;
s->text_bytes += ev->text_len;
break;
case CTL_EV_ERROR:
s->n_error++;
break;
default:
break;
}
}
static int expect(int cond, const char *msg) {
if (!cond) {
fprintf(stderr, "FAIL: %s\n", msg);
return 0;
}
return 1;
}
static int test_chunked_confirm(void) {
sink_t s = {0};
ctl_parser_t *p = ctl_parser_create(on_ev, &s);
const char *msg =
"I'll read the file.\n"
"call t1 read_file\n"
"arg path 10\n"
"README.mdx"
"end\n";
/* feed 1 byte at a time */
for (size_t i = 0; msg[i]; i++) {
if (ctl_parser_feed(p, &msg[i], 1) != CTL_OK) {
fprintf(stderr, "feed failed at %zu\n", i);
ctl_parser_destroy(p);
return 0;
}
}
int ok = 1;
ok &= expect(ctl_parser_finish(p) == CTL_OK, "finish ok");
ok &= expect(s.n_ready == 1, "one ready");
ok &= expect(s.n_open == 1, "one open");
ok &= expect(s.n_arg == 1, "one arg");
ok &= expect(strcmp(s.last_name, "read_file") == 0, "name");
ok &= expect(strcmp(s.last_path, "README.mdx") == 0, "path");
ok &= expect(s.n_error == 0, "no error");
ok &= expect(ctl_parser_pending(p) == 0, "pending 0");
/* pending peak should be bounded by line/arg */
ok &= expect(ctl_parser_pending_peak(p) <= CTL_MAX_LINE, "peak bounded");
ctl_parser_destroy(p);
return ok;
}
static int test_truncate_no_execute(void) {
sink_t s = {0};
ctl_parser_t *p = ctl_parser_create(on_ev, &s);
const char *msg =
"call t1 read_file\n"
"arg path 20\n"
"partial"; /* incomplete: need 20 bytes, then end */
ctl_parser_feed(p, msg, strlen(msg));
int ok = 1;
ok &= expect(s.n_ready == 0, "no ready before EOF");
ok &= expect(s.n_open == 1, "open confirmed");
ok &= expect(ctl_parser_finish(p) == CTL_ERR_CONTRACT, "finish error");
ok &= expect(s.n_error >= 1, "error emitted");
ok &= expect(s.n_ready == 0, "still no ready");
ctl_parser_destroy(p);
return ok;
}
static int test_monotonic_no_retract(void) {
/* Once CALL_READY fires, further feed of garbage should error, not retract */
sink_t s = {0};
ctl_parser_t *p = ctl_parser_create(on_ev, &s);
const char *okmsg =
"call a1 run_shell\n"
"arg cmd 5\n"
"ls -l"
"end\n";
ctl_parser_feed(p, okmsg, strlen(okmsg));
int ready = s.n_ready;
int ok = expect(ready == 1, "ready once");
/* text after is fine */
ctl_parser_feed(p, "done.\n", 6);
ok &= expect(s.n_ready == 1, "ready unchanged");
ctl_parser_finish(p);
ctl_parser_destroy(p);
return ok;
}
static int test_text_before_call(void) {
sink_t s = {0};
ctl_parser_t *p = ctl_parser_create(on_ev, &s);
const char *msg = "Hello\nWorld\n";
ctl_parser_feed(p, msg, strlen(msg));
ctl_parser_finish(p);
int ok = expect(s.n_text == 2, "two text lines");
ok &= expect(s.n_ready == 0, "no calls");
ctl_parser_destroy(p);
return ok;
}
int main(void) {
int nfail = 0;
if (!test_chunked_confirm())
nfail++;
if (!test_truncate_no_execute())
nfail++;
if (!test_monotonic_no_retract())
nfail++;
if (!test_text_before_call())
nfail++;
if (nfail) {
fprintf(stderr, "%d test(s) failed\n", nfail);
return 1;
}
printf("test_ctl_frontier: OK\n");
return 0;
}
+55
View File
@@ -0,0 +1,55 @@
#include "cst_agent.h"
#include <stdio.h>
#include <string.h>
static int expect(int cond, const char *msg) {
if (!cond) {
fprintf(stderr, "FAIL: %s\n", msg);
return 0;
}
return 1;
}
static int test_complete_json(void) {
const char *j =
"Here is a call {\"name\":\"read_file\",\"arguments\":{\"path\":\"a.c\"}} "
"done";
cst_json_tool_t t;
int ok = cst_json_try_parse_tool(j, strlen(j), &t);
int pass = expect(ok == 1, "parse ok");
pass &= expect(t.ok == 1, "ok flag");
pass &= expect(strcmp(t.name, "read_file") == 0, "name");
pass &= expect(strstr(t.arguments_json, "path") != NULL, "args");
return pass;
}
static int test_truncated_json(void) {
const char *j = "{\"name\":\"read_file\",\"arguments\":{\"path\":\"a";
cst_json_tool_t t;
int ok = cst_json_try_parse_tool(j, strlen(j), &t);
return expect(ok == 0, "truncated must fail");
}
static int test_unclosed_brace(void) {
const char *j = "{\"name\":\"run_shell\",\"arguments\":{\"cmd\":\"ls\"";
cst_json_tool_t t;
int ok = cst_json_try_parse_tool(j, strlen(j), &t);
return expect(ok == 0, "unclosed brace fails");
}
int main(void) {
int nfail = 0;
if (!test_complete_json())
nfail++;
if (!test_truncated_json())
nfail++;
if (!test_unclosed_brace())
nfail++;
if (nfail) {
fprintf(stderr, "%d failed\n", nfail);
return 1;
}
printf("test_json_baseline: OK\n");
return 0;
}
+65
View File
@@ -0,0 +1,65 @@
#include "mm_tool.h"
#include <stdio.h>
#include <string.h>
typedef struct {
int n_ready;
int n_text;
char name[64];
char path[256];
} sink_t;
static void on_ev(const ctl_event_t *ev, void *ud) {
sink_t *s = ud;
if (ev->type == CTL_EV_TEXT)
s->n_text++;
if (ev->type == CTL_EV_CALL_READY && ev->call) {
s->n_ready++;
snprintf(s->name, sizeof(s->name), "%s", ev->call->name);
if (ev->call->nargs > 0 && ev->call->args[0].value)
snprintf(s->path, sizeof(s->path), "%s", ev->call->args[0].value);
}
}
static int expect(int c, const char *m) {
if (!c) {
fprintf(stderr, "FAIL: %s\n", m);
return 0;
}
return 1;
}
int main(void) {
sink_t s = {0};
mm_scan_t *mm = mm_scan_create(on_ev, &s);
const char *msg =
"我来读一下。\n"
"<minimax:tool_call>\n"
"invoke read_file\n"
"<arg name=\"path\">./README.md</arg>\n"
"</minimax:tool_call>\n"
"读完了。\n";
/* byte-at-a-time */
for (size_t i = 0; msg[i]; i++)
mm_scan_feed(mm, &msg[i], 1);
mm_scan_finish(mm);
int ok = 1;
ok &= expect(s.n_ready == 1, "one ready");
ok &= expect(strcmp(s.name, "read_file") == 0, "name");
ok &= expect(strcmp(s.path, "./README.md") == 0, "path");
ok &= expect(s.n_text >= 1, "text emitted");
/* truncated: no execute */
sink_t s2 = {0};
mm_scan_t *mm2 = mm_scan_create(on_ev, &s2);
const char *trunc = "<minimax:tool_call>\ninvoke read_file\n";
mm_scan_feed(mm2, trunc, strlen(trunc));
mm_scan_finish(mm2);
ok &= expect(s2.n_ready == 0, "trunc no ready");
mm_scan_destroy(mm);
mm_scan_destroy(mm2);
if (!ok)
return 1;
printf("test_mm_tool: OK\n");
return 0;
}
+102
View File
@@ -0,0 +1,102 @@
#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;
}