From 217d3ad0881252b03f14a32b85040b2cd3a79825 Mon Sep 17 00:00:00 2001 From: Antoine Griffon Date: Fri, 12 Sep 2025 16:38:19 +0200 Subject: [PATCH 1/3] feat(profiler): trace and display AgentInterface calls --- src/ai-bundle/config/services.php | 9 + src/ai-bundle/src/Profiler/DataCollector.php | 39 ++- src/ai-bundle/src/Profiler/TraceableAgent.php | 60 +++++ .../templates/data_collector.html.twig | 238 +++++++++++------- 4 files changed, 250 insertions(+), 96 deletions(-) create mode 100644 src/ai-bundle/src/Profiler/TraceableAgent.php diff --git a/src/ai-bundle/config/services.php b/src/ai-bundle/config/services.php index bb5289196..1ad3e5842 100644 --- a/src/ai-bundle/config/services.php +++ b/src/ai-bundle/config/services.php @@ -11,6 +11,7 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; +use Symfony\AI\Agent\AgentInterface; use Symfony\AI\Agent\StructuredOutput\AgentProcessor as StructureOutputProcessor; use Symfony\AI\Agent\StructuredOutput\ResponseFormatFactory; use Symfony\AI\Agent\StructuredOutput\ResponseFormatFactoryInterface; @@ -23,6 +24,7 @@ use Symfony\AI\Agent\Toolbox\ToolResultConverter; use Symfony\AI\AiBundle\Command\AgentCallCommand; use Symfony\AI\AiBundle\Profiler\DataCollector; +use Symfony\AI\AiBundle\Profiler\TraceableAgent; use Symfony\AI\AiBundle\Profiler\TraceableToolbox; use Symfony\AI\AiBundle\Security\EventListener\IsGrantedToolAttributeListener; use Symfony\AI\Platform\Bridge\AiMlApi\ModelCatalog as AiMlApiModelCatalog; @@ -169,6 +171,13 @@ ]) ->tag('kernel.event_listener') + ->set('ai.traceable_agent', TraceableAgent::class) + ->decorate(AgentInterface::class, priority: 5) + ->args([ + service('.inner'), + service('ai.data_collector'), + ]) + // profiler ->set('ai.data_collector', DataCollector::class) ->args([ diff --git a/src/ai-bundle/src/Profiler/DataCollector.php b/src/ai-bundle/src/Profiler/DataCollector.php index 546ecdabd..8c6e1af57 100644 --- a/src/ai-bundle/src/Profiler/DataCollector.php +++ b/src/ai-bundle/src/Profiler/DataCollector.php @@ -37,6 +37,11 @@ final class DataCollector extends AbstractDataCollector implements LateDataColle */ private readonly array $toolboxes; + /** + * @var list + */ + private array $collectedChatCalls = []; + /** * @param TraceablePlatform[] $platforms * @param TraceableToolbox[] $toolboxes @@ -52,7 +57,6 @@ public function __construct( public function collect(Request $request, Response $response, ?\Throwable $exception = null): void { - $this->lateCollect(); } public function lateCollect(): void @@ -61,6 +65,18 @@ public function lateCollect(): void 'tools' => $this->defaultToolBox->getTools(), 'platform_calls' => array_merge(...array_map($this->awaitCallResults(...), $this->platforms)), 'tool_calls' => array_merge(...array_map(fn (TraceableToolbox $toolbox) => $toolbox->calls, $this->toolboxes)), + 'chat_calls' => $this->cloneVar($this->collectedChatCalls), + ]; + } + + public function collectChatCall(string $method, float $duration, mixed $input, mixed $result, ?\Throwable $error): void + { + $this->collectedChatCalls[] = [ + 'method' => $method, + 'duration' => $duration, + 'input' => $input, + 'result' => $result, + 'error' => $error, ]; } @@ -93,6 +109,27 @@ public function getToolCalls(): array return $this->data['tool_calls'] ?? []; } + /** + * @return list + */ + public function getChatCalls(): array + { + if (!isset($this->data['chat_calls'])) { + return []; + } + + /** @var list $chatCalls */ + $chatCalls = $this->data['chat_calls']->getValue(true); + + return $chatCalls; + } + + public function reset(): void + { + $this->data = []; + $this->collectedChatCalls = []; + } + /** * @return array{ * model: string, diff --git a/src/ai-bundle/src/Profiler/TraceableAgent.php b/src/ai-bundle/src/Profiler/TraceableAgent.php new file mode 100644 index 000000000..a62b609a5 --- /dev/null +++ b/src/ai-bundle/src/Profiler/TraceableAgent.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\AI\AiBundle\Profiler; + +use Symfony\AI\Agent\AgentInterface; +use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Platform\Result\ResultInterface; +use Symfony\Contracts\Service\ResetInterface; + +final class TraceableAgent implements AgentInterface, ResetInterface +{ + public function __construct( + private readonly AgentInterface $decorated, + private readonly DataCollector $collector, + ) { + } + + public function call(MessageBag $messages, array $options = []): ResultInterface + { + $startTime = microtime(true); + $error = null; + $response = null; + + try { + return $response = $this->decorated->call($messages, $options); + } catch (\Throwable $e) { + $error = $e; + throw $e; + } finally { + $this->collector->collectChatCall( + 'call', + microtime(true) - $startTime, + $messages, + $response, + $error + ); + } + } + + public function reset(): void + { + if ($this->decorated instanceof ResetInterface) { + $this->decorated->reset(); + } + } + + public function getName(): string + { + return 'TraceableAgent'; + } +} diff --git a/src/ai-bundle/templates/data_collector.html.twig b/src/ai-bundle/templates/data_collector.html.twig index ec064e634..70b21de5e 100644 --- a/src/ai-bundle/templates/data_collector.html.twig +++ b/src/ai-bundle/templates/data_collector.html.twig @@ -12,6 +12,10 @@ {% set text %}
+
+ Chat Calls + {{ collector.chatCalls|length }} +
Configured Platforms 1 @@ -57,7 +61,51 @@ {% block panel %}

Symfony AI

+ +

Chat Calls

+ {% if collector.chatCalls|length %} + + + + + + + + + + + + {% for call in collector.chatCalls %} + + + + + + + + {% endfor %} + +
MethodDurationInputResultError
{{ call.method }}{{ (call.duration * 1000)|round(2) }} ms{{ dump(call.input) }}{{ dump(call.result) }} + {% if call.error %} + {{ dump(call.error) }} + {% else %} + None + {% endif %} +
+ {% else %} +
+

No chat calls were made.

+
+ {% endif %} +
+
+
+ {{ collector.chatCalls|length }} + Chat Calls +
+
+
1 @@ -89,83 +137,83 @@ {% for call in collector.platformCalls %} - - - + + + - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - + + {% else %} + {{ call.result }} + {% endif %} + +
Call {{ loop.index }}
Call {{ loop.index }}
Model{{ constant('class', call.model) }} (Version: {{ call.model.name }})
Input - {% if call.input.messages is defined %}{# expect MessageBag #} -
    - {% for message in call.input.messages %} -
  1. - {{ message.role.value|title }}: - {% if 'assistant' == message.role.value and message.hasToolCalls%} - {{ _self.tool_calls(message.toolCalls) }} - {% elseif 'tool' == message.role.value %} - Result of tool call with ID {{ message.toolCall.id }}
    - {{ message.content|nl2br }} - {% elseif 'user' == message.role.value %} - {% for item in message.content %} - {% if item.text is defined %} - {{ item.text|nl2br }} - {% else %} - - {% endif %} - {% endfor %} - {% else %} - {{ message.content|nl2br }} - {% endif %} -
  2. - {% endfor %} -
- {% else %} - {{ dump(call.input) }} - {% endif %} -
Options -
    - {% for key, value in call.options %} - {% if key == 'tools' %} -
  • {{ key }}: -
      - {% for tool in value %} -
    • {{ tool.name }}
    • - {% endfor %} -
    -
  • - {% else %} -
  • {{ key }}: {{ dump(value) }}
  • - {% endif %} +
Model{{ constant('class', call.model) }} (Version: {{ call.model.name }})
Input + {% if call.input.messages is defined %}{# expect MessageBag #} +
    + {% for message in call.input.messages %} +
  1. + {{ message.role.value|title }}: + {% if 'assistant' == message.role.value and message.hasToolCalls%} + {{ _self.tool_calls(message.toolCalls) }} + {% elseif 'tool' == message.role.value %} + Result of tool call with ID {{ message.toolCall.id }}
    + {{ message.content|nl2br }} + {% elseif 'user' == message.role.value %} + {% for item in message.content %} + {% if item.text is defined %} + {{ item.text|nl2br }} + {% else %} + + {% endif %} + {% endfor %} + {% else %} + {{ message.content|nl2br }} + {% endif %} +
  2. + {% endfor %} +
+ {% else %} + {{ dump(call.input) }} + {% endif %} +
Options +
    + {% for key, value in call.options %} + {% if key == 'tools' %} +
  • {{ key }}: +
      + {% for tool in value %} +
    • {{ tool.name }}
    • + {% endfor %} +
    +
  • + {% else %} +
  • {{ key }}: {{ dump(value) }}
  • + {% endif %} + {% endfor %} +
+
Result + {% if call.input.messages is defined and call.result is iterable %}{# expect array of ToolCall #} + {{ _self.tool_calls(call.result) }} + {% elseif call.result is iterable %}{# expect array of Vectors #} +
    + {% for vector in call.result %} +
  1. Vector with {{ vector.dimensions }} dimensions
  2. {% endfor %} - -
Result - {% if call.input.messages is defined and call.result is iterable %}{# expect array of ToolCall #} - {{ _self.tool_calls(call.result) }} - {% elseif call.result is iterable %}{# expect array of Vectors #} -
    - {% for vector in call.result %} -
  1. Vector with {{ vector.dimensions }} dimensions
  2. - {% endfor %} -
- {% else %} - {{ call.result }} - {% endif %} -
{% endfor %} @@ -182,12 +230,12 @@ {% if collector.tools|length %} - - - - - - + + + + + + {% for tool in collector.tools %} @@ -224,23 +272,23 @@ {% for call in collector.toolCalls %}
NameDescriptionClass & MethodParameters
NameDescriptionClass & MethodParameters
- - - + + + - - - - - - - - - - - - + + + + + + + + + + + +
{{ call.call.name }}
{{ call.call.name }}
ID{{ call.call.id }}
Arguments{{ dump(call.call.arguments) }}
Result{{ dump(call.result) }}
ID{{ call.call.id }}
Arguments{{ dump(call.call.arguments) }}
Result{{ dump(call.result) }}
{% endfor %} From 85aea02dedfc4dc65b5753fe0247c39700a55dfe Mon Sep 17 00:00:00 2001 From: Antoine Griffon Date: Sat, 13 Sep 2025 09:22:34 +0200 Subject: [PATCH 2/3] naming, improving display --- src/ai-bundle/src/Profiler/DataCollector.php | 4 +- src/ai-bundle/src/Profiler/TraceableAgent.php | 2 +- .../templates/data_collector.html.twig | 93 +++++++++++-------- 3 files changed, 56 insertions(+), 43 deletions(-) diff --git a/src/ai-bundle/src/Profiler/DataCollector.php b/src/ai-bundle/src/Profiler/DataCollector.php index 8c6e1af57..a8a008d8b 100644 --- a/src/ai-bundle/src/Profiler/DataCollector.php +++ b/src/ai-bundle/src/Profiler/DataCollector.php @@ -69,7 +69,7 @@ public function lateCollect(): void ]; } - public function collectChatCall(string $method, float $duration, mixed $input, mixed $result, ?\Throwable $error): void + public function collectAgentCall(string $method, float $duration, mixed $input, mixed $result, ?\Throwable $error): void { $this->collectedChatCalls[] = [ 'method' => $method, @@ -112,7 +112,7 @@ public function getToolCalls(): array /** * @return list */ - public function getChatCalls(): array + public function getAgentCalls(): array { if (!isset($this->data['chat_calls'])) { return []; diff --git a/src/ai-bundle/src/Profiler/TraceableAgent.php b/src/ai-bundle/src/Profiler/TraceableAgent.php index a62b609a5..a24061b63 100644 --- a/src/ai-bundle/src/Profiler/TraceableAgent.php +++ b/src/ai-bundle/src/Profiler/TraceableAgent.php @@ -36,7 +36,7 @@ public function call(MessageBag $messages, array $options = []): ResultInterface $error = $e; throw $e; } finally { - $this->collector->collectChatCall( + $this->collector->collectAgentCall( 'call', microtime(true) - $startTime, $messages, diff --git a/src/ai-bundle/templates/data_collector.html.twig b/src/ai-bundle/templates/data_collector.html.twig index 70b21de5e..c2323bb99 100644 --- a/src/ai-bundle/templates/data_collector.html.twig +++ b/src/ai-bundle/templates/data_collector.html.twig @@ -1,5 +1,16 @@ {% extends '@WebProfiler/Profiler/layout.html.twig' %} +{% block head %} + {{ parent() }} + +{% endblock %} + {% block toolbar %} {% if collector.platformCalls|length > 0 %} {% set icon %} @@ -13,8 +24,8 @@ {% set text %}
- Chat Calls - {{ collector.chatCalls|length }} + Agent Calls + {{ collector.agentCalls|length }}
Configured Platforms @@ -62,8 +73,8 @@ {% block panel %}

Symfony AI

-

Chat Calls

- {% if collector.chatCalls|length %} +

Agent Calls

+ {% if collector.agentCalls|length %} @@ -75,15 +86,19 @@ - {% for call in collector.chatCalls %} + {% for call in collector.agentCalls %} - - + +
{{ call.method }} {{ (call.duration * 1000)|round(2) }} ms{{ dump(call.input) }}{{ dump(call.result) }} +
{{ dump(call.input) }}
+
+
{{ dump(call.result) }}
+
{% if call.error %} - {{ dump(call.error) }} +
{{ dump(call.error) }}
{% else %} None {% endif %} @@ -94,19 +109,16 @@
{% else %}
-

No chat calls were made.

+

No agent calls were made.

{% endif %}
- {{ collector.chatCalls|length }} - Chat Calls + {{ collector.agentCalls|length }} + Agent Calls
-
-
-
1 Platforms @@ -128,6 +140,7 @@
+

Platform Calls

{% if collector.platformCalls|length %}
@@ -137,9 +150,9 @@ {% for call in collector.platformCalls %} - - - + + + @@ -174,7 +187,7 @@ {% endfor %} {% else %} - {{ dump(call.input) }} +
{{ dump(call.input) }}
{% endif %} @@ -192,7 +205,7 @@ {% else %} -
  • {{ key }}: {{ dump(value) }}
  • +
  • {{ key }}:
    {{ dump(value) }}
  • {% endif %} {% endfor %} @@ -230,12 +243,12 @@ {% if collector.tools|length %}
    Call {{ loop.index }}
    Call {{ loop.index }}
    - - - - - - + + + + + + {% for tool in collector.tools %} @@ -272,23 +285,23 @@ {% for call in collector.toolCalls %}
    NameDescriptionClass & MethodParameters
    NameDescriptionClass & MethodParameters
    - - - + + + - - - - - - - - - - - - + + + + + + + + + + + +
    {{ call.call.name }}
    {{ call.call.name }}
    ID{{ call.call.id }}
    Arguments{{ dump(call.call.arguments) }}
    Result{{ dump(call.result) }}
    ID{{ call.call.id }}
    Arguments
    {{ dump(call.call.arguments) }}
    Result
    {{ dump(call.result) }}
    {% endfor %} From 1c2623945ffcc9159f365ccae094ed997ffffed1 Mon Sep 17 00:00:00 2001 From: Antoine Griffon Date: Sat, 13 Sep 2025 23:09:37 +0200 Subject: [PATCH 3/3] reworked data collector, use profiler_dump for display --- src/ai-bundle/config/services.php | 13 +- src/ai-bundle/src/Profiler/DataCollector.php | 91 ++++++------ .../templates/data_collector.html.twig | 129 +++--------------- .../tests/Profiler/DataCollectorTest.php | 4 +- 4 files changed, 75 insertions(+), 162 deletions(-) diff --git a/src/ai-bundle/config/services.php b/src/ai-bundle/config/services.php index 1ad3e5842..f57cd478a 100644 --- a/src/ai-bundle/config/services.php +++ b/src/ai-bundle/config/services.php @@ -171,14 +171,13 @@ ]) ->tag('kernel.event_listener') - ->set('ai.traceable_agent', TraceableAgent::class) - ->decorate(AgentInterface::class, priority: 5) - ->args([ - service('.inner'), - service('ai.data_collector'), - ]) - // profiler + ->set('ai.traceable_agent', TraceableAgent::class) + ->decorate(AgentInterface::class, priority: 5) + ->args([ + service('.inner'), + service('ai.data_collector'), + ]) ->set('ai.data_collector', DataCollector::class) ->args([ tagged_iterator('ai.traceable_platform'), diff --git a/src/ai-bundle/src/Profiler/DataCollector.php b/src/ai-bundle/src/Profiler/DataCollector.php index a8a008d8b..13a538d3d 100644 --- a/src/ai-bundle/src/Profiler/DataCollector.php +++ b/src/ai-bundle/src/Profiler/DataCollector.php @@ -18,11 +18,11 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface; +use Symfony\Component\VarDumper\Cloner\Data; /** * @author Christopher Hertel * - * @phpstan-import-type PlatformCallData from TraceablePlatform * @phpstan-import-type ToolCallData from TraceableToolbox */ final class DataCollector extends AbstractDataCollector implements LateDataCollectorInterface @@ -40,7 +40,7 @@ final class DataCollector extends AbstractDataCollector implements LateDataColle /** * @var list */ - private array $collectedChatCalls = []; + private array $collectedCalls = []; /** * @param TraceablePlatform[] $platforms @@ -61,22 +61,51 @@ public function collect(Request $request, Response $response, ?\Throwable $excep public function lateCollect(): void { + $platformCalls = []; + foreach ($this->platforms as $platform) { + $calls = $platform->calls; + foreach ($calls as $call) { + $result = $call['result']->await(); + if (isset($platform->resultCache[$result])) { + $call['result'] = $platform->resultCache[$result]; + } else { + $call['result'] = $result->getContent(); + } + + $call['model'] = $this->cloneVar($call['model']); + $call['input'] = $this->cloneVar($call['input']); + $call['options'] = $this->cloneVar($call['options']); + $call['result'] = $this->cloneVar($call['result']); + + $platformCalls[] = $call; + } + } + + $toolCalls = []; + foreach ($this->toolboxes as $toolbox) { + foreach ($toolbox->calls as $call) { + $call['call'] = $this->cloneVar($call['call']); + $call['result'] = $this->cloneVar($call['result']); + $toolCalls[] = $call; + } + } + $this->data = [ 'tools' => $this->defaultToolBox->getTools(), - 'platform_calls' => array_merge(...array_map($this->awaitCallResults(...), $this->platforms)), - 'tool_calls' => array_merge(...array_map(fn (TraceableToolbox $toolbox) => $toolbox->calls, $this->toolboxes)), - 'chat_calls' => $this->cloneVar($this->collectedChatCalls), + 'platform_calls' => $platformCalls, + 'tool_calls' => $toolCalls, + 'agent_calls' => $this->collectedCalls, ]; } public function collectAgentCall(string $method, float $duration, mixed $input, mixed $result, ?\Throwable $error): void { - $this->collectedChatCalls[] = [ + $this->collectedCalls[] = [ 'method' => $method, 'duration' => $duration, - 'input' => $input, - 'result' => $result, - 'error' => $error, + 'input' => $this->cloneVar($input), + 'result' => $this->cloneVar($result), + 'error' => $this->cloneVar($error), ]; } @@ -86,7 +115,12 @@ public static function getTemplate(): string } /** - * @return PlatformCallData[] + * @return array{ + * model: Data, + * input: Data, + * options: Data, + * result: Data + * }[] */ public function getPlatformCalls(): array { @@ -114,45 +148,12 @@ public function getToolCalls(): array */ public function getAgentCalls(): array { - if (!isset($this->data['chat_calls'])) { - return []; - } - - /** @var list $chatCalls */ - $chatCalls = $this->data['chat_calls']->getValue(true); - - return $chatCalls; + return $this->data['agent_calls'] ?? []; } public function reset(): void { $this->data = []; - $this->collectedChatCalls = []; - } - - /** - * @return array{ - * model: string, - * input: array|string|object, - * options: array, - * result: string|iterable|object|null - * }[] - */ - private function awaitCallResults(TraceablePlatform $platform): array - { - $calls = $platform->calls; - foreach ($calls as $key => $call) { - $result = $call['result']->await(); - - if (isset($platform->resultCache[$result])) { - $call['result'] = $platform->resultCache[$result]; - } else { - $call['result'] = $result->getContent(); - } - - $calls[$key] = $call; - } - - return $calls; + $this->collectedCalls = []; } } diff --git a/src/ai-bundle/templates/data_collector.html.twig b/src/ai-bundle/templates/data_collector.html.twig index c2323bb99..4e18cc30c 100644 --- a/src/ai-bundle/templates/data_collector.html.twig +++ b/src/ai-bundle/templates/data_collector.html.twig @@ -58,18 +58,6 @@ {% endblock %} -{% macro tool_calls(toolCalls) %} - Tool call{{ toolCalls|length > 1 ? 's' }}: -
      - {% for toolCall in toolCalls %} -
    1. - {{ toolCall.name }}({{ toolCall.arguments|map((value, key) => "#{key}: #{value|json_encode}")|join(', ') }}) - (ID: {{ toolCall.id }}) -
    2. - {% endfor %} -
    -{% endmacro %} - {% block panel %}

    Symfony AI

    @@ -90,19 +78,9 @@ {{ call.method }} {{ (call.duration * 1000)|round(2) }} ms - -
    {{ dump(call.input) }}
    - - -
    {{ dump(call.result) }}
    - - - {% if call.error %} -
    {{ dump(call.error) }}
    - {% else %} - None - {% endif %} - + {{ profiler_dump(call.input) }} + {{ profiler_dump(call.result) }} + {{ profiler_dump(call.error) }} {% endfor %} @@ -157,75 +135,19 @@ Model - {{ constant('class', call.model) }} (Version: {{ call.model.name }}) + {{ profiler_dump(call.model) }} Input - - {% if call.input.messages is defined %}{# expect MessageBag #} -
      - {% for message in call.input.messages %} -
    1. - {{ message.role.value|title }}: - {% if 'assistant' == message.role.value and message.hasToolCalls%} - {{ _self.tool_calls(message.toolCalls) }} - {% elseif 'tool' == message.role.value %} - Result of tool call with ID {{ message.toolCall.id }}
      - {{ message.content|nl2br }} - {% elseif 'user' == message.role.value %} - {% for item in message.content %} - {% if item.text is defined %} - {{ item.text|nl2br }} - {% else %} - - {% endif %} - {% endfor %} - {% else %} - {{ message.content|nl2br }} - {% endif %} -
    2. - {% endfor %} -
    - {% else %} -
    {{ dump(call.input) }}
    - {% endif %} - + {{ profiler_dump(call.input) }} Options - -
      - {% for key, value in call.options %} - {% if key == 'tools' %} -
    • {{ key }}: -
        - {% for tool in value %} -
      • {{ tool.name }}
      • - {% endfor %} -
      -
    • - {% else %} -
    • {{ key }}:
      {{ dump(value) }}
    • - {% endif %} - {% endfor %} -
    - + {{ profiler_dump(call.options) }} Result - - {% if call.input.messages is defined and call.result is iterable %}{# expect array of ToolCall #} - {{ _self.tool_calls(call.result) }} - {% elseif call.result is iterable %}{# expect array of Vectors #} -
      - {% for vector in call.result %} -
    1. Vector with {{ vector.dimensions }} dimensions
    2. - {% endfor %} -
    - {% else %} - {{ call.result }} - {% endif %} - + {{ profiler_dump(call.result) }} @@ -251,27 +173,14 @@ - {% for tool in collector.tools %} - - {{ tool.name }} - {{ tool.description }} - {{ tool.reference.class }}::{{ tool.reference.method }} - - {% if tool.parameters %} -
      - {% for name, parameter in tool.parameters.properties %} -
    • - {{ name }} ({{ parameter.type is iterable ? parameter.type|join(', ') : parameter.type }})
      - {{ parameter.description|default() }} -
    • - {% endfor %} -
    - {% else %} - none - {% endif %} - - - {% endfor %} + {% for tool in collector.tools %} + + {{ tool.name }} + {{ tool.description }} + {{ profiler_dump(tool.reference) }} + {{ profiler_dump(tool.parameters) }} + + {% endfor %} {% else %} @@ -296,11 +205,15 @@ Arguments -
    {{ dump(call.call.arguments) }}
    +
    {{ profiler_dump(call.call.arguments) }}
    + + + Call + {{ profiler_dump(call.call) }} Result -
    {{ dump(call.result) }}
    + {{ profiler_dump(call.result) }} diff --git a/src/ai-bundle/tests/Profiler/DataCollectorTest.php b/src/ai-bundle/tests/Profiler/DataCollectorTest.php index bed7ded34..c4ea8b562 100644 --- a/src/ai-bundle/tests/Profiler/DataCollectorTest.php +++ b/src/ai-bundle/tests/Profiler/DataCollectorTest.php @@ -42,7 +42,7 @@ public function testCollectsDataForNonStreamingResponse() $dataCollector->lateCollect(); $this->assertCount(1, $dataCollector->getPlatformCalls()); - $this->assertSame('Assistant response', $dataCollector->getPlatformCalls()[0]['result']); + $this->assertSame('Assistant response', $dataCollector->getPlatformCalls()[0]['result']->getValue(true)); } public function testCollectsDataForStreamingResponse() @@ -66,6 +66,6 @@ public function testCollectsDataForStreamingResponse() $dataCollector->lateCollect(); $this->assertCount(1, $dataCollector->getPlatformCalls()); - $this->assertSame('Assistant response', $dataCollector->getPlatformCalls()[0]['result']); + $this->assertSame('Assistant response', $dataCollector->getPlatformCalls()[0]['result']->getValue(true)); } }