Graine AI

Screen context, actions and components

Tell the agent what the user can see, let it act in your app through handlers you write, check which actions work, mask your own formats, and show the components it draws — lists, plans, slots, choices — on every platform.

Three things make the agent part of your app rather than beside it: it knows the screen and its fields (screen context), it can do what you allow (actions: named handlers your app writes), and it can draw components — a list, a plan, time slots, a choice — whose tap is the user's next turn.

What it needs in the dashboard

WhereSettingValue
Embed & Widgets → ActionsEach action the agent may call: its name, what it does, its argumentsDeclared and saved (an import that is not saved does nothing). The name must match your handler's
Agent → Web componentsEach component: template, content, Tool nameBuilt once
Embed & Widgets → On screenThe components this agent may drawTicked, and named in the prompt
Embed & Widgets → FrictionWhen the agent speaks up for a user who looks stuckOptional

What to do, in order

  1. Report each screen when it appears and whenever a field changes: an id, a title, the fields with their real values (personal numbers are masked on the device before they leave it).
  2. Register a handler per declared action, once, at launch. → The agent calls it mid-conversation; you do the work and say what actually happened, within six seconds.
  3. Check, once at startup, which actions work: registered and declared (usable), registered only (undeclared — the agent cannot call it), declared only (unhandled — it will be refused).
  4. Show the components: the SDK's bar and chat draw them (on iOS, place GraineWidgetView where they should appear). → A tap answers the agent.
  5. Mask your own formats — a policy number, an internal id — once.
  6. Clean up: unregister a handler a screen registered, and clear the screen when it goes away.

The code, platform by platform

1. Report the screen:

let graine = GraineInApp.shared
graine.setScreen(GraineScreen(
    screen: "order_details",
    title: "Your order",
    journey: GraineScreen.Journey(name: "Returns", step: 2, of: 3),
    fields: [GraineField(name: "delivery_date", label: "Delivery date", value: "14 Oct", status: .filled)]
))
graine.updateField(GraineField(name: "delivery_date", label: "Delivery date", value: "16 Oct", status: .filled))

A labelled control is noticed when tapped: Button("Track") { … }.graineTap("Track order").

2. Register an action — the main thread; return what actually happened:

let stop = GraineInApp.shared.registerAction("set_language") { args in
    guard let language = args["language"] as? String else { return .refused("No language was given.") }
    print("Switching to \(language)")
    return .ok("The app is now in \(language).")
}

Work that finishes later: registerAction("upload_document", deferred: { args, done in … done(.ok("Uploaded.")) }).

3. Check:

let check = GraineInApp.shared.checkActions()
print("usable:", check.usable, "undeclared:", check.undeclared, "unhandled:", check.unhandled)

4. Components: GraineWidgetView() above the bar (install) draws them and answers the agent.

5. Mask a format of your own:

GraineMasking.addRule(try! NSRegularExpression(pattern: "POL-[0-9]{8}"), token: "[POLICY]")

6. Clean up: stop(); GraineInApp.shared.clearScreen(nil).

Troubleshooting

What you seeWhyFix
The agent says it cannot do somethingThe action is not declared, not saved, or not registered — or the names differcheckActions(); declare and save it; register a handler with the same name
"It's done", and it is notThe handler returned ok without doing itReturn refused or error with the reason
The agent does not know the screensetScreen not called on that screen, or not on every changeCall it on appear and on each change
No componentNot ticked under On screen, not named in the prompt, or (iOS) no GraineWidgetViewComponents → Is it actually on the agent?

In depth: Screen context · Actions · Components · Friction.

On this page