Files
clawdbot/src/auto-reply/reply/directives.ts
2026-01-09 17:10:53 +01:00

177 lines
4.4 KiB
TypeScript

import type { ReasoningLevel } from "../thinking.js";
import {
type ElevatedLevel,
normalizeElevatedLevel,
normalizeReasoningLevel,
normalizeThinkLevel,
normalizeVerboseLevel,
type ThinkLevel,
type VerboseLevel,
} from "../thinking.js";
type ExtractedLevel<T> = {
cleaned: string;
level?: T;
rawLevel?: string;
hasDirective: boolean;
};
const escapeRegExp = (value: string) =>
value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const matchLevelDirective = (
body: string,
names: string[],
): { start: number; end: number; rawLevel?: string } | null => {
const namePattern = names.map(escapeRegExp).join("|");
const match = body.match(
new RegExp(`(?:^|\\s)\\/(?:${namePattern})(?=$|\\s|:)`, "i"),
);
if (!match || match.index === undefined) return null;
const start = match.index;
let end = match.index + match[0].length;
let i = end;
while (i < body.length && /\s/.test(body[i])) i += 1;
if (body[i] === ":") {
i += 1;
while (i < body.length && /\s/.test(body[i])) i += 1;
}
const argStart = i;
while (i < body.length && /[A-Za-z-]/.test(body[i])) i += 1;
const rawLevel = i > argStart ? body.slice(argStart, i) : undefined;
end = i;
return { start, end, rawLevel };
};
const extractLevelDirective = <T>(
body: string,
names: string[],
normalize: (raw?: string) => T | undefined,
): ExtractedLevel<T> => {
const match = matchLevelDirective(body, names);
if (!match) {
return { cleaned: body.trim(), hasDirective: false };
}
const rawLevel = match.rawLevel;
const level = normalize(rawLevel);
const cleaned = body
.slice(0, match.start)
.concat(" ")
.concat(body.slice(match.end))
.replace(/\s+/g, " ")
.trim();
return {
cleaned,
level,
rawLevel,
hasDirective: true,
};
};
const extractSimpleDirective = (
body: string,
names: string[],
): { cleaned: string; hasDirective: boolean } => {
const namePattern = names.map(escapeRegExp).join("|");
const match = body.match(
new RegExp(`(?:^|\\s)\\/(?:${namePattern})(?=$|\\s|:)(?:\\s*:\\s*)?`, "i"),
);
const cleaned = match
? body.replace(match[0], " ").replace(/\s+/g, " ").trim()
: body.trim();
return {
cleaned,
hasDirective: Boolean(match),
};
};
export function extractThinkDirective(body?: string): {
cleaned: string;
thinkLevel?: ThinkLevel;
rawLevel?: string;
hasDirective: boolean;
} {
if (!body) return { cleaned: "", hasDirective: false };
const extracted = extractLevelDirective(
body,
["thinking", "think", "t"],
normalizeThinkLevel,
);
return {
cleaned: extracted.cleaned,
thinkLevel: extracted.level,
rawLevel: extracted.rawLevel,
hasDirective: extracted.hasDirective,
};
}
export function extractVerboseDirective(body?: string): {
cleaned: string;
verboseLevel?: VerboseLevel;
rawLevel?: string;
hasDirective: boolean;
} {
if (!body) return { cleaned: "", hasDirective: false };
const extracted = extractLevelDirective(
body,
["verbose", "v"],
normalizeVerboseLevel,
);
return {
cleaned: extracted.cleaned,
verboseLevel: extracted.level,
rawLevel: extracted.rawLevel,
hasDirective: extracted.hasDirective,
};
}
export function extractElevatedDirective(body?: string): {
cleaned: string;
elevatedLevel?: ElevatedLevel;
rawLevel?: string;
hasDirective: boolean;
} {
if (!body) return { cleaned: "", hasDirective: false };
const extracted = extractLevelDirective(
body,
["elevated", "elev"],
normalizeElevatedLevel,
);
return {
cleaned: extracted.cleaned,
elevatedLevel: extracted.level,
rawLevel: extracted.rawLevel,
hasDirective: extracted.hasDirective,
};
}
export function extractReasoningDirective(body?: string): {
cleaned: string;
reasoningLevel?: ReasoningLevel;
rawLevel?: string;
hasDirective: boolean;
} {
if (!body) return { cleaned: "", hasDirective: false };
const extracted = extractLevelDirective(
body,
["reasoning", "reason"],
normalizeReasoningLevel,
);
return {
cleaned: extracted.cleaned,
reasoningLevel: extracted.level,
rawLevel: extracted.rawLevel,
hasDirective: extracted.hasDirective,
};
}
export function extractStatusDirective(body?: string): {
cleaned: string;
hasDirective: boolean;
} {
if (!body) return { cleaned: "", hasDirective: false };
return extractSimpleDirective(body, ["status", "usage"]);
}
export type { ElevatedLevel, ReasoningLevel, ThinkLevel, VerboseLevel };