chatccc 0.2.197 → 0.2.199
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-prompts/cursor_specific.md +13 -13
- package/bin/cccagent.mjs +17 -17
- package/config.sample.json +27 -27
- package/package.json +2 -1
- package/src/__tests__/agent-reload-config-rpc.test.ts +99 -99
- package/src/__tests__/builtin-chat-session.test.ts +277 -277
- package/src/__tests__/builtin-cli-json.test.ts +39 -39
- package/src/__tests__/builtin-config.test.ts +33 -33
- package/src/__tests__/builtin-context.test.ts +163 -163
- package/src/__tests__/builtin-file-tools.test.ts +224 -224
- package/src/__tests__/builtin-session-select.test.ts +116 -116
- package/src/__tests__/builtin-sigint.test.ts +56 -56
- package/src/__tests__/cards.test.ts +109 -109
- package/src/__tests__/ccc-adapter.test.ts +114 -114
- package/src/__tests__/chatgpt-subscription-rpc.test.ts +89 -89
- package/src/__tests__/chatgpt-subscription.test.ts +135 -135
- package/src/__tests__/chrome-devtools-guard.test.ts +165 -165
- package/src/__tests__/claude-raw-stream-log.test.ts +87 -87
- package/src/__tests__/codex-raw-stream-log.test.ts +163 -120
- package/src/__tests__/config-reload.test.ts +10 -10
- package/src/__tests__/config-sample.test.ts +18 -18
- package/src/__tests__/cursor-adapter.test.ts +114 -1
- package/src/__tests__/feishu-avatar.test.ts +40 -40
- package/src/__tests__/jsonl-stream.test.ts +79 -0
- package/src/__tests__/orchestrator.test.ts +200 -200
- package/src/__tests__/raw-stream-log.test.ts +106 -106
- package/src/__tests__/session.test.ts +40 -40
- package/src/__tests__/sim-platform.test.ts +12 -12
- package/src/__tests__/web-ui.test.ts +209 -209
- package/src/adapters/ccc-adapter.ts +121 -121
- package/src/adapters/claude-adapter.ts +603 -603
- package/src/adapters/codex-adapter.ts +380 -392
- package/src/adapters/cursor-adapter.ts +56 -30
- package/src/adapters/jsonl-stream.ts +157 -0
- package/src/adapters/raw-stream-log.ts +124 -124
- package/src/agent-reload-config-rpc.ts +34 -34
- package/src/builtin/cli.ts +473 -473
- package/src/builtin/context.ts +323 -323
- package/src/builtin/file-tools.ts +1072 -1072
- package/src/builtin/index.ts +404 -404
- package/src/builtin/session-select.ts +48 -48
- package/src/builtin/sigint.ts +50 -50
- package/src/cards.ts +195 -195
- package/src/chatgpt-subscription-rpc.ts +27 -27
- package/src/chatgpt-subscription.ts +299 -299
- package/src/chrome-devtools-guard.ts +318 -318
- package/src/config.ts +125 -125
- package/src/feishu-api.ts +49 -49
- package/src/orchestrator.ts +179 -179
- package/src/runtime-reload.ts +34 -34
- package/src/session.ts +141 -141
- package/src/web-ui.ts +205 -205
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { ChatSession } from "../builtin/index.ts";
|
|
4
|
-
import { config } from "../config.ts";
|
|
5
|
-
|
|
6
|
-
const originalDeepSeekApiKey = process.env.DEEPSEEK_API_KEY;
|
|
7
|
-
const originalCccConfig = structuredClone(config.ccc);
|
|
8
|
-
|
|
9
|
-
afterEach(() => {
|
|
10
|
-
if (originalDeepSeekApiKey === undefined) {
|
|
11
|
-
delete process.env.DEEPSEEK_API_KEY;
|
|
12
|
-
} else {
|
|
13
|
-
process.env.DEEPSEEK_API_KEY = originalDeepSeekApiKey;
|
|
14
|
-
}
|
|
15
|
-
config.ccc = structuredClone(originalCccConfig);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
describe("builtin ChatSession config", () => {
|
|
19
|
-
it("does not fall back to DEEPSEEK_API_KEY environment variable", () => {
|
|
20
|
-
config.ccc = {
|
|
21
|
-
DEEPSEEK_API_KEY: "",
|
|
22
|
-
DEEPSEEK_BASE_URL: "https://api.deepseek.com/v1",
|
|
23
|
-
model: "deepseek-v4-pro",
|
|
24
|
-
};
|
|
25
|
-
process.env.DEEPSEEK_API_KEY = "sk-env-should-not-be-used";
|
|
26
|
-
|
|
27
|
-
expect(() => new ChatSession()).toThrow("ccc.DEEPSEEK_API_KEY 未设置");
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it("allows constructor parameters to override config defaults", () => {
|
|
31
|
-
expect(() => new ChatSession({ apiKey: "sk-test" })).not.toThrow();
|
|
32
|
-
});
|
|
33
|
-
});
|
|
1
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { ChatSession } from "../builtin/index.ts";
|
|
4
|
+
import { config } from "../config.ts";
|
|
5
|
+
|
|
6
|
+
const originalDeepSeekApiKey = process.env.DEEPSEEK_API_KEY;
|
|
7
|
+
const originalCccConfig = structuredClone(config.ccc);
|
|
8
|
+
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
if (originalDeepSeekApiKey === undefined) {
|
|
11
|
+
delete process.env.DEEPSEEK_API_KEY;
|
|
12
|
+
} else {
|
|
13
|
+
process.env.DEEPSEEK_API_KEY = originalDeepSeekApiKey;
|
|
14
|
+
}
|
|
15
|
+
config.ccc = structuredClone(originalCccConfig);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe("builtin ChatSession config", () => {
|
|
19
|
+
it("does not fall back to DEEPSEEK_API_KEY environment variable", () => {
|
|
20
|
+
config.ccc = {
|
|
21
|
+
DEEPSEEK_API_KEY: "",
|
|
22
|
+
DEEPSEEK_BASE_URL: "https://api.deepseek.com/v1",
|
|
23
|
+
model: "deepseek-v4-pro",
|
|
24
|
+
};
|
|
25
|
+
process.env.DEEPSEEK_API_KEY = "sk-env-should-not-be-used";
|
|
26
|
+
|
|
27
|
+
expect(() => new ChatSession()).toThrow("ccc.DEEPSEEK_API_KEY 未设置");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("allows constructor parameters to override config defaults", () => {
|
|
31
|
+
expect(() => new ChatSession({ apiKey: "sk-test" })).not.toThrow();
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -1,163 +1,163 @@
|
|
|
1
|
-
import { mkdtemp, readFile } from "node:fs/promises";
|
|
2
|
-
import { tmpdir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
|
|
5
|
-
import { describe, expect, it } from "vitest";
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
BuiltinContextManager,
|
|
9
|
-
estimateBuiltinContextTokens,
|
|
10
|
-
listBuiltinContextSessions,
|
|
11
|
-
newBuiltinSessionId,
|
|
12
|
-
serializeMessagesForSummary,
|
|
13
|
-
} from "../builtin/context.ts";
|
|
14
|
-
|
|
15
|
-
describe("BuiltinContextManager", () => {
|
|
16
|
-
it("persists and restores summary, messages, and total message count", async () => {
|
|
17
|
-
const dir = await mkdtemp(join(tmpdir(), "chatccc-builtin-context-"));
|
|
18
|
-
|
|
19
|
-
const first = new BuiltinContextManager({
|
|
20
|
-
persist: true,
|
|
21
|
-
contextDir: dir,
|
|
22
|
-
sessionId: "persisted",
|
|
23
|
-
});
|
|
24
|
-
first.setSummary("## 用户目标\n- 保留这个摘要");
|
|
25
|
-
first.appendMessage({ role: "user", content: "第一轮" });
|
|
26
|
-
first.appendMessage({ role: "assistant", content: "第一轮回复" });
|
|
27
|
-
first.save();
|
|
28
|
-
|
|
29
|
-
const restored = new BuiltinContextManager({
|
|
30
|
-
persist: true,
|
|
31
|
-
contextDir: dir,
|
|
32
|
-
sessionId: "persisted",
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
expect(restored.summary).toContain("保留这个摘要");
|
|
36
|
-
expect(restored.messages).toEqual([
|
|
37
|
-
{ role: "user", content: "第一轮" },
|
|
38
|
-
{ role: "assistant", content: "第一轮回复" },
|
|
39
|
-
]);
|
|
40
|
-
expect(restored.totalMessages).toBe(2);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it("selects only older messages for compaction and keeps recent messages raw", () => {
|
|
44
|
-
const context = new BuiltinContextManager({
|
|
45
|
-
compactAtTokens: 1,
|
|
46
|
-
keepRecentMessages: 2,
|
|
47
|
-
persist: false,
|
|
48
|
-
});
|
|
49
|
-
context.appendMessage({ role: "user", content: "旧用户消息" });
|
|
50
|
-
context.appendMessage({ role: "assistant", content: "旧助手回复" });
|
|
51
|
-
context.appendMessage({ role: "user", content: "近期用户消息" });
|
|
52
|
-
context.appendMessage({ role: "assistant", content: "近期助手回复" });
|
|
53
|
-
|
|
54
|
-
const plan = context.planCompaction();
|
|
55
|
-
|
|
56
|
-
expect(plan).not.toBeNull();
|
|
57
|
-
expect(plan?.oldMessages).toEqual([
|
|
58
|
-
{ role: "user", content: "旧用户消息" },
|
|
59
|
-
{ role: "assistant", content: "旧助手回复" },
|
|
60
|
-
]);
|
|
61
|
-
expect(plan?.recentMessages).toEqual([
|
|
62
|
-
{ role: "user", content: "近期用户消息" },
|
|
63
|
-
{ role: "assistant", content: "近期助手回复" },
|
|
64
|
-
]);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it("applies a compacted summary and builds model messages with summary plus recent raw turns", () => {
|
|
68
|
-
const context = new BuiltinContextManager({
|
|
69
|
-
compactAtTokens: 1,
|
|
70
|
-
keepRecentMessages: 1,
|
|
71
|
-
persist: false,
|
|
72
|
-
});
|
|
73
|
-
context.appendMessage({ role: "user", content: "old" });
|
|
74
|
-
context.appendMessage({ role: "assistant", content: "recent" });
|
|
75
|
-
|
|
76
|
-
const plan = context.planCompaction();
|
|
77
|
-
expect(plan).not.toBeNull();
|
|
78
|
-
context.applyCompaction("## 当前任务状态\n- 已压缩旧上下文", plan!);
|
|
79
|
-
|
|
80
|
-
expect(context.summary).toContain("已压缩旧上下文");
|
|
81
|
-
expect(context.messages).toEqual([{ role: "assistant", content: "recent" }]);
|
|
82
|
-
expect(context.buildModelMessages()).toEqual([
|
|
83
|
-
{
|
|
84
|
-
role: "user",
|
|
85
|
-
content: expect.stringContaining("较早对话摘要"),
|
|
86
|
-
},
|
|
87
|
-
{ role: "assistant", content: "recent" },
|
|
88
|
-
]);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it("reset clears memory and the persisted context file", async () => {
|
|
92
|
-
const dir = await mkdtemp(join(tmpdir(), "chatccc-builtin-context-reset-"));
|
|
93
|
-
const context = new BuiltinContextManager({
|
|
94
|
-
persist: true,
|
|
95
|
-
contextDir: dir,
|
|
96
|
-
sessionId: "reset",
|
|
97
|
-
});
|
|
98
|
-
context.setSummary("summary");
|
|
99
|
-
context.appendMessage({ role: "user", content: "hello" });
|
|
100
|
-
context.save();
|
|
101
|
-
|
|
102
|
-
context.reset();
|
|
103
|
-
|
|
104
|
-
expect(context.summary).toBe("");
|
|
105
|
-
expect(context.messages).toEqual([]);
|
|
106
|
-
expect(context.totalMessages).toBe(0);
|
|
107
|
-
|
|
108
|
-
const raw = await readFile(join(dir, "reset", "context.json"), "utf8");
|
|
109
|
-
const persisted = JSON.parse(raw) as { summary: string; messages: unknown[]; totalMessages: number };
|
|
110
|
-
expect(persisted.summary).toBe("");
|
|
111
|
-
expect(persisted.messages).toEqual([]);
|
|
112
|
-
expect(persisted.totalMessages).toBe(0);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it("persists cwd metadata and lists saved sessions newest first", async () => {
|
|
116
|
-
const dir = await mkdtemp(join(tmpdir(), "chatccc-builtin-context-list-"));
|
|
117
|
-
|
|
118
|
-
const first = new BuiltinContextManager({
|
|
119
|
-
persist: true,
|
|
120
|
-
contextDir: dir,
|
|
121
|
-
sessionId: "older",
|
|
122
|
-
cwd: "C:\\repo-a",
|
|
123
|
-
});
|
|
124
|
-
first.appendMessage({ role: "user", content: "old" });
|
|
125
|
-
|
|
126
|
-
const second = new BuiltinContextManager({
|
|
127
|
-
persist: true,
|
|
128
|
-
contextDir: dir,
|
|
129
|
-
sessionId: "newer",
|
|
130
|
-
cwd: "C:\\repo-b",
|
|
131
|
-
});
|
|
132
|
-
second.appendMessage({ role: "user", content: "new" });
|
|
133
|
-
|
|
134
|
-
const sessions = listBuiltinContextSessions(dir);
|
|
135
|
-
|
|
136
|
-
expect(sessions.map((s) => s.sessionId)).toEqual(["newer", "older"]);
|
|
137
|
-
expect(sessions[0]).toEqual(expect.objectContaining({
|
|
138
|
-
cwd: "C:\\repo-b",
|
|
139
|
-
totalMessages: 1,
|
|
140
|
-
hasSummary: false,
|
|
141
|
-
}));
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
describe("builtin context helpers", () => {
|
|
146
|
-
it("creates readable timestamp-based session ids", () => {
|
|
147
|
-
const id = newBuiltinSessionId(new Date(2026, 6, 2, 12, 15, 30), "a1b2c3");
|
|
148
|
-
|
|
149
|
-
expect(id).toBe("session-20260702-121530-a1b2c3");
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it("estimates tokens from summary and messages", () => {
|
|
153
|
-
expect(estimateBuiltinContextTokens("abc", [{ role: "user", content: "abcdef" }]))
|
|
154
|
-
.toBeGreaterThanOrEqual(3);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it("serializes messages for summarization with stable role labels", () => {
|
|
158
|
-
expect(serializeMessagesForSummary([
|
|
159
|
-
{ role: "user", content: "你好" },
|
|
160
|
-
{ role: "assistant", content: "收到" },
|
|
161
|
-
])).toContain("user");
|
|
162
|
-
});
|
|
163
|
-
});
|
|
1
|
+
import { mkdtemp, readFile } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
|
|
5
|
+
import { describe, expect, it } from "vitest";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
BuiltinContextManager,
|
|
9
|
+
estimateBuiltinContextTokens,
|
|
10
|
+
listBuiltinContextSessions,
|
|
11
|
+
newBuiltinSessionId,
|
|
12
|
+
serializeMessagesForSummary,
|
|
13
|
+
} from "../builtin/context.ts";
|
|
14
|
+
|
|
15
|
+
describe("BuiltinContextManager", () => {
|
|
16
|
+
it("persists and restores summary, messages, and total message count", async () => {
|
|
17
|
+
const dir = await mkdtemp(join(tmpdir(), "chatccc-builtin-context-"));
|
|
18
|
+
|
|
19
|
+
const first = new BuiltinContextManager({
|
|
20
|
+
persist: true,
|
|
21
|
+
contextDir: dir,
|
|
22
|
+
sessionId: "persisted",
|
|
23
|
+
});
|
|
24
|
+
first.setSummary("## 用户目标\n- 保留这个摘要");
|
|
25
|
+
first.appendMessage({ role: "user", content: "第一轮" });
|
|
26
|
+
first.appendMessage({ role: "assistant", content: "第一轮回复" });
|
|
27
|
+
first.save();
|
|
28
|
+
|
|
29
|
+
const restored = new BuiltinContextManager({
|
|
30
|
+
persist: true,
|
|
31
|
+
contextDir: dir,
|
|
32
|
+
sessionId: "persisted",
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
expect(restored.summary).toContain("保留这个摘要");
|
|
36
|
+
expect(restored.messages).toEqual([
|
|
37
|
+
{ role: "user", content: "第一轮" },
|
|
38
|
+
{ role: "assistant", content: "第一轮回复" },
|
|
39
|
+
]);
|
|
40
|
+
expect(restored.totalMessages).toBe(2);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("selects only older messages for compaction and keeps recent messages raw", () => {
|
|
44
|
+
const context = new BuiltinContextManager({
|
|
45
|
+
compactAtTokens: 1,
|
|
46
|
+
keepRecentMessages: 2,
|
|
47
|
+
persist: false,
|
|
48
|
+
});
|
|
49
|
+
context.appendMessage({ role: "user", content: "旧用户消息" });
|
|
50
|
+
context.appendMessage({ role: "assistant", content: "旧助手回复" });
|
|
51
|
+
context.appendMessage({ role: "user", content: "近期用户消息" });
|
|
52
|
+
context.appendMessage({ role: "assistant", content: "近期助手回复" });
|
|
53
|
+
|
|
54
|
+
const plan = context.planCompaction();
|
|
55
|
+
|
|
56
|
+
expect(plan).not.toBeNull();
|
|
57
|
+
expect(plan?.oldMessages).toEqual([
|
|
58
|
+
{ role: "user", content: "旧用户消息" },
|
|
59
|
+
{ role: "assistant", content: "旧助手回复" },
|
|
60
|
+
]);
|
|
61
|
+
expect(plan?.recentMessages).toEqual([
|
|
62
|
+
{ role: "user", content: "近期用户消息" },
|
|
63
|
+
{ role: "assistant", content: "近期助手回复" },
|
|
64
|
+
]);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("applies a compacted summary and builds model messages with summary plus recent raw turns", () => {
|
|
68
|
+
const context = new BuiltinContextManager({
|
|
69
|
+
compactAtTokens: 1,
|
|
70
|
+
keepRecentMessages: 1,
|
|
71
|
+
persist: false,
|
|
72
|
+
});
|
|
73
|
+
context.appendMessage({ role: "user", content: "old" });
|
|
74
|
+
context.appendMessage({ role: "assistant", content: "recent" });
|
|
75
|
+
|
|
76
|
+
const plan = context.planCompaction();
|
|
77
|
+
expect(plan).not.toBeNull();
|
|
78
|
+
context.applyCompaction("## 当前任务状态\n- 已压缩旧上下文", plan!);
|
|
79
|
+
|
|
80
|
+
expect(context.summary).toContain("已压缩旧上下文");
|
|
81
|
+
expect(context.messages).toEqual([{ role: "assistant", content: "recent" }]);
|
|
82
|
+
expect(context.buildModelMessages()).toEqual([
|
|
83
|
+
{
|
|
84
|
+
role: "user",
|
|
85
|
+
content: expect.stringContaining("较早对话摘要"),
|
|
86
|
+
},
|
|
87
|
+
{ role: "assistant", content: "recent" },
|
|
88
|
+
]);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("reset clears memory and the persisted context file", async () => {
|
|
92
|
+
const dir = await mkdtemp(join(tmpdir(), "chatccc-builtin-context-reset-"));
|
|
93
|
+
const context = new BuiltinContextManager({
|
|
94
|
+
persist: true,
|
|
95
|
+
contextDir: dir,
|
|
96
|
+
sessionId: "reset",
|
|
97
|
+
});
|
|
98
|
+
context.setSummary("summary");
|
|
99
|
+
context.appendMessage({ role: "user", content: "hello" });
|
|
100
|
+
context.save();
|
|
101
|
+
|
|
102
|
+
context.reset();
|
|
103
|
+
|
|
104
|
+
expect(context.summary).toBe("");
|
|
105
|
+
expect(context.messages).toEqual([]);
|
|
106
|
+
expect(context.totalMessages).toBe(0);
|
|
107
|
+
|
|
108
|
+
const raw = await readFile(join(dir, "reset", "context.json"), "utf8");
|
|
109
|
+
const persisted = JSON.parse(raw) as { summary: string; messages: unknown[]; totalMessages: number };
|
|
110
|
+
expect(persisted.summary).toBe("");
|
|
111
|
+
expect(persisted.messages).toEqual([]);
|
|
112
|
+
expect(persisted.totalMessages).toBe(0);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("persists cwd metadata and lists saved sessions newest first", async () => {
|
|
116
|
+
const dir = await mkdtemp(join(tmpdir(), "chatccc-builtin-context-list-"));
|
|
117
|
+
|
|
118
|
+
const first = new BuiltinContextManager({
|
|
119
|
+
persist: true,
|
|
120
|
+
contextDir: dir,
|
|
121
|
+
sessionId: "older",
|
|
122
|
+
cwd: "C:\\repo-a",
|
|
123
|
+
});
|
|
124
|
+
first.appendMessage({ role: "user", content: "old" });
|
|
125
|
+
|
|
126
|
+
const second = new BuiltinContextManager({
|
|
127
|
+
persist: true,
|
|
128
|
+
contextDir: dir,
|
|
129
|
+
sessionId: "newer",
|
|
130
|
+
cwd: "C:\\repo-b",
|
|
131
|
+
});
|
|
132
|
+
second.appendMessage({ role: "user", content: "new" });
|
|
133
|
+
|
|
134
|
+
const sessions = listBuiltinContextSessions(dir);
|
|
135
|
+
|
|
136
|
+
expect(sessions.map((s) => s.sessionId)).toEqual(["newer", "older"]);
|
|
137
|
+
expect(sessions[0]).toEqual(expect.objectContaining({
|
|
138
|
+
cwd: "C:\\repo-b",
|
|
139
|
+
totalMessages: 1,
|
|
140
|
+
hasSummary: false,
|
|
141
|
+
}));
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe("builtin context helpers", () => {
|
|
146
|
+
it("creates readable timestamp-based session ids", () => {
|
|
147
|
+
const id = newBuiltinSessionId(new Date(2026, 6, 2, 12, 15, 30), "a1b2c3");
|
|
148
|
+
|
|
149
|
+
expect(id).toBe("session-20260702-121530-a1b2c3");
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("estimates tokens from summary and messages", () => {
|
|
153
|
+
expect(estimateBuiltinContextTokens("abc", [{ role: "user", content: "abcdef" }]))
|
|
154
|
+
.toBeGreaterThanOrEqual(3);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("serializes messages for summarization with stable role labels", () => {
|
|
158
|
+
expect(serializeMessagesForSummary([
|
|
159
|
+
{ role: "user", content: "你好" },
|
|
160
|
+
{ role: "assistant", content: "收到" },
|
|
161
|
+
])).toContain("user");
|
|
162
|
+
});
|
|
163
|
+
});
|