onboarding: support plugin-owned interactive channel flows

This commit is contained in:
Gustavo Madeira Santana
2026-02-25 23:54:15 -05:00
parent 39a1c13635
commit 218f4d525a
2 changed files with 58 additions and 0 deletions

View File

@@ -62,6 +62,13 @@ export type ChannelOnboardingResult = {
accountId?: string;
};
export type ChannelOnboardingConfiguredResult = ChannelOnboardingResult | "skip";
export type ChannelOnboardingInteractiveContext = ChannelOnboardingConfigureContext & {
configured: boolean;
label: string;
};
export type ChannelOnboardingDmPolicy = {
label: string;
channel: ChannelId;
@@ -80,6 +87,12 @@ export type ChannelOnboardingAdapter = {
channel: ChannelId;
getStatus: (ctx: ChannelOnboardingStatusContext) => Promise<ChannelOnboardingStatus>;
configure: (ctx: ChannelOnboardingConfigureContext) => Promise<ChannelOnboardingResult>;
configureInteractive?: (
ctx: ChannelOnboardingInteractiveContext,
) => Promise<ChannelOnboardingConfiguredResult>;
configureWhenConfigured?: (
ctx: ChannelOnboardingConfigureContext,
) => Promise<ChannelOnboardingConfiguredResult>;
dmPolicy?: ChannelOnboardingDmPolicy;
onAccountRecorded?: (accountId: string, options?: SetupChannelsOptions) => void;
disable?: (cfg: OpenClawConfig) => OpenClawConfig;

View File

@@ -514,6 +514,27 @@ export async function setupChannels(
const handleConfiguredChannel = async (channel: ChannelChoice, label: string) => {
const plugin = getChannelPlugin(channel);
const adapter = getChannelOnboardingAdapter(channel);
if (adapter?.configureWhenConfigured) {
const custom = await adapter.configureWhenConfigured({
cfg: next,
runtime,
prompter,
options,
accountOverrides,
shouldPromptAccountIds,
forceAllowFrom: forceAllowFromChannels.has(channel),
});
if (custom === "skip") {
return;
}
next = custom.cfg;
if (custom.accountId) {
recordAccount(channel, custom.accountId);
}
addSelection(channel);
await refreshStatus(channel);
return;
}
const supportsDisable = Boolean(
options?.allowDisable && (plugin?.config.setAccountEnabled || adapter?.disable),
);
@@ -615,9 +636,33 @@ export async function setupChannels(
}
const plugin = getChannelPlugin(channel);
const adapter = getChannelOnboardingAdapter(channel);
const label = plugin?.meta.label ?? catalogEntry?.meta.label ?? channel;
const status = statusByChannel.get(channel);
const configured = status?.configured ?? false;
if (adapter?.configureInteractive) {
const custom = await adapter.configureInteractive({
cfg: next,
runtime,
prompter,
options,
accountOverrides,
shouldPromptAccountIds,
forceAllowFrom: forceAllowFromChannels.has(channel),
configured,
label,
});
if (custom === "skip") {
return;
}
next = custom.cfg;
if (custom.accountId) {
recordAccount(channel, custom.accountId);
}
addSelection(channel);
await refreshStatus(channel);
return;
}
if (configured) {
await handleConfiguredChannel(channel, label);
return;