@yanhaidao/wecom 2.4.120 → 2.5.110
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.md +4 -5
- package/dist/index.js +68 -0
- package/dist/src/accounts.js +20 -0
- package/dist/src/agent/handler.js +895 -0
- package/dist/src/agent/index.js +5 -0
- package/dist/src/app/account-runtime.js +216 -0
- package/dist/src/app/bootstrap.js +19 -0
- package/dist/src/app/index.js +118 -0
- package/dist/src/capability/agent/delivery-service.js +63 -0
- package/dist/src/capability/agent/fallback-policy.js +6 -0
- package/dist/src/capability/agent/ingress-service.js +33 -0
- package/dist/src/capability/agent/upstream-delivery-service.js +71 -0
- package/dist/src/capability/bot/dispatch-config.js +45 -0
- package/dist/src/capability/bot/fallback-delivery.js +147 -0
- package/dist/src/capability/bot/local-path-delivery.js +178 -0
- package/dist/src/capability/bot/sandbox-media.js +138 -0
- package/dist/src/capability/bot/service.js +49 -0
- package/dist/src/capability/bot/stream-delivery.js +321 -0
- package/dist/src/capability/bot/stream-finalizer.js +81 -0
- package/dist/src/capability/bot/stream-orchestrator.js +318 -0
- package/dist/src/capability/bot/types.js +1 -0
- package/{src/capability/calendar/client.ts → dist/src/capability/calendar/client.js} +118 -241
- package/{src/capability/calendar/schema.ts → dist/src/capability/calendar/schema.js} +0 -38
- package/dist/src/capability/calendar/tool.js +365 -0
- package/dist/src/capability/calendar/types.js +12 -0
- package/{src/capability/doc/client.ts → dist/src/capability/doc/client.js} +370 -605
- package/{src/capability/doc/schema.ts → dist/src/capability/doc/schema.js} +345 -394
- package/dist/src/capability/doc/tool.js +1556 -0
- package/dist/src/capability/doc/types.js +113 -0
- package/dist/src/capability/mcp/index.js +3 -0
- package/dist/src/capability/mcp/schema.js +102 -0
- package/dist/src/capability/mcp/tool.js +146 -0
- package/dist/src/capability/mcp/transport.js +293 -0
- package/dist/src/channel.js +224 -0
- package/dist/src/config/accounts.js +236 -0
- package/dist/src/config/derived-paths.js +31 -0
- package/dist/src/config/index.js +7 -0
- package/dist/src/config/media.js +110 -0
- package/dist/src/config/network.js +32 -0
- package/dist/src/config/routing.js +20 -0
- package/dist/src/config/runtime-config.js +25 -0
- package/dist/src/config/schema.js +4 -0
- package/{src/config-schema.ts → dist/src/config-schema.js} +1 -1
- package/dist/src/context-store.js +219 -0
- package/{src/crypto/aes.ts → dist/src/crypto/aes.js} +11 -28
- package/dist/src/crypto/index.js +9 -0
- package/{src/crypto/signature.ts → dist/src/crypto/signature.js} +3 -18
- package/{src/crypto/xml.ts → dist/src/crypto/xml.js} +3 -11
- package/dist/src/crypto.js +145 -0
- package/dist/src/domain/models.js +1 -0
- package/dist/src/domain/policies.js +32 -0
- package/{src/dynamic-agent.ts → dist/src/dynamic-agent.js} +36 -73
- package/dist/src/gateway-monitor.js +139 -0
- package/dist/src/http.js +114 -0
- package/{src/media.ts → dist/src/media.js} +21 -40
- package/dist/src/monitor/limits.js +7 -0
- package/dist/src/monitor/state.js +28 -0
- package/dist/src/monitor.js +84 -0
- package/dist/src/observability/audit-log.js +30 -0
- package/dist/src/observability/legacy-operational-event-store.js +22 -0
- package/dist/src/observability/raw-envelope-log.js +24 -0
- package/dist/src/observability/status-registry.js +9 -0
- package/dist/src/observability/transport-session-view.js +14 -0
- package/dist/src/onboarding.js +546 -0
- package/dist/src/outbound.js +557 -0
- package/dist/src/runtime/dispatcher.js +57 -0
- package/{src/runtime/index.ts → dist/src/runtime/index.js} +0 -1
- package/dist/src/runtime/outbound-intent.js +1 -0
- package/dist/src/runtime/reply-orchestrator.js +38 -0
- package/dist/src/runtime/routing-bridge.js +26 -0
- package/dist/src/runtime/session-manager.js +112 -0
- package/dist/src/runtime/source-registry.js +174 -0
- package/dist/src/runtime.js +1 -0
- package/dist/src/shared/command-auth.js +57 -0
- package/{src/shared/index.ts → dist/src/shared/index.js} +0 -1
- package/dist/src/shared/media-asset.js +65 -0
- package/dist/src/shared/media-service.js +59 -0
- package/dist/src/shared/media-types.js +1 -0
- package/{src/shared/xml-parser.ts → dist/src/shared/xml-parser.js} +72 -63
- package/dist/src/store/active-reply-store.js +41 -0
- package/dist/src/store/interfaces.js +1 -0
- package/dist/src/store/memory-store.js +33 -0
- package/dist/src/store/stream-batch-store.js +319 -0
- package/{src/target.ts → dist/src/target.js} +15 -48
- package/dist/src/transport/agent-api/client.js +168 -0
- package/dist/src/transport/agent-api/core.js +337 -0
- package/dist/src/transport/agent-api/delivery.js +28 -0
- package/dist/src/transport/agent-api/media-upload.js +4 -0
- package/dist/src/transport/agent-api/reply.js +24 -0
- package/dist/src/transport/agent-api/upstream-delivery.js +30 -0
- package/dist/src/transport/agent-api/upstream-media-upload.js +46 -0
- package/dist/src/transport/agent-api/upstream-reply.js +26 -0
- package/dist/src/transport/agent-callback/http-handler.js +30 -0
- package/dist/src/transport/agent-callback/inbound.js +4 -0
- package/dist/src/transport/agent-callback/reply.js +8 -0
- package/dist/src/transport/agent-callback/request-handler.js +189 -0
- package/dist/src/transport/agent-callback/session.js +15 -0
- package/dist/src/transport/bot-webhook/active-reply.js +27 -0
- package/dist/src/transport/bot-webhook/http-handler.js +31 -0
- package/dist/src/transport/bot-webhook/inbound-normalizer.js +496 -0
- package/dist/src/transport/bot-webhook/inbound.js +4 -0
- package/dist/src/transport/bot-webhook/message-shape.js +98 -0
- package/dist/src/transport/bot-webhook/protocol.js +124 -0
- package/dist/src/transport/bot-webhook/reply.js +9 -0
- package/dist/src/transport/bot-webhook/request-handler.js +285 -0
- package/dist/src/transport/bot-webhook/session.js +15 -0
- package/dist/src/transport/bot-ws/inbound.js +147 -0
- package/dist/src/transport/bot-ws/media.js +236 -0
- package/dist/src/transport/bot-ws/reply.js +310 -0
- package/dist/src/transport/bot-ws/sdk-adapter.js +257 -0
- package/dist/src/transport/bot-ws/session.js +15 -0
- package/dist/src/transport/http/common.js +78 -0
- package/dist/src/transport/http/registry.js +71 -0
- package/dist/src/transport/http/request-handler.js +51 -0
- package/{src/transport/index.ts → dist/src/transport/index.js} +2 -10
- package/dist/src/types/account.js +1 -0
- package/dist/src/types/config.js +1 -0
- package/dist/src/types/constants.js +28 -0
- package/dist/src/types/events.js +1 -0
- package/dist/src/types/index.js +1 -0
- package/dist/src/types/legacy-stream.js +1 -0
- package/dist/src/types/message.js +5 -0
- package/dist/src/types/runtime-context.js +1 -0
- package/dist/src/types/runtime.js +1 -0
- package/dist/src/types.js +1 -0
- package/dist/src/upstream/index.js +111 -0
- package/dist/src/wecom_msg_adapter/markdown_adapter.js +280 -0
- package/openclaw.plugin.json +15 -0
- package/package.json +18 -1
- package/.github/workflows/release.yml +0 -143
- package/GOVERNANCE.md +0 -26
- package/MENU_EVENT_CONF.md +0 -500
- package/MENU_EVENT_PLAN.md +0 -440
- package/SKILLS_CAL.md +0 -895
- package/SKILLS_DOC.md +0 -2288
- package/UPSTREAM_CONFIG.md +0 -170
- package/UPSTREAM_PLAN.md +0 -175
- package/assets/01.bot-add.png +0 -0
- package/assets/01.bot-setp2.png +0 -0
- package/assets/01.image.jpg +0 -0
- package/assets/02.agent.add.png +0 -0
- package/assets/02.agent.api-set.png +0 -0
- package/assets/02.image.jpg +0 -0
- package/assets/03.agent.page.png +0 -0
- package/assets/03.bot.page.png +0 -0
- package/assets/link-me.jpg +0 -0
- package/assets/register.png +0 -0
- package/changelog/v2.2.28.md +0 -70
- package/changelog/v2.3.10.md +0 -17
- package/changelog/v2.3.11.md +0 -19
- package/changelog/v2.3.12.md +0 -25
- package/changelog/v2.3.13.md +0 -19
- package/changelog/v2.3.14.md +0 -48
- package/changelog/v2.3.15.md +0 -15
- package/changelog/v2.3.16.md +0 -11
- package/changelog/v2.3.18.md +0 -22
- package/changelog/v2.3.19.md +0 -73
- package/changelog/v2.3.2.md +0 -28
- package/changelog/v2.3.26.md +0 -21
- package/changelog/v2.3.27.md +0 -33
- package/changelog/v2.3.4.md +0 -20
- package/changelog/v2.3.9.md +0 -22
- package/changelog/v2.4.12.md +0 -37
- package/compat-single-account.md +0 -148
- package/index.test.ts +0 -38
- package/scripts/test-proxy.ts +0 -70
- package/scripts/wecom/README.md +0 -123
- package/scripts/wecom/menu-click-help.js +0 -59
- package/scripts/wecom/menu-click-help.py +0 -55
- package/src/accounts.ts +0 -34
- package/src/agent/api-client.upload.test.ts +0 -109
- package/src/agent/event-router.test.ts +0 -421
- package/src/agent/event-router.ts +0 -272
- package/src/agent/handler.event-filter.test.ts +0 -135
- package/src/agent/handler.ts +0 -1250
- package/src/agent/index.ts +0 -12
- package/src/agent/script-runner.ts +0 -186
- package/src/agent/test-fixtures/invalid-json-script.mjs +0 -1
- package/src/agent/test-fixtures/reply-event-script.mjs +0 -29
- package/src/agent/test-fixtures/reply-event-script.py +0 -17
- package/src/app/account-runtime.ts +0 -276
- package/src/app/bootstrap.ts +0 -29
- package/src/app/index.ts +0 -192
- package/src/capability/agent/delivery-service.ts +0 -87
- package/src/capability/agent/fallback-policy.ts +0 -13
- package/src/capability/agent/ingress-service.ts +0 -38
- package/src/capability/agent/upstream-delivery-service.ts +0 -96
- package/src/capability/bot/dispatch-config.ts +0 -47
- package/src/capability/bot/fallback-delivery.ts +0 -178
- package/src/capability/bot/local-path-delivery.ts +0 -215
- package/src/capability/bot/sandbox-media.test.ts +0 -221
- package/src/capability/bot/sandbox-media.ts +0 -176
- package/src/capability/bot/service.ts +0 -56
- package/src/capability/bot/stream-delivery.ts +0 -379
- package/src/capability/bot/stream-finalizer.ts +0 -120
- package/src/capability/bot/stream-orchestrator.ts +0 -371
- package/src/capability/bot/types.ts +0 -8
- package/src/capability/calendar/SKILLS_CHECKLIST.md +0 -251
- package/src/capability/calendar/tool.ts +0 -417
- package/src/capability/calendar/types.ts +0 -309
- package/src/capability/doc/tool.ts +0 -1629
- package/src/capability/doc/types.ts +0 -792
- package/src/capability/mcp/index.ts +0 -10
- package/src/capability/mcp/schema.ts +0 -107
- package/src/capability/mcp/tool.ts +0 -174
- package/src/capability/mcp/transport.ts +0 -394
- package/src/channel.config.test.ts +0 -180
- package/src/channel.lifecycle.test.ts +0 -255
- package/src/channel.meta.test.ts +0 -26
- package/src/channel.ts +0 -256
- package/src/config/accounts.resolve.test.ts +0 -75
- package/src/config/accounts.ts +0 -312
- package/src/config/derived-paths.test.ts +0 -111
- package/src/config/derived-paths.ts +0 -41
- package/src/config/index.ts +0 -22
- package/src/config/media.test.ts +0 -113
- package/src/config/media.ts +0 -139
- package/src/config/network.ts +0 -20
- package/src/config/routing.test.ts +0 -88
- package/src/config/routing.ts +0 -26
- package/src/config/runtime-config.ts +0 -46
- package/src/config/schema.ts +0 -144
- package/src/context-store.ts +0 -297
- package/src/crypto/index.ts +0 -24
- package/src/crypto.test.ts +0 -32
- package/src/crypto.ts +0 -176
- package/src/domain/models.ts +0 -7
- package/src/domain/policies.ts +0 -36
- package/src/dynamic-agent.account-scope.test.ts +0 -17
- package/src/gateway-monitor.ts +0 -181
- package/src/http.ts +0 -137
- package/src/media.test.ts +0 -82
- package/src/monitor/limits.ts +0 -7
- package/src/monitor/state.queue.test.ts +0 -185
- package/src/monitor/state.ts +0 -34
- package/src/monitor.active.test.ts +0 -245
- package/src/monitor.inbound-filter.test.ts +0 -63
- package/src/monitor.integration.test.ts +0 -208
- package/src/monitor.ts +0 -121
- package/src/monitor.webhook.test.ts +0 -774
- package/src/observability/audit-log.ts +0 -48
- package/src/observability/legacy-operational-event-store.ts +0 -36
- package/src/observability/raw-envelope-log.ts +0 -28
- package/src/observability/status-registry.ts +0 -13
- package/src/observability/transport-session-view.ts +0 -14
- package/src/onboarding.test.ts +0 -336
- package/src/onboarding.ts +0 -704
- package/src/outbound.test.ts +0 -1271
- package/src/outbound.ts +0 -746
- package/src/runtime/dispatcher.ts +0 -71
- package/src/runtime/outbound-intent.ts +0 -4
- package/src/runtime/reply-orchestrator.test.ts +0 -71
- package/src/runtime/reply-orchestrator.ts +0 -67
- package/src/runtime/routing-bridge.test.ts +0 -115
- package/src/runtime/routing-bridge.ts +0 -44
- package/src/runtime/session-manager.test.ts +0 -174
- package/src/runtime/session-manager.ts +0 -139
- package/src/runtime/source-registry.ts +0 -249
- package/src/runtime.ts +0 -14
- package/src/shared/command-auth.ts +0 -87
- package/src/shared/media-asset.ts +0 -78
- package/src/shared/media-service.test.ts +0 -111
- package/src/shared/media-service.ts +0 -84
- package/src/shared/media-types.ts +0 -5
- package/src/shared/xml-parser.test.ts +0 -50
- package/src/store/active-reply-store.ts +0 -42
- package/src/store/interfaces.ts +0 -11
- package/src/store/memory-store.ts +0 -43
- package/src/store/stream-batch-store.ts +0 -350
- package/src/transport/agent-api/client.ts +0 -277
- package/src/transport/agent-api/core.ts +0 -463
- package/src/transport/agent-api/delivery.ts +0 -41
- package/src/transport/agent-api/media-upload.ts +0 -11
- package/src/transport/agent-api/reply.ts +0 -39
- package/src/transport/agent-api/upstream-delivery.ts +0 -45
- package/src/transport/agent-api/upstream-media-upload.ts +0 -70
- package/src/transport/agent-api/upstream-reply.ts +0 -43
- package/src/transport/agent-callback/http-handler.ts +0 -47
- package/src/transport/agent-callback/inbound.ts +0 -5
- package/src/transport/agent-callback/reply.ts +0 -13
- package/src/transport/agent-callback/request-handler.ts +0 -244
- package/src/transport/agent-callback/session.ts +0 -23
- package/src/transport/bot-webhook/active-reply.ts +0 -39
- package/src/transport/bot-webhook/http-handler.ts +0 -48
- package/src/transport/bot-webhook/inbound-normalizer.ts +0 -371
- package/src/transport/bot-webhook/inbound.ts +0 -5
- package/src/transport/bot-webhook/message-shape.ts +0 -89
- package/src/transport/bot-webhook/protocol.ts +0 -148
- package/src/transport/bot-webhook/reply.ts +0 -15
- package/src/transport/bot-webhook/request-handler.ts +0 -394
- package/src/transport/bot-webhook/session.ts +0 -23
- package/src/transport/bot-ws/inbound.test.ts +0 -96
- package/src/transport/bot-ws/inbound.ts +0 -116
- package/src/transport/bot-ws/media.test.ts +0 -44
- package/src/transport/bot-ws/media.ts +0 -321
- package/src/transport/bot-ws/reply.test.ts +0 -450
- package/src/transport/bot-ws/reply.ts +0 -365
- package/src/transport/bot-ws/sdk-adapter.test.ts +0 -187
- package/src/transport/bot-ws/sdk-adapter.ts +0 -314
- package/src/transport/bot-ws/session.ts +0 -28
- package/src/transport/http/common.ts +0 -109
- package/src/transport/http/registry.ts +0 -92
- package/src/transport/http/request-handler.ts +0 -84
- package/src/types/account.ts +0 -72
- package/src/types/config.ts +0 -166
- package/src/types/constants.ts +0 -31
- package/src/types/events.ts +0 -21
- package/src/types/global.d.ts +0 -9
- package/src/types/index.ts +0 -17
- package/src/types/legacy-stream.ts +0 -50
- package/src/types/message.ts +0 -187
- package/src/types/runtime-context.ts +0 -28
- package/src/types/runtime.ts +0 -165
- package/src/types.ts +0 -41
- package/src/upstream/index.ts +0 -150
- package/src/upstream.test.ts +0 -84
- package/src/wecom_msg_adapter/markdown_adapter.ts +0 -331
- package/tsconfig.json +0 -22
- package/vitest.config.ts +0 -26
- /package/{src/capability/agent/index.ts → dist/src/capability/agent/index.js} +0 -0
- /package/{src/capability/bot/index.ts → dist/src/capability/bot/index.js} +0 -0
- /package/{src/capability/calendar/index.ts → dist/src/capability/calendar/index.js} +0 -0
- /package/{src/capability/index.ts → dist/src/capability/index.js} +0 -0
package/src/app/index.ts
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import type { PluginRuntime } from "openclaw/plugin-sdk";
|
|
2
|
-
import { clearWecomSourceAccount } from "../runtime/source-registry.js";
|
|
3
|
-
import type { ReplyHandle } from "../types/index.js";
|
|
4
|
-
import { WecomAccountRuntime } from "./account-runtime.js";
|
|
5
|
-
|
|
6
|
-
let runtime: PluginRuntime | null = null;
|
|
7
|
-
const runtimes = new Map<string, WecomAccountRuntime>();
|
|
8
|
-
const botWsPushHandles = new Map<string, BotWsPushHandle>();
|
|
9
|
-
const activeBotWsReplyHandlesBySession = new Map<string, ReplyHandle>();
|
|
10
|
-
const activeBotWsReplyHandlesByPeer = new Map<string, ReplyHandle>();
|
|
11
|
-
|
|
12
|
-
export type BotWsPushHandle = {
|
|
13
|
-
isConnected: () => boolean;
|
|
14
|
-
sendMarkdown: (chatId: string, content: string) => Promise<void>;
|
|
15
|
-
replyCommand: (params: {
|
|
16
|
-
cmd: string;
|
|
17
|
-
body?: Record<string, unknown>;
|
|
18
|
-
headers?: ({ req_id?: string } & Record<string, string>) | undefined;
|
|
19
|
-
}) => Promise<Record<string, unknown>>;
|
|
20
|
-
sendMedia: (params: {
|
|
21
|
-
chatId: string;
|
|
22
|
-
mediaUrl: string;
|
|
23
|
-
text?: string;
|
|
24
|
-
mediaLocalRoots?: readonly string[];
|
|
25
|
-
maxBytes?: number;
|
|
26
|
-
}) => Promise<{
|
|
27
|
-
ok: boolean;
|
|
28
|
-
messageId?: string;
|
|
29
|
-
rejected?: boolean;
|
|
30
|
-
rejectReason?: string;
|
|
31
|
-
error?: string;
|
|
32
|
-
}>;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
function normalizeOptional(value: string | null | undefined): string | undefined {
|
|
36
|
-
const trimmed = String(value ?? "").trim();
|
|
37
|
-
return trimmed || undefined;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function normalizePeerId(value: string | null | undefined): string | undefined {
|
|
41
|
-
const trimmed = normalizeOptional(value);
|
|
42
|
-
return trimmed ? trimmed.toLowerCase() : undefined;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function buildSessionHandleKey(accountId: string, sessionKey: string): string {
|
|
46
|
-
return `${accountId}::session::${sessionKey}`;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function buildPeerHandleKey(
|
|
50
|
-
accountId: string,
|
|
51
|
-
peerKind: "direct" | "group",
|
|
52
|
-
peerId: string,
|
|
53
|
-
): string {
|
|
54
|
-
return `${accountId}::peer::${peerKind}::${peerId}`;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function setWecomRuntime(next: PluginRuntime): void {
|
|
58
|
-
runtime = next;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function getWecomRuntime(): PluginRuntime {
|
|
62
|
-
if (!runtime) {
|
|
63
|
-
throw new Error("WeCom runtime not initialized");
|
|
64
|
-
}
|
|
65
|
-
return runtime;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function registerAccountRuntime(accountRuntime: WecomAccountRuntime): void {
|
|
69
|
-
runtimes.set(accountRuntime.account.accountId, accountRuntime);
|
|
70
|
-
console.log(`[wecom-runtime] register account=${accountRuntime.account.accountId}`);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function getAccountRuntime(accountId: string): WecomAccountRuntime | undefined {
|
|
74
|
-
return runtimes.get(accountId);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export function getAccountRuntimeSnapshot(accountId: string) {
|
|
78
|
-
return runtimes.get(accountId)?.buildRuntimeStatus();
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function registerBotWsPushHandle(accountId: string, handle: BotWsPushHandle): void {
|
|
82
|
-
botWsPushHandles.set(accountId, handle);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export function getBotWsPushHandle(accountId: string): BotWsPushHandle | undefined {
|
|
86
|
-
return botWsPushHandles.get(accountId);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export function registerActiveBotWsReplyHandle(params: {
|
|
90
|
-
accountId: string;
|
|
91
|
-
sessionKey?: string | null;
|
|
92
|
-
peerKind?: "direct" | "group" | null;
|
|
93
|
-
peerId?: string | null;
|
|
94
|
-
handle: ReplyHandle;
|
|
95
|
-
}): void {
|
|
96
|
-
const accountId = normalizeOptional(params.accountId);
|
|
97
|
-
const sessionKey = normalizeOptional(params.sessionKey);
|
|
98
|
-
const peerId = normalizePeerId(params.peerId);
|
|
99
|
-
if (!accountId) {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
if (sessionKey) {
|
|
103
|
-
activeBotWsReplyHandlesBySession.set(
|
|
104
|
-
buildSessionHandleKey(accountId, sessionKey),
|
|
105
|
-
params.handle,
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
if ((params.peerKind === "direct" || params.peerKind === "group") && peerId) {
|
|
109
|
-
activeBotWsReplyHandlesByPeer.set(
|
|
110
|
-
buildPeerHandleKey(accountId, params.peerKind, peerId),
|
|
111
|
-
params.handle,
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export function getActiveBotWsReplyHandle(params: {
|
|
117
|
-
accountId: string;
|
|
118
|
-
sessionKey?: string | null;
|
|
119
|
-
peerKind?: "direct" | "group" | null;
|
|
120
|
-
peerId?: string | null;
|
|
121
|
-
}): ReplyHandle | undefined {
|
|
122
|
-
const accountId = normalizeOptional(params.accountId);
|
|
123
|
-
const sessionKey = normalizeOptional(params.sessionKey);
|
|
124
|
-
const peerId = normalizePeerId(params.peerId);
|
|
125
|
-
if (!accountId) {
|
|
126
|
-
return undefined;
|
|
127
|
-
}
|
|
128
|
-
if (sessionKey) {
|
|
129
|
-
const handle = activeBotWsReplyHandlesBySession.get(
|
|
130
|
-
buildSessionHandleKey(accountId, sessionKey),
|
|
131
|
-
);
|
|
132
|
-
if (handle) {
|
|
133
|
-
return handle;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
if ((params.peerKind === "direct" || params.peerKind === "group") && peerId) {
|
|
137
|
-
return activeBotWsReplyHandlesByPeer.get(
|
|
138
|
-
buildPeerHandleKey(accountId, params.peerKind, peerId),
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
return undefined;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export function unregisterActiveBotWsReplyHandle(params: {
|
|
145
|
-
accountId: string;
|
|
146
|
-
sessionKey?: string | null;
|
|
147
|
-
peerKind?: "direct" | "group" | null;
|
|
148
|
-
peerId?: string | null;
|
|
149
|
-
handle?: ReplyHandle;
|
|
150
|
-
}): void {
|
|
151
|
-
const accountId = normalizeOptional(params.accountId);
|
|
152
|
-
const sessionKey = normalizeOptional(params.sessionKey);
|
|
153
|
-
const peerId = normalizePeerId(params.peerId);
|
|
154
|
-
if (!accountId) {
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
if (sessionKey) {
|
|
158
|
-
const key = buildSessionHandleKey(accountId, sessionKey);
|
|
159
|
-
const current = activeBotWsReplyHandlesBySession.get(key);
|
|
160
|
-
if (!params.handle || current === params.handle) {
|
|
161
|
-
activeBotWsReplyHandlesBySession.delete(key);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
if ((params.peerKind === "direct" || params.peerKind === "group") && peerId) {
|
|
165
|
-
const key = buildPeerHandleKey(accountId, params.peerKind, peerId);
|
|
166
|
-
const current = activeBotWsReplyHandlesByPeer.get(key);
|
|
167
|
-
if (!params.handle || current === params.handle) {
|
|
168
|
-
activeBotWsReplyHandlesByPeer.delete(key);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
export function unregisterBotWsPushHandle(accountId: string): void {
|
|
174
|
-
botWsPushHandles.delete(accountId);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
export function unregisterAccountRuntime(accountId: string): void {
|
|
178
|
-
runtimes.delete(accountId);
|
|
179
|
-
botWsPushHandles.delete(accountId);
|
|
180
|
-
for (const key of activeBotWsReplyHandlesBySession.keys()) {
|
|
181
|
-
if (key.startsWith(`${accountId}::`)) {
|
|
182
|
-
activeBotWsReplyHandlesBySession.delete(key);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
for (const key of activeBotWsReplyHandlesByPeer.keys()) {
|
|
186
|
-
if (key.startsWith(`${accountId}::`)) {
|
|
187
|
-
activeBotWsReplyHandlesByPeer.delete(key);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
clearWecomSourceAccount(accountId);
|
|
191
|
-
console.log(`[wecom-runtime] unregister account=${accountId}`);
|
|
192
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import type { ResolvedAgentAccount } from "../../types/index.js";
|
|
2
|
-
import { resolveScopedWecomTarget } from "../../target.js";
|
|
3
|
-
import { deliverAgentApiMedia, deliverAgentApiText } from "../../transport/agent-api/delivery.js";
|
|
4
|
-
import { canUseAgentApiDelivery } from "./fallback-policy.js";
|
|
5
|
-
import { getWecomRuntime } from "../../runtime.js";
|
|
6
|
-
|
|
7
|
-
export class WecomAgentDeliveryService {
|
|
8
|
-
constructor(private readonly agent: ResolvedAgentAccount) { }
|
|
9
|
-
|
|
10
|
-
assertAvailable(): void {
|
|
11
|
-
if (!canUseAgentApiDelivery(this.agent)) {
|
|
12
|
-
throw new Error(
|
|
13
|
-
`WeCom outbound requires channels.wecom.accounts.<accountId>.agent.agentId (or legacy channels.wecom.agent.agentId) for account=${this.agent.accountId}.`,
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
resolveTargetOrThrow(to: string | undefined) {
|
|
19
|
-
const scoped = resolveScopedWecomTarget(to, this.agent.accountId);
|
|
20
|
-
if (!scoped) {
|
|
21
|
-
console.error(`[wecom-agent-delivery] missing target account=${this.agent.accountId}`);
|
|
22
|
-
throw new Error("WeCom outbound requires a target (userid, partyid, tagid or chatid).");
|
|
23
|
-
}
|
|
24
|
-
if (scoped.accountId && scoped.accountId !== this.agent.accountId) {
|
|
25
|
-
console.error(
|
|
26
|
-
`[wecom-agent-delivery] account mismatch current=${this.agent.accountId} targetAccount=${scoped.accountId} raw=${String(to ?? "")}`,
|
|
27
|
-
);
|
|
28
|
-
throw new Error(
|
|
29
|
-
`WeCom outbound account mismatch: target belongs to account=${scoped.accountId}, current account=${this.agent.accountId}.`,
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
const target = scoped.target;
|
|
33
|
-
if (target.chatid) {
|
|
34
|
-
console.warn(
|
|
35
|
-
`[wecom-agent-delivery] blocked chat target account=${this.agent.accountId} chatId=${target.chatid}`,
|
|
36
|
-
);
|
|
37
|
-
throw new Error(
|
|
38
|
-
`企业微信(WeCom)Agent 主动发送不支持向群 chatId 发送(chatId=${target.chatid})。` +
|
|
39
|
-
`该路径在实际环境中经常失败(例如 86008:无权限访问该会话/会话由其他应用创建)。` +
|
|
40
|
-
`请改为发送给用户(userid / user:xxx),或由 Bot 模式在群内交付。`,
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
return target;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async sendText(params: { to: string | undefined; text: string }): Promise<void> {
|
|
47
|
-
this.assertAvailable();
|
|
48
|
-
const target = this.resolveTargetOrThrow(params.to);
|
|
49
|
-
console.log(
|
|
50
|
-
`[wecom-agent-delivery] sendText account=${this.agent.accountId} to=${String(params.to ?? "")} len=${params.text.length}`,
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
const runtime = getWecomRuntime();
|
|
54
|
-
const chunks = runtime.channel.text.chunkText(params.text, 2048);
|
|
55
|
-
|
|
56
|
-
for (const chunk of chunks) {
|
|
57
|
-
if (!chunk.trim()) continue;
|
|
58
|
-
await deliverAgentApiText({
|
|
59
|
-
agent: this.agent,
|
|
60
|
-
target,
|
|
61
|
-
text: chunk,
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async sendMedia(params: {
|
|
67
|
-
to: string | undefined;
|
|
68
|
-
text?: string;
|
|
69
|
-
buffer: Buffer;
|
|
70
|
-
filename: string;
|
|
71
|
-
contentType: string;
|
|
72
|
-
}): Promise<void> {
|
|
73
|
-
this.assertAvailable();
|
|
74
|
-
const target = this.resolveTargetOrThrow(params.to);
|
|
75
|
-
console.log(
|
|
76
|
-
`[wecom-agent-delivery] sendMedia account=${this.agent.accountId} to=${String(params.to ?? "")} filename=${params.filename} contentType=${params.contentType}`,
|
|
77
|
-
);
|
|
78
|
-
await deliverAgentApiMedia({
|
|
79
|
-
agent: this.agent,
|
|
80
|
-
target,
|
|
81
|
-
buffer: params.buffer,
|
|
82
|
-
filename: params.filename,
|
|
83
|
-
contentType: params.contentType,
|
|
84
|
-
text: params.text,
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { ResolvedAgentAccount } from "../../types/index.js";
|
|
2
|
-
|
|
3
|
-
export function canUseAgentApiDelivery(agent: ResolvedAgentAccount | undefined): boolean {
|
|
4
|
-
return Boolean(agent?.apiConfigured && typeof agent.agentId === "number");
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function shouldFallbackToAgentApi(params: {
|
|
8
|
-
agent: ResolvedAgentAccount | undefined;
|
|
9
|
-
hasText?: boolean;
|
|
10
|
-
hasMedia?: boolean;
|
|
11
|
-
}): boolean {
|
|
12
|
-
return canUseAgentApiDelivery(params.agent) && Boolean(params.hasText || params.hasMedia);
|
|
13
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { OpenClawConfig } from "openclaw/plugin-sdk";
|
|
2
|
-
|
|
3
|
-
import type { WecomRuntimeEnv } from "../../types/runtime-context.js";
|
|
4
|
-
import type { WecomAccountRuntime } from "../../app/account-runtime.js";
|
|
5
|
-
import { startAgentCallbackTransport } from "../../transport/agent-callback/http-handler.js";
|
|
6
|
-
|
|
7
|
-
export class WecomAgentIngressService {
|
|
8
|
-
private stopTransport?: () => void;
|
|
9
|
-
|
|
10
|
-
constructor(
|
|
11
|
-
private readonly runtime: WecomAccountRuntime,
|
|
12
|
-
private readonly cfg: OpenClawConfig,
|
|
13
|
-
private readonly runtimeEnv: WecomRuntimeEnv,
|
|
14
|
-
) {}
|
|
15
|
-
|
|
16
|
-
start(): { transport: "agent-callback"; descriptors: string[] } | undefined {
|
|
17
|
-
const agent = this.runtime.account.agent;
|
|
18
|
-
if (!agent?.callbackConfigured) {
|
|
19
|
-
return undefined;
|
|
20
|
-
}
|
|
21
|
-
const callback = startAgentCallbackTransport({
|
|
22
|
-
account: agent,
|
|
23
|
-
cfg: this.cfg,
|
|
24
|
-
runtime: this.runtime,
|
|
25
|
-
runtimeEnv: this.runtimeEnv,
|
|
26
|
-
});
|
|
27
|
-
this.stopTransport = callback.stop;
|
|
28
|
-
return {
|
|
29
|
-
transport: "agent-callback",
|
|
30
|
-
descriptors: callback.paths,
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
stop(): void {
|
|
35
|
-
this.stopTransport?.();
|
|
36
|
-
this.stopTransport = undefined;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import type { ResolvedAgentAccount } from "../../types/index.js";
|
|
2
|
-
import { resolveScopedWecomTarget } from "../../target.js";
|
|
3
|
-
import { deliverUpstreamAgentApiMedia, deliverUpstreamAgentApiText } from "../../transport/agent-api/upstream-delivery.js";
|
|
4
|
-
import { canUseAgentApiDelivery } from "./fallback-policy.js";
|
|
5
|
-
import { getWecomRuntime } from "../../runtime.js";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* 上下游企业消息发送服务
|
|
9
|
-
*
|
|
10
|
-
* 使用下游企业的 access_token 和 agentId 发送消息
|
|
11
|
-
*/
|
|
12
|
-
export class WecomUpstreamAgentDeliveryService {
|
|
13
|
-
constructor(
|
|
14
|
-
private readonly upstreamAgent: ResolvedAgentAccount,
|
|
15
|
-
private readonly primaryAgent: ResolvedAgentAccount,
|
|
16
|
-
) { }
|
|
17
|
-
|
|
18
|
-
assertAvailable(): void {
|
|
19
|
-
if (!canUseAgentApiDelivery(this.upstreamAgent)) {
|
|
20
|
-
throw new Error(
|
|
21
|
-
`WeCom upstream outbound requires channels.wecom.accounts.<accountId>.agent.agentId for upstream corp=${this.upstreamAgent.corpId}.`,
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
resolveTargetOrThrow(to: string | undefined) {
|
|
27
|
-
const scoped = resolveScopedWecomTarget(to, this.upstreamAgent.accountId);
|
|
28
|
-
if (!scoped) {
|
|
29
|
-
console.error(`[wecom-upstream-delivery] missing target account=${this.upstreamAgent.accountId}`);
|
|
30
|
-
throw new Error("WeCom upstream outbound requires a target (userid, partyid, tagid or chatid).");
|
|
31
|
-
}
|
|
32
|
-
if (scoped.accountId && scoped.accountId !== this.upstreamAgent.accountId) {
|
|
33
|
-
console.error(
|
|
34
|
-
`[wecom-upstream-delivery] account mismatch current=${this.upstreamAgent.accountId} targetAccount=${scoped.accountId} raw=${String(to ?? "")}`,
|
|
35
|
-
);
|
|
36
|
-
throw new Error(
|
|
37
|
-
`WeCom upstream outbound account mismatch: target belongs to account=${scoped.accountId}, current account=${this.upstreamAgent.accountId}.`,
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
const target = scoped.target;
|
|
41
|
-
if (target.chatid) {
|
|
42
|
-
console.warn(
|
|
43
|
-
`[wecom-upstream-delivery] blocked chat target account=${this.upstreamAgent.accountId} chatId=${target.chatid}`,
|
|
44
|
-
);
|
|
45
|
-
throw new Error(
|
|
46
|
-
`企业微信(WeCom)上下游 Agent 主动发送不支持向群 chatId 发送(chatId=${target.chatid})。` +
|
|
47
|
-
`请改为发送给用户(userid / user:xxx)。`,
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
return target;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async sendText(params: { to: string | undefined; text: string }): Promise<void> {
|
|
54
|
-
this.assertAvailable();
|
|
55
|
-
const target = this.resolveTargetOrThrow(params.to);
|
|
56
|
-
console.log(
|
|
57
|
-
`[wecom-upstream-delivery] sendText account=${this.upstreamAgent.accountId} corpId=${this.upstreamAgent.corpId} to=${String(params.to ?? "")} len=${params.text.length}`,
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
const runtime = getWecomRuntime();
|
|
61
|
-
const chunks = runtime.channel.text.chunkText(params.text, 2048);
|
|
62
|
-
|
|
63
|
-
for (const chunk of chunks) {
|
|
64
|
-
if (!chunk.trim()) continue;
|
|
65
|
-
await deliverUpstreamAgentApiText({
|
|
66
|
-
upstreamAgent: this.upstreamAgent,
|
|
67
|
-
primaryAgent: this.primaryAgent,
|
|
68
|
-
target,
|
|
69
|
-
text: chunk,
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async sendMedia(params: {
|
|
75
|
-
to: string | undefined;
|
|
76
|
-
text?: string;
|
|
77
|
-
buffer: Buffer;
|
|
78
|
-
filename: string;
|
|
79
|
-
contentType: string;
|
|
80
|
-
}): Promise<void> {
|
|
81
|
-
this.assertAvailable();
|
|
82
|
-
const target = this.resolveTargetOrThrow(params.to);
|
|
83
|
-
console.log(
|
|
84
|
-
`[wecom-upstream-delivery] sendMedia account=${this.upstreamAgent.accountId} corpId=${this.upstreamAgent.corpId} to=${String(params.to ?? "")} filename=${params.filename} contentType=${params.contentType}`,
|
|
85
|
-
);
|
|
86
|
-
await deliverUpstreamAgentApiMedia({
|
|
87
|
-
upstreamAgent: this.upstreamAgent,
|
|
88
|
-
primaryAgent: this.primaryAgent,
|
|
89
|
-
target,
|
|
90
|
-
buffer: params.buffer,
|
|
91
|
-
filename: params.filename,
|
|
92
|
-
contentType: params.contentType,
|
|
93
|
-
text: params.text,
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import type { OpenClawConfig } from "openclaw/plugin-sdk";
|
|
2
|
-
|
|
3
|
-
export function buildWecomBotDispatchConfig(config: OpenClawConfig): OpenClawConfig {
|
|
4
|
-
const baseAgents = (config as any)?.agents ?? {};
|
|
5
|
-
const baseAgentDefaults = (baseAgents as any)?.defaults ?? {};
|
|
6
|
-
const baseBlockChunk = (baseAgentDefaults as any)?.blockStreamingChunk ?? {};
|
|
7
|
-
const baseBlockCoalesce = (baseAgentDefaults as any)?.blockStreamingCoalesce ?? {};
|
|
8
|
-
const baseTools = (config as any)?.tools ?? {};
|
|
9
|
-
const baseSandbox = (baseTools as any)?.sandbox ?? {};
|
|
10
|
-
const baseSandboxTools = (baseSandbox as any)?.tools ?? {};
|
|
11
|
-
const existingTopLevelDeny = Array.isArray((baseTools as any).deny) ? ((baseTools as any).deny as string[]) : [];
|
|
12
|
-
const existingSandboxDeny = Array.isArray((baseSandboxTools as any).deny) ? ((baseSandboxTools as any).deny as string[]) : [];
|
|
13
|
-
const topLevelDeny = Array.from(new Set([...existingTopLevelDeny, "message"]));
|
|
14
|
-
const sandboxDeny = Array.from(new Set([...existingSandboxDeny, "message"]));
|
|
15
|
-
return {
|
|
16
|
-
...(config as any),
|
|
17
|
-
agents: {
|
|
18
|
-
...baseAgents,
|
|
19
|
-
defaults: {
|
|
20
|
-
...baseAgentDefaults,
|
|
21
|
-
blockStreamingChunk: {
|
|
22
|
-
...baseBlockChunk,
|
|
23
|
-
minChars: baseBlockChunk.minChars ?? 120,
|
|
24
|
-
maxChars: baseBlockChunk.maxChars ?? 360,
|
|
25
|
-
breakPreference: baseBlockChunk.breakPreference ?? "sentence",
|
|
26
|
-
},
|
|
27
|
-
blockStreamingCoalesce: {
|
|
28
|
-
...baseBlockCoalesce,
|
|
29
|
-
minChars: baseBlockCoalesce.minChars ?? 120,
|
|
30
|
-
maxChars: baseBlockCoalesce.maxChars ?? 360,
|
|
31
|
-
idleMs: baseBlockCoalesce.idleMs ?? 250,
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
tools: {
|
|
36
|
-
...baseTools,
|
|
37
|
-
deny: topLevelDeny,
|
|
38
|
-
sandbox: {
|
|
39
|
-
...baseSandbox,
|
|
40
|
-
tools: {
|
|
41
|
-
...baseSandboxTools,
|
|
42
|
-
deny: sandboxDeny,
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
} as OpenClawConfig;
|
|
47
|
-
}
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import type { OpenClawConfig, PluginRuntime } from "openclaw/plugin-sdk";
|
|
2
|
-
|
|
3
|
-
import { resolveWecomAccount } from "../../config/index.js";
|
|
4
|
-
import { wecomFetch } from "../../http.js";
|
|
5
|
-
import { LIMITS } from "../../monitor/state.js";
|
|
6
|
-
import type { StreamState } from "../../types/legacy-stream.js";
|
|
7
|
-
import type { ResolvedAgentAccount } from "../../types/index.js";
|
|
8
|
-
import { sendMedia as sendAgentMedia, sendText as sendAgentText, uploadMedia } from "../../transport/agent-api/core.js";
|
|
9
|
-
import { buildStreamReplyFromState } from "../../transport/bot-webhook/protocol.js";
|
|
10
|
-
import { useActiveReplyOnce } from "../../transport/bot-webhook/active-reply.js";
|
|
11
|
-
import { guessContentTypeFromPath } from "../../transport/bot-webhook/inbound-normalizer.js";
|
|
12
|
-
|
|
13
|
-
const STREAM_MAX_DM_BYTES = 200_000;
|
|
14
|
-
|
|
15
|
-
export function appendDmContent(state: StreamState, text: string): void {
|
|
16
|
-
const next = state.dmContent ? `${state.dmContent}\n\n${text}`.trim() : text.trim();
|
|
17
|
-
const buf = Buffer.from(next, "utf8");
|
|
18
|
-
state.dmContent = buf.length <= STREAM_MAX_DM_BYTES ? next : buf.subarray(buf.length - STREAM_MAX_DM_BYTES).toString("utf8");
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function resolveAgentAccountOrUndefined(cfg: OpenClawConfig, accountId: string): ResolvedAgentAccount | undefined {
|
|
22
|
-
const agent = resolveWecomAccount({ cfg, accountId }).agent;
|
|
23
|
-
return agent?.configured ? agent : undefined;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function buildFallbackPrompt(params: {
|
|
27
|
-
kind: "media" | "timeout" | "error";
|
|
28
|
-
agentConfigured: boolean;
|
|
29
|
-
userId?: string;
|
|
30
|
-
filename?: string;
|
|
31
|
-
chatType?: "group" | "direct";
|
|
32
|
-
}): string {
|
|
33
|
-
const who = params.userId ? `(${params.userId})` : "";
|
|
34
|
-
const scope = params.chatType === "group" ? "群聊" : params.chatType === "direct" ? "私聊" : "会话";
|
|
35
|
-
if (!params.agentConfigured) {
|
|
36
|
-
return `${scope}中需要通过应用私信发送${params.filename ? `(${params.filename})` : ""},但管理员尚未配置企业微信自建应用(Agent)通道。请联系管理员配置后再试。${who}`.trim();
|
|
37
|
-
}
|
|
38
|
-
if (!params.userId) {
|
|
39
|
-
return `${scope}中需要通过应用私信兜底发送${params.filename ? `(${params.filename})` : ""},但本次回调未能识别触发者 userid(请检查企微回调字段 from.userid / fromuserid)。请联系管理员排查配置。`.trim();
|
|
40
|
-
}
|
|
41
|
-
if (params.kind === "media") {
|
|
42
|
-
return `已生成文件${params.filename ? `(${params.filename})` : ""},将通过应用私信发送给你。${who}`.trim();
|
|
43
|
-
}
|
|
44
|
-
if (params.kind === "timeout") {
|
|
45
|
-
return `内容较长,为避免超时,后续内容将通过应用私信发送给你。${who}`.trim();
|
|
46
|
-
}
|
|
47
|
-
return `交付出现异常,已尝试通过应用私信发送给你。${who}`.trim();
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export async function sendBotFallbackPromptNow(params: { streamId: string; text: string }): Promise<void> {
|
|
51
|
-
await useActiveReplyOnce(params.streamId, async ({ responseUrl, proxyUrl }) => {
|
|
52
|
-
const payload = {
|
|
53
|
-
msgtype: "stream",
|
|
54
|
-
stream: {
|
|
55
|
-
id: params.streamId,
|
|
56
|
-
finish: true,
|
|
57
|
-
content: params.text.trim() || "1",
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
|
-
const res = await wecomFetch(
|
|
61
|
-
responseUrl,
|
|
62
|
-
{
|
|
63
|
-
method: "POST",
|
|
64
|
-
headers: { "Content-Type": "application/json" },
|
|
65
|
-
body: JSON.stringify(payload),
|
|
66
|
-
},
|
|
67
|
-
{ proxyUrl, timeoutMs: LIMITS.REQUEST_TIMEOUT_MS },
|
|
68
|
-
);
|
|
69
|
-
if (!res.ok) {
|
|
70
|
-
throw new Error(`fallback prompt push failed: ${res.status}`);
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export async function pushFinalStreamReplyNow(params: { streamId: string; state: StreamState }): Promise<void> {
|
|
76
|
-
const finalReply = buildStreamReplyFromState(params.state) as unknown as Record<string, unknown>;
|
|
77
|
-
await useActiveReplyOnce(params.streamId, async ({ responseUrl, proxyUrl }) => {
|
|
78
|
-
const res = await wecomFetch(
|
|
79
|
-
responseUrl,
|
|
80
|
-
{
|
|
81
|
-
method: "POST",
|
|
82
|
-
headers: { "Content-Type": "application/json" },
|
|
83
|
-
body: JSON.stringify(finalReply),
|
|
84
|
-
},
|
|
85
|
-
{ proxyUrl, timeoutMs: LIMITS.REQUEST_TIMEOUT_MS },
|
|
86
|
-
);
|
|
87
|
-
if (!res.ok) {
|
|
88
|
-
throw new Error(`final stream push failed: ${res.status}`);
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export async function sendAgentDmText(params: {
|
|
94
|
-
agent: ResolvedAgentAccount;
|
|
95
|
-
userId: string;
|
|
96
|
-
text: string;
|
|
97
|
-
core: PluginRuntime;
|
|
98
|
-
}): Promise<void> {
|
|
99
|
-
const chunks = params.core.channel.text.chunkText(params.text, 2048);
|
|
100
|
-
for (const chunk of chunks) {
|
|
101
|
-
const trimmed = chunk.trim();
|
|
102
|
-
if (!trimmed) continue;
|
|
103
|
-
await sendAgentText({ agent: params.agent, toUser: params.userId, text: trimmed });
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export async function sendAgentDmMedia(params: {
|
|
108
|
-
agent: ResolvedAgentAccount;
|
|
109
|
-
userId: string;
|
|
110
|
-
mediaUrlOrPath: string;
|
|
111
|
-
contentType?: string;
|
|
112
|
-
filename: string;
|
|
113
|
-
}): Promise<void> {
|
|
114
|
-
let buffer: Buffer;
|
|
115
|
-
let inferredContentType = params.contentType;
|
|
116
|
-
const looksLikeUrl = /^https?:\/\//i.test(params.mediaUrlOrPath);
|
|
117
|
-
if (looksLikeUrl) {
|
|
118
|
-
const res = await fetch(params.mediaUrlOrPath, { signal: AbortSignal.timeout(30_000) });
|
|
119
|
-
if (!res.ok) throw new Error(`media download failed: ${res.status}`);
|
|
120
|
-
buffer = Buffer.from(await res.arrayBuffer());
|
|
121
|
-
inferredContentType = inferredContentType || res.headers.get("content-type") || "application/octet-stream";
|
|
122
|
-
} else {
|
|
123
|
-
const fs = await import("node:fs/promises");
|
|
124
|
-
buffer = await fs.readFile(params.mediaUrlOrPath);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
let mediaType: "image" | "voice" | "video" | "file" = "file";
|
|
128
|
-
const ct = (inferredContentType || "").toLowerCase();
|
|
129
|
-
if (ct.startsWith("image/")) mediaType = "image";
|
|
130
|
-
else if (ct.startsWith("audio/")) mediaType = "voice";
|
|
131
|
-
else if (ct.startsWith("video/")) mediaType = "video";
|
|
132
|
-
|
|
133
|
-
const mediaId = await uploadMedia({
|
|
134
|
-
agent: params.agent,
|
|
135
|
-
type: mediaType,
|
|
136
|
-
buffer,
|
|
137
|
-
filename: params.filename,
|
|
138
|
-
});
|
|
139
|
-
await sendAgentMedia({
|
|
140
|
-
agent: params.agent,
|
|
141
|
-
toUser: params.userId,
|
|
142
|
-
mediaId,
|
|
143
|
-
mediaType,
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export function extractLocalImagePathsFromText(params: { text: string; mustAlsoAppearIn: string }): string[] {
|
|
148
|
-
const text = params.text;
|
|
149
|
-
const mustAlsoAppearIn = params.mustAlsoAppearIn;
|
|
150
|
-
if (!text.trim()) return [];
|
|
151
|
-
const exts = "(png|jpg|jpeg|gif|webp|bmp)";
|
|
152
|
-
const re = new RegExp(String.raw`(\/(?:Users|tmp|root|home)\/[^\s"'<>]+?\.${exts})`, "gi");
|
|
153
|
-
const found = new Set<string>();
|
|
154
|
-
let m: RegExpExecArray | null;
|
|
155
|
-
while ((m = re.exec(text))) {
|
|
156
|
-
const p = m[1];
|
|
157
|
-
if (!p) continue;
|
|
158
|
-
if (!mustAlsoAppearIn.includes(p)) continue;
|
|
159
|
-
found.add(p);
|
|
160
|
-
}
|
|
161
|
-
return Array.from(found);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
export function extractLocalFilePathsFromText(text: string): string[] {
|
|
165
|
-
if (!text.trim()) return [];
|
|
166
|
-
const re = /\/(?:Users|tmp|root|home)\/[^\s"'<>]+/g;
|
|
167
|
-
const found = new Set<string>();
|
|
168
|
-
let m: RegExpExecArray | null;
|
|
169
|
-
while ((m = re.exec(text))) {
|
|
170
|
-
const p = m[0]?.trim();
|
|
171
|
-
if (p) found.add(p);
|
|
172
|
-
}
|
|
173
|
-
return Array.from(found);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
export function guessLocalPathContentType(filePath: string): string | undefined {
|
|
177
|
-
return guessContentTypeFromPath(filePath);
|
|
178
|
-
}
|