Class: Inquirex::DSL::FlowBuilder

Inherits:
Object
  • Object
show all
Includes:
RuleHelpers
Defined in:
lib/inquirex/dsl/flow_builder.rb

Overview

Builds a Definition from the declarative DSL block used in Inquirex.define. Provides start, meta, and all verb methods (ask, say, header, btw, warning, confirm).

Constant Summary collapse

THEME_KEY_ALIASES =

Maps snake_case theme keys (idiomatic in Ruby) to the camelCase names the JS widget (inquirex-js ThemeOverrides) expects on the wire.

{
  on_brand:    :onBrand,
  text_muted:  :textMuted,
  header_font: :headerFont
}.freeze

Instance Method Summary collapse

Methods included from RuleHelpers

#all, #any, #contains, #equals, #greater_than, #less_than, #not_empty

Constructor Details

#initialize(id: nil, version: "1.0.0") ⇒ FlowBuilder

Returns a new instance of FlowBuilder.

Parameters:

  • id (String, nil) (defaults to: nil)

    optional flow identifier

  • version (String) (defaults to: "1.0.0")

    semver



12
13
14
15
16
17
18
19
20
# File 'lib/inquirex/dsl/flow_builder.rb', line 12

def initialize(id: nil, version: "1.0.0")
  @flow_id = id
  @flow_version = version
  @start_step_id = nil
  @nodes = {}
  @meta = {}
  @accumulators = {}
  @send_emails = []
end

Instance Method Details

#accumulator(name, type: :decimal, default: nil) ⇒ Object

Declares a named running total the flow accumulates into as answers come in. The :price accumulator is the common lead-qualification use case; others (e.g. :complexity, :credit_score) work identically.

A :text accumulator is filled by the engine rather than by accumulate declarations: it collects everything the user was shown and every answer they gave, which is what an LLM summarize step reads. See Accumulator.

Parameters:

  • name (Symbol)

    e.g. :price, :transcript

  • type (Symbol) (defaults to: :decimal)

    one of Node::TYPES (default :currency-ish: :decimal)

  • default (Numeric, String, nil) (defaults to: nil)

    starting value; nil (the default) takes the type's own zero, so a :text accumulator starts at "" and every other kind starts at 0



36
37
38
39
# File 'lib/inquirex/dsl/flow_builder.rb', line 36

def accumulator(name, type: :decimal, default: nil)
  sym = name.to_sym
  @accumulators[sym] = Accumulator.new(name: sym, type:, default:)
end

#ask(id) { ... } ⇒ Object

Defines a question step that collects typed input from the user.

Parameters:

  • id (Symbol)

    step id

Yields:

  • block evaluated in StepBuilder (type, question, options, transition, etc.)



76
77
78
# File 'lib/inquirex/dsl/flow_builder.rb', line 76

def ask(id, &)
  add_step(id, :ask, &)
end

#btw(id) ⇒ Object

Defines an admonition or sidebar note step (no input collected).

Parameters:

  • id (Symbol)

    step id



97
98
99
# File 'lib/inquirex/dsl/flow_builder.rb', line 97

def btw(id, &)
  add_step(id, :btw, &)
end

#buildDefinition

Produces the frozen Definition.

Returns:

Raises:



160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/inquirex/dsl/flow_builder.rb', line 160

def build
  raise Errors::DefinitionError, "No start step defined" if @start_step_id.nil?
  raise Errors::DefinitionError, "No steps defined" if @nodes.empty?

  Definition.new(
    start_step_id: @start_step_id,
    nodes:         @nodes,
    id:            @flow_id,
    version:       @flow_version,
    meta:          @meta,
    accumulators:  @accumulators,
    send_emails:   @send_emails
  )
end

#confirm(id) ⇒ Object

Defines a yes/no confirmation gate (collects a boolean answer).

Parameters:

  • id (Symbol)

    step id



111
112
113
# File 'lib/inquirex/dsl/flow_builder.rb', line 111

def confirm(id, &)
  add_step(id, :confirm, &)
end

#header(id) ⇒ Object

Defines a section heading step (no input collected).

Parameters:

  • id (Symbol)

    step id



90
91
92
# File 'lib/inquirex/dsl/flow_builder.rb', line 90

def header(id, &)
  add_step(id, :header, &)
end

#meta(title: nil, subtitle: nil, brand: nil, theme: nil) ⇒ Object

Sets frontend metadata: title, subtitle, brand, and theme.

Examples:

meta title: "Tax Intake",
  subtitle: "Let's get started",
  brand: { name: "Agentica", logo: "https://cdn.example.com/logo.png" },
  theme: { brand: "#2563eb", radius: "18px", font: "Inter, system-ui" }

Parameters:

  • title (String, nil) (defaults to: nil)
  • subtitle (String, nil) (defaults to: nil)
  • brand (Hash, nil) (defaults to: nil)

    identity — { name: "Acme", logo: "https://..." }. Colors and fonts belong in theme:, not here.

  • theme (Hash, nil) (defaults to: nil)

    visual overrides consumed by the JS widget. Every key maps 1:1 to a CSS custom property on the widget's shadow root. Supported keys: :brand, :on_brand (or :onBrand), :background, :surface, :text, :text_muted (or :textMuted), :border, :radius, :font, :header_font (or :headerFont).



65
66
67
68
69
70
# File 'lib/inquirex/dsl/flow_builder.rb', line 65

def meta(title: nil, subtitle: nil, brand: nil, theme: nil)
  @meta[:title] = title if title
  @meta[:subtitle] = subtitle if subtitle
  @meta[:brand] = brand if brand
  @meta[:theme] = normalize_theme(theme) if theme
end

#say(id) ⇒ Object

Defines an informational message step (no input collected).

Parameters:

  • id (Symbol)

    step id



83
84
85
# File 'lib/inquirex/dsl/flow_builder.rb', line 83

def say(id, &)
  add_step(id, :say, &)
end

#send_email(**opts) { ... } ⇒ void

This method returns an undefined value.

Declares an email the host application builds and delivers after the flow finishes, from the collected answers. Declarations run in order; gate with a serializable rule via the if: option. This is the only completion declaration the core DSL carries — richer post-completion behavior belongs to the host application.

Examples:

Receipt sent only when the visitor left an email address

send_email if: not_empty(:email) do
  to      "{{email}}"
  from    "forms@agentica.group"
  subject "Thanks {{name}} — we got your inquiry"
  markdown_text <<~TEXT
    Hi {{name}},

    We received your answers and will reply within one business day.

    {{answers_summary}}
  TEXT
end

Parameters:

  • opts (Hash)

    if: takes a Rules::Base gate; any remaining keys are SendEmail fields (to:, subject:, text:, ...) for the inline form

Yields:

  • block evaluated in SendEmailBuilder (to, from, subject, ...); block values override same-named inline keys

Raises:



141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/inquirex/dsl/flow_builder.rb', line 141

def send_email(**opts, &block)
  rule = opts.delete(:if)
  params = opts
  if block
    builder = SendEmailBuilder.new
    builder.instance_eval(&block)
    params = params.merge(builder.params)
  end
  begin
    @send_emails << SendEmail.new(**params, rule:)
  rescue ArgumentError => e
    raise Errors::DefinitionError, "send_email: #{e.message}"
  end
end

#start(step_id) ⇒ Object

Sets the entry step id for the flow.

Parameters:

  • step_id (Symbol)


44
45
46
# File 'lib/inquirex/dsl/flow_builder.rb', line 44

def start(step_id)
  @start_step_id = step_id
end

#warning(id) ⇒ Object

Defines an important alert step (no input collected).

Parameters:

  • id (Symbol)

    step id



104
105
106
# File 'lib/inquirex/dsl/flow_builder.rb', line 104

def warning(id, &)
  add_step(id, :warning, &)
end