refactor: remove type-only import cycles

This commit is contained in:
Peter Steinberger
2026-04-10 15:13:57 +01:00
parent fe1fd055d5
commit 9fd08f9d0f
37 changed files with 785 additions and 693 deletions

View File

@@ -1,2 +1,2 @@
268aca42eaae8b4dd37d7eddb7202d002db16a4a27830cd90d98b5c4413cbbe7 plugin-sdk-api-baseline.json
4fe4fc194bec72a58bdd5566c4b31c00b2c0a520941fdcdd0f42bdf02b683ea5 plugin-sdk-api-baseline.jsonl
70ecd040dd5815b237eb749db2de98e300fd53630e5b418deea0865b781adf4a plugin-sdk-api-baseline.json
7a7b08495662e48d466a1c7cb20d6e81557df05d361de0bebc54369e34dffa35 plugin-sdk-api-baseline.jsonl

View File

@@ -1,4 +1,4 @@
import type { OpenClawConfig } from "../../config/config.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { SecretRef } from "../../config/types.secrets.js";
export type OAuthProvider = string;

View File

@@ -2,8 +2,8 @@
// unintentionally breaking on newlines. Using [\s\S] keeps newlines inside
// the chunk so messages are only split when they truly exceed the limit.
import type { ChannelId } from "../channels/plugins/types.js";
import type { OpenClawConfig } from "../config/config.js";
import type { ChannelId } from "../channels/plugins/types.core.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { findFenceSpanAt, isSafeFenceBreak, parseFenceSpans } from "../markdown/fences.js";
import { resolveChannelStreamingChunkMode } from "../plugin-sdk/channel-streaming.js";
import { resolveAccountEntry } from "../routing/account-lookup.js";

View File

@@ -0,0 +1,7 @@
export type CommandArgValue = string | number | boolean | bigint;
export type CommandArgValues = Record<string, CommandArgValue>;
export type CommandArgs = {
raw?: string;
values?: CommandArgValues;
};

View File

@@ -1,4 +1,7 @@
import type { OpenClawConfig } from "../config/types.js";
import type { CommandArgValues } from "./commands-args.types.js";
export type { CommandArgValue, CommandArgValues, CommandArgs } from "./commands-args.types.js";
export type CommandScope = "text" | "native" | "both";
@@ -40,14 +43,6 @@ export type CommandArgMenuSpec = {
title?: string;
};
export type CommandArgValue = string | number | boolean | bigint;
export type CommandArgValues = Record<string, CommandArgValue>;
export type CommandArgs = {
raw?: string;
values?: CommandArgValues;
};
export type CommandArgsParsing = "none" | "positional";
export type ChatCommandDefinition = {

View File

@@ -6,7 +6,7 @@ import type { SessionEntry, SessionScope } from "../../config/sessions.js";
import type { MsgContext } from "../templating.js";
import type { ElevatedLevel, ReasoningLevel, ThinkLevel, VerboseLevel } from "../thinking.js";
import type { GetReplyOptions, ReplyPayload } from "../types.js";
import type { InlineDirectives } from "./directive-handling.js";
import type { InlineDirectives } from "./directive-handling.parse.js";
import type { TypingController } from "./typing.js";
export type CommandContext = {

View File

@@ -1,14 +1,13 @@
import type { ChannelId } from "../channels/plugins/types.js";
import type {
MediaUnderstandingDecision,
MediaUnderstandingOutput,
} from "../media-understanding/types.js";
import type { InputProvenance } from "../sessions/input-provenance.js";
import type { CommandArgs } from "./commands-registry.types.js";
import type { CommandArgs } from "./commands-args.types.js";
import type { ReplyThreadingPolicy } from "./types.js";
/** Valid message channels for routing. */
export type OriginatingChannelType = ChannelId;
export type OriginatingChannelType = string & { readonly __originatingChannelBrand?: never };
export type StickerContextMetadata = {
cachedDescription?: string;

View File

@@ -1,4 +1,3 @@
import type { OpenClawConfig } from "../../config/config.js";
import { resolveAccountEntry } from "../../routing/account-lookup.js";
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../routing/session-key.js";
@@ -11,6 +10,10 @@ type ChannelConfigWithAccounts = {
accounts?: Record<string, AccountConfigWithWrites>;
};
type ConfigWritePolicyConfig = {
channels?: Record<string, ChannelConfigWithAccounts>;
};
export type ConfigWriteScopeLike<TChannelId extends string = string> = {
channelId?: TChannelId | null;
accountId?: string | null;
@@ -46,13 +49,13 @@ function listConfigWriteTargetScopes<TChannelId extends string>(
}
function resolveChannelConfig<TChannelId extends string>(
cfg: OpenClawConfig,
cfg: ConfigWritePolicyConfig,
channelId?: TChannelId | null,
): ChannelConfigWithAccounts | undefined {
if (!channelId) {
return undefined;
}
return (cfg.channels as Record<string, ChannelConfigWithAccounts> | undefined)?.[channelId];
return cfg.channels?.[channelId];
}
function resolveChannelAccountConfig(
@@ -63,7 +66,7 @@ function resolveChannelAccountConfig(
}
export function resolveChannelConfigWritesShared<TChannelId extends string>(params: {
cfg: OpenClawConfig;
cfg: ConfigWritePolicyConfig;
channelId?: TChannelId | null;
accountId?: string | null;
}): boolean {
@@ -77,7 +80,7 @@ export function resolveChannelConfigWritesShared<TChannelId extends string>(para
}
export function authorizeConfigWriteShared<TChannelId extends string>(params: {
cfg: OpenClawConfig;
cfg: ConfigWritePolicyConfig;
origin?: ConfigWriteScopeLike<TChannelId>;
target?: ConfigWriteTargetLike<TChannelId>;
allowBypass?: boolean;

View File

@@ -1,6 +1,5 @@
import type { OpenClawConfig } from "../../config/config.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
import { isInternalMessageChannel } from "../../utils/message-channel.js";
import {
authorizeConfigWriteShared,
canBypassConfigWritePolicyShared,
@@ -12,11 +11,15 @@ import {
type ConfigWriteScopeLike,
type ConfigWriteTargetLike,
} from "./config-write-policy-shared.js";
import type { ChannelId } from "./types.js";
import type { ChannelId } from "./types.core.js";
export type ConfigWriteScope = ConfigWriteScopeLike<ChannelId>;
export type ConfigWriteTarget = ConfigWriteTargetLike<ChannelId>;
export type ConfigWriteAuthorizationResult = ConfigWriteAuthorizationResultLike<ChannelId>;
function isInternalConfigWriteMessageChannel(channel?: string | null): boolean {
return normalizeLowercaseStringOrEmpty(channel) === "webchat";
}
export function resolveChannelConfigWrites(params: {
cfg: OpenClawConfig;
channelId?: ChannelId | null;
@@ -51,7 +54,7 @@ export function canBypassConfigWritePolicy(params: {
}): boolean {
return canBypassConfigWritePolicyShared({
...params,
isInternalMessageChannel,
isInternalMessageChannel: isInternalConfigWriteMessageChannel,
});
}

View File

@@ -1,10 +1,12 @@
import type { WizardPrompter } from "../../wizard/prompts.js";
import { splitSetupEntries } from "./setup-wizard-helpers.js";
export type ChannelAccessPolicy = "allowlist" | "open" | "disabled";
export function parseAllowlistEntries(raw: string): string[] {
return splitSetupEntries(String(raw ?? ""));
return String(raw ?? "")
.split(/[\n,;]+/g)
.map((entry) => entry.trim())
.filter(Boolean);
}
export function formatAllowlistEntries(entries: string[]): string {

View File

@@ -1,5 +1,5 @@
import type { OpenClawConfig } from "../../config/config.js";
import type { DmPolicy, GroupPolicy } from "../../config/types.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { SecretInput } from "../../config/types.secrets.js";
import { resolveSecretInputModeForEnvSelection } from "../../plugins/provider-auth-mode.js";
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../routing/session-key.js";
@@ -12,14 +12,12 @@ import {
} from "./setup-helpers.js";
import type {
ChannelSetupDmPolicy,
PromptAccountId,
PromptAccountIdParams,
} from "./setup-wizard-types.js";
import type {
ChannelSetupWizard,
ChannelSetupWizardAllowFromEntry,
ChannelSetupWizardStatus,
} from "./setup-wizard.js";
PromptAccountId,
PromptAccountIdParams,
} from "./setup-wizard-types.js";
let providerAuthInputPromise:
| Promise<Pick<typeof import("../../plugins/provider-auth-ref.js"), "promptSecretRefForSetup">>

View File

@@ -1,13 +1,287 @@
import type { OpenClawConfig } from "../../config/config.js";
import type { DmPolicy } from "../../config/types.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { RuntimeEnv } from "../../runtime.js";
import type { WizardPrompter } from "../../wizard/prompts.js";
import type { ChannelId, ChannelPlugin } from "./types.js";
import type { ChannelAccessPolicy } from "./setup-group-access.js";
import type { ChannelConfigAdapter, ChannelSetupAdapter } from "./types.adapters.js";
import type {
ChannelCapabilities,
ChannelId,
ChannelMeta,
ChannelSetupInput,
} from "./types.core.js";
export type ChannelSetupPlugin = Pick<
ChannelPlugin,
"id" | "meta" | "capabilities" | "config" | "setup" | "setupWizard"
>;
export type ChannelSetupPlugin = {
id: ChannelId;
meta: ChannelMeta;
capabilities: ChannelCapabilities;
config: ChannelConfigAdapter<unknown>;
setup?: ChannelSetupAdapter;
setupWizard?: ChannelSetupWizard | ChannelSetupWizardAdapter;
};
export type ChannelSetupWizardStatus = {
configuredLabel: string;
unconfiguredLabel: string;
configuredHint?: string;
unconfiguredHint?: string;
configuredScore?: number;
unconfiguredScore?: number;
resolveConfigured: (params: {
cfg: OpenClawConfig;
accountId?: string;
}) => boolean | Promise<boolean>;
resolveStatusLines?: (params: {
cfg: OpenClawConfig;
accountId?: string;
configured: boolean;
}) => string[] | Promise<string[]>;
resolveSelectionHint?: (params: {
cfg: OpenClawConfig;
accountId?: string;
configured: boolean;
}) => string | undefined | Promise<string | undefined>;
resolveQuickstartScore?: (params: {
cfg: OpenClawConfig;
accountId?: string;
configured: boolean;
}) => number | undefined | Promise<number | undefined>;
};
export type ChannelSetupWizardCredentialState = {
accountConfigured: boolean;
hasConfiguredValue: boolean;
resolvedValue?: string;
envValue?: string;
};
export type ChannelSetupWizardCredentialValues = Partial<Record<string, string>>;
export type ChannelSetupWizardNote = {
title: string;
lines: string[];
shouldShow?: (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
}) => boolean | Promise<boolean>;
};
export type ChannelSetupWizardEnvShortcut = {
prompt: string;
preferredEnvVar?: string;
isAvailable: (params: { cfg: OpenClawConfig; accountId: string }) => boolean;
apply: (params: {
cfg: OpenClawConfig;
accountId: string;
}) => OpenClawConfig | Promise<OpenClawConfig>;
};
export type ChannelSetupWizardCredential = {
inputKey: keyof ChannelSetupInput;
providerHint: string;
credentialLabel: string;
preferredEnvVar?: string;
helpTitle?: string;
helpLines?: string[];
envPrompt: string;
keepPrompt: string;
inputPrompt: string;
allowEnv?: (params: { cfg: OpenClawConfig; accountId: string }) => boolean;
inspect: (params: {
cfg: OpenClawConfig;
accountId: string;
}) => ChannelSetupWizardCredentialState;
shouldPrompt?: (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
currentValue?: string;
state: ChannelSetupWizardCredentialState;
}) => boolean | Promise<boolean>;
applyUseEnv?: (params: {
cfg: OpenClawConfig;
accountId: string;
}) => OpenClawConfig | Promise<OpenClawConfig>;
applySet?: (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
value: unknown;
resolvedValue: string;
}) => OpenClawConfig | Promise<OpenClawConfig>;
};
export type ChannelSetupWizardTextInput = {
inputKey: keyof ChannelSetupInput;
message: string;
placeholder?: string;
required?: boolean;
applyEmptyValue?: boolean;
helpTitle?: string;
helpLines?: string[];
confirmCurrentValue?: boolean;
keepPrompt?: string | ((value: string) => string);
currentValue?: (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
}) => string | undefined | Promise<string | undefined>;
initialValue?: (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
}) => string | undefined | Promise<string | undefined>;
shouldPrompt?: (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
currentValue?: string;
}) => boolean | Promise<boolean>;
applyCurrentValue?: boolean;
validate?: (params: {
value: string;
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
}) => string | undefined;
normalizeValue?: (params: {
value: string;
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
}) => string;
applySet?: (params: {
cfg: OpenClawConfig;
accountId: string;
value: string;
}) => OpenClawConfig | Promise<OpenClawConfig>;
};
export type ChannelSetupWizardAllowFromEntry = {
input: string;
resolved: boolean;
id: string | null;
};
export type ChannelSetupWizardAllowFrom = {
helpTitle?: string;
helpLines?: string[];
credentialInputKey?: keyof ChannelSetupInput;
message: string;
placeholder: string;
invalidWithoutCredentialNote: string;
parseInputs?: (raw: string) => string[];
parseId: (raw: string) => string | null;
resolveEntries: (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
entries: string[];
}) => Promise<ChannelSetupWizardAllowFromEntry[]>;
apply: (params: {
cfg: OpenClawConfig;
accountId: string;
allowFrom: string[];
}) => OpenClawConfig | Promise<OpenClawConfig>;
};
export type ChannelSetupWizardGroupAccess = {
label: string;
placeholder: string;
helpTitle?: string;
helpLines?: string[];
skipAllowlistEntries?: boolean;
currentPolicy: (params: { cfg: OpenClawConfig; accountId: string }) => ChannelAccessPolicy;
currentEntries: (params: { cfg: OpenClawConfig; accountId: string }) => string[];
updatePrompt: (params: { cfg: OpenClawConfig; accountId: string }) => boolean;
setPolicy: (params: {
cfg: OpenClawConfig;
accountId: string;
policy: ChannelAccessPolicy;
}) => OpenClawConfig;
resolveAllowlist?: (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
entries: string[];
prompter: Pick<WizardPrompter, "note">;
}) => Promise<unknown>;
applyAllowlist?: (params: {
cfg: OpenClawConfig;
accountId: string;
resolved: unknown;
}) => OpenClawConfig;
};
export type ChannelSetupWizardPrepare = (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
runtime: ChannelSetupConfigureContext["runtime"];
prompter: WizardPrompter;
options?: ChannelSetupConfigureContext["options"];
}) =>
| {
cfg?: OpenClawConfig;
credentialValues?: ChannelSetupWizardCredentialValues;
}
| void
| Promise<{
cfg?: OpenClawConfig;
credentialValues?: ChannelSetupWizardCredentialValues;
} | void>;
export type ChannelSetupWizardFinalize = (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
runtime: ChannelSetupConfigureContext["runtime"];
prompter: WizardPrompter;
options?: ChannelSetupConfigureContext["options"];
forceAllowFrom: boolean;
}) =>
| {
cfg?: OpenClawConfig;
credentialValues?: ChannelSetupWizardCredentialValues;
}
| void
| Promise<{
cfg?: OpenClawConfig;
credentialValues?: ChannelSetupWizardCredentialValues;
} | void>;
export type ChannelSetupWizard = {
channel: string;
status: ChannelSetupWizardStatus;
introNote?: ChannelSetupWizardNote;
envShortcut?: ChannelSetupWizardEnvShortcut;
resolveAccountIdForConfigure?: (params: {
cfg: OpenClawConfig;
prompter: WizardPrompter;
options?: ChannelSetupConfigureContext["options"];
accountOverride?: string;
shouldPromptAccountIds: boolean;
listAccountIds: ChannelSetupPlugin["config"]["listAccountIds"];
defaultAccountId: string;
}) => string | Promise<string>;
resolveShouldPromptAccountIds?: (params: {
cfg: OpenClawConfig;
options?: ChannelSetupConfigureContext["options"];
shouldPromptAccountIds: boolean;
}) => boolean;
prepare?: ChannelSetupWizardPrepare;
stepOrder?: "credentials-first" | "text-first";
credentials: ChannelSetupWizardCredential[];
textInputs?: ChannelSetupWizardTextInput[];
finalize?: ChannelSetupWizardFinalize;
completionNote?: ChannelSetupWizardNote;
dmPolicy?: ChannelSetupDmPolicy;
allowFrom?: ChannelSetupWizardAllowFrom;
groupAccess?: ChannelSetupWizardGroupAccess;
disable?: (cfg: OpenClawConfig) => OpenClawConfig;
onAccountRecorded?: ChannelSetupWizardAdapter["onAccountRecorded"];
};
export type SetupChannelsOptions = {
allowDisable?: boolean;

View File

@@ -1,9 +1,7 @@
import type { OpenClawConfig } from "../../config/config.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { DEFAULT_ACCOUNT_ID } from "../../routing/session-key.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import type { WizardPrompter } from "../../wizard/prompts.js";
import { configureChannelAccessWithAllowlist } from "./setup-group-access-configure.js";
import type { ChannelAccessPolicy } from "./setup-group-access.js";
import {
promptResolvedAllowFrom,
resolveAccountIdForConfigure,
@@ -13,275 +11,28 @@ import {
import type {
ChannelSetupPlugin,
ChannelSetupWizardAdapter,
ChannelSetupConfigureContext,
ChannelSetupDmPolicy,
ChannelSetupWizard,
ChannelSetupWizardCredentialValues,
ChannelSetupWizardTextInput,
ChannelSetupStatus,
ChannelSetupStatusContext,
} from "./setup-wizard-types.js";
import type { ChannelSetupInput } from "./types.core.js";
export type ChannelSetupWizardStatus = {
configuredLabel: string;
unconfiguredLabel: string;
configuredHint?: string;
unconfiguredHint?: string;
configuredScore?: number;
unconfiguredScore?: number;
resolveConfigured: (params: {
cfg: OpenClawConfig;
accountId?: string;
}) => boolean | Promise<boolean>;
resolveStatusLines?: (params: {
cfg: OpenClawConfig;
accountId?: string;
configured: boolean;
}) => string[] | Promise<string[]>;
resolveSelectionHint?: (params: {
cfg: OpenClawConfig;
accountId?: string;
configured: boolean;
}) => string | undefined | Promise<string | undefined>;
resolveQuickstartScore?: (params: {
cfg: OpenClawConfig;
accountId?: string;
configured: boolean;
}) => number | undefined | Promise<number | undefined>;
};
export type ChannelSetupWizardCredentialState = {
accountConfigured: boolean;
hasConfiguredValue: boolean;
resolvedValue?: string;
envValue?: string;
};
type ChannelSetupWizardCredentialValues = Partial<Record<string, string>>;
export type ChannelSetupWizardNote = {
title: string;
lines: string[];
shouldShow?: (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
}) => boolean | Promise<boolean>;
};
export type ChannelSetupWizardEnvShortcut = {
prompt: string;
preferredEnvVar?: string;
isAvailable: (params: { cfg: OpenClawConfig; accountId: string }) => boolean;
apply: (params: {
cfg: OpenClawConfig;
accountId: string;
}) => OpenClawConfig | Promise<OpenClawConfig>;
};
export type ChannelSetupWizardCredential = {
inputKey: keyof ChannelSetupInput;
providerHint: string;
credentialLabel: string;
preferredEnvVar?: string;
helpTitle?: string;
helpLines?: string[];
envPrompt: string;
keepPrompt: string;
inputPrompt: string;
allowEnv?: (params: { cfg: OpenClawConfig; accountId: string }) => boolean;
inspect: (params: {
cfg: OpenClawConfig;
accountId: string;
}) => ChannelSetupWizardCredentialState;
shouldPrompt?: (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
currentValue?: string;
state: ChannelSetupWizardCredentialState;
}) => boolean | Promise<boolean>;
applyUseEnv?: (params: {
cfg: OpenClawConfig;
accountId: string;
}) => OpenClawConfig | Promise<OpenClawConfig>;
applySet?: (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
value: unknown;
resolvedValue: string;
}) => OpenClawConfig | Promise<OpenClawConfig>;
};
export type ChannelSetupWizardTextInput = {
inputKey: keyof ChannelSetupInput;
message: string;
placeholder?: string;
required?: boolean;
applyEmptyValue?: boolean;
helpTitle?: string;
helpLines?: string[];
confirmCurrentValue?: boolean;
keepPrompt?: string | ((value: string) => string);
currentValue?: (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
}) => string | undefined | Promise<string | undefined>;
initialValue?: (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
}) => string | undefined | Promise<string | undefined>;
shouldPrompt?: (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
currentValue?: string;
}) => boolean | Promise<boolean>;
applyCurrentValue?: boolean;
validate?: (params: {
value: string;
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
}) => string | undefined;
normalizeValue?: (params: {
value: string;
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
}) => string;
applySet?: (params: {
cfg: OpenClawConfig;
accountId: string;
value: string;
}) => OpenClawConfig | Promise<OpenClawConfig>;
};
export type ChannelSetupWizardAllowFromEntry = {
input: string;
resolved: boolean;
id: string | null;
};
export type ChannelSetupWizardAllowFrom = {
helpTitle?: string;
helpLines?: string[];
credentialInputKey?: keyof ChannelSetupInput;
message: string;
placeholder: string;
invalidWithoutCredentialNote: string;
parseInputs?: (raw: string) => string[];
parseId: (raw: string) => string | null;
resolveEntries: (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
entries: string[];
}) => Promise<ChannelSetupWizardAllowFromEntry[]>;
apply: (params: {
cfg: OpenClawConfig;
accountId: string;
allowFrom: string[];
}) => OpenClawConfig | Promise<OpenClawConfig>;
};
export type ChannelSetupWizardGroupAccess = {
label: string;
placeholder: string;
helpTitle?: string;
helpLines?: string[];
skipAllowlistEntries?: boolean;
currentPolicy: (params: { cfg: OpenClawConfig; accountId: string }) => ChannelAccessPolicy;
currentEntries: (params: { cfg: OpenClawConfig; accountId: string }) => string[];
updatePrompt: (params: { cfg: OpenClawConfig; accountId: string }) => boolean;
setPolicy: (params: {
cfg: OpenClawConfig;
accountId: string;
policy: ChannelAccessPolicy;
}) => OpenClawConfig;
resolveAllowlist?: (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
entries: string[];
prompter: Pick<WizardPrompter, "note">;
}) => Promise<unknown>;
applyAllowlist?: (params: {
cfg: OpenClawConfig;
accountId: string;
resolved: unknown;
}) => OpenClawConfig;
};
export type ChannelSetupWizardPrepare = (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
runtime: ChannelSetupConfigureContext["runtime"];
prompter: WizardPrompter;
options?: ChannelSetupConfigureContext["options"];
}) =>
| {
cfg?: OpenClawConfig;
credentialValues?: ChannelSetupWizardCredentialValues;
}
| void
| Promise<{
cfg?: OpenClawConfig;
credentialValues?: ChannelSetupWizardCredentialValues;
} | void>;
export type ChannelSetupWizardFinalize = (params: {
cfg: OpenClawConfig;
accountId: string;
credentialValues: ChannelSetupWizardCredentialValues;
runtime: ChannelSetupConfigureContext["runtime"];
prompter: WizardPrompter;
options?: ChannelSetupConfigureContext["options"];
forceAllowFrom: boolean;
}) =>
| {
cfg?: OpenClawConfig;
credentialValues?: ChannelSetupWizardCredentialValues;
}
| void
| Promise<{
cfg?: OpenClawConfig;
credentialValues?: ChannelSetupWizardCredentialValues;
} | void>;
export type ChannelSetupWizard = {
channel: string;
status: ChannelSetupWizardStatus;
introNote?: ChannelSetupWizardNote;
envShortcut?: ChannelSetupWizardEnvShortcut;
resolveAccountIdForConfigure?: (params: {
cfg: OpenClawConfig;
prompter: WizardPrompter;
options?: ChannelSetupConfigureContext["options"];
accountOverride?: string;
shouldPromptAccountIds: boolean;
listAccountIds: ChannelSetupWizardPlugin["config"]["listAccountIds"];
defaultAccountId: string;
}) => string | Promise<string>;
resolveShouldPromptAccountIds?: (params: {
cfg: OpenClawConfig;
options?: ChannelSetupConfigureContext["options"];
shouldPromptAccountIds: boolean;
}) => boolean;
prepare?: ChannelSetupWizardPrepare;
stepOrder?: "credentials-first" | "text-first";
credentials: ChannelSetupWizardCredential[];
textInputs?: ChannelSetupWizardTextInput[];
finalize?: ChannelSetupWizardFinalize;
completionNote?: ChannelSetupWizardNote;
dmPolicy?: ChannelSetupDmPolicy;
allowFrom?: ChannelSetupWizardAllowFrom;
groupAccess?: ChannelSetupWizardGroupAccess;
disable?: (cfg: OpenClawConfig) => OpenClawConfig;
onAccountRecorded?: ChannelSetupWizardAdapter["onAccountRecorded"];
};
export type {
ChannelSetupWizard,
ChannelSetupWizardAllowFrom,
ChannelSetupWizardAllowFromEntry,
ChannelSetupWizardCredential,
ChannelSetupWizardCredentialState,
ChannelSetupWizardEnvShortcut,
ChannelSetupWizardFinalize,
ChannelSetupWizardGroupAccess,
ChannelSetupWizardNote,
ChannelSetupWizardPrepare,
ChannelSetupWizardStatus,
ChannelSetupWizardTextInput,
} from "./setup-wizard-types.js";
type ChannelSetupWizardPlugin = ChannelSetupPlugin;

View File

@@ -1,12 +1,13 @@
import type { ReplyPayload } from "../../auto-reply/types.js";
import type { ConfiguredBindingRule } from "../../config/bindings.js";
import type { OpenClawConfig } from "../../config/config.js";
import type { LegacyConfigRule } from "../../config/legacy.shared.js";
import type { AgentBinding } from "../../config/types.agents.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { GroupToolPolicyConfig } from "../../config/types.tools.js";
import type { ChannelApprovalNativeRuntimeAdapter } from "../../infra/approval-handler-runtime.js";
import type { ChannelApprovalNativeRuntimeAdapter } from "../../infra/approval-handler-runtime-types.js";
import type { ExecApprovalRequest, ExecApprovalResolved } from "../../infra/exec-approvals.js";
import type { OutboundDeliveryResult, OutboundSendDeps } from "../../infra/outbound/deliver.js";
import type { OutboundIdentity } from "../../infra/outbound/identity.js";
import type { OutboundDeliveryResult } from "../../infra/outbound/deliver-types.js";
import type { OutboundIdentity } from "../../infra/outbound/identity-types.js";
import type { OutboundSendDeps } from "../../infra/outbound/send-deps.js";
import type {
PluginApprovalRequest,
PluginApprovalResolved,
@@ -34,6 +35,8 @@ import type {
ChannelStatusIssue,
} from "./types.core.js";
type ConfiguredBindingRule = AgentBinding;
export type ChannelActionAvailabilityState =
| { kind: "enabled" }
| { kind: "disabled" }

View File

@@ -2,17 +2,16 @@ import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core";
import type { TSchema } from "@sinclair/typebox";
import type { MsgContext } from "../../auto-reply/templating.js";
import type { ReplyPayload } from "../../auto-reply/types.js";
import type { OpenClawConfig } from "../../config/config.js";
import type { MarkdownTableMode } from "../../config/types.base.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { GatewayClientMode, GatewayClientName } from "../../gateway/protocol/client-info.js";
import type { OutboundMediaAccess } from "../../media/load-options.js";
import type { PollInput } from "../../polls.js";
import type { GatewayClientMode, GatewayClientName } from "../../utils/message-channel.js";
import type { ChatType } from "../chat-type.js";
import type { ChatChannelId } from "../registry.js";
import type { ChannelMessageActionName as ChannelMessageActionNameFromList } from "./message-action-names.js";
import type { ChannelMessageCapability } from "./message-capabilities.js";
export type ChannelId = ChatChannelId | (string & {});
export type ChannelId = string & { readonly __openclawChannelIdBrand?: never };
export type ChannelExposure = {
configured?: boolean;

View File

@@ -1,5 +1,4 @@
import type { ChannelSetupWizardAdapter } from "./setup-wizard-types.js";
import type { ChannelSetupWizard } from "./setup-wizard.js";
import type { ChannelSetupWizard, ChannelSetupWizardAdapter } from "./setup-wizard-types.js";
import type {
ChannelApprovalCapability,
ChannelAuthAdapter,

View File

@@ -1,4 +1,3 @@
import type { ChannelId } from "../channels/plugins/types.js";
import type { AgentModelConfig, AgentSandboxConfig } from "./types.agents-shared.js";
import type {
BlockStreamingChunkConfig,
@@ -272,7 +271,7 @@ export type AgentDefaultsConfig = {
/** Session key for heartbeat runs ("main" or explicit session key). */
session?: string;
/** Delivery target ("last", "none", or a channel id). */
target?: ChannelId;
target?: string;
/** Direct/DM delivery policy. Default: "allow". */
directPolicy?: "allow" | "block";
/** Optional delivery override (E.164 for WhatsApp, chat id for Telegram). Supports :topic:NNN suffix for Telegram topics. */

View File

@@ -2,7 +2,7 @@ import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import type {
ChannelApprovalNativeAvailabilityAdapter,
ChannelApprovalNativeRuntimeAdapter,
} from "./approval-handler-runtime.js";
} from "./approval-handler-runtime-types.js";
import type { ExecApprovalChannelRuntimeEventKind } from "./exec-approval-channel-runtime.js";
export const CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY = "approval.native";

View File

@@ -0,0 +1,335 @@
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { ChannelApprovalNativePlannedTarget } from "./approval-native-delivery.js";
import type { PreparedChannelNativeApprovalTarget } from "./approval-native-runtime.js";
import type {
ExpiredApprovalView,
PendingApprovalView,
ResolvedApprovalView,
} from "./approval-view-model.js";
import type { ExecApprovalChannelRuntimeEventKind } from "./exec-approval-channel-runtime.js";
import type { ExecApprovalRequest, ExecApprovalResolved } from "./exec-approvals.js";
import type { PluginApprovalRequest, PluginApprovalResolved } from "./plugin-approvals.js";
export type ApprovalRequest = ExecApprovalRequest | PluginApprovalRequest;
export type ApprovalResolved = ExecApprovalResolved | PluginApprovalResolved;
export type ChannelApprovalKind = "exec" | "plugin";
export type ChannelApprovalCapabilityHandlerContext = {
cfg: OpenClawConfig;
accountId?: string | null;
gatewayUrl?: string;
context?: unknown;
};
export type ChannelApprovalNativeFinalAction<TPayload> =
| { kind: "update"; payload: TPayload }
| { kind: "delete" }
| { kind: "clear-actions" }
| { kind: "leave" };
export type ChannelApprovalNativeAvailabilityAdapter = {
isConfigured: (params: ChannelApprovalCapabilityHandlerContext) => boolean;
shouldHandle: (
params: ChannelApprovalCapabilityHandlerContext & { request: ApprovalRequest },
) => boolean;
};
export type ChannelApprovalNativePresentationAdapter<
TPendingPayload = unknown,
TFinalPayload = unknown,
> = {
buildPendingPayload: (
params: ChannelApprovalCapabilityHandlerContext & {
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
nowMs: number;
view: PendingApprovalView;
},
) => TPendingPayload | Promise<TPendingPayload>;
buildResolvedResult: (
params: ChannelApprovalCapabilityHandlerContext & {
request: ApprovalRequest;
resolved: ApprovalResolved;
view: ResolvedApprovalView;
entry: unknown;
},
) =>
| ChannelApprovalNativeFinalAction<TFinalPayload>
| Promise<ChannelApprovalNativeFinalAction<TFinalPayload>>;
buildExpiredResult: (
params: ChannelApprovalCapabilityHandlerContext & {
request: ApprovalRequest;
view: ExpiredApprovalView;
entry: unknown;
},
) =>
| ChannelApprovalNativeFinalAction<TFinalPayload>
| Promise<ChannelApprovalNativeFinalAction<TFinalPayload>>;
};
export type ChannelApprovalNativeTransportAdapter<
TPreparedTarget = unknown,
TPendingEntry = unknown,
TPendingPayload = unknown,
TFinalPayload = unknown,
> = {
prepareTarget: (
params: ChannelApprovalCapabilityHandlerContext & {
plannedTarget: ChannelApprovalNativePlannedTarget;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: PendingApprovalView;
pendingPayload: TPendingPayload;
},
) =>
| PreparedChannelNativeApprovalTarget<TPreparedTarget>
| null
| Promise<PreparedChannelNativeApprovalTarget<TPreparedTarget> | null>;
deliverPending: (
params: ChannelApprovalCapabilityHandlerContext & {
plannedTarget: ChannelApprovalNativePlannedTarget;
preparedTarget: TPreparedTarget;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: PendingApprovalView;
pendingPayload: TPendingPayload;
},
) => TPendingEntry | null | Promise<TPendingEntry | null>;
updateEntry?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
payload: TFinalPayload;
phase: "resolved" | "expired";
},
) => Promise<void>;
deleteEntry?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
phase: "resolved" | "expired";
},
) => Promise<void>;
};
export type ChannelApprovalNativeInteractionAdapter<TPendingEntry = unknown, TBinding = unknown> = {
bindPending?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: PendingApprovalView;
pendingPayload: unknown;
},
) => TBinding | null | Promise<TBinding | null>;
unbindPending?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
binding: TBinding;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
},
) => Promise<void> | void;
clearPendingActions?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
phase: "resolved" | "expired";
},
) => Promise<void>;
};
export type ChannelApprovalNativeObserveAdapter<
TPreparedTarget = unknown,
TPendingPayload = unknown,
TPendingEntry = unknown,
> = {
onDeliveryError?: (
params: ChannelApprovalCapabilityHandlerContext & {
error: unknown;
plannedTarget: ChannelApprovalNativePlannedTarget;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: PendingApprovalView;
pendingPayload: TPendingPayload;
},
) => void;
onDuplicateSkipped?: (
params: ChannelApprovalCapabilityHandlerContext & {
plannedTarget: ChannelApprovalNativePlannedTarget;
preparedTarget: PreparedChannelNativeApprovalTarget<TPreparedTarget>;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: PendingApprovalView;
pendingPayload: TPendingPayload;
},
) => void;
onDelivered?: (
params: ChannelApprovalCapabilityHandlerContext & {
plannedTarget: ChannelApprovalNativePlannedTarget;
preparedTarget: PreparedChannelNativeApprovalTarget<TPreparedTarget>;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: PendingApprovalView;
pendingPayload: TPendingPayload;
entry: TPendingEntry;
},
) => void;
};
export type ChannelApprovalNativeRuntimeAdapter<
TPendingPayload = unknown,
TPreparedTarget = unknown,
TPendingEntry = unknown,
TBinding = unknown,
TFinalPayload = unknown,
> = {
eventKinds?: readonly ExecApprovalChannelRuntimeEventKind[];
resolveApprovalKind?: (request: ApprovalRequest) => ChannelApprovalKind;
availability: ChannelApprovalNativeAvailabilityAdapter;
presentation: ChannelApprovalNativePresentationAdapter<TPendingPayload, TFinalPayload>;
transport: ChannelApprovalNativeTransportAdapter<
TPreparedTarget,
TPendingEntry,
TPendingPayload,
TFinalPayload
>;
interactions?: ChannelApprovalNativeInteractionAdapter<TPendingEntry, TBinding>;
observe?: ChannelApprovalNativeObserveAdapter;
};
export type ChannelApprovalNativeRuntimeSpec<
TPendingPayload,
TPreparedTarget,
TPendingEntry,
TBinding = unknown,
TFinalPayload = unknown,
TPendingView extends PendingApprovalView = PendingApprovalView,
TResolvedView extends ResolvedApprovalView = ResolvedApprovalView,
TExpiredView extends ExpiredApprovalView = ExpiredApprovalView,
> = {
eventKinds?: readonly ExecApprovalChannelRuntimeEventKind[];
resolveApprovalKind?: (request: ApprovalRequest) => ChannelApprovalKind;
availability: ChannelApprovalNativeAvailabilityAdapter;
presentation: {
buildPendingPayload: (
params: ChannelApprovalCapabilityHandlerContext & {
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
nowMs: number;
view: TPendingView;
},
) => TPendingPayload | Promise<TPendingPayload>;
buildResolvedResult: (
params: ChannelApprovalCapabilityHandlerContext & {
request: ApprovalRequest;
resolved: ApprovalResolved;
view: TResolvedView;
entry: TPendingEntry;
},
) =>
| ChannelApprovalNativeFinalAction<TFinalPayload>
| Promise<ChannelApprovalNativeFinalAction<TFinalPayload>>;
buildExpiredResult: (
params: ChannelApprovalCapabilityHandlerContext & {
request: ApprovalRequest;
view: TExpiredView;
entry: TPendingEntry;
},
) =>
| ChannelApprovalNativeFinalAction<TFinalPayload>
| Promise<ChannelApprovalNativeFinalAction<TFinalPayload>>;
};
transport: {
prepareTarget: (
params: ChannelApprovalCapabilityHandlerContext & {
plannedTarget: ChannelApprovalNativePlannedTarget;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: TPendingView;
pendingPayload: TPendingPayload;
},
) =>
| PreparedChannelNativeApprovalTarget<TPreparedTarget>
| null
| Promise<PreparedChannelNativeApprovalTarget<TPreparedTarget> | null>;
deliverPending: (
params: ChannelApprovalCapabilityHandlerContext & {
plannedTarget: ChannelApprovalNativePlannedTarget;
preparedTarget: TPreparedTarget;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: TPendingView;
pendingPayload: TPendingPayload;
},
) => TPendingEntry | null | Promise<TPendingEntry | null>;
updateEntry?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
payload: TFinalPayload;
phase: "resolved" | "expired";
},
) => Promise<void>;
deleteEntry?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
phase: "resolved" | "expired";
},
) => Promise<void>;
};
interactions?: {
bindPending?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: TPendingView;
pendingPayload: TPendingPayload;
},
) => TBinding | null | Promise<TBinding | null>;
unbindPending?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
binding: TBinding;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
},
) => Promise<void> | void;
clearPendingActions?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
phase: "resolved" | "expired";
},
) => Promise<void>;
};
observe?: {
onDeliveryError?: (
params: ChannelApprovalCapabilityHandlerContext & {
error: unknown;
plannedTarget: ChannelApprovalNativePlannedTarget;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: TPendingView;
pendingPayload: TPendingPayload;
},
) => void;
onDuplicateSkipped?: (
params: ChannelApprovalCapabilityHandlerContext & {
plannedTarget: ChannelApprovalNativePlannedTarget;
preparedTarget: PreparedChannelNativeApprovalTarget<TPreparedTarget>;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: TPendingView;
pendingPayload: TPendingPayload;
},
) => void;
onDelivered?: (
params: ChannelApprovalCapabilityHandlerContext & {
plannedTarget: ChannelApprovalNativePlannedTarget;
preparedTarget: PreparedChannelNativeApprovalTarget<TPreparedTarget>;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: TPendingView;
pendingPayload: TPendingPayload;
entry: TPendingEntry;
},
) => void;
};
};

View File

@@ -1,15 +1,23 @@
import type {
ChannelApprovalCapability,
ChannelApprovalKind,
ChannelApprovalNativeAdapter,
} from "../channels/plugins/types.adapters.js";
import type { OpenClawConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import { resolveApprovalOverGateway } from "./approval-gateway-resolver.js";
import {
CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY,
createLazyChannelApprovalNativeRuntimeAdapter,
} from "./approval-handler-adapter-runtime.js";
import type {
ApprovalRequest,
ApprovalResolved,
ChannelApprovalCapabilityHandlerContext,
ChannelApprovalKind,
ChannelApprovalNativeFinalAction,
ChannelApprovalNativeRuntimeAdapter,
ChannelApprovalNativeRuntimeSpec,
} from "./approval-handler-runtime-types.js";
import type { ChannelApprovalNativePlannedTarget } from "./approval-native-delivery.js";
import {
createChannelNativeApprovalRuntime,
@@ -31,8 +39,6 @@ import type {
ExecApprovalChannelRuntime,
ExecApprovalChannelRuntimeEventKind,
} from "./exec-approval-channel-runtime.js";
import { type ExecApprovalRequest, type ExecApprovalResolved } from "./exec-approvals.js";
import type { PluginApprovalRequest, PluginApprovalResolved } from "./plugin-approvals.js";
export type {
ApprovalActionView,
@@ -53,335 +59,24 @@ export {
CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY,
createLazyChannelApprovalNativeRuntimeAdapter,
};
type ApprovalRequest = ExecApprovalRequest | PluginApprovalRequest;
type ApprovalResolved = ExecApprovalResolved | PluginApprovalResolved;
export type {
ChannelApprovalCapabilityHandlerContext,
ChannelApprovalKind,
ChannelApprovalNativeAvailabilityAdapter,
ChannelApprovalNativeFinalAction,
ChannelApprovalNativeInteractionAdapter,
ChannelApprovalNativeObserveAdapter,
ChannelApprovalNativePresentationAdapter,
ChannelApprovalNativeRuntimeAdapter,
ChannelApprovalNativeRuntimeSpec,
ChannelApprovalNativeTransportAdapter,
} from "./approval-handler-runtime-types.js";
export type ChannelApprovalHandler<
TRequest extends ApprovalRequest = ApprovalRequest,
TResolved extends ApprovalResolved = ApprovalResolved,
> = ExecApprovalChannelRuntime<TRequest, TResolved>;
export type ChannelApprovalCapabilityHandlerContext = {
cfg: OpenClawConfig;
accountId?: string | null;
gatewayUrl?: string;
context?: unknown;
};
export type ChannelApprovalNativeFinalAction<TPayload> =
| { kind: "update"; payload: TPayload }
| { kind: "delete" }
| { kind: "clear-actions" }
| { kind: "leave" };
export type ChannelApprovalNativeAvailabilityAdapter = {
isConfigured: (params: ChannelApprovalCapabilityHandlerContext) => boolean;
shouldHandle: (
params: ChannelApprovalCapabilityHandlerContext & { request: ApprovalRequest },
) => boolean;
};
export type ChannelApprovalNativePresentationAdapter<
TPendingPayload = unknown,
TFinalPayload = unknown,
> = {
buildPendingPayload: (
params: ChannelApprovalCapabilityHandlerContext & {
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
nowMs: number;
view: PendingApprovalView;
},
) => TPendingPayload | Promise<TPendingPayload>;
buildResolvedResult: (
params: ChannelApprovalCapabilityHandlerContext & {
request: ApprovalRequest;
resolved: ApprovalResolved;
view: ResolvedApprovalView;
entry: unknown;
},
) =>
| ChannelApprovalNativeFinalAction<TFinalPayload>
| Promise<ChannelApprovalNativeFinalAction<TFinalPayload>>;
buildExpiredResult: (
params: ChannelApprovalCapabilityHandlerContext & {
request: ApprovalRequest;
view: ExpiredApprovalView;
entry: unknown;
},
) =>
| ChannelApprovalNativeFinalAction<TFinalPayload>
| Promise<ChannelApprovalNativeFinalAction<TFinalPayload>>;
};
export type ChannelApprovalNativeTransportAdapter<
TPreparedTarget = unknown,
TPendingEntry = unknown,
TPendingPayload = unknown,
TFinalPayload = unknown,
> = {
prepareTarget: (
params: ChannelApprovalCapabilityHandlerContext & {
plannedTarget: ChannelApprovalNativePlannedTarget;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: PendingApprovalView;
pendingPayload: TPendingPayload;
},
) =>
| PreparedChannelNativeApprovalTarget<TPreparedTarget>
| null
| Promise<PreparedChannelNativeApprovalTarget<TPreparedTarget> | null>;
deliverPending: (
params: ChannelApprovalCapabilityHandlerContext & {
plannedTarget: ChannelApprovalNativePlannedTarget;
preparedTarget: TPreparedTarget;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: PendingApprovalView;
pendingPayload: TPendingPayload;
},
) => TPendingEntry | null | Promise<TPendingEntry | null>;
updateEntry?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
payload: TFinalPayload;
phase: "resolved" | "expired";
},
) => Promise<void>;
deleteEntry?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
phase: "resolved" | "expired";
},
) => Promise<void>;
};
export type ChannelApprovalNativeInteractionAdapter<TPendingEntry = unknown, TBinding = unknown> = {
bindPending?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: PendingApprovalView;
pendingPayload: unknown;
},
) => TBinding | null | Promise<TBinding | null>;
unbindPending?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
binding: TBinding;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
},
) => Promise<void> | void;
clearPendingActions?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
phase: "resolved" | "expired";
},
) => Promise<void>;
};
export type ChannelApprovalNativeObserveAdapter<
TPreparedTarget = unknown,
TPendingPayload = unknown,
TPendingEntry = unknown,
> = {
onDeliveryError?: (
params: ChannelApprovalCapabilityHandlerContext & {
error: unknown;
plannedTarget: ChannelApprovalNativePlannedTarget;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: PendingApprovalView;
pendingPayload: TPendingPayload;
},
) => void;
onDuplicateSkipped?: (
params: ChannelApprovalCapabilityHandlerContext & {
plannedTarget: ChannelApprovalNativePlannedTarget;
preparedTarget: PreparedChannelNativeApprovalTarget<TPreparedTarget>;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: PendingApprovalView;
pendingPayload: TPendingPayload;
},
) => void;
onDelivered?: (
params: ChannelApprovalCapabilityHandlerContext & {
plannedTarget: ChannelApprovalNativePlannedTarget;
preparedTarget: PreparedChannelNativeApprovalTarget<TPreparedTarget>;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: PendingApprovalView;
pendingPayload: TPendingPayload;
entry: TPendingEntry;
},
) => void;
};
export type ChannelApprovalNativeRuntimeAdapter<
TPendingPayload = unknown,
TPreparedTarget = unknown,
TPendingEntry = unknown,
TBinding = unknown,
TFinalPayload = unknown,
> = {
eventKinds?: readonly ExecApprovalChannelRuntimeEventKind[];
resolveApprovalKind?: (request: ApprovalRequest) => ChannelApprovalKind;
availability: ChannelApprovalNativeAvailabilityAdapter;
presentation: ChannelApprovalNativePresentationAdapter<TPendingPayload, TFinalPayload>;
transport: ChannelApprovalNativeTransportAdapter<
TPreparedTarget,
TPendingEntry,
TPendingPayload,
TFinalPayload
>;
interactions?: ChannelApprovalNativeInteractionAdapter<TPendingEntry, TBinding>;
observe?: ChannelApprovalNativeObserveAdapter;
};
export type ChannelApprovalNativeRuntimeSpec<
TPendingPayload,
TPreparedTarget,
TPendingEntry,
TBinding = unknown,
TFinalPayload = unknown,
TPendingView extends PendingApprovalView = PendingApprovalView,
TResolvedView extends ResolvedApprovalView = ResolvedApprovalView,
TExpiredView extends ExpiredApprovalView = ExpiredApprovalView,
> = {
eventKinds?: readonly ExecApprovalChannelRuntimeEventKind[];
resolveApprovalKind?: (request: ApprovalRequest) => ChannelApprovalKind;
availability: ChannelApprovalNativeAvailabilityAdapter;
presentation: {
buildPendingPayload: (
params: ChannelApprovalCapabilityHandlerContext & {
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
nowMs: number;
view: TPendingView;
},
) => TPendingPayload | Promise<TPendingPayload>;
buildResolvedResult: (
params: ChannelApprovalCapabilityHandlerContext & {
request: ApprovalRequest;
resolved: ApprovalResolved;
view: TResolvedView;
entry: TPendingEntry;
},
) =>
| ChannelApprovalNativeFinalAction<TFinalPayload>
| Promise<ChannelApprovalNativeFinalAction<TFinalPayload>>;
buildExpiredResult: (
params: ChannelApprovalCapabilityHandlerContext & {
request: ApprovalRequest;
view: TExpiredView;
entry: TPendingEntry;
},
) =>
| ChannelApprovalNativeFinalAction<TFinalPayload>
| Promise<ChannelApprovalNativeFinalAction<TFinalPayload>>;
};
transport: {
prepareTarget: (
params: ChannelApprovalCapabilityHandlerContext & {
plannedTarget: ChannelApprovalNativePlannedTarget;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: TPendingView;
pendingPayload: TPendingPayload;
},
) =>
| PreparedChannelNativeApprovalTarget<TPreparedTarget>
| null
| Promise<PreparedChannelNativeApprovalTarget<TPreparedTarget> | null>;
deliverPending: (
params: ChannelApprovalCapabilityHandlerContext & {
plannedTarget: ChannelApprovalNativePlannedTarget;
preparedTarget: TPreparedTarget;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: TPendingView;
pendingPayload: TPendingPayload;
},
) => TPendingEntry | null | Promise<TPendingEntry | null>;
updateEntry?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
payload: TFinalPayload;
phase: "resolved" | "expired";
},
) => Promise<void>;
deleteEntry?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
phase: "resolved" | "expired";
},
) => Promise<void>;
};
interactions?: {
bindPending?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: TPendingView;
pendingPayload: TPendingPayload;
},
) => TBinding | null | Promise<TBinding | null>;
unbindPending?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
binding: TBinding;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
},
) => Promise<void> | void;
clearPendingActions?: (
params: ChannelApprovalCapabilityHandlerContext & {
entry: TPendingEntry;
phase: "resolved" | "expired";
},
) => Promise<void>;
};
observe?: {
onDeliveryError?: (
params: ChannelApprovalCapabilityHandlerContext & {
error: unknown;
plannedTarget: ChannelApprovalNativePlannedTarget;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: TPendingView;
pendingPayload: TPendingPayload;
},
) => void;
onDuplicateSkipped?: (
params: ChannelApprovalCapabilityHandlerContext & {
plannedTarget: ChannelApprovalNativePlannedTarget;
preparedTarget: PreparedChannelNativeApprovalTarget<TPreparedTarget>;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: TPendingView;
pendingPayload: TPendingPayload;
},
) => void;
onDelivered?: (
params: ChannelApprovalCapabilityHandlerContext & {
plannedTarget: ChannelApprovalNativePlannedTarget;
preparedTarget: PreparedChannelNativeApprovalTarget<TPreparedTarget>;
request: ApprovalRequest;
approvalKind: ChannelApprovalKind;
view: TPendingView;
pendingPayload: TPendingPayload;
entry: TPendingEntry;
},
) => void;
};
};
type WrappedPendingEntry = {
entry: unknown;
binding?: unknown;

View File

@@ -34,7 +34,7 @@ function resolveKnownChannel(value?: string | null): MessageChannelId | undefine
if (!isKnownChannel(normalized)) {
return undefined;
}
return normalized as MessageChannelId;
return normalized;
}
function resolveAvailableKnownChannel(params: {

View File

@@ -0,0 +1,15 @@
import type { OutboundChannel } from "./targets.js";
export type OutboundDeliveryResult = {
channel: Exclude<OutboundChannel, "none">;
messageId: string;
chatId?: string;
channelId?: string;
roomId?: string;
conversationId?: string;
timestamp?: number;
toJid?: string;
pollId?: string;
// Channel docking: stash channel-specific fields here to avoid core type churn.
meta?: Record<string, unknown>;
};

View File

@@ -14,8 +14,8 @@ import type {
ChannelOutboundAdapter,
ChannelOutboundContext,
} from "../../channels/plugins/types.js";
import type { OpenClawConfig } from "../../config/config.js";
import { resolveMirroredTranscriptText } from "../../config/sessions/transcript-mirror.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { fireAndForgetHook } from "../../hooks/fire-and-forget.js";
import { createInternalHookEvent, triggerInternalHook } from "../../hooks/internal-hooks.js";
import {
@@ -31,6 +31,7 @@ import { resolveAgentScopedOutboundMediaAccess } from "../../media/read-capabili
import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js";
import { formatErrorMessage } from "../errors.js";
import { throwIfAborted } from "./abort.js";
import type { OutboundDeliveryResult } from "./deliver-types.js";
import { ackDelivery, enqueueDelivery, failDelivery } from "./delivery-queue.js";
import type { OutboundIdentity } from "./identity.js";
import type { DeliveryMirror } from "./mirror.js";
@@ -40,6 +41,7 @@ import { resolveOutboundSendDep, type OutboundSendDeps } from "./send-deps.js";
import type { OutboundSessionContext } from "./session-context.js";
import type { OutboundChannel } from "./targets.js";
export type { OutboundDeliveryResult } from "./deliver-types.js";
export type { NormalizedOutboundPayload } from "./payloads.js";
export { normalizeOutboundPayloads } from "./payloads.js";
export { resolveOutboundSendDep, type OutboundSendDeps } from "./send-deps.js";
@@ -63,20 +65,6 @@ async function loadChannelBootstrapRuntime() {
return await channelBootstrapRuntimePromise;
}
export type OutboundDeliveryResult = {
channel: Exclude<OutboundChannel, "none">;
messageId: string;
chatId?: string;
channelId?: string;
roomId?: string;
conversationId?: string;
timestamp?: number;
toJid?: string;
pollId?: string;
// Channel docking: stash channel-specific fields here to avoid core type churn.
meta?: Record<string, unknown>;
};
type Chunker = (text: string, limit: number) => string[];
type ChannelHandler = {

View File

@@ -0,0 +1,6 @@
export type OutboundIdentity = {
name?: string;
avatarUrl?: string;
emoji?: string;
theme?: string;
};

View File

@@ -1,14 +1,10 @@
import { resolveAgentAvatar } from "../../agents/identity-avatar.js";
import { resolveAgentIdentity } from "../../agents/identity.js";
import type { OpenClawConfig } from "../../config/config.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import type { OutboundIdentity } from "./identity-types.js";
export type OutboundIdentity = {
name?: string;
avatarUrl?: string;
emoji?: string;
theme?: string;
};
export type { OutboundIdentity } from "./identity-types.js";
export function normalizeOutboundIdentity(
identity?: OutboundIdentity | null,

View File

@@ -1,4 +1,4 @@
import type { OpenClawConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { compileConfigRegex } from "../security/config-regex.js";
import { resolveNodeRequireFromMeta } from "./node-require.js";
import { replacePatternBounded } from "./redact-bounded.js";

View File

@@ -1,5 +1,3 @@
import type { ProviderRequestTransportOverrides } from "../agents/provider-request-config.js";
export type MediaUnderstandingKind =
| "audio.transcription"
| "video.description"
@@ -50,6 +48,31 @@ export type MediaUnderstandingDecision = {
attachments: MediaUnderstandingAttachmentDecision[];
};
export type MediaUnderstandingProviderRequestAuthOverride =
| { mode: "provider-default" }
| { mode: "authorization-bearer"; token: string }
| { mode: "header"; headerName: string; value: string; prefix?: string };
export type MediaUnderstandingProviderRequestTlsOverride = {
ca?: string;
cert?: string;
key?: string;
passphrase?: string;
serverName?: string;
insecureSkipVerify?: boolean;
};
export type MediaUnderstandingProviderRequestProxyOverride =
| { mode: "env-proxy"; tls?: MediaUnderstandingProviderRequestTlsOverride }
| { mode: "explicit-proxy"; url: string; tls?: MediaUnderstandingProviderRequestTlsOverride };
export type MediaUnderstandingProviderRequestTransportOverrides = {
headers?: Record<string, string>;
auth?: MediaUnderstandingProviderRequestAuthOverride;
proxy?: MediaUnderstandingProviderRequestProxyOverride;
tls?: MediaUnderstandingProviderRequestTlsOverride;
};
export type AudioTranscriptionRequest = {
buffer: Buffer;
fileName: string;
@@ -57,7 +80,7 @@ export type AudioTranscriptionRequest = {
apiKey: string;
baseUrl?: string;
headers?: Record<string, string>;
request?: ProviderRequestTransportOverrides;
request?: MediaUnderstandingProviderRequestTransportOverrides;
model?: string;
language?: string;
prompt?: string;
@@ -78,7 +101,7 @@ export type VideoDescriptionRequest = {
apiKey: string;
baseUrl?: string;
headers?: Record<string, string>;
request?: ProviderRequestTransportOverrides;
request?: MediaUnderstandingProviderRequestTransportOverrides;
model?: string;
prompt?: string;
timeoutMs: number;

View File

@@ -1,4 +1,4 @@
import type { ChannelSetupWizard } from "../channels/plugins/setup-wizard.js";
import type { ChannelSetupWizard } from "../channels/plugins/setup-wizard-types.js";
import type { ChannelSetupAdapter } from "../channels/plugins/types.adapters.js";
import type { ChannelSetupInput } from "../channels/plugins/types.core.js";
import {

View File

@@ -40,7 +40,7 @@ export type {
export type {
ChannelSetupWizard,
ChannelSetupWizardAllowFromEntry,
} from "../channels/plugins/setup-wizard.js";
} from "../channels/plugins/setup-wizard-types.js";
export type {
AnyAgentTool,
CliBackendPlugin,

View File

@@ -1,4 +1,4 @@
import type { ChannelSetupWizard } from "../channels/plugins/setup-wizard.js";
import type { ChannelSetupWizard } from "../channels/plugins/setup-wizard-types.js";
import type { ChannelSetupAdapter } from "../channels/plugins/types.adapters.js";
import { DEFAULT_ACCOUNT_ID } from "../routing/session-key.js";
import { formatDocsLink } from "../terminal/links.js";

View File

@@ -1,12 +1,12 @@
export type { OpenClawConfig } from "../config/config.js";
export type { WizardPrompter } from "../wizard/prompts.js";
export type { ChannelSetupAdapter } from "../channels/plugins/types.adapters.js";
export type { ChannelSetupDmPolicy } from "../channels/plugins/setup-wizard-types.js";
export type {
ChannelSetupDmPolicy,
ChannelSetupWizard,
ChannelSetupWizardAllowFromEntry,
ChannelSetupWizardTextInput,
} from "../channels/plugins/setup-wizard.js";
} from "../channels/plugins/setup-wizard-types.js";
export { DEFAULT_ACCOUNT_ID } from "../routing/session-key.js";

View File

@@ -10,12 +10,10 @@ export type { ChannelSetupInput } from "../channels/plugins/types.core.js";
export type {
ChannelSetupDmPolicy,
ChannelSetupWizardAdapter,
} from "../channels/plugins/setup-wizard-types.js";
export type {
ChannelSetupWizard,
ChannelSetupWizardAllowFromEntry,
ChannelSetupWizardTextInput,
} from "../channels/plugins/setup-wizard.js";
} from "../channels/plugins/setup-wizard-types.js";
export { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.js";
export { formatCliCommand } from "../cli/command-format.js";

View File

@@ -22,13 +22,13 @@ import type { FinalizedMsgContext } from "../auto-reply/templating.js";
import type { ThinkLevel } from "../auto-reply/thinking.js";
import type { ReplyPayload } from "../auto-reply/types.js";
import type { ChannelId, ChannelPlugin } from "../channels/plugins/types.js";
import type { OpenClawConfig } from "../config/config.js";
import type {
CliBackendConfig,
ModelProviderAuthMode,
ModelProviderConfig,
} from "../config/types.js";
import type { ModelCompatConfig } from "../config/types.models.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { TtsAutoMode } from "../config/types.tts.js";
import type { OperatorScope } from "../gateway/method-scopes.js";
import type { GatewayRequestHandler } from "../gateway/server-methods/types.js";

View File

@@ -0,0 +1,4 @@
export type SecretRefResolveCache = {
resolvedByRefKey?: Map<string, Promise<unknown>>;
filePayloadByProvider?: Map<string, Promise<unknown>>;
};

View File

@@ -1,7 +1,7 @@
import { spawn } from "node:child_process";
import fs from "node:fs/promises";
import path from "node:path";
import type { OpenClawConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type {
ExecSecretProviderConfig,
FileSecretProviderConfig,
@@ -22,6 +22,7 @@ import {
resolveDefaultSecretProviderAlias,
secretRefKey,
} from "./ref-contract.js";
import type { SecretRefResolveCache } from "./resolve-types.js";
import { isNonEmptyString, isRecord, normalizePositiveInt } from "./shared.js";
const DEFAULT_PROVIDER_CONCURRENCY = 4;
@@ -34,10 +35,7 @@ const DEFAULT_EXEC_MAX_OUTPUT_BYTES = 1024 * 1024;
const WINDOWS_ABS_PATH_PATTERN = /^[A-Za-z]:[\\/]/;
const WINDOWS_UNC_PATH_PATTERN = /^\\\\[^\\]+\\[^\\]+/;
export type SecretRefResolveCache = {
resolvedByRefKey?: Map<string, Promise<unknown>>;
filePayloadByProvider?: Map<string, Promise<unknown>>;
};
export type { SecretRefResolveCache } from "./resolve-types.js";
type ResolveSecretRefOptions = {
config: OpenClawConfig;

View File

@@ -1,7 +1,7 @@
import type { OpenClawConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { coerceSecretRef, type SecretRef } from "../config/types.secrets.js";
import { secretRefKey } from "./ref-contract.js";
import type { SecretRefResolveCache } from "./resolve.js";
import type { SecretRefResolveCache } from "./resolve-types.js";
import { assertExpectedResolvedSecretValue } from "./secret-value.js";
import { isRecord } from "./shared.js";
@@ -40,6 +40,7 @@ export type ResolverContext = {
};
export type SecretDefaults = NonNullable<OpenClawConfig["secrets"]>["defaults"];
export type { SecretRefResolveCache } from "./resolve-types.js";
export function createResolverContext(params: {
sourceConfig: OpenClawConfig;

View File

@@ -1,4 +1,3 @@
import type { ChannelId } from "../channels/plugins/types.js";
import {
CHANNEL_IDS,
getChatChannelMeta,
@@ -19,6 +18,8 @@ import {
} from "../gateway/protocol/client-info.js";
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
type ChannelId = string & { readonly __openclawChannelIdBrand?: never };
export const INTERNAL_MESSAGE_CHANNEL = "webchat" as const;
export type InternalMessageChannel = typeof INTERNAL_MESSAGE_CHANNEL;