*/ final class ToolCaller implements ToolCallerInterface { public function __construct( private readonly ReferenceProviderInterface $referenceProvider, private readonly ReferenceHandlerInterface $referenceHandler, private readonly LoggerInterface $logger = new NullLogger(), ) { } /** * @throws ToolCallException if the tool execution fails * @throws ToolNotFoundException if the tool is not found */ public function call(CallToolRequest $request): CallToolResult { $toolName = $request->name; $arguments = $request->arguments ?? []; $this->logger->debug('Executing tool', ['name' => $toolName, 'arguments' => $arguments]); $toolReference = $this->referenceProvider->getTool($toolName); if (null === $toolReference) { $this->logger->warning('Tool not found', ['name' => $toolName]); throw new ToolNotFoundException($request); } try { $result = $this->referenceHandler->handle($toolReference, $arguments); /** @var TextContent[]|ImageContent[]|EmbeddedResource[]|AudioContent[] $formattedResult */ $formattedResult = $toolReference->formatResult($result); $this->logger->debug('Tool executed successfully', [ 'name' => $toolName, 'result_type' => \gettype($result), ]); return new CallToolResult($formattedResult); } catch (\Throwable $e) { $this->logger->error('Tool execution failed', [ 'name' => $toolName, 'exception' => $e->getMessage(), 'trace' => $e->getTraceAsString(), ]); throw new ToolCallException($request, $e); } } }