Intrinsic Functions

This guide will walk you through intrinsic functions and the Command class.

Intrinsic functions should define a specific operation that affect the agent’s memory.

The Command Class

Intrinsic functions should inherit from Command. This class will serve as the blueprint for customs functions.

from agent.commands.core import Command

class CustomThinkCommand(Command):
    """A custom command to perform a specific task."""

Command Metadata

The command requires metadata, including its name and description. These serve an important role when the language model must make decisions about which commands to execute. This leads to the following:

class CustomThinkCommand(Command):
    name: str = "think"
    description: str = "Produce a thought about the observation of the environment"

Specifically, the name and description of a command will be fed into the language model during decision flows. Here is a basic example of how these can be used to prompt the language model.

Your response should be an available command in the format "Command: <command>",
where <command> is the name of the command below.
Here is what happened so far:
  ...

Here is a list of the available commands:
- {name1}: {description1}.
- {name2}: {description2}.

Please pick between {name1} and {name2}.

Obviously, the bracketed terms are replaced with the names and descriptions of the commands as defined in this class.

Input and Output Keys

The expected inputs and the outputs of the command are declared as class attributes using dictionaries.

  • input_keys :

    Memory keys that are expected to be in the memory when the function is executed. The key to the dictionary is the argument name and the value is passed as an argument value. For example, a dictionary such as {"key": "value"} means that func will be called as func(key=value). The keyword arguments are collected from all of input_keys, output_keys, and required_prompt_templates. For this reason, keys have to be unique among input_keys, output_keys and required_prompt_templates.

  • output_keys :

    Memory keys that are going to be created or altered when the function is executed. The key to the dictionary is the argument name and the value is passed as an argument value. See documentation of input_keys for an explanation of how this is used.

class CustomThinkCommand(Command):
    ...

    input_keys: Dict[str, MemKey] = {
        'observation_mem_key': MemKey.OBSERVATION,
    }
    output_keys: Dict[str, MemKey] = {
        'output_mem_key': MemKey.THOUGHT,
    }

Required Prompt Templates

If a command relies on language model prompts, it should define the necessary templates. These are specified in the required_prompt_templates dictionary.

  • required_prompt_templates :

    Prompt templates used by this function. These templates need to exist within the searchable paths. The key to the dictionary is the argument name and the value is passed as an argument value. See documentation of input_keys for an explanation of how this is used.

class CustomThinkCommand(Command):
    ...

    required_prompt_templates: Dict[str, str] = {
        'ask_for_thought_template': 'think.jinja'
    }

The func Method

The func method is overwritten from the parent Command class and defines the operation of the command. This method should accept agent as its first parameter, followed by the required inputs defined in input_keys, output_keys, and required_prompt_templates. Note how the arguments to this function match the keys of the dictionaries provided above (input/output keys).

In this function, feel free to use agent.memory for memory operations and agent.llm for language model interactions, as well as using agent.prompt_builder as shown below.

Note

Right now there are no checks to enforce the use of input/output/templates that were defined above (i.e., you can do whatever you want here). However do NOT do this, as we do have plans of enforcing this in the future. Also, you might find that your functions are going to be easier to reuse or override if you stick to this template.

Here is an example of the func() :

class CustomThinkCommand(Command):
    ...

    def func(
    self,
    agent,
    # see how the arguments below match the keys in `input_keys`, `output_keys`, and `required_prompt_templates`:
    observation_mem_key,
    output_mem_key,
    ask_for_thought_template
    ):

        # Example: Retrieve input from memory
        observation = agent.memory.retrieve({observation_mem_key: 1.0})

        # Example: Generate a prompt using a template
        prompt = agent.prompt_builder(ask_for_thought_template, {'text_obs': observation}) # key will be inserted in jinja template

        # Example: Call the language model and process the response
        response = agent.llm.chat_completion(prompt)

        # Example: Store the result in memory
        agent.memory.store(response, {output_mem_key})

Shortcuts to Delete and Rename Memory Keys (Optional)

Optionally, it is possible to define memory keys that should be renamed or deleted after the command’s execution using renamed_keys and deleted_keys. These are shortcuts and keys can always be deleted or renamed without including them in the output_keys dictionary.

  • renamed_keys :

    Memory keys that will be renamed. The key of this dictionary is the source name and the value is the new name. Renaming happens after the main function is executed, but before deletions.

  • deleted_keys :

    Memory keys that will be deleted. Deletion happens at the end of the function call.

class CustomThinkCommand(Command):
    ...

    renamed_keys: Dict[MemKey, MemKey] = {
        MemKey.OLD_KEY: MemKey.NEW_KEY
    }
    deleted_keys: List[MemKey] = [MemKey.KEY_TO_DELETE]