feat(#2050): set matrix avatar in the daemon over the live client
This commit is contained in:
parent
63e9e80232
commit
c99fa714d9
8 changed files with 118 additions and 210 deletions
|
|
@ -165,9 +165,8 @@ Tree-shape version:
|
|||
`systemd.globalEnvironment` in `meta.rs` for every container
|
||||
(manager included), so all token/state paths resolve through
|
||||
`$HYPERHIVE_STATE_DIR`. The harness-base shell scripts
|
||||
(tea-login, forge-avatar-sync, matrix-avatar-sync) simplified
|
||||
from glob+for loops to a direct `$HYPERHIVE_STATE_DIR/<token>`
|
||||
read.
|
||||
(tea-login, forge-avatar-sync) simplified from glob+for loops to a
|
||||
direct `$HYPERHIVE_STATE_DIR/<token>` read.
|
||||
|
||||
### E — prompt + tools
|
||||
|
||||
|
|
|
|||
|
|
@ -474,10 +474,10 @@ the state dir at provisioning time:
|
|||
- `forge-avatar-sync` — uploads `hyperhive.icon` SVG to the
|
||||
agent's Forgejo profile, so the icon shows up on commits / PRs /
|
||||
issue comments.
|
||||
- `matrix-avatar-sync` — same idea for matrix profile avatars
|
||||
(two-step `media upload` → `set avatar_url` dance — see
|
||||
`docs/persistence.md::matrix-avatar-sync` for the protocol
|
||||
detail).
|
||||
|
||||
(The matrix profile avatar is **not** a oneshot — `hive-matrix-daemon`
|
||||
sets it over its live authenticated Client; see
|
||||
`docs/persistence.md::matrix avatar`.)
|
||||
|
||||
Shape contract — every one of these:
|
||||
|
||||
|
|
@ -498,7 +498,7 @@ Shape contract — every one of these:
|
|||
5. **Re-runnable**: a second invocation produces the same final
|
||||
state (idempotent uploads, idempotent config rewrites). Used
|
||||
by the `.path` watchers that re-fire on token appearance (see
|
||||
`docs/persistence.md::matrix-avatar-sync`).
|
||||
`docs/persistence.md::Matrix per-agent daemon`).
|
||||
|
||||
The artefact lives under the agent user's home where applicable
|
||||
(`~/.config/tea/config.yml`) and is chown'd to that user, but the
|
||||
|
|
|
|||
|
|
@ -396,39 +396,35 @@ agent containers come up. Without the path-trigger sibling
|
|||
first time it ran and the MCP would have no backend until the next
|
||||
restart. The `.path` unit makes the appearance of the token re-fire
|
||||
the service so the daemon comes alive in the same boot cycle as
|
||||
provisioning. `matrix-avatar-sync.path` uses the same pattern for
|
||||
the icon-upload oneshot.
|
||||
provisioning. The same token watcher also drives avatar setting: on a
|
||||
restart the daemon re-runs each account's bring-up, which sets the
|
||||
avatar (see below).
|
||||
|
||||
### matrix-avatar-sync (two-step media + profile dance)
|
||||
### matrix avatar (set by the daemon over the live Client)
|
||||
|
||||
Mirrors the forge-avatar oneshot's shape (`docs/conventions.md::
|
||||
Best-effort oneshot services`) but differs in protocol: matrix
|
||||
avatars are a two-step `POST /media/r0/upload` → `PUT
|
||||
/profile/<user_id>/avatar_url` dance, both authenticated by the
|
||||
`access_token` written by `hive-c0re::matrix::ensure_user_for` to
|
||||
`<state>/matrix-token`.
|
||||
The agent icon (`hyperhive.icon`, an SVG) is published as each matrix
|
||||
account's profile avatar by `hive-matrix-daemon` itself
|
||||
(`hive-matrix-mcp::client::sync_avatar`), not a separate oneshot. After
|
||||
the daemon builds + restores an account's `Client` (authenticated,
|
||||
pointed at that account's resolved homeserver), it calls matrix-sdk's
|
||||
`account().upload_avatar()` — one call that uploads the media and sets
|
||||
`avatar_url`. Because it reuses the live Client, there is no hardcoded
|
||||
homeserver URL, no token re-read, and no token-file globbing: the daemon
|
||||
already iterates every configured + dashboard-discovered account in its
|
||||
bring-up loop, so the avatar is set for **every** account.
|
||||
|
||||
The oneshot syncs the avatar for **every** account, not just the
|
||||
hive-internal one: a `sync_one` shell function runs the upload + set
|
||||
dance for the bare `matrix-token` (`main`, against `localhost:8008`)
|
||||
and then for each dashboard-provisioned `matrix-token-<name>`, reading
|
||||
that account's homeserver from its `matrix-account-<name>.json` sidecar
|
||||
(mirrors `accounts::discover_token_accounts`). Idempotency is
|
||||
**per-account**: a `matrix-avatar-icon-hash[-<name>]` file each, because
|
||||
the `mxc://` URI is homeserver-scoped so every account uploads to its own
|
||||
homeserver independently.
|
||||
Nix rasterizes the SVG to a 512x512 PNG at build time (`iconPng`, via
|
||||
librsvg) and forwards its store path as `HIVE_ICON_PNG` on the daemon
|
||||
unit, gated on `hyperhive.icon != null`. No icon configured → the env is
|
||||
unset → `sync_avatar` returns early and no avatar is set.
|
||||
|
||||
Triggered by EITHER boot (`wantedBy = multi-user.target`) OR the
|
||||
sibling `matrix-avatar-sync.path` firing on token appearance — its glob
|
||||
covers both `matrix-token` and `matrix-token-*`, so an account logged in
|
||||
after boot gets its avatar without a restart. Both paths re-run the
|
||||
oneshot idempotently — running the avatar set twice is harmless.
|
||||
|
||||
Critically: **`RemainAfterExit = false`** (not the more common
|
||||
`true` for oneshots). systemd treats `RemainAfterExit = true`
|
||||
oneshots as "still running" after the first exit, so the second
|
||||
trigger from the `.path` watcher becomes a no-op. Setting it to
|
||||
`false` lets re-fires actually re-execute. The trade-off is the
|
||||
service unit shows `inactive (dead)` between fires — visible in
|
||||
`journalctl` but harmless; the `.path` unit drives the lifecycle.
|
||||
Idempotency is **per-account**: an `avatar-icon-hash` file in each
|
||||
account's matrix-sdk `state_dir`. The daemon hashes the PNG bytes and
|
||||
skips the upload when unchanged, because every upload mints a fresh
|
||||
`mxc://` URI that emits a profile state event in every joined room —
|
||||
re-uploading identical bytes is timeline spam. A dashboard-provisioned
|
||||
account gets its avatar when the `systemd.paths.hive-matrix-daemon` token
|
||||
watcher restarts the daemon (which re-runs the per-account bring-up), so
|
||||
no separate avatar trigger is needed. Avatar failures are swallowed
|
||||
(logged, non-fatal) so they never break account bring-up or sync.
|
||||
|
||||
|
|
|
|||
|
|
@ -317,9 +317,9 @@ hyperhive.icon = ./icon.svg; # default: null (falls back to shared hyperhive lo
|
|||
Path to an SVG file used as this agent's visual identity — shown in
|
||||
the per-agent page header, as the page favicon, and uploaded to the
|
||||
agent's Forgejo profile avatar (via the `forge-avatar-sync` boot
|
||||
unit) and Matrix profile avatar (via `matrix-avatar-sync`). Commit
|
||||
the SVG next to `agent.nix` in the config repo and reference it as a
|
||||
relative path.
|
||||
unit) and Matrix profile avatar (set by `hive-matrix-daemon` over its
|
||||
live Client). Commit the SVG next to `agent.nix` in the config repo
|
||||
and reference it as a relative path.
|
||||
|
||||
When `null` (the default), the agent falls back to the shared
|
||||
hyperhive branding mark. The harness serves whichever icon is active
|
||||
|
|
|
|||
Loading…
Reference in a new issue