|
46 | 46 | from pyagentspec.flows.nodes.agentnode import AgentNode as AgentSpecAgentNode |
47 | 47 | from pyagentspec.flows.nodes.apinode import ApiNode as AgentSpecApiNode |
48 | 48 | from pyagentspec.flows.nodes.branchingnode import BranchingNode as AgentSpecBranchingNode |
| 49 | +from pyagentspec.flows.nodes.catchexceptionnode import ( |
| 50 | + CatchExceptionNode as AgentSpecCatchExceptionNode, |
| 51 | +) |
49 | 52 | from pyagentspec.flows.nodes.endnode import EndNode as AgentSpecEndNode |
50 | 53 | from pyagentspec.flows.nodes.flownode import FlowNode as AgentSpecFlowNode |
51 | 54 | from pyagentspec.flows.nodes.llmnode import LlmNode as AgentSpecLlmNode |
|
379 | 382 | from wayflowcore.outputparser import PythonToolOutputParser as RuntimePythonToolOutputParser |
380 | 383 | from wayflowcore.outputparser import RegexOutputParser as RuntimeRegexOutputParser |
381 | 384 | from wayflowcore.outputparser import RegexPattern as RuntimeRegexPattern |
| 385 | +from wayflowcore.property import AnyProperty as RuntimeAnyProperty |
382 | 386 | from wayflowcore.property import JsonSchemaParam |
383 | 387 | from wayflowcore.property import ListProperty as RuntimeListProperty |
384 | 388 | from wayflowcore.property import Property as RuntimeProperty |
@@ -1105,10 +1109,18 @@ def _find_property(properties: List[AgentSpecProperty], name: str) -> AgentSpecP |
1105 | 1109 | conversion_context.convert(edge, tool_registry, converted_components) |
1106 | 1110 | for edge in data_flow_connections or [] |
1107 | 1111 | ] |
1108 | | - control_flow_edges: List[RuntimeControlFlowEdge] = [ |
1109 | | - conversion_context.convert(edge, tool_registry, converted_components) |
1110 | | - for edge in agentspec_component.control_flow_connections |
1111 | | - ] |
| 1112 | + control_flow_edges: List[RuntimeControlFlowEdge] = [] |
| 1113 | + for edge in agentspec_component.control_flow_connections: |
| 1114 | + if ( |
| 1115 | + isinstance(edge.from_node, AgentSpecCatchExceptionNode) |
| 1116 | + and edge.from_branch == AgentSpecCatchExceptionNode.CAUGHT_EXCEPTION_BRANCH |
| 1117 | + ): |
| 1118 | + # we need to rename the branch used in the CatchExceptionNode |
| 1119 | + edge.from_branch = RuntimeCatchExceptionStep.DEFAULT_EXCEPTION_BRANCH |
| 1120 | + control_flow_edges.append( |
| 1121 | + conversion_context.convert(edge, tool_registry, converted_components) |
| 1122 | + ) |
| 1123 | + |
1112 | 1124 | for step in steps.values(): |
1113 | 1125 | for branch in step.get_branches(): |
1114 | 1126 | edge_exists = any( |
@@ -1482,6 +1494,55 @@ def _find_property(properties: List[AgentSpecProperty], name: str) -> AgentSpecP |
1482 | 1494 | except_on=agentspec_component.except_on, |
1483 | 1495 | **self._get_rt_nodes_arguments(agentspec_component, metadata_info), |
1484 | 1496 | ) |
| 1497 | + elif isinstance(agentspec_component, AgentSpecCatchExceptionNode): |
| 1498 | + # Standard CatchExceptionNode from Agent Spec does not expose catch_all_exceptions |
| 1499 | + # and except_on fields |
| 1500 | + # Also, the output of the catch exception node might be renamed, |
| 1501 | + # so we have to use output mapping when needed |
| 1502 | + rt_nodes_arguments = self._get_node_arguments(agentspec_component, metadata_info) |
| 1503 | + if agentspec_component.outputs: |
| 1504 | + subflow_outputs_titles = { |
| 1505 | + p.title for p in agentspec_component.subflow.outputs or [] |
| 1506 | + } |
| 1507 | + caught_exception_property = next( |
| 1508 | + ( |
| 1509 | + p |
| 1510 | + for p in agentspec_component.outputs |
| 1511 | + if p.title not in subflow_outputs_titles |
| 1512 | + ), |
| 1513 | + None, |
| 1514 | + ) |
| 1515 | + if caught_exception_property is None: |
| 1516 | + raise ValueError( |
| 1517 | + f"Internal error: Agent Spec CatchExceptionNode '{agentspec_component.name}' " |
| 1518 | + "is missing a output for the exception info. Make sure the pyagentspec " |
| 1519 | + "component is successfully validated." |
| 1520 | + ) |
| 1521 | + if ( |
| 1522 | + caught_exception_property.title |
| 1523 | + != RuntimeCatchExceptionStep.EXCEPTION_PAYLOAD_OUTPUT_NAME |
| 1524 | + ): |
| 1525 | + # there is no output mapping by default. We add one to handle renaming |
| 1526 | + rt_nodes_arguments["output_mapping"] = { |
| 1527 | + RuntimeCatchExceptionStep.EXCEPTION_PAYLOAD_OUTPUT_NAME: caught_exception_property.title |
| 1528 | + } |
| 1529 | + |
| 1530 | + # we need to add a default output property for the exception name |
| 1531 | + rt_nodes_arguments["output_descriptors"].append( |
| 1532 | + RuntimeAnyProperty( |
| 1533 | + name=RuntimeCatchExceptionStep.EXCEPTION_NAME_OUTPUT_NAME, |
| 1534 | + default_value="", |
| 1535 | + ) |
| 1536 | + ) |
| 1537 | + |
| 1538 | + return RuntimeCatchExceptionStep( |
| 1539 | + flow=conversion_context.convert( |
| 1540 | + agentspec_component.subflow, tool_registry, converted_components |
| 1541 | + ), |
| 1542 | + catch_all_exceptions=True, |
| 1543 | + except_on=None, |
| 1544 | + **rt_nodes_arguments, |
| 1545 | + ) |
1485 | 1546 | elif isinstance(agentspec_component, AgentSpecPluginRegexNode): |
1486 | 1547 | regex_pattern = self._regex_pattern_to_runtime(agentspec_component.regex_pattern) |
1487 | 1548 | if not ( |
|
0 commit comments