signalwire-agents 0.1.16__tar.gz → 0.1.18__tar.gz

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.
Files changed (74) hide show
  1. {signalwire_agents-0.1.16/signalwire_agents.egg-info → signalwire_agents-0.1.18}/PKG-INFO +43 -30
  2. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/README.md +42 -29
  3. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/pyproject.toml +2 -2
  4. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/__init__.py +1 -1
  5. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/cli/build_search.py +152 -4
  6. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/core/agent_base.py +77 -4
  7. signalwire_agents-0.1.18/signalwire_agents/core/contexts.py +622 -0
  8. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/core/swml_handler.py +27 -21
  9. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/skills/web_search/skill.py +1 -1
  10. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18/signalwire_agents.egg-info}/PKG-INFO +43 -30
  11. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents.egg-info/SOURCES.txt +2 -2
  12. signalwire_agents-0.1.16/signalwire_agents/core/contexts.py +0 -289
  13. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/LICENSE +0 -0
  14. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/schema.json +0 -0
  15. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/setup.cfg +0 -0
  16. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/setup.py +0 -0
  17. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/agent_server.py +0 -0
  18. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/cli/__init__.py +0 -0
  19. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/cli/test_swaig.py +0 -0
  20. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/core/__init__.py +0 -0
  21. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/core/data_map.py +0 -0
  22. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/core/function_result.py +0 -0
  23. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/core/logging_config.py +0 -0
  24. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/core/pom_builder.py +0 -0
  25. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/core/security/__init__.py +0 -0
  26. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/core/security/session_manager.py +0 -0
  27. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/core/skill_base.py +0 -0
  28. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/core/skill_manager.py +0 -0
  29. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/core/state/__init__.py +0 -0
  30. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/core/state/file_state_manager.py +0 -0
  31. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/core/state/state_manager.py +0 -0
  32. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/core/swaig_function.py +0 -0
  33. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/core/swml_builder.py +0 -0
  34. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/core/swml_renderer.py +0 -0
  35. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/core/swml_service.py +0 -0
  36. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/prefabs/__init__.py +0 -0
  37. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/prefabs/concierge.py +0 -0
  38. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/prefabs/faq_bot.py +0 -0
  39. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/prefabs/info_gatherer.py +0 -0
  40. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/prefabs/receptionist.py +0 -0
  41. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/prefabs/survey.py +0 -0
  42. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/schema.json +0 -0
  43. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/search/__init__.py +0 -0
  44. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/search/document_processor.py +0 -0
  45. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/search/index_builder.py +0 -0
  46. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/search/query_processor.py +0 -0
  47. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/search/search_engine.py +0 -0
  48. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/search/search_service.py +0 -0
  49. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/skills/__init__.py +0 -0
  50. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/skills/datasphere/__init__.py +0 -0
  51. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/skills/datasphere/skill.py +0 -0
  52. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/skills/datasphere_serverless/__init__.py +0 -0
  53. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/skills/datasphere_serverless/skill.py +0 -0
  54. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/skills/datetime/__init__.py +0 -0
  55. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/skills/datetime/skill.py +0 -0
  56. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/skills/joke/__init__.py +0 -0
  57. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/skills/joke/skill.py +0 -0
  58. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/skills/math/__init__.py +0 -0
  59. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/skills/math/skill.py +0 -0
  60. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/skills/native_vector_search/__init__.py +0 -0
  61. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/skills/native_vector_search/skill.py +0 -0
  62. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/skills/registry.py +0 -0
  63. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/skills/web_search/__init__.py +0 -0
  64. {signalwire_agents-0.1.16/signalwire_agents/skills/wikipedia → signalwire_agents-0.1.18/signalwire_agents/skills/wikipedia_search}/__init__.py +0 -0
  65. {signalwire_agents-0.1.16/signalwire_agents/skills/wikipedia → signalwire_agents-0.1.18/signalwire_agents/skills/wikipedia_search}/skill.py +0 -0
  66. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/utils/__init__.py +0 -0
  67. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/utils/pom_utils.py +0 -0
  68. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/utils/schema_utils.py +0 -0
  69. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/utils/token_generators.py +0 -0
  70. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents/utils/validators.py +0 -0
  71. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents.egg-info/dependency_links.txt +0 -0
  72. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents.egg-info/entry_points.txt +0 -0
  73. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents.egg-info/requires.txt +0 -0
  74. {signalwire_agents-0.1.16 → signalwire_agents-0.1.18}/signalwire_agents.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: signalwire_agents
3
- Version: 0.1.16
3
+ Version: 0.1.18
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") \
@@ -221,7 +221,7 @@ For detailed documentation, see [DataMap Guide](docs/datamap_guide.md).
221
221
 
222
222
  ## Contexts and Steps
223
223
 
224
- 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.
224
+ 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.
225
225
 
226
226
  ### Why Use Contexts and Steps?
227
227
 
@@ -230,7 +230,7 @@ The SignalWire Agents SDK provides a powerful alternative to traditional Prompt
230
230
  - **Completion Criteria**: Set specific criteria for step completion and progression
231
231
  - **Function Restrictions**: Limit which AI tools are available in each step
232
232
  - **Workflow Isolation**: Create separate contexts for different conversation flows
233
- - **Backward Compatibility**: Works alongside traditional prompts and all existing AgentBase features
233
+ - **Enhanced Base Prompts**: Adds structured workflows on top of your existing prompt foundation
234
234
 
235
235
  ### Basic Usage
236
236
 
@@ -241,30 +241,34 @@ class WorkflowAgent(AgentBase):
241
241
  def __init__(self):
242
242
  super().__init__(name="Workflow Assistant", route="/workflow")
243
243
 
244
- # Define contexts and steps (alternative to traditional prompts)
244
+ # Set base prompt (required even when using contexts)
245
+ self.prompt_add_section("Role", "You are a helpful workflow assistant.")
246
+ self.prompt_add_section("Instructions", "Guide users through structured processes step by step.")
247
+
248
+ # Define contexts and steps (adds structured workflow to base prompt)
245
249
  contexts = self.define_contexts()
246
250
 
247
251
  # Create a single context named "default" (required for single context)
248
- context = contexts.create_context("default")
252
+ context = contexts.add_context("default")
249
253
 
250
254
  # Add step-by-step workflow
251
- context.create_step("greeting") \
255
+ context.add_step("greeting") \
252
256
  .set_text("Welcome! I'm here to help you complete your application. Let's start with your personal information.") \
253
257
  .set_step_criteria("User has provided their name and confirmed they want to continue") \
254
258
  .set_valid_steps(["personal_info"]) # Can only go to personal_info step
255
259
 
256
- context.create_step("personal_info") \
260
+ context.add_step("personal_info") \
257
261
  .add_section("Instructions", "Collect the user's personal information") \
258
262
  .add_bullets(["Ask for full name", "Ask for email address", "Ask for phone number"]) \
259
263
  .set_step_criteria("All personal information has been collected and confirmed") \
260
264
  .set_valid_steps(["review", "personal_info"]) # Can stay or move to review
261
265
 
262
- context.create_step("review") \
266
+ context.add_step("review") \
263
267
  .set_text("Let me review the information you've provided. Please confirm if everything is correct.") \
264
268
  .set_step_criteria("User has confirmed or requested changes") \
265
269
  .set_valid_steps(["personal_info", "complete"]) # Can go back or complete
266
270
 
267
- context.create_step("complete") \
271
+ context.add_step("complete") \
268
272
  .set_text("Thank you! Your application has been submitted successfully.") \
269
273
  .set_step_criteria("Application processing is complete")
270
274
  # No valid_steps = end of workflow
@@ -280,22 +284,27 @@ class MultiContextAgent(AgentBase):
280
284
  def __init__(self):
281
285
  super().__init__(name="Multi-Context Agent", route="/multi-context")
282
286
 
283
- # Add skills first
287
+ # Set base prompt (required)
288
+ self.prompt_add_section("Role", "You are a versatile AI assistant.")
289
+ self.prompt_add_section("Capabilities", "You can help with calculations and provide time information.")
290
+
291
+ # Add skills
284
292
  self.add_skill("datetime")
285
293
  self.add_skill("math")
286
294
 
295
+ # Define contexts for different service modes
287
296
  contexts = self.define_contexts()
288
297
 
289
298
  # Main conversation context
290
- main_context = contexts.create_context("main")
291
- main_context.create_step("welcome") \
299
+ main_context = contexts.add_context("main")
300
+ main_context.add_step("welcome") \
292
301
  .set_text("Welcome! I can help with calculations or provide date/time info. What would you like to do?") \
293
302
  .set_step_criteria("User has chosen a service type") \
294
303
  .set_valid_contexts(["calculator", "datetime_info"]) # Can switch contexts
295
304
 
296
305
  # Calculator context with function restrictions
297
- calc_context = contexts.create_context("calculator")
298
- calc_context.create_step("math_mode") \
306
+ calc_context = contexts.add_context("calculator")
307
+ calc_context.add_step("math_mode") \
299
308
  .add_section("Role", "You are a mathematical assistant") \
300
309
  .add_section("Instructions", "Help users with calculations") \
301
310
  .set_functions(["math"]) # Only math function available \
@@ -303,8 +312,8 @@ class MultiContextAgent(AgentBase):
303
312
  .set_valid_contexts(["main"]) # Can return to main
304
313
 
305
314
  # DateTime context
306
- datetime_context = contexts.create_context("datetime_info")
307
- datetime_context.create_step("time_mode") \
315
+ datetime_context = contexts.add_context("datetime_info")
316
+ datetime_context.add_step("time_mode") \
308
317
  .set_text("I can provide current date and time information. What would you like to know?") \
309
318
  .set_functions(["datetime"]) # Only datetime function available \
310
319
  .set_step_criteria("Date/time information has been provided") \
@@ -314,7 +323,7 @@ class MultiContextAgent(AgentBase):
314
323
  ### Context and Step Methods
315
324
 
316
325
  #### Context Methods
317
- - `create_step(name)`: Create a new step in this context
326
+ - `add_step(name)`: Create a new step in this context
318
327
  - `set_valid_contexts(contexts)`: Control which contexts can be accessed from this context
319
328
 
320
329
  #### Step Methods
@@ -340,41 +349,45 @@ class SupportAgent(AgentBase):
340
349
  def __init__(self):
341
350
  super().__init__(name="Customer Support", route="/support")
342
351
 
352
+ # Set base prompt (required)
353
+ self.prompt_add_section("Role", "You are a professional customer support representative.")
354
+ self.prompt_add_section("Goal", "Provide excellent customer service using structured workflows.")
355
+
343
356
  # Add skills for enhanced capabilities
344
357
  self.add_skill("datetime")
345
358
  self.add_skill("web_search", {"api_key": "your-key", "search_engine_id": "your-id"})
346
359
 
360
+ # Define support workflow contexts
347
361
  contexts = self.define_contexts()
348
362
 
349
363
  # Triage context
350
- triage = contexts.create_context("triage")
351
- triage.create_step("initial_greeting") \
352
- .add_section("Role", "You are a helpful customer support agent") \
353
- .add_section("Goal", "Understand the customer's issue and route them appropriately") \
354
- .add_bullets(["Be empathetic and professional", "Ask clarifying questions", "Categorize the issue"]) \
364
+ triage = contexts.add_context("triage")
365
+ triage.add_step("initial_greeting") \
366
+ .add_section("Current Task", "Understand the customer's issue and route them appropriately") \
367
+ .add_bullets("Questions to Ask", ["What problem are you experiencing?", "How urgent is this issue?", "Have you tried any troubleshooting steps?"]) \
355
368
  .set_step_criteria("Issue type has been identified") \
356
369
  .set_valid_contexts(["technical_support", "billing_support", "general_inquiry"])
357
370
 
358
371
  # Technical support context
359
- tech = contexts.create_context("technical_support")
360
- tech.create_step("technical_diagnosis") \
361
- .add_section("Role", "You are a technical support specialist") \
362
- .add_section("Instructions", "Help diagnose and resolve technical issues") \
372
+ tech = contexts.add_context("technical_support")
373
+ tech.add_step("technical_diagnosis") \
374
+ .add_section("Current Task", "Help diagnose and resolve technical issues") \
375
+ .add_section("Available Tools", "Use web search to find solutions and datetime to check service windows") \
363
376
  .set_functions(["web_search", "datetime"]) # Can search for solutions and check times \
364
377
  .set_step_criteria("Technical issue is resolved or escalated") \
365
378
  .set_valid_contexts(["triage"]) # Can return to triage
366
379
 
367
380
  # Billing support context
368
- billing = contexts.create_context("billing_support")
369
- billing.create_step("billing_assistance") \
381
+ billing = contexts.add_context("billing_support")
382
+ billing.add_step("billing_assistance") \
370
383
  .set_text("I'll help you with your billing inquiry. Please provide your account details.") \
371
384
  .set_functions("none") # No external tools for sensitive billing info \
372
385
  .set_step_criteria("Billing issue is addressed") \
373
386
  .set_valid_contexts(["triage"])
374
387
 
375
388
  # General inquiry context
376
- general = contexts.create_context("general_inquiry")
377
- general.create_step("general_help") \
389
+ general = contexts.add_context("general_inquiry")
390
+ general.add_step("general_help") \
378
391
  .set_text("I'm here to help with general questions. What can I assist you with?") \
379
392
  .set_functions(["web_search", "datetime"]) # Full access to search and time \
380
393
  .set_step_criteria("Inquiry has been answered") \
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "signalwire_agents"
7
- version = "0.1.16"
7
+ version = "0.1.18"
8
8
  description = "SignalWire AI Agents SDK"
9
9
  authors = [
10
10
  {name = "SignalWire Team", email = "info@signalwire.com"}
@@ -93,7 +93,7 @@ swaig-test = "signalwire_agents.cli.test_swaig:console_entry_point"
93
93
  sw-search = "signalwire_agents.cli.sw_search_fast:main"
94
94
 
95
95
  [tool.setuptools]
96
- packages = ["signalwire_agents", "signalwire_agents.prefabs", "signalwire_agents.utils", "signalwire_agents.core", "signalwire_agents.core.state", "signalwire_agents.core.security", "signalwire_agents.skills", "signalwire_agents.skills.web_search", "signalwire_agents.skills.datetime", "signalwire_agents.skills.math", "signalwire_agents.skills.joke", "signalwire_agents.skills.datasphere", "signalwire_agents.skills.datasphere_serverless", "signalwire_agents.skills.wikipedia", "signalwire_agents.skills.native_vector_search", "signalwire_agents.cli", "signalwire_agents.search"]
96
+ packages = ["signalwire_agents", "signalwire_agents.prefabs", "signalwire_agents.utils", "signalwire_agents.core", "signalwire_agents.core.state", "signalwire_agents.core.security", "signalwire_agents.skills", "signalwire_agents.skills.web_search", "signalwire_agents.skills.datetime", "signalwire_agents.skills.math", "signalwire_agents.skills.joke", "signalwire_agents.skills.datasphere", "signalwire_agents.skills.datasphere_serverless", "signalwire_agents.skills.wikipedia_search", "signalwire_agents.skills.native_vector_search", "signalwire_agents.cli", "signalwire_agents.search"]
97
97
  include-package-data = true
98
98
 
99
99
  [tool.setuptools.package-data]
@@ -18,7 +18,7 @@ A package for building AI agents using SignalWire's AI and SWML capabilities.
18
18
  from .core.logging_config import configure_logging
19
19
  configure_logging()
20
20
 
21
- __version__ = "0.1.16"
21
+ __version__ = "0.1.18"
22
22
 
23
23
  # Import core classes for easier access
24
24
  from .core.agent_base import AgentBase
@@ -85,6 +85,10 @@ Examples:
85
85
  sw-search search ./docs.swsearch "how to create an agent"
86
86
  sw-search search ./docs.swsearch "API reference" --count 3 --verbose
87
87
  sw-search search ./docs.swsearch "configuration" --tags documentation --json
88
+
89
+ # Search via remote API
90
+ sw-search remote http://localhost:8001 "how to create an agent" --index-name docs
91
+ sw-search remote localhost:8001 "API reference" --index-name docs --count 3 --verbose
88
92
  """
89
93
  )
90
94
 
@@ -263,7 +267,7 @@ Examples:
263
267
 
264
268
  try:
265
269
  # Create index builder - import only when actually needed
266
- from ..search.index_builder import IndexBuilder
270
+ from signalwire_agents.search.index_builder import IndexBuilder
267
271
  builder = IndexBuilder(
268
272
  model_name=args.model,
269
273
  chunking_strategy=args.chunking_strategy,
@@ -328,7 +332,7 @@ def validate_command():
328
332
  sys.exit(1)
329
333
 
330
334
  try:
331
- from ..search.index_builder import IndexBuilder
335
+ from signalwire_agents.search.index_builder import IndexBuilder
332
336
  builder = IndexBuilder()
333
337
 
334
338
  validation = builder.validate_index(args.index_file)
@@ -376,8 +380,8 @@ def search_command():
376
380
  try:
377
381
  # Import search dependencies
378
382
  try:
379
- from ..search.search_engine import SearchEngine
380
- from ..search.query_processor import preprocess_query
383
+ from signalwire_agents.search.search_engine import SearchEngine
384
+ from signalwire_agents.search.query_processor import preprocess_query
381
385
  except ImportError as e:
382
386
  print(f"Error: Search functionality not available. Install with: pip install signalwire-agents[search]")
383
387
  print(f"Details: {e}")
@@ -478,6 +482,141 @@ def search_command():
478
482
  traceback.print_exc()
479
483
  sys.exit(1)
480
484
 
485
+ def remote_command():
486
+ """Search via remote API endpoint"""
487
+ parser = argparse.ArgumentParser(description='Search via remote API endpoint')
488
+ parser.add_argument('endpoint', help='Remote API endpoint URL (e.g., http://localhost:8001)')
489
+ parser.add_argument('query', help='Search query')
490
+ parser.add_argument('--index-name', required=True, help='Name of the index to search')
491
+ parser.add_argument('--count', type=int, default=5, help='Number of results to return (default: 5)')
492
+ parser.add_argument('--distance-threshold', type=float, default=0.0, help='Minimum similarity score (default: 0.0)')
493
+ parser.add_argument('--tags', help='Comma-separated tags to filter by')
494
+ parser.add_argument('--verbose', action='store_true', help='Show detailed information')
495
+ parser.add_argument('--json', action='store_true', help='Output results as JSON')
496
+ parser.add_argument('--no-content', action='store_true', help='Hide content in results (show only metadata)')
497
+ parser.add_argument('--timeout', type=int, default=30, help='Request timeout in seconds (default: 30)')
498
+
499
+ args = parser.parse_args()
500
+
501
+ # Ensure endpoint starts with http:// or https://
502
+ endpoint = args.endpoint
503
+ if not endpoint.startswith(('http://', 'https://')):
504
+ endpoint = f"http://{endpoint}"
505
+
506
+ # Ensure endpoint ends with /search
507
+ if not endpoint.endswith('/search'):
508
+ if endpoint.endswith('/'):
509
+ endpoint += 'search'
510
+ else:
511
+ endpoint += '/search'
512
+
513
+ try:
514
+ import requests
515
+ except ImportError:
516
+ print("Error: requests library not available. Install with: pip install requests")
517
+ sys.exit(1)
518
+
519
+ # Prepare request payload
520
+ payload = {
521
+ 'query': args.query,
522
+ 'index_name': args.index_name,
523
+ 'count': args.count,
524
+ 'distance_threshold': args.distance_threshold
525
+ }
526
+
527
+ if args.tags:
528
+ payload['tags'] = [tag.strip() for tag in args.tags.split(',')]
529
+
530
+ if args.verbose:
531
+ print(f"Searching remote endpoint: {endpoint}")
532
+ print(f"Payload: {payload}")
533
+ print()
534
+
535
+ try:
536
+ # Make the API request
537
+ response = requests.post(
538
+ endpoint,
539
+ json=payload,
540
+ headers={'Content-Type': 'application/json'},
541
+ timeout=args.timeout
542
+ )
543
+
544
+ if response.status_code == 200:
545
+ result = response.json()
546
+
547
+ if args.json:
548
+ # Output raw JSON response
549
+ import json
550
+ print(json.dumps(result, indent=2))
551
+ else:
552
+ # Human-readable output
553
+ results = result.get('results', [])
554
+ if not results:
555
+ print(f"No results found for '{args.query}' in index '{args.index_name}'")
556
+ sys.exit(0)
557
+
558
+ print(f"Found {len(results)} result(s) for '{args.query}' in index '{args.index_name}':")
559
+ if result.get('enhanced_query') and result.get('enhanced_query') != args.query:
560
+ print(f"Enhanced query: '{result.get('enhanced_query')}'")
561
+ print("=" * 80)
562
+
563
+ for i, search_result in enumerate(results):
564
+ print(f"\n[{i+1}] Score: {search_result.get('score', 0):.4f}")
565
+
566
+ # Show metadata
567
+ metadata = search_result.get('metadata', {})
568
+ print(f"File: {metadata.get('filename', 'Unknown')}")
569
+ if metadata.get('section'):
570
+ print(f"Section: {metadata['section']}")
571
+ if metadata.get('line_start'):
572
+ print(f"Lines: {metadata['line_start']}-{metadata.get('line_end', metadata['line_start'])}")
573
+ if metadata.get('tags'):
574
+ print(f"Tags: {', '.join(metadata['tags'])}")
575
+
576
+ # Show content unless suppressed
577
+ if not args.no_content and 'content' in search_result:
578
+ content = search_result['content']
579
+ if len(content) > 500 and not args.verbose:
580
+ content = content[:500] + "..."
581
+ print(f"\nContent:\n{content}")
582
+
583
+ if i < len(results) - 1:
584
+ print("-" * 80)
585
+
586
+ elif response.status_code == 404:
587
+ try:
588
+ error_detail = response.json()
589
+ error_msg = error_detail.get('detail', 'Index not found')
590
+ except:
591
+ error_msg = 'Index not found'
592
+ print(f"Error: {error_msg}")
593
+ sys.exit(1)
594
+ else:
595
+ try:
596
+ error_detail = response.json()
597
+ error_msg = error_detail.get('detail', f'HTTP {response.status_code}')
598
+ except:
599
+ error_msg = f'HTTP {response.status_code}: {response.text}'
600
+ print(f"Error: {error_msg}")
601
+ sys.exit(1)
602
+
603
+ except requests.ConnectionError:
604
+ print(f"Error: Could not connect to {endpoint}")
605
+ print("Make sure the search server is running")
606
+ sys.exit(1)
607
+ except requests.Timeout:
608
+ print(f"Error: Request timed out after {args.timeout} seconds")
609
+ sys.exit(1)
610
+ except requests.RequestException as e:
611
+ print(f"Error making request: {e}")
612
+ sys.exit(1)
613
+ except Exception as e:
614
+ print(f"Error: {e}")
615
+ if args.verbose:
616
+ import traceback
617
+ traceback.print_exc()
618
+ sys.exit(1)
619
+
481
620
  def console_entry_point():
482
621
  """Console script entry point for pip installation"""
483
622
  import sys
@@ -594,6 +733,10 @@ Examples:
594
733
  sw-search search ./docs.swsearch "how to create an agent"
595
734
  sw-search search ./docs.swsearch "API reference" --count 3 --verbose
596
735
  sw-search search ./docs.swsearch "configuration" --tags documentation --json
736
+
737
+ # Search via remote API
738
+ sw-search remote http://localhost:8001 "how to create an agent" --index-name docs
739
+ sw-search remote localhost:8001 "API reference" --index-name docs --count 3 --verbose
597
740
  """)
598
741
  return
599
742
 
@@ -609,6 +752,11 @@ Examples:
609
752
  sys.argv.pop(1)
610
753
  search_command()
611
754
  return
755
+ elif sys.argv[1] == 'remote':
756
+ # Remove 'remote' from argv and call remote_command
757
+ sys.argv.pop(1)
758
+ remote_command()
759
+ return
612
760
 
613
761
  # Regular build command
614
762
  main()