@xmanrui/dsh-im 2.4.0 → 2.6.0
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.en.md +2 -2
- package/README.md +2 -2
- package/lib/client.js +322 -109
- package/lib/index.js +218 -211
- package/package.json +1 -1
- package/plugin-src/client/channel-card-meta.js +36 -1
- package/plugin-src/client/channels/dingtalk/api.js +2 -0
- package/plugin-src/client/channels/dingtalk/index.js +9 -1
- package/plugin-src/client/channels/feishu/api.js +3 -0
- package/plugin-src/client/channels/feishu/index.js +9 -1
- package/plugin-src/client/channels/qq/api.js +2 -0
- package/plugin-src/client/channels/qq/index.js +9 -1
- package/plugin-src/client/channels/shared/token-api.js +2 -0
- package/plugin-src/client/channels/shared/token-channel.js +9 -1
- package/plugin-src/client/channels/wecom/api.js +2 -0
- package/plugin-src/client/channels/wecom/index.js +9 -1
- package/plugin-src/client/channels/weixin/api.js +2 -10
- package/plugin-src/client/channels/weixin/index.js +9 -5
- package/plugin-src/client/channels/whatsapp/api.js +2 -0
- package/plugin-src/client/channels/whatsapp/index.js +9 -1
- package/plugin-src/client/i18n.js +4 -0
- package/plugin-src/client/index.js +16 -2
- package/plugin-src/client/last-message-error.js +17 -0
- package/plugin-src/client/styles.js +5 -1
- package/plugin-src/host/channels/feishu/rpc.mjs +3 -0
- package/src/channels/dingtalk/dingtalk-api.mjs +102 -6
- package/src/channels/dingtalk/dingtalk-bridge.mjs +247 -38
- package/src/channels/dingtalk/dingtalk-card-stream.mjs +2 -2
- package/src/channels/dingtalk/dingtalk-controller.mjs +2 -0
- package/src/channels/discord/discord-api.mjs +35 -0
- package/src/channels/discord/discord-bridge.mjs +1 -0
- package/src/channels/discord/discord-runtime.mjs +26 -0
- package/src/channels/feishu/bridge.mjs +115 -69
- package/src/channels/feishu/multi-bot-controller.mjs +2 -0
- package/src/channels/qq/qq-bridge.mjs +83 -28
- package/src/channels/qq/qq-controller.mjs +2 -0
- package/src/channels/shared/harness-client.mjs +40 -4
- package/src/channels/shared/i18n-en/shared-a.mjs +77 -0
- package/src/channels/shared/message-failure.mjs +244 -0
- package/src/channels/shared/semantic/artifact-delivery.mjs +9 -2
- package/src/channels/shared/status-reaction.mjs +107 -0
- package/src/channels/shared/text-harness-bridge.mjs +123 -66
- package/src/channels/shared/token-bot-controller.mjs +2 -0
- package/src/channels/slack/manifest.mjs +1 -0
- package/src/channels/slack/slack-api.mjs +28 -0
- package/src/channels/slack/slack-bridge.mjs +5 -0
- package/src/channels/slack/slack-controller.mjs +2 -0
- package/src/channels/slack/slack-runtime.mjs +24 -0
- package/src/channels/telegram/telegram-api.mjs +9 -0
- package/src/channels/telegram/telegram-bridge.mjs +1 -0
- package/src/channels/telegram/telegram-runtime.mjs +20 -0
- package/src/channels/wecom/wecom-bridge.mjs +49 -15
- package/src/channels/wecom/wecom-controller.mjs +2 -0
- package/src/channels/weixin/weixin-api.mjs +47 -0
- package/src/channels/weixin/weixin-bridge.mjs +261 -43
- package/src/channels/weixin/weixin-controller.mjs +2 -15
- package/src/channels/weixin/weixin-runtime.mjs +1 -0
- package/src/channels/whatsapp/whatsapp-bridge.mjs +1 -0
- package/src/channels/whatsapp/whatsapp-controller.mjs +2 -0
- package/src/channels/whatsapp/whatsapp-runtime.mjs +36 -0
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
import {
|
|
30
30
|
fetchImageBuffer,
|
|
31
31
|
hasInboundImages,
|
|
32
|
+
imagePromptDiagnostic,
|
|
32
33
|
imagePromptUserMessage,
|
|
33
34
|
promptContentForMessage,
|
|
34
35
|
} from '../shared/image-prompt.mjs';
|
|
@@ -45,6 +46,12 @@ import {
|
|
|
45
46
|
createDeliveryReceipt,
|
|
46
47
|
providerMessageIdsFor,
|
|
47
48
|
} from '../shared/semantic/delivery.mjs';
|
|
49
|
+
import {
|
|
50
|
+
channelDeliveryFailure,
|
|
51
|
+
clearLastMessageFailure,
|
|
52
|
+
messageFailureText,
|
|
53
|
+
setLastMessageFailure,
|
|
54
|
+
} from '../shared/message-failure.mjs';
|
|
48
55
|
import { sendMarkdownReply } from './markdown-reply.mjs';
|
|
49
56
|
import { t } from '../shared/i18n.mjs';
|
|
50
57
|
|
|
@@ -216,9 +223,15 @@ function answerTextForDelivery(answer, artifacts) {
|
|
|
216
223
|
}
|
|
217
224
|
|
|
218
225
|
function qqArtifactError(error, { dispatched = false } = {}) {
|
|
219
|
-
if (error?.code?.startsWith?.('artifact-')
|
|
226
|
+
if (error?.code?.startsWith?.('artifact-')) {
|
|
220
227
|
return error;
|
|
221
228
|
}
|
|
229
|
+
if (error?.name === 'UploadDailyLimitExceededError') {
|
|
230
|
+
const wrapped = new Error('QQ daily file upload limit exceeded', { cause: error });
|
|
231
|
+
wrapped.name = error.name;
|
|
232
|
+
wrapped.code = 'artifact-rate-limited';
|
|
233
|
+
return wrapped;
|
|
234
|
+
}
|
|
222
235
|
const status = Number(error?.httpStatus);
|
|
223
236
|
const wrapped = new Error('QQ file delivery failed', { cause: error });
|
|
224
237
|
if (status === 401 || status === 403) wrapped.code = 'artifact-permission-required';
|
|
@@ -341,6 +354,7 @@ export function createQqBridgeStatus() {
|
|
|
341
354
|
lastReplyAt: null,
|
|
342
355
|
lastRejectedAt: null,
|
|
343
356
|
lastError: null,
|
|
357
|
+
lastMessageError: null,
|
|
344
358
|
};
|
|
345
359
|
}
|
|
346
360
|
|
|
@@ -470,8 +484,12 @@ export class QqHarnessBridge {
|
|
|
470
484
|
).catch((error) => {
|
|
471
485
|
if (error?.code === 'turn-stopped' || this.#signal?.aborted) return;
|
|
472
486
|
this.#status.lastError = error?.message ?? String(error);
|
|
473
|
-
|
|
474
|
-
|
|
487
|
+
const failure = setLastMessageFailure(this.#status, error);
|
|
488
|
+
this.#logger.error?.(
|
|
489
|
+
`[dsh-im:qq] failed to process a command [${failure.referenceId}]:`,
|
|
490
|
+
error,
|
|
491
|
+
);
|
|
492
|
+
return this.#bot.sendText(message.replyTarget, messageFailureText(failure))
|
|
475
493
|
.catch(() => undefined);
|
|
476
494
|
}).finally(() => {
|
|
477
495
|
this.#acceptedMessageIds.delete(messageId);
|
|
@@ -614,8 +632,12 @@ export class QqHarnessBridge {
|
|
|
614
632
|
}).catch(async (error) => {
|
|
615
633
|
if (this.#signal?.aborted) return;
|
|
616
634
|
this.#status.lastError = error?.message ?? String(error);
|
|
617
|
-
|
|
618
|
-
|
|
635
|
+
const failure = setLastMessageFailure(this.#status, error);
|
|
636
|
+
this.#logger.error?.(
|
|
637
|
+
`[dsh-im:qq] failed to process a batch input message [${failure.referenceId}]:`,
|
|
638
|
+
error,
|
|
639
|
+
);
|
|
640
|
+
await this.#bot.sendText(message.replyTarget, messageFailureText(failure))
|
|
619
641
|
.catch(() => undefined);
|
|
620
642
|
}).finally(() => {
|
|
621
643
|
this.#acceptedMessageIds.delete(messageId);
|
|
@@ -627,7 +649,7 @@ export class QqHarnessBridge {
|
|
|
627
649
|
|
|
628
650
|
async #deliverArtifacts(target, replyTo, artifacts = [], baseReceipt = null) {
|
|
629
651
|
if (artifacts.length === 0) {
|
|
630
|
-
return { receipt: baseReceipt, failureNoticeVisible: false };
|
|
652
|
+
return { receipt: baseReceipt, failureNoticeVisible: false, artifactSendErrors: 0 };
|
|
631
653
|
}
|
|
632
654
|
const delivery = await deliverOutboundArtifacts({
|
|
633
655
|
artifacts,
|
|
@@ -645,9 +667,13 @@ export class QqHarnessBridge {
|
|
|
645
667
|
signal: this.#signal,
|
|
646
668
|
timeoutMs: this.#fileUploadTimeoutMs,
|
|
647
669
|
}),
|
|
648
|
-
|
|
670
|
+
onFailure: (artifact, error) => setLastMessageFailure(this.#status, error, {
|
|
671
|
+
userMessage: artifactFailureText(artifact?.fileName, error),
|
|
672
|
+
reason: error?.code,
|
|
673
|
+
}),
|
|
674
|
+
sendFailureNotice: (_artifact, _error, failure) => this.#bot.sendText(
|
|
649
675
|
target,
|
|
650
|
-
|
|
676
|
+
messageFailureText(failure),
|
|
651
677
|
),
|
|
652
678
|
logger: this.#logger,
|
|
653
679
|
});
|
|
@@ -658,6 +684,7 @@ export class QqHarnessBridge {
|
|
|
658
684
|
return {
|
|
659
685
|
receipt: delivery.receipt,
|
|
660
686
|
failureNoticeVisible: delivery.failureNoticeVisible,
|
|
687
|
+
artifactSendErrors: delivery.artifactSendErrors,
|
|
661
688
|
};
|
|
662
689
|
}
|
|
663
690
|
|
|
@@ -676,6 +703,12 @@ export class QqHarnessBridge {
|
|
|
676
703
|
this.#status.messagesReceived += 1;
|
|
677
704
|
this.#status.lastMessageAt = new Date().toISOString();
|
|
678
705
|
}
|
|
706
|
+
let messageRecorded = alreadyRecorded;
|
|
707
|
+
const markMessageSeen = async () => {
|
|
708
|
+
if (messageRecorded) return;
|
|
709
|
+
await this.#state.markSeen(messageId);
|
|
710
|
+
messageRecorded = true;
|
|
711
|
+
};
|
|
679
712
|
if (this.#ownerUserOpenid !== '*' && sender !== this.#ownerUserOpenid) {
|
|
680
713
|
this.#status.messagesRejected += 1;
|
|
681
714
|
this.#status.lastRejectedAt = new Date().toISOString();
|
|
@@ -694,25 +727,25 @@ export class QqHarnessBridge {
|
|
|
694
727
|
try {
|
|
695
728
|
if (!text && !hasImages && !hasFiles) {
|
|
696
729
|
await this.#bot.sendText(target, t('目前支持文字、图片和文件消息。'));
|
|
697
|
-
await
|
|
730
|
+
await markMessageSeen();
|
|
698
731
|
return;
|
|
699
732
|
}
|
|
700
733
|
const command = text.toLowerCase();
|
|
701
734
|
if (!hasImages && !hasFiles && command === '/help') {
|
|
702
735
|
await this.#bot.sendText(target, helpText());
|
|
703
|
-
await
|
|
736
|
+
await markMessageSeen();
|
|
704
737
|
return;
|
|
705
738
|
}
|
|
706
739
|
if (!hasImages && !hasFiles && command === '/status') {
|
|
707
740
|
await this.#harness.ensureRunning({ signal: this.#signal });
|
|
708
741
|
await this.#bot.sendText(target, t('QQ 机器人与 DeepSeek Harness 连接正常。'));
|
|
709
|
-
await
|
|
742
|
+
await markMessageSeen();
|
|
710
743
|
return;
|
|
711
744
|
}
|
|
712
745
|
if (!hasImages && !hasFiles && command === '/new') {
|
|
713
746
|
await this.#state.clearSession(key);
|
|
714
747
|
await this.#bot.sendText(target, t('已开启新会话。请发送你的问题。'));
|
|
715
|
-
await
|
|
748
|
+
await markMessageSeen();
|
|
716
749
|
return;
|
|
717
750
|
}
|
|
718
751
|
const workspaceCommand = hasImages || hasFiles
|
|
@@ -722,7 +755,7 @@ export class QqHarnessBridge {
|
|
|
722
755
|
for (const reply of workspaceCommand.messages ?? [workspaceCommand.message]) {
|
|
723
756
|
await this.#bot.sendText(target, reply);
|
|
724
757
|
}
|
|
725
|
-
await
|
|
758
|
+
await markMessageSeen();
|
|
726
759
|
return;
|
|
727
760
|
}
|
|
728
761
|
const compactCommand = hasImages || hasFiles
|
|
@@ -736,7 +769,7 @@ export class QqHarnessBridge {
|
|
|
736
769
|
);
|
|
737
770
|
if (compactCommand) {
|
|
738
771
|
await this.#bot.sendText(target, compactCommand.message);
|
|
739
|
-
await
|
|
772
|
+
await markMessageSeen();
|
|
740
773
|
return;
|
|
741
774
|
}
|
|
742
775
|
|
|
@@ -757,6 +790,9 @@ export class QqHarnessBridge {
|
|
|
757
790
|
let answer;
|
|
758
791
|
let artifacts = [];
|
|
759
792
|
try {
|
|
793
|
+
// Persist consumption before handing the prompt to Harness. Provider
|
|
794
|
+
// redelivery after a failed error notice must never execute it twice.
|
|
795
|
+
await markMessageSeen();
|
|
760
796
|
({ answer, artifacts = [] } = await askInWorkspaceSession({
|
|
761
797
|
harness: this.#harness,
|
|
762
798
|
state: this.#state,
|
|
@@ -771,10 +807,13 @@ export class QqHarnessBridge {
|
|
|
771
807
|
progressMode: 'all',
|
|
772
808
|
onUpdate: (update) => {
|
|
773
809
|
if (update.error) {
|
|
774
|
-
const
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
toolErrors.push(
|
|
810
|
+
const name = (nonEmptyString(update.toolName) ?? t('工具'))
|
|
811
|
+
.replace(/[\r\n]+/gu, ' ')
|
|
812
|
+
.slice(0, 80);
|
|
813
|
+
toolErrors.push(t(
|
|
814
|
+
'工具调用「{name}」未成功,请检查工具配置或稍后重试。',
|
|
815
|
+
{ name },
|
|
816
|
+
));
|
|
778
817
|
}
|
|
779
818
|
},
|
|
780
819
|
onInteraction: (interaction) => this.#handleInteraction(interaction, {
|
|
@@ -836,7 +875,7 @@ export class QqHarnessBridge {
|
|
|
836
875
|
});
|
|
837
876
|
}
|
|
838
877
|
} catch (error) {
|
|
839
|
-
textSendError = error;
|
|
878
|
+
textSendError = channelDeliveryFailure(error);
|
|
840
879
|
this.#logger.warn?.('[dsh-im:qq] final text delivery failed; continuing with result files:', error);
|
|
841
880
|
}
|
|
842
881
|
const delivery = await this.#deliverArtifacts(target, messageId, artifacts, textReceipt);
|
|
@@ -846,10 +885,15 @@ export class QqHarnessBridge {
|
|
|
846
885
|
if (textSendError && !artifactDispatched && !delivery.failureNoticeVisible) {
|
|
847
886
|
throw textSendError;
|
|
848
887
|
}
|
|
849
|
-
|
|
888
|
+
if (textSendError && delivery.artifactSendErrors === 0) {
|
|
889
|
+
setLastMessageFailure(this.#status, textSendError);
|
|
890
|
+
}
|
|
850
891
|
this.#status.messagesReplied += 1;
|
|
851
892
|
this.#status.lastReplyAt = new Date().toISOString();
|
|
852
893
|
this.#status.lastError = null;
|
|
894
|
+
if (!textSendError && delivery.artifactSendErrors === 0) {
|
|
895
|
+
clearLastMessageFailure(this.#status);
|
|
896
|
+
}
|
|
853
897
|
return delivery.receipt;
|
|
854
898
|
} catch (error) {
|
|
855
899
|
let batchFailureMessage = null;
|
|
@@ -872,7 +916,7 @@ export class QqHarnessBridge {
|
|
|
872
916
|
} catch (sendError) {
|
|
873
917
|
this.#logger.warn?.('[dsh-im:qq] unable to announce a stopped QQ turn:', sendError);
|
|
874
918
|
}
|
|
875
|
-
await
|
|
919
|
+
await markMessageSeen();
|
|
876
920
|
return;
|
|
877
921
|
}
|
|
878
922
|
try {
|
|
@@ -882,16 +926,23 @@ export class QqHarnessBridge {
|
|
|
882
926
|
}
|
|
883
927
|
if (this.#signal?.aborted) return;
|
|
884
928
|
this.#status.lastError = error?.message ?? String(error);
|
|
885
|
-
|
|
929
|
+
const userMessage = inboundFileUserMessage(error)
|
|
930
|
+
?? imagePromptUserMessage(error);
|
|
931
|
+
const failure = setLastMessageFailure(this.#status, error, {
|
|
932
|
+
userMessage,
|
|
933
|
+
reason: imagePromptDiagnostic(error)?.reason,
|
|
934
|
+
});
|
|
935
|
+
this.#logger.error?.(
|
|
936
|
+
`[dsh-im:qq] failed to process an inbound message [${failure.referenceId}]:`,
|
|
937
|
+
error,
|
|
938
|
+
);
|
|
886
939
|
try {
|
|
887
|
-
const errorMessage =
|
|
888
|
-
?? imagePromptUserMessage(error)
|
|
889
|
-
?? t('消息处理失败,请稍后重试。');
|
|
940
|
+
const errorMessage = messageFailureText(failure);
|
|
890
941
|
await this.#bot.sendText(
|
|
891
942
|
target,
|
|
892
943
|
batchFailureMessage ? `${errorMessage}\n\n${batchFailureMessage}` : errorMessage,
|
|
893
944
|
);
|
|
894
|
-
await
|
|
945
|
+
await markMessageSeen();
|
|
895
946
|
} catch (sendError) {
|
|
896
947
|
this.#logger.error?.('[dsh-im:qq] failed to send the safe error reply:', sendError);
|
|
897
948
|
}
|
|
@@ -1166,11 +1217,15 @@ export class QqHarnessBridge {
|
|
|
1166
1217
|
async #handleInteractionFailure(message, messageId, error) {
|
|
1167
1218
|
if (this.#signal?.aborted) return;
|
|
1168
1219
|
this.#status.lastError = error?.message ?? String(error);
|
|
1169
|
-
|
|
1220
|
+
const failure = setLastMessageFailure(this.#status, error);
|
|
1221
|
+
this.#logger.error?.(
|
|
1222
|
+
`[dsh-im:qq] failed to process an interaction reply [${failure.referenceId}]:`,
|
|
1223
|
+
error,
|
|
1224
|
+
);
|
|
1170
1225
|
if (!this.#state.hasSeen(messageId)) {
|
|
1171
1226
|
await this.#state.markSeen(messageId).catch(() => undefined);
|
|
1172
1227
|
}
|
|
1173
|
-
await this.#bot.sendText(message.replyTarget,
|
|
1228
|
+
await this.#bot.sendText(message.replyTarget, messageFailureText(failure))
|
|
1174
1229
|
.catch(() => undefined);
|
|
1175
1230
|
}
|
|
1176
1231
|
}
|
|
@@ -2,6 +2,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
|
|
3
3
|
import { connectionTestMessage } from '../shared/connection-test.mjs';
|
|
4
4
|
import { t } from '../shared/i18n.mjs';
|
|
5
|
+
import { publicMessageFailure } from '../shared/message-failure.mjs';
|
|
5
6
|
import { deriveQqBotIdentity, maskQqAppId } from './config-store.mjs';
|
|
6
7
|
|
|
7
8
|
const ACTIVE_ATTEMPT_STATES = new Set(['starting', 'pending', 'refreshing', 'connecting']);
|
|
@@ -319,6 +320,7 @@ export class QqController {
|
|
|
319
320
|
messagesReceived: runtimeStatus?.messagesReceived ?? 0,
|
|
320
321
|
messagesReplied: runtimeStatus?.messagesReplied ?? 0,
|
|
321
322
|
},
|
|
323
|
+
lastMessageError: publicMessageFailure(runtimeStatus?.lastMessageError),
|
|
322
324
|
error: structuredClone(this.#errors.get(config.botId) ?? null),
|
|
323
325
|
};
|
|
324
326
|
});
|
|
@@ -532,6 +532,41 @@ export class HarnessInteractionError extends Error {
|
|
|
532
532
|
}
|
|
533
533
|
}
|
|
534
534
|
|
|
535
|
+
export class HarnessTurnError extends Error {
|
|
536
|
+
constructor(code, { reason, providerCode } = {}) {
|
|
537
|
+
super(`Harness turn failed (${code})`);
|
|
538
|
+
this.name = 'HarnessTurnError';
|
|
539
|
+
this.code = code;
|
|
540
|
+
this.promptAccepted = true;
|
|
541
|
+
if (reason && typeof reason === 'object') this.reason = reason;
|
|
542
|
+
if (typeof providerCode === 'string' && providerCode) this.providerCode = providerCode;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function harnessTurnError(reason) {
|
|
547
|
+
const kind = nonEmptyText(reason?.kind) ?? nonEmptyText(reason);
|
|
548
|
+
if (kind === 'error') {
|
|
549
|
+
const failure = reason?.error ?? reason?.failure;
|
|
550
|
+
return new HarnessTurnError('harness-turn-failed', {
|
|
551
|
+
reason,
|
|
552
|
+
providerCode: nonEmptyText(failure?.code) ?? undefined,
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
if (kind === 'max-tokens') return new HarnessTurnError('model-max-tokens', { reason });
|
|
556
|
+
if (kind === 'blocked') return new HarnessTurnError('turn-blocked', { reason });
|
|
557
|
+
if (['interrupted', 'stopped', 'cancelled', 'canceled'].includes(kind)) {
|
|
558
|
+
return new HarnessTurnError('turn-interrupted', { reason });
|
|
559
|
+
}
|
|
560
|
+
if (kind === 'aborted') return new HarnessTurnError('turn-aborted', { reason });
|
|
561
|
+
if (kind === 'completed') return new HarnessTurnError('model-empty-response', { reason });
|
|
562
|
+
return new HarnessTurnError('harness-turn-failed', { reason });
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
function harnessTurnSucceeded(reason) {
|
|
566
|
+
if (reason === null || reason === undefined) return true;
|
|
567
|
+
return (nonEmptyText(reason?.kind) ?? nonEmptyText(reason)) === 'completed';
|
|
568
|
+
}
|
|
569
|
+
|
|
535
570
|
export class HarnessClient {
|
|
536
571
|
#baseUrl;
|
|
537
572
|
#workspace;
|
|
@@ -1282,6 +1317,9 @@ export class HarnessClient {
|
|
|
1282
1317
|
}
|
|
1283
1318
|
if (!tracker.finished) continue;
|
|
1284
1319
|
turnFinished = true;
|
|
1320
|
+
if (!ownership?.stopRequested && !harnessTurnSucceeded(tracker.reason)) {
|
|
1321
|
+
throw harnessTurnError(tracker.reason);
|
|
1322
|
+
}
|
|
1285
1323
|
// An accepted /stop revokes attachment delivery even when Harness
|
|
1286
1324
|
// preserved a useful partial text answer for the existing UX.
|
|
1287
1325
|
const artifactCount = ownership?.stopRequested
|
|
@@ -1292,11 +1330,9 @@ export class HarnessClient {
|
|
|
1292
1330
|
}
|
|
1293
1331
|
if (artifactCount > 0) return '';
|
|
1294
1332
|
if (ownership?.stopRequested) throw turnStoppedError();
|
|
1295
|
-
throw
|
|
1296
|
-
`Harness turn ended without a text reply${tracker.reason ? ` (${JSON.stringify(tracker.reason)})` : ''}`,
|
|
1297
|
-
);
|
|
1333
|
+
throw harnessTurnError(tracker.reason);
|
|
1298
1334
|
}
|
|
1299
|
-
throw new
|
|
1335
|
+
throw new HarnessTurnError('harness-reply-timeout');
|
|
1300
1336
|
} catch (error) {
|
|
1301
1337
|
// Once cancellation was accepted, transport/poll failures and timeouts
|
|
1302
1338
|
// describe the convergence of that stop, not an unrelated ask failure.
|
|
@@ -27,6 +27,83 @@ export default {
|
|
|
27
27
|
'结果文件「{name}」已生成,但当前渠道暂时未能发送,请稍后重试。':
|
|
28
28
|
'The result file "{name}" was generated, but this channel could not send it right now. Please try again later.',
|
|
29
29
|
'消息处理失败,请稍后重试。': 'Failed to process the message. Please try again later.',
|
|
30
|
+
'卡片已结束,请查看后续消息。': 'This card has ended. Please check the next message.',
|
|
31
|
+
'工具调用「{name}」未成功,请检查工具配置或稍后重试。': 'Tool call "{name}" did not succeed. Check the tool configuration or try again later.',
|
|
32
|
+
'无法连接处理服务,消息尚未提交。请确认 DeepSeek Harness 正在运行后重试。':
|
|
33
|
+
'Could not connect to the processing service, so the message was not submitted. Make sure DeepSeek Harness is running, then try again.',
|
|
34
|
+
'处理服务响应超时,消息尚未开始处理。请稍后重试。':
|
|
35
|
+
'The processing service timed out before the message started. Please try again later.',
|
|
36
|
+
'暂时无法确认任务状态,任务可能已经开始。请先等待或发送 /stop,不要立即重复提交。':
|
|
37
|
+
'The task status could not be confirmed and the task may have started. Wait or send /stop before submitting it again.',
|
|
38
|
+
'消息提交结果未能确认,任务可能已经开始。请先等待或发送 /status 查看状态,不要立即重复提交。':
|
|
39
|
+
'The message submission could not be confirmed and the task may have started. Wait or send /status before submitting it again.',
|
|
40
|
+
'暂时无法读取任务进度,任务可能仍在运行。请先等待或发送 /stop,不要立即重复提交。':
|
|
41
|
+
'Task progress is temporarily unavailable and the task may still be running. Wait or send /stop before submitting it again.',
|
|
42
|
+
'处理服务拒绝了机器人连接。请管理员检查 Harness 地址、代理或访问配置后重试。':
|
|
43
|
+
'The processing service rejected the bot connection. Ask an administrator to check the Harness address, proxy, or access settings.',
|
|
44
|
+
'机器人与 DeepSeek Harness 的接口不兼容。请管理员检查 Harness 地址并更新相关版本。':
|
|
45
|
+
'The bot and DeepSeek Harness use incompatible APIs. Ask an administrator to check the Harness address and update the related components.',
|
|
46
|
+
'DeepSeek Harness 暂时无法完成请求,请稍后重试。':
|
|
47
|
+
'DeepSeek Harness could not complete the request. Please try again later.',
|
|
48
|
+
'等待模型回复超时,任务可能仍在运行。请先等待或发送 /stop,不要立即重复提交。':
|
|
49
|
+
'Waiting for the model reply timed out and the task may still be running. Wait or send /stop before submitting it again.',
|
|
50
|
+
'模型凭据缺失或已失效。请管理员检查模型配置后重试。':
|
|
51
|
+
'The model credentials are missing or invalid. Ask an administrator to check the model settings.',
|
|
52
|
+
'模型额度或余额不足,本次任务未完成。请管理员补充额度或切换模型后重试。':
|
|
53
|
+
'The model quota or balance is insufficient. Ask an administrator to add quota or switch models, then try again.',
|
|
54
|
+
'模型服务正在限流,本次任务未完成。请稍后重试。':
|
|
55
|
+
'The model service is rate-limiting requests. Please try again later.',
|
|
56
|
+
'当前会话内容超过模型上下文上限。请发送 /compact 或 /new 后重试。':
|
|
57
|
+
'This conversation exceeds the model context limit. Send /compact or /new, then try again.',
|
|
58
|
+
'当前模型不存在或暂不可用。请发送 /models 查看并使用 /model 切换模型。':
|
|
59
|
+
'The current model does not exist or is unavailable. Send /models and use /model to switch models.',
|
|
60
|
+
'当前模型不存在或不支持所选配置。请发送 /models,并使用 /model 重新选择。':
|
|
61
|
+
'The current model does not exist or does not support the selected settings. Send /models and use /model to choose again.',
|
|
62
|
+
'当前模型不支持这类内容或所选配置。请调整内容、模型或推理等级后重试。':
|
|
63
|
+
'The current model does not support this content or the selected settings. Adjust the content, model, or reasoning effort and try again.',
|
|
64
|
+
'当前模型不支持所选配置。请切换模型或推理等级后重试。':
|
|
65
|
+
'The current model does not support the selected settings. Switch the model or reasoning effort, then try again.',
|
|
66
|
+
'模型服务响应超时,本次任务未完成。请稍后重试。':
|
|
67
|
+
'The model service timed out and the task did not finish. Please try again later.',
|
|
68
|
+
'暂时无法连接模型服务,本次任务未完成。请稍后重试。':
|
|
69
|
+
'The model service is temporarily unreachable and the task did not finish. Please try again later.',
|
|
70
|
+
'模型服务暂时异常,本次任务未完成。请稍后重试。':
|
|
71
|
+
'The model service is temporarily unavailable and the task did not finish. Please try again later.',
|
|
72
|
+
'模型回复中断或格式异常,本次任务未完成。请重试。':
|
|
73
|
+
'The model reply was interrupted or malformed, so the task did not finish. Please try again.',
|
|
74
|
+
'模型没有返回可显示的内容。请重试;若持续发生,请切换模型。':
|
|
75
|
+
'The model returned no displayable content. Try again, or switch models if this keeps happening.',
|
|
76
|
+
'模型拒绝处理当前内容。请调整问题内容后重试。':
|
|
77
|
+
'The model rejected the current content. Revise the request and try again.',
|
|
78
|
+
'模型达到输出长度上限,但没有生成可显示的结果。请缩小任务范围后重试。':
|
|
79
|
+
'The model reached its output limit without producing a displayable result. Reduce the task scope and try again.',
|
|
80
|
+
'任务正在等待无法在当前渠道完成的操作。请在 DeepSeek Harness 中处理后再试。':
|
|
81
|
+
'The task is waiting for an action that cannot be completed in this channel. Handle it in DeepSeek Harness, then try again.',
|
|
82
|
+
'任务被意外中断,本次未完成。请重试。':
|
|
83
|
+
'The task was unexpectedly interrupted and did not finish. Please try again.',
|
|
84
|
+
'当前会话已不存在。请发送 /new 创建新会话后重试。':
|
|
85
|
+
'The current Session no longer exists. Send /new to create one, then try again.',
|
|
86
|
+
'当前会话仍在处理上一项任务。请等待完成,或发送 /stop 后重试。':
|
|
87
|
+
'The current Session is still processing the previous task. Wait for it to finish, or send /stop before trying again.',
|
|
88
|
+
'工作区或会话状态刚刚发生变化。请重新发送这条消息。':
|
|
89
|
+
'The Workspace or Session state just changed. Please send this message again.',
|
|
90
|
+
'当前工作区不存在或暂不可用。请重新选择工作区后重试。':
|
|
91
|
+
'The current Workspace does not exist or is unavailable. Select another Workspace and try again.',
|
|
92
|
+
'当前 Agent Preset 不存在或暂不可用。请发送 /presetlist 后重新选择。':
|
|
93
|
+
'The current Agent Preset does not exist or is unavailable. Send /presetlist and select another one.',
|
|
94
|
+
'回复已经生成,但机器人没有发送权限。请联系管理员检查渠道权限或重新绑定机器人。':
|
|
95
|
+
'The reply was generated, but the bot cannot send it. Ask an administrator to check channel permissions or reconnect the bot.',
|
|
96
|
+
'回复已经生成,但当前渠道正在限流,暂时无法发送。请稍后重试。':
|
|
97
|
+
'The reply was generated, but this channel is rate-limiting messages. Please try again later.',
|
|
98
|
+
'回复发送结果未能确认。请先检查聊天内是否已经收到,不要立即重复提交。':
|
|
99
|
+
'Reply delivery could not be confirmed. Check whether it already arrived before submitting the task again.',
|
|
100
|
+
'回复已经生成,但当前渠道暂时无法发送。请稍后重试。':
|
|
101
|
+
'The reply was generated, but this channel could not send it. Please try again later.',
|
|
102
|
+
'当前消息包含无法处理的图片或文件。请调整后重新发送。':
|
|
103
|
+
'This message contains an image or file that cannot be processed. Adjust it and send it again.',
|
|
104
|
+
'任务未完成,暂时无法确定原因。请重试;若持续发生,请将参考号提供给管理员。':
|
|
105
|
+
'The task did not finish and the cause could not be determined. Try again; if it persists, give the reference ID to an administrator.',
|
|
106
|
+
'错误码:{code};参考号:{referenceId}': 'Error code: {code}; reference: {referenceId}',
|
|
30
107
|
'{label}机器人': '{label} bot',
|
|
31
108
|
'目前支持文字和图片消息。': 'Only text and image messages are supported at the moment.',
|
|
32
109
|
'目前支持文字、图片和文件消息。':
|