@wu529778790/open-im 1.3.0 → 1.3.1-beta.1
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.
|
@@ -117,9 +117,18 @@ export class ClaudeSDKAdapter {
|
|
|
117
117
|
queryClosed = true;
|
|
118
118
|
const m = msg;
|
|
119
119
|
const success = m.subtype === 'success';
|
|
120
|
+
const errs = m.errors ?? [];
|
|
121
|
+
const noConvErr = errs.find((e) => e.includes('No conversation found with session ID'));
|
|
122
|
+
if (!success && noConvErr) {
|
|
123
|
+
log.warn(`SDK session invalid: ${noConvErr}`);
|
|
124
|
+
callbacks.onSessionInvalid?.();
|
|
125
|
+
callbacks.onError('会话已过期,请发送 /new 开始新会话');
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const resultText = m.result ?? '';
|
|
120
129
|
const result = {
|
|
121
130
|
success,
|
|
122
|
-
result:
|
|
131
|
+
result: resultText,
|
|
123
132
|
accumulated: success ? accumulated : '',
|
|
124
133
|
cost: m.total_cost_usd ?? 0,
|
|
125
134
|
durationMs: m.duration_ms ?? 0,
|
|
@@ -128,6 +137,17 @@ export class ClaudeSDKAdapter {
|
|
|
128
137
|
};
|
|
129
138
|
if (!result.accumulated && result.result)
|
|
130
139
|
result.accumulated = result.result;
|
|
140
|
+
if (!result.accumulated && !result.result && accumulated) {
|
|
141
|
+
log.debug(`Result event had no text but accumulated=${accumulated.length} chars, using accumulated`);
|
|
142
|
+
result.accumulated = accumulated;
|
|
143
|
+
result.result = accumulated;
|
|
144
|
+
}
|
|
145
|
+
if (!result.accumulated && !result.result) {
|
|
146
|
+
const errMsg = errs[0] ?? '未知错误';
|
|
147
|
+
log.warn(`SDK result empty: subtype=${m.subtype}, errors=${JSON.stringify(errs)}`);
|
|
148
|
+
callbacks.onError(errMsg);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
131
151
|
callbacks.onComplete(result);
|
|
132
152
|
return;
|
|
133
153
|
}
|
|
@@ -18,6 +18,8 @@ export interface RunCallbacks {
|
|
|
18
18
|
onComplete: (result: ParsedResult) => void;
|
|
19
19
|
onError: (error: string) => void;
|
|
20
20
|
onSessionId?: (sessionId: string) => void;
|
|
21
|
+
/** SDK 报 "No conversation found" 时调用,用于清除无效 session */
|
|
22
|
+
onSessionInvalid?: () => void;
|
|
21
23
|
}
|
|
22
24
|
export interface RunOptions {
|
|
23
25
|
skipPermissions?: boolean;
|
|
@@ -7,6 +7,8 @@ export declare class SessionManager {
|
|
|
7
7
|
constructor(defaultWorkDir: string, allowedBaseDirs: string[]);
|
|
8
8
|
getSessionIdForConv(userId: string, convId: string): string | undefined;
|
|
9
9
|
setSessionIdForConv(userId: string, convId: string, sessionId: string): void;
|
|
10
|
+
/** 清除指定会话的 sessionId(用于 SDK 报 "No conversation found" 时) */
|
|
11
|
+
clearSessionForConv(userId: string, convId: string): void;
|
|
10
12
|
getSessionIdForThread(_userId: string, _threadId: string): string | undefined;
|
|
11
13
|
setSessionIdForThread(userId: string, threadId: string, sessionId: string): void;
|
|
12
14
|
getWorkDir(userId: string): string;
|
|
@@ -33,6 +33,16 @@ export class SessionManager {
|
|
|
33
33
|
this.convSessionMap.set(`${userId}:${convId}`, sessionId);
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
+
/** 清除指定会话的 sessionId(用于 SDK 报 "No conversation found" 时) */
|
|
37
|
+
clearSessionForConv(userId, convId) {
|
|
38
|
+
const s = this.sessions.get(userId);
|
|
39
|
+
if (s?.activeConvId === convId) {
|
|
40
|
+
s.sessionId = undefined;
|
|
41
|
+
this.save();
|
|
42
|
+
}
|
|
43
|
+
this.convSessionMap.delete(`${userId}:${convId}`);
|
|
44
|
+
log.info(`Cleared session for user ${userId}, convId=${convId}`);
|
|
45
|
+
}
|
|
36
46
|
getSessionIdForThread(_userId, _threadId) {
|
|
37
47
|
return undefined;
|
|
38
48
|
}
|
package/dist/shared/ai-task.js
CHANGED
|
@@ -103,6 +103,10 @@ export function runAITask(deps, ctx, prompt, toolAdapter, platformAdapter) {
|
|
|
103
103
|
else if (ctx.convId)
|
|
104
104
|
sessionManager.setSessionIdForConv(ctx.userId, ctx.convId, id);
|
|
105
105
|
},
|
|
106
|
+
onSessionInvalid: () => {
|
|
107
|
+
if (ctx.convId)
|
|
108
|
+
sessionManager.clearSessionForConv(ctx.userId, ctx.convId);
|
|
109
|
+
},
|
|
106
110
|
onThinking: (t) => {
|
|
107
111
|
if (!firstContentLogged) {
|
|
108
112
|
firstContentLogged = true;
|
|
@@ -147,9 +151,19 @@ export function runAITask(deps, ctx, prompt, toolAdapter, platformAdapter) {
|
|
|
147
151
|
pendingUpdate = null;
|
|
148
152
|
}
|
|
149
153
|
const note = buildCompletionNote(result, sessionManager, ctx, mode);
|
|
150
|
-
|
|
154
|
+
// 优先用 adapter 返回的 accumulated/result;若为空则用流式期间累积的 latestContent(SDK 有时 result 事件不携带文本)
|
|
155
|
+
const output = result.accumulated ||
|
|
156
|
+
result.result ||
|
|
157
|
+
taskState.latestContent ||
|
|
158
|
+
'(无输出)';
|
|
159
|
+
if (!result.accumulated && !result.result && taskState.latestContent) {
|
|
160
|
+
log.warn(`Empty AI output from adapter but had streamed content (${taskState.latestContent.length} chars), using latestContent. platform=${ctx.platform}, taskKey=${ctx.taskKey}`);
|
|
161
|
+
}
|
|
162
|
+
else if (!output || output === '(无输出)') {
|
|
163
|
+
log.warn(`Empty AI output for user ${ctx.userId}, platform=${ctx.platform}, taskKey=${ctx.taskKey}`);
|
|
164
|
+
}
|
|
151
165
|
try {
|
|
152
|
-
await platformAdapter.sendComplete(
|
|
166
|
+
await platformAdapter.sendComplete(output, note, thinkingText || undefined);
|
|
153
167
|
}
|
|
154
168
|
catch (err) {
|
|
155
169
|
log.error('Failed to send complete:', err);
|