mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-14 02:31:24 +00:00
fix: preserve commands.list metadata (#64147)
Merged via squash. Reviewed-by: @frankekn
This commit is contained in:
@@ -69,6 +69,7 @@ Docs: https://docs.openclaw.ai
|
||||
- UI/compaction: keep the compaction indicator in a retry-pending state until the run actually finishes, so the UI does not show `Context compacted` before compaction actually finishes. (#55132) Thanks @mpz4life.
|
||||
- Cron/tool schemas: keep cron tool schemas strict-model-friendly while still preserving `failureAlert=false`, nullable `agentId`/`sessionKey`, and flattened add/update recovery for the newly exposed cron job fields. (#55043) Thanks @brunolorente.
|
||||
- Git metadata: read commit ids from packed refs as well as loose refs so version and status metadata stay accurate after repository maintenance. (#63943)
|
||||
- Gateway: keep `commands.list` skill entries categorized under tools and include provider-aware plugin `nativeName` metadata even when `scope=text`, so remote clients can group skills correctly and map text-surface plugin commands back to native aliases.
|
||||
|
||||
## 2026.4.9
|
||||
|
||||
|
||||
@@ -100,6 +100,9 @@ describe("commands registry", () => {
|
||||
{ skillCommands },
|
||||
);
|
||||
expect(commands.find((spec) => spec.nativeName === "demo_skill")).toBeTruthy();
|
||||
expect(commands.find((spec) => spec.nativeName === "demo_skill")).toMatchObject({
|
||||
category: "tools",
|
||||
});
|
||||
|
||||
const native = listNativeCommandSpecsForConfig(
|
||||
{ commands: { config: false, plugins: false, debug: false, native: true } },
|
||||
|
||||
@@ -88,6 +88,7 @@ function buildSkillCommandDefinitions(skillCommands?: SkillCommandSpec[]): ChatC
|
||||
acceptsArgs: true,
|
||||
argsParsing: "none",
|
||||
scope: "both",
|
||||
category: "tools",
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -299,12 +299,35 @@ describe("commands.list handler", () => {
|
||||
it("keeps plugin text commands visible for scope=text even without native provider support", () => {
|
||||
const { payload } = callHandler({ provider: "whatsapp", scope: "text" });
|
||||
const { commands } = payload as {
|
||||
commands: Array<{ name: string; source: string; textAliases?: string[] }>;
|
||||
commands: Array<{
|
||||
name: string;
|
||||
source: string;
|
||||
textAliases?: string[];
|
||||
nativeName?: string;
|
||||
}>;
|
||||
};
|
||||
expect(commands.find((c) => c.source === "plugin")).toMatchObject({
|
||||
name: "tts",
|
||||
textAliases: ["/tts"],
|
||||
});
|
||||
expect(commands.find((c) => c.source === "plugin")?.nativeName).toBeUndefined();
|
||||
});
|
||||
|
||||
it("keeps plugin text names while exposing provider-native aliases for scope=text", () => {
|
||||
const { payload } = callHandler({ provider: "discord", scope: "text" });
|
||||
const { commands } = payload as {
|
||||
commands: Array<{
|
||||
name: string;
|
||||
source: string;
|
||||
textAliases?: string[];
|
||||
nativeName?: string;
|
||||
}>;
|
||||
};
|
||||
expect(commands.find((c) => c.source === "plugin")).toMatchObject({
|
||||
name: "tts",
|
||||
nativeName: "discord_tts",
|
||||
textAliases: ["/tts"],
|
||||
});
|
||||
});
|
||||
|
||||
it("returns provider-specific plugin command names", () => {
|
||||
|
||||
@@ -120,6 +120,34 @@ function mapCommand(
|
||||
};
|
||||
}
|
||||
|
||||
function buildPluginCommandEntries(params: {
|
||||
provider?: string;
|
||||
nameSurface: CommandNameSurface;
|
||||
}): CommandEntry[] {
|
||||
const pluginTextSpecs = listPluginCommands();
|
||||
const pluginNativeSpecs = getPluginCommandSpecs(params.provider);
|
||||
const entries: CommandEntry[] = [];
|
||||
|
||||
for (const [index, textSpec] of pluginTextSpecs.entries()) {
|
||||
const nativeSpec = pluginNativeSpecs[index];
|
||||
const nativeName = nativeSpec?.name;
|
||||
entries.push({
|
||||
name: params.nameSurface === "text" ? textSpec.name : (nativeName ?? textSpec.name),
|
||||
...(nativeName ? { nativeName } : {}),
|
||||
textAliases: [`/${textSpec.name}`],
|
||||
description: textSpec.description,
|
||||
source: "plugin",
|
||||
scope: "both",
|
||||
acceptsArgs: textSpec.acceptsArgs,
|
||||
});
|
||||
}
|
||||
|
||||
if (params.nameSurface === "native") {
|
||||
return entries.filter((entry) => entry.nativeName);
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
export function buildCommandsListResult(params: {
|
||||
cfg: ReturnType<typeof loadConfig>;
|
||||
agentId: string;
|
||||
@@ -153,33 +181,7 @@ export function buildCommandsListResult(params: {
|
||||
);
|
||||
}
|
||||
|
||||
if (nameSurface === "text") {
|
||||
for (const spec of listPluginCommands()) {
|
||||
commands.push({
|
||||
name: spec.name,
|
||||
textAliases: [`/${spec.name}`],
|
||||
description: spec.description,
|
||||
source: "plugin",
|
||||
scope: "both",
|
||||
acceptsArgs: spec.acceptsArgs,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const pluginTextSpecs = listPluginCommands();
|
||||
const pluginSpecs = getPluginCommandSpecs(provider);
|
||||
for (const [index, spec] of pluginSpecs.entries()) {
|
||||
const textName = pluginTextSpecs[index]?.name ?? spec.name;
|
||||
commands.push({
|
||||
name: spec.name,
|
||||
nativeName: spec.name,
|
||||
textAliases: [`/${textName}`],
|
||||
description: spec.description,
|
||||
source: "plugin",
|
||||
scope: "both",
|
||||
acceptsArgs: spec.acceptsArgs,
|
||||
});
|
||||
}
|
||||
}
|
||||
commands.push(...buildPluginCommandEntries({ provider, nameSurface }));
|
||||
|
||||
return { commands };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user