The ``text_match.py`` module ============================ .. py:module:: ansys.cfx.mcp.common.text_match Summary ------- .. py:currentmodule:: text_match .. tab-set:: .. tab-item:: Functions .. list-table:: :header-rows: 0 :widths: auto * - :py:obj:`~edit_distance_le_one` - Return True iff Levenshtein distance between ``a`` and ``b`` is at most 1. * - :py:obj:`~fuzzy_normalize` - Normalize ``value`` to a canonical spelling from ``allowed``. * - :py:obj:`~sanitize_named_object_key` - Return ``(sanitized_name, notice_or_None)`` for a NamedObject key. Description ----------- Shared string-matching utilities for fuzzy/typo-tolerant lookup. These helpers are used everywhere the agent has to reconcile an LLM-supplied identifier against a finite, authoritative set of known strings — material names, allowed values of an enum-typed setting, NamedObject keys, dict-key schemas, command kwargs, etc. Keeping the implementation in one place avoids the trap we hit historically: ``_check_value`` learned to tolerate the LLM's ``"least-squares-cell-based"`` → ``"least-square-cell-based"`` typo while ``copy_material`` could not even resolve ``"water-vapour"`` → ``"water-vapor"``. Both are the same single-edit problem; both should share the same solution. Public API: * :func:`edit_distance_le_one` — fast ``≤ 1`` Levenshtein verdict. * :func:`fuzzy_normalize` — return the canonical spelling if and only if exactly one entry in ``allowed`` is within edit distance 1 (case-insensitive), else ``None``. * :func:`sanitize_named_object_key` — collapse whitespace in a NamedObject key to the idiomatic hyphen separator. .. !! processed by numpydoc !! Module detail ------------- .. py:function:: edit_distance_le_one(a: str, b: str) -> bool Return True iff Levenshtein distance between ``a`` and ``b`` is at most 1. Faster than computing the full distance because we only need the ``≤ 1`` verdict. :Parameters: **a** : :class:`python:str` A supplied to the function. **b** : :class:`python:str` B supplied to the function. :Returns: :ref:`bool ` Boolean result produced by the function. .. !! processed by numpydoc !! .. py:function:: fuzzy_normalize(value: str, allowed: collections.abc.Iterable[str]) -> str | None Normalize ``value`` to a canonical spelling from ``allowed``. It returns the canonical spelling for ``value`` if exactly one entry in ``allowed`` is within edit distance 1 (case-insensitive), else ``None``. Uniqueness is required so a near-spelling never silently overwrites a value when two candidates are equally plausible — surface the ambiguity to the caller instead. :Parameters: **value** : :class:`python:str` Value supplied to the function. **allowed** : :obj:`Iterable`\[:class:`python:str`] Allowed supplied to the function. :Returns: :class:`python:str` | :data:`python:None` String result produced by the function. .. !! processed by numpydoc !! .. py:function:: sanitize_named_object_key(name: str, *, replacement: str = '-') -> tuple[str, str | None] Return ``(sanitized_name, notice_or_None)`` for a NamedObject key. Some backends reject whitespace in NamedObject instance keys (BC names, cell-zone names, material names, named-expression keys, ...). Internal whitespace runs are collapsed to ``replacement`` (hyphen by default — the idiomatic separator, e.g. ``pressure-outlet-1``, ``phase-1``, ``cold-inlet``) and leading or trailing whitespace is stripped. The function is conservative — it ONLY rewrites whitespace. Other illegal characters (``/``, ``\\``, ``:``, brackets, ...) are rare in natural-language intent and are deliberately left alone so a deterministic rewrite never corrupts a name the user intentionally typed; the backend surfaces those at apply time. Returns a 2-tuple: * ``sanitized_name`` — the cleaned name (equal to ``name`` when no rewrite was needed). * ``notice`` — a one-line human-readable explanation of the rewrite, or ``None`` when the input was already clean. Non-string inputs are returned unchanged with ``notice=None`` so callers can pipe values through this helper unconditionally. Example:: >>> sanitize_named_object_key("oil inlet") ('oil-inlet', "name 'oil inlet' contained whitespace; ...") >>> sanitize_named_object_key("phase-1") ('phase-1', None) :Parameters: **name** : :class:`python:str` Name of the object, module, or setting being processed. **replacement** : :class:`python:str` Replacement supplied to the function. :Returns: :class:`python:tuple`\[:class:`python:str`, :class:`python:str` | :data:`python:None`] Collection containing the operation results. .. !! processed by numpydoc !!