Guided setup¶
An app can ship a Studio wizard that walks someone through configuring the bot
after install. The wizard is a Bubblescript file named guided_setup. If that
file exists, Studio shows a Guided setup item in the bot menu for users who
can edit the bot.
The file is part of the app, so it is copied onto the installed bot with the
rest of the scripts. It runs in that bot's context. It does not share functions,
constants, or dialogs with other files; keep everything the wizard needs in
guided_setup itself.
Create the file in the native app (title guided_setup, type Bubblescript).
Studio fills in a template that only shows the channels step. That is a complete
wizard. Change setup_init when you need more steps.
Leave guided_setup out of editable_scripts unless you want people who
installed the app to edit the wizard.
Callbacks¶
Three functions drive the wizard:
setup_init()is called once when the user opens Guided setup. It must return a setup built withSetup.new/1.setup_step(setup, step)is called every time the user completes a step. It receives the setup as it currently stands and the completed step, including the data the user filled in. The step is not part of the setup yet: putting it back withSetup.replace_step/2accepts the change; returning the setup without it rejects the change. Returning a further modified setup is how steps are added, removed, skipped or pre-filled while the wizard is running.setup_finish(setup, per_step_data)is called after the last step is accepted.per_step_datais a map keyed by step id. This is where you write scripts and call APIs. The return value is ignored; the call must succeed. Raise orfatalto fail the finish.setup_callout(setup, per_step_data, result)is optional. It is called aftersetup_finishand after the publish, and may return aSetup.callout/1that is shown at the top of the dashboard. See Callout.
Every step is rendered as a header with the title and description, an optional
list of best practices, the form described by the step's schema and
ui_schema, and a button to continue. Disabled steps are skipped.
A minimal wizard:
function setup_init() do
return Setup.new(
steps: [
Setup.step(
id: "greeting",
name: "Greeting",
title: "Greeting",
description: "How the bot says hello",
schema: %{"type" => "string"},
ui_schema: %{}
),
Setup.channels_step()
]
)
end
function setup_step(_setup, _step) do
return Setup.replace_step(_setup, _step)
end
function setup_finish(_setup, _data) do
write_script("settings", yaml_build(%{"greeting" => _data.greeting}), type: "text/yaml+data")
end
write_script is allowed
during guided setup. It writes the draft; a publish is still required to put
the change live.
After a successful finish, Studio returns to the bot home, with a callout on top of the dashboard.
Publishing¶
On the last step the user either finishes the setup or finishes and publishes.
When publishing is requested, Studio publishes the draft after setup_finish
has run, as that is what writes the draft. Publishing only happens when the
bot has no errors. If the setup was finished without publishing, the callout
gets a Publish button that is added by Studio.
Callout¶
setup_callout(setup, per_step_data, result) can return a Setup.callout/1
that is shown at the top of the dashboard, for example to say what was set up,
or what to do next. per_step_data is the same map as setup_finish gets, so
the text can be personalised. result is a map telling what happened to
publishing:
publish_requested- the user chose to publish.published- the draft was published.publish_errors- publishing was requested, but the bot has errors that prevent it.
function setup_callout(_setup, _data, _result) do
if _result.published do
return Setup.callout(
intent: :success,
icon: "tick-circle",
title: "#{_data.name} is live",
value: "Try it out in the preview, then share your phone number.",
ui_schema: %{"ui:widget" => "markdown"}
)
end
return Setup.callout(
title: "Setup complete",
value: "Test #{_data.name} in the preview. Customers see it after you publish.",
ui_schema: %{"ui:widget" => "markdown"}
)
end
Without a setup_callout function, or when it fails or returns something that
is not a callout, Studio shows a default message. A failing setup_callout
never fails the setup itself.
The :value is rendered with the same :ui_schema as
Setup.review/1, except that markdown is shown as
plain text: no links, images or variables. Values the user typed that you put
in the callout can contain anything, so don't count on them being formatted.
Platform steps¶
The platform provides three steps you can drop in. Their IDs are fixed. You can
override name, title, description, and best_practices; the form itself
is owned by the platform, and so is the data setup_step receives.
Setup.channels_step()("$channels"). The user enables and configures channels. Data:%{"channel_names" => ["phone", "email"]}.Setup.knowledgebase_step()("$knowledgebase"). The user picks or creates knowledge bases and uploads documents. Data:
%{
"knowledge_bases" => [
%{
"id" => "example",
"label" => "Example",
"strategy" => "managed_vertex_rag"
}
]
}
Setup.review_step()("$review"). Recap of steps that have areviewfield. Submitting it runssetup_finish. This step has no data of its own.
Custom steps¶
Setup.step/1 builds a form from a JSON schema and
a uiSchema.
Forms use the same stack as the CMS; see Content
management for widgets.
id is how setup_step recognises the step. name is the breadcrumb label
and is required. title and description are the heading on the page.
Callouts between the header and the form:
Setup.best_practice(
icon: "tick",
title: "Keep instructions concise",
description: "Focus on clear rules instead of a broad brief."
)
icon is a Blueprint icon name.
To show a step on the review page, set _step.review in setup_step, or pass
:review when you build the step:
_step.review = Setup.review(
title: "Greeting",
icon: "chat",
value: _step.data,
ui_schema: %{}
)
Review is not a form. Supported widgets: markdown, channels (or
channel), tags (or tag, badge, badges), icon. Objects are shown as
labeled fields; ui:title overrides the label; horizontal: true in
ui:options lays them out in a row.
Changing steps while the wizard runs¶
setup_step can return a different list of steps than setup_init did.
Setup.insert_after/3, Setup.insert_before/3, Setup.append_step/2,
Setup.delete_step/2, Setup.set_disabled/3, and Setup.set_data/3 are the
usual tools. Disabled steps are skipped.
If the user goes back and changes an earlier step, setup_step runs again for
that step. Prefills you apply then will overwrite later steps unless you check.
Reporting progress¶
setup_step and setup_finish can take a while, for example when they fetch a
website or call an LLM. Studio shows a loading state while the callback runs.
Call Setup.progress/2 to tell the user what is
happening. The progress is shown on top of the step that is being submitted,
and disappears when the callback returns.
function setup_step(_setup, _step) do
_setup = Setup.replace_step(_setup, _step)
if _step.id == "identity" do
_phases = ["Read company details", "Draft the agent prompt", "Prepare the next step"]
Setup.progress(phases: _phases, phase: 1)
_name = _step.data.name
Setup.progress(phases: _phases, phase: 2, detail: "Asking the AI to write a prompt for " + _name)
_result = LLM.complete(@prompts.draft, name: _name)
Setup.progress(phases: _phases, phase: 3)
_setup = Setup.set_data(_setup, "prompt", %{"prompt" => _result.text})
end
return _setup
end
For a single status line, pass a label instead:
Setup.progress("Fetching your website…", detail: _url).
Without phases and percent the progress bar is animated, as there is nothing
to measure. A callback is stopped after 50 seconds, whether or not it reports
progress.
Trying it¶
On the native app, the same Guided setup menu item runs the wizard against the bot you are editing. Publish the app and install it to see the copy that ships to customers.
The Setup.* functions are listed in the Guided setup
reference.