Skip to content

Commit 7964563

Browse files
committed
refactor: finish plugin-owned channel runtime seams
1 parent e90c1d9 commit 7964563

29 files changed

+488
-296
lines changed

extensions/discord/src/channel.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,17 @@ import {
4141
type OpenClawConfig,
4242
type ResolvedDiscordAccount,
4343
} from "openclaw/plugin-sdk/discord";
44+
import {
45+
buildAgentSessionKey,
46+
resolveThreadSessionKeys,
47+
type RoutePeer,
48+
} from "openclaw/plugin-sdk/routing";
4449
import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js";
4550
import { normalizeMessageChannel } from "../../../src/utils/message-channel.js";
46-
import { isDiscordExecApprovalClientEnabled } from "./exec-approvals.js";
51+
import {
52+
isDiscordExecApprovalClientEnabled,
53+
shouldSuppressLocalDiscordExecApprovalPrompt,
54+
} from "./exec-approvals.js";
4755
import type { DiscordProbe } from "./probe.js";
4856
import { resolveDiscordUserAllowlist } from "./resolve-users.js";
4957
import { getDiscordRuntime } from "./runtime.js";
@@ -453,6 +461,12 @@ export const discordPlugin: ChannelPlugin<ResolvedDiscordAccount> = {
453461
isDiscordExecApprovalClientEnabled({ cfg, accountId })
454462
? { kind: "enabled" }
455463
: { kind: "disabled" },
464+
shouldSuppressLocalPrompt: ({ cfg, accountId, payload }) =>
465+
shouldSuppressLocalDiscordExecApprovalPrompt({
466+
cfg,
467+
accountId,
468+
payload,
469+
}),
456470
hasConfiguredDmRoute: ({ cfg }) => hasDiscordExecApprovalDmRoute(cfg),
457471
shouldSuppressForwardingFallback: ({ cfg, target }) =>
458472
(normalizeMessageChannel(target.channel) ?? target.channel) === "discord" &&

extensions/imessage/src/channel.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
type ChannelPlugin,
2828
type ResolvedIMessageAccount,
2929
} from "openclaw/plugin-sdk/imessage";
30+
import { buildAgentSessionKey, type RoutePeer } from "openclaw/plugin-sdk/routing";
3031
import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js";
3132
import { buildPassiveProbedChannelStatusSummary } from "../../shared/channel-status-summary.js";
3233
import { getIMessageRuntime } from "./runtime.js";

extensions/signal/src/channel.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
createScopedAccountConfigAccessors,
55
collectAllowlistProviderRestrictSendersWarnings,
66
} from "openclaw/plugin-sdk/compat";
7-
import { buildAgentSessionKey, type RoutePeer } from "openclaw/plugin-sdk/core";
7+
import { buildAgentSessionKey, type RoutePeer } from "openclaw/plugin-sdk/routing";
88
import {
99
buildBaseAccountStatusSnapshot,
1010
buildBaseChannelStatusSummary,

extensions/slack/src/channel.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
buildAgentSessionKey,
1212
resolveThreadSessionKeys,
1313
type RoutePeer,
14-
} from "openclaw/plugin-sdk/core";
14+
} from "openclaw/plugin-sdk/routing";
1515
import {
1616
buildComputedAccountStatusSnapshot,
1717
buildChannelConfigSchema,

extensions/telegram/src/channel.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
buildAgentSessionKey,
1212
resolveThreadSessionKeys,
1313
type RoutePeer,
14-
} from "openclaw/plugin-sdk/core";
14+
} from "openclaw/plugin-sdk/routing";
1515
import {
1616
buildChannelConfigSchema,
1717
buildTokenChannelStatusSummary,

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@
4848
"types": "./dist/plugin-sdk/compat.d.ts",
4949
"default": "./dist/plugin-sdk/compat.js"
5050
},
51+
"./plugin-sdk/routing": {
52+
"types": "./dist/plugin-sdk/routing.d.ts",
53+
"default": "./dist/plugin-sdk/routing.js"
54+
},
5155
"./plugin-sdk/telegram": {
5256
"types": "./dist/plugin-sdk/telegram.d.ts",
5357
"default": "./dist/plugin-sdk/telegram.js"

scripts/lib/plugin-sdk-entrypoints.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"index",
33
"core",
44
"compat",
5+
"routing",
56
"telegram",
67
"discord",
78
"slack",

src/auto-reply/reply/commands-subagents/shared.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { parseDiscordTarget } from "../../../../extensions/discord/src/targets.js";
21
import { resolveStoredSubagentCapabilities } from "../../../agents/subagent-capabilities.js";
32
import type { ResolvedSubagentController } from "../../../agents/subagent-control.js";
43
import {
@@ -12,6 +11,7 @@ import {
1211
sanitizeTextContent,
1312
stripToolMessages,
1413
} from "../../../agents/tools/sessions-helpers.js";
14+
import { parseExplicitTargetForChannel } from "../../../channels/plugins/target-parsing.js";
1515
import type {
1616
SessionEntry,
1717
loadSessionStore as loadSessionStoreFn,
@@ -335,13 +335,9 @@ export function resolveDiscordChannelIdForFocus(
335335
typeof params.ctx.To === "string" ? params.ctx.To.trim() : "",
336336
].filter(Boolean);
337337
for (const candidate of toCandidates) {
338-
try {
339-
const target = parseDiscordTarget(candidate, { defaultKind: "channel" });
340-
if (target?.kind === "channel" && target.id) {
341-
return target.id;
342-
}
343-
} catch {
344-
// Ignore parse failures and try the next candidate.
338+
const target = parseExplicitTargetForChannel("discord", candidate);
339+
if (target?.chatType === "channel" && target.to) {
340+
return target.to;
345341
}
346342
}
347343
return undefined;

src/auto-reply/reply/dispatch-from-config.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import { beforeEach, describe, expect, it, vi } from "vitest";
2+
import { discordPlugin } from "../../../extensions/discord/src/channel.js";
23
import { AcpRuntimeError } from "../../acp/runtime/errors.js";
34
import type { OpenClawConfig } from "../../config/config.js";
45
import type { SessionBindingRecord } from "../../infra/outbound/session-binding-service.js";
56
import type { PluginTargetedInboundClaimOutcome } from "../../plugins/hooks.js";
7+
import { setActivePluginRegistry } from "../../plugins/runtime.js";
8+
import { createTestRegistry } from "../../test-utils/channel-plugins.js";
69
import { createInternalHookEventPayload } from "../../test-utils/internal-hook-event-payload.js";
710
import type { MsgContext } from "../templating.js";
811
import type { GetReplyOptions, ReplyPayload } from "../types.js";
@@ -252,6 +255,9 @@ async function dispatchTwiceWithFreshDispatchers(params: Omit<DispatchReplyArgs,
252255

253256
describe("dispatchReplyFromConfig", () => {
254257
beforeEach(() => {
258+
setActivePluginRegistry(
259+
createTestRegistry([{ pluginId: "discord", source: "test", plugin: discordPlugin }]),
260+
);
255261
acpManagerTesting.resetAcpSessionManagerForTests();
256262
resetInboundDedupe();
257263
mocks.routeReply.mockReset();
@@ -1295,6 +1301,11 @@ describe("dispatchReplyFromConfig", () => {
12951301
commands: {
12961302
text: false,
12971303
},
1304+
session: {
1305+
sendPolicy: {
1306+
default: "allow",
1307+
},
1308+
},
12981309
} as OpenClawConfig;
12991310
const dispatcher = createDispatcher();
13001311
const ctx = buildTestCtx({

src/auto-reply/reply/dispatch-from-config.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { shouldSuppressLocalDiscordExecApprovalPrompt } from "../../../extensions/discord/src/exec-approvals.js";
21
import { resolveSessionAgentId } from "../../agents/agent-scope.js";
2+
import { shouldSuppressLocalExecApprovalPrompt } from "../../channels/plugins/exec-approval-local.js";
33
import type { OpenClawConfig } from "../../config/config.js";
44
import {
55
loadSessionStore,
@@ -506,8 +506,8 @@ export async function dispatchReplyFromConfig(params: {
506506

507507
const resolveToolDeliveryPayload = (payload: ReplyPayload): ReplyPayload | null => {
508508
if (
509-
normalizeMessageChannel(ctx.Surface ?? ctx.Provider) === "discord" &&
510-
shouldSuppressLocalDiscordExecApprovalPrompt({
509+
shouldSuppressLocalExecApprovalPrompt({
510+
channel: normalizeMessageChannel(ctx.Surface ?? ctx.Provider),
511511
cfg,
512512
accountId: ctx.AccountId,
513513
payload,

0 commit comments

Comments
 (0)