Skip to content

Prompts

BasePromptComponent

Bases: BaseComponent

Base class for prompt components.

Parameters:

Name Type Description Default
template PromptTemplate

The prompt template.

required
**kwargs

Any additional keyword arguments that will be used to populate the given template.

{}
Source code in libs/kotaemon/kotaemon/llms/prompts/base.py
class BasePromptComponent(BaseComponent):
    """
    Base class for prompt components.

    Args:
        template (PromptTemplate): The prompt template.
        **kwargs: Any additional keyword arguments that will be used to populate the
            given template.
    """

    class Config:
        middleware_switches = {"theflow.middleware.CachingMiddleware": False}
        allow_extra = True

    template: str | PromptTemplate

    @Param.auto(depends_on="template")
    def template__(self):
        return (
            self.template
            if isinstance(self.template, PromptTemplate)
            else PromptTemplate(self.template)
        )

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.__set(**kwargs)

    def __check_redundant_kwargs(self, **kwargs):
        """
        Check for redundant keyword arguments.

        Parameters:
            **kwargs (dict): A dictionary of keyword arguments.

        Raises:
            ValueError: If any keys provided are not in the template.

        Returns:
            None
        """
        self.template__.check_redundant_kwargs(**kwargs)

    def __check_unset_placeholders(self):
        """
        Check if all the placeholders in the template are set.

        This function checks if all the expected placeholders in the template are set as
            attributes of the object. If any placeholders are missing, a `ValueError`
            is raised with the names of the missing keys.

        Parameters:
            None

        Returns:
            None
        """
        self.template__.check_missing_kwargs(**self.__dict__)

    def __validate_value_type(self, **kwargs):
        """
        Validates the value types of the given keyword arguments.

        Parameters:
            **kwargs (dict): A dictionary of keyword arguments to be validated.

        Raises:
            ValueError: If any of the values in the kwargs dictionary have an
                unsupported type.

        Returns:
            None
        """
        type_error = []
        for k, v in kwargs.items():
            if k.startswith("template"):
                continue
            if not isinstance(v, (str, int, Document, Callable)):  # type: ignore
                type_error.append((k, type(v)))

        if type_error:
            raise ValueError(
                "Type of values must be either int, str, Document, Callable, "
                f"found unsupported type for (key, type): {type_error}"
            )

    def __set(self, **kwargs):
        """
        Set the values of the attributes in the object based on the provided keyword
            arguments.

        Args:
            kwargs (dict): A dictionary with the attribute names as keys and the new
                values as values.

        Returns:
            None
        """
        self.__check_redundant_kwargs(**kwargs)
        self.__validate_value_type(**kwargs)

        self.__dict__.update(kwargs)

    def __prepare_value(self):
        """
        Generate a dictionary of keyword arguments based on the template's placeholders
            and the current instance's attributes.

        Returns:
            dict: A dictionary of keyword arguments.
        """

        def __prepare(key, value):
            if isinstance(value, str):
                return value
            if isinstance(value, (int, Document)):
                return str(value)

            raise ValueError(
                f"Unsupported type {type(value)} for template value of key {key}"
            )

        kwargs = {}
        for k in self.template__.placeholders:
            v = getattr(self, k)

            # if get a callable, execute to get its output
            if isinstance(v, Callable):  # type: ignore[arg-type]
                v = v()

            if isinstance(v, list):
                v = str([__prepare(k, each) for each in v])
            elif isinstance(v, (str, int, Document)):
                v = __prepare(k, v)
            else:
                raise ValueError(
                    f"Unsupported type {type(v)} for template value of key `{k}`"
                )
            kwargs[k] = v

        return kwargs

    def set_value(self, **kwargs):
        """
        Similar to `__set` but for external use.

        Set the values of the attributes in the object based on the provided keyword
            arguments.

        Args:
            kwargs (dict): A dictionary with the attribute names as keys and the new
                values as values.

        Returns:
            None
        """
        self.__set(**kwargs)

    def run(self, **kwargs):
        """
        Run the function with the given keyword arguments.

        Args:
            **kwargs: The keyword arguments to pass to the function.

        Returns:
            The result of calling the `populate` method of the `template` object
            with the given keyword arguments.
        """
        self.__set(**kwargs)
        self.__check_unset_placeholders()
        prepared_kwargs = self.__prepare_value()

        text = self.template__.populate(**prepared_kwargs)
        return Document(text=text, metadata={"origin": "PromptComponent"})

    def flow(self):
        return self.__call__()

set_value

set_value(**kwargs)

Similar to __set but for external use.

Set the values of the attributes in the object based on the provided keyword arguments.

Parameters:

Name Type Description Default
kwargs dict

A dictionary with the attribute names as keys and the new values as values.

{}

Returns:

Type Description

None

Source code in libs/kotaemon/kotaemon/llms/prompts/base.py
def set_value(self, **kwargs):
    """
    Similar to `__set` but for external use.

    Set the values of the attributes in the object based on the provided keyword
        arguments.

    Args:
        kwargs (dict): A dictionary with the attribute names as keys and the new
            values as values.

    Returns:
        None
    """
    self.__set(**kwargs)

run

run(**kwargs)

Run the function with the given keyword arguments.

Parameters:

Name Type Description Default
**kwargs

The keyword arguments to pass to the function.

{}

Returns:

Type Description

The result of calling the populate method of the template object

with the given keyword arguments.

Source code in libs/kotaemon/kotaemon/llms/prompts/base.py
def run(self, **kwargs):
    """
    Run the function with the given keyword arguments.

    Args:
        **kwargs: The keyword arguments to pass to the function.

    Returns:
        The result of calling the `populate` method of the `template` object
        with the given keyword arguments.
    """
    self.__set(**kwargs)
    self.__check_unset_placeholders()
    prepared_kwargs = self.__prepare_value()

    text = self.template__.populate(**prepared_kwargs)
    return Document(text=text, metadata={"origin": "PromptComponent"})

PromptTemplate

Base class for prompt templates.

Source code in libs/kotaemon/kotaemon/llms/prompts/template.py
class PromptTemplate:
    """
    Base class for prompt templates.
    """

    def __init__(self, template: str, ignore_invalid=True):
        template = template
        formatter = Formatter()
        parsed_template = list(formatter.parse(template))

        placeholders = set()
        for _, key, _, _ in parsed_template:
            if key is None:
                continue
            if not key.isidentifier():
                if ignore_invalid:
                    warnings.warn(f"Ignore invalid placeholder: {key}.", UserWarning)
                else:
                    raise ValueError(
                        "Placeholder name must be a valid Python identifier, found:"
                        f" {key}."
                    )
            placeholders.add(key)

        self.template = template
        self.placeholders = placeholders
        self.__formatter = formatter
        self.__parsed_template = parsed_template

    def check_missing_kwargs(self, **kwargs):
        """
        Check if all the placeholders in the template are set.

        This function checks if all the expected placeholders in the template are set as
            attributes of the object. If any placeholders are missing, a `ValueError`
            is raised with the names of the missing keys.

        Parameters:
            None

        Returns:
            None
        """
        missing_keys = self.placeholders.difference(kwargs.keys())
        if missing_keys:
            raise ValueError(f"Missing keys in template: {','.join(missing_keys)}")

    def check_redundant_kwargs(self, **kwargs):
        """
        Check if all the placeholders in the template are set.

        This function checks if all the expected placeholders in the template are set as
            attributes of the object. If any placeholders are missing, a `ValueError`
            is raised with the names of the missing keys.

        Parameters:
            None

        Returns:
            None
        """
        provided_keys = set(kwargs.keys())
        redundant_keys = provided_keys - self.placeholders

        if redundant_keys:
            warnings.warn(
                f"Keys provided but not in template: {','.join(redundant_keys)}",
                UserWarning,
            )

    def populate(self, **kwargs) -> str:
        """
        Strictly populate the template with the given keyword arguments.

        Args:
            **kwargs: The keyword arguments to populate the template.
                      Each keyword corresponds to a placeholder in the template.

        Returns:
            The populated template.

        Raises:
            ValueError: If an unknown placeholder is provided.
        """
        self.check_missing_kwargs(**kwargs)

        return self.partial_populate(**kwargs)

    def partial_populate(self, **kwargs):
        """
        Partially populate the template with the given keyword arguments.

        Args:
            **kwargs: The keyword arguments to populate the template.
                      Each keyword corresponds to a placeholder in the template.

        Returns:
            str: The populated template.
        """
        self.check_redundant_kwargs(**kwargs)

        prompt = []
        for literal_text, field_name, format_spec, conversion in self.__parsed_template:
            prompt.append(literal_text)

            if field_name is None:
                continue

            if field_name not in kwargs:
                if conversion:
                    value = f"{{{field_name}}}!{conversion}:{format_spec}"
                else:
                    value = f"{{{field_name}:{format_spec}}}"
            else:
                value = kwargs[field_name]
                if conversion is not None:
                    value = self.__formatter.convert_field(value, conversion)
                if format_spec is not None:
                    value = self.__formatter.format_field(value, format_spec)

            prompt.append(value)

        return "".join(prompt)

    def __add__(self, other):
        """
        Create a new PromptTemplate object by concatenating the template of the current
            object with the template of another PromptTemplate object.

        Parameters:
            other (PromptTemplate): Another PromptTemplate object.

        Returns:
            PromptTemplate: A new PromptTemplate object with the concatenated templates.
        """
        return PromptTemplate(self.template + "\n" + other.template)

check_missing_kwargs

check_missing_kwargs(**kwargs)

Check if all the placeholders in the template are set.

This function checks if all the expected placeholders in the template are set as attributes of the object. If any placeholders are missing, a ValueError is raised with the names of the missing keys.

Returns:

Type Description

None

Source code in libs/kotaemon/kotaemon/llms/prompts/template.py
def check_missing_kwargs(self, **kwargs):
    """
    Check if all the placeholders in the template are set.

    This function checks if all the expected placeholders in the template are set as
        attributes of the object. If any placeholders are missing, a `ValueError`
        is raised with the names of the missing keys.

    Parameters:
        None

    Returns:
        None
    """
    missing_keys = self.placeholders.difference(kwargs.keys())
    if missing_keys:
        raise ValueError(f"Missing keys in template: {','.join(missing_keys)}")

check_redundant_kwargs

check_redundant_kwargs(**kwargs)

Check if all the placeholders in the template are set.

This function checks if all the expected placeholders in the template are set as attributes of the object. If any placeholders are missing, a ValueError is raised with the names of the missing keys.

Returns:

Type Description

None

Source code in libs/kotaemon/kotaemon/llms/prompts/template.py
def check_redundant_kwargs(self, **kwargs):
    """
    Check if all the placeholders in the template are set.

    This function checks if all the expected placeholders in the template are set as
        attributes of the object. If any placeholders are missing, a `ValueError`
        is raised with the names of the missing keys.

    Parameters:
        None

    Returns:
        None
    """
    provided_keys = set(kwargs.keys())
    redundant_keys = provided_keys - self.placeholders

    if redundant_keys:
        warnings.warn(
            f"Keys provided but not in template: {','.join(redundant_keys)}",
            UserWarning,
        )

populate

populate(**kwargs)

Strictly populate the template with the given keyword arguments.

Parameters:

Name Type Description Default
**kwargs

The keyword arguments to populate the template. Each keyword corresponds to a placeholder in the template.

{}

Returns:

Type Description
str

The populated template.

Raises:

Type Description
ValueError

If an unknown placeholder is provided.

Source code in libs/kotaemon/kotaemon/llms/prompts/template.py
def populate(self, **kwargs) -> str:
    """
    Strictly populate the template with the given keyword arguments.

    Args:
        **kwargs: The keyword arguments to populate the template.
                  Each keyword corresponds to a placeholder in the template.

    Returns:
        The populated template.

    Raises:
        ValueError: If an unknown placeholder is provided.
    """
    self.check_missing_kwargs(**kwargs)

    return self.partial_populate(**kwargs)

partial_populate

partial_populate(**kwargs)

Partially populate the template with the given keyword arguments.

Parameters:

Name Type Description Default
**kwargs

The keyword arguments to populate the template. Each keyword corresponds to a placeholder in the template.

{}

Returns:

Name Type Description
str

The populated template.

Source code in libs/kotaemon/kotaemon/llms/prompts/template.py
def partial_populate(self, **kwargs):
    """
    Partially populate the template with the given keyword arguments.

    Args:
        **kwargs: The keyword arguments to populate the template.
                  Each keyword corresponds to a placeholder in the template.

    Returns:
        str: The populated template.
    """
    self.check_redundant_kwargs(**kwargs)

    prompt = []
    for literal_text, field_name, format_spec, conversion in self.__parsed_template:
        prompt.append(literal_text)

        if field_name is None:
            continue

        if field_name not in kwargs:
            if conversion:
                value = f"{{{field_name}}}!{conversion}:{format_spec}"
            else:
                value = f"{{{field_name}:{format_spec}}}"
        else:
            value = kwargs[field_name]
            if conversion is not None:
                value = self.__formatter.convert_field(value, conversion)
            if format_spec is not None:
                value = self.__formatter.format_field(value, format_spec)

        prompt.append(value)

    return "".join(prompt)