@xmanrui/dsh-im 0.7.1 → 0.7.2
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/lib/index.js +113 -112
- package/package.json +1 -1
- package/src/channels/dingtalk/dingtalk-bridge.mjs +66 -3
- package/src/channels/discord/discord-api.mjs +1 -1
- package/src/channels/feishu/bridge.mjs +52 -3
- package/src/channels/qq/qq-bridge.mjs +51 -3
- package/src/channels/shared/harness-approval.mjs +472 -0
- package/src/channels/shared/harness-client.mjs +37 -4
- package/src/channels/shared/text-harness-bridge.mjs +54 -4
- package/src/channels/wecom/wecom-bridge.mjs +51 -3
- package/src/channels/weixin/weixin-api.mjs +1 -1
- package/src/channels/weixin/weixin-bridge.mjs +52 -3
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
harnessQuestionText,
|
|
5
5
|
validHarnessQuestion,
|
|
6
6
|
} from '../shared/harness-question.mjs';
|
|
7
|
+
import { HarnessApprovalQueue } from '../shared/harness-approval.mjs';
|
|
7
8
|
import { runWorkspaceCommand } from '../shared/workspace-command.mjs';
|
|
8
9
|
import { askInWorkspaceSession } from '../shared/workspace-session.mjs';
|
|
9
10
|
|
|
@@ -114,6 +115,8 @@ export class WecomHarnessBridge {
|
|
|
114
115
|
#pendingInteractions = new Map();
|
|
115
116
|
#interactionKeys = new Map();
|
|
116
117
|
#acceptedMessageIds = new Set();
|
|
118
|
+
#approvalTasks = new Set();
|
|
119
|
+
#approvals;
|
|
117
120
|
|
|
118
121
|
constructor({
|
|
119
122
|
client,
|
|
@@ -137,6 +140,7 @@ export class WecomHarnessBridge {
|
|
|
137
140
|
this.#replyTimeoutMs = replyTimeoutMs;
|
|
138
141
|
this.#generateReqId = generateStreamId;
|
|
139
142
|
this.#signal = signal;
|
|
143
|
+
this.#approvals = new HarnessApprovalQueue({ label: 'wecom', logger });
|
|
140
144
|
}
|
|
141
145
|
|
|
142
146
|
get status() {
|
|
@@ -159,6 +163,35 @@ export class WecomHarnessBridge {
|
|
|
159
163
|
const key = conversationKey(frame);
|
|
160
164
|
this.#acceptedMessageIds.add(messageId);
|
|
161
165
|
const pending = this.#pendingInteractions.get(key);
|
|
166
|
+
const approval = this.#approvals.claimReply({
|
|
167
|
+
key,
|
|
168
|
+
actor: senderId,
|
|
169
|
+
messageId,
|
|
170
|
+
text: messageText(frame),
|
|
171
|
+
addressed: true,
|
|
172
|
+
hasPendingQuestion: Boolean(pending),
|
|
173
|
+
questionCompletion: pending?.submitting || pending?.claimedReplyMessageId
|
|
174
|
+
? pending.queue
|
|
175
|
+
: null,
|
|
176
|
+
isQuestionPending: () => this.#pendingInteractions.has(key),
|
|
177
|
+
send: (text) => this.#sendImmediate(frame, chatId, text),
|
|
178
|
+
});
|
|
179
|
+
if (approval) {
|
|
180
|
+
let task;
|
|
181
|
+
task = approval.process(async () => {
|
|
182
|
+
if (this.#state.hasSeen(messageId)) return false;
|
|
183
|
+
await this.#state.markSeen(messageId);
|
|
184
|
+
this.#status.messagesReceived += 1;
|
|
185
|
+
this.#status.lastMessageAt = new Date().toISOString();
|
|
186
|
+
return true;
|
|
187
|
+
})
|
|
188
|
+
.finally(() => {
|
|
189
|
+
this.#acceptedMessageIds.delete(messageId);
|
|
190
|
+
this.#approvalTasks.delete(task);
|
|
191
|
+
});
|
|
192
|
+
this.#approvalTasks.add(task);
|
|
193
|
+
return task;
|
|
194
|
+
}
|
|
162
195
|
if (pending && pending.actor !== senderId) {
|
|
163
196
|
return this.#enqueueMessage(frame, messageId, key);
|
|
164
197
|
}
|
|
@@ -215,6 +248,7 @@ export class WecomHarnessBridge {
|
|
|
215
248
|
...[...this.#pendingInteractions.values()].flatMap((pending) => (
|
|
216
249
|
pending.queue ? [pending.queue] : []
|
|
217
250
|
)),
|
|
251
|
+
...this.#approvalTasks,
|
|
218
252
|
]);
|
|
219
253
|
}
|
|
220
254
|
|
|
@@ -355,7 +389,10 @@ export class WecomHarnessBridge {
|
|
|
355
389
|
this.#logger.error?.('[dsh-im:wecom] failed to send the safe error reply');
|
|
356
390
|
}
|
|
357
391
|
} finally {
|
|
358
|
-
await
|
|
392
|
+
await Promise.allSettled([
|
|
393
|
+
this.#cancelPendingInteraction(key),
|
|
394
|
+
this.#approvals.closeRoute(key),
|
|
395
|
+
]);
|
|
359
396
|
}
|
|
360
397
|
}
|
|
361
398
|
|
|
@@ -481,7 +518,14 @@ export class WecomHarnessBridge {
|
|
|
481
518
|
chatId,
|
|
482
519
|
requiresMention,
|
|
483
520
|
}) {
|
|
484
|
-
|
|
521
|
+
if (interaction?.kind === 'approval') {
|
|
522
|
+
return this.#approvals.handleRequested(interaction, {
|
|
523
|
+
key,
|
|
524
|
+
actor,
|
|
525
|
+
requiresMention,
|
|
526
|
+
send: (text) => this.#sendActive(chatId, text),
|
|
527
|
+
});
|
|
528
|
+
}
|
|
485
529
|
if (interaction?.kind !== 'question') return;
|
|
486
530
|
const questions = interaction?.payload?.questions;
|
|
487
531
|
const interactionId = typeof interaction?.interactionId === 'string'
|
|
@@ -555,7 +599,11 @@ export class WecomHarnessBridge {
|
|
|
555
599
|
await this.#presentInteraction(pending);
|
|
556
600
|
}
|
|
557
601
|
|
|
558
|
-
#handleInteractionResolved(resolution) {
|
|
602
|
+
async #handleInteractionResolved(resolution) {
|
|
603
|
+
if (resolution?.kind === 'approval') {
|
|
604
|
+
await this.#approvals.handleResolved(resolution);
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
559
607
|
const interactionId = resolution?.interactionId;
|
|
560
608
|
if (resolution?.kind !== 'question' || typeof interactionId !== 'string') return;
|
|
561
609
|
const key = this.#interactionKeys.get(interactionId);
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
harnessQuestionText,
|
|
9
9
|
validHarnessQuestion,
|
|
10
10
|
} from '../shared/harness-question.mjs';
|
|
11
|
+
import { HarnessApprovalQueue } from '../shared/harness-approval.mjs';
|
|
11
12
|
import { runWorkspaceCommand } from '../shared/workspace-command.mjs';
|
|
12
13
|
import { askInWorkspaceSession } from '../shared/workspace-session.mjs';
|
|
13
14
|
|
|
@@ -68,6 +69,8 @@ export class WeixinHarnessBridge {
|
|
|
68
69
|
#pendingInteractions = new Map();
|
|
69
70
|
#interactionKeys = new Map();
|
|
70
71
|
#acceptedMessageIds = new Set();
|
|
72
|
+
#approvalTasks = new Set();
|
|
73
|
+
#approvals;
|
|
71
74
|
|
|
72
75
|
constructor({
|
|
73
76
|
api,
|
|
@@ -96,6 +99,7 @@ export class WeixinHarnessBridge {
|
|
|
96
99
|
this.#replyTimeoutMs = replyTimeoutMs;
|
|
97
100
|
this.#maxMessageChars = maxMessageChars;
|
|
98
101
|
this.#signal = signal;
|
|
102
|
+
this.#approvals = new HarnessApprovalQueue({ label: 'weixin', logger });
|
|
99
103
|
}
|
|
100
104
|
|
|
101
105
|
get status() {
|
|
@@ -111,7 +115,38 @@ export class WeixinHarnessBridge {
|
|
|
111
115
|
|| this.#acceptedMessageIds.has(messageId)) return Promise.resolve();
|
|
112
116
|
this.#acceptedMessageIds.add(messageId);
|
|
113
117
|
const key = conversationKey(sender);
|
|
118
|
+
const contextToken = nonEmptyString(message?.context_token) ?? undefined;
|
|
119
|
+
const runId = nonEmptyString(message?.run_id) ?? undefined;
|
|
114
120
|
const pending = this.#pendingInteractions.get(key);
|
|
121
|
+
const approval = this.#approvals.claimReply({
|
|
122
|
+
key,
|
|
123
|
+
actor: sender,
|
|
124
|
+
messageId,
|
|
125
|
+
text: extractWeixinText(message),
|
|
126
|
+
addressed: true,
|
|
127
|
+
hasPendingQuestion: Boolean(pending),
|
|
128
|
+
questionCompletion: pending?.submitting || pending?.claimedReplyMessageId
|
|
129
|
+
? pending.queue
|
|
130
|
+
: null,
|
|
131
|
+
isQuestionPending: () => this.#pendingInteractions.has(key),
|
|
132
|
+
send: (text) => this.#send(sender, text, contextToken, runId),
|
|
133
|
+
});
|
|
134
|
+
if (approval) {
|
|
135
|
+
let task;
|
|
136
|
+
task = approval.process(async () => {
|
|
137
|
+
if (this.#state.hasSeen(messageId)) return false;
|
|
138
|
+
await this.#state.markSeen(messageId);
|
|
139
|
+
this.#status.messagesReceived += 1;
|
|
140
|
+
this.#status.lastMessageAt = new Date().toISOString();
|
|
141
|
+
return true;
|
|
142
|
+
})
|
|
143
|
+
.finally(() => {
|
|
144
|
+
this.#acceptedMessageIds.delete(messageId);
|
|
145
|
+
this.#approvalTasks.delete(task);
|
|
146
|
+
});
|
|
147
|
+
this.#approvalTasks.add(task);
|
|
148
|
+
return task;
|
|
149
|
+
}
|
|
115
150
|
if (pending?.submitting || pending?.claimedReplyMessageId) {
|
|
116
151
|
return this.#enqueueMessage(message, messageId, key);
|
|
117
152
|
}
|
|
@@ -157,6 +192,7 @@ export class WeixinHarnessBridge {
|
|
|
157
192
|
...[...this.#pendingInteractions.values()].flatMap((pending) => (
|
|
158
193
|
pending.queue ? [pending.queue] : []
|
|
159
194
|
)),
|
|
195
|
+
...this.#approvalTasks,
|
|
160
196
|
]);
|
|
161
197
|
}
|
|
162
198
|
|
|
@@ -235,7 +271,10 @@ export class WeixinHarnessBridge {
|
|
|
235
271
|
},
|
|
236
272
|
}));
|
|
237
273
|
} finally {
|
|
238
|
-
await
|
|
274
|
+
await Promise.allSettled([
|
|
275
|
+
this.#cancelPendingInteraction(key),
|
|
276
|
+
this.#approvals.closeRoute(key),
|
|
277
|
+
]);
|
|
239
278
|
}
|
|
240
279
|
await this.#send(sender, answer, contextToken, runId);
|
|
241
280
|
await this.#state.markSeen(messageId);
|
|
@@ -391,7 +430,13 @@ export class WeixinHarnessBridge {
|
|
|
391
430
|
contextToken,
|
|
392
431
|
runId,
|
|
393
432
|
}) {
|
|
394
|
-
|
|
433
|
+
if (interaction?.kind === 'approval') {
|
|
434
|
+
return this.#approvals.handleRequested(interaction, {
|
|
435
|
+
key,
|
|
436
|
+
actor,
|
|
437
|
+
send: (text) => this.#send(actor, text, contextToken, runId),
|
|
438
|
+
});
|
|
439
|
+
}
|
|
395
440
|
if (interaction?.kind !== 'question') return;
|
|
396
441
|
const questions = interaction?.payload?.questions;
|
|
397
442
|
const interactionId = typeof interaction?.interactionId === 'string'
|
|
@@ -466,7 +511,11 @@ export class WeixinHarnessBridge {
|
|
|
466
511
|
await this.#presentInteraction(pending);
|
|
467
512
|
}
|
|
468
513
|
|
|
469
|
-
#handleInteractionResolved(resolution) {
|
|
514
|
+
async #handleInteractionResolved(resolution) {
|
|
515
|
+
if (resolution?.kind === 'approval') {
|
|
516
|
+
await this.#approvals.handleResolved(resolution);
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
470
519
|
const interactionId = resolution?.interactionId;
|
|
471
520
|
if (resolution?.kind !== 'question' || typeof interactionId !== 'string') return;
|
|
472
521
|
const key = this.#interactionKeys.get(interactionId);
|