refactor: differentiate reference marker handling between stream and non-stream modes

- Stream: strip both and [reference:N] markers to prevent
  leaking partial link metadata during incremental output
- Non-stream: convert citation/reference markers to Markdown links for
  Claude Messages, Gemini generateContent, and OpenAI Chat/Responses
- Remove StripReferenceMarkers option from call sites; behavior is now
  determined automatically by stream vs non-stream context
- Extend JS runtime stripReferenceMarkersText() to also match [citation:N]
- Add tests for streaming marker stripping and non-stream link conversion

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
CJACK
2026-05-03 17:53:49 +08:00
parent c099a6f7bf
commit 112bedb05d
14 changed files with 99 additions and 52 deletions

View File

@@ -615,17 +615,17 @@ test('parseChunkForContent preserves space-only content tokens', () => {
assert.deepEqual(parsed.parts, [{ text: ' ', type: 'text' }]);
});
test('parseChunkForContent strips reference markers from fragment content', () => {
test('parseChunkForContent strips citation and reference markers from fragment content', () => {
const chunk = {
p: 'response/fragments',
o: 'APPEND',
v: [
{ type: 'RESPONSE', content: '广州天气 [reference:12] 多云' },
{ type: 'RESPONSE', content: '广州天气 [citation:1] [reference:12] 多云' },
],
};
const parsed = parseChunkForContent(chunk, false, 'text');
assert.equal(parsed.finished, false);
assert.deepEqual(parsed.parts, [{ text: '广州天气 多云', type: 'text' }]);
assert.deepEqual(parsed.parts, [{ text: '广州天气 多云', type: 'text' }]);
});
test('parseChunkForContent detects content_filter status and ignores upstream output tokens', () => {