@soimy/dingtalk 3.6.11 → 3.7.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/dist/index.d.ts +1 -1
- package/dist/index.js +11684 -10583
- package/dist/src/{ack-reaction-service.d.ts → ack-reaction/ack-reaction-service.d.ts} +1 -1
- package/dist/src/ack-reaction/dynamic-ack-reaction-controller.d.ts +3 -3
- package/dist/src/card/ask-user-question-context.d.ts +1 -1
- package/dist/src/card/ask-user-question-store.d.ts +1 -1
- package/dist/src/card/ask-user-question.d.ts +1 -1
- package/dist/src/card/card-action-handler.d.ts +2 -2
- package/dist/src/{card-draft-controller.d.ts → card/card-draft-controller.d.ts} +5 -1
- package/dist/src/card/card-run-registry.d.ts +2 -2
- package/dist/src/{card-service.d.ts → card/card-service.d.ts} +1 -1
- package/dist/src/card/card-stop-handler.d.ts +1 -1
- package/dist/src/card/card-streaming-mode.d.ts +1 -1
- package/dist/src/card/card-task-progress.d.ts +60 -0
- package/dist/src/channel.d.ts +6 -6
- package/dist/src/command/card-stop-command.d.ts +1 -1
- package/dist/src/{feedback-learning-service.d.ts → command/feedback-learning-service.d.ts} +1 -1
- package/dist/src/command/inbound-command-dispatch-service.d.ts +2 -2
- package/dist/src/{learning-command-service.d.ts → command/learning-command-service.d.ts} +1 -1
- package/dist/src/gateway/channel-gateway.d.ts +1 -1
- package/dist/src/{connection-manager.d.ts → gateway/connection-manager.d.ts} +1 -1
- package/dist/src/{docs-service.d.ts → gateway/docs-service.d.ts} +1 -1
- package/dist/src/{inbound-handler.d.ts → gateway/inbound-handler.d.ts} +1 -1
- package/dist/src/gateway/inbound-session-queue-dispatcher.d.ts +1 -1
- package/dist/src/messaging/attachment-text-extractor.d.ts +1 -1
- package/dist/src/messaging/btw-deliver.d.ts +1 -1
- package/dist/src/messaging/channel-outbound.d.ts +1 -1
- package/dist/src/{media-utils.d.ts → messaging/media-utils.d.ts} +1 -1
- package/dist/src/{message-context-store.d.ts → messaging/message-context-store.d.ts} +7 -1
- package/dist/src/{message-utils.d.ts → messaging/message-utils.d.ts} +1 -1
- package/dist/src/messaging/quoted-context.d.ts +2 -2
- package/dist/src/messaging/quoted-file-service.d.ts +1 -1
- package/dist/src/messaging/quoted-ref.d.ts +2 -2
- package/dist/src/{reply-strategy-card.d.ts → messaging/reply-strategy-card.d.ts} +1 -1
- package/dist/src/{reply-strategy-types.d.ts → messaging/reply-strategy-types.d.ts} +10 -1
- package/dist/src/{reply-strategy-with-reaction.d.ts → messaging/reply-strategy-with-reaction.d.ts} +1 -1
- package/dist/src/{reply-strategy.d.ts → messaging/reply-strategy.d.ts} +1 -1
- package/dist/src/{send-service.d.ts → messaging/send-service.d.ts} +1 -1
- package/dist/src/platform/channel-status.d.ts +1 -1
- package/dist/src/platform/config.d.ts +110 -0
- package/dist/src/platform/runtime-events.d.ts +67 -0
- package/dist/src/{types.d.ts → platform/types.d.ts} +74 -1
- package/dist/src/{persistence-store.d.ts → shared/persistence-store.d.ts} +1 -1
- package/dist/src/{utils.d.ts → shared/utils.d.ts} +1 -1
- package/dist/src/targeting/agent-name-matcher.d.ts +1 -1
- package/dist/src/targeting/agent-routing.d.ts +3 -3
- package/dist/src/{session-routing.d.ts → targeting/session-routing.d.ts} +1 -1
- package/index.ts +193 -69
- package/openclaw.plugin.json +158 -2
- package/package.json +16 -16
- package/src/{ack-reaction-classifier.ts → ack-reaction/ack-reaction-classifier.ts} +85 -13
- package/src/{ack-reaction-service.ts → ack-reaction/ack-reaction-service.ts} +13 -7
- package/src/ack-reaction/dynamic-ack-reaction-controller.ts +46 -31
- package/src/ack-reaction/dynamic-ack-reaction-progress.ts +4 -1
- package/src/card/ask-user-question-context.ts +1 -1
- package/src/card/ask-user-question-store.ts +2 -2
- package/src/card/ask-user-question.ts +11 -7
- package/src/card/card-action-handler.ts +2 -2
- package/src/{card-callback-service.ts → card/card-callback-service.ts} +7 -9
- package/src/card/card-draft-controller.ts +770 -0
- package/src/card/card-markdown-image-reroute.ts +8 -2
- package/src/card/card-run-registry.ts +17 -7
- package/src/{card-service.ts → card/card-service.ts} +91 -61
- package/src/card/card-stop-handler.ts +12 -8
- package/src/card/card-streaming-mode.ts +1 -1
- package/src/card/card-task-progress.ts +330 -0
- package/src/card/draft-stream-loop.ts +119 -0
- package/src/card/reasoning-answer-split.ts +125 -121
- package/src/card/reasoning-block-assembler.ts +122 -123
- package/src/{run-usage-store.ts → card/run-usage-store.ts} +18 -6
- package/src/card/statusline-renderer.ts +14 -5
- package/src/card/task-model-metadata.ts +8 -3
- package/src/channel.ts +14 -16
- package/src/command/card-stop-command.ts +2 -2
- package/src/{feedback-learning-service.ts → command/feedback-learning-service.ts} +36 -16
- package/src/{feedback-learning-store.ts → command/feedback-learning-store.ts} +133 -81
- package/src/command/inbound-command-dispatch-service.ts +12 -6
- package/src/{learning-command-service.ts → command/learning-command-service.ts} +36 -29
- package/src/{session-command-service.ts → command/session-command-service.ts} +3 -1
- package/src/gateway/channel-gateway.ts +106 -28
- package/src/{connection-manager.ts → gateway/connection-manager.ts} +45 -30
- package/src/{docs-service.ts → gateway/docs-service.ts} +5 -5
- package/src/{inbound-handler.ts → gateway/inbound-handler.ts} +139 -84
- package/src/gateway/inbound-session-queue-dispatcher.ts +18 -14
- package/src/{session-lock.ts → gateway/session-lock.ts} +14 -14
- package/src/messaging/attachment-text-extractor.ts +21 -7
- package/src/messaging/btw-deliver.ts +2 -2
- package/src/messaging/channel-actions.ts +15 -7
- package/src/messaging/channel-outbound.ts +16 -11
- package/src/{media-utils.ts → messaging/media-utils.ts} +276 -72
- package/src/{message-context-store.ts → messaging/message-context-store.ts} +11 -2
- package/src/{message-utils.ts → messaging/message-utils.ts} +46 -11
- package/src/messaging/quoted-context.ts +2 -2
- package/src/messaging/quoted-file-service.ts +311 -294
- package/src/messaging/quoted-ref.ts +11 -7
- package/src/{reply-strategy-card.ts → messaging/reply-strategy-card.ts} +178 -101
- package/src/{reply-strategy-markdown.ts → messaging/reply-strategy-markdown.ts} +8 -2
- package/src/{reply-strategy-types.ts → messaging/reply-strategy-types.ts} +11 -1
- package/src/{reply-strategy-with-reaction.ts → messaging/reply-strategy-with-reaction.ts} +6 -1
- package/src/{reply-strategy.ts → messaging/reply-strategy.ts} +2 -2
- package/src/{send-service.ts → messaging/send-service.ts} +100 -65
- package/src/{auth.ts → platform/auth.ts} +2 -2
- package/src/platform/channel-status.ts +3 -3
- package/src/{config-schema.ts → platform/config-schema.ts} +81 -4
- package/src/{config.ts → platform/config.ts} +167 -19
- package/src/{device-registration.ts → platform/device-registration.ts} +5 -4
- package/src/{onboarding.ts → platform/onboarding.ts} +1 -4
- package/src/{plugin-sdk-channel-actions-augment.ts → platform/plugin-sdk-channel-actions-augment.ts} +6 -5
- package/src/platform/runtime-events.ts +202 -0
- package/src/{secret-input.ts → platform/secret-input.ts} +117 -11
- package/src/{types.ts → platform/types.ts} +76 -1
- package/src/{http-client.ts → shared/http-client.ts} +1 -3
- package/src/{persistence-store.ts → shared/persistence-store.ts} +6 -6
- package/src/{utils.ts → shared/utils.ts} +30 -13
- package/src/targeting/agent-name-matcher.ts +1 -1
- package/src/targeting/agent-routing.ts +7 -7
- package/src/targeting/group-members-store.ts +1 -1
- package/src/{session-peer-store.ts → targeting/session-peer-store.ts} +9 -4
- package/src/{session-routing.ts → targeting/session-routing.ts} +1 -1
- package/src/targeting/target-directory-adapter.ts +3 -3
- package/src/targeting/target-directory-store.ts +1 -1
- package/src/targeting/target-input.ts +1 -1
- package/dist/src/ack-reaction/dynamic-ack-reaction-events.d.ts +0 -35
- package/dist/src/config.d.ts +0 -59
- package/src/ack-reaction/dynamic-ack-reaction-events.ts +0 -123
- package/src/card-draft-controller.ts +0 -637
- package/src/draft-stream-loop.ts +0 -119
- /package/dist/src/{ack-reaction-classifier.d.ts → ack-reaction/ack-reaction-classifier.d.ts} +0 -0
- /package/dist/src/{card-callback-service.d.ts → card/card-callback-service.d.ts} +0 -0
- /package/dist/src/{draft-stream-loop.d.ts → card/draft-stream-loop.d.ts} +0 -0
- /package/dist/src/{run-usage-store.d.ts → card/run-usage-store.d.ts} +0 -0
- /package/dist/src/{feedback-learning-store.d.ts → command/feedback-learning-store.d.ts} +0 -0
- /package/dist/src/{session-command-service.d.ts → command/session-command-service.d.ts} +0 -0
- /package/dist/src/{session-lock.d.ts → gateway/session-lock.d.ts} +0 -0
- /package/dist/src/{proactive-risk-registry.d.ts → messaging/proactive-risk-registry.d.ts} +0 -0
- /package/dist/src/{reply-strategy-markdown.d.ts → messaging/reply-strategy-markdown.d.ts} +0 -0
- /package/dist/src/{access-control.d.ts → platform/access-control.d.ts} +0 -0
- /package/dist/src/{auth.d.ts → platform/auth.d.ts} +0 -0
- /package/dist/src/{config-schema.d.ts → platform/config-schema.d.ts} +0 -0
- /package/dist/src/{device-registration.d.ts → platform/device-registration.d.ts} +0 -0
- /package/dist/src/{logger-context.d.ts → platform/logger-context.d.ts} +0 -0
- /package/dist/src/{onboarding.d.ts → platform/onboarding.d.ts} +0 -0
- /package/dist/src/{plugin-sdk-channel-actions-augment.d.ts → platform/plugin-sdk-channel-actions-augment.d.ts} +0 -0
- /package/dist/src/{runtime.d.ts → platform/runtime.d.ts} +0 -0
- /package/dist/src/{secret-input.d.ts → platform/secret-input.d.ts} +0 -0
- /package/dist/src/{session-state.d.ts → platform/session-state.d.ts} +0 -0
- /package/dist/src/{signature.d.ts → platform/signature.d.ts} +0 -0
- /package/dist/src/{dedup.d.ts → shared/dedup.d.ts} +0 -0
- /package/dist/src/{http-client.d.ts → shared/http-client.d.ts} +0 -0
- /package/dist/src/{path-utils.d.ts → shared/path-utils.d.ts} +0 -0
- /package/dist/src/{peer-id-registry.d.ts → targeting/peer-id-registry.d.ts} +0 -0
- /package/dist/src/{session-peer-store.d.ts → targeting/session-peer-store.d.ts} +0 -0
- /package/src/{proactive-risk-registry.ts → messaging/proactive-risk-registry.ts} +0 -0
- /package/src/{access-control.ts → platform/access-control.ts} +0 -0
- /package/src/{logger-context.ts → platform/logger-context.ts} +0 -0
- /package/src/{runtime.ts → platform/runtime.ts} +0 -0
- /package/src/{session-state.ts → platform/session-state.ts} +0 -0
- /package/src/{signature.ts → platform/signature.ts} +0 -0
- /package/src/{dedup.ts → shared/dedup.ts} +0 -0
- /package/src/{path-utils.ts → shared/path-utils.ts} +0 -0
- /package/src/{peer-id-registry.ts → targeting/peer-id-registry.ts} +0 -0
|
@@ -10,14 +10,20 @@ export interface MarkdownImageCandidate {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
const MARKDOWN_IMAGE_RE = /!\[([^\]]*)\]\(([^)]+)\)/g;
|
|
13
|
-
const PRIVATE_HOST_RE =
|
|
13
|
+
const PRIVATE_HOST_RE =
|
|
14
|
+
/^(?:localhost|127\.0\.0\.1|10\.\d+\.\d+\.\d+|192\.168\.\d+\.\d+|172\.(?:1[6-9]|2\d|3[0-1])\.\d+\.\d+)$/;
|
|
14
15
|
|
|
15
16
|
function isLikelyPlainRelativePath(url: string): boolean {
|
|
16
17
|
return !/^[a-zA-Z][a-zA-Z\d+.-]*:/.test(url) && !url.startsWith("//");
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
function isLikelyLocalPath(url: string): boolean {
|
|
20
|
-
return
|
|
21
|
+
return (
|
|
22
|
+
url.startsWith("./") ||
|
|
23
|
+
url.startsWith("../") ||
|
|
24
|
+
url.startsWith("/") ||
|
|
25
|
+
isLikelyPlainRelativePath(url)
|
|
26
|
+
);
|
|
21
27
|
}
|
|
22
28
|
|
|
23
29
|
function safeFileNameFromUrl(url: string): string {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AICardInstance } from "../platform/types";
|
|
1
2
|
/**
|
|
2
3
|
* In-process card run registry for tracking active AI card runs.
|
|
3
4
|
*
|
|
@@ -7,8 +8,7 @@
|
|
|
7
8
|
* the stop button to silently fail. Ensure single-process deployment or sticky
|
|
8
9
|
* routing per card callback when using the stop button feature.
|
|
9
10
|
*/
|
|
10
|
-
import type { CardDraftController } from "
|
|
11
|
-
import type { AICardInstance } from "../types";
|
|
11
|
+
import type { CardDraftController } from "./card-draft-controller";
|
|
12
12
|
|
|
13
13
|
export interface CardRunRecord {
|
|
14
14
|
outTrackId: string;
|
|
@@ -110,10 +110,16 @@ export function resolveCardRunByConversation(
|
|
|
110
110
|
const targetOwner = options?.ownerUserId;
|
|
111
111
|
let latest: CardRunRecord | null = null;
|
|
112
112
|
for (const record of records.values()) {
|
|
113
|
-
if (record.accountId !== accountId) {
|
|
114
|
-
|
|
113
|
+
if (record.accountId !== accountId) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (!record.sessionKey.toLowerCase().includes(lowerCid)) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
115
119
|
// If ownerUserId filter is specified, only match runs owned by that user
|
|
116
|
-
if (targetOwner !== undefined && record.ownerUserId !== targetOwner) {
|
|
120
|
+
if (targetOwner !== undefined && record.ownerUserId !== targetOwner) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
117
123
|
if (!latest || record.registeredAt > latest.registeredAt) {
|
|
118
124
|
latest = record;
|
|
119
125
|
}
|
|
@@ -134,8 +140,12 @@ export function resolveCardRunByOwner(
|
|
|
134
140
|
): CardRunRecord | null {
|
|
135
141
|
let latest: CardRunRecord | null = null;
|
|
136
142
|
for (const record of records.values()) {
|
|
137
|
-
if (record.accountId !== accountId) {
|
|
138
|
-
|
|
143
|
+
if (record.accountId !== accountId) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (record.ownerUserId !== ownerUserId) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
139
149
|
if (!latest || record.registeredAt > latest.registeredAt) {
|
|
140
150
|
latest = record;
|
|
141
151
|
}
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
-
import axios from "./http-client";
|
|
5
|
-
import { getAccessToken } from "./auth";
|
|
6
|
-
import { updateCardVariables } from "./card-callback-service";
|
|
7
|
-
import { DINGTALK_CARD_TEMPLATE, STOP_ACTION_VISIBLE, STOP_ACTION_HIDDEN } from "./card/card-template";
|
|
8
|
-
import { resolveRobotCode, stripTargetPrefix } from "./config";
|
|
9
|
-
import { resolveOriginalPeerId } from "./peer-id-registry";
|
|
10
4
|
import {
|
|
11
5
|
createSyntheticOutboundMsgId,
|
|
12
6
|
clearMessageContextCacheForTest,
|
|
@@ -16,12 +10,9 @@ import {
|
|
|
16
10
|
inferConversationChatType,
|
|
17
11
|
resolveByCreatedAtWindow,
|
|
18
12
|
upsertOutboundMessageContext,
|
|
19
|
-
} from "
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
resolveNamespacePath,
|
|
23
|
-
writeNamespaceJsonAtomic,
|
|
24
|
-
} from "./persistence-store";
|
|
13
|
+
} from "../messaging/message-context-store";
|
|
14
|
+
import { getAccessToken } from "../platform/auth";
|
|
15
|
+
import { resolveRobotCode, stripTargetPrefix } from "../platform/config";
|
|
25
16
|
import type {
|
|
26
17
|
AICardInstance,
|
|
27
18
|
AICardStreamingRequest,
|
|
@@ -30,9 +21,18 @@ import type {
|
|
|
30
21
|
DingTalkTrackingMetadata,
|
|
31
22
|
Logger,
|
|
32
23
|
QuotedRef,
|
|
33
|
-
} from "
|
|
34
|
-
import { AICardStatus } from "
|
|
35
|
-
import
|
|
24
|
+
} from "../platform/types";
|
|
25
|
+
import { AICardStatus } from "../platform/types";
|
|
26
|
+
import axios from "../shared/http-client";
|
|
27
|
+
import {
|
|
28
|
+
readNamespaceJson,
|
|
29
|
+
resolveNamespacePath,
|
|
30
|
+
writeNamespaceJsonAtomic,
|
|
31
|
+
} from "../shared/persistence-store";
|
|
32
|
+
import { formatDingTalkErrorPayloadLog, getProxyBypassOption } from "../shared/utils";
|
|
33
|
+
import { resolveOriginalPeerId } from "../targeting/peer-id-registry";
|
|
34
|
+
import { updateCardVariables } from "./card-callback-service";
|
|
35
|
+
import { DINGTALK_CARD_TEMPLATE, STOP_ACTION_VISIBLE, STOP_ACTION_HIDDEN } from "./card-template";
|
|
36
36
|
|
|
37
37
|
const DINGTALK_API = "https://api.dingtalk.com";
|
|
38
38
|
// Thinking/tool stream snippets are truncated to keep card updates compact.
|
|
@@ -85,7 +85,10 @@ function pruneInMemoryCardContentEntries(
|
|
|
85
85
|
return entries.filter((entry) => nowMs < entry.expiresAt).slice(-CARD_CACHE_MAX_PER_CONVERSATION);
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
function touchInMemoryCardContentBucket(
|
|
88
|
+
function touchInMemoryCardContentBucket(
|
|
89
|
+
scopeKey: string,
|
|
90
|
+
nowMs: number,
|
|
91
|
+
): {
|
|
89
92
|
entries: Array<{ content: string; createdAt: number; expiresAt: number }>;
|
|
90
93
|
lastActiveAt: number;
|
|
91
94
|
} {
|
|
@@ -282,7 +285,11 @@ async function putAICardStreamingField(
|
|
|
282
285
|
};
|
|
283
286
|
|
|
284
287
|
try {
|
|
285
|
-
const streamResp = await axios.put(
|
|
288
|
+
const streamResp = await axios.put(
|
|
289
|
+
`${DINGTALK_API}/v1.0/card/streaming`,
|
|
290
|
+
streamBody,
|
|
291
|
+
requestConfig,
|
|
292
|
+
);
|
|
286
293
|
log?.debug?.(
|
|
287
294
|
`[DingTalk][AICard] Streaming response: status=${streamResp.status}, data=${JSON.stringify(streamResp.data)}`,
|
|
288
295
|
);
|
|
@@ -408,8 +415,11 @@ function normalizePendingState(parsed: Partial<PendingCardStateFile>): PendingCa
|
|
|
408
415
|
typeof entry.conversationId === "string" &&
|
|
409
416
|
(entry.lastContent === undefined || typeof entry.lastContent === "string") &&
|
|
410
417
|
(entry.lastBlockListJson === undefined || typeof entry.lastBlockListJson === "string") &&
|
|
411
|
-
(entry.streamLifecycleOpened === undefined ||
|
|
412
|
-
|
|
418
|
+
(entry.streamLifecycleOpened === undefined ||
|
|
419
|
+
typeof entry.streamLifecycleOpened === "boolean") &&
|
|
420
|
+
(entry.recoveryAction === undefined ||
|
|
421
|
+
entry.recoveryAction === "finalize" ||
|
|
422
|
+
entry.recoveryAction === "recall"),
|
|
413
423
|
),
|
|
414
424
|
),
|
|
415
425
|
};
|
|
@@ -517,9 +527,7 @@ function buildStoppedCardFinalizePayload(params: {
|
|
|
517
527
|
const baseContent = params.previousContent?.trim() || "";
|
|
518
528
|
const blocks = parseStoredBlockList(params.previousBlockListJson);
|
|
519
529
|
blocks.push({ type: 0, markdown: markerText });
|
|
520
|
-
const content = baseContent
|
|
521
|
-
? `${baseContent}\n\n---\n*${markerText}*`
|
|
522
|
-
: markerText;
|
|
530
|
+
const content = baseContent ? `${baseContent}\n\n---\n*${markerText}*` : markerText;
|
|
523
531
|
return {
|
|
524
532
|
blockListJson: JSON.stringify(blocks),
|
|
525
533
|
content,
|
|
@@ -593,9 +601,9 @@ function normalizeRecoveredState(state: string): AICardInstance["state"] {
|
|
|
593
601
|
// Helper to identify card terminal states.
|
|
594
602
|
export function isCardInTerminalState(state: string): boolean {
|
|
595
603
|
return (
|
|
596
|
-
state === AICardStatus.FINISHED
|
|
597
|
-
|
|
598
|
-
|
|
604
|
+
state === AICardStatus.FINISHED ||
|
|
605
|
+
state === AICardStatus.STOPPED ||
|
|
606
|
+
state === AICardStatus.FAILED
|
|
599
607
|
);
|
|
600
608
|
}
|
|
601
609
|
|
|
@@ -619,7 +627,10 @@ async function ensureFreshToken(card: AICardInstance, log?: Logger): Promise<voi
|
|
|
619
627
|
}
|
|
620
628
|
}
|
|
621
629
|
|
|
622
|
-
export function formatContentForCard(
|
|
630
|
+
export function formatContentForCard(
|
|
631
|
+
content: string | undefined,
|
|
632
|
+
type: "thinking" | "tool",
|
|
633
|
+
): string {
|
|
623
634
|
if (!content) {
|
|
624
635
|
return "";
|
|
625
636
|
}
|
|
@@ -693,10 +704,14 @@ export async function sendProactiveCardText(
|
|
|
693
704
|
return { ok: false, error: "Failed to create AI card" };
|
|
694
705
|
}
|
|
695
706
|
const blockListJson = JSON.stringify([{ type: 0, markdown: content } satisfies CardBlock]);
|
|
696
|
-
await commitAICardBlocks(
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
707
|
+
await commitAICardBlocks(
|
|
708
|
+
card,
|
|
709
|
+
{
|
|
710
|
+
blockListJson,
|
|
711
|
+
content,
|
|
712
|
+
},
|
|
713
|
+
log,
|
|
714
|
+
);
|
|
700
715
|
return {
|
|
701
716
|
ok: true,
|
|
702
717
|
processQueryKey: card.processQueryKey,
|
|
@@ -749,8 +764,9 @@ async function finalizePendingCardsByAccount(
|
|
|
749
764
|
|
|
750
765
|
const pendingCards = listPendingCardsByAccount(accountId, storePath, log).filter(
|
|
751
766
|
(item) =>
|
|
752
|
-
(item.recoveryAction === "recall" && mode === "recover")
|
|
753
|
-
|
|
767
|
+
(item.recoveryAction === "recall" && mode === "recover") ||
|
|
768
|
+
(item.recoveryAction !== "recall" &&
|
|
769
|
+
(!isCardInTerminalState(item.state) || item.recoveryAction === "finalize")),
|
|
754
770
|
);
|
|
755
771
|
if (pendingCards.length === 0) {
|
|
756
772
|
return 0;
|
|
@@ -794,11 +810,15 @@ async function finalizePendingCardsByAccount(
|
|
|
794
810
|
}
|
|
795
811
|
continue;
|
|
796
812
|
}
|
|
797
|
-
await finalizeStoppedAICard(
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
813
|
+
await finalizeStoppedAICard(
|
|
814
|
+
card,
|
|
815
|
+
{
|
|
816
|
+
reason,
|
|
817
|
+
previousContent: entry.lastContent,
|
|
818
|
+
previousBlockListJson: entry.lastBlockListJson,
|
|
819
|
+
},
|
|
820
|
+
log,
|
|
821
|
+
);
|
|
802
822
|
finalizedCount += 1;
|
|
803
823
|
} catch (err: unknown) {
|
|
804
824
|
const action = mode === "recover" ? "recover" : "finalize";
|
|
@@ -904,7 +924,11 @@ export async function createAICard(
|
|
|
904
924
|
cardInstanceId?: unknown;
|
|
905
925
|
}
|
|
906
926
|
| undefined;
|
|
907
|
-
const deliverResults = (
|
|
927
|
+
const deliverResults = (
|
|
928
|
+
responseData?.result as
|
|
929
|
+
| { deliverResults?: Array<{ success?: boolean; errorMsg?: string }> }
|
|
930
|
+
| undefined
|
|
931
|
+
)?.deliverResults;
|
|
908
932
|
if (Array.isArray(deliverResults)) {
|
|
909
933
|
const failedDelivery = deliverResults.find((item) => item?.success === false);
|
|
910
934
|
if (failedDelivery) {
|
|
@@ -1130,7 +1154,9 @@ async function finalizeAICardStreamingLifecycleIfNeeded(
|
|
|
1130
1154
|
});
|
|
1131
1155
|
} catch (err: unknown) {
|
|
1132
1156
|
const message = err instanceof Error ? err.message : String(err);
|
|
1133
|
-
log?.warn?.(
|
|
1157
|
+
log?.warn?.(
|
|
1158
|
+
`[DingTalk][AICard] Streaming lifecycle finalize failed; continuing instances finalize: ${message}`,
|
|
1159
|
+
);
|
|
1134
1160
|
}
|
|
1135
1161
|
}
|
|
1136
1162
|
|
|
@@ -1189,8 +1215,8 @@ export async function commitAICardBlocks(
|
|
|
1189
1215
|
|
|
1190
1216
|
log?.debug?.(
|
|
1191
1217
|
`[DingTalk][AICard] Finalizing via instances API: outTrackId=${card.outTrackId || card.cardInstanceId} ` +
|
|
1192
|
-
|
|
1193
|
-
|
|
1218
|
+
`blockListLen=${options.blockListJson.length} contentLen=${options.content.length} flowStatus=3` +
|
|
1219
|
+
(options.statusLine ? ` statusLine="${options.statusLine}"` : ""),
|
|
1194
1220
|
);
|
|
1195
1221
|
|
|
1196
1222
|
try {
|
|
@@ -1233,10 +1259,11 @@ export async function commitAICardBlocks(
|
|
|
1233
1259
|
card.state = AICardStatus.FINISHED;
|
|
1234
1260
|
card.lastUpdated = Date.now();
|
|
1235
1261
|
removePendingCard(card, log);
|
|
1236
|
-
log?.info?.(
|
|
1262
|
+
log?.info?.(
|
|
1263
|
+
`[DingTalk][AICard] Card finalized: outTrackId=${card.outTrackId || card.cardInstanceId} state=FINISHED`,
|
|
1264
|
+
);
|
|
1237
1265
|
}
|
|
1238
1266
|
|
|
1239
|
-
|
|
1240
1267
|
export async function streamAICard(
|
|
1241
1268
|
card: AICardInstance,
|
|
1242
1269
|
content: string,
|
|
@@ -1270,8 +1297,8 @@ export async function streamAICard(
|
|
|
1270
1297
|
retainPendingCardForRecovery(card, options.recoveryAction ?? "finalize", log);
|
|
1271
1298
|
if (err.response?.status === 500 && err.response?.data?.code === "unknownError") {
|
|
1272
1299
|
const errorMsg =
|
|
1273
|
-
"⚠️ **[DingTalk] AI Card 串流更新失败 (500 unknownError)**\n\n"
|
|
1274
|
-
|
|
1300
|
+
"⚠️ **[DingTalk] AI Card 串流更新失败 (500 unknownError)**\n\n" +
|
|
1301
|
+
"这通常表示当前内置模板契约与钉钉侧模板字段不一致,当前及后续消息将自动回退为 Markdown 发送。";
|
|
1275
1302
|
await sendTemplateMismatchNotification(card, errorMsg, log);
|
|
1276
1303
|
}
|
|
1277
1304
|
throw err;
|
|
@@ -1300,7 +1327,9 @@ export async function finishAICard(
|
|
|
1300
1327
|
const token = await getAccessToken(card.config, log);
|
|
1301
1328
|
await hideCardStopButton(card.outTrackId, token, card.config);
|
|
1302
1329
|
} catch (err: any) {
|
|
1303
|
-
log?.debug?.(
|
|
1330
|
+
log?.debug?.(
|
|
1331
|
+
`[DingTalk][AICard] Non-critical: failed to hide stop button on finish: ${err.message}`,
|
|
1332
|
+
);
|
|
1304
1333
|
}
|
|
1305
1334
|
}
|
|
1306
1335
|
if (card.conversationId && content.trim() && card.accountId && card.processQueryKey) {
|
|
@@ -1334,14 +1363,12 @@ function parseRecallFailureEntries(payload: unknown): Array<[string, string]> {
|
|
|
1334
1363
|
if (!payload || typeof payload !== "object") {
|
|
1335
1364
|
return [];
|
|
1336
1365
|
}
|
|
1337
|
-
return Object.entries(payload as Record<string, unknown>)
|
|
1338
|
-
|
|
1366
|
+
return Object.entries(payload as Record<string, unknown>).map(
|
|
1367
|
+
([key, value]) => [String(key), String(value ?? "")] as [string, string],
|
|
1368
|
+
);
|
|
1339
1369
|
}
|
|
1340
1370
|
|
|
1341
|
-
export async function recallAICardMessage(
|
|
1342
|
-
card: AICardInstance,
|
|
1343
|
-
log?: Logger,
|
|
1344
|
-
): Promise<boolean> {
|
|
1371
|
+
export async function recallAICardMessage(card: AICardInstance, log?: Logger): Promise<boolean> {
|
|
1345
1372
|
const config = card.config;
|
|
1346
1373
|
const processQueryKey = card.processQueryKey?.trim();
|
|
1347
1374
|
const robotCode = config ? resolveRobotCode(config) : "";
|
|
@@ -1349,8 +1376,8 @@ export async function recallAICardMessage(
|
|
|
1349
1376
|
if (!config || !processQueryKey || !robotCode) {
|
|
1350
1377
|
log?.warn?.(
|
|
1351
1378
|
`[DingTalk][AICard] Skip recall because required metadata is missing: ` +
|
|
1352
|
-
|
|
1353
|
-
|
|
1379
|
+
`card=${card.cardInstanceId} hasConfig=${Boolean(config)} ` +
|
|
1380
|
+
`processQueryKey=${processQueryKey || "(none)"} robotCode=${robotCode || "(none)"}`,
|
|
1354
1381
|
);
|
|
1355
1382
|
return false;
|
|
1356
1383
|
}
|
|
@@ -1383,9 +1410,12 @@ export async function recallAICardMessage(
|
|
|
1383
1410
|
},
|
|
1384
1411
|
...getProxyBypassOption(config),
|
|
1385
1412
|
});
|
|
1386
|
-
const successResults = Array.isArray(
|
|
1387
|
-
|
|
1388
|
-
|
|
1413
|
+
const successResults = Array.isArray(
|
|
1414
|
+
(response.data as Record<string, unknown> | undefined)?.successResult,
|
|
1415
|
+
)
|
|
1416
|
+
? ((response.data as Record<string, unknown>).successResult as unknown[]).map((item) =>
|
|
1417
|
+
String(item),
|
|
1418
|
+
)
|
|
1389
1419
|
: [];
|
|
1390
1420
|
const failedEntries = parseRecallFailureEntries(
|
|
1391
1421
|
(response.data as Record<string, unknown> | undefined)?.failedResult,
|
|
@@ -1393,14 +1423,14 @@ export async function recallAICardMessage(
|
|
|
1393
1423
|
if (failedEntries.length > 0) {
|
|
1394
1424
|
log?.warn?.(
|
|
1395
1425
|
`[DingTalk][AICard] Recall reported failedResult: card=${card.cardInstanceId} ` +
|
|
1396
|
-
|
|
1426
|
+
`processQueryKey=${processQueryKey} failed=${JSON.stringify(failedEntries)}`,
|
|
1397
1427
|
);
|
|
1398
1428
|
return false;
|
|
1399
1429
|
}
|
|
1400
1430
|
if (!successResults.includes(processQueryKey)) {
|
|
1401
1431
|
log?.warn?.(
|
|
1402
1432
|
`[DingTalk][AICard] Recall response missing successResult for processQueryKey=${processQueryKey} ` +
|
|
1403
|
-
|
|
1433
|
+
`payload=${JSON.stringify(response.data)}`,
|
|
1404
1434
|
);
|
|
1405
1435
|
return false;
|
|
1406
1436
|
}
|
|
@@ -1410,7 +1440,7 @@ export async function recallAICardMessage(
|
|
|
1410
1440
|
removePendingCard(card, log);
|
|
1411
1441
|
log?.info?.(
|
|
1412
1442
|
`[DingTalk][AICard] Recalled empty card message: card=${card.cardInstanceId} ` +
|
|
1413
|
-
|
|
1443
|
+
`conversationId=${target.conversationId} processQueryKey=${processQueryKey} mode=${target.isGroup ? "group" : "direct"}`,
|
|
1414
1444
|
);
|
|
1415
1445
|
return true;
|
|
1416
1446
|
} catch (err: any) {
|
|
@@ -1514,7 +1544,7 @@ function cacheCardContentByProcessQueryKey(
|
|
|
1514
1544
|
}
|
|
1515
1545
|
log?.debug?.(
|
|
1516
1546
|
`[DingTalk][QuotedRef][Persist] direction=outbound scope=${conversationId} messageType=card ` +
|
|
1517
|
-
|
|
1547
|
+
`processQueryKey=${processQueryKey} quotedRef=${quotedRef ? JSON.stringify(quotedRef) : "(none)"}`,
|
|
1518
1548
|
);
|
|
1519
1549
|
upsertOutboundMessageContext({
|
|
1520
1550
|
storePath,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { OpenClawConfig } from "openclaw/plugin-sdk/core";
|
|
2
|
-
import { finalizeStoppedAICard } from "../card-service";
|
|
3
2
|
import { dispatchDingTalkCardStopCommand } from "../command/card-stop-command";
|
|
4
|
-
import type { DingTalkConfig, Logger } from "../types";
|
|
5
|
-
import { AICardStatus } from "../types";
|
|
3
|
+
import type { DingTalkConfig, Logger } from "../platform/types";
|
|
4
|
+
import { AICardStatus } from "../platform/types";
|
|
6
5
|
import { markCardRunStopRequested, resolveCardRun } from "./card-run-registry";
|
|
6
|
+
import { finalizeStoppedAICard } from "./card-service";
|
|
7
7
|
|
|
8
8
|
export interface StopCardRunResult {
|
|
9
9
|
ok: boolean;
|
|
@@ -68,11 +68,15 @@ export async function stopCardRun(params: {
|
|
|
68
68
|
// --- Phase 2: Finalize card via instances API so V2 blockList/content stay consistent ---
|
|
69
69
|
if (record.card) {
|
|
70
70
|
try {
|
|
71
|
-
await finalizeStoppedAICard(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
await finalizeStoppedAICard(
|
|
72
|
+
record.card,
|
|
73
|
+
{
|
|
74
|
+
reason: "⏹️ 已停止",
|
|
75
|
+
previousContent: lastContent,
|
|
76
|
+
previousBlockListJson: lastBlockListJson,
|
|
77
|
+
},
|
|
78
|
+
params.log,
|
|
79
|
+
);
|
|
76
80
|
} catch (error) {
|
|
77
81
|
params.log?.warn?.(
|
|
78
82
|
`[${params.accountId}] [DingTalk][CardStop] failed to finalize stopped card: ${error instanceof Error ? error.message : String(error)}`,
|