signalwire-sdk 3.2.0.dev96__tar.gz → 3.2.0.dev99__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 (252) hide show
  1. {signalwire_sdk-3.2.0.dev96/signalwire/signalwire_sdk.egg-info → signalwire_sdk-3.2.0.dev99}/PKG-INFO +10 -2
  2. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/README.md +8 -1
  3. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/pyproject.toml +15 -1
  4. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/__init__.py +6 -1
  5. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/agent_server.py +1 -1
  6. signalwire_sdk-3.2.0.dev99/signalwire/signalwire/agents/__init__.py +16 -0
  7. signalwire_sdk-3.2.0.dev99/signalwire/signalwire/ai_chat/__init__.py +37 -0
  8. signalwire_sdk-3.2.0.dev99/signalwire/signalwire/ai_chat/client.py +344 -0
  9. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/contexts.py +32 -0
  10. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/swml_renderer.py +6 -2
  11. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/swml_service.py +24 -0
  12. signalwire_sdk-3.2.0.dev99/signalwire/signalwire/schema.json +12616 -0
  13. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/utils/schema_utils.py +58 -0
  14. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99/signalwire/signalwire_sdk.egg-info}/PKG-INFO +10 -2
  15. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire_sdk.egg-info/SOURCES.txt +3 -0
  16. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire_sdk.egg-info/requires.txt +1 -0
  17. signalwire_sdk-3.2.0.dev96/signalwire/signalwire/schema.json +0 -12533
  18. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/LICENSE +0 -0
  19. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/man/sw-agent-init.1 +0 -0
  20. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/man/sw-search.1 +0 -0
  21. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/man/swaig-test.1 +0 -0
  22. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/setup.cfg +0 -0
  23. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/setup.py +0 -0
  24. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/agents/bedrock.py +0 -0
  25. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/__init__.py +0 -0
  26. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/build_search.py +0 -0
  27. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/config.py +0 -0
  28. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/core/__init__.py +0 -0
  29. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/core/agent_loader.py +0 -0
  30. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/core/argparse_helpers.py +0 -0
  31. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/core/dynamic_config.py +0 -0
  32. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/core/service_loader.py +0 -0
  33. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/dokku.py +0 -0
  34. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/execution/__init__.py +0 -0
  35. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/execution/datamap_exec.py +0 -0
  36. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/execution/webhook_exec.py +0 -0
  37. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/init_project.py +0 -0
  38. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/output/__init__.py +0 -0
  39. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/output/output_formatter.py +0 -0
  40. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/output/swml_dump.py +0 -0
  41. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/simulation/__init__.py +0 -0
  42. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/simulation/data_generation.py +0 -0
  43. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/simulation/data_overrides.py +0 -0
  44. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/simulation/mock_env.py +0 -0
  45. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/swaig_test_wrapper.py +0 -0
  46. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/test_swaig.py +0 -0
  47. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/cli/types.py +0 -0
  48. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/__init__.py +0 -0
  49. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/_agent_host.py +0 -0
  50. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/agent/__init__.py +0 -0
  51. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/agent/config/__init__.py +0 -0
  52. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/agent/deployment/__init__.py +0 -0
  53. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/agent/deployment/handlers/__init__.py +0 -0
  54. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/agent/prompt/__init__.py +0 -0
  55. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/agent/prompt/manager.py +0 -0
  56. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/agent/routing/__init__.py +0 -0
  57. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/agent/security/__init__.py +0 -0
  58. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/agent/swml/__init__.py +0 -0
  59. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/agent/tools/__init__.py +0 -0
  60. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/agent/tools/decorator.py +0 -0
  61. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/agent/tools/registry.py +0 -0
  62. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/agent/tools/type_inference.py +0 -0
  63. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/agent_base.py +0 -0
  64. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/auth_handler.py +0 -0
  65. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/config_loader.py +0 -0
  66. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/data_map.py +0 -0
  67. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/function_result.py +0 -0
  68. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/logging_config.py +0 -0
  69. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/mixins/__init__.py +0 -0
  70. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/mixins/_mixin_host.py +0 -0
  71. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/mixins/ai_config_mixin.py +0 -0
  72. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/mixins/auth_mixin.py +0 -0
  73. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/mixins/mcp_server_mixin.py +0 -0
  74. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/mixins/prompt_mixin.py +0 -0
  75. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/mixins/serverless_mixin.py +0 -0
  76. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/mixins/skill_mixin.py +0 -0
  77. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/mixins/state_mixin.py +0 -0
  78. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/mixins/tool_mixin.py +0 -0
  79. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/mixins/web_mixin.py +0 -0
  80. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/pom_builder.py +0 -0
  81. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/post_prompt_generated.py +0 -0
  82. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/security/__init__.py +0 -0
  83. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/security/security_utils.py +0 -0
  84. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/security/session_manager.py +0 -0
  85. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/security/webhook_middleware.py +0 -0
  86. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/security/webhook_validator.py +0 -0
  87. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/security_config.py +0 -0
  88. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/skill_base.py +0 -0
  89. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/skill_manager.py +0 -0
  90. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/swaig_actions_generated.py +0 -0
  91. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/swaig_function.py +0 -0
  92. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/swaig_request_generated.py +0 -0
  93. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/swml_builder.py +0 -0
  94. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/swml_handler.py +0 -0
  95. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/swml_verbs_generated.py +0 -0
  96. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/core/web.py +0 -0
  97. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/livewire/__init__.py +0 -0
  98. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/livewire/plugins.py +0 -0
  99. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/mcp_gateway/__init__.py +0 -0
  100. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/mcp_gateway/gateway_service.py +0 -0
  101. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/mcp_gateway/mcp_manager.py +0 -0
  102. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/mcp_gateway/session_manager.py +0 -0
  103. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/pom/__init__.py +0 -0
  104. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/pom/pom.py +0 -0
  105. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/pom/pom_tool.py +0 -0
  106. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/prefabs/__init__.py +0 -0
  107. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/prefabs/concierge.py +0 -0
  108. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/prefabs/faq_bot.py +0 -0
  109. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/prefabs/info_gatherer.py +0 -0
  110. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/prefabs/receptionist.py +0 -0
  111. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/prefabs/survey.py +0 -0
  112. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/py.typed +0 -0
  113. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/relay/__init__.py +0 -0
  114. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/relay/call.py +0 -0
  115. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/relay/client.py +0 -0
  116. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/relay/constants.py +0 -0
  117. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/relay/event.py +0 -0
  118. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/relay/message.py +0 -0
  119. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/relay/protocol_types_generated.py +0 -0
  120. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/__init__.py +0 -0
  121. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/_base.py +0 -0
  122. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/_pagination.py +0 -0
  123. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/_request_options.py +0 -0
  124. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/call_handler.py +0 -0
  125. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/client.py +0 -0
  126. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/__init__.py +0 -0
  127. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/_client_tree_generated.py +0 -0
  128. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/addresses.py +0 -0
  129. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/calling.py +0 -0
  130. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/calling_resources_generated.py +0 -0
  131. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/calling_types_generated.py +0 -0
  132. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/chat.py +0 -0
  133. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/chat_resources_generated.py +0 -0
  134. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/chat_types_generated.py +0 -0
  135. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/datasphere.py +0 -0
  136. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/datasphere_resources_generated.py +0 -0
  137. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/datasphere_types_generated.py +0 -0
  138. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/fabric.py +0 -0
  139. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/fabric_resources_generated.py +0 -0
  140. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/fabric_types_generated.py +0 -0
  141. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/fax_resources_generated.py +0 -0
  142. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/fax_types_generated.py +0 -0
  143. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/imported_numbers.py +0 -0
  144. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/logs.py +0 -0
  145. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/logs_resources_generated.py +0 -0
  146. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/logs_types_generated.py +0 -0
  147. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/lookup.py +0 -0
  148. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/message_resources_generated.py +0 -0
  149. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/message_types_generated.py +0 -0
  150. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/messages_resources_generated.py +0 -0
  151. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/messages_types_generated.py +0 -0
  152. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/mfa.py +0 -0
  153. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/number_groups.py +0 -0
  154. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/phone_numbers.py +0 -0
  155. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/project.py +0 -0
  156. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/project_resources_generated.py +0 -0
  157. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/project_types_generated.py +0 -0
  158. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/projects_resources_generated.py +0 -0
  159. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/projects_types_generated.py +0 -0
  160. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/pubsub.py +0 -0
  161. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/pubsub_resources_generated.py +0 -0
  162. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/pubsub_types_generated.py +0 -0
  163. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/queues.py +0 -0
  164. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/recordings.py +0 -0
  165. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/registry.py +0 -0
  166. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/relay_rest_resources_generated.py +0 -0
  167. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/relay_rest_types_generated.py +0 -0
  168. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/short_codes.py +0 -0
  169. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/sip_profile.py +0 -0
  170. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/swml_webhooks_types_generated.py +0 -0
  171. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/verified_callers.py +0 -0
  172. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/video.py +0 -0
  173. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/video_resources_generated.py +0 -0
  174. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/video_types_generated.py +0 -0
  175. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/voice_resources_generated.py +0 -0
  176. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/rest/namespaces/voice_types_generated.py +0 -0
  177. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/search/__init__.py +0 -0
  178. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/search/document_processor.py +0 -0
  179. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/search/index_builder.py +0 -0
  180. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/search/migration.py +0 -0
  181. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/search/models.py +0 -0
  182. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/search/pgvector_backend.py +0 -0
  183. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/search/query_processor.py +0 -0
  184. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/search/search_engine.py +0 -0
  185. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/search/search_service.py +0 -0
  186. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/README.md +0 -0
  187. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/__init__.py +0 -0
  188. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/api_ninjas_trivia/README.md +0 -0
  189. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/api_ninjas_trivia/__init__.py +0 -0
  190. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/api_ninjas_trivia/skill.py +0 -0
  191. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/claude_skills/README.md +0 -0
  192. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/claude_skills/__init__.py +0 -0
  193. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/claude_skills/skill.py +0 -0
  194. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/datasphere/README.md +0 -0
  195. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/datasphere/__init__.py +0 -0
  196. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/datasphere/skill.py +0 -0
  197. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/datasphere_serverless/README.md +0 -0
  198. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/datasphere_serverless/__init__.py +0 -0
  199. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/datasphere_serverless/skill.py +0 -0
  200. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/datetime/README.md +0 -0
  201. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/datetime/__init__.py +0 -0
  202. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/datetime/skill.py +0 -0
  203. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/google_maps/__init__.py +0 -0
  204. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/google_maps/skill.py +0 -0
  205. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/info_gatherer/README.md +0 -0
  206. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/info_gatherer/__init__.py +0 -0
  207. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/info_gatherer/skill.py +0 -0
  208. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/joke/README.md +0 -0
  209. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/joke/__init__.py +0 -0
  210. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/joke/skill.py +0 -0
  211. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/math/README.md +0 -0
  212. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/math/__init__.py +0 -0
  213. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/math/skill.py +0 -0
  214. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/mcp_gateway/README.md +0 -0
  215. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/mcp_gateway/__init__.py +0 -0
  216. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/mcp_gateway/skill.py +0 -0
  217. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/native_vector_search/README.md +0 -0
  218. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/native_vector_search/__init__.py +0 -0
  219. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/native_vector_search/skill.py +0 -0
  220. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/play_background_file/README.md +0 -0
  221. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/play_background_file/__init__.py +0 -0
  222. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/play_background_file/skill.py +0 -0
  223. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/registry.py +0 -0
  224. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/spider/README.md +0 -0
  225. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/spider/__init__.py +0 -0
  226. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/spider/skill.py +0 -0
  227. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/swml_transfer/README.md +0 -0
  228. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/swml_transfer/__init__.py +0 -0
  229. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/swml_transfer/skill.py +0 -0
  230. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/weather_api/README.md +0 -0
  231. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/weather_api/__init__.py +0 -0
  232. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/weather_api/skill.py +0 -0
  233. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/web_search/README.md +0 -0
  234. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/web_search/__init__.py +0 -0
  235. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/web_search/skill.py +0 -0
  236. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/web_search/skill_improved.py +0 -0
  237. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/web_search/skill_original.py +0 -0
  238. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/wikipedia_search/README.md +0 -0
  239. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/wikipedia_search/__init__.py +0 -0
  240. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/skills/wikipedia_search/skill.py +0 -0
  241. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/utils/__init__.py +0 -0
  242. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/utils/pom_utils.py +0 -0
  243. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/utils/token_generators.py +0 -0
  244. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/utils/url_validator.py +0 -0
  245. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/utils/validators.py +0 -0
  246. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/web/__init__.py +0 -0
  247. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire/web/web_service.py +0 -0
  248. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire_sdk.egg-info/dependency_links.txt +0 -0
  249. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire_sdk.egg-info/entry_points.txt +0 -0
  250. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/signalwire/signalwire_sdk.egg-info/top_level.txt +0 -0
  251. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/tests/test_examples.py +0 -0
  252. {signalwire_sdk-3.2.0.dev96 → signalwire_sdk-3.2.0.dev99}/tests/test_mcp_integration.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: signalwire-sdk
3
- Version: 3.2.0.dev96
3
+ Version: 3.2.0.dev99
4
4
  Summary: SignalWire SDK
5
5
  Author-email: SignalWire Team <info@signalwire.com>
6
6
  License: MIT
@@ -17,6 +17,7 @@ Classifier: Programming Language :: Python :: 3.13
17
17
  Requires-Python: >=3.10
18
18
  Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
+ Requires-Dist: aiohttp>=3.9.0
20
21
  Requires-Dist: fastapi>=0.115.12
21
22
  Requires-Dist: pydantic>=2.11.4
22
23
  Requires-Dist: PyYAML>=6.0.2
@@ -142,6 +143,7 @@ Each agent is a self-contained microservice that generates [SWML](docs/swml_serv
142
143
  from signalwire import AgentBase
143
144
  from signalwire.core.function_result import FunctionResult
144
145
 
146
+
145
147
  class MyAgent(AgentBase):
146
148
  def __init__(self):
147
149
  super().__init__(name="my-agent", route="/agent")
@@ -153,8 +155,10 @@ class MyAgent(AgentBase):
153
155
  def get_time(self):
154
156
  """Get the current time"""
155
157
  from datetime import datetime
158
+
156
159
  return FunctionResult(f"The time is {datetime.now().strftime('%H:%M:%S')}")
157
160
 
161
+
158
162
  if __name__ == "__main__":
159
163
  agent = MyAgent()
160
164
  agent.run()
@@ -213,7 +217,10 @@ Real-time call control and messaging over WebSocket. The RELAY client connects t
213
217
  ```python
214
218
  from signalwire.relay import RelayClient
215
219
 
216
- client = RelayClient(project="...", token="...", host="example.signalwire.com", contexts=["default"])
220
+ client = RelayClient(
221
+ project="...", token="...", host="example.signalwire.com", contexts=["default"]
222
+ )
223
+
217
224
 
218
225
  @client.on_call
219
226
  async def handle(call):
@@ -222,6 +229,7 @@ async def handle(call):
222
229
  await action.wait()
223
230
  await call.hangup()
224
231
 
232
+
225
233
  client.run()
226
234
  ```
227
235
 
@@ -45,6 +45,7 @@ Each agent is a self-contained microservice that generates [SWML](docs/swml_serv
45
45
  from signalwire import AgentBase
46
46
  from signalwire.core.function_result import FunctionResult
47
47
 
48
+
48
49
  class MyAgent(AgentBase):
49
50
  def __init__(self):
50
51
  super().__init__(name="my-agent", route="/agent")
@@ -56,8 +57,10 @@ class MyAgent(AgentBase):
56
57
  def get_time(self):
57
58
  """Get the current time"""
58
59
  from datetime import datetime
60
+
59
61
  return FunctionResult(f"The time is {datetime.now().strftime('%H:%M:%S')}")
60
62
 
63
+
61
64
  if __name__ == "__main__":
62
65
  agent = MyAgent()
63
66
  agent.run()
@@ -116,7 +119,10 @@ Real-time call control and messaging over WebSocket. The RELAY client connects t
116
119
  ```python
117
120
  from signalwire.relay import RelayClient
118
121
 
119
- client = RelayClient(project="...", token="...", host="example.signalwire.com", contexts=["default"])
122
+ client = RelayClient(
123
+ project="...", token="...", host="example.signalwire.com", contexts=["default"]
124
+ )
125
+
120
126
 
121
127
  @client.on_call
122
128
  async def handle(call):
@@ -125,6 +131,7 @@ async def handle(call):
125
131
  await action.wait()
126
132
  await call.hangup()
127
133
 
134
+
128
135
  client.run()
129
136
  ```
130
137
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "signalwire-sdk"
7
- version = "3.2.0.dev96"
7
+ version = "3.2.0.dev99"
8
8
  description = "SignalWire SDK"
9
9
  authors = [
10
10
  {name = "SignalWire Team", email = "info@signalwire.com"}
@@ -24,6 +24,7 @@ classifiers = [
24
24
  "Programming Language :: Python :: 3.13",
25
25
  ]
26
26
  dependencies = [
27
+ "aiohttp>=3.9.0",
27
28
  "fastapi>=0.115.12",
28
29
  "pydantic>=2.11.4",
29
30
  "PyYAML>=6.0.2",
@@ -201,6 +202,19 @@ select = ["E4", "E7", "E9", "F", "B", "S", "C4", "PERF", "SIM", "PTH", "RET", "R
201
202
  # subscript is a runtime NameError under TYPE_CHECKING). Exempt F401 here; mypy +
202
203
  # the SIGNATURES/DRIFT gate prove these imports are real and correct.
203
204
  "signalwire/signalwire/rest/namespaces/*.py" = ["F401"]
205
+ # Runnable docs — examples/, rest/examples/, relay/examples/. These are teaching
206
+ # programs, not shipped SDK surface, so a few production-lint rules are demo-idiomatic
207
+ # noise here (and are the ONLY findings that survive after autofix):
208
+ # E402 — a leading module docstring / "set your creds here" preamble before imports
209
+ # is the natural example shape (imports-not-at-top).
210
+ # S104 — binding 0.0.0.0 is how a demo server example says "listen on all interfaces".
211
+ # S106 — literal "password"/"token" kwargs are obvious placeholder creds in a snippet.
212
+ # S311 — non-crypto random (sample data / demo ids), never used for security here.
213
+ # Everything else (F401 unused imports, F541 empty f-strings, C4/B/RET/SIM/…) is a real
214
+ # smell and stays enforced so `examples/**` is gate-cleanable to zero.
215
+ "examples/**" = ["E402", "S104", "S106", "S311"]
216
+ "rest/examples/**" = ["E402", "S104", "S106", "S311"]
217
+ "relay/examples/**" = ["E402", "S104", "S106", "S311"]
204
218
 
205
219
  [tool.ruff.lint.flake8-bugbear]
206
220
  # FastAPI's dependency-injection idiom puts Depends()/Query()/etc. in argument
@@ -52,7 +52,7 @@ if TYPE_CHECKING:
52
52
  from signalwire.utils.schema_utils import SchemaValidationError
53
53
  from signalwire.web import WebService
54
54
 
55
- __version__ = "3.2.0.dev96"
55
+ __version__ = "3.2.0.dev99"
56
56
 
57
57
  # §6.2-python (owner decision: NO packaging split — one package, all deps required;
58
58
  # IMPORT-TIME behavior only): the agent/web symbols are lazy-imported via module
@@ -81,6 +81,10 @@ _LAZY_IMPORTS: dict[str, tuple[str, str]] = {
81
81
  "BedrockAgent": ("signalwire.agents.bedrock", "BedrockAgent"),
82
82
  "SchemaValidationError": ("signalwire.utils.schema_utils", "SchemaValidationError"),
83
83
  "WebService": ("signalwire.web", "WebService"),
84
+ # AI Chat client — lazy so its aiohttp dep loads only on first access (mirrors how
85
+ # every other public client here is exposed; RestClient's factory form is the odd
86
+ # one out). Makes `from signalwire import AIChatClient` work like every sibling.
87
+ "AIChatClient": ("signalwire.ai_chat", "AIChatClient"),
84
88
  }
85
89
 
86
90
 
@@ -195,6 +199,7 @@ def RestClient(*args: Any, **kwargs: Any) -> "_RestClient":
195
199
 
196
200
 
197
201
  __all__ = [
202
+ "AIChatClient",
198
203
  "AgentBase",
199
204
  "AgentServer",
200
205
  "BedrockAgent",
@@ -68,7 +68,7 @@ class AgentServer:
68
68
  self.app = FastAPI(
69
69
  title="SignalWire AI Agents",
70
70
  description="Hosted SignalWire AI Agents",
71
- version="3.2.0.dev96",
71
+ version="3.2.0.dev99",
72
72
  redirect_slashes=False,
73
73
  docs_url=None,
74
74
  redoc_url=None,
@@ -0,0 +1,16 @@
1
+ """
2
+ Copyright (c) 2025 SignalWire
3
+
4
+ This file is part of the SignalWire SDK.
5
+
6
+ Licensed under the MIT License.
7
+ See LICENSE file in the project root for full license information.
8
+
9
+ Specialized agent implementations backed by specific inference providers.
10
+ """
11
+
12
+ from signalwire.agents.bedrock import BedrockAgent
13
+
14
+ __all__ = [
15
+ "BedrockAgent",
16
+ ]
@@ -0,0 +1,37 @@
1
+ """
2
+ Copyright (c) 2026 SignalWire
3
+
4
+ This file is part of the SignalWire SDK.
5
+
6
+ Licensed under the MIT License.
7
+ See LICENSE file in the project root for full license information.
8
+
9
+ Async client for the SignalWire AI Chat service — see
10
+ :mod:`signalwire.ai_chat.client` for the full protocol notes.
11
+ """
12
+
13
+ from .client import (
14
+ AIChatClient,
15
+ AIChatError,
16
+ AuthenticationError,
17
+ ChatInProgressError,
18
+ ChatLog,
19
+ ChatResponse,
20
+ ConversationInfo,
21
+ ConversationNotFoundError,
22
+ RateLimitError,
23
+ SummaryError,
24
+ )
25
+
26
+ __all__ = [
27
+ "AIChatClient",
28
+ "AIChatError",
29
+ "AuthenticationError",
30
+ "ChatInProgressError",
31
+ "ChatLog",
32
+ "ChatResponse",
33
+ "ConversationInfo",
34
+ "ConversationNotFoundError",
35
+ "RateLimitError",
36
+ "SummaryError",
37
+ ]
@@ -0,0 +1,344 @@
1
+ """
2
+ Copyright (c) 2026 SignalWire
3
+
4
+ This file is part of the SignalWire SDK.
5
+
6
+ Licensed under the MIT License.
7
+ See LICENSE file in the project root for full license information.
8
+
9
+ Async client for the SignalWire AI Chat service.
10
+
11
+ The client speaks the standard SignalWire front-door protocol: HTTP Basic
12
+ ``project:api_token`` with the space in the hostname —
13
+ ``POST https://{space}.signalwire.com/api/ai/chat`` — carrying a JSON-RPC 2.0
14
+ body whose params are pure payload (identity never appears in the body).
15
+
16
+ Async-first by design: a ``chat()`` call waits on a full LLM round trip
17
+ (seconds, not milliseconds), and the typical consumers — bots, MCP servers —
18
+ run on asyncio event loops where a blocking HTTP call would stall every other
19
+ conversation. Use it as an async context manager::
20
+
21
+ from signalwire.ai_chat import AIChatClient
22
+
23
+ async with AIChatClient(space="myspace") as client: # env supplies creds
24
+ await client.create_conversation("conv-1", config_url=CONFIG_URL)
25
+ reply = await client.chat("conv-1", "hello")
26
+ print(reply.text)
27
+
28
+ URL resolution, in order:
29
+
30
+ 1. ``url=`` constructor argument — used verbatim.
31
+ 2. ``RAILS_DEV_MODE`` environment variable — a full URL used verbatim
32
+ (point it at a dev chat service, e.g. ``http://localhost:8080/``).
33
+ 3. ``https://{space}.signalwire.com/api/ai/chat`` built from ``space``
34
+ (argument or ``SIGNALWIRE_SPACE``).
35
+
36
+ Credentials come from the constructor or the standard environment variables
37
+ ``SIGNALWIRE_PROJECT_ID`` / ``SIGNALWIRE_API_TOKEN``.
38
+ """
39
+
40
+ import os
41
+ from dataclasses import dataclass, field
42
+ from typing import Any
43
+
44
+ import aiohttp
45
+
46
+ from signalwire.rest._base import _user_agent
47
+
48
+ DEFAULT_PATH = "/api/ai/chat"
49
+
50
+ # The service streams keepalive whitespace ahead of slow responses (every
51
+ # ~10s), so liveness is byte-driven, not wall-clock: no total cap (turn
52
+ # length is the server's business), ``sock_read`` as the dead-connection
53
+ # detector (60s of true byte silence means the request is dead — the proxy
54
+ # itself severs after 30s of upstream silence), and a bounded connect.
55
+ # The leading whitespace is valid JSON, so ``resp.json()`` is unaffected.
56
+ # Pass your own ``session=`` to override.
57
+ DEFAULT_TIMEOUT = aiohttp.ClientTimeout(total=None, connect=10, sock_read=60)
58
+
59
+
60
+ # ── Errors ───────────────────────────────────────────────────────────
61
+
62
+
63
+ class AIChatError(Exception):
64
+ """Base error for AI Chat service failures."""
65
+
66
+ def __init__(self, code: int | None, message: str) -> None:
67
+ self.code = code
68
+ self.message = message
69
+ super().__init__(f"[{code}] {message}")
70
+
71
+
72
+ class AuthenticationError(AIChatError):
73
+ """Missing/rejected identity (HTTP 401 / JSON-RPC -32009)."""
74
+
75
+
76
+ class ConversationNotFoundError(AIChatError):
77
+ """The conversation does not exist in this project (-32001)."""
78
+
79
+
80
+ class RateLimitError(AIChatError):
81
+ """Project or conversation rate limit hit (-32005 / -32006)."""
82
+
83
+
84
+ class ChatInProgressError(AIChatError):
85
+ """Another message is being processed for this conversation (-32007)."""
86
+
87
+
88
+ class SummaryError(AIChatError):
89
+ """Summary generation failed. ``summarize`` returns EXACTLY ONE of
90
+ ``{summary}`` (success) or ``{error}`` (generation failed), and the failure
91
+ rides the JSON-RPC *success* envelope — not an ``error`` object — so it never
92
+ reaches the ``_ERROR_BY_CODE`` mapping. Surfaced here so a failed summary
93
+ can't masquerade as an empty string. ``code`` is None (no JSON-RPC code)."""
94
+
95
+
96
+ _ERROR_BY_CODE = {
97
+ -32001: ConversationNotFoundError,
98
+ -32005: RateLimitError,
99
+ -32006: RateLimitError,
100
+ -32007: ChatInProgressError,
101
+ -32009: AuthenticationError,
102
+ }
103
+
104
+
105
+ # ── Response models ──────────────────────────────────────────────────
106
+
107
+
108
+ @dataclass
109
+ class ConversationInfo:
110
+ id: str
111
+ status: str
112
+ initial_message: str | None = None
113
+
114
+
115
+ @dataclass
116
+ class ChatResponse:
117
+ text: str
118
+ conversation_id: str
119
+ user_event: dict[str, Any] | None = None
120
+
121
+
122
+ @dataclass
123
+ class ChatLog:
124
+ messages: list[dict[str, Any]] = field(default_factory=list)
125
+ call_timeline: list[dict[str, Any]] = field(default_factory=list)
126
+
127
+
128
+ # ── Client ───────────────────────────────────────────────────────────
129
+
130
+
131
+ class AIChatClient:
132
+ """Async client for the SignalWire AI Chat service."""
133
+
134
+ def __init__(
135
+ self,
136
+ project: str | None = None,
137
+ token: str | None = None,
138
+ space: str | None = None,
139
+ url: str | None = None,
140
+ session: aiohttp.ClientSession | None = None,
141
+ ) -> None:
142
+ self._project = project or os.environ.get("SIGNALWIRE_PROJECT_ID", "")
143
+ self._token = token or os.environ.get("SIGNALWIRE_API_TOKEN", "")
144
+ space = space or os.environ.get("SIGNALWIRE_SPACE", "")
145
+
146
+ if not self._project:
147
+ raise ValueError(
148
+ "project is required. Provide it as an argument or set the "
149
+ "SIGNALWIRE_PROJECT_ID environment variable."
150
+ )
151
+
152
+ self.url = self._resolve_url(url, space)
153
+ self._auth = aiohttp.BasicAuth(self._project, self._token)
154
+ self._headers = {"User-Agent": _user_agent()}
155
+ self._session = session
156
+ self._owns_session = session is None
157
+ self._request_counter = 0
158
+
159
+ @staticmethod
160
+ def _resolve_url(url: str | None, space: str) -> str:
161
+ if url:
162
+ return url
163
+ dev_url = os.environ.get("RAILS_DEV_MODE", "").strip()
164
+ if dev_url and dev_url.lower() not in (
165
+ "false",
166
+ "0",
167
+ "no",
168
+ "off",
169
+ "true",
170
+ "1",
171
+ "yes",
172
+ "on",
173
+ ):
174
+ # RAILS_DEV_MODE doubles as the service's persona switch, so
175
+ # plain booleans mean "on" without carrying a URL — only a real
176
+ # URL-looking value overrides the target here.
177
+ return dev_url
178
+ if space:
179
+ return f"https://{space}.signalwire.com{DEFAULT_PATH}"
180
+ raise ValueError(
181
+ "No service URL: provide url=, set RAILS_DEV_MODE to a full URL, "
182
+ "or provide space= / SIGNALWIRE_SPACE."
183
+ )
184
+
185
+ # ── Session lifecycle ────────────────────────────────────────────
186
+
187
+ async def __aenter__(self) -> "AIChatClient":
188
+ await self._ensure_session()
189
+ return self
190
+
191
+ async def __aexit__(self, *exc: Any) -> None:
192
+ await self.close()
193
+
194
+ async def _ensure_session(self) -> aiohttp.ClientSession:
195
+ if self._session is None:
196
+ self._session = aiohttp.ClientSession(
197
+ auth=self._auth, headers=self._headers, timeout=DEFAULT_TIMEOUT
198
+ )
199
+ return self._session
200
+
201
+ async def close(self) -> None:
202
+ if self._owns_session and self._session is not None:
203
+ await self._session.close()
204
+ self._session = None
205
+
206
+ # ── Wire ─────────────────────────────────────────────────────────
207
+
208
+ async def _request(self, method: str, params: dict[str, Any]) -> dict[str, Any]:
209
+ session = await self._ensure_session()
210
+ self._request_counter += 1
211
+ payload = {
212
+ "jsonrpc": "2.0",
213
+ "method": method,
214
+ "params": params,
215
+ "id": f"req-{self._request_counter}",
216
+ }
217
+ async with session.post(self.url, json=payload) as resp:
218
+ try:
219
+ body = await resp.json()
220
+ except (aiohttp.ContentTypeError, ValueError) as err:
221
+ raise AIChatError(
222
+ resp.status, f"non-JSON response (HTTP {resp.status})"
223
+ ) from err
224
+ # Success/failure is decided by the JSON-RPC body, NOT the HTTP status:
225
+ # the service's keepalive heartbeat commits ``200`` before the turn's
226
+ # outcome is known (heartbeat.py), so a slow error arrives as
227
+ # ``200 + {"error": …}``. Never gate on ``resp.status`` here.
228
+ if "error" in body:
229
+ error = body["error"] or {}
230
+ code = error.get("code")
231
+ exc_type = (
232
+ _ERROR_BY_CODE.get(code, AIChatError)
233
+ if code is not None
234
+ else AIChatError
235
+ )
236
+ raise exc_type(code, error.get("message", ""))
237
+ result = body.get("result")
238
+ return result if isinstance(result, dict) else {}
239
+
240
+ # ── API methods ──────────────────────────────────────────────────
241
+
242
+ async def create_conversation(
243
+ self,
244
+ conversation_id: str,
245
+ config_url: str,
246
+ user_message: str | None = None,
247
+ timeout: int | None = None,
248
+ user_metadata: dict[str, Any] | None = None,
249
+ reinit: bool = False,
250
+ ) -> ConversationInfo:
251
+ """Create a conversation (or reinitialize an existing one)."""
252
+ params: dict[str, Any] = {"id": conversation_id, "config_url": config_url}
253
+ if user_message:
254
+ params["user_message"] = user_message
255
+ if timeout:
256
+ params["conversation_timeout"] = timeout
257
+ if user_metadata:
258
+ params["user_meta_data"] = user_metadata
259
+ if reinit:
260
+ params["reinit"] = True
261
+ result = await self._request("create_conversation", params)
262
+ return ConversationInfo(
263
+ id=conversation_id,
264
+ status=result.get("status", "created"),
265
+ initial_message=result.get("initial_message"),
266
+ )
267
+
268
+ async def chat(
269
+ self,
270
+ conversation_id: str,
271
+ message: str,
272
+ role: str = "user",
273
+ config_url: str | None = None,
274
+ user_metadata: dict[str, Any] | None = None,
275
+ timeout: int | None = None,
276
+ reinit: bool = False,
277
+ ) -> ChatResponse:
278
+ """Send a message and return the AI reply.
279
+
280
+ This awaits a full LLM round trip server-side — expect seconds.
281
+ Passing ``config_url`` auto-creates the conversation if it doesn't
282
+ exist yet; ``timeout`` and ``reinit`` apply to that auto-create,
283
+ with the same meaning as on :meth:`create_conversation`.
284
+ """
285
+ params: dict[str, Any] = {
286
+ "id": conversation_id,
287
+ "message": message,
288
+ "role": role,
289
+ }
290
+ if config_url:
291
+ params["config_url"] = config_url
292
+ if user_metadata:
293
+ params["user_meta_data"] = user_metadata
294
+ if timeout:
295
+ params["conversation_timeout"] = timeout
296
+ if reinit:
297
+ params["reinit"] = True
298
+ result = await self._request("chat", params)
299
+ return ChatResponse(
300
+ text=result.get("response", ""),
301
+ conversation_id=conversation_id,
302
+ user_event=result.get("user_event"),
303
+ )
304
+
305
+ async def end(self, conversation_id: str) -> bool:
306
+ """End a conversation (triggers server-side post-processing)."""
307
+ result = await self._request("end_conversation", {"id": conversation_id})
308
+ return result.get("status") == "ended"
309
+
310
+ async def delete(self, conversation_id: str) -> bool:
311
+ """Permanently delete a conversation and its data."""
312
+ result = await self._request("delete", {"id": conversation_id})
313
+ return result.get("status") == "deleted"
314
+
315
+ async def log(self, conversation_id: str) -> ChatLog:
316
+ """Full message history plus the call timeline."""
317
+ result = await self._request("chat_log", {"id": conversation_id})
318
+ return ChatLog(
319
+ messages=result.get("chat_log", []),
320
+ call_timeline=result.get("call_timeline", []),
321
+ )
322
+
323
+ async def summarize(
324
+ self,
325
+ conversation_id: str,
326
+ summary_prompt: str | None = None,
327
+ **sampling: Any,
328
+ ) -> str:
329
+ """AI summary of the conversation (rate limited server-side).
330
+
331
+ Raises :class:`SummaryError` when the server reports that summary
332
+ generation failed — the service returns EXACTLY ONE of ``{summary}`` or
333
+ ``{error}`` (both on the success envelope), so a failure must surface as
334
+ an error, never as an empty string.
335
+ """
336
+ params: dict[str, Any] = {"id": conversation_id}
337
+ if summary_prompt:
338
+ params["summary_prompt"] = summary_prompt
339
+ params.update({k: v for k, v in sampling.items() if v is not None})
340
+ result = await self._request("summarize", params)
341
+ if "error" in result and "summary" not in result:
342
+ raise SummaryError(None, str(result["error"]))
343
+ summary = result.get("summary", "")
344
+ return summary if isinstance(summary, str) else str(summary)
@@ -1493,6 +1493,38 @@ class ContextBuilder:
1493
1493
  f"avoid the collision."
1494
1494
  )
1495
1495
 
1496
+ # Validate step set_functions([...]) whitelists against the known
1497
+ # tool universe. A step that whitelists a function which is neither
1498
+ # a registered SWAIG tool nor a reserved native tool is a DANGLING
1499
+ # reference: it renders a step whose active-function set silently
1500
+ # points at nothing (r5 F3 — get_datetime vs get_current_time).
1501
+ # Only enforce when a real registry is present; a contexts builder
1502
+ # with no agent (or a mock registry) cannot know the tool universe,
1503
+ # so we must not red a valid document there.
1504
+ if isinstance(registered, dict):
1505
+ known_functions = set(registered.keys()) | RESERVED_NATIVE_TOOL_NAMES
1506
+ for context_name, context in self._contexts.items():
1507
+ for step_name, step in context._steps.items():
1508
+ funcs = step._functions
1509
+ # "none" and [] are explicit disable-all — not lists of
1510
+ # references to resolve.
1511
+ if not isinstance(funcs, list):
1512
+ continue
1513
+ for fn in funcs:
1514
+ if fn not in known_functions:
1515
+ available = sorted(known_functions)
1516
+ raise ValueError(
1517
+ f"Step '{step_name}' in context "
1518
+ f"'{context_name}' whitelists function "
1519
+ f"'{fn}' via set_functions(), but no such "
1520
+ f"SWAIG tool is registered on the agent and "
1521
+ f"it is not a reserved native tool. This "
1522
+ f"would emit a dangling function reference. "
1523
+ f"Register the tool (define_tool / a skill) "
1524
+ f"or remove it from the step. Available: "
1525
+ f"{available}"
1526
+ )
1527
+
1496
1528
  def to_dict(self) -> dict[str, Any]:
1497
1529
  """Convert all contexts to dictionary for SWML generation"""
1498
1530
  self.validate()
@@ -168,9 +168,13 @@ class SwmlRenderer:
168
168
  # Use the service to build the document
169
169
  service.reset_document()
170
170
 
171
- # Add a play block for the response if provided
171
+ # Add a play block for the response if provided. Text is played via the
172
+ # `say:` URL scheme — the SWML `play` verb has no `text` key (its config is
173
+ # PlayWithURL/PlayWithURLS, url matching `^...|say: ?.*|...$`). Emitting
174
+ # `{"text": ...}` produced a document the SWML schema rejects; the canonical
175
+ # form (mirrors SWMLBuilder.play) is `url: "say:<text>"`.
172
176
  if response_text:
173
- service.add_verb("play", {"text": response_text})
177
+ service.add_verb("play", {"url": f"say:{response_text}"})
174
178
 
175
179
  # Add any actions that were provided
176
180
  if actions:
@@ -534,6 +534,22 @@ class SWMLService(ToolMixin):
534
534
  handler = self.verb_registry.get_handler(verb_name)
535
535
  assert handler is not None # noqa: S101 # type-narrowing invariant (not input validation): guaranteed by has_handler() above
536
536
  is_valid, errors = handler.validate_config(config)
537
+ # A handler's validate_config carries verb-specific diagnostics
538
+ # (e.g. the ai verb's prompt/SWAIG shape checks) but does NOT reject
539
+ # unknown/misspelled TOP-LEVEL keys — so a typo'd key would slip
540
+ # through silently (r5 silent-drop family: ai temperatur/zzz). Add a
541
+ # shallow unknown-top-level-key check against the schema so a handler
542
+ # verb rejects stray keys like every other verb. We deliberately do
543
+ # NOT run the full deep schema here: the ai verb's DEEP shapes
544
+ # (an empty prompt.pom for a promptless agent, the SWAIG function
545
+ # shape) are the handler's remit and are legitimately emitted by the
546
+ # SDK in forms the JSON-schema's oneOf/pom rules don't all accept —
547
+ # full validation would false-reject valid documents. The shallow
548
+ # check is a no-op when validation is disabled.
549
+ if is_valid:
550
+ is_valid, errors = self.schema_utils._validate_verb_top_level_keys(
551
+ verb_name, config
552
+ )
537
553
  else:
538
554
  # Use schema-based validation for standard verbs
539
555
  is_valid, errors = self.schema_utils.validate_verb(verb_name, config)
@@ -603,6 +619,14 @@ class SWMLService(ToolMixin):
603
619
  handler = self.verb_registry.get_handler(verb_name)
604
620
  assert handler is not None # noqa: S101 # type-narrowing invariant (not input validation): guaranteed by has_handler() above
605
621
  is_valid, errors = handler.validate_config(config)
622
+ # See add_verb: also run the shallow unknown-top-level-key check so a
623
+ # handler verb rejects misspelled/unknown top-level keys (NOT the full
624
+ # deep schema, which would false-reject the ai verb's legitimate
625
+ # empty-pom / SWAIG emissions). No-op when validation is disabled.
626
+ if is_valid:
627
+ is_valid, errors = self.schema_utils._validate_verb_top_level_keys(
628
+ verb_name, config
629
+ )
606
630
  else:
607
631
  # Use schema-based validation for standard verbs
608
632
  is_valid, errors = self.schema_utils.validate_verb(verb_name, config)