@wu529778790/open-im 1.11.4-beta.0 → 1.11.4-beta.10
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/README.md +21 -0
- package/dist/adapters/claude-sdk-adapter.js +2 -2
- package/dist/adapters/tool-adapter.interface.d.ts +2 -0
- package/dist/clawbot/event-handler.js +2 -4
- package/dist/clawbot/message-sender.js +4 -16
- package/dist/session/session-manager.d.ts +5 -0
- package/dist/session/session-manager.js +11 -0
- package/dist/shared/ai-task.js +2 -0
- package/dist/workbuddy/event-handler.js +2 -4
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -137,6 +137,27 @@ claude -c # 接上手机端的对话
|
|
|
137
137
|
}
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
+
### 语音回复(可选)
|
|
141
|
+
|
|
142
|
+
ClawBot 支持语音回复,需要 Python 3 + edge-tts:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# 安装依赖
|
|
146
|
+
pip3 install edge-tts
|
|
147
|
+
|
|
148
|
+
# 启用语音
|
|
149
|
+
# 在管理页面 http://127.0.0.1:39282 打开 ClawBot 的「语音回复」开关
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
支持的中文声音:
|
|
153
|
+
- 晓晓(女声,温柔)
|
|
154
|
+
- 晓伊(女声,活泼)
|
|
155
|
+
- 云希(男声,年轻)
|
|
156
|
+
- 云健(男声,沉稳)
|
|
157
|
+
- 云扬(男声,专业)
|
|
158
|
+
|
|
159
|
+
> 不安装 Python 也能正常使用 open-im,语音回复是可选功能。
|
|
160
|
+
|
|
140
161
|
### 环境变量
|
|
141
162
|
|
|
142
163
|
- **`ANTHROPIC_*`** — Claude API 配置
|
|
@@ -378,9 +378,9 @@ export class ClaudeSDKAdapter {
|
|
|
378
378
|
let actualSessionId;
|
|
379
379
|
let hadSessionInvalid = false;
|
|
380
380
|
try {
|
|
381
|
-
// 先尝试自动恢复 CLI 的最新 session(如果用户没有指定 sessionId)
|
|
381
|
+
// 先尝试自动恢复 CLI 的最新 session(如果用户没有指定 sessionId,且不是 /new 后的新 session)
|
|
382
382
|
let resumeId = sessionId;
|
|
383
|
-
if (!resumeId) {
|
|
383
|
+
if (!resumeId && !options?.skipAutoResume) {
|
|
384
384
|
const latest = await findLatestClaudeSession(workDir);
|
|
385
385
|
if (latest) {
|
|
386
386
|
const cliActive = isCliSessionActive(latest.sessionId, latest.filePath);
|
|
@@ -23,10 +23,8 @@ export function setupClawbotHandlers(config, sessionManager) {
|
|
|
23
23
|
});
|
|
24
24
|
const stopTaskCleanup = startTaskCleanup(ctx.runningTasks);
|
|
25
25
|
const platformSender = {
|
|
26
|
-
sendThinkingMessage: async (
|
|
27
|
-
|
|
28
|
-
await sendTextReply(chatId, '🤔 正在处理...');
|
|
29
|
-
return 'clawbot_thinking';
|
|
26
|
+
sendThinkingMessage: async (_chatId, _replyToMessageId, _toolId) => {
|
|
27
|
+
return 'clawbot_no_thinking';
|
|
30
28
|
},
|
|
31
29
|
sendTextReply: async (chatId, text) => {
|
|
32
30
|
await sendTextReply(chatId, text);
|
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { randomBytes } from 'node:crypto';
|
|
7
7
|
import { createLogger } from '../logger.js';
|
|
8
|
-
import {
|
|
9
|
-
import { MAX_CLAWBOT_MESSAGE_LENGTH } from '../constants.js';
|
|
8
|
+
import { toReplyPlainText } from '../shared/utils.js';
|
|
10
9
|
import { getChannelState } from './client.js';
|
|
11
10
|
import { getActiveChatId, getClawbotContextToken } from '../shared/active-chats.js';
|
|
12
11
|
const log = createLogger('ClawBotSender');
|
|
@@ -94,20 +93,9 @@ async function postMessage(chatId, text, contextToken) {
|
|
|
94
93
|
*/
|
|
95
94
|
export async function sendTextReply(chatId, text, contextToken) {
|
|
96
95
|
const plainText = toReplyPlainText(text);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
await postMessage(chatId, plainText, contextToken);
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
log.info(`Sending ClawBot reply in ${parts.length} parts to chatId=${chatId}, totalLen=${plainText.length}`);
|
|
104
|
-
for (let i = 0; i < parts.length; i++) {
|
|
105
|
-
const partText = i === 0
|
|
106
|
-
? `${parts[i]}\n\n_(1/${parts.length})_`
|
|
107
|
-
: `_(续 ${i + 1}/${parts.length})_\n\n${parts[i]}`;
|
|
108
|
-
await postMessage(chatId, partText, contextToken);
|
|
109
|
-
log.info(`ClawBot part ${i + 1}/${parts.length} sent`);
|
|
110
|
-
}
|
|
96
|
+
// 发送文字消息
|
|
97
|
+
log.info(`Sending ClawBot reply to chatId=${chatId}, len=${plainText.length}`);
|
|
98
|
+
await postMessage(chatId, plainText, contextToken);
|
|
111
99
|
}
|
|
112
100
|
/**
|
|
113
101
|
* Send error reply to a ClawBot chat.
|
|
@@ -17,6 +17,11 @@ export declare class SessionManager {
|
|
|
17
17
|
getSessionIdForThread(_userId: string, _threadId: string, _toolId: ToolId): string | undefined;
|
|
18
18
|
setSessionIdForThread(userId: string, threadId: string, toolId: ToolId, sessionId: string): void;
|
|
19
19
|
getWorkDir(userId: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* 检查 session 是否是 /new 后的新 session
|
|
22
|
+
* 如果是,不应该自动恢复 CLI session
|
|
23
|
+
*/
|
|
24
|
+
isFreshSession(userId: string): boolean;
|
|
20
25
|
/**
|
|
21
26
|
* 获取最近活跃的 session 的工作目录
|
|
22
27
|
* 如果没有 session,返回默认工作目录
|
|
@@ -87,10 +87,20 @@ export class SessionManager {
|
|
|
87
87
|
const s = this.sessions.get(userId);
|
|
88
88
|
if (s) {
|
|
89
89
|
s.lastActiveAt = Date.now();
|
|
90
|
+
// 首次访问后清除 freshSession 标记(允许后续消息恢复 CLI session)
|
|
91
|
+
if (s.freshSession)
|
|
92
|
+
s.freshSession = false;
|
|
90
93
|
return s.workDir;
|
|
91
94
|
}
|
|
92
95
|
return this.defaultWorkDir;
|
|
93
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* 检查 session 是否是 /new 后的新 session
|
|
99
|
+
* 如果是,不应该自动恢复 CLI session
|
|
100
|
+
*/
|
|
101
|
+
isFreshSession(userId) {
|
|
102
|
+
return this.sessions.get(userId)?.freshSession === true;
|
|
103
|
+
}
|
|
94
104
|
/**
|
|
95
105
|
* 获取最近活跃的 session 的工作目录
|
|
96
106
|
* 如果没有 session,返回默认工作目录
|
|
@@ -158,6 +168,7 @@ export class SessionManager {
|
|
|
158
168
|
s.sessionIds = {};
|
|
159
169
|
s.activeConvId = randomBytes(4).toString('hex');
|
|
160
170
|
s.totalTurns = 0;
|
|
171
|
+
s.freshSession = true; // 标记为新 session,阻止自动恢复 CLI session
|
|
161
172
|
this.flushSync();
|
|
162
173
|
log.info(`New session for user ${userId}: oldConvId=${oldConvId}, oldSessionIds=${JSON.stringify(oldSessionIds)}, newConvId=${s.activeConvId}, sessionIds={}`);
|
|
163
174
|
return true;
|
package/dist/shared/ai-task.js
CHANGED
|
@@ -294,6 +294,8 @@ export function runAITask(deps, ctx, prompt, toolAdapter, platformAdapter) {
|
|
|
294
294
|
chatId: ctx.chatId,
|
|
295
295
|
// 默认跳过权限确认,保持全自动执行(可通过 config 或环境变量关闭)
|
|
296
296
|
skipPermissions: config.skipPermissions ?? true,
|
|
297
|
+
// /new 后跳过自动恢复 CLI session
|
|
298
|
+
skipAutoResume: sessionManager.isFreshSession(ctx.userId),
|
|
297
299
|
...(aiCommand === 'codex' && config.codexProxy ? { proxy: config.codexProxy } : {}),
|
|
298
300
|
});
|
|
299
301
|
return activeHandle;
|
|
@@ -26,10 +26,8 @@ export function setupWorkBuddyHandlers(config, sessionManager) {
|
|
|
26
26
|
const stopTaskCleanup = startTaskCleanup(ctx.runningTasks);
|
|
27
27
|
// WorkBuddy-specific sender callbacks
|
|
28
28
|
const platformSender = {
|
|
29
|
-
sendThinkingMessage: async (
|
|
30
|
-
|
|
31
|
-
await sendTextReply(null, chatId, '🤔 正在处理...', '');
|
|
32
|
-
return 'workbuddy_thinking';
|
|
29
|
+
sendThinkingMessage: async (_chatId, _replyToMessageId, _toolId) => {
|
|
30
|
+
return 'workbuddy_no_thinking';
|
|
33
31
|
},
|
|
34
32
|
sendTextReply: async (chatId, text) => {
|
|
35
33
|
await sendTextReply(null, chatId, text, '');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wu529778790/open-im",
|
|
3
|
-
"version": "1.11.4-beta.
|
|
3
|
+
"version": "1.11.4-beta.10",
|
|
4
4
|
"description": "Your AI coding assistant, in every chat app. Multi-platform IM bridge for Claude Code, Codex, and CodeBuddy.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -58,9 +58,13 @@
|
|
|
58
58
|
"@sentry/node": "^10.58.0",
|
|
59
59
|
"centrifuge": "^5.5.3",
|
|
60
60
|
"dingtalk-stream": "^2.1.4",
|
|
61
|
+
"edge-tts": "^1.0.1",
|
|
62
|
+
"https-proxy-agent": "^9.1.0",
|
|
63
|
+
"node-edge-tts": "^1.2.10",
|
|
61
64
|
"prompts": "^2.4.2",
|
|
65
|
+
"say": "^0.16.0",
|
|
62
66
|
"telegraf": "^4.16.3",
|
|
63
|
-
"ws": "^8.
|
|
67
|
+
"ws": "^8.21.0"
|
|
64
68
|
},
|
|
65
69
|
"devDependencies": {
|
|
66
70
|
"@eslint/js": "^9.15.0",
|