soprano-sdk 0.2.1__py3-none-any.whl → 0.2.2__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.
@@ -70,10 +70,7 @@ def mfa_validate_user_input(**state: dict):
70
70
  if error:
71
71
  if _mfa['retry_count'] == 1:
72
72
  _mfa['status'] = 'ERRORED'
73
- _mfa['message'] = (
74
- f"You Have Entered Invalid {_mfa['challengeType']}. {_mfa['message']}"
75
- )
76
- return False
73
+ return False, f"You Have Entered Invalid {_mfa['challengeType']}. {_mfa['message']}"
77
74
 
78
75
  if response and 'token' in response:
79
76
  token = response['token']
@@ -90,10 +87,10 @@ def mfa_validate_user_input(**state: dict):
90
87
  )
91
88
  if authorize.status_code == 204:
92
89
  _mfa['status'] = 'COMPLETED'
93
- return True
90
+ return True, None
94
91
  else:
95
92
  _mfa['status'] = 'FAILED'
96
- return False
93
+ return False, f"You Have Entered Invalid {_mfa['challengeType']}. {_mfa['message']}"
97
94
 
98
95
 
99
96
  class MFANodeConfig:
@@ -140,8 +137,12 @@ class MFANodeConfig:
140
137
  - Extract ONLY the OTP code value
141
138
  - Output in the exact format shown below
142
139
 
140
+ Examples:
141
+ * User says: "1234" → `MFA_CAPTURED:1223`
142
+ * User says: "2345e" → `MFA_CAPTURED:1223e
143
+
143
144
  **Output Format:**
144
- MFA_CAPTURED:
145
+ MFA_CAPTURED:<input_field_name>
145
146
 
146
147
  """),
147
148
  transitions=[
@@ -34,7 +34,7 @@ class WorkflowEngine:
34
34
  self.workflow_name = self.config['name']
35
35
  self.workflow_description = self.config['description']
36
36
  self.workflow_version = self.config['version']
37
- self.mfa_node_indexes: list[int] = []
37
+ self.mfa_validator_steps: set[str] = set()
38
38
  self.steps: list = self.load_steps()
39
39
  self.step_map = {step['id']: step for step in self.steps}
40
40
  self.data_fields = self.load_data()
@@ -201,7 +201,8 @@ class WorkflowEngine:
201
201
 
202
202
  def load_steps(self):
203
203
  prepared_steps: list = []
204
- previous_step: dict | None = None
204
+ mfa_redirects: Dict[str, str] = {}
205
+
205
206
  for step in self.config['steps']:
206
207
  step_id = step['id']
207
208
 
@@ -215,32 +216,46 @@ class WorkflowEngine:
215
216
  next_node=mfa_data_collector['id'],
216
217
  mfa=mfa_config
217
218
  )
219
+
218
220
  prepared_steps.append(mfa_start)
219
221
  prepared_steps.append(mfa_data_collector)
220
- self.mfa_node_indexes.append(len(prepared_steps) - 1)
222
+ self.mfa_validator_steps.add(mfa_data_collector['id'])
221
223
 
222
- if previous_step and previous_step.get('transitions'):
223
- for transition in previous_step.get('transitions'):
224
- if transition.get('next') == step_id:
225
- transition['next'] = mfa_start['id']
224
+ mfa_redirects[step_id] = mfa_start['id']
226
225
 
227
226
  del step['mfa']
228
227
 
229
228
  prepared_steps.append(step)
230
- previous_step = step
229
+
230
+ for step in prepared_steps:
231
+ if step['id'] in self.mfa_validator_steps: # MFA Validator
232
+ continue
233
+
234
+ elif 'mfa' in step: # MFA Start
235
+ continue
236
+
237
+ elif step.get('transitions'):
238
+ for transition in step.get('transitions'):
239
+ next_step = transition.get('next')
240
+ if next_step in mfa_redirects:
241
+ transition['next'] = mfa_redirects[next_step]
242
+
243
+ elif step.get('next') in mfa_redirects:
244
+ step['next'] = mfa_redirects[step['next']]
245
+
231
246
  return prepared_steps
232
247
 
233
248
  def load_data(self):
234
249
  data: list = self.config['data']
235
- for mfa_node_index in self.mfa_node_indexes:
250
+ for step_id in self.mfa_validator_steps:
251
+ step_details = self.step_map[step_id]
236
252
  data.append(
237
253
  dict(
238
- name=f'{self.steps[mfa_node_index]['field']}',
254
+ name=f'{step_details['field']}',
239
255
  type='text',
240
256
  description='Input Recieved from the user during MFA'
241
257
  )
242
258
  )
243
-
244
259
  return data
245
260
 
246
261
 
@@ -298,7 +298,11 @@ class CollectInputStrategy(ActionStrategy):
298
298
  instructions = self._render_template_string(instructions, state)
299
299
 
300
300
  if collector_nodes:
301
- instructions = _wrap_instructions_with_intent_detection(instructions, collector_nodes, self.is_structured_output)
301
+ collector_nodes_for_intent_change = {
302
+ node_id: node_desc for node_id, node_desc in collector_nodes.items()
303
+ if node_id not in self.engine_context.mfa_validator_steps
304
+ }
305
+ instructions = _wrap_instructions_with_intent_detection(instructions, collector_nodes_for_intent_change, self.is_structured_output)
302
306
  return instructions
303
307
 
304
308
  def _load_agent_tools(self, state: Dict[str, Any]) -> List:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: soprano-sdk
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: YAML-driven workflow engine with AI agent integration for building conversational SOPs
5
5
  Author: Arvind Thangamani
6
6
  License: MIT
@@ -6,16 +6,16 @@ soprano_sdk/agents/adaptor.py,sha256=Cm02YKFclrESu-Qq4CTknCgU7KaA7Z_2FspnQDkEVfU
6
6
  soprano_sdk/agents/factory.py,sha256=Aucfz4rZVKCXMAQtbGAqp1JR8aYwa66mokRmKkKGhYA,6699
7
7
  soprano_sdk/agents/structured_output.py,sha256=7DSVzfMPsZAqBwI3v6XL15qG5Gh4jJ-qddcVPaa3gdc,3326
8
8
  soprano_sdk/authenticators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- soprano_sdk/authenticators/mfa.py,sha256=23A7HEm6kXaz_aFD2HmANgcWMawCKnHiW_c72V9z1MM,5234
9
+ soprano_sdk/authenticators/mfa.py,sha256=st71m2R2Ag8l4dEbvARbIXV6kdqACBO9i5DaPK0rlWs,5429
10
10
  soprano_sdk/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  soprano_sdk/core/constants.py,sha256=-Ij4bbSDsyxQ_NZ5NiusJeepWhoe13WGuzN3LlnXqWY,2017
12
- soprano_sdk/core/engine.py,sha256=w1ofIGmBaXBa4UxWwYzRjIdJiCFC6QXqivuo3eESW5M,10085
12
+ soprano_sdk/core/engine.py,sha256=BNwmydKlqm64ZIj7VVVqSbn9ebKvOmUvHSr5XZBdQo4,10473
13
13
  soprano_sdk/core/rollback_strategies.py,sha256=NjDTtBCZlqyDql5PSwI9SMDLK7_BNlTxbW_cq_5gV0g,7783
14
14
  soprano_sdk/core/state.py,sha256=ENf81OOe4C2IEYGWUcaBwJ3O1P6VRg4DVirOXFXjioA,2899
15
15
  soprano_sdk/nodes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  soprano_sdk/nodes/base.py,sha256=idFyOGGPnjsASYnrOF_NIh7eFcSuJqw61EoVN_WCTaU,2360
17
17
  soprano_sdk/nodes/call_function.py,sha256=Quys2Rf2JitV1fnTpnEIpIoCCOQDzhWBriRXO59UqqI,5469
18
- soprano_sdk/nodes/collect_input.py,sha256=pR4PrQfnufAZmCpN_1T14zBp3rg8BkSWGP7eMSa3pZE,23140
18
+ soprano_sdk/nodes/collect_input.py,sha256=2zhUXYrWlMJ8KH3qo39hZdPiYmc0_moNvvuP3tl3RGY,23381
19
19
  soprano_sdk/nodes/factory.py,sha256=l-Gysfgnao-o2dphhnbjjxcH3ojZanZNYN3CBH9dDbA,1624
20
20
  soprano_sdk/routing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  soprano_sdk/routing/router.py,sha256=SrNciTIXXdC9bAbbO5bX7PN9mlRbITjr4RZdNm4jEVA,3450
@@ -28,7 +28,7 @@ soprano_sdk/utils/tracing.py,sha256=gSHeBDLe-MbAZ9rkzpCoGFveeMdR9KLaA6tteB0IWjk,
28
28
  soprano_sdk/validation/__init__.py,sha256=ImChmO86jYHU90xzTttto2-LmOUOmvY_ibOQaLRz5BA,262
29
29
  soprano_sdk/validation/schema.py,sha256=R6bm4Pzgx8p08o77FN9FFSKTLTKOCf7WuThrR6rV2FI,14578
30
30
  soprano_sdk/validation/validator.py,sha256=mUTweaQyDaPqHWQDlsE9AFwnB3_MQAEOBrj1hwKQK68,7888
31
- soprano_sdk-0.2.1.dist-info/METADATA,sha256=XxCrRnMd6wRoFXdEW9H9lcAShKYvmi7eZZjUGlgNz-M,11297
32
- soprano_sdk-0.2.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
33
- soprano_sdk-0.2.1.dist-info/licenses/LICENSE,sha256=A1aBauSjPNtVehOXJe3WuvdU2xvM9H8XmigFMm6665s,1073
34
- soprano_sdk-0.2.1.dist-info/RECORD,,
31
+ soprano_sdk-0.2.2.dist-info/METADATA,sha256=lH2Z9tMo_U7riXwJ_Ucgmp7I0foTtlfsU4MWKBscQPU,11297
32
+ soprano_sdk-0.2.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
33
+ soprano_sdk-0.2.2.dist-info/licenses/LICENSE,sha256=A1aBauSjPNtVehOXJe3WuvdU2xvM9H8XmigFMm6665s,1073
34
+ soprano_sdk-0.2.2.dist-info/RECORD,,