refactor: drop channel onboarding fallback

This commit is contained in:
Peter Steinberger
2026-03-15 18:23:18 -07:00
parent 0958aea112
commit 26a8aee01c
6 changed files with 46 additions and 31 deletions

View File

@@ -1437,16 +1437,6 @@ Preferred setup split:
- `plugin.setup` owns account-id normalization, validation, and config writes.
- `plugin.setupWizard` lets the host run the common wizard flow while the channel only supplies status, credential, DM allowlist, and channel-access descriptors.
Use `plugin.onboarding` only when the host-owned setup wizard cannot express the flow and the
channel needs to fully own prompting.
Wizard precedence:
1. `plugin.setupWizard` (preferred, host-owned prompts)
2. `plugin.onboarding.configureInteractive`
3. `plugin.onboarding.configureWhenConfigured` (already-configured channel only)
4. `plugin.onboarding.configure`
`plugin.setupWizard` is best for channels that fit the shared pattern:
- one account picker driven by `plugin.config.listAccountIds`
@@ -1458,11 +1448,6 @@ Wizard precedence:
- optional DM allowlist resolution (for example `@username` -> numeric id)
- optional completion note after setup finishes
`plugin.onboarding` hooks still return the same values as before:
- `"skip"` leaves selection and account tracking unchanged.
- `{ cfg, accountId? }` applies config updates and records account selection.
### Write a new messaging channel (stepbystep)
Use this when you want a **new chat surface** (a "messaging channel"), not a model provider.

View File

@@ -1,4 +1,3 @@
import type { ChannelOnboardingAdapter } from "./onboarding-types.js";
import type { ChannelSetupWizard } from "./setup-wizard.js";
import type {
ChannelAuthAdapter,
@@ -57,8 +56,6 @@ export type ChannelPlugin<ResolvedAccount = any, Probe = unknown, Audit = unknow
};
};
reload?: { configPrefixes: string[]; noopPrefixes?: string[] };
// CLI onboarding wizard hooks for this channel.
onboarding?: ChannelOnboardingAdapter;
setupWizard?: ChannelSetupWizard;
config: ChannelConfigAdapter<ResolvedAccount>;
configSchema?: ChannelConfigSchema;

View File

@@ -472,15 +472,17 @@ describe("setupChannels", () => {
)?.accounts?.[accountId] ?? { accountId },
setAccountEnabled,
},
onboarding: {
getStatus: vi.fn(async ({ cfg }: { cfg: OpenClawConfig }) => ({
channel: "msteams",
configured: Boolean(
(cfg.channels?.msteams as { tenantId?: string } | undefined)?.tenantId,
),
statusLines: [],
selectionHint: "configured",
})),
setupWizard: {
channel: "msteams",
status: {
configuredLabel: "configured",
unconfiguredLabel: "needs setup",
resolveConfigured: ({ cfg }: { cfg: OpenClawConfig }) =>
Boolean((cfg.channels?.msteams as { tenantId?: string } | undefined)?.tenantId),
resolveStatusLines: async () => [],
resolveSelectionHint: async () => "configured",
},
credentials: [],
},
outbound: { deliveryMode: "direct" },
},

View File

@@ -5,6 +5,7 @@ import {
getChannelSetupPlugin,
listChannelSetupPlugins,
} from "../channels/plugins/setup-registry.js";
import { buildChannelOnboardingAdapterFromSetupWizard } from "../channels/plugins/setup-wizard.js";
import type { ChannelMeta, ChannelPlugin } from "../channels/plugins/types.js";
import {
formatChannelPrimerLine,
@@ -354,7 +355,14 @@ export async function setupChannels(
if (adapter) {
return adapter;
}
return scopedPluginsById.get(channel)?.onboarding;
const scopedPlugin = scopedPluginsById.get(channel);
if (!scopedPlugin?.setupWizard) {
return undefined;
}
return buildChannelOnboardingAdapterFromSetupWizard({
plugin: scopedPlugin,
wizard: scopedPlugin.setupWizard,
});
};
const preloadConfiguredExternalPlugins = () => {
// Keep onboarding memory bounded by snapshot-loading only configured external plugins.

View File

@@ -60,9 +60,6 @@ function resolveChannelOnboardingAdapter(
setupWizardAdapters.set(plugin, adapter);
return adapter;
}
if (plugin.onboarding) {
return plugin.onboarding;
}
return undefined;
}

View File

@@ -101,6 +101,12 @@ describe("plugin-sdk subpath exports", () => {
expect("resolveWhatsAppMentionStripPatterns" in whatsappSdk).toBe(false);
});
it("exports Feishu helpers", async () => {
const feishuSdk = await import("openclaw/plugin-sdk/feishu");
expect(typeof feishuSdk.feishuSetupWizard).toBe("object");
expect(typeof feishuSdk.feishuSetupAdapter).toBe("object");
});
it("exports LINE helpers", () => {
expect(typeof lineSdk.processLineMessage).toBe("function");
expect(typeof lineSdk.createInfoCard).toBe("function");
@@ -109,6 +115,8 @@ describe("plugin-sdk subpath exports", () => {
it("exports Microsoft Teams helpers", () => {
expect(typeof msteamsSdk.resolveControlCommandGate).toBe("function");
expect(typeof msteamsSdk.loadOutboundMediaFromUrl).toBe("function");
expect(typeof msteamsSdk.msteamsSetupWizard).toBe("object");
expect(typeof msteamsSdk.msteamsSetupAdapter).toBe("object");
});
it("exports Google Chat helpers", async () => {
@@ -117,6 +125,18 @@ describe("plugin-sdk subpath exports", () => {
expect(typeof googlechatSdk.googlechatSetupAdapter).toBe("object");
});
it("exports Zalo helpers", async () => {
const zaloSdk = await import("openclaw/plugin-sdk/zalo");
expect(typeof zaloSdk.zaloSetupWizard).toBe("object");
expect(typeof zaloSdk.zaloSetupAdapter).toBe("object");
});
it("exports Zalouser helpers", async () => {
const zalouserSdk = await import("openclaw/plugin-sdk/zalouser");
expect(typeof zalouserSdk.zalouserSetupWizard).toBe("object");
expect(typeof zalouserSdk.zalouserSetupAdapter).toBe("object");
});
it("exports Tlon helpers", async () => {
const tlonSdk = await import("openclaw/plugin-sdk/tlon");
expect(typeof tlonSdk.fetchWithSsrFGuard).toBe("function");
@@ -142,6 +162,10 @@ describe("plugin-sdk subpath exports", () => {
const bluebubbles = await import("openclaw/plugin-sdk/bluebubbles");
expect(typeof bluebubbles.parseFiniteNumber).toBe("function");
const matrix = await import("openclaw/plugin-sdk/matrix");
expect(typeof matrix.matrixSetupWizard).toBe("object");
expect(typeof matrix.matrixSetupAdapter).toBe("object");
const mattermost = await import("openclaw/plugin-sdk/mattermost");
expect(typeof mattermost.parseStrictPositiveInteger).toBe("function");
@@ -151,6 +175,8 @@ describe("plugin-sdk subpath exports", () => {
const twitch = await import("openclaw/plugin-sdk/twitch");
expect(typeof twitch.DEFAULT_ACCOUNT_ID).toBe("string");
expect(typeof twitch.normalizeAccountId).toBe("function");
expect(typeof twitch.twitchSetupWizard).toBe("object");
expect(typeof twitch.twitchSetupAdapter).toBe("object");
const zalo = await import("openclaw/plugin-sdk/zalo");
expect(typeof zalo.resolveClientIp).toBe("function");