Repository navigation
fix(greeting): introduce the agent by its s.space display name - #6270
Conversation
A greeting (the first-contact reply, the room-onboard greeting) had no source for the agent's own name, so the model fell back to a persona or default name that can differ from the display name s.space shows. src/agent_display_name.py is the one resolver for that name: the live Matrix profile displayname, then the connection record's display name for this agent, then SUTANDO_DISPLAY_NAME / AGENT_DISPLAY_NAME, then the mxid localpart, then "Sutando"; never a Stand persona name. The tutorial's `--name auto` now delegates to it, and CLAUDE.md/AGENTS.md and the room-onboard skill tell the agent to use it when introducing itself. Sutando-Task: task-51d648dbbfc7cfcd16 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Coverage Gate✅ Diff coverage PASSES the 95% bar. Whole-tree (informational): 93%. Diff CoverageDiff: origin/main...HEAD, staged and unstaged changes
Summary
|
…process resolve() with no mxid, and the CLI's --room / --agent-mxid / own-identity order, now run in process so diff coverage sees them; the channel_value import guard is dropped (the module sits beside it in src/). Sutando-Task: task-51d648dbbfc7cfcd16 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
qingyun-wu
left a comment
There was a problem hiding this comment.
Reviewed at b27cf73. CI is green, and the design is right: one resolver, the tutorial delegates to it with no copy left behind, and voice/phone are untouched. One fix is needed before this merges:
--room loses the cross-server guard (src/agent_display_name.py, _main). room_agent_mxid() returns '' on purpose when the room's connection names no identity. Its docstring says this is "so another server's identity is never used". mxid = room_agent_mxid(args.room) or None turns that '' into None, so the next block falls back to agent_mxid(), the primary connection's identity. A NoConnectionForRoom raised inside the suppress does the same.
Failure case: an install with several connections greets a room on a secondary server whose row names no identity. It introduces itself by the primary agent's display name, the wrong-name bug this PR exists to fix. Keep '' as '', so resolve("") gives the configured name and then "Sutando". Decide explicitly whether NoConnectionForRoom should fall back. Add a test for the '' return; the current test pins the fallback.
Non-blocking:
- The
from channel_credentials import ...inconfigured_nameandagent_mxidsits outside any suppress. A failed import makesresolve()raise, which breaks the "never fails" promise. - The profile tier wins with Synapse's default displayname, the localpart. An agent that never set a name is introduced as its raw account name. That matches what s.space shows, so it's fine if intended.
…nt's name `--room` turned room_agent_mxid()'s deliberate '' (the room's connection names no identity) into None, and swallowed NoConnectionForRoom the same way, so both fell back to the primary connection's identity and its display name. Both now resolve with no mxid: the configured name, else "Sutando". A tier that raises (a failed import included) now leaves the next tier instead of failing resolve(). Sutando-Task: task-51d648dbbfc7cfcd16 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@cla-assistant check |
|
Thanks @qingyun-wu, good catch. Fixed in 5bcb555. Cross-server guard (blocking). In Never fails (non-blocking). I took this one too: a tier that raises, a failed import included, now falls through to the next tier instead of raising from Profile tier with the server's default displayname. That's intended. It is what s.space shows for the agent, so the greeting matches it. Tests. I added three to
(agent-assisted, Claude Code for Chi Wang's seat) |
qingyun-wu
left a comment
There was a problem hiding this comment.
Re-reviewed at 5bcb555; the blocking point is fixed. room_agent_mxid's '' is now kept and resolves to the configured name or 'Sutando', and any failure of the room lookup sets mxid to '', so the primary's identity is never borrowed. OtherServerRoomTest pins both cases, and both would fail at b27cf73. resolve() now isolates each tier, so a failed import can't make it raise. CI: 46 pass, 1 skipped. Nit, non-blocking: the broad except at the room lookup also catches an ImportError of channel_credentials. That fails closed and is consistent with the rule, but narrowing it to NoConnectionForRoom would make the intent exact.
Priority
Level: high
Reason: P1 from QA stress tests: on a fresh install the agent's greeting introduces it by a different name than the one s.space shows for it.
Closes
N/A (QA report, no issue filed).
Summary
Bug. A test agent whose display name differs from its internal persona name greeted its owner with the persona/default name instead of its s.space display name.
Root cause. Nothing hands the text agent its own display name. The bridge writes no agent-name task header (and reads only the mxid from whoami),
SUTANDO_DISPLAY_NAMEonly flows outward in the profile card, and neither CLAUDE.md/AGENTS.md nor the room-onboard skill ("I'm ") names a source. The model fills the gap with "Sutando" or a persona/Stand name from memory. Only the tutorial's Getting started page looked the display name up, privately ingetting_started.py.Fix. One resolver,
src/agent_display_name.py, for the name used in any self-introduction:agent_display_namethe gateway recorded for this same agent on its connection row (state/connections.json), when (1) is unreachable;SUTANDO_DISPLAY_NAME, elseAGENT_DISPLAY_NAME(env, else the channel env file);Sutando.A Stand persona name is never used. CLI:
python3 src/agent_display_name.py [--room ROOM] [--json].Every introduction path now uses it:
--name auto:getting_started.resolve_namedelegates to the resolver (its private profile/localpart/mxid code moved there, so there's one copy).No tuned prompt text changed beyond naming the name source.
Look first at:
src/agent_display_name.py, thenskills/tutorial/scripts/getting_started.py(the delegation).Out of scope, flagged: the local voice and phone prompts (
src/voice-agent-config.ts,skills/phone-conversation/) introduce the agent as "Sutando — ". These are tuned voice prompts on surfaces that are not s.space, so they're left unchanged here. Moving them to this name needs a separate decision.Docs: N/A. The behavior lives in the skill docs this PR updates (room-onboard, tutorial) and in CLAUDE.md. No
docs/canonical page covers greeting names.docs/src-map.mdis regenerated for the new module.Checklist
gh pr list --state open --search "greeting OR display name OR persona")origin/main(below)tests/agent-display-name.test.pyscripts/review-checks.shPASSconnections.read_rows/channel_credentials/claude_home_path, no new path resolutionBefore / after evidence
The test fixture is a test agent with display name "Display Name X" and a different persona name in
stand-identity.json.Before (origin/main + the new test):
With only the resolver module copied onto main, the greeting-path contract still fails, because no introduction path names a source:
After (head):
Each run used
env -i,nice -n 19, and the shared test lock.Mutations (each killed):
FAILED (failures=1)FAILED (failures=1)Also run:
ruff checkclean,bash scripts/agents-md-sync.sh --checkup to date,lint-skill0 errors, lint-workspace-resolution / lint-claude-home-path / lint-sutando-home-path / lint-host-label pass,tests/agents-md-sync.test.pyandtests/claude-md-conduct-rules.test.pypass.Agent-assisted: written by Claude Code for Chi Wang.
🤖 Generated with Claude Code