signalwire-agents 0.1.47__py3-none-any.whl → 0.1.49__py3-none-any.whl
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/__init__.py +1 -1
- signalwire_agents/cli/build_search.py +516 -12
- signalwire_agents/core/mixins/ai_config_mixin.py +4 -0
- signalwire_agents/schema.json +57 -1
- signalwire_agents/search/__init__.py +7 -1
- signalwire_agents/search/document_processor.py +11 -8
- signalwire_agents/search/index_builder.py +112 -13
- signalwire_agents/search/migration.py +418 -0
- signalwire_agents/search/models.py +30 -0
- signalwire_agents/search/pgvector_backend.py +236 -13
- signalwire_agents/search/query_processor.py +87 -9
- signalwire_agents/search/search_engine.py +835 -31
- signalwire_agents/search/search_service.py +56 -6
- signalwire_agents/skills/native_vector_search/skill.py +208 -33
- {signalwire_agents-0.1.47.dist-info → signalwire_agents-0.1.49.dist-info}/METADATA +1 -1
- {signalwire_agents-0.1.47.dist-info → signalwire_agents-0.1.49.dist-info}/RECORD +20 -18
- {signalwire_agents-0.1.47.dist-info → signalwire_agents-0.1.49.dist-info}/WHEEL +0 -0
- {signalwire_agents-0.1.47.dist-info → signalwire_agents-0.1.49.dist-info}/entry_points.txt +0 -0
- {signalwire_agents-0.1.47.dist-info → signalwire_agents-0.1.49.dist-info}/licenses/LICENSE +0 -0
- {signalwire_agents-0.1.47.dist-info → signalwire_agents-0.1.49.dist-info}/top_level.txt +0 -0
@@ -31,7 +31,7 @@ try:
|
|
31
31
|
except ImportError:
|
32
32
|
SentenceTransformer = None
|
33
33
|
|
34
|
-
from .query_processor import preprocess_query
|
34
|
+
from .query_processor import preprocess_query, set_global_model
|
35
35
|
from .search_engine import SearchEngine
|
36
36
|
from signalwire_agents.core.security_config import SecurityConfig
|
37
37
|
from signalwire_agents.core.config_loader import ConfigLoader
|
@@ -39,6 +39,11 @@ from signalwire_agents.core.logging_config import get_logger
|
|
39
39
|
|
40
40
|
logger = get_logger("search_service")
|
41
41
|
|
42
|
+
# Simple LRU cache for query results
|
43
|
+
from functools import lru_cache
|
44
|
+
import hashlib
|
45
|
+
import json
|
46
|
+
|
42
47
|
# Pydantic models for API
|
43
48
|
if BaseModel:
|
44
49
|
class SearchRequest(BaseModel):
|
@@ -81,6 +86,17 @@ else:
|
|
81
86
|
self.results = results
|
82
87
|
self.query_analysis = query_analysis
|
83
88
|
|
89
|
+
def _cache_key(query: str, index_name: str, count: int, tags: Optional[List[str]] = None) -> str:
|
90
|
+
"""Generate cache key for query results"""
|
91
|
+
key_data = {
|
92
|
+
'query': query.lower().strip(),
|
93
|
+
'index': index_name,
|
94
|
+
'count': count,
|
95
|
+
'tags': sorted(tags) if tags else []
|
96
|
+
}
|
97
|
+
key_str = json.dumps(key_data, sort_keys=True)
|
98
|
+
return hashlib.md5(key_str.encode()).hexdigest()
|
99
|
+
|
84
100
|
class SearchService:
|
85
101
|
"""Local search service with HTTP API supporting both SQLite and pgvector backends"""
|
86
102
|
|
@@ -102,6 +118,8 @@ class SearchService:
|
|
102
118
|
|
103
119
|
self.search_engines = {}
|
104
120
|
self.model = None
|
121
|
+
self._query_cache = {} # Simple query result cache
|
122
|
+
self._cache_size = 100 # Max number of cached queries
|
105
123
|
|
106
124
|
# Load security configuration with optional config file
|
107
125
|
self.security = SecurityConfig(config_file=config_file, service_name="search")
|
@@ -270,7 +288,11 @@ class SearchService:
|
|
270
288
|
else:
|
271
289
|
# SQLite backend
|
272
290
|
self.indexes[index_name] = index_path
|
273
|
-
self.search_engines[index_name] = SearchEngine(
|
291
|
+
self.search_engines[index_name] = SearchEngine(
|
292
|
+
backend='sqlite',
|
293
|
+
index_path=index_path,
|
294
|
+
model=self.model
|
295
|
+
)
|
274
296
|
return {"status": "reloaded", "index": index_name, "backend": "sqlite"}
|
275
297
|
|
276
298
|
def _load_resources(self):
|
@@ -298,6 +320,8 @@ class SearchService:
|
|
298
320
|
model_name = self._get_model_name(sample_index)
|
299
321
|
try:
|
300
322
|
self.model = SentenceTransformer(model_name)
|
323
|
+
# Set the global model for query processor to avoid reloading
|
324
|
+
set_global_model(self.model)
|
301
325
|
except Exception as e:
|
302
326
|
logger.warning(f"Could not load sentence transformer model: {e}")
|
303
327
|
self.model = None
|
@@ -305,7 +329,11 @@ class SearchService:
|
|
305
329
|
# Load search engines for each index
|
306
330
|
for index_name, index_path in self.indexes.items():
|
307
331
|
try:
|
308
|
-
self.search_engines[index_name] = SearchEngine(
|
332
|
+
self.search_engines[index_name] = SearchEngine(
|
333
|
+
backend='sqlite',
|
334
|
+
index_path=index_path,
|
335
|
+
model=self.model
|
336
|
+
)
|
309
337
|
except Exception as e:
|
310
338
|
logger.error(f"Error loading search engine for {index_name}: {e}")
|
311
339
|
|
@@ -330,21 +358,34 @@ class SearchService:
|
|
330
358
|
return 'sentence-transformers/all-mpnet-base-v2'
|
331
359
|
|
332
360
|
async def _handle_search(self, request: SearchRequest) -> SearchResponse:
|
333
|
-
"""Handle search request"""
|
361
|
+
"""Handle search request with caching"""
|
334
362
|
if request.index_name not in self.search_engines:
|
335
363
|
if HTTPException:
|
336
364
|
raise HTTPException(status_code=404, detail=f"Index '{request.index_name}' not found")
|
337
365
|
else:
|
338
366
|
raise ValueError(f"Index '{request.index_name}' not found")
|
339
367
|
|
368
|
+
# Check cache first
|
369
|
+
cache_key = _cache_key(request.query, request.index_name, request.count, request.tags)
|
370
|
+
if cache_key in self._query_cache:
|
371
|
+
logger.info(f"Cache hit for query: {request.query[:50]}...")
|
372
|
+
return self._query_cache[cache_key]
|
373
|
+
|
340
374
|
search_engine = self.search_engines[request.index_name]
|
341
375
|
|
376
|
+
# Get model name from the search engine config
|
377
|
+
model_name = None
|
378
|
+
if hasattr(search_engine, 'config') and search_engine.config:
|
379
|
+
# pgvector uses 'model_name', sqlite uses 'embedding_model'
|
380
|
+
model_name = search_engine.config.get('model_name') or search_engine.config.get('embedding_model')
|
381
|
+
|
342
382
|
# Enhance query
|
343
383
|
try:
|
344
384
|
enhanced = preprocess_query(
|
345
385
|
request.query,
|
346
386
|
language=request.language or 'auto',
|
347
|
-
vector=True
|
387
|
+
vector=True,
|
388
|
+
model_name=model_name # Pass the correct model!
|
348
389
|
)
|
349
390
|
except Exception as e:
|
350
391
|
logger.error(f"Error preprocessing query: {e}")
|
@@ -377,7 +418,7 @@ class SearchService:
|
|
377
418
|
for result in results
|
378
419
|
]
|
379
420
|
|
380
|
-
|
421
|
+
response = SearchResponse(
|
381
422
|
results=search_results,
|
382
423
|
query_analysis={
|
383
424
|
'original_query': request.query,
|
@@ -386,6 +427,15 @@ class SearchService:
|
|
386
427
|
'pos_analysis': enhanced.get('POS')
|
387
428
|
}
|
388
429
|
)
|
430
|
+
|
431
|
+
# Cache the result
|
432
|
+
if len(self._query_cache) >= self._cache_size:
|
433
|
+
# Simple FIFO eviction
|
434
|
+
first_key = next(iter(self._query_cache))
|
435
|
+
del self._query_cache[first_key]
|
436
|
+
self._query_cache[cache_key] = response
|
437
|
+
|
438
|
+
return response
|
389
439
|
|
390
440
|
def search_direct(self, query: str, index_name: str = "default", count: int = 3,
|
391
441
|
distance: float = 0.0, tags: Optional[List[str]] = None,
|
@@ -136,6 +136,11 @@ class NativeVectorSearchSkill(SkillBase):
|
|
136
136
|
"default": "",
|
137
137
|
"required": False
|
138
138
|
},
|
139
|
+
"response_format_callback": {
|
140
|
+
"type": "callable",
|
141
|
+
"description": "Optional callback function to format/transform the response. Called with (response, agent, query, results, args). Must return a string.",
|
142
|
+
"required": False
|
143
|
+
},
|
139
144
|
"description": {
|
140
145
|
"type": "string",
|
141
146
|
"description": "Tool description",
|
@@ -192,6 +197,26 @@ class NativeVectorSearchSkill(SkillBase):
|
|
192
197
|
"description": "Enable verbose logging",
|
193
198
|
"default": False,
|
194
199
|
"required": False
|
200
|
+
},
|
201
|
+
"keyword_weight": {
|
202
|
+
"type": "number",
|
203
|
+
"description": "Manual keyword weight (0.0-1.0). Overrides automatic weight detection",
|
204
|
+
"default": None,
|
205
|
+
"required": False,
|
206
|
+
"minimum": 0.0,
|
207
|
+
"maximum": 1.0
|
208
|
+
},
|
209
|
+
"model_name": {
|
210
|
+
"type": "string",
|
211
|
+
"description": "Embedding model to use. Options: 'mini' (fastest, 384 dims), 'base' (balanced, 768 dims), 'large' (same as base). Or specify full model name like 'sentence-transformers/all-MiniLM-L6-v2'",
|
212
|
+
"default": "mini",
|
213
|
+
"required": False
|
214
|
+
},
|
215
|
+
"overwrite": {
|
216
|
+
"type": "boolean",
|
217
|
+
"description": "Overwrite existing pgvector collection when building index (pgvector backend only)",
|
218
|
+
"default": False,
|
219
|
+
"required": False
|
195
220
|
}
|
196
221
|
})
|
197
222
|
return schema
|
@@ -226,11 +251,29 @@ class NativeVectorSearchSkill(SkillBase):
|
|
226
251
|
)
|
227
252
|
self.response_prefix = self.params.get('response_prefix', '')
|
228
253
|
self.response_postfix = self.params.get('response_postfix', '')
|
254
|
+
self.response_format_callback = self.params.get('response_format_callback')
|
255
|
+
self.keyword_weight = self.params.get('keyword_weight')
|
256
|
+
self.model_name = self.params.get('model_name', 'mini')
|
229
257
|
|
230
258
|
# Remote search server configuration
|
231
|
-
self.remote_url = self.params.get('remote_url') # e.g., "http://localhost:8001"
|
259
|
+
self.remote_url = self.params.get('remote_url') # e.g., "http://user:pass@localhost:8001"
|
232
260
|
self.index_name = self.params.get('index_name', 'default') # For remote searches
|
233
261
|
|
262
|
+
# Parse auth from URL if present
|
263
|
+
self.remote_auth = None
|
264
|
+
self.remote_base_url = self.remote_url
|
265
|
+
if self.remote_url:
|
266
|
+
from urllib.parse import urlparse
|
267
|
+
parsed = urlparse(self.remote_url)
|
268
|
+
if parsed.username and parsed.password:
|
269
|
+
self.remote_auth = (parsed.username, parsed.password)
|
270
|
+
# Reconstruct URL without auth for display
|
271
|
+
self.remote_base_url = f"{parsed.scheme}://{parsed.hostname}"
|
272
|
+
if parsed.port:
|
273
|
+
self.remote_base_url += f":{parsed.port}"
|
274
|
+
if parsed.path:
|
275
|
+
self.remote_base_url += parsed.path
|
276
|
+
|
234
277
|
# SWAIG fields for function fillers
|
235
278
|
self.swaig_fields = self.params.get('swaig_fields', {})
|
236
279
|
|
@@ -244,11 +287,20 @@ class NativeVectorSearchSkill(SkillBase):
|
|
244
287
|
# Test remote connection (lightweight check)
|
245
288
|
try:
|
246
289
|
import requests
|
247
|
-
|
290
|
+
# Use parsed base URL and auth
|
291
|
+
response = requests.get(
|
292
|
+
f"{self.remote_base_url}/health",
|
293
|
+
auth=self.remote_auth,
|
294
|
+
timeout=5
|
295
|
+
)
|
248
296
|
if response.status_code == 200:
|
249
|
-
self.logger.info("Remote search server is available")
|
297
|
+
self.logger.info(f"Remote search server is available at {self.remote_base_url}")
|
250
298
|
self.search_available = True
|
251
299
|
return True # Success - skip all local setup
|
300
|
+
elif response.status_code == 401:
|
301
|
+
self.logger.error("Authentication failed for remote search server. Check credentials.")
|
302
|
+
self.search_available = False
|
303
|
+
return False
|
252
304
|
else:
|
253
305
|
self.logger.error(f"Remote search server returned status {response.status_code}")
|
254
306
|
self.search_available = False
|
@@ -295,32 +347,72 @@ class NativeVectorSearchSkill(SkillBase):
|
|
295
347
|
|
296
348
|
# Auto-build index if requested and search is available
|
297
349
|
if self.build_index and self.source_dir and self.search_available:
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
350
|
+
# Handle auto-build for different backends
|
351
|
+
if self.backend == 'sqlite':
|
352
|
+
if not self.index_file:
|
353
|
+
# Generate index filename from source directory
|
354
|
+
source_name = Path(self.source_dir).name
|
355
|
+
self.index_file = f"{source_name}.swsearch"
|
356
|
+
|
357
|
+
# Build index if it doesn't exist
|
358
|
+
if not os.path.exists(self.index_file):
|
359
|
+
try:
|
360
|
+
self.logger.info(f"Building search index from {self.source_dir}...")
|
361
|
+
from signalwire_agents.search import IndexBuilder
|
362
|
+
|
363
|
+
# Resolve model alias if needed
|
364
|
+
from signalwire_agents.search.models import resolve_model_alias
|
365
|
+
model_to_use = resolve_model_alias(self.model_name)
|
366
|
+
|
367
|
+
builder = IndexBuilder(
|
368
|
+
model_name=model_to_use,
|
369
|
+
verbose=self.params.get('verbose', False),
|
370
|
+
index_nlp_backend=self.index_nlp_backend
|
371
|
+
)
|
372
|
+
builder.build_index(
|
373
|
+
source_dir=self.source_dir,
|
374
|
+
output_file=self.index_file,
|
375
|
+
file_types=self.params.get('file_types', ['md', 'txt']),
|
376
|
+
exclude_patterns=self.params.get('exclude_patterns'),
|
377
|
+
tags=self.params.get('global_tags')
|
378
|
+
)
|
379
|
+
self.logger.info(f"Search index created: {self.index_file}")
|
380
|
+
except Exception as e:
|
381
|
+
self.logger.error(f"Failed to build search index: {e}")
|
382
|
+
self.search_available = False
|
383
|
+
|
384
|
+
elif self.backend == 'pgvector':
|
385
|
+
# Auto-build for pgvector
|
386
|
+
if self.connection_string and self.collection_name:
|
387
|
+
try:
|
388
|
+
self.logger.info(f"Building pgvector index from {self.source_dir}...")
|
389
|
+
from signalwire_agents.search import IndexBuilder
|
390
|
+
from signalwire_agents.search.models import resolve_model_alias
|
391
|
+
|
392
|
+
model_to_use = resolve_model_alias(self.model_name)
|
393
|
+
|
394
|
+
builder = IndexBuilder(
|
395
|
+
backend='pgvector',
|
396
|
+
connection_string=self.connection_string,
|
397
|
+
model_name=model_to_use,
|
398
|
+
verbose=self.params.get('verbose', False),
|
399
|
+
index_nlp_backend=self.index_nlp_backend
|
400
|
+
)
|
401
|
+
|
402
|
+
builder.build_index(
|
403
|
+
source_dir=self.source_dir,
|
404
|
+
output_file=self.collection_name, # pgvector uses this as collection name
|
405
|
+
file_types=self.params.get('file_types', ['md', 'txt']),
|
406
|
+
exclude_patterns=self.params.get('exclude_patterns'),
|
407
|
+
tags=self.params.get('global_tags'),
|
408
|
+
overwrite=self.params.get('overwrite', False)
|
409
|
+
)
|
410
|
+
self.logger.info(f"pgvector collection created: {self.collection_name}")
|
411
|
+
except Exception as e:
|
412
|
+
self.logger.error(f"Failed to build pgvector index: {e}")
|
413
|
+
# Don't set search_available to False - we might be connecting to existing collection
|
414
|
+
else:
|
415
|
+
self.logger.warning("pgvector auto-build requires connection_string and collection_name")
|
324
416
|
|
325
417
|
# Initialize local search engine
|
326
418
|
self.search_engine = None
|
@@ -347,6 +439,12 @@ class NativeVectorSearchSkill(SkillBase):
|
|
347
439
|
try:
|
348
440
|
from signalwire_agents.search import SearchEngine
|
349
441
|
self.search_engine = SearchEngine(backend='sqlite', index_path=self.index_file)
|
442
|
+
# The SearchEngine will auto-detect the model from the index
|
443
|
+
# Get the model name from config for query processing
|
444
|
+
if hasattr(self.search_engine, 'config'):
|
445
|
+
index_model = self.search_engine.config.get('embedding_model')
|
446
|
+
if index_model:
|
447
|
+
self.logger.info(f"Using model from index: {index_model}")
|
350
448
|
except Exception as e:
|
351
449
|
self.logger.error(f"Failed to load search index {self.index_file}: {e}")
|
352
450
|
self.search_available = False
|
@@ -451,13 +549,29 @@ class NativeVectorSearchSkill(SkillBase):
|
|
451
549
|
else:
|
452
550
|
# For local searches, preprocess the query locally
|
453
551
|
from signalwire_agents.search.query_processor import preprocess_query
|
454
|
-
|
552
|
+
|
553
|
+
# Get model name from index config if available
|
554
|
+
model_for_query = None
|
555
|
+
if hasattr(self.search_engine, 'config'):
|
556
|
+
model_for_query = self.search_engine.config.get('embedding_model')
|
557
|
+
|
558
|
+
enhanced = preprocess_query(
|
559
|
+
query,
|
560
|
+
language='en',
|
561
|
+
vector=True,
|
562
|
+
query_nlp_backend=self.query_nlp_backend,
|
563
|
+
model_name=model_for_query, # Use model from index
|
564
|
+
preserve_original=True, # Keep original query terms
|
565
|
+
max_synonyms=2 # Reduce synonym expansion
|
566
|
+
)
|
455
567
|
results = self.search_engine.search(
|
456
568
|
query_vector=enhanced.get('vector', []),
|
457
569
|
enhanced_text=enhanced['enhanced_text'],
|
458
570
|
count=count,
|
459
571
|
distance_threshold=self.distance_threshold,
|
460
|
-
tags=self.tags
|
572
|
+
tags=self.tags,
|
573
|
+
keyword_weight=self.keyword_weight,
|
574
|
+
original_query=query # Pass original for exact match boosting
|
461
575
|
)
|
462
576
|
|
463
577
|
if not results:
|
@@ -466,6 +580,25 @@ class NativeVectorSearchSkill(SkillBase):
|
|
466
580
|
no_results_msg = f"{self.response_prefix} {no_results_msg}"
|
467
581
|
if self.response_postfix:
|
468
582
|
no_results_msg = f"{no_results_msg} {self.response_postfix}"
|
583
|
+
|
584
|
+
# Apply custom formatting callback for no results case
|
585
|
+
if self.response_format_callback and callable(self.response_format_callback):
|
586
|
+
try:
|
587
|
+
callback_context = {
|
588
|
+
'response': no_results_msg,
|
589
|
+
'agent': self.agent,
|
590
|
+
'query': query,
|
591
|
+
'results': [], # Empty results
|
592
|
+
'args': args,
|
593
|
+
'count': count,
|
594
|
+
'skill': self
|
595
|
+
}
|
596
|
+
formatted_response = self.response_format_callback(**callback_context)
|
597
|
+
if isinstance(formatted_response, str):
|
598
|
+
no_results_msg = formatted_response
|
599
|
+
except Exception as e:
|
600
|
+
self.logger.error(f"Error in response_format_callback (no results): {e}", exc_info=True)
|
601
|
+
|
469
602
|
return SwaigFunctionResult(no_results_msg)
|
470
603
|
|
471
604
|
# Format results
|
@@ -483,9 +616,20 @@ class NativeVectorSearchSkill(SkillBase):
|
|
483
616
|
score = result['score']
|
484
617
|
content = result['content']
|
485
618
|
|
619
|
+
# Get tags from either top level or metadata
|
620
|
+
tags = result.get('tags', [])
|
621
|
+
if not tags and 'metadata' in result['metadata'] and 'tags' in result['metadata']['metadata']:
|
622
|
+
# Handle double-nested metadata from older indexes
|
623
|
+
tags = result['metadata']['metadata']['tags']
|
624
|
+
elif not tags and 'tags' in result['metadata']:
|
625
|
+
# Check in metadata directly
|
626
|
+
tags = result['metadata']['tags']
|
627
|
+
|
486
628
|
result_text = f"**Result {i}** (from {filename}"
|
487
629
|
if section:
|
488
630
|
result_text += f", section: {section}"
|
631
|
+
if tags:
|
632
|
+
result_text += f", tags: {', '.join(tags)}"
|
489
633
|
result_text += f", relevance: {score:.2f})\n{content}\n"
|
490
634
|
|
491
635
|
response_parts.append(result_text)
|
@@ -494,7 +638,37 @@ class NativeVectorSearchSkill(SkillBase):
|
|
494
638
|
if self.response_postfix:
|
495
639
|
response_parts.append(self.response_postfix)
|
496
640
|
|
497
|
-
|
641
|
+
# Build the initial response
|
642
|
+
response = "\n".join(response_parts)
|
643
|
+
|
644
|
+
# Apply custom formatting callback if provided
|
645
|
+
if self.response_format_callback and callable(self.response_format_callback):
|
646
|
+
try:
|
647
|
+
# Prepare callback context
|
648
|
+
callback_context = {
|
649
|
+
'response': response,
|
650
|
+
'agent': self.agent,
|
651
|
+
'query': query,
|
652
|
+
'results': results,
|
653
|
+
'args': args,
|
654
|
+
'count': count,
|
655
|
+
'skill': self
|
656
|
+
}
|
657
|
+
|
658
|
+
# Call the callback
|
659
|
+
formatted_response = self.response_format_callback(**callback_context)
|
660
|
+
|
661
|
+
# Validate callback returned a string
|
662
|
+
if isinstance(formatted_response, str):
|
663
|
+
response = formatted_response
|
664
|
+
else:
|
665
|
+
self.logger.warning(f"response_format_callback returned non-string type: {type(formatted_response)}")
|
666
|
+
|
667
|
+
except Exception as e:
|
668
|
+
self.logger.error(f"Error in response_format_callback: {e}", exc_info=True)
|
669
|
+
# Continue with original response if callback fails
|
670
|
+
|
671
|
+
return SwaigFunctionResult(response)
|
498
672
|
|
499
673
|
except Exception as e:
|
500
674
|
# Log the full error details for debugging
|
@@ -531,8 +705,9 @@ class NativeVectorSearchSkill(SkillBase):
|
|
531
705
|
}
|
532
706
|
|
533
707
|
response = requests.post(
|
534
|
-
f"{self.
|
708
|
+
f"{self.remote_base_url}/search",
|
535
709
|
json=search_request,
|
710
|
+
auth=self.remote_auth,
|
536
711
|
timeout=30
|
537
712
|
)
|
538
713
|
|
@@ -1,9 +1,9 @@
|
|
1
|
-
signalwire_agents/__init__.py,sha256=
|
1
|
+
signalwire_agents/__init__.py,sha256=1byn77sqQkdmsLFanfvelyOr7MVKqyIP9iLOPZ37tAk,5031
|
2
2
|
signalwire_agents/agent_server.py,sha256=x9HyWia8D3r6KMqY-Q4DtNVivfJWLTx8B-KzUI8okuA,26880
|
3
|
-
signalwire_agents/schema.json,sha256=
|
3
|
+
signalwire_agents/schema.json,sha256=2nuBXteuQUvrmmfbkMocQOTsM5BtUHADtMcjMTK72rA,240060
|
4
4
|
signalwire_agents/agents/bedrock.py,sha256=J582gooNtxtep4xdVOfyDzRtHp_XrurPMS93xf2Xod0,10836
|
5
5
|
signalwire_agents/cli/__init__.py,sha256=XbxAQFaCIdGXIXJiriVBWoFPOJsC401u21588nO4TG8,388
|
6
|
-
signalwire_agents/cli/build_search.py,sha256=
|
6
|
+
signalwire_agents/cli/build_search.py,sha256=Yh5hNM0ur88UMuKo5ZDoN_bAzBGpj2RG1Ys1_3xlfUc,54144
|
7
7
|
signalwire_agents/cli/config.py,sha256=2i4e0BArdKsaXxjeueYYRNke7GWicHPYC2wuitVrP7A,2541
|
8
8
|
signalwire_agents/cli/swaig_test_wrapper.py,sha256=t63HQpEc1Up5AcysEHP1OsEQcgSMKH-9H1L2IhFso18,1533
|
9
9
|
signalwire_agents/cli/test_swaig.py,sha256=-v-XjTUWZNxmMJuOF5_cB1Jz8x8emJoqgqS_8jLeT4Y,31487
|
@@ -53,7 +53,7 @@ signalwire_agents/core/agent/tools/__init__.py,sha256=eOcmyeGm6qogT3wsBx7QvdjmTb
|
|
53
53
|
signalwire_agents/core/agent/tools/decorator.py,sha256=pC6j1114GwVBd2U3h23I9gKLtu8AgeiuWV0lUzz682U,2961
|
54
54
|
signalwire_agents/core/agent/tools/registry.py,sha256=HScbKKwpJqFZ_odmeFklSQ0p0EMasEyKSxNwX568OPo,8054
|
55
55
|
signalwire_agents/core/mixins/__init__.py,sha256=NsFpfF7TDP_lNR0Riw4Nbvt4fDbv_A3OoVbBqRrtXQM,652
|
56
|
-
signalwire_agents/core/mixins/ai_config_mixin.py,sha256=
|
56
|
+
signalwire_agents/core/mixins/ai_config_mixin.py,sha256=8SwDnzBuRkD2I5AvY4FutataDo9huOW59Gpr5UDIfRM,16213
|
57
57
|
signalwire_agents/core/mixins/auth_mixin.py,sha256=Y9kR423-76U_pKL7KXzseeXX2a-4WxNWyo3odS7TDQM,9879
|
58
58
|
signalwire_agents/core/mixins/prompt_mixin.py,sha256=bEsuw9J2F_upFYI02KyC7o2eGZjwOKQ352rmJBZirAM,13729
|
59
59
|
signalwire_agents/core/mixins/serverless_mixin.py,sha256=QIIbl_-16XFJi5aqrWpNzORbyCJQmhaplWXnW6U9i68,16137
|
@@ -69,13 +69,15 @@ signalwire_agents/prefabs/faq_bot.py,sha256=cUuHhnDB8S4aVg-DiQe4jBmCAPrYQrND_Mff
|
|
69
69
|
signalwire_agents/prefabs/info_gatherer.py,sha256=0LpYTaU7C76Efp3yUIdNX6xzWH7mj5pBYewilpkCL5g,15189
|
70
70
|
signalwire_agents/prefabs/receptionist.py,sha256=em0uk_F0tmePvzE6Hi9HFlL3MHChH0RaHHqSvww9pK0,10323
|
71
71
|
signalwire_agents/prefabs/survey.py,sha256=a-0-xAnQYhdX4Lzgyna14lpNfaCV-rLUFkQF6QOCQAY,14534
|
72
|
-
signalwire_agents/search/__init__.py,sha256=
|
73
|
-
signalwire_agents/search/document_processor.py,sha256=
|
74
|
-
signalwire_agents/search/index_builder.py,sha256=
|
75
|
-
signalwire_agents/search/
|
76
|
-
signalwire_agents/search/
|
77
|
-
signalwire_agents/search/
|
78
|
-
signalwire_agents/search/
|
72
|
+
signalwire_agents/search/__init__.py,sha256=cb8Rtg4Jut9ZhuSbiaHl79G0iWgMhJkLu84urkY0lRc,4215
|
73
|
+
signalwire_agents/search/document_processor.py,sha256=zDih-xBWq2kEQkQblh4xXZE1uIQ9aBBFLjjsi3CYfRU,48196
|
74
|
+
signalwire_agents/search/index_builder.py,sha256=v1LGhbzzKlCilO4g6nqQJVYEAWvInP2j5B1QrAEj4V8,33772
|
75
|
+
signalwire_agents/search/migration.py,sha256=UZPrpUOMZeLVNO1cEDp3tnZYG6ys8-VCFlZXmzig_E0,16582
|
76
|
+
signalwire_agents/search/models.py,sha256=isYOYwQT0eWCVdcYSSd8w6z2gFYUobtC8BAUhV7FUVI,840
|
77
|
+
signalwire_agents/search/pgvector_backend.py,sha256=waneT_cBmWGE79kpN5Ie4ax6VDuyWb7QmjzXzGFjY7w,28400
|
78
|
+
signalwire_agents/search/query_processor.py,sha256=qpUFQqxobx8IymcXBTdPUirfawZVCKtRdSlMHw3nA0s,19656
|
79
|
+
signalwire_agents/search/search_engine.py,sha256=dHwhAknIw0paAVQx3ccgVOkaiFqMpDOAriH8lQrBYm8,55671
|
80
|
+
signalwire_agents/search/search_service.py,sha256=KV0luon18gPBcoyQ8L_Lagi1CgkJSOwGWshpCjvj1ks,20360
|
79
81
|
signalwire_agents/skills/README.md,sha256=sM1_08IsKdRDCzYHPLzppJbaK5MvRelsVL6Kd9A9Ubo,12193
|
80
82
|
signalwire_agents/skills/__init__.py,sha256=9AMEcyk2tDaGiUjwVIson_tVWxV4oU_2NnGGNTbHuyQ,533
|
81
83
|
signalwire_agents/skills/registry.py,sha256=zURdeAaccZyUSwLRl8K4ILXICMV3ouYQIA4rUBq6b5E,20792
|
@@ -102,7 +104,7 @@ signalwire_agents/skills/mcp_gateway/__init__.py,sha256=zLgOa7s0sIQphTNJjvasIAW7
|
|
102
104
|
signalwire_agents/skills/mcp_gateway/skill.py,sha256=rtXs8CayjWH8WOrpjGMbbG11dJCNK2RUA06Ysc1cK8g,17167
|
103
105
|
signalwire_agents/skills/native_vector_search/README.md,sha256=eFVRoDwZlZwbBXUKyKrvfC6AL4T8MXj0B-IgIdBZF70,5526
|
104
106
|
signalwire_agents/skills/native_vector_search/__init__.py,sha256=RofpN3Sd-vyWeUCTYH2dRVrl7h6YuyG5OK772UQ-KFk,220
|
105
|
-
signalwire_agents/skills/native_vector_search/skill.py,sha256=
|
107
|
+
signalwire_agents/skills/native_vector_search/skill.py,sha256=ltIFXwxxyqYkTSG2exUsSuJB4tOAiTwYrG7PYtVDCJw,36208
|
106
108
|
signalwire_agents/skills/play_background_file/README.md,sha256=omJ_jY5Co6Mk-gJt_hoSl40wemmTbzae3DBll6HL0B4,7026
|
107
109
|
signalwire_agents/skills/play_background_file/__init__.py,sha256=iETc6e-0Cai3RUTQWhg9BieWi3NF3_DWWBKdYXcd4ok,273
|
108
110
|
signalwire_agents/skills/play_background_file/skill.py,sha256=HgPc2FIvXKJHZ7gO2QEzQe6-uUBPrw_6sRJJpU83GTY,8822
|
@@ -128,9 +130,9 @@ signalwire_agents/utils/token_generators.py,sha256=4Mr7baQ_xR_hfJ72YxQRAT_GFa663
|
|
128
130
|
signalwire_agents/utils/validators.py,sha256=4Mr7baQ_xR_hfJ72YxQRAT_GFa663YjFX_PumJ35Xds,191
|
129
131
|
signalwire_agents/web/__init__.py,sha256=XE_pSTY9Aalzr7J7wqFth1Zr3cccQHPPcF5HWNrOpz8,383
|
130
132
|
signalwire_agents/web/web_service.py,sha256=a2PSHJgX1tlZr0Iz1A1UouZjXEePJAZL632evvLVM38,21071
|
131
|
-
signalwire_agents-0.1.
|
132
|
-
signalwire_agents-0.1.
|
133
|
-
signalwire_agents-0.1.
|
134
|
-
signalwire_agents-0.1.
|
135
|
-
signalwire_agents-0.1.
|
136
|
-
signalwire_agents-0.1.
|
133
|
+
signalwire_agents-0.1.49.dist-info/licenses/LICENSE,sha256=NYvAsB-rTcSvG9cqHt9EUHAWLiA9YzM4Qfz-mPdvDR0,1067
|
134
|
+
signalwire_agents-0.1.49.dist-info/METADATA,sha256=VxZ5sTQ3vESbK10ztr5XkLRko2VkGIjUEu6SbcZRfYU,41596
|
135
|
+
signalwire_agents-0.1.49.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
136
|
+
signalwire_agents-0.1.49.dist-info/entry_points.txt,sha256=ZDT65zfTO_YyDzi_hwQbCxIhrUfu_t8RpNXMMXlUPWI,144
|
137
|
+
signalwire_agents-0.1.49.dist-info/top_level.txt,sha256=kDGS6ZYv84K9P5Kyg9_S8P_pbUXoHkso0On_DB5bbWc,18
|
138
|
+
signalwire_agents-0.1.49.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|