fix: prompt explorer citations always empty (annotations have no type field)#82
Open
bookingseo wants to merge 1 commit into
Open
fix: prompt explorer citations always empty (annotations have no type field)#82bookingseo wants to merge 1 commit into
bookingseo wants to merge 1 commit into
Conversation
extractCitations filtered annotations on `type === "citation"`, but
DataForSEO's LLM Responses payload returns untyped `{ title, url }`
reference objects — the SDK's AnnotationInfo has no type discriminator,
so the filter matched nothing and the prompt explorer's citations were
always empty even with web search enabled. Guard on URL safety only
(the real reason the loop existed) and add a unit test covering the
untyped-annotation, dedupe, unsafe-scheme, and non-message-item cases.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
extractCitationsinpromptExplorer.tsfilters annotations with:But the DataForSEO LLM Responses payload returns references as untyped
{ title, url }objects. The SDK model (AnnotationInfoindataforseo-client) is literally:There is no
typediscriminator, soannotation.typeis alwaysundefined, the guard is always true, and every citation is dropped — the Prompt Explorer shows sources in the model text but an empty citations list even whenweb_searchran. Thetype !== "citation"check looks copied from OpenAI's native Responses API (where annotations are typedurl_citation), but DataForSEO normalizes them to untyped references.Fix
Drop the spurious type filter; keep the URL-safety guard (
safeHttpUrl), which is the real reason the loop rejects entries (e.g.javascript:payloads rendered as<a href>). Confirmed against the DataForSEO docs (annotations documented as{ title, url }) and the generated SDK model.Adds a
promptExplorer.test.tscovering: untyped annotations are kept, URLs dedupe, unsafe schemes drop, and annotations outside message items are ignored.tscclean; new test passes.(Found while auditing AI-visibility citation coverage on a self-hosted deployment — citation rate was 0% across ChatGPT and Perplexity despite web search.)
Greptile Summary
This PR fixes Prompt Explorer citation extraction for DataForSEO LLM responses. The main changes are:
{ title, url }references.Confidence Score: 5/5
Safe to merge with minimal risk.
The production change is narrowly scoped to citation extraction, keeps the existing URL safety boundary, and includes focused tests for the changed behavior.
No files require special attention.
What T-Rex did
Important Files Changed
extractCitationsfor direct testing and accepts DataForSEO's untyped annotation references while preserving URL safety and dedupe guards.Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant PE as Prompt Explorer participant DFS as DataForSEO LLM Response participant EC as extractCitations participant UI as Prompt Explorer UI PE->>DFS: fetch model response DFS-->>PE: "items[].sections[].annotations [{title, url}]" PE->>EC: shapeSuccess(response) loop message item sections EC->>EC: validate annotation.url with safeHttpUrl EC->>EC: dedupe accepted URLs end EC-->>PE: PromptExplorerCitation[] PE-->>UI: model result with citations%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant PE as Prompt Explorer participant DFS as DataForSEO LLM Response participant EC as extractCitations participant UI as Prompt Explorer UI PE->>DFS: fetch model response DFS-->>PE: "items[].sections[].annotations [{title, url}]" PE->>EC: shapeSuccess(response) loop message item sections EC->>EC: validate annotation.url with safeHttpUrl EC->>EC: dedupe accepted URLs end EC-->>PE: PromptExplorerCitation[] PE-->>UI: model result with citationsReviews (1): Last reviewed commit: "fix(ai-search): stop dropping every LLM ..." | Re-trigger Greptile