@yanhaidao/wecom 2.3.4 → 2.3.10
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 +222 -335
- package/assets/03.bot.page.png +0 -0
- package/changelog/v2.3.10.md +17 -0
- package/changelog/v2.3.9.md +22 -0
- package/compat-single-account.md +34 -4
- package/index.ts +5 -5
- package/package.json +8 -7
- package/src/agent/api-client.upload.test.ts +1 -2
- package/src/agent/handler.ts +82 -9
- package/src/agent/index.ts +1 -1
- package/src/app/account-runtime.ts +245 -0
- package/src/app/bootstrap.ts +29 -0
- package/src/app/index.ts +31 -0
- package/src/capability/agent/delivery-service.ts +79 -0
- package/src/capability/agent/fallback-policy.ts +13 -0
- package/src/capability/agent/index.ts +3 -0
- package/src/capability/agent/ingress-service.ts +38 -0
- package/src/capability/bot/dispatch-config.ts +47 -0
- package/src/capability/bot/fallback-delivery.ts +178 -0
- package/src/capability/bot/index.ts +1 -0
- package/src/capability/bot/local-path-delivery.ts +215 -0
- package/src/capability/bot/service.ts +56 -0
- package/src/capability/bot/stream-delivery.ts +379 -0
- package/src/capability/bot/stream-finalizer.ts +120 -0
- package/src/capability/bot/stream-orchestrator.ts +352 -0
- package/src/capability/bot/types.ts +8 -0
- package/src/capability/index.ts +2 -0
- package/src/channel.lifecycle.test.ts +9 -6
- package/src/channel.meta.test.ts +12 -0
- package/src/channel.ts +48 -21
- package/src/config/accounts.resolve.test.ts +39 -2
- package/src/config/accounts.ts +242 -280
- package/src/config/derived-paths.test.ts +111 -0
- package/src/config/derived-paths.ts +41 -0
- package/src/config/index.ts +10 -12
- package/src/config/runtime-config.ts +46 -0
- package/src/config/schema.ts +65 -103
- package/src/domain/models.ts +7 -0
- package/src/domain/policies.ts +36 -0
- package/src/dynamic-agent.ts +6 -0
- package/src/gateway-monitor.ts +43 -93
- package/src/http.ts +23 -2
- package/src/monitor/limits.ts +7 -0
- package/src/monitor/state.ts +28 -508
- package/src/monitor.active.test.ts +3 -3
- package/src/monitor.integration.test.ts +0 -1
- package/src/monitor.ts +64 -2603
- package/src/monitor.webhook.test.ts +127 -42
- package/src/observability/audit-log.ts +48 -0
- package/src/observability/legacy-operational-event-store.ts +36 -0
- package/src/observability/raw-envelope-log.ts +28 -0
- package/src/observability/status-registry.ts +13 -0
- package/src/observability/transport-session-view.ts +14 -0
- package/src/onboarding.test.ts +268 -0
- package/src/onboarding.ts +95 -78
- package/src/outbound.test.ts +5 -5
- package/src/outbound.ts +18 -66
- package/src/runtime/dispatcher.ts +52 -0
- package/src/runtime/index.ts +4 -0
- package/src/runtime/outbound-intent.ts +4 -0
- package/src/runtime/reply-orchestrator.test.ts +38 -0
- package/src/runtime/reply-orchestrator.ts +55 -0
- package/src/runtime/routing-bridge.ts +19 -0
- package/src/runtime/session-manager.ts +76 -0
- package/src/runtime.ts +7 -14
- package/src/shared/command-auth.ts +1 -17
- package/src/shared/media-service.ts +36 -0
- package/src/shared/media-types.ts +5 -0
- package/src/store/active-reply-store.ts +42 -0
- package/src/store/interfaces.ts +11 -0
- package/src/store/memory-store.ts +43 -0
- package/src/store/stream-batch-store.ts +350 -0
- package/src/target.ts +28 -0
- package/src/transport/agent-api/client.ts +44 -0
- package/src/transport/agent-api/core.ts +367 -0
- package/src/transport/agent-api/delivery.ts +41 -0
- package/src/transport/agent-api/media-upload.ts +11 -0
- package/src/transport/agent-api/reply.ts +39 -0
- package/src/transport/agent-callback/http-handler.ts +47 -0
- package/src/transport/agent-callback/inbound.ts +5 -0
- package/src/transport/agent-callback/reply.ts +13 -0
- package/src/transport/agent-callback/request-handler.ts +244 -0
- package/src/transport/agent-callback/session.ts +23 -0
- package/src/transport/bot-webhook/active-reply.ts +36 -0
- package/src/transport/bot-webhook/http-handler.ts +48 -0
- package/src/transport/bot-webhook/inbound-normalizer.ts +371 -0
- package/src/transport/bot-webhook/inbound.ts +5 -0
- package/src/transport/bot-webhook/message-shape.ts +89 -0
- package/src/transport/bot-webhook/protocol.ts +148 -0
- package/src/transport/bot-webhook/reply.ts +15 -0
- package/src/transport/bot-webhook/request-handler.ts +394 -0
- package/src/transport/bot-webhook/session.ts +23 -0
- package/src/transport/bot-ws/inbound.ts +108 -0
- package/src/transport/bot-ws/reply.ts +63 -0
- package/src/transport/bot-ws/sdk-adapter.ts +180 -0
- package/src/transport/bot-ws/session.ts +28 -0
- package/src/transport/http/common.ts +109 -0
- package/src/transport/http/registry.ts +92 -0
- package/src/transport/http/request-handler.ts +84 -0
- package/src/transport/index.ts +14 -0
- package/src/types/account.ts +56 -91
- package/src/types/config.ts +64 -112
- package/src/types/constants.ts +20 -35
- package/src/types/events.ts +21 -0
- package/src/types/index.ts +14 -38
- package/src/types/legacy-stream.ts +50 -0
- package/src/types/runtime-context.ts +28 -0
- package/src/types/runtime.ts +161 -0
- package/src/agent/api-client.ts +0 -383
- package/src/monitor/types.ts +0 -136
package/src/gateway-monitor.ts
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ChannelGatewayContext,
|
|
3
3
|
OpenClawConfig,
|
|
4
|
-
PluginRuntime,
|
|
5
4
|
} from "openclaw/plugin-sdk";
|
|
6
5
|
|
|
7
6
|
import {
|
|
8
|
-
detectMode,
|
|
9
7
|
listWecomAccountIds,
|
|
8
|
+
resolveDerivedPathSummary,
|
|
10
9
|
resolveWecomAccount,
|
|
11
10
|
resolveWecomAccountConflict,
|
|
12
11
|
} from "./config/index.js";
|
|
13
|
-
import {
|
|
12
|
+
import { createAccountRuntime } from "./app/bootstrap.js";
|
|
13
|
+
import { registerAccountRuntime, unregisterAccountRuntime } from "./app/index.js";
|
|
14
14
|
import type { ResolvedWecomAccount, WecomConfig } from "./types/index.js";
|
|
15
|
-
import {
|
|
15
|
+
import { WecomBotCapabilityService } from "./capability/bot/index.js";
|
|
16
|
+
import { WecomAgentIngressService } from "./capability/agent/index.js";
|
|
17
|
+
import type { WecomRuntimeEnv } from "./types/runtime-context.js";
|
|
16
18
|
|
|
17
19
|
type AccountRouteRegistryItem = {
|
|
18
20
|
botPaths: string[];
|
|
@@ -75,30 +77,6 @@ function waitForAbortSignal(abortSignal: AbortSignal): Promise<void> {
|
|
|
75
77
|
});
|
|
76
78
|
}
|
|
77
79
|
|
|
78
|
-
function uniquePaths(paths: string[]): string[] {
|
|
79
|
-
return Array.from(new Set(paths.map((path) => path.trim()).filter(Boolean)));
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function resolveBotRegistrationPaths(params: { accountId: string; matrixMode: boolean }): string[] {
|
|
83
|
-
if (params.matrixMode) {
|
|
84
|
-
return uniquePaths([
|
|
85
|
-
`${WEBHOOK_PATHS.BOT_PLUGIN}/${params.accountId}`,
|
|
86
|
-
`${WEBHOOK_PATHS.BOT_ALT}/${params.accountId}`,
|
|
87
|
-
]);
|
|
88
|
-
}
|
|
89
|
-
return uniquePaths([WEBHOOK_PATHS.BOT_PLUGIN, WEBHOOK_PATHS.BOT, WEBHOOK_PATHS.BOT_ALT]);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function resolveAgentRegistrationPaths(params: { accountId: string; matrixMode: boolean }): string[] {
|
|
93
|
-
if (params.matrixMode) {
|
|
94
|
-
return uniquePaths([
|
|
95
|
-
`${WEBHOOK_PATHS.AGENT_PLUGIN}/${params.accountId}`,
|
|
96
|
-
`${WEBHOOK_PATHS.AGENT}/${params.accountId}`,
|
|
97
|
-
]);
|
|
98
|
-
}
|
|
99
|
-
return uniquePaths([WEBHOOK_PATHS.AGENT_PLUGIN, WEBHOOK_PATHS.AGENT]);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
80
|
/**
|
|
103
81
|
* Keeps WeCom webhook targets registered for the account lifecycle.
|
|
104
82
|
* The promise only settles after gateway abort/reload signals shutdown.
|
|
@@ -122,29 +100,11 @@ export async function monitorWecomProvider(
|
|
|
122
100
|
});
|
|
123
101
|
throw new Error(conflict.message);
|
|
124
102
|
}
|
|
125
|
-
const mode = detectMode(cfg.channels?.wecom as WecomConfig | undefined);
|
|
126
|
-
const matrixMode = mode === "matrix";
|
|
127
103
|
const bot = account.bot;
|
|
128
104
|
const agent = account.agent;
|
|
129
105
|
const botConfigured = Boolean(bot?.configured);
|
|
130
106
|
const agentConfigured = Boolean(agent?.configured);
|
|
131
107
|
|
|
132
|
-
if (mode === "legacy" && (botConfigured || agentConfigured)) {
|
|
133
|
-
if (agentConfigured && !botConfigured) {
|
|
134
|
-
ctx.log?.warn(
|
|
135
|
-
`[${account.accountId}] 检测到仍在使用单 Agent 兼容模式。建议尽快升级为多账号模式:` +
|
|
136
|
-
`将 channels.wecom.agent 迁移到 channels.wecom.accounts.<accountId>.agent,` +
|
|
137
|
-
`并设置 channels.wecom.defaultAccount。`,
|
|
138
|
-
);
|
|
139
|
-
} else {
|
|
140
|
-
ctx.log?.warn(
|
|
141
|
-
`[${account.accountId}] 检测到仍在使用单账号兼容模式。建议尽快升级为多账号模式:` +
|
|
142
|
-
`将 channels.wecom.bot/agent 迁移到 channels.wecom.accounts.<accountId>.bot/agent,` +
|
|
143
|
-
`并设置 channels.wecom.defaultAccount。`,
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
108
|
if (!botConfigured && !agentConfigured) {
|
|
149
109
|
ctx.log?.warn(`[${account.accountId}] wecom not configured; channel is idle`);
|
|
150
110
|
ctx.setStatus({ accountId: account.accountId, running: false, configured: false });
|
|
@@ -152,50 +112,38 @@ export async function monitorWecomProvider(
|
|
|
152
112
|
return;
|
|
153
113
|
}
|
|
154
114
|
|
|
155
|
-
const
|
|
115
|
+
const accountRuntime = createAccountRuntime(ctx);
|
|
116
|
+
registerAccountRuntime(accountRuntime);
|
|
156
117
|
const botPaths: string[] = [];
|
|
157
118
|
const agentPaths: string[] = [];
|
|
119
|
+
const runtimeEnv: WecomRuntimeEnv = {
|
|
120
|
+
log: (message) => ctx.log?.info(message),
|
|
121
|
+
error: (message) => ctx.log?.error(message),
|
|
122
|
+
};
|
|
123
|
+
const botService = new WecomBotCapabilityService(
|
|
124
|
+
accountRuntime,
|
|
125
|
+
cfg,
|
|
126
|
+
runtimeEnv,
|
|
127
|
+
);
|
|
128
|
+
const agentIngress = new WecomAgentIngressService(accountRuntime, cfg, runtimeEnv);
|
|
158
129
|
try {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
config: cfg,
|
|
169
|
-
runtime: ctx.runtime,
|
|
170
|
-
// The HTTP handler resolves the active PluginRuntime via getWecomRuntime().
|
|
171
|
-
// The stored target only needs to be decrypt/verify-capable.
|
|
172
|
-
core: {} as PluginRuntime,
|
|
173
|
-
path,
|
|
174
|
-
statusSink: (patch) => ctx.setStatus({ accountId: ctx.accountId, ...patch }),
|
|
175
|
-
}),
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
botPaths.push(...paths);
|
|
179
|
-
ctx.log?.info(`[${account.accountId}] wecom bot webhook registered at ${paths.join(", ")}`);
|
|
130
|
+
ctx.log?.info(
|
|
131
|
+
`[${account.accountId}] wecom runtime start bot=${bot?.primaryTransport ?? "disabled"} agent=${agentConfigured ? "callback/api" : "disabled"}`,
|
|
132
|
+
);
|
|
133
|
+
const botRegistration = botService.start();
|
|
134
|
+
if (botRegistration) {
|
|
135
|
+
botPaths.push(...botRegistration.descriptors);
|
|
136
|
+
ctx.log?.info(
|
|
137
|
+
`[${account.accountId}] wecom bot ${botRegistration.transport} started: ${botRegistration.descriptors.join(", ")}`,
|
|
138
|
+
);
|
|
180
139
|
}
|
|
181
140
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
unregisters.push(
|
|
189
|
-
registerAgentWebhookTarget({
|
|
190
|
-
agent,
|
|
191
|
-
config: cfg,
|
|
192
|
-
runtime: ctx.runtime,
|
|
193
|
-
path,
|
|
194
|
-
}),
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
agentPaths.push(...paths);
|
|
198
|
-
ctx.log?.info(`[${account.accountId}] wecom agent webhook registered at ${paths.join(", ")}`);
|
|
141
|
+
const agentRegistration = agentIngress.start();
|
|
142
|
+
if (agentRegistration) {
|
|
143
|
+
agentPaths.push(...agentRegistration.descriptors);
|
|
144
|
+
ctx.log?.info(
|
|
145
|
+
`[${account.accountId}] wecom agent ${agentRegistration.transport} started: ${agentRegistration.descriptors.join(", ")}`,
|
|
146
|
+
);
|
|
199
147
|
}
|
|
200
148
|
|
|
201
149
|
accountRouteRegistry.set(account.accountId, { botPaths, agentPaths });
|
|
@@ -207,25 +155,27 @@ export async function monitorWecomProvider(
|
|
|
207
155
|
}
|
|
208
156
|
|
|
209
157
|
ctx.setStatus({
|
|
210
|
-
accountId: account.accountId,
|
|
211
158
|
running: true,
|
|
212
159
|
configured: true,
|
|
213
|
-
webhookPath:
|
|
214
|
-
? (botPaths[0] ?? WEBHOOK_PATHS.BOT_PLUGIN)
|
|
215
|
-
: (agentPaths[0] ?? WEBHOOK_PATHS.AGENT_PLUGIN),
|
|
160
|
+
webhookPath: botPaths[0] ?? agentPaths[0] ?? null,
|
|
216
161
|
lastStartAt: Date.now(),
|
|
162
|
+
...accountRuntime.buildRuntimeStatus(),
|
|
217
163
|
});
|
|
164
|
+
ctx.log?.info(
|
|
165
|
+
`[${account.accountId}] runtime status health=${accountRuntime.buildRuntimeStatus().health} transports=${(accountRuntime.buildRuntimeStatus().transportSessions ?? []).join(" | ") || "none"}`,
|
|
166
|
+
);
|
|
218
167
|
|
|
219
168
|
await waitForAbortSignal(ctx.abortSignal);
|
|
220
169
|
} finally {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
170
|
+
botService.stop();
|
|
171
|
+
agentIngress.stop();
|
|
224
172
|
accountRouteRegistry.delete(account.accountId);
|
|
173
|
+
unregisterAccountRuntime(account.accountId);
|
|
225
174
|
ctx.setStatus({
|
|
226
|
-
accountId: account.accountId,
|
|
227
175
|
running: false,
|
|
228
176
|
lastStopAt: Date.now(),
|
|
177
|
+
...accountRuntime.buildRuntimeStatus(),
|
|
229
178
|
});
|
|
179
|
+
ctx.log?.info(`[${account.accountId}] wecom runtime stopped`);
|
|
230
180
|
}
|
|
231
181
|
}
|
package/src/http.ts
CHANGED
|
@@ -18,6 +18,15 @@ function getProxyDispatcher(proxyUrl: string): ProxyDispatcher {
|
|
|
18
18
|
return created;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
function summarizeHttpTarget(input: string | URL): string {
|
|
22
|
+
try {
|
|
23
|
+
const url = typeof input === "string" ? new URL(input) : input;
|
|
24
|
+
return `${url.origin}${url.pathname}`;
|
|
25
|
+
} catch {
|
|
26
|
+
return String(input);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
21
30
|
function mergeAbortSignal(params: {
|
|
22
31
|
signal?: AbortSignal;
|
|
23
32
|
timeoutMs?: number;
|
|
@@ -54,6 +63,9 @@ export type WecomHttpOptions = {
|
|
|
54
63
|
export async function wecomFetch(input: string | URL, init?: RequestInit, opts?: WecomHttpOptions): Promise<Response> {
|
|
55
64
|
const proxyUrl = opts?.proxyUrl?.trim() ?? "";
|
|
56
65
|
const dispatcher = proxyUrl ? getProxyDispatcher(proxyUrl) : undefined;
|
|
66
|
+
const startedAt = Date.now();
|
|
67
|
+
const method = (init?.method ?? "GET").toUpperCase();
|
|
68
|
+
const target = summarizeHttpTarget(input);
|
|
57
69
|
|
|
58
70
|
const initSignal = init?.signal ?? undefined;
|
|
59
71
|
const signal = mergeAbortSignal({ signal: opts?.signal ?? initSignal, timeoutMs: opts?.timeoutMs });
|
|
@@ -71,11 +83,20 @@ export async function wecomFetch(input: string | URL, init?: RequestInit, opts?:
|
|
|
71
83
|
};
|
|
72
84
|
|
|
73
85
|
try {
|
|
74
|
-
|
|
86
|
+
console.log(
|
|
87
|
+
`[wecom-http] request method=${method} target=${target} proxy=${proxyUrl || "none"} timeoutMs=${String(opts?.timeoutMs ?? "none")}`,
|
|
88
|
+
);
|
|
89
|
+
const response = await undiciFetch(input, nextInit as Parameters<typeof undiciFetch>[1]) as unknown as Response;
|
|
90
|
+
console.log(
|
|
91
|
+
`[wecom-http] response method=${method} target=${target} status=${response.status} durationMs=${Date.now() - startedAt}`,
|
|
92
|
+
);
|
|
93
|
+
return response;
|
|
75
94
|
} catch (err: unknown) {
|
|
76
95
|
if (err instanceof Error && err.name === "TypeError" && err.message === "fetch failed") {
|
|
77
96
|
const cause = (err as any).cause;
|
|
78
|
-
console.error(
|
|
97
|
+
console.error(
|
|
98
|
+
`[wecom-http] fetch failed method=${method} target=${target} durationMs=${Date.now() - startedAt} proxy=${proxyUrl || "none"}${cause ? ` cause=${String(cause)}` : ""}`,
|
|
99
|
+
);
|
|
79
100
|
}
|
|
80
101
|
throw err;
|
|
81
102
|
}
|