Merge branch 'main' into commands-list-clean
This commit is contained in:
@@ -126,11 +126,12 @@ function extractCompactInstructions(params: {
|
||||
rawBody?: string;
|
||||
ctx: MsgContext;
|
||||
cfg: ClawdbotConfig;
|
||||
agentId?: string;
|
||||
isGroup: boolean;
|
||||
}): string | undefined {
|
||||
const raw = stripStructuralPrefixes(params.rawBody ?? "");
|
||||
const stripped = params.isGroup
|
||||
? stripMentions(raw, params.ctx, params.cfg)
|
||||
? stripMentions(raw, params.ctx, params.cfg, params.agentId)
|
||||
: raw;
|
||||
const trimmed = stripped.trim();
|
||||
if (!trimmed) return undefined;
|
||||
@@ -145,12 +146,14 @@ function extractCompactInstructions(params: {
|
||||
export function buildCommandContext(params: {
|
||||
ctx: MsgContext;
|
||||
cfg: ClawdbotConfig;
|
||||
agentId?: string;
|
||||
sessionKey?: string;
|
||||
isGroup: boolean;
|
||||
triggerBodyNormalized: string;
|
||||
commandAuthorized: boolean;
|
||||
}): CommandContext {
|
||||
const { ctx, cfg, sessionKey, isGroup, triggerBodyNormalized } = params;
|
||||
const { ctx, cfg, agentId, sessionKey, isGroup, triggerBodyNormalized } =
|
||||
params;
|
||||
const auth = resolveCommandAuthorization({
|
||||
ctx,
|
||||
cfg,
|
||||
@@ -162,7 +165,9 @@ export function buildCommandContext(params: {
|
||||
sessionKey ?? (auth.from || undefined) ?? (auth.to || undefined);
|
||||
const rawBodyNormalized = triggerBodyNormalized;
|
||||
const commandBodyNormalized = normalizeCommandBody(
|
||||
isGroup ? stripMentions(rawBodyNormalized, ctx, cfg) : rawBodyNormalized,
|
||||
isGroup
|
||||
? stripMentions(rawBodyNormalized, ctx, cfg, agentId)
|
||||
: rawBodyNormalized,
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -207,6 +212,7 @@ export async function handleCommands(params: {
|
||||
ctx: MsgContext;
|
||||
cfg: ClawdbotConfig;
|
||||
command: CommandContext;
|
||||
agentId?: string;
|
||||
directives: InlineDirectives;
|
||||
sessionEntry?: SessionEntry;
|
||||
sessionStore?: Record<string, SessionEntry>;
|
||||
@@ -542,6 +548,7 @@ export async function handleCommands(params: {
|
||||
rawBody: ctx.Body,
|
||||
ctx,
|
||||
cfg,
|
||||
agentId: params.agentId,
|
||||
isGroup,
|
||||
});
|
||||
const result = await compactEmbeddedPiSession({
|
||||
|
||||
@@ -184,7 +184,7 @@ export type InlineDirectives = {
|
||||
|
||||
export function parseInlineDirectives(
|
||||
body: string,
|
||||
options?: { modelAliases?: string[] },
|
||||
options?: { modelAliases?: string[]; disableElevated?: boolean },
|
||||
): InlineDirectives {
|
||||
const {
|
||||
cleaned: thinkCleaned,
|
||||
@@ -209,7 +209,14 @@ export function parseInlineDirectives(
|
||||
elevatedLevel,
|
||||
rawLevel: rawElevatedLevel,
|
||||
hasDirective: hasElevatedDirective,
|
||||
} = extractElevatedDirective(reasoningCleaned);
|
||||
} = options?.disableElevated
|
||||
? {
|
||||
cleaned: reasoningCleaned,
|
||||
elevatedLevel: undefined,
|
||||
rawLevel: undefined,
|
||||
hasDirective: false,
|
||||
}
|
||||
: extractElevatedDirective(reasoningCleaned);
|
||||
const { cleaned: statusCleaned, hasDirective: hasStatusDirective } =
|
||||
extractStatusDirective(elevatedCleaned);
|
||||
const {
|
||||
@@ -272,9 +279,10 @@ export function isDirectiveOnly(params: {
|
||||
cleanedBody: string;
|
||||
ctx: MsgContext;
|
||||
cfg: ClawdbotConfig;
|
||||
agentId?: string;
|
||||
isGroup: boolean;
|
||||
}): boolean {
|
||||
const { directives, cleanedBody, ctx, cfg, isGroup } = params;
|
||||
const { directives, cleanedBody, ctx, cfg, agentId, isGroup } = params;
|
||||
if (
|
||||
!directives.hasThinkDirective &&
|
||||
!directives.hasVerboseDirective &&
|
||||
@@ -285,7 +293,9 @@ export function isDirectiveOnly(params: {
|
||||
)
|
||||
return false;
|
||||
const stripped = stripStructuralPrefixes(cleanedBody ?? "");
|
||||
const noMentions = isGroup ? stripMentions(stripped, ctx, cfg) : stripped;
|
||||
const noMentions = isGroup
|
||||
? stripMentions(stripped, ctx, cfg, agentId)
|
||||
: stripped;
|
||||
return noMentions.length === 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ const extractLevelDirective = <T>(
|
||||
const level = normalize(rawLevel);
|
||||
const cleaned = body
|
||||
.slice(0, match.start)
|
||||
.concat(" ")
|
||||
.concat(body.slice(match.end))
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
@@ -76,7 +77,7 @@ const extractSimpleDirective = (
|
||||
new RegExp(`(?:^|\\s)\\/(?:${namePattern})(?=$|\\s|:)(?:\\s*:\\s*)?`, "i"),
|
||||
);
|
||||
const cleaned = match
|
||||
? body.replace(match[0], "").replace(/\s+/g, " ").trim()
|
||||
? body.replace(match[0], " ").replace(/\s+/g, " ").trim()
|
||||
: body.trim();
|
||||
return {
|
||||
cleaned,
|
||||
|
||||
@@ -27,4 +27,20 @@ describe("mention helpers", () => {
|
||||
});
|
||||
expect(matchesMentionPatterns("CLAWD: hi", regexes)).toBe(true);
|
||||
});
|
||||
|
||||
it("uses per-agent mention patterns when configured", () => {
|
||||
const regexes = buildMentionRegexes(
|
||||
{
|
||||
routing: {
|
||||
groupChat: { mentionPatterns: ["\\bglobal\\b"] },
|
||||
agents: {
|
||||
work: { mentionPatterns: ["\\bworkbot\\b"] },
|
||||
},
|
||||
},
|
||||
},
|
||||
"work",
|
||||
);
|
||||
expect(matchesMentionPatterns("workbot: hi", regexes)).toBe(true);
|
||||
expect(matchesMentionPatterns("global: hi", regexes)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,8 +1,23 @@
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MsgContext } from "../templating.js";
|
||||
|
||||
export function buildMentionRegexes(cfg: ClawdbotConfig | undefined): RegExp[] {
|
||||
const patterns = cfg?.routing?.groupChat?.mentionPatterns ?? [];
|
||||
function resolveMentionPatterns(
|
||||
cfg: ClawdbotConfig | undefined,
|
||||
agentId?: string,
|
||||
): string[] {
|
||||
if (!cfg) return [];
|
||||
const agentConfig = agentId ? cfg.routing?.agents?.[agentId] : undefined;
|
||||
if (agentConfig && Object.hasOwn(agentConfig, "mentionPatterns")) {
|
||||
return agentConfig.mentionPatterns ?? [];
|
||||
}
|
||||
return cfg.routing?.groupChat?.mentionPatterns ?? [];
|
||||
}
|
||||
|
||||
export function buildMentionRegexes(
|
||||
cfg: ClawdbotConfig | undefined,
|
||||
agentId?: string,
|
||||
): RegExp[] {
|
||||
const patterns = resolveMentionPatterns(cfg, agentId);
|
||||
return patterns
|
||||
.map((pattern) => {
|
||||
try {
|
||||
@@ -48,9 +63,10 @@ export function stripMentions(
|
||||
text: string,
|
||||
ctx: MsgContext,
|
||||
cfg: ClawdbotConfig | undefined,
|
||||
agentId?: string,
|
||||
): string {
|
||||
let result = text;
|
||||
const patterns = cfg?.routing?.groupChat?.mentionPatterns ?? [];
|
||||
const patterns = resolveMentionPatterns(cfg, agentId);
|
||||
for (const p of patterns) {
|
||||
try {
|
||||
const re = new RegExp(p, "gi");
|
||||
|
||||
@@ -271,8 +271,9 @@ export function extractQueueDirective(body?: string): {
|
||||
const argsStart = start + "/queue".length;
|
||||
const args = body.slice(argsStart);
|
||||
const parsed = parseQueueDirectiveArgs(args);
|
||||
const cleanedRaw =
|
||||
body.slice(0, start) + body.slice(argsStart + parsed.consumed);
|
||||
const cleanedRaw = `${body.slice(0, start)} ${body.slice(
|
||||
argsStart + parsed.consumed,
|
||||
)}`;
|
||||
const cleaned = cleanedRaw.replace(/\s+/g, " ").trim();
|
||||
return {
|
||||
cleaned,
|
||||
|
||||
@@ -136,7 +136,7 @@ export async function initSessionState(params: {
|
||||
// web inbox before we get here. They prevented reset triggers like "/new"
|
||||
// from matching, so strip structural wrappers when checking for resets.
|
||||
const strippedForReset = isGroup
|
||||
? stripMentions(triggerBodyNormalized, ctx, cfg)
|
||||
? stripMentions(triggerBodyNormalized, ctx, cfg, agentId)
|
||||
: triggerBodyNormalized;
|
||||
for (const trigger of resetTriggers) {
|
||||
if (!trigger) continue;
|
||||
|
||||
Reference in New Issue
Block a user