mirror of
https://github.com/symfony/ai.git
synced 2026-03-23 23:42:18 +01:00
bug #1748 [AI Bundle][Profiler] Fix all tools listing duplicates for each agent (DZunke)
This PR was squashed before being merged into the main branch.
Discussion
----------
[AI Bundle][Profiler] Fix all tools listing duplicates for each agent
| Q | A
| ------------- | ---
| Bug fix? | yes
| New feature? | no
| Docs? | no
| Issues |
| License | MIT
If one is registering multiple agents the tools listing in the profiler is getting full of duplicates. So, for example, there is a `search_entries` tool and a `entry_detail` tool but you have two different agents and both get all tools, then the "Tools" section in the profiler which should just be a list of all tools available shows each of these tools in double.
I first deduplicated by taking the execution class and method as a unique selling point but had to take also the name into account as, with the names, it is also possible to have multiple tools with the same execution reference but just different names. That popped up as i thought about the subagent tool.
So hopefully `__name__::__class__::__method__` is unique enough for deduplication in the profiler all tools listing in any case.
Commits
-------
75077c5d [AI Bundle][Profiler] Fix all tools listing duplicates for each agent
This commit is contained in:
@@ -181,7 +181,20 @@ final class DataCollector extends AbstractDataCollector implements LateDataColle
|
||||
*/
|
||||
private function getAllTools(): array
|
||||
{
|
||||
return array_merge(...array_map(static fn (TraceableToolbox $toolbox) => $toolbox->getTools(), $this->toolboxes));
|
||||
$uniqueTools = [];
|
||||
|
||||
foreach ($this->toolboxes as $toolbox) {
|
||||
foreach ($toolbox->getTools() as $tool) {
|
||||
$reference = $tool->getReference();
|
||||
$key = $tool->getName().'::'.$reference->getClass().'::'.$reference->getMethod();
|
||||
|
||||
if (!isset($uniqueTools[$key])) {
|
||||
$uniqueTools[$key] = $tool;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_values($uniqueTools);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,12 +14,15 @@ namespace Symfony\AI\AiBundle\Tests\Profiler;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\AI\Agent\AgentInterface;
|
||||
use Symfony\AI\Agent\MockAgent;
|
||||
use Symfony\AI\Agent\Toolbox\Tool\Subagent;
|
||||
use Symfony\AI\Agent\Toolbox\ToolboxInterface;
|
||||
use Symfony\AI\AiBundle\Profiler\DataCollector;
|
||||
use Symfony\AI\AiBundle\Profiler\TraceableAgent;
|
||||
use Symfony\AI\AiBundle\Profiler\TraceableChat;
|
||||
use Symfony\AI\AiBundle\Profiler\TraceableMessageStore;
|
||||
use Symfony\AI\AiBundle\Profiler\TraceablePlatform;
|
||||
use Symfony\AI\AiBundle\Profiler\TraceableStore;
|
||||
use Symfony\AI\AiBundle\Profiler\TraceableToolbox;
|
||||
use Symfony\AI\Chat\Chat;
|
||||
use Symfony\AI\Chat\InMemory\Store as InMemoryStore;
|
||||
use Symfony\AI\Platform\Message\Content\Text;
|
||||
@@ -32,6 +35,8 @@ use Symfony\AI\Platform\Result\DeferredResult;
|
||||
use Symfony\AI\Platform\Result\RawResultInterface;
|
||||
use Symfony\AI\Platform\Result\StreamResult;
|
||||
use Symfony\AI\Platform\Result\TextResult;
|
||||
use Symfony\AI\Platform\Tool\ExecutionReference;
|
||||
use Symfony\AI\Platform\Tool\Tool;
|
||||
use Symfony\AI\Platform\Vector\Vector;
|
||||
use Symfony\AI\Store\Document\VectorDocument;
|
||||
use Symfony\AI\Store\InMemory\Store;
|
||||
@@ -236,4 +241,76 @@ class DataCollectorTest extends TestCase
|
||||
|
||||
$this->assertCount(1, $dataCollector->getStores());
|
||||
}
|
||||
|
||||
public function testDeduplicatesToolsBasedOnNameAndExecutionReference()
|
||||
{
|
||||
$tool1 = new Tool(
|
||||
new ExecutionReference('App\Tool\FirstTool', 'first'),
|
||||
'first_tool',
|
||||
'Does Something'
|
||||
);
|
||||
|
||||
$tool2 = new Tool(
|
||||
new ExecutionReference('App\Tool\FirstTool', 'first'),
|
||||
'first_tool',
|
||||
'Does Something'
|
||||
);
|
||||
|
||||
$tool3 = new Tool(
|
||||
new ExecutionReference('App\Tool\SecondTool', 'second'),
|
||||
'second_tool',
|
||||
'Does Something Else'
|
||||
);
|
||||
|
||||
$toolbox1 = $this->createStub(ToolboxInterface::class);
|
||||
$toolbox1->method('getTools')->willReturn([$tool1, $tool3]);
|
||||
|
||||
$toolbox2 = $this->createStub(ToolboxInterface::class);
|
||||
$toolbox2->method('getTools')->willReturn([$tool2, $tool3]);
|
||||
|
||||
$traceableToolbox1 = new TraceableToolbox($toolbox1);
|
||||
$traceableToolbox2 = new TraceableToolbox($toolbox2);
|
||||
|
||||
$dataCollector = new DataCollector([], [$traceableToolbox1, $traceableToolbox2], [], [], [], []);
|
||||
$dataCollector->lateCollect();
|
||||
|
||||
$tools = $dataCollector->getTools();
|
||||
|
||||
$this->assertCount(2, $tools);
|
||||
$this->assertSame('first_tool', $tools[0]->getName());
|
||||
$this->assertSame('second_tool', $tools[1]->getName());
|
||||
}
|
||||
|
||||
public function testDoesNotDeduplicateToolsWithSameExecutionReferenceButDifferentNames()
|
||||
{
|
||||
$tool1 = new Tool(
|
||||
new ExecutionReference(Subagent::class, '__invoke'),
|
||||
'research_agent',
|
||||
'Research Agent'
|
||||
);
|
||||
|
||||
$tool2 = new Tool(
|
||||
new ExecutionReference(Subagent::class, '__invoke'),
|
||||
'writer_agent',
|
||||
'Writer Agent'
|
||||
);
|
||||
|
||||
$toolbox1 = $this->createStub(ToolboxInterface::class);
|
||||
$toolbox1->method('getTools')->willReturn([$tool1]);
|
||||
|
||||
$toolbox2 = $this->createStub(ToolboxInterface::class);
|
||||
$toolbox2->method('getTools')->willReturn([$tool2]);
|
||||
|
||||
$traceableToolbox1 = new TraceableToolbox($toolbox1);
|
||||
$traceableToolbox2 = new TraceableToolbox($toolbox2);
|
||||
|
||||
$dataCollector = new DataCollector([], [$traceableToolbox1, $traceableToolbox2], [], [], [], []);
|
||||
$dataCollector->lateCollect();
|
||||
|
||||
$tools = $dataCollector->getTools();
|
||||
|
||||
$this->assertCount(2, $tools);
|
||||
$this->assertSame('research_agent', $tools[0]->getName());
|
||||
$this->assertSame('writer_agent', $tools[1]->getName());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user