signalwire-agents 0.1.13__py3-none-any.whl → 0.1.15__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 +446 -78
- signalwire_agents/core/logging_config.py +162 -18
- signalwire_agents/core/skill_manager.py +2 -2
- 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.13.dist-info → signalwire_agents-0.1.15.dist-info}/METADATA +1 -1
- {signalwire_agents-0.1.13.dist-info → signalwire_agents-0.1.15.dist-info}/RECORD +20 -20
- {signalwire_agents-0.1.13.dist-info → signalwire_agents-0.1.15.dist-info}/entry_points.txt +1 -1
- {signalwire_agents-0.1.13.data → signalwire_agents-0.1.15.data}/data/schema.json +0 -0
- {signalwire_agents-0.1.13.dist-info → signalwire_agents-0.1.15.dist-info}/WHEEL +0 -0
- {signalwire_agents-0.1.13.dist-info → signalwire_agents-0.1.15.dist-info}/licenses/LICENSE +0 -0
- {signalwire_agents-0.1.13.dist-info → signalwire_agents-0.1.15.dist-info}/top_level.txt +0 -0
@@ -46,8 +46,14 @@ Examples:
|
|
46
46
|
swaig-test examples/my_agent.py --dump-swml --raw | jq '.sections.main[1].ai.SWAIG.functions'
|
47
47
|
"""
|
48
48
|
|
49
|
+
# CRITICAL: Set environment variable BEFORE any imports to suppress logs for --raw
|
49
50
|
import sys
|
50
51
|
import os
|
52
|
+
|
53
|
+
if "--raw" in sys.argv or "--dump-swml" in sys.argv:
|
54
|
+
os.environ["SIGNALWIRE_LOG_MODE"] = "off"
|
55
|
+
|
56
|
+
import warnings
|
51
57
|
import json
|
52
58
|
import importlib.util
|
53
59
|
import argparse
|
@@ -56,13 +62,18 @@ import time
|
|
56
62
|
import hashlib
|
57
63
|
import re
|
58
64
|
import requests
|
59
|
-
import warnings
|
60
65
|
from pathlib import Path
|
61
66
|
from typing import Dict, Any, Optional, List, Tuple
|
62
67
|
from datetime import datetime
|
63
68
|
import logging
|
64
69
|
import inspect
|
65
70
|
|
71
|
+
# Store original print function before any potential suppression
|
72
|
+
original_print = print
|
73
|
+
|
74
|
+
# Add the parent directory to the path so we can import signalwire_agents
|
75
|
+
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
76
|
+
|
66
77
|
try:
|
67
78
|
# Try to import the AgentBase class
|
68
79
|
from signalwire_agents.core.agent_base import AgentBase
|
@@ -72,22 +83,15 @@ except ImportError:
|
|
72
83
|
AgentBase = None
|
73
84
|
SwaigFunctionResult = None
|
74
85
|
|
75
|
-
#
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
# Add the parent directory to the path so we can import signalwire_agents
|
86
|
-
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
87
|
-
|
88
|
-
from signalwire_agents import AgentBase
|
89
|
-
from signalwire_agents.core.function_result import SwaigFunctionResult
|
90
|
-
|
86
|
+
# Reset logging configuration if --raw flag was set
|
87
|
+
# This must happen AFTER signalwire_agents imports but BEFORE any logging is used
|
88
|
+
if "--raw" in sys.argv or "--dump-swml" in sys.argv:
|
89
|
+
try:
|
90
|
+
from signalwire_agents.core.logging_config import reset_logging_configuration, configure_logging
|
91
|
+
reset_logging_configuration()
|
92
|
+
configure_logging() # Reconfigure with the new environment variable
|
93
|
+
except ImportError:
|
94
|
+
pass
|
91
95
|
|
92
96
|
# ===== MOCK REQUEST OBJECTS FOR DYNAMIC AGENT TESTING =====
|
93
97
|
|
@@ -666,7 +670,6 @@ def handle_dump_swml(agent: 'AgentBase', args: argparse.Namespace) -> int:
|
|
666
670
|
Exit code (0 for success, 1 for error)
|
667
671
|
"""
|
668
672
|
if not args.raw:
|
669
|
-
print("\nGenerating SWML document...")
|
670
673
|
if args.verbose:
|
671
674
|
print(f"Agent: {agent.get_name()}")
|
672
675
|
print(f"Route: {agent.route}")
|
@@ -767,20 +770,13 @@ def handle_dump_swml(agent: 'AgentBase', args: argparse.Namespace) -> int:
|
|
767
770
|
# Output only the raw JSON for piping to jq/yq
|
768
771
|
print(swml_doc)
|
769
772
|
else:
|
770
|
-
#
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
# Parse and show formatted JSON for better readability
|
778
|
-
try:
|
779
|
-
swml_parsed = json.loads(swml_doc)
|
780
|
-
print("\nFormatted SWML:")
|
781
|
-
print(json.dumps(swml_parsed, indent=2))
|
782
|
-
except json.JSONDecodeError:
|
783
|
-
print("\nNote: SWML document is not valid JSON format")
|
773
|
+
# Output formatted JSON (like raw but pretty-printed)
|
774
|
+
try:
|
775
|
+
swml_parsed = json.loads(swml_doc)
|
776
|
+
print(json.dumps(swml_parsed, indent=2))
|
777
|
+
except json.JSONDecodeError:
|
778
|
+
# If not valid JSON, show raw
|
779
|
+
print(swml_doc)
|
784
780
|
|
785
781
|
return 0
|
786
782
|
|
@@ -1375,6 +1371,94 @@ def execute_external_webhook_function(func: 'SWAIGFunction', function_name: str,
|
|
1375
1371
|
return {"error": error_msg}
|
1376
1372
|
|
1377
1373
|
|
1374
|
+
def display_agent_tools(agent: 'AgentBase', verbose: bool = False) -> None:
|
1375
|
+
"""
|
1376
|
+
Display the available SWAIG functions for an agent
|
1377
|
+
|
1378
|
+
Args:
|
1379
|
+
agent: The agent instance
|
1380
|
+
verbose: Whether to show verbose details
|
1381
|
+
"""
|
1382
|
+
print("\nAvailable SWAIG functions:")
|
1383
|
+
if hasattr(agent, '_swaig_functions') and agent._swaig_functions:
|
1384
|
+
for name, func in agent._swaig_functions.items():
|
1385
|
+
if isinstance(func, dict):
|
1386
|
+
# DataMap function
|
1387
|
+
description = func.get('description', 'DataMap function (serverless)')
|
1388
|
+
print(f" {name} - {description}")
|
1389
|
+
|
1390
|
+
# Show parameters for DataMap functions
|
1391
|
+
if 'parameters' in func and func['parameters']:
|
1392
|
+
params = func['parameters']
|
1393
|
+
# Handle both formats: direct properties dict or full schema
|
1394
|
+
if 'properties' in params:
|
1395
|
+
properties = params['properties']
|
1396
|
+
required_fields = params.get('required', [])
|
1397
|
+
else:
|
1398
|
+
properties = params
|
1399
|
+
required_fields = []
|
1400
|
+
|
1401
|
+
if properties:
|
1402
|
+
print(f" Parameters:")
|
1403
|
+
for param_name, param_def in properties.items():
|
1404
|
+
param_type = param_def.get('type', 'unknown')
|
1405
|
+
param_desc = param_def.get('description', 'No description')
|
1406
|
+
is_required = param_name in required_fields
|
1407
|
+
required_marker = " (required)" if is_required else ""
|
1408
|
+
print(f" {param_name} ({param_type}){required_marker}: {param_desc}")
|
1409
|
+
else:
|
1410
|
+
print(f" Parameters: None")
|
1411
|
+
else:
|
1412
|
+
print(f" Parameters: None")
|
1413
|
+
|
1414
|
+
if verbose:
|
1415
|
+
print(f" Config: {json.dumps(func, indent=6)}")
|
1416
|
+
else:
|
1417
|
+
# Regular SWAIG function
|
1418
|
+
func_type = ""
|
1419
|
+
if hasattr(func, 'webhook_url') and func.webhook_url and func.is_external:
|
1420
|
+
func_type = " (EXTERNAL webhook)"
|
1421
|
+
elif hasattr(func, 'webhook_url') and func.webhook_url:
|
1422
|
+
func_type = " (webhook)"
|
1423
|
+
else:
|
1424
|
+
func_type = " (LOCAL webhook)"
|
1425
|
+
|
1426
|
+
print(f" {name} - {func.description}{func_type}")
|
1427
|
+
|
1428
|
+
# Show external URL if applicable
|
1429
|
+
if hasattr(func, 'webhook_url') and func.webhook_url and func.is_external:
|
1430
|
+
print(f" External URL: {func.webhook_url}")
|
1431
|
+
|
1432
|
+
# Show parameters
|
1433
|
+
if hasattr(func, 'parameters') and func.parameters:
|
1434
|
+
params = func.parameters
|
1435
|
+
# Handle both formats: direct properties dict or full schema
|
1436
|
+
if 'properties' in params:
|
1437
|
+
properties = params['properties']
|
1438
|
+
required_fields = params.get('required', [])
|
1439
|
+
else:
|
1440
|
+
properties = params
|
1441
|
+
required_fields = []
|
1442
|
+
|
1443
|
+
if properties:
|
1444
|
+
print(f" Parameters:")
|
1445
|
+
for param_name, param_def in properties.items():
|
1446
|
+
param_type = param_def.get('type', 'unknown')
|
1447
|
+
param_desc = param_def.get('description', 'No description')
|
1448
|
+
is_required = param_name in required_fields
|
1449
|
+
required_marker = " (required)" if is_required else ""
|
1450
|
+
print(f" {param_name} ({param_type}){required_marker}: {param_desc}")
|
1451
|
+
else:
|
1452
|
+
print(f" Parameters: None")
|
1453
|
+
else:
|
1454
|
+
print(f" Parameters: None")
|
1455
|
+
|
1456
|
+
if verbose:
|
1457
|
+
print(f" Function object: {func}")
|
1458
|
+
else:
|
1459
|
+
print(" No SWAIG functions registered")
|
1460
|
+
|
1461
|
+
|
1378
1462
|
def discover_agents_in_file(agent_path: str) -> List[Dict[str, Any]]:
|
1379
1463
|
"""
|
1380
1464
|
Discover all available agents in a Python file without instantiating them
|
@@ -2315,7 +2399,29 @@ Examples:
|
|
2315
2399
|
|
2316
2400
|
print()
|
2317
2401
|
|
2318
|
-
if
|
2402
|
+
# Show tools if there's only one agent or if --agent-class is specified
|
2403
|
+
show_tools = False
|
2404
|
+
selected_agent = None
|
2405
|
+
|
2406
|
+
if len(agents) == 1:
|
2407
|
+
# Single agent - show tools automatically
|
2408
|
+
show_tools = True
|
2409
|
+
selected_agent = agents[0]['object']
|
2410
|
+
print("This file contains a single agent, no --agent-class needed.")
|
2411
|
+
elif args.agent_class:
|
2412
|
+
# Specific agent class requested - show tools for that agent
|
2413
|
+
for agent_info in agents:
|
2414
|
+
if agent_info['class_name'] == args.agent_class:
|
2415
|
+
show_tools = True
|
2416
|
+
selected_agent = agent_info['object']
|
2417
|
+
break
|
2418
|
+
|
2419
|
+
if not selected_agent:
|
2420
|
+
print(f"Error: Agent class '{args.agent_class}' not found.")
|
2421
|
+
print(f"Available agents: {[a['class_name'] for a in agents]}")
|
2422
|
+
return 1
|
2423
|
+
else:
|
2424
|
+
# Multiple agents, no specific class - show usage examples
|
2319
2425
|
print("To use a specific agent with this tool:")
|
2320
2426
|
print(f" swaig-test {args.agent_path} [tool_name] [args] --agent-class <AgentClassName>")
|
2321
2427
|
print()
|
@@ -2324,8 +2430,24 @@ Examples:
|
|
2324
2430
|
print(f" swaig-test {args.agent_path} --list-tools --agent-class {agent_info['class_name']}")
|
2325
2431
|
print(f" swaig-test {args.agent_path} --dump-swml --agent-class {agent_info['class_name']}")
|
2326
2432
|
print()
|
2327
|
-
|
2328
|
-
|
2433
|
+
|
2434
|
+
# Show tools if we have a selected agent
|
2435
|
+
if show_tools and selected_agent:
|
2436
|
+
try:
|
2437
|
+
# If it's a class, try to instantiate it
|
2438
|
+
if not isinstance(selected_agent, AgentBase):
|
2439
|
+
if isinstance(selected_agent, type) and issubclass(selected_agent, AgentBase):
|
2440
|
+
selected_agent = selected_agent()
|
2441
|
+
else:
|
2442
|
+
print(f"Warning: Cannot instantiate agent to show tools")
|
2443
|
+
return 0
|
2444
|
+
|
2445
|
+
display_agent_tools(selected_agent, args.verbose)
|
2446
|
+
except Exception as e:
|
2447
|
+
print(f"Warning: Could not load agent tools: {e}")
|
2448
|
+
if args.verbose:
|
2449
|
+
import traceback
|
2450
|
+
traceback.print_exc()
|
2329
2451
|
|
2330
2452
|
return 0
|
2331
2453
|
|
@@ -2374,84 +2496,7 @@ Examples:
|
|
2374
2496
|
|
2375
2497
|
# List tools if requested
|
2376
2498
|
if args.list_tools:
|
2377
|
-
|
2378
|
-
if hasattr(agent, '_swaig_functions') and agent._swaig_functions:
|
2379
|
-
for name, func in agent._swaig_functions.items():
|
2380
|
-
if isinstance(func, dict):
|
2381
|
-
# DataMap function
|
2382
|
-
description = func.get('description', 'DataMap function (serverless)')
|
2383
|
-
print(f" {name} - {description}")
|
2384
|
-
|
2385
|
-
# Show parameters for DataMap functions
|
2386
|
-
if 'parameters' in func and func['parameters']:
|
2387
|
-
params = func['parameters']
|
2388
|
-
# Handle both formats: direct properties dict or full schema
|
2389
|
-
if 'properties' in params:
|
2390
|
-
properties = params['properties']
|
2391
|
-
required_fields = params.get('required', [])
|
2392
|
-
else:
|
2393
|
-
properties = params
|
2394
|
-
required_fields = []
|
2395
|
-
|
2396
|
-
if properties:
|
2397
|
-
print(f" Parameters:")
|
2398
|
-
for param_name, param_def in properties.items():
|
2399
|
-
param_type = param_def.get('type', 'unknown')
|
2400
|
-
param_desc = param_def.get('description', 'No description')
|
2401
|
-
is_required = param_name in required_fields
|
2402
|
-
required_marker = " (required)" if is_required else ""
|
2403
|
-
print(f" {param_name} ({param_type}){required_marker}: {param_desc}")
|
2404
|
-
else:
|
2405
|
-
print(f" Parameters: None")
|
2406
|
-
else:
|
2407
|
-
print(f" Parameters: None")
|
2408
|
-
|
2409
|
-
if args.verbose:
|
2410
|
-
print(f" Config: {json.dumps(func, indent=6)}")
|
2411
|
-
else:
|
2412
|
-
# Regular SWAIG function
|
2413
|
-
func_type = ""
|
2414
|
-
if hasattr(func, 'webhook_url') and func.webhook_url and func.is_external:
|
2415
|
-
func_type = " (EXTERNAL webhook)"
|
2416
|
-
elif hasattr(func, 'webhook_url') and func.webhook_url:
|
2417
|
-
func_type = " (webhook)"
|
2418
|
-
else:
|
2419
|
-
func_type = " (LOCAL webhook)"
|
2420
|
-
|
2421
|
-
print(f" {name} - {func.description}{func_type}")
|
2422
|
-
|
2423
|
-
# Show external URL if applicable
|
2424
|
-
if hasattr(func, 'webhook_url') and func.webhook_url and func.is_external:
|
2425
|
-
print(f" External URL: {func.webhook_url}")
|
2426
|
-
|
2427
|
-
# Show parameters
|
2428
|
-
if hasattr(func, 'parameters') and func.parameters:
|
2429
|
-
params = func.parameters
|
2430
|
-
# Handle both formats: direct properties dict or full schema
|
2431
|
-
if 'properties' in params:
|
2432
|
-
properties = params['properties']
|
2433
|
-
required_fields = params.get('required', [])
|
2434
|
-
else:
|
2435
|
-
properties = params
|
2436
|
-
required_fields = []
|
2437
|
-
|
2438
|
-
if properties:
|
2439
|
-
print(f" Parameters:")
|
2440
|
-
for param_name, param_def in properties.items():
|
2441
|
-
param_type = param_def.get('type', 'unknown')
|
2442
|
-
param_desc = param_def.get('description', 'No description')
|
2443
|
-
is_required = param_name in required_fields
|
2444
|
-
required_marker = " (required)" if is_required else ""
|
2445
|
-
print(f" {param_name} ({param_type}){required_marker}: {param_desc}")
|
2446
|
-
else:
|
2447
|
-
print(f" Parameters: None")
|
2448
|
-
else:
|
2449
|
-
print(f" Parameters: None")
|
2450
|
-
|
2451
|
-
if args.verbose:
|
2452
|
-
print(f" Function object: {func}")
|
2453
|
-
else:
|
2454
|
-
print(" No SWAIG functions registered")
|
2499
|
+
display_agent_tools(agent, args.verbose)
|
2455
2500
|
return 0
|
2456
2501
|
|
2457
2502
|
# Dump SWML if requested
|
@@ -2606,4 +2651,4 @@ def console_entry_point():
|
|
2606
2651
|
|
2607
2652
|
|
2608
2653
|
if __name__ == "__main__":
|
2609
|
-
sys.exit(main())
|
2654
|
+
sys.exit(main())
|