Skip to content

fix(profiles): preserve nonlocal agent identity in profile fallback - #327

Open
matt2e wants to merge 3 commits into
mainfrom
agents-confused-as-humans
Open

matt2e wants to merge 3 commits into
mainfrom
agents-confused-as-humans

Conversation

@matt2e

@matt2e matt2e commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Fix

Preserve an agent's identity when its profile has no public metadata and it is not managed locally. Opening an agent message now carries the existing agent display hint into the profile panel, including from a thread.

  • Use an agent-shaped avatar and Unknown agent fallback instead of an unknown, human-shaped profile. Unclassified identities fall back to their short public key without being labeled agents. The full public key remains below the heading.
  • Keep public metadata and configured names first, including stopped local agents' names. An empty, loaded local inventory says Not managed on this device, without claiming the agent is offline elsewhere.
  • Treat the hint as presentation only. It does not populate shared agent choices or grant ownership, runtime controls, memories, or other private actions. Public profile targets and copyable full keys remain unchanged.

The Instances section already existed before this PR. Recognizing the message-only agent now makes that section visible for this case; its empty-state wording is updated as described above.

Before

Base 85d6bf82c54d1c8d930d58444597a1fe31cc8975: an agent message already has a squircle avatar, but opening its profile shows Unknown profile with a circular avatar. The recording opens the profile, retries missing metadata, and opens the same agent from a thread.

before.mp4

After

Head 48ea5bfb3e6ede721e5a020e036d67fbbd1beaa5: the identical identity and actions retain the agent-shaped avatar, show Unknown agent, and explain Not managed on this device. Neither snapshot has a local agent record, library identity, or public profile for this agent.

after.mp4

Validation

  • At 48ea5bfb: pre-push TypeScript, 823 related tests in 52 files, design-system checks, and hosted DCO passed.
  • Existing profile browser journeys at 16f45ba6: 14/14 passed, Chromium and WebKit. No browser test cases added or removed. Added mounted/unit coverage for message hint navigation, strict target parsing, exact-key/community boundaries, metadata hydration/retry, stopped names, and hint-only profiles without private controls; the wording expectations were updated at 48ea5bfb.
  • Recorded production channel/profile composition from separate git-archive snapshots with identical synthetic data. Verified channel and thread navigation, retry, exact full key, empty shared/native inventories, and absent private controls. Repeated the after workflow at 48ea5bfb in Chromium/WebKit desktop and Chromium at 390px, with no profile overflow or page errors. Both MP4s are H.264; encoded frames were visually inspected.
  • Full frontend Vitest at 48ea5bfb: 4433 passed, 1 failed (391 files passed, 1 failed). dev/vite-config.test.mjs:128 failed because its config-loading subprocess exceeded its 10-second timeout (ETIMEDOUT). That file is outside this change; a baseline reproduction was not established. The full local suite is not green.

Previous-head CI (16f45ba6) passed JavaScript, Rust/integration, Chromium and two WebKit shards; one WebKit shard failed in navigation-repairs.spec.mjs:89 when the fixture observed a relay-query access-control console error during reload/Back. Failed job. This is outside the changed profile paths; no baseline reproduction was established. CI runs again for the new head.

The recordings use a synthetic read transport and empty native inventory, not a live relay or running agent process. External requests were blocked; none were attempted. They exercise production UI wiring, not packaged startup/authentication. Recording fixtures and media are local-only, not committed. Native/ACP, full browser-suite, and packaged acceptance remain deferred locally; hosted CI runs separately.

Draft pending human testing. Open a message from an agent that has no local record or public profile, retry, then open it from a thread: expect the agent-shaped avatar, Unknown agent heading, and no private controls. Verify named and stopped local agents retain their names. Human acceptance has not been confirmed.

Use the existing exact-key agent evidence to show Agent when no public or configured name resolves. Preserve relay metadata and configured names for stopped local agents.

Add mounted profile-panel regression coverage for identity evidence, failed profile reads and retry recovery, remote metadata, and stopped-agent names.

Signed-off-by: Matt Toohey <contact@matttoohey.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
@matt2e matt2e changed the title fix(profiles): identify known agents in profile fallback fix(profiles): preserve nonlocal agent identity in profile fallback Sep 28, 2026
Signed-off-by: Matt Toohey <contact@matttoohey.com>
@matt2e
matt2e marked this pull request as ready for review September 28, 2026 03:44
@matt2e
matt2e requested review from a team, comp615 and wesbillman as code owners September 28, 2026 03:44

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Star Lord automated source review (via Wes’s account)

No actionable findings in the reviewed change. This is a non-blocking source-review comment, not approval or merge authorization.

  • Head: 48ea5bfb3e6ede721e5a020e036d67fbbd1beaa5
  • Base/merge base: 85d6bf82c54d1c8d930d58444597a1fe31cc8975

Reviewed the complete eight-file diff, added test sources, applicable repository/product guidance, and the relevant callers and lifecycle. The avatar hint follows both channel and thread MessageRow paths through the existing panel resolver (ChannelsPage.tsx:729–800, ThreadPanel.tsx:513–519,626–632). Public identity links and the copyable npub retain their ordinary path.

The presentation/authority split is preserved: ProfilePanel.tsx:196–220,436–452 uses the hint for appearance and the Instances presentation, not owner evidence or Runtime/Memories admission. ProfileInstances.tsx:47–70,97–118 still matches exact keys within the active community and separately gates private navigation; local lifecycle actions retain exact native-record matching. Configured names, profile hydration/retry, and shared-directory membership remain owned by existing services. The change is proportionate to the stated fallback fix.

Validation limits: source analysis only; no PR code, tests, builds, app launches, or live workflows executed. Inspected sources were verified against pinned Git blobs; no dirty checkout inputs or delegated lanes. The PR reports 4,433 passing frontend tests and one config-subprocess timeout at this head, with no baseline reproduction established; it also reports a previous-head WebKit failure without a baseline reproduction. Those are author-reported results, not independently reproduced or classified as baseline failures here. No new CI snapshot was taken. Synthetic recordings do not establish live-relay/native/packaged behavior, and human acceptance remains unconfirmed in the PR description.

@kalvinnchau kalvinnchau left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 One profile-presentation boundary finding inline; no privilege escalation established.


export function profileKey(target: string): string | undefined {
if (profileAgentHint(target))
return target.slice("buzz:agent-profile:".length);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [P2] Keep app-local presentation hints out of public profile parsing

Expanding profileKey to accept the internal agent-hint form also admits it through MessageMarkdown’s URL transform and profile-link renderer. With Profiles enabled, the real panel matcher accepts that target, so a message-body link can make a human identity open with agent appearance and the agent empty-state presentation despite lacking agent evidence. This contradicts docs/profiles.md:167–173, which limits the hint to existing app-local display evidence. Ownership, Runtime and Memories remain independently gated; this is misleading presentation, not privilege escalation.

Keep the general message-body profile locator restricted to the ordinary public identity format, and handle the internal hint separately at the trusted panel boundary. Add a regression asserting that message-body parsing cannot introduce an agent appearance hint.

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.

3 participants