1"""PromptRegistry — named template lookup and registration."""
2
3from __future__ import annotations
4
5from typing import TYPE_CHECKING
6
7from lexigram.ai.prompt.exceptions import PromptNotFoundError
8
9if TYPE_CHECKING:
10 from lexigram.ai.prompt.template.base import AbstractPromptTemplate
11
12
13class PromptRegistry:
14 """A thread-safe, in-memory registry that maps names to templates.
15
16 Templates are registered once and can thereafter be retrieved by name.
17 The registry supports optional *namespacing* via dotted names
18 (e.g. ``"support.greeting"``).
19
20 Example::
21
22 registry = PromptRegistry()
23 registry.register("hello", tmpl)
24 retrieved = registry.get("hello")
25 """
26
27 def __init__(self) -> None:
28 self._store: dict[str, AbstractPromptTemplate] = {}
29
30 def register(
31 self,
32 name: str,
33 template: AbstractPromptTemplate,
34 *,
35 overwrite: bool = False,
36 ) -> None:
37 """Register *template* under *name*.
38
39 Args:
40 name: Lookup key.
41 template: Template instance to register.
42 overwrite: Allow replacing an existing registration. Defaults to
43 ``False`` to prevent accidental overwrites.
44
45 Raises:
46 ValueError: *name* already registered and *overwrite* is ``False``.
47 """
48 if name in self._store and not overwrite:
49 raise ValueError(
50 f"Template '{name}' is already registered. "
51 "Pass overwrite=True to replace it."
52 )
53 self._store[name] = template
54
55 def get(self, name: str) -> AbstractPromptTemplate:
56 """Retrieve a template by *name*.
57
58 Args:
59 name: Lookup key.
60
61 Returns:
62 The registered template.
63
64 Raises:
65 :class:`~lexigram.ai.prompt.exceptions.PromptNotFoundError`:
66 No template is registered under *name*.
67 """
68 try:
69 return self._store[name]
70 except KeyError:
71 raise PromptNotFoundError(
72 f"No template registered under '{name}'. "
73 f"Available: {sorted(self._store)!r}"
74 ) from None
75
76 def list_names(self) -> list[str]:
77 """Return a sorted list of all registered template names."""
78 return sorted(self._store)
79
80 def unregister(self, name: str) -> None:
81 """Remove template *name* from the registry.
82
83 Args:
84 name: Lookup key.
85
86 Raises:
87 :class:`~lexigram.ai.prompt.exceptions.PromptNotFoundError`:
88 *name* is not registered.
89 """
90 if name not in self._store:
91 raise PromptNotFoundError(f"Cannot unregister unknown template '{name}'.")
92 del self._store[name]
93
94 def __contains__(self, name: str) -> bool:
95 return name in self._store
96
97 def __len__(self) -> int:
98 return len(self._store)
99
100 def __repr__(self) -> str: # pragma: no cover
101 return f"PromptRegistry(templates={sorted(self._store)!r})"
102
103
104__all__ = ["PromptRegistry"]