feat(coding-agent): add configurable title system prompt for sessions
- add discovery of `TITLE_SYSTEM.md` and pass it through interactive startup context - route custom title prompts to online and local tiny title generators via protocol - update session-title docs and changelog with override behavior - add tests for prompt discovery, forwarding, and fallback to bundled title prompts
This commit is contained in:
@@ -71,6 +71,49 @@ describe("title generator", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("uses the bundled default prompt when no title prompt file is resolved", async () => {
|
||||
const model = getModelOrThrow("claude-sonnet-4-5");
|
||||
const completeSimpleMock = vi.spyOn(ai, "completeSimple").mockResolvedValue({
|
||||
stopReason: "stop",
|
||||
content: [{ type: "toolCall", id: "call-title", name: "set_title", arguments: { title: "Default Prompt" } }],
|
||||
} as never);
|
||||
|
||||
await generateSessionTitle("Investigate the resolver", createRegistry(model), createSettings(model));
|
||||
|
||||
const request = completeSimpleMock.mock.calls[0]?.[1] as { systemPrompt?: string[] } | undefined;
|
||||
expect(request?.systemPrompt).toHaveLength(1);
|
||||
expect(request?.systemPrompt?.[0]).toContain("Generate a concise, sentence-case title");
|
||||
});
|
||||
|
||||
it("uses the resolved TITLE_SYSTEM.md prompt for online title generation", async () => {
|
||||
const model = getModelOrThrow("claude-sonnet-4-5");
|
||||
const customPrompt = "Generate lowercase colon-delimited session names.";
|
||||
const completeSimpleMock = vi.spyOn(ai, "completeSimple").mockResolvedValue({
|
||||
stopReason: "stop",
|
||||
content: [{ type: "toolCall", id: "call-title", name: "set_title", arguments: { title: "fix:resolver" } }],
|
||||
} as never);
|
||||
|
||||
await generateSessionTitle(
|
||||
"Investigate the resolver",
|
||||
createRegistry(model),
|
||||
createSettings(model),
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
customPrompt,
|
||||
);
|
||||
|
||||
const request = completeSimpleMock.mock.calls[0]?.[1] as
|
||||
| { systemPrompt?: string[]; tools?: Array<{ name?: string }> }
|
||||
| undefined;
|
||||
const options = completeSimpleMock.mock.calls[0]?.[2] as
|
||||
| { toolChoice?: { type?: string; name?: string } }
|
||||
| undefined;
|
||||
expect(request?.systemPrompt).toEqual([customPrompt]);
|
||||
expect(request?.tools?.[0]?.name).toBe("set_title");
|
||||
expect(options?.toolChoice).toEqual({ type: "tool", name: "set_title" });
|
||||
});
|
||||
|
||||
it("falls back to text content when no set_title tool call is returned", async () => {
|
||||
const model = getModelOrThrow("claude-sonnet-4-5");
|
||||
vi.spyOn(ai, "completeSimple").mockResolvedValue({
|
||||
|
||||
Reference in New Issue
Block a user