u
This commit is contained in:
@@ -1119,7 +1119,7 @@
|
||||
* description: Id of the conversation that started this one as a subagent, or null for a top-level conversation. Deleting a conversation also deletes every conversation below it in this chain.
|
||||
* first_message:
|
||||
* type: [string, 'null']
|
||||
* description: Only returned by the list endpoint. Plain text of the conversation's first user message (max 200 chars, ellipsis if cut), or null if there is none yet.
|
||||
* description: Plain text of the conversation's first user message (XML stripped, max 100 chars, ellipsis if cut), or null if there is none yet.
|
||||
* ModelConversationCreateInput:
|
||||
* type: object
|
||||
* required: [provider, model]
|
||||
|
||||
@@ -4,7 +4,7 @@ import { RETIRED_MODELS, resolveDefaultModel } from '../../tools/llm-key.js';
|
||||
import { emit } from '../sse.js';
|
||||
import { getOrCreateManager, removeManager, cleanUserMessageContent } from '../../services/conversationManager.js';
|
||||
|
||||
const FIRST_MESSAGE_MAX_CHARS = 200;
|
||||
const FIRST_MESSAGE_MAX_CHARS = 100;
|
||||
|
||||
// #region Helpers
|
||||
|
||||
@@ -24,9 +24,26 @@ function parsePositiveInt(value, field) {
|
||||
return { id };
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes XML elements together with their content (e.g. `<USERENV><ROUTE>…</ROUTE></USERENV>`)
|
||||
* and any leftover self-closing tags.
|
||||
* @param {string} text
|
||||
* @returns {string}
|
||||
*/
|
||||
function stripXmlElements(text) {
|
||||
const elementPattern = /<([A-Za-z][\w:.-]*)(?:\s[^>]*)?>[\s\S]*?<\/\1\s*>/g;
|
||||
let previous;
|
||||
let stripped = text;
|
||||
do {
|
||||
previous = stripped;
|
||||
stripped = stripped.replace(elementPattern, '');
|
||||
} while (stripped !== previous);
|
||||
return stripped.replace(/<[A-Za-z][\w:.-]*(?:\s[^>]*)?\/>/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns the stored first user message payload (`{"content": ...}`) into short plain text
|
||||
* for conversation lists.
|
||||
* for conversation lists: JSON content only, XML elements stripped, outer whitespace trimmed.
|
||||
* @param {string|null} storedMessage
|
||||
* @returns {string|null}
|
||||
*/
|
||||
@@ -38,10 +55,19 @@ function buildFirstMessagePreview(storedMessage) {
|
||||
} catch {
|
||||
rawContent = storedMessage;
|
||||
}
|
||||
const text = cleanUserMessageContent(rawContent).trim();
|
||||
const text = stripXmlElements(cleanUserMessageContent(rawContent)).trim();
|
||||
return text.length > FIRST_MESSAGE_MAX_CHARS ? `${text.slice(0, FIRST_MESSAGE_MAX_CHARS)}…` : text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the store's raw `first_user_message` with the plain-text `first_message` preview.
|
||||
* @param {{ first_user_message: string|null }} row
|
||||
* @returns {object}
|
||||
*/
|
||||
function buildConversationResponse({ first_user_message: storedFirstMessage, ...conversation }) {
|
||||
return { ...conversation, first_message: buildFirstMessagePreview(storedFirstMessage) };
|
||||
}
|
||||
|
||||
function modelConversationErrorStatus(error) {
|
||||
if (error.message === 'No company selected') return 400;
|
||||
if (error.message === 'Not authorized') return 403;
|
||||
@@ -113,10 +139,7 @@ export function register(app, basePath = '') {
|
||||
|
||||
try {
|
||||
const rows = await db.list(req.user.id);
|
||||
const conversations = rows.map(({ first_user_message: storedFirstMessage, ...conversation }) => ({
|
||||
...conversation,
|
||||
first_message: buildFirstMessagePreview(storedFirstMessage),
|
||||
}));
|
||||
const conversations = rows.map(buildConversationResponse);
|
||||
res.status(200).json({ conversations });
|
||||
} catch (error) {
|
||||
const status = modelConversationErrorStatus(error);
|
||||
@@ -269,7 +292,7 @@ export function register(app, basePath = '') {
|
||||
}
|
||||
|
||||
try {
|
||||
const conversation = await db.get(req.user.id, parsedId.id);
|
||||
const conversation = buildConversationResponse(await db.get(req.user.id, parsedId.id));
|
||||
res.status(200).json({ conversation });
|
||||
} catch (error) {
|
||||
const status = modelConversationErrorStatus(error);
|
||||
|
||||
Reference in New Issue
Block a user