mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-23 10:55:31 -06:00
fix(telegram): resolve native command names from the loaded registry only (#123607)
Telegram native-command registration resolved provider names through the bundled channel-plugin fallback, which jiti-transpiles the entire plugin plus core graph from source when no registry entry is loaded (~190s silent CPU) — tripping the 300s no-output CI watchdog on the two Telegram test files that register at module scope. Telegram defines no resolveNativeCommandName hook, so the load resolved nothing. Thread the existing includeBundledChannelFallback option through the spec-listing helpers and use loaded-registry-only lookups in the Telegram plugin, matching the Discord sibling. Runtime names are byte-identical; both files drop from 200s to ~5s.
This commit is contained in:
@@ -253,7 +253,11 @@ export async function executeTelegramBuiltinCommand(
|
||||
if (!dispatch) {
|
||||
return false;
|
||||
}
|
||||
const commandDefinition = findCommandByNativeName(params.commandName, "telegram");
|
||||
// Loaded-registry lookup only: Telegram defines no resolveNativeCommandName
|
||||
// hook, and the bundled fallback would jiti-load the plugin source in dev/test.
|
||||
const commandDefinition = findCommandByNativeName(params.commandName, "telegram", {
|
||||
includeBundledChannelFallback: false,
|
||||
});
|
||||
const commandArgs = commandDefinition
|
||||
? parseCommandArgs(commandDefinition, params.rawText)
|
||||
: params.rawText
|
||||
|
||||
@@ -184,6 +184,7 @@ describe("registerTelegramNativeCommands", () => {
|
||||
const native = listNativeCommandSpecsForConfig(cfg, {
|
||||
skillCommands,
|
||||
provider: "telegram",
|
||||
includeBundledChannelFallback: false,
|
||||
}).map((command) => ({
|
||||
command: normalizeTelegramCommandName(command.name),
|
||||
description: command.description,
|
||||
@@ -239,7 +240,11 @@ describe("registerTelegramNativeCommands", () => {
|
||||
"Telegram menu pressure omitted per-skill commands; removing per-skill commands and keeping /skill.",
|
||||
);
|
||||
const expectedTotalCommands =
|
||||
customCommands.length + listNativeCommandSpecsForConfig(cfg, { provider: "telegram" }).length;
|
||||
customCommands.length +
|
||||
listNativeCommandSpecsForConfig(cfg, {
|
||||
provider: "telegram",
|
||||
includeBundledChannelFallback: false,
|
||||
}).length;
|
||||
expect(runtimeLog).toHaveBeenCalledWith(
|
||||
`Telegram limits bots to 100 commands. ${expectedTotalCommands} configured; registering first 100. Use channels.telegram.commands.native: false to disable, or reduce plugin/skill/custom commands.`,
|
||||
);
|
||||
|
||||
@@ -104,12 +104,19 @@ export const registerTelegramNativeCommands = ({
|
||||
: [];
|
||||
const pluginCommandRuntime = createPluginCommandRuntime();
|
||||
const pluginCommandSpecs = pluginCommandRuntime.listNativeCandidates("telegram");
|
||||
// Telegram is the channel here: resolve native names from the loaded registry
|
||||
// only. The bundled fallback would jiti-load this whole plugin from source in
|
||||
// dev/test checkouts (minutes of transpile) to call a hook Telegram never defines.
|
||||
const nativeCommands = nativeEnabled
|
||||
? listNativeCommandSpecsForConfig(cfg, { skillCommands, provider: "telegram" })
|
||||
? listNativeCommandSpecsForConfig(cfg, {
|
||||
skillCommands,
|
||||
provider: "telegram",
|
||||
includeBundledChannelFallback: false,
|
||||
})
|
||||
: [];
|
||||
const reservedCommands = new Set(
|
||||
listNativeCommandSpecs({ provider: "telegram" }).map((command) =>
|
||||
normalizeTelegramCommandName(command.name),
|
||||
listNativeCommandSpecs({ provider: "telegram", includeBundledChannelFallback: false }).map(
|
||||
(command) => normalizeTelegramCommandName(command.name),
|
||||
),
|
||||
);
|
||||
for (const command of skillCommands) {
|
||||
@@ -131,7 +138,10 @@ export const registerTelegramNativeCommands = ({
|
||||
runtime.error?.(danger(issue));
|
||||
}
|
||||
const firstSkillCommandIndex = nativeEnabled
|
||||
? listNativeCommandSpecsForConfig(cfg, { provider: "telegram" }).length
|
||||
? listNativeCommandSpecsForConfig(cfg, {
|
||||
provider: "telegram",
|
||||
includeBundledChannelFallback: false,
|
||||
}).length
|
||||
: 0;
|
||||
const nativeMenuCommands = nativeCommands
|
||||
.map((command, index): TelegramMenuCommand | null => {
|
||||
@@ -171,8 +181,13 @@ export const registerTelegramNativeCommands = ({
|
||||
"Telegram menu pressure omitted per-skill commands; removing per-skill commands and keeping /skill.",
|
||||
);
|
||||
}
|
||||
const loginCommand = listNativeCommandSpecsForConfig(cfg, { provider: "telegram" }).find(
|
||||
(command) => findCommandByNativeName(command.name, "telegram")?.key === "login",
|
||||
const loginCommand = listNativeCommandSpecsForConfig(cfg, {
|
||||
provider: "telegram",
|
||||
includeBundledChannelFallback: false,
|
||||
}).find(
|
||||
(command) =>
|
||||
findCommandByNativeName(command.name, "telegram", { includeBundledChannelFallback: false })
|
||||
?.key === "login",
|
||||
);
|
||||
const nativeCommandsToHandle = nativeEnabled
|
||||
? nativeCommands
|
||||
@@ -264,7 +279,10 @@ export const registerTelegramNativeCommands = ({
|
||||
);
|
||||
});
|
||||
}
|
||||
if (findCommandByNativeName(command.name, "telegram")?.key === "login") {
|
||||
if (
|
||||
findCommandByNativeName(command.name, "telegram", { includeBundledChannelFallback: false })
|
||||
?.key === "login"
|
||||
) {
|
||||
handleLoginCallback = handleNativeCommand;
|
||||
}
|
||||
}
|
||||
@@ -300,7 +318,7 @@ export const registerTelegramNativeCommands = ({
|
||||
.split("@", 1)[0]
|
||||
?.toLowerCase();
|
||||
const commandDefinition = commandName
|
||||
? findCommandByNativeName(commandName, "telegram")
|
||||
? findCommandByNativeName(commandName, "telegram", { includeBundledChannelFallback: false })
|
||||
: undefined;
|
||||
if (commandDefinition?.key !== "login") {
|
||||
return { handled: false, clearButtons: false };
|
||||
|
||||
@@ -79,9 +79,13 @@ function resolveNativeName(
|
||||
);
|
||||
}
|
||||
|
||||
function toNativeCommandSpec(command: ChatCommandDefinition, provider?: string): NativeCommandSpec {
|
||||
function toNativeCommandSpec(
|
||||
command: ChatCommandDefinition,
|
||||
provider?: string,
|
||||
options?: NativeCommandProviderLookupOptions,
|
||||
): NativeCommandSpec {
|
||||
const spec: NativeCommandSpec = {
|
||||
name: resolveNativeName(command, provider) ?? command.key,
|
||||
name: resolveNativeName(command, provider, options) ?? command.key,
|
||||
description: command.description,
|
||||
acceptsArgs: Boolean(command.acceptsArgs),
|
||||
args: command.args,
|
||||
@@ -92,8 +96,12 @@ function toNativeCommandSpec(command: ChatCommandDefinition, provider?: string):
|
||||
return spec;
|
||||
}
|
||||
|
||||
function resolveNativeNames(command: ChatCommandDefinition, provider?: string): string[] {
|
||||
const primary = resolveNativeName(command, provider);
|
||||
function resolveNativeNames(
|
||||
command: ChatCommandDefinition,
|
||||
provider?: string,
|
||||
options?: NativeCommandProviderLookupOptions,
|
||||
): string[] {
|
||||
const primary = resolveNativeName(command, provider, options);
|
||||
return [primary, ...(command.nativeAliases ?? [])].filter((name): name is string =>
|
||||
Boolean(name),
|
||||
);
|
||||
@@ -115,6 +123,7 @@ function supportsNativeProvider(command: ChatCommandDefinition, provider?: strin
|
||||
function listNativeSpecsFromCommands(
|
||||
commands: ChatCommandDefinition[],
|
||||
provider?: string,
|
||||
options?: NativeCommandProviderLookupOptions,
|
||||
): NativeCommandSpec[] {
|
||||
return commands
|
||||
.filter(
|
||||
@@ -122,8 +131,8 @@ function listNativeSpecsFromCommands(
|
||||
command.scope !== "text" && command.nativeName && supportsNativeProvider(command, provider),
|
||||
)
|
||||
.flatMap((command) => {
|
||||
const spec = toNativeCommandSpec(command, provider);
|
||||
return resolveNativeNames(command, provider).map((name, index) => {
|
||||
const spec = toNativeCommandSpec(command, provider, options);
|
||||
return resolveNativeNames(command, provider, options).map((name, index) => {
|
||||
const nativeSpec: NativeCommandSpec = {
|
||||
name,
|
||||
description: spec.description,
|
||||
@@ -145,22 +154,32 @@ function listNativeSpecsFromCommands(
|
||||
}
|
||||
|
||||
/** Lists native command specs registered for a provider, including skill commands. */
|
||||
export function listNativeCommandSpecs(params?: {
|
||||
skillCommands?: SkillCommandSpec[];
|
||||
provider?: string;
|
||||
}): NativeCommandSpec[] {
|
||||
export function listNativeCommandSpecs(
|
||||
params?: {
|
||||
skillCommands?: SkillCommandSpec[];
|
||||
provider?: string;
|
||||
} & NativeCommandProviderLookupOptions,
|
||||
): NativeCommandSpec[] {
|
||||
return listNativeSpecsFromCommands(
|
||||
listChatCommands({ skillCommands: params?.skillCommands }),
|
||||
params?.provider,
|
||||
params,
|
||||
);
|
||||
}
|
||||
|
||||
/** Lists native command specs that are enabled for the provided config. */
|
||||
export function listNativeCommandSpecsForConfig(
|
||||
cfg: OpenClawConfig,
|
||||
params?: { skillCommands?: SkillCommandSpec[]; provider?: string },
|
||||
params?: {
|
||||
skillCommands?: SkillCommandSpec[];
|
||||
provider?: string;
|
||||
} & NativeCommandProviderLookupOptions,
|
||||
): NativeCommandSpec[] {
|
||||
return listNativeSpecsFromCommands(listChatCommandsForConfig(cfg, params), params?.provider);
|
||||
return listNativeSpecsFromCommands(
|
||||
listChatCommandsForConfig(cfg, params),
|
||||
params?.provider,
|
||||
params,
|
||||
);
|
||||
}
|
||||
|
||||
export function mergeNativeCommandSpecs(params: {
|
||||
|
||||
Reference in New Issue
Block a user