Files
Agent-System/web/src/engine/messageIdentity.ts
T
WeiCHEN d084056638 feat(task): inject uploaded documents into task materials and enable LAN host access
- backend: add Materials field to TaskRunRequestDTO and forward to ExecuteTask
- backend: add TestTaskStream_MaterialsInjection test case in taskstream_test.go
- web: serialize materials in buildTaskRequest and add unit test
- web: improve isSameMessage identity comparison in messageIdentity.ts
- web: configure host: '0.0.0.0' in vite.config.ts for LAN collaboration access
2026-09-11 13:22:02 +08:00

86 lines
2.4 KiB
TypeScript

import type { ChatMessage } from '../types/workbench';
/** 收集消息的所有可对账身份键 */
export function getMessageKeys(m: ChatMessage): string[] {
const keys: string[] = [];
if (m.clientTurnId) {
keys.push(`turn:${m.clientTurnId}:${m.role}`);
}
if (m.clientMessageId) {
keys.push(`client:${m.clientMessageId}`);
}
keys.push(`id:${m.id}`);
if (m.serverId) {
keys.push(`server:${m.serverId}`);
}
return keys;
}
/** 判断两条消息是否代表同一条物理消息 */
export function isSameMessage(a: ChatMessage, b: ChatMessage): boolean {
if (a.sessionId !== b.sessionId || a.role !== b.role) {
return false;
}
if (a.id && b.id && a.id === b.id) {
return true;
}
if (a.clientTurnId && b.clientTurnId && a.clientTurnId === b.clientTurnId) {
return true;
}
if (a.serverId && b.serverId && a.serverId === b.serverId) {
return true;
}
if (a.clientMessageId && b.clientMessageId && a.clientMessageId === b.clientMessageId) {
return true;
}
if (a.content === b.content && a.timestamp === b.timestamp) {
return true;
}
return false;
}
/** 构建历史 bucket 中已有消息的身份键集合 */
export function buildExistingMessageKeySet(messages: ChatMessage[]): Set<string> {
const keys = new Set<string>();
for (const m of messages) {
for (const k of getMessageKeys(m)) {
keys.add(k);
}
}
return keys;
}
/** live 消息是否已在历史中(按身份对账,而非仅 m.id) */
export function isLiveMessageInHistory(
live: ChatMessage,
historyMessages: ChatMessage[],
): boolean {
return historyMessages.some((h) => isSameMessage(live, h));
}
/** 过滤出尚未出现在历史中的 live 消息 */
export function filterPendingLiveMessages(
liveMessages: ChatMessage[],
historyMessages: ChatMessage[],
): ChatMessage[] {
return liveMessages.filter((m) => !isLiveMessageInHistory(m, historyMessages));
}
/** 用 live 流状态覆盖历史快照中的同一条消息 */
export function mergeLiveOverHistory(
history: ChatMessage,
live: ChatMessage,
): ChatMessage {
if (!isSameMessage(history, live)) {
return history;
}
return {
...history,
...live,
id: history.id,
serverId: live.serverId ?? history.serverId,
clientTurnId: live.clientTurnId ?? history.clientTurnId,
clientMessageId: live.clientMessageId ?? history.clientMessageId,
};
}