Action Parameters#
This section describes the special parameters automatically provided to actions by the NeMo Guardrails library.
Special Parameters#
When you include these parameters in your action’s function signature, they are automatically populated:
Parameter |
Type |
Description |
|---|---|---|
|
|
Context data available to the action |
|
|
History of events in the conversation |
|
|
Access to the LLM instance |
|
|
The full configuration instance |
|
|
Access to the LLM task manager for prompt rendering |
|
|
The runtime state object (Colang 2.x only) |
Important
Special parameters are only injected for actions that run locally. When an actions_server_url is configured, non-system actions are sent to the remote server and do not receive these parameters. To ensure an action always receives special parameters, mark it with is_system_action=True. When no actions server is configured, all actions run locally and receive these parameters regardless of is_system_action.
The context Parameter#
The context parameter provides access to conversation state and variables:
from typing import Optional
from nemoguardrails.actions import action
@action(is_system_action=True)
async def my_action(context: Optional[dict] = None):
# Access context variables
user_message = context.get("last_user_message")
bot_message = context.get("bot_message")
relevant_chunks = context.get("relevant_chunks")
return True
Common Context Variables#
Variable |
Description |
Availability |
|---|---|---|
|
The most recent user message |
Always available after user input |
|
The current bot message (in output rails) |
Available in output rails |
|
The previous bot message |
Available after first bot response |
|
Retrieved knowledge base chunks |
Only after |
|
The canonical user intent |
Only after |
|
The canonical bot intent |
Only after |
Accessing Custom Context#
Custom context variables set in flows are also accessible:
# In a Colang flow
$user_preference = "dark_mode"
execute check_preference
@action()
async def check_preference(context: Optional[dict] = None):
preference = context.get("user_preference")
return preference == "dark_mode"
The events Parameter#
The events parameter provides the complete event history:
from typing import List, Optional
from nemoguardrails.actions import action
@action()
async def analyze_conversation(events: Optional[List[dict]] = None):
# Count user messages
user_messages = [
e for e in events
if e.get("type") == "UtteranceUserActionFinished"
]
return {"message_count": len(user_messages)}
Event Types#
Event Type |
Description |
|---|---|
|
User sent a message |
|
Bot started responding |
|
Bot finished responding |
|
System action started |
|
System action completed |
|
User intent was determined |
|
Bot intent was determined |
Event Structure Example#
{
"type": "UtteranceUserActionFinished",
"uid": "abc123",
"final_transcript": "Hello, how are you?",
"action_uid": "action_001",
"is_success": True
}
The llm Parameter#
The llm parameter provides direct access to the LLM instance:
from typing import Optional
from langchain_core.language_models import BaseLLM
from nemoguardrails.actions import action
@action()
async def custom_llm_call(
prompt: str,
llm: Optional[BaseLLM] = None
):
"""Make a custom LLM call."""
if llm is None:
return "LLM not available"
response = await llm.agenerate([prompt])
return response.generations[0][0].text
Use Cases for LLM Access#
Custom prompt engineering
Multiple LLM calls within a single action
Specialized text processing
@action()
async def summarize_and_validate(
text: str,
llm: Optional[BaseLLM] = None
):
"""Summarize text and validate the summary."""
# First call: summarize
summary_prompt = f"Summarize this text: {text}"
summary = await llm.agenerate([summary_prompt])
summary_text = summary.generations[0][0].text
# Second call: validate
validation_prompt = f"Is this summary accurate? {summary_text}"
validation = await llm.agenerate([validation_prompt])
return {
"summary": summary_text,
"validation": validation.generations[0][0].text
}
Action-Specific LLM#
You can register a dedicated LLM for a specific action using the {action_name}_llm naming convention. When registered, it overrides the default llm parameter for that action:
from nemoguardrails import LLMRails, RailsConfig
config = RailsConfig.from_path("config")
rails = LLMRails(config)
rails.register_action_param("my_custom_action_llm", specialized_llm)
When my_custom_action runs and requests the llm parameter, it receives specialized_llm instead of the default LLM.
The config Parameter#
The config parameter provides access to the full configuration:
from typing import Optional
from nemoguardrails import RailsConfig
from nemoguardrails.actions import action
@action()
async def check_config_setting(config: Optional[RailsConfig] = None):
"""Access configuration settings."""
# Access model configuration
models = config.models
main_model = next(
(m for m in models if m.type == "main"),
None
)
# Access custom config data
custom_data = config.custom_data
return {
"model_engine": main_model.engine if main_model else None,
"custom_data": custom_data
}
Configuration Access Examples#
@action()
async def get_active_rails(config: Optional[RailsConfig] = None):
"""Get list of active rails."""
rails_config = config.rails
return {
"input_rails": rails_config.input.flows if rails_config.input else [],
"output_rails": rails_config.output.flows if rails_config.output else []
}
The llm_task_manager Parameter#
The llm_task_manager parameter provides access to prompt rendering and LLM task management:
from typing import Optional
from nemoguardrails.actions import action
from nemoguardrails.llm.taskmanager import LLMTaskManager
@action()
async def custom_task(llm_task_manager: Optional[LLMTaskManager] = None):
"""Use the LLM task manager for prompt rendering."""
pass
Combining Multiple Parameters#
You can use multiple special parameters together:
@action(is_system_action=True)
async def advanced_check(
context: Optional[dict] = None,
events: Optional[List[dict]] = None,
llm: Optional[BaseLLM] = None,
config: Optional[RailsConfig] = None
):
"""Advanced action using multiple special parameters."""
# Get current message from context
message = context.get("last_user_message", "")
# Count previous interactions from events
interaction_count = len([
e for e in events
if e.get("type") == "UtteranceUserActionFinished"
])
# Check config for thresholds
max_interactions = config.custom_data.get("max_interactions", 100)
if interaction_count > max_interactions:
return False
# Use LLM for complex validation if needed
if needs_llm_check(message):
result = await llm.agenerate([f"Is this safe? {message}"])
return "yes" in result.generations[0][0].text.lower()
return True
Parameter Type Annotations#
Always use proper type annotations for special parameters:
from typing import Optional, List
from langchain_core.language_models import BaseLLM
from nemoguardrails import RailsConfig
from nemoguardrails.actions import action
from nemoguardrails.llm.taskmanager import LLMTaskManager
@action()
async def properly_typed_action(
# Regular parameters
query: str,
limit: int = 10,
# Special parameters with correct types
context: Optional[dict] = None,
events: Optional[List[dict]] = None,
llm: Optional[BaseLLM] = None,
config: Optional[RailsConfig] = None,
llm_task_manager: Optional[LLMTaskManager] = None,
):
"""Action with proper type annotations."""
pass