signalwire-agents 1.0.8__tar.gz → 1.0.9__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 (149) hide show
  1. {signalwire_agents-1.0.8/signalwire_agents.egg-info → signalwire_agents-1.0.9}/PKG-INFO +1 -1
  2. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/pyproject.toml +1 -1
  3. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/__init__.py +1 -1
  4. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/agent_base.py +21 -2
  5. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/mixins/auth_mixin.py +6 -13
  6. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/mixins/serverless_mixin.py +137 -73
  7. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/mixins/web_mixin.py +1 -1
  8. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9/signalwire_agents.egg-info}/PKG-INFO +1 -1
  9. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/LICENSE +0 -0
  10. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/README.md +0 -0
  11. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/man/sw-agent-init.1 +0 -0
  12. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/man/sw-search.1 +0 -0
  13. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/man/swaig-test.1 +0 -0
  14. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/setup.cfg +0 -0
  15. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/setup.py +0 -0
  16. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/agent_server.py +0 -0
  17. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/agents/bedrock.py +0 -0
  18. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/__init__.py +0 -0
  19. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/build_search.py +0 -0
  20. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/config.py +0 -0
  21. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/core/__init__.py +0 -0
  22. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/core/agent_loader.py +0 -0
  23. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/core/argparse_helpers.py +0 -0
  24. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/core/dynamic_config.py +0 -0
  25. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/core/service_loader.py +0 -0
  26. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/execution/__init__.py +0 -0
  27. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/execution/datamap_exec.py +0 -0
  28. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/execution/webhook_exec.py +0 -0
  29. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/init_project.py +0 -0
  30. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/output/__init__.py +0 -0
  31. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/output/output_formatter.py +0 -0
  32. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/output/swml_dump.py +0 -0
  33. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/simulation/__init__.py +0 -0
  34. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/simulation/data_generation.py +0 -0
  35. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/simulation/data_overrides.py +0 -0
  36. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/simulation/mock_env.py +0 -0
  37. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/swaig_test_wrapper.py +0 -0
  38. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/test_swaig.py +0 -0
  39. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/cli/types.py +0 -0
  40. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/__init__.py +0 -0
  41. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/agent/__init__.py +0 -0
  42. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/agent/config/__init__.py +0 -0
  43. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/agent/deployment/__init__.py +0 -0
  44. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/agent/deployment/handlers/__init__.py +0 -0
  45. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/agent/prompt/__init__.py +0 -0
  46. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/agent/prompt/manager.py +0 -0
  47. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/agent/routing/__init__.py +0 -0
  48. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/agent/security/__init__.py +0 -0
  49. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/agent/swml/__init__.py +0 -0
  50. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/agent/tools/__init__.py +0 -0
  51. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/agent/tools/decorator.py +0 -0
  52. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/agent/tools/registry.py +0 -0
  53. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/auth_handler.py +0 -0
  54. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/config_loader.py +0 -0
  55. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/contexts.py +0 -0
  56. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/data_map.py +0 -0
  57. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/function_result.py +0 -0
  58. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/logging_config.py +0 -0
  59. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/mixins/__init__.py +0 -0
  60. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/mixins/ai_config_mixin.py +0 -0
  61. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/mixins/prompt_mixin.py +0 -0
  62. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/mixins/skill_mixin.py +0 -0
  63. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/mixins/state_mixin.py +0 -0
  64. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/mixins/tool_mixin.py +0 -0
  65. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/pom_builder.py +0 -0
  66. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/security/__init__.py +0 -0
  67. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/security/session_manager.py +0 -0
  68. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/security_config.py +0 -0
  69. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/skill_base.py +0 -0
  70. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/skill_manager.py +0 -0
  71. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/swaig_function.py +0 -0
  72. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/swml_builder.py +0 -0
  73. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/swml_handler.py +0 -0
  74. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/swml_renderer.py +0 -0
  75. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/core/swml_service.py +0 -0
  76. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/prefabs/__init__.py +0 -0
  77. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/prefabs/concierge.py +0 -0
  78. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/prefabs/faq_bot.py +0 -0
  79. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/prefabs/info_gatherer.py +0 -0
  80. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/prefabs/receptionist.py +0 -0
  81. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/prefabs/survey.py +0 -0
  82. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/schema.json +0 -0
  83. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/search/__init__.py +0 -0
  84. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/search/document_processor.py +0 -0
  85. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/search/index_builder.py +0 -0
  86. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/search/migration.py +0 -0
  87. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/search/models.py +0 -0
  88. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/search/pgvector_backend.py +0 -0
  89. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/search/query_processor.py +0 -0
  90. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/search/search_engine.py +0 -0
  91. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/search/search_service.py +0 -0
  92. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/README.md +0 -0
  93. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/__init__.py +0 -0
  94. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/api_ninjas_trivia/README.md +0 -0
  95. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/api_ninjas_trivia/__init__.py +0 -0
  96. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/api_ninjas_trivia/skill.py +0 -0
  97. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/datasphere/README.md +0 -0
  98. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/datasphere/__init__.py +0 -0
  99. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/datasphere/skill.py +0 -0
  100. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/datasphere_serverless/README.md +0 -0
  101. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/datasphere_serverless/__init__.py +0 -0
  102. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/datasphere_serverless/skill.py +0 -0
  103. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/datetime/README.md +0 -0
  104. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/datetime/__init__.py +0 -0
  105. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/datetime/skill.py +0 -0
  106. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/joke/README.md +0 -0
  107. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/joke/__init__.py +0 -0
  108. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/joke/skill.py +0 -0
  109. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/math/README.md +0 -0
  110. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/math/__init__.py +0 -0
  111. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/math/skill.py +0 -0
  112. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/mcp_gateway/README.md +0 -0
  113. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/mcp_gateway/__init__.py +0 -0
  114. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/mcp_gateway/skill.py +0 -0
  115. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/native_vector_search/README.md +0 -0
  116. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/native_vector_search/__init__.py +0 -0
  117. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/native_vector_search/skill.py +0 -0
  118. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/play_background_file/README.md +0 -0
  119. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/play_background_file/__init__.py +0 -0
  120. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/play_background_file/skill.py +0 -0
  121. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/registry.py +0 -0
  122. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/spider/README.md +0 -0
  123. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/spider/__init__.py +0 -0
  124. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/spider/skill.py +0 -0
  125. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/swml_transfer/README.md +0 -0
  126. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/swml_transfer/__init__.py +0 -0
  127. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/swml_transfer/skill.py +0 -0
  128. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/weather_api/README.md +0 -0
  129. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/weather_api/__init__.py +0 -0
  130. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/weather_api/skill.py +0 -0
  131. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/web_search/README.md +0 -0
  132. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/web_search/__init__.py +0 -0
  133. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/web_search/skill.py +0 -0
  134. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/wikipedia_search/README.md +0 -0
  135. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/wikipedia_search/__init__.py +0 -0
  136. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/skills/wikipedia_search/skill.py +0 -0
  137. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/utils/__init__.py +0 -0
  138. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/utils/pom_utils.py +0 -0
  139. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/utils/schema_utils.py +0 -0
  140. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/utils/token_generators.py +0 -0
  141. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/utils/validators.py +0 -0
  142. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/web/__init__.py +0 -0
  143. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents/web/web_service.py +0 -0
  144. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents.egg-info/SOURCES.txt +0 -0
  145. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents.egg-info/dependency_links.txt +0 -0
  146. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents.egg-info/entry_points.txt +0 -0
  147. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents.egg-info/requires.txt +0 -0
  148. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/signalwire_agents.egg-info/top_level.txt +0 -0
  149. {signalwire_agents-1.0.8 → signalwire_agents-1.0.9}/tests/test_examples.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: signalwire_agents
3
- Version: 1.0.8
3
+ Version: 1.0.9
4
4
  Summary: SignalWire AI Agents SDK
5
5
  Author-email: SignalWire Team <info@signalwire.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "signalwire_agents"
7
- version = "1.0.8"
7
+ version = "1.0.9"
8
8
  description = "SignalWire AI Agents SDK"
9
9
  authors = [
10
10
  {name = "SignalWire Team", email = "info@signalwire.com"}
@@ -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.8"
21
+ __version__ = "1.0.9"
22
22
 
23
23
  # Import core classes for easier access
24
24
  from .core.agent_base import AgentBase
@@ -317,13 +317,32 @@ class AgentBase(
317
317
  def get_full_url(self, include_auth: bool = False) -> str:
318
318
  """
319
319
  Get the full URL for this agent's endpoint
320
-
320
+
321
321
  Args:
322
322
  include_auth: Whether to include authentication credentials in the URL
323
-
323
+
324
324
  Returns:
325
325
  Full URL including host, port, and route (with auth if requested)
326
326
  """
327
+ # If _proxy_url_base is set (e.g., from request URL detection), use it
328
+ if hasattr(self, '_proxy_url_base') and self._proxy_url_base:
329
+ base_url = self._proxy_url_base.rstrip('/')
330
+ # Add authentication if requested
331
+ if include_auth:
332
+ username, password = self.get_basic_auth_credentials()
333
+ if username and password:
334
+ from urllib.parse import urlparse, urlunparse
335
+ parsed = urlparse(base_url)
336
+ base_url = urlunparse((
337
+ parsed.scheme,
338
+ f"{username}:{password}@{parsed.netloc}",
339
+ parsed.path,
340
+ parsed.params,
341
+ parsed.query,
342
+ parsed.fragment
343
+ ))
344
+ return base_url
345
+
327
346
  mode = get_execution_mode()
328
347
 
329
348
  if mode == 'cgi':
@@ -196,11 +196,8 @@ class AuthMixin:
196
196
  return False
197
197
 
198
198
  # Check for authorization header (case-insensitive)
199
- auth_header = None
200
- for key in request.headers:
201
- if key.lower() == 'authorization':
202
- auth_header = request.headers[key]
203
- break
199
+ # Flask headers can be accessed directly with .get() which is case-insensitive
200
+ auth_header = request.headers.get('Authorization')
204
201
 
205
202
  if not auth_header or not auth_header.startswith('Basic '):
206
203
  return False
@@ -246,14 +243,10 @@ class AuthMixin:
246
243
  """
247
244
  if not hasattr(req, 'headers'):
248
245
  return False
249
-
250
- # Check for authorization header (case-insensitive)
251
- auth_header = None
252
- for key, value in req.headers.items():
253
- if key.lower() == 'authorization':
254
- auth_header = value
255
- break
256
-
246
+
247
+ # Check for authorization header - use .get() which works with both dict and Flask headers
248
+ auth_header = req.headers.get('Authorization')
249
+
257
250
  if not auth_header or not auth_header.startswith('Basic '):
258
251
  return False
259
252
 
@@ -80,52 +80,76 @@ class ServerlessMixin:
80
80
  # Check authentication in Lambda mode
81
81
  if not self._check_lambda_auth(event):
82
82
  return self._send_lambda_auth_challenge()
83
-
83
+
84
84
  if event:
85
- path = event.get('pathParameters', {}).get('proxy', '') if event.get('pathParameters') else ''
86
- if not path:
87
- swml_response = self._render_swml()
85
+ # Support both HTTP API (v2) and REST API (v1) payload formats
86
+ # HTTP API v2 uses rawPath, REST API v1 uses pathParameters.proxy
87
+ path = event.get('rawPath', '').strip('/')
88
+ if not path and event.get('pathParameters'):
89
+ path = event.get('pathParameters', {}).get('proxy', '')
90
+
91
+ # Parse request body if present
92
+ args = {}
93
+ call_id = None
94
+ raw_data = None
95
+ function_name = None
96
+
97
+ body_content = event.get('body')
98
+ if body_content:
99
+ try:
100
+ if event.get('isBase64Encoded'):
101
+ import base64
102
+ body_content = base64.b64decode(body_content).decode('utf-8')
103
+ if isinstance(body_content, str):
104
+ raw_data = json.loads(body_content)
105
+ else:
106
+ raw_data = body_content
107
+
108
+ call_id = raw_data.get("call_id")
109
+ function_name = raw_data.get("function")
110
+
111
+ # Extract arguments like the FastAPI handler does
112
+ if "argument" in raw_data and isinstance(raw_data["argument"], dict):
113
+ if "parsed" in raw_data["argument"] and isinstance(raw_data["argument"]["parsed"], list) and raw_data["argument"]["parsed"]:
114
+ args = raw_data["argument"]["parsed"][0]
115
+ elif "raw" in raw_data["argument"]:
116
+ try:
117
+ args = json.loads(raw_data["argument"]["raw"])
118
+ except Exception:
119
+ pass
120
+ except Exception:
121
+ # If parsing fails, continue with empty args
122
+ pass
123
+
124
+ # Determine if this is a SWAIG function call
125
+ # Case 1: /swaig endpoint with function name in body
126
+ # Case 2: /{function_name} path-based routing
127
+ # Case 3: Root path - return SWML
128
+
129
+ if path in ('swaig', 'swaig/') and function_name:
130
+ # /swaig endpoint with function name in body
131
+ result = self._execute_swaig_function(function_name, args, call_id, raw_data)
88
132
  return {
89
133
  "statusCode": 200,
90
134
  "headers": {"Content-Type": "application/json"},
91
- "body": swml_response
135
+ "body": json.dumps(result) if isinstance(result, dict) else str(result)
92
136
  }
93
- else:
94
- # Parse Lambda event for SWAIG function call
95
- args = {}
96
- call_id = None
97
- raw_data = None
98
-
99
- # Parse request body if present
100
- body_content = event.get('body')
101
- if body_content:
102
- try:
103
- if isinstance(body_content, str):
104
- raw_data = json.loads(body_content)
105
- else:
106
- raw_data = body_content
107
-
108
- call_id = raw_data.get("call_id")
109
-
110
- # Extract arguments like the FastAPI handler does
111
- if "argument" in raw_data and isinstance(raw_data["argument"], dict):
112
- if "parsed" in raw_data["argument"] and isinstance(raw_data["argument"]["parsed"], list) and raw_data["argument"]["parsed"]:
113
- args = raw_data["argument"]["parsed"][0]
114
- elif "raw" in raw_data["argument"]:
115
- try:
116
- args = json.loads(raw_data["argument"]["raw"])
117
- except Exception:
118
- pass
119
- except Exception:
120
- # If parsing fails, continue with empty args
121
- pass
122
-
137
+ elif path and path not in ('', 'swaig', 'swaig/'):
138
+ # Path-based function routing (e.g., /say_hello)
123
139
  result = self._execute_swaig_function(path, args, call_id, raw_data)
124
140
  return {
125
141
  "statusCode": 200,
126
142
  "headers": {"Content-Type": "application/json"},
127
143
  "body": json.dumps(result) if isinstance(result, dict) else str(result)
128
144
  }
145
+ else:
146
+ # Root path or /swaig without function - return SWML
147
+ swml_response = self._render_swml()
148
+ return {
149
+ "statusCode": 200,
150
+ "headers": {"Content-Type": "application/json"},
151
+ "body": swml_response
152
+ }
129
153
  else:
130
154
  # Handle case when event is None (direct Lambda call with no event)
131
155
  swml_response = self._render_swml()
@@ -152,7 +176,9 @@ class ServerlessMixin:
152
176
 
153
177
  except Exception as e:
154
178
  import logging
179
+ import traceback
155
180
  logging.error(f"Error in serverless request handler: {e}")
181
+ logging.error(f"Traceback: {traceback.format_exc()}")
156
182
  if mode == 'lambda':
157
183
  return {
158
184
  "statusCode": 500,
@@ -302,61 +328,99 @@ class ServerlessMixin:
302
328
  def _handle_azure_function_request(self, req):
303
329
  """
304
330
  Handle Azure Functions specific requests
305
-
331
+
306
332
  Args:
307
333
  req: Azure Functions HttpRequest object
308
-
334
+
309
335
  Returns:
310
336
  Azure Functions HttpResponse object
311
337
  """
312
338
  try:
313
339
  import azure.functions as func
314
-
315
- # Get the path from the request
316
- path = req.url.split('/')[-1] if req.url else ''
317
-
318
- if not path or path == 'api':
319
- # Root request - return SWML
320
- swml_response = self._render_swml()
340
+ from urllib.parse import urlparse
341
+
342
+ # Get the path from the request URL
343
+ # Azure Functions URLs look like: https://app.azurewebsites.net/api/function_name/path
344
+ path = ''
345
+ base_url = None
346
+ if req.url:
347
+ parsed = urlparse(req.url)
348
+ # Full path after /api/ e.g. "function_app" or "function_app/swaig"
349
+ url_parts = req.url.split('/api/')
350
+ if len(url_parts) > 1:
351
+ full_path = url_parts[1].strip('/')
352
+ # Split into function name and sub-path
353
+ path_parts = full_path.split('/', 1)
354
+ function_app_name = path_parts[0] if path_parts else ''
355
+ path = path_parts[1] if len(path_parts) > 1 else ''
356
+
357
+ # Base URL includes the function app name for webhook URLs
358
+ # e.g., https://app.azurewebsites.net/api/function_app
359
+ base_url = f"{parsed.scheme}://{parsed.netloc}/api/{function_app_name}"
360
+ else:
361
+ base_url = f"{parsed.scheme}://{parsed.netloc}/api"
362
+
363
+ # Set the proxy URL base so SWML renders correct webhook URLs
364
+ if base_url and not getattr(self, '_proxy_url_base_from_env', False):
365
+ self._proxy_url_base = base_url
366
+
367
+ # Parse request body if present
368
+ args = {}
369
+ call_id = None
370
+ raw_data = None
371
+ function_name = None
372
+
373
+ if req.method == 'POST':
374
+ try:
375
+ body = req.get_body()
376
+ if body:
377
+ raw_data = json.loads(body.decode('utf-8'))
378
+ call_id = raw_data.get("call_id")
379
+ function_name = raw_data.get("function")
380
+
381
+ # Extract arguments like the FastAPI handler does
382
+ if "argument" in raw_data and isinstance(raw_data["argument"], dict):
383
+ if "parsed" in raw_data["argument"] and isinstance(raw_data["argument"]["parsed"], list) and raw_data["argument"]["parsed"]:
384
+ args = raw_data["argument"]["parsed"][0]
385
+ elif "raw" in raw_data["argument"]:
386
+ try:
387
+ args = json.loads(raw_data["argument"]["raw"])
388
+ except Exception:
389
+ pass
390
+ except Exception:
391
+ # If parsing fails, continue with empty args
392
+ pass
393
+
394
+ # Determine if this is a SWAIG function call
395
+ # Case 1: /swaig endpoint with function name in body
396
+ # Case 2: /{function_name} path-based routing
397
+ # Case 3: Root path - return SWML
398
+
399
+ if path in ('swaig', 'swaig/') and function_name:
400
+ # /swaig endpoint with function name in body
401
+ result = self._execute_swaig_function(function_name, args, call_id, raw_data)
321
402
  return func.HttpResponse(
322
- body=swml_response,
403
+ body=json.dumps(result) if isinstance(result, dict) else str(result),
323
404
  status_code=200,
324
405
  headers={"Content-Type": "application/json"}
325
406
  )
326
- else:
327
- # SWAIG function call
328
- args = {}
329
- call_id = None
330
- raw_data = None
331
-
332
- # Parse request data
333
- if req.method == 'POST':
334
- try:
335
- body = req.get_body()
336
- if body:
337
- raw_data = json.loads(body.decode('utf-8'))
338
- call_id = raw_data.get("call_id")
339
-
340
- # Extract arguments like the FastAPI handler does
341
- if "argument" in raw_data and isinstance(raw_data["argument"], dict):
342
- if "parsed" in raw_data["argument"] and isinstance(raw_data["argument"]["parsed"], list) and raw_data["argument"]["parsed"]:
343
- args = raw_data["argument"]["parsed"][0]
344
- elif "raw" in raw_data["argument"]:
345
- try:
346
- args = json.loads(raw_data["argument"]["raw"])
347
- except Exception:
348
- pass
349
- except Exception:
350
- # If parsing fails, continue with empty args
351
- pass
352
-
407
+ elif path and path not in ('', 'api', 'swaig', 'swaig/'):
408
+ # Path-based function routing (e.g., /say_hello)
353
409
  result = self._execute_swaig_function(path, args, call_id, raw_data)
354
410
  return func.HttpResponse(
355
411
  body=json.dumps(result) if isinstance(result, dict) else str(result),
356
412
  status_code=200,
357
413
  headers={"Content-Type": "application/json"}
358
414
  )
359
-
415
+ else:
416
+ # Root path or /swaig without function - return SWML
417
+ swml_response = self._render_swml()
418
+ return func.HttpResponse(
419
+ body=swml_response,
420
+ status_code=200,
421
+ headers={"Content-Type": "application/json"}
422
+ )
423
+
360
424
  except Exception as e:
361
425
  import logging
362
426
  logging.error(f"Error in Azure Function request handler: {e}")
@@ -302,7 +302,7 @@ class WebMixin:
302
302
  response = self.handle_serverless_request(event, context, mode)
303
303
  print(response)
304
304
  return response
305
- elif mode == 'lambda':
305
+ elif mode in ['lambda', 'google_cloud_function']:
306
306
  return self.handle_serverless_request(event, context, mode)
307
307
  else:
308
308
  # Server mode - use existing serve method
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: signalwire_agents
3
- Version: 1.0.8
3
+ Version: 1.0.9
4
4
  Summary: SignalWire AI Agents SDK
5
5
  Author-email: SignalWire Team <info@signalwire.com>
6
6
  License: MIT