|
33 | 33 | from pyagentspec.flows.nodes.agentnode import AgentNode as AgentSpecAgentNode |
34 | 34 | from pyagentspec.flows.nodes.apinode import ApiNode as AgentSpecApiNode |
35 | 35 | from pyagentspec.flows.nodes.branchingnode import BranchingNode as AgentSpecBranchingNode |
| 36 | +from pyagentspec.flows.nodes.catchexceptionnode import ( |
| 37 | + CatchExceptionNode as AgentSpecCatchExceptionNode, |
| 38 | +) |
36 | 39 | from pyagentspec.flows.nodes.endnode import EndNode as AgentSpecEndNode |
37 | 40 | from pyagentspec.flows.nodes.flownode import FlowNode as AgentSpecFlowNode |
38 | 41 | from pyagentspec.flows.nodes.llmnode import LlmNode as AgentSpecLlmNode |
|
115 | 118 | from wayflowcore.agentspec.components import ( |
116 | 119 | PluginVllmEmbeddingConfig as AgentSpecPluginVllmEmbeddingConfig, |
117 | 120 | ) |
118 | | -from wayflowcore.agentspec.components import all_deserialization_plugin |
| 121 | +from wayflowcore.agentspec.components import ( |
| 122 | + all_deserialization_plugin, |
| 123 | +) |
119 | 124 | from wayflowcore.agentspec.components.agent import ExtendedAgent as AgentSpecExtendedAgent |
120 | 125 | from wayflowcore.agentspec.components.contextprovider import ( |
121 | 126 | PluginConstantContextProvider as AgentSpecPluginConstantContextProvider, |
|
359 | 364 | from wayflowcore.outputparser import PythonToolOutputParser as RuntimePythonToolOutputParser |
360 | 365 | from wayflowcore.outputparser import RegexOutputParser as RuntimeRegexOutputParser |
361 | 366 | from wayflowcore.outputparser import RegexPattern as RuntimeRegexPattern |
| 367 | +from wayflowcore.property import AnyProperty as RuntimeAnyProperty |
362 | 368 | from wayflowcore.property import JsonSchemaParam |
363 | 369 | from wayflowcore.property import ListProperty as RuntimeListProperty |
364 | 370 | from wayflowcore.property import Property as RuntimeProperty |
@@ -997,10 +1003,18 @@ def _find_property(properties: List[AgentSpecProperty], name: str) -> AgentSpecP |
997 | 1003 | conversion_context.convert(edge, tool_registry, converted_components) |
998 | 1004 | for edge in data_flow_connections or [] |
999 | 1005 | ] |
1000 | | - control_flow_edges: List[RuntimeControlFlowEdge] = [ |
1001 | | - conversion_context.convert(edge, tool_registry, converted_components) |
1002 | | - for edge in agentspec_component.control_flow_connections |
1003 | | - ] |
| 1006 | + control_flow_edges: List[RuntimeControlFlowEdge] = [] |
| 1007 | + for edge in agentspec_component.control_flow_connections: |
| 1008 | + if ( |
| 1009 | + isinstance(edge.from_node, AgentSpecCatchExceptionNode) |
| 1010 | + and edge.from_branch == AgentSpecCatchExceptionNode.CAUGHT_EXCEPTION_BRANCH |
| 1011 | + ): |
| 1012 | + # we need to rename the branch used in the CatchExceptionNode |
| 1013 | + edge.from_branch = RuntimeCatchExceptionStep.DEFAULT_EXCEPTION_BRANCH |
| 1014 | + control_flow_edges.append( |
| 1015 | + conversion_context.convert(edge, tool_registry, converted_components) |
| 1016 | + ) |
| 1017 | + |
1004 | 1018 | for step in steps.values(): |
1005 | 1019 | for branch in step.get_branches(): |
1006 | 1020 | edge_exists = any( |
@@ -1359,6 +1373,55 @@ def _find_property(properties: List[AgentSpecProperty], name: str) -> AgentSpecP |
1359 | 1373 | except_on=agentspec_component.except_on, |
1360 | 1374 | **self._get_rt_nodes_arguments(agentspec_component, metadata_info), |
1361 | 1375 | ) |
| 1376 | + elif isinstance(agentspec_component, AgentSpecCatchExceptionNode): |
| 1377 | + # Standard CatchExceptionNode from Agent Spec does not expose catch_all_exceptions |
| 1378 | + # and except_on fields |
| 1379 | + # Also, the output of the catch exception node might be renamed, |
| 1380 | + # so we have to use output mapping when needed |
| 1381 | + rt_nodes_arguments = self._get_node_arguments(agentspec_component, metadata_info) |
| 1382 | + if agentspec_component.outputs: |
| 1383 | + subflow_outputs_titles = { |
| 1384 | + p.title for p in agentspec_component.subflow.outputs or [] |
| 1385 | + } |
| 1386 | + caught_exception_property = next( |
| 1387 | + ( |
| 1388 | + p |
| 1389 | + for p in agentspec_component.outputs |
| 1390 | + if p.title not in subflow_outputs_titles |
| 1391 | + ), |
| 1392 | + None, |
| 1393 | + ) |
| 1394 | + if caught_exception_property is None: |
| 1395 | + raise ValueError( |
| 1396 | + f"Internal error: Agent Spec CatchExceptionNode '{agentspec_component.name}' " |
| 1397 | + "is missing a output for the exception info. Make sure the pyagentspec " |
| 1398 | + "component is successfully validated." |
| 1399 | + ) |
| 1400 | + if ( |
| 1401 | + caught_exception_property.title |
| 1402 | + != RuntimeCatchExceptionStep.EXCEPTION_PAYLOAD_OUTPUT_NAME |
| 1403 | + ): |
| 1404 | + # there is no output mapping by default. We add one to handle renaming |
| 1405 | + rt_nodes_arguments["output_mapping"] = { |
| 1406 | + RuntimeCatchExceptionStep.EXCEPTION_PAYLOAD_OUTPUT_NAME: caught_exception_property.title |
| 1407 | + } |
| 1408 | + |
| 1409 | + # we need to add a default output property for the exception name |
| 1410 | + rt_nodes_arguments["output_descriptors"].append( |
| 1411 | + RuntimeAnyProperty( |
| 1412 | + name=RuntimeCatchExceptionStep.EXCEPTION_NAME_OUTPUT_NAME, |
| 1413 | + default_value="", |
| 1414 | + ) |
| 1415 | + ) |
| 1416 | + |
| 1417 | + return RuntimeCatchExceptionStep( |
| 1418 | + flow=conversion_context.convert( |
| 1419 | + agentspec_component.subflow, tool_registry, converted_components |
| 1420 | + ), |
| 1421 | + catch_all_exceptions=True, |
| 1422 | + except_on=None, |
| 1423 | + **rt_nodes_arguments, |
| 1424 | + ) |
1362 | 1425 | elif isinstance(agentspec_component, AgentSpecPluginRegexNode): |
1363 | 1426 | regex_pattern = self._regex_pattern_to_runtime(agentspec_component.regex_pattern) |
1364 | 1427 | if not ( |
|
0 commit comments