feat(KB-621): add AI title summarization feature
- Add core AI summarization service with model selection hierarchy - Modify task store to support title generation callback pattern - Add POST /api/ai/summarize-title endpoint with rate limiting - Wire up summarization in dashboard task creation flow - Add AI Summarization settings UI section in dashboard - Add comprehensive tests for summarization service and API - Document auto-summarization settings in AGENTS.md
This commit is contained in:
@@ -1667,3 +1667,58 @@ export function importSettings(
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
// --- AI Summarization API ---
|
||||
|
||||
/** Response from title summarization endpoint */
|
||||
export interface SummarizeTitleResponse {
|
||||
title: string;
|
||||
}
|
||||
|
||||
/** Summarize a task description into a concise title using AI.
|
||||
* @param description - The task description to summarize (must be 141-2000 chars)
|
||||
* @param provider - Optional AI model provider (e.g., "anthropic")
|
||||
* @param modelId - Optional AI model ID (e.g., "claude-sonnet-4-5")
|
||||
* @returns The generated title (guaranteed ≤60 characters)
|
||||
* @throws Error with descriptive message for 400/429/503 errors
|
||||
*/
|
||||
export async function summarizeTitle(
|
||||
description: string,
|
||||
provider?: string,
|
||||
modelId?: string
|
||||
): Promise<string> {
|
||||
const res = await fetch("/api/ai/summarize-title", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ description, provider, modelId }),
|
||||
});
|
||||
|
||||
const contentType = res.headers.get("content-type") ?? "";
|
||||
const bodyText = await res.text();
|
||||
const isJson = contentType.includes("application/json");
|
||||
|
||||
if (!isJson) {
|
||||
throw new Error(`API returned non-JSON response: ${bodyText.slice(0, 100)}`);
|
||||
}
|
||||
|
||||
const data = JSON.parse(bodyText) as { title?: string; error?: string };
|
||||
|
||||
if (!res.ok) {
|
||||
const errorMessage = data.error || "Request failed";
|
||||
if (res.status === 400) {
|
||||
throw new Error(`Invalid request: ${errorMessage}`);
|
||||
} else if (res.status === 429) {
|
||||
throw new Error(`Rate limit exceeded: ${errorMessage}`);
|
||||
} else if (res.status === 503) {
|
||||
throw new Error(`AI service temporarily unavailable: ${errorMessage}`);
|
||||
} else {
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
if (!data.title) {
|
||||
throw new Error("API returned empty title");
|
||||
}
|
||||
|
||||
return data.title;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user