feat: AI 会话支持按轮保存完整笔记
This commit is contained in:
@@ -14,7 +14,6 @@ const GLOBAL_ENTRY_ID = 'system:global-chat';
|
||||
const LIMITS = {
|
||||
sessionId: 160,
|
||||
title: 200,
|
||||
messageText: 20000,
|
||||
question: 4000,
|
||||
contextText: 12000,
|
||||
contextHash: 32,
|
||||
@@ -252,7 +251,9 @@ function buildMessage(raw, role, lenient) {
|
||||
return {
|
||||
id: newId('msg'),
|
||||
role,
|
||||
text: limitedString(value.text, role === 'user' ? LIMITS.question : LIMITS.messageText),
|
||||
text: role === 'user'
|
||||
? limitedString(value.text, LIMITS.question)
|
||||
: String(value.text == null ? '' : value.text),
|
||||
task: normalizeTask(value.task, lenient),
|
||||
contextRef: role === 'user' ? normalizeContextRef(value.contextRef, lenient) : null,
|
||||
images: normalizeImages(value.images, lenient),
|
||||
@@ -807,7 +808,7 @@ function finishAssistant(sessionId, messageId, patch) {
|
||||
? held.message
|
||||
: doc.messages.find((item) => item.id === msgId && item.role === 'assistant');
|
||||
if (!message) throw new Error('会话消息不存在');
|
||||
message.text = limitedString(value.text == null ? message.text : value.text, LIMITS.messageText);
|
||||
message.text = String(value.text == null ? message.text : value.text);
|
||||
if (value.task !== undefined) message.task = normalizeTask(value.task, false);
|
||||
if (value.images !== undefined) message.images = normalizeImages(value.images, false);
|
||||
if (value.tokensEstimate !== undefined) message.tokensEstimate = count(value.tokensEstimate, 1e9);
|
||||
@@ -843,7 +844,7 @@ function normalizeBudget(budget) {
|
||||
return {
|
||||
maxChars: clampInt(value.maxChars, 50, 4000000, LIMITS.contextText),
|
||||
maxMessages: clampInt(value.maxMessages, 1, LIMITS.messagesPerSession, 20),
|
||||
maxMessageChars: clampInt(value.maxMessageChars, 50, LIMITS.messageText, LIMITS.question)
|
||||
maxMessageChars: clampInt(value.maxMessageChars, 50, 4000000, LIMITS.question)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+13
-17
@@ -11,7 +11,7 @@ const STANDALONE_ENTRY_ID = 'system:standalone-notes';
|
||||
const LIMITS = {
|
||||
id: 160,
|
||||
title: 500,
|
||||
text: 20000,
|
||||
canvasText: 20000,
|
||||
quote: 10000,
|
||||
context: 20000,
|
||||
aiTask: 500,
|
||||
@@ -24,7 +24,7 @@ const LIMITS = {
|
||||
locatorJson: 50000,
|
||||
richBlocks: 500,
|
||||
richOps: 5000,
|
||||
richJson: 12 * 1024 * 1024,
|
||||
canvasRichJson: 12 * 1024 * 1024,
|
||||
richImages: 12,
|
||||
richImageBytes: 2 * 1024 * 1024,
|
||||
richImageTotalBytes: 8 * 1024 * 1024,
|
||||
@@ -316,7 +316,6 @@ function normalizeRichContent(input) {
|
||||
}
|
||||
if (value.ops.length > LIMITS.richOps) throw new Error('富文本笔记内容过多');
|
||||
const result = { version: 2, ops: [] };
|
||||
let textLength = 0;
|
||||
let imageCount = 0;
|
||||
let imageBytes = 0;
|
||||
for (const op of value.ops) {
|
||||
@@ -325,8 +324,6 @@ function normalizeRichContent(input) {
|
||||
}
|
||||
const attributes = normalizeRichAttributes(op.attributes);
|
||||
if (typeof op.insert === 'string') {
|
||||
textLength += op.insert.length;
|
||||
if (textLength > LIMITS.text) throw new Error('富文本笔记文字过多');
|
||||
if (op.insert) result.ops.push({
|
||||
insert: op.insert,
|
||||
...(attributes ? { attributes } : {})
|
||||
@@ -349,7 +346,6 @@ function normalizeRichContent(input) {
|
||||
}
|
||||
result.ops.push({ insert: { image: image.dataUrl } });
|
||||
}
|
||||
if (JSON.stringify(result).length > LIMITS.richJson) throw new Error('富文本笔记过大');
|
||||
return hasRichContent(result) ? result : null;
|
||||
}
|
||||
|
||||
@@ -359,8 +355,7 @@ function richPlainText(content) {
|
||||
.filter((op) => typeof op.insert === 'string')
|
||||
.map((op) => op.insert)
|
||||
.join('')
|
||||
.replace(/\n$/, '')
|
||||
.slice(0, LIMITS.text);
|
||||
.replace(/\n$/, '');
|
||||
}
|
||||
|
||||
function hasRichContent(content) {
|
||||
@@ -431,7 +426,7 @@ function normalizeCanvasObject(value, imageTotals) {
|
||||
throw new Error('画布对象线宽无效');
|
||||
}
|
||||
if (value.canvasKind === 'text'
|
||||
&& (typeof value.text !== 'string' || value.text.length > LIMITS.text)) {
|
||||
&& (typeof value.text !== 'string' || value.text.length > LIMITS.canvasText)) {
|
||||
throw new Error('画布文字无效');
|
||||
}
|
||||
if ((value.canvasKind === 'pen' || value.canvasKind === 'highlight')
|
||||
@@ -475,7 +470,7 @@ function normalizeCanvasFlow(value, pageIds, firstPageId) {
|
||||
}
|
||||
if (typeof op.insert === 'string') {
|
||||
textLength += op.insert.length;
|
||||
if (textLength > LIMITS.text) throw new Error('画布全局文本文字过多');
|
||||
if (textLength > LIMITS.canvasText) throw new Error('画布全局文本文字过多');
|
||||
const attributes = normalizeRichAttributes(op.attributes);
|
||||
if (op.insert) result.ops.push({
|
||||
insert: op.insert,
|
||||
@@ -499,7 +494,7 @@ function normalizeCanvasFlow(value, pageIds, firstPageId) {
|
||||
breakIds.add(pageId);
|
||||
result.ops.push({ insert: { canvasPageBreak: pageId } });
|
||||
}
|
||||
if (JSON.stringify(result).length > LIMITS.richJson) throw new Error('画布全局文本过大');
|
||||
if (JSON.stringify(result).length > LIMITS.canvasRichJson) throw new Error('画布全局文本过大');
|
||||
const meaningful = result.ops.some((op) => (
|
||||
typeof op.insert === 'string' ? op.insert.trim() : !!op.insert.canvasPageBreak
|
||||
));
|
||||
@@ -593,14 +588,15 @@ function canvasPlainText(content) {
|
||||
return [flowText, objectText]
|
||||
.filter((text) => text.trim())
|
||||
.join('\n')
|
||||
.slice(0, LIMITS.text);
|
||||
.slice(0, LIMITS.canvasText);
|
||||
}
|
||||
|
||||
function notePlainText(richContent, canvasContent, fallback) {
|
||||
return [
|
||||
richContent ? richPlainText(richContent) : String(fallback || ''),
|
||||
const text = [
|
||||
richContent ? richPlainText(richContent) : String(fallback == null ? '' : fallback),
|
||||
canvasPlainText(canvasContent)
|
||||
].filter((value) => value.trim()).join('\n').slice(0, LIMITS.text);
|
||||
].filter((value) => value.trim()).join('\n');
|
||||
return canvasContent ? text.slice(0, LIMITS.canvasText) : text;
|
||||
}
|
||||
|
||||
function hasCanvasContent(content) {
|
||||
@@ -1023,7 +1019,7 @@ function noteInput(note, c) {
|
||||
if (noteType === 'canvas' && !hasCanvasContent(canvasContent)) {
|
||||
throw new Error('画布笔记内容为空');
|
||||
}
|
||||
const text = notePlainText(richContent, canvasContent, limitedString(note.text, LIMITS.text));
|
||||
const text = notePlainText(richContent, canvasContent, note.text);
|
||||
const quote = limitedString(note.quote, LIMITS.quote);
|
||||
if (!text.trim() && !quote.trim()
|
||||
&& !hasRichContent(richContent) && !hasCanvasContent(canvasContent)) {
|
||||
@@ -1104,7 +1100,7 @@ function updateNote(id, noteId, patch) {
|
||||
else delete note.canvasContent;
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(patch, 'text')) {
|
||||
fallbackText = limitedString(patch.text, LIMITS.text);
|
||||
fallbackText = String(patch.text == null ? '' : patch.text);
|
||||
if (note.noteType !== 'canvas'
|
||||
&& !Object.prototype.hasOwnProperty.call(patch, 'richContent')) {
|
||||
delete note.richContent;
|
||||
|
||||
Reference in New Issue
Block a user