Skip to content

Support registering custom action steps #663

@adjerbetian

Description

@adjerbetian

Is your feature request related to a problem? Please describe.

We need app-specific click behavior that does not map cleanly to the built-in action steps (@ToAssistant, @OpenUrl, @Run, @Set, @Reset). In our case, we want the model to say what happens when tapping a card: open a menu, post a message, reset the conversation etc.

Today, unknown @ calls are not evaluated as action steps. We work around this by preprocessing OpenUI Lang before render, rewriting syntax like:

Action([@OpenMenu(["option 1", "option 2"])])

into a plain object literal that our component reads from an action prop. That works, but it is brittle (regex/string rewriting), duplicates knowledge already in the system prompt, and is easy to get wrong while streaming.

Describe the solution you'd like

A public API to register custom action handlers, e.g.:

registerActionStep({
  name: "OpenMenu",
  description: "Opens a menu with the given options",
  props: z.object({
    options: z.array(z.string()),
  }),
  evaluate: (props) => ({
    openMenu(props.options);
  }),
});

Requirements:

  • Registered steps appear in generated system prompts (like built-ins).
  • They can be used inside Action([...]).
  • They dispatch to the host app via onAction (or a similar callback), with a typed params payload.
  • Unknown @ steps fail clearly at parse/eval time instead of being silently dropped.

Describe alternatives you've considered

  • Object literals in props — e.g. { intent: "product_select", name, variantId } on action: z.any(). Works, but is less ergonomic for the LLM and not documented as a first-class action pattern.
  • Component-only handling — custom card components with explicit props instead of Action([...]). More verbose in generated Lang.
  • String preprocessing — rewrite Lang before Renderer. Current approach; fragile and hard to maintain.
  • Always use @ToAssistant — sends a message immediately; cannot support intermediate UI like a product menu.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions