feat(bridges): render agents under their display name on Teams and Telegram - #338
Open
raullopez-sandbox wants to merge 3 commits into
Open
Conversation
…legram The two platforms that still showed the identifier now show the presentation `display_name`, where one is set. The escaping they need already landed with the base resolver, so this is the rendering half alone. Teams resolves once per send. `_message_activity` called `agent_icon_url` and then handed `sender_name` to the card, which is two names for one speaker as soon as a display name exists; it now takes a single `AgentRendering` and `agent_message_card` takes it whole. The card header and `fallbackText` use `body_label` because a TextBlock renders markdown; `altText` and the activity `summary` use `field_label` because neither is rendered by any markup engine and the escaped form would show its own defusal to the reader. `mentions` is required rather than defaulting to `None` — every caller passes it, and the default only hid that. Telegram puts the label in the body because it has no per-message identity: one bot posts for every agent, so the name is the only thing telling two agents apart. All four attribution sites — message, attachment caption, album caption, runtime-status edit — take `body_label`, never `field_label`. Telegram links a bare `@handle` out of ordinary message text with no markup involved, so the unescaped form would notify that account from the prefix alone. The two escapes there do not compound: `escape_label_for_body` defuses the markup and `html.escape` neutralises the tags, and a zero-width space is not an entity. The per-agent mark stays keyed on the identifier. `display_name` and `icon_url` are both owner-settable, which leaves the mark as the only per-speaker signal on a Telegram message an impersonating agent cannot control. Keyed on the label instead, two agents sharing a display name would collapse onto one mark and an agent's mark would move when it is renamed, losing the recognisability the mark exists for. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
raullopez-sandbox
requested review from
amaudruz and
christian-mcdermott
as code owners
September 2, 2026 07:47
This was referenced Sep 2, 2026
…y-name-03-teams-telegram
The agent list API endpoint was not returning the display_name field, causing the Switch Console UI to not show agent display names. Changes: - Add display_name field to AgentInfo schema - Update list_agents handler to include display_name in response - Update list_delegatable_agents to include display_name Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
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.
Fourth PR in the display-name stack. Base is #330 — review that one first.
display_namecolumn has merged into it)feat(agents): store an optional human display name #326— thedisplay_namecolumn + API (merged)What changes
The two platforms that still showed the identifier now show the presentation
display_name, where one is set. The escaping they need already landed in #330,so this is the rendering half alone.
Teams
_message_activitycalledagent_icon_urland then handedsender_nameto thecard — two names for one speaker as soon as a display name exists. It now takes
a single
AgentRenderingandagent_message_cardtakes it whole, so a send isone DB lookup rather than two.
The same name is escaped in one place and raw in another, deliberately:
body_labelfallbackTextbody_labelaltTextfield_labelsummaryfield_labelA hostile display name of
[Switch Support](https://evil.example)thereforereaches the header defused and the
summaryraw. Escaping uniformly would havebeen the easier call and it degrades both — a screen reader would read the
zero-width space out, and the toast would show it.
mentionsonagent_message_cardis now required rather than defaulting toNone. Every caller passes it; the default only hid that.Telegram
Telegram has no per-message identity — one bot posts for every agent, so the
name in the body is the only thing telling two agents apart. All four
attribution sites take
body_label, neverfield_label: message, attachmentcaption, album caption, and the live runtime-status card that is edited in place
(which rebuilds the prefix itself rather than going through
send_message).field_labelwould be wrong here specifically because Telegram links a bare@handleout of ordinary message text with no markup involved, so theunescaped form would notify that account from the prefix alone.
The two escapes on that path do not compound:
escape_label_for_bodydefusesthe markup and
html.escapeneutralises the tags, and a zero-width space is notan entity.
The per-agent mark stays keyed on the identifier
display_nameandicon_urlare both owner-settable, which leaves the colouredmark as the only per-speaker signal on a Telegram message that an impersonating
agent cannot control. Keyed on the label instead, two agents sharing a display
name would collapse onto one mark, and an agent's mark would move when it is
renamed — losing the recognisability the mark exists for.
Captured from the real adapter:
Verification
mainin a throwaway worktree: clean, 2195 pass.before/afterdiffed.🤖 Generated with Claude Code