signalwire-agents 0.1.13__py3-none-any.whl → 1.0.17.dev4__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 (143) hide show
  1. signalwire_agents/__init__.py +99 -15
  2. signalwire_agents/agent_server.py +248 -60
  3. signalwire_agents/agents/bedrock.py +296 -0
  4. signalwire_agents/cli/__init__.py +9 -0
  5. signalwire_agents/cli/build_search.py +951 -41
  6. signalwire_agents/cli/config.py +80 -0
  7. signalwire_agents/cli/core/__init__.py +10 -0
  8. signalwire_agents/cli/core/agent_loader.py +470 -0
  9. signalwire_agents/cli/core/argparse_helpers.py +179 -0
  10. signalwire_agents/cli/core/dynamic_config.py +71 -0
  11. signalwire_agents/cli/core/service_loader.py +303 -0
  12. signalwire_agents/cli/dokku.py +2320 -0
  13. signalwire_agents/cli/execution/__init__.py +10 -0
  14. signalwire_agents/cli/execution/datamap_exec.py +446 -0
  15. signalwire_agents/cli/execution/webhook_exec.py +134 -0
  16. signalwire_agents/cli/init_project.py +2636 -0
  17. signalwire_agents/cli/output/__init__.py +10 -0
  18. signalwire_agents/cli/output/output_formatter.py +255 -0
  19. signalwire_agents/cli/output/swml_dump.py +186 -0
  20. signalwire_agents/cli/simulation/__init__.py +10 -0
  21. signalwire_agents/cli/simulation/data_generation.py +374 -0
  22. signalwire_agents/cli/simulation/data_overrides.py +200 -0
  23. signalwire_agents/cli/simulation/mock_env.py +282 -0
  24. signalwire_agents/cli/swaig_test_wrapper.py +52 -0
  25. signalwire_agents/cli/test_swaig.py +566 -2366
  26. signalwire_agents/cli/types.py +81 -0
  27. signalwire_agents/core/__init__.py +2 -2
  28. signalwire_agents/core/agent/__init__.py +12 -0
  29. signalwire_agents/core/agent/config/__init__.py +12 -0
  30. signalwire_agents/core/agent/deployment/__init__.py +9 -0
  31. signalwire_agents/core/agent/deployment/handlers/__init__.py +9 -0
  32. signalwire_agents/core/agent/prompt/__init__.py +14 -0
  33. signalwire_agents/core/agent/prompt/manager.py +306 -0
  34. signalwire_agents/core/agent/routing/__init__.py +9 -0
  35. signalwire_agents/core/agent/security/__init__.py +9 -0
  36. signalwire_agents/core/agent/swml/__init__.py +9 -0
  37. signalwire_agents/core/agent/tools/__init__.py +15 -0
  38. signalwire_agents/core/agent/tools/decorator.py +97 -0
  39. signalwire_agents/core/agent/tools/registry.py +210 -0
  40. signalwire_agents/core/agent_base.py +845 -2916
  41. signalwire_agents/core/auth_handler.py +233 -0
  42. signalwire_agents/core/config_loader.py +259 -0
  43. signalwire_agents/core/contexts.py +418 -0
  44. signalwire_agents/core/data_map.py +3 -15
  45. signalwire_agents/core/function_result.py +116 -44
  46. signalwire_agents/core/logging_config.py +162 -18
  47. signalwire_agents/core/mixins/__init__.py +28 -0
  48. signalwire_agents/core/mixins/ai_config_mixin.py +442 -0
  49. signalwire_agents/core/mixins/auth_mixin.py +280 -0
  50. signalwire_agents/core/mixins/prompt_mixin.py +358 -0
  51. signalwire_agents/core/mixins/serverless_mixin.py +460 -0
  52. signalwire_agents/core/mixins/skill_mixin.py +55 -0
  53. signalwire_agents/core/mixins/state_mixin.py +153 -0
  54. signalwire_agents/core/mixins/tool_mixin.py +230 -0
  55. signalwire_agents/core/mixins/web_mixin.py +1142 -0
  56. signalwire_agents/core/security_config.py +333 -0
  57. signalwire_agents/core/skill_base.py +84 -1
  58. signalwire_agents/core/skill_manager.py +62 -20
  59. signalwire_agents/core/swaig_function.py +18 -5
  60. signalwire_agents/core/swml_builder.py +207 -11
  61. signalwire_agents/core/swml_handler.py +27 -21
  62. signalwire_agents/core/swml_renderer.py +123 -312
  63. signalwire_agents/core/swml_service.py +171 -203
  64. signalwire_agents/mcp_gateway/__init__.py +29 -0
  65. signalwire_agents/mcp_gateway/gateway_service.py +564 -0
  66. signalwire_agents/mcp_gateway/mcp_manager.py +513 -0
  67. signalwire_agents/mcp_gateway/session_manager.py +218 -0
  68. signalwire_agents/prefabs/concierge.py +0 -3
  69. signalwire_agents/prefabs/faq_bot.py +0 -3
  70. signalwire_agents/prefabs/info_gatherer.py +0 -3
  71. signalwire_agents/prefabs/receptionist.py +0 -3
  72. signalwire_agents/prefabs/survey.py +0 -3
  73. signalwire_agents/schema.json +9218 -5489
  74. signalwire_agents/search/__init__.py +7 -1
  75. signalwire_agents/search/document_processor.py +490 -31
  76. signalwire_agents/search/index_builder.py +307 -37
  77. signalwire_agents/search/migration.py +418 -0
  78. signalwire_agents/search/models.py +30 -0
  79. signalwire_agents/search/pgvector_backend.py +748 -0
  80. signalwire_agents/search/query_processor.py +162 -31
  81. signalwire_agents/search/search_engine.py +916 -35
  82. signalwire_agents/search/search_service.py +376 -53
  83. signalwire_agents/skills/README.md +452 -0
  84. signalwire_agents/skills/__init__.py +14 -2
  85. signalwire_agents/skills/api_ninjas_trivia/README.md +215 -0
  86. signalwire_agents/skills/api_ninjas_trivia/__init__.py +12 -0
  87. signalwire_agents/skills/api_ninjas_trivia/skill.py +237 -0
  88. signalwire_agents/skills/datasphere/README.md +210 -0
  89. signalwire_agents/skills/datasphere/skill.py +84 -3
  90. signalwire_agents/skills/datasphere_serverless/README.md +258 -0
  91. signalwire_agents/skills/datasphere_serverless/__init__.py +9 -0
  92. signalwire_agents/skills/datasphere_serverless/skill.py +82 -1
  93. signalwire_agents/skills/datetime/README.md +132 -0
  94. signalwire_agents/skills/datetime/__init__.py +9 -0
  95. signalwire_agents/skills/datetime/skill.py +20 -7
  96. signalwire_agents/skills/joke/README.md +149 -0
  97. signalwire_agents/skills/joke/__init__.py +9 -0
  98. signalwire_agents/skills/joke/skill.py +21 -0
  99. signalwire_agents/skills/math/README.md +161 -0
  100. signalwire_agents/skills/math/__init__.py +9 -0
  101. signalwire_agents/skills/math/skill.py +18 -4
  102. signalwire_agents/skills/mcp_gateway/README.md +230 -0
  103. signalwire_agents/skills/mcp_gateway/__init__.py +10 -0
  104. signalwire_agents/skills/mcp_gateway/skill.py +421 -0
  105. signalwire_agents/skills/native_vector_search/README.md +210 -0
  106. signalwire_agents/skills/native_vector_search/__init__.py +9 -0
  107. signalwire_agents/skills/native_vector_search/skill.py +569 -101
  108. signalwire_agents/skills/play_background_file/README.md +218 -0
  109. signalwire_agents/skills/play_background_file/__init__.py +12 -0
  110. signalwire_agents/skills/play_background_file/skill.py +242 -0
  111. signalwire_agents/skills/registry.py +395 -40
  112. signalwire_agents/skills/spider/README.md +236 -0
  113. signalwire_agents/skills/spider/__init__.py +13 -0
  114. signalwire_agents/skills/spider/skill.py +598 -0
  115. signalwire_agents/skills/swml_transfer/README.md +395 -0
  116. signalwire_agents/skills/swml_transfer/__init__.py +10 -0
  117. signalwire_agents/skills/swml_transfer/skill.py +359 -0
  118. signalwire_agents/skills/weather_api/README.md +178 -0
  119. signalwire_agents/skills/weather_api/__init__.py +12 -0
  120. signalwire_agents/skills/weather_api/skill.py +191 -0
  121. signalwire_agents/skills/web_search/README.md +163 -0
  122. signalwire_agents/skills/web_search/__init__.py +9 -0
  123. signalwire_agents/skills/web_search/skill.py +586 -112
  124. signalwire_agents/skills/wikipedia_search/README.md +228 -0
  125. signalwire_agents/{core/state → skills/wikipedia_search}/__init__.py +5 -4
  126. signalwire_agents/skills/{wikipedia → wikipedia_search}/skill.py +33 -3
  127. signalwire_agents/web/__init__.py +17 -0
  128. signalwire_agents/web/web_service.py +559 -0
  129. signalwire_agents-1.0.17.dev4.data/data/share/man/man1/sw-agent-init.1 +400 -0
  130. signalwire_agents-1.0.17.dev4.data/data/share/man/man1/sw-search.1 +483 -0
  131. signalwire_agents-1.0.17.dev4.data/data/share/man/man1/swaig-test.1 +308 -0
  132. {signalwire_agents-0.1.13.dist-info → signalwire_agents-1.0.17.dev4.dist-info}/METADATA +347 -215
  133. signalwire_agents-1.0.17.dev4.dist-info/RECORD +147 -0
  134. signalwire_agents-1.0.17.dev4.dist-info/entry_points.txt +6 -0
  135. signalwire_agents/core/state/file_state_manager.py +0 -219
  136. signalwire_agents/core/state/state_manager.py +0 -101
  137. signalwire_agents/skills/wikipedia/__init__.py +0 -9
  138. signalwire_agents-0.1.13.data/data/schema.json +0 -5611
  139. signalwire_agents-0.1.13.dist-info/RECORD +0 -67
  140. signalwire_agents-0.1.13.dist-info/entry_points.txt +0 -3
  141. {signalwire_agents-0.1.13.dist-info → signalwire_agents-1.0.17.dev4.dist-info}/WHEEL +0 -0
  142. {signalwire_agents-0.1.13.dist-info → signalwire_agents-1.0.17.dev4.dist-info}/licenses/LICENSE +0 -0
  143. {signalwire_agents-0.1.13.dist-info → signalwire_agents-1.0.17.dev4.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,282 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Copyright (c) 2025 SignalWire
4
+
5
+ This file is part of the SignalWire AI Agents SDK.
6
+
7
+ Licensed under the MIT License.
8
+ See LICENSE file in the project root for full license information.
9
+ """
10
+
11
+ """
12
+ Mock environment and serverless simulation functionality
13
+ """
14
+
15
+ import os
16
+ import json
17
+ from typing import Optional, Dict, Any
18
+ from ..types import PostData
19
+
20
+
21
+ class MockQueryParams:
22
+ """Mock FastAPI QueryParams (simple dict-like)"""
23
+ def __init__(self, params: Optional[Dict[str, str]] = None):
24
+ self._params = params or {}
25
+
26
+ def get(self, key: str, default: Optional[str] = None) -> Optional[str]:
27
+ return self._params.get(key, default)
28
+
29
+ def __getitem__(self, key: str) -> str:
30
+ return self._params[key]
31
+
32
+ def __contains__(self, key: str) -> bool:
33
+ return key in self._params
34
+
35
+ def items(self):
36
+ return self._params.items()
37
+
38
+ def keys(self):
39
+ return self._params.keys()
40
+
41
+ def values(self):
42
+ return self._params.values()
43
+
44
+
45
+ class MockHeaders:
46
+ """Mock FastAPI Headers (case-insensitive dict-like)"""
47
+ def __init__(self, headers: Optional[Dict[str, str]] = None):
48
+ # Store headers with lowercase keys for case-insensitive lookup
49
+ self._headers = {}
50
+ if headers:
51
+ for k, v in headers.items():
52
+ self._headers[k.lower()] = v
53
+
54
+ def get(self, key: str, default: Optional[str] = None) -> Optional[str]:
55
+ return self._headers.get(key.lower(), default)
56
+
57
+ def __getitem__(self, key: str) -> str:
58
+ return self._headers[key.lower()]
59
+
60
+ def __contains__(self, key: str) -> bool:
61
+ return key.lower() in self._headers
62
+
63
+ def items(self):
64
+ return self._headers.items()
65
+
66
+ def keys(self):
67
+ return self._headers.keys()
68
+
69
+ def values(self):
70
+ return self._headers.values()
71
+
72
+
73
+ class MockURL:
74
+ """Mock FastAPI URL object"""
75
+ def __init__(self, url: str = "http://localhost:8080/swml"):
76
+ self._url = url
77
+ # Parse basic components
78
+ if "?" in url:
79
+ self.path, query_string = url.split("?", 1)
80
+ self.query = query_string
81
+ else:
82
+ self.path = url
83
+ self.query = ""
84
+
85
+ # Extract scheme and netloc
86
+ if "://" in url:
87
+ self.scheme, rest = url.split("://", 1)
88
+ if "/" in rest:
89
+ self.netloc = rest.split("/", 1)[0]
90
+ else:
91
+ self.netloc = rest
92
+ else:
93
+ self.scheme = "http"
94
+ self.netloc = "localhost:8080"
95
+
96
+ def __str__(self):
97
+ return self._url
98
+
99
+
100
+ class MockRequest:
101
+ """Mock FastAPI Request object for dynamic agent testing"""
102
+ def __init__(self, method: str = "POST", url: str = "http://localhost:8080/swml",
103
+ headers: Optional[Dict[str, str]] = None,
104
+ query_params: Optional[Dict[str, str]] = None,
105
+ json_body: Optional[Dict[str, Any]] = None):
106
+ self.method = method
107
+ self.url = MockURL(url)
108
+ self.headers = MockHeaders(headers)
109
+ self.query_params = MockQueryParams(query_params)
110
+ self._json_body = json_body or {}
111
+ self._body = json.dumps(self._json_body).encode('utf-8')
112
+ # Add state object for request state (used by FastAPI)
113
+ self.state = type('State', (), {})()
114
+
115
+ async def json(self) -> Dict[str, Any]:
116
+ """Return the JSON body"""
117
+ return self._json_body
118
+
119
+ async def body(self) -> bytes:
120
+ """Return the raw body bytes"""
121
+ return self._body
122
+
123
+ def client(self):
124
+ """Mock client property"""
125
+ return type('MockClient', (), {'host': '127.0.0.1', 'port': 0})()
126
+
127
+
128
+ def create_mock_request(method: str = "POST", url: str = "http://localhost:8080/swml",
129
+ headers: Optional[Dict[str, str]] = None,
130
+ query_params: Optional[Dict[str, str]] = None,
131
+ body: Optional[Dict[str, Any]] = None) -> MockRequest:
132
+ """
133
+ Factory function to create a mock FastAPI Request object
134
+ """
135
+ return MockRequest(method=method, url=url, headers=headers,
136
+ query_params=query_params, json_body=body)
137
+
138
+
139
+ class ServerlessSimulator:
140
+ """Manages serverless environment simulation for different platforms"""
141
+
142
+ # Default environment presets for each platform
143
+ PLATFORM_PRESETS = {
144
+ 'lambda': {
145
+ 'AWS_LAMBDA_FUNCTION_NAME': 'test-agent-function',
146
+ 'AWS_LAMBDA_FUNCTION_URL': 'https://abc123.lambda-url.us-east-1.on.aws/',
147
+ 'AWS_REGION': 'us-east-1',
148
+ '_HANDLER': 'lambda_function.lambda_handler'
149
+ },
150
+ 'cgi': {
151
+ 'GATEWAY_INTERFACE': 'CGI/1.1',
152
+ 'HTTP_HOST': 'example.com',
153
+ 'SCRIPT_NAME': '/cgi-bin/agent.cgi',
154
+ 'HTTPS': 'on',
155
+ 'SERVER_NAME': 'example.com'
156
+ },
157
+ 'cloud_function': {
158
+ 'GOOGLE_CLOUD_PROJECT': 'test-project',
159
+ 'FUNCTION_URL': 'https://my-function-abc123.cloudfunctions.net',
160
+ 'GOOGLE_CLOUD_REGION': 'us-central1',
161
+ 'K_SERVICE': 'agent'
162
+ },
163
+ 'azure_function': {
164
+ 'AZURE_FUNCTIONS_ENVIRONMENT': 'Development',
165
+ 'FUNCTIONS_WORKER_RUNTIME': 'python',
166
+ 'WEBSITE_SITE_NAME': 'my-function-app'
167
+ }
168
+ }
169
+
170
+ def __init__(self, platform: str, overrides: Optional[Dict[str, str]] = None):
171
+ self.platform = platform
172
+ self.original_env = dict(os.environ)
173
+ self.preset_env = self.PLATFORM_PRESETS.get(platform, {}).copy()
174
+ self.overrides = overrides or {}
175
+ self.active = False
176
+ self._cleared_vars = {}
177
+
178
+ def activate(self, verbose: bool = False):
179
+ """Apply serverless environment simulation"""
180
+ if self.active:
181
+ return
182
+
183
+ # Clear conflicting environment variables
184
+ self._clear_conflicting_env()
185
+
186
+ # Apply preset environment
187
+ os.environ.update(self.preset_env)
188
+
189
+ # Apply user overrides
190
+ os.environ.update(self.overrides)
191
+
192
+ # Set appropriate logging mode for serverless simulation
193
+ if self.platform == 'cgi' and 'SIGNALWIRE_LOG_MODE' not in self.overrides:
194
+ # CGI mode should default to 'off' unless explicitly overridden
195
+ os.environ['SIGNALWIRE_LOG_MODE'] = 'off'
196
+
197
+ self.active = True
198
+
199
+ if verbose:
200
+ print(f"✓ Activated {self.platform} environment simulation")
201
+
202
+ # Debug: Show key environment variables
203
+ if self.platform == 'lambda':
204
+ print(f" AWS_LAMBDA_FUNCTION_NAME: {os.environ.get('AWS_LAMBDA_FUNCTION_NAME')}")
205
+ print(f" AWS_LAMBDA_FUNCTION_URL: {os.environ.get('AWS_LAMBDA_FUNCTION_URL')}")
206
+ print(f" AWS_REGION: {os.environ.get('AWS_REGION')}")
207
+ elif self.platform == 'cgi':
208
+ print(f" GATEWAY_INTERFACE: {os.environ.get('GATEWAY_INTERFACE')}")
209
+ print(f" HTTP_HOST: {os.environ.get('HTTP_HOST')}")
210
+ print(f" SCRIPT_NAME: {os.environ.get('SCRIPT_NAME')}")
211
+ print(f" SIGNALWIRE_LOG_MODE: {os.environ.get('SIGNALWIRE_LOG_MODE')}")
212
+ elif self.platform == 'cloud_function':
213
+ print(f" GOOGLE_CLOUD_PROJECT: {os.environ.get('GOOGLE_CLOUD_PROJECT')}")
214
+ print(f" FUNCTION_URL: {os.environ.get('FUNCTION_URL')}")
215
+ print(f" GOOGLE_CLOUD_REGION: {os.environ.get('GOOGLE_CLOUD_REGION')}")
216
+ elif self.platform == 'azure_function':
217
+ print(f" AZURE_FUNCTIONS_ENVIRONMENT: {os.environ.get('AZURE_FUNCTIONS_ENVIRONMENT')}")
218
+ print(f" WEBSITE_SITE_NAME: {os.environ.get('WEBSITE_SITE_NAME')}")
219
+
220
+ # Debug: Confirm SWML_PROXY_URL_BASE is cleared
221
+ proxy_url = os.environ.get('SWML_PROXY_URL_BASE')
222
+ if proxy_url:
223
+ print(f" WARNING: SWML_PROXY_URL_BASE still set: {proxy_url}")
224
+ else:
225
+ print(f" ✓ SWML_PROXY_URL_BASE cleared successfully")
226
+
227
+ def deactivate(self, verbose: bool = False):
228
+ """Restore original environment"""
229
+ if not self.active:
230
+ return
231
+
232
+ os.environ.clear()
233
+ os.environ.update(self.original_env)
234
+ self.active = False
235
+
236
+ if verbose:
237
+ print(f"✓ Deactivated {self.platform} environment simulation")
238
+
239
+ def _clear_conflicting_env(self):
240
+ """Clear environment variables that might conflict with simulation"""
241
+ # Remove variables from other platforms
242
+ conflicting_vars = []
243
+ for platform, preset in self.PLATFORM_PRESETS.items():
244
+ if platform != self.platform:
245
+ conflicting_vars.extend(preset.keys())
246
+
247
+ # Always clear SWML_PROXY_URL_BASE during serverless simulation
248
+ # so that platform-specific URL generation takes precedence
249
+ conflicting_vars.append('SWML_PROXY_URL_BASE')
250
+
251
+ for var in conflicting_vars:
252
+ if var in os.environ:
253
+ self._cleared_vars[var] = os.environ[var]
254
+ os.environ.pop(var)
255
+
256
+ def add_override(self, key: str, value: str):
257
+ """Add an environment variable override"""
258
+ self.overrides[key] = value
259
+ if self.active:
260
+ os.environ[key] = value
261
+
262
+ def get_current_env(self) -> Dict[str, str]:
263
+ """Get the current environment that would be applied"""
264
+ env = self.preset_env.copy()
265
+ env.update(self.overrides)
266
+ return env
267
+
268
+
269
+ def load_env_file(env_file_path: str) -> Dict[str, str]:
270
+ """Load environment variables from a file"""
271
+ env_vars = {}
272
+ if not os.path.exists(env_file_path):
273
+ raise FileNotFoundError(f"Environment file not found: {env_file_path}")
274
+
275
+ with open(env_file_path, 'r') as f:
276
+ for line in f:
277
+ line = line.strip()
278
+ if line and not line.startswith('#') and '=' in line:
279
+ key, value = line.split('=', 1)
280
+ env_vars[key.strip()] = value.strip()
281
+
282
+ return env_vars
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Copyright (c) 2025 SignalWire
4
+
5
+ This file is part of the SignalWire AI Agents SDK.
6
+
7
+ Licensed under the MIT License.
8
+ See LICENSE file in the project root for full license information.
9
+ """
10
+
11
+ """
12
+ Wrapper script for swaig-test that sets environment variables before importing any modules.
13
+ This allows proper control of logging before the logging system is initialized.
14
+ """
15
+
16
+ import os
17
+ import sys
18
+ import subprocess
19
+
20
+
21
+ def main():
22
+ """Main entry point for the swaig-test command"""
23
+ # Determine if we should show logs based on arguments
24
+ args = sys.argv[1:]
25
+
26
+ # Check for verbose flag
27
+ show_logs = '--verbose' in args or '-v' in args
28
+
29
+ # Special cases that always suppress logs
30
+ force_suppress = '--dump-swml' in args or '--raw' in args
31
+
32
+ # Set logging mode
33
+ if force_suppress:
34
+ os.environ['SIGNALWIRE_LOG_MODE'] = 'off'
35
+ elif show_logs:
36
+ os.environ['SIGNALWIRE_LOG_MODE'] = 'default'
37
+ else:
38
+ # Default: suppress logs unless verbose is requested
39
+ os.environ['SIGNALWIRE_LOG_MODE'] = 'off'
40
+
41
+ # Execute the actual implementation
42
+ # Use sys.executable to ensure we use the same Python interpreter
43
+ # Add -W ignore::RuntimeWarning to suppress the sys.modules warning
44
+ cmd = [sys.executable, '-W', 'ignore::RuntimeWarning', '-m', 'signalwire_agents.cli.test_swaig'] + args
45
+
46
+ # Run the command and exit with its exit code
47
+ result = subprocess.run(cmd)
48
+ sys.exit(result.returncode)
49
+
50
+
51
+ if __name__ == '__main__':
52
+ main()