mirror of https://github.com/openclaw/openclaw.git
fix(mattermost): export skill-commands via plugin-sdk + thread triggerMap for accurate command name resolution
- Export listSkillCommandsForAgents and SkillCommandSpec from plugin-sdk/index.ts (removes deep relative import in monitor.ts) - Add originalName field to MattermostCommandSpec for preserving pre-prefix names - Build trigger→originalName map in monitor.ts, thread through slash-state → slash-http - resolveCommandText() now uses triggerMap for accurate name lookup (oc_report → /oc_report correctly, not /report)
This commit is contained in:
parent
81087ecb6b
commit
5bbe16f2ce
|
|
@ -25,6 +25,7 @@ import {
|
|||
resolveDefaultGroupPolicy,
|
||||
resolveChannelMediaMaxBytes,
|
||||
warnMissingProviderGroupPolicyFallbackOnce,
|
||||
listSkillCommandsForAgents,
|
||||
type HistoryEntry,
|
||||
} from "openclaw/plugin-sdk";
|
||||
import { getMattermostRuntime } from "../runtime.js";
|
||||
|
|
@ -258,8 +259,6 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {}
|
|||
|
||||
if (slashConfig.nativeSkills === true) {
|
||||
try {
|
||||
const { listSkillCommandsForAgents } =
|
||||
await import("../../../../src/auto-reply/skill-commands.js");
|
||||
const skillCommands = listSkillCommandsForAgents({ cfg: cfg as any });
|
||||
for (const spec of skillCommands) {
|
||||
const name = typeof spec.name === "string" ? spec.name.trim() : "";
|
||||
|
|
@ -270,6 +269,7 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {}
|
|||
description: spec.description || `Run skill ${name}`,
|
||||
autoComplete: true,
|
||||
autoCompleteHint: "[args]",
|
||||
originalName: name,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
|
|
@ -300,10 +300,19 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {}
|
|||
allRegistered.push(...registered);
|
||||
}
|
||||
|
||||
// Build trigger→originalName map for accurate command name resolution
|
||||
const triggerMap = new Map<string, string>();
|
||||
for (const cmd of dedupedCommands) {
|
||||
if (cmd.originalName) {
|
||||
triggerMap.set(cmd.trigger, cmd.originalName);
|
||||
}
|
||||
}
|
||||
|
||||
activateSlashCommands({
|
||||
account,
|
||||
commandTokens: allRegistered.map((cmd) => cmd.token).filter(Boolean),
|
||||
registeredCommands: allRegistered,
|
||||
triggerMap,
|
||||
api: { cfg, runtime },
|
||||
log: (msg) => runtime.log?.(msg),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ export type MattermostCommandSpec = {
|
|||
description: string;
|
||||
autoComplete: boolean;
|
||||
autoCompleteHint?: string;
|
||||
/** Original command name (for skill commands that start with oc_) */
|
||||
originalName?: string;
|
||||
};
|
||||
|
||||
export type MattermostRegisteredCommand = {
|
||||
|
|
@ -128,39 +130,46 @@ type MattermostCommandResponse = {
|
|||
export const DEFAULT_COMMAND_SPECS: MattermostCommandSpec[] = [
|
||||
{
|
||||
trigger: "oc_status",
|
||||
originalName: "status",
|
||||
description: "Show session status (model, usage, uptime)",
|
||||
autoComplete: true,
|
||||
},
|
||||
{
|
||||
trigger: "oc_model",
|
||||
originalName: "model",
|
||||
description: "View or change the current model",
|
||||
autoComplete: true,
|
||||
autoCompleteHint: "[model-name]",
|
||||
},
|
||||
{
|
||||
trigger: "oc_new",
|
||||
originalName: "new",
|
||||
description: "Start a new conversation session",
|
||||
autoComplete: true,
|
||||
},
|
||||
{
|
||||
trigger: "oc_help",
|
||||
originalName: "help",
|
||||
description: "Show available commands",
|
||||
autoComplete: true,
|
||||
},
|
||||
{
|
||||
trigger: "oc_think",
|
||||
originalName: "think",
|
||||
description: "Set thinking/reasoning level",
|
||||
autoComplete: true,
|
||||
autoCompleteHint: "[off|low|medium|high]",
|
||||
},
|
||||
{
|
||||
trigger: "oc_reasoning",
|
||||
originalName: "reasoning",
|
||||
description: "Toggle reasoning mode",
|
||||
autoComplete: true,
|
||||
autoCompleteHint: "[on|off]",
|
||||
},
|
||||
{
|
||||
trigger: "oc_verbose",
|
||||
originalName: "verbose",
|
||||
description: "Toggle verbose mode",
|
||||
autoComplete: true,
|
||||
autoCompleteHint: "[on|off]",
|
||||
|
|
@ -435,9 +444,14 @@ export function parseSlashCommandPayload(
|
|||
* Map the trigger word back to the original OpenClaw command name.
|
||||
* e.g. "oc_status" -> "/status", "oc_model" -> "/model"
|
||||
*/
|
||||
export function resolveCommandText(trigger: string, text: string): string {
|
||||
// Strip the "oc_" prefix to get the original command name
|
||||
const commandName = trigger.startsWith("oc_") ? trigger.slice(3) : trigger;
|
||||
export function resolveCommandText(
|
||||
trigger: string,
|
||||
text: string,
|
||||
triggerMap?: ReadonlyMap<string, string>,
|
||||
): string {
|
||||
// Use the trigger map if available for accurate name resolution
|
||||
const commandName =
|
||||
triggerMap?.get(trigger) ?? (trigger.startsWith("oc_") ? trigger.slice(3) : trigger);
|
||||
const args = text.trim();
|
||||
return args ? `/${commandName} ${args}` : `/${commandName}`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ type SlashHttpHandlerParams = {
|
|||
runtime: RuntimeEnv;
|
||||
/** Expected token from registered commands (for validation). */
|
||||
commandTokens: Set<string>;
|
||||
/** Map from trigger to original command name (for skill commands that start with oc_). */
|
||||
triggerMap?: ReadonlyMap<string, string>;
|
||||
log?: (msg: string) => void;
|
||||
};
|
||||
|
||||
|
|
@ -361,7 +363,7 @@ async function authorizeSlashInvocation(params: {
|
|||
* from the Mattermost server when a user invokes a registered slash command.
|
||||
*/
|
||||
export function createSlashCommandHttpHandler(params: SlashHttpHandlerParams) {
|
||||
const { account, cfg, runtime, commandTokens, log } = params;
|
||||
const { account, cfg, runtime, commandTokens, triggerMap, log } = params;
|
||||
|
||||
const MAX_BODY_BYTES = 64 * 1024; // 64KB
|
||||
|
||||
|
|
@ -404,7 +406,7 @@ export function createSlashCommandHttpHandler(params: SlashHttpHandlerParams) {
|
|||
|
||||
// Extract command info
|
||||
const trigger = payload.command.replace(/^\//, "").trim();
|
||||
const commandText = resolveCommandText(trigger, payload.text);
|
||||
const commandText = resolveCommandText(trigger, payload.text, triggerMap);
|
||||
const channelId = payload.channel_id;
|
||||
const senderId = payload.user_id;
|
||||
const senderName = payload.user_name ?? senderId;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ type SlashCommandAccountState = {
|
|||
handler: ((req: IncomingMessage, res: ServerResponse) => Promise<void>) | null;
|
||||
/** The account that activated slash commands. */
|
||||
account: ResolvedMattermostAccount;
|
||||
/** Map from trigger to original command name (for skill commands that start with oc_). */
|
||||
triggerMap: Map<string, string>;
|
||||
};
|
||||
|
||||
/** Map from accountId → per-account slash command state. */
|
||||
|
|
@ -53,13 +55,14 @@ export function activateSlashCommands(params: {
|
|||
account: ResolvedMattermostAccount;
|
||||
commandTokens: string[];
|
||||
registeredCommands: MattermostRegisteredCommand[];
|
||||
triggerMap?: Map<string, string>;
|
||||
api: {
|
||||
cfg: import("openclaw/plugin-sdk").OpenClawConfig;
|
||||
runtime: import("openclaw/plugin-sdk").RuntimeEnv;
|
||||
};
|
||||
log?: (msg: string) => void;
|
||||
}) {
|
||||
const { account, commandTokens, registeredCommands, api, log } = params;
|
||||
const { account, commandTokens, registeredCommands, triggerMap, api, log } = params;
|
||||
const accountId = account.accountId;
|
||||
|
||||
const tokenSet = new Set(commandTokens);
|
||||
|
|
@ -69,6 +72,7 @@ export function activateSlashCommands(params: {
|
|||
cfg: api.cfg,
|
||||
runtime: api.runtime,
|
||||
commandTokens: tokenSet,
|
||||
triggerMap,
|
||||
log,
|
||||
});
|
||||
|
||||
|
|
@ -77,6 +81,7 @@ export function activateSlashCommands(params: {
|
|||
registeredCommands,
|
||||
handler,
|
||||
account,
|
||||
triggerMap: triggerMap ?? new Map(),
|
||||
});
|
||||
|
||||
log?.(
|
||||
|
|
|
|||
|
|
@ -543,6 +543,8 @@ export type {
|
|||
} from "../infra/diagnostic-events.js";
|
||||
export { detectMime, extensionForMime, getFileExtension } from "../media/mime.js";
|
||||
export { extractOriginalFilename } from "../media/store.js";
|
||||
export { listSkillCommandsForAgents } from "../auto-reply/skill-commands.js";
|
||||
export type { SkillCommandSpec } from "../agents/skills.js";
|
||||
|
||||
// Channel: Discord
|
||||
export {
|
||||
|
|
|
|||
Loading…
Reference in New Issue