@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
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
export var NodeType;
|
|
2
|
+
(function (NodeType) {
|
|
3
|
+
NodeType["Document"] = "Document";
|
|
4
|
+
NodeType["MainStory"] = "MainStory";
|
|
5
|
+
NodeType["Section"] = "Section";
|
|
6
|
+
NodeType["Paragraph"] = "Paragraph";
|
|
7
|
+
NodeType["Table"] = "Table";
|
|
8
|
+
NodeType["TableRow"] = "TableRow";
|
|
9
|
+
NodeType["TableCell"] = "TableCell";
|
|
10
|
+
NodeType["Text"] = "Text";
|
|
11
|
+
NodeType["Drawing"] = "Drawing";
|
|
12
|
+
})(NodeType || (NodeType = {}));
|
|
13
|
+
export var LineSpacingRule;
|
|
14
|
+
(function (LineSpacingRule) {
|
|
15
|
+
LineSpacingRule["UNSPECIFIED"] = "LINE_SPACING_RULE_UNSPECIFIED";
|
|
16
|
+
LineSpacingRule["AUTO"] = "LINE_SPACING_RULE_AUTO";
|
|
17
|
+
LineSpacingRule["EXACT"] = "LINE_SPACING_RULE_EXACT";
|
|
18
|
+
LineSpacingRule["AT_LEAST"] = "LINE_SPACING_RULE_AT_LEAST";
|
|
19
|
+
})(LineSpacingRule || (LineSpacingRule = {}));
|
|
20
|
+
export var AlignmentType;
|
|
21
|
+
(function (AlignmentType) {
|
|
22
|
+
AlignmentType["UNSPECIFIED"] = "ALIGNMENT_TYPE_UNSPECIFIED";
|
|
23
|
+
AlignmentType["CENTER"] = "ALIGNMENT_TYPE_CENTER";
|
|
24
|
+
AlignmentType["BOTH"] = "ALIGNMENT_TYPE_BOTH";
|
|
25
|
+
AlignmentType["DISTRIBUTE"] = "ALIGNMENT_TYPE_DISTRIBUTE";
|
|
26
|
+
AlignmentType["LEFT"] = "ALIGNMENT_TYPE_LEFT";
|
|
27
|
+
AlignmentType["RIGHT"] = "ALIGNMENT_TYPE_RIGHT";
|
|
28
|
+
})(AlignmentType || (AlignmentType = {}));
|
|
29
|
+
export var TextDirection;
|
|
30
|
+
(function (TextDirection) {
|
|
31
|
+
TextDirection["UNSPECIFIED"] = "TEXT_DIRECTION_UNSPECIFIED";
|
|
32
|
+
TextDirection["RTL"] = "TEXT_DIRECTION_RIGHT_TO_LEFT";
|
|
33
|
+
TextDirection["LTR"] = "TEXT_DIRECTION_LEFT_TO_RIGHT";
|
|
34
|
+
})(TextDirection || (TextDirection = {}));
|
|
35
|
+
export var TextVerticalAlign;
|
|
36
|
+
(function (TextVerticalAlign) {
|
|
37
|
+
TextVerticalAlign["UNSPECIFIED"] = "RUN_VERTICAL_ALIGN_UNSPECIFIED";
|
|
38
|
+
TextVerticalAlign["BASELINE"] = "RUN_VERTICAL_ALIGN_BASELINE";
|
|
39
|
+
TextVerticalAlign["SUPER_SCRIPT"] = "RUN_VERTICAL_ALIGN_SUPER_SCRIPT";
|
|
40
|
+
TextVerticalAlign["SUB_SCRIPT"] = "RUN_VERTICAL_ALIGN_SUB_SCRIPT";
|
|
41
|
+
})(TextVerticalAlign || (TextVerticalAlign = {}));
|
|
42
|
+
export var TableHorizontalAlignmentType;
|
|
43
|
+
(function (TableHorizontalAlignmentType) {
|
|
44
|
+
TableHorizontalAlignmentType["UNSPECIFIED"] = "TABLE_HORIZONTAL_ALIGNMENT_TYPE_UNSPECIFIED";
|
|
45
|
+
TableHorizontalAlignmentType["CENTER"] = "TABLE_HORIZONTAL_ALIGNMENT_TYPE_CENTER";
|
|
46
|
+
TableHorizontalAlignmentType["LEFT"] = "TABLE_HORIZONTAL_ALIGNMENT_TYPE_LEFT";
|
|
47
|
+
TableHorizontalAlignmentType["START"] = "TABLE_HORIZONTAL_ALIGNMENT_TYPE_START";
|
|
48
|
+
})(TableHorizontalAlignmentType || (TableHorizontalAlignmentType = {}));
|
|
49
|
+
export var TableLayoutType;
|
|
50
|
+
(function (TableLayoutType) {
|
|
51
|
+
TableLayoutType["UNSPECIFIED"] = "TABLE_LAYOUT_TYPE_UNSPECIFIED";
|
|
52
|
+
TableLayoutType["FIXED"] = "TABLE_LAYOUT_TYPE_FIXED";
|
|
53
|
+
TableLayoutType["AUTO_FIT"] = "TABLE_LAYOUT_TYPE_AUTO_FIT";
|
|
54
|
+
})(TableLayoutType || (TableLayoutType = {}));
|
|
55
|
+
export var TableWidthType;
|
|
56
|
+
(function (TableWidthType) {
|
|
57
|
+
TableWidthType["UNSPECIFIED"] = "TABLE_LAYOUT_TYPE_UNSPECIFIED";
|
|
58
|
+
TableWidthType["FIXED"] = "TABLE_LAYOUT_TYPE_FIXED";
|
|
59
|
+
TableWidthType["AUTO_FIT"] = "TABLE_LAYOUT_TYPE_AUTO_FIT";
|
|
60
|
+
})(TableWidthType || (TableWidthType = {}));
|
|
61
|
+
export var VerticalAlignment;
|
|
62
|
+
(function (VerticalAlignment) {
|
|
63
|
+
VerticalAlignment["UNSPECIFIED"] = "VERTICAL_ALIGNMENT__UNSPECIFIED";
|
|
64
|
+
VerticalAlignment["TOP"] = "VERTICAL_ALIGNMENT_TOP";
|
|
65
|
+
VerticalAlignment["CENTER"] = "VERTICAL_ALIGNMENT_CENTER";
|
|
66
|
+
VerticalAlignment["BOTH"] = "VERTICAL_ALIGNMENT_BOTH";
|
|
67
|
+
VerticalAlignment["BOTTOM"] = "VERTICAL_ALIGNMENT_BOTTOM";
|
|
68
|
+
})(VerticalAlignment || (VerticalAlignment = {}));
|
|
69
|
+
export var AddonSourceType;
|
|
70
|
+
(function (AddonSourceType) {
|
|
71
|
+
AddonSourceType["UNSPECIFIED"] = "ADDON_SOURCE_TYPE_UNSPECIFIED";
|
|
72
|
+
AddonSourceType["NONE"] = "ADDON_SOURCE_TYPE_NONE";
|
|
73
|
+
AddonSourceType["LATEX"] = "ADDON_SOURCE_TYPE_LATEX";
|
|
74
|
+
AddonSourceType["SIGN"] = "ADDON_SOURCE_TYPE_SIGN";
|
|
75
|
+
AddonSourceType["SIGN_BAR"] = "ADDON_SOURCE_TYPE_SIGN_BAR";
|
|
76
|
+
})(AddonSourceType || (AddonSourceType = {}));
|
|
77
|
+
export var RelativeFromHorizontal;
|
|
78
|
+
(function (RelativeFromHorizontal) {
|
|
79
|
+
RelativeFromHorizontal["UNSPECIFIED"] = "RELATIVE_FROM_HORIZONTAL_UNSPECIFIED";
|
|
80
|
+
RelativeFromHorizontal["MARGIN"] = "RELATIVE_FROM_HORIZONTAL_MARGIN";
|
|
81
|
+
RelativeFromHorizontal["PAGE"] = "RELATIVE_FROM_HORIZONTAL_PAGE";
|
|
82
|
+
RelativeFromHorizontal["COLUMN"] = "RELATIVE_FROM_HORIZONTAL_COLUMN";
|
|
83
|
+
RelativeFromHorizontal["CHARACTER"] = "RELATIVE_FROM_HORIZONTAL_CHARACTER";
|
|
84
|
+
RelativeFromHorizontal["LEFT_MARGIN"] = "RELATIVE_FROM_HORIZONTAL_LEFT_MARGIN";
|
|
85
|
+
RelativeFromHorizontal["RIGHT_MARGIN"] = "RELATIVE_FROM_HORIZONTAL_RIGHT_MARGIN";
|
|
86
|
+
RelativeFromHorizontal["INSIDE_MARGIN"] = "RELATIVE_FROM_HORIZONTAL_INSIDE_MARGIN";
|
|
87
|
+
RelativeFromHorizontal["OUTSIDE_MARGIN"] = "RELATIVE_FROM_HORIZONTAL_OUTSIDE_MARGIN";
|
|
88
|
+
})(RelativeFromHorizontal || (RelativeFromHorizontal = {}));
|
|
89
|
+
export var RelativeFromVertical;
|
|
90
|
+
(function (RelativeFromVertical) {
|
|
91
|
+
RelativeFromVertical["UNSPECIFIED"] = "RELATIVE_FROM_VERTICAL_UNSPECIFIED";
|
|
92
|
+
RelativeFromVertical["MARGIN"] = "RELATIVE_FROM_VERTICAL_MARGIN";
|
|
93
|
+
RelativeFromVertical["PAGE"] = "RELATIVE_FROM_VERTICAL_PAGE";
|
|
94
|
+
RelativeFromVertical["PARAGRAPH"] = "RELATIVE_FROM_VERTICAL_PARAGRAPH";
|
|
95
|
+
RelativeFromVertical["LINE"] = "RELATIVE_FROM_VERTICAL_LINE";
|
|
96
|
+
RelativeFromVertical["TOP_MARGIN"] = "RELATIVE_FROM_VERTICAL_TOP_MARGIN";
|
|
97
|
+
RelativeFromVertical["BOTTOM_MARGIN"] = "RELATIVE_FROM_VERTICAL_BOTTOM_MARGIN";
|
|
98
|
+
RelativeFromVertical["INSIDE_MARGIN"] = "RELATIVE_FROM_VERTICAL_INSIDE_MARGIN";
|
|
99
|
+
RelativeFromVertical["OUTSIDE_MARGIN"] = "RELATIVE_FROM_VERTICAL_OUTSIDE_MARGIN";
|
|
100
|
+
})(RelativeFromVertical || (RelativeFromVertical = {}));
|
|
101
|
+
export var WrapText;
|
|
102
|
+
(function (WrapText) {
|
|
103
|
+
WrapText["UNSPECIFIED"] = "WRAP_TEXT_BOTH_UNSPECIFIED";
|
|
104
|
+
WrapText["BOTH_SIDES"] = "WRAP_TEXT_BOTH_SIDES";
|
|
105
|
+
WrapText["LEFT"] = "WRAP_TEXT_LEFT";
|
|
106
|
+
WrapText["RIGHT"] = "WRAP_TEXT_RIGHT";
|
|
107
|
+
WrapText["LARGEST"] = "WRAP_TEXT_LARGEST";
|
|
108
|
+
})(WrapText || (WrapText = {}));
|
|
109
|
+
export var Dimension;
|
|
110
|
+
(function (Dimension) {
|
|
111
|
+
Dimension["ROW"] = "ROW";
|
|
112
|
+
Dimension["COLUMN"] = "COLUMN"; // 列
|
|
113
|
+
})(Dimension || (Dimension = {}));
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
const GEMINI_UNSUPPORTED_KEYWORDS = new Set([
|
|
2
|
+
"patternProperties",
|
|
3
|
+
"additionalProperties",
|
|
4
|
+
"$schema",
|
|
5
|
+
"$id",
|
|
6
|
+
"$ref",
|
|
7
|
+
"$defs",
|
|
8
|
+
"definitions",
|
|
9
|
+
"examples",
|
|
10
|
+
"minLength",
|
|
11
|
+
"maxLength",
|
|
12
|
+
"minimum",
|
|
13
|
+
"maximum",
|
|
14
|
+
"multipleOf",
|
|
15
|
+
"pattern",
|
|
16
|
+
"format",
|
|
17
|
+
"minItems",
|
|
18
|
+
"maxItems",
|
|
19
|
+
"uniqueItems",
|
|
20
|
+
"minProperties",
|
|
21
|
+
"maxProperties",
|
|
22
|
+
]);
|
|
23
|
+
export function cleanSchemaForGemini(schema) {
|
|
24
|
+
if (!schema || typeof schema !== "object")
|
|
25
|
+
return schema;
|
|
26
|
+
if (Array.isArray(schema))
|
|
27
|
+
return schema.map(cleanSchemaForGemini);
|
|
28
|
+
const obj = schema;
|
|
29
|
+
const defs = {
|
|
30
|
+
...(obj.$defs && typeof obj.$defs === "object" ? obj.$defs : {}),
|
|
31
|
+
...(obj.definitions && typeof obj.definitions === "object"
|
|
32
|
+
? obj.definitions
|
|
33
|
+
: {}),
|
|
34
|
+
};
|
|
35
|
+
return cleanWithDefs(obj, defs, new Set());
|
|
36
|
+
}
|
|
37
|
+
function cleanWithDefs(schema, defs, refStack) {
|
|
38
|
+
if (!schema || typeof schema !== "object")
|
|
39
|
+
return schema;
|
|
40
|
+
if (Array.isArray(schema))
|
|
41
|
+
return schema.map((item) => cleanWithDefs(item, defs, refStack));
|
|
42
|
+
const obj = schema;
|
|
43
|
+
if (obj.$defs && typeof obj.$defs === "object") {
|
|
44
|
+
Object.assign(defs, obj.$defs);
|
|
45
|
+
}
|
|
46
|
+
if (obj.definitions && typeof obj.definitions === "object") {
|
|
47
|
+
Object.assign(defs, obj.definitions);
|
|
48
|
+
}
|
|
49
|
+
if (typeof obj.$ref === "string") {
|
|
50
|
+
const ref = obj.$ref;
|
|
51
|
+
if (refStack.has(ref))
|
|
52
|
+
return {};
|
|
53
|
+
const match = ref.match(/^#\/(?:\$defs|definitions)\/(.+)$/);
|
|
54
|
+
if (match?.[1] && defs[match[1]]) {
|
|
55
|
+
const nextStack = new Set(refStack);
|
|
56
|
+
nextStack.add(ref);
|
|
57
|
+
return cleanWithDefs(defs[match[1]], defs, nextStack);
|
|
58
|
+
}
|
|
59
|
+
return {};
|
|
60
|
+
}
|
|
61
|
+
const cleaned = {};
|
|
62
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
63
|
+
if (GEMINI_UNSUPPORTED_KEYWORDS.has(key))
|
|
64
|
+
continue;
|
|
65
|
+
if (key === "const") {
|
|
66
|
+
cleaned.enum = [value];
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (key === "properties" && value && typeof value === "object" && !Array.isArray(value)) {
|
|
70
|
+
cleaned[key] = Object.fromEntries(Object.entries(value).map(([propKey, propValue]) => [
|
|
71
|
+
propKey,
|
|
72
|
+
cleanWithDefs(propValue, defs, refStack),
|
|
73
|
+
]));
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (key === "items" && value) {
|
|
77
|
+
cleaned[key] = Array.isArray(value)
|
|
78
|
+
? value.map((item) => cleanWithDefs(item, defs, refStack))
|
|
79
|
+
: cleanWithDefs(value, defs, refStack);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if ((key === "anyOf" || key === "oneOf" || key === "allOf") && Array.isArray(value)) {
|
|
83
|
+
const nonNull = value.filter((variant) => {
|
|
84
|
+
if (!variant || typeof variant !== "object")
|
|
85
|
+
return true;
|
|
86
|
+
return variant.type !== "null";
|
|
87
|
+
});
|
|
88
|
+
if (nonNull.length === 1) {
|
|
89
|
+
const single = cleanWithDefs(nonNull[0], defs, refStack);
|
|
90
|
+
if (single && typeof single === "object" && !Array.isArray(single)) {
|
|
91
|
+
Object.assign(cleaned, single);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
cleaned[key] = nonNull.map((variant) => cleanWithDefs(variant, defs, refStack));
|
|
96
|
+
}
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
cleaned[key] = value;
|
|
100
|
+
}
|
|
101
|
+
return cleaned;
|
|
102
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { resolveWecomSourceSnapshot } from "../../runtime/source-registry.js";
|
|
2
|
+
import { cleanSchemaForGemini } from "./schema.js";
|
|
3
|
+
import { clearWecomMcpCategoryCache, sendJsonRpc } from "./transport.js";
|
|
4
|
+
const BIZ_CACHE_CLEAR_ERROR_CODES = new Set([850002]);
|
|
5
|
+
function textResult(data) {
|
|
6
|
+
return {
|
|
7
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
8
|
+
details: data,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function errorResult(error) {
|
|
12
|
+
if (error && typeof error === "object" && "errcode" in error) {
|
|
13
|
+
const errcode = Number(error.errcode ?? 0);
|
|
14
|
+
const errmsg = String(error.errmsg ?? `错误码: ${errcode}`);
|
|
15
|
+
return textResult({ error: errmsg, errcode });
|
|
16
|
+
}
|
|
17
|
+
return textResult({
|
|
18
|
+
error: error instanceof Error ? error.message : String(error),
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function parseArgs(args) {
|
|
22
|
+
if (!args)
|
|
23
|
+
return {};
|
|
24
|
+
if (typeof args === "object")
|
|
25
|
+
return args;
|
|
26
|
+
try {
|
|
27
|
+
return JSON.parse(args);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
const detail = error instanceof SyntaxError ? error.message : String(error);
|
|
31
|
+
throw new Error(`args 不是合法的 JSON: ${args} (${detail})`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function extractToolAccountId(ctx) {
|
|
35
|
+
const explicit = String(ctx.accountId ?? "").trim();
|
|
36
|
+
if (explicit)
|
|
37
|
+
return explicit;
|
|
38
|
+
const agentAccountId = String(ctx.agentAccountId ?? "").trim();
|
|
39
|
+
return agentAccountId || undefined;
|
|
40
|
+
}
|
|
41
|
+
async function handleList(accountId, category) {
|
|
42
|
+
const result = (await sendJsonRpc(accountId, category, "tools/list"));
|
|
43
|
+
const tools = result?.tools ?? [];
|
|
44
|
+
return {
|
|
45
|
+
accountId,
|
|
46
|
+
category,
|
|
47
|
+
count: tools.length,
|
|
48
|
+
tools: tools.map((tool) => ({
|
|
49
|
+
name: tool.name,
|
|
50
|
+
description: tool.description ?? "",
|
|
51
|
+
inputSchema: tool.inputSchema ? cleanSchemaForGemini(tool.inputSchema) : undefined,
|
|
52
|
+
})),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function checkBizErrorAndClearCache(result, accountId, category) {
|
|
56
|
+
if (!result || typeof result !== "object")
|
|
57
|
+
return;
|
|
58
|
+
const content = result.content;
|
|
59
|
+
if (!Array.isArray(content))
|
|
60
|
+
return;
|
|
61
|
+
for (const item of content) {
|
|
62
|
+
if (item.type !== "text" || !item.text)
|
|
63
|
+
continue;
|
|
64
|
+
try {
|
|
65
|
+
const parsed = JSON.parse(item.text);
|
|
66
|
+
if (typeof parsed.errcode === "number" && BIZ_CACHE_CLEAR_ERROR_CODES.has(parsed.errcode)) {
|
|
67
|
+
clearWecomMcpCategoryCache(accountId, category);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// Ignore non-JSON content.
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async function handleCall(accountId, category, method, args) {
|
|
77
|
+
const result = await sendJsonRpc(accountId, category, "tools/call", {
|
|
78
|
+
name: method,
|
|
79
|
+
arguments: args,
|
|
80
|
+
});
|
|
81
|
+
checkBizErrorAndClearCache(result, accountId, category);
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
export function createWeComMcpToolFactory() {
|
|
85
|
+
return (toolContext) => {
|
|
86
|
+
if (toolContext.messageChannel !== "wecom") {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const accountId = extractToolAccountId(toolContext);
|
|
90
|
+
const source = resolveWecomSourceSnapshot({
|
|
91
|
+
accountId,
|
|
92
|
+
sessionKey: toolContext.sessionKey,
|
|
93
|
+
sessionId: toolContext.sessionId,
|
|
94
|
+
});
|
|
95
|
+
if (!source || source.source !== "bot-ws") {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
name: "wecom_mcp",
|
|
100
|
+
label: "WeCom MCP",
|
|
101
|
+
description: "企业微信 Bot WS MCP 工具。仅在 WeCom Bot WS 会话中可用,用于列出和调用企业微信 MCP 能力。",
|
|
102
|
+
parameters: {
|
|
103
|
+
type: "object",
|
|
104
|
+
properties: {
|
|
105
|
+
action: {
|
|
106
|
+
type: "string",
|
|
107
|
+
enum: ["list", "call"],
|
|
108
|
+
description: "操作类型:list 或 call",
|
|
109
|
+
},
|
|
110
|
+
category: {
|
|
111
|
+
type: "string",
|
|
112
|
+
description: "MCP 品类,如 contact、todo、meeting、doc",
|
|
113
|
+
},
|
|
114
|
+
method: {
|
|
115
|
+
type: "string",
|
|
116
|
+
description: "action=call 时要调用的工具方法名",
|
|
117
|
+
},
|
|
118
|
+
args: {
|
|
119
|
+
type: "string",
|
|
120
|
+
description: "action=call 时传入的 JSON 字符串参数,默认 {}",
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
required: ["action", "category"],
|
|
124
|
+
},
|
|
125
|
+
async execute(_toolCallId, rawParams) {
|
|
126
|
+
try {
|
|
127
|
+
const params = rawParams;
|
|
128
|
+
const effectiveAccountId = extractToolAccountId(toolContext);
|
|
129
|
+
if (!effectiveAccountId) {
|
|
130
|
+
throw new Error("当前会话缺少 WeCom accountId,无法调用 wecom_mcp。");
|
|
131
|
+
}
|
|
132
|
+
if (params.action === "list") {
|
|
133
|
+
return textResult(await handleList(effectiveAccountId, params.category));
|
|
134
|
+
}
|
|
135
|
+
if (!params.method) {
|
|
136
|
+
return textResult({ error: "action=call 时必须提供 method" });
|
|
137
|
+
}
|
|
138
|
+
return textResult(await handleCall(effectiveAccountId, params.category, params.method, parseArgs(params.args)));
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
return errorResult(error);
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import { generateReqId } from "@wecom/aibot-node-sdk";
|
|
2
|
+
import { getBotWsPushHandle } from "../../runtime.js";
|
|
3
|
+
const HTTP_REQUEST_TIMEOUT_MS = 30_000;
|
|
4
|
+
const MCP_CONFIG_FETCH_TIMEOUT_MS = 15_000;
|
|
5
|
+
const MCP_GET_CONFIG_CMD = "aibot_get_mcp_config";
|
|
6
|
+
const MCP_PLUGIN_VERSION = "wecom-dual-plane";
|
|
7
|
+
const LOG_TAG = "[wecom-mcp]";
|
|
8
|
+
const CACHE_CLEAR_ERROR_CODES = new Set([-32001, -32002, -32003]);
|
|
9
|
+
const mcpConfigCache = new Map();
|
|
10
|
+
const mcpSessionCache = new Map();
|
|
11
|
+
const statelessKeys = new Set();
|
|
12
|
+
const inflightInitRequests = new Map();
|
|
13
|
+
function cacheKey(accountId, category) {
|
|
14
|
+
return `${accountId}::${category}`;
|
|
15
|
+
}
|
|
16
|
+
function withTimeout(promise, timeoutMs, message) {
|
|
17
|
+
let timeoutId;
|
|
18
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
19
|
+
timeoutId = setTimeout(() => reject(new Error(message)), timeoutMs);
|
|
20
|
+
});
|
|
21
|
+
return Promise.race([promise, timeoutPromise]).finally(() => {
|
|
22
|
+
if (timeoutId)
|
|
23
|
+
clearTimeout(timeoutId);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
export class McpRpcError extends Error {
|
|
27
|
+
code;
|
|
28
|
+
data;
|
|
29
|
+
constructor(code, message, data) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.code = code;
|
|
32
|
+
this.data = data;
|
|
33
|
+
this.name = "McpRpcError";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export class McpHttpError extends Error {
|
|
37
|
+
statusCode;
|
|
38
|
+
constructor(statusCode, message) {
|
|
39
|
+
super(message);
|
|
40
|
+
this.statusCode = statusCode;
|
|
41
|
+
this.name = "McpHttpError";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function fetchMcpConfig(accountId, category) {
|
|
45
|
+
const handle = getBotWsPushHandle(accountId);
|
|
46
|
+
if (!handle?.isConnected()) {
|
|
47
|
+
throw new Error(`当前企微账号 MCP 服务未就绪:account=${accountId} 的 Bot WS 未连接。`);
|
|
48
|
+
}
|
|
49
|
+
const response = await withTimeout(handle.replyCommand({
|
|
50
|
+
cmd: MCP_GET_CONFIG_CMD,
|
|
51
|
+
body: {
|
|
52
|
+
biz_type: category,
|
|
53
|
+
plugin_version: MCP_PLUGIN_VERSION,
|
|
54
|
+
},
|
|
55
|
+
headers: {
|
|
56
|
+
req_id: generateReqId("mcp_config"),
|
|
57
|
+
},
|
|
58
|
+
}), MCP_CONFIG_FETCH_TIMEOUT_MS, `MCP config fetch timed out after ${MCP_CONFIG_FETCH_TIMEOUT_MS}ms`);
|
|
59
|
+
const errcode = Number(response.errcode ?? 0);
|
|
60
|
+
if (errcode !== 0) {
|
|
61
|
+
throw new Error(`MCP 配置请求失败: errcode=${String(response.errcode)} errmsg=${String(response.errmsg ?? "unknown")}`);
|
|
62
|
+
}
|
|
63
|
+
const body = response.body;
|
|
64
|
+
if (!body?.url) {
|
|
65
|
+
throw new Error(`MCP 配置响应缺少 url 字段 (account=${accountId}, category=${category})`);
|
|
66
|
+
}
|
|
67
|
+
console.log(`${LOG_TAG} config ready account=${accountId} category=${category} url=${body.url}`);
|
|
68
|
+
return body;
|
|
69
|
+
}
|
|
70
|
+
async function getMcpUrl(accountId, category) {
|
|
71
|
+
const key = cacheKey(accountId, category);
|
|
72
|
+
const cached = mcpConfigCache.get(key);
|
|
73
|
+
if (cached?.url) {
|
|
74
|
+
return String(cached.url);
|
|
75
|
+
}
|
|
76
|
+
const body = await fetchMcpConfig(accountId, category);
|
|
77
|
+
mcpConfigCache.set(key, body);
|
|
78
|
+
return String(body.url);
|
|
79
|
+
}
|
|
80
|
+
async function sendRawJsonRpc(url, session, body) {
|
|
81
|
+
const controller = new AbortController();
|
|
82
|
+
const timeoutId = setTimeout(() => controller.abort(), HTTP_REQUEST_TIMEOUT_MS);
|
|
83
|
+
try {
|
|
84
|
+
const headers = {
|
|
85
|
+
"Content-Type": "application/json",
|
|
86
|
+
Accept: "application/json, text/event-stream",
|
|
87
|
+
};
|
|
88
|
+
if (session.sessionId) {
|
|
89
|
+
headers["Mcp-Session-Id"] = session.sessionId;
|
|
90
|
+
}
|
|
91
|
+
const response = await fetch(url, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
headers,
|
|
94
|
+
body: JSON.stringify(body),
|
|
95
|
+
signal: controller.signal,
|
|
96
|
+
});
|
|
97
|
+
const newSessionId = response.headers.get("mcp-session-id");
|
|
98
|
+
if (!response.ok) {
|
|
99
|
+
throw new McpHttpError(response.status, `MCP HTTP 请求失败: ${response.status} ${response.statusText}`);
|
|
100
|
+
}
|
|
101
|
+
const contentLength = response.headers.get("content-length");
|
|
102
|
+
if (response.status === 204 || contentLength === "0") {
|
|
103
|
+
return { rpcResult: undefined, newSessionId };
|
|
104
|
+
}
|
|
105
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
106
|
+
if (contentType.includes("text/event-stream")) {
|
|
107
|
+
return {
|
|
108
|
+
rpcResult: await parseSseResponse(response),
|
|
109
|
+
newSessionId,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
const text = await response.text();
|
|
113
|
+
if (!text.trim()) {
|
|
114
|
+
return { rpcResult: undefined, newSessionId };
|
|
115
|
+
}
|
|
116
|
+
const rpc = JSON.parse(text);
|
|
117
|
+
if (rpc.error) {
|
|
118
|
+
throw new McpRpcError(rpc.error.code, `MCP 调用错误 [${rpc.error.code}]: ${rpc.error.message}`, rpc.error.data);
|
|
119
|
+
}
|
|
120
|
+
return { rpcResult: rpc.result, newSessionId };
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
124
|
+
throw new Error(`MCP 请求超时 (${HTTP_REQUEST_TIMEOUT_MS}ms)`);
|
|
125
|
+
}
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
clearTimeout(timeoutId);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async function initializeSession(accountId, category, url) {
|
|
133
|
+
const key = cacheKey(accountId, category);
|
|
134
|
+
const session = { sessionId: null, initialized: false, stateless: false };
|
|
135
|
+
const initializeRequest = {
|
|
136
|
+
jsonrpc: "2.0",
|
|
137
|
+
id: generateReqId("mcp_init"),
|
|
138
|
+
method: "initialize",
|
|
139
|
+
params: {
|
|
140
|
+
protocolVersion: "2025-03-26",
|
|
141
|
+
capabilities: {},
|
|
142
|
+
clientInfo: { name: "wecom_mcp", version: MCP_PLUGIN_VERSION },
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
const initResult = await sendRawJsonRpc(url, session, initializeRequest);
|
|
146
|
+
if (initResult.newSessionId) {
|
|
147
|
+
session.sessionId = initResult.newSessionId;
|
|
148
|
+
}
|
|
149
|
+
if (!session.sessionId) {
|
|
150
|
+
session.stateless = true;
|
|
151
|
+
session.initialized = true;
|
|
152
|
+
statelessKeys.add(key);
|
|
153
|
+
mcpSessionCache.set(key, session);
|
|
154
|
+
return session;
|
|
155
|
+
}
|
|
156
|
+
const notifyRequest = {
|
|
157
|
+
jsonrpc: "2.0",
|
|
158
|
+
method: "notifications/initialized",
|
|
159
|
+
};
|
|
160
|
+
const notifyResult = await sendRawJsonRpc(url, session, notifyRequest);
|
|
161
|
+
if (notifyResult.newSessionId) {
|
|
162
|
+
session.sessionId = notifyResult.newSessionId;
|
|
163
|
+
}
|
|
164
|
+
session.initialized = true;
|
|
165
|
+
mcpSessionCache.set(key, session);
|
|
166
|
+
return session;
|
|
167
|
+
}
|
|
168
|
+
async function getOrCreateSession(accountId, category, url) {
|
|
169
|
+
const key = cacheKey(accountId, category);
|
|
170
|
+
if (statelessKeys.has(key)) {
|
|
171
|
+
const cached = mcpSessionCache.get(key);
|
|
172
|
+
if (cached)
|
|
173
|
+
return cached;
|
|
174
|
+
}
|
|
175
|
+
const cached = mcpSessionCache.get(key);
|
|
176
|
+
if (cached?.initialized) {
|
|
177
|
+
return cached;
|
|
178
|
+
}
|
|
179
|
+
const inflight = inflightInitRequests.get(key);
|
|
180
|
+
if (inflight) {
|
|
181
|
+
return inflight;
|
|
182
|
+
}
|
|
183
|
+
const promise = initializeSession(accountId, category, url).finally(() => {
|
|
184
|
+
inflightInitRequests.delete(key);
|
|
185
|
+
});
|
|
186
|
+
inflightInitRequests.set(key, promise);
|
|
187
|
+
return promise;
|
|
188
|
+
}
|
|
189
|
+
async function rebuildSession(accountId, category, url) {
|
|
190
|
+
const key = cacheKey(accountId, category);
|
|
191
|
+
const inflight = inflightInitRequests.get(key);
|
|
192
|
+
if (inflight)
|
|
193
|
+
return inflight;
|
|
194
|
+
const promise = initializeSession(accountId, category, url).finally(() => {
|
|
195
|
+
inflightInitRequests.delete(key);
|
|
196
|
+
});
|
|
197
|
+
inflightInitRequests.set(key, promise);
|
|
198
|
+
return promise;
|
|
199
|
+
}
|
|
200
|
+
async function parseSseResponse(response) {
|
|
201
|
+
const text = await response.text();
|
|
202
|
+
const lines = text.split("\n");
|
|
203
|
+
let currentParts = [];
|
|
204
|
+
let lastEventData = "";
|
|
205
|
+
for (const line of lines) {
|
|
206
|
+
if (line.startsWith("data: ")) {
|
|
207
|
+
currentParts.push(line.slice(6));
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
if (line.startsWith("data:")) {
|
|
211
|
+
currentParts.push(line.slice(5));
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
if (line.trim() === "" && currentParts.length > 0) {
|
|
215
|
+
lastEventData = currentParts.join("\n").trim();
|
|
216
|
+
currentParts = [];
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (currentParts.length > 0) {
|
|
220
|
+
lastEventData = currentParts.join("\n").trim();
|
|
221
|
+
}
|
|
222
|
+
if (!lastEventData) {
|
|
223
|
+
throw new Error("SSE 响应中未包含有效数据");
|
|
224
|
+
}
|
|
225
|
+
const rpc = JSON.parse(lastEventData);
|
|
226
|
+
if (rpc.error) {
|
|
227
|
+
throw new McpRpcError(rpc.error.code, `MCP 调用错误 [${rpc.error.code}]: ${rpc.error.message}`, rpc.error.data);
|
|
228
|
+
}
|
|
229
|
+
return rpc.result;
|
|
230
|
+
}
|
|
231
|
+
export function clearWecomMcpCategoryCache(accountId, category) {
|
|
232
|
+
const key = cacheKey(accountId, category);
|
|
233
|
+
console.log(`${LOG_TAG} clear cache account=${accountId} category=${category}`);
|
|
234
|
+
mcpConfigCache.delete(key);
|
|
235
|
+
mcpSessionCache.delete(key);
|
|
236
|
+
statelessKeys.delete(key);
|
|
237
|
+
inflightInitRequests.delete(key);
|
|
238
|
+
}
|
|
239
|
+
export function clearWecomMcpAccountCache(accountId) {
|
|
240
|
+
const prefix = `${accountId}::`;
|
|
241
|
+
for (const key of [...mcpConfigCache.keys()]) {
|
|
242
|
+
if (key.startsWith(prefix))
|
|
243
|
+
mcpConfigCache.delete(key);
|
|
244
|
+
}
|
|
245
|
+
for (const key of [...mcpSessionCache.keys()]) {
|
|
246
|
+
if (key.startsWith(prefix))
|
|
247
|
+
mcpSessionCache.delete(key);
|
|
248
|
+
}
|
|
249
|
+
for (const key of [...statelessKeys]) {
|
|
250
|
+
if (key.startsWith(prefix))
|
|
251
|
+
statelessKeys.delete(key);
|
|
252
|
+
}
|
|
253
|
+
for (const key of [...inflightInitRequests.keys()]) {
|
|
254
|
+
if (key.startsWith(prefix))
|
|
255
|
+
inflightInitRequests.delete(key);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
export async function sendJsonRpc(accountId, category, method, params) {
|
|
259
|
+
const url = await getMcpUrl(accountId, category);
|
|
260
|
+
const body = {
|
|
261
|
+
jsonrpc: "2.0",
|
|
262
|
+
id: generateReqId("mcp_rpc"),
|
|
263
|
+
method,
|
|
264
|
+
...(params !== undefined ? { params } : {}),
|
|
265
|
+
};
|
|
266
|
+
let session = await getOrCreateSession(accountId, category, url);
|
|
267
|
+
try {
|
|
268
|
+
const result = await sendRawJsonRpc(url, session, body);
|
|
269
|
+
if (result.newSessionId) {
|
|
270
|
+
session.sessionId = result.newSessionId;
|
|
271
|
+
}
|
|
272
|
+
return result.rpcResult;
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
if (error instanceof McpRpcError && CACHE_CLEAR_ERROR_CODES.has(error.code)) {
|
|
276
|
+
clearWecomMcpCategoryCache(accountId, category);
|
|
277
|
+
}
|
|
278
|
+
if (session.stateless) {
|
|
279
|
+
throw error;
|
|
280
|
+
}
|
|
281
|
+
if (error instanceof McpHttpError && error.statusCode === 404) {
|
|
282
|
+
mcpSessionCache.delete(cacheKey(accountId, category));
|
|
283
|
+
session = await rebuildSession(accountId, category, url);
|
|
284
|
+
const result = await sendRawJsonRpc(url, session, body);
|
|
285
|
+
if (result.newSessionId) {
|
|
286
|
+
session.sessionId = result.newSessionId;
|
|
287
|
+
}
|
|
288
|
+
return result.rpcResult;
|
|
289
|
+
}
|
|
290
|
+
console.error(`${LOG_TAG} rpc failed account=${accountId} category=${category} method=${method} error=${error instanceof Error ? error.message : String(error)}`);
|
|
291
|
+
throw error;
|
|
292
|
+
}
|
|
293
|
+
}
|