Class: SignalWire::Contexts::Step
- Inherits:
-
Object
- Object
- SignalWire::Contexts::Step
- Defined in:
- lib/signalwire/contexts/context_builder.rb
Overview
Represents a single step within a context.
All mutator methods return self for fluent chaining.
Instance Attribute Summary collapse
-
#name ⇒ Object
readonly
Returns the value of attribute name.
Instance Method Summary collapse
-
#add_bullets(title, bullets) ⇒ Object
Add a POM section with bullet points.
-
#add_gather_question(key:, question:, type: 'string', confirm: false, prompt: nil, functions: nil) ⇒ Object
Add a question to this step’s gather_info configuration.
-
#add_section(title, body) ⇒ Object
Add a POM section (title + body).
-
#clear_sections ⇒ Object
Remove all POM sections and direct text.
-
#initialize(name) ⇒ Step
constructor
A new instance of Step.
-
#set_end(is_end) ⇒ Object
Mark this step as terminal for the step flow.
-
#set_functions(functions) ⇒ Object
Set which non-internal functions are callable while this step is active.
-
#set_gather_info(output_key: nil, completion_action: nil, prompt: nil) ⇒ Object
Enable info gathering for this step.
- #set_reset_consolidate(val) ⇒ Object
- #set_reset_full_reset(val) ⇒ Object
- #set_reset_system_prompt(prompt) ⇒ Object
- #set_reset_user_prompt(prompt) ⇒ Object
- #set_skip_to_next_step(skip) ⇒ Object
- #set_skip_user_turn(skip) ⇒ Object
- #set_step_criteria(criteria) ⇒ Object
-
#set_text(text) ⇒ Object
Set the step’s prompt text directly.
- #set_valid_contexts(contexts) ⇒ Object
- #set_valid_steps(steps) ⇒ Object
- #to_h ⇒ Object
Constructor Details
#initialize(name) ⇒ Step
Returns a new instance of Step.
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/signalwire/contexts/context_builder.rb', line 92 def initialize(name) @name = name @text = nil @step_criteria = nil @functions = nil # nil | "none" | Array<String> @valid_steps = nil @valid_contexts = nil @sections = [] @gather_info = nil # Behavior flags @end = false @skip_user_turn = false @skip_to_next_step = false # Reset object for context-switching from steps @reset_system_prompt = nil @reset_user_prompt = nil @reset_consolidate = false @reset_full_reset = false end |
Instance Attribute Details
#name ⇒ Object (readonly)
Returns the value of attribute name.
90 91 92 |
# File 'lib/signalwire/contexts/context_builder.rb', line 90 def name @name end |
Instance Method Details
#add_bullets(title, bullets) ⇒ Object
Add a POM section with bullet points. Mutually exclusive with set_text.
131 132 133 134 135 136 |
# File 'lib/signalwire/contexts/context_builder.rb', line 131 def add_bullets(title, bullets) raise ArgumentError, "Cannot add POM sections when set_text has been used" unless @text.nil? @sections << { "title" => title, "bullets" => bullets } self end |
#add_gather_question(key:, question:, type: 'string', confirm: false, prompt: nil, functions: nil) ⇒ Object
Add a question to this step’s gather_info configuration. set_gather_info must be called first.
IMPORTANT — gather mode locks function access:
While the model is asking gather questions, the runtime
forcibly deactivates ALL of the step's other functions. The
only callable tools during a gather question are:
- +gather_submit+ (the native answer-submission tool)
- Whatever names you pass in this question's +functions:+
option
+next_step+ and +change_context+ are also filtered out — the
model cannot navigate away until the gather completes. This
is by design: it forces a tight ask → submit → next-question
loop.
If a question needs to call out to a tool (e.g. validate an
email, geocode a ZIP), pass that tool name in this question's
+functions:+ option. Functions listed here are active ONLY for
this question.
Python parity: “add_gather_question(key, question, type=‘string’, confirm=False, prompt=None, functions=None)“. Ruby exposes the same parameter set as keyword args.
251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/signalwire/contexts/context_builder.rb', line 251 def add_gather_question(key:, question:, type: 'string', confirm: false, prompt: nil, functions: nil) raise ArgumentError, "Must call set_gather_info before add_gather_question" if @gather_info.nil? @gather_info.add_question( key: key, question: question, type: type, confirm: confirm, prompt: prompt, functions: functions ) self end |
#add_section(title, body) ⇒ Object
Add a POM section (title + body). Mutually exclusive with set_text.
123 124 125 126 127 128 |
# File 'lib/signalwire/contexts/context_builder.rb', line 123 def add_section(title, body) raise ArgumentError, "Cannot add POM sections when set_text has been used" unless @text.nil? @sections << { "title" => title, "body" => body } self end |
#clear_sections ⇒ Object
Remove all POM sections and direct text.
267 268 269 270 271 |
# File 'lib/signalwire/contexts/context_builder.rb', line 267 def clear_sections @sections = [] @text = nil self end |
#set_end(is_end) ⇒ Object
Mark this step as terminal for the step flow.
IMPORTANT: is_end = true does NOT end the conversation or hang up the call. It exits step mode entirely after this step executes — clearing the steps list, current step index, valid_steps, and valid_contexts. The agent keeps running, but operates only under the base system prompt and the context-level prompt; no more step instructions are injected and no more next_step tool is offered.
To actually end the call, call a hangup tool or define a hangup hook.
201 202 203 204 |
# File 'lib/signalwire/contexts/context_builder.rb', line 201 def set_end(is_end) @end = is_end self end |
#set_functions(functions) ⇒ Object
Set which non-internal functions are callable while this step is active.
IMPORTANT — inheritance behavior:
If you do NOT call this method, the step inherits whichever
function set was active on the previous step (or the previous
context's last step). The server-side runtime only resets the
active set when a step explicitly declares its +functions+
field. This is the most common source of bugs in multi-step
agents: forgetting +set_functions+ on a later step lets the
previous step's tools leak through. Best practice is to call
+set_functions+ explicitly on every step that should differ
from the previous one.
Keep the per-step active set small: LLM tool selection accuracy degrades noticeably past ~7-8 simultaneously-active tools per call. Use per-step whitelisting to partition large tool collections.
Internal functions (e.g. gather_submit, hangup hook) are ALWAYS protected and cannot be deactivated by this whitelist. The native navigation tools next_step and change_context are injected automatically when set_valid_steps/set_valid_contexts is used; they are not affected by this list and do not need to appear in it.
174 175 176 177 |
# File 'lib/signalwire/contexts/context_builder.rb', line 174 def set_functions(functions) @functions = functions self end |
#set_gather_info(output_key: nil, completion_action: nil, prompt: nil) ⇒ Object
Enable info gathering for this step. Returns self. After calling this, use add_gather_question to define questions.
218 219 220 221 222 223 224 225 |
# File 'lib/signalwire/contexts/context_builder.rb', line 218 def set_gather_info(output_key: nil, completion_action: nil, prompt: nil) @gather_info = GatherInfo.new( output_key: output_key, completion_action: completion_action, prompt: prompt ) self end |
#set_reset_consolidate(val) ⇒ Object
283 284 285 286 |
# File 'lib/signalwire/contexts/context_builder.rb', line 283 def set_reset_consolidate(val) @reset_consolidate = val self end |
#set_reset_full_reset(val) ⇒ Object
288 289 290 291 |
# File 'lib/signalwire/contexts/context_builder.rb', line 288 def set_reset_full_reset(val) @reset_full_reset = val self end |
#set_reset_system_prompt(prompt) ⇒ Object
273 274 275 276 |
# File 'lib/signalwire/contexts/context_builder.rb', line 273 def set_reset_system_prompt(prompt) @reset_system_prompt = prompt self end |
#set_reset_user_prompt(prompt) ⇒ Object
278 279 280 281 |
# File 'lib/signalwire/contexts/context_builder.rb', line 278 def set_reset_user_prompt(prompt) @reset_user_prompt = prompt self end |
#set_skip_to_next_step(skip) ⇒ Object
211 212 213 214 |
# File 'lib/signalwire/contexts/context_builder.rb', line 211 def set_skip_to_next_step(skip) @skip_to_next_step = skip self end |
#set_skip_user_turn(skip) ⇒ Object
206 207 208 209 |
# File 'lib/signalwire/contexts/context_builder.rb', line 206 def set_skip_user_turn(skip) @skip_user_turn = skip self end |
#set_step_criteria(criteria) ⇒ Object
138 139 140 141 |
# File 'lib/signalwire/contexts/context_builder.rb', line 138 def set_step_criteria(criteria) @step_criteria = criteria self end |
#set_text(text) ⇒ Object
Set the step’s prompt text directly. Mutually exclusive with POM sections.
115 116 117 118 119 120 |
# File 'lib/signalwire/contexts/context_builder.rb', line 115 def set_text(text) raise ArgumentError, "Cannot use set_text when POM sections have been added" if @sections.any? @text = text self end |
#set_valid_contexts(contexts) ⇒ Object
184 185 186 187 |
# File 'lib/signalwire/contexts/context_builder.rb', line 184 def set_valid_contexts(contexts) @valid_contexts = contexts self end |
#set_valid_steps(steps) ⇒ Object
179 180 181 182 |
# File 'lib/signalwire/contexts/context_builder.rb', line 179 def set_valid_steps(steps) @valid_steps = steps self end |
#to_h ⇒ Object
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
# File 'lib/signalwire/contexts/context_builder.rb', line 293 def to_h step_h = { "name" => @name, "text" => render_text } step_h["step_criteria"] = @step_criteria if @step_criteria step_h["functions"] = @functions unless @functions.nil? step_h["valid_steps"] = @valid_steps if @valid_steps step_h["valid_contexts"] = @valid_contexts if @valid_contexts step_h["end"] = true if @end step_h["skip_user_turn"] = true if @skip_user_turn step_h["skip_to_next_step"] = true if @skip_to_next_step reset = {} reset["system_prompt"] = @reset_system_prompt if @reset_system_prompt reset["user_prompt"] = @reset_user_prompt if @reset_user_prompt reset["consolidate"] = @reset_consolidate if @reset_consolidate reset["full_reset"] = @reset_full_reset if @reset_full_reset step_h["reset"] = reset if reset.any? step_h["gather_info"] = @gather_info.to_h if @gather_info step_h end |