Skip to content

V2 chat: inline media players, image cards, agent-posted markdown, and interactive maps (0.261.224) - #1612

Merged
Paul Lizer (paullizer) merged 16 commits into
paullizer-react-v2-uifrom
paullizer-react-v2-inline-media
Oct 2, 2026
Merged

Paul Lizer (paullizer) merged 16 commits into
paullizer-react-v2-uifrom
paullizer-react-v2-inline-media

Conversation

@paullizer

@paullizer Paul Lizer (paullizer) commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Plays audio and video inline in the V2 chat, shows markdown images as captioned cards, renders messages an agent posts through the Simple Chat action as markdown, and draws interactive maps from Azure Maps action results. Adds an optional, validated allowlist of external media origins to the CSP media-src directive.

Refs #1611 and #1609. Stacked on #1608 (paullizer-react-v2-fix-group-upload-call-agent).

Changes

  • Inline audio player (InlineAudioPlayer.tsx): a markdown link whose URL path ends in an audio extension renders as an expanding bar with play/pause, title and elapsed/total time; expanded, it adds a seek slider, stop, volume and mute, playback speed and an open-in-new-tab link. Starting one recording pauses any other.
  • Inline video cards (InlineVideoCard.tsx): native controls (play, seek, volume, fullscreen) with a caption.
  • Image cards (InlineImageCard.tsx): markdown images become captioned cards that open the existing lightbox (rendered through a portal).
  • Fallback (InlineMediaFallback.tsx): media that cannot play shows a short notice and a link.
  • Renderer wiring (AssistantMarkdown.tsx, lib/inlineMedia.ts): new a and img components. Raw HTML stays off and react-markdown's default URL transform is unchanged; media sources and links pass through safeMediaUrl / safeMarkdownHref.
  • Agent-posted messages: add_conversation_message_for_current_user marks personal and shared messages with posted_via: agent_action and content_format: markdown; V2 renders only those as markdown in the neutral bubble and labels them "posted through an agent". Messages people type stay plain text.
  • CSP: CSP_MEDIA_SRC_ORIGINS (new csp_media_sources.py) appends validated bare https:// origins to media-src; anything else is rejected and logged.
  • Version 0.261.222.

Validation

  • functional_tests/test_v2_inline_media_players.py (7 checks, including the Node run of test_v2_inline_media_logic.mjs): passed.
  • test_v2_rich_rendering.py, test_v2_message_masking.py, test_v2_citations.py: passed (37 total with the new test).
  • test_simplechat_conversation_messages.py updated for the new keyword and marker; it needs the Cosmos test environment, as before.
  • XSS sink checker on the added lines: passed. V2 tsc --noEmit: passed.
  • Deployed to a SimpleChat POC deployment and exercised end to end with an agent that returns signed media links.

Docs

  • Feature doc: docs/explanation/features/V2_INLINE_MEDIA_AND_AGENT_MESSAGES.md.
  • Guides: create-an-action.md (media an action returns, CSP_MEDIA_SRC_ORIGINS), collaborate-in-a-conversation.md (messages an agent posts for you).
  • REACT_V2_UI.md CSP note.
  • Maps: docs/explanation/features/V2_INTERACTIVE_MAPS.md, the Azure Maps action reference ("What people see in chat"), the vendored-library table and test list in REACT_V2_UI.md, and the 0.261.223 release notes.

Interactive maps (0.261.223)

Replies that used the Azure Maps action now show their map in the V2 chat. Refs #1609.

  • Map card under the reply. Opens fitted to every marker, path and area. Pan by dragging; zoom with the buttons, double-click, pinch or Ctrl/Cmd + scroll (a plain scroll keeps scrolling the conversation); Full screen expands the map.
  • Details. Hovering a marker, path or area shows its label and description; a click keeps them open until the reader clicks elsewhere on the map or presses Escape.
  • Text alternative. List what the map shows lists every marker, path and area as text, for keyboard and screen reader users.
  • Vendored OpenLayers 10.6.1 under application/v2_ui/public/vendor/openlayers-10.6.1/ (ol.js, ol.css, LICENSE.md), byte-identical to the published ol@10.6.1 package and to the classic chat's copy, loaded only when a reply has a map. No npm dependency, no CDN asset, CSP unchanged.
  • Action output stays text. Titles, labels and descriptions are rendered by React or set with textContent. OpenLayers' attribution control writes its strings as HTML, so it is turned off and the attribution is shown as text in the footer. Tile templates must be /api/azure-maps/tile?... with {z}, {x}, {y}; colours must look like colours; coordinates are range-checked.
  • Compact citations. A map citation whose full result was moved to an artifact is fetched once through GET /api/conversation/<id>/agent-citation/<artifact_id>. Only map functions are fetched.
  • Tile tokens in older messages. GET /api/get_messages and GET /api/collaboration/conversations/<id>/messages now reissue expired tile tokens through refresh_azure_maps_message_citations, as the classic message route already did, so maps in older replies and in group conversations load their tiles. refresh_azure_maps_function_result no longer parses JSON-text results that cannot be maps.
  • Legacy {{map:...}} blocks are hidden from V2 reply text, as the classic chat hides them; the map comes from the tool result.

Validation

  • functional_tests/test_v2_inline_maps.py: 7 passed. Vendored bytes match the published SHA-256, no HTML sink, attribution control off, tiles only through the proxy, wiring, both endpoints refresh, and the refresh helper reissues expired tokens in object and JSON-text results without mutating its input.
  • functional_tests/test_v2_inline_maps_logic.mjs: 13 passed (Node, real module).
  • ui_tests/test_v2_inline_maps.py: 4 passed. Real MessageList and card in Chromium with production CSS: tiles from the proxy, Full screen control, no HTML attribution control, legacy block hidden, hover details, click to pin, Escape, compact citation fetched and drawn, text list, fallback when OpenLayers cannot load.
  • functional_tests/test_v2_rich_rendering.py registers OpenLayers with the vendored-library and forbidden npm dependency checks. functional_tests/test_content_screening_history.py gets the new helper in its route namespace. functional_tests/test_v2_enhanced_citations.py now checks the built media-src directive, since 0.261.222 moved that literal out of config.py.
  • npm run typecheck and the Vite build pass.
  • Also exercised in a browser harness against stored map payloads from a SimpleChat POC deployment: both maps drew with tiles only through the proxy and no console errors.

Not in this change

  • Classic chat still shows details on click only; hover tooltips are V2-only for now.
  • Conversation exports do not draw maps.

Map tiles in stored replies (0.261.224)

Deploying 0.261.223 to a SimpleChat POC deployment showed the cards drawing correctly but every tile request returning 400. The cause was older than the V2 work.

  • Tool results go through sanitize_plugin_invocation_value before they are stored as citations, in chat and in the workflow runner. Its token= rule replaced the map payload's tile proxy token with ***REDACTED***, so every stored map, classic or V2, drew on blank tiles.
  • _redact_secret_assignment now keeps the token= value only where it directly follows /api/azure-maps/tile?, which is where build_tile_proxy_url_template writes it. That token is encrypted with the app's secret key, expires, and only works on SimpleChat's signed-in tile proxy. Every other token=, another key after the prefix, a token later in the query, absolute URLs and every other secret are still redacted.
  • Maps stored before this change keep the redacted token, which cannot be reissued. They still show no tiles.
  • Tests: test_v2_inline_maps.py::test_tool_result_redaction_keeps_only_the_tile_proxy_token runs the real logger and Azure Maps helpers. test_plugin_tool_agent_security_audit.py and test_log_injection_codeql_alerts_fix.py still pass (47).
  • Docs: docs/explanation/fixes/AZURE_MAPS_TILE_TOKEN_REDACTION_FIX.md, the V2 maps feature doc and the 0.261.224 release notes.

Post the upload status before reading the document so the etag-guarded write in upload_to_blob no longer conflicts with its own status update (every group upload failed with Enhanced Citations on). Allow the server-bound scope_id on Call agent manifests so scoped saves pass validation. Adds regression tests and fix notes; version 0.261.217.
…p members without Graph

Background runs take the owner's stored display name and email instead of the bare object ID, which also stops them overwriting the stored display name. add_user_to_group accepts a user_id with email or display name, as the REST members route does, and group conversation invites match current group members before any directory lookup. Version 0.261.218.
GPT-6 deployments reject max_tokens. Recognize gpt-6 alongside gpt-5 so response length uses max_completion_tokens and no temperature is sent. Version 0.261.219.
…restriction in the model catalog

gpt-6-astra becomes a token-evidenced record: 1,050,000 context, 922,000 input and 128,000 output for OpenAI and Azure, total-generation accounting, and a Chat Completions reasoning policy of low, medium, high and xhigh. Azure Chat Completions rejects its function tools unless reasoning_effort is none, which the model rejects; toolReasoningEfforts can't express that, so it's recorded in notes. Refs #1606.

Version 0.261.220.
…rt none

gpt-6-sol gets verified 1,050,000 context, 922,000 input and 128,000 output limits, a reasoning policy of none through xhigh, and Chat Completions toolReasoningEfforts of none for OpenAI and Azure. OpenAI documents that its Chat Completions function calling requires none, and Azure behaved the same. Agents with tools and no effort now send none; another explicit effort fails before the request. Refs #1606.

Version 0.261.221.
Group document uploads with Enhanced Citations, Call agent action saves, scheduled-run identity, GPT-6 request parameters, and the GPT-6 Astra and Sol catalog records. Refs #1605, #1606.
…der agent-posted messages as markdown

Audio links become an expanding player (play/pause, stop, seek, volume, speed), video links become cards with native controls, and markdown images become captioned cards with the lightbox. One recording plays at a time. Messages an agent posts through add_conversation_message are marked as agent-authored markdown and render like agent replies. CSP_MEDIA_SRC_ORIGINS adds validated https origins to media-src. Version 0.261.222. Refs #1611.
Comment thread functional_tests/test_group_document_blob_upload_etag.py Fixed
Replies that used the Azure Maps action now show their map under the text in the V2 chat. The map opens fitted to all features. It pans and zooms with Ctrl/Cmd + scroll, so a plain scroll still scrolls the conversation, and it has a full screen control. Hovering a marker, path or area shows its details, and a click pins them. A text list shows everything on the map.

OpenLayers 10.6.1 is vendored into public/vendor, byte-identical to the published package and to the classic chat's copy, and loaded only when a reply has a map. Map text is only written as text. OpenLayers' HTML attribution control is off, and tiles only load through /api/azure-maps/tile.

/api/get_messages and the collaboration messages endpoint now reissue expired tile tokens, so maps in older replies and in group conversations load their tiles. Compact map citations are fetched by artifact. Legacy {{map:...}} blocks are hidden from reply text.

Also updates the V2 enhanced citations CSP check for the media-src directive that 0.261.222 moved into csp_media_sources.py.

Version 0.261.223. Refs #1609.
@paullizer Paul Lizer (paullizer) changed the title V2 chat: inline audio and video players, image cards, and agent-posted markdown (0.261.222) V2 chat: inline media players, image cards, agent-posted markdown, and interactive maps (0.261.223) Oct 2, 2026
@paullizer Paul Lizer (paullizer) changed the title V2 chat: inline media players, image cards, agent-posted markdown, and interactive maps (0.261.223) V2 chat: inline audio and video players, image cards, and agent-posted markdown (0.261.222) Oct 2, 2026
@paullizer Paul Lizer (paullizer) changed the title V2 chat: inline audio and video players, image cards, and agent-posted markdown (0.261.222) V2 chat: inline media players, image cards, agent-posted markdown, and interactive maps (0.261.223) Oct 2, 2026
Tool results are redacted before they are stored as a reply's citations, and that redaction replaced the map payload's tile proxy token with ***REDACTED***. Every stored map then requested tiles with an unusable token and drew its markers and paths on blank tiles, in the classic and V2 chat alike.

sanitize_plugin_invocation_value now keeps the token= value only where it directly follows /api/azure-maps/tile?, which is exactly where build_tile_proxy_url_template writes it. That token is encrypted with the app's secret key, expires, and only works on SimpleChat's signed-in tile proxy. Every other token= value, a token later in the query, another key after the prefix, absolute URLs and every other secret are still redacted.

Maps stored before this change keep the redacted token and still show no tiles.

Version 0.261.224. Refs #1609.
@paullizer Paul Lizer (paullizer) changed the title V2 chat: inline media players, image cards, agent-posted markdown, and interactive maps (0.261.223) V2 chat: inline media players, image cards, agent-posted markdown, and interactive maps (0.261.224) Oct 2, 2026
Paul Lizer (paullizer) and others added 2 commits October 2, 2026 16:13
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
…call-agent

Resolves the conflicts with #1607. Both branches started from 0.261.216 and used 0.261.217. VERSION stays 0.261.221, and the release notes combine both 0.261.217 entries under one heading.
…oad-call-agent' into paullizer-react-v2-fix-group-upload-call-agent
…eact-v2-inline-media

Brings in #1608 and the base (#1607). VERSION stays 0.261.224. The group upload test keeps #1608's version of the shared CodeQL autofix.
A map point can carry an https photo, a caption and label/value fields. The V2 popup shows them as text, the photo opens full size, and the map's text list includes them. The popup opens on the side with room and a pinned popup pans into view. Refs #1609. Version 0.261.225.
@paullizer
Paul Lizer (paullizer) merged commit 16d4734 into paullizer-react-v2-ui Oct 2, 2026
10 checks passed
Paul Lizer (paullizer) added a commit to paullizer/simplechat that referenced this pull request Oct 2, 2026
) into 6b-1

Merged with rerere disabled. Two files conflicted:
- application/single_app/config.py: kept this branch's VERSION line for the
  merge; the next commit renumbers 0.261.218 to 0.261.226 because V2 is now
  at 0.261.225.
- docs/explanation/release_notes.md: this branch's section stays on top,
  followed by V2's 0.261.224 to 0.261.218 sections unchanged.

route_backend_conversations.py merged cleanly (hunks do not overlap).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer) added a commit to paullizer/simplechat that referenced this pull request Oct 2, 2026
V2 is now at 0.261.225 (microsoft#1612 with microsoft#1608), so this branch takes the next
version. Mechanical change only: 51 occurrences in 21 files, all on lines this
branch added (config.py VERSION, the release-notes heading, test headers,
route-inventory docstrings and the feature docs). V2's own 0.261.218 lines
from microsoft#1608 are unchanged.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants