"""
Framework prompt loader system.
This file implements the registration and dependency injection system for framework prompts.
It solves the architectural challenge of allowing framework infrastructure to use domain-specific
prompts without creating circular dependencies. Applications register their prompt providers here,
and framework components can request prompts through the abstract interface without knowing which
specific application is providing them. This achieves true dependency inversion - the framework
depends on abstractions, not concrete implementations.
"""
from typing import Dict, Optional
from .base import FrameworkPromptBuilder
[docs]
class FrameworkPromptProvider:
"""Abstract provider interface for framework prompt builders with dependency injection support.
This class defines the contract that applications must implement to provide
domain-specific prompt builders to the framework infrastructure. It enables
clean separation of concerns where the framework handles orchestration, task
extraction, and response generation logic while applications provide the
domain-specific prompts and terminology.
The provider pattern solves the architectural challenge of allowing framework
infrastructure to use application-specific prompts without creating circular
dependencies. Framework components request prompt builders through this
abstract interface, and the registry system injects the appropriate
application-specific implementations at runtime.
Prompt builders are organized into two categories:
**Infrastructure Prompts**: Used by core framework components like
orchestration, task extraction, and response generation. These prompts
control the fundamental behavior of the agent system.
**Framework Capability Prompts**: Used by built-in framework capabilities
like memory extraction, time parsing, and Python execution. These prompts
can be customized to use domain-specific terminology and examples.
:raises NotImplementedError: All methods must be implemented by concrete providers
.. note::
Applications typically inherit from this class and override only the
prompt builders they want to customize, using framework defaults for
the rest through composition patterns.
.. warning::
All methods in this interface must be implemented. Use framework defaults
or delegation patterns if you don't need custom behavior for specific prompts.
Examples:
Basic application-specific provider::
class ALSPromptProvider(FrameworkPromptProvider):
def __init__(self):
# Use custom builders for key infrastructure prompts
self._orchestrator = ALSOrchestratorPromptBuilder()
self._task_extraction = ALSTaskExtractionPromptBuilder()
# Use framework defaults for others
from framework.prompts.defaults import DefaultPromptProvider
self._defaults = DefaultPromptProvider()
def get_orchestrator_prompt_builder(self):
return self._orchestrator
def get_task_extraction_prompt_builder(self):
return self._task_extraction
def get_classification_prompt_builder(self):
# Delegate to framework default
return self._defaults.get_classification_prompt_builder()
Registration in application registry::
framework_prompt_providers=[
FrameworkPromptProviderRegistration(
application_name="als_expert",
module_path="applications.als_expert.framework_prompts",
description="ALS-specific framework prompt provider",
prompt_builders={
"orchestrator": "ALSOrchestratorPromptBuilder",
"task_extraction": "ALSTaskExtractionPromptBuilder"
# Others use framework defaults
}
)
]
.. seealso::
:class:`FrameworkPromptBuilder` : Base class for individual prompt builders
:class:`FrameworkPromptLoader` : Global loader for provider management
:func:`register_framework_prompt_provider` : Provider registration function
:doc:`/developer-guides/03_core-framework-systems/04_prompt-customization` : Complete customization guide
"""
# =================================================================
# Infrastructure prompts (used by framework infrastructure)
# =================================================================
[docs]
def get_orchestrator_prompt_builder(self) -> FrameworkPromptBuilder:
"""Provide prompt builder for execution planning and orchestration.
This prompt builder is used by the orchestration node to create detailed
execution plans that break down user requests into specific, actionable
steps. The orchestrator prompt is critical for the agent's ability to
coordinate multiple capabilities and manage complex workflows.
:return: Orchestrator prompt builder instance
:rtype: FrameworkPromptBuilder
:raises NotImplementedError: Must be implemented by concrete providers
.. note::
The orchestrator prompt heavily influences the agent's planning
capabilities and should include domain-specific planning patterns
and capability integration guidance.
.. seealso::
:class:`OrchestrationNode` : Infrastructure component that uses this prompt
:class:`OrchestratorGuide` : Planning guidance structure
"""
raise NotImplementedError
[docs]
def get_response_generation_prompt_builder(self) -> FrameworkPromptBuilder:
"""Provide prompt builder for generating final user responses.
This prompt builder is used by the response generation system to create
coherent, helpful responses based on execution results. It handles the
synthesis of multiple execution outputs into user-friendly responses
with appropriate formatting and context.
:return: Response generation prompt builder instance
:rtype: FrameworkPromptBuilder
:raises NotImplementedError: Must be implemented by concrete providers
.. note::
Response generation prompts should reflect the application's
communication style and include domain-specific formatting guidelines.
.. seealso::
:class:`RespondCapability` : Component that uses this prompt
:func:`_get_base_system_prompt` : Response prompt composition
"""
raise NotImplementedError
[docs]
def get_classification_prompt_builder(self) -> FrameworkPromptBuilder:
"""Provide prompt builder for task and capability classification.
This prompt builder is used by the classification system to determine
which capabilities are needed for specific tasks. It enables intelligent
routing of tasks to appropriate capabilities based on content analysis
and domain-specific patterns.
:return: Classification prompt builder instance
:rtype: FrameworkPromptBuilder
:raises NotImplementedError: Must be implemented by concrete providers
.. note::
Classification prompts should include clear criteria for capability
selection and domain-specific task categorization patterns.
.. seealso::
:func:`select_capabilities` : Task classification function
:class:`TaskClassifierGuide` : Classification guidance structure
"""
raise NotImplementedError
[docs]
def get_error_analysis_prompt_builder(self) -> FrameworkPromptBuilder:
"""Provide prompt builder for error analysis and recovery guidance.
This prompt builder is used by the error handling system to analyze
failures and provide meaningful explanations to users. It focuses on
translating technical errors into understandable explanations with
appropriate recovery suggestions.
:return: Error analysis prompt builder instance
:rtype: FrameworkPromptBuilder
:raises NotImplementedError: Must be implemented by concrete providers
.. note::
Error analysis prompts should provide domain-specific context for
common failure modes and recovery patterns.
.. seealso::
:class:`ErrorNode` : Infrastructure component for error handling
:class:`ErrorClassification` : Error categorization system
"""
raise NotImplementedError
[docs]
def get_clarification_prompt_builder(self) -> FrameworkPromptBuilder:
"""Provide prompt builder for generating clarifying questions.
This prompt builder is used by the clarification system to generate
targeted questions when user requests are ambiguous or incomplete.
It helps gather the specific information needed to provide accurate
and helpful responses.
:return: Clarification prompt builder instance
:rtype: FrameworkPromptBuilder
:raises NotImplementedError: Must be implemented by concrete providers
.. note::
Clarification prompts should include domain-specific question
patterns and common ambiguity resolution strategies.
.. seealso::
:class:`ClarifyCapability` : Component that uses this prompt
:class:`ClarifyingQuestionsResponse` : Output structure for questions
"""
raise NotImplementedError
# =================================================================
# Framework capability prompts (used by framework capabilities)
# =================================================================
[docs]
def get_time_range_parsing_prompt_builder(self) -> FrameworkPromptBuilder:
"""Provide prompt builder for parsing natural language time expressions.
This prompt builder is used by the time range parsing capability to
convert natural language time expressions into structured datetime
ranges. It handles relative expressions, absolute dates, and
domain-specific time references.
:return: Time range parsing prompt builder instance
:rtype: FrameworkPromptBuilder
:raises NotImplementedError: Must be implemented by concrete providers
.. note::
Time parsing prompts should include domain-specific time patterns
and examples relevant to the application's temporal context.
.. seealso::
:class:`TimeRangeParsingCapability` : Framework capability that uses this prompt
:class:`TimeRange` : Output structure for parsed time ranges
"""
raise NotImplementedError
[docs]
def get_python_prompt_builder(self) -> FrameworkPromptBuilder:
"""Provide prompt builder for Python code generation and execution.
This prompt builder is used by the Python execution capability to
generate and execute Python code for data analysis, calculations,
and other computational tasks. It includes safety guidelines and
domain-specific code patterns.
:return: Python capability prompt builder instance
:rtype: FrameworkPromptBuilder
:raises NotImplementedError: Must be implemented by concrete providers
.. note::
Python prompts should include domain-specific libraries, patterns,
and safety constraints appropriate for the application context.
.. seealso::
:class:`PythonCapability` : Framework capability that uses this prompt
:class:`PythonExecutionService` : Code execution infrastructure
"""
raise NotImplementedError
[docs]
class FrameworkPromptLoader:
"""Global registry and dependency injection system for framework prompt providers.
This class manages the registration and retrieval of application-specific
prompt providers, enabling the framework infrastructure to access domain-specific
prompts without creating circular dependencies. It implements a service locator
pattern with fail-fast error handling and clear diagnostics.
The loader maintains a registry of prompt providers keyed by application name,
with automatic default provider selection and explicit provider override
capabilities. It's designed to be used as a singleton through the global
module-level functions.
:param _providers: Registry of application prompt providers
:type _providers: Dict[str, FrameworkPromptProvider]
:param _default_provider: Name of the default provider application
:type _default_provider: Optional[str]
.. note::
This class is typically accessed through the module-level functions
rather than instantiated directly. The global instance handles all
framework prompt provider management.
.. warning::
Provider registration must occur during application initialization
before any framework components attempt to access prompts.
Examples:
Typical usage through module functions::
# Registration (usually in application initialization)
register_framework_prompt_provider("als_expert", ALSPromptProvider())
# Access (from framework infrastructure)
provider = get_framework_prompts()
orchestrator_builder = provider.get_orchestrator_prompt_builder()
Direct usage for testing or specialized cases::
loader = FrameworkPromptLoader()
loader.register_provider("test_app", TestPromptProvider())
provider = loader.get_provider("test_app")
.. seealso::
:func:`get_framework_prompts` : Primary access function
:func:`register_framework_prompt_provider` : Provider registration
:class:`FrameworkPromptProvider` : Provider interface
"""
[docs]
def __init__(self):
"""Initialize empty prompt provider registry.
Creates a new loader instance with empty provider registry and no
default provider. The first registered provider automatically becomes
the default unless explicitly overridden.
"""
self._providers: Dict[str, FrameworkPromptProvider] = {}
self._default_provider: Optional[str] = None
[docs]
def register_provider(self, application_name: str, provider: FrameworkPromptProvider):
"""Register a prompt provider for an application with automatic default selection.
Adds the provider to the registry and automatically sets it as the default
if no default provider is currently configured. This enables simple
single-application setups while supporting multi-application scenarios.
:param application_name: Unique identifier for the application
:type application_name: str
:param provider: Prompt provider implementation for the application
:type provider: FrameworkPromptProvider
.. note::
The first registered provider automatically becomes the default.
Use set_default_provider() to change the default selection.
Examples:
Basic registration::
loader.register_provider("als_expert", ALSPromptProvider())
# als_expert becomes default if first registration
Multiple application registration::
loader.register_provider("als_expert", ALSPromptProvider())
loader.register_provider("wind_turbine", WindTurbinePromptProvider())
# als_expert remains default
.. seealso::
:meth:`set_default_provider` : Explicit default provider selection
:meth:`get_provider` : Provider retrieval
"""
self._providers[application_name] = provider
if self._default_provider is None:
self._default_provider = application_name
[docs]
def set_default_provider(self, application_name: str):
"""Set the default prompt provider with validation.
Changes the default provider to the specified application, with
validation to ensure the provider is already registered. The default
provider is used when no specific application is requested.
:param application_name: Name of registered application to use as default
:type application_name: str
:raises ValueError: If the specified provider is not registered
Examples:
Setting default after multiple registrations::
loader.register_provider("als_expert", ALSPromptProvider())
loader.register_provider("wind_turbine", WindTurbinePromptProvider())
loader.set_default_provider("wind_turbine")
# wind_turbine is now default instead of als_expert
.. seealso::
:meth:`register_provider` : Provider registration with auto-default
:meth:`get_provider` : Provider retrieval using defaults
"""
if application_name not in self._providers:
raise ValueError(f"Provider '{application_name}' not registered")
self._default_provider = application_name
[docs]
def get_provider(self, application_name: Optional[str] = None) -> FrameworkPromptProvider:
"""Retrieve prompt provider with fail-fast error handling and clear diagnostics.
Returns the prompt provider for the specified application, or the default
provider if no application is specified. Provides comprehensive error
messages with available alternatives when providers are not found.
:param application_name: Specific application name, or None for default
:type application_name: Optional[str]
:return: Prompt provider implementation for the application
:rtype: FrameworkPromptProvider
:raises ValueError: If no default provider is configured
:raises ValueError: If specified provider is not found
.. note::
This method uses fail-fast error handling to catch configuration
issues early in the application lifecycle with clear error messages.
Examples:
Using default provider::
provider = loader.get_provider() # Uses default
orchestrator = provider.get_orchestrator_prompt_builder()
Using specific provider::
provider = loader.get_provider("als_expert")
task_extractor = provider.get_task_extraction_prompt_builder()
Error handling::
try:
provider = loader.get_provider("nonexistent")
except ValueError as e:
print(f"Provider error: {e}")
# Error includes list of available providers
.. seealso::
:meth:`register_provider` : Provider registration
:meth:`set_default_provider` : Default provider management
"""
if application_name is None:
application_name = self._default_provider
if application_name is None:
raise ValueError("No default prompt provider configured")
if application_name not in self._providers:
available = list(self._providers.keys())
raise ValueError(f"Prompt provider '{application_name}' not found. Available: {available}")
return self._providers[application_name]
# Global prompt loader instance - singleton for framework-wide prompt provider management
_prompt_loader = FrameworkPromptLoader()
[docs]
def get_framework_prompts(application_name: Optional[str] = None) -> FrameworkPromptProvider:
"""Access the framework prompt provider system with optional application targeting.
This is the primary entry point for framework components to access prompt
builders. It provides a clean interface to the global prompt provider registry,
enabling dependency injection of application-specific prompts without
circular dependencies.
The function supports both default provider access (for single-application
deployments) and explicit provider selection (for multi-application scenarios).
It integrates with the global prompt loader to provide consistent access
patterns across the framework.
:param application_name: Specific application provider to use, or None for default
:type application_name: Optional[str]
:return: Prompt provider implementation for the specified or default application
:rtype: FrameworkPromptProvider
:raises ValueError: If no providers are registered or specified provider not found
.. note::
This function is the recommended way to access prompt providers from
framework infrastructure components. It provides consistent error handling
and integrates with the application registry system.
Examples:
Framework infrastructure usage::
# In orchestration_node.py
prompt_provider = get_framework_prompts()
orchestrator_builder = prompt_provider.get_orchestrator_prompt_builder()
system_prompt = orchestrator_builder.get_system_instructions(
capabilities=active_capabilities,
context_manager=context_manager
)
Multi-application deployment::
# Use specific application's prompts
als_provider = get_framework_prompts("als_expert")
wind_provider = get_framework_prompts("wind_turbine")
Error handling pattern::
try:
provider = get_framework_prompts()
except ValueError as e:
logger.error(f"Prompt provider not configured: {e}")
# Fallback to framework defaults or fail gracefully
.. seealso::
:func:`register_framework_prompt_provider` : Provider registration
:class:`FrameworkPromptProvider` : Provider interface definition
:class:`FrameworkPromptLoader` : Underlying registry implementation
"""
return _prompt_loader.get_provider(application_name)
[docs]
def register_framework_prompt_provider(application_name: str, provider: FrameworkPromptProvider):
"""Register an application-specific prompt provider in the global registry.
This function integrates application prompt providers with the framework's
dependency injection system. It's typically called during application
initialization to make domain-specific prompts available to framework
infrastructure components.
The registration enables the framework to use application-specific terminology,
examples, and patterns while maintaining clean architectural separation.
The first registered provider automatically becomes the default for
single-application deployments.
:param application_name: Unique identifier for the application
:type application_name: str
:param provider: Implementation of the prompt provider interface
:type provider: FrameworkPromptProvider
.. note::
This function should be called during application initialization,
typically from the application's registry configuration or startup code.
.. warning::
Provider registration must occur before any framework components
attempt to access prompts, or ValueError exceptions will be raised.
Examples:
Application initialization::
# In als_expert/__init__.py or registry setup
from applications.als_expert.framework_prompts import ALSPromptProvider
register_framework_prompt_provider(
"als_expert",
ALSPromptProvider()
)
Multiple application setup::
register_framework_prompt_provider("als_expert", ALSPromptProvider())
register_framework_prompt_provider("wind_turbine", WindTurbinePromptProvider())
# First registration (als_expert) becomes default
Testing setup::
# In test fixtures
test_provider = MockPromptProvider()
register_framework_prompt_provider("test", test_provider)
.. seealso::
:func:`get_framework_prompts` : Provider access function
:func:`set_default_framework_prompt_provider` : Default provider management
:class:`FrameworkPromptProviderRegistration` : Registry metadata structure
"""
_prompt_loader.register_provider(application_name, provider)
def set_default_framework_prompt_provider(application_name: str):
"""Configure the default prompt provider for framework components.
This function changes which application's prompt provider is used when
framework components don't specify a particular application. It's useful
in multi-application deployments where you want to control which
application's prompts are used by default.
The default provider is used by get_framework_prompts() when no specific
application name is provided, enabling clean single-application usage
patterns while supporting multi-application flexibility.
:param application_name: Name of registered application to use as default
:type application_name: str
:raises ValueError: If the specified application is not registered
.. note::
The first registered provider automatically becomes the default.
This function is only needed to change the default selection.
Examples:
Changing default in multi-application setup::
# Register multiple providers
register_framework_prompt_provider("als_expert", ALSPromptProvider())
register_framework_prompt_provider("wind_turbine", WindTurbinePromptProvider())
# als_expert is default (first registered)
# Change to wind_turbine as default
set_default_framework_prompt_provider("wind_turbine")
# Now get_framework_prompts() returns wind_turbine provider
Runtime provider switching::
# Switch defaults based on configuration or context
if config.get("primary_application") == "wind_turbine":
set_default_framework_prompt_provider("wind_turbine")
else:
set_default_framework_prompt_provider("als_expert")
.. seealso::
:func:`register_framework_prompt_provider` : Provider registration
:func:`get_framework_prompts` : Provider access with default selection
:class:`FrameworkPromptLoader` : Underlying registry implementation
"""
_prompt_loader.set_default_provider(application_name)