@wu529778790/open-im 1.5.3 → 1.5.4
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/wework/message-sender.js +88 -13
- package/package.json +1 -1
|
@@ -8,6 +8,8 @@ import { splitLongContent, getAIToolDisplayName } from '../shared/utils.js';
|
|
|
8
8
|
import { MAX_WEWORK_MESSAGE_LENGTH } from '../constants.js';
|
|
9
9
|
import { randomBytes } from 'node:crypto';
|
|
10
10
|
const log = createLogger('WeWorkSender');
|
|
11
|
+
const STREAM_SEND_INTERVAL_MS = 900;
|
|
12
|
+
const STREAM_SAFE_TTL_MS = 5 * 60 * 1000;
|
|
11
13
|
/** 当前同步处理中的 req_id(仅用于 commandHandler 等同步调用) */
|
|
12
14
|
let currentReqId = null;
|
|
13
15
|
export function setCurrentReqId(reqId) {
|
|
@@ -61,11 +63,61 @@ function formatWeWorkMessage(title, content, status, note) {
|
|
|
61
63
|
}
|
|
62
64
|
return message;
|
|
63
65
|
}
|
|
64
|
-
/**
|
|
65
|
-
* Local tracking for stream states
|
|
66
|
-
* WeWork doesn't support message editing, so we track stream IDs locally
|
|
67
|
-
*/
|
|
68
66
|
const streamStates = new Map();
|
|
67
|
+
function sleep(ms) {
|
|
68
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
69
|
+
}
|
|
70
|
+
function getOrCreateStreamState(streamId, chatId) {
|
|
71
|
+
const existing = streamStates.get(streamId);
|
|
72
|
+
if (existing)
|
|
73
|
+
return existing;
|
|
74
|
+
const state = {
|
|
75
|
+
chatId,
|
|
76
|
+
content: '',
|
|
77
|
+
createdAt: Date.now(),
|
|
78
|
+
lastSentAt: 0,
|
|
79
|
+
closed: false,
|
|
80
|
+
expired: false,
|
|
81
|
+
flushing: false,
|
|
82
|
+
expireLogged: false,
|
|
83
|
+
};
|
|
84
|
+
streamStates.set(streamId, state);
|
|
85
|
+
return state;
|
|
86
|
+
}
|
|
87
|
+
function markExpired(state, streamId) {
|
|
88
|
+
state.expired = true;
|
|
89
|
+
if (!state.expireLogged) {
|
|
90
|
+
state.expireLogged = true;
|
|
91
|
+
log.warn(`Stream expired locally, switching to text fallback: streamId=${streamId}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async function flushStreamUpdate(streamId, state) {
|
|
95
|
+
if (state.flushing || state.closed || state.expired)
|
|
96
|
+
return;
|
|
97
|
+
state.flushing = true;
|
|
98
|
+
try {
|
|
99
|
+
while (state.pendingUpdate && !state.closed && !state.expired) {
|
|
100
|
+
const queued = state.pendingUpdate;
|
|
101
|
+
state.pendingUpdate = undefined;
|
|
102
|
+
if (Date.now() - state.createdAt >= STREAM_SAFE_TTL_MS) {
|
|
103
|
+
markExpired(state, streamId);
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
const elapsed = Date.now() - state.lastSentAt;
|
|
107
|
+
if (elapsed < STREAM_SEND_INTERVAL_MS) {
|
|
108
|
+
await sleep(STREAM_SEND_INTERVAL_MS - elapsed);
|
|
109
|
+
}
|
|
110
|
+
if (state.closed || state.expired)
|
|
111
|
+
break;
|
|
112
|
+
sendStream(getReqId(queued.reqId), streamId, queued.message, false);
|
|
113
|
+
state.lastSentAt = Date.now();
|
|
114
|
+
log.info(`Message updated: ${queued.status}, streamId=${streamId}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
state.flushing = false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
69
121
|
/**
|
|
70
122
|
* Send thinking message to WeWork
|
|
71
123
|
* Returns a stream ID that can be used for updates
|
|
@@ -78,7 +130,7 @@ export async function sendThinkingMessage(chatId, _replyToMessageId, toolId = 'c
|
|
|
78
130
|
try {
|
|
79
131
|
log.info(`Sending thinking message to user ${chatId}, streamId=${streamId}`);
|
|
80
132
|
// Store initial stream state
|
|
81
|
-
|
|
133
|
+
getOrCreateStreamState(streamId, chatId);
|
|
82
134
|
// Send initial stream message (not finished)
|
|
83
135
|
sendStream(getReqId(reqId), streamId, content, false);
|
|
84
136
|
log.info(`Thinking message sent: ${streamId}`);
|
|
@@ -96,12 +148,18 @@ export async function sendThinkingMessage(chatId, _replyToMessageId, toolId = 'c
|
|
|
96
148
|
export async function updateMessage(chatId, streamId, content, status, note, toolId = 'claude', reqId) {
|
|
97
149
|
const title = getToolTitle(toolId, status);
|
|
98
150
|
const message = formatWeWorkMessage(title, content, status, note);
|
|
151
|
+
const state = getOrCreateStreamState(streamId, chatId);
|
|
99
152
|
try {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
153
|
+
state.chatId = chatId;
|
|
154
|
+
state.content = content;
|
|
155
|
+
if (state.closed)
|
|
156
|
+
return;
|
|
157
|
+
if (Date.now() - state.createdAt >= STREAM_SAFE_TTL_MS) {
|
|
158
|
+
markExpired(state, streamId);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
state.pendingUpdate = { message, status, reqId };
|
|
162
|
+
await flushStreamUpdate(streamId, state);
|
|
105
163
|
}
|
|
106
164
|
catch (err) {
|
|
107
165
|
log.error('Failed to update message:', err);
|
|
@@ -117,9 +175,26 @@ export async function sendFinalMessages(chatId, streamId, fullContent, note, too
|
|
|
117
175
|
// Send final stream message to finish the stream
|
|
118
176
|
const finalMessage = formatWeWorkMessage(title, parts[0], 'done', parts.length > 1 ? `内容较长,已分段发送 (1/${parts.length})` : note);
|
|
119
177
|
try {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
178
|
+
const state = streamStates.get(streamId);
|
|
179
|
+
const shouldFallbackToText = !!state && (state.expired || Date.now() - state.createdAt >= STREAM_SAFE_TTL_MS);
|
|
180
|
+
if (state) {
|
|
181
|
+
state.closed = true;
|
|
182
|
+
state.pendingUpdate = undefined;
|
|
183
|
+
}
|
|
184
|
+
if (!shouldFallbackToText) {
|
|
185
|
+
if (state) {
|
|
186
|
+
const elapsed = Date.now() - state.lastSentAt;
|
|
187
|
+
if (elapsed < STREAM_SEND_INTERVAL_MS) {
|
|
188
|
+
await sleep(STREAM_SEND_INTERVAL_MS - elapsed);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
sendStream(getReqId(reqId), streamId, finalMessage, true);
|
|
192
|
+
log.info(`Final stream message sent, streamId=${streamId}`);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
sendText(getReqId(reqId), finalMessage);
|
|
196
|
+
log.info(`Final stream expired, sent text fallback instead: streamId=${streamId}`);
|
|
197
|
+
}
|
|
123
198
|
streamStates.delete(streamId);
|
|
124
199
|
// Send remaining parts as separate messages
|
|
125
200
|
for (let i = 1; i < parts.length; i++) {
|