Files
beaver_project/app-instance/frontend/lib/chat-messages.ts
steven_li 6e9e74d1ee feat(engine): 添加运行时上下文支持并重构工具迭代限制
添加 RuntimeContext 类用于捕获模型运行时的日期时间信息,
包括UTC时间、本地时间和时区信息,并在系统提示中显示这些信息。

同时增加最大上下文消息数和工具迭代次数的配置选项,
将验证服务从引擎加载器中移除,并更新相关的数据结构和接口。

BREAKING CHANGE: 移除了验证服务,相关字段被替换为证据状态和接受状态。

- 添加 RuntimeContext 类和相关渲染方法
- 增加 max_context_messages 和 max_tool_iterations 配置
- 移除 ValidationService 相关代码
- 更新消息记录中的验证状态字段
- 添加原始工具调用检测和回退处理
2026-05-26 11:18:35 +08:00

104 lines
2.8 KiB
TypeScript

import type { ChatMessage } from '@/types';
const INVISIBLE_CONTENT_CHARS = /[\u200B-\u200D\uFEFF]/g;
export function normalizedMessageText(content: unknown): string {
if (typeof content === 'string') {
return content.replace(INVISIBLE_CONTENT_CHARS, '').trim();
}
if (content == null) {
return '';
}
return String(content).replace(INVISIBLE_CONTENT_CHARS, '').trim();
}
export function hasVisibleChatContent(msg: ChatMessage): boolean {
if (normalizedMessageText(msg.content)) {
return true;
}
return Boolean(msg.attachments?.length);
}
export function shouldDisplayChatMessage(msg: ChatMessage): boolean {
return msg.role !== 'assistant' || hasVisibleChatContent(msg);
}
export function messageFingerprint(msg: ChatMessage): string {
const attachmentKey = (msg.attachments ?? [])
.map((a) => `${a.file_id ?? ''}:${a.name}:${a.content_type}:${a.size ?? ''}`)
.join('|');
return `${msg.role}::${String(msg.content)}::${attachmentKey}`;
}
export function mergeServerWithPendingUsers(serverMessages: ChatMessage[], localMessages: ChatMessage[]): ChatMessage[] {
const counts = new Map<string, number>();
for (const message of serverMessages) {
const key = messageFingerprint(message);
counts.set(key, (counts.get(key) ?? 0) + 1);
}
const pendingUsers: ChatMessage[] = [];
for (const message of localMessages) {
const key = messageFingerprint(message);
const count = counts.get(key) ?? 0;
if (count > 0) {
counts.set(key, count - 1);
continue;
}
if (message.role === 'user') {
pendingUsers.push(message);
}
}
return [...serverMessages, ...pendingUsers];
}
export function shouldMergePendingUsers(
serverMessages: ChatMessage[],
localMessages: ChatMessage[],
waitingForReply: boolean
): boolean {
if (waitingForReply) {
return true;
}
const lastLocal = localMessages[localMessages.length - 1];
if (lastLocal?.role !== 'user') {
return false;
}
const counts = new Map<string, number>();
for (const message of serverMessages) {
const key = messageFingerprint(message);
counts.set(key, (counts.get(key) ?? 0) + 1);
}
for (const message of localMessages) {
if (message.role !== 'user') {
continue;
}
const key = messageFingerprint(message);
const count = counts.get(key) ?? 0;
if (count > 0) {
counts.set(key, count - 1);
continue;
}
return true;
}
return false;
}
export function getTaskCardMessageIndexes(messages: ChatMessage[]): Set<number> {
const latestByTask = new Map<string, number>();
messages.forEach((message, index) => {
if (message.role !== 'assistant' || !message.task_id) {
return;
}
latestByTask.set(message.task_id, index);
});
return new Set(latestByTask.values());
}