fix(first-run/runtime): clean two-option onboarding chooser + runtime/instance-management hardening - #11509
Conversation
…raw UnknownHostException
When the device is offline (or DNS/timeout), getCloudCompatAgents() throws and
its raw err.message ('Unable to resolve host "api.elizacloud.ai": No address
associated with hostname') was stuffed into the error outcome and seeded
verbatim into the onboarding chat. A thrown error there is always a transport
failure (the client returns { success:false } for real API errors), so surface
a friendly, actionable line. The re-offered runtime choice already makes the
flow recoverable. Test updated to guard the friendly message.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…en-composer hint - ChoiceWidget: first-run scope renders full-width stacked rows with a chevron affordance instead of compact inline chips, so the options read as obvious next-step targets. The single '(recommended)' option carries the accent; the rest are prominent neutral (one orange accent = brand rule). Other CHOICE scopes (mid-conversation disambiguation) are unchanged. - Composer: while onboarding freezes the input, the placeholder is now the directive 'Tap a highlighted option above to continue' at 70% opacity (was a greyed-out 45% 'Choose an option to continue' that read as dead). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…vice) Remove the 'Bring your own keys' (runtime:other) button from the onboarding 'where should your agent run?' chooser. It was never a location — it ran the local backend and only pre-highlighted the BYOK inference provider, so it lived on the wrong axis and confused the choice. BYOK stays fully reachable one step later via the provider sub-choice (provider:other → localInference 'configure-later' → Settings handoff banner, no silent model download). Remote agents + multi-instance management live in Settings → Runtime (post-#9952). Also de-dupe the re-offered runtime choice in seedError to reuse RUNTIME_CHOICE instead of an inline copy (the two had already drifted). Tests: rewrite the BYOK-path test to assert reachability via runtime:local → provider:other, add a two-buttons-only assertion + stale-runtime:other-is-a-no-op guard, and keep runtime:other in the fuzz storm as a retired no-op. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t/switch (My Runtimes was going stale) Cross-surface state drift: applyLaunchConnection (the remote-connect + cloud launch-session path) and CloudAgentsSection.bindAndReload (cloud-agent switch) wrote ONLY elizaos:active-server and never touched the agent-profile registry (elizaos:agent-profiles) that 'My Runtimes' reads. So a remote connected in Settings, or a cloud agent switched in 'Eliza Cloud Agents', was invisible to the runtime switcher and left its Active badge stale — even though onboarding already seeds profiles for local/cloud. Add upsertAndActivateAgentProfile(): find by (kind, apiBase) → re-activate + refresh token/label (idempotent — reconnecting the same host never duplicates, and a re-activate that carries no token keeps the prior one); otherwise add + activate. Route both write-paths through it alongside the active-server write. Real tests (jsdom + real localStorage): upsert add/idempotent/distinct-host/ token-preservation, and a browser-launch assertion that applyLaunchConnection syncs the registry. 12/12 green; ui typecheck clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ere hidden behind a collapsed grabber) On a home-view boot the sheet could settle COLLAPSED during onboarding — the frozen composer showed 'Tap a highlighted option above to continue' while the seeded greeting + Cloud/On-this-device choices sat hidden behind the grabber, because openness was derived from a raceable mount/effect path. Pin it structurally: while firstRunOpen, the derived openness (pilled/sheetOpen/ expanded) is always FULL via an effectiveMode, independent of the underlying mode-transition race. The existing pin-full effect still drives the real mode so the falling edge (onboarding complete) auto-collapses correctly. Regression test asserts chat-sheet data-variant='open' + chat-thread present under firstRunOpen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…e cleanup Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
Merged ✅ — verified on develop ( |
#11509) (#11656) PR #11509 removed the third runtime chip (`runtime:other` = "Bring your own keys") from the in-chat onboarding conductor — it conflated the inference- provider axis with the runtime-location axis. Four ui-smoke specs still asserted that deleted chip is VISIBLE, so they are guaranteed-red on develop: - runtime-configurability.spec.ts - first-run-startup.spec.ts - walkthrough/walkthrough-capture-smoke.spec.ts - walkthrough/journey.ts (step 02) Each now asserts the chip is absent (`toHaveCount(0)`) instead of visible, and the stale header/expectation comments + the IN_CHAT_ONBOARDING_DESIGN.md option list are corrected to the shipped Cloud/Local chooser. The conductor seeds only runtime:cloud + runtime:local (use-first-run-conductor.ts:108-113); BYOK remains reachable as provider:other one step later. The unit tests that assert a stale runtime:other pick is consumed as a no-op are correct and left unchanged. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…dings (#11509 #11506) (#11710) On-device (Pixel 6a) evidence for the Android onboarding review: - BEFORE (stale 12:56 build): the 3-option runtime chooser WITH 'Bring your own keys' (02-...-symptom2), the Custom-Tab cloud sign-in (00-current-state), and onboarding resetting after the #11506 process restart (07-...). - AFTER (fresh develop build, agent-bundle staged, verified lastUpdateTime): boots straight to home with a working local agent, no chooser, no BYOK chip, pid stable >2min (no #11506 churn in-window) — 01-fresh-develop-boots-to-home. - FINDINGS.md: all four reported symptoms root-caused with file:line. Honest caveats documented: this build omits local model inference (fused lib / omnivoice FFI header not in the worktree); the cloud-sign-in persistence bug is Settings-gated on develop and not exercised here. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…d + locked-composer placeholder The onboarding-to-home ui-smoke suite (10 specs, desktop + mobile) had been fully red: the shared helper still asserted the removed runtime:other choice (the chooser is now cloud/local/remote — #11509) and the old locked-composer placeholder 'Choose an option to continue' (shipped text is 'Tap a highlighted option above to continue'). Point the runtime assertion at 'remote', reach the provider:other handoff via runtime local, and match the real placeholder. All 10 pass — cloud + local + cloud-inference + other-provider + remote + tutorial, desktop and mobile touch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n choices to a11y (#11899) * fix(ui): show onboarding greeting immediately — stop gating it on the agent-wake probe Fresh-install onboarding stranded the user at a locked composer ('Tap a highlighted option above to continue') with NO visible choices whenever the local agent was slow/wedged to wake: the conductor only seeded the greeting + runtime choice inside the then()/catch() of client.listLocalAgentBackups(), which hits the still-booting agent API and can hang indefinitely. Now the greeting + runtime choice seed synchronously on mount, independent of agent readiness; the local-backup probe is a purely additive upgrade that appends the restore choice below the greeting only if backups exist AND the user hasn't already advanced past it (atomic updater, no double-seed). Two new conductor tests cover the never-settling probe (greeting still appears + a runtime pick works) and the racing-late-backups guard. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(a11y): expose in-chat first-run choices to the accessibility tree + add onboarding probe The assistant message bubble in ContinuousChatOverlay's ThreadLine wrapped its content in role=button aria-label="Show message actions" whenever it had row-actions. WebKit maps an ARIA button to an ATOMIC accessibility leaf (its aria-label becomes the node name and ALL descendants are dropped), so the onboarding greeting text and every ChoiceWidget button vanished from the native AX tree: unreachable by VoiceOver AND by on-device XCUITest (only the collapsed "Show message actions" node was exposed). Fix: a choice/form/followups-bearing assistant turn (every first-run onboarding turn) now stays a plain container -- bubbleInteractive gains a !hasInteractiveWidget guard (detected via the existing choice/form/followups parsers). Normal turns keep the tap-to-reveal Copy/Play/Edit row unchanged. Also adds an sr-only onboarding-state-probe (mirroring chat-detent-probe / home-launcher-page-probe) exposing the current first-run step id + choice ids so on-device automation can observe/drive onboarding deterministically. Two new unit tests cover both. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(onboarding): cloud login no longer restarts at the greeting — resume into chat after WebView eviction On a native device the first-run cloud login opens an external browser (SFSafariViewController) that backgrounds the WebView; iOS frequently cold-launches the app on return, wiping the conductor's in-memory flow state and the volatile __ELIZA_CLOUD_AUTH_TOKEN__ global. The result was a "restart": the user was bounced back to "where should your agent run?" instead of landing in chat. Two durable channels close the gap: - Persist the cloud token to the steward-session store (getCloudAuthToken reads it first) on poll/direct auth success, so elizaCloudConnected recomputes true after relaunch. - A cloud-login resume marker (localStorage) armed at cloud/hybrid pick time and cleared on completion or a fresh runtime re-pick. On relaunch the conductor rehydrates the interrupted flow (draft + pending-resume) and continues into chat instead of re-seeding the greeting. Fixes the effect-ordering trap where the auto-resume effect fired before the mount effect armed the marker: the resume body is extracted into runCloudResume and kicked directly when the connection is already live at mount. Tests: first-run-cloud-resume unit (round-trip/validation), conductor regressions (marker armed on pick, resume-on-relaunch with no greeting restart, cleared on fresh local pick). 26 pass; typecheck + biome clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vq3VfLC939jy9e4aA12KGP * fix(ios-local): serve POST /api/first-run in the JSContext kernel — fixes local onboarding "not found" loop On a dev iOS device the local agent runs through the JSContext compatibility kernel (ios-local-agent-kernel.ts), which implemented GET /api/first-run/status but had NO POST /api/first-run handler. finishLocal's submitFirstRun POST fell through to the catch-all 404 ("Not found"); the conductor's seedError turned that into a re-offer of the "where should your agent run?" runtime chooser — the on-device "local path → not found → pick the targets again" loop the user hit. (The full-Bun store build + the mocked web e2e both serve the route, which is why neither caught it.) Add the handler: accept + ack the finish payload (no-op success matching the full-Bun bundle). Regression test asserts the kernel serves it 200 instead of 404. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(test): restore onboarding→home e2e — align stale runtime choice id + locked-composer placeholder The onboarding-to-home ui-smoke suite (10 specs, desktop + mobile) had been fully red: the shared helper still asserted the removed runtime:other choice (the chooser is now cloud/local/remote — #11509) and the old locked-composer placeholder 'Choose an option to continue' (shipped text is 'Tap a highlighted option above to continue'). Point the runtime assertion at 'remote', reach the provider:other handoff via runtime local, and match the real placeholder. All 10 pass — cloud + local + cloud-inference + other-provider + remote + tutorial, desktop and mobile touch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Shaw <shawgotbags@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Onboarding cleanup + runtime/instance-management hardening
Cleans up the in-chat onboarding runtime chooser and fixes two bugs a deep-scan
surfaced in the shared runtime/instance-management layer. All six changes were
verified on a real Pixel 6a (screenshots below), and every change ships real
tests (jsdom + real localStorage — no mock standing in for the thing under test).
What changed
getCloudCompatAgents()stuffed the rawerr.message(
Unable to resolve host "api.elizacloud.ai"…) into the onboarding chat. Athrown error there is always transport (the client returns
{success:false}for real API errors), so surface
Couldn't reach Eliza Cloud — check your internet connection and try again.The re-offered runtime choice keeps theflow recoverable.
ChoiceWidgetfirst-runscope renders full-width stacked rows with a
›chevron + ✓-on-select(were tiny low-contrast chips). The single
(recommended)option carries theaccent; the rest are neutral (one orange accent = brand rule). Other CHOICE
scopes unchanged.
is now
Tap a highlighted option above to continueat higher contrast (was agreyed-out
Choose an option to continue).runtime:other=“Bring your own keys” — it was never a location (it ran thelocal backend and only pre-highlighted the BYOK inference provider). BYOK stays
reachable one step later via
provider:other→configure-later→ Settingsbanner (no silent model download). Remote + multi-instance management live in
Settings → Runtime (per first-run: replace the full-screen onboarding gate with an in-chat login + runtime + provider flow (agent greets first) #9952). Also de-duped the re-offered choice to reuse
RUNTIME_CHOICE.applyLaunchConnection(remote-connect +cloud launch-session) and
CloudAgentsSection.bindAndReload(cloud-agentswitch) wrote only
elizaos:active-serverand never the agent-profile registrythat “My Runtimes” reads — so an instance connected/switched in Settings was
invisible there with a stale Active badge. New idempotent
upsertAndActivateAgentProfile()(find by kind+apiBase → re-activate + refreshtoken/label; else add) routes both write-paths through it — reconnecting the
same host never duplicates.
settle collapsed during onboarding — the frozen composer said “tap an option
above” while the greeting + choices sat hidden behind the grabber (openness was
derived from a raceable effect). Pinned structurally: while
firstRunOpenthederived openness is always FULL via
effectiveMode.Evidence
chevrons + ✓, directive hint, friendly cloud error (device was offline — exactly
the path this fixes), and the sheet auto-opens so options show without a manual
swipe. Captures in
.github/issue-evidence/onboarding-runtime-cleanup/.changed (onboarding UI + client-side instance registry only).
Deferred (genuine product/security decisions — filed as
needs-humanissues)Remote trust-bar unification, Settings IA consolidation (3 overlapping runtime
surfaces), destructive-vs-in-place cloud/local switch, deep-link-remote persistence.
🤖 Generated with Claude Code