feat(block-h): plugin-contributable intents for fallback action mapper
This commit is contained in:
@@ -6,9 +6,12 @@ Supports keyword-based intent detection for common CRM operations.
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import re
|
import re
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Precompiled patterns for intent detection
|
# Precompiled patterns for intent detection
|
||||||
_PATTERNS = {
|
_PATTERNS = {
|
||||||
"create_contact": re.compile(
|
"create_contact": re.compile(
|
||||||
@@ -27,6 +30,37 @@ _PATTERNS = {
|
|||||||
"help": re.compile(r"\b(help|what can you do|assist)\b", re.IGNORECASE),
|
"help": re.compile(r"\b(help|what can you do|assist)\b", re.IGNORECASE),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Plugin-contributed intents: pattern -> callable(query, context) -> list[dict] | None.
|
||||||
|
# Registered via ``register_intent_pattern`` so plugins can extend the fallback
|
||||||
|
# mapper without touching core code (Block H / HC-A).
|
||||||
|
_CONTRIBUTED_INTENTS: list[tuple[re.Pattern[str], Any]] = []
|
||||||
|
|
||||||
|
|
||||||
|
def register_intent_pattern(
|
||||||
|
pattern: str | re.Pattern[str],
|
||||||
|
handler: Any,
|
||||||
|
*,
|
||||||
|
owner: str = "",
|
||||||
|
) -> None:
|
||||||
|
"""Register a plugin-contributed intent for the fallback action mapper.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
pattern: Regex (compiled or raw string) matching the user query.
|
||||||
|
handler: Callable ``(query, context) -> list[dict] | None`` producing
|
||||||
|
proposed actions when the pattern matches.
|
||||||
|
owner: Optional plugin name, used by ``unregister_intent_patterns``.
|
||||||
|
"""
|
||||||
|
compiled = re.compile(pattern) if isinstance(pattern, str) else pattern
|
||||||
|
_CONTRIBUTED_INTENTS.append((compiled, handler))
|
||||||
|
|
||||||
|
|
||||||
|
def unregister_intent_patterns(owner: str) -> None:
|
||||||
|
"""Remove all intents contributed by ``owner`` (plugin deactivation)."""
|
||||||
|
global _CONTRIBUTED_INTENTS
|
||||||
|
_CONTRIBUTED_INTENTS = [
|
||||||
|
entry for entry in _CONTRIBUTED_INTENTS if getattr(entry[1], "owner_tag", None) != owner
|
||||||
|
]
|
||||||
|
|
||||||
# Name extraction patterns - using single-quoted strings to avoid escaping issues
|
# Name extraction patterns - using single-quoted strings to avoid escaping issues
|
||||||
_NAME_PATTERNS = [
|
_NAME_PATTERNS = [
|
||||||
re.compile(r"\b(?:named|called|for)\s+['\"]?([^'\".,]+)['\"]?", re.IGNORECASE),
|
re.compile(r"\b(?:named|called|for)\s+['\"]?([^'\".,]+)['\"]?", re.IGNORECASE),
|
||||||
@@ -147,6 +181,16 @@ def map_query_to_actions(query: str, context: dict[str, Any] | None = None) -> l
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# --- Plugin-contributed intents (Block H / HC-A) ---
|
||||||
|
for pattern, handler in _CONTRIBUTED_INTENTS:
|
||||||
|
try:
|
||||||
|
if pattern.search(q):
|
||||||
|
contributed = handler(query, context)
|
||||||
|
if contributed:
|
||||||
|
actions.extend(contributed)
|
||||||
|
except Exception:
|
||||||
|
logger.warning("Contributed intent handler failed", exc_info=True)
|
||||||
|
|
||||||
# --- Generic fallback ---
|
# --- Generic fallback ---
|
||||||
if not actions:
|
if not actions:
|
||||||
if _PATTERNS["help"].search(q):
|
if _PATTERNS["help"].search(q):
|
||||||
|
|||||||
Reference in New Issue
Block a user