signalwire-agents 0.1.36__tar.gz → 0.1.38__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 (139) hide show
  1. {signalwire_agents-0.1.36/signalwire_agents.egg-info → signalwire_agents-0.1.38}/PKG-INFO +66 -1
  2. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/README.md +47 -0
  3. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/pyproject.toml +27 -1
  4. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/__init__.py +1 -1
  5. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/build_search.py +95 -19
  6. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/agent_base.py +38 -0
  7. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/mixins/ai_config_mixin.py +120 -0
  8. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/skill_manager.py +47 -0
  9. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/search/index_builder.py +105 -10
  10. signalwire_agents-0.1.38/signalwire_agents/search/pgvector_backend.py +523 -0
  11. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/search/search_engine.py +41 -4
  12. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/search/search_service.py +86 -35
  13. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/api_ninjas_trivia/skill.py +37 -1
  14. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/datasphere/skill.py +82 -0
  15. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/datasphere_serverless/skill.py +82 -0
  16. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/joke/skill.py +21 -0
  17. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/mcp_gateway/skill.py +82 -0
  18. signalwire_agents-0.1.38/signalwire_agents/skills/native_vector_search/README.md +210 -0
  19. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/native_vector_search/skill.py +197 -7
  20. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/play_background_file/skill.py +36 -0
  21. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/registry.py +36 -0
  22. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/spider/skill.py +113 -0
  23. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/swml_transfer/skill.py +90 -0
  24. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/weather_api/skill.py +28 -0
  25. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/wikipedia_search/skill.py +22 -0
  26. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38/signalwire_agents.egg-info}/PKG-INFO +66 -1
  27. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents.egg-info/SOURCES.txt +2 -0
  28. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents.egg-info/requires.txt +20 -0
  29. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/LICENSE +0 -0
  30. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/setup.cfg +0 -0
  31. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/setup.py +0 -0
  32. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/agent_server.py +0 -0
  33. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/__init__.py +0 -0
  34. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/config.py +0 -0
  35. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/core/__init__.py +0 -0
  36. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/core/agent_loader.py +0 -0
  37. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/core/argparse_helpers.py +0 -0
  38. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/core/dynamic_config.py +0 -0
  39. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/core/service_loader.py +0 -0
  40. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/execution/__init__.py +0 -0
  41. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/execution/datamap_exec.py +0 -0
  42. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/execution/webhook_exec.py +0 -0
  43. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/output/__init__.py +0 -0
  44. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/output/output_formatter.py +0 -0
  45. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/output/swml_dump.py +0 -0
  46. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/simulation/__init__.py +0 -0
  47. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/simulation/data_generation.py +0 -0
  48. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/simulation/data_overrides.py +0 -0
  49. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/simulation/mock_env.py +0 -0
  50. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/swaig_test_wrapper.py +0 -0
  51. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/test_swaig.py +0 -0
  52. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/cli/types.py +0 -0
  53. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/__init__.py +0 -0
  54. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/agent/__init__.py +0 -0
  55. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/agent/config/__init__.py +0 -0
  56. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/agent/deployment/__init__.py +0 -0
  57. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/agent/deployment/handlers/__init__.py +0 -0
  58. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/agent/prompt/__init__.py +0 -0
  59. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/agent/prompt/manager.py +0 -0
  60. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/agent/routing/__init__.py +0 -0
  61. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/agent/security/__init__.py +0 -0
  62. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/agent/swml/__init__.py +0 -0
  63. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/agent/tools/__init__.py +0 -0
  64. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/agent/tools/decorator.py +0 -0
  65. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/agent/tools/registry.py +0 -0
  66. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/auth_handler.py +0 -0
  67. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/config_loader.py +0 -0
  68. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/contexts.py +0 -0
  69. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/data_map.py +0 -0
  70. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/function_result.py +0 -0
  71. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/logging_config.py +0 -0
  72. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/mixins/__init__.py +0 -0
  73. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/mixins/auth_mixin.py +0 -0
  74. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/mixins/prompt_mixin.py +0 -0
  75. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/mixins/serverless_mixin.py +0 -0
  76. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/mixins/skill_mixin.py +0 -0
  77. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/mixins/state_mixin.py +0 -0
  78. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/mixins/tool_mixin.py +0 -0
  79. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/mixins/web_mixin.py +0 -0
  80. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/pom_builder.py +0 -0
  81. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/security/__init__.py +0 -0
  82. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/security/session_manager.py +0 -0
  83. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/security_config.py +0 -0
  84. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/skill_base.py +0 -0
  85. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/swaig_function.py +0 -0
  86. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/swml_builder.py +0 -0
  87. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/swml_handler.py +0 -0
  88. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/swml_renderer.py +0 -0
  89. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/core/swml_service.py +0 -0
  90. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/prefabs/__init__.py +0 -0
  91. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/prefabs/concierge.py +0 -0
  92. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/prefabs/faq_bot.py +0 -0
  93. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/prefabs/info_gatherer.py +0 -0
  94. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/prefabs/receptionist.py +0 -0
  95. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/prefabs/survey.py +0 -0
  96. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/schema.json +0 -0
  97. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/search/__init__.py +0 -0
  98. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/search/document_processor.py +0 -0
  99. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/search/query_processor.py +0 -0
  100. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/README.md +0 -0
  101. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/__init__.py +0 -0
  102. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/api_ninjas_trivia/README.md +0 -0
  103. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/api_ninjas_trivia/__init__.py +0 -0
  104. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/datasphere/README.md +0 -0
  105. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/datasphere/__init__.py +0 -0
  106. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/datasphere_serverless/README.md +0 -0
  107. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/datasphere_serverless/__init__.py +0 -0
  108. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/datetime/README.md +0 -0
  109. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/datetime/__init__.py +0 -0
  110. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/datetime/skill.py +0 -0
  111. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/joke/README.md +0 -0
  112. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/joke/__init__.py +0 -0
  113. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/math/README.md +0 -0
  114. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/math/__init__.py +0 -0
  115. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/math/skill.py +0 -0
  116. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/mcp_gateway/README.md +0 -0
  117. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/mcp_gateway/__init__.py +0 -0
  118. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/native_vector_search/__init__.py +0 -0
  119. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/play_background_file/README.md +0 -0
  120. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/play_background_file/__init__.py +0 -0
  121. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/spider/README.md +0 -0
  122. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/spider/__init__.py +0 -0
  123. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/swml_transfer/README.md +0 -0
  124. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/swml_transfer/__init__.py +0 -0
  125. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/weather_api/README.md +0 -0
  126. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/weather_api/__init__.py +0 -0
  127. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/web_search/README.md +0 -0
  128. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/web_search/__init__.py +0 -0
  129. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/web_search/skill.py +0 -0
  130. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/wikipedia_search/README.md +0 -0
  131. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/skills/wikipedia_search/__init__.py +0 -0
  132. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/utils/__init__.py +0 -0
  133. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/utils/pom_utils.py +0 -0
  134. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/utils/schema_utils.py +0 -0
  135. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/utils/token_generators.py +0 -0
  136. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents/utils/validators.py +0 -0
  137. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents.egg-info/dependency_links.txt +0 -0
  138. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents.egg-info/entry_points.txt +0 -0
  139. {signalwire_agents-0.1.36 → signalwire_agents-0.1.38}/signalwire_agents.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: signalwire_agents
3
- Version: 0.1.36
3
+ Version: 0.1.38
4
4
  Summary: SignalWire AI Agents SDK
5
5
  Author-email: SignalWire Team <info@signalwire.com>
6
6
  License: MIT
@@ -70,6 +70,24 @@ Requires-Dist: striprtf>=0.0.26; extra == "search-all"
70
70
  Requires-Dist: openpyxl>=3.1.0; extra == "search-all"
71
71
  Requires-Dist: python-pptx>=0.6.21; extra == "search-all"
72
72
  Requires-Dist: python-magic>=0.4.27; extra == "search-all"
73
+ Requires-Dist: psycopg2-binary>=2.9.0; extra == "search-all"
74
+ Requires-Dist: pgvector>=0.2.0; extra == "search-all"
75
+ Provides-Extra: pgvector
76
+ Requires-Dist: psycopg2-binary>=2.9.0; extra == "pgvector"
77
+ Requires-Dist: pgvector>=0.2.0; extra == "pgvector"
78
+ Provides-Extra: all
79
+ Requires-Dist: sentence-transformers>=2.2.0; extra == "all"
80
+ Requires-Dist: scikit-learn>=1.3.0; extra == "all"
81
+ Requires-Dist: nltk>=3.8; extra == "all"
82
+ Requires-Dist: numpy>=1.24.0; extra == "all"
83
+ Requires-Dist: spacy>=3.6.0; extra == "all"
84
+ Requires-Dist: pdfplumber>=0.9.0; extra == "all"
85
+ Requires-Dist: python-docx>=0.8.11; extra == "all"
86
+ Requires-Dist: markdown>=3.4.0; extra == "all"
87
+ Requires-Dist: striprtf>=0.0.26; extra == "all"
88
+ Requires-Dist: openpyxl>=3.1.0; extra == "all"
89
+ Requires-Dist: python-pptx>=0.6.21; extra == "all"
90
+ Requires-Dist: python-magic>=0.4.27; extra == "all"
73
91
  Dynamic: license-file
74
92
 
75
93
  <!-- Header -->
@@ -630,6 +648,53 @@ if __name__ == "__main__":
630
648
  agent.serve(host="0.0.0.0", port=8000)
631
649
  ```
632
650
 
651
+ ### Customizing LLM Parameters
652
+
653
+ The SDK allows you to customize LLM parameters for both the main prompt and post-prompt, giving you fine control over the AI's behavior:
654
+
655
+ ```python
656
+ from signalwire_agents import AgentBase
657
+
658
+ class PreciseAgent(AgentBase):
659
+ def __init__(self):
660
+ super().__init__(name="precise", route="/precise")
661
+
662
+ # Configure the agent's personality
663
+ self.prompt_add_section("Role", "You are a precise technical assistant.")
664
+ self.prompt_add_section("Instructions", "Provide accurate, detailed information.")
665
+
666
+ # Set custom LLM parameters for the main prompt
667
+ self.set_prompt_llm_params(
668
+ temperature=0.3, # Low temperature for more consistent responses
669
+ top_p=0.9, # Slightly reduced for focused responses
670
+ barge_confidence=0.7, # Moderate interruption threshold
671
+ presence_penalty=0.1, # Slight penalty for repetition
672
+ frequency_penalty=0.2 # Encourage varied vocabulary
673
+ )
674
+
675
+ # Set post-prompt for summaries
676
+ self.set_post_prompt("Provide a concise summary of the key points discussed.")
677
+
678
+ # Different parameters for post-prompt (summaries should be even more focused)
679
+ self.set_post_prompt_llm_params(
680
+ temperature=0.2, # Very low for consistent summaries
681
+ top_p=0.85 # More focused token selection
682
+ )
683
+
684
+ agent = PreciseAgent()
685
+ agent.serve()
686
+ ```
687
+
688
+ #### Available LLM Parameters
689
+
690
+ - **temperature** (0.0-1.5): Controls randomness. Lower = more focused, higher = more creative
691
+ - **top_p** (0.0-1.0): Nucleus sampling. Lower = more focused on likely tokens
692
+ - **barge_confidence** (0.0-1.0): ASR confidence to interrupt. Higher = harder to interrupt
693
+ - **presence_penalty** (-2.0-2.0): Topic diversity. Positive = new topics
694
+ - **frequency_penalty** (-2.0-2.0): Repetition control. Positive = varied vocabulary
695
+
696
+ For more details on LLM parameter tuning, see [LLM Parameters Guide](docs/llm_parameters.md).
697
+
633
698
  ### Using Prefab Agents
634
699
 
635
700
  ```python
@@ -556,6 +556,53 @@ if __name__ == "__main__":
556
556
  agent.serve(host="0.0.0.0", port=8000)
557
557
  ```
558
558
 
559
+ ### Customizing LLM Parameters
560
+
561
+ The SDK allows you to customize LLM parameters for both the main prompt and post-prompt, giving you fine control over the AI's behavior:
562
+
563
+ ```python
564
+ from signalwire_agents import AgentBase
565
+
566
+ class PreciseAgent(AgentBase):
567
+ def __init__(self):
568
+ super().__init__(name="precise", route="/precise")
569
+
570
+ # Configure the agent's personality
571
+ self.prompt_add_section("Role", "You are a precise technical assistant.")
572
+ self.prompt_add_section("Instructions", "Provide accurate, detailed information.")
573
+
574
+ # Set custom LLM parameters for the main prompt
575
+ self.set_prompt_llm_params(
576
+ temperature=0.3, # Low temperature for more consistent responses
577
+ top_p=0.9, # Slightly reduced for focused responses
578
+ barge_confidence=0.7, # Moderate interruption threshold
579
+ presence_penalty=0.1, # Slight penalty for repetition
580
+ frequency_penalty=0.2 # Encourage varied vocabulary
581
+ )
582
+
583
+ # Set post-prompt for summaries
584
+ self.set_post_prompt("Provide a concise summary of the key points discussed.")
585
+
586
+ # Different parameters for post-prompt (summaries should be even more focused)
587
+ self.set_post_prompt_llm_params(
588
+ temperature=0.2, # Very low for consistent summaries
589
+ top_p=0.85 # More focused token selection
590
+ )
591
+
592
+ agent = PreciseAgent()
593
+ agent.serve()
594
+ ```
595
+
596
+ #### Available LLM Parameters
597
+
598
+ - **temperature** (0.0-1.5): Controls randomness. Lower = more focused, higher = more creative
599
+ - **top_p** (0.0-1.0): Nucleus sampling. Lower = more focused on likely tokens
600
+ - **barge_confidence** (0.0-1.0): ASR confidence to interrupt. Higher = harder to interrupt
601
+ - **presence_penalty** (-2.0-2.0): Topic diversity. Positive = new topics
602
+ - **frequency_penalty** (-2.0-2.0): Repetition control. Positive = varied vocabulary
603
+
604
+ For more details on LLM parameter tuning, see [LLM Parameters Guide](docs/llm_parameters.md).
605
+
559
606
  ### Using Prefab Agents
560
607
 
561
608
  ```python
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "signalwire_agents"
7
- version = "0.1.36"
7
+ version = "0.1.38"
8
8
  description = "SignalWire AI Agents SDK"
9
9
  authors = [
10
10
  {name = "SignalWire Team", email = "info@signalwire.com"}
@@ -95,6 +95,32 @@ search-all = [
95
95
  "openpyxl>=3.1.0",
96
96
  "python-pptx>=0.6.21",
97
97
  "python-magic>=0.4.27",
98
+ # pgvector support
99
+ "psycopg2-binary>=2.9.0",
100
+ "pgvector>=0.2.0",
101
+ ]
102
+
103
+ # PostgreSQL pgvector support
104
+ pgvector = [
105
+ "psycopg2-binary>=2.9.0",
106
+ "pgvector>=0.2.0",
107
+ ]
108
+
109
+ # All optional dependencies
110
+ all = [
111
+ "sentence-transformers>=2.2.0",
112
+ "scikit-learn>=1.3.0",
113
+ "nltk>=3.8",
114
+ "numpy>=1.24.0",
115
+ "spacy>=3.6.0",
116
+ # Document processing dependencies
117
+ "pdfplumber>=0.9.0",
118
+ "python-docx>=0.8.11",
119
+ "markdown>=3.4.0",
120
+ "striprtf>=0.0.26",
121
+ "openpyxl>=3.1.0",
122
+ "python-pptx>=0.6.21",
123
+ "python-magic>=0.4.27",
98
124
  ]
99
125
 
100
126
  [project.urls]
@@ -18,7 +18,7 @@ A package for building AI agents using SignalWire's AI and SWML capabilities.
18
18
  from .core.logging_config import configure_logging
19
19
  configure_logging()
20
20
 
21
- __version__ = "0.1.36"
21
+ __version__ = "0.1.38"
22
22
 
23
23
  # Import core classes for easier access
24
24
  from .core.agent_base import AgentBase
@@ -89,6 +89,24 @@ Examples:
89
89
  # Search via remote API
90
90
  sw-search remote http://localhost:8001 "how to create an agent" --index-name docs
91
91
  sw-search remote localhost:8001 "API reference" --index-name docs --count 3 --verbose
92
+
93
+ # PostgreSQL pgvector backend
94
+ sw-search ./docs \\
95
+ --backend pgvector \\
96
+ --connection-string "postgresql://user:pass@localhost/knowledge" \\
97
+ --output docs_collection
98
+
99
+ # Overwrite existing pgvector collection
100
+ sw-search ./docs \\
101
+ --backend pgvector \\
102
+ --connection-string "postgresql://user:pass@localhost/knowledge" \\
103
+ --output docs_collection \\
104
+ --overwrite
105
+
106
+ # Search in pgvector collection
107
+ sw-search search docs_collection "how to create an agent" \\
108
+ --backend pgvector \\
109
+ --connection-string "postgresql://user:pass@localhost/knowledge"
92
110
  """
93
111
  )
94
112
 
@@ -100,7 +118,25 @@ Examples:
100
118
 
101
119
  parser.add_argument(
102
120
  '--output',
103
- help='Output .swsearch file (default: sources.swsearch)'
121
+ help='Output .swsearch file (default: sources.swsearch) or collection name for pgvector'
122
+ )
123
+
124
+ parser.add_argument(
125
+ '--backend',
126
+ choices=['sqlite', 'pgvector'],
127
+ default='sqlite',
128
+ help='Storage backend to use (default: sqlite)'
129
+ )
130
+
131
+ parser.add_argument(
132
+ '--connection-string',
133
+ help='PostgreSQL connection string for pgvector backend'
134
+ )
135
+
136
+ parser.add_argument(
137
+ '--overwrite',
138
+ action='store_true',
139
+ help='Overwrite existing collection (pgvector backend only)'
104
140
  )
105
141
 
106
142
  parser.add_argument(
@@ -213,18 +249,31 @@ Examples:
213
249
  print("Error: No valid sources found")
214
250
  sys.exit(1)
215
251
 
252
+ # Validate backend configuration
253
+ if args.backend == 'pgvector' and not args.connection_string:
254
+ print("Error: --connection-string is required for pgvector backend")
255
+ sys.exit(1)
256
+
216
257
  # Default output filename
217
258
  if not args.output:
218
- if len(valid_sources) == 1:
219
- # Single source - use its name
220
- source_name = valid_sources[0].stem if valid_sources[0].is_file() else valid_sources[0].name
221
- args.output = f"{source_name}.swsearch"
259
+ if args.backend == 'sqlite':
260
+ if len(valid_sources) == 1:
261
+ # Single source - use its name
262
+ source_name = valid_sources[0].stem if valid_sources[0].is_file() else valid_sources[0].name
263
+ args.output = f"{source_name}.swsearch"
264
+ else:
265
+ # Multiple sources - use generic name
266
+ args.output = "sources.swsearch"
222
267
  else:
223
- # Multiple sources - use generic name
224
- args.output = "sources.swsearch"
268
+ # For pgvector, use a default collection name
269
+ if len(valid_sources) == 1:
270
+ source_name = valid_sources[0].stem if valid_sources[0].is_file() else valid_sources[0].name
271
+ args.output = source_name
272
+ else:
273
+ args.output = "documents"
225
274
 
226
- # Ensure output has .swsearch extension
227
- if not args.output.endswith('.swsearch'):
275
+ # Ensure output has .swsearch extension for sqlite
276
+ if args.backend == 'sqlite' and not args.output.endswith('.swsearch'):
228
277
  args.output += '.swsearch'
229
278
 
230
279
  # Parse lists
@@ -235,8 +284,13 @@ Examples:
235
284
 
236
285
  if args.verbose:
237
286
  print(f"Building search index:")
287
+ print(f" Backend: {args.backend}")
238
288
  print(f" Sources: {[str(s) for s in valid_sources]}")
239
- print(f" Output: {args.output}")
289
+ if args.backend == 'sqlite':
290
+ print(f" Output file: {args.output}")
291
+ else:
292
+ print(f" Collection name: {args.output}")
293
+ print(f" Connection: {args.connection_string}")
240
294
  print(f" File types (for directories): {file_types}")
241
295
  print(f" Exclude patterns: {exclude_patterns}")
242
296
  print(f" Languages: {languages}")
@@ -278,7 +332,9 @@ Examples:
278
332
  index_nlp_backend=args.index_nlp_backend,
279
333
  verbose=args.verbose,
280
334
  semantic_threshold=args.semantic_threshold,
281
- topic_threshold=args.topic_threshold
335
+ topic_threshold=args.topic_threshold,
336
+ backend=args.backend,
337
+ connection_string=args.connection_string
282
338
  )
283
339
 
284
340
  # Build index with multiple sources
@@ -288,7 +344,8 @@ Examples:
288
344
  file_types=file_types,
289
345
  exclude_patterns=exclude_patterns,
290
346
  languages=languages,
291
- tags=tags
347
+ tags=tags,
348
+ overwrite=args.overwrite if args.backend == 'pgvector' else False
292
349
  )
293
350
 
294
351
  # Validate if requested
@@ -307,7 +364,11 @@ Examples:
307
364
  print(f"✗ Index validation failed: {validation['error']}")
308
365
  sys.exit(1)
309
366
 
310
- print(f"\n✓ Search index created successfully: {args.output}")
367
+ if args.backend == 'sqlite':
368
+ print(f"\n✓ Search index created successfully: {args.output}")
369
+ else:
370
+ print(f"\n✓ Search collection created successfully: {args.output}")
371
+ print(f" Connection: {args.connection_string}")
311
372
 
312
373
  except KeyboardInterrupt:
313
374
  print("\n\nBuild interrupted by user")
@@ -359,9 +420,12 @@ def validate_command():
359
420
 
360
421
  def search_command():
361
422
  """Search within an existing search index"""
362
- parser = argparse.ArgumentParser(description='Search within a .swsearch index file')
363
- parser.add_argument('index_file', help='Path to .swsearch file to search')
423
+ parser = argparse.ArgumentParser(description='Search within a .swsearch index file or pgvector collection')
424
+ parser.add_argument('index_source', help='Path to .swsearch file or collection name for pgvector')
364
425
  parser.add_argument('query', help='Search query')
426
+ parser.add_argument('--backend', choices=['sqlite', 'pgvector'], default='sqlite',
427
+ help='Storage backend (default: sqlite)')
428
+ parser.add_argument('--connection-string', help='PostgreSQL connection string for pgvector backend')
365
429
  parser.add_argument('--count', type=int, default=5, help='Number of results to return (default: 5)')
366
430
  parser.add_argument('--distance-threshold', type=float, default=0.0, help='Minimum similarity score (default: 0.0)')
367
431
  parser.add_argument('--tags', help='Comma-separated tags to filter by')
@@ -373,8 +437,13 @@ def search_command():
373
437
 
374
438
  args = parser.parse_args()
375
439
 
376
- if not Path(args.index_file).exists():
377
- print(f"Error: Index file does not exist: {args.index_file}")
440
+ # Validate backend configuration
441
+ if args.backend == 'pgvector' and not args.connection_string:
442
+ print("Error: --connection-string is required for pgvector backend")
443
+ sys.exit(1)
444
+
445
+ if args.backend == 'sqlite' and not Path(args.index_source).exists():
446
+ print(f"Error: Index file does not exist: {args.index_source}")
378
447
  sys.exit(1)
379
448
 
380
449
  try:
@@ -389,9 +458,16 @@ def search_command():
389
458
 
390
459
  # Load search engine
391
460
  if args.verbose:
392
- print(f"Loading search index: {args.index_file}")
461
+ if args.backend == 'sqlite':
462
+ print(f"Loading search index: {args.index_source}")
463
+ else:
464
+ print(f"Connecting to pgvector collection: {args.index_source}")
393
465
 
394
- engine = SearchEngine(args.index_file)
466
+ if args.backend == 'sqlite':
467
+ engine = SearchEngine(backend='sqlite', index_path=args.index_source)
468
+ else:
469
+ engine = SearchEngine(backend='pgvector', connection_string=args.connection_string,
470
+ collection_name=args.index_source)
395
471
 
396
472
  # Get index stats
397
473
  stats = engine.get_stats()
@@ -238,6 +238,20 @@ class AgentBase(
238
238
  self._params = {}
239
239
  self._global_data = {}
240
240
  self._function_includes = []
241
+ # Initialize with default LLM params
242
+ self._prompt_llm_params = {
243
+ 'temperature': 0.3,
244
+ 'top_p': 1.0,
245
+ 'barge_confidence': 0.0,
246
+ 'presence_penalty': 0.1,
247
+ 'frequency_penalty': 0.1
248
+ }
249
+ self._post_prompt_llm_params = {
250
+ 'temperature': 0.0,
251
+ 'top_p': 1.0,
252
+ 'presence_penalty': 0.0,
253
+ 'frequency_penalty': 0.0
254
+ }
241
255
 
242
256
  # Dynamic configuration callback
243
257
  self._dynamic_config_callback = None
@@ -763,6 +777,30 @@ class AgentBase(
763
777
  # Add global_data if any
764
778
  if agent_to_use._global_data:
765
779
  ai_config["global_data"] = agent_to_use._global_data
780
+
781
+ # Always add LLM parameters to prompt
782
+ if "prompt" in ai_config:
783
+ # Update existing prompt with LLM params
784
+ if isinstance(ai_config["prompt"], dict):
785
+ ai_config["prompt"].update(agent_to_use._prompt_llm_params)
786
+ elif isinstance(ai_config["prompt"], str):
787
+ # Convert string prompt to dict format
788
+ ai_config["prompt"] = {
789
+ "text": ai_config["prompt"],
790
+ **agent_to_use._prompt_llm_params
791
+ }
792
+
793
+ # Always add LLM parameters to post_prompt if post_prompt exists
794
+ if post_prompt and "post_prompt" in ai_config:
795
+ # Update existing post_prompt with LLM params
796
+ if isinstance(ai_config["post_prompt"], dict):
797
+ ai_config["post_prompt"].update(agent_to_use._post_prompt_llm_params)
798
+ elif isinstance(ai_config["post_prompt"], str):
799
+ # Convert string post_prompt to dict format
800
+ ai_config["post_prompt"] = {
801
+ "text": ai_config["post_prompt"],
802
+ **agent_to_use._post_prompt_llm_params
803
+ }
766
804
 
767
805
  except ValueError as e:
768
806
  if not agent_to_use._suppress_logs:
@@ -370,4 +370,124 @@ class AIConfigMixin:
370
370
  valid_includes.append(include)
371
371
 
372
372
  self._function_includes = valid_includes
373
+ return self
374
+
375
+ def set_prompt_llm_params(
376
+ self,
377
+ temperature: Optional[float] = None,
378
+ top_p: Optional[float] = None,
379
+ barge_confidence: Optional[float] = None,
380
+ presence_penalty: Optional[float] = None,
381
+ frequency_penalty: Optional[float] = None
382
+ ) -> 'AgentBase':
383
+ """
384
+ Set LLM parameters for the main prompt.
385
+
386
+ Args:
387
+ temperature: Randomness setting (0.0-1.5). Lower values make output more deterministic.
388
+ Default: 0.3
389
+ top_p: Alternative to temperature (0.0-1.0). Controls nucleus sampling.
390
+ Default: 1.0
391
+ barge_confidence: ASR confidence to interrupt (0.0-1.0). Higher values make it harder to interrupt.
392
+ Default: 0.0
393
+ presence_penalty: Topic diversity (-2.0 to 2.0). Positive values encourage new topics.
394
+ Default: 0.1
395
+ frequency_penalty: Repetition control (-2.0 to 2.0). Positive values reduce repetition.
396
+ Default: 0.1
397
+
398
+ Returns:
399
+ Self for method chaining
400
+
401
+ Example:
402
+ agent.set_prompt_llm_params(
403
+ temperature=0.7,
404
+ top_p=0.9,
405
+ barge_confidence=0.6
406
+ )
407
+ """
408
+ # Validate and set temperature
409
+ if temperature is not None:
410
+ if not 0.0 <= temperature <= 1.5:
411
+ raise ValueError("temperature must be between 0.0 and 1.5")
412
+ self._prompt_llm_params['temperature'] = temperature
413
+
414
+ # Validate and set top_p
415
+ if top_p is not None:
416
+ if not 0.0 <= top_p <= 1.0:
417
+ raise ValueError("top_p must be between 0.0 and 1.0")
418
+ self._prompt_llm_params['top_p'] = top_p
419
+
420
+ # Validate and set barge_confidence
421
+ if barge_confidence is not None:
422
+ if not 0.0 <= barge_confidence <= 1.0:
423
+ raise ValueError("barge_confidence must be between 0.0 and 1.0")
424
+ self._prompt_llm_params['barge_confidence'] = barge_confidence
425
+
426
+ # Validate and set presence_penalty
427
+ if presence_penalty is not None:
428
+ if not -2.0 <= presence_penalty <= 2.0:
429
+ raise ValueError("presence_penalty must be between -2.0 and 2.0")
430
+ self._prompt_llm_params['presence_penalty'] = presence_penalty
431
+
432
+ # Validate and set frequency_penalty
433
+ if frequency_penalty is not None:
434
+ if not -2.0 <= frequency_penalty <= 2.0:
435
+ raise ValueError("frequency_penalty must be between -2.0 and 2.0")
436
+ self._prompt_llm_params['frequency_penalty'] = frequency_penalty
437
+
438
+ return self
439
+
440
+ def set_post_prompt_llm_params(
441
+ self,
442
+ temperature: Optional[float] = None,
443
+ top_p: Optional[float] = None,
444
+ presence_penalty: Optional[float] = None,
445
+ frequency_penalty: Optional[float] = None
446
+ ) -> 'AgentBase':
447
+ """
448
+ Set LLM parameters for the post-prompt.
449
+
450
+ Args:
451
+ temperature: Randomness setting (0.0-1.5). Lower values make output more deterministic.
452
+ Default: 0.0
453
+ top_p: Alternative to temperature (0.0-1.0). Controls nucleus sampling.
454
+ Default: 1.0
455
+ presence_penalty: Topic diversity (-2.0 to 2.0). Positive values encourage new topics.
456
+ Default: 0.0
457
+ frequency_penalty: Repetition control (-2.0 to 2.0). Positive values reduce repetition.
458
+ Default: 0.0
459
+
460
+ Returns:
461
+ Self for method chaining
462
+
463
+ Example:
464
+ agent.set_post_prompt_llm_params(
465
+ temperature=0.5, # More deterministic for post-prompt
466
+ top_p=0.9
467
+ )
468
+ """
469
+ # Validate and set temperature
470
+ if temperature is not None:
471
+ if not 0.0 <= temperature <= 1.5:
472
+ raise ValueError("temperature must be between 0.0 and 1.5")
473
+ self._post_prompt_llm_params['temperature'] = temperature
474
+
475
+ # Validate and set top_p
476
+ if top_p is not None:
477
+ if not 0.0 <= top_p <= 1.0:
478
+ raise ValueError("top_p must be between 0.0 and 1.0")
479
+ self._post_prompt_llm_params['top_p'] = top_p
480
+
481
+ # Validate and set presence_penalty
482
+ if presence_penalty is not None:
483
+ if not -2.0 <= presence_penalty <= 2.0:
484
+ raise ValueError("presence_penalty must be between -2.0 and 2.0")
485
+ self._post_prompt_llm_params['presence_penalty'] = presence_penalty
486
+
487
+ # Validate and set frequency_penalty
488
+ if frequency_penalty is not None:
489
+ if not -2.0 <= frequency_penalty <= 2.0:
490
+ raise ValueError("frequency_penalty must be between -2.0 and 2.0")
491
+ self._post_prompt_llm_params['frequency_penalty'] = frequency_penalty
492
+
373
493
  return self
@@ -45,6 +45,53 @@ class SkillManager:
45
45
  self.logger.error(error_msg)
46
46
  return False, error_msg
47
47
 
48
+ # Validate that the skill has a proper parameter schema
49
+ if not hasattr(skill_class, 'get_parameter_schema') or not callable(getattr(skill_class, 'get_parameter_schema')):
50
+ error_msg = f"Skill '{skill_name}' must have get_parameter_schema() classmethod"
51
+ self.logger.error(error_msg)
52
+ return False, error_msg
53
+
54
+ try:
55
+ # Validate the parameter schema
56
+ schema = skill_class.get_parameter_schema()
57
+ if not isinstance(schema, dict):
58
+ error_msg = f"Skill '{skill_name}'.get_parameter_schema() must return a dictionary"
59
+ self.logger.error(error_msg)
60
+ return False, error_msg
61
+
62
+ # Ensure it's not an empty schema
63
+ if not schema:
64
+ error_msg = f"Skill '{skill_name}'.get_parameter_schema() returned empty dictionary"
65
+ self.logger.error(error_msg)
66
+ return False, error_msg
67
+
68
+ # Check if the skill has overridden the method
69
+ from signalwire_agents.core.skill_base import SkillBase
70
+ skill_method = getattr(skill_class, 'get_parameter_schema', None)
71
+ base_method = getattr(SkillBase, 'get_parameter_schema', None)
72
+
73
+ if skill_method and base_method:
74
+ # For class methods, check the underlying function
75
+ skill_func = skill_method.__func__ if hasattr(skill_method, '__func__') else skill_method
76
+ base_func = base_method.__func__ if hasattr(base_method, '__func__') else base_method
77
+
78
+ if skill_func is base_func:
79
+ # Get base schema to check if skill added any parameters
80
+ base_schema = SkillBase.get_parameter_schema()
81
+ if set(schema.keys()) == set(base_schema.keys()):
82
+ error_msg = f"Skill '{skill_name}' must override get_parameter_schema() to define its specific parameters"
83
+ self.logger.error(error_msg)
84
+ return False, error_msg
85
+
86
+ except AttributeError as e:
87
+ error_msg = f"Skill '{skill_name}' must properly implement get_parameter_schema() classmethod"
88
+ self.logger.error(error_msg)
89
+ return False, error_msg
90
+ except Exception as e:
91
+ error_msg = f"Skill '{skill_name}'.get_parameter_schema() failed: {e}"
92
+ self.logger.error(error_msg)
93
+ return False, error_msg
94
+
48
95
  try:
49
96
  # Create skill instance with parameters to get the instance key
50
97
  skill_instance = skill_class(self.agent, params)