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.
- signalwire_agents/__init__.py +99 -15
- signalwire_agents/agent_server.py +248 -60
- signalwire_agents/agents/bedrock.py +296 -0
- signalwire_agents/cli/__init__.py +9 -0
- signalwire_agents/cli/build_search.py +951 -41
- signalwire_agents/cli/config.py +80 -0
- signalwire_agents/cli/core/__init__.py +10 -0
- signalwire_agents/cli/core/agent_loader.py +470 -0
- signalwire_agents/cli/core/argparse_helpers.py +179 -0
- signalwire_agents/cli/core/dynamic_config.py +71 -0
- signalwire_agents/cli/core/service_loader.py +303 -0
- signalwire_agents/cli/dokku.py +2320 -0
- signalwire_agents/cli/execution/__init__.py +10 -0
- signalwire_agents/cli/execution/datamap_exec.py +446 -0
- signalwire_agents/cli/execution/webhook_exec.py +134 -0
- signalwire_agents/cli/init_project.py +2636 -0
- signalwire_agents/cli/output/__init__.py +10 -0
- signalwire_agents/cli/output/output_formatter.py +255 -0
- signalwire_agents/cli/output/swml_dump.py +186 -0
- signalwire_agents/cli/simulation/__init__.py +10 -0
- signalwire_agents/cli/simulation/data_generation.py +374 -0
- signalwire_agents/cli/simulation/data_overrides.py +200 -0
- signalwire_agents/cli/simulation/mock_env.py +282 -0
- signalwire_agents/cli/swaig_test_wrapper.py +52 -0
- signalwire_agents/cli/test_swaig.py +566 -2366
- signalwire_agents/cli/types.py +81 -0
- signalwire_agents/core/__init__.py +2 -2
- signalwire_agents/core/agent/__init__.py +12 -0
- signalwire_agents/core/agent/config/__init__.py +12 -0
- signalwire_agents/core/agent/deployment/__init__.py +9 -0
- signalwire_agents/core/agent/deployment/handlers/__init__.py +9 -0
- signalwire_agents/core/agent/prompt/__init__.py +14 -0
- signalwire_agents/core/agent/prompt/manager.py +306 -0
- signalwire_agents/core/agent/routing/__init__.py +9 -0
- signalwire_agents/core/agent/security/__init__.py +9 -0
- signalwire_agents/core/agent/swml/__init__.py +9 -0
- signalwire_agents/core/agent/tools/__init__.py +15 -0
- signalwire_agents/core/agent/tools/decorator.py +97 -0
- signalwire_agents/core/agent/tools/registry.py +210 -0
- signalwire_agents/core/agent_base.py +845 -2916
- signalwire_agents/core/auth_handler.py +233 -0
- signalwire_agents/core/config_loader.py +259 -0
- signalwire_agents/core/contexts.py +418 -0
- signalwire_agents/core/data_map.py +3 -15
- signalwire_agents/core/function_result.py +116 -44
- signalwire_agents/core/logging_config.py +162 -18
- signalwire_agents/core/mixins/__init__.py +28 -0
- signalwire_agents/core/mixins/ai_config_mixin.py +442 -0
- signalwire_agents/core/mixins/auth_mixin.py +280 -0
- signalwire_agents/core/mixins/prompt_mixin.py +358 -0
- signalwire_agents/core/mixins/serverless_mixin.py +460 -0
- signalwire_agents/core/mixins/skill_mixin.py +55 -0
- signalwire_agents/core/mixins/state_mixin.py +153 -0
- signalwire_agents/core/mixins/tool_mixin.py +230 -0
- signalwire_agents/core/mixins/web_mixin.py +1142 -0
- signalwire_agents/core/security_config.py +333 -0
- signalwire_agents/core/skill_base.py +84 -1
- signalwire_agents/core/skill_manager.py +62 -20
- signalwire_agents/core/swaig_function.py +18 -5
- signalwire_agents/core/swml_builder.py +207 -11
- signalwire_agents/core/swml_handler.py +27 -21
- signalwire_agents/core/swml_renderer.py +123 -312
- signalwire_agents/core/swml_service.py +171 -203
- signalwire_agents/mcp_gateway/__init__.py +29 -0
- signalwire_agents/mcp_gateway/gateway_service.py +564 -0
- signalwire_agents/mcp_gateway/mcp_manager.py +513 -0
- signalwire_agents/mcp_gateway/session_manager.py +218 -0
- signalwire_agents/prefabs/concierge.py +0 -3
- signalwire_agents/prefabs/faq_bot.py +0 -3
- signalwire_agents/prefabs/info_gatherer.py +0 -3
- signalwire_agents/prefabs/receptionist.py +0 -3
- signalwire_agents/prefabs/survey.py +0 -3
- signalwire_agents/schema.json +9218 -5489
- signalwire_agents/search/__init__.py +7 -1
- signalwire_agents/search/document_processor.py +490 -31
- signalwire_agents/search/index_builder.py +307 -37
- signalwire_agents/search/migration.py +418 -0
- signalwire_agents/search/models.py +30 -0
- signalwire_agents/search/pgvector_backend.py +748 -0
- signalwire_agents/search/query_processor.py +162 -31
- signalwire_agents/search/search_engine.py +916 -35
- signalwire_agents/search/search_service.py +376 -53
- signalwire_agents/skills/README.md +452 -0
- signalwire_agents/skills/__init__.py +14 -2
- signalwire_agents/skills/api_ninjas_trivia/README.md +215 -0
- signalwire_agents/skills/api_ninjas_trivia/__init__.py +12 -0
- signalwire_agents/skills/api_ninjas_trivia/skill.py +237 -0
- signalwire_agents/skills/datasphere/README.md +210 -0
- signalwire_agents/skills/datasphere/skill.py +84 -3
- signalwire_agents/skills/datasphere_serverless/README.md +258 -0
- signalwire_agents/skills/datasphere_serverless/__init__.py +9 -0
- signalwire_agents/skills/datasphere_serverless/skill.py +82 -1
- signalwire_agents/skills/datetime/README.md +132 -0
- signalwire_agents/skills/datetime/__init__.py +9 -0
- signalwire_agents/skills/datetime/skill.py +20 -7
- signalwire_agents/skills/joke/README.md +149 -0
- signalwire_agents/skills/joke/__init__.py +9 -0
- signalwire_agents/skills/joke/skill.py +21 -0
- signalwire_agents/skills/math/README.md +161 -0
- signalwire_agents/skills/math/__init__.py +9 -0
- signalwire_agents/skills/math/skill.py +18 -4
- signalwire_agents/skills/mcp_gateway/README.md +230 -0
- signalwire_agents/skills/mcp_gateway/__init__.py +10 -0
- signalwire_agents/skills/mcp_gateway/skill.py +421 -0
- signalwire_agents/skills/native_vector_search/README.md +210 -0
- signalwire_agents/skills/native_vector_search/__init__.py +9 -0
- signalwire_agents/skills/native_vector_search/skill.py +569 -101
- signalwire_agents/skills/play_background_file/README.md +218 -0
- signalwire_agents/skills/play_background_file/__init__.py +12 -0
- signalwire_agents/skills/play_background_file/skill.py +242 -0
- signalwire_agents/skills/registry.py +395 -40
- signalwire_agents/skills/spider/README.md +236 -0
- signalwire_agents/skills/spider/__init__.py +13 -0
- signalwire_agents/skills/spider/skill.py +598 -0
- signalwire_agents/skills/swml_transfer/README.md +395 -0
- signalwire_agents/skills/swml_transfer/__init__.py +10 -0
- signalwire_agents/skills/swml_transfer/skill.py +359 -0
- signalwire_agents/skills/weather_api/README.md +178 -0
- signalwire_agents/skills/weather_api/__init__.py +12 -0
- signalwire_agents/skills/weather_api/skill.py +191 -0
- signalwire_agents/skills/web_search/README.md +163 -0
- signalwire_agents/skills/web_search/__init__.py +9 -0
- signalwire_agents/skills/web_search/skill.py +586 -112
- signalwire_agents/skills/wikipedia_search/README.md +228 -0
- signalwire_agents/{core/state → skills/wikipedia_search}/__init__.py +5 -4
- signalwire_agents/skills/{wikipedia → wikipedia_search}/skill.py +33 -3
- signalwire_agents/web/__init__.py +17 -0
- signalwire_agents/web/web_service.py +559 -0
- signalwire_agents-1.0.17.dev4.data/data/share/man/man1/sw-agent-init.1 +400 -0
- signalwire_agents-1.0.17.dev4.data/data/share/man/man1/sw-search.1 +483 -0
- signalwire_agents-1.0.17.dev4.data/data/share/man/man1/swaig-test.1 +308 -0
- {signalwire_agents-0.1.13.dist-info → signalwire_agents-1.0.17.dev4.dist-info}/METADATA +347 -215
- signalwire_agents-1.0.17.dev4.dist-info/RECORD +147 -0
- signalwire_agents-1.0.17.dev4.dist-info/entry_points.txt +6 -0
- signalwire_agents/core/state/file_state_manager.py +0 -219
- signalwire_agents/core/state/state_manager.py +0 -101
- signalwire_agents/skills/wikipedia/__init__.py +0 -9
- signalwire_agents-0.1.13.data/data/schema.json +0 -5611
- signalwire_agents-0.1.13.dist-info/RECORD +0 -67
- signalwire_agents-0.1.13.dist-info/entry_points.txt +0 -3
- {signalwire_agents-0.1.13.dist-info → signalwire_agents-1.0.17.dev4.dist-info}/WHEEL +0 -0
- {signalwire_agents-0.1.13.dist-info → signalwire_agents-1.0.17.dev4.dist-info}/licenses/LICENSE +0 -0
- {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()
|