646c97645c
modules that own those concepts No behavior change. `Runner` had grown four private helpers that parse node paths, classify branches and scan events, none of which depend on runner state: - `_strip_run_ids_from_path` -> `_NodePathBuilder.static_path`. Node paths are `/`-separated and owned by `_NodePathBuilder`, which already strips the run id off the leaf segment; this generalises that to every segment instead of reimplementing the parsing in `Runner`. - `_is_tool_branch` -> `_BranchPath.is_tool_branch`. Branches are `.`-separated and owned by `_BranchPath`, which the helper already depended on. - `_collect_function_call_ids` -> `_collect_function_call_ids` in `flows/llm_flows/functions`, next to `find_event_by_function_call_id`. - `_find_static_node_path` -> `find_static_node_path` in `workflow/_base_node`, the module that defines the node tree it walks. Keeping the two path types with their own classes also removes a hazard: node paths and branches both look like `name@id` segments but use different separators, so parsing them by hand in a third module invites applying the wrong one. Co-authored-by: Shangjie Chen <deanchen@google.com> PiperOrigin-RevId: 970192989