Skip to content

Commit e0584ed

Browse files
committed
fix(session): strip needle periods and require http(s) schemes
1 parent 6c30013 commit e0584ed

2 files changed

Lines changed: 63 additions & 4 deletions

File tree

‎src/session/compaction-verify.test.ts‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,13 @@ describe("extractContinuationFacts", () => {
119119
const report = verifyCompactionSummary("anything", facts);
120120
expect(report.supported).toBe(true);
121121
});
122+
123+
test("uppercase HTTP URL in user text is lifted into exactNames", () => {
124+
const facts = extractContinuationFacts([
125+
textTurn("user", "Call HTTP://API.COM next"),
126+
]);
127+
expect(facts.exactNames).toContain("HTTP://API.COM");
128+
});
122129
});
123130

124131
describe("verifyCompactionSummary", () => {
@@ -160,6 +167,28 @@ describe("verifyCompactionSummary", () => {
160167
}
161168
});
162169

170+
test("trailing period on a goal needle does not miss an unpunctuated summary", () => {
171+
const facts = extractContinuationFacts([textTurn("user", "Fix auth now.")]);
172+
const report = verifyCompactionSummary("Fix auth now", facts);
173+
expect(report.misses.some((m) => m.kind === "goal")).toBe(false);
174+
});
175+
176+
test("trailing period on a constraint needle does not miss an unpunctuated summary", () => {
177+
const facts = {
178+
goal: "Fix auth now",
179+
constraints: ["Never use emojis."],
180+
nextAction: "",
181+
verification: [],
182+
blockers: [],
183+
exactNames: [],
184+
};
185+
const report = verifyCompactionSummary(
186+
"Fix auth now. Never use emojis",
187+
facts,
188+
);
189+
expect(report.misses.some((m) => m.kind === "constraint")).toBe(false);
190+
});
191+
163192
test("denying failure while errors were dropped is a contradiction", () => {
164193
const facts = extractContinuationFacts(droppedTurns());
165194
const report = verifyCompactionSummary(
@@ -337,6 +366,31 @@ describe("verifyCompactionSummary", () => {
337366
expect(report.misses.some((m) => m.kind === "exactName")).toBe(false);
338367
});
339368

369+
test("http/client.ts is covered by basename client.ts", () => {
370+
for (const filePath of ["http/client.ts", "HTTP/Client.ts"]) {
371+
const facts = extractContinuationFacts([
372+
textTurn("user", "Fix auth now"),
373+
{
374+
role: "assistant",
375+
content: [
376+
{
377+
type: "tool_call",
378+
id: "c1",
379+
name: "read_file",
380+
arguments: { path: filePath },
381+
},
382+
],
383+
timestamp: 2,
384+
},
385+
]);
386+
const report = verifyCompactionSummary(
387+
"Fix auth now. Read client.ts next.",
388+
facts,
389+
);
390+
expect(report.misses.some((m) => m.kind === "exactName")).toBe(false);
391+
}
392+
});
393+
340394
test("uppercase HTTP URL scores hostname case-insensitively", () => {
341395
const facts = extractContinuationFacts([
342396
textTurn("user", "Fix auth now"),

‎src/session/compaction-verify.ts‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,11 @@ const STOPWORDS = new Set([
115115

116116
function significantTokens(text: string, cap = 24): string[] {
117117
const out: string[] = [];
118-
for (const word of text.toLowerCase().split(/[^a-z0-9_./-]+/)) {
118+
for (const raw of text.toLowerCase().split(/[^a-z0-9_./-]+/)) {
119+
// `.` stays in the splitter so `vite.config.ts` is one token; a sentence
120+
// period still glues to the last word (`now.`, `emojis.`). Strip it from
121+
// the needle so an unpunctuated summary still covers the fact.
122+
const word = raw.replace(/\.+$/, "");
119123
if (word.length < 4 || STOPWORDS.has(word)) continue;
120124
if (!out.includes(word)) out.push(word);
121125
if (out.length >= cap) break;
@@ -292,7 +296,7 @@ export function extractContinuationFacts(
292296
}
293297
}
294298
for (const text of [...users, ...assistants]) {
295-
for (const match of text.match(/https?:\/\/[^\s)]+/g) ?? []) {
299+
for (const match of text.match(/https?:\/\/[^\s)]+/gi) ?? []) {
296300
if (!exactNames.includes(match)) exactNames.push(match);
297301
}
298302
}
@@ -319,11 +323,12 @@ export function extractContinuationFacts(
319323
// its basename.
320324
function exactNameSupported(name: string, summary: string): boolean {
321325
const lowered = summary.toLowerCase();
322-
if (name.toLowerCase().startsWith("http")) {
326+
const loweredName = name.toLowerCase();
327+
if (loweredName.startsWith("http://") || loweredName.startsWith("https://")) {
323328
const host = hostnameOf(name);
324329
if (host !== undefined && tokenAppears(host.toLowerCase(), lowered))
325330
return true;
326-
return tokenAppears(name.toLowerCase(), lowered);
331+
return tokenAppears(loweredName, lowered);
327332
}
328333
const base = name.split("/").pop() ?? name;
329334
return base.length > 0 && tokenAppears(base.toLowerCase(), lowered);

0 commit comments

Comments
 (0)