signalwire-agents 0.1.12__py3-none-any.whl → 0.1.14__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 +28 -11
- signalwire_agents/cli/build_search.py +174 -14
- signalwire_agents/cli/test_swaig.py +159 -114
- signalwire_agents/core/agent_base.py +7 -38
- signalwire_agents/core/logging_config.py +143 -14
- signalwire_agents/core/skill_manager.py +2 -2
- signalwire_agents/core/swaig_function.py +2 -3
- signalwire_agents/core/swml_renderer.py +43 -28
- signalwire_agents/core/swml_service.py +5 -45
- signalwire_agents/search/document_processor.py +275 -14
- signalwire_agents/search/index_builder.py +45 -10
- signalwire_agents/search/query_processor.py +27 -12
- signalwire_agents/skills/__init__.py +1 -1
- signalwire_agents/skills/native_vector_search/skill.py +24 -6
- signalwire_agents/skills/registry.py +58 -42
- {signalwire_agents-0.1.12.dist-info → signalwire_agents-0.1.14.dist-info}/METADATA +1 -1
- {signalwire_agents-0.1.12.dist-info → signalwire_agents-0.1.14.dist-info}/RECORD +22 -22
- {signalwire_agents-0.1.12.dist-info → signalwire_agents-0.1.14.dist-info}/entry_points.txt +1 -1
- {signalwire_agents-0.1.12.data → signalwire_agents-0.1.14.data}/data/schema.json +0 -0
- {signalwire_agents-0.1.12.dist-info → signalwire_agents-0.1.14.dist-info}/WHEEL +0 -0
- {signalwire_agents-0.1.12.dist-info → signalwire_agents-0.1.14.dist-info}/licenses/LICENSE +0 -0
- {signalwire_agents-0.1.12.dist-info → signalwire_agents-0.1.14.dist-info}/top_level.txt +0 -0
signalwire_agents/__init__.py
CHANGED
@@ -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.
|
21
|
+
__version__ = "0.1.14"
|
22
22
|
|
23
23
|
# Import core classes for easier access
|
24
24
|
from .core.agent_base import AgentBase
|
@@ -31,19 +31,36 @@ from signalwire_agents.core.swml_builder import SWMLBuilder
|
|
31
31
|
from signalwire_agents.core.function_result import SwaigFunctionResult
|
32
32
|
from signalwire_agents.core.swaig_function import SWAIGFunction
|
33
33
|
|
34
|
-
#
|
35
|
-
|
34
|
+
# Lazy import skills to avoid slow startup for CLI tools
|
35
|
+
# Skills are now loaded on-demand when requested
|
36
|
+
def _get_skill_registry():
|
37
|
+
"""Lazy import and return skill registry"""
|
38
|
+
import signalwire_agents.skills
|
39
|
+
return signalwire_agents.skills.skill_registry
|
36
40
|
|
37
|
-
#
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
41
|
+
# Lazy import convenience functions from the CLI (if available)
|
42
|
+
def start_agent(*args, **kwargs):
|
43
|
+
"""Start an agent (lazy import)"""
|
44
|
+
try:
|
45
|
+
from signalwire_agents.cli.helpers import start_agent as _start_agent
|
46
|
+
return _start_agent(*args, **kwargs)
|
47
|
+
except ImportError:
|
43
48
|
raise NotImplementedError("CLI helpers not available")
|
44
|
-
|
49
|
+
|
50
|
+
def run_agent(*args, **kwargs):
|
51
|
+
"""Run an agent (lazy import)"""
|
52
|
+
try:
|
53
|
+
from signalwire_agents.cli.helpers import run_agent as _run_agent
|
54
|
+
return _run_agent(*args, **kwargs)
|
55
|
+
except ImportError:
|
45
56
|
raise NotImplementedError("CLI helpers not available")
|
46
|
-
|
57
|
+
|
58
|
+
def list_skills(*args, **kwargs):
|
59
|
+
"""List available skills (lazy import)"""
|
60
|
+
try:
|
61
|
+
from signalwire_agents.cli.helpers import list_skills as _list_skills
|
62
|
+
return _list_skills(*args, **kwargs)
|
63
|
+
except ImportError:
|
47
64
|
raise NotImplementedError("CLI helpers not available")
|
48
65
|
|
49
66
|
__all__ = [
|
@@ -10,7 +10,6 @@ See LICENSE file in the project root for full license information.
|
|
10
10
|
import argparse
|
11
11
|
import sys
|
12
12
|
from pathlib import Path
|
13
|
-
from ..search.index_builder import IndexBuilder
|
14
13
|
|
15
14
|
def main():
|
16
15
|
"""Main entry point for the build-search command"""
|
@@ -19,7 +18,7 @@ def main():
|
|
19
18
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
20
19
|
epilog="""
|
21
20
|
Examples:
|
22
|
-
# Basic usage with directory (defaults to sentence chunking with
|
21
|
+
# Basic usage with directory (defaults to sentence chunking with 5 sentences per chunk)
|
23
22
|
sw-search ./docs
|
24
23
|
|
25
24
|
# Multiple directories
|
@@ -34,7 +33,7 @@ Examples:
|
|
34
33
|
# Sentence-based chunking with custom parameters
|
35
34
|
sw-search ./docs \\
|
36
35
|
--chunking-strategy sentence \\
|
37
|
-
--max-sentences-per-chunk
|
36
|
+
--max-sentences-per-chunk 10 \\
|
38
37
|
--split-newlines 2
|
39
38
|
|
40
39
|
# Sliding window chunking
|
@@ -53,11 +52,25 @@ Examples:
|
|
53
52
|
--chunking-strategy page \\
|
54
53
|
--file-types pdf
|
55
54
|
|
55
|
+
# Semantic chunking (groups semantically similar sentences)
|
56
|
+
sw-search ./docs \\
|
57
|
+
--chunking-strategy semantic \\
|
58
|
+
--semantic-threshold 0.6
|
59
|
+
|
60
|
+
# Topic-based chunking (groups by topic changes)
|
61
|
+
sw-search ./docs \\
|
62
|
+
--chunking-strategy topic \\
|
63
|
+
--topic-threshold 0.2
|
64
|
+
|
65
|
+
# QA-optimized chunking (optimized for question-answering)
|
66
|
+
sw-search ./docs \\
|
67
|
+
--chunking-strategy qa
|
68
|
+
|
56
69
|
# Full configuration example
|
57
70
|
sw-search ./docs ./examples README.md \\
|
58
71
|
--output ./knowledge.swsearch \\
|
59
72
|
--chunking-strategy sentence \\
|
60
|
-
--max-sentences-per-chunk
|
73
|
+
--max-sentences-per-chunk 8 \\
|
61
74
|
--file-types md,txt,rst,py \\
|
62
75
|
--exclude "**/test/**,**/__pycache__/**" \\
|
63
76
|
--languages en,es,fr \\
|
@@ -88,7 +101,7 @@ Examples:
|
|
88
101
|
|
89
102
|
parser.add_argument(
|
90
103
|
'--chunking-strategy',
|
91
|
-
choices=['sentence', 'sliding', 'paragraph', 'page'],
|
104
|
+
choices=['sentence', 'sliding', 'paragraph', 'page', 'semantic', 'topic', 'qa'],
|
92
105
|
default='sentence',
|
93
106
|
help='Chunking strategy to use (default: sentence)'
|
94
107
|
)
|
@@ -96,8 +109,8 @@ Examples:
|
|
96
109
|
parser.add_argument(
|
97
110
|
'--max-sentences-per-chunk',
|
98
111
|
type=int,
|
99
|
-
default=
|
100
|
-
help='Maximum sentences per chunk for sentence strategy (default:
|
112
|
+
default=5,
|
113
|
+
help='Maximum sentences per chunk for sentence strategy (default: 5)'
|
101
114
|
)
|
102
115
|
|
103
116
|
parser.add_argument(
|
@@ -117,7 +130,7 @@ Examples:
|
|
117
130
|
parser.add_argument(
|
118
131
|
'--split-newlines',
|
119
132
|
type=int,
|
120
|
-
help='Split on multiple newlines for sentence strategy
|
133
|
+
help='Split on multiple newlines (for sentence strategy)'
|
121
134
|
)
|
122
135
|
|
123
136
|
parser.add_argument(
|
@@ -148,6 +161,13 @@ Examples:
|
|
148
161
|
help='Comma-separated tags to add to all chunks'
|
149
162
|
)
|
150
163
|
|
164
|
+
parser.add_argument(
|
165
|
+
'--index-nlp-backend',
|
166
|
+
choices=['nltk', 'spacy'],
|
167
|
+
default='nltk',
|
168
|
+
help='NLP backend for document processing: nltk (fast, default) or spacy (better quality, slower)'
|
169
|
+
)
|
170
|
+
|
151
171
|
parser.add_argument(
|
152
172
|
'--verbose',
|
153
173
|
action='store_true',
|
@@ -160,6 +180,20 @@ Examples:
|
|
160
180
|
help='Validate the created index after building'
|
161
181
|
)
|
162
182
|
|
183
|
+
parser.add_argument(
|
184
|
+
'--semantic-threshold',
|
185
|
+
type=float,
|
186
|
+
default=0.5,
|
187
|
+
help='Similarity threshold for semantic chunking (default: 0.5)'
|
188
|
+
)
|
189
|
+
|
190
|
+
parser.add_argument(
|
191
|
+
'--topic-threshold',
|
192
|
+
type=float,
|
193
|
+
default=0.3,
|
194
|
+
help='Similarity threshold for topic chunking (default: 0.3)'
|
195
|
+
)
|
196
|
+
|
163
197
|
args = parser.parse_args()
|
164
198
|
|
165
199
|
# Validate sources
|
@@ -204,6 +238,7 @@ Examples:
|
|
204
238
|
print(f" Languages: {languages}")
|
205
239
|
print(f" Model: {args.model}")
|
206
240
|
print(f" Chunking strategy: {args.chunking_strategy}")
|
241
|
+
print(f" Index NLP backend: {args.index_nlp_backend}")
|
207
242
|
|
208
243
|
if args.chunking_strategy == 'sentence':
|
209
244
|
print(f" Max sentences per chunk: {args.max_sentences_per_chunk}")
|
@@ -216,12 +251,19 @@ Examples:
|
|
216
251
|
print(f" Chunking by paragraphs (double newlines)")
|
217
252
|
elif args.chunking_strategy == 'page':
|
218
253
|
print(f" Chunking by pages")
|
254
|
+
elif args.chunking_strategy == 'semantic':
|
255
|
+
print(f" Semantic chunking (similarity threshold: {args.semantic_threshold})")
|
256
|
+
elif args.chunking_strategy == 'topic':
|
257
|
+
print(f" Topic-based chunking (similarity threshold: {args.topic_threshold})")
|
258
|
+
elif args.chunking_strategy == 'qa':
|
259
|
+
print(f" QA-optimized chunking")
|
219
260
|
|
220
261
|
print(f" Tags: {tags}")
|
221
262
|
print()
|
222
263
|
|
223
264
|
try:
|
224
|
-
# Create index builder
|
265
|
+
# Create index builder - import only when actually needed
|
266
|
+
from ..search.index_builder import IndexBuilder
|
225
267
|
builder = IndexBuilder(
|
226
268
|
model_name=args.model,
|
227
269
|
chunking_strategy=args.chunking_strategy,
|
@@ -229,7 +271,10 @@ Examples:
|
|
229
271
|
chunk_size=args.chunk_size,
|
230
272
|
chunk_overlap=args.overlap_size,
|
231
273
|
split_newlines=args.split_newlines,
|
232
|
-
|
274
|
+
index_nlp_backend=args.index_nlp_backend,
|
275
|
+
verbose=args.verbose,
|
276
|
+
semantic_threshold=args.semantic_threshold,
|
277
|
+
topic_threshold=args.topic_threshold
|
233
278
|
)
|
234
279
|
|
235
280
|
# Build index with multiple sources
|
@@ -316,8 +361,8 @@ def search_command():
|
|
316
361
|
parser.add_argument('--count', type=int, default=5, help='Number of results to return (default: 5)')
|
317
362
|
parser.add_argument('--distance-threshold', type=float, default=0.0, help='Minimum similarity score (default: 0.0)')
|
318
363
|
parser.add_argument('--tags', help='Comma-separated tags to filter by')
|
319
|
-
parser.add_argument('--nlp-backend', choices=['nltk', 'spacy'], default='nltk',
|
320
|
-
help='NLP backend
|
364
|
+
parser.add_argument('--query-nlp-backend', choices=['nltk', 'spacy'], default='nltk',
|
365
|
+
help='NLP backend for query processing: nltk (fast, default) or spacy (better quality, slower)')
|
321
366
|
parser.add_argument('--verbose', action='store_true', help='Show detailed information')
|
322
367
|
parser.add_argument('--json', action='store_true', help='Output results as JSON')
|
323
368
|
parser.add_argument('--no-content', action='store_true', help='Hide content in results (show only metadata)')
|
@@ -349,11 +394,11 @@ def search_command():
|
|
349
394
|
if args.verbose:
|
350
395
|
print(f"Index contains {stats['total_chunks']} chunks from {stats['total_files']} files")
|
351
396
|
print(f"Searching for: '{args.query}'")
|
352
|
-
print(f"NLP Backend: {args.
|
397
|
+
print(f"Query NLP Backend: {args.query_nlp_backend}")
|
353
398
|
print()
|
354
399
|
|
355
400
|
# Preprocess query
|
356
|
-
enhanced = preprocess_query(args.query, vector=True,
|
401
|
+
enhanced = preprocess_query(args.query, vector=True, query_nlp_backend=args.query_nlp_backend)
|
357
402
|
|
358
403
|
# Parse tags if provided
|
359
404
|
tags = [tag.strip() for tag in args.tags.split(',')] if args.tags else None
|
@@ -437,6 +482,121 @@ def console_entry_point():
|
|
437
482
|
"""Console script entry point for pip installation"""
|
438
483
|
import sys
|
439
484
|
|
485
|
+
# Fast help check - show help without importing heavy modules
|
486
|
+
if len(sys.argv) > 1 and sys.argv[1] in ['--help', '-h']:
|
487
|
+
print("""usage: sw-search [-h] [--output OUTPUT] [--chunking-strategy {sentence,sliding,paragraph,page,semantic,topic,qa}]
|
488
|
+
[--max-sentences-per-chunk MAX_SENTENCES_PER_CHUNK] [--chunk-size CHUNK_SIZE]
|
489
|
+
[--overlap-size OVERLAP_SIZE] [--split-newlines SPLIT_NEWLINES] [--file-types FILE_TYPES]
|
490
|
+
[--exclude EXCLUDE] [--languages LANGUAGES] [--model MODEL] [--tags TAGS]
|
491
|
+
[--index-nlp-backend {nltk,spacy}] [--verbose] [--validate]
|
492
|
+
[--semantic-threshold SEMANTIC_THRESHOLD] [--topic-threshold TOPIC_THRESHOLD]
|
493
|
+
sources [sources ...]
|
494
|
+
|
495
|
+
Build local search index from documents
|
496
|
+
|
497
|
+
positional arguments:
|
498
|
+
sources Source files and/or directories to index
|
499
|
+
|
500
|
+
options:
|
501
|
+
-h, --help show this help message and exit
|
502
|
+
--output OUTPUT Output .swsearch file (default: sources.swsearch)
|
503
|
+
--chunking-strategy {sentence,sliding,paragraph,page,semantic,topic,qa}
|
504
|
+
Chunking strategy to use (default: sentence)
|
505
|
+
--max-sentences-per-chunk MAX_SENTENCES_PER_CHUNK
|
506
|
+
Maximum sentences per chunk for sentence strategy (default: 5)
|
507
|
+
--chunk-size CHUNK_SIZE
|
508
|
+
Chunk size in words for sliding window strategy (default: 50)
|
509
|
+
--overlap-size OVERLAP_SIZE
|
510
|
+
Overlap size in words for sliding window strategy (default: 10)
|
511
|
+
--split-newlines SPLIT_NEWLINES
|
512
|
+
Split on multiple newlines (for sentence strategy)
|
513
|
+
--file-types FILE_TYPES
|
514
|
+
Comma-separated file extensions to include for directories (default: md,txt,rst)
|
515
|
+
--exclude EXCLUDE Comma-separated glob patterns to exclude (e.g., "**/test/**,**/__pycache__/**")
|
516
|
+
--languages LANGUAGES
|
517
|
+
Comma-separated language codes (default: en)
|
518
|
+
--model MODEL Sentence transformer model name (default: sentence-transformers/all-mpnet-base-v2)
|
519
|
+
--tags TAGS Comma-separated tags to add to all chunks
|
520
|
+
--index-nlp-backend {nltk,spacy}
|
521
|
+
NLP backend for document processing: nltk (fast, default) or spacy (better quality, slower)
|
522
|
+
--verbose Enable verbose output
|
523
|
+
--validate Validate the created index after building
|
524
|
+
--semantic-threshold SEMANTIC_THRESHOLD
|
525
|
+
Similarity threshold for semantic chunking (default: 0.5)
|
526
|
+
--topic-threshold TOPIC_THRESHOLD
|
527
|
+
Similarity threshold for topic chunking (default: 0.3)
|
528
|
+
|
529
|
+
Examples:
|
530
|
+
# Basic usage with directory (defaults to sentence chunking with 5 sentences per chunk)
|
531
|
+
sw-search ./docs
|
532
|
+
|
533
|
+
# Multiple directories
|
534
|
+
sw-search ./docs ./examples --file-types md,txt,py
|
535
|
+
|
536
|
+
# Individual files
|
537
|
+
sw-search README.md ./docs/guide.md ./src/main.py
|
538
|
+
|
539
|
+
# Mixed sources (directories and files)
|
540
|
+
sw-search ./docs README.md ./examples specific_file.txt --file-types md,txt,py
|
541
|
+
|
542
|
+
# Sentence-based chunking with custom parameters
|
543
|
+
sw-search ./docs \\
|
544
|
+
--chunking-strategy sentence \\
|
545
|
+
--max-sentences-per-chunk 10 \\
|
546
|
+
--split-newlines 2
|
547
|
+
|
548
|
+
# Sliding window chunking
|
549
|
+
sw-search ./docs \\
|
550
|
+
--chunking-strategy sliding \\
|
551
|
+
--chunk-size 100 \\
|
552
|
+
--overlap-size 20
|
553
|
+
|
554
|
+
# Paragraph-based chunking
|
555
|
+
sw-search ./docs \\
|
556
|
+
--chunking-strategy paragraph \\
|
557
|
+
--file-types md,txt,rst
|
558
|
+
|
559
|
+
# Page-based chunking (good for PDFs)
|
560
|
+
sw-search ./docs \\
|
561
|
+
--chunking-strategy page \\
|
562
|
+
--file-types pdf
|
563
|
+
|
564
|
+
# Semantic chunking (groups semantically similar sentences)
|
565
|
+
sw-search ./docs \\
|
566
|
+
--chunking-strategy semantic \\
|
567
|
+
--semantic-threshold 0.6
|
568
|
+
|
569
|
+
# Topic-based chunking (groups by topic changes)
|
570
|
+
sw-search ./docs \\
|
571
|
+
--chunking-strategy topic \\
|
572
|
+
--topic-threshold 0.2
|
573
|
+
|
574
|
+
# QA-optimized chunking (optimized for question-answering)
|
575
|
+
sw-search ./docs \\
|
576
|
+
--chunking-strategy qa
|
577
|
+
|
578
|
+
# Full configuration example
|
579
|
+
sw-search ./docs ./examples README.md \\
|
580
|
+
--output ./knowledge.swsearch \\
|
581
|
+
--chunking-strategy sentence \\
|
582
|
+
--max-sentences-per-chunk 8 \\
|
583
|
+
--file-types md,txt,rst,py \\
|
584
|
+
--exclude "**/test/**,**/__pycache__/**" \\
|
585
|
+
--languages en,es,fr \\
|
586
|
+
--model sentence-transformers/all-mpnet-base-v2 \\
|
587
|
+
--tags documentation,api \\
|
588
|
+
--verbose
|
589
|
+
|
590
|
+
# Validate an existing index
|
591
|
+
sw-search validate ./docs.swsearch
|
592
|
+
|
593
|
+
# Search within an index
|
594
|
+
sw-search search ./docs.swsearch "how to create an agent"
|
595
|
+
sw-search search ./docs.swsearch "API reference" --count 3 --verbose
|
596
|
+
sw-search search ./docs.swsearch "configuration" --tags documentation --json
|
597
|
+
""")
|
598
|
+
return
|
599
|
+
|
440
600
|
# Check for subcommands
|
441
601
|
if len(sys.argv) > 1:
|
442
602
|
if sys.argv[1] == 'validate':
|