@wu529778790/open-im 1.11.1-beta.8 → 1.11.1-beta.9
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/dist/adapters/claude-sdk-adapter.d.ts +35 -1
- package/dist/adapters/claude-sdk-adapter.js +135 -2
- package/dist/adapters/tool-adapter.interface.d.ts +4 -0
- package/dist/commands/handler.d.ts +6 -0
- package/dist/commands/handler.js +181 -0
- package/dist/constants.js +0 -1
- package/package.json +1 -1
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* - 支持 resume/cwd/model 等 options,无需 process.chdir hack
|
|
7
7
|
* - SDK 内部管理 session 生命周期,无需手动维护 session pool
|
|
8
8
|
*/
|
|
9
|
-
import
|
|
9
|
+
import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
10
|
+
import type { SDKSessionInfo, SessionMessage, ModelInfo, SDKControlGetContextUsageResponse, AccountInfo } from '@anthropic-ai/claude-agent-sdk';
|
|
10
11
|
import type { ToolAdapter, RunCallbacks, RunOptions, RunHandle } from './tool-adapter.interface.js';
|
|
11
12
|
interface ClaudeSessionMeta {
|
|
12
13
|
sessionId: string;
|
|
@@ -28,6 +29,39 @@ export declare class ClaudeSDKAdapter implements ToolAdapter {
|
|
|
28
29
|
* List sessions for a directory using the SDK's listSessions API.
|
|
29
30
|
*/
|
|
30
31
|
static listSessionsForDir(workDir: string, limit?: number): Promise<SDKSessionInfo[]>;
|
|
32
|
+
/**
|
|
33
|
+
* Get session messages for a given session ID.
|
|
34
|
+
*/
|
|
35
|
+
static getSessionMessagesForId(sessionId: string, workDir: string, limit?: number): Promise<SessionMessage[]>;
|
|
36
|
+
/**
|
|
37
|
+
* Delete a session by ID.
|
|
38
|
+
*/
|
|
39
|
+
static deleteSessionById(sessionId: string, workDir?: string): Promise<boolean>;
|
|
40
|
+
/**
|
|
41
|
+
* Rename a session.
|
|
42
|
+
*/
|
|
43
|
+
static renameSessionById(sessionId: string, title: string, workDir?: string): Promise<boolean>;
|
|
44
|
+
/**
|
|
45
|
+
* Fork a session.
|
|
46
|
+
*/
|
|
47
|
+
static forkSessionById(sessionId: string, workDir?: string): Promise<string | undefined>;
|
|
48
|
+
/**
|
|
49
|
+
* Create a short-lived query for fetching session info (models, context, etc).
|
|
50
|
+
* The caller must close the returned query when done.
|
|
51
|
+
*/
|
|
52
|
+
static createInfoQuery(workDir: string, model?: string): Promise<ReturnType<typeof query>>;
|
|
53
|
+
/**
|
|
54
|
+
* Get available models for a work directory.
|
|
55
|
+
*/
|
|
56
|
+
static getSupportedModels(workDir: string, model?: string): Promise<ModelInfo[]>;
|
|
57
|
+
/**
|
|
58
|
+
* Get context usage for a work directory.
|
|
59
|
+
*/
|
|
60
|
+
static getContextUsage(workDir: string, model?: string): Promise<SDKControlGetContextUsageResponse | undefined>;
|
|
61
|
+
/**
|
|
62
|
+
* Get account info for a work directory.
|
|
63
|
+
*/
|
|
64
|
+
static getAccountInfo(workDir: string, model?: string): Promise<AccountInfo | undefined>;
|
|
31
65
|
run(prompt: string, sessionId: string | undefined, workDir: string, callbacks: RunCallbacks, options?: RunOptions): RunHandle;
|
|
32
66
|
}
|
|
33
67
|
export {};
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - 支持 resume/cwd/model 等 options,无需 process.chdir hack
|
|
7
7
|
* - SDK 内部管理 session 生命周期,无需手动维护 session pool
|
|
8
8
|
*/
|
|
9
|
-
import { query, listSessions } from '@anthropic-ai/claude-agent-sdk';
|
|
9
|
+
import { query, listSessions, getSessionMessages, deleteSession, renameSession, forkSession } from '@anthropic-ai/claude-agent-sdk';
|
|
10
10
|
import { existsSync, readFileSync, statSync, openSync, readSync, closeSync } from 'fs';
|
|
11
11
|
import { execSync } from 'child_process';
|
|
12
12
|
import { homedir } from 'os';
|
|
@@ -199,7 +199,6 @@ export class ClaudeSDKAdapter {
|
|
|
199
199
|
*/
|
|
200
200
|
static destroy() {
|
|
201
201
|
// query() API 的 Query 对象通过 abortController.abort() 清理
|
|
202
|
-
// 不再需要手动管理 session pool
|
|
203
202
|
}
|
|
204
203
|
/**
|
|
205
204
|
* List sessions for a directory using the SDK's listSessions API.
|
|
@@ -213,6 +212,138 @@ export class ClaudeSDKAdapter {
|
|
|
213
212
|
return [];
|
|
214
213
|
}
|
|
215
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* Get session messages for a given session ID.
|
|
217
|
+
*/
|
|
218
|
+
static async getSessionMessagesForId(sessionId, workDir, limit = 50) {
|
|
219
|
+
try {
|
|
220
|
+
return await getSessionMessages(sessionId, { dir: workDir, limit });
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
log.warn(`Failed to get session messages for ${sessionId}: ${err}`);
|
|
224
|
+
return [];
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Delete a session by ID.
|
|
229
|
+
*/
|
|
230
|
+
static async deleteSessionById(sessionId, workDir) {
|
|
231
|
+
try {
|
|
232
|
+
await deleteSession(sessionId, { dir: workDir });
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
catch (err) {
|
|
236
|
+
log.warn(`Failed to delete session ${sessionId}: ${err}`);
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Rename a session.
|
|
242
|
+
*/
|
|
243
|
+
static async renameSessionById(sessionId, title, workDir) {
|
|
244
|
+
try {
|
|
245
|
+
await renameSession(sessionId, title, { dir: workDir });
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
catch (err) {
|
|
249
|
+
log.warn(`Failed to rename session ${sessionId}: ${err}`);
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Fork a session.
|
|
255
|
+
*/
|
|
256
|
+
static async forkSessionById(sessionId, workDir) {
|
|
257
|
+
try {
|
|
258
|
+
const result = await forkSession(sessionId, { dir: workDir });
|
|
259
|
+
return result.sessionId;
|
|
260
|
+
}
|
|
261
|
+
catch (err) {
|
|
262
|
+
log.warn(`Failed to fork session ${sessionId}: ${err}`);
|
|
263
|
+
return undefined;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Create a short-lived query for fetching session info (models, context, etc).
|
|
268
|
+
* The caller must close the returned query when done.
|
|
269
|
+
*/
|
|
270
|
+
static async createInfoQuery(workDir, model) {
|
|
271
|
+
const resolvedModel = model?.trim() || process.env.ANTHROPIC_MODEL?.trim() || 'claude-opus-4-5';
|
|
272
|
+
return query({
|
|
273
|
+
prompt: '',
|
|
274
|
+
options: {
|
|
275
|
+
cwd: workDir,
|
|
276
|
+
model: resolvedModel,
|
|
277
|
+
permissionMode: 'default',
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Get available models for a work directory.
|
|
283
|
+
*/
|
|
284
|
+
static async getSupportedModels(workDir, model) {
|
|
285
|
+
let q;
|
|
286
|
+
try {
|
|
287
|
+
q = await this.createInfoQuery(workDir, model);
|
|
288
|
+
return await q.supportedModels();
|
|
289
|
+
}
|
|
290
|
+
catch (err) {
|
|
291
|
+
log.warn(`Failed to get supported models: ${err}`);
|
|
292
|
+
return [];
|
|
293
|
+
}
|
|
294
|
+
finally {
|
|
295
|
+
if (q) {
|
|
296
|
+
try {
|
|
297
|
+
await q.return(undefined);
|
|
298
|
+
}
|
|
299
|
+
catch { /* ignore */ }
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Get context usage for a work directory.
|
|
305
|
+
*/
|
|
306
|
+
static async getContextUsage(workDir, model) {
|
|
307
|
+
let q;
|
|
308
|
+
try {
|
|
309
|
+
q = await this.createInfoQuery(workDir, model);
|
|
310
|
+
return await q.getContextUsage();
|
|
311
|
+
}
|
|
312
|
+
catch (err) {
|
|
313
|
+
log.warn(`Failed to get context usage: ${err}`);
|
|
314
|
+
return undefined;
|
|
315
|
+
}
|
|
316
|
+
finally {
|
|
317
|
+
if (q) {
|
|
318
|
+
try {
|
|
319
|
+
await q.return(undefined);
|
|
320
|
+
}
|
|
321
|
+
catch { /* ignore */ }
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Get account info for a work directory.
|
|
327
|
+
*/
|
|
328
|
+
static async getAccountInfo(workDir, model) {
|
|
329
|
+
let q;
|
|
330
|
+
try {
|
|
331
|
+
q = await this.createInfoQuery(workDir, model);
|
|
332
|
+
return await q.accountInfo();
|
|
333
|
+
}
|
|
334
|
+
catch (err) {
|
|
335
|
+
log.warn(`Failed to get account info: ${err}`);
|
|
336
|
+
return undefined;
|
|
337
|
+
}
|
|
338
|
+
finally {
|
|
339
|
+
if (q) {
|
|
340
|
+
try {
|
|
341
|
+
await q.return(undefined);
|
|
342
|
+
}
|
|
343
|
+
catch { /* ignore */ }
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
216
347
|
run(prompt, sessionId, workDir, callbacks, options) {
|
|
217
348
|
// 刷新 Claude 环境变量(支持 cc switch 后无需重启即可生效)
|
|
218
349
|
refreshClaudeEnvToProcess();
|
|
@@ -261,6 +392,8 @@ export class ClaudeSDKAdapter {
|
|
|
261
392
|
model: resolvedModel,
|
|
262
393
|
permissionMode,
|
|
263
394
|
...(resumeId ? { resume: resumeId } : {}),
|
|
395
|
+
...(options?.fallbackModel ? { fallbackModel: options.fallbackModel } : {}),
|
|
396
|
+
...(options?.disallowedTools?.length ? { disallowedTools: options.disallowedTools } : {}),
|
|
264
397
|
abortController,
|
|
265
398
|
stderr: (data) => {
|
|
266
399
|
recentStderr = appendStderrSnippet(recentStderr, data);
|
|
@@ -30,6 +30,10 @@ export interface RunOptions {
|
|
|
30
30
|
hookPort?: number;
|
|
31
31
|
/** Codex 专用:HTTP/HTTPS 代理地址,如 http://127.0.0.1:7890 */
|
|
32
32
|
proxy?: string;
|
|
33
|
+
/** 备用模型,主模型过载时自动切换 */
|
|
34
|
+
fallbackModel?: string;
|
|
35
|
+
/** 禁用的工具列表 */
|
|
36
|
+
disallowedTools?: string[];
|
|
33
37
|
}
|
|
34
38
|
export interface RunHandle {
|
|
35
39
|
abort: () => void;
|
|
@@ -30,6 +30,12 @@ export declare class CommandHandler {
|
|
|
30
30
|
private handlePwd;
|
|
31
31
|
private handleStatus;
|
|
32
32
|
private handleCd;
|
|
33
|
+
private handleHistory;
|
|
34
|
+
private handleDelete;
|
|
35
|
+
private handleRename;
|
|
36
|
+
private handleFork;
|
|
37
|
+
private handleModels;
|
|
38
|
+
private handleContext;
|
|
33
39
|
private getAiVersion;
|
|
34
40
|
}
|
|
35
41
|
/**
|
package/dist/commands/handler.js
CHANGED
|
@@ -81,6 +81,18 @@ export class CommandHandler {
|
|
|
81
81
|
return this.handleSessions(chatId, userId, platform);
|
|
82
82
|
if (t.startsWith('/resume '))
|
|
83
83
|
return this.handleResume(chatId, userId, t.slice(8).trim(), platform);
|
|
84
|
+
if (t.startsWith('/history'))
|
|
85
|
+
return this.handleHistory(chatId, userId, t.slice(8).trim());
|
|
86
|
+
if (t.startsWith('/delete '))
|
|
87
|
+
return this.handleDelete(chatId, userId, t.slice(8).trim());
|
|
88
|
+
if (t.startsWith('/rename '))
|
|
89
|
+
return this.handleRename(chatId, userId, t.slice(8).trim());
|
|
90
|
+
if (t.startsWith('/fork'))
|
|
91
|
+
return this.handleFork(chatId, userId, t.slice(5).trim());
|
|
92
|
+
if (t === '/models')
|
|
93
|
+
return this.handleModels(chatId, userId, platform);
|
|
94
|
+
if (t === '/context')
|
|
95
|
+
return this.handleContext(chatId, userId, platform);
|
|
84
96
|
if (t === '/pwd')
|
|
85
97
|
return this.handlePwd(chatId, userId);
|
|
86
98
|
if (t === '/status')
|
|
@@ -108,6 +120,12 @@ export class CommandHandler {
|
|
|
108
120
|
'/new - 开始新会话(AI 上下文重置)',
|
|
109
121
|
'/sessions - 查看历史会话',
|
|
110
122
|
'/resume [序号] - 恢复历史会话(无参数恢复最近一条)',
|
|
123
|
+
'/history [序号] - 查看会话对话记录',
|
|
124
|
+
'/delete <序号> - 删除历史会话',
|
|
125
|
+
'/rename <标题> - 重命名当前会话',
|
|
126
|
+
'/fork [序号] - 分支会话(创建副本)',
|
|
127
|
+
'/models - 查看可用模型',
|
|
128
|
+
'/context - 查看上下文窗口占用',
|
|
111
129
|
'/status - 显示状态',
|
|
112
130
|
'/cd <路径> - 切换工作目录',
|
|
113
131
|
'/pwd - 当前工作目录',
|
|
@@ -191,6 +209,20 @@ export class CommandHandler {
|
|
|
191
209
|
`工作目录: ${escapePathForMarkdown(workDir)}`,
|
|
192
210
|
`会话: ${sessionId ?? '无'}`,
|
|
193
211
|
];
|
|
212
|
+
// 账号信息(仅 claude)
|
|
213
|
+
if (aiCommand === 'claude') {
|
|
214
|
+
try {
|
|
215
|
+
const account = await ClaudeSDKAdapter.getAccountInfo(workDir);
|
|
216
|
+
if (account) {
|
|
217
|
+
lines.push('', '👤 账号:');
|
|
218
|
+
if (account.email)
|
|
219
|
+
lines.push(`邮箱: ${account.email}`);
|
|
220
|
+
if (account.organization)
|
|
221
|
+
lines.push(`组织: ${account.organization}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
catch { /* ignore */ }
|
|
225
|
+
}
|
|
194
226
|
await this.replySender().sendTextReply(chatId, lines.join('\n'));
|
|
195
227
|
return true;
|
|
196
228
|
}
|
|
@@ -217,6 +249,155 @@ export class CommandHandler {
|
|
|
217
249
|
}
|
|
218
250
|
return true;
|
|
219
251
|
}
|
|
252
|
+
async handleHistory(chatId, userId, arg) {
|
|
253
|
+
const workDir = this.deps.sessionManager.getWorkDir(userId);
|
|
254
|
+
const sessions = await ClaudeSDKAdapter.listSessionsForDir(workDir);
|
|
255
|
+
if (sessions.length === 0) {
|
|
256
|
+
await this.replySender().sendTextReply(chatId, '暂无会话记录。');
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
let targetSession = sessions[0]; // 默认当前/最近会话
|
|
260
|
+
if (arg) {
|
|
261
|
+
const index = parseInt(arg, 10);
|
|
262
|
+
if (isNaN(index) || index < 1 || index > sessions.length) {
|
|
263
|
+
await this.replySender().sendTextReply(chatId, `序号无效,共 ${sessions.length} 个会话。`);
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
targetSession = sessions[index - 1];
|
|
267
|
+
}
|
|
268
|
+
const messages = await ClaudeSDKAdapter.getSessionMessagesForId(targetSession.sessionId, workDir, 30);
|
|
269
|
+
if (messages.length === 0) {
|
|
270
|
+
await this.replySender().sendTextReply(chatId, '该会话暂无对话记录。');
|
|
271
|
+
return true;
|
|
272
|
+
}
|
|
273
|
+
const preview = truncateSummary(targetSession);
|
|
274
|
+
const lines = [`📜 会话记录: ${preview}`, ''];
|
|
275
|
+
for (const msg of messages) {
|
|
276
|
+
if (msg.type === 'system')
|
|
277
|
+
continue;
|
|
278
|
+
const m = msg.message;
|
|
279
|
+
let text = '';
|
|
280
|
+
if (typeof m === 'string') {
|
|
281
|
+
text = m;
|
|
282
|
+
}
|
|
283
|
+
else if (m && typeof m === 'object') {
|
|
284
|
+
const content = m.content;
|
|
285
|
+
if (Array.isArray(content) && content[0]?.text) {
|
|
286
|
+
text = content[0].text;
|
|
287
|
+
}
|
|
288
|
+
else if (typeof content === 'string') {
|
|
289
|
+
text = content;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (!text)
|
|
293
|
+
continue;
|
|
294
|
+
const prefix = msg.type === 'user' ? '👤' : '🤖';
|
|
295
|
+
lines.push(`${prefix} ${text.slice(0, 200)}`);
|
|
296
|
+
}
|
|
297
|
+
await this.replySender().sendTextReply(chatId, lines.join('\n'));
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
300
|
+
async handleDelete(chatId, userId, arg) {
|
|
301
|
+
const workDir = this.deps.sessionManager.getWorkDir(userId);
|
|
302
|
+
const sessions = await ClaudeSDKAdapter.listSessionsForDir(workDir);
|
|
303
|
+
const index = parseInt(arg, 10);
|
|
304
|
+
if (isNaN(index) || index < 1 || index > sessions.length) {
|
|
305
|
+
await this.replySender().sendTextReply(chatId, `用法: /delete <序号>\n共 ${sessions.length} 个会话。`);
|
|
306
|
+
return true;
|
|
307
|
+
}
|
|
308
|
+
const session = sessions[index - 1];
|
|
309
|
+
const preview = truncateSummary(session);
|
|
310
|
+
const ok = await ClaudeSDKAdapter.deleteSessionById(session.sessionId, workDir);
|
|
311
|
+
await this.replySender().sendTextReply(chatId, ok ? `✅ 已删除会话: ${preview}` : `❌ 删除失败`);
|
|
312
|
+
return true;
|
|
313
|
+
}
|
|
314
|
+
async handleRename(chatId, userId, title) {
|
|
315
|
+
if (!title) {
|
|
316
|
+
await this.replySender().sendTextReply(chatId, '用法: /rename <新标题>');
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
const workDir = this.deps.sessionManager.getWorkDir(userId);
|
|
320
|
+
const convId = this.deps.sessionManager.getConvId(userId);
|
|
321
|
+
const aiCommand = 'claude';
|
|
322
|
+
const sessionId = this.deps.sessionManager.getSessionIdForConv(userId, convId, aiCommand);
|
|
323
|
+
if (!sessionId) {
|
|
324
|
+
await this.replySender().sendTextReply(chatId, '当前没有活动会话。');
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
const ok = await ClaudeSDKAdapter.renameSessionById(sessionId, title, workDir);
|
|
328
|
+
await this.replySender().sendTextReply(chatId, ok ? `✅ 会话已重命名为: ${title}` : '❌ 重命名失败');
|
|
329
|
+
return true;
|
|
330
|
+
}
|
|
331
|
+
async handleFork(chatId, userId, arg) {
|
|
332
|
+
const workDir = this.deps.sessionManager.getWorkDir(userId);
|
|
333
|
+
const sessions = await ClaudeSDKAdapter.listSessionsForDir(workDir);
|
|
334
|
+
if (sessions.length === 0) {
|
|
335
|
+
await this.replySender().sendTextReply(chatId, '暂无会话可分支。');
|
|
336
|
+
return true;
|
|
337
|
+
}
|
|
338
|
+
let targetSession = sessions[0];
|
|
339
|
+
if (arg) {
|
|
340
|
+
const index = parseInt(arg, 10);
|
|
341
|
+
if (isNaN(index) || index < 1 || index > sessions.length) {
|
|
342
|
+
await this.replySender().sendTextReply(chatId, `序号无效,共 ${sessions.length} 个会话。`);
|
|
343
|
+
return true;
|
|
344
|
+
}
|
|
345
|
+
targetSession = sessions[index - 1];
|
|
346
|
+
}
|
|
347
|
+
const newSessionId = await ClaudeSDKAdapter.forkSessionById(targetSession.sessionId, workDir);
|
|
348
|
+
if (newSessionId) {
|
|
349
|
+
this.deps.sessionManager.setActiveSessionId(userId, newSessionId);
|
|
350
|
+
const preview = truncateSummary(targetSession);
|
|
351
|
+
await this.replySender().sendTextReply(chatId, `✅ 已分支会话: ${preview}\n新会话 ID: ${newSessionId.slice(0, 8)}...\n继续发消息即可。`);
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
await this.replySender().sendTextReply(chatId, '❌ 分支失败');
|
|
355
|
+
}
|
|
356
|
+
return true;
|
|
357
|
+
}
|
|
358
|
+
async handleModels(chatId, userId, _platform) {
|
|
359
|
+
const workDir = this.deps.sessionManager.getWorkDir(userId);
|
|
360
|
+
const models = await ClaudeSDKAdapter.getSupportedModels(workDir);
|
|
361
|
+
if (models.length === 0) {
|
|
362
|
+
await this.replySender().sendTextReply(chatId, '暂无可用模型信息。');
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
const lines = ['🤖 可用模型:', ''];
|
|
366
|
+
for (const model of models) {
|
|
367
|
+
const name = model.displayName || model.value;
|
|
368
|
+
const desc = model.description ? ` - ${model.description.slice(0, 60)}` : '';
|
|
369
|
+
lines.push(`• ${name}${desc}`);
|
|
370
|
+
}
|
|
371
|
+
await this.replySender().sendTextReply(chatId, lines.join('\n'));
|
|
372
|
+
return true;
|
|
373
|
+
}
|
|
374
|
+
async handleContext(chatId, userId, _platform) {
|
|
375
|
+
const workDir = this.deps.sessionManager.getWorkDir(userId);
|
|
376
|
+
const usage = await ClaudeSDKAdapter.getContextUsage(workDir);
|
|
377
|
+
if (!usage) {
|
|
378
|
+
await this.replySender().sendTextReply(chatId, '暂无上下文信息。');
|
|
379
|
+
return true;
|
|
380
|
+
}
|
|
381
|
+
const lines = ['📏 上下文窗口占用:', ''];
|
|
382
|
+
if (usage.model)
|
|
383
|
+
lines.push(`模型: ${usage.model}`);
|
|
384
|
+
if (usage.totalTokens)
|
|
385
|
+
lines.push(`已用: ${usage.totalTokens.toLocaleString()} tokens`);
|
|
386
|
+
if (usage.maxTokens)
|
|
387
|
+
lines.push(`上限: ${usage.maxTokens.toLocaleString()} tokens`);
|
|
388
|
+
if (usage.percentage != null)
|
|
389
|
+
lines.push(`使用率: ${usage.percentage}%`);
|
|
390
|
+
if (usage.categories?.length) {
|
|
391
|
+
lines.push('', '分类:');
|
|
392
|
+
for (const cat of usage.categories) {
|
|
393
|
+
if (cat.tokens > 0) {
|
|
394
|
+
lines.push(` ${cat.name}: ${cat.tokens.toLocaleString()}`);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
await this.replySender().sendTextReply(chatId, lines.join('\n'));
|
|
399
|
+
return true;
|
|
400
|
+
}
|
|
220
401
|
getAiVersion(aiCommand) {
|
|
221
402
|
if (aiCommand === 'claude') {
|
|
222
403
|
return Promise.resolve('SDK Mode');
|
package/dist/constants.js
CHANGED