(node, *, parent: str | None = None)
| 156 | return file_path, line |
| 157 | |
| 158 | def ensure_node(node, *, parent: str | None = None) -> str: |
| 159 | nid = node_id(node) |
| 160 | if nid not in node_types: |
| 161 | nodes.append(nid) |
| 162 | resolved_type = node_type(node) |
| 163 | node_types[nid] = resolved_type |
| 164 | |
| 165 | # Human-friendly aliases for internal control nodes. |
| 166 | if resolved_type == "entry": |
| 167 | node_aliases[nid] = ["entry"] |
| 168 | elif resolved_type == "exit": |
| 169 | node_aliases[nid] = ["exit"] |
| 170 | elif resolved_type == "Controller": |
| 171 | node_aliases[nid] = ["controller"] |
| 172 | elif resolved_type == "TerminateNode": |
| 173 | node_aliases[nid] = ["terminate"] |
| 174 | |
| 175 | try: |
| 176 | fp, ln = _source_info(node) |
| 177 | if fp: |
| 178 | node_file_paths[nid] = fp |
| 179 | if ln is not None: |
| 180 | node_line_numbers[nid] = ln |
| 181 | except Exception: |
| 182 | pass |
| 183 | |
| 184 | pull = _keys_semantics(getattr(node, "_pull_keys", None)) |
| 185 | push = _keys_semantics(getattr(node, "_push_keys", None)) |
| 186 | if pull is not None: |
| 187 | node_pull_keys[nid] = pull |
| 188 | if push is not None: |
| 189 | node_push_keys[nid] = push |
| 190 | |
| 191 | # Prefer _default_attributes snapshot (this matches what the node actually uses). |
| 192 | default_attrs = getattr(node, "_default_attributes", None) |
| 193 | if isinstance(default_attrs, dict): |
| 194 | node_attributes[nid] = _safe_obj(default_attrs) |
| 195 | |
| 196 | # Message keys on edges (input/output) |
| 197 | try: |
| 198 | in_keys = getattr(node, "input_keys", None) |
| 199 | out_keys = getattr(node, "output_keys", None) |
| 200 | if isinstance(in_keys, dict) and len(in_keys) > 0: |
| 201 | node_input_keys[nid] = _safe_obj(in_keys) |
| 202 | if isinstance(out_keys, dict) and len(out_keys) > 0: |
| 203 | node_output_keys[nid] = _safe_obj(out_keys) |
| 204 | except Exception: |
| 205 | pass |
| 206 | |
| 207 | if isinstance(node, Agent): |
| 208 | try: |
| 209 | ins = getattr(node, "instructions", None) |
| 210 | if isinstance(ins, str) and ins.strip(): |
| 211 | node_instructions[nid] = ins |
| 212 | except Exception: |
| 213 | pass |
| 214 | try: |
| 215 | tmpl = getattr(node, "_prompt_template", None) |
no test coverage detected