chatccc 0.2.137 → 0.2.138
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/config.sample.json +1 -1
- package/package.json +2 -2
- package/src/__tests__/config-reload.test.ts +18 -16
- package/src/adapters/claude-adapter.ts +44 -27
- package/src/config.ts +3 -2
package/config.sample.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chatccc",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.138",
|
|
4
4
|
"description": "Feishu bot bridge for Claude Code",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@ai-sdk/openai-compatible": "^2.0.47",
|
|
44
|
-
"@anthropic-ai/claude-agent-sdk": "0.
|
|
44
|
+
"@anthropic-ai/claude-agent-sdk": "0.2.133",
|
|
45
45
|
"@larksuiteoapi/node-sdk": "^1.59.0",
|
|
46
46
|
"@openilink/openilink-sdk-node": "^0.6.0",
|
|
47
47
|
"ai": "^6.0.184",
|
|
@@ -8,10 +8,11 @@ import {
|
|
|
8
8
|
APP_ID,
|
|
9
9
|
APP_SECRET,
|
|
10
10
|
CHATCCC_PORT,
|
|
11
|
-
CLAUDE_API_KEY,
|
|
12
|
-
CLAUDE_BASE_URL,
|
|
13
|
-
CLAUDE_EFFORT,
|
|
14
|
-
|
|
11
|
+
CLAUDE_API_KEY,
|
|
12
|
+
CLAUDE_BASE_URL,
|
|
13
|
+
CLAUDE_EFFORT,
|
|
14
|
+
CLAUDE_MAX_TURN,
|
|
15
|
+
CLAUDE_MODEL,
|
|
15
16
|
CLAUDE_SUBAGENT_MODEL,
|
|
16
17
|
CURSOR_AGENT_ARGS,
|
|
17
18
|
CURSOR_AGENT_COMMAND,
|
|
@@ -81,7 +82,7 @@ describe("applyLoadedConfig — 刷新 export let 常量", () => {
|
|
|
81
82
|
expect(APP_SECRET).toBe("NEW_APP_SECRET");
|
|
82
83
|
});
|
|
83
84
|
|
|
84
|
-
it("更新 Claude 配置(model / subagentModel / effort / apiKey / baseUrl)", () => {
|
|
85
|
+
it("更新 Claude 配置(model / subagentModel / effort / maxTurn / apiKey / baseUrl)", () => {
|
|
85
86
|
applyLoadedConfig({
|
|
86
87
|
...structuredClone(baseAppConfig),
|
|
87
88
|
claude: {
|
|
@@ -89,17 +90,18 @@ describe("applyLoadedConfig — 刷新 export let 常量", () => {
|
|
|
89
90
|
defaultAgent: true,
|
|
90
91
|
model: "claude-sonnet-4-6",
|
|
91
92
|
subagentModel: "claude-haiku-4-5-20251001",
|
|
92
|
-
effort: "high",
|
|
93
|
-
apiKey: "sk-test",
|
|
94
|
-
baseUrl: "https://api.example.com",
|
|
95
|
-
maxTurn:
|
|
96
|
-
},
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
expect(CLAUDE_MODEL).toBe("claude-sonnet-4-6");
|
|
100
|
-
expect(CLAUDE_SUBAGENT_MODEL).toBe("claude-haiku-4-5-20251001");
|
|
101
|
-
expect(CLAUDE_EFFORT).toBe("high");
|
|
102
|
-
expect(
|
|
93
|
+
effort: "high",
|
|
94
|
+
apiKey: "sk-test",
|
|
95
|
+
baseUrl: "https://api.example.com",
|
|
96
|
+
maxTurn: 7,
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
expect(CLAUDE_MODEL).toBe("claude-sonnet-4-6");
|
|
101
|
+
expect(CLAUDE_SUBAGENT_MODEL).toBe("claude-haiku-4-5-20251001");
|
|
102
|
+
expect(CLAUDE_EFFORT).toBe("high");
|
|
103
|
+
expect(CLAUDE_MAX_TURN).toBe(7);
|
|
104
|
+
expect(CLAUDE_API_KEY).toBe("sk-test");
|
|
103
105
|
expect(CLAUDE_BASE_URL).toBe("https://api.example.com");
|
|
104
106
|
});
|
|
105
107
|
|
|
@@ -5,9 +5,12 @@ import { fileURLToPath } from "node:url";
|
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
7
|
getSessionInfo as sdkGetSessionInfo,
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
unstable_v2_createSession,
|
|
9
|
+
unstable_v2_resumeSession,
|
|
10
10
|
type SDKMessage,
|
|
11
|
+
type SDKSession,
|
|
12
|
+
type SDKSessionOptions,
|
|
13
|
+
type EffortLevel,
|
|
11
14
|
} from "@anthropic-ai/claude-agent-sdk";
|
|
12
15
|
|
|
13
16
|
import type {
|
|
@@ -220,6 +223,17 @@ export function buildClaudePromptText(
|
|
|
220
223
|
].join("\n");
|
|
221
224
|
}
|
|
222
225
|
|
|
226
|
+
type ClaudeSdkSessionOptions = Omit<SDKSessionOptions, "model"> & {
|
|
227
|
+
model?: string;
|
|
228
|
+
abortController?: AbortController;
|
|
229
|
+
autoCompactEnabled?: boolean;
|
|
230
|
+
effort?: EffortLevel | number;
|
|
231
|
+
maxTurns?: number;
|
|
232
|
+
mcpServers?: Record<string, unknown>;
|
|
233
|
+
skills?: "all";
|
|
234
|
+
stderr?: (data: string) => void;
|
|
235
|
+
};
|
|
236
|
+
|
|
223
237
|
function buildSdkOptions(args: {
|
|
224
238
|
cwd: string;
|
|
225
239
|
model: string;
|
|
@@ -230,9 +244,8 @@ function buildSdkOptions(args: {
|
|
|
230
244
|
baseUrl?: string;
|
|
231
245
|
maxTurn: number;
|
|
232
246
|
planMode?: boolean;
|
|
233
|
-
resume?: string;
|
|
234
247
|
abortController?: AbortController;
|
|
235
|
-
}):
|
|
248
|
+
}): ClaudeSdkSessionOptions {
|
|
236
249
|
const {
|
|
237
250
|
cwd,
|
|
238
251
|
model,
|
|
@@ -243,17 +256,16 @@ function buildSdkOptions(args: {
|
|
|
243
256
|
baseUrl,
|
|
244
257
|
maxTurn,
|
|
245
258
|
planMode,
|
|
246
|
-
resume,
|
|
247
259
|
abortController,
|
|
248
260
|
} = args;
|
|
249
261
|
|
|
250
|
-
const options:
|
|
262
|
+
const options: ClaudeSdkSessionOptions = {
|
|
251
263
|
cwd,
|
|
252
264
|
abortController,
|
|
253
265
|
settingSources: ["user", "project", "local"] as SettingSource[],
|
|
254
266
|
permissionMode: planMode ? "plan" : "bypassPermissions",
|
|
267
|
+
autoCompactEnabled: true,
|
|
255
268
|
maxTurns: maxTurn,
|
|
256
|
-
maxBudgetUsd: 999999999,
|
|
257
269
|
skills: "all",
|
|
258
270
|
stderr: (data) => {
|
|
259
271
|
const trimmed = data.trim();
|
|
@@ -270,10 +282,7 @@ function buildSdkOptions(args: {
|
|
|
270
282
|
options.model = model;
|
|
271
283
|
}
|
|
272
284
|
if (!isEmpty(effort)) {
|
|
273
|
-
options.effort = effort as
|
|
274
|
-
}
|
|
275
|
-
if (resume) {
|
|
276
|
-
options.resume = resume;
|
|
285
|
+
options.effort = effort as ClaudeSdkSessionOptions["effort"];
|
|
277
286
|
}
|
|
278
287
|
|
|
279
288
|
const env = buildSdkEnv(subagentModel, apiKey, baseUrl);
|
|
@@ -283,7 +292,7 @@ function buildSdkOptions(args: {
|
|
|
283
292
|
|
|
284
293
|
const mcpServers = readMcpServersConfig();
|
|
285
294
|
if (mcpServers) {
|
|
286
|
-
options.mcpServers = mcpServers
|
|
295
|
+
options.mcpServers = mcpServers;
|
|
287
296
|
}
|
|
288
297
|
|
|
289
298
|
return options;
|
|
@@ -307,6 +316,14 @@ function bridgeAbortSignal(
|
|
|
307
316
|
return () => signal.removeEventListener("abort", onAbort);
|
|
308
317
|
}
|
|
309
318
|
|
|
319
|
+
function closeSdkSession(session: SDKSession): void {
|
|
320
|
+
session.close();
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function toSdkSessionOptions(options: ClaudeSdkSessionOptions): SDKSessionOptions {
|
|
324
|
+
return options as SDKSessionOptions;
|
|
325
|
+
}
|
|
326
|
+
|
|
310
327
|
class ClaudeAdapter implements ToolAdapter {
|
|
311
328
|
readonly displayName = "Claude Code";
|
|
312
329
|
readonly sessionDescPrefix = "Claude Code Session:";
|
|
@@ -334,9 +351,8 @@ class ClaudeAdapter implements ToolAdapter {
|
|
|
334
351
|
logMcpConfig();
|
|
335
352
|
const abortController = new AbortController();
|
|
336
353
|
let sessionId: string | undefined;
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
options: buildSdkOptions({
|
|
354
|
+
const session = unstable_v2_createSession(
|
|
355
|
+
toSdkSessionOptions(buildSdkOptions({
|
|
340
356
|
cwd,
|
|
341
357
|
model: this.model,
|
|
342
358
|
effort: this.effort,
|
|
@@ -346,11 +362,12 @@ class ClaudeAdapter implements ToolAdapter {
|
|
|
346
362
|
baseUrl: this.baseUrl,
|
|
347
363
|
maxTurn: this.maxTurn,
|
|
348
364
|
abortController,
|
|
349
|
-
}),
|
|
350
|
-
|
|
365
|
+
})),
|
|
366
|
+
);
|
|
351
367
|
|
|
352
368
|
try {
|
|
353
|
-
|
|
369
|
+
await session.send("ok");
|
|
370
|
+
for await (const raw of session.stream()) {
|
|
354
371
|
const msg = toMessageLike(raw);
|
|
355
372
|
if (msg.session_id && !sessionId) {
|
|
356
373
|
sessionId = msg.session_id;
|
|
@@ -363,7 +380,7 @@ class ClaudeAdapter implements ToolAdapter {
|
|
|
363
380
|
}
|
|
364
381
|
}
|
|
365
382
|
} finally {
|
|
366
|
-
|
|
383
|
+
closeSdkSession(session);
|
|
367
384
|
}
|
|
368
385
|
|
|
369
386
|
if (sessionId) return { sessionId };
|
|
@@ -382,9 +399,9 @@ class ClaudeAdapter implements ToolAdapter {
|
|
|
382
399
|
if (abortController.signal.aborted) return;
|
|
383
400
|
let aborted = false;
|
|
384
401
|
|
|
385
|
-
const
|
|
386
|
-
|
|
387
|
-
|
|
402
|
+
const session = unstable_v2_resumeSession(
|
|
403
|
+
sessionId,
|
|
404
|
+
toSdkSessionOptions(buildSdkOptions({
|
|
388
405
|
cwd,
|
|
389
406
|
model: this.model,
|
|
390
407
|
effort: this.effort,
|
|
@@ -394,13 +411,13 @@ class ClaudeAdapter implements ToolAdapter {
|
|
|
394
411
|
baseUrl: this.baseUrl,
|
|
395
412
|
maxTurn: this.maxTurn,
|
|
396
413
|
planMode: options?.planMode,
|
|
397
|
-
resume: sessionId,
|
|
398
414
|
abortController,
|
|
399
|
-
}),
|
|
400
|
-
|
|
415
|
+
})),
|
|
416
|
+
);
|
|
401
417
|
|
|
402
418
|
try {
|
|
403
|
-
|
|
419
|
+
await session.send(buildClaudePromptText(userText));
|
|
420
|
+
for await (const raw of session.stream()) {
|
|
404
421
|
if (abortController.signal.aborted) {
|
|
405
422
|
aborted = true;
|
|
406
423
|
break;
|
|
@@ -423,8 +440,8 @@ class ClaudeAdapter implements ToolAdapter {
|
|
|
423
440
|
removeAbortListener?.();
|
|
424
441
|
if (aborted || abortController.signal.aborted) {
|
|
425
442
|
abortController.abort();
|
|
426
|
-
stream.close();
|
|
427
443
|
}
|
|
444
|
+
closeSdkSession(session);
|
|
428
445
|
}
|
|
429
446
|
}
|
|
430
447
|
|
package/src/config.ts
CHANGED
|
@@ -605,8 +605,9 @@ export function applyLoadedConfig(next: AppConfig): void {
|
|
|
605
605
|
ILINK_REUSE_TOKEN_ON_START = next.platforms.ilink.reuseTokenOnStart ?? true;
|
|
606
606
|
CLAUDE_MODEL = next.claude.model;
|
|
607
607
|
CLAUDE_SUBAGENT_MODEL = next.claude.subagentModel;
|
|
608
|
-
CLAUDE_EFFORT = next.claude.effort;
|
|
609
|
-
|
|
608
|
+
CLAUDE_EFFORT = next.claude.effort;
|
|
609
|
+
CLAUDE_MAX_TURN = next.claude.maxTurn;
|
|
610
|
+
CLAUDE_API_KEY = next.claude.apiKey;
|
|
610
611
|
CLAUDE_BASE_URL = next.claude.baseUrl;
|
|
611
612
|
GIT_TIMEOUT_SECONDS = next.gitTimeoutSeconds;
|
|
612
613
|
GIT_TIMEOUT_MS = GIT_TIMEOUT_SECONDS * 1000;
|