style: 应用 clang-format
This commit is contained in:
1 parent
016a45bc6e
commit
d1612f1d31
65 files changed
+7288
-5983
No files matched your search
+64
-66
@@ -10,23 +10,23 @@
|
||||
static int failures = 0;
|
||||
static int checks = 0;
|
||||
|
||||
#define CHECK(cond, ...) \
|
||||
do { \
|
||||
checks++; \
|
||||
if (!(cond)) { \
|
||||
failures++; \
|
||||
printf(" ✗ %s:%d: ", __FILE__, __LINE__); \
|
||||
printf(__VA_ARGS__); \
|
||||
printf("\n"); \
|
||||
} \
|
||||
#define CHECK(cond, ...) \
|
||||
do { \
|
||||
checks++; \
|
||||
if (!(cond)) { \
|
||||
failures++; \
|
||||
printf(" ✗ %s:%d: ", __FILE__, __LINE__); \
|
||||
printf(__VA_ARGS__); \
|
||||
printf("\n"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static size_t count_role(const Agent *a, const char *role)
|
||||
{
|
||||
static size_t count_role(const Agent *a, const char *role) {
|
||||
size_t n = 0;
|
||||
for (size_t i = 0; i < json_array_size(a->messages); i++) {
|
||||
const char *r = json_get_string(json_array_get(a->messages, i), "role");
|
||||
if (r && strcmp(r, role) == 0) n++;
|
||||
if (r && strcmp(r, role) == 0)
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
@@ -35,8 +35,7 @@ static size_t count_role(const Agent *a, const char *role)
|
||||
/* 上下文超限的自动恢复 */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static void add_msg(Agent *a, const char *role, const char *content)
|
||||
{
|
||||
static void add_msg(Agent *a, const char *role, const char *content) {
|
||||
JsonValue *m = json_new_object();
|
||||
json_object_set_string(m, "role", role);
|
||||
json_object_set_string(m, "content", content);
|
||||
@@ -44,8 +43,8 @@ static void add_msg(Agent *a, const char *role, const char *content)
|
||||
}
|
||||
|
||||
/* 造一条 assistant 带 tool_calls 的消息 */
|
||||
static void add_assistant_tool_call(Agent *a, const char *id, const char *name)
|
||||
{
|
||||
static void add_assistant_tool_call(Agent *a, const char *id,
|
||||
const char *name) {
|
||||
JsonValue *m = json_new_object();
|
||||
json_object_set_string(m, "role", "assistant");
|
||||
json_object_set_null(m, "content");
|
||||
@@ -62,8 +61,7 @@ static void add_assistant_tool_call(Agent *a, const char *id, const char *name)
|
||||
json_array_push(a->messages, m);
|
||||
}
|
||||
|
||||
static void add_tool_result(Agent *a, const char *id, const char *content)
|
||||
{
|
||||
static void add_tool_result(Agent *a, const char *id, const char *content) {
|
||||
JsonValue *m = json_new_object();
|
||||
json_object_set_string(m, "role", "tool");
|
||||
json_object_set_string(m, "tool_call_id", id);
|
||||
@@ -72,20 +70,17 @@ static void add_tool_result(Agent *a, const char *id, const char *content)
|
||||
}
|
||||
|
||||
/* 序列化历史, 便于断言 */
|
||||
static char *dump_history(const Agent *a)
|
||||
{
|
||||
return json_dump(a->messages);
|
||||
}
|
||||
static char *dump_history(const Agent *a) { return json_dump(a->messages); }
|
||||
|
||||
/* 配对不变量: 任何 assistant(tool_calls) 后面必须**紧跟**同 id 的 tool 消息.
|
||||
/* 配对不变量: 任何 assistant(tool_calls) 后面必须**紧跟**同 id 的 tool 消息.
|
||||
* 服务端就是这么要求的, 违反了下一轮直接 400 —— 所以每次动过历史之后都要查. */
|
||||
static void check_pairing(Agent *a)
|
||||
{
|
||||
static void check_pairing(Agent *a) {
|
||||
size_t n = json_array_size(a->messages);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
JsonValue *m = json_array_get(a->messages, i);
|
||||
JsonValue *tcs = json_object_get(m, "tool_calls");
|
||||
if (!tcs) continue;
|
||||
if (!tcs)
|
||||
continue;
|
||||
const char *id = json_get_string(json_array_get(tcs, 0), "id");
|
||||
CHECK(i + 1 < n, "tool_calls 之后必须有消息");
|
||||
if (i + 1 < n) {
|
||||
@@ -97,15 +92,14 @@ static void check_pairing(Agent *a)
|
||||
}
|
||||
}
|
||||
|
||||
/* 一轮一轮摘下去 (/back 走的就是这条路), 历史在每一步都必须仍然自洽.
|
||||
/* 一轮一轮摘下去 (/back 走的就是这条路), 历史在每一步都必须仍然自洽.
|
||||
*
|
||||
* 这里原来测的是"上下文超限自动裁剪" (agent_drop_oldest_round)—— 那套机制
|
||||
* 已经**整个删掉**: 它的判据只是错误文案里的关键词, 却会不可逆地删掉最老的
|
||||
* 几轮对话. 现在超限就是如实报错、历史一个字节都不动, 怎么处理由用户决定
|
||||
* (/back 摘一轮、/reset 重来). 但"摘掉一整轮之后 tool 配对不能散"这条
|
||||
* 不变量与由谁触发无关, 所以留着继续测. */
|
||||
static void test_take_rounds_keeps_pairing(void)
|
||||
{
|
||||
static void test_take_rounds_keeps_pairing(void) {
|
||||
puts("逐轮摘掉之后历史仍然自洽");
|
||||
Agent a;
|
||||
agent_init(&a);
|
||||
@@ -122,10 +116,11 @@ static void test_take_rounds_keeps_pairing(void)
|
||||
int rounds = 0;
|
||||
for (;;) {
|
||||
JsonValue *r = agent_take_last_round(&a);
|
||||
if (!r) break;
|
||||
if (!r)
|
||||
break;
|
||||
json_free(r);
|
||||
rounds++;
|
||||
check_pairing(&a); /* 每摘一轮都查一遍配对 */
|
||||
check_pairing(&a); /* 每摘一轮都查一遍配对 */
|
||||
}
|
||||
CHECK(rounds == 4, "共应摘掉 4 轮, 实际 %d", rounds);
|
||||
CHECK(agent_history_len(&a) == 1, "最后应只剩 system, 实际 %zu",
|
||||
@@ -133,8 +128,7 @@ static void test_take_rounds_keeps_pairing(void)
|
||||
agent_free(&a);
|
||||
}
|
||||
|
||||
static void test_take_last_round(void)
|
||||
{
|
||||
static void test_take_last_round(void) {
|
||||
puts("摘掉最近一轮 (/back 用)");
|
||||
Agent a;
|
||||
agent_init(&a);
|
||||
@@ -146,7 +140,8 @@ static void test_take_last_round(void)
|
||||
add_msg(&a, "user", "U2");
|
||||
add_msg(&a, "assistant", "A2");
|
||||
|
||||
CHECK(agent_history_len(&a) == 7, "初始 7 条, 实际 %zu", agent_history_len(&a));
|
||||
CHECK(agent_history_len(&a) == 7, "初始 7 条, 实际 %zu",
|
||||
agent_history_len(&a));
|
||||
|
||||
JsonValue *r = agent_take_last_round(&a);
|
||||
CHECK(r != NULL, "应摘到一轮");
|
||||
@@ -192,8 +187,7 @@ static void test_take_last_round(void)
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/* 造一条 assistant, 带 count 个工具调用 (id 依次是 c0, c1, ...) */
|
||||
static JsonValue *mk_assistant(size_t count)
|
||||
{
|
||||
static JsonValue *mk_assistant(size_t count) {
|
||||
JsonValue *m = json_new_object();
|
||||
json_object_set_string(m, "role", "assistant");
|
||||
JsonValue *tcs = json_new_array();
|
||||
@@ -213,8 +207,7 @@ static JsonValue *mk_assistant(size_t count)
|
||||
return m;
|
||||
}
|
||||
|
||||
static JsonValue *mk_tool(const char *id)
|
||||
{
|
||||
static JsonValue *mk_tool(const char *id) {
|
||||
JsonValue *m = json_new_object();
|
||||
json_object_set_string(m, "role", "tool");
|
||||
json_object_set_string(m, "tool_call_id", id);
|
||||
@@ -222,8 +215,7 @@ static JsonValue *mk_tool(const char *id)
|
||||
return m;
|
||||
}
|
||||
|
||||
static JsonValue *mk_plain(const char *role, const char *text)
|
||||
{
|
||||
static JsonValue *mk_plain(const char *role, const char *text) {
|
||||
JsonValue *m = json_new_object();
|
||||
json_object_set_string(m, "role", role);
|
||||
json_object_set_string(m, "content", text);
|
||||
@@ -231,35 +223,37 @@ static JsonValue *mk_plain(const char *role, const char *text)
|
||||
}
|
||||
|
||||
/* 数一数某个 assistant 之后紧跟的 tool 消息覆盖了几个 id */
|
||||
static const char *nth_role(const JsonValue *msgs, size_t i)
|
||||
{
|
||||
static const char *nth_role(const JsonValue *msgs, size_t i) {
|
||||
return json_get_string(json_array_get((JsonValue *)msgs, i), "role");
|
||||
}
|
||||
|
||||
static int pairing_ok(const JsonValue *msgs)
|
||||
{
|
||||
static int pairing_ok(const JsonValue *msgs) {
|
||||
size_t n = json_array_size((JsonValue *)msgs);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
JsonValue *m = json_array_get((JsonValue *)msgs, i);
|
||||
const char *r = json_get_string(m, "role");
|
||||
if (!r || strcmp(r, "assistant") != 0) continue;
|
||||
if (!r || strcmp(r, "assistant") != 0)
|
||||
continue;
|
||||
JsonValue *tcs = json_object_get(m, "tool_calls");
|
||||
if (!tcs || json_array_size(tcs) == 0) continue;
|
||||
if (!tcs || json_array_size(tcs) == 0)
|
||||
continue;
|
||||
for (size_t k = 0; k < json_array_size(tcs); k++) {
|
||||
const char *id = json_get_string(json_array_get(tcs, k), "id");
|
||||
size_t j = i + 1;
|
||||
int found = 0;
|
||||
for (; j < n && strcmp(nth_role(msgs, j), "tool") == 0; j++)
|
||||
if (strcmp(json_get_string(json_array_get((JsonValue *)msgs, j),
|
||||
"tool_call_id"), id) == 0) found = 1;
|
||||
if (!found) return 0;
|
||||
"tool_call_id"),
|
||||
id) == 0)
|
||||
found = 1;
|
||||
if (!found)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void test_repair_pairing(void)
|
||||
{
|
||||
static void test_repair_pairing(void) {
|
||||
int fixed = 0;
|
||||
|
||||
puts("结构体检: 本来没问题就不该动它");
|
||||
@@ -290,18 +284,19 @@ static void test_repair_pairing(void)
|
||||
if (r) {
|
||||
CHECK(pairing_ok(r), "修完之后配对必须成立");
|
||||
/* 两处: 给 c1 补一条占位 (它没被回应), 再把错位的那条 c1 结果丢掉
|
||||
* (它被 user 消息隔开, 已经不在 tool 段里了 —— 留着就是孤儿).
|
||||
* (它被 user 消息隔开, 已经不在 tool 段里了 —— 留着就是孤儿).
|
||||
* 丢掉真实结果听着可惜, 但结构坏了只能二选一: 要么丢它, 要么留一段
|
||||
* 服务端必然拒绝的历史. 模型会从占位消息里知道该重跑. */
|
||||
CHECK(fixed == 2, "应补 1 处、丢 1 处孤儿, 实际 %d", fixed);
|
||||
CHECK(json_array_size(r) == 5,
|
||||
"补一条、丢一条之后仍是 5 条, 实际 %zu", json_array_size(r));
|
||||
CHECK(json_array_size(r) == 5, "补一条、丢一条之后仍是 5 条, 实际 %zu",
|
||||
json_array_size(r));
|
||||
/* 占位消息必须紧跟在 assistant 的 tool 段里, 而不是被塞到最后 */
|
||||
CHECK(strcmp(nth_role(r, 2), "tool") == 0 &&
|
||||
strcmp(nth_role(r, 3), "tool") == 0,
|
||||
strcmp(nth_role(r, 3), "tool") == 0,
|
||||
"两条 tool 消息应紧跟在 assistant 之后");
|
||||
const char *c = json_get_string(json_array_get(r, 3), "content");
|
||||
CHECK(c && strstr(c, "没有执行") == NULL && strstr(c, "没有得到结果") != NULL,
|
||||
CHECK(c && strstr(c, "没有执行") == NULL &&
|
||||
strstr(c, "没有得到结果") != NULL,
|
||||
"占位消息要说明它没拿到结果, 实际 %s", c ? c : "(null)");
|
||||
json_free(r);
|
||||
}
|
||||
@@ -313,7 +308,8 @@ static void test_repair_pairing(void)
|
||||
json_array_push(tail, mk_assistant(1));
|
||||
fixed = 0;
|
||||
r = agent_repair_tool_pairing(tail, &fixed);
|
||||
CHECK(r && pairing_ok(r) && fixed == 1, "结尾缺的也要补上 (fixed=%d)", fixed);
|
||||
CHECK(r && pairing_ok(r) && fixed == 1, "结尾缺的也要补上 (fixed=%d)",
|
||||
fixed);
|
||||
json_free(r);
|
||||
json_free(tail);
|
||||
|
||||
@@ -329,7 +325,8 @@ static void test_repair_pairing(void)
|
||||
|
||||
puts("空输入与边界");
|
||||
fixed = 7;
|
||||
CHECK(agent_repair_tool_pairing(NULL, &fixed) == NULL && fixed == 0, "NULL 输入");
|
||||
CHECK(agent_repair_tool_pairing(NULL, &fixed) == NULL && fixed == 0,
|
||||
"NULL 输入");
|
||||
JsonValue *empty = json_new_array();
|
||||
CHECK(agent_repair_tool_pairing(empty, &fixed) == NULL, "空历史没什么可修");
|
||||
json_free(empty);
|
||||
@@ -346,8 +343,7 @@ static void test_repair_pairing(void)
|
||||
/* 面向用户的历史口径: 不含 system */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static void test_conversation_len(void)
|
||||
{
|
||||
static void test_conversation_len(void) {
|
||||
puts("历史条数: system 是配置, 不该算进对话");
|
||||
Agent a;
|
||||
agent_init(&a);
|
||||
@@ -382,8 +378,7 @@ static void test_conversation_len(void)
|
||||
agent_free(&b);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int main(void) {
|
||||
Agent a;
|
||||
agent_init(&a);
|
||||
CHECK(a.messages && a.messages->type == JSON_ARRAY, "messages 应为数组");
|
||||
@@ -397,11 +392,13 @@ int main(void)
|
||||
|
||||
/* 关键不变量: 重复设置 system 应替换而不是追加 */
|
||||
agent_add_system(&a, "S2");
|
||||
CHECK(count_role(&a, "system") == 1, "重复设置 system 不应叠加, 实际 %zu 条",
|
||||
count_role(&a, "system"));
|
||||
CHECK(strcmp(json_get_string(json_array_get(a.messages, 0), "content"), "S2") == 0,
|
||||
CHECK(count_role(&a, "system") == 1,
|
||||
"重复设置 system 不应叠加, 实际 %zu 条", count_role(&a, "system"));
|
||||
CHECK(strcmp(json_get_string(json_array_get(a.messages, 0), "content"),
|
||||
"S2") == 0,
|
||||
"新 system 应在第 0 条");
|
||||
CHECK(strcmp(json_get_string(json_array_get(a.messages, 1), "content"), "U1") == 0,
|
||||
CHECK(strcmp(json_get_string(json_array_get(a.messages, 1), "content"),
|
||||
"U1") == 0,
|
||||
"原有对话应保留");
|
||||
|
||||
agent_add_user(&a, "U2");
|
||||
@@ -411,7 +408,8 @@ int main(void)
|
||||
CHECK(agent_history_len(&a) == 1, "reset 后只保留 system, 实际 %zu",
|
||||
agent_history_len(&a));
|
||||
CHECK(count_role(&a, "system") == 1, "reset 后 system 仍在");
|
||||
CHECK(strcmp(json_get_string(json_array_get(a.messages, 0), "content"), "S2") == 0,
|
||||
CHECK(strcmp(json_get_string(json_array_get(a.messages, 0), "content"),
|
||||
"S2") == 0,
|
||||
"reset 保留的是最新 system");
|
||||
|
||||
/* 历史里没有 system 时 reset 应得到空历史 */
|
||||
|
||||
Reference in new issue
Block a user