fix: avoid directive hits inside URLs and add tests

This commit is contained in:
Peter Steinberger
2025-12-05 22:28:36 +00:00
parent 5949ef0e2c
commit 99b174f495
2 changed files with 38 additions and 5 deletions

View File

@@ -0,0 +1,29 @@
import { describe, expect, it } from "vitest";
import { extractVerboseDirective, extractThinkDirective } from "./reply.js";
describe("directive parsing", () => {
it("ignores verbose directive inside URL", () => {
const body = "https://x.com/verioussmith/status/1997066835133669687";
const res = extractVerboseDirective(body);
expect(res.hasDirective).toBe(false);
expect(res.cleaned).toBe(body);
});
it("ignores think directive inside URL", () => {
const body = "see https://example.com/path/thinkstuff";
const res = extractThinkDirective(body);
expect(res.hasDirective).toBe(false);
});
it("matches verbose with leading space", () => {
const res = extractVerboseDirective(" please /verbose on now");
expect(res.hasDirective).toBe(true);
expect(res.verboseLevel).toBe("on");
});
it("matches think at start of line", () => {
const res = extractThinkDirective("/think:high run slow");
expect(res.hasDirective).toBe(true);
expect(res.thinkLevel).toBe("high");
});
});

View File

@@ -36,15 +36,18 @@ export type { GetReplyOptions, ReplyPayload } from "./types.js";
const ABORT_TRIGGERS = new Set(["stop", "esc", "abort", "wait", "exit"]);
const ABORT_MEMORY = new Map<string, boolean>();
function extractThinkDirective(body?: string): {
export function extractThinkDirective(body?: string): {
cleaned: string;
thinkLevel?: ThinkLevel;
rawLevel?: string;
hasDirective: boolean;
} {
if (!body) return { cleaned: "", hasDirective: false };
// Match the longest keyword first to avoid partial captures (e.g. "/think:high")
const match = body.match(/\/(?:thinking|think|t)\s*:?\s*([a-zA-Z-]+)\b/i);
// Match the longest keyword first to avoid partial captures (e.g. "/think:high").
// Require start of string or whitespace before "/" to avoid catching URLs.
const match = body.match(
/(?:^|\s)\/(?:thinking|think|t)\s*:?\s*([a-zA-Z-]+)\b/i,
);
const thinkLevel = normalizeThinkLevel(match?.[1]);
const cleaned = match
? body.replace(match[0], "").replace(/\s+/g, " ").trim()
@@ -57,14 +60,15 @@ function extractThinkDirective(body?: string): {
};
}
function extractVerboseDirective(body?: string): {
export function extractVerboseDirective(body?: string): {
cleaned: string;
verboseLevel?: VerboseLevel;
rawLevel?: string;
hasDirective: boolean;
} {
if (!body) return { cleaned: "", hasDirective: false };
const match = body.match(/\/(?:verbose|v)\s*:?\s*([a-zA-Z-]+)\b/i);
// Require start or whitespace before "/verbose" to avoid matching URLs like /verioussmith.
const match = body.match(/(?:^|\s)\/(?:verbose|v)\s*:?\s*([a-zA-Z-]+)\b/i);
const verboseLevel = normalizeVerboseLevel(match?.[1]);
const cleaned = match
? body.replace(match[0], "").replace(/\s+/g, " ").trim()