signalwire-agents 0.1.11__py3-none-any.whl → 0.1.13__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.
Files changed (26) hide show
  1. signalwire_agents/__init__.py +5 -1
  2. signalwire_agents/agent_server.py +222 -13
  3. signalwire_agents/cli/build_search.py +457 -0
  4. signalwire_agents/cli/test_swaig.py +177 -113
  5. signalwire_agents/core/agent_base.py +1 -3
  6. signalwire_agents/core/logging_config.py +232 -0
  7. signalwire_agents/core/swaig_function.py +2 -3
  8. signalwire_agents/core/swml_renderer.py +43 -28
  9. signalwire_agents/search/__init__.py +131 -0
  10. signalwire_agents/search/document_processor.py +764 -0
  11. signalwire_agents/search/index_builder.py +534 -0
  12. signalwire_agents/search/query_processor.py +371 -0
  13. signalwire_agents/search/search_engine.py +383 -0
  14. signalwire_agents/search/search_service.py +251 -0
  15. signalwire_agents/skills/native_vector_search/__init__.py +1 -0
  16. signalwire_agents/skills/native_vector_search/skill.py +352 -0
  17. signalwire_agents/skills/registry.py +2 -15
  18. signalwire_agents/utils/__init__.py +13 -1
  19. {signalwire_agents-0.1.11.dist-info → signalwire_agents-0.1.13.dist-info}/METADATA +110 -3
  20. {signalwire_agents-0.1.11.dist-info → signalwire_agents-0.1.13.dist-info}/RECORD +25 -16
  21. {signalwire_agents-0.1.11.dist-info → signalwire_agents-0.1.13.dist-info}/entry_points.txt +1 -0
  22. signalwire_agents/utils/serverless.py +0 -38
  23. {signalwire_agents-0.1.11.data → signalwire_agents-0.1.13.data}/data/schema.json +0 -0
  24. {signalwire_agents-0.1.11.dist-info → signalwire_agents-0.1.13.dist-info}/WHEEL +0 -0
  25. {signalwire_agents-0.1.11.dist-info → signalwire_agents-0.1.13.dist-info}/licenses/LICENSE +0 -0
  26. {signalwire_agents-0.1.11.dist-info → signalwire_agents-0.1.13.dist-info}/top_level.txt +0 -0
@@ -61,6 +61,7 @@ from pathlib import Path
61
61
  from typing import Dict, Any, Optional, List, Tuple
62
62
  from datetime import datetime
63
63
  import logging
64
+ import inspect
64
65
 
65
66
  try:
66
67
  # Try to import the AgentBase class
@@ -71,8 +72,11 @@ except ImportError:
71
72
  AgentBase = None
72
73
  SwaigFunctionResult = None
73
74
 
74
- # Early warning suppression for module execution warnings
75
+ # Early setup for raw mode using the central logging system
75
76
  if "--raw" in sys.argv:
77
+ # Use the central logging system's OFF mode for raw output
78
+ # This eliminates all logging output without complex suppression hacks
79
+ os.environ["SIGNALWIRE_LOG_MODE"] = "off"
76
80
  warnings.filterwarnings("ignore")
77
81
 
78
82
  # Store original print function before any potential suppression
@@ -258,6 +262,11 @@ class ServerlessSimulator:
258
262
  # Apply user overrides
259
263
  os.environ.update(self.overrides)
260
264
 
265
+ # Set appropriate logging mode for serverless simulation
266
+ if self.platform == 'cgi' and 'SIGNALWIRE_LOG_MODE' not in self.overrides:
267
+ # CGI mode should default to 'off' unless explicitly overridden
268
+ os.environ['SIGNALWIRE_LOG_MODE'] = 'off'
269
+
261
270
  self.active = True
262
271
 
263
272
  if verbose:
@@ -272,6 +281,7 @@ class ServerlessSimulator:
272
281
  print(f" GATEWAY_INTERFACE: {os.environ.get('GATEWAY_INTERFACE')}")
273
282
  print(f" HTTP_HOST: {os.environ.get('HTTP_HOST')}")
274
283
  print(f" SCRIPT_NAME: {os.environ.get('SCRIPT_NAME')}")
284
+ print(f" SIGNALWIRE_LOG_MODE: {os.environ.get('SIGNALWIRE_LOG_MODE')}")
275
285
  elif self.platform == 'cloud_function':
276
286
  print(f" GOOGLE_CLOUD_PROJECT: {os.environ.get('GOOGLE_CLOUD_PROJECT')}")
277
287
  print(f" FUNCTION_URL: {os.environ.get('FUNCTION_URL')}")
@@ -790,46 +800,18 @@ def handle_dump_swml(agent: 'AgentBase', args: argparse.Namespace) -> int:
790
800
 
791
801
 
792
802
  def setup_raw_mode_suppression():
793
- """Set up comprehensive output suppression for raw mode"""
794
- # Suppress all warnings including RuntimeWarnings
803
+ """Set up output suppression for raw mode using central logging system"""
804
+ # The central logging system is already configured via environment variable
805
+ # Just suppress any remaining warnings
795
806
  warnings.filterwarnings("ignore")
796
807
 
797
- # More aggressive logging suppression for raw mode
798
- logging.getLogger().setLevel(logging.CRITICAL + 1) # Suppress everything
799
- logging.getLogger().addHandler(logging.NullHandler())
800
-
801
- # Monkey-patch specific loggers to completely silence them
802
- def silent_log(*args, **kwargs):
803
- pass
804
-
805
- # Capture and suppress print statements in raw mode
808
+ # Capture and suppress print statements in raw mode if needed
806
809
  def suppressed_print(*args, **kwargs):
807
810
  pass
808
811
 
809
- # Replace print function globally
812
+ # Replace print function globally for raw mode
810
813
  import builtins
811
814
  builtins.print = suppressed_print
812
-
813
- # Also suppress specific loggers
814
- loggers_to_suppress = [
815
- "skill_registry",
816
- "simple_agent",
817
- "swml_service",
818
- "agent_base",
819
- "signalwire_agents"
820
- ]
821
-
822
- for logger_name in loggers_to_suppress:
823
- # Suppress standard Python logger
824
- logger = logging.getLogger(logger_name)
825
- logger.setLevel(logging.CRITICAL + 1)
826
- logger.addHandler(logging.NullHandler())
827
- # Monkey-patch all logging methods
828
- logger.debug = silent_log
829
- logger.info = silent_log
830
- logger.warning = silent_log
831
- logger.error = silent_log
832
- logger.critical = silent_log
833
815
 
834
816
 
835
817
  def generate_comprehensive_post_data(function_name: str, args: Dict[str, Any],
@@ -1767,9 +1749,71 @@ def main():
1767
1749
  original_argv = sys.argv[:]
1768
1750
  sys.argv = [sys.argv[0]] + cli_args
1769
1751
 
1770
- parser = argparse.ArgumentParser(
1752
+ # Custom ArgumentParser class with better error handling
1753
+ class CustomArgumentParser(argparse.ArgumentParser):
1754
+ def __init__(self, *args, **kwargs):
1755
+ super().__init__(*args, **kwargs)
1756
+ self._suppress_usage = False
1757
+
1758
+ def _print_message(self, message, file=None):
1759
+ """Override to suppress usage output for specific errors"""
1760
+ if self._suppress_usage:
1761
+ return
1762
+ super()._print_message(message, file)
1763
+
1764
+ def error(self, message):
1765
+ """Override error method to provide user-friendly error messages"""
1766
+ if "required" in message.lower() and "agent_path" in message:
1767
+ self._suppress_usage = True
1768
+ print("Error: Missing required argument.")
1769
+ print()
1770
+ print(f"Usage: {self.prog} <agent_path> [options]")
1771
+ print()
1772
+ print("Examples:")
1773
+ print(f" {self.prog} examples/my_agent.py --list-tools")
1774
+ print(f" {self.prog} examples/my_agent.py --dump-swml")
1775
+ print(f" {self.prog} examples/my_agent.py --exec my_function --param value")
1776
+ print()
1777
+ print(f"For full help: {self.prog} --help")
1778
+ sys.exit(2)
1779
+ else:
1780
+ # For other errors, use the default behavior
1781
+ super().error(message)
1782
+
1783
+ def print_usage(self, file=None):
1784
+ """Override print_usage to suppress output when we want custom error handling"""
1785
+ if self._suppress_usage:
1786
+ return
1787
+ super().print_usage(file)
1788
+
1789
+ def parse_args(self, args=None, namespace=None):
1790
+ """Override parse_args to provide custom error handling for missing arguments"""
1791
+ # Check if no arguments provided (just the program name)
1792
+ import sys
1793
+ if args is None:
1794
+ args = sys.argv[1:]
1795
+
1796
+ # If no arguments provided, show custom error
1797
+ if not args:
1798
+ print("Error: Missing required argument.")
1799
+ print()
1800
+ print(f"Usage: {self.prog} <agent_path> [options]")
1801
+ print()
1802
+ print("Examples:")
1803
+ print(f" {self.prog} examples/my_agent.py --list-tools")
1804
+ print(f" {self.prog} examples/my_agent.py --dump-swml")
1805
+ print(f" {self.prog} examples/my_agent.py --exec my_function --param value")
1806
+ print()
1807
+ print(f"For full help: {self.prog} --help")
1808
+ sys.exit(2)
1809
+
1810
+ # Otherwise, use default parsing
1811
+ return super().parse_args(args, namespace)
1812
+
1813
+ parser = CustomArgumentParser(
1771
1814
  description="Test SWAIG functions from agent applications with comprehensive simulation",
1772
1815
  formatter_class=argparse.RawDescriptionHelpFormatter,
1816
+ usage="%(prog)s <agent_path> [options]",
1773
1817
  epilog="""
1774
1818
  Examples:
1775
1819
  # Function testing with --exec syntax
@@ -1834,6 +1878,7 @@ Examples:
1834
1878
  """
1835
1879
  )
1836
1880
 
1881
+ # Required positional arguments
1837
1882
  parser.add_argument(
1838
1883
  "agent_path",
1839
1884
  help="Path to the Python file containing the agent"
@@ -1851,260 +1896,279 @@ Examples:
1851
1896
  help="JSON string containing the arguments to pass to the function (when using positional tool_name)"
1852
1897
  )
1853
1898
 
1854
- parser.add_argument(
1899
+ # Function Execution Options
1900
+ func_group = parser.add_argument_group('Function Execution Options')
1901
+ func_group.add_argument(
1855
1902
  "--exec",
1856
1903
  metavar="FUNCTION",
1857
1904
  help="Execute a function with CLI-style arguments (replaces tool_name and --args)"
1858
1905
  )
1859
1906
 
1860
- parser.add_argument(
1907
+ func_group.add_argument(
1861
1908
  "--custom-data",
1862
1909
  help="Optional JSON string containing custom post_data overrides",
1863
1910
  default="{}"
1864
1911
  )
1865
1912
 
1866
- parser.add_argument(
1913
+ # Agent Discovery and Selection
1914
+ agent_group = parser.add_argument_group('Agent Discovery and Selection')
1915
+ agent_group.add_argument(
1867
1916
  "--agent-class",
1868
1917
  help="Name of the agent class to use (required only if multiple agents in file)"
1869
1918
  )
1870
1919
 
1871
- parser.add_argument(
1872
- "--list-tools",
1920
+ agent_group.add_argument(
1921
+ "--list-agents",
1873
1922
  action="store_true",
1874
- help="List all available tools in the agent and exit"
1923
+ help="List all available agents in the file and exit"
1875
1924
  )
1876
1925
 
1877
- parser.add_argument(
1878
- "--list-agents",
1926
+ agent_group.add_argument(
1927
+ "--list-tools",
1879
1928
  action="store_true",
1880
- help="List all available agents in the file and exit"
1929
+ help="List all available tools in the agent and exit"
1881
1930
  )
1882
1931
 
1883
- parser.add_argument(
1932
+ # Output and Debugging Options
1933
+ output_group = parser.add_argument_group('Output and Debugging Options')
1934
+ output_group.add_argument(
1884
1935
  "--verbose", "-v",
1885
1936
  action="store_true",
1886
1937
  help="Enable verbose output"
1887
1938
  )
1888
1939
 
1889
- parser.add_argument(
1890
- "--fake-full-data",
1891
- action="store_true",
1892
- help="Generate comprehensive fake post_data with all possible keys"
1893
- )
1894
-
1895
- parser.add_argument(
1896
- "--minimal",
1940
+ output_group.add_argument(
1941
+ "--raw",
1897
1942
  action="store_true",
1898
- help="Use minimal post_data (only essential keys)"
1943
+ help="Output raw SWML JSON only (no headers, useful for piping to jq/yq)"
1899
1944
  )
1900
1945
 
1901
- parser.add_argument(
1946
+ # SWML Generation and Testing
1947
+ swml_group = parser.add_argument_group('SWML Generation and Testing')
1948
+ swml_group.add_argument(
1902
1949
  "--dump-swml",
1903
1950
  action="store_true",
1904
1951
  help="Dump the SWML document from the agent and exit"
1905
1952
  )
1906
1953
 
1907
- parser.add_argument(
1908
- "--raw",
1909
- action="store_true",
1910
- help="Output raw SWML JSON only (no headers, useful for piping to jq/yq)"
1954
+ swml_group.add_argument(
1955
+ "--fake-full-data",
1956
+ action="store_true",
1957
+ help="Generate comprehensive fake post_data with all possible keys"
1911
1958
  )
1912
1959
 
1913
- # ===== NEW SWML TESTING ARGUMENTS =====
1960
+ swml_group.add_argument(
1961
+ "--minimal",
1962
+ action="store_true",
1963
+ help="Use minimal post_data (only essential keys)"
1964
+ )
1914
1965
 
1915
- parser.add_argument(
1966
+ # Call Configuration Options
1967
+ call_group = parser.add_argument_group('Call Configuration Options')
1968
+ call_group.add_argument(
1916
1969
  "--call-type",
1917
1970
  choices=["sip", "webrtc"],
1918
1971
  default="webrtc",
1919
1972
  help="Type of call for SWML generation (default: webrtc)"
1920
1973
  )
1921
1974
 
1922
- parser.add_argument(
1975
+ call_group.add_argument(
1923
1976
  "--call-direction",
1924
1977
  choices=["inbound", "outbound"],
1925
1978
  default="inbound",
1926
1979
  help="Direction of call for SWML generation (default: inbound)"
1927
1980
  )
1928
1981
 
1929
- parser.add_argument(
1982
+ call_group.add_argument(
1930
1983
  "--call-state",
1931
1984
  default="created",
1932
1985
  help="State of call for SWML generation (default: created)"
1933
1986
  )
1934
1987
 
1935
- parser.add_argument(
1988
+ call_group.add_argument(
1936
1989
  "--call-id",
1937
1990
  help="Override call_id in fake SWML post_data"
1938
1991
  )
1939
1992
 
1940
- parser.add_argument(
1941
- "--project-id",
1942
- help="Override project_id in fake SWML post_data"
1943
- )
1944
-
1945
- parser.add_argument(
1946
- "--space-id",
1947
- help="Override space_id in fake SWML post_data"
1948
- )
1949
-
1950
- parser.add_argument(
1993
+ call_group.add_argument(
1951
1994
  "--from-number",
1952
1995
  help="Override 'from' address in fake SWML post_data"
1953
1996
  )
1954
1997
 
1955
- parser.add_argument(
1998
+ call_group.add_argument(
1956
1999
  "--to-extension",
1957
2000
  help="Override 'to' address in fake SWML post_data"
1958
2001
  )
1959
2002
 
1960
- parser.add_argument(
2003
+ # SignalWire Platform Configuration
2004
+ platform_group = parser.add_argument_group('SignalWire Platform Configuration')
2005
+ platform_group.add_argument(
2006
+ "--project-id",
2007
+ help="Override project_id in fake SWML post_data"
2008
+ )
2009
+
2010
+ platform_group.add_argument(
2011
+ "--space-id",
2012
+ help="Override space_id in fake SWML post_data"
2013
+ )
2014
+
2015
+ # User Variables and Query Parameters
2016
+ vars_group = parser.add_argument_group('User Variables and Query Parameters')
2017
+ vars_group.add_argument(
1961
2018
  "--user-vars",
1962
2019
  help="JSON string for vars.userVariables in fake SWML post_data"
1963
2020
  )
1964
2021
 
1965
- parser.add_argument(
2022
+ vars_group.add_argument(
1966
2023
  "--query-params",
1967
2024
  help="JSON string for query parameters (merged into userVariables)"
1968
2025
  )
1969
2026
 
1970
- parser.add_argument(
2027
+ # Data Override Options
2028
+ override_group = parser.add_argument_group('Data Override Options')
2029
+ override_group.add_argument(
1971
2030
  "--override",
1972
2031
  action="append",
1973
2032
  default=[],
1974
2033
  help="Override specific values using dot notation (e.g., --override call.state=answered)"
1975
2034
  )
1976
2035
 
1977
- parser.add_argument(
2036
+ override_group.add_argument(
1978
2037
  "--override-json",
1979
2038
  action="append",
1980
2039
  default=[],
1981
2040
  help="Override with JSON values using dot notation (e.g., --override-json vars.custom='{\"key\":\"value\"}')"
1982
2041
  )
1983
2042
 
1984
- parser.add_argument(
2043
+ # HTTP Request Simulation
2044
+ http_group = parser.add_argument_group('HTTP Request Simulation')
2045
+ http_group.add_argument(
1985
2046
  "--header",
1986
2047
  action="append",
1987
2048
  default=[],
1988
2049
  help="Add HTTP headers for mock request (e.g., --header Authorization=Bearer token)"
1989
2050
  )
1990
2051
 
1991
- parser.add_argument(
2052
+ http_group.add_argument(
1992
2053
  "--method",
1993
2054
  default="POST",
1994
2055
  help="HTTP method for mock request (default: POST)"
1995
2056
  )
1996
2057
 
1997
- parser.add_argument(
2058
+ http_group.add_argument(
1998
2059
  "--body",
1999
2060
  help="JSON string for mock request body"
2000
2061
  )
2001
2062
 
2002
- # ===== SERVERLESS SIMULATION ARGUMENTS =====
2003
-
2004
- parser.add_argument(
2063
+ # Serverless Environment Simulation
2064
+ serverless_group = parser.add_argument_group('Serverless Environment Simulation')
2065
+ serverless_group.add_argument(
2005
2066
  "--simulate-serverless",
2006
2067
  choices=["lambda", "cgi", "cloud_function", "azure_function"],
2007
2068
  help="Simulate serverless platform environment (lambda, cgi, cloud_function, azure_function)"
2008
2069
  )
2009
2070
 
2010
- parser.add_argument(
2071
+ serverless_group.add_argument(
2011
2072
  "--env",
2012
2073
  action="append",
2013
2074
  default=[],
2014
2075
  help="Set environment variable (e.g., --env API_KEY=secret123)"
2015
2076
  )
2016
2077
 
2017
- parser.add_argument(
2078
+ serverless_group.add_argument(
2018
2079
  "--env-file",
2019
2080
  help="Load environment variables from file"
2020
2081
  )
2021
2082
 
2022
- # AWS Lambda specific options
2023
- parser.add_argument(
2083
+ serverless_group.add_argument(
2084
+ "--serverless-mode",
2085
+ help="Legacy option for serverless mode (use --simulate-serverless instead)"
2086
+ )
2087
+
2088
+ # AWS Lambda Configuration
2089
+ aws_group = parser.add_argument_group('AWS Lambda Configuration')
2090
+ aws_group.add_argument(
2024
2091
  "--aws-function-name",
2025
2092
  help="AWS Lambda function name (overrides default)"
2026
2093
  )
2027
2094
 
2028
- parser.add_argument(
2095
+ aws_group.add_argument(
2029
2096
  "--aws-function-url",
2030
2097
  help="AWS Lambda function URL (overrides default)"
2031
2098
  )
2032
2099
 
2033
- parser.add_argument(
2100
+ aws_group.add_argument(
2034
2101
  "--aws-region",
2035
2102
  help="AWS region (overrides default)"
2036
2103
  )
2037
2104
 
2038
- parser.add_argument(
2105
+ aws_group.add_argument(
2039
2106
  "--aws-api-gateway-id",
2040
2107
  help="AWS API Gateway ID for API Gateway URLs"
2041
2108
  )
2042
2109
 
2043
- parser.add_argument(
2110
+ aws_group.add_argument(
2044
2111
  "--aws-stage",
2045
2112
  help="AWS API Gateway stage (default: prod)"
2046
2113
  )
2047
2114
 
2048
- # CGI specific options
2049
- parser.add_argument(
2115
+ # CGI Configuration
2116
+ cgi_group = parser.add_argument_group('CGI Configuration')
2117
+ cgi_group.add_argument(
2050
2118
  "--cgi-host",
2051
2119
  help="CGI server hostname (required for CGI simulation)"
2052
2120
  )
2053
2121
 
2054
- parser.add_argument(
2122
+ cgi_group.add_argument(
2055
2123
  "--cgi-script-name",
2056
2124
  help="CGI script name/path (overrides default)"
2057
2125
  )
2058
2126
 
2059
- parser.add_argument(
2127
+ cgi_group.add_argument(
2060
2128
  "--cgi-https",
2061
2129
  action="store_true",
2062
2130
  help="Use HTTPS for CGI URLs"
2063
2131
  )
2064
2132
 
2065
- parser.add_argument(
2133
+ cgi_group.add_argument(
2066
2134
  "--cgi-path-info",
2067
2135
  help="CGI PATH_INFO value"
2068
2136
  )
2069
2137
 
2070
- # Google Cloud Functions specific options
2071
- parser.add_argument(
2138
+ # Google Cloud Platform Configuration
2139
+ gcp_group = parser.add_argument_group('Google Cloud Platform Configuration')
2140
+ gcp_group.add_argument(
2072
2141
  "--gcp-project",
2073
2142
  help="Google Cloud project ID (overrides default)"
2074
2143
  )
2075
2144
 
2076
- parser.add_argument(
2145
+ gcp_group.add_argument(
2077
2146
  "--gcp-function-url",
2078
2147
  help="Google Cloud Function URL (overrides default)"
2079
2148
  )
2080
2149
 
2081
- parser.add_argument(
2150
+ gcp_group.add_argument(
2082
2151
  "--gcp-region",
2083
2152
  help="Google Cloud region (overrides default)"
2084
2153
  )
2085
2154
 
2086
- parser.add_argument(
2155
+ gcp_group.add_argument(
2087
2156
  "--gcp-service",
2088
2157
  help="Google Cloud service name (overrides default)"
2089
2158
  )
2090
2159
 
2091
- # Azure Functions specific options
2092
- parser.add_argument(
2160
+ # Azure Functions Configuration
2161
+ azure_group = parser.add_argument_group('Azure Functions Configuration')
2162
+ azure_group.add_argument(
2093
2163
  "--azure-env",
2094
2164
  help="Azure Functions environment (overrides default)"
2095
2165
  )
2096
2166
 
2097
- parser.add_argument(
2167
+ azure_group.add_argument(
2098
2168
  "--azure-function-url",
2099
2169
  help="Azure Function URL (overrides default)"
2100
2170
  )
2101
2171
 
2102
- # Legacy compatibility
2103
- parser.add_argument(
2104
- "--serverless-mode",
2105
- help="Legacy option for serverless mode (use --simulate-serverless instead)"
2106
- )
2107
-
2108
2172
  args = parser.parse_args()
2109
2173
 
2110
2174
  # Restore original sys.argv
@@ -80,7 +80,7 @@ from signalwire_agents.core.swml_service import SWMLService
80
80
  from signalwire_agents.core.swml_handler import AIVerbHandler
81
81
  from signalwire_agents.core.skill_manager import SkillManager
82
82
  from signalwire_agents.utils.schema_utils import SchemaUtils
83
- from signalwire_agents.utils.serverless import get_execution_mode, is_serverless_mode
83
+ from signalwire_agents.core.logging_config import get_logger, get_execution_mode
84
84
 
85
85
  # Create a logger
86
86
  logger = structlog.get_logger("agent_base")
@@ -2227,8 +2227,6 @@ class AgentBase(SWMLService):
2227
2227
 
2228
2228
  self.log.info("callback_endpoint_registered", path=callback_path)
2229
2229
 
2230
- @classmethod
2231
-
2232
2230
  # ----------------------------------------------------------------------
2233
2231
  # AI Verb Configuration Methods
2234
2232
  # ----------------------------------------------------------------------