signalwire-agents 0.1.17__py3-none-any.whl → 0.1.19__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,9 +18,16 @@ class Step:
18
18
  self._step_criteria: Optional[str] = None
19
19
  self._functions: Optional[Union[str, List[str]]] = None
20
20
  self._valid_steps: Optional[List[str]] = None
21
+ self._valid_contexts: Optional[List[str]] = None
21
22
 
22
23
  # POM-style sections for rich prompts
23
24
  self._sections: List[Dict[str, Any]] = []
25
+
26
+ # Reset object for context switching from steps
27
+ self._reset_system_prompt: Optional[str] = None
28
+ self._reset_user_prompt: Optional[str] = None
29
+ self._reset_consolidate: bool = False
30
+ self._reset_full_reset: bool = False
24
31
 
25
32
  def set_text(self, text: str) -> 'Step':
26
33
  """
@@ -108,6 +115,71 @@ class Step:
108
115
  self._valid_steps = steps
109
116
  return self
110
117
 
118
+ def set_valid_contexts(self, contexts: List[str]) -> 'Step':
119
+ """
120
+ Set which contexts can be navigated to from this step
121
+
122
+ Args:
123
+ contexts: List of valid context names
124
+
125
+ Returns:
126
+ Self for method chaining
127
+ """
128
+ self._valid_contexts = contexts
129
+ return self
130
+
131
+ def set_reset_system_prompt(self, system_prompt: str) -> 'Step':
132
+ """
133
+ Set system prompt for context switching when this step navigates to a context
134
+
135
+ Args:
136
+ system_prompt: New system prompt for context switching
137
+
138
+ Returns:
139
+ Self for method chaining
140
+ """
141
+ self._reset_system_prompt = system_prompt
142
+ return self
143
+
144
+ def set_reset_user_prompt(self, user_prompt: str) -> 'Step':
145
+ """
146
+ Set user prompt for context switching when this step navigates to a context
147
+
148
+ Args:
149
+ user_prompt: User message to inject for context switching
150
+
151
+ Returns:
152
+ Self for method chaining
153
+ """
154
+ self._reset_user_prompt = user_prompt
155
+ return self
156
+
157
+ def set_reset_consolidate(self, consolidate: bool) -> 'Step':
158
+ """
159
+ Set whether to consolidate conversation when this step switches contexts
160
+
161
+ Args:
162
+ consolidate: Whether to consolidate previous conversation
163
+
164
+ Returns:
165
+ Self for method chaining
166
+ """
167
+ self._reset_consolidate = consolidate
168
+ return self
169
+
170
+ def set_reset_full_reset(self, full_reset: bool) -> 'Step':
171
+ """
172
+ Set whether to do full reset when this step switches contexts
173
+
174
+ Args:
175
+ full_reset: Whether to completely rewrite system prompt vs inject
176
+
177
+ Returns:
178
+ Self for method chaining
179
+ """
180
+ self._reset_full_reset = full_reset
181
+ return self
182
+
111
183
  def _render_text(self) -> str:
112
184
  """Render the step's prompt text"""
113
185
  if self._text is not None:
@@ -145,6 +217,23 @@ class Step:
145
217
  if self._valid_steps is not None:
146
218
  step_dict["valid_steps"] = self._valid_steps
147
219
 
220
+ if self._valid_contexts is not None:
221
+ step_dict["valid_contexts"] = self._valid_contexts
222
+
223
+ # Add reset object if any reset parameters are set
224
+ reset_obj = {}
225
+ if self._reset_system_prompt is not None:
226
+ reset_obj["system_prompt"] = self._reset_system_prompt
227
+ if self._reset_user_prompt is not None:
228
+ reset_obj["user_prompt"] = self._reset_user_prompt
229
+ if self._reset_consolidate:
230
+ reset_obj["consolidate"] = self._reset_consolidate
231
+ if self._reset_full_reset:
232
+ reset_obj["full_reset"] = self._reset_full_reset
233
+
234
+ if reset_obj:
235
+ step_dict["reset"] = reset_obj
236
+
148
237
  return step_dict
149
238
 
150
239
 
@@ -156,6 +245,19 @@ class Context:
156
245
  self._steps: Dict[str, Step] = {}
157
246
  self._step_order: List[str] = []
158
247
  self._valid_contexts: Optional[List[str]] = None
248
+
249
+ # Context entry parameters
250
+ self._post_prompt: Optional[str] = None
251
+ self._system_prompt: Optional[str] = None
252
+ self._system_prompt_sections: List[Dict[str, Any]] = [] # For POM-style system prompts
253
+ self._consolidate: bool = False
254
+ self._full_reset: bool = False
255
+ self._user_prompt: Optional[str] = None
256
+ self._isolated: bool = False
257
+
258
+ # Context prompt (separate from system_prompt)
259
+ self._prompt_text: Optional[str] = None
260
+ self._prompt_sections: List[Dict[str, Any]] = []
159
261
 
160
262
  def add_step(self, name: str) -> Step:
161
263
  """
@@ -188,6 +290,209 @@ class Context:
188
290
  self._valid_contexts = contexts
189
291
  return self
190
292
 
293
+ def set_post_prompt(self, post_prompt: str) -> 'Context':
294
+ """
295
+ Set post prompt override for this context
296
+
297
+ Args:
298
+ post_prompt: Post prompt text to use when this context is active
299
+
300
+ Returns:
301
+ Self for method chaining
302
+ """
303
+ self._post_prompt = post_prompt
304
+ return self
305
+
306
+ def set_system_prompt(self, system_prompt: str) -> 'Context':
307
+ """
308
+ Set system prompt for context switching (triggers context reset)
309
+
310
+ Args:
311
+ system_prompt: New system prompt for when this context is entered
312
+
313
+ Returns:
314
+ Self for method chaining
315
+ """
316
+ if self._system_prompt_sections:
317
+ raise ValueError("Cannot use set_system_prompt() when POM sections have been added for system prompt. Use one approach or the other.")
318
+ self._system_prompt = system_prompt
319
+ return self
320
+
321
+ def set_consolidate(self, consolidate: bool) -> 'Context':
322
+ """
323
+ Set whether to consolidate conversation history when entering this context
324
+
325
+ Args:
326
+ consolidate: Whether to consolidate previous conversation
327
+
328
+ Returns:
329
+ Self for method chaining
330
+ """
331
+ self._consolidate = consolidate
332
+ return self
333
+
334
+ def set_full_reset(self, full_reset: bool) -> 'Context':
335
+ """
336
+ Set whether to do full reset when entering this context
337
+
338
+ Args:
339
+ full_reset: Whether to completely rewrite system prompt vs inject
340
+
341
+ Returns:
342
+ Self for method chaining
343
+ """
344
+ self._full_reset = full_reset
345
+ return self
346
+
347
+ def set_user_prompt(self, user_prompt: str) -> 'Context':
348
+ """
349
+ Set user prompt to inject when entering this context
350
+
351
+ Args:
352
+ user_prompt: User message to inject for context
353
+
354
+ Returns:
355
+ Self for method chaining
356
+ """
357
+ self._user_prompt = user_prompt
358
+ return self
359
+
360
+ def set_isolated(self, isolated: bool) -> 'Context':
361
+ """
362
+ Set whether to truncate conversation history when entering this context
363
+
364
+ Args:
365
+ isolated: Whether to truncate conversation on context switch
366
+
367
+ Returns:
368
+ Self for method chaining
369
+ """
370
+ self._isolated = isolated
371
+ return self
372
+
373
+ def add_system_section(self, title: str, body: str) -> 'Context':
374
+ """
375
+ Add a POM section to the system prompt
376
+
377
+ Args:
378
+ title: Section title
379
+ body: Section body text
380
+
381
+ Returns:
382
+ Self for method chaining
383
+ """
384
+ if self._system_prompt is not None:
385
+ raise ValueError("Cannot add POM sections for system prompt when set_system_prompt() has been used. Use one approach or the other.")
386
+ self._system_prompt_sections.append({"title": title, "body": body})
387
+ return self
388
+
389
+ def add_system_bullets(self, title: str, bullets: List[str]) -> 'Context':
390
+ """
391
+ Add a POM section with bullet points to the system prompt
392
+
393
+ Args:
394
+ title: Section title
395
+ bullets: List of bullet points
396
+
397
+ Returns:
398
+ Self for method chaining
399
+ """
400
+ if self._system_prompt is not None:
401
+ raise ValueError("Cannot add POM sections for system prompt when set_system_prompt() has been used. Use one approach or the other.")
402
+ self._system_prompt_sections.append({"title": title, "bullets": bullets})
403
+ return self
404
+
405
+ def set_prompt(self, prompt: str) -> 'Context':
406
+ """
407
+ Set the context's prompt text directly
408
+
409
+ Args:
410
+ prompt: The prompt text for this context
411
+
412
+ Returns:
413
+ Self for method chaining
414
+ """
415
+ if self._prompt_sections:
416
+ raise ValueError("Cannot use set_prompt() when POM sections have been added. Use one approach or the other.")
417
+ self._prompt_text = prompt
418
+ return self
419
+
420
+ def add_section(self, title: str, body: str) -> 'Context':
421
+ """
422
+ Add a POM section to the context prompt
423
+
424
+ Args:
425
+ title: Section title
426
+ body: Section body text
427
+
428
+ Returns:
429
+ Self for method chaining
430
+ """
431
+ if self._prompt_text is not None:
432
+ raise ValueError("Cannot add POM sections when set_prompt() has been used. Use one approach or the other.")
433
+ self._prompt_sections.append({"title": title, "body": body})
434
+ return self
435
+
436
+ def add_bullets(self, title: str, bullets: List[str]) -> 'Context':
437
+ """
438
+ Add a POM section with bullet points to the context prompt
439
+
440
+ Args:
441
+ title: Section title
442
+ bullets: List of bullet points
443
+
444
+ Returns:
445
+ Self for method chaining
446
+ """
447
+ if self._prompt_text is not None:
448
+ raise ValueError("Cannot add POM sections when set_prompt() has been used. Use one approach or the other.")
449
+ self._prompt_sections.append({"title": title, "bullets": bullets})
450
+ return self
451
+
452
+ def _render_prompt(self) -> Optional[str]:
453
+ """Render the context's prompt text"""
454
+ if self._prompt_text is not None:
455
+ return self._prompt_text
456
+
457
+ if not self._prompt_sections:
458
+ return None
459
+
460
+ # Convert POM sections to markdown
461
+ markdown_parts = []
462
+ for section in self._prompt_sections:
463
+ if "bullets" in section:
464
+ markdown_parts.append(f"## {section['title']}")
465
+ for bullet in section["bullets"]:
466
+ markdown_parts.append(f"- {bullet}")
467
+ else:
468
+ markdown_parts.append(f"## {section['title']}")
469
+ markdown_parts.append(section["body"])
470
+ markdown_parts.append("") # Add spacing
471
+
472
+ return "\n".join(markdown_parts).strip()
473
+
474
+ def _render_system_prompt(self) -> Optional[str]:
475
+ """Render the system prompt text"""
476
+ if self._system_prompt is not None:
477
+ return self._system_prompt
478
+
479
+ if not self._system_prompt_sections:
480
+ return None
481
+
482
+ # Convert POM sections to markdown
483
+ markdown_parts = []
484
+ for section in self._system_prompt_sections:
485
+ if "bullets" in section:
486
+ markdown_parts.append(f"## {section['title']}")
487
+ for bullet in section["bullets"]:
488
+ markdown_parts.append(f"- {bullet}")
489
+ else:
490
+ markdown_parts.append(f"## {section['title']}")
491
+ markdown_parts.append(section["body"])
492
+ markdown_parts.append("") # Add spacing
493
+
494
+ return "\n".join(markdown_parts).strip()
495
+
191
496
  def to_dict(self) -> Dict[str, Any]:
192
497
  """Convert context to dictionary for SWML generation"""
193
498
  if not self._steps:
@@ -199,6 +504,34 @@ class Context:
199
504
 
200
505
  if self._valid_contexts is not None:
201
506
  context_dict["valid_contexts"] = self._valid_contexts
507
+
508
+ # Add context entry parameters
509
+ if self._post_prompt is not None:
510
+ context_dict["post_prompt"] = self._post_prompt
511
+
512
+ rendered_system_prompt = self._render_system_prompt()
513
+ if rendered_system_prompt is not None:
514
+ context_dict["system_prompt"] = rendered_system_prompt
515
+
516
+ if self._consolidate:
517
+ context_dict["consolidate"] = self._consolidate
518
+
519
+ if self._full_reset:
520
+ context_dict["full_reset"] = self._full_reset
521
+
522
+ if self._user_prompt is not None:
523
+ context_dict["user_prompt"] = self._user_prompt
524
+
525
+ if self._isolated:
526
+ context_dict["isolated"] = self._isolated
527
+
528
+ # Add context prompt - use POM structure if sections exist, otherwise use string
529
+ if self._prompt_sections:
530
+ # Use structured POM format
531
+ context_dict["pom"] = self._prompt_sections
532
+ elif self._prompt_text is not None:
533
+ # Use string format
534
+ context_dict["prompt"] = self._prompt_text
202
535
 
203
536
  return context_dict
204
537
 
@@ -103,19 +103,19 @@ class AIVerbHandler(SWMLVerbHandler):
103
103
  errors.append("'prompt' must be an object")
104
104
  return False, errors
105
105
 
106
- # Check that prompt contains one of: text, pom, or contexts
106
+ # Check that prompt contains either text or pom (required)
107
107
  has_text = "text" in prompt
108
108
  has_pom = "pom" in prompt
109
109
  has_contexts = "contexts" in prompt
110
110
 
111
- options_count = sum([has_text, has_pom, has_contexts])
111
+ # Require either text or pom (mutually exclusive)
112
+ base_prompt_count = sum([has_text, has_pom])
113
+ if base_prompt_count == 0:
114
+ errors.append("'prompt' must contain either 'text' or 'pom' as base prompt")
115
+ elif base_prompt_count > 1:
116
+ errors.append("'prompt' can only contain one of: 'text' or 'pom' (mutually exclusive)")
112
117
 
113
- if options_count == 0:
114
- errors.append("'prompt' must contain one of: 'text', 'pom', or 'contexts'")
115
- elif options_count > 1:
116
- errors.append("'prompt' can only contain one of: 'text', 'pom', or 'contexts'")
117
-
118
- # Validate contexts structure if present
118
+ # Contexts are optional and can be combined with text or pom
119
119
  if has_contexts:
120
120
  contexts = prompt["contexts"]
121
121
  if not isinstance(contexts, dict):
@@ -141,9 +141,9 @@ class AIVerbHandler(SWMLVerbHandler):
141
141
  Build a configuration for the AI verb
142
142
 
143
143
  Args:
144
- prompt_text: Text prompt for the AI (mutually exclusive with prompt_pom and contexts)
145
- prompt_pom: POM structure for the AI prompt (mutually exclusive with prompt_text and contexts)
146
- contexts: Contexts and steps configuration (mutually exclusive with prompt_text and prompt_pom)
144
+ prompt_text: Text prompt for the AI (mutually exclusive with prompt_pom)
145
+ prompt_pom: POM structure for the AI prompt (mutually exclusive with prompt_text)
146
+ contexts: Optional contexts and steps configuration (can be combined with text or pom)
147
147
  post_prompt: Optional post-prompt text
148
148
  post_prompt_url: Optional URL for post-prompt processing
149
149
  swaig: Optional SWAIG configuration
@@ -154,19 +154,25 @@ class AIVerbHandler(SWMLVerbHandler):
154
154
  """
155
155
  config = {}
156
156
 
157
- # Add prompt (either text, POM, or contexts - mutually exclusive)
158
- prompt_options_count = sum(x is not None for x in [prompt_text, prompt_pom, contexts])
159
- if prompt_options_count == 0:
160
- raise ValueError("One of prompt_text, prompt_pom, or contexts must be provided")
161
- elif prompt_options_count > 1:
162
- raise ValueError("prompt_text, prompt_pom, and contexts are mutually exclusive")
157
+ # Require either text or pom as base prompt (mutually exclusive)
158
+ base_prompt_count = sum(x is not None for x in [prompt_text, prompt_pom])
159
+ if base_prompt_count == 0:
160
+ raise ValueError("Either prompt_text or prompt_pom must be provided as base prompt")
161
+ elif base_prompt_count > 1:
162
+ raise ValueError("prompt_text and prompt_pom are mutually exclusive")
163
163
 
164
+ # Build prompt object with base prompt
165
+ prompt_config = {}
164
166
  if prompt_text is not None:
165
- config["prompt"] = {"text": prompt_text}
167
+ prompt_config["text"] = prompt_text
166
168
  elif prompt_pom is not None:
167
- config["prompt"] = {"pom": prompt_pom}
168
- elif contexts is not None:
169
- config["prompt"] = {"contexts": contexts}
169
+ prompt_config["pom"] = prompt_pom
170
+
171
+ # Add contexts if provided (optional, activates steps feature)
172
+ if contexts is not None:
173
+ prompt_config["contexts"] = contexts
174
+
175
+ config["prompt"] = prompt_config
170
176
 
171
177
  # Add post-prompt if provided
172
178
  if post_prompt is not None:
@@ -83,7 +83,6 @@ class DataSphereServerlessSkill(SkillBase):
83
83
  webhook_params = {
84
84
  "document_id": self.document_id,
85
85
  "query_string": "${args.query}", # Only this is dynamic from user input
86
- "distance": self.distance,
87
86
  "count": self.count
88
87
  }
89
88
 
@@ -224,7 +224,7 @@ class WebSearchSkill(SkillBase):
224
224
  formatted_message = self.no_results_message.format(query=query) if '{query}' in self.no_results_message else self.no_results_message
225
225
  return SwaigFunctionResult(formatted_message)
226
226
 
227
- response = f"I found {num_results} results for '{query}':\n\n{search_results}"
227
+ response = f"Here are {num_results} results for '{query}':\n\nReiterate them to the user in a concise summary format\n\n{search_results}"
228
228
  return SwaigFunctionResult(response)
229
229
 
230
230
  except Exception as e:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: signalwire_agents
3
- Version: 0.1.17
3
+ Version: 0.1.19
4
4
  Summary: SignalWire AI Agents SDK
5
5
  Author-email: SignalWire Team <info@signalwire.com>
6
6
  Project-URL: Homepage, https://github.com/signalwire/signalwire-ai-agents
@@ -287,7 +287,7 @@ For detailed documentation, see [DataMap Guide](docs/datamap_guide.md).
287
287
 
288
288
  ## Contexts and Steps
289
289
 
290
- The SignalWire Agents SDK provides a powerful alternative to traditional Prompt Object Model (POM) prompts through the **Contexts and Steps** system. This feature allows you to create structured, workflow-driven AI interactions with explicit navigation control and step-by-step guidance.
290
+ The SignalWire Agents SDK provides a powerful enhancement to traditional prompts through the **Contexts and Steps** system. This feature allows you to add structured, workflow-driven AI interactions on top of your base prompt, with explicit navigation control and step-by-step guidance.
291
291
 
292
292
  ### Why Use Contexts and Steps?
293
293
 
@@ -296,7 +296,7 @@ The SignalWire Agents SDK provides a powerful alternative to traditional Prompt
296
296
  - **Completion Criteria**: Set specific criteria for step completion and progression
297
297
  - **Function Restrictions**: Limit which AI tools are available in each step
298
298
  - **Workflow Isolation**: Create separate contexts for different conversation flows
299
- - **Backward Compatibility**: Works alongside traditional prompts and all existing AgentBase features
299
+ - **Enhanced Base Prompts**: Adds structured workflows on top of your existing prompt foundation
300
300
 
301
301
  ### Basic Usage
302
302
 
@@ -307,30 +307,34 @@ class WorkflowAgent(AgentBase):
307
307
  def __init__(self):
308
308
  super().__init__(name="Workflow Assistant", route="/workflow")
309
309
 
310
- # Define contexts and steps (alternative to traditional prompts)
310
+ # Set base prompt (required even when using contexts)
311
+ self.prompt_add_section("Role", "You are a helpful workflow assistant.")
312
+ self.prompt_add_section("Instructions", "Guide users through structured processes step by step.")
313
+
314
+ # Define contexts and steps (adds structured workflow to base prompt)
311
315
  contexts = self.define_contexts()
312
316
 
313
317
  # Create a single context named "default" (required for single context)
314
- context = contexts.create_context("default")
318
+ context = contexts.add_context("default")
315
319
 
316
320
  # Add step-by-step workflow
317
- context.create_step("greeting") \
321
+ context.add_step("greeting") \
318
322
  .set_text("Welcome! I'm here to help you complete your application. Let's start with your personal information.") \
319
323
  .set_step_criteria("User has provided their name and confirmed they want to continue") \
320
324
  .set_valid_steps(["personal_info"]) # Can only go to personal_info step
321
325
 
322
- context.create_step("personal_info") \
326
+ context.add_step("personal_info") \
323
327
  .add_section("Instructions", "Collect the user's personal information") \
324
328
  .add_bullets(["Ask for full name", "Ask for email address", "Ask for phone number"]) \
325
329
  .set_step_criteria("All personal information has been collected and confirmed") \
326
330
  .set_valid_steps(["review", "personal_info"]) # Can stay or move to review
327
331
 
328
- context.create_step("review") \
332
+ context.add_step("review") \
329
333
  .set_text("Let me review the information you've provided. Please confirm if everything is correct.") \
330
334
  .set_step_criteria("User has confirmed or requested changes") \
331
335
  .set_valid_steps(["personal_info", "complete"]) # Can go back or complete
332
336
 
333
- context.create_step("complete") \
337
+ context.add_step("complete") \
334
338
  .set_text("Thank you! Your application has been submitted successfully.") \
335
339
  .set_step_criteria("Application processing is complete")
336
340
  # No valid_steps = end of workflow
@@ -346,22 +350,27 @@ class MultiContextAgent(AgentBase):
346
350
  def __init__(self):
347
351
  super().__init__(name="Multi-Context Agent", route="/multi-context")
348
352
 
349
- # Add skills first
353
+ # Set base prompt (required)
354
+ self.prompt_add_section("Role", "You are a versatile AI assistant.")
355
+ self.prompt_add_section("Capabilities", "You can help with calculations and provide time information.")
356
+
357
+ # Add skills
350
358
  self.add_skill("datetime")
351
359
  self.add_skill("math")
352
360
 
361
+ # Define contexts for different service modes
353
362
  contexts = self.define_contexts()
354
363
 
355
364
  # Main conversation context
356
- main_context = contexts.create_context("main")
357
- main_context.create_step("welcome") \
365
+ main_context = contexts.add_context("main")
366
+ main_context.add_step("welcome") \
358
367
  .set_text("Welcome! I can help with calculations or provide date/time info. What would you like to do?") \
359
368
  .set_step_criteria("User has chosen a service type") \
360
369
  .set_valid_contexts(["calculator", "datetime_info"]) # Can switch contexts
361
370
 
362
371
  # Calculator context with function restrictions
363
- calc_context = contexts.create_context("calculator")
364
- calc_context.create_step("math_mode") \
372
+ calc_context = contexts.add_context("calculator")
373
+ calc_context.add_step("math_mode") \
365
374
  .add_section("Role", "You are a mathematical assistant") \
366
375
  .add_section("Instructions", "Help users with calculations") \
367
376
  .set_functions(["math"]) # Only math function available \
@@ -369,8 +378,8 @@ class MultiContextAgent(AgentBase):
369
378
  .set_valid_contexts(["main"]) # Can return to main
370
379
 
371
380
  # DateTime context
372
- datetime_context = contexts.create_context("datetime_info")
373
- datetime_context.create_step("time_mode") \
381
+ datetime_context = contexts.add_context("datetime_info")
382
+ datetime_context.add_step("time_mode") \
374
383
  .set_text("I can provide current date and time information. What would you like to know?") \
375
384
  .set_functions(["datetime"]) # Only datetime function available \
376
385
  .set_step_criteria("Date/time information has been provided") \
@@ -380,7 +389,7 @@ class MultiContextAgent(AgentBase):
380
389
  ### Context and Step Methods
381
390
 
382
391
  #### Context Methods
383
- - `create_step(name)`: Create a new step in this context
392
+ - `add_step(name)`: Create a new step in this context
384
393
  - `set_valid_contexts(contexts)`: Control which contexts can be accessed from this context
385
394
 
386
395
  #### Step Methods
@@ -406,41 +415,45 @@ class SupportAgent(AgentBase):
406
415
  def __init__(self):
407
416
  super().__init__(name="Customer Support", route="/support")
408
417
 
418
+ # Set base prompt (required)
419
+ self.prompt_add_section("Role", "You are a professional customer support representative.")
420
+ self.prompt_add_section("Goal", "Provide excellent customer service using structured workflows.")
421
+
409
422
  # Add skills for enhanced capabilities
410
423
  self.add_skill("datetime")
411
424
  self.add_skill("web_search", {"api_key": "your-key", "search_engine_id": "your-id"})
412
425
 
426
+ # Define support workflow contexts
413
427
  contexts = self.define_contexts()
414
428
 
415
429
  # Triage context
416
- triage = contexts.create_context("triage")
417
- triage.create_step("initial_greeting") \
418
- .add_section("Role", "You are a helpful customer support agent") \
419
- .add_section("Goal", "Understand the customer's issue and route them appropriately") \
420
- .add_bullets(["Be empathetic and professional", "Ask clarifying questions", "Categorize the issue"]) \
430
+ triage = contexts.add_context("triage")
431
+ triage.add_step("initial_greeting") \
432
+ .add_section("Current Task", "Understand the customer's issue and route them appropriately") \
433
+ .add_bullets("Questions to Ask", ["What problem are you experiencing?", "How urgent is this issue?", "Have you tried any troubleshooting steps?"]) \
421
434
  .set_step_criteria("Issue type has been identified") \
422
435
  .set_valid_contexts(["technical_support", "billing_support", "general_inquiry"])
423
436
 
424
437
  # Technical support context
425
- tech = contexts.create_context("technical_support")
426
- tech.create_step("technical_diagnosis") \
427
- .add_section("Role", "You are a technical support specialist") \
428
- .add_section("Instructions", "Help diagnose and resolve technical issues") \
438
+ tech = contexts.add_context("technical_support")
439
+ tech.add_step("technical_diagnosis") \
440
+ .add_section("Current Task", "Help diagnose and resolve technical issues") \
441
+ .add_section("Available Tools", "Use web search to find solutions and datetime to check service windows") \
429
442
  .set_functions(["web_search", "datetime"]) # Can search for solutions and check times \
430
443
  .set_step_criteria("Technical issue is resolved or escalated") \
431
444
  .set_valid_contexts(["triage"]) # Can return to triage
432
445
 
433
446
  # Billing support context
434
- billing = contexts.create_context("billing_support")
435
- billing.create_step("billing_assistance") \
447
+ billing = contexts.add_context("billing_support")
448
+ billing.add_step("billing_assistance") \
436
449
  .set_text("I'll help you with your billing inquiry. Please provide your account details.") \
437
450
  .set_functions("none") # No external tools for sensitive billing info \
438
451
  .set_step_criteria("Billing issue is addressed") \
439
452
  .set_valid_contexts(["triage"])
440
453
 
441
454
  # General inquiry context
442
- general = contexts.create_context("general_inquiry")
443
- general.create_step("general_help") \
455
+ general = contexts.add_context("general_inquiry")
456
+ general.add_step("general_help") \
444
457
  .set_text("I'm here to help with general questions. What can I assist you with?") \
445
458
  .set_functions(["web_search", "datetime"]) # Full access to search and time \
446
459
  .set_step_criteria("Inquiry has been answered") \