Source code for nemoguardrails.actions.actions
# SPDX-FileCopyrightText: Copyright (c) 2023-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from dataclasses import dataclass, field
from typing import (
Any,
Callable,
List,
Optional,
Type,
TypedDict,
TypeVar,
Union,
cast,
)
class ActionMeta(TypedDict):
name: str
is_system_action: bool
execute_async: bool
output_mapping: Optional[Callable[[Any], bool]]
# Create a TypeVar to represent the decorated function or class
T = TypeVar("T", bound=Union[Callable[..., Any], Type[Any]])
[docs]
def action(
is_system_action: bool = False,
name: Optional[str] = None,
execute_async: bool = False,
output_mapping: Optional[Callable[[Any], bool]] = None,
) -> Callable[[T], T]:
"""Decorator to mark a function or class as an action.
Args:
is_system_action (bool): Flag indicating if the action is a system action.
name (str): The name to associate with the action.
execute_async: Whether the function should be executed in async mode.
output_mapping (Optional[Callable[[Any], bool]]): A function to interpret the action's result.
It accepts the return value (e.g. the first element of a tuple) and return True if the output
is not safe.
Returns:
callable: The decorated function or class.
"""
def decorator(fn_or_cls: Union[Callable, Type]) -> Union[Callable, Type]:
"""Inner decorator function to add metadata to the action.
Args:
fn_or_cls: The function or class being decorated.
"""
fn_or_cls_target = getattr(fn_or_cls, "__func__", fn_or_cls)
# Action name is optional for the decorator, but mandatory for ActionMeta TypedDict
action_name: str = cast(str, name or fn_or_cls.__name__)
action_meta: ActionMeta = {
"name": action_name,
"is_system_action": is_system_action,
"execute_async": execute_async,
"output_mapping": output_mapping,
}
setattr(fn_or_cls_target, "action_meta", action_meta)
return fn_or_cls
return decorator # pyright: ignore (TODO - resolve how the Actionable Protocol doesn't resolve the issue)
@dataclass
class ActionResult:
"""Data class representing the result of an action.
Attributes:
return_value (Optional[Any]): The value returned by the action.
events (Optional[List[dict]]): The events to be added to the stream.
context_updates (Optional[dict]): Updates made to the context by this action.
"""
# The value returned by the action
return_value: Optional[Any] = None
# The events that should be added to the stream
events: Optional[List[dict]] = None
# The updates made to the context by this action
context_updates: Optional[dict] = field(default_factory=dict)