fix(yuanbao-adapter): correct fragment merge and json candidate parsing
Stop dropping short repeated fragments in mergeText (append them unless the duplicate is long enough to be a real echo) and drop the unreliable reverse-overlap branch. Return early from extractJSONCandidates when the whole body parses, and drop the seen-set so line-level frames are no longer deduped away. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -69,6 +69,36 @@ describe('yuanbao adapter helpers', () => {
|
||||
expect(mergeText(first, repeated)).toBe(repeated)
|
||||
})
|
||||
|
||||
it('preserves repeated Markdown tokens from incremental SSE frames', () => {
|
||||
const fragments = [
|
||||
'### 推荐清单\n\n- **',
|
||||
'拾光里',
|
||||
'**:本地工厂',
|
||||
'\n- **',
|
||||
'欧派',
|
||||
'**:全国连锁',
|
||||
'\n\n1. **',
|
||||
'看板材',
|
||||
'**',
|
||||
'\n2. **',
|
||||
'看封边',
|
||||
'**',
|
||||
]
|
||||
|
||||
const summary = parseYuanbaoCaptures([
|
||||
{
|
||||
url: 'https://yuanbao.tencent.com/api/chat/conversation-markdown',
|
||||
status: 200,
|
||||
contentType: 'text/event-stream',
|
||||
body: fragments.map((msg) => `data: ${JSON.stringify({ type: 'text', msg })}`).join('\n\n'),
|
||||
},
|
||||
])
|
||||
|
||||
expect(summary.answer).toBe(
|
||||
'### 推荐清单\n\n- **拾光里**:本地工厂\n- **欧派**:全国连锁\n\n1. **看板材**\n2. **看封边**',
|
||||
)
|
||||
})
|
||||
|
||||
it('keeps a valid API SSE answer even when the DOM fallback is longer', () => {
|
||||
const apiAnswer =
|
||||
'### 核心结论\n\n混动车兼顾补能效率与低速油耗。\n\n- 适合长途出行\n- 适合没有固定充电桩的用户'
|
||||
|
||||
@@ -426,8 +426,8 @@ function mergeText(current: string | null, nextFragment: string | null): string
|
||||
if (!current) {
|
||||
return nextFragment
|
||||
}
|
||||
if (current === nextFragment || current.includes(nextFragment)) {
|
||||
return current
|
||||
if (current === nextFragment) {
|
||||
return nextFragment.length >= 16 ? current : `${current}${nextFragment}`
|
||||
}
|
||||
if (nextFragment.startsWith(current)) {
|
||||
return nextFragment
|
||||
@@ -438,11 +438,6 @@ function mergeText(current: string | null, nextFragment: string | null): string
|
||||
return `${current}${nextFragment.slice(forwardOverlap)}`
|
||||
}
|
||||
|
||||
const reverseOverlap = sharedBoundaryLength(nextFragment, current)
|
||||
if (reverseOverlap > 0) {
|
||||
return `${nextFragment}${current.slice(reverseOverlap)}`
|
||||
}
|
||||
|
||||
const commonPrefixLength = sharedPrefixLength(current, nextFragment)
|
||||
const duplicatePrefixThreshold = Math.max(
|
||||
16,
|
||||
@@ -978,22 +973,24 @@ function attachYuanbaoResponseCapture(
|
||||
|
||||
function extractJSONCandidates(body: string): unknown[] {
|
||||
const values: unknown[] = []
|
||||
const seen = new Set<string>()
|
||||
|
||||
const pushParsed = (raw: string) => {
|
||||
const pushParsed = (raw: string): boolean => {
|
||||
const normalized = raw.trim()
|
||||
if (!normalized || seen.has(normalized)) {
|
||||
return
|
||||
if (!normalized) {
|
||||
return false
|
||||
}
|
||||
try {
|
||||
values.push(JSON.parse(normalized))
|
||||
seen.add(normalized)
|
||||
return true
|
||||
} catch {
|
||||
// Ignore malformed frames and continue with the remaining candidates.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
pushParsed(body)
|
||||
if (pushParsed(body)) {
|
||||
return values
|
||||
}
|
||||
|
||||
for (const rawLine of body.split(/\r?\n/)) {
|
||||
const line = rawLine.trim()
|
||||
|
||||
Reference in New Issue
Block a user