[1/5] feat(intelligence): surface own tiny.place identity + relay in Orchestration tab#4588
Conversation
Re-export handle_tinyplace_signal_key_status / directory_reverse / directory_get_agent from the tinyplace mod so the orchestration layer can compose them, and add ops::relay_endpoint() (+ pure relay_network_label, unit-tested) exposing the configured relay base URL and a staging|prod label.
Two renderer-only controllers: orchestration_self_identity composes the
tinyplace signal/directory reads into { agentId, handles, primaryHandle,
cardPublished, keyPublished, discoverable } — surfacing whether peers can DM
this agent (a fresh identity accepts contacts yet stays un-messageable until it
registers a @handle, which is what publishes its card + key). orchestration_relay_info
returns { baseUrl, network }. Composition is split into a pure build_self_identity
fn with unit tests. Both auto-register via all_registered_controllers.
Typed renderer wrappers over openhuman.orchestration_self_identity / _relay_info, with SelfIdentity/SelfHandle/RelayInfo response types.
Always-visible STAGING/PRODUCTION pill for the active tiny.place relay, so a relay mismatch (the silent prod-vs-staging 404 hit during live debugging) is obvious instead of opaque. Presentational; parent supplies RelayInfo.
Pinned card showing OpenHuman's own tiny.place @handle/address (with copy) plus its discoverability — directory-card + encryption-key published state and whether peers can DM it — with a register hint when un-messageable. Presentational.
Fetch selfIdentity + relayInfo (best-effort, non-blocking) and render the RelayBadge in the header and SelfIdentityCard atop the roster; refresh reloads both. Extends the tab test mocks/fixtures for the two new client methods.
13 keys (tinyplaceOrchestration.identity.* + .relay.*) with real translations across en + 13 locales for the SelfIdentityCard and RelayBadge.
📝 WalkthroughWalkthroughAdds backend orchestration endpoints for self identity and relay info, exposes them through the orchestration client, renders relay and identity UI in the TinyPlace orchestration tab, and adds matching translation keys across supported locales. ChangesSelf identity and relay badge feature
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant TinyPlaceOrchestrationTab
participant orchestrationClient
participant schemas
participant tinyplace ops
participant orchestration ops
TinyPlaceOrchestrationTab->>orchestrationClient: selfIdentity() and relayInfo()
orchestrationClient->>schemas: JSON-RPC requests
schemas->>tinyplace ops: relay_endpoint()
schemas->>orchestration ops: build_self_identity(...)
schemas-->>orchestrationClient: RelayInfo / SelfIdentity
orchestrationClient-->>TinyPlaceOrchestrationTab: resolved data
Possibly related PRs
Suggested labels: Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 616def8b36
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
src/openhuman/orchestration/schemas.rs (1)
635-686: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
build_self_identitybusiness logic lives inschemas.rsinstead ofops.rs.As per coding guidelines,
src/openhuman/**/{types,store,ops,schemas,tools,bus}.rsshould follow the shape: "ops.rs for business logic andRpcOutcome<T>handlers, schemas.rs for RPC-facing schemas and delegating handlers."build_self_identityperforms non-trivial composition/parsing logic (handle parsing, primary-handle selection, discoverability derivation) and would fit better as anops.rsfunction thathandle_self_identitymerely delegates to.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/openhuman/orchestration/schemas.rs` around lines 635 - 686, The `build_self_identity` function currently contains business logic in `schemas.rs`, but it should live in `ops.rs` per the module split. Move the non-trivial parsing/composition logic (handle extraction, primary-handle fallback, and discoverable derivation) into an `ops.rs` helper, and keep `handle_self_identity` in `schemas.rs` as a thin delegator that calls that helper. Make sure the new `ops.rs` function uses the same `build_self_identity`-style behavior so existing `SelfIdentity`, `HandleEntry`, and `handle_self_identity` call sites continue to work unchanged.Source: Path instructions
app/src/components/intelligence/SelfIdentityCard.tsx (1)
61-61: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winFallback ignores the
primaryflag onSelfHandle.When
primaryHandleis unset, this falls back tohandles[0]rather than the handle actually flaggedprimary. If the backend doesn't guarantee the primary handle is always first in the array, the wrong@handlecould be displayed.♻️ Proposed fix
- const primaryHandle = identity.primaryHandle ?? identity.handles[0]?.username; + const primaryHandle = + identity.primaryHandle ?? + identity.handles.find(h => h.primary)?.username ?? + identity.handles[0]?.username;Please confirm whether
handlesfromorchestration_self_identityis always primary-first, or if this fallback should defensively check theprimaryflag.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/components/intelligence/SelfIdentityCard.tsx` at line 61, The fallback in SelfIdentityCard’s primaryHandle logic ignores the SelfHandle primary flag and may show the wrong `@handle`. Update the primaryHandle selection so it first uses identity.primaryHandle, then defensively searches identity.handles for the handle marked primary before falling back to the first username, using the existing SelfIdentityCard render logic and SelfHandle shape.app/src/components/intelligence/TinyPlaceOrchestrationTab.tsx (1)
273-298: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winPromise.all couples identity and relay failures.
selfIdentity()andrelayInfo()are independent, best-effort reads per the surrounding comments, butPromise.allmeans a failure in either call discards the successful result of the other — e.g. an offline relay would also hide a successfully-fetched self-identity card.♻️ Proposed fix using Promise.allSettled for independent degradation
const loadIdentity = useCallback(async () => { debug('[tinyplace-orchestration] identity load entry'); - try { - const [identity, relay] = await Promise.all([ - orchestrationClient.selfIdentity(), - orchestrationClient.relayInfo(), - ]); - if (!mountedRef.current) return; - debug( - '[tinyplace-orchestration] identity load exit discoverable=%s network=%s', - identity.discoverable, - relay.network - ); - setSelfIdentity(identity); - setRelayInfo(relay); - } catch (error) { - if (!mountedRef.current) return; - // Identity/relay are informational; a read failure (locked wallet, offline - // relay) must not break the chat surface. Leave the card/badge hidden. - const message = error instanceof Error ? error.message : String(error); - debug('[tinyplace-orchestration] identity load error %s', message); - } finally { - if (mountedRef.current) setIdentityLoading(false); - } + const [identityResult, relayResult] = await Promise.allSettled([ + orchestrationClient.selfIdentity(), + orchestrationClient.relayInfo(), + ]); + if (!mountedRef.current) return; + if (identityResult.status === 'fulfilled') { + setSelfIdentity(identityResult.value); + } else { + debug('[tinyplace-orchestration] identity load error %s', identityResult.reason); + } + if (relayResult.status === 'fulfilled') { + setRelayInfo(relayResult.value); + } else { + debug('[tinyplace-orchestration] relay load error %s', relayResult.reason); + } + setIdentityLoading(false); }, []);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/components/intelligence/TinyPlaceOrchestrationTab.tsx` around lines 273 - 298, In loadIdentity within TinyPlaceOrchestrationTab, selfIdentity() and relayInfo() should be treated as independent best-effort reads instead of being coupled by Promise.all. Update the orchestrationClient.selfIdentity and orchestrationClient.relayInfo handling to use Promise.allSettled or separate awaits so a failure in one does not discard the successful result of the other, then only setSelfIdentity and setRelayInfo for the calls that succeeded while keeping the existing mountedRef and loading-state behavior intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/src/lib/i18n/pl.ts`:
- Line 316: The Polish translation entry in the i18n map uses the incorrect form
"Nieopublikowano"; update the value for
tinyplaceOrchestration.identity.notPublished in pl.ts to the separated negation
"Nie opublikowano" so it matches the style used by the nearby published string
and the rest of the translation set.
---
Nitpick comments:
In `@app/src/components/intelligence/SelfIdentityCard.tsx`:
- Line 61: The fallback in SelfIdentityCard’s primaryHandle logic ignores the
SelfHandle primary flag and may show the wrong `@handle`. Update the primaryHandle
selection so it first uses identity.primaryHandle, then defensively searches
identity.handles for the handle marked primary before falling back to the first
username, using the existing SelfIdentityCard render logic and SelfHandle shape.
In `@app/src/components/intelligence/TinyPlaceOrchestrationTab.tsx`:
- Around line 273-298: In loadIdentity within TinyPlaceOrchestrationTab,
selfIdentity() and relayInfo() should be treated as independent best-effort
reads instead of being coupled by Promise.all. Update the
orchestrationClient.selfIdentity and orchestrationClient.relayInfo handling to
use Promise.allSettled or separate awaits so a failure in one does not discard
the successful result of the other, then only setSelfIdentity and setRelayInfo
for the calls that succeeded while keeping the existing mountedRef and
loading-state behavior intact.
In `@src/openhuman/orchestration/schemas.rs`:
- Around line 635-686: The `build_self_identity` function currently contains
business logic in `schemas.rs`, but it should live in `ops.rs` per the module
split. Move the non-trivial parsing/composition logic (handle extraction,
primary-handle fallback, and discoverable derivation) into an `ops.rs` helper,
and keep `handle_self_identity` in `schemas.rs` as a thin delegator that calls
that helper. Make sure the new `ops.rs` function uses the same
`build_self_identity`-style behavior so existing `SelfIdentity`, `HandleEntry`,
and `handle_self_identity` call sites continue to work unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9ff0a351-c44e-4569-a3ea-cc61400bd865
📒 Files selected for processing (24)
app/src/components/intelligence/RelayBadge.test.tsxapp/src/components/intelligence/RelayBadge.tsxapp/src/components/intelligence/SelfIdentityCard.test.tsxapp/src/components/intelligence/SelfIdentityCard.tsxapp/src/components/intelligence/TinyPlaceOrchestrationTab.test.tsxapp/src/components/intelligence/TinyPlaceOrchestrationTab.tsxapp/src/lib/i18n/ar.tsapp/src/lib/i18n/bn.tsapp/src/lib/i18n/de.tsapp/src/lib/i18n/en.tsapp/src/lib/i18n/es.tsapp/src/lib/i18n/fr.tsapp/src/lib/i18n/hi.tsapp/src/lib/i18n/id.tsapp/src/lib/i18n/it.tsapp/src/lib/i18n/ko.tsapp/src/lib/i18n/pl.tsapp/src/lib/i18n/pt.tsapp/src/lib/i18n/ru.tsapp/src/lib/i18n/zh-CN.tsapp/src/lib/orchestration/orchestrationClient.tssrc/openhuman/orchestration/schemas.rssrc/openhuman/tinyplace/mod.rssrc/openhuman/tinyplace/ops.rs
Business logic (identity composition + its SelfIdentity/HandleEntry DTOs) belongs in ops.rs per the domain module conventions; schemas.rs keeps only the RPC handler, which now delegates. Tests move with the fn. No behavior change.
|
Addressed the |
selfIdentity() builds the tiny.place client from the wallet and can reject on a locked/unconfigured wallet; relayInfo() only reads the configured base URL. Promise.all discarded the relay result on identity failure, hiding the relay badge even though it is wallet-independent. Settle the two reads independently so a relay mismatch stays visible regardless of identity discovery. Adds a regression test.
Polish negates the impersonal verb form as a separate word: 'nie opublikowano', not the prefixed 'Nieopublikowano'.
# Conflicts: # app/src/lib/i18n/ar.ts # app/src/lib/i18n/bn.ts # app/src/lib/i18n/de.ts # app/src/lib/i18n/en.ts # app/src/lib/i18n/es.ts # app/src/lib/i18n/fr.ts # app/src/lib/i18n/hi.ts # app/src/lib/i18n/id.ts # app/src/lib/i18n/it.ts # app/src/lib/i18n/ko.ts # app/src/lib/i18n/pl.ts # app/src/lib/i18n/pt.ts # app/src/lib/i18n/ru.ts # app/src/lib/i18n/zh-CN.ts
Summary
orchestration_self_identityandorchestration_relay_info— surfacing OpenHuman's own tiny.place identity and the active relay in the Brain → Orchestration → TinyPlace tab.SelfIdentityCard: shows this agent's@handle/ address (with copy) plus its discoverability — whether its directory card and Signal encryption key are published, and therefore whether peers can DM it — with a register hint when it is un-messageable.RelayBadge: an always-visibleSTAGING/PRODUCTIONpill for the relay the core is talking to.Problem
The tab shows peers/contacts but never OpenHuman's own tiny.place agent id, so there is no way to hand a peer your address to be messaged inbound. Worse, a freshly-provisioned identity can accept contacts yet still be un-messageable: it only publishes its Signal key bundle / directory card during
@handleregistration, so every DM to it 404s on/directory/agents/<addr>until then — with nothing on screen explaining why.Separately, the relay endpoint (staging vs prod) was invisible. A mismatch — one side on
staging-api.tiny.place, the core defaulted to prodapi.tiny.place— produced a silent 404 with no on-screen signal of which relay either side used.Solution
orchestration_self_identitycomposes the existing internal tiny.place reads (signal_key_status+directory_reverse(self)+directory_get_agent(self)) into{ agentId, handles, primaryHandle?, cardPublished, keyPublished, discoverable }.discoverable = cardPublished && keyPublished— the bottom line the card renders. Parsing/composition is split into a purebuild_self_identityfn so it is unit-tested without a live wallet.orchestration_relay_inforeturns{ baseUrl, network }from the configured relay base URL (stagingwhen the host carries a staging marker, elseprod), via a pure, unit-testedrelay_network_label.orchestrationClient.selfIdentity()/relayInfo(), two presentational components with co-located tests, wired into the tab header/roster best-effort (a failed read hides the card/badge rather than breaking the chat surface). Full i18n across en + 13 locales.Submission Checklist
build_self_identity(published / primary-fallback / undiscoverable) +relay_network_label; frontend:RelayBadge(3),SelfIdentityCard(6, incl. loading/undiscoverable/copy), tab suite extended.build_self_identity/relay_network_labelhelpers and all components are directly unit-tested.## Related): none — no matrix IDs.Closes #NNN): design-driven, no tracking issue.Impact
Related
AI Authored PR Metadata (required for Codex/Linear PRs)
Linear Issue
Commit & Branch
design/harness-uiValidation Run
pnpm --filter openhuman-app format:checkpnpm typecheckvitest run RelayBadge / SelfIdentityCard / TinyPlaceOrchestrationTab(21 passed);cargo test --lib openhuman::orchestration::schemas / openhuman::tinyplace::opscargo fmt --check,cargo check,cargo clippy --libapp/src-taurichangesValidation Blocked
command:N/Aerror:N/Aimpact:N/ABehavior Changes
Parity Contract
Duplicate / Superseded PR Handling
Summary by CodeRabbit