diff --git a/src/auto-reply/model.ts b/src/auto-reply/model.ts index 56bb6e19e..37adeeab8 100644 --- a/src/auto-reply/model.ts +++ b/src/auto-reply/model.ts @@ -1,14 +1,36 @@ -export function extractModelDirective(body?: string): { +function escapeRegExp(value: string) { + return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} + +export function extractModelDirective( + body?: string, + options?: { aliases?: string[] }, +): { cleaned: string; rawModel?: string; rawProfile?: string; hasDirective: boolean; } { if (!body) return { cleaned: "", hasDirective: false }; - const match = body.match( + + const modelMatch = body.match( /(?:^|\s)\/model(?=$|\s|:)\s*:?\s*([A-Za-z0-9_.:@-]+(?:\/[A-Za-z0-9_.:@-]+)?)?/i, ); - const raw = match?.[1]?.trim(); + + const aliases = (options?.aliases ?? []).map((alias) => alias.trim()).filter(Boolean); + const aliasMatch = + modelMatch || aliases.length === 0 + ? null + : body.match( + new RegExp( + `(?:^|\\s)\\/(${aliases.map(escapeRegExp).join("|")})(?=$|\\s|:)`, + "i", + ), + ); + + const match = modelMatch ?? aliasMatch; + const raw = modelMatch ? modelMatch?.[1]?.trim() : aliasMatch?.[1]?.trim(); + let rawModel = raw; let rawProfile: string | undefined; if (raw?.includes("@")) { @@ -16,9 +38,11 @@ export function extractModelDirective(body?: string): { rawModel = parts[0]?.trim(); rawProfile = parts.slice(1).join("@").trim() || undefined; } + const cleaned = match ? body.replace(match[0], "").replace(/\s+/g, " ").trim() : body.trim(); + return { cleaned, rawModel, diff --git a/src/auto-reply/reply.ts b/src/auto-reply/reply.ts index aaa9efd76..c2bd3ecb3 100644 --- a/src/auto-reply/reply.ts +++ b/src/auto-reply/reply.ts @@ -312,7 +312,12 @@ export async function getReplyFromConfig( rawDrop: undefined, hasQueueOptions: false, }); - let parsedDirectives = parseInlineDirectives(rawBody); + const configuredAliases = Object.values(cfg.agent?.models ?? {}) + .map((entry) => entry.alias) + .filter((alias): alias is string => Boolean(alias)); + let parsedDirectives = parseInlineDirectives(rawBody, { + modelAliases: configuredAliases, + }); const hasDirective = parsedDirectives.hasThinkDirective || parsedDirectives.hasVerboseDirective || diff --git a/src/auto-reply/reply/directive-handling.ts b/src/auto-reply/reply/directive-handling.ts index b811248c3..5c368721c 100644 --- a/src/auto-reply/reply/directive-handling.ts +++ b/src/auto-reply/reply/directive-handling.ts @@ -181,7 +181,10 @@ export type InlineDirectives = { hasQueueOptions: boolean; }; -export function parseInlineDirectives(body: string): InlineDirectives { +export function parseInlineDirectives( + body: string, + options?: { modelAliases?: string[] }, +): InlineDirectives { const { cleaned: thinkCleaned, thinkLevel, @@ -213,7 +216,9 @@ export function parseInlineDirectives(body: string): InlineDirectives { rawModel, rawProfile, hasDirective: hasModelDirective, - } = extractModelDirective(statusCleaned); + } = extractModelDirective(statusCleaned, { + aliases: options?.modelAliases, + }); const { cleaned: queueCleaned, queueMode,