feat: add user input history MCP and rebuild release
This commit is contained in:
98
server.js
98
server.js
@@ -5475,6 +5475,18 @@ function clampMcpLimit(value) {
|
||||
return Math.max(1, Math.min(100, parsed));
|
||||
}
|
||||
|
||||
function clampUserInputsLimit(value) {
|
||||
const parsed = Number.parseInt(String(value || ''), 10);
|
||||
if (!Number.isFinite(parsed)) return 15;
|
||||
return Math.max(1, Math.min(50, parsed));
|
||||
}
|
||||
|
||||
function clampUserInputsMaxChars(value) {
|
||||
const parsed = Number.parseInt(String(value || ''), 10);
|
||||
if (!Number.isFinite(parsed)) return 1000;
|
||||
return Math.max(1, Math.min(1000, parsed));
|
||||
}
|
||||
|
||||
function listConversationSummaries(args = {}, sourceSessionId = '') {
|
||||
reconcilePendingCrossConversationReplies();
|
||||
const scope = args.scope === 'children' ? 'children' : 'all';
|
||||
@@ -5532,6 +5544,90 @@ function listConversationSummaries(args = {}, sourceSessionId = '') {
|
||||
};
|
||||
}
|
||||
|
||||
function listUserInputHistory(args = {}, sourceSessionId = '') {
|
||||
const hasExplicitConversationId = Object.prototype.hasOwnProperty.call(args, 'conversationId');
|
||||
let conversationId;
|
||||
if (hasExplicitConversationId) {
|
||||
const rawConversationId = String(args.conversationId || '').trim();
|
||||
const sanitizedConversationId = sanitizeId(rawConversationId);
|
||||
if (!sanitizedConversationId || sanitizedConversationId !== rawConversationId) {
|
||||
return mcpToolError('invalid_conversation_id', 'conversationId 无效。', {
|
||||
conversationId: rawConversationId || null,
|
||||
});
|
||||
}
|
||||
conversationId = sanitizedConversationId;
|
||||
} else {
|
||||
conversationId = sanitizeId(sourceSessionId || '');
|
||||
if (!conversationId) {
|
||||
return mcpToolError('missing_source_conversation', '缺少来源对话 ID。');
|
||||
}
|
||||
}
|
||||
|
||||
const session = loadSession(conversationId);
|
||||
if (!session) {
|
||||
return mcpToolError('conversation_not_found', '目标对话不存在。', {
|
||||
conversationId,
|
||||
});
|
||||
}
|
||||
|
||||
const requestedLimit = clampUserInputsLimit(args.limit);
|
||||
const maxChars = clampUserInputsMaxChars(args.maxChars);
|
||||
const userMessages = (Array.isArray(session.messages) ? session.messages : [])
|
||||
.filter((message) => message?.role === 'user' && typeof message.content === 'string' && message.content.trim())
|
||||
.map((message) => ({
|
||||
messageId: message.id || message.messageId || null,
|
||||
createdAt: message.createdAt || message.timestamp || null,
|
||||
content: message.content,
|
||||
}));
|
||||
const candidates = userMessages.slice(-requestedLimit);
|
||||
const items = [];
|
||||
let remainingChars = maxChars;
|
||||
let totalChars = 0;
|
||||
let budgetLimited = false;
|
||||
|
||||
for (let index = candidates.length - 1; index >= 0; index -= 1) {
|
||||
if (remainingChars <= 0) {
|
||||
budgetLimited = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const candidate = candidates[index];
|
||||
const codePoints = Array.from(candidate.content);
|
||||
const originalChars = codePoints.length;
|
||||
const truncated = originalChars > remainingChars;
|
||||
const content = truncated ? codePoints.slice(0, remainingChars).join('') : candidate.content;
|
||||
const contentChars = truncated ? remainingChars : originalChars;
|
||||
|
||||
items.push({
|
||||
messageId: candidate.messageId,
|
||||
createdAt: candidate.createdAt,
|
||||
content,
|
||||
contentChars,
|
||||
originalChars,
|
||||
truncated,
|
||||
});
|
||||
totalChars += contentChars;
|
||||
remainingChars -= contentChars;
|
||||
|
||||
if (truncated) {
|
||||
budgetLimited = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
items.reverse();
|
||||
return {
|
||||
ok: true,
|
||||
conversationId,
|
||||
requestedLimit,
|
||||
maxChars,
|
||||
totalChars,
|
||||
returnedCount: items.length,
|
||||
hasMore: userMessages.length > candidates.length || budgetLimited || items.length < candidates.length,
|
||||
items,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeMcpPromptText(value, maxChars) {
|
||||
if (value === null || value === undefined) return '';
|
||||
return truncateTextValue(String(value).trim(), maxChars, '...');
|
||||
@@ -6296,6 +6392,8 @@ function callInternalMcpTool(tool, args, sourceSessionId, sourceHopCount) {
|
||||
return createCcwebDisplayImage(args, sourceSessionId);
|
||||
case 'ccweb_list_conversations':
|
||||
return listConversationSummaries(args, sanitizeId(sourceSessionId || ''));
|
||||
case 'ccweb_list_user_inputs':
|
||||
return listUserInputHistory(args, sourceSessionId);
|
||||
case 'ccweb_set_title':
|
||||
return setCurrentConversationTitle(args, sourceSessionId);
|
||||
case 'ccweb_create_conversation':
|
||||
|
||||
Reference in New Issue
Block a user