fix(task): treat case-insensitive Name-N labels as handle echoes
The exact-echo check used accent-insensitive compare, but the collision suffix path was a case-sensitive startsWith. AuthLoader-3 vs authloader therefore leaked through as a real description.
This commit is contained in:
@@ -13,8 +13,11 @@ const TASK_LABEL_SYSTEM_PROMPT = prompt.render(taskLabelSystemPrompt);
|
||||
export function labelEchoesHandle(handle: string | undefined, label: string): boolean {
|
||||
if (!handle) return false;
|
||||
if (label.localeCompare(handle, undefined, { sensitivity: "accent" }) === 0) return true;
|
||||
const suffix = handle.startsWith(`${label}-`) ? handle.slice(label.length + 1) : "";
|
||||
return /^\d+$/.test(suffix);
|
||||
const separator = handle.lastIndexOf("-");
|
||||
if (separator <= 0) return false;
|
||||
const prefix = handle.slice(0, separator);
|
||||
const suffix = handle.slice(separator + 1);
|
||||
return /^\d+$/.test(suffix) && prefix.localeCompare(label, undefined, { sensitivity: "accent" }) === 0;
|
||||
}
|
||||
|
||||
/** Compresses a delegated assignment into a one-sentence UI label via the tiny title model — fired by the executor spawn path because the task wire schema no longer carries a `description`; null on empty input or failure. */
|
||||
|
||||
@@ -141,6 +141,16 @@ describe("subagent HUD lines", () => {
|
||||
expect(collision).toMatch(/AuthLoader-3.*scout/);
|
||||
expect(collision).not.toContain("AuthLoader-3: AuthLoader");
|
||||
|
||||
const mixedCase = render([
|
||||
makeSession({
|
||||
id: "AuthLoader-3",
|
||||
agent: "scout",
|
||||
description: "authloader",
|
||||
}),
|
||||
]);
|
||||
expect(mixedCase).toContain("AuthLoader-3");
|
||||
expect(mixedCase).not.toContain("AuthLoader-3: authloader");
|
||||
|
||||
const defaultWorker = render([
|
||||
makeSession({ id: "SchemaMigrator", agent: "task", description: "Migrate users" }),
|
||||
]);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { afterEach, describe, expect, it, vi } from "bun:test";
|
||||
import type { Api, Model } from "@oh-my-pi/pi-ai";
|
||||
import * as ai from "@oh-my-pi/pi-ai";
|
||||
import { getBundledModel } from "@oh-my-pi/pi-catalog/models";
|
||||
import { generateTaskLabel } from "@oh-my-pi/pi-coding-agent/task/label";
|
||||
import { generateTaskLabel, labelEchoesHandle } from "@oh-my-pi/pi-coding-agent/task/label";
|
||||
|
||||
function getModelOrThrow(id: string): Model<Api> {
|
||||
const model = getBundledModel("anthropic", id);
|
||||
@@ -93,4 +93,11 @@ describe("task label generation", () => {
|
||||
);
|
||||
expect(labeled).toBe("Sleep then reply done");
|
||||
});
|
||||
|
||||
it("treats a case-insensitive Name-N collision as an echoed handle", () => {
|
||||
expect(labelEchoesHandle("AuthLoader-3", "authloader")).toBe(true);
|
||||
expect(labelEchoesHandle("AuthLoader-3", "AuthLoader")).toBe(true);
|
||||
expect(labelEchoesHandle("AuthLoader", "authloader")).toBe(true);
|
||||
expect(labelEchoesHandle("AuthLoader-3", "Migrate users")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user