signalwire-agents 0.1.6__py3-none-any.whl → 0.1.8__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.
@@ -9,9 +9,12 @@ See LICENSE file in the project root for full license information.
9
9
 
10
10
  """
11
11
  InfoGathererAgent - Prefab agent for collecting answers to a series of questions
12
+
13
+ Supports both static (questions provided at init) and dynamic (questions determined
14
+ by a callback function) configuration modes.
12
15
  """
13
16
 
14
- from typing import List, Dict, Any, Optional, Union
17
+ from typing import List, Dict, Any, Optional, Union, Callable
15
18
  import json
16
19
 
17
20
  from signalwire_agents.core.agent_base import AgentBase
@@ -39,21 +42,24 @@ class InfoGathererAgent(AgentBase):
39
42
 
40
43
  def __init__(
41
44
  self,
42
- questions: List[Dict[str, str]],
45
+ questions: Optional[List[Dict[str, str]]] = None,
43
46
  name: str = "info_gatherer",
44
47
  route: str = "/info_gatherer",
48
+ enable_state_tracking: bool = True, # Enable state tracking by default for InfoGatherer
45
49
  **kwargs
46
50
  ):
47
51
  """
48
52
  Initialize an information gathering agent
49
53
 
50
54
  Args:
51
- questions: List of questions to ask, each with:
55
+ questions: Optional list of questions to ask. If None, questions will be determined
56
+ dynamically via a callback function. Each question dict should have:
52
57
  - key_name: Identifier for storing the answer
53
58
  - question_text: The actual question to ask the user
54
59
  - confirm: (Optional) If set to True, the agent will confirm the answer before submitting
55
60
  name: Agent name for the route
56
61
  route: HTTP route for this agent
62
+ enable_state_tracking: Whether to enable state tracking (default: True)
57
63
  **kwargs: Additional arguments for AgentBase
58
64
  """
59
65
  # Initialize the base agent
@@ -61,42 +67,88 @@ class InfoGathererAgent(AgentBase):
61
67
  name=name,
62
68
  route=route,
63
69
  use_pom=True,
70
+ enable_state_tracking=enable_state_tracking, # Pass state tracking parameter to base
64
71
  **kwargs
65
72
  )
66
73
 
67
- # Validate questions format
68
- self._validate_questions(questions)
69
-
70
- # Set up global data with questions and initial state
71
- self.set_global_data({
72
- "questions": questions,
73
- "question_index": 0,
74
- "answers": []
75
- })
74
+ # Store whether we're in static or dynamic mode
75
+ self._static_questions = questions
76
+ self._question_callback = None
76
77
 
77
- # Build a minimal prompt
78
- self._build_prompt()
78
+ if questions is not None:
79
+ # Static mode: validate questions and set up immediately
80
+ self._validate_questions(questions)
81
+ self.set_global_data({
82
+ "questions": questions,
83
+ "question_index": 0,
84
+ "answers": []
85
+ })
86
+ # Build prompt for static configuration
87
+ self._build_prompt()
88
+ else:
89
+ # Dynamic mode: questions will be set up via callback in on_swml_request
90
+ # Build a generic prompt
91
+ self._build_prompt("dynamic")
79
92
 
80
93
  # Configure additional agent settings
81
94
  self._configure_agent_settings()
82
95
 
96
+ def set_question_callback(self, callback: Callable[[dict, dict, dict], List[Dict[str, str]]]):
97
+ """
98
+ Set a callback function for dynamic question configuration
99
+
100
+ Args:
101
+ callback: Function that takes (query_params, body_params, headers) and returns
102
+ a list of question dictionaries. Each question dict should have:
103
+ - key_name: Identifier for storing the answer
104
+ - question_text: The actual question to ask the user
105
+ - confirm: (Optional) If True, agent will confirm answer before submitting
106
+
107
+ Example:
108
+ def my_question_callback(query_params, body_params, headers):
109
+ question_set = query_params.get('set', 'default')
110
+ if question_set == 'support':
111
+ return [
112
+ {"key_name": "name", "question_text": "What is your name?"},
113
+ {"key_name": "issue", "question_text": "What's the issue?"}
114
+ ]
115
+ else:
116
+ return [{"key_name": "name", "question_text": "What is your name?"}]
117
+
118
+ agent.set_question_callback(my_question_callback)
119
+ """
120
+ self._question_callback = callback
121
+
83
122
  def _validate_questions(self, questions):
84
123
  """Validate that questions are in the correct format"""
85
124
  if not questions:
86
125
  raise ValueError("At least one question is required")
87
126
 
127
+ if not isinstance(questions, list):
128
+ raise ValueError("Questions must be a list")
129
+
88
130
  for i, question in enumerate(questions):
131
+ if not isinstance(question, dict):
132
+ raise ValueError(f"Question {i+1} must be a dictionary")
89
133
  if "key_name" not in question:
90
134
  raise ValueError(f"Question {i+1} is missing 'key_name' field")
91
135
  if "question_text" not in question:
92
136
  raise ValueError(f"Question {i+1} is missing 'question_text' field")
93
137
 
94
- def _build_prompt(self):
138
+ def _build_prompt(self, mode="static"):
95
139
  """Build a minimal prompt with just the objective"""
96
- self.prompt_add_section(
97
- "Objective",
98
- body="Your role is to get answers to a series of questions. Begin by asking the user if they are ready to answer some questions. If they confirm they are ready, call the start_questions function to begin the process."
99
- )
140
+ if mode == "dynamic":
141
+ # Generic prompt for dynamic mode - will be customized later
142
+ self.prompt_add_section(
143
+ "Objective",
144
+ body="Your role is to gather information by asking questions. Begin by asking the user if they are ready to answer some questions. If they confirm they are ready, call the start_questions function to begin the process."
145
+ )
146
+ else:
147
+ # Original static prompt
148
+ self.prompt_add_section(
149
+ "Objective",
150
+ body="Your role is to get answers to a series of questions. Begin by asking the user if they are ready to answer some questions. If they confirm they are ready, call the start_questions function to begin the process."
151
+ )
100
152
 
101
153
  def _configure_agent_settings(self):
102
154
  """Configure additional agent settings"""
@@ -106,6 +158,77 @@ class InfoGathererAgent(AgentBase):
106
158
  "speech_event_timeout": 1000 # Slightly longer for thoughtful responses
107
159
  })
108
160
 
161
+ def on_swml_request(self, request_data=None, callback_path=None, request=None):
162
+ """
163
+ Handle dynamic configuration using the callback function
164
+
165
+ This method is called when SWML is requested and allows us to configure
166
+ the agent just-in-time using the provided callback.
167
+ """
168
+ # Only process if we're in dynamic mode (no static questions)
169
+ if self._static_questions is not None:
170
+ return None
171
+
172
+ # If no callback is set, provide a basic fallback
173
+ if self._question_callback is None:
174
+ fallback_questions = [
175
+ {"key_name": "name", "question_text": "What is your name?"},
176
+ {"key_name": "message", "question_text": "How can I help you today?"}
177
+ ]
178
+ return {
179
+ "global_data": {
180
+ "questions": fallback_questions,
181
+ "question_index": 0,
182
+ "answers": []
183
+ }
184
+ }
185
+
186
+ # Extract request information for callback
187
+ query_params = {}
188
+ body_params = request_data or {}
189
+ headers = {}
190
+
191
+ if request and hasattr(request, 'query_params'):
192
+ query_params = dict(request.query_params)
193
+
194
+ if request and hasattr(request, 'headers'):
195
+ headers = dict(request.headers)
196
+
197
+ try:
198
+ # Call the user-provided callback to get questions
199
+ print(f"Calling question callback with query_params: {query_params}")
200
+ questions = self._question_callback(query_params, body_params, headers)
201
+ print(f"Callback returned {len(questions)} questions")
202
+
203
+ # Validate the returned questions
204
+ self._validate_questions(questions)
205
+
206
+ # Return global data modifications
207
+ return {
208
+ "global_data": {
209
+ "questions": questions,
210
+ "question_index": 0,
211
+ "answers": []
212
+ }
213
+ }
214
+
215
+ except Exception as e:
216
+ # Log error and fall back to basic questions
217
+ print(f"Error in question callback: {e}")
218
+ fallback_questions = [
219
+ {"key_name": "name", "question_text": "What is your name?"},
220
+ {"key_name": "message", "question_text": "How can I help you today?"}
221
+ ]
222
+ return {
223
+ "global_data": {
224
+ "questions": fallback_questions,
225
+ "question_index": 0,
226
+ "answers": []
227
+ }
228
+ }
229
+
230
+
231
+
109
232
  def _generate_question_instruction(self, question_text: str, needs_confirmation: bool, is_first_question: bool = False) -> str:
110
233
  """
111
234
  Generate the instruction text for asking a question
@@ -236,13 +359,11 @@ class InfoGathererAgent(AgentBase):
236
359
  # Create response with the global data update and next question
237
360
  result = SwaigFunctionResult(instruction)
238
361
 
239
- # Add actions to update global data
240
- result.add_actions([
241
- {"set_global_data": {
242
- "answers": new_answers,
243
- "question_index": new_question_index
244
- }}
245
- ])
362
+ # Use the helper method to update global data
363
+ result.update_global_data({
364
+ "answers": new_answers,
365
+ "question_index": new_question_index
366
+ })
246
367
 
247
368
  return result
248
369
  else:
@@ -251,13 +372,11 @@ class InfoGathererAgent(AgentBase):
251
372
  "Thank you! All questions have been answered. You can now summarize the information collected or ask if there's anything else the user would like to discuss."
252
373
  )
253
374
 
254
- # Add actions to update global data
255
- result.add_actions([
256
- {"set_global_data": {
257
- "answers": new_answers,
258
- "question_index": new_question_index
259
- }}
260
- ])
375
+ # Use the helper method to update global data
376
+ result.update_global_data({
377
+ "answers": new_answers,
378
+ "question_index": new_question_index
379
+ })
261
380
 
262
381
  return result
263
382
 
@@ -40,7 +40,8 @@ class ReceptionistAgent(AgentBase):
40
40
  name: str = "receptionist",
41
41
  route: str = "/receptionist",
42
42
  greeting: str = "Thank you for calling. How can I help you today?",
43
- voice: str = "elevenlabs.josh",
43
+ voice: str = "rime.spore",
44
+ enable_state_tracking: bool = True, # Enable state tracking by default
44
45
  **kwargs
45
46
  ):
46
47
  """
@@ -55,6 +56,7 @@ class ReceptionistAgent(AgentBase):
55
56
  route: HTTP route for this agent
56
57
  greeting: Initial greeting message
57
58
  voice: Voice ID to use
59
+ enable_state_tracking: Whether to enable state tracking (default: True)
58
60
  **kwargs: Additional arguments for AgentBase
59
61
  """
60
62
  # Initialize the base agent
@@ -62,6 +64,7 @@ class ReceptionistAgent(AgentBase):
62
64
  name=name,
63
65
  route=route,
64
66
  use_pom=True,
67
+ enable_state_tracking=enable_state_tracking, # Pass state tracking parameter to base
65
68
  **kwargs
66
69
  )
67
70
 
@@ -258,28 +261,20 @@ class ReceptionistAgent(AgentBase):
258
261
  # Get transfer number
259
262
  transfer_number = department.get("number", "")
260
263
 
261
- # Create result with transfer SWML
262
- result = SwaigFunctionResult(f"I'll transfer you to our {department_name} department now. Thank you for calling, {name}!")
264
+ # Create result with transfer using the connect helper method
265
+ # post_process=True allows the AI to speak the response before executing the transfer
266
+ result = SwaigFunctionResult(
267
+ f"I'll transfer you to our {department_name} department now. Thank you for calling, {name}!",
268
+ post_process=True
269
+ )
263
270
 
264
- # Add the SWML to execute the transfer
265
- # Add actions to update global data
266
- result.add_actions([
267
- {
268
- "SWML": {
269
- "sections": {
270
- "main": [
271
- {
272
- "connect": {
273
- "to": transfer_number
274
- }
275
- }
276
- ]
277
- },
278
- "version": "1.0.0"
279
- },
280
- "transfer": "true"
281
- }
282
- ])
271
+ # Use the connect helper instead of manually constructing SWML
272
+ # final=True means this is a permanent transfer (call exits the agent)
273
+ result.connect(transfer_number, final=True)
274
+
275
+ # Alternative: Immediate transfer without AI speaking (faster but less friendly)
276
+ # result = SwaigFunctionResult() # No response text needed
277
+ # result.connect(transfer_number, final=True) # Executes immediately from function call
283
278
 
284
279
  return result
285
280
 
@@ -60,6 +60,9 @@ class SurveyAgent(AgentBase):
60
60
  conclusion: Optional[str] = None,
61
61
  brand_name: Optional[str] = None,
62
62
  max_retries: int = 2,
63
+ name: str = "survey",
64
+ route: str = "/survey",
65
+ enable_state_tracking: bool = True, # Enable state tracking by default
63
66
  **kwargs
64
67
  ):
65
68
  """
@@ -78,13 +81,17 @@ class SurveyAgent(AgentBase):
78
81
  conclusion: Optional custom conclusion message
79
82
  brand_name: Optional brand or company name
80
83
  max_retries: Maximum number of times to retry invalid answers
84
+ name: Name for the agent (default: "survey")
85
+ route: HTTP route for the agent (default: "/survey")
86
+ enable_state_tracking: Whether to enable state tracking (default: True)
81
87
  **kwargs: Additional arguments for AgentBase
82
88
  """
83
89
  # Initialize the base agent
84
90
  super().__init__(
85
- name="survey",
86
- route="/survey",
91
+ name=name,
92
+ route=route,
87
93
  use_pom=True,
94
+ enable_state_tracking=enable_state_tracking, # Pass state tracking parameter to base
88
95
  **kwargs
89
96
  )
90
97
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: signalwire_agents
3
- Version: 0.1.6
3
+ Version: 0.1.8
4
4
  Summary: SignalWire AI Agents SDK
5
5
  Author-email: SignalWire Team <info@signalwire.com>
6
6
  Project-URL: Homepage, https://github.com/signalwire/signalwire-ai-agents
@@ -35,7 +35,9 @@ A Python SDK for creating, hosting, and securing SignalWire AI agents as microse
35
35
  - **Self-Contained Agents**: Each agent is both a web app and an AI persona
36
36
  - **Prompt Object Model**: Structured prompt composition using POM
37
37
  - **SWAIG Integration**: Easily define and handle AI tools/functions
38
+ - **Dynamic Configuration**: Configure agents per-request for multi-tenant apps and personalization
38
39
  - **Custom Routing**: Dynamic request handling for different paths and content
40
+ - **SIP Integration**: Route SIP calls to agents based on SIP usernames
39
41
  - **Security Built-In**: Session management, function-specific security tokens, and basic auth
40
42
  - **State Management**: Persistent conversation state with automatic tracking
41
43
  - **Prefab Archetypes**: Ready-to-use agent types for common scenarios
@@ -164,6 +166,73 @@ Available prefabs include:
164
166
  - `FAQBotAgent`: Answers questions based on a knowledge base
165
167
  - `ConciergeAgent`: Routes users to specialized agents
166
168
  - `SurveyAgent`: Conducts structured surveys with questions and rating scales
169
+ - `ReceptionistAgent`: Greets callers and transfers them to appropriate departments
170
+
171
+ ## Dynamic Agent Configuration
172
+
173
+ Configure agents dynamically based on request parameters for multi-tenant applications, A/B testing, and personalization.
174
+
175
+ ### Static vs Dynamic Configuration
176
+
177
+ - **Static**: Agent configured once at startup (traditional approach)
178
+ - **Dynamic**: Agent configured fresh for each request based on parameters
179
+
180
+ ### Basic Example
181
+
182
+ ```python
183
+ from signalwire_agents import AgentBase
184
+
185
+ class DynamicAgent(AgentBase):
186
+ def __init__(self):
187
+ super().__init__(name="dynamic-agent", route="/dynamic")
188
+
189
+ # Set up dynamic configuration callback
190
+ self.set_dynamic_config_callback(self.configure_per_request)
191
+
192
+ def configure_per_request(self, query_params, body_params, headers, agent):
193
+ """Configure agent based on request parameters"""
194
+
195
+ # Extract parameters from request
196
+ tier = query_params.get('tier', 'standard')
197
+ language = query_params.get('language', 'en')
198
+ customer_id = query_params.get('customer_id')
199
+
200
+ # Configure voice and language
201
+ if language == 'es':
202
+ agent.add_language("Spanish", "es-ES", "rime.spore:mistv2")
203
+ else:
204
+ agent.add_language("English", "en-US", "rime.spore:mistv2")
205
+
206
+ # Configure based on service tier
207
+ if tier == 'premium':
208
+ agent.set_params({"end_of_speech_timeout": 300}) # Faster response
209
+ agent.prompt_add_section("Service Level", "You provide premium support.")
210
+ else:
211
+ agent.set_params({"end_of_speech_timeout": 500}) # Standard response
212
+ agent.prompt_add_section("Service Level", "You provide standard support.")
213
+
214
+ # Personalize with customer data
215
+ global_data = {"tier": tier, "language": language}
216
+ if customer_id:
217
+ global_data["customer_id"] = customer_id
218
+ agent.set_global_data(global_data)
219
+
220
+ # Usage examples:
221
+ # curl "http://localhost:3000/dynamic?tier=premium&language=es&customer_id=123"
222
+ # curl "http://localhost:3000/dynamic?tier=standard&language=en"
223
+ ```
224
+
225
+ ### Use Cases
226
+
227
+ - **Multi-tenant SaaS**: Different configurations per customer/organization
228
+ - **A/B Testing**: Test different agent behaviors with different user groups
229
+ - **Personalization**: Customize voice, prompts, and behavior per user
230
+ - **Localization**: Language and cultural adaptation based on user location
231
+ - **Dynamic Pricing**: Adjust features and capabilities based on subscription tiers
232
+
233
+ The `EphemeralAgentConfig` object provides all the same familiar methods as `AgentBase` (like `add_language()`, `prompt_add_section()`, `set_global_data()`) but applies them per-request instead of at startup.
234
+
235
+ For detailed documentation and advanced examples, see the [Agent Guide](docs/agent_guide.md#dynamic-agent-configuration).
167
236
 
168
237
  ## Configuration
169
238
 
@@ -188,7 +257,7 @@ To enable HTTPS directly (without a reverse proxy), set `SWML_SSL_ENABLED` to "t
188
257
 
189
258
  The package includes comprehensive documentation in the `docs/` directory:
190
259
 
191
- - [Agent Guide](docs/agent_guide.md) - Detailed guide to creating and customizing agents
260
+ - [Agent Guide](docs/agent_guide.md) - Detailed guide to creating and customizing agents, including dynamic configuration
192
261
  - [Architecture](docs/architecture.md) - Overview of the SDK architecture and core concepts
193
262
  - [SWML Service Guide](docs/swml_service_guide.md) - Guide to the underlying SWML service
194
263
 
@@ -1,34 +1,34 @@
1
- signalwire_agents/__init__.py,sha256=q_3tXAaEKU5Yrua20bVq-dFYg0Q4burukwe_9KBujdw,800
1
+ signalwire_agents/__init__.py,sha256=0epKP_LHIiz6nCNxn-hQvDfdYGfKvTxpu9oe-OThvEc,800
2
2
  signalwire_agents/agent_server.py,sha256=se_YzOQE5UUoRUKCbTnOg9qr4G3qN7iVuQLutwXEwFU,12850
3
3
  signalwire_agents/schema.json,sha256=M8Mn6pQda2P9jhbmkALrLr1wt-fRuhYRqdmEi9Rbhqk,178075
4
4
  signalwire_agents/core/__init__.py,sha256=mVDLbpq1pg_WwiqsQR28NNZwJ6-VUXFIfg-vN7pk0ew,806
5
- signalwire_agents/core/agent_base.py,sha256=Qd25AARkFl7zGj01o7XZogtk6f8PpXYsz7bfRcpwUuA,99436
6
- signalwire_agents/core/function_result.py,sha256=vD8eBDJBQNNnss1jShadfogCZw_prODB6eBkTuVgZKA,3538
5
+ signalwire_agents/core/agent_base.py,sha256=GLnjisSPNEqJMG4-eb3TS_fBtNLPbvgjd1cTVWxqxJ4,112500
6
+ signalwire_agents/core/function_result.py,sha256=OXzm4GOvA6TKbzZFsdz3iBU5vQs9LXxsmQue7zWVolE,43538
7
7
  signalwire_agents/core/pom_builder.py,sha256=ywuiIfP8BeLBPo_G4X1teZlG6zTCMkW71CZnmyoDTAQ,6636
8
8
  signalwire_agents/core/swaig_function.py,sha256=WoHGQuCmU9L9k39pttRunmfRtIa_PnNRn9W0Xq3MfIk,6316
9
- signalwire_agents/core/swml_builder.py,sha256=Y_eHThVVso-_Hz4f73eEuu3HJstsM9PtBl-36GvAXhI,6594
9
+ signalwire_agents/core/swml_builder.py,sha256=Q1ikU9pedgjW888mjbqDFv-jMDvDZ-tZgfyMfu4qQN0,6719
10
10
  signalwire_agents/core/swml_handler.py,sha256=KvphI_YY47VWGVXaix_N3SuQSyygHEUr9We6xESQK44,7002
11
11
  signalwire_agents/core/swml_renderer.py,sha256=iobMWWoBR7dkHndI3Qlwf4C0fg2p7DmAU2Rb7ZmmLhA,13891
12
- signalwire_agents/core/swml_service.py,sha256=J3IHJxU172bQa0zd2xRtFwVWonui4f1v_ki1KYHl9lI,47414
12
+ signalwire_agents/core/swml_service.py,sha256=4zTtpIKDtL59MzKgkBdpPmBCT6s1wVIikWEzZ1hqnyc,49309
13
13
  signalwire_agents/core/security/__init__.py,sha256=4Mr7baQ_xR_hfJ72YxQRAT_GFa663YjFX_PumJ35Xds,191
14
- signalwire_agents/core/security/session_manager.py,sha256=5y0Mr3cI63cO34ctFgq-KX26mdG0Tpr7rTEsgoTS_44,5229
14
+ signalwire_agents/core/security/session_manager.py,sha256=s5hXYcFnrsYFoyo-zcN7EJy-wInZQI_cWTBHX9MxHR4,9164
15
15
  signalwire_agents/core/state/__init__.py,sha256=qpYIfQBApet6VQsy6diS3yu0lMxCBC6REOUk5l1McUw,379
16
16
  signalwire_agents/core/state/file_state_manager.py,sha256=52I_KVlmhHCbKIaHj74Q-ksP_-AF6ewYmOXCf4n5DTQ,7307
17
17
  signalwire_agents/core/state/state_manager.py,sha256=76B4mDutMb826dK4c_IJhOXH09BW1bJu6EZa6Mh_LB4,2511
18
18
  signalwire_agents/prefabs/__init__.py,sha256=MW11J63XH7KxF2MWguRsMFM9iqMWexaEO9ynDPL_PDM,715
19
- signalwire_agents/prefabs/concierge.py,sha256=--esvAV1lozQGYXHAqvSg8_TtlIoVfQK75APJ5zqX9I,9779
20
- signalwire_agents/prefabs/faq_bot.py,sha256=cUuHhnDB8S4aVg-DiQe4jBmCAPrYQrND_Mff9iaeEa0,10572
21
- signalwire_agents/prefabs/info_gatherer.py,sha256=y9gxjq1vF0-TrE6m734dCcAHqxt0I_DyCqxoM45QY8U,9940
22
- signalwire_agents/prefabs/receptionist.py,sha256=Wb22igXTD8QK9lQVcJq88eIk7qQ2GSSIzSGuYyK-Dbk,10293
23
- signalwire_agents/prefabs/survey.py,sha256=1pyUeZ5heDqFAYqkYs5fHN_jQ7TKqJInnOOUQEajSsY,14358
19
+ signalwire_agents/prefabs/concierge.py,sha256=FQxSUBAVH2ECtNs4GGa3f0EPiOrAKaz14h7byNFy5K8,10106
20
+ signalwire_agents/prefabs/faq_bot.py,sha256=NrUn5AGmtdzYTyxTHPt8BZ14ZN1sh4xKA2SVQUlfPPQ,10834
21
+ signalwire_agents/prefabs/info_gatherer.py,sha256=dr9UUgNGX7MIKdCMth3jDVLf6OrHov5G6_zIuNvnrOY,15468
22
+ signalwire_agents/prefabs/receptionist.py,sha256=8EyQ6M0Egs3g7KKWukHFiO9UPoVUxT4MLkvyT3V8o64,10585
23
+ signalwire_agents/prefabs/survey.py,sha256=IIIQfgvMlfVNjEEEdWUn4lAJqVsCDlBsIAkOJ1ckyAE,14796
24
24
  signalwire_agents/utils/__init__.py,sha256=4Mr7baQ_xR_hfJ72YxQRAT_GFa663YjFX_PumJ35Xds,191
25
25
  signalwire_agents/utils/pom_utils.py,sha256=4Mr7baQ_xR_hfJ72YxQRAT_GFa663YjFX_PumJ35Xds,191
26
26
  signalwire_agents/utils/schema_utils.py,sha256=LvFCFvJTQk_xYK0B-NXbkXKEF7Zmv-LqpV_vfpPnOb4,13473
27
27
  signalwire_agents/utils/token_generators.py,sha256=4Mr7baQ_xR_hfJ72YxQRAT_GFa663YjFX_PumJ35Xds,191
28
28
  signalwire_agents/utils/validators.py,sha256=4Mr7baQ_xR_hfJ72YxQRAT_GFa663YjFX_PumJ35Xds,191
29
- signalwire_agents-0.1.6.data/data/schema.json,sha256=M8Mn6pQda2P9jhbmkALrLr1wt-fRuhYRqdmEi9Rbhqk,178075
30
- signalwire_agents-0.1.6.dist-info/licenses/LICENSE,sha256=NYvAsB-rTcSvG9cqHt9EUHAWLiA9YzM4Qfz-mPdvDR0,1067
31
- signalwire_agents-0.1.6.dist-info/METADATA,sha256=A4krRD2w2jb0ukbBI1kHZ6nYctSZodaaMC6Oyja13nI,7414
32
- signalwire_agents-0.1.6.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
33
- signalwire_agents-0.1.6.dist-info/top_level.txt,sha256=kDGS6ZYv84K9P5Kyg9_S8P_pbUXoHkso0On_DB5bbWc,18
34
- signalwire_agents-0.1.6.dist-info/RECORD,,
29
+ signalwire_agents-0.1.8.data/data/schema.json,sha256=M8Mn6pQda2P9jhbmkALrLr1wt-fRuhYRqdmEi9Rbhqk,178075
30
+ signalwire_agents-0.1.8.dist-info/licenses/LICENSE,sha256=NYvAsB-rTcSvG9cqHt9EUHAWLiA9YzM4Qfz-mPdvDR0,1067
31
+ signalwire_agents-0.1.8.dist-info/METADATA,sha256=kTDyXqy-gZ6JMfVCr6EIsj-EB2hKtgN5wxp1VPBnNek,10507
32
+ signalwire_agents-0.1.8.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
33
+ signalwire_agents-0.1.8.dist-info/top_level.txt,sha256=kDGS6ZYv84K9P5Kyg9_S8P_pbUXoHkso0On_DB5bbWc,18
34
+ signalwire_agents-0.1.8.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.7.1)
2
+ Generator: setuptools (80.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5