Improve chat title generation and context compacting
This commit is contained in:
@@ -38,7 +38,7 @@ body.site-page { width:100%; max-width:none; margin:0; padding:0; background:var
|
||||
.chat-page .sidebar-workspace-card h2 { margin:0; font-size:.85rem; letter-spacing:0; font-family:var(--font-body); color:var(--text-soft); }
|
||||
.chat-page .chat-main { grid-template-rows:auto minmax(0,1fr) auto; }
|
||||
.chat-heading { min-width:0; }
|
||||
.chat-heading #workspaceNotice { margin:0; padding:10px 24px; border-width:0 0 1px; border-radius:0; font-size:.85rem; }
|
||||
.chat-heading #workspaceNotice { position:absolute; top:12px; right:16px; z-index:25; width:min(420px,calc(100% - 32px)); margin:0; padding:10px 14px; border-width:1px; border-radius:var(--radius-md); font-size:.85rem; box-shadow:var(--shadow-md); }
|
||||
.chat-page .chat-header { min-height:76px; }
|
||||
@media(max-width:1100px) { .shell-header { grid-template-columns:170px minmax(0,1fr) auto; gap:12px; padding:0 24px; }.shell-nav a { padding:0 10px; }.shell-username { max-width:90px; } }
|
||||
@media(max-width:980px) {
|
||||
|
||||
@@ -426,8 +426,9 @@ input:focus, textarea:focus, select:focus { border-color: var(--brand); }
|
||||
|
||||
.messages-wrap { min-height: 0; position: relative; display: grid; grid-template-rows: auto auto auto minmax(0, 1fr); }
|
||||
.messages-wrap > .messages-panel { grid-row: 4; }
|
||||
.conversation-search-toggle { display: none; }
|
||||
.conversation-search { padding: 8px max(16px, calc((100% - 940px) / 2)); display: flex; align-items: center; gap: 8px; border-bottom: 1px solid var(--border); }
|
||||
.conversation-search-toggle { display: block; justify-self: start; min-height: 32px; margin: 4px 10px; padding: 4px 10px; font-size: .75rem; }
|
||||
.conversation-search { display: none; padding: 8px max(16px, calc((100% - 940px) / 2)); align-items: center; gap: 8px; border-bottom: 1px solid var(--border); }
|
||||
.conversation-search.is-open { display: flex; }
|
||||
.conversation-search label { flex: 0 0 auto; color: var(--text-soft); font-size: .76rem; font-weight: 700; }
|
||||
.conversation-search input { min-width: 0; width: min(280px, 100%); min-height: 34px; }
|
||||
.conversation-search span { min-width: 64px; color: var(--text-muted); font-size: .72rem; white-space: nowrap; }
|
||||
@@ -700,7 +701,6 @@ input:focus, textarea:focus, select:focus { border-color: var(--brand); }
|
||||
.messages-empty-actions { display: grid; }
|
||||
.chat-drawer-action-list { grid-template-columns: 1fr; }
|
||||
.chat-drawer-action-list > * { grid-column: auto; }
|
||||
.conversation-search-toggle { display: block; justify-self: start; min-height: 32px; margin: 4px 10px; padding: 4px 10px; font-size: .75rem; }
|
||||
.conversation-search:not(.is-open) { display: none; }
|
||||
.conversation-search { padding: 6px 10px; flex-wrap: wrap; gap: 5px; }
|
||||
.conversation-search label { width: 100%; }
|
||||
|
||||
@@ -200,7 +200,6 @@ export function createComposerController({
|
||||
}
|
||||
await loadSummary();
|
||||
markOnboardingCompleted(); maybeShowPersonaNudge();
|
||||
setNotice("Reply received.", "success");
|
||||
} catch (error) {
|
||||
loadingMsg?.remove();
|
||||
const messageText = signal.aborted ? "Generation stopped." : error?.message || "Unable to send message.";
|
||||
|
||||
@@ -71,7 +71,9 @@ export function createConfig(overrides = {}) {
|
||||
chatHistoryLimit: positiveInt(process.env.CHAT_HISTORY_LIMIT, 20),
|
||||
chatSummaryUpdateEveryMessages: positiveInt(process.env.CHAT_SUMMARY_UPDATE_EVERY_MESSAGES, 8),
|
||||
chatSummaryMaxChars: positiveInt(process.env.CHAT_SUMMARY_MAX_CHARS, 2200),
|
||||
contextSummaryModel: process.env.CONTEXT_SUMMARY_MODEL || "nomic-embed-text:latest",
|
||||
chatMaxRetries: nonNegativeInt(process.env.CHAT_MAX_RETRIES, 5),
|
||||
titleModel: process.env.TITLE_MODEL || "nomic-embed-text:latest",
|
||||
modelApiBaseUrl: process.env.MODEL_API_BASE_URL || "https://ai.krishd.ch/api",
|
||||
modelRequestTimeoutMs: positiveInt(process.env.MODEL_REQUEST_TIMEOUT_MS, 180000),
|
||||
modelConnectTimeoutMs: positiveInt(process.env.MODEL_CONNECT_TIMEOUT_MS, 30000),
|
||||
|
||||
@@ -199,7 +199,7 @@ export function createChatService(repositories, modelService, config, webSearchP
|
||||
if (summarizable.length < config.chatSummaryUpdateEveryMessages) return;
|
||||
|
||||
const previousSummary = String(session.context_summary || "").trim();
|
||||
const summary = await modelService.generateReply(selectedModel, [
|
||||
const summary = await modelService.generateReply(config.contextSummaryModel || "nomic-embed-text:latest", [
|
||||
{
|
||||
role: "system",
|
||||
content: [
|
||||
@@ -687,8 +687,7 @@ export function createChatService(repositories, modelService, config, webSearchP
|
||||
if (session.assistant_persona_id || session.title !== "New chat" || repositories.getLatestChatMessage(chatId)) {
|
||||
return {title: session.title};
|
||||
}
|
||||
const {model: effectiveModel} = getGenerationSettings(session, model);
|
||||
const title = await generateChatTitle(message, effectiveModel, signal);
|
||||
const title = await generateChatTitle(message, config.titleModel || "nomic-embed-text:latest", signal);
|
||||
if (title !== "New chat") repositories.updateChatTitle(chatId, user, title);
|
||||
return {title};
|
||||
},
|
||||
|
||||
@@ -752,9 +752,11 @@ test("chat memories are durable facts included in model payload", async () => {
|
||||
test("chat context summary rolls up older messages into future payloads", async () => {
|
||||
let replyCount = 0;
|
||||
let latestPayload = [];
|
||||
let summaryModel = null;
|
||||
const modelService = {
|
||||
async generateReply(model, messagesPayload) {
|
||||
if (messagesPayload.some((message) => message.content.includes("Merge the previous summary"))) {
|
||||
summaryModel = model;
|
||||
return "Summary: user greeted the assistant and asked for continuity.";
|
||||
}
|
||||
latestPayload = messagesPayload;
|
||||
@@ -810,6 +812,7 @@ test("chat context summary rolls up older messages into future payloads", async
|
||||
|
||||
assert.ok(latestPayload.some((message) => message.role === "system" && message.content.includes("CONVERSATION SUMMARY")));
|
||||
assert.ok(latestPayload.some((message) => message.content.includes("user greeted the assistant")));
|
||||
assert.equal(summaryModel, "nomic-embed-text:latest");
|
||||
|
||||
await server.close();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user