Skip to content

feat: Agent display_name — schema, API, and MCP surface (#964 follow-up 1/5) #1639

Description

@vybe

Summary

Add an optional owner-settable display_name column to agent_ownership and surface it end-to-end through GET /api/agents and the MCP list_agents response. Ships no UI — this is the data layer that unblocks the rest of the #964 split.

Follow-up 1 of 5 from the design decision on #964. The slug remains the identity everywhere machines look; display_name is additive and UI-only.

Context

Per the decision recorded on #964: a friendly agent name already renders on three surfaces today, sourced from template.yaml — but it isn't owner-editable, disappears when the agent stops (it's a live HTTP call into the container), and covers 3 of ~67 render sites. Two further surfaces already fake a friendly name: src/backend/routers/public.py falls back through template info → trinity.agent-type label → slug, and src/backend/routers/voice.py uses agent_name.replace("-", " ").title().

This issue makes the field durable and universally available. Precedence:

agent_ownership.display_name   (owner-set, durable, renders when stopped)
  ↓ falls back to
template.yaml display_name     (today's behavior)
  ↓ falls back to
agent_name (slug)

Acceptance Criteria

  • display_name TEXT (nullable) added to agent_ownership in src/backend/db/schema.py and to the MetaData in src/backend/db/tables.py
  • SQLite migration added to src/backend/db/migrations.py (private fn + registry entry, following the agent_ownership_mcp_exposed pattern)
  • Alembic revision added under src/backend/migrations/versions/ on top of the current head 0023_agent_sync_state_gc_signals, idempotent (ADD COLUMN IF NOT EXISTS)
  • display_name added to the batched query in src/backend/db/agent_settings/metadata.py (get_all_agent_metadata) — must add zero additional queries
  • display_name merged into the list response in src/backend/services/agent_service/helpers.py, including the orphan branch (Docker-present/DB-absent) which sets None for shape consistency
  • display_name?: string added to the Agent interface in src/mcp-server/src/types.ts
  • MCP list_agents returns both name (slug) and display_name; agents remain addressable by slug only
  • list_agents / get_agent_info tool descriptions updated to disambiguate the two display_name sources
  • Migration docstring states that display_name survives a slug rename untouched
  • docs/memory/architecture.md agent_ownership schema block updated
  • Both migration tracks verified (schema-parity CI job + a real alembic upgrade head)

Technical Notes

Cheap by construction. GET /api/agents returns enriched plain dicts (no response_model); list_all_agents_fast supplies Docker-label identity and get_accessible_agents merges DB fields via one batched fleet-wide query. Adding a DB-sourced field here is +1 column, +0 queries. Exact precedent: mcp_exposed (#846) is an agent_ownership column already surfaced through this same path.

Do NOT add display_name to AgentStatus / list_all_agents_fast. That is a hot labels-only path (startup, telemetry, ops, monitoring); adding it there forces either a per-agent DB lookup or a new Docker label — and a mutable friendly name in a Docker label cuts against Invariant #11's slug-as-identity. Docker stays authoritative for name; the DB owns display_name.

MCP needs almost no code. list_agents / get_agent / get_agent_info in src/mcp-server/src/tools/agents.ts are thin pass-throughs that serialize the backend payload verbatim (list_agents only touches .name, to filter by permission), so the field flows through automatically once it's on GET /api/agents.

Naming collision. get_agent_info already returns a display_name meaning the template's name (from the agent container's /api/template/info). Per the #964 decision we keep the key and let the DB value win where both exist — one concept with a fallback chain. This needs an explicit doc note since GET /api/agents and GET /api/agents/{name}/info will both carry the key from different sources.

Rename is a no-op for this field. agent_ownership is not in AGENT_REFS; the cascade only re-keys the agent_name column, so the friendly name survives a slug rename. Intended semantic — state it explicitly.

Guard for downstream issues: AgentAvatar hashes the agent name into its gradient and derives initials from it. Later UI issues must keep passing the slug to AgentAvatar, or every agent's avatar silently recolors the moment a display name is set.

Depends on: nothing. Blocks: the other four #964 follow-ups.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions