Standardize admin endpoint address path params - #81
Conversation
Admin (and list) endpoints addressed resources by three inconsistent slices of the canonical MAIL address: agents used a partial address (name@swarm), daemons/users a bare id, and lists the full list:name@swarm@host address. None of the path params were declared to FastAPI, so they were undocumented in OpenAPI and unvalidated. Standardize on a single rule: the path param is the resource's local identifier, with the user-agent prefix implied by the route and the host implied by the server (agents name@swarm, daemons worker_name, users user_id, swarms swarm_name, lists name@swarm, webhooks wh_<uuid>). member_address stays a full MAIL address — a list member may be any user-agent, possibly remote. - Add typed Path(...) params + shape validation across admin/lists routers: 422 on malformed, 404 on well-formed-but-unknown; params now documented in spec/openapi.yaml. - Lists HTTP surface now addresses lists by local name@swarm; the router reconstructs the full list: key so backends are unchanged. Message recipients still use the full list: address (delivery unchanged). - Rename agent_address -> local_address through base/memory/sqlite backends; declare host on the backend Protocol. - Fix stale "Corresponds to" docstrings, the daemon-get CLI arg bug, and list-address help text (local form). - Update tests + fixtures to local addresses; add 422 path-param tests. BREAKING CHANGE: list HTTP endpoints now take the local address (name@swarm) instead of the full list:name@swarm@host address. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
rheaton64
left a comment
There was a problem hiding this comment.
Hi Addison —
Reviewed PR #81 and updated chorus to send the new local form
on the consumer side. Approving the PR via gh momentarily.
What I changed on chorus side (commit c299d29 on master):
-
Single shared helper
chorus.mail._to_local_addressthat
accepts every shape (full, local, list-prefixed full,
list-prefixed local) and returns the local form. Idempotent
on already-local inputs. Unfamiliar shapes pass through so
your 422 validator gets a clean view rather than us
silently mangling. -
MailClient.delete_agentkeeps the full-address parameter
(chorus stores full addresses inmail_credentialsfor
routing reasons), strips to local on the wire. -
mb subscribe/mb unsubscribekeep accepting the
user's fulllist:foo@chorus@chrn.aiform on the CLI
(matches user habits and what other tools generate); the
helper strips for the URL.
The PR itself reads cleanly. Specific things I noticed and
liked:
-
The chosen path-param vocabulary table (agents:
name@swarm, daemons:worker_name, users:
user_id, lists:name@swarm, webhooks:
wh_<uuid>, member_address stays full) is the right
set. Reserving member_address as full because a member can
be remote under federation is the right hedge. -
422 on malformedvs404 on well-formed-but-unknown
is the discipline you want for documented path params.
Catching the path-shape issue at the validator means
client bugs surface with precise error messages rather
than ambiguous 404s. -
The list router's
_full_list_addressnormalization
preserves backend keys as full addresses so the storage
layer doesn't need to change. Clean seam. -
The CLI
daemon-getarg bug fix (local_address/
daemon@swarm→worker_name) is the kind of thing
that's easy to miss; glad you caught it in the same PR.
Two small things I'd note, neither blocking:
-
The non-list endpoints'
hostis implied by the server.
If MAIL ever supports multi-host deployment, the implication
stops holding. That's far-future and you'd see it coming;
just flagging that the standardization commits to
single-host-per-server semantics here. -
member_addressstaying full is the right call for
federation-future, but it's also the one path param that
doesn't match the new pattern — worth a one-line comment
at the route definition naming why, so future maintainers
don't "fix" it.
Approving. Merge when ready.
— minichorus-pm
Summary
Standardizes how MAIL addresses are accepted as path parameters across the server admin (and list) endpoints. Previously the same conceptual identifier was expressed three different ways:
name@swarm)worker_name/user_id)list:name@swarm@host)None of these path params were declared to FastAPI (all read via
request.path_params.get(...)), so they were undocumented inopenapi.yamland unvalidated — malformed input fell through to a 404 or 500.The standard
The path param is now the resource's local identifier, with the user-agent prefix implied by the route and the host implied by the server:
name@swarmworker_nameuser_idswarm_namename@swarmwh_<uuid>member_address(list members) deliberately stays a full MAIL address — a member can be any user-agent, possibly remote under future federation.Every by-id endpoint now uses a typed
Path(...)param with description/example (documented in OpenAPI) and validates shape: 422 on malformed, 404 on well-formed-but-unknown.Changes
admin.pyandlists.pyconverted to typedPathparams + validation; lists router normalizes local→full (_full_list_address) so backends keep their full-address key;agent_address→local_addressrename throughbase.py(+host: strProtocol attr), memory, and sqlite.Corresponds todocstrings (incl.POST /admin/agentsingular typo); fixed thedaemon-getCLI arg bug (local_address/"daemon@swarm" →worker_name); clarified list-address help as local form.seed_listreturns local form, added 422 path-param tests; regeneratedspec/openapi.yaml.The list HTTP endpoints now take the local address (
name@swarm) instead of the fulllist:name@swarm@hostaddress. Message recipients are unaffected — they still use the fulllist:address (delivery resolution is unchanged). Sharing for team review before merge so callers can be updated; the server could be made to accept both forms during a transition if preferred.Verification
684 passed(default suite) +6 e2e passed+ OpenAPI drift check green🤖 Generated with Claude Code