Use case
graphistrygpt + likely other consumers need to detect "this GFQL chain ends with a layout helper" to apply layout-aware defaults (URL params, axis encoding back-fill).
Today this is a string-match against function names:
```python
def _chain_contains_radial_layout(chain) -> bool:
if isinstance(chain, str):
return any(name in chain for name in ('ring_categorical_layout', 'time_ring_layout', ...))
if isinstance(chain, list):
return any(op.get('function') in ('ring_categorical_layout', ...) for op in chain)
...
```
Brittle: every new layout helper added in pygraphistry needs the consumer to update its string list, OR consumers fall behind silently.
Ask
```python
from graphistry.compute.gfql import is_layout_chain
is_layout_chain(chain) # → True if any op is a layout helper (ring/time/force/etc.)
is_layout_kind(chain) # → 'ring_categorical' | 'time_ring' | 'force_directed' | None
```
The same call_safelist that already lives in pygraphistry knows which functions are layout vs encoding vs filter.
Effort
Low. The categorization already exists implicitly in the call_safelist; expose it as a typed predicate.
Filed via Louie graphistrygpt PR #2791 audit (findings.md upstream issue #4). Tracked at graphistrygpt/plugins/graphistry/tool.py:_chain_contains_radial_layout and _contains_radial_markers.
Use case
graphistrygpt + likely other consumers need to detect "this GFQL chain ends with a layout helper" to apply layout-aware defaults (URL params, axis encoding back-fill).
Today this is a string-match against function names:
```python
def _chain_contains_radial_layout(chain) -> bool:
if isinstance(chain, str):
return any(name in chain for name in ('ring_categorical_layout', 'time_ring_layout', ...))
if isinstance(chain, list):
return any(op.get('function') in ('ring_categorical_layout', ...) for op in chain)
...
```
Brittle: every new layout helper added in pygraphistry needs the consumer to update its string list, OR consumers fall behind silently.
Ask
```python
from graphistry.compute.gfql import is_layout_chain
is_layout_chain(chain) # → True if any op is a layout helper (ring/time/force/etc.)
is_layout_kind(chain) # → 'ring_categorical' | 'time_ring' | 'force_directed' | None
```
The same call_safelist that already lives in pygraphistry knows which functions are layout vs encoding vs filter.
Effort
Low. The categorization already exists implicitly in the call_safelist; expose it as a typed predicate.
Filed via Louie graphistrygpt PR #2791 audit (findings.md upstream issue #4). Tracked at
graphistrygpt/plugins/graphistry/tool.py:_chain_contains_radial_layoutand_contains_radial_markers.