Skip to content

feat(commands): render agents under their display name in room commands - #343

Open
raullopez-sandbox wants to merge 1 commit into
feat/display-name-03-teams-telegramfrom
feat/display-name-06-commands
Open

feat(commands): render agents under their display name in room commands#343
raullopez-sandbox wants to merge 1 commit into
feat/display-name-03-teams-telegramfrom
feat/display-name-06-commands

Conversation

@raullopez-sandbox

Copy link
Copy Markdown
Collaborator

Stacked on #338. Review that one first; this diff is only the last commit.

What

The ! command surface was the last place still naming every agent by its
routing identifier. A room that shows "Switch Dev" in every bridged message
dropped back to "switchdev" the moment anyone ran !list-agents.

Which name a command prints is decided by one question — does the reader
have to type it back?

Surface Prints Why
!list-agents, !list-all-agents, !invite-agent, !alias, status replies Switch Dev (`switchdev`) the identifier is the thing you type next
!roles holders, !list-documents creators Switch Dev nobody addresses a document's author
room greeting @switchdev it is a live mention token and has to stay one

Listings sort on the label, so the order matches what is on screen rather than
a hidden identifier.

The security half

A display name is text a user typed, and these replies are handed to the
bridge, which escapes nothing on the way out but does rewrite a plain
@handle into a real mention. A display name of @everyone would have been a
mass ping — latent before this feature existed, armed by it.

Every command therefore defuses the label first. The zero-width-space
treatment the platform adapters already applied moves down into
agent_display_name so the command layer shares that one implementation
instead of growing a second copy:

stored : '@everyone'
posted : '- **@​everyone (`switchdev`)**'

Invisible to a reader, inert to the mention parser.

Verification

2237 pass (+47), ruff and mypy clean. Beyond the suite I mutation-tested the
six load-bearing claims — every one of them fails the suite when broken:

  • defusal reduced to identity → 41 failures (the bridge suite goes with it,
    which is what proves the extraction is genuinely shared rather than a copy)
  • agent_label / agent_label_with_identifier skipping defusal → 6 / 14
  • an agent with no display name rendering switchdev (`switchdev`) → 12
  • sort key reverting to the identifier → 2
  • a routing site switched to the display name → 1

That last one is the one worth keeping: it is the check that stops a later
edit from "consistently" applying the display name to the greeting and
silently breaking the mention it hands out.

🤖 Generated with Claude Code

The `!` command surface still named every agent by its routing identifier, so
a room that shows "Switch Dev" everywhere else fell back to "switchdev" the
moment someone ran `!list-agents`.

Which of the two names a command prints depends on what the reader does next:

- `!list-agents`, `!list-all-agents`, `!invite-agent`, `!alias` and the status
  replies print both — `Switch Dev (`switchdev`)` — because the identifier is
  what you type back.
- `!roles` holders and `!list-documents` creators print the label alone;
  nobody addresses a document's author.
- The room greeting keeps the bare identifier, because "Mention @switchdev"
  is a live mention token and has to stay one.

Listings now sort on the label, so the order matches what is on screen.

A display name is user-supplied text landing in a message body, and the
bridges rewrite a plain `@handle` into a real mention on the way out — so a
display name of `@everyone` was a mass ping waiting to happen. The zero-width
defusal that the platform adapters already applied moves into
`agent_display_name`, where the command layer shares one implementation of it
rather than growing a second.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.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.

1 participant