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.
- {signalwire_agents-0.1.54/signalwire_agents.egg-info → signalwire_agents-1.0.0}/PKG-INFO +1 -1
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/pyproject.toml +1 -1
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/__init__.py +1 -1
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/build_search.py +3 -3
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/pgvector_backend.py +17 -11
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/query_processor.py +28 -31
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/search_engine.py +8 -8
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/search_service.py +44 -11
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/native_vector_search/skill.py +16 -10
- signalwire_agents-1.0.0/signalwire_agents/skills/web_search/skill.py +739 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0/signalwire_agents.egg-info}/PKG-INFO +1 -1
- signalwire_agents-0.1.54/signalwire_agents/skills/web_search/skill.py +0 -344
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/LICENSE +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/README.md +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/setup.cfg +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/setup.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/agent_server.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/agents/bedrock.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/config.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/core/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/core/agent_loader.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/core/argparse_helpers.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/core/dynamic_config.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/core/service_loader.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/execution/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/execution/datamap_exec.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/execution/webhook_exec.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/output/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/output/output_formatter.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/output/swml_dump.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/simulation/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/simulation/data_generation.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/simulation/data_overrides.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/simulation/mock_env.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/swaig_test_wrapper.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/test_swaig.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/cli/types.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/config/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/deployment/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/deployment/handlers/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/prompt/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/prompt/manager.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/routing/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/security/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/swml/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/tools/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/tools/decorator.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent/tools/registry.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/agent_base.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/auth_handler.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/config_loader.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/contexts.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/data_map.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/function_result.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/logging_config.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/mixins/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/mixins/ai_config_mixin.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/mixins/auth_mixin.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/mixins/prompt_mixin.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/mixins/serverless_mixin.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/mixins/skill_mixin.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/mixins/state_mixin.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/mixins/tool_mixin.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/mixins/web_mixin.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/pom_builder.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/security/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/security/session_manager.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/security_config.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/skill_base.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/skill_manager.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/swaig_function.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/swml_builder.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/swml_handler.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/swml_renderer.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/core/swml_service.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/prefabs/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/prefabs/concierge.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/prefabs/faq_bot.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/prefabs/info_gatherer.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/prefabs/receptionist.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/prefabs/survey.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/schema.json +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/document_processor.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/index_builder.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/migration.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/models.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/README.md +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/api_ninjas_trivia/README.md +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/api_ninjas_trivia/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/api_ninjas_trivia/skill.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/datasphere/README.md +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/datasphere/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/datasphere/skill.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/datasphere_serverless/README.md +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/datasphere_serverless/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/datasphere_serverless/skill.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/datetime/README.md +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/datetime/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/datetime/skill.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/joke/README.md +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/joke/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/joke/skill.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/math/README.md +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/math/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/math/skill.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/mcp_gateway/README.md +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/mcp_gateway/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/mcp_gateway/skill.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/native_vector_search/README.md +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/native_vector_search/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/play_background_file/README.md +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/play_background_file/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/play_background_file/skill.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/registry.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/spider/README.md +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/spider/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/spider/skill.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/swml_transfer/README.md +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/swml_transfer/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/swml_transfer/skill.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/weather_api/README.md +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/weather_api/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/weather_api/skill.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/web_search/README.md +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/web_search/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/wikipedia_search/README.md +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/wikipedia_search/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/skills/wikipedia_search/skill.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/utils/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/utils/pom_utils.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/utils/schema_utils.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/utils/token_generators.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/utils/validators.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/web/__init__.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/web/web_service.py +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents.egg-info/SOURCES.txt +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents.egg-info/dependency_links.txt +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents.egg-info/entry_points.txt +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents.egg-info/requires.txt +0 -0
- {signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents.egg-info/top_level.txt +0 -0
|
@@ -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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
'
|
|
1121
|
+
'similarity_threshold': args.similarity_threshold
|
|
1122
1122
|
}
|
|
1123
1123
|
|
|
1124
1124
|
if args.tags:
|
{signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/pgvector_backend.py
RENAMED
|
@@ -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,
|
|
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
|
-
|
|
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'] >=
|
|
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
|
{signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/query_processor.py
RENAMED
|
@@ -77,62 +77,59 @@ def load_spacy_model(language: str):
|
|
|
77
77
|
_spacy_warning_shown = True
|
|
78
78
|
return None
|
|
79
79
|
|
|
80
|
-
#
|
|
81
|
-
|
|
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
|
-
"""
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
|
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
|
-
#
|
|
108
|
-
if
|
|
109
|
-
|
|
110
|
-
|
|
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
|
|
120
|
-
|
|
121
|
-
|
|
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
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
"""
|
{signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/search_engine.py
RENAMED
|
@@ -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,
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
|
177
|
+
if similarity_threshold > 0:
|
|
178
178
|
final_results = [r for r in final_results
|
|
179
|
-
if r.get('vector_distance', 0) <=
|
|
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
|
-
|
|
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,
|
|
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:
|
{signalwire_agents-0.1.54 → signalwire_agents-1.0.0}/signalwire_agents/search/search_service.py
RENAMED
|
@@ -50,7 +50,7 @@ if BaseModel:
|
|
|
50
50
|
query: str
|
|
51
51
|
index_name: str = "default"
|
|
52
52
|
count: int = 3
|
|
53
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
302
|
-
#
|
|
303
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
"
|
|
77
|
+
"similarity_threshold": {
|
|
78
78
|
"type": "number",
|
|
79
|
-
"description": "
|
|
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.
|
|
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
|
-
|
|
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
|
-
"
|
|
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
|
-
|
|
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', []):
|