I think we should make it explicit and not allow for it to default to 'process'. I'll update this and merge it in. This is obvious BC breaking, but I think it's worth it while we still can change it.
Ok, so I'm relying on the normalizer being able to turn typed data/definitions into json schema, which it looks like is not being back ported to D10, and is only available from 11.2 on. That is my mistake. The AI module does provide a custom normalizer that could be leveraged, but I didn't want to add a dependency from Tool API to the AI module if the intention is to be used elsewhere. Which leaves us writing our own normalizer and then revisiting using the one from core later...
We also need to make a pass on permissions throughout. Two areas in particular:
- Confirm
checkAccess()logic in each tool is correct - Confirm anywhere we have 'reads' that are formatting the data(instead of just returning an entity object), are properly checking access on said data. For example, checking access on displaying the values of individual fields.
I can get an issue created.
Thanks for your work on this. I've merged it in, but the only thing I may go back in and change is if we should just make it a required property.
Maybe the tool could live in the ai_search module?
The Tool Explorer module has been added, can can be accessed at /admin/config/tool/explorer.
Good to know! I'm proposing removing the _sleep() method override in this particular case, so win-win.
Also worth noting, if you look at \Drupal\Core\TypedData\ListDataDefinition, we do not unset itemDefinition during serialization. Which means there's a discrepancy between how they are handling their child definitions.
I've been experimenting with some different versions of just that, though I do believe it differs from the agent tool dynamic discussion.
Instead of giving the LLM all the tools, I just exposed 3 tools: tool_list, tool_plan, and tool_execute. The LLM can use list to find the right one, plan to make sure it understands the tool and execute to actually call the tool. I had pretty good results, though I only pushed it so far. I think as the library of tools grows, we can definitely get creative here.
I could certainly use some help on the categorization/grouping side. I want to introduce the concept of 'Toolsets', but again, outside the scope of this conversation.
I'm of the belief that the overlap between Agents and Tools is pretty significant and we could potentially reuse some of those parts from Tool API for our agent approach. I really see an agent as a composite tool, that just uses AI to determine which(subtools) to use. It also has the benefit of additional context/prompting/etc that a single individual tool is lacking.
I put together an example of what an agent definition/plugin could look like:
namespace Drupal\ai_agents\Plugin\agent\Agent;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\tool\TypedData\EntityInputDefinition;
/**
* Plugin implementation of an example agent.
*/
#[Agent(
id: 'example',
label: new TranslatableMarkup('Example'),
description: new TranslatableMarkup('Does example stuff'),
prompt: '.......',
provider: Provider::SITE_DEFAULT,
max_retries: 3,
input_definitions: [
'entity' => new EntityInputDefinition(
data_type: 'entity:node',
label: new TranslatableMarkup("Node"),
required: TRUE,
description: new TranslatableMarkup("The node entity"),
),
],
tools: [
// Attach by Tool ID.
'tool_debug.example_tool',
// Attach with additional configuration.
Agent::attachTool(
id: 'tool_debug.example_tool_2',
prompt: '...',
),
// Attach a Sub-Agent.
Agent::attachSubAgent(
id: 'tool_debug.example_sub_agent',
tools: [
'tool_debug.example_tool_3',
],
),
],
output_definitions: [
'updated_entity' => new EntityInputDefinition(
data_type: 'entity:node',
label: new TranslatableMarkup("Node"),
required: TRUE,
description: new TranslatableMarkup("The node entity"),
),
],
)]
class Example extends AgentBase {
// Nothing necessarily has to be here if you just want it to use the tools.
}
By getting the definition in a good place, where one can easily define an agent without any additional behavior in the class, and allow prompts/overrides/constraints/etc. We can really nail the agent pattern and then the UI should fall into place rather easily.
See 📌 Remove 'Exists' condition tools Fixed .
michaellander → changed the visibility of the branch 3550861-tools-create-fieldadd to hidden.
michaellander → changed the visibility of the branch 3556855-create-distinction-between to hidden.
Accidentally pushed into 1.0.x directly. That's my bad.
Do we need to add toArray() to the \Drupal\Core\TypedData\DataDefinitionInterface()? I'm needing either toArray() or offsetGet() but the former isn't under contract.
michaellander → made their first commit to this issue’s fork.
michaellander → made their first commit to this issue’s fork.
michaellander → created an issue.
This fixes this specific issue, but we should probably add test coverage and try more versions of this(maps for example) with constraints.
michaellander → created an issue.
michaellander → created an issue.
I would like to opt-in this module:
https://www.drupal.org/project/tool →
It has 48 total issues, and all maintainers agree we are ready to try GitLab issues. We understand we cannot revert this change and there may be some unexpected issues as early adopters.
michaellander → created an issue.
There are a few PHPStan flags that I'm not sure the best way to fix. The one about using \Drupal to get the tempstore service is intentional, however, as I would like to replace the token stuff with a common API that works across modules and don't want to tie the tempstore service into the dependency injection until a unified solution is in place.
michaellander → created an issue.
michaellander → created an issue.
michaellander → created an issue.
michaellander → created an issue.
This branch depends on 📌 Determine path forward for turning Attributes into JSON schema Active , which I'm hoping to have fixed shortly.