Repository navigation
feat(get-data): Spotter answer data (default on, with expired-answer reload) and iframe suppression flag - #225
mouryabalabhadra wants to merge 4 commits into
Conversation
… flags Let Claude read the rows behind an unsaved Analytics Agent answer, and let callers such as TriNet's proxy strip embedded visualizations from tool output. Both are behind undocumented URL flags and off by default. - enable-spotter-answer-data=true: get_data accepts object_type SPOTTER_ANSWER with the answer_id from get_session_updates. Rows come from the answer's CSV export (session + generation number) and are parsed into the get_data shape, skipping the data-extract watermark preamble. The description keeps the iframe-first default. - suppress-iframes=true: implies the above, drops iframe_url from session updates and its schema, strips embed links and iframe tags from update text (thinking included), drops frame_url from getAnswer, and steers Claude to build visuals from get_data.
There was a problem hiding this comment.
Code Review
This pull request introduces support for two new URL flags: enable-spotter-answer-data and suppress-iframes. These flags enable fetching the underlying data rows of unsaved Analytics Agent (Spotter) answers via CSV export, and stripping iframe HTML or embedded visualization links from the agent's responses. The changes include updating tool definitions, schemas, and handlers, implementing a custom CSV parser to handle the exports (including watermark removal), and adding comprehensive test coverage. There are no review comments to address, and I have no feedback to provide.
|
@copilot review PR |
Finding — Medium: |
…frame-suppression # Conflicts: # src/servers/mcp-server.ts # src/servers/tool-definitions.ts # src/services/clients/get-data/spotter-answer-data.ts # test/streaming-utils.spec.ts
- Strip the watermark preamble only when it reads "Data extract…", so a single-column answer with an empty cell no longer loses rows - Coerce a cell to a number only when it round-trips exactly, keeping leading-zero IDs, >2^53 integers and formatted text as strings - Give a permission hint instead of the expiry hint on 403 - Drop the unused title parameter
…ault
- answer_id now also carries conversation_id and message_id. These outlive
the answer's session ids (about 8 hours), and existing readers ignore them
- When the CSV export fails, get_data loads the answer again through
/conversation/v2/{conv}/message/{id}/load/public (the call the Visual
Embed SDK uses to replay answers) and exports with the fresh ids.
Not on 401/403, or for answer_ids without the conversation ids
- get_data on SPOTTER_ANSWER is on by default; enable-spotter-answer-data=false
turns it off. suppress-iframes stays opt-in and forces it on
What
get_datacan now read the rows behind a Spotter answer, including temporary and expired ones. This is on by default. A separate opt-in URL flag strips iframes. Design doc: "Spotter answer data in getData + iframe suppression".Spotter answer data (on by default;
enable-spotter-answer-data=falseturns it off)get_dataacceptsobject_type: "SPOTTER_ANSWER", withobject_idset to theanswer_idfromget_session_updates.exportAnswerReport(CSV, session + generation number), parsed into the existingget_dataresult shape:total_row_countis the full row count.max_rowshandling match the existingget_data(25 rows)."Data extract produced by …"preamble before the header, and it is only recognised by that text, so single-column answers with empty cells keep all their rows.get_datadescription keeps the iframe-first default: Claude shows Spotter's visualization, and fetches rows only when the user asks to chart, reshape, combine or build a dashboard.Expired answers
answer_idnow also carriesconversation_idandmessage_id, which last as long as the conversation does. Existing readers that only usesession_idandgen_no, such as the dashboard tools, are unaffected.get_dataloads the answer again withPOST /conversation/v2/{conversation_id}/message/{message_id}/load/public, then exports with the fresh ids. This is the same call the Visual Embed SDK makes to replay a stored answer. It re-runs the query, so it can be slow.answer_idissued before this change.suppress-iframes=true(opt-in and undocumented; also forces answer data on)iframe_urlis removed fromget_session_updatesresults and from its output schema. The schema text no longer mentions iframes, embeds or visualizations.<iframe>tags are stripped from update text, including thinking (and fromcontentin raw mode).frame_urlis removed from V1getAnswer.get_datadescription tells Claude to build visuals from the returned rows.With
suppress-iframesunset, iframes behave exactly as before. Withenable-spotter-answer-data=false,get_datais unchanged from before this PR.Why
Customers can front the server with its own proxy and Claude client. Today Claude can show a Spotter answer but can't read its rows, and Customer has no way to turn iframes off. Answer data is on by default for the doc's default-user story: "turn that into a Claude chart I can tweak".
Implementation notes
src/index.ts. Answer data is treated as on unless the prop is explicitlyfalse, so other entry points also default to on.applyUrlFlagToolOverrides(tool-definitions.ts). Stripping happens whenget_session_updatesreads the stored updates (stripEmbeddedVisualizations).answer_idis built inbuildAnswerId(streaming-utils.ts). The reload isloadSpotter3Answerinspotter-3-client.ts, recorded as theload_agent_conversation_answerupstream operation.Testing
SPOTTER_ANSWERcall paths: success, off switch, badanswer_id, export failure, 403;answer_id, conversation gone;loadSpotter3Answer, andgetAnswer.wrangler devagainst champagne-master-aws staging:SPOTTER_ANSWERis offered, iframes are kept, and real rows come back.enable-spotter-answer-data=false: unchanged from before, andSPOTTER_ANSWERis rejected.suppress-iframes=true: notsmcp, embed or iframe text in any update or tool definition, and real rows come back.session_idwith real conversation ids was reloaded throughload/publicand returned the same rows, in both default and suppress modes.Known gaps / follow-ups
SPOTTER_ANSWER. We rely on the tool description to keep models iframe-first, which needs a check in Claude before release.max_rows.get_datais hidden for them.skills/analyzing-data-with-thoughtspot/SKILL.md("Don't generate your own charts") conflicts with the suppressed flow.