foundry-mcp 0.8.22__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of foundry-mcp might be problematic. Click here for more details.

Files changed (153) hide show
  1. foundry_mcp/__init__.py +13 -0
  2. foundry_mcp/cli/__init__.py +67 -0
  3. foundry_mcp/cli/__main__.py +9 -0
  4. foundry_mcp/cli/agent.py +96 -0
  5. foundry_mcp/cli/commands/__init__.py +37 -0
  6. foundry_mcp/cli/commands/cache.py +137 -0
  7. foundry_mcp/cli/commands/dashboard.py +148 -0
  8. foundry_mcp/cli/commands/dev.py +446 -0
  9. foundry_mcp/cli/commands/journal.py +377 -0
  10. foundry_mcp/cli/commands/lifecycle.py +274 -0
  11. foundry_mcp/cli/commands/modify.py +824 -0
  12. foundry_mcp/cli/commands/plan.py +640 -0
  13. foundry_mcp/cli/commands/pr.py +393 -0
  14. foundry_mcp/cli/commands/review.py +667 -0
  15. foundry_mcp/cli/commands/session.py +472 -0
  16. foundry_mcp/cli/commands/specs.py +686 -0
  17. foundry_mcp/cli/commands/tasks.py +807 -0
  18. foundry_mcp/cli/commands/testing.py +676 -0
  19. foundry_mcp/cli/commands/validate.py +982 -0
  20. foundry_mcp/cli/config.py +98 -0
  21. foundry_mcp/cli/context.py +298 -0
  22. foundry_mcp/cli/logging.py +212 -0
  23. foundry_mcp/cli/main.py +44 -0
  24. foundry_mcp/cli/output.py +122 -0
  25. foundry_mcp/cli/registry.py +110 -0
  26. foundry_mcp/cli/resilience.py +178 -0
  27. foundry_mcp/cli/transcript.py +217 -0
  28. foundry_mcp/config.py +1454 -0
  29. foundry_mcp/core/__init__.py +144 -0
  30. foundry_mcp/core/ai_consultation.py +1773 -0
  31. foundry_mcp/core/batch_operations.py +1202 -0
  32. foundry_mcp/core/cache.py +195 -0
  33. foundry_mcp/core/capabilities.py +446 -0
  34. foundry_mcp/core/concurrency.py +898 -0
  35. foundry_mcp/core/context.py +540 -0
  36. foundry_mcp/core/discovery.py +1603 -0
  37. foundry_mcp/core/error_collection.py +728 -0
  38. foundry_mcp/core/error_store.py +592 -0
  39. foundry_mcp/core/health.py +749 -0
  40. foundry_mcp/core/intake.py +933 -0
  41. foundry_mcp/core/journal.py +700 -0
  42. foundry_mcp/core/lifecycle.py +412 -0
  43. foundry_mcp/core/llm_config.py +1376 -0
  44. foundry_mcp/core/llm_patterns.py +510 -0
  45. foundry_mcp/core/llm_provider.py +1569 -0
  46. foundry_mcp/core/logging_config.py +374 -0
  47. foundry_mcp/core/metrics_persistence.py +584 -0
  48. foundry_mcp/core/metrics_registry.py +327 -0
  49. foundry_mcp/core/metrics_store.py +641 -0
  50. foundry_mcp/core/modifications.py +224 -0
  51. foundry_mcp/core/naming.py +146 -0
  52. foundry_mcp/core/observability.py +1216 -0
  53. foundry_mcp/core/otel.py +452 -0
  54. foundry_mcp/core/otel_stubs.py +264 -0
  55. foundry_mcp/core/pagination.py +255 -0
  56. foundry_mcp/core/progress.py +387 -0
  57. foundry_mcp/core/prometheus.py +564 -0
  58. foundry_mcp/core/prompts/__init__.py +464 -0
  59. foundry_mcp/core/prompts/fidelity_review.py +691 -0
  60. foundry_mcp/core/prompts/markdown_plan_review.py +515 -0
  61. foundry_mcp/core/prompts/plan_review.py +627 -0
  62. foundry_mcp/core/providers/__init__.py +237 -0
  63. foundry_mcp/core/providers/base.py +515 -0
  64. foundry_mcp/core/providers/claude.py +472 -0
  65. foundry_mcp/core/providers/codex.py +637 -0
  66. foundry_mcp/core/providers/cursor_agent.py +630 -0
  67. foundry_mcp/core/providers/detectors.py +515 -0
  68. foundry_mcp/core/providers/gemini.py +426 -0
  69. foundry_mcp/core/providers/opencode.py +718 -0
  70. foundry_mcp/core/providers/opencode_wrapper.js +308 -0
  71. foundry_mcp/core/providers/package-lock.json +24 -0
  72. foundry_mcp/core/providers/package.json +25 -0
  73. foundry_mcp/core/providers/registry.py +607 -0
  74. foundry_mcp/core/providers/test_provider.py +171 -0
  75. foundry_mcp/core/providers/validation.py +857 -0
  76. foundry_mcp/core/rate_limit.py +427 -0
  77. foundry_mcp/core/research/__init__.py +68 -0
  78. foundry_mcp/core/research/memory.py +528 -0
  79. foundry_mcp/core/research/models.py +1234 -0
  80. foundry_mcp/core/research/providers/__init__.py +40 -0
  81. foundry_mcp/core/research/providers/base.py +242 -0
  82. foundry_mcp/core/research/providers/google.py +507 -0
  83. foundry_mcp/core/research/providers/perplexity.py +442 -0
  84. foundry_mcp/core/research/providers/semantic_scholar.py +544 -0
  85. foundry_mcp/core/research/providers/tavily.py +383 -0
  86. foundry_mcp/core/research/workflows/__init__.py +25 -0
  87. foundry_mcp/core/research/workflows/base.py +298 -0
  88. foundry_mcp/core/research/workflows/chat.py +271 -0
  89. foundry_mcp/core/research/workflows/consensus.py +539 -0
  90. foundry_mcp/core/research/workflows/deep_research.py +4142 -0
  91. foundry_mcp/core/research/workflows/ideate.py +682 -0
  92. foundry_mcp/core/research/workflows/thinkdeep.py +405 -0
  93. foundry_mcp/core/resilience.py +600 -0
  94. foundry_mcp/core/responses.py +1624 -0
  95. foundry_mcp/core/review.py +366 -0
  96. foundry_mcp/core/security.py +438 -0
  97. foundry_mcp/core/spec.py +4119 -0
  98. foundry_mcp/core/task.py +2463 -0
  99. foundry_mcp/core/testing.py +839 -0
  100. foundry_mcp/core/validation.py +2357 -0
  101. foundry_mcp/dashboard/__init__.py +32 -0
  102. foundry_mcp/dashboard/app.py +119 -0
  103. foundry_mcp/dashboard/components/__init__.py +17 -0
  104. foundry_mcp/dashboard/components/cards.py +88 -0
  105. foundry_mcp/dashboard/components/charts.py +177 -0
  106. foundry_mcp/dashboard/components/filters.py +136 -0
  107. foundry_mcp/dashboard/components/tables.py +195 -0
  108. foundry_mcp/dashboard/data/__init__.py +11 -0
  109. foundry_mcp/dashboard/data/stores.py +433 -0
  110. foundry_mcp/dashboard/launcher.py +300 -0
  111. foundry_mcp/dashboard/views/__init__.py +12 -0
  112. foundry_mcp/dashboard/views/errors.py +217 -0
  113. foundry_mcp/dashboard/views/metrics.py +164 -0
  114. foundry_mcp/dashboard/views/overview.py +96 -0
  115. foundry_mcp/dashboard/views/providers.py +83 -0
  116. foundry_mcp/dashboard/views/sdd_workflow.py +255 -0
  117. foundry_mcp/dashboard/views/tool_usage.py +139 -0
  118. foundry_mcp/prompts/__init__.py +9 -0
  119. foundry_mcp/prompts/workflows.py +525 -0
  120. foundry_mcp/resources/__init__.py +9 -0
  121. foundry_mcp/resources/specs.py +591 -0
  122. foundry_mcp/schemas/__init__.py +38 -0
  123. foundry_mcp/schemas/intake-schema.json +89 -0
  124. foundry_mcp/schemas/sdd-spec-schema.json +414 -0
  125. foundry_mcp/server.py +150 -0
  126. foundry_mcp/tools/__init__.py +10 -0
  127. foundry_mcp/tools/unified/__init__.py +92 -0
  128. foundry_mcp/tools/unified/authoring.py +3620 -0
  129. foundry_mcp/tools/unified/context_helpers.py +98 -0
  130. foundry_mcp/tools/unified/documentation_helpers.py +268 -0
  131. foundry_mcp/tools/unified/environment.py +1341 -0
  132. foundry_mcp/tools/unified/error.py +479 -0
  133. foundry_mcp/tools/unified/health.py +225 -0
  134. foundry_mcp/tools/unified/journal.py +841 -0
  135. foundry_mcp/tools/unified/lifecycle.py +640 -0
  136. foundry_mcp/tools/unified/metrics.py +777 -0
  137. foundry_mcp/tools/unified/plan.py +876 -0
  138. foundry_mcp/tools/unified/pr.py +294 -0
  139. foundry_mcp/tools/unified/provider.py +589 -0
  140. foundry_mcp/tools/unified/research.py +1283 -0
  141. foundry_mcp/tools/unified/review.py +1042 -0
  142. foundry_mcp/tools/unified/review_helpers.py +314 -0
  143. foundry_mcp/tools/unified/router.py +102 -0
  144. foundry_mcp/tools/unified/server.py +565 -0
  145. foundry_mcp/tools/unified/spec.py +1283 -0
  146. foundry_mcp/tools/unified/task.py +3846 -0
  147. foundry_mcp/tools/unified/test.py +431 -0
  148. foundry_mcp/tools/unified/verification.py +520 -0
  149. foundry_mcp-0.8.22.dist-info/METADATA +344 -0
  150. foundry_mcp-0.8.22.dist-info/RECORD +153 -0
  151. foundry_mcp-0.8.22.dist-info/WHEEL +4 -0
  152. foundry_mcp-0.8.22.dist-info/entry_points.txt +3 -0
  153. foundry_mcp-0.8.22.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,464 @@
1
+ """
2
+ Prompt templates and builders for AI consultation workflows.
3
+
4
+ This package provides:
5
+ 1. PromptTemplate dataclass for defining structured prompts
6
+ 2. PromptRegistry for registering and retrieving prompts by ID
7
+ 3. Workflow-specific prompt builders for different consultation use cases
8
+
9
+ Workflow Coverage:
10
+ - plan_review: Review and critique SDD specifications
11
+ - fidelity_review: Compare implementation against specifications
12
+
13
+ Example Usage:
14
+ from foundry_mcp.core.prompts import (
15
+ PromptTemplate,
16
+ PromptRegistry,
17
+ get_prompt_builder,
18
+ )
19
+ from foundry_mcp.core.ai_consultation import ConsultationWorkflow
20
+
21
+ # Register a custom prompt template
22
+ template = PromptTemplate(
23
+ id="custom_analysis",
24
+ version="1.0",
25
+ system_prompt="You are an expert code reviewer.",
26
+ user_template="Analyze the following code: {code}",
27
+ required_context=["code"],
28
+ )
29
+ registry = PromptRegistry()
30
+ registry.register(template)
31
+
32
+ # Or use workflow-specific builders
33
+ builder = get_prompt_builder(ConsultationWorkflow.PLAN_REVIEW)
34
+ prompt = builder.build("spec_review", {"spec_content": "..."})
35
+ """
36
+
37
+ from __future__ import annotations
38
+
39
+ import logging
40
+ import re
41
+ from abc import ABC, abstractmethod
42
+ from dataclasses import dataclass, field
43
+ from typing import Any, Dict, List, Optional, Set, TYPE_CHECKING
44
+
45
+ if TYPE_CHECKING:
46
+ from foundry_mcp.core.ai_consultation import ConsultationWorkflow
47
+
48
+ logger = logging.getLogger(__name__)
49
+
50
+
51
+ # =============================================================================
52
+ # PromptTemplate Dataclass
53
+ # =============================================================================
54
+
55
+
56
+ @dataclass(frozen=True)
57
+ class PromptTemplate:
58
+ """
59
+ Structured prompt template for AI consultations.
60
+
61
+ Defines a reusable prompt with system and user components, required
62
+ context variables, and metadata for tracking and versioning.
63
+
64
+ Attributes:
65
+ id: Unique identifier for the template (e.g., "analyze_module")
66
+ version: Template version for tracking changes (e.g., "1.0", "2.1")
67
+ system_prompt: System/instruction prompt (sent as system message)
68
+ user_template: User message template with {variable} placeholders
69
+ required_context: List of required context keys for rendering
70
+ optional_context: List of optional context keys (have defaults)
71
+ metadata: Additional template metadata (author, tags, etc.)
72
+
73
+ Example:
74
+ template = PromptTemplate(
75
+ id="analyze_module",
76
+ version="1.0",
77
+ system_prompt="You are an expert Python developer.",
78
+ user_template="Analyze this module:\\n\\n{code}\\n\\nFile: {file_path}",
79
+ required_context=["code", "file_path"],
80
+ metadata={"author": "system", "category": "documentation"},
81
+ )
82
+ """
83
+
84
+ id: str
85
+ version: str
86
+ system_prompt: str
87
+ user_template: str
88
+ required_context: List[str] = field(default_factory=list)
89
+ optional_context: List[str] = field(default_factory=list)
90
+ metadata: Dict[str, Any] = field(default_factory=dict)
91
+
92
+ def __post_init__(self) -> None:
93
+ """Validate template after initialization."""
94
+ if not self.id:
95
+ raise ValueError("Template id cannot be empty")
96
+ if not self.version:
97
+ raise ValueError("Template version cannot be empty")
98
+ if not self.user_template:
99
+ raise ValueError("Template user_template cannot be empty")
100
+
101
+ def get_variables(self) -> Set[str]:
102
+ """
103
+ Extract all variable names from the user template.
104
+
105
+ Returns:
106
+ Set of variable names found in {variable} placeholders
107
+ """
108
+ # Find all {variable} patterns, excluding {{ and }}
109
+ pattern = r'\{([a-zA-Z_][a-zA-Z0-9_]*)\}'
110
+ return set(re.findall(pattern, self.user_template))
111
+
112
+ def validate_context(self, context: Dict[str, Any]) -> List[str]:
113
+ """
114
+ Validate that context contains all required keys.
115
+
116
+ Args:
117
+ context: Context dict to validate
118
+
119
+ Returns:
120
+ List of missing required keys (empty if valid)
121
+ """
122
+ missing = []
123
+ for key in self.required_context:
124
+ if key not in context:
125
+ missing.append(key)
126
+ return missing
127
+
128
+ def render(
129
+ self,
130
+ context: Dict[str, Any],
131
+ *,
132
+ strict: bool = True,
133
+ defaults: Optional[Dict[str, Any]] = None,
134
+ ) -> str:
135
+ """
136
+ Render the user template with context substitution.
137
+
138
+ Args:
139
+ context: Context dict with variable values
140
+ strict: If True, raise ValueError for missing required keys
141
+ defaults: Default values for optional context keys
142
+
143
+ Returns:
144
+ Rendered template string
145
+
146
+ Raises:
147
+ ValueError: If strict=True and required keys are missing
148
+ """
149
+ # Validate required context
150
+ missing = self.validate_context(context)
151
+ if missing and strict:
152
+ raise ValueError(
153
+ f"Missing required context keys for template '{self.id}': {missing}"
154
+ )
155
+
156
+ # Build render context with defaults
157
+ render_context = dict(defaults or {})
158
+ render_context.update(context)
159
+
160
+ # Provide empty string for missing optional keys
161
+ for key in self.optional_context:
162
+ if key not in render_context:
163
+ render_context[key] = ""
164
+
165
+ try:
166
+ return self.user_template.format(**render_context)
167
+ except KeyError as exc:
168
+ raise ValueError(
169
+ f"Missing context key for template '{self.id}': {exc}"
170
+ ) from exc
171
+
172
+
173
+ # =============================================================================
174
+ # PromptRegistry
175
+ # =============================================================================
176
+
177
+
178
+ class PromptRegistry:
179
+ """
180
+ Registry for managing prompt templates.
181
+
182
+ Provides registration, retrieval, and listing of prompt templates
183
+ by ID, with optional namespace support for organizing templates.
184
+
185
+ Attributes:
186
+ templates: Dict mapping template IDs to PromptTemplate instances
187
+
188
+ Example:
189
+ registry = PromptRegistry()
190
+
191
+ # Register a template
192
+ template = PromptTemplate(
193
+ id="analyze_code",
194
+ version="1.0",
195
+ system_prompt="You are a code analyst.",
196
+ user_template="Analyze: {code}",
197
+ required_context=["code"],
198
+ )
199
+ registry.register(template)
200
+
201
+ # Retrieve and use
202
+ t = registry.get("analyze_code")
203
+ prompt = t.render({"code": "def foo(): pass"})
204
+ """
205
+
206
+ def __init__(self) -> None:
207
+ """Initialize an empty registry."""
208
+ self._templates: Dict[str, PromptTemplate] = {}
209
+
210
+ def register(
211
+ self,
212
+ template: PromptTemplate,
213
+ *,
214
+ replace: bool = False,
215
+ ) -> None:
216
+ """
217
+ Register a prompt template.
218
+
219
+ Args:
220
+ template: The PromptTemplate to register
221
+ replace: If True, replace existing template with same ID
222
+
223
+ Raises:
224
+ ValueError: If template ID already registered and replace=False
225
+ """
226
+ if template.id in self._templates and not replace:
227
+ raise ValueError(
228
+ f"Template '{template.id}' is already registered. "
229
+ "Use replace=True to overwrite."
230
+ )
231
+
232
+ self._templates[template.id] = template
233
+ logger.debug(
234
+ "Registered prompt template '%s' (version %s)",
235
+ template.id,
236
+ template.version,
237
+ )
238
+
239
+ def get(self, template_id: str) -> Optional[PromptTemplate]:
240
+ """
241
+ Retrieve a template by ID.
242
+
243
+ Args:
244
+ template_id: The template identifier
245
+
246
+ Returns:
247
+ PromptTemplate if found, None otherwise
248
+ """
249
+ return self._templates.get(template_id)
250
+
251
+ def get_required(self, template_id: str) -> PromptTemplate:
252
+ """
253
+ Retrieve a template by ID, raising if not found.
254
+
255
+ Args:
256
+ template_id: The template identifier
257
+
258
+ Returns:
259
+ The PromptTemplate
260
+
261
+ Raises:
262
+ KeyError: If template not found
263
+ """
264
+ template = self._templates.get(template_id)
265
+ if template is None:
266
+ available = ", ".join(sorted(self._templates.keys())) or "(none)"
267
+ raise KeyError(
268
+ f"Template '{template_id}' not found. Available: {available}"
269
+ )
270
+ return template
271
+
272
+ def list_templates(self) -> List[str]:
273
+ """
274
+ Return list of registered template IDs.
275
+
276
+ Returns:
277
+ Sorted list of template IDs
278
+ """
279
+ return sorted(self._templates.keys())
280
+
281
+ def unregister(self, template_id: str) -> bool:
282
+ """
283
+ Remove a template from the registry.
284
+
285
+ Args:
286
+ template_id: The template identifier
287
+
288
+ Returns:
289
+ True if template was removed, False if not found
290
+ """
291
+ if template_id in self._templates:
292
+ del self._templates[template_id]
293
+ logger.debug("Unregistered prompt template '%s'", template_id)
294
+ return True
295
+ return False
296
+
297
+ def clear(self) -> None:
298
+ """Remove all templates from the registry."""
299
+ self._templates.clear()
300
+ logger.debug("Cleared all prompt templates from registry")
301
+
302
+ def render(
303
+ self,
304
+ template_id: str,
305
+ context: Dict[str, Any],
306
+ *,
307
+ strict: bool = True,
308
+ ) -> str:
309
+ """
310
+ Render a template by ID with context.
311
+
312
+ Convenience method combining get_required() and render().
313
+
314
+ Args:
315
+ template_id: The template identifier
316
+ context: Context dict for rendering
317
+ strict: If True, raise for missing required keys
318
+
319
+ Returns:
320
+ Rendered template string
321
+
322
+ Raises:
323
+ KeyError: If template not found
324
+ ValueError: If strict=True and required keys missing
325
+ """
326
+ template = self.get_required(template_id)
327
+ return template.render(context, strict=strict)
328
+
329
+ def __len__(self) -> int:
330
+ """Return number of registered templates."""
331
+ return len(self._templates)
332
+
333
+ def __contains__(self, template_id: str) -> bool:
334
+ """Check if template ID is registered."""
335
+ return template_id in self._templates
336
+
337
+
338
+ # =============================================================================
339
+ # Global Registry Instance
340
+ # =============================================================================
341
+
342
+
343
+ # Default global registry for application-wide templates
344
+ _global_registry: Optional[PromptRegistry] = None
345
+
346
+
347
+ def get_global_registry() -> PromptRegistry:
348
+ """
349
+ Get the global prompt registry singleton.
350
+
351
+ Returns:
352
+ The global PromptRegistry instance
353
+ """
354
+ global _global_registry
355
+ if _global_registry is None:
356
+ _global_registry = PromptRegistry()
357
+ return _global_registry
358
+
359
+
360
+ def reset_global_registry() -> None:
361
+ """Reset the global registry (primarily for testing)."""
362
+ global _global_registry
363
+ _global_registry = None
364
+
365
+
366
+ # =============================================================================
367
+ # PromptBuilder ABC (Workflow-specific)
368
+ # =============================================================================
369
+
370
+
371
+ class PromptBuilder(ABC):
372
+ """
373
+ Abstract base class for workflow-specific prompt builders.
374
+
375
+ Subclasses implement prompt templates for specific consultation workflows,
376
+ providing a consistent interface for prompt generation. Each builder
377
+ manages its own set of templates internally.
378
+
379
+ Methods:
380
+ build: Generate a prompt from a template ID and context
381
+ list_prompts: Return available prompt IDs for this workflow
382
+ """
383
+
384
+ @abstractmethod
385
+ def build(self, prompt_id: str, context: Dict[str, Any]) -> str:
386
+ """
387
+ Build a prompt from template ID and context.
388
+
389
+ Args:
390
+ prompt_id: Identifier for the prompt template
391
+ context: Structured context data to inject
392
+
393
+ Returns:
394
+ The rendered prompt string
395
+
396
+ Raises:
397
+ ValueError: If prompt_id is not recognized
398
+ """
399
+ raise NotImplementedError
400
+
401
+ @abstractmethod
402
+ def list_prompts(self) -> List[str]:
403
+ """
404
+ Return list of available prompt IDs.
405
+
406
+ Returns:
407
+ List of prompt template IDs
408
+ """
409
+ raise NotImplementedError
410
+
411
+
412
+ # =============================================================================
413
+ # Workflow Builder Factory
414
+ # =============================================================================
415
+
416
+
417
+ def get_prompt_builder(workflow: "ConsultationWorkflow") -> PromptBuilder:
418
+ """
419
+ Get the prompt builder for a consultation workflow.
420
+
421
+ Args:
422
+ workflow: The consultation workflow type
423
+
424
+ Returns:
425
+ PromptBuilder instance for the workflow
426
+
427
+ Raises:
428
+ ValueError: If workflow is not supported
429
+ """
430
+ # Import here to avoid circular imports
431
+ from foundry_mcp.core.ai_consultation import ConsultationWorkflow
432
+ from foundry_mcp.core.prompts.plan_review import PlanReviewPromptBuilder
433
+ from foundry_mcp.core.prompts.fidelity_review import FidelityReviewPromptBuilder
434
+ from foundry_mcp.core.prompts.markdown_plan_review import MarkdownPlanReviewPromptBuilder
435
+
436
+ builders: Dict[ConsultationWorkflow, type[PromptBuilder]] = {
437
+ ConsultationWorkflow.PLAN_REVIEW: PlanReviewPromptBuilder,
438
+ ConsultationWorkflow.FIDELITY_REVIEW: FidelityReviewPromptBuilder,
439
+ ConsultationWorkflow.MARKDOWN_PLAN_REVIEW: MarkdownPlanReviewPromptBuilder,
440
+ }
441
+
442
+ builder_class = builders.get(workflow)
443
+ if builder_class is None:
444
+ raise ValueError(f"Unsupported workflow: {workflow}")
445
+
446
+ return builder_class()
447
+
448
+
449
+ # =============================================================================
450
+ # Module Exports
451
+ # =============================================================================
452
+
453
+
454
+ __all__ = [
455
+ # Template dataclass
456
+ "PromptTemplate",
457
+ # Registry
458
+ "PromptRegistry",
459
+ "get_global_registry",
460
+ "reset_global_registry",
461
+ # Builder ABC
462
+ "PromptBuilder",
463
+ "get_prompt_builder",
464
+ ]