fix(commands): harden model alias parsing
This commit is contained in:
@@ -32,14 +32,18 @@ describe("extractModelDirective", () => {
|
||||
|
||||
describe("alias shortcuts", () => {
|
||||
it("recognizes /gpt as model directive when alias is configured", () => {
|
||||
const result = extractModelDirective("/gpt", { aliases: ["gpt", "sonnet", "opus"] });
|
||||
const result = extractModelDirective("/gpt", {
|
||||
aliases: ["gpt", "sonnet", "opus"],
|
||||
});
|
||||
expect(result.hasDirective).toBe(true);
|
||||
expect(result.rawModel).toBe("gpt");
|
||||
expect(result.cleaned).toBe("");
|
||||
});
|
||||
|
||||
it("recognizes /sonnet as model directive", () => {
|
||||
const result = extractModelDirective("/sonnet", { aliases: ["gpt", "sonnet", "opus"] });
|
||||
const result = extractModelDirective("/sonnet", {
|
||||
aliases: ["gpt", "sonnet", "opus"],
|
||||
});
|
||||
expect(result.hasDirective).toBe(true);
|
||||
expect(result.rawModel).toBe("sonnet");
|
||||
});
|
||||
@@ -60,18 +64,24 @@ describe("extractModelDirective", () => {
|
||||
});
|
||||
|
||||
it("does not match alias without leading slash", () => {
|
||||
const result = extractModelDirective("gpt is great", { aliases: ["gpt"] });
|
||||
const result = extractModelDirective("gpt is great", {
|
||||
aliases: ["gpt"],
|
||||
});
|
||||
expect(result.hasDirective).toBe(false);
|
||||
});
|
||||
|
||||
it("does not match unknown aliases", () => {
|
||||
const result = extractModelDirective("/unknown", { aliases: ["gpt", "sonnet"] });
|
||||
const result = extractModelDirective("/unknown", {
|
||||
aliases: ["gpt", "sonnet"],
|
||||
});
|
||||
expect(result.hasDirective).toBe(false);
|
||||
expect(result.cleaned).toBe("/unknown");
|
||||
});
|
||||
|
||||
it("prefers /model over alias when both present", () => {
|
||||
const result = extractModelDirective("/model haiku", { aliases: ["gpt"] });
|
||||
const result = extractModelDirective("/model haiku", {
|
||||
aliases: ["gpt"],
|
||||
});
|
||||
expect(result.hasDirective).toBe(true);
|
||||
expect(result.rawModel).toBe("haiku");
|
||||
});
|
||||
|
||||
@@ -17,7 +17,9 @@ export function extractModelDirective(
|
||||
/(?:^|\s)\/model(?=$|\s|:)\s*:?\s*([A-Za-z0-9_.:@-]+(?:\/[A-Za-z0-9_.:@-]+)?)?/i,
|
||||
);
|
||||
|
||||
const aliases = (options?.aliases ?? []).map((alias) => alias.trim()).filter(Boolean);
|
||||
const aliases = (options?.aliases ?? [])
|
||||
.map((alias) => alias.trim())
|
||||
.filter(Boolean);
|
||||
const aliasMatch =
|
||||
modelMatch || aliases.length === 0
|
||||
? null
|
||||
|
||||
@@ -144,6 +144,36 @@ describe("directive parsing", () => {
|
||||
expect(res.cleaned).toBe("please now");
|
||||
});
|
||||
|
||||
it("keeps reserved command aliases from matching after trimming", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{
|
||||
Body: "/help",
|
||||
From: "+1222",
|
||||
To: "+1222",
|
||||
},
|
||||
{},
|
||||
{
|
||||
agent: {
|
||||
model: "anthropic/claude-opus-4-5",
|
||||
workspace: path.join(home, "clawd"),
|
||||
models: {
|
||||
"anthropic/claude-opus-4-5": { alias: " help " },
|
||||
},
|
||||
},
|
||||
whatsapp: { allowFrom: ["*"] },
|
||||
session: { store: path.join(home, "sessions.json") },
|
||||
},
|
||||
);
|
||||
|
||||
const text = Array.isArray(res) ? res[0]?.text : res?.text;
|
||||
expect(text).toContain("Help");
|
||||
expect(runEmbeddedPiAgent).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it("errors on invalid queue options", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(runEmbeddedPiAgent).mockReset();
|
||||
|
||||
@@ -321,7 +321,7 @@ export async function getReplyFromConfig(
|
||||
),
|
||||
);
|
||||
const configuredAliases = Object.values(cfg.agent?.models ?? {})
|
||||
.map((entry) => entry.alias)
|
||||
.map((entry) => entry.alias?.trim())
|
||||
.filter((alias): alias is string => Boolean(alias))
|
||||
.filter((alias) => !reservedCommands.has(alias.toLowerCase()));
|
||||
let parsedDirectives = parseInlineDirectives(rawBody, {
|
||||
|
||||
Reference in New Issue
Block a user