soprano-sdk 0.1.96__py3-none-any.whl → 0.1.97__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.
- soprano_sdk/agents/structured_output.py +1 -1
- soprano_sdk/nodes/collect_input.py +22 -18
- soprano_sdk/tools.py +5 -17
- {soprano_sdk-0.1.96.dist-info → soprano_sdk-0.1.97.dist-info}/METADATA +1 -1
- {soprano_sdk-0.1.96.dist-info → soprano_sdk-0.1.97.dist-info}/RECORD +7 -7
- {soprano_sdk-0.1.96.dist-info → soprano_sdk-0.1.97.dist-info}/WHEEL +0 -0
- {soprano_sdk-0.1.96.dist-info → soprano_sdk-0.1.97.dist-info}/licenses/LICENSE +0 -0
|
@@ -20,7 +20,7 @@ def create_structured_output_model(
|
|
|
20
20
|
if not fields:
|
|
21
21
|
raise ValueError("At least one field definition is required")
|
|
22
22
|
|
|
23
|
-
field_definitions = {"bot_response": (Optional[str], Field(None, description="bot response for the user query"))}
|
|
23
|
+
field_definitions = {"bot_response": (Optional[str], Field(None, description="bot response for the user query, only use this for clarification or asking for more information"))}
|
|
24
24
|
|
|
25
25
|
if needs_intent_change:
|
|
26
26
|
field_definitions["intent_change"] = (Optional[str], Field(None, description="node name for handling new intent"))
|
|
@@ -61,6 +61,12 @@ IF the user's query continues with the SAME intent OR does not match any intent
|
|
|
61
61
|
- Proceed with your normal response
|
|
62
62
|
- Do NOT mention intent detection
|
|
63
63
|
- Answer the user's question as configured
|
|
64
|
+
|
|
65
|
+
BOT RESPONSE RULES:
|
|
66
|
+
- If the user is asking a question or needs information, provide a helpful and concise response
|
|
67
|
+
- If the user input is unclear or does not provide enough information, ask for clarification or more details
|
|
68
|
+
- { "populate bot_response field to respond back to the user" if with_structured_output else ""}
|
|
69
|
+
- Do not respond or use bot_response if the user provides a valid input
|
|
64
70
|
"""
|
|
65
71
|
|
|
66
72
|
def _create_rollback_strategy(strategy_name: str) -> RollbackStrategy:
|
|
@@ -178,7 +184,8 @@ class CollectInputStrategy(ActionStrategy):
|
|
|
178
184
|
return template_loader.from_string(template_str).render(state)
|
|
179
185
|
|
|
180
186
|
def _apply_context_value(self, state: Dict[str, Any], span) -> None:
|
|
181
|
-
|
|
187
|
+
context_value = self.engine_context.get_context_value(self.field)
|
|
188
|
+
if context_value is None:
|
|
182
189
|
return
|
|
183
190
|
logger.info(f"Using context value for '{self.field}': {context_value}")
|
|
184
191
|
state[self.field] = context_value
|
|
@@ -231,7 +238,7 @@ class CollectInputStrategy(ActionStrategy):
|
|
|
231
238
|
def _handle_pre_populated_field(self, state: Dict[str, Any], conversation: List) -> Dict[str, Any]:
|
|
232
239
|
logger.info(f"Field '{self.field}' is populated, skipping collection")
|
|
233
240
|
|
|
234
|
-
is_valid_input,
|
|
241
|
+
is_valid_input, message = self._validate_collected_input(state)
|
|
235
242
|
if not is_valid_input:
|
|
236
243
|
self._set_status(state, "collecting")
|
|
237
244
|
return self._handle_validation_failure(state, conversation, message=f"{state[self.field]}", role="user")
|
|
@@ -391,6 +398,11 @@ class CollectInputStrategy(ActionStrategy):
|
|
|
391
398
|
workflow_steps=workflow_steps
|
|
392
399
|
)
|
|
393
400
|
|
|
401
|
+
for key, value in restored_state.items():
|
|
402
|
+
context_value = self.engine_context.get_context_value(key)
|
|
403
|
+
if context_value is not None:
|
|
404
|
+
restored_state[key] = context_value
|
|
405
|
+
|
|
394
406
|
if not restored_state:
|
|
395
407
|
logger.warning(f"Rollback strategy returned empty state for node '{target_node}'")
|
|
396
408
|
return {}
|
|
@@ -472,25 +484,17 @@ class CollectInputStrategy(ActionStrategy):
|
|
|
472
484
|
return state
|
|
473
485
|
|
|
474
486
|
def _find_matching_transition(self, agent_response: Any) -> Optional[str]:
|
|
475
|
-
is_structured_output = isinstance(agent_response, dict)
|
|
476
|
-
|
|
477
487
|
for transition in self.transitions:
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
ref_field = transition.get("ref")
|
|
488
|
+
next_node = transition.get("next")
|
|
489
|
+
match_value = transition.get("match")
|
|
490
|
+
ref_field = transition.get("ref")
|
|
482
491
|
|
|
483
|
-
|
|
484
|
-
|
|
492
|
+
if not next_node or not ref_field or match_value is None:
|
|
493
|
+
raise RuntimeError(f"Transition in step '{self.step_id}' missing required properties for structured output routing")
|
|
485
494
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
else:
|
|
490
|
-
next_node = transition.get("next")
|
|
491
|
-
pattern = transition.get("pattern")
|
|
492
|
-
if pattern in agent_response:
|
|
493
|
-
return next_node
|
|
495
|
+
field_value = agent_response.get(ref_field)
|
|
496
|
+
if field_value == match_value:
|
|
497
|
+
return next_node
|
|
494
498
|
|
|
495
499
|
return None
|
|
496
500
|
|
soprano_sdk/tools.py
CHANGED
|
@@ -78,35 +78,23 @@ class WorkflowTool:
|
|
|
78
78
|
) as span:
|
|
79
79
|
callback_handler = CallbackHandler()
|
|
80
80
|
config = {"configurable": {"thread_id": thread_id}, "callbacks": [callback_handler]}
|
|
81
|
-
|
|
82
|
-
update_context
|
|
83
|
-
|
|
84
|
-
for key, value in initial_context.items():
|
|
85
|
-
if key in self.engine.collect_input_fields:
|
|
86
|
-
engine_context_data[key] = value
|
|
87
|
-
continue
|
|
88
|
-
if value:
|
|
89
|
-
update_context[key] = value
|
|
90
|
-
|
|
91
|
-
if engine_context_data:
|
|
92
|
-
self.engine.update_context(engine_context_data)
|
|
93
|
-
span.add_event("context.updated", {"fields": list(engine_context_data.keys())})
|
|
81
|
+
|
|
82
|
+
self.engine.update_context(initial_context)
|
|
83
|
+
span.add_event("context.updated", {"fields": list(initial_context.keys())})
|
|
94
84
|
|
|
95
85
|
state = self.graph.get_state(config)
|
|
96
86
|
|
|
97
87
|
if state.next:
|
|
98
|
-
# Workflow is interrupted and waiting for input
|
|
99
88
|
span.set_attribute("workflow.resumed", True)
|
|
100
89
|
logger.info(f"[WorkflowTool] Resuming interrupted workflow {self.name} (thread: {thread_id})")
|
|
101
90
|
result = self.graph.invoke(
|
|
102
|
-
Command(resume=user_message or "", update=
|
|
91
|
+
Command(resume=user_message or "", update=initial_context),
|
|
103
92
|
config=config
|
|
104
93
|
)
|
|
105
94
|
else:
|
|
106
|
-
# Workflow is fresh or completed, start/restart
|
|
107
95
|
span.set_attribute("workflow.resumed", False)
|
|
108
96
|
logger.info(f"[WorkflowTool] Starting fresh workflow {self.name} (thread: {thread_id})")
|
|
109
|
-
result = self.graph.invoke(
|
|
97
|
+
result = self.graph.invoke(initial_context, config=config)
|
|
110
98
|
|
|
111
99
|
final_state = self.graph.get_state(config)
|
|
112
100
|
if not final_state.next and self.checkpointer:
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
soprano_sdk/__init__.py,sha256=y3c4i7Q7SAPS2Tee7V0TzWdhgMxBWfDJJ98eqD1HxGI,188
|
|
2
2
|
soprano_sdk/engine.py,sha256=EFK91iTHjp72otLN6Kg-yeLye2J3CAKN0QH4FI2taL8,14838
|
|
3
|
-
soprano_sdk/tools.py,sha256=
|
|
3
|
+
soprano_sdk/tools.py,sha256=_lSZJoVwjy2RjCs4yXDupMlMSSApYB-XX57qYuy7mmE,7497
|
|
4
4
|
soprano_sdk/agents/__init__.py,sha256=Yzbtv6iP_ABRgZo0IUjy9vDofEvLFbOjuABw758176A,636
|
|
5
5
|
soprano_sdk/agents/adaptor.py,sha256=IMMgo9_KLI82i1eenOaojw7UE0jjx9vjm8mjfsodKSM,3226
|
|
6
6
|
soprano_sdk/agents/factory.py,sha256=Aucfz4rZVKCXMAQtbGAqp1JR8aYwa66mokRmKkKGhYA,6699
|
|
7
|
-
soprano_sdk/agents/structured_output.py,sha256=
|
|
7
|
+
soprano_sdk/agents/structured_output.py,sha256=7DSVzfMPsZAqBwI3v6XL15qG5Gh4jJ-qddcVPaa3gdc,3326
|
|
8
8
|
soprano_sdk/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
soprano_sdk/core/constants.py,sha256=pEwW_NeHhxs7aG457uiBCs65czAapozY6r9JAegc01Y,1451
|
|
10
10
|
soprano_sdk/core/engine.py,sha256=WEyqGaBasGnSqlBAkFSQIZXJb7T6OEsN-DWznIBAzNs,8341
|
|
@@ -13,7 +13,7 @@ soprano_sdk/core/state.py,sha256=h0Uo4uCwBAGTWrmzpDbcTwH6lI97-fXU9ek0tc3p2bM,261
|
|
|
13
13
|
soprano_sdk/nodes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
14
|
soprano_sdk/nodes/base.py,sha256=H6wvvN3kUeXluZAt5Hf3iocO9NjTElAH4fTb2-1JKr0,2233
|
|
15
15
|
soprano_sdk/nodes/call_function.py,sha256=UM-JpaG6DutuaFhOrXxEcT_fnK85aH6sFCVkfeYIfwc,4350
|
|
16
|
-
soprano_sdk/nodes/collect_input.py,sha256=
|
|
16
|
+
soprano_sdk/nodes/collect_input.py,sha256=lAt1lonezXab0pVdzRGXPa1POAuIOmkMcAj0Kxwfi3I,22277
|
|
17
17
|
soprano_sdk/nodes/factory.py,sha256=l-Gysfgnao-o2dphhnbjjxcH3ojZanZNYN3CBH9dDbA,1624
|
|
18
18
|
soprano_sdk/routing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
19
|
soprano_sdk/routing/router.py,sha256=SrNciTIXXdC9bAbbO5bX7PN9mlRbITjr4RZdNm4jEVA,3450
|
|
@@ -26,7 +26,7 @@ soprano_sdk/utils/tracing.py,sha256=iSJlTAaiGzgBvZhLISCGAd9_7F2HRzhcIUNHuaFv_Zc,
|
|
|
26
26
|
soprano_sdk/validation/__init__.py,sha256=ImChmO86jYHU90xzTttto2-LmOUOmvY_ibOQaLRz5BA,262
|
|
27
27
|
soprano_sdk/validation/schema.py,sha256=uJJZRDgwzWT2W8amd_W8mUAULvDnHJhiMEl-5so1ZK0,13559
|
|
28
28
|
soprano_sdk/validation/validator.py,sha256=l2P24wiCWBNTZ9-dRbgWwK48BGaR1xIdnBxzSCu0RPM,6498
|
|
29
|
-
soprano_sdk-0.1.
|
|
30
|
-
soprano_sdk-0.1.
|
|
31
|
-
soprano_sdk-0.1.
|
|
32
|
-
soprano_sdk-0.1.
|
|
29
|
+
soprano_sdk-0.1.97.dist-info/METADATA,sha256=opdDgT9ecUMXJJP7Dr93lnrPgwXsFqMfeJ1jRnCeh38,11269
|
|
30
|
+
soprano_sdk-0.1.97.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
31
|
+
soprano_sdk-0.1.97.dist-info/licenses/LICENSE,sha256=A1aBauSjPNtVehOXJe3WuvdU2xvM9H8XmigFMm6665s,1073
|
|
32
|
+
soprano_sdk-0.1.97.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|