signalwire-agents 1.0.3__tar.gz → 1.0.5__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 (144) hide show
  1. {signalwire_agents-1.0.3/signalwire_agents.egg-info → signalwire_agents-1.0.5}/PKG-INFO +2 -2
  2. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/pyproject.toml +3 -3
  3. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/__init__.py +1 -1
  4. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/agent_base.py +221 -14
  5. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5/signalwire_agents.egg-info}/PKG-INFO +2 -2
  6. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents.egg-info/requires.txt +1 -1
  7. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/LICENSE +0 -0
  8. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/README.md +0 -0
  9. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/setup.cfg +0 -0
  10. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/setup.py +0 -0
  11. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/agent_server.py +0 -0
  12. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/agents/bedrock.py +0 -0
  13. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/__init__.py +0 -0
  14. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/build_search.py +0 -0
  15. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/config.py +0 -0
  16. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/core/__init__.py +0 -0
  17. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/core/agent_loader.py +0 -0
  18. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/core/argparse_helpers.py +0 -0
  19. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/core/dynamic_config.py +0 -0
  20. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/core/service_loader.py +0 -0
  21. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/execution/__init__.py +0 -0
  22. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/execution/datamap_exec.py +0 -0
  23. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/execution/webhook_exec.py +0 -0
  24. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/output/__init__.py +0 -0
  25. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/output/output_formatter.py +0 -0
  26. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/output/swml_dump.py +0 -0
  27. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/simulation/__init__.py +0 -0
  28. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/simulation/data_generation.py +0 -0
  29. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/simulation/data_overrides.py +0 -0
  30. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/simulation/mock_env.py +0 -0
  31. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/swaig_test_wrapper.py +0 -0
  32. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/test_swaig.py +0 -0
  33. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/cli/types.py +0 -0
  34. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/__init__.py +0 -0
  35. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/agent/__init__.py +0 -0
  36. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/agent/config/__init__.py +0 -0
  37. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/agent/deployment/__init__.py +0 -0
  38. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/agent/deployment/handlers/__init__.py +0 -0
  39. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/agent/prompt/__init__.py +0 -0
  40. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/agent/prompt/manager.py +0 -0
  41. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/agent/routing/__init__.py +0 -0
  42. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/agent/security/__init__.py +0 -0
  43. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/agent/swml/__init__.py +0 -0
  44. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/agent/tools/__init__.py +0 -0
  45. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/agent/tools/decorator.py +0 -0
  46. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/agent/tools/registry.py +0 -0
  47. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/auth_handler.py +0 -0
  48. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/config_loader.py +0 -0
  49. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/contexts.py +0 -0
  50. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/data_map.py +0 -0
  51. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/function_result.py +0 -0
  52. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/logging_config.py +0 -0
  53. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/mixins/__init__.py +0 -0
  54. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/mixins/ai_config_mixin.py +0 -0
  55. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/mixins/auth_mixin.py +0 -0
  56. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/mixins/prompt_mixin.py +0 -0
  57. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/mixins/serverless_mixin.py +0 -0
  58. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/mixins/skill_mixin.py +0 -0
  59. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/mixins/state_mixin.py +0 -0
  60. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/mixins/tool_mixin.py +0 -0
  61. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/mixins/web_mixin.py +0 -0
  62. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/pom_builder.py +0 -0
  63. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/security/__init__.py +0 -0
  64. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/security/session_manager.py +0 -0
  65. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/security_config.py +0 -0
  66. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/skill_base.py +0 -0
  67. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/skill_manager.py +0 -0
  68. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/swaig_function.py +0 -0
  69. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/swml_builder.py +0 -0
  70. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/swml_handler.py +0 -0
  71. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/swml_renderer.py +0 -0
  72. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/core/swml_service.py +0 -0
  73. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/prefabs/__init__.py +0 -0
  74. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/prefabs/concierge.py +0 -0
  75. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/prefabs/faq_bot.py +0 -0
  76. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/prefabs/info_gatherer.py +0 -0
  77. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/prefabs/receptionist.py +0 -0
  78. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/prefabs/survey.py +0 -0
  79. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/schema.json +0 -0
  80. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/search/__init__.py +0 -0
  81. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/search/document_processor.py +0 -0
  82. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/search/index_builder.py +0 -0
  83. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/search/migration.py +0 -0
  84. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/search/models.py +0 -0
  85. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/search/pgvector_backend.py +0 -0
  86. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/search/query_processor.py +0 -0
  87. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/search/search_engine.py +0 -0
  88. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/search/search_service.py +0 -0
  89. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/README.md +0 -0
  90. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/__init__.py +0 -0
  91. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/api_ninjas_trivia/README.md +0 -0
  92. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/api_ninjas_trivia/__init__.py +0 -0
  93. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/api_ninjas_trivia/skill.py +0 -0
  94. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/datasphere/README.md +0 -0
  95. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/datasphere/__init__.py +0 -0
  96. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/datasphere/skill.py +0 -0
  97. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/datasphere_serverless/README.md +0 -0
  98. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/datasphere_serverless/__init__.py +0 -0
  99. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/datasphere_serverless/skill.py +0 -0
  100. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/datetime/README.md +0 -0
  101. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/datetime/__init__.py +0 -0
  102. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/datetime/skill.py +0 -0
  103. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/joke/README.md +0 -0
  104. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/joke/__init__.py +0 -0
  105. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/joke/skill.py +0 -0
  106. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/math/README.md +0 -0
  107. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/math/__init__.py +0 -0
  108. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/math/skill.py +0 -0
  109. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/mcp_gateway/README.md +0 -0
  110. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/mcp_gateway/__init__.py +0 -0
  111. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/mcp_gateway/skill.py +0 -0
  112. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/native_vector_search/README.md +0 -0
  113. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/native_vector_search/__init__.py +0 -0
  114. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/native_vector_search/skill.py +0 -0
  115. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/play_background_file/README.md +0 -0
  116. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/play_background_file/__init__.py +0 -0
  117. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/play_background_file/skill.py +0 -0
  118. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/registry.py +0 -0
  119. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/spider/README.md +0 -0
  120. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/spider/__init__.py +0 -0
  121. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/spider/skill.py +0 -0
  122. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/swml_transfer/README.md +0 -0
  123. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/swml_transfer/__init__.py +0 -0
  124. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/swml_transfer/skill.py +0 -0
  125. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/weather_api/README.md +0 -0
  126. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/weather_api/__init__.py +0 -0
  127. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/weather_api/skill.py +0 -0
  128. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/web_search/README.md +0 -0
  129. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/web_search/__init__.py +0 -0
  130. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/web_search/skill.py +0 -0
  131. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/wikipedia_search/README.md +0 -0
  132. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/wikipedia_search/__init__.py +0 -0
  133. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/skills/wikipedia_search/skill.py +0 -0
  134. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/utils/__init__.py +0 -0
  135. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/utils/pom_utils.py +0 -0
  136. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/utils/schema_utils.py +0 -0
  137. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/utils/token_generators.py +0 -0
  138. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/utils/validators.py +0 -0
  139. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/web/__init__.py +0 -0
  140. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents/web/web_service.py +0 -0
  141. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents.egg-info/SOURCES.txt +0 -0
  142. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents.egg-info/dependency_links.txt +0 -0
  143. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/signalwire_agents.egg-info/entry_points.txt +0 -0
  144. {signalwire_agents-1.0.3 → signalwire_agents-1.0.5}/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: 1.0.3
3
+ Version: 1.0.5
4
4
  Summary: SignalWire AI Agents SDK
5
5
  Author-email: SignalWire Team <info@signalwire.com>
6
6
  License: MIT
@@ -22,7 +22,7 @@ Requires-Dist: fastapi>=0.115.12
22
22
  Requires-Dist: pydantic>=2.11.4
23
23
  Requires-Dist: PyYAML>=6.0.2
24
24
  Requires-Dist: Requests>=2.32.3
25
- Requires-Dist: setuptools>=66.1.1
25
+ Requires-Dist: setuptools<81,>=66.1.1
26
26
  Requires-Dist: signalwire_pom>=2.7.1
27
27
  Requires-Dist: structlog>=25.3.0
28
28
  Requires-Dist: uvicorn>=0.34.2
@@ -1,10 +1,10 @@
1
1
  [build-system]
2
- requires = ["setuptools>=61.0", "wheel"]
2
+ requires = ["setuptools>=61.0,<81", "wheel"]
3
3
  build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "signalwire_agents"
7
- version = "1.0.3"
7
+ version = "1.0.5"
8
8
  description = "SignalWire AI Agents SDK"
9
9
  authors = [
10
10
  {name = "SignalWire Team", email = "info@signalwire.com"}
@@ -29,7 +29,7 @@ dependencies = [
29
29
  "pydantic>=2.11.4",
30
30
  "PyYAML>=6.0.2",
31
31
  "Requests>=2.32.3",
32
- "setuptools>=66.1.1",
32
+ "setuptools>=66.1.1,<81",
33
33
  "signalwire_pom>=2.7.1",
34
34
  "structlog>=25.3.0",
35
35
  "uvicorn>=0.34.2",
@@ -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__ = "1.0.3"
21
+ __version__ = "1.0.5"
22
22
 
23
23
  # Import core classes for easier access
24
24
  from .core.agent_base import AgentBase
@@ -266,7 +266,21 @@ class AgentBase(
266
266
 
267
267
  # Initialize SWAIG query params for dynamic config
268
268
  self._swaig_query_params = {}
269
-
269
+
270
+ # Initialize verb insertion points for call flow customization
271
+ self._pre_answer_verbs = [] # Verbs to run before answer (e.g., ringback, screening)
272
+ self._answer_config = {} # Configuration for the answer verb
273
+ self._post_answer_verbs = [] # Verbs to run after answer, before AI (e.g., announcements)
274
+ self._post_ai_verbs = [] # Verbs to run after AI ends (e.g., cleanup, transfers)
275
+
276
+ # Verb categories for pre-answer validation
277
+ _PRE_ANSWER_SAFE_VERBS = {
278
+ "transfer", "execute", "return", "label", "goto", "request",
279
+ "switch", "cond", "if", "eval", "set", "unset", "hangup",
280
+ "send_sms", "sleep", "stop_record_call", "stop_denoise", "stop_tap"
281
+ }
282
+ _AUTO_ANSWER_VERBS = {"play", "connect"}
283
+
270
284
  @staticmethod
271
285
  def _load_service_config(config_file: Optional[str], service_name: str) -> dict:
272
286
  """Load service configuration from config file if available"""
@@ -380,14 +394,166 @@ class AgentBase(
380
394
  def on_summary(self, summary: Optional[Dict[str, Any]], raw_data: Optional[Dict[str, Any]] = None) -> None:
381
395
  """
382
396
  Called when a post-prompt summary is received
383
-
397
+
384
398
  Args:
385
399
  summary: The summary object or None if no summary was found
386
400
  raw_data: The complete raw POST data from the request
387
401
  """
388
402
  # Default implementation does nothing
389
403
  pass
390
-
404
+
405
+ # ==================== Call Flow Verb Insertion Methods ====================
406
+
407
+ def add_pre_answer_verb(self, verb_name: str, config: Dict[str, Any]) -> 'AgentBase':
408
+ """
409
+ Add a verb to run before the call is answered.
410
+
411
+ Pre-answer verbs execute while the call is still ringing. Only certain
412
+ verbs are safe to use before answering:
413
+
414
+ Safe verbs: transfer, execute, return, label, goto, request, switch,
415
+ cond, if, eval, set, unset, hangup, send_sms, sleep,
416
+ stop_record_call, stop_denoise, stop_tap
417
+
418
+ Verbs with auto_answer option (play, connect): Must include
419
+ "auto_answer": False in config to prevent automatic answering.
420
+
421
+ Args:
422
+ verb_name: The SWML verb name (e.g., "play", "sleep", "request")
423
+ config: Verb configuration dictionary
424
+
425
+ Returns:
426
+ Self for method chaining
427
+
428
+ Raises:
429
+ ValueError: If verb is not safe for pre-answer use
430
+
431
+ Example:
432
+ # Play ringback tone before answering
433
+ agent.add_pre_answer_verb("play", {
434
+ "urls": ["ring:us"],
435
+ "auto_answer": False
436
+ })
437
+ """
438
+ # Validate verb is safe for pre-answer use
439
+ if verb_name in self._AUTO_ANSWER_VERBS:
440
+ if not config.get("auto_answer") is False:
441
+ self.log.warning(
442
+ "pre_answer_verb_will_answer",
443
+ verb=verb_name,
444
+ hint=f"Add 'auto_answer': False to prevent {verb_name} from answering the call"
445
+ )
446
+ elif verb_name not in self._PRE_ANSWER_SAFE_VERBS:
447
+ raise ValueError(
448
+ f"Verb '{verb_name}' is not safe for pre-answer use. "
449
+ f"Safe verbs: {', '.join(sorted(self._PRE_ANSWER_SAFE_VERBS))}"
450
+ )
451
+
452
+ self._pre_answer_verbs.append((verb_name, config))
453
+ return self
454
+
455
+ def add_answer_verb(self, config: Optional[Dict[str, Any]] = None) -> 'AgentBase':
456
+ """
457
+ Configure the answer verb.
458
+
459
+ The answer verb connects the call. Use this method to customize
460
+ answer behavior, such as setting max_duration.
461
+
462
+ Args:
463
+ config: Optional answer verb configuration (e.g., {"max_duration": 3600})
464
+
465
+ Returns:
466
+ Self for method chaining
467
+
468
+ Example:
469
+ # Set maximum call duration to 1 hour
470
+ agent.add_answer_verb({"max_duration": 3600})
471
+ """
472
+ self._answer_config = config or {}
473
+ return self
474
+
475
+ def add_post_answer_verb(self, verb_name: str, config: Dict[str, Any]) -> 'AgentBase':
476
+ """
477
+ Add a verb to run after the call is answered but before the AI starts.
478
+
479
+ Post-answer verbs run after the call is connected. Common uses include
480
+ welcome messages, legal disclaimers, and hold music.
481
+
482
+ Args:
483
+ verb_name: The SWML verb name (e.g., "play", "sleep")
484
+ config: Verb configuration dictionary
485
+
486
+ Returns:
487
+ Self for method chaining
488
+
489
+ Example:
490
+ # Play welcome message
491
+ agent.add_post_answer_verb("play", {
492
+ "url": "say:Welcome to Acme Corporation."
493
+ })
494
+ # Brief pause
495
+ agent.add_post_answer_verb("sleep", {"time": 500})
496
+ """
497
+ self._post_answer_verbs.append((verb_name, config))
498
+ return self
499
+
500
+ def add_post_ai_verb(self, verb_name: str, config: Dict[str, Any]) -> 'AgentBase':
501
+ """
502
+ Add a verb to run after the AI conversation ends.
503
+
504
+ Post-AI verbs run when the AI completes its conversation. Common uses
505
+ include clean disconnects, transfers, and logging.
506
+
507
+ Args:
508
+ verb_name: The SWML verb name (e.g., "hangup", "transfer", "request")
509
+ config: Verb configuration dictionary
510
+
511
+ Returns:
512
+ Self for method chaining
513
+
514
+ Example:
515
+ # Log call completion and hang up
516
+ agent.add_post_ai_verb("request", {
517
+ "url": "https://api.example.com/call-complete",
518
+ "method": "POST"
519
+ })
520
+ agent.add_post_ai_verb("hangup", {})
521
+ """
522
+ self._post_ai_verbs.append((verb_name, config))
523
+ return self
524
+
525
+ def clear_pre_answer_verbs(self) -> 'AgentBase':
526
+ """
527
+ Remove all pre-answer verbs.
528
+
529
+ Returns:
530
+ Self for method chaining
531
+ """
532
+ self._pre_answer_verbs = []
533
+ return self
534
+
535
+ def clear_post_answer_verbs(self) -> 'AgentBase':
536
+ """
537
+ Remove all post-answer verbs.
538
+
539
+ Returns:
540
+ Self for method chaining
541
+ """
542
+ self._post_answer_verbs = []
543
+ return self
544
+
545
+ def clear_post_ai_verbs(self) -> 'AgentBase':
546
+ """
547
+ Remove all post-AI verbs.
548
+
549
+ Returns:
550
+ Self for method chaining
551
+ """
552
+ self._post_ai_verbs = []
553
+ return self
554
+
555
+ # ==================== End Call Flow Verb Insertion Methods ====================
556
+
391
557
  def enable_sip_routing(self, auto_map: bool = True, path: str = "/sip") -> 'AgentBase':
392
558
  """
393
559
  Enable SIP-based routing for this agent
@@ -746,15 +912,29 @@ class AgentBase(
746
912
  if hasattr(agent_to_use, '_post_prompt_url_override') and agent_to_use._post_prompt_url_override:
747
913
  post_prompt_url = agent_to_use._post_prompt_url_override
748
914
 
749
- # Add answer verb with auto-answer enabled
750
- agent_to_use.add_verb("answer", {})
751
-
752
- # Add recording if enabled
915
+ # ========== PHASE 1: PRE-ANSWER VERBS ==========
916
+ # These run while the call is still ringing
917
+ for verb_name, verb_config in agent_to_use._pre_answer_verbs:
918
+ agent_to_use.add_verb(verb_name, verb_config)
919
+
920
+ # ========== PHASE 2: ANSWER VERB ==========
921
+ # Only add answer verb if auto_answer is enabled
922
+ if agent_to_use._auto_answer:
923
+ agent_to_use.add_verb("answer", agent_to_use._answer_config)
924
+
925
+ # ========== PHASE 3: POST-ANSWER VERBS ==========
926
+ # These run after answer but before AI
927
+
928
+ # Add recording if enabled (this is a post-answer verb)
753
929
  if agent_to_use._record_call:
754
930
  agent_to_use.add_verb("record_call", {
755
931
  "format": agent_to_use._record_format,
756
932
  "stereo": agent_to_use._record_stereo
757
933
  })
934
+
935
+ # Add user-defined post-answer verbs
936
+ for verb_name, verb_config in agent_to_use._post_answer_verbs:
937
+ agent_to_use.add_verb(verb_name, verb_config)
758
938
 
759
939
  # Use the AI verb handler to build and validate the AI verb config
760
940
  ai_config = {}
@@ -881,10 +1061,16 @@ class AgentBase(
881
1061
 
882
1062
  if agent_to_use._global_data and "global_data" not in ai_config:
883
1063
  ai_config["global_data"] = agent_to_use._global_data
884
-
1064
+
1065
+ # ========== PHASE 4: AI VERB ==========
885
1066
  # Add the AI verb to the document
886
1067
  agent_to_use.add_verb("ai", ai_config)
887
-
1068
+
1069
+ # ========== PHASE 5: POST-AI VERBS ==========
1070
+ # These run after the AI conversation ends
1071
+ for verb_name, verb_config in agent_to_use._post_ai_verbs:
1072
+ agent_to_use.add_verb(verb_name, verb_config)
1073
+
888
1074
  # Apply any modifications from the callback to agent state
889
1075
  if modifications and isinstance(modifications, dict):
890
1076
  # Handle global_data modifications by updating the AI config directly
@@ -900,16 +1086,31 @@ class AgentBase(
900
1086
 
901
1087
  # Clear and rebuild the document with the modified AI config
902
1088
  agent_to_use.reset_document()
903
- agent_to_use.add_verb("answer", {})
904
-
905
- # Add recording if enabled
1089
+
1090
+ # Rebuild with 5-phase approach
1091
+ # PHASE 1: Pre-answer verbs
1092
+ for verb_name, verb_config in agent_to_use._pre_answer_verbs:
1093
+ agent_to_use.add_verb(verb_name, verb_config)
1094
+
1095
+ # PHASE 2: Answer verb (if auto_answer enabled)
1096
+ if agent_to_use._auto_answer:
1097
+ agent_to_use.add_verb("answer", agent_to_use._answer_config)
1098
+
1099
+ # PHASE 3: Post-answer verbs
906
1100
  if agent_to_use._record_call:
907
1101
  agent_to_use.add_verb("record_call", {
908
1102
  "format": agent_to_use._record_format,
909
1103
  "stereo": agent_to_use._record_stereo
910
1104
  })
911
-
1105
+ for verb_name, verb_config in agent_to_use._post_answer_verbs:
1106
+ agent_to_use.add_verb(verb_name, verb_config)
1107
+
1108
+ # PHASE 4: AI verb
912
1109
  agent_to_use.add_verb("ai", ai_config)
1110
+
1111
+ # PHASE 5: Post-AI verbs
1112
+ for verb_name, verb_config in agent_to_use._post_ai_verbs:
1113
+ agent_to_use.add_verb(verb_name, verb_config)
913
1114
 
914
1115
  # Return the rendered document as a string
915
1116
  return agent_to_use.render_document()
@@ -1015,7 +1216,13 @@ class AgentBase(
1015
1216
  ephemeral_agent._pronounce = copy.deepcopy(self._pronounce)
1016
1217
  ephemeral_agent._global_data = copy.deepcopy(self._global_data)
1017
1218
  ephemeral_agent._function_includes = copy.deepcopy(self._function_includes)
1018
-
1219
+
1220
+ # Deep copy verb insertion points for call flow customization
1221
+ ephemeral_agent._pre_answer_verbs = copy.deepcopy(self._pre_answer_verbs)
1222
+ ephemeral_agent._answer_config = copy.deepcopy(self._answer_config)
1223
+ ephemeral_agent._post_answer_verbs = copy.deepcopy(self._post_answer_verbs)
1224
+ ephemeral_agent._post_ai_verbs = copy.deepcopy(self._post_ai_verbs)
1225
+
1019
1226
  # Deep copy LLM parameters
1020
1227
  ephemeral_agent._prompt_llm_params = copy.deepcopy(self._prompt_llm_params)
1021
1228
  ephemeral_agent._post_prompt_llm_params = copy.deepcopy(self._post_prompt_llm_params)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: signalwire_agents
3
- Version: 1.0.3
3
+ Version: 1.0.5
4
4
  Summary: SignalWire AI Agents SDK
5
5
  Author-email: SignalWire Team <info@signalwire.com>
6
6
  License: MIT
@@ -22,7 +22,7 @@ Requires-Dist: fastapi>=0.115.12
22
22
  Requires-Dist: pydantic>=2.11.4
23
23
  Requires-Dist: PyYAML>=6.0.2
24
24
  Requires-Dist: Requests>=2.32.3
25
- Requires-Dist: setuptools>=66.1.1
25
+ Requires-Dist: setuptools<81,>=66.1.1
26
26
  Requires-Dist: signalwire_pom>=2.7.1
27
27
  Requires-Dist: structlog>=25.3.0
28
28
  Requires-Dist: uvicorn>=0.34.2
@@ -2,7 +2,7 @@ fastapi>=0.115.12
2
2
  pydantic>=2.11.4
3
3
  PyYAML>=6.0.2
4
4
  Requests>=2.32.3
5
- setuptools>=66.1.1
5
+ setuptools<81,>=66.1.1
6
6
  signalwire_pom>=2.7.1
7
7
  structlog>=25.3.0
8
8
  uvicorn>=0.34.2