diff --git a/README.md b/README.md index ac65db86d..5a69f6db4 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Symfony AI consists of several lower and higher level **components** and the res * **Components** * **[Platform](src/platform/README.md)**: A unified interface to various AI platforms like OpenAI, Anthropic, Azure, Gemini, VertexAI, and more. * **[Agent](src/agent/README.md)**: Framework for building AI agents that can interact with users and perform tasks. + * **[Tools](src/tools/README.md)**: Collection of third-party tools for AI agents. * **[Store](src/store/README.md)**: Data storage abstraction with indexing and retrieval for AI applications. * **[MCP SDK](src/mcp-sdk/README.md)**: SDK for [Model Context Protocol](https://modelcontextprotocol.io) enabling communication between AI agents and tools. * **Bundles** diff --git a/demo/composer.json b/demo/composer.json index 63c271867..2e5edc558 100644 --- a/demo/composer.json +++ b/demo/composer.json @@ -13,6 +13,7 @@ "php-http/discovery": "^1.20", "runtime/frankenphp-symfony": "^0.2.0", "symfony/ai-bundle": "@dev", + "symfony/ai-tools": "@dev", "symfony/asset": "~7.3.0", "symfony/asset-mapper": "~7.3.0", "symfony/clock": "~7.3.0", diff --git a/demo/config/packages/ai.yaml b/demo/config/packages/ai.yaml index c33e60a9b..ba35dcea0 100644 --- a/demo/config/packages/ai.yaml +++ b/demo/config/packages/ai.yaml @@ -38,7 +38,7 @@ ai: text: 'Please answer the users question based on Wikipedia and provide a link to the article.' include_tools: true tools: - - 'Symfony\AI\Agent\Toolbox\Tool\Wikipedia' + - 'Symfony\AI\Tools\Tool\Wikipedia' audio: model: class: 'Symfony\AI\Platform\Bridge\OpenAi\Gpt' @@ -75,14 +75,15 @@ services: autoconfigure: true # Symfony\AI\Agent\Toolbox\Tool\Clock: ~ - # Symfony\AI\Agent\Toolbox\Tool\OpenMeteo: ~ - # Symfony\AI\Agent\Toolbox\Tool\SerpApi: - # $apiKey: '%env(SERP_API_KEY)%' - Symfony\AI\Agent\Toolbox\Tool\Wikipedia: ~ Symfony\AI\Agent\Toolbox\Tool\SimilaritySearch: $vectorizer: '@ai.vectorizer.openai' $store: '@ai.store.chroma_db.symfonycon' + # Symfony\AI\Tools\Tool\OpenMeteo: ~ + # Symfony\AI\Tools\Tool\SerpApi: + # $apiKey: '%env(SERP_API_KEY)%' + Symfony\AI\Tools\Tool\Wikipedia: ~ + Symfony\AI\Store\Document\Loader\RssFeedLoader: ~ Symfony\AI\Store\Document\Transformer\TextTrimTransformer: ~ diff --git a/examples/aimlapi/toolcall.php b/examples/aimlapi/toolcall.php index 5895d18dd..142612db7 100644 --- a/examples/aimlapi/toolcall.php +++ b/examples/aimlapi/toolcall.php @@ -11,13 +11,13 @@ use Symfony\AI\Agent\Agent; use Symfony\AI\Agent\Toolbox\AgentProcessor; -use Symfony\AI\Agent\Toolbox\Tool\Wikipedia; use Symfony\AI\Agent\Toolbox\Toolbox; use Symfony\AI\Platform\Bridge\AiMlApi\Completions; use Symfony\AI\Platform\Bridge\AiMlApi\PlatformFactory; use Symfony\AI\Platform\Capability; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Tools\Tool\Wikipedia; require_once dirname(__DIR__).'/bootstrap.php'; diff --git a/examples/anthropic/toolcall.php b/examples/anthropic/toolcall.php index 06a37a835..237ac195c 100644 --- a/examples/anthropic/toolcall.php +++ b/examples/anthropic/toolcall.php @@ -11,12 +11,12 @@ use Symfony\AI\Agent\Agent; use Symfony\AI\Agent\Toolbox\AgentProcessor; -use Symfony\AI\Agent\Toolbox\Tool\Wikipedia; use Symfony\AI\Agent\Toolbox\Toolbox; use Symfony\AI\Platform\Bridge\Anthropic\Claude; use Symfony\AI\Platform\Bridge\Anthropic\PlatformFactory; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Tools\Tool\Wikipedia; require_once dirname(__DIR__).'/bootstrap.php'; diff --git a/examples/bedrock/toolcall-claude.php b/examples/bedrock/toolcall-claude.php index 16b23403b..a69679324 100644 --- a/examples/bedrock/toolcall-claude.php +++ b/examples/bedrock/toolcall-claude.php @@ -11,12 +11,12 @@ use Symfony\AI\Agent\Agent; use Symfony\AI\Agent\Toolbox\AgentProcessor; -use Symfony\AI\Agent\Toolbox\Tool\Wikipedia; use Symfony\AI\Agent\Toolbox\Toolbox; use Symfony\AI\Platform\Bridge\Anthropic\Claude; use Symfony\AI\Platform\Bridge\Bedrock\PlatformFactory; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Tools\Tool\Wikipedia; require_once dirname(__DIR__).'/bootstrap.php'; diff --git a/examples/bedrock/toolcall-nova.php b/examples/bedrock/toolcall-nova.php index 2b361b9f4..b45df42a8 100644 --- a/examples/bedrock/toolcall-nova.php +++ b/examples/bedrock/toolcall-nova.php @@ -11,12 +11,12 @@ use Symfony\AI\Agent\Agent; use Symfony\AI\Agent\Toolbox\AgentProcessor; -use Symfony\AI\Agent\Toolbox\Tool\Wikipedia; use Symfony\AI\Agent\Toolbox\Toolbox; use Symfony\AI\Platform\Bridge\Bedrock\Nova\Nova; use Symfony\AI\Platform\Bridge\Bedrock\PlatformFactory; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Tools\Tool\Wikipedia; require_once dirname(__DIR__).'/bootstrap.php'; diff --git a/examples/composer.json b/examples/composer.json index d3a4ebda1..d67c3fe20 100644 --- a/examples/composer.json +++ b/examples/composer.json @@ -19,6 +19,7 @@ "symfony/ai-agent": "@dev", "symfony/ai-platform": "@dev", "symfony/ai-store": "@dev", + "symfony/ai-tools": "@dev", "symfony/cache": "^7.3|^8.0", "symfony/console": "^7.3|^8.0", "symfony/css-selector": "^7.3|^8.0", diff --git a/examples/dockermodelrunner/toolcall.php b/examples/dockermodelrunner/toolcall.php index 012cb259f..64662ef19 100644 --- a/examples/dockermodelrunner/toolcall.php +++ b/examples/dockermodelrunner/toolcall.php @@ -11,12 +11,12 @@ use Symfony\AI\Agent\Agent; use Symfony\AI\Agent\Toolbox\AgentProcessor; -use Symfony\AI\Agent\Toolbox\Tool\Wikipedia; use Symfony\AI\Agent\Toolbox\Toolbox; use Symfony\AI\Platform\Bridge\DockerModelRunner\Completions; use Symfony\AI\Platform\Bridge\DockerModelRunner\PlatformFactory; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Tools\Tool\Wikipedia; require_once dirname(__DIR__).'/bootstrap.php'; diff --git a/examples/mistral/toolcall-stream.php b/examples/mistral/toolcall-stream.php index b13a54ab7..419a75dcd 100644 --- a/examples/mistral/toolcall-stream.php +++ b/examples/mistral/toolcall-stream.php @@ -11,12 +11,12 @@ use Symfony\AI\Agent\Agent; use Symfony\AI\Agent\Toolbox\AgentProcessor; -use Symfony\AI\Agent\Toolbox\Tool\YouTubeTranscriber; use Symfony\AI\Agent\Toolbox\Toolbox; use Symfony\AI\Platform\Bridge\Mistral\Mistral; use Symfony\AI\Platform\Bridge\Mistral\PlatformFactory; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Tools\Tool\YouTubeTranscriber; require_once dirname(__DIR__).'/bootstrap.php'; diff --git a/examples/openai/toolcall-stream.php b/examples/openai/toolcall-stream.php index bba5bd6d2..bd82d93b5 100644 --- a/examples/openai/toolcall-stream.php +++ b/examples/openai/toolcall-stream.php @@ -11,12 +11,12 @@ use Symfony\AI\Agent\Agent; use Symfony\AI\Agent\Toolbox\AgentProcessor; -use Symfony\AI\Agent\Toolbox\Tool\Wikipedia; use Symfony\AI\Agent\Toolbox\Toolbox; use Symfony\AI\Platform\Bridge\OpenAi\Gpt; use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Tools\Tool\Wikipedia; require_once dirname(__DIR__).'/bootstrap.php'; diff --git a/examples/openai/toolcall.php b/examples/openai/toolcall.php index a99d9247d..963f015b5 100644 --- a/examples/openai/toolcall.php +++ b/examples/openai/toolcall.php @@ -11,12 +11,12 @@ use Symfony\AI\Agent\Agent; use Symfony\AI\Agent\Toolbox\AgentProcessor; -use Symfony\AI\Agent\Toolbox\Tool\YouTubeTranscriber; use Symfony\AI\Agent\Toolbox\Toolbox; use Symfony\AI\Platform\Bridge\OpenAi\Gpt; use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Tools\Tool\YouTubeTranscriber; require_once dirname(__DIR__).'/bootstrap.php'; diff --git a/examples/toolbox/brave.php b/examples/toolbox/brave.php index f0729733e..3029daa44 100644 --- a/examples/toolbox/brave.php +++ b/examples/toolbox/brave.php @@ -11,13 +11,13 @@ use Symfony\AI\Agent\Agent; use Symfony\AI\Agent\Toolbox\AgentProcessor; -use Symfony\AI\Agent\Toolbox\Tool\Brave; use Symfony\AI\Agent\Toolbox\Tool\Crawler; use Symfony\AI\Agent\Toolbox\Toolbox; use Symfony\AI\Platform\Bridge\OpenAi\Gpt; use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Tools\Tool\Brave; require_once dirname(__DIR__).'/bootstrap.php'; diff --git a/examples/toolbox/firecrawl-crawl.php b/examples/toolbox/firecrawl-crawl.php index 041a1c224..51977daef 100644 --- a/examples/toolbox/firecrawl-crawl.php +++ b/examples/toolbox/firecrawl-crawl.php @@ -11,12 +11,12 @@ use Symfony\AI\Agent\Agent; use Symfony\AI\Agent\Toolbox\AgentProcessor; -use Symfony\AI\Agent\Toolbox\Tool\Firecrawl; use Symfony\AI\Agent\Toolbox\Toolbox; use Symfony\AI\Platform\Bridge\OpenAi\Gpt; use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Tools\Tool\Firecrawl; require_once dirname(__DIR__).'/bootstrap.php'; diff --git a/examples/toolbox/firecrawl-map.php b/examples/toolbox/firecrawl-map.php index 7893e97c7..b3779cd18 100644 --- a/examples/toolbox/firecrawl-map.php +++ b/examples/toolbox/firecrawl-map.php @@ -11,12 +11,12 @@ use Symfony\AI\Agent\Agent; use Symfony\AI\Agent\Toolbox\AgentProcessor; -use Symfony\AI\Agent\Toolbox\Tool\Firecrawl; use Symfony\AI\Agent\Toolbox\Toolbox; use Symfony\AI\Platform\Bridge\OpenAi\Gpt; use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Tools\Tool\Firecrawl; require_once dirname(__DIR__).'/bootstrap.php'; diff --git a/examples/toolbox/firecrawl-scrape.php b/examples/toolbox/firecrawl-scrape.php index 81da48f59..512fab17e 100644 --- a/examples/toolbox/firecrawl-scrape.php +++ b/examples/toolbox/firecrawl-scrape.php @@ -11,12 +11,12 @@ use Symfony\AI\Agent\Agent; use Symfony\AI\Agent\Toolbox\AgentProcessor; -use Symfony\AI\Agent\Toolbox\Tool\Firecrawl; use Symfony\AI\Agent\Toolbox\Toolbox; use Symfony\AI\Platform\Bridge\OpenAi\Gpt; use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Tools\Tool\Firecrawl; require_once dirname(__DIR__).'/bootstrap.php'; diff --git a/examples/toolbox/mapbox-geocode.php b/examples/toolbox/mapbox-geocode.php index 5ed906e3f..efeaeb4ab 100644 --- a/examples/toolbox/mapbox-geocode.php +++ b/examples/toolbox/mapbox-geocode.php @@ -11,12 +11,12 @@ use Symfony\AI\Agent\Agent; use Symfony\AI\Agent\Toolbox\AgentProcessor; -use Symfony\AI\Agent\Toolbox\Tool\Mapbox; use Symfony\AI\Agent\Toolbox\Toolbox; use Symfony\AI\Platform\Bridge\OpenAi\Gpt; use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Tools\Tool\Mapbox; require_once dirname(__DIR__).'/bootstrap.php'; diff --git a/examples/toolbox/mapbox-reverse-geocode.php b/examples/toolbox/mapbox-reverse-geocode.php index d9f14403f..40f6de33b 100644 --- a/examples/toolbox/mapbox-reverse-geocode.php +++ b/examples/toolbox/mapbox-reverse-geocode.php @@ -11,12 +11,12 @@ use Symfony\AI\Agent\Agent; use Symfony\AI\Agent\Toolbox\AgentProcessor; -use Symfony\AI\Agent\Toolbox\Tool\Mapbox; use Symfony\AI\Agent\Toolbox\Toolbox; use Symfony\AI\Platform\Bridge\OpenAi\Gpt; use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Tools\Tool\Mapbox; require_once dirname(__DIR__).'/bootstrap.php'; diff --git a/examples/toolbox/serpapi.php b/examples/toolbox/serpapi.php index 393c3b15e..6883d017c 100644 --- a/examples/toolbox/serpapi.php +++ b/examples/toolbox/serpapi.php @@ -11,12 +11,12 @@ use Symfony\AI\Agent\Agent; use Symfony\AI\Agent\Toolbox\AgentProcessor; -use Symfony\AI\Agent\Toolbox\Tool\SerpApi; use Symfony\AI\Agent\Toolbox\Toolbox; use Symfony\AI\Platform\Bridge\OpenAi\Gpt; use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Tools\Tool\SerpApi; require_once dirname(__DIR__).'/bootstrap.php'; diff --git a/examples/toolbox/tavily.php b/examples/toolbox/tavily.php index 6e5ec1682..fb94d4440 100644 --- a/examples/toolbox/tavily.php +++ b/examples/toolbox/tavily.php @@ -11,12 +11,12 @@ use Symfony\AI\Agent\Agent; use Symfony\AI\Agent\Toolbox\AgentProcessor; -use Symfony\AI\Agent\Toolbox\Tool\Tavily; use Symfony\AI\Agent\Toolbox\Toolbox; use Symfony\AI\Platform\Bridge\OpenAi\Gpt; use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Tools\Tool\Tavily; require_once dirname(__DIR__).'/bootstrap.php'; diff --git a/examples/toolbox/weather-event.php b/examples/toolbox/weather-event.php index fbd136f07..96f4ecd2f 100644 --- a/examples/toolbox/weather-event.php +++ b/examples/toolbox/weather-event.php @@ -12,13 +12,13 @@ use Symfony\AI\Agent\Agent; use Symfony\AI\Agent\Toolbox\AgentProcessor; use Symfony\AI\Agent\Toolbox\Event\ToolCallsExecuted; -use Symfony\AI\Agent\Toolbox\Tool\OpenMeteo; use Symfony\AI\Agent\Toolbox\Toolbox; use Symfony\AI\Platform\Bridge\OpenAi\Gpt; use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; use Symfony\AI\Platform\Result\ObjectResult; +use Symfony\AI\Tools\Tool\OpenMeteo; use Symfony\Component\EventDispatcher\EventDispatcher; require_once dirname(__DIR__).'/bootstrap.php'; diff --git a/src/agent/CHANGELOG.md b/src/agent/CHANGELOG.md index b82ee4f76..8dc7cc713 100644 --- a/src/agent/CHANGELOG.md +++ b/src/agent/CHANGELOG.md @@ -24,14 +24,7 @@ CHANGELOG - `SimilaritySearch` for RAG/vector store searches - `Agent` allowing agents to use other agents as tools - `Clock` for current date/time - - `Brave` for web search integration - `Crawler` for web page crawling - - `Mapbox` for geocoding addresses to coordinates and reverse geocoding - - `OpenMeteo` for weather information - - `SerpApi` for search engine results - - `Tavily` for AI-powered search - - `Wikipedia` for Wikipedia content retrieval - - `YouTubeTranscriber` for YouTube video transcription * Add structured output support: - PHP class output with automatic conversion from LLM responses - Array structure output with JSON schema validation diff --git a/src/agent/doc/index.rst b/src/agent/doc/index.rst index 103987c12..8eb5146c3 100644 --- a/src/agent/doc/index.rst +++ b/src/agent/doc/index.rst @@ -77,7 +77,7 @@ Tool calling can be enabled by registering the processors in the agent:: Custom tools can basically be any class, but must configure by the ``#[AsTool]`` attribute:: - use Symfony\AI\Toolbox\Attribute\AsTool; + use Symfony\AI\Agent\Toolbox\Attribute\AsTool; #[AsTool('company_name', 'Provides the name of your company')] final class CompanyName @@ -97,7 +97,7 @@ JsonSerializable interface, to JSON strings for you. So you can return arrays or You can configure the method to be called by the LLM with the #[AsTool] attribute and have multiple tools per class:: - use Symfony\AI\Toolbox\Attribute\AsTool; + use Symfony\AI\Agent\Toolbox\Attribute\AsTool; #[AsTool( name: 'weather_current', diff --git a/src/ai-bundle/doc/index.rst b/src/ai-bundle/doc/index.rst index 0d867a839..8b4156938 100644 --- a/src/ai-bundle/doc/index.rst +++ b/src/ai-bundle/doc/index.rst @@ -87,15 +87,15 @@ Configuration # Referencing a agent => agent in agent 🤯 - agent: 'research' - name: 'wikipedia_research' - description: 'Can research on Wikipedia' + name: 'similarity_research' + description: 'Can search through stored documents' research: platform: 'ai.platform.anthropic' model: class: 'Symfony\AI\Platform\Bridge\Anthropic\Claude' name: !php/const Symfony\AI\Platform\Bridge\Anthropic\Claude::SONNET_37 tools: # If undefined, all tools are injected into the agent, use "tools: false" to disable tools. - - 'Symfony\AI\Agent\Toolbox\Tool\Wikipedia' + - 'Symfony\AI\Agent\Toolbox\Tool\SimilaritySearch' fault_tolerant_toolbox: false # Disables fault tolerant toolbox, default is true search_agent: platform: 'ai.platform.perplexity' @@ -408,19 +408,7 @@ To use existing tools, you can register them as a service: autoconfigure: true Symfony\AI\Agent\Toolbox\Tool\Clock: ~ - Symfony\AI\Agent\Toolbox\Tool\OpenMeteo: ~ - Symfony\AI\Agent\Toolbox\Tool\SerpApi: - $apiKey: '%env(SERP_API_KEY)%' Symfony\AI\Agent\Toolbox\Tool\SimilaritySearch: ~ - Symfony\AI\Agent\Toolbox\Tool\Tavily: - $apiKey: '%env(TAVILY_API_KEY)%' - Symfony\AI\Agent\Toolbox\Tool\Wikipedia: ~ - Symfony\AI\Agent\Toolbox\Tool\YouTubeTranscriber: ~ - Symfony\AI\Agent\Toolbox\Tool\Firecrawl: - $endpoint: '%env(FIRECRAWL_ENDPOINT)%' - $apiKey: '%env(FIRECRAWL_API_KEY)%' - Symfony\AI\Agent\Toolbox\Tool\Brave: - $apiKey: '%env(BRAVE_API_KEY)%' Custom tools can be registered by using the ``#[AsTool]`` attribute:: diff --git a/src/tools/.gitattributes b/src/tools/.gitattributes new file mode 100644 index 000000000..6ad0287aa --- /dev/null +++ b/src/tools/.gitattributes @@ -0,0 +1,7 @@ +/.gitattributes export-ignore +/.gitignore export-ignore +/AGENTS.md export-ignore +/CLAUDE.md export-ignore +/phpunit.xml.dist export-ignore +/phpstan.dist.neon export-ignore +/tests export-ignore diff --git a/src/tools/AGENTS.md b/src/tools/AGENTS.md new file mode 100644 index 000000000..587fe13fd --- /dev/null +++ b/src/tools/AGENTS.md @@ -0,0 +1,29 @@ +# AGENTS.md + +## AI Agent Tools Package + +This package provides third-party tools for AI agents including: + +- **Brave Search**: Web search functionality using the Brave Search API +- **Firecrawl**: Website scraping, crawling, and URL mapping capabilities +- **Mapbox**: Geocoding and reverse geocoding services +- **OpenMeteo**: Weather data and forecasting services +- **SerpApi**: Internet search functionality via SerpApi +- **Tavily**: Web search and content extraction services +- **Wikipedia**: Search and article retrieval from Wikipedia +- **YouTube Transcriber**: Fetch transcripts from YouTube videos + +### Usage + +These tools can be registered with AI agents to provide external data access capabilities. Each tool is automatically configured with the `#[AsTool]` attribute for easy integration. + +### Requirements + +- PHP 8.2+ +- Various API keys depending on tools used: + - Brave Search API key (for Brave tool) + - Mapbox access token (for Mapbox tool) + - SerpApi key (for SerpApi tool) + - Tavily API key (for Tavily tool) +- HTTP client implementation +- Optional: `mrmysql/youtube-transcript` package (for YouTube Transcriber) \ No newline at end of file diff --git a/src/tools/CHANGELOG.md b/src/tools/CHANGELOG.md new file mode 100644 index 000000000..dbfa82b1b --- /dev/null +++ b/src/tools/CHANGELOG.md @@ -0,0 +1,14 @@ +CHANGELOG +========= + +0.1 +--- + +- Add Brave Search tool +- Add Firecrawl tool +- Add Mapbox tool +- Add OpenMeteo tool +- Add SerpApi tool +- Add Tavily tool +- Add Wikipedia tool +- Add YouTube Transcriber tool \ No newline at end of file diff --git a/src/tools/CLAUDE.md b/src/tools/CLAUDE.md new file mode 100644 index 000000000..bcb46ff02 --- /dev/null +++ b/src/tools/CLAUDE.md @@ -0,0 +1,63 @@ +# CLAUDE.md + +This package provides third-party tools for Symfony AI agents. + +## Available Tools + +### Brave Search Tool +- Provides web search functionality via Brave Search API +- Requires API key configuration +- Returns formatted search results + +### Firecrawl Tool +- Website scraping with `firecrawl_scrape` method +- Website crawling with `firecrawl_crawl` method +- URL mapping with `firecrawl_map` method +- Requires API key and endpoint configuration + +### Mapbox Tool +- Address geocoding with `geocode` method +- Reverse geocoding with `reverse_geocode` method +- Requires Mapbox access token + +### OpenMeteo Tool +- Current weather data with `weather_current` method +- Weather forecasting with `weather_forecast` method +- No API key required (public API) + +### SerpApi Tool +- Internet search functionality via SerpApi +- Requires SerpApi key configuration +- Returns search result titles + +### Tavily Tool +- Web search with `tavily_search` method +- Content extraction with `tavily_extract` method +- Requires Tavily API key + +### Wikipedia Tool +- Searches Wikipedia articles with `wikipedia_search` method +- Retrieves full article content with `wikipedia_article` method +- Supports multiple languages +- No API key required + +### YouTube Transcriber Tool +- Fetches transcripts from YouTube videos +- Requires `mrmysql/youtube-transcript` package +- No API key required + +## Development + +Run tests: +```bash +vendor/bin/phpunit +``` + +Run static analysis: +```bash +vendor/bin/phpstan analyse +``` + +## Tool Integration + +All tools are automatically configured with the `#[AsTool]` attribute and can be easily integrated into AI agents using the agent framework. \ No newline at end of file diff --git a/src/tools/LICENSE b/src/tools/LICENSE new file mode 100644 index 000000000..f35e0bb34 --- /dev/null +++ b/src/tools/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2025-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/src/tools/README.md b/src/tools/README.md new file mode 100644 index 000000000..4370f4759 --- /dev/null +++ b/src/tools/README.md @@ -0,0 +1,172 @@ +# Symfony AI Tools + +A collection of third-party tools for Symfony AI agents. + +## Available Tools + +- [**Brave Search**](#brave-search-tool): Web search functionality using the Brave Search API +- [**Firecrawl**](#firecrawl-tool): Website scraping, crawling, and URL mapping capabilities +- [**Mapbox**](#mapbox-tool): Geocoding and reverse geocoding services +- [**OpenMeteo**](#openmeteo-tool): Weather data and forecasting services +- [**SerpApi**](#serpapi-tool): Internet search functionality via SerpApi +- [**Tavily**](#tavily-tool): Web search and content extraction services +- [**Wikipedia**](#wikipedia-tool): Search and retrieve Wikipedia articles +- [**YouTube Transcriber**](#youtube-transcriber-tool): Fetch transcripts from YouTube videos + +## Installation + +```bash +composer require symfony/ai-tools +``` + +## Usage + +### Brave Search Tool + +```php +use Symfony\AI\Tools\Brave; +use Symfony\Component\HttpClient\HttpClient; + +$httpClient = HttpClient::create(); +$brave = new Brave($httpClient, 'your-brave-api-key'); + +$results = $brave('search query'); +``` + +### Firecrawl Tool + +```php +use Symfony\AI\Tools\Firecrawl; +use Symfony\Component\HttpClient\HttpClient; + +$httpClient = HttpClient::create(); +$firecrawl = new Firecrawl($httpClient, 'your-api-key', 'https://api.firecrawl.dev'); + +// Scrape a single page +$scraped = $firecrawl->scrape('https://example.com'); + +// Crawl an entire website +$crawled = $firecrawl->crawl('https://example.com'); + +// Map all URLs from a website +$mapped = $firecrawl->map('https://example.com'); +``` + +### Mapbox Tool + +```php +use Symfony\AI\Tools\Mapbox; +use Symfony\Component\HttpClient\HttpClient; + +$httpClient = HttpClient::create(); +$mapbox = new Mapbox($httpClient, 'your-mapbox-access-token'); + +// Convert address to coordinates +$coordinates = $mapbox->geocode('1600 Pennsylvania Ave, Washington DC'); + +// Convert coordinates to address +$address = $mapbox->reverseGeocode(-77.0365, 38.8977); +``` + +### OpenMeteo Tool + +```php +use Symfony\AI\Tools\OpenMeteo; +use Symfony\Component\HttpClient\HttpClient; + +$httpClient = HttpClient::create(); +$openMeteo = new OpenMeteo($httpClient); + +// Get current weather +$currentWeather = $openMeteo->current(52.52, 13.4050); // Berlin coordinates + +// Get weather forecast +$forecast = $openMeteo->forecast(52.52, 13.4050); // Berlin coordinates +``` + +### SerpApi Tool + +```php +use Symfony\AI\Tools\SerpApi; +use Symfony\Component\HttpClient\HttpClient; + +$httpClient = HttpClient::create(); +$serpApi = new SerpApi($httpClient, 'your-serpapi-key'); + +$results = $serpApi('artificial intelligence trends'); +``` + +### Tavily Tool + +```php +use Symfony\AI\Tools\Tavily; +use Symfony\Component\HttpClient\HttpClient; + +$httpClient = HttpClient::create(); +$tavily = new Tavily($httpClient, 'your-tavily-api-key'); + +// Search for information +$searchResults = $tavily->search('latest AI developments'); + +// Extract content from a website +$extractedContent = $tavily->extract(['https://example.com']); +``` + +### Wikipedia Tool + +```php +use Symfony\AI\Tools\Wikipedia; +use Symfony\Component\HttpClient\HttpClient; + +$httpClient = HttpClient::create(); +$wikipedia = new Wikipedia($httpClient); + +// Search for articles +$searchResults = $wikipedia->search('artificial intelligence'); + +// Get article content +$article = $wikipedia->article('Artificial intelligence'); + +// Use different language (optional) +$germanWikipedia = new Wikipedia($httpClient, 'de'); +``` + +### YouTube Transcriber Tool + +```php +use Symfony\AI\Tools\YouTubeTranscriber; +use Symfony\Component\HttpClient\HttpClient; + +$httpClient = HttpClient::create(); +$transcriber = new YouTubeTranscriber($httpClient); + +// Get transcript from YouTube video ID +$transcript = $transcriber('dQw4w9WgXcQ'); +``` + +## Requirements + +- PHP 8.2 or higher +- Symfony HTTP Client +- API keys for specific tools: + - Brave Search API key (for Brave tool) + - Firecrawl API key and endpoint (for Firecrawl tool) + - Mapbox access token (for Mapbox tool) + - SerpApi key (for SerpApi tool) + - Tavily API key (for Tavily tool) +- Optional dependencies: + - `mrmysql/youtube-transcript` package (for YouTube Transcriber tool) + +**Note**: OpenMeteo and Wikipedia tools require no API keys. + +## Testing + +```bash +vendor/bin/phpunit +``` + +## Static Analysis + +```bash +vendor/bin/phpstan analyse +``` \ No newline at end of file diff --git a/src/tools/composer.json b/src/tools/composer.json new file mode 100644 index 000000000..1b4036130 --- /dev/null +++ b/src/tools/composer.json @@ -0,0 +1,53 @@ +{ + "name": "symfony/ai-tools", + "description": "Collection of third-party tools for AI agents", + "license": "MIT", + "type": "library", + "keywords": [ + "ai", + "tools", + "brave", + "wikipedia" + ], + "authors": [ + { + "name": "Christopher Hertel", + "email": "mail@christopher-hertel.de" + }, + { + "name": "Oskar Stark", + "email": "oskarstark@googlemail.com" + } + ], + "require": { + "php": ">=8.2", + "symfony/ai-agent": "@dev", + "symfony/ai-platform": "@dev", + "symfony/http-client": "^7.3|^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^2.1.17", + "phpunit/phpunit": "^11.5" + }, + "autoload": { + "psr-4": { + "Symfony\\AI\\Tools\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Symfony\\AI\\PHPStan\\": "../../.phpstan/", + "Symfony\\AI\\Tools\\Tests\\": "tests/" + } + }, + "config": { + "sort-packages": true + }, + "extra": { + "thanks": { + "name": "symfony/ai", + "url": "https://github.com/symfony/ai" + } + }, + "minimum-stability": "dev" +} diff --git a/src/tools/doc/index.rst b/src/tools/doc/index.rst new file mode 100644 index 000000000..de47b2ea7 --- /dev/null +++ b/src/tools/doc/index.rst @@ -0,0 +1,125 @@ +Symfony AI - Tools +=================== + +The Tools component provides a collection of third-party tools for AI agents, including web search and knowledge retrieval capabilities. + +Installation +------------ + +Install the component using Composer: + +.. code-block:: terminal + + $ composer require symfony/ai-tools + +Available Tools +--------------- + +The Toolbox component includes ready-to-use tools that can be integrated with AI agents: + +Brave Search Tool +~~~~~~~~~~~~~~~~~ + +Provides web search functionality using the Brave Search API:: + + use Symfony\AI\Tools\Brave; + use Symfony\Component\HttpClient\HttpClient; + + $httpClient = HttpClient::create(); + $brave = new Brave($httpClient, 'your-brave-api-key'); + + // Search the web + $results = $brave('latest news about Symfony'); + +The Brave tool returns an array of search results with title, description, and URL for each result. + +**Configuration Options** + +You can pass additional options to customize the search behavior:: + + $brave = new Brave($httpClient, $apiKey, [ + 'country' => 'US', + 'safesearch' => 'moderate', + 'freshness' => 'pw', // Past week + ]); + +See the `Brave Search API documentation`_ for all available options. + +Wikipedia Tool +~~~~~~~~~~~~~~ + +Provides search and article retrieval from Wikipedia:: + + use Symfony\AI\Tools\Wikipedia; + use Symfony\Component\HttpClient\HttpClient; + + $httpClient = HttpClient::create(); + $wikipedia = new Wikipedia($httpClient); + + // Search for articles + $searchResults = $wikipedia->search('artificial intelligence'); + + // Get article content + $article = $wikipedia->article('Artificial intelligence'); + +The Wikipedia tool supports multiple languages by passing a locale parameter:: + + $wikipedia = new Wikipedia($httpClient, 'de'); // German Wikipedia + +**Tool Methods** + +The Wikipedia tool provides two methods that can be used as separate tools: + +* ``search``: Search for articles by query +* ``article``: Retrieve full article content by title + +Agent Integration +----------------- + +These tools are designed to work with the `Agent Component`_ and can be registered using the ``#[AsTool]`` attribute:: + + use Symfony\AI\Agent\Agent; + use Symfony\AI\Agent\Toolbox\AgentProcessor; + use Symfony\AI\Agent\Toolbox\Toolbox; + use Symfony\AI\Tools\Brave; + use Symfony\AI\Tools\Wikipedia; + + // Initialize HTTP client and tools + $httpClient = HttpClient::create(); + $brave = new Brave($httpClient, $braveApiKey); + $wikipedia = new Wikipedia($httpClient); + + // Create toolbox and processor + $toolbox = new Toolbox([$brave, $wikipedia]); + $processor = new AgentProcessor($toolbox); + + // Create agent with tools + $agent = new Agent($platform, $model, [$processor], [$processor]); + +Tool Configuration +------------------ + +Each tool is automatically configured with the ``#[AsTool]`` attribute: + +* **Brave Search**: Registered as ``brave_search`` tool +* **Wikipedia Search**: Registered as ``wikipedia_search`` tool +* **Wikipedia Article**: Registered as ``wikipedia_article`` tool + +Requirements +------------ + +* PHP 8.2 or higher +* Symfony HTTP Client component +* Brave Search API key (for Brave tool only) + +The Wikipedia tool requires no API key as it uses the public Wikipedia API. + +**Code Examples** + +* `Brave Search Example`_ +* `Wikipedia Search Example`_ + +.. _`Brave Search API documentation`: https://api-dashboard.search.brave.com/app/documentation/web-search/query +.. _`Agent Component`: https://github.com/symfony/ai-agent +.. _`Brave Search Example`: https://github.com/symfony/ai/blob/main/examples/toolbox/brave.php +.. _`Wikipedia Search Example`: https://github.com/symfony/ai/blob/main/examples/toolbox/wikipedia.php \ No newline at end of file diff --git a/src/tools/phpstan.dist.neon b/src/tools/phpstan.dist.neon new file mode 100644 index 000000000..087b39901 --- /dev/null +++ b/src/tools/phpstan.dist.neon @@ -0,0 +1,15 @@ +includes: + - ../../.phpstan/extension.neon + +parameters: + level: 6 + paths: + - src/ + - tests/ + treatPhpDocTypesAsCertain: false + ignoreErrors: + - + message: "#^Method .*::test.*\\(\\) has no return type specified\\.$#" + - + identifier: missingType.iterableValue + path: tests/* diff --git a/src/tools/phpunit.xml.dist b/src/tools/phpunit.xml.dist new file mode 100644 index 000000000..2563d38d6 --- /dev/null +++ b/src/tools/phpunit.xml.dist @@ -0,0 +1,24 @@ + + + + + tests + + + + + + src + + + diff --git a/src/agent/src/Toolbox/Tool/Brave.php b/src/tools/src/Brave.php similarity index 98% rename from src/agent/src/Toolbox/Tool/Brave.php rename to src/tools/src/Brave.php index f0c01d1e0..91af658d9 100644 --- a/src/agent/src/Toolbox/Tool/Brave.php +++ b/src/tools/src/Brave.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Agent\Toolbox\Tool; +namespace Symfony\AI\Tools; use Symfony\AI\Agent\Toolbox\Attribute\AsTool; use Symfony\AI\Platform\Contract\JsonSchema\Attribute\With; diff --git a/src/agent/src/Toolbox/Tool/Firecrawl.php b/src/tools/src/Firecrawl.php similarity index 98% rename from src/agent/src/Toolbox/Tool/Firecrawl.php rename to src/tools/src/Firecrawl.php index ec5f2570c..8b22906d6 100644 --- a/src/agent/src/Toolbox/Tool/Firecrawl.php +++ b/src/tools/src/Firecrawl.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Agent\Toolbox\Tool; +namespace Symfony\AI\Tools; use Symfony\AI\Agent\Toolbox\Attribute\AsTool; use Symfony\Contracts\HttpClient\HttpClientInterface; diff --git a/src/agent/src/Toolbox/Tool/Mapbox.php b/src/tools/src/Mapbox.php similarity index 99% rename from src/agent/src/Toolbox/Tool/Mapbox.php rename to src/tools/src/Mapbox.php index 8caefd85c..0cf69ac4c 100644 --- a/src/agent/src/Toolbox/Tool/Mapbox.php +++ b/src/tools/src/Mapbox.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Agent\Toolbox\Tool; +namespace Symfony\AI\Tools; use Symfony\AI\Agent\Toolbox\Attribute\AsTool; use Symfony\AI\Platform\Contract\JsonSchema\Attribute\With; diff --git a/src/agent/src/Toolbox/Tool/OpenMeteo.php b/src/tools/src/OpenMeteo.php similarity index 99% rename from src/agent/src/Toolbox/Tool/OpenMeteo.php rename to src/tools/src/OpenMeteo.php index 6283614a9..a67ff2d67 100644 --- a/src/agent/src/Toolbox/Tool/OpenMeteo.php +++ b/src/tools/src/OpenMeteo.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Agent\Toolbox\Tool; +namespace Symfony\AI\Tools; use Symfony\AI\Agent\Toolbox\Attribute\AsTool; use Symfony\AI\Platform\Contract\JsonSchema\Attribute\With; diff --git a/src/agent/src/Toolbox/Tool/SerpApi.php b/src/tools/src/SerpApi.php similarity index 97% rename from src/agent/src/Toolbox/Tool/SerpApi.php rename to src/tools/src/SerpApi.php index aa04e4424..191b2dd81 100644 --- a/src/agent/src/Toolbox/Tool/SerpApi.php +++ b/src/tools/src/SerpApi.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Agent\Toolbox\Tool; +namespace Symfony\AI\Tools; use Symfony\AI\Agent\Toolbox\Attribute\AsTool; use Symfony\Contracts\HttpClient\HttpClientInterface; diff --git a/src/agent/src/Toolbox/Tool/Tavily.php b/src/tools/src/Tavily.php similarity index 97% rename from src/agent/src/Toolbox/Tool/Tavily.php rename to src/tools/src/Tavily.php index 36405b42e..d26974763 100644 --- a/src/agent/src/Toolbox/Tool/Tavily.php +++ b/src/tools/src/Tavily.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Agent\Toolbox\Tool; +namespace Symfony\AI\Tools; use Symfony\AI\Agent\Toolbox\Attribute\AsTool; use Symfony\Contracts\HttpClient\HttpClientInterface; diff --git a/src/agent/src/Toolbox/Tool/Wikipedia.php b/src/tools/src/Wikipedia.php similarity index 98% rename from src/agent/src/Toolbox/Tool/Wikipedia.php rename to src/tools/src/Wikipedia.php index 8cf85e4a7..791623fa5 100644 --- a/src/agent/src/Toolbox/Tool/Wikipedia.php +++ b/src/tools/src/Wikipedia.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Agent\Toolbox\Tool; +namespace Symfony\AI\Tools; use Symfony\AI\Agent\Toolbox\Attribute\AsTool; use Symfony\Contracts\HttpClient\HttpClientInterface; diff --git a/src/agent/src/Toolbox/Tool/YouTubeTranscriber.php b/src/tools/src/YouTubeTranscriber.php similarity index 97% rename from src/agent/src/Toolbox/Tool/YouTubeTranscriber.php rename to src/tools/src/YouTubeTranscriber.php index be81d1096..7ee308b59 100644 --- a/src/agent/src/Toolbox/Tool/YouTubeTranscriber.php +++ b/src/tools/src/YouTubeTranscriber.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Agent\Toolbox\Tool; +namespace Symfony\AI\Tools; use MrMySQL\YoutubeTranscript\TranscriptListFetcher; use Symfony\AI\Agent\Exception\LogicException; diff --git a/src/agent/tests/Toolbox/Tool/BraveTest.php b/src/tools/tests/BraveTest.php similarity index 90% rename from src/agent/tests/Toolbox/Tool/BraveTest.php rename to src/tools/tests/BraveTest.php index d84444503..31c62d7e9 100644 --- a/src/agent/tests/Toolbox/Tool/BraveTest.php +++ b/src/tools/tests/BraveTest.php @@ -9,11 +9,11 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Agent\Tests\Toolbox\Tool; +namespace Symfony\AI\Tools\Tests; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\AI\Agent\Toolbox\Tool\Brave; +use Symfony\AI\Tools\Brave; use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpClient\Response\JsonMockResponse; use Symfony\Component\HttpClient\Response\MockResponse; @@ -23,7 +23,7 @@ final class BraveTest extends TestCase { public function testReturnsSearchResults() { - $result = JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/brave.json'); + $result = JsonMockResponse::fromFile(__DIR__.'/fixtures/brave.json'); $httpClient = new MockHttpClient($result); $brave = new Brave($httpClient, 'test-api-key'); @@ -40,7 +40,7 @@ public function testReturnsSearchResults() public function testPassesCorrectParametersToApi() { - $result = JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/brave.json'); + $result = JsonMockResponse::fromFile(__DIR__.'/fixtures/brave.json'); $httpClient = new MockHttpClient($result); $brave = new Brave($httpClient, 'test-api-key', ['extra' => 'option']); diff --git a/src/agent/tests/Toolbox/Tool/FirecrawlTest.php b/src/tools/tests/FirecrawlTest.php similarity index 75% rename from src/agent/tests/Toolbox/Tool/FirecrawlTest.php rename to src/tools/tests/FirecrawlTest.php index 90ae79838..14c9ff026 100644 --- a/src/agent/tests/Toolbox/Tool/FirecrawlTest.php +++ b/src/tools/tests/FirecrawlTest.php @@ -9,11 +9,11 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Agent\Tests\Toolbox\Tool; +namespace Symfony\AI\Tools\Tests; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\AI\Agent\Toolbox\Tool\Firecrawl; +use Symfony\AI\Tools\Firecrawl; use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpClient\Response\JsonMockResponse; @@ -23,7 +23,7 @@ final class FirecrawlTest extends TestCase public function testScrape() { $httpClient = new MockHttpClient([ - JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/firecrawl-scrape.json'), + JsonMockResponse::fromFile(__DIR__.'/fixtures/firecrawl-scrape.json'), ]); $firecrawl = new Firecrawl($httpClient, 'test', 'https://127.0.0.1:3002'); @@ -39,10 +39,10 @@ public function testScrape() public function testCrawl() { $httpClient = new MockHttpClient([ - JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/firecrawl-crawl-wait.json'), - JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/firecrawl-crawl-status.json'), - JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/firecrawl-crawl-status-done.json'), - JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/firecrawl-crawl.json'), + JsonMockResponse::fromFile(__DIR__.'/fixtures/firecrawl-crawl-wait.json'), + JsonMockResponse::fromFile(__DIR__.'/fixtures/firecrawl-crawl-status.json'), + JsonMockResponse::fromFile(__DIR__.'/fixtures/firecrawl-crawl-status-done.json'), + JsonMockResponse::fromFile(__DIR__.'/fixtures/firecrawl-crawl.json'), ]); $firecrawl = new Firecrawl($httpClient, 'test', 'https://127.0.0.1:3002'); @@ -62,7 +62,7 @@ public function testCrawl() public function testMap() { $httpClient = new MockHttpClient([ - JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/firecrawl-map.json'), + JsonMockResponse::fromFile(__DIR__.'/fixtures/firecrawl-map.json'), ]); $firecrawl = new Firecrawl($httpClient, 'test', 'https://127.0.0.1:3002'); diff --git a/src/agent/tests/Toolbox/Tool/MapboxTest.php b/src/tools/tests/MapboxTest.php similarity index 87% rename from src/agent/tests/Toolbox/Tool/MapboxTest.php rename to src/tools/tests/MapboxTest.php index 4a6093cbe..b6f33a619 100644 --- a/src/agent/tests/Toolbox/Tool/MapboxTest.php +++ b/src/tools/tests/MapboxTest.php @@ -9,11 +9,11 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Agent\Tests\Toolbox\Tool; +namespace Symfony\AI\Tools\Tests; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\AI\Agent\Toolbox\Tool\Mapbox; +use Symfony\AI\Tools\Mapbox; use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpClient\Response\JsonMockResponse; @@ -22,7 +22,7 @@ final class MapboxTest extends TestCase { public function testGeocodeWithSingleResult() { - $result = JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/mapbox-geocode-single.json'); + $result = JsonMockResponse::fromFile(__DIR__.'/fixtures/mapbox-geocode-single.json'); $httpClient = new MockHttpClient($result); $mapbox = new Mapbox($httpClient, 'test_token'); @@ -48,7 +48,7 @@ public function testGeocodeWithSingleResult() public function testGeocodeWithMultipleResults() { - $result = JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/mapbox-geocode-multiple.json'); + $result = JsonMockResponse::fromFile(__DIR__.'/fixtures/mapbox-geocode-multiple.json'); $httpClient = new MockHttpClient($result); $mapbox = new Mapbox($httpClient, 'test_token'); @@ -83,7 +83,7 @@ public function testGeocodeWithMultipleResults() public function testGeocodeWithNoResults() { - $result = JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/mapbox-geocode-empty.json'); + $result = JsonMockResponse::fromFile(__DIR__.'/fixtures/mapbox-geocode-empty.json'); $httpClient = new MockHttpClient($result); $mapbox = new Mapbox($httpClient, 'test_token'); @@ -99,7 +99,7 @@ public function testGeocodeWithNoResults() public function testReverseGeocodeWithValidCoordinates() { - $result = JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/mapbox-reverse-geocode.json'); + $result = JsonMockResponse::fromFile(__DIR__.'/fixtures/mapbox-reverse-geocode.json'); $httpClient = new MockHttpClient($result); $mapbox = new Mapbox($httpClient, 'test_token'); @@ -141,7 +141,7 @@ public function testReverseGeocodeWithValidCoordinates() public function testReverseGeocodeWithNoResults() { - $result = JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/mapbox-reverse-geocode-empty.json'); + $result = JsonMockResponse::fromFile(__DIR__.'/fixtures/mapbox-reverse-geocode-empty.json'); $httpClient = new MockHttpClient($result); $mapbox = new Mapbox($httpClient, 'test_token'); diff --git a/src/agent/tests/Toolbox/Tool/OpenMeteoTest.php b/src/tools/tests/OpenMeteoTest.php similarity index 86% rename from src/agent/tests/Toolbox/Tool/OpenMeteoTest.php rename to src/tools/tests/OpenMeteoTest.php index 364ad55e8..ff30d90ce 100644 --- a/src/agent/tests/Toolbox/Tool/OpenMeteoTest.php +++ b/src/tools/tests/OpenMeteoTest.php @@ -9,11 +9,11 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Agent\Tests\Toolbox\Tool; +namespace Symfony\AI\Tools\Tests; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\AI\Agent\Toolbox\Tool\OpenMeteo; +use Symfony\AI\Tools\OpenMeteo; use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpClient\Response\JsonMockResponse; @@ -22,7 +22,7 @@ final class OpenMeteoTest extends TestCase { public function testCurrent() { - $result = JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/openmeteo-current.json'); + $result = JsonMockResponse::fromFile(__DIR__.'/fixtures/openmeteo-current.json'); $httpClient = new MockHttpClient($result); $openMeteo = new OpenMeteo($httpClient); @@ -40,7 +40,7 @@ public function testCurrent() public function testForecast() { - $result = JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/openmeteo-forecast.json'); + $result = JsonMockResponse::fromFile(__DIR__.'/fixtures/openmeteo-forecast.json'); $httpClient = new MockHttpClient($result); $openMeteo = new OpenMeteo($httpClient); diff --git a/src/agent/tests/Toolbox/Tool/WikipediaTest.php b/src/tools/tests/WikipediaTest.php similarity index 85% rename from src/agent/tests/Toolbox/Tool/WikipediaTest.php rename to src/tools/tests/WikipediaTest.php index 9bc20c311..e506814be 100644 --- a/src/agent/tests/Toolbox/Tool/WikipediaTest.php +++ b/src/tools/tests/WikipediaTest.php @@ -9,11 +9,11 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Agent\Tests\Toolbox\Tool; +namespace Symfony\AI\Tools\Tests; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Symfony\AI\Agent\Toolbox\Tool\Wikipedia; +use Symfony\AI\Tools\Wikipedia; use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpClient\Response\JsonMockResponse; @@ -22,7 +22,7 @@ final class WikipediaTest extends TestCase { public function testSearchWithResults() { - $result = JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/wikipedia-search-result.json'); + $result = JsonMockResponse::fromFile(__DIR__.'/fixtures/wikipedia-search-result.json'); $httpClient = new MockHttpClient($result); $wikipedia = new Wikipedia($httpClient); @@ -49,7 +49,7 @@ public function testSearchWithResults() public function testSearchWithoutResults() { - $result = JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/wikipedia-search-empty.json'); + $result = JsonMockResponse::fromFile(__DIR__.'/fixtures/wikipedia-search-empty.json'); $httpClient = new MockHttpClient($result); $wikipedia = new Wikipedia($httpClient); @@ -62,7 +62,7 @@ public function testSearchWithoutResults() public function testArticleWithResult() { - $result = JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/wikipedia-article.json'); + $result = JsonMockResponse::fromFile(__DIR__.'/fixtures/wikipedia-article.json'); $httpClient = new MockHttpClient($result); $wikipedia = new Wikipedia($httpClient); @@ -78,7 +78,7 @@ public function testArticleWithResult() public function testArticleWithRedirect() { - $result = JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/wikipedia-article-redirect.json'); + $result = JsonMockResponse::fromFile(__DIR__.'/fixtures/wikipedia-article-redirect.json'); $httpClient = new MockHttpClient($result); $wikipedia = new Wikipedia($httpClient); @@ -96,7 +96,7 @@ public function testArticleWithRedirect() public function testArticleMissing() { - $result = JsonMockResponse::fromFile(__DIR__.'/../../fixtures/Tool/wikipedia-article-missing.json'); + $result = JsonMockResponse::fromFile(__DIR__.'/fixtures/wikipedia-article-missing.json'); $httpClient = new MockHttpClient($result); $wikipedia = new Wikipedia($httpClient); diff --git a/src/agent/tests/fixtures/Tool/brave.json b/src/tools/tests/fixtures/brave.json similarity index 100% rename from src/agent/tests/fixtures/Tool/brave.json rename to src/tools/tests/fixtures/brave.json diff --git a/src/agent/tests/fixtures/Tool/firecrawl-crawl-status-done.json b/src/tools/tests/fixtures/firecrawl-crawl-status-done.json similarity index 100% rename from src/agent/tests/fixtures/Tool/firecrawl-crawl-status-done.json rename to src/tools/tests/fixtures/firecrawl-crawl-status-done.json diff --git a/src/agent/tests/fixtures/Tool/firecrawl-crawl-status.json b/src/tools/tests/fixtures/firecrawl-crawl-status.json similarity index 100% rename from src/agent/tests/fixtures/Tool/firecrawl-crawl-status.json rename to src/tools/tests/fixtures/firecrawl-crawl-status.json diff --git a/src/agent/tests/fixtures/Tool/firecrawl-crawl-wait.json b/src/tools/tests/fixtures/firecrawl-crawl-wait.json similarity index 100% rename from src/agent/tests/fixtures/Tool/firecrawl-crawl-wait.json rename to src/tools/tests/fixtures/firecrawl-crawl-wait.json diff --git a/src/agent/tests/fixtures/Tool/firecrawl-crawl.json b/src/tools/tests/fixtures/firecrawl-crawl.json similarity index 100% rename from src/agent/tests/fixtures/Tool/firecrawl-crawl.json rename to src/tools/tests/fixtures/firecrawl-crawl.json diff --git a/src/agent/tests/fixtures/Tool/firecrawl-map.json b/src/tools/tests/fixtures/firecrawl-map.json similarity index 100% rename from src/agent/tests/fixtures/Tool/firecrawl-map.json rename to src/tools/tests/fixtures/firecrawl-map.json diff --git a/src/agent/tests/fixtures/Tool/firecrawl-scrape.json b/src/tools/tests/fixtures/firecrawl-scrape.json similarity index 100% rename from src/agent/tests/fixtures/Tool/firecrawl-scrape.json rename to src/tools/tests/fixtures/firecrawl-scrape.json diff --git a/src/agent/tests/fixtures/Tool/mapbox-geocode-empty.json b/src/tools/tests/fixtures/mapbox-geocode-empty.json similarity index 100% rename from src/agent/tests/fixtures/Tool/mapbox-geocode-empty.json rename to src/tools/tests/fixtures/mapbox-geocode-empty.json diff --git a/src/agent/tests/fixtures/Tool/mapbox-geocode-multiple.json b/src/tools/tests/fixtures/mapbox-geocode-multiple.json similarity index 100% rename from src/agent/tests/fixtures/Tool/mapbox-geocode-multiple.json rename to src/tools/tests/fixtures/mapbox-geocode-multiple.json diff --git a/src/agent/tests/fixtures/Tool/mapbox-geocode-single.json b/src/tools/tests/fixtures/mapbox-geocode-single.json similarity index 100% rename from src/agent/tests/fixtures/Tool/mapbox-geocode-single.json rename to src/tools/tests/fixtures/mapbox-geocode-single.json diff --git a/src/agent/tests/fixtures/Tool/mapbox-reverse-geocode-empty.json b/src/tools/tests/fixtures/mapbox-reverse-geocode-empty.json similarity index 100% rename from src/agent/tests/fixtures/Tool/mapbox-reverse-geocode-empty.json rename to src/tools/tests/fixtures/mapbox-reverse-geocode-empty.json diff --git a/src/agent/tests/fixtures/Tool/mapbox-reverse-geocode.json b/src/tools/tests/fixtures/mapbox-reverse-geocode.json similarity index 100% rename from src/agent/tests/fixtures/Tool/mapbox-reverse-geocode.json rename to src/tools/tests/fixtures/mapbox-reverse-geocode.json diff --git a/src/agent/tests/fixtures/Tool/openmeteo-current.json b/src/tools/tests/fixtures/openmeteo-current.json similarity index 100% rename from src/agent/tests/fixtures/Tool/openmeteo-current.json rename to src/tools/tests/fixtures/openmeteo-current.json diff --git a/src/agent/tests/fixtures/Tool/openmeteo-forecast.json b/src/tools/tests/fixtures/openmeteo-forecast.json similarity index 100% rename from src/agent/tests/fixtures/Tool/openmeteo-forecast.json rename to src/tools/tests/fixtures/openmeteo-forecast.json diff --git a/src/agent/tests/fixtures/Tool/wikipedia-article-missing.json b/src/tools/tests/fixtures/wikipedia-article-missing.json similarity index 100% rename from src/agent/tests/fixtures/Tool/wikipedia-article-missing.json rename to src/tools/tests/fixtures/wikipedia-article-missing.json diff --git a/src/agent/tests/fixtures/Tool/wikipedia-article-redirect.json b/src/tools/tests/fixtures/wikipedia-article-redirect.json similarity index 100% rename from src/agent/tests/fixtures/Tool/wikipedia-article-redirect.json rename to src/tools/tests/fixtures/wikipedia-article-redirect.json diff --git a/src/agent/tests/fixtures/Tool/wikipedia-article.json b/src/tools/tests/fixtures/wikipedia-article.json similarity index 100% rename from src/agent/tests/fixtures/Tool/wikipedia-article.json rename to src/tools/tests/fixtures/wikipedia-article.json diff --git a/src/agent/tests/fixtures/Tool/wikipedia-search-empty.json b/src/tools/tests/fixtures/wikipedia-search-empty.json similarity index 100% rename from src/agent/tests/fixtures/Tool/wikipedia-search-empty.json rename to src/tools/tests/fixtures/wikipedia-search-empty.json diff --git a/src/agent/tests/fixtures/Tool/wikipedia-search-result.json b/src/tools/tests/fixtures/wikipedia-search-result.json similarity index 100% rename from src/agent/tests/fixtures/Tool/wikipedia-search-result.json rename to src/tools/tests/fixtures/wikipedia-search-result.json