fix(ui): stabilize company chat result topology

This commit is contained in:
LZH-YS1998
2026-07-14 20:31:10 +08:00
parent 0a6246aff9
commit 5938b4c215
25 changed files with 1917 additions and 381 deletions
@@ -23,8 +23,8 @@ function messageMetadata(message: ChatMessage): Record<string, unknown> {
return (message.metadata ?? {}) as Record<string, unknown>
}
function normalizeMessageContent(content: string): string {
const normalized = String(content ?? '')
function normalizeMessageFormatting(content: string): string {
return String(content ?? '')
.replace(/\r\n/g, '\n')
.replace(/\r/g, '\n')
.split('\n')
@@ -32,6 +32,10 @@ function normalizeMessageContent(content: string): string {
.join('\n')
.replace(/\n{3,}/g, '\n\n')
.trim()
}
function normalizeMessageContent(content: string): string {
const normalized = normalizeMessageFormatting(content)
const titleStripped = stripNarrativeTitlePrefix(normalized)
const paragraphs = titleStripped.split(/\n{2,}/).map(part => part.trim()).filter(Boolean)
if (paragraphs.length > 1 && /^Verification:\s/i.test(paragraphs[paragraphs.length - 1])) {
@@ -41,21 +45,40 @@ function normalizeMessageContent(content: string): string {
}
function stripNarrativeTitlePrefix(content: string): string {
const trimmed = String(content || '').trim()
const markdownTitle = trimmed.match(/^\*\*(.{8,160}?)\*\*:\s+([\s\S]+)$/)
if (markdownTitle) {
let trimmed = String(content || '').trim()
// Only an explicit, first-line "**Title**: body" wrapper is removable.
// Searching for an arbitrary `: ` in the first N characters is destructive:
// ordinary Markdown such as "**Work Item 1: ...**" and list fields such as
// "- ID: ..." would be peeled one layer at a time on repeated syncs.
for (;;) {
const markdownTitle = trimmed.match(/^\*\*([^\r\n]{8,160}?)\*\*:(?:[ \t]+|\r?\n+)([\s\S]+)$/)
if (!markdownTitle) return trimmed
const body = markdownTitle[2].trim()
if (body.length >= 80) return body
if (body.length < 80 || body === trimmed) return trimmed
trimmed = body
}
const colonIndex = trimmed.indexOf(': ')
if (colonIndex < 8 || colonIndex > 160) return trimmed
}
const prefix = trimmed.slice(0, colonIndex).replace(/\*/g, '').trim()
const body = trimmed.slice(colonIndex + 2).trim()
if (body.length < 80) return trimmed
if (!/[A-Za-z\u4e00-\u9fff]/.test(prefix)) return trimmed
if (/^(https?|file)$/i.test(prefix)) return trimmed
return body
function losslessIdentityContent(
existing: ChatMessage,
candidate: ChatMessage,
preferred: ChatMessage,
sharesConcreteIdentity: boolean,
): string {
if (!sharesConcreteIdentity) return preferred.content
const existingComparable = normalizeMessageFormatting(existing.content)
const candidateComparable = normalizeMessageFormatting(candidate.content)
if (!existingComparable || !candidateComparable || existingComparable === candidateComparable) {
return preferred.content
}
// A cache/detail replay can contain a prefix-truncated copy of the same
// persistent message. Preserve the lossless source regardless of arrival
// order; unrelated edits still follow the normal preference rules.
if (existingComparable.endsWith(candidateComparable)) return existing.content
if (candidateComparable.endsWith(existingComparable)) return candidate.content
return preferred.content
}
function messageIdentityKeys(message: ChatMessage): Set<string> {
@@ -66,6 +89,9 @@ function messageIdentityKeys(message: ChatMessage): Set<string> {
for (const value of [
message.id,
typeof metadata.ui_message_id === 'string' ? metadata.ui_message_id : '',
typeof metadata.result_delivery_id === 'string' && metadata.result_delivery_id.trim()
? `delivery:${metadata.result_delivery_id.trim()}`
: '',
checkpointType && checkpointId ? `checkpoint:${checkpointType}:${checkpointId}` : '',
]) {
const normalized = String(value ?? '').trim()
@@ -81,7 +107,7 @@ function scopedMessageIdentityKeys(message: ChatMessage): Set<string> {
}
function isDerivedIdentityKey(value: string): boolean {
return value.startsWith('checkpoint:')
return value.startsWith('checkpoint:') || value.startsWith('delivery:')
}
function messageTimestamp(message: ChatMessage): number {
@@ -229,18 +255,17 @@ function mergeDuplicateMessages(
const existingIds = messageIdentityKeys(existing)
const candidateIds = messageIdentityKeys(candidate)
let sharesConcreteIdentity = false
let canonicalId = ''
for (const id of existingIds) {
if (candidateIds.has(id) && !isDerivedIdentityKey(id)) {
canonicalId = id
break
if (!candidateIds.has(id)) continue
if (!isDerivedIdentityKey(id)) {
sharesConcreteIdentity = true
if (!canonicalId) canonicalId = id
}
}
const normalizedContent = normalizeMessageContent(preferred.content)
const content = normalizedContent && normalizedContent === normalizeMessageContent(secondary.content)
? normalizedContent
: preferred.content
const content = losslessIdentityContent(existing, candidate, preferred, sharesConcreteIdentity)
const existingCheckpointId = String(messageMetadata(existing).checkpoint_id ?? '').trim()
const candidateCheckpointId = String(messageMetadata(candidate).checkpoint_id ?? '').trim()