diff --git a/config/schema/ai_agents.schema.yml b/config/schema/ai_agents.schema.yml
index b21f9293891b5a4f1ee38fd6bee1cfe686aa7f1b..65aac49d286ca641de4b5bf5080d9c3bdfa74deb 100644
--- a/config/schema/ai_agents.schema.yml
+++ b/config/schema/ai_agents.schema.yml
@@ -17,10 +17,49 @@ ai_agents.ai_agent.*:
     id:
       type: string
       label: ID
+      description: 'The ID of the AI agent. This is the machine name of the AI agent. Can only contain lowercase letters, numbers and underscores.'
     label:
       type: label
       label: Label
+      description: 'The label of the AI agent. This is the name that will be displayed in the UI and that any orchestration tool sees.'
     uuid:
       type: string
+      label: UUID
+      description: 'The UUID of the AI agent. Fill this in only if you want to import an existing AI agent.'
     description:
       type: string
+      label: Description
+      description: 'A description of the AI agent. This is really important, because triage agents or orchestration tools will base their decisions to pick the right agent on this.'
+    system_prompt:
+      type: string
+      label: System Prompt
+      description: 'The system prompt that the AI agent will use to handle its tasks. This is the text that the AI agent will use to interact with the user and pick tools. Agents are usually looping, so this is the text that will be repeated.'
+    tools:
+      type: sequence
+      label: Tools
+      description: 'The tools that the AI agent can use. This is a list of tools that the AI agent can use to perform its tasks. The AI agent will pick the right tool based on the system prompt and the user input. It only have to list the tools used. Not disabled tools.'
+      sequence:
+        type: mapping
+        label: Tool
+        mapping:
+          key:
+            type: string
+            label: Key
+            description: 'The key of the tool. This is the machine name of the tool. Can only contain lowercase letters, numbers, colon, dash and underscores.'
+          value:
+            type: boolean
+            label: Value
+            description: 'Whether the tool is enabled or not.'
+    orchestration_agent:
+      type: boolean
+      label: Orchestration Agent
+      description: 'Whether the AI agent is an orchestration agent or not. Orchestration agents are agents that only will pick other agents to do their work. They are the top level agents that can be used by the user.'
+    triage_agent:
+      type: boolean
+      label: Triage Agent
+      description: 'Whether the AI agent is a triage agent or not. Triage agents are agents that can pick other agents to do their work, but that can also do work themselves. They are the middle level agents that can be used by the user.'
+    max_loops:
+      type: integer
+      label: Max Loops
+      description: 'The maximum number of loops that the AI agent can do. This is to prevent infinite loops. If the AI agent reaches this number of loops, it will stop and return the result.'
+      default: 3
diff --git a/src/Entity/AiAgent.php b/src/Entity/AiAgent.php
index 1fa21c665ef86f128bcb524e9380b08815f009a2..7602c9f88e060e093210bab5fbd69f39a39030a5 100644
--- a/src/Entity/AiAgent.php
+++ b/src/Entity/AiAgent.php
@@ -78,7 +78,7 @@ final class AiAgent extends ConfigEntityBase implements AiAgentInterface {
   /**
    * The dynamic context tools.
    */
-  protected string $default_information_tools;
+  protected ?string $default_information_tools = NULL;
 
   /**
    * The system prompt.
@@ -93,7 +93,7 @@ final class AiAgent extends ConfigEntityBase implements AiAgentInterface {
   /**
    * The tool usage limits.
    */
-  protected array $tool_usage_limits;
+  protected ?array $tool_usage_limits = NULL;
 
   /**
    * Is this an orchestration agent.
diff --git a/src/Form/AiAgentForm.php b/src/Form/AiAgentForm.php
index 2e6b8f0fe135a107f076c4a9b43be887ec3ba32a..4d25478e62983a3c4d425fa890c4c03e11cfee30 100644
--- a/src/Form/AiAgentForm.php
+++ b/src/Form/AiAgentForm.php
@@ -295,9 +295,14 @@ final class AiAgentForm extends EntityForm {
         '#tree' => TRUE,
       ];
       foreach (array_keys($selected_tools) as $tool_id) {
-        $tool = $function_call_plugin_manager->createInstance($tool_id);
-        $definition = $function_call_plugin_manager->getDefinition($tool_id);
-        $this->createToolUsageForm($tool, $definition, $form, $form_state);
+        try {
+          $tool = $function_call_plugin_manager->createInstance($tool_id);
+          $definition = $function_call_plugin_manager->getDefinition($tool_id);
+          $this->createToolUsageForm($tool, $definition, $form, $form_state);
+        }
+        catch (\Exception $e) {
+          // Do nothing.
+        }
       }
     }
 
diff --git a/src/Plugin/AiFunctionCall/AddAiAssistantAgentAction.php b/src/Plugin/AiFunctionCall/AddAiAssistantAgentAction.php
new file mode 100644
index 0000000000000000000000000000000000000000..b22b8b1fb9ab9b2cdf0b65c4d30238c3aef2292a
--- /dev/null
+++ b/src/Plugin/AiFunctionCall/AddAiAssistantAgentAction.php
@@ -0,0 +1,131 @@
+<?php
+
+namespace Drupal\ai_agents\Plugin\AiFunctionCall;
+
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\Core\Session\AccountProxyInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\ai\Attribute\FunctionCall;
+use Drupal\ai\Base\FunctionCallBase;
+use Drupal\ai\Service\FunctionCalling\ExecutableFunctionCallInterface;
+use Drupal\ai\Service\FunctionCalling\FunctionCallInterface;
+use Drupal\ai\Utility\ContextDefinitionNormalizer;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Plugin implementation to add an ai assistant agent action.
+ */
+#[FunctionCall(
+  id: 'ai_agent:add_ai_assistant_agent_action',
+  function_name: 'ai_agent_add_ai_assistant_agent_action',
+  name: 'Add AI Assistant Action',
+  description: 'This tool can add an AI assistant agent action.',
+  group: 'modification_tools',
+  context_definitions: [
+    'id' => new ContextDefinition(
+      data_type: 'string',
+      label: new TranslatableMarkup("Assistant ID"),
+      description: new TranslatableMarkup("The required AI Assistant ID."),
+      required: TRUE,
+      constraints: ['Regex' => '/^[a-zA-Z0-9_]+$/'],
+    ),
+    'action' => new ContextDefinition(
+      data_type: 'string',
+      label: new TranslatableMarkup("Action"),
+      description: new TranslatableMarkup("The action that should be added to the assistant."),
+      required: TRUE,
+    ),
+  ],
+)]
+class AddAiAssistantAgentAction extends FunctionCallBase implements ExecutableFunctionCallInterface {
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected EntityTypeManagerInterface $entityTypeManager;
+
+  /**
+   * The current user.
+   *
+   * @var \Drupal\Core\Session\AccountProxyInterface
+   */
+  protected AccountProxyInterface $currentUser;
+
+  /**
+   * Load from dependency injection container.
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): FunctionCallInterface|static {
+    $instance = new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      new ContextDefinitionNormalizer(),
+    );
+    $instance->entityTypeManager = $container->get('entity_type.manager');
+    $instance->currentUser = $container->get('current_user');
+    return $instance;
+  }
+
+  /**
+   * The information if something was saved or not.
+   *
+   * @var string
+   */
+  protected string $information = "";
+
+  /**
+   * {@inheritdoc}
+   */
+  public function execute() {
+    // Collect the context values.
+    $id = $this->getContextValue('id');
+    $action = $this->getContextValue('action');
+
+    // Make sure that the user has the right permissions.
+    if (!$this->currentUser->hasPermission('administer ai assistant')) {
+      throw new \Exception('The current user does not have the right permissions to administer the assistants.');
+    }
+
+    $storage = $this->entityTypeManager->getStorage('ai_assistant');
+
+    $entity = NULL;
+    try {
+      /** @var \Drupal\ai_agents\Entity\AiAssistant $entity */
+      $entity = $storage->load($id);
+    }
+    catch (\Exception $e) {
+      $this->information = $this->t('The assistant (%id) could not be loaded.', [
+        '%id' => $id,
+      ]);
+      return;
+    }
+    // Add the assistant action.
+    $actions = $entity->get('actions_enabled');
+    $actions['agent_action']['agent_ids'][$action] = $action;
+    $entity->set('actions_enabled', $actions);
+    try {
+      $entity->save();
+      $this->information = $this->t('The action (%action) was added to the assistant (%id).', [
+        '%action' => $action,
+        '%id' => $id,
+      ]);
+    }
+    catch (\Exception $e) {
+      $this->information = $this->t('The action (%action) could not be added to the assistant (%id).', [
+        '%action' => $action,
+        '%id' => $id,
+      ]);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getReadableOutput(): string {
+    return $this->information;
+  }
+
+}
diff --git a/src/Plugin/AiFunctionCall/Children/CreateAgentConfigToolsEnabled.php b/src/Plugin/AiFunctionCall/Children/CreateAgentConfigToolsEnabled.php
new file mode 100644
index 0000000000000000000000000000000000000000..1e9188dafd215d685b91f6b169ae755223afa4a5
--- /dev/null
+++ b/src/Plugin/AiFunctionCall/Children/CreateAgentConfigToolsEnabled.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace Drupal\ai_agents\Plugin\AiFunctionCall\Children;
+
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\ai\Attribute\FunctionCall;
+use Drupal\ai\Base\FunctionCallBase;
+
+/**
+ * Wrapper of the array of values for the tools.
+ */
+#[FunctionCall(
+  id: 'ai_agent:create_agent_config_tools_enabled',
+  function_name: 'ai_agents_create_agent_config_tools_enabled',
+  name: 'Tools',
+  description: 'The list of enabled tools.',
+  context_definitions: [
+    'key' => new ContextDefinition(
+      data_type: 'string',
+      label: new TranslatableMarkup("Tools Id"),
+      description: new TranslatableMarkup("The id of the tool."),
+      required: TRUE
+    ),
+    'value' => new ContextDefinition(
+      data_type: 'boolean',
+      label: new TranslatableMarkup("Enabled"),
+      description: new TranslatableMarkup("If the tool is enabled."),
+      required: TRUE
+    ),
+  ],
+)]
+class CreateAgentConfigToolsEnabled extends FunctionCallBase {
+
+}
diff --git a/src/Plugin/AiFunctionCall/CreateAgentConfig.php b/src/Plugin/AiFunctionCall/CreateAgentConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..299febd252ed6364414d5ff7b074929e9e13d93f
--- /dev/null
+++ b/src/Plugin/AiFunctionCall/CreateAgentConfig.php
@@ -0,0 +1,180 @@
+<?php
+
+namespace Drupal\ai_agents\Plugin\AiFunctionCall;
+
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\Core\Session\AccountProxyInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\ai\Attribute\FunctionCall;
+use Drupal\ai\Base\FunctionCallBase;
+use Drupal\ai\Service\FunctionCalling\ExecutableFunctionCallInterface;
+use Drupal\ai\Service\FunctionCalling\FunctionCallInterface;
+use Drupal\ai\Utility\ContextDefinitionNormalizer;
+use Drupal\ai_agents\Plugin\AiFunctionCall\Children\CreateAgentConfigToolsEnabled;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Plugin implementation of the create agents function.
+ */
+#[FunctionCall(
+  id: 'ai_agent:create_agent_config',
+  function_name: 'ai_agent_create_agent_config',
+  name: 'Create Agent Config',
+  description: 'This tool can save an agent config.',
+  group: 'modification_tools',
+  context_definitions: [
+    'id' => new ContextDefinition(
+      data_type: 'string',
+      label: new TranslatableMarkup("ID"),
+      description: new TranslatableMarkup("The required agent config ID."),
+      required: TRUE,
+      constraints: ['Regex' => '/^[a-zA-Z0-9_]+$/'],
+    ),
+    'label' => new ContextDefinition(
+      data_type: 'string',
+      label: new TranslatableMarkup("Label"),
+      description: new TranslatableMarkup("The required agent config label."),
+      required: TRUE,
+    ),
+    'description' => new ContextDefinition(
+      data_type: 'string',
+      label: new TranslatableMarkup("Description"),
+      description: new TranslatableMarkup("The required agent config description."),
+      required: TRUE,
+    ),
+    'system_prompt' => new ContextDefinition(
+      data_type: 'string',
+      label: new TranslatableMarkup("System Prompt"),
+      description: new TranslatableMarkup("The required agent config system prompt."),
+      required: TRUE,
+    ),
+    'tools' => new ContextDefinition(
+      data_type: 'map',
+      label: new TranslatableMarkup("Entity Array"),
+      description: new TranslatableMarkup("The entity array to seed the entity with."),
+      required: TRUE,
+      multiple: TRUE,
+      constraints: [
+        'ComplexToolItems' => CreateAgentConfigToolsEnabled::class,
+      ],
+    ),
+    'orchestration_agent' => new ContextDefinition(
+      data_type: 'boolean',
+      label: new TranslatableMarkup("Orchestration Agent"),
+      description: new TranslatableMarkup("If this is an orchestration agent."),
+      required: TRUE,
+    ),
+    'triage_agent' => new ContextDefinition(
+      data_type: 'boolean',
+      label: new TranslatableMarkup("Triage Agent"),
+      description: new TranslatableMarkup("If this is a triage agent."),
+      required: TRUE,
+    ),
+    'max_loops' => new ContextDefinition(
+      data_type: 'integer',
+      label: new TranslatableMarkup("Max Loops"),
+      description: new TranslatableMarkup("The maximum number of loops."),
+      required: TRUE,
+      default_value: 3,
+    ),
+  ],
+)]
+class CreateAgentConfig extends FunctionCallBase implements ExecutableFunctionCallInterface {
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected EntityTypeManagerInterface $entityTypeManager;
+
+  /**
+   * The current user.
+   *
+   * @var \Drupal\Core\Session\AccountProxyInterface
+   */
+  protected AccountProxyInterface $currentUser;
+
+  /**
+   * Load from dependency injection container.
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): FunctionCallInterface|static {
+    $instance = new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      new ContextDefinitionNormalizer(),
+    );
+    $instance->entityTypeManager = $container->get('entity_type.manager');
+    $instance->currentUser = $container->get('current_user');
+    return $instance;
+  }
+
+  /**
+   * The information if something was saved or not.
+   *
+   * @var string
+   */
+  protected string $information = "";
+
+  /**
+   * {@inheritdoc}
+   */
+  public function execute() {
+    // Collect the context values.
+    $id = $this->getContextValue('id');
+    $label = $this->getContextValue('label');
+    $description = $this->getContextValue('description');
+    $system_prompt = $this->getContextValue('system_prompt');
+    $tools = $this->getContextValue('tools');
+    $orchestration_agent = $this->getContextValue('orchestration_agent');
+    $triage_agent = $this->getContextValue('triage_agent');
+    $max_loops = $this->getContextValue('max_loops');
+
+    // Make sure that the user has the right permissions.
+    if (!$this->currentUser->hasPermission('administer ai agent')) {
+      throw new \Exception('The current user does not have the right permissions to create agents.');
+    }
+
+    $storage = $this->entityTypeManager->getStorage('ai_agent');
+
+    $listed_tools = [];
+    foreach ($tools as $tool) {
+      $listed_tools[$tool['key']] = $tool['value'];
+    }
+    try {
+      $entity = $storage->create([
+        'id' => $id,
+        'label' => $label,
+        'description' => $description,
+        'system_prompt' => $system_prompt,
+        'tools' => $listed_tools,
+        'orchestration_agent' => $orchestration_agent,
+        'triage_agent' => $triage_agent,
+        'max_loops' => $max_loops,
+        'default_information_tools' => '',
+        'tool_usage_limits' => [],
+      ]);
+      $entity->save();
+      $this->information = $this->t('The agent config %label (%id) has been saved.', [
+        '%label' => $label,
+        '%id' => $id,
+      ]);
+    }
+    catch (\Exception $e) {
+      $this->information = $this->t('The agent config %label (%id) could not be saved.', [
+        '%label' => $label,
+        '%id' => $id,
+      ]);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getReadableOutput(): string {
+    return $this->information;
+  }
+
+}
diff --git a/src/Plugin/AiFunctionCall/GetConfigSchema.php b/src/Plugin/AiFunctionCall/GetConfigSchema.php
new file mode 100644
index 0000000000000000000000000000000000000000..6d54d2d2632b252296d0f31c0b11abffb23442a1
--- /dev/null
+++ b/src/Plugin/AiFunctionCall/GetConfigSchema.php
@@ -0,0 +1,81 @@
+<?php
+
+namespace Drupal\ai_agents\Plugin\AiFunctionCall;
+
+use Drupal\Core\Config\TypedConfigManagerInterface;
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\ai\Attribute\FunctionCall;
+use Drupal\ai\Base\FunctionCallBase;
+use Drupal\ai\Service\FunctionCalling\ExecutableFunctionCallInterface;
+use Drupal\ai\Service\FunctionCalling\FunctionCallInterface;
+use Drupal\ai\Utility\ContextDefinitionNormalizer;
+use Drupal\ai_agents\PluginInterfaces\AiAgentContextInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Yaml\Yaml;
+
+/**
+ * Plugin implementation of the describe config function.
+ */
+#[FunctionCall(
+  id: 'ai_agent:get_config_schema',
+  function_name: 'ai_agent_get_config_schema',
+  name: 'Get Config Schema',
+  description: 'This gets the Drupal configuration schema for a single schema.',
+  group: 'information_tools',
+  context_definitions: [
+    'schema_id' => new ContextDefinition(
+      data_type: 'string',
+      label: 'Entity Type',
+      description: 'The entity type to get the configuration schema for.',
+      required: TRUE,
+    ),
+  ],
+)]
+class GetConfigSchema extends FunctionCallBase implements ExecutableFunctionCallInterface, AiAgentContextInterface {
+
+  /**
+   * The config typed data manager.
+   *
+   * @var \Drupal\Core\Config\TypedConfigManagerInterface
+   */
+  protected TypedConfigManagerInterface $typedConfigManager;
+
+  /**
+   * Load from dependency injection container.
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): FunctionCallInterface|static {
+    $instance = new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      new ContextDefinitionNormalizer(),
+    );
+    $instance->typedConfigManager = $container->get('config.typed');
+    return $instance;
+  }
+
+  /**
+   * The schema.
+   *
+   * @var array
+   */
+  protected array $schema = [];
+
+  /**
+   * {@inheritdoc}
+   */
+  public function execute() {
+    // Collect the context values.
+    $schema_id = $this->getContextValue('schema_id');
+    // @todo Permissions?
+    $this->schema = $this->typedConfigManager->getDefinition($schema_id);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getReadableOutput(): string {
+    return Yaml::dump($this->schema, 10, 2);
+  }
+
+}
diff --git a/src/Plugin/AiFunctionCall/GetToolExecuteCode.php b/src/Plugin/AiFunctionCall/GetToolExecuteCode.php
new file mode 100644
index 0000000000000000000000000000000000000000..160a070d2b7cb938306351890b42bafe1d34222c
--- /dev/null
+++ b/src/Plugin/AiFunctionCall/GetToolExecuteCode.php
@@ -0,0 +1,104 @@
+<?php
+
+namespace Drupal\ai_agents\Plugin\AiFunctionCall;
+
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\Core\Session\AccountProxyInterface;
+use Drupal\ai\Attribute\FunctionCall;
+use Drupal\ai\Base\FunctionCallBase;
+use Drupal\ai\Service\FunctionCalling\ExecutableFunctionCallInterface;
+use Drupal\ai\Service\FunctionCalling\FunctionCallInterface;
+use Drupal\ai\Service\FunctionCalling\FunctionCallPluginManager;
+use Drupal\ai\Utility\ContextDefinitionNormalizer;
+use Drupal\ai_agents\PluginInterfaces\AiAgentContextInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Plugin implementation of the describe tool code.
+ */
+#[FunctionCall(
+  id: 'ai_agent:get_tool_execute_code',
+  function_name: 'ai_agent_get_tool_execute_code',
+  name: 'Get Tool Execute Code',
+  description: 'This tool can get the execute code of a tool.',
+  group: 'information_tools',
+  context_definitions: [
+    'tool_id' => new ContextDefinition(
+      data_type: 'string',
+      label: 'Tool ID',
+      description: 'The required tool ID to read the execute code.',
+      required: TRUE,
+    ),
+  ],
+)]
+class GetToolExecuteCode extends FunctionCallBase implements ExecutableFunctionCallInterface, AiAgentContextInterface {
+
+  /**
+   * The Function Call Plugin Manager.
+   *
+   * @var \Drupal\ai\Service\FunctionCalling\FunctionCallPluginManager
+   */
+  protected FunctionCallPluginManager $functionCallPluginManager;
+
+  /**
+   * The current user.
+   *
+   * @var \Drupal\Core\Session\AccountProxyInterface
+   */
+  protected AccountProxyInterface $currentUser;
+
+  /**
+   * Load from dependency injection container.
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): FunctionCallInterface|static {
+    $instance = new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      new ContextDefinitionNormalizer(),
+    );
+    $instance->functionCallPluginManager = $container->get('plugin.manager.ai.function_calls');
+    $instance->currentUser = $container->get('current_user');
+    return $instance;
+  }
+
+  /**
+   * The code.
+   *
+   * @var string
+   */
+  protected string $code = '';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function execute() {
+    // Collect the context values.
+    $tool_id = $this->getContextValue('tool_id');
+    // Just set the highest permission possible here.
+    if (!$this->currentUser->hasPermission('administer permissions')) {
+      $this->code = 'You do not have the right permissions to view this code.';
+      return;
+    }
+    $tool = $this->functionCallPluginManager->getDefinition($tool_id);
+    $class = $tool['class'];
+    // Create reflection class.
+    $reflector = new \ReflectionMethod($class, 'execute');
+    // Output the execute code.
+    $file = new \SplFileObject($reflector->getFileName());
+    $file->seek($reflector->getStartLine() - 1);
+
+    while ($file->key() < $reflector->getEndLine()) {
+      $this->code .= $file->current();
+      $file->next();
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getReadableOutput(): string {
+    return $this->code;
+  }
+
+}
diff --git a/src/Plugin/AiFunctionCall/ListAiTools.php b/src/Plugin/AiFunctionCall/ListAiTools.php
new file mode 100644
index 0000000000000000000000000000000000000000..b76a584495a09ee438f4208903810d150ba8a796
--- /dev/null
+++ b/src/Plugin/AiFunctionCall/ListAiTools.php
@@ -0,0 +1,102 @@
+<?php
+
+namespace Drupal\ai_agents\Plugin\AiFunctionCall;
+
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\ai\Attribute\FunctionCall;
+use Drupal\ai\Base\FunctionCallBase;
+use Drupal\ai\Service\FunctionCalling\ExecutableFunctionCallInterface;
+use Drupal\ai\Service\FunctionCalling\FunctionCallInterface;
+use Drupal\ai\Service\FunctionCalling\FunctionCallPluginManager;
+use Drupal\ai\Utility\ContextDefinitionNormalizer;
+use Drupal\ai_agents\PluginInterfaces\AiAgentContextInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Yaml\Yaml;
+
+/**
+ * Plugin implementation of the list tools function.
+ */
+#[FunctionCall(
+  id: 'ai_agent:list_ai_tools',
+  function_name: 'ai_agent_list_ai_tools',
+  name: 'List Tools',
+  description: 'This method can list all the tools for function calling.',
+  group: 'information_tools',
+  context_definitions: [
+    'function_group' => new ContextDefinition(
+      data_type: 'string',
+      label: new TranslatableMarkup("Function Group"),
+      description: new TranslatableMarkup("Options filter for a specific function group."),
+      required: FALSE,
+    ),
+  ],
+)]
+class ListAiTools extends FunctionCallBase implements ExecutableFunctionCallInterface, AiAgentContextInterface {
+
+  /**
+   * The Function Call Plugin Manager.
+   *
+   * @var \Drupal\ai\Service\FunctionCalling\FunctionCallPluginManager
+   */
+  protected FunctionCallPluginManager $functionCallPluginManager;
+
+  /**
+   * Load from dependency injection container.
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): FunctionCallInterface|static {
+    $instance = new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      new ContextDefinitionNormalizer(),
+    );
+    $instance->functionCallPluginManager = $container->get('plugin.manager.ai.function_calls');
+    return $instance;
+  }
+
+  /**
+   * The list.
+   *
+   * @var array
+   */
+  protected array $list = [];
+
+  /**
+   * {@inheritdoc}
+   */
+  public function execute() {
+    // Collect the context values.
+    $function_group = $this->getContextValue('function_group');
+    $this->list = [];
+    foreach ($this->functionCallPluginManager->getDefinitions() as $definition) {
+      if ($function_group && $definition['group'] !== $function_group) {
+        continue;
+      }
+      $this->list[$definition['id']] = [
+        'id' => $definition['id'],
+        'name' => $definition['name'],
+        'description' => $definition['description'],
+        'group' => $definition['group'],
+        'module_dependencies' => $definition['module_dependencies'] ?? [],
+      ];
+
+      foreach ($definition['context_definitions'] as $context_name => $context_definition) {
+        $this->list[$definition['id']]['context_definitions'][$context_name] = [
+          'data_type' => $context_definition->getDataType(),
+          'label' => (string) $context_definition->getLabel(),
+          'description' => (string) $context_definition->getDescription(),
+          'required' => $context_definition->isRequired(),
+        ];
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getReadableOutput(): string {
+    return Yaml::dump($this->list, 10, 2);
+  }
+
+}