feat(ai): single-shot note polishing for logged work entries

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Dave 2026-09-19 10:51:43 +02:00
parent 5283a455fa
commit 3c8edeb946

39
src/lib/ai/polish.ts Normal file
View file

@ -0,0 +1,39 @@
import "server-only";
import { getProvider, getSystemPrompt, AiError } from "@/lib/ai";
/** Longer than this and the model has ignored the "one or two sentences" instruction. */
const MAX_POLISHED_LENGTH = 600;
/**
* Rewrite a single owner-typed note in the same voice as a commit summary.
*
* Unlike summarise.ts's summariseProject, this is not batch- or DB-coupled —
* it is one piece of text being composed interactively in a form, so it is
* one direct provider call rather than the pending-rows pipeline built for
* re-summarizing hundreds of ingested commits at once.
*/
export async function polishNote(text: string): Promise<string> {
const provider = await getProvider();
const system = await getSystemPrompt();
const result = await provider.complete({
system,
user: `Rewrite the note below as one or two plain-English sentences for the client, in the same voice you use for commit summaries. Stay grounded in exactly what is written — do not invent detail, dates, or claims of completion beyond what the note itself says. Reply with only the rewritten text, nothing else.
Note:
${text.trim()}`,
// 16k, not a number that looks sufficient for two sentences — see the
// note in summarise.ts about MiniMax's inline reasoning being billed
// against max_tokens. A too-low cap here would silently return an
// empty string with no error, exactly as it did for commit summaries.
maxTokens: 16384,
});
const polished = result.text.trim();
if (!polished) {
throw new AiError("The assistant returned nothing usable", true);
}
return polished.slice(0, MAX_POLISHED_LENGTH);
}