diff --git a/internal/sse/citation_links.go b/internal/sse/citation_links.go index 17a6dbb..ef744b4 100644 --- a/internal/sse/citation_links.go +++ b/internal/sse/citation_links.go @@ -7,14 +7,12 @@ import ( type citationLinkCollector struct { ordered []string - seen map[string]struct{} explicitRaw map[int]string hasZeroIdx bool } func newCitationLinkCollector() *citationLinkCollector { return &citationLinkCollector{ - seen: map[string]struct{}{}, explicitRaw: map[int]string{}, } } @@ -129,10 +127,6 @@ func (c *citationLinkCollector) captureURLAndIndex(m map[string]any) { } func (c *citationLinkCollector) addOrdered(url string) { - if _, ok := c.seen[url]; ok { - return - } - c.seen[url] = struct{}{} c.ordered = append(c.ordered, url) } diff --git a/internal/sse/consumer_edge_test.go b/internal/sse/consumer_edge_test.go index 9b49788..d720414 100644 --- a/internal/sse/consumer_edge_test.go +++ b/internal/sse/consumer_edge_test.go @@ -166,6 +166,25 @@ func TestCollectStreamExtractsCitationLinksForOneBasedIndices(t *testing.T) { } } +func TestCollectStreamExtractsCitationLinksWithRepeatedURLsAndNilIndices(t *testing.T) { + resp := makeHTTPResponse( + "data: {\"p\":\"response/fragments/-1/results\",\"v\":[{\"url\":\"https://example.com/a\",\"cite_index\":null},{\"url\":\"https://example.com/a\",\"cite_index\":null},{\"url\":\"https://example.com/b\",\"cite_index\":null}]}\n" + + "data: {\"p\":\"response/content\",\"v\":\"结论[citation:1][citation:2][citation:3]\"}\n" + + "data: [DONE]\n", + ) + result := CollectStream(resp, false, false) + + if got := result.CitationLinks[1]; got != "https://example.com/a" { + t.Fatalf("expected citation 1 link, got %q", got) + } + if got := result.CitationLinks[2]; got != "https://example.com/a" { + t.Fatalf("expected citation 2 link, got %q", got) + } + if got := result.CitationLinks[3]; got != "https://example.com/b" { + t.Fatalf("expected citation 3 link, got %q", got) + } +} + func TestCollectStreamMultipleThinkingChunks(t *testing.T) { resp := makeHTTPResponse( "data: {\"p\":\"response/thinking_content\",\"v\":\"part1\"}\n" +