@wu529778790/open-im 1.10.7-beta.1 → 1.10.7-beta.3
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/commands/handler.js
CHANGED
|
@@ -123,6 +123,7 @@ export class CommandHandler {
|
|
|
123
123
|
return true;
|
|
124
124
|
}
|
|
125
125
|
const entry = history[index - 1];
|
|
126
|
+
this.deps.requestQueue.cancelUser(userId);
|
|
126
127
|
const ok = this.deps.sessionManager.resumeConv(userId, entry.convId);
|
|
127
128
|
if (ok) {
|
|
128
129
|
await this.replySender().sendTextReply(chatId, `✅ 已恢复会话 ${index} (${entry.convId}),共 ${entry.totalTurns}轮对话。\n继续发消息即可。`);
|
|
@@ -133,6 +134,7 @@ export class CommandHandler {
|
|
|
133
134
|
return true;
|
|
134
135
|
}
|
|
135
136
|
async handleNew(chatId, userId) {
|
|
137
|
+
this.deps.requestQueue.cancelUser(userId);
|
|
136
138
|
const ok = this.deps.sessionManager.newSession(userId);
|
|
137
139
|
await this.replySender().sendTextReply(chatId, ok
|
|
138
140
|
? '✅ AI 会话已重置,下一条消息将使用全新上下文。'
|
|
@@ -175,6 +177,7 @@ export class CommandHandler {
|
|
|
175
177
|
return true;
|
|
176
178
|
}
|
|
177
179
|
try {
|
|
180
|
+
this.deps.requestQueue.cancelUser(userId);
|
|
178
181
|
const resolved = await this.deps.sessionManager.setWorkDir(userId, dir);
|
|
179
182
|
await this.replySender().sendTextReply(chatId, `📁 工作目录已切换到: ${escapePathForMarkdown(resolved)}\n\n` +
|
|
180
183
|
`🔄 AI 会话已重置,下一条消息将使用全新上下文。`);
|
package/dist/index.js
CHANGED
|
@@ -214,9 +214,8 @@ export async function main() {
|
|
|
214
214
|
}
|
|
215
215
|
log.info(`启用平台: ${config.enabledPlatforms.join(", ")}`);
|
|
216
216
|
const sessionManager = new SessionManager(startupCwd, config.claudeWorkDir);
|
|
217
|
-
//
|
|
218
|
-
//
|
|
219
|
-
sessionManager.clearAllCliSessionIds();
|
|
217
|
+
// Codex/CodeBuddy 的 sessionId 持久化在 sessions.json;重启后沿用以便 --resume 续聊。
|
|
218
|
+
// 若 CLI 判定会话无效,ai-task 会通过 onSessionInvalid 清理并提示重试。
|
|
220
219
|
// Track active platform handles and successfully initialized platforms
|
|
221
220
|
const activeHandles = new Map();
|
|
222
221
|
const successfulPlatforms = [];
|
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
export type EnqueueResult = 'running' | 'queued' | 'rejected';
|
|
2
2
|
export declare class RequestQueue {
|
|
3
3
|
private queues;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
/** AbortController for the task currently running per user (key = userId). */
|
|
5
|
+
private runningControllers;
|
|
6
|
+
/**
|
|
7
|
+
* Enqueue an AI task. Tasks are serialized per `userId` only — `convId` is ignored for queue
|
|
8
|
+
* partitioning so that `/new` and `/cd` (which change `convId`) cannot leave a long-running
|
|
9
|
+
* request on the old conversation executing in parallel with new messages.
|
|
10
|
+
*/
|
|
11
|
+
enqueue(userId: string, _convId: string, prompt: string, execute: (prompt: string, signal: AbortSignal) => Promise<void>): EnqueueResult;
|
|
12
|
+
/**
|
|
13
|
+
* Abort the running task for this user (if any) and drop all queued tasks.
|
|
14
|
+
* Used when `/new`, `/cd`, or `/resume` changes conversation state so stale completions
|
|
15
|
+
* are not delivered to the wrong WeChat/Telegram message.
|
|
16
|
+
*/
|
|
17
|
+
cancelUser(userId: string): void;
|
|
18
|
+
/** 清除指定用户的所有排队任务(不中止正在运行的任务)。`convId` 仅保留兼容签名。 */
|
|
19
|
+
clear(userId: string, _convId: string): number;
|
|
7
20
|
private run;
|
|
8
21
|
}
|
|
@@ -3,8 +3,15 @@ const log = createLogger('Queue');
|
|
|
3
3
|
const MAX_QUEUE_SIZE = 3;
|
|
4
4
|
export class RequestQueue {
|
|
5
5
|
queues = new Map();
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
/** AbortController for the task currently running per user (key = userId). */
|
|
7
|
+
runningControllers = new Map();
|
|
8
|
+
/**
|
|
9
|
+
* Enqueue an AI task. Tasks are serialized per `userId` only — `convId` is ignored for queue
|
|
10
|
+
* partitioning so that `/new` and `/cd` (which change `convId`) cannot leave a long-running
|
|
11
|
+
* request on the old conversation executing in parallel with new messages.
|
|
12
|
+
*/
|
|
13
|
+
enqueue(userId, _convId, prompt, execute) {
|
|
14
|
+
const key = userId;
|
|
8
15
|
let q = this.queues.get(key);
|
|
9
16
|
if (!q) {
|
|
10
17
|
q = { running: false, tasks: [] };
|
|
@@ -23,9 +30,28 @@ export class RequestQueue {
|
|
|
23
30
|
});
|
|
24
31
|
return 'running';
|
|
25
32
|
}
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Abort the running task for this user (if any) and drop all queued tasks.
|
|
35
|
+
* Used when `/new`, `/cd`, or `/resume` changes conversation state so stale completions
|
|
36
|
+
* are not delivered to the wrong WeChat/Telegram message.
|
|
37
|
+
*/
|
|
38
|
+
cancelUser(userId) {
|
|
39
|
+
const key = userId;
|
|
40
|
+
const c = this.runningControllers.get(key);
|
|
41
|
+
if (c) {
|
|
42
|
+
c.abort();
|
|
43
|
+
}
|
|
44
|
+
const q = this.queues.get(key);
|
|
45
|
+
if (!q)
|
|
46
|
+
return;
|
|
47
|
+
const cleared = q.tasks.length;
|
|
48
|
+
q.tasks.length = 0;
|
|
49
|
+
if (cleared > 0)
|
|
50
|
+
log.info(`cancelUser: dropped ${cleared} queued task(s) for ${key}`);
|
|
51
|
+
}
|
|
52
|
+
/** 清除指定用户的所有排队任务(不中止正在运行的任务)。`convId` 仅保留兼容签名。 */
|
|
53
|
+
clear(userId, _convId) {
|
|
54
|
+
const key = userId;
|
|
29
55
|
const q = this.queues.get(key);
|
|
30
56
|
if (!q)
|
|
31
57
|
return 0;
|
|
@@ -37,14 +63,22 @@ export class RequestQueue {
|
|
|
37
63
|
}
|
|
38
64
|
async run(key, prompt, execute) {
|
|
39
65
|
const controller = new AbortController();
|
|
66
|
+
this.runningControllers.set(key, controller);
|
|
40
67
|
try {
|
|
41
68
|
await execute(prompt, controller.signal);
|
|
42
69
|
}
|
|
43
70
|
catch (err) {
|
|
44
|
-
|
|
45
|
-
|
|
71
|
+
const aborted = err instanceof Error && err.name === 'AbortError';
|
|
72
|
+
if (aborted) {
|
|
73
|
+
log.debug(`Task aborted for ${key}`);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
log.error(`Error executing task for ${key}:`, err);
|
|
77
|
+
throw err;
|
|
78
|
+
}
|
|
46
79
|
}
|
|
47
80
|
finally {
|
|
81
|
+
this.runningControllers.delete(key);
|
|
48
82
|
const q = this.queues.get(key);
|
|
49
83
|
if (!q)
|
|
50
84
|
return;
|
|
@@ -25,11 +25,6 @@ export declare class SessionManager {
|
|
|
25
25
|
hasUserSession(userId: string): boolean;
|
|
26
26
|
getConvId(userId: string): string;
|
|
27
27
|
setWorkDir(userId: string, workDir: string): Promise<string>;
|
|
28
|
-
/**
|
|
29
|
-
* 服务启动时调用:清除所有用户的 CLI sessionId。
|
|
30
|
-
* Codex/CodeBuddy 的 session 是进程级别的,服务重启后旧 session 一定无效。
|
|
31
|
-
*/
|
|
32
|
-
clearAllCliSessionIds(): void;
|
|
33
28
|
newSession(userId: string): boolean;
|
|
34
29
|
clearActiveToolSession(userId: string, toolId: ToolId): boolean;
|
|
35
30
|
listConvHistory(userId: string): ConvHistoryEntry[];
|
|
@@ -136,41 +136,6 @@ export class SessionManager {
|
|
|
136
136
|
log.info(`WorkDir changed for user ${userId}: ${realPath}, oldConvId=${oldConvId}`);
|
|
137
137
|
return realPath;
|
|
138
138
|
}
|
|
139
|
-
/**
|
|
140
|
-
* 服务启动时调用:清除所有用户的 CLI sessionId。
|
|
141
|
-
* Codex/CodeBuddy 的 session 是进程级别的,服务重启后旧 session 一定无效。
|
|
142
|
-
*/
|
|
143
|
-
clearAllCliSessionIds() {
|
|
144
|
-
let changed = false;
|
|
145
|
-
for (const [, s] of this.sessions) {
|
|
146
|
-
for (const toolId of ['codex', 'codebuddy']) {
|
|
147
|
-
if (this.getToolSessionId(s, toolId) !== undefined) {
|
|
148
|
-
this.clearToolSessionId(s, toolId);
|
|
149
|
-
changed = true;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
if (s.threads) {
|
|
153
|
-
for (const t of Object.values(s.threads)) {
|
|
154
|
-
for (const toolId of ['codex', 'codebuddy']) {
|
|
155
|
-
if (t.sessionIds?.[toolId] !== undefined) {
|
|
156
|
-
delete t.sessionIds[toolId];
|
|
157
|
-
changed = true;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
for (const key of [...this.convSessionMap.keys()]) {
|
|
164
|
-
if (key.endsWith(':codex') || key.endsWith(':codebuddy')) {
|
|
165
|
-
this.convSessionMap.delete(key);
|
|
166
|
-
changed = true;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
if (changed) {
|
|
170
|
-
this.flushSync();
|
|
171
|
-
log.info('Cleared CLI session IDs for codex/codebuddy on startup');
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
139
|
newSession(userId) {
|
|
175
140
|
const s = this.sessions.get(userId);
|
|
176
141
|
if (s) {
|