signalwire-agents 0.1.54__tar.gz → 1.0.0__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 (145) hide show
  1. {signalwire_agents-0.1.54/signalwire_agents.egg-info → signalwire_agents-1.0.0}/PKG-INFO +1 -1
  2. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/pyproject.toml +1 -1
  3. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/__init__.py +1 -1
  4. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/build_search.py +3 -3
  5. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/pgvector_backend.py +17 -11
  6. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/query_processor.py +28 -31
  7. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/search_engine.py +8 -8
  8. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/search_service.py +44 -11
  9. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/native_vector_search/skill.py +16 -10
  10. signalwire_agents-1.0.0/signalwire_agents/skills/web_search/skill.py +739 -0
  11. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0/signalwire_agents.egg-info}/PKG-INFO +1 -1
  12. signalwire_agents-0.1.54/signalwire_agents/skills/web_search/skill.py +0 -344
  13. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/LICENSE +0 -0
  14. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/README.md +0 -0
  15. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/setup.cfg +0 -0
  16. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/setup.py +0 -0
  17. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/agent_server.py +0 -0
  18. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/agents/bedrock.py +0 -0
  19. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/__init__.py +0 -0
  20. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/config.py +0 -0
  21. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/core/__init__.py +0 -0
  22. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/core/agent_loader.py +0 -0
  23. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/core/argparse_helpers.py +0 -0
  24. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/core/dynamic_config.py +0 -0
  25. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/core/service_loader.py +0 -0
  26. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/execution/__init__.py +0 -0
  27. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/execution/datamap_exec.py +0 -0
  28. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/execution/webhook_exec.py +0 -0
  29. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/output/__init__.py +0 -0
  30. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/output/output_formatter.py +0 -0
  31. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/output/swml_dump.py +0 -0
  32. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/simulation/__init__.py +0 -0
  33. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/simulation/data_generation.py +0 -0
  34. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/simulation/data_overrides.py +0 -0
  35. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/simulation/mock_env.py +0 -0
  36. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/swaig_test_wrapper.py +0 -0
  37. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/test_swaig.py +0 -0
  38. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/types.py +0 -0
  39. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/__init__.py +0 -0
  40. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/__init__.py +0 -0
  41. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/config/__init__.py +0 -0
  42. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/deployment/__init__.py +0 -0
  43. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/deployment/handlers/__init__.py +0 -0
  44. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/prompt/__init__.py +0 -0
  45. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/prompt/manager.py +0 -0
  46. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/routing/__init__.py +0 -0
  47. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/security/__init__.py +0 -0
  48. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/swml/__init__.py +0 -0
  49. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/tools/__init__.py +0 -0
  50. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/tools/decorator.py +0 -0
  51. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/tools/registry.py +0 -0
  52. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent_base.py +0 -0
  53. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/auth_handler.py +0 -0
  54. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/config_loader.py +0 -0
  55. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/contexts.py +0 -0
  56. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/data_map.py +0 -0
  57. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/function_result.py +0 -0
  58. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/logging_config.py +0 -0
  59. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/mixins/__init__.py +0 -0
  60. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/mixins/ai_config_mixin.py +0 -0
  61. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/mixins/auth_mixin.py +0 -0
  62. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/mixins/prompt_mixin.py +0 -0
  63. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/mixins/serverless_mixin.py +0 -0
  64. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/mixins/skill_mixin.py +0 -0
  65. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/mixins/state_mixin.py +0 -0
  66. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/mixins/tool_mixin.py +0 -0
  67. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/mixins/web_mixin.py +0 -0
  68. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/pom_builder.py +0 -0
  69. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/security/__init__.py +0 -0
  70. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/security/session_manager.py +0 -0
  71. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/security_config.py +0 -0
  72. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/skill_base.py +0 -0
  73. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/skill_manager.py +0 -0
  74. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/swaig_function.py +0 -0
  75. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/swml_builder.py +0 -0
  76. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/swml_handler.py +0 -0
  77. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/swml_renderer.py +0 -0
  78. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/swml_service.py +0 -0
  79. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/prefabs/__init__.py +0 -0
  80. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/prefabs/concierge.py +0 -0
  81. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/prefabs/faq_bot.py +0 -0
  82. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/prefabs/info_gatherer.py +0 -0
  83. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/prefabs/receptionist.py +0 -0
  84. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/prefabs/survey.py +0 -0
  85. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/schema.json +0 -0
  86. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/__init__.py +0 -0
  87. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/document_processor.py +0 -0
  88. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/index_builder.py +0 -0
  89. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/migration.py +0 -0
  90. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/models.py +0 -0
  91. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/README.md +0 -0
  92. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/__init__.py +0 -0
  93. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/api_ninjas_trivia/README.md +0 -0
  94. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/api_ninjas_trivia/__init__.py +0 -0
  95. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/api_ninjas_trivia/skill.py +0 -0
  96. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/datasphere/README.md +0 -0
  97. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/datasphere/__init__.py +0 -0
  98. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/datasphere/skill.py +0 -0
  99. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/datasphere_serverless/README.md +0 -0
  100. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/datasphere_serverless/__init__.py +0 -0
  101. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/datasphere_serverless/skill.py +0 -0
  102. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/datetime/README.md +0 -0
  103. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/datetime/__init__.py +0 -0
  104. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/datetime/skill.py +0 -0
  105. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/joke/README.md +0 -0
  106. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/joke/__init__.py +0 -0
  107. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/joke/skill.py +0 -0
  108. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/math/README.md +0 -0
  109. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/math/__init__.py +0 -0
  110. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/math/skill.py +0 -0
  111. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/mcp_gateway/README.md +0 -0
  112. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/mcp_gateway/__init__.py +0 -0
  113. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/mcp_gateway/skill.py +0 -0
  114. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/native_vector_search/README.md +0 -0
  115. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/native_vector_search/__init__.py +0 -0
  116. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/play_background_file/README.md +0 -0
  117. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/play_background_file/__init__.py +0 -0
  118. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/play_background_file/skill.py +0 -0
  119. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/registry.py +0 -0
  120. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/spider/README.md +0 -0
  121. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/spider/__init__.py +0 -0
  122. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/spider/skill.py +0 -0
  123. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/swml_transfer/README.md +0 -0
  124. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/swml_transfer/__init__.py +0 -0
  125. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/swml_transfer/skill.py +0 -0
  126. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/weather_api/README.md +0 -0
  127. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/weather_api/__init__.py +0 -0
  128. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/weather_api/skill.py +0 -0
  129. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/web_search/README.md +0 -0
  130. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/web_search/__init__.py +0 -0
  131. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/wikipedia_search/README.md +0 -0
  132. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/wikipedia_search/__init__.py +0 -0
  133. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/wikipedia_search/skill.py +0 -0
  134. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/utils/__init__.py +0 -0
  135. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/utils/pom_utils.py +0 -0
  136. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/utils/schema_utils.py +0 -0
  137. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/utils/token_generators.py +0 -0
  138. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/utils/validators.py +0 -0
  139. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/web/__init__.py +0 -0
  140. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/web/web_service.py +0 -0
  141. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents.egg-info/SOURCES.txt +0 -0
  142. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents.egg-info/dependency_links.txt +0 -0
  143. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents.egg-info/entry_points.txt +0 -0
  144. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents.egg-info/requires.txt +0 -0
  145. {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/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.54
3
+ Version: 1.0.0
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 = "0.1.54"
7
+ version = "1.0.0"
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__ = "0.1.54"
21
+ __version__ = "1.0.0"
22
22
 
23
23
  # Import core classes for easier access
24
24
  from .core.agent_base import AgentBase
@@ -793,7 +793,7 @@ def search_command():
793
793
  query_vector=enhanced.get('vector'),
794
794
  enhanced_text=enhanced.get('enhanced_text', query),
795
795
  count=args.count,
796
- distance_threshold=args.distance_threshold,
796
+ similarity_threshold=args.similarity_threshold,
797
797
  tags=tags,
798
798
  keyword_weight=args.keyword_weight,
799
799
  original_query=query
@@ -871,7 +871,7 @@ def search_command():
871
871
  query_vector=enhanced.get('vector'),
872
872
  enhanced_text=enhanced.get('enhanced_text', args.query),
873
873
  count=args.count,
874
- distance_threshold=args.distance_threshold,
874
+ similarity_threshold=args.similarity_threshold,
875
875
  tags=tags,
876
876
  keyword_weight=args.keyword_weight,
877
877
  original_query=args.query # Pass original for exact match boosting
@@ -1118,7 +1118,7 @@ def remote_command():
1118
1118
  'query': args.query,
1119
1119
  'index_name': args.index_name,
1120
1120
  'count': args.count,
1121
- 'distance_threshold': args.distance_threshold
1121
+ 'similarity_threshold': args.similarity_threshold
1122
1122
  }
1123
1123
 
1124
1124
  if args.tags:
@@ -423,7 +423,7 @@ class PgVectorSearchBackend:
423
423
  return {}
424
424
 
425
425
  def search(self, query_vector: List[float], enhanced_text: str,
426
- count: int = 5, distance_threshold: float = 0.0,
426
+ count: int = 5, similarity_threshold: float = 0.0,
427
427
  tags: Optional[List[str]] = None,
428
428
  keyword_weight: Optional[float] = None) -> List[Dict[str, Any]]:
429
429
  """
@@ -433,7 +433,7 @@ class PgVectorSearchBackend:
433
433
  query_vector: Embedding vector for the query
434
434
  enhanced_text: Processed query text for keyword search
435
435
  count: Number of results to return
436
- distance_threshold: Minimum similarity score
436
+ similarity_threshold: Minimum similarity score
437
437
  tags: Filter by tags
438
438
  keyword_weight: Manual keyword weight (0.0-1.0). If None, uses default weighting
439
439
 
@@ -447,33 +447,39 @@ class PgVectorSearchBackend:
447
447
 
448
448
  # Vector search
449
449
  vector_results = self._vector_search(query_vector, count * 2, tags)
450
-
450
+
451
451
  # Keyword search
452
452
  keyword_results = self._keyword_search(enhanced_text, count * 2, tags)
453
-
453
+
454
454
  # Metadata search
455
455
  metadata_results = self._metadata_search(query_terms, count * 2, tags)
456
-
456
+
457
+
457
458
  # Merge all results
458
459
  merged_results = self._merge_all_results(vector_results, keyword_results, metadata_results, keyword_weight)
459
-
460
+
461
+
460
462
  # Filter by distance threshold
461
463
  filtered_results = [
462
- r for r in merged_results
463
- if r['score'] >= distance_threshold
464
+ r for r in merged_results
465
+ if r['score'] >= similarity_threshold
464
466
  ]
467
+
465
468
 
466
469
  # Ensure 'score' field exists for CLI compatibility
467
470
  for r in filtered_results:
468
471
  if 'score' not in r:
469
472
  r['score'] = r.get('final_score', 0.0)
470
-
473
+
471
474
  return filtered_results[:count]
472
475
 
473
476
  def _vector_search(self, query_vector: List[float], count: int,
474
477
  tags: Optional[List[str]] = None) -> List[Dict[str, Any]]:
475
478
  """Perform vector similarity search"""
476
479
  with self.conn.cursor() as cursor:
480
+ # Set ef_search for HNSW index to ensure we get enough results
481
+ # ef_search must be at least as large as the LIMIT
482
+ cursor.execute(f"SET LOCAL hnsw.ef_search = {max(count, 40)}")
477
483
  # Build query
478
484
  query = f"""
479
485
  SELECT id, content, filename, section, tags, metadata,
@@ -491,9 +497,9 @@ class PgVectorSearchBackend:
491
497
 
492
498
  query += " ORDER BY embedding <=> %s::vector LIMIT %s"
493
499
  params.extend([query_vector, count])
494
-
500
+
495
501
  cursor.execute(query, params)
496
-
502
+
497
503
  results = []
498
504
  for row in cursor.fetchall():
499
505
  chunk_id, content, filename, section, tags_json, metadata_json, similarity = row
@@ -77,62 +77,59 @@ def load_spacy_model(language: str):
77
77
  _spacy_warning_shown = True
78
78
  return None
79
79
 
80
- # Global model cache
81
- _cached_model = None
80
+ # Model cache - stores multiple models by name
81
+ _model_cache = {} # model_name -> SentenceTransformer instance
82
82
  _model_lock = None
83
83
 
84
84
  def set_global_model(model):
85
- """Set the global cached model instance"""
86
- global _cached_model
87
- _cached_model = model
88
- logger.info("Global model set for query processor")
85
+ """Legacy function - adds model to cache instead of setting globally"""
86
+ if model and hasattr(model, 'model_name'):
87
+ _model_cache[model.model_name] = model
88
+ logger.info(f"Model added to cache: {model.model_name}")
89
89
 
90
90
  def _get_cached_model(model_name: str = None):
91
91
  """Get or create cached sentence transformer model
92
-
92
+
93
93
  Args:
94
94
  model_name: Optional model name. If not provided, uses default.
95
95
  """
96
- global _cached_model, _model_lock
97
-
96
+ global _model_cache, _model_lock
97
+
98
98
  # Default model
99
99
  if model_name is None:
100
100
  model_name = 'sentence-transformers/all-mpnet-base-v2'
101
-
101
+
102
102
  # Initialize lock if needed
103
103
  if _model_lock is None:
104
104
  import threading
105
105
  _model_lock = threading.Lock()
106
-
107
- # Return cached model if available and same model
108
- if _cached_model is not None:
109
- # Check if it's the same model (simple check - assumes model has a name attribute)
110
- try:
111
- if hasattr(_cached_model, 'model_name') and _cached_model.model_name == model_name:
112
- return _cached_model
113
- except:
114
- pass
115
-
106
+
107
+ # Check if model is already in cache
108
+ if model_name in _model_cache:
109
+ return _model_cache[model_name]
110
+
116
111
  # Load model with lock to prevent race conditions
117
112
  with _model_lock:
118
113
  # Double check in case another thread loaded it
119
- if _cached_model is not None:
120
- try:
121
- if hasattr(_cached_model, 'model_name') and _cached_model.model_name == model_name:
122
- return _cached_model
123
- except:
124
- pass
125
-
114
+ if model_name in _model_cache:
115
+ return _model_cache[model_name]
116
+
126
117
  try:
127
118
  from sentence_transformers import SentenceTransformer
128
119
  logger.info(f"Loading sentence transformer model: {model_name}")
129
- _cached_model = SentenceTransformer(model_name)
130
- _cached_model.model_name = model_name # Store for later comparison
131
- logger.info("Model loaded and cached successfully")
132
- return _cached_model
120
+ model = SentenceTransformer(model_name)
121
+ # Store the model name for identification
122
+ model.model_name = model_name
123
+ # Add to cache
124
+ _model_cache[model_name] = model
125
+ logger.info(f"Successfully loaded and cached model: {model_name}")
126
+ return model
133
127
  except ImportError:
134
128
  logger.error("sentence-transformers not available. Cannot load model.")
135
129
  return None
130
+ except Exception as e:
131
+ logger.error(f"Failed to load model {model_name}: {e}")
132
+ return None
136
133
 
137
134
  def vectorize_query(query: str, model=None, model_name: str = None):
138
135
  """
@@ -73,7 +73,7 @@ class SearchEngine:
73
73
  return {}
74
74
 
75
75
  def search(self, query_vector: List[float], enhanced_text: str,
76
- count: int = 3, distance_threshold: float = 0.0,
76
+ count: int = 3, similarity_threshold: float = 0.0,
77
77
  tags: Optional[List[str]] = None,
78
78
  keyword_weight: Optional[float] = None,
79
79
  original_query: Optional[str] = None) -> List[Dict[str, Any]]:
@@ -89,7 +89,7 @@ class SearchEngine:
89
89
  query_vector: Embedding vector for the query
90
90
  enhanced_text: Processed query text for keyword search
91
91
  count: Number of results to return
92
- distance_threshold: Minimum similarity score
92
+ similarity_threshold: Minimum similarity score
93
93
  tags: Filter by tags
94
94
  keyword_weight: Optional manual weight for keyword vs vector
95
95
  original_query: Original query for exact matching
@@ -100,7 +100,7 @@ class SearchEngine:
100
100
 
101
101
  # Use pgvector backend if available
102
102
  if self.backend == 'pgvector':
103
- return self._backend.search(query_vector, enhanced_text, count, distance_threshold, tags, keyword_weight)
103
+ return self._backend.search(query_vector, enhanced_text, count, similarity_threshold, tags, keyword_weight)
104
104
 
105
105
  # Check for numpy/sklearn availability
106
106
  if not np or not cosine_similarity:
@@ -161,7 +161,7 @@ class SearchEngine:
161
161
  final_results = []
162
162
  for chunk_id, candidate in candidates.items():
163
163
  # Calculate final score combining all signals
164
- score = self._calculate_combined_score(candidate, distance_threshold)
164
+ score = self._calculate_combined_score(candidate, similarity_threshold)
165
165
  candidate['final_score'] = score
166
166
  final_results.append(candidate)
167
167
 
@@ -174,9 +174,9 @@ class SearchEngine:
174
174
  if any(tag in r['metadata'].get('tags', []) for tag in tags)]
175
175
 
176
176
  # Apply distance threshold as final filter (soft threshold already applied in scoring)
177
- if distance_threshold > 0:
177
+ if similarity_threshold > 0:
178
178
  final_results = [r for r in final_results
179
- if r.get('vector_distance', 0) <= distance_threshold * 1.5
179
+ if r.get('vector_distance', 0) <= similarity_threshold * 1.5
180
180
  or 'vector' not in r.get('sources', {})]
181
181
 
182
182
  # Boost exact matches if we have the original query
@@ -987,7 +987,7 @@ class SearchEngine:
987
987
  return []
988
988
 
989
989
  def _add_vector_scores_to_candidates(self, candidates: Dict[str, Dict], query_vector: NDArray,
990
- distance_threshold: float):
990
+ similarity_threshold: float):
991
991
  """Add vector similarity scores to existing candidates"""
992
992
  if not candidates or not np:
993
993
  return
@@ -1034,7 +1034,7 @@ class SearchEngine:
1034
1034
  except Exception as e:
1035
1035
  logger.error(f"Error in vector re-ranking: {e}")
1036
1036
 
1037
- def _calculate_combined_score(self, candidate: Dict, distance_threshold: float) -> float:
1037
+ def _calculate_combined_score(self, candidate: Dict, similarity_threshold: float) -> float:
1038
1038
  """Calculate final score with hybrid vector + metadata weighting
1039
1039
 
1040
1040
  Hybrid approach:
@@ -50,7 +50,7 @@ if BaseModel:
50
50
  query: str
51
51
  index_name: str = "default"
52
52
  count: int = 3
53
- distance: float = 0.0
53
+ similarity_threshold: float = 0.0
54
54
  tags: Optional[List[str]] = None
55
55
  language: Optional[str] = None
56
56
 
@@ -65,13 +65,13 @@ if BaseModel:
65
65
  else:
66
66
  # Fallback classes when FastAPI is not available
67
67
  class SearchRequest:
68
- def __init__(self, query: str, index_name: str = "default", count: int = 3,
69
- distance: float = 0.0, tags: Optional[List[str]] = None,
68
+ def __init__(self, query: str, index_name: str = "default", count: int = 3,
69
+ similarity_threshold: float = 0.0, tags: Optional[List[str]] = None,
70
70
  language: Optional[str] = None):
71
71
  self.query = query
72
72
  self.index_name = index_name
73
73
  self.count = count
74
- self.distance = distance
74
+ self.similarity_threshold = similarity_threshold
75
75
  self.tags = tags
76
76
  self.language = language
77
77
 
@@ -298,16 +298,41 @@ class SearchService:
298
298
  def _load_resources(self):
299
299
  """Load embedding model and search indexes"""
300
300
  if self.backend == 'pgvector':
301
- # For pgvector, we don't need to load a model locally
302
- # The embeddings are already stored in the database
303
- # Load search engines for each collection
301
+ # For pgvector, we need to load models for query embeddings
302
+ # Different collections might use different models
303
+ self.models = {} # model_name -> SentenceTransformer instance
304
+ self.collection_models = {} # collection_name -> model_name
305
+
306
+ # Load search engines for each collection and their models
304
307
  for collection_name in self.indexes.keys():
305
308
  try:
306
- self.search_engines[collection_name] = SearchEngine(
309
+ search_engine = SearchEngine(
307
310
  backend='pgvector',
308
311
  connection_string=self.connection_string,
309
312
  collection_name=collection_name
310
313
  )
314
+ self.search_engines[collection_name] = search_engine
315
+
316
+ # Get the model name from the collection config
317
+ model_name = search_engine.config.get('model_name')
318
+ if model_name:
319
+ self.collection_models[collection_name] = model_name
320
+
321
+ # Load the model if we haven't already
322
+ if model_name not in self.models:
323
+ logger.info(f"Loading model {model_name} for collection {collection_name}")
324
+ try:
325
+ model = SentenceTransformer(model_name)
326
+ model.model_name = model_name # Store for cache comparison
327
+ self.models[model_name] = model
328
+ except Exception as e:
329
+ logger.error(f"Failed to load model {model_name}: {e}")
330
+ raise
331
+ else:
332
+ logger.info(f"Using cached model {model_name} for collection {collection_name}")
333
+ else:
334
+ logger.warning(f"No model_name in config for collection {collection_name}")
335
+
311
336
  logger.info(f"Loaded pgvector collection: {collection_name}")
312
337
  except Exception as e:
313
338
  logger.error(f"Error loading pgvector collection {collection_name}: {e}")
@@ -372,13 +397,21 @@ class SearchService:
372
397
  return self._query_cache[cache_key]
373
398
 
374
399
  search_engine = self.search_engines[request.index_name]
375
-
400
+
401
+ # For pgvector, set the correct model globally before query processing
402
+ if self.backend == 'pgvector' and hasattr(self, 'collection_models'):
403
+ collection_model_name = self.collection_models.get(request.index_name)
404
+ if collection_model_name and collection_model_name in self.models:
405
+ # Set this model globally so query processor uses it
406
+ set_global_model(self.models[collection_model_name])
407
+ logger.debug(f"Set global model to {collection_model_name} for collection {request.index_name}")
408
+
376
409
  # Get model name from the search engine config
377
410
  model_name = None
378
411
  if hasattr(search_engine, 'config') and search_engine.config:
379
412
  # pgvector uses 'model_name', sqlite uses 'embedding_model'
380
413
  model_name = search_engine.config.get('model_name') or search_engine.config.get('embedding_model')
381
-
414
+
382
415
  # Enhance query
383
416
  try:
384
417
  enhanced = preprocess_query(
@@ -401,7 +434,7 @@ class SearchService:
401
434
  query_vector=enhanced.get('vector', []),
402
435
  enhanced_text=enhanced['enhanced_text'],
403
436
  count=request.count,
404
- distance_threshold=request.distance,
437
+ similarity_threshold=request.similarity_threshold,
405
438
  tags=request.tags
406
439
  )
407
440
  except Exception as e:
@@ -74,9 +74,9 @@ class NativeVectorSearchSkill(SkillBase):
74
74
  "minimum": 1,
75
75
  "maximum": 20
76
76
  },
77
- "distance_threshold": {
77
+ "similarity_threshold": {
78
78
  "type": "number",
79
- "description": "Maximum distance threshold for results (0.0 = no limit)",
79
+ "description": "Minimum similarity score for results (0.0 = no limit, 1.0 = exact match)",
80
80
  "default": 0.0,
81
81
  "required": False,
82
82
  "minimum": 0.0,
@@ -250,7 +250,7 @@ class NativeVectorSearchSkill(SkillBase):
250
250
  self.build_index = self.params.get('build_index', False)
251
251
  self.source_dir = self.params.get('source_dir')
252
252
  self.count = self.params.get('count', 5)
253
- self.distance_threshold = self.params.get('distance_threshold', 0.0)
253
+ self.similarity_threshold = self.params.get('similarity_threshold', 0.0)
254
254
  self.tags = self.params.get('tags', [])
255
255
  self.no_results_message = self.params.get(
256
256
  'no_results_message',
@@ -550,9 +550,12 @@ class NativeVectorSearchSkill(SkillBase):
550
550
 
551
551
  try:
552
552
  # Perform search (local or remote)
553
+ self.logger.info(f"DEBUG: use_remote={self.use_remote}, remote_base_url={self.remote_base_url}")
553
554
  if self.use_remote:
554
555
  # For remote searches, let the server handle query preprocessing
556
+ self.logger.info(f"DEBUG: Calling _search_remote with query='{query}', count={count}")
555
557
  results = self._search_remote(query, None, count)
558
+ self.logger.info(f"DEBUG: _search_remote returned {len(results)} results")
556
559
  else:
557
560
  # For local searches, preprocess the query locally
558
561
  from signalwire_agents.search.query_processor import preprocess_query
@@ -575,7 +578,7 @@ class NativeVectorSearchSkill(SkillBase):
575
578
  query_vector=enhanced.get('vector', []),
576
579
  enhanced_text=enhanced['enhanced_text'],
577
580
  count=count,
578
- distance_threshold=self.distance_threshold,
581
+ similarity_threshold=self.similarity_threshold,
579
582
  tags=self.tags,
580
583
  keyword_weight=self.keyword_weight,
581
584
  original_query=query # Pass original for exact match boosting
@@ -721,20 +724,23 @@ class NativeVectorSearchSkill(SkillBase):
721
724
  "query": query,
722
725
  "index_name": self.index_name,
723
726
  "count": count,
724
- "distance": self.distance_threshold,
725
- "tags": self.tags,
726
- "language": "en"
727
+ "similarity_threshold": self.similarity_threshold,
728
+ "tags": self.tags
727
729
  }
728
-
730
+
731
+ url = f"{self.remote_base_url}/search"
732
+ self.logger.info(f"DEBUG: Sending POST to {url} with request: {search_request}")
733
+
729
734
  response = requests.post(
730
- f"{self.remote_base_url}/search",
735
+ url,
731
736
  json=search_request,
732
737
  auth=self.remote_auth,
733
738
  timeout=30
734
739
  )
735
-
740
+
736
741
  if response.status_code == 200:
737
742
  data = response.json()
743
+ self.logger.info(f"DEBUG: Got response with {len(data.get('results', []))} results")
738
744
  # Convert remote response format to local format
739
745
  results = []
740
746
  for result in data.get('results', []):