@soimy/dingtalk 3.6.10 → 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 +11655 -10324
- 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} +5 -5
- 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/messaging/inline-directives.d.ts +42 -0
- 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} +75 -2
- 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} +144 -85
- 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/messaging/inline-directives.ts +342 -0
- 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} +77 -2
- 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
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-domain runtime agent-event infrastructure.
|
|
3
|
+
*
|
|
4
|
+
* Owns the generic OpenClaw `events.onAgentEvent` surface that several
|
|
5
|
+
* domains consume: event typing, reference-counted fan-out, field accessors,
|
|
6
|
+
* and run correlation. Domain owners (ack reactions, AI card task progress)
|
|
7
|
+
* build their own behavior on top of these primitives instead of importing
|
|
8
|
+
* each other's private modules.
|
|
9
|
+
*/
|
|
10
|
+
export type RuntimeEventsLogger = {
|
|
11
|
+
debug?: (msg: string) => void;
|
|
12
|
+
info?: (msg: string) => void;
|
|
13
|
+
warn?: (msg: string) => void;
|
|
14
|
+
};
|
|
15
|
+
export type RuntimeAgentEvent = {
|
|
16
|
+
stream?: string;
|
|
17
|
+
runId?: string;
|
|
18
|
+
sessionKey?: string;
|
|
19
|
+
data?: {
|
|
20
|
+
phase?: string;
|
|
21
|
+
name?: string;
|
|
22
|
+
args?: unknown;
|
|
23
|
+
runId?: string;
|
|
24
|
+
sessionKey?: string;
|
|
25
|
+
toolCallId?: string;
|
|
26
|
+
meta?: {
|
|
27
|
+
runId?: string;
|
|
28
|
+
sessionKey?: string;
|
|
29
|
+
} | null;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
export type RuntimeEventsSurface = {
|
|
33
|
+
onAgentEvent?: (listener: (event: unknown) => void) => () => void;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Fan one upstream `onAgentEvent` subscription out to multiple local consumers.
|
|
37
|
+
*
|
|
38
|
+
* The upstream subscription is reference-counted: it is created with the first
|
|
39
|
+
* local listener and released with the last one. Each listener is isolated so a
|
|
40
|
+
* throwing consumer can neither starve the remaining consumers nor bubble back
|
|
41
|
+
* into the host event emitter.
|
|
42
|
+
*/
|
|
43
|
+
export declare function createRuntimeEventsFanout(upstream: RuntimeEventsSurface | undefined, options?: {
|
|
44
|
+
log?: RuntimeEventsLogger;
|
|
45
|
+
}): RuntimeEventsSurface;
|
|
46
|
+
export declare function getEventRunId(event: RuntimeAgentEvent | undefined): string | undefined;
|
|
47
|
+
export declare function getEventSessionKey(event: RuntimeAgentEvent | undefined): string | undefined;
|
|
48
|
+
export declare function describeEvent(event: RuntimeAgentEvent | undefined): string;
|
|
49
|
+
/**
|
|
50
|
+
* Build a predicate that decides whether an agent event belongs to one reply.
|
|
51
|
+
*
|
|
52
|
+
* Correlation prefers an already captured `runId`; otherwise it accepts events
|
|
53
|
+
* whose `sessionKey` matches, and finally falls back to optimistically
|
|
54
|
+
* capturing the first session-less lifecycle start inside a short window.
|
|
55
|
+
*
|
|
56
|
+
* `consumer` labels the debug logs so two consumers sharing the same session
|
|
57
|
+
* (ack reactions and card task progress) stay distinguishable while triaging.
|
|
58
|
+
*/
|
|
59
|
+
export declare function createAgentEventCorrelator(params: {
|
|
60
|
+
/** Short label identifying the consuming domain in debug logs. */
|
|
61
|
+
consumer: string;
|
|
62
|
+
sessionKey: string;
|
|
63
|
+
enabled: boolean;
|
|
64
|
+
createdAt: number;
|
|
65
|
+
optimisticCaptureWindowMs: number;
|
|
66
|
+
log?: RuntimeEventsLogger;
|
|
67
|
+
}): (event: RuntimeAgentEvent | undefined) => boolean;
|
|
@@ -8,14 +8,39 @@
|
|
|
8
8
|
* - Media files and streams
|
|
9
9
|
* - Session and token management
|
|
10
10
|
*/
|
|
11
|
-
import type { ChannelAccountSnapshot as SDKChannelAccountSnapshot, ChannelGatewayContext as SDKChannelGatewayContext, ChannelLogSink as SDKChannelLogSink } from "openclaw/plugin-sdk/channel-
|
|
11
|
+
import type { ChannelAccountSnapshot as SDKChannelAccountSnapshot, ChannelGatewayContext as SDKChannelGatewayContext, ChannelLogSink as SDKChannelLogSink } from "openclaw/plugin-sdk/channel-contract";
|
|
12
12
|
import type { ChannelPlugin as SDKChannelPlugin, OpenClawConfig } from "openclaw/plugin-sdk/core";
|
|
13
13
|
import type { ChannelSetupWizard } from "openclaw/plugin-sdk/setup";
|
|
14
14
|
import type { SecretInput } from "./secret-input";
|
|
15
15
|
export type AckReactionMode = "off" | "emoji" | "kaomoji";
|
|
16
16
|
export type AckReactionConfigValue = string;
|
|
17
17
|
export type CardStreamingMode = "off" | "answer" | "all";
|
|
18
|
+
/** How tool-driven task-progress changes reach the card:
|
|
19
|
+
* - `heartbeat` (default): coalesced into the 30s progress heartbeat
|
|
20
|
+
* - `interval`: pushed on every correlated tool event, throttled by `cardStreamInterval` */
|
|
21
|
+
export type CardTaskProgressRefresh = "heartbeat" | "interval";
|
|
18
22
|
export type ContextVisibilityMode = "all" | "allowlist" | "allowlist_quote";
|
|
23
|
+
/**
|
|
24
|
+
* Gateway RPC capability configuration (Issue #608, 问题 3).
|
|
25
|
+
* Aligns with the official connector's `tools: { docs, media }` gate shape.
|
|
26
|
+
* All capabilities default to enabled for backward compatibility.
|
|
27
|
+
*/
|
|
28
|
+
export interface DingTalkGatewayCapabilitiesConfig {
|
|
29
|
+
tools?: {
|
|
30
|
+
/** Enable `dingtalk.docs.*` and `dingtalk-connector.docs.*` Gateway RPCs (default: true) */
|
|
31
|
+
docs?: boolean;
|
|
32
|
+
/** Enable proactive-send Gateway RPCs: `dingtalk-connector.sendToUser/sendToGroup/send` (default: true) */
|
|
33
|
+
proactiveSend?: boolean;
|
|
34
|
+
};
|
|
35
|
+
/** Optional doc-space allowlist; when set, docs RPCs only accept these `spaceId` values */
|
|
36
|
+
docs?: {
|
|
37
|
+
allowedSpaceIds?: string[];
|
|
38
|
+
};
|
|
39
|
+
/** Optional proactive-send target allowlist; entries must be `user:*` or `group:*` */
|
|
40
|
+
send?: {
|
|
41
|
+
allowedTargets?: string[];
|
|
42
|
+
};
|
|
43
|
+
}
|
|
19
44
|
/**
|
|
20
45
|
* DingTalk channel configuration (extends base OpenClaw config)
|
|
21
46
|
*/
|
|
@@ -70,10 +95,23 @@ export interface DingTalkConfig extends OpenClawConfig {
|
|
|
70
95
|
* - answer: stream answer text
|
|
71
96
|
* - all: stream answer + reasoning text */
|
|
72
97
|
cardStreamingMode?: CardStreamingMode;
|
|
98
|
+
/** Internal derived flag, not a user-facing config key: whether
|
|
99
|
+
* `cardStreamingMode` came from an explicit user setting instead of the
|
|
100
|
+
* runtime default. Written by config normalization only. */
|
|
101
|
+
cardStreamingModeConfigured?: boolean;
|
|
73
102
|
/** @deprecated Use `cardStreamingMode` instead. */
|
|
74
103
|
cardRealTimeStream?: boolean;
|
|
75
104
|
/** Throttle interval in ms for card stream updates (default 1000) */
|
|
76
105
|
cardStreamInterval?: number;
|
|
106
|
+
/** Live "task in progress" block on AI cards for long-running tasks.
|
|
107
|
+
* `true` forces it on, `false` forces it off; when unset it is on unless
|
|
108
|
+
* `cardStreamingMode` is explicitly `"off"`. */
|
|
109
|
+
cardTaskProgress?: boolean;
|
|
110
|
+
/** How stage/step changes reach the progress block. `heartbeat` (default)
|
|
111
|
+
* keeps the documented "once on appearance, then once per 30s" budget;
|
|
112
|
+
* `interval` pushes on every correlated tool event, throttled by
|
|
113
|
+
* `cardStreamInterval`, trading card updates for a fresher stage label. */
|
|
114
|
+
cardTaskProgressRefresh?: CardTaskProgressRefresh;
|
|
77
115
|
/** AICard degrade duration in milliseconds after trigger errors (default 30m) */
|
|
78
116
|
aicardDegradeMs?: number;
|
|
79
117
|
/** Enable local learning loop (events/reflections/session notes/global rules) */
|
|
@@ -95,6 +133,8 @@ export interface DingTalkConfig extends OpenClawConfig {
|
|
|
95
133
|
tokens?: boolean;
|
|
96
134
|
dapiUsage?: boolean;
|
|
97
135
|
};
|
|
136
|
+
/** Gateway RPC capability gates and allowlists (docs RPCs + proactive-send RPCs). Named `gatewayCapabilities` because host `OpenClawConfig` already owns `gateway` and `tools`, and a bare `capabilities` key would collide with this plugin's channel capabilities metadata. */
|
|
137
|
+
gatewayCapabilities?: DingTalkGatewayCapabilitiesConfig;
|
|
98
138
|
}
|
|
99
139
|
/**
|
|
100
140
|
* Multi-account DingTalk configuration wrapper
|
|
@@ -150,10 +190,23 @@ export interface DingTalkChannelConfig {
|
|
|
150
190
|
* - answer: stream answer text
|
|
151
191
|
* - all: stream answer + reasoning text */
|
|
152
192
|
cardStreamingMode?: CardStreamingMode;
|
|
193
|
+
/** Internal derived flag, not a user-facing config key: whether
|
|
194
|
+
* `cardStreamingMode` came from an explicit user setting instead of the
|
|
195
|
+
* runtime default. Written by config normalization only. */
|
|
196
|
+
cardStreamingModeConfigured?: boolean;
|
|
153
197
|
/** @deprecated Use `cardStreamingMode` instead. */
|
|
154
198
|
cardRealTimeStream?: boolean;
|
|
155
199
|
/** Throttle interval in ms for card stream updates (default 1000) */
|
|
156
200
|
cardStreamInterval?: number;
|
|
201
|
+
/** Live "task in progress" block on AI cards for long-running tasks.
|
|
202
|
+
* `true` forces it on, `false` forces it off; when unset it is on unless
|
|
203
|
+
* `cardStreamingMode` is explicitly `"off"`. */
|
|
204
|
+
cardTaskProgress?: boolean;
|
|
205
|
+
/** How stage/step changes reach the progress block. `heartbeat` (default)
|
|
206
|
+
* keeps the documented "once on appearance, then once per 30s" budget;
|
|
207
|
+
* `interval` pushes on every correlated tool event, throttled by
|
|
208
|
+
* `cardStreamInterval`, trading card updates for a fresher stage label. */
|
|
209
|
+
cardTaskProgressRefresh?: CardTaskProgressRefresh;
|
|
157
210
|
/** AICard degrade duration in milliseconds after trigger errors (default 30m) */
|
|
158
211
|
aicardDegradeMs?: number;
|
|
159
212
|
/** Enable local learning loop (events/reflections/session notes/global rules) */
|
|
@@ -166,6 +219,8 @@ export interface DingTalkChannelConfig {
|
|
|
166
219
|
convertMarkdownTables?: boolean;
|
|
167
220
|
/** @mention the sender after card finalization in group chats; value is the message text */
|
|
168
221
|
cardAtSender?: string;
|
|
222
|
+
/** Gateway RPC capability gates and allowlists (docs RPCs + proactive-send RPCs). Named `gatewayCapabilities` because host `OpenClawConfig` already owns `gateway` and `tools`, and a bare `capabilities` key would collide with this plugin's channel capabilities metadata. */
|
|
223
|
+
gatewayCapabilities?: DingTalkGatewayCapabilitiesConfig;
|
|
169
224
|
}
|
|
170
225
|
/**
|
|
171
226
|
* DingTalk token info for caching
|
|
@@ -211,6 +266,16 @@ export interface DocInfo {
|
|
|
211
266
|
creatorId?: string;
|
|
212
267
|
updatedAt?: number | string;
|
|
213
268
|
}
|
|
269
|
+
/**
|
|
270
|
+
* Recursive element node of an interactiveCard `cardContent` payload.
|
|
271
|
+
* Real DingTalk quote callbacks carry card text as nested element trees
|
|
272
|
+
* (e.g. LIST -> RICHTEXT -> TEXT nodes) rather than a flat `text` field.
|
|
273
|
+
*/
|
|
274
|
+
export interface DingTalkCardContentNode {
|
|
275
|
+
elementType?: string;
|
|
276
|
+
value?: string;
|
|
277
|
+
children?: DingTalkCardContentNode[];
|
|
278
|
+
}
|
|
214
279
|
/**
|
|
215
280
|
* DingTalk incoming message (Stream mode)
|
|
216
281
|
*/
|
|
@@ -236,9 +301,13 @@ export interface DingTalkInboundMessage {
|
|
|
236
301
|
createdAt?: number;
|
|
237
302
|
content?: {
|
|
238
303
|
text?: string;
|
|
304
|
+
/** Quoted text message body in real payloads (`msgType: "text"`). */
|
|
305
|
+
content?: string;
|
|
239
306
|
downloadCode?: string;
|
|
240
307
|
fileName?: string;
|
|
241
308
|
biz_custom_action_url?: string;
|
|
309
|
+
/** interactiveCard quoted content as nested element tree. */
|
|
310
|
+
cardContent?: DingTalkCardContentNode[];
|
|
242
311
|
richText?: Array<{
|
|
243
312
|
msgType?: string;
|
|
244
313
|
type?: string;
|
|
@@ -386,7 +455,11 @@ export interface SendMessageOptions {
|
|
|
386
455
|
/** Force markdown/text delivery even when messageType is "card". Bypasses card
|
|
387
456
|
* creation while preserving journal writes and other side-effects. */
|
|
388
457
|
forceMarkdown?: boolean;
|
|
389
|
-
/**
|
|
458
|
+
/**
|
|
459
|
+
* Host-provided allowlist of local media roots. When set, caller-supplied
|
|
460
|
+
* host paths whose canonical location is outside these roots are resolved
|
|
461
|
+
* through the runtime media bridge instead of being read directly.
|
|
462
|
+
*/
|
|
390
463
|
mediaLocalRoots?: string[];
|
|
391
464
|
}
|
|
392
465
|
export interface DingTalkTrackingMetadata {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as dns from "node:dns";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as net from "node:net";
|
|
4
|
-
import type { Logger, RetryOptions } from "
|
|
4
|
+
import type { Logger, RetryOptions } from "../platform/types";
|
|
5
5
|
type PluginDebugLogParams = {
|
|
6
6
|
accountId: string;
|
|
7
7
|
storePath?: string;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Matches @mentions to agent IDs based on name and id fields in agents.list config.
|
|
5
5
|
*/
|
|
6
6
|
import type { OpenClawConfig } from "openclaw/plugin-sdk/core";
|
|
7
|
-
import type { AtMention, AgentNameMatch } from "../types";
|
|
7
|
+
import type { AtMention, AgentNameMatch } from "../platform/types";
|
|
8
8
|
interface AgentConfig {
|
|
9
9
|
id: string;
|
|
10
10
|
name?: string;
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* (channel + accountId + peer), not content-based dynamic routing.
|
|
8
8
|
*/
|
|
9
9
|
import type { OpenClawConfig } from "openclaw/plugin-sdk/core";
|
|
10
|
-
import { getDingTalkRuntime } from "../runtime";
|
|
11
|
-
import type { AgentNameMatch, DingTalkConfig, DingTalkInboundMessage, HandleDingTalkMessageParams, Logger, MessageContent, ResolvedDingTalkRoute } from "../types";
|
|
12
|
-
import type { ResolvedDingTalkSessionPeer } from "
|
|
10
|
+
import { getDingTalkRuntime } from "../platform/runtime";
|
|
11
|
+
import type { AgentNameMatch, DingTalkConfig, DingTalkInboundMessage, HandleDingTalkMessageParams, Logger, MessageContent, ResolvedDingTalkRoute } from "../platform/types";
|
|
12
|
+
import type { ResolvedDingTalkSessionPeer } from "./session-routing";
|
|
13
13
|
export declare class HostRoutingHelperUnavailableError extends Error {
|
|
14
14
|
constructor(message?: string);
|
|
15
15
|
}
|
package/index.ts
CHANGED
|
@@ -4,26 +4,106 @@ import {
|
|
|
4
4
|
type OpenClawPluginDefinition,
|
|
5
5
|
} from "openclaw/plugin-sdk/core";
|
|
6
6
|
import { readStringParam } from "openclaw/plugin-sdk/param-readers";
|
|
7
|
-
import { getAccessToken } from "./src/auth";
|
|
8
7
|
import { registerDingTalkAskUserQuestionTool } from "./src/card/ask-user-question";
|
|
8
|
+
import { accumulateUsage } from "./src/card/run-usage-store";
|
|
9
9
|
import { dingtalkPlugin } from "./src/channel";
|
|
10
|
-
import { getConfig, listDingTalkAccountIds, resolveDingTalkAccount } from "./src/config";
|
|
11
10
|
import {
|
|
12
11
|
appendToDoc,
|
|
13
12
|
createDoc,
|
|
14
13
|
DocCreateAppendError,
|
|
15
14
|
listDocs,
|
|
16
15
|
searchDocs,
|
|
17
|
-
} from "./src/docs-service";
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
16
|
+
} from "./src/gateway/docs-service";
|
|
17
|
+
import { sendMessage } from "./src/messaging/send-service";
|
|
18
|
+
import { getAccessToken } from "./src/platform/auth";
|
|
19
|
+
import {
|
|
20
|
+
checkDocsGatewayCapability,
|
|
21
|
+
checkProactiveSendGatewayCapability,
|
|
22
|
+
getConfig,
|
|
23
|
+
listDingTalkAccountIds,
|
|
24
|
+
PROACTIVE_SEND_GATE_DISABLED_REASON,
|
|
25
|
+
resolveDingTalkAccount,
|
|
26
|
+
resolveGatewayCapabilityConfig,
|
|
27
|
+
} from "./src/platform/config";
|
|
28
|
+
import { setDingTalkRuntime } from "./src/platform/runtime";
|
|
21
29
|
|
|
22
30
|
type GatewayMethodContext = Pick<
|
|
23
31
|
Parameters<Parameters<OpenClawPluginApi["registerGatewayMethod"]>[1]>[0],
|
|
24
32
|
"context" | "params" | "respond"
|
|
25
33
|
>;
|
|
26
34
|
|
|
35
|
+
type GatewayMethodArgs = Parameters<Parameters<OpenClawPluginApi["registerGatewayMethod"]>[1]>[0];
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Respond with a capability denial for a Gateway RPC call.
|
|
39
|
+
* Logged under `[DingTalk][GatewayRPC][Denied]` for fast audit diagnosis.
|
|
40
|
+
*/
|
|
41
|
+
function denyGatewayCapability(
|
|
42
|
+
api: OpenClawPluginApi,
|
|
43
|
+
method: string,
|
|
44
|
+
reason: string,
|
|
45
|
+
respond: GatewayMethodContext["respond"],
|
|
46
|
+
): ReturnType<GatewayMethodContext["respond"]> {
|
|
47
|
+
api.logger?.warn?.(`[DingTalk][GatewayRPC][Denied] ${method}: ${reason}`);
|
|
48
|
+
return respond(false, { error: reason });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Wrap a docs Gateway RPC handler with the `gatewayCapabilities.tools.docs` capability gate
|
|
53
|
+
* and the optional `gatewayCapabilities.docs.allowedSpaceIds` allowlist (Issue #608, 问题 3).
|
|
54
|
+
* `dingtalk.docs.*` and `dingtalk-connector.docs.*` aliases share handlers, so
|
|
55
|
+
* the gate automatically applies to both namespaces.
|
|
56
|
+
*/
|
|
57
|
+
function withDocsGatewayCapability(
|
|
58
|
+
api: OpenClawPluginApi,
|
|
59
|
+
method: string,
|
|
60
|
+
handler: (args: GatewayMethodArgs) => Promise<void>,
|
|
61
|
+
): (args: GatewayMethodArgs) => Promise<void> {
|
|
62
|
+
return async (args: GatewayMethodArgs) => {
|
|
63
|
+
const { respond, params } = args;
|
|
64
|
+
const accountId = readStringParam(params, "accountId");
|
|
65
|
+
const caps = resolveGatewayCapabilityConfig(api.config, accountId ?? undefined);
|
|
66
|
+
// `checkDocsGatewayCapability` evaluates the capability switch first, so a
|
|
67
|
+
// disabled tool answers with a structured deny before any method params
|
|
68
|
+
// (all optional for docs RPCs) are inspected.
|
|
69
|
+
const spaceId = readStringParam(params, "spaceId") ?? undefined;
|
|
70
|
+
const denial = checkDocsGatewayCapability(caps, spaceId);
|
|
71
|
+
if (denial) {
|
|
72
|
+
return denyGatewayCapability(api, method, denial, respond);
|
|
73
|
+
}
|
|
74
|
+
return handler(args);
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Wrap a proactive-send Gateway RPC handler with the `gatewayCapabilities.tools.proactiveSend`
|
|
80
|
+
* capability gate and the optional `gatewayCapabilities.send.allowedTargets` allowlist
|
|
81
|
+
* (Issue #608, 问题 3).
|
|
82
|
+
*/
|
|
83
|
+
function withProactiveSendGatewayCapability(
|
|
84
|
+
api: OpenClawPluginApi,
|
|
85
|
+
method: string,
|
|
86
|
+
resolveTarget: (params: Record<string, unknown>) => string | undefined,
|
|
87
|
+
handler: (args: GatewayMethodArgs, target: string) => Promise<void>,
|
|
88
|
+
): (args: GatewayMethodArgs) => Promise<void> {
|
|
89
|
+
return async (args: GatewayMethodArgs) => {
|
|
90
|
+
const { respond, params } = args;
|
|
91
|
+
const accountId = readStringParam(params, "accountId");
|
|
92
|
+
const caps = resolveGatewayCapabilityConfig(api.config, accountId ?? undefined);
|
|
93
|
+
// Fast-path the capability switch before resolving required params so a
|
|
94
|
+
// disabled tool answers with a structured deny rather than a param error.
|
|
95
|
+
if (!caps.proactiveSendEnabled) {
|
|
96
|
+
return denyGatewayCapability(api, method, PROACTIVE_SEND_GATE_DISABLED_REASON, respond);
|
|
97
|
+
}
|
|
98
|
+
const target = resolveTarget(params) ?? "";
|
|
99
|
+
const denial = checkProactiveSendGatewayCapability(caps, target);
|
|
100
|
+
if (denial) {
|
|
101
|
+
return denyGatewayCapability(api, method, denial, respond);
|
|
102
|
+
}
|
|
103
|
+
return handler(args, target);
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
27
107
|
/**
|
|
28
108
|
* Register the canonical OpenClaw DingTalk docs RPC namespace.
|
|
29
109
|
*
|
|
@@ -93,14 +173,38 @@ function registerDingTalkDocsGatewayMethods(api: OpenClawPluginApi): void {
|
|
|
93
173
|
return respond(true, { docs });
|
|
94
174
|
};
|
|
95
175
|
|
|
96
|
-
api.registerGatewayMethod(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
api.registerGatewayMethod(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
176
|
+
api.registerGatewayMethod(
|
|
177
|
+
"dingtalk.docs.create",
|
|
178
|
+
withDocsGatewayCapability(api, "dingtalk.docs.create", createHandler),
|
|
179
|
+
);
|
|
180
|
+
api.registerGatewayMethod(
|
|
181
|
+
"dingtalk.docs.append",
|
|
182
|
+
withDocsGatewayCapability(api, "dingtalk.docs.append", appendHandler),
|
|
183
|
+
);
|
|
184
|
+
api.registerGatewayMethod(
|
|
185
|
+
"dingtalk.docs.search",
|
|
186
|
+
withDocsGatewayCapability(api, "dingtalk.docs.search", searchHandler),
|
|
187
|
+
);
|
|
188
|
+
api.registerGatewayMethod(
|
|
189
|
+
"dingtalk.docs.list",
|
|
190
|
+
withDocsGatewayCapability(api, "dingtalk.docs.list", listHandler),
|
|
191
|
+
);
|
|
192
|
+
api.registerGatewayMethod(
|
|
193
|
+
"dingtalk-connector.docs.create",
|
|
194
|
+
withDocsGatewayCapability(api, "dingtalk-connector.docs.create", createHandler),
|
|
195
|
+
);
|
|
196
|
+
api.registerGatewayMethod(
|
|
197
|
+
"dingtalk-connector.docs.append",
|
|
198
|
+
withDocsGatewayCapability(api, "dingtalk-connector.docs.append", appendHandler),
|
|
199
|
+
);
|
|
200
|
+
api.registerGatewayMethod(
|
|
201
|
+
"dingtalk-connector.docs.search",
|
|
202
|
+
withDocsGatewayCapability(api, "dingtalk-connector.docs.search", searchHandler),
|
|
203
|
+
);
|
|
204
|
+
api.registerGatewayMethod(
|
|
205
|
+
"dingtalk-connector.docs.list",
|
|
206
|
+
withDocsGatewayCapability(api, "dingtalk-connector.docs.list", listHandler),
|
|
207
|
+
);
|
|
104
208
|
}
|
|
105
209
|
|
|
106
210
|
function getContentParam(params: Record<string, unknown>): string | undefined {
|
|
@@ -176,68 +280,88 @@ async function sendGatewayMessage(params: {
|
|
|
176
280
|
function registerDingTalkConnectorCompatibilityGatewayMethods(api: OpenClawPluginApi): void {
|
|
177
281
|
api.registerGatewayMethod(
|
|
178
282
|
"dingtalk-connector.sendToUser",
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
return
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
283
|
+
withProactiveSendGatewayCapability(
|
|
284
|
+
api,
|
|
285
|
+
"dingtalk-connector.sendToUser",
|
|
286
|
+
(params) => {
|
|
287
|
+
const userId = readStringParam(params, "userId", { required: true });
|
|
288
|
+
return userId ? `user:${userId}` : undefined;
|
|
289
|
+
},
|
|
290
|
+
async ({ context, respond, params }, target) => {
|
|
291
|
+
const accountId = readStringParam(params, "accountId");
|
|
292
|
+
const content = getContentParam(params);
|
|
293
|
+
if (!content) {
|
|
294
|
+
return respond(false, { error: "content or message is required" });
|
|
295
|
+
}
|
|
296
|
+
return sendGatewayMessage({
|
|
297
|
+
api,
|
|
298
|
+
respond,
|
|
299
|
+
accountId: accountId ?? undefined,
|
|
300
|
+
target,
|
|
301
|
+
content,
|
|
302
|
+
storePath: context?.cronStorePath,
|
|
303
|
+
useAICard: params.useAICard,
|
|
304
|
+
});
|
|
305
|
+
},
|
|
306
|
+
),
|
|
196
307
|
);
|
|
197
308
|
|
|
198
309
|
api.registerGatewayMethod(
|
|
199
310
|
"dingtalk-connector.sendToGroup",
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
content
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
311
|
+
withProactiveSendGatewayCapability(
|
|
312
|
+
api,
|
|
313
|
+
"dingtalk-connector.sendToGroup",
|
|
314
|
+
(params) => {
|
|
315
|
+
const openConversationId = readStringParam(params, "openConversationId", {
|
|
316
|
+
required: true,
|
|
317
|
+
});
|
|
318
|
+
return openConversationId ? `group:${openConversationId}` : undefined;
|
|
319
|
+
},
|
|
320
|
+
async ({ context, respond, params }, target) => {
|
|
321
|
+
const accountId = readStringParam(params, "accountId");
|
|
322
|
+
const content = getContentParam(params);
|
|
323
|
+
if (!content) {
|
|
324
|
+
return respond(false, { error: "content or message is required" });
|
|
325
|
+
}
|
|
326
|
+
return sendGatewayMessage({
|
|
327
|
+
api,
|
|
328
|
+
respond,
|
|
329
|
+
accountId: accountId ?? undefined,
|
|
330
|
+
target,
|
|
331
|
+
content,
|
|
332
|
+
storePath: context?.cronStorePath,
|
|
333
|
+
useAICard: params.useAICard,
|
|
334
|
+
});
|
|
335
|
+
},
|
|
336
|
+
),
|
|
217
337
|
);
|
|
218
338
|
|
|
219
339
|
api.registerGatewayMethod(
|
|
220
340
|
"dingtalk-connector.send",
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
341
|
+
withProactiveSendGatewayCapability(
|
|
342
|
+
api,
|
|
343
|
+
"dingtalk-connector.send",
|
|
344
|
+
(params) => readStringParam(params, "target", { required: true }) ?? undefined,
|
|
345
|
+
async ({ context, respond, params }, target) => {
|
|
346
|
+
const accountId = readStringParam(params, "accountId");
|
|
347
|
+
const content = getContentParam(params);
|
|
348
|
+
if (!content) {
|
|
349
|
+
return respond(false, { error: "content or message is required" });
|
|
350
|
+
}
|
|
351
|
+
if (!isConnectorSendTarget(target)) {
|
|
352
|
+
return respond(false, { error: "target must start with user: or group:" });
|
|
353
|
+
}
|
|
354
|
+
return sendGatewayMessage({
|
|
355
|
+
api,
|
|
356
|
+
respond,
|
|
357
|
+
accountId: accountId ?? undefined,
|
|
358
|
+
target,
|
|
359
|
+
content,
|
|
360
|
+
storePath: context?.cronStorePath,
|
|
361
|
+
useAICard: params.useAICard,
|
|
362
|
+
});
|
|
363
|
+
},
|
|
364
|
+
),
|
|
241
365
|
);
|
|
242
366
|
|
|
243
367
|
api.registerGatewayMethod(
|
|
@@ -282,7 +406,7 @@ function registerDingTalkConnectorCompatibilityGatewayMethods(api: OpenClawPlugi
|
|
|
282
406
|
}
|
|
283
407
|
|
|
284
408
|
export { dingtalkPlugin } from "./src/channel";
|
|
285
|
-
export { setDingTalkRuntime } from "./src/runtime";
|
|
409
|
+
export { setDingTalkRuntime } from "./src/platform/runtime";
|
|
286
410
|
|
|
287
411
|
const dingtalkEntry = defineChannelPluginEntry({
|
|
288
412
|
id: "dingtalk",
|