Skip to content

Have the Expert open the onboarding conversation - #8467

Merged
cstns merged 2 commits into
8383-suppress-tourfrom
8369-open-conversation
Sep 14, 2026
Merged

cstns merged 2 commits into
8383-suppress-tourfrom
8369-open-conversation

Conversation

@cstns

@cstns cstns commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

The Expert speaks first on the onboarding page, so the frontend needs a way to start a turn the user has not typed.

Heads up for whoever reviews this

This is the first PR in the stack whose behaviour cannot be verified from the frontend side. It sends the opening turn and renders whatever comes back. Whether the Expert actually produces a sensible first turn for an empty query is the other half, and that lives in the expert flows (#8371), not here.

If the agent is not ready for it, nothing errors. Verify input accepts an empty string, the fast-reply switch does not match it, and the turn goes to the LLM as an empty user message. So the page opens, the request goes out, a reply comes back and renders. It reads as working right up until you look at what the Expert actually said. A blank or confused first message is the failure mode, not a stack trace.

So testing this means reading the opening turn, not just checking that one appears.

What it does

openConversation sends a turn with an empty query. That is not a new protocol: resumeToolApprovals already does exactly this, described in its own comment as "an ordinary chat request with no query". Worth noting the expert-side Verify input check turns out to be looser than #8371 assumed, it requires query to be a string rather than to be non-empty, so an empty string already passes it today.

Two things it deliberately does not do:

  • No user message is added. The user has not said anything, so nothing of theirs belongs in the transcript.
  • The session clock is left unstarted. This is the concern raised in Let the Expert open a chat session before the user types #8371. The expiry warning fires at 25 minutes and the session is declared expired at 28, tracking the agent's own 30 minute history GC. If that clock started when the conversation opened, someone reading the first question could be told their history had expired without ever having typed. handleQuery already starts the clock on the first turn where it is unset, so the user's first reply picks it up naturally.

The onboarding flag is added to both branches of the context getter. They build their objects separately, so a field added to one goes missing depending on load timing. It is sourced from ux.isOnboarding, which tracks the conversation rather than the deployment: it stays true after the Expert moves the user into the editor, and goes false once onboarding is finished or skipped, so a later ordinary chat is not treated as one. That settles the open question on #8370.

Also drops onboardingFixture.js, the hardcoded placeholder transcript that stood in while this was missing, along with its seeding call and the stale TEMPORARY comment. The drawer's canned welcome was already suppressed on this surface, so nothing else was hardcoded. The old guard is kept: a transcript holding only canned messages counts as empty and gets cleared, so arriving from the drawer does not leave its greeting in the way, while a real conversation is left alone, which is what makes the page resumable.

Closes #8369
Closes #8370
Closes #8371

@cstns
cstns added this pull request to stack #8441 September 10, 2026 11:44
@cstns cstns added the area:frontend For any issues that require work in the frontend/UI label Sep 10, 2026
@cstns cstns self-assigned this Sep 10, 2026
@cstns cstns added area:ff-expert FlowFuse AI Assistant type:enhancement labels Sep 10, 2026
@cstns cstns changed the title [8369] Have the Expert open the onboarding conversation Have the Expert open the onboarding conversation Sep 10, 2026
@cstns
cstns force-pushed the 8369-open-conversation branch 2 times, most recently from 93f5f11 to c96e33a Compare September 10, 2026 11:57
@codecov

codecov Bot commented Sep 10, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 76.88%. Comparing base (3aa741d) to head (b209d72).

Additional details and impacted files
@@                 Coverage Diff                 @@
##           8383-suppress-tour    #8467   +/-   ##
===================================================
  Coverage               76.88%   76.88%           
===================================================
  Files                     460      460           
  Lines                   24778    24778           
  Branches                 6609     6609           
===================================================
  Hits                    19051    19051           
  Misses                   5727     5727           
Flag Coverage Δ
backend 76.88% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@andypalmi andypalmi 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 inline note on the opening-turn error path.

Comment on lines +243 to +246
if (!this.shouldUseMqtt) {
console.error('Expert API error:', error)
}
this.addPredefinedAiMessage('Sorry, I could not get started. Please refresh to try again.', { isError: true })

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.

Over MQTT _onMqttError already adds an error bubble on a failed publish, so this line adds a second one on top of it. handleQuery keeps its message inside the !shouldUseMqtt guard for that reason. Moving it in matches that and avoids the double bubble:

Suggested change
if (!this.shouldUseMqtt) {
console.error('Expert API error:', error)
}
this.addPredefinedAiMessage('Sorry, I could not get started. Please refresh to try again.', { isError: true })
if (!this.shouldUseMqtt) {
console.error('Expert API error:', error)
this.addPredefinedAiMessage('Sorry, I could not get started. Please refresh to try again.', { isError: true })
}

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.

Suggested change
if (!this.shouldUseMqtt) {
console.error('Expert API error:', error)
}
this.addPredefinedAiMessage('Sorry, I could not get started. Please refresh to try again.', { isError: true })
if (!this.shouldUseMqtt) {
console.error('Expert API error:', error)
this.addPredefinedAiMessage('Sorry, I could not get started. Please refresh to try again.', { isError: true })
}

@andypalmi

Copy link
Copy Markdown
Contributor

Minor: the skip-onboarding ff-button's label sits inline with its tags, tripping the singleline-html-element-content-newline warning. Putting it on its own line clears it (whitespace-only, non-blocking):

                >
                    Set it up myself
                </ff-button>

The Expert speaks first on the onboarding page, so the frontend needs a way
to start a turn the user has not typed. openConversation sends a turn with an
empty query, the same shape resumeToolApprovals already uses, and the agent
tells onboarding apart from ordinary support by the onboarding flag now
carried on the context object.

Two things it deliberately does not do. No user message is added, since the
user has not said anything. And the session clock is left unstarted, so the
25 minute warning and 28 minute expiry begin when the user first replies
rather than while they are still reading the opening question.

The onboarding flag goes on both branches of the context getter: they build
their objects separately, so a field added to one goes missing depending on
load timing. It tracks the conversation rather than the deployment, staying
true after the Expert moves the user into the editor and going false once
onboarding is finished or skipped.

Drops the hardcoded placeholder transcript that stood in while this was
missing. A transcript holding only canned messages still counts as empty and
gets cleared, so arriving from the drawer does not leave its greeting in the
way, while a real conversation is left alone and picked up where it stopped.
@cstns
cstns force-pushed the 8369-open-conversation branch from 8f0b67a to b7b3c3d Compare September 14, 2026 11:37
@cstns
cstns merged commit d668ffe into main Sep 14, 2026
36 of 38 checks passed
@cstns
cstns deleted the 8369-open-conversation branch September 14, 2026 12:34

This branch was successfully deployed

1 active deployment
staging — b209d72b Deployed Sep 14, 2026 by cstns via Remove application #11597
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:ff-expert FlowFuse AI Assistant area:frontend For any issues that require work in the frontend/UI type:enhancement

Projects

None yet

2 participants