diff --git a/examples/browser_summarizer/pubspec.lock b/examples/browser_summarizer/pubspec.lock index 17d43f80..c32f085f 100644 --- a/examples/browser_summarizer/pubspec.lock +++ b/examples/browser_summarizer/pubspec.lock @@ -491,6 +491,13 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + tavily_dart: + dependency: "direct overridden" + description: + path: "../../packages/tavily_dart" + relative: true + source: path + version: "0.0.1-dev.1" term_glyph: dependency: transitive description: diff --git a/examples/browser_summarizer/pubspec_overrides.yaml b/examples/browser_summarizer/pubspec_overrides.yaml index 3947b2ae..49be75a7 100644 --- a/examples/browser_summarizer/pubspec_overrides.yaml +++ b/examples/browser_summarizer/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: langchain,langchain_openai,openai_dart,langchain_core,langchain_community +# melos_managed_dependency_overrides: langchain,langchain_openai,openai_dart,langchain_core,langchain_community,tavily_dart dependency_overrides: langchain: path: ../../packages/langchain @@ -10,3 +10,5 @@ dependency_overrides: path: ../../packages/langchain_openai openai_dart: path: ../../packages/openai_dart + tavily_dart: + path: ../../packages/tavily_dart diff --git a/examples/docs_examples/pubspec.lock b/examples/docs_examples/pubspec.lock index 55f94891..650cd5be 100644 --- a/examples/docs_examples/pubspec.lock +++ b/examples/docs_examples/pubspec.lock @@ -148,10 +148,10 @@ packages: dependency: transitive description: name: google_generative_ai - sha256: bb7d3480b05afb3b1f2459b52893cb22f69ded4e2fb853e212437123c457f1be + sha256: "76e35d93b8c1cd888f69a1a371f8c5dc54cec372b6c74a4c0a5d506e7cf82c1a" url: "https://pub.dev" source: hosted - version: "0.4.0" + version: "0.4.3" google_identity_services_web: dependency: transitive description: @@ -413,6 +413,13 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + tavily_dart: + dependency: "direct overridden" + description: + path: "../../packages/tavily_dart" + relative: true + source: path + version: "0.0.1-dev.1" term_glyph: dependency: transitive description: diff --git a/examples/docs_examples/pubspec_overrides.yaml b/examples/docs_examples/pubspec_overrides.yaml index e02da308..cc3f10d6 100644 --- a/examples/docs_examples/pubspec_overrides.yaml +++ b/examples/docs_examples/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: chromadb,langchain,langchain_chroma,langchain_google,langchain_mistralai,langchain_ollama,langchain_openai,mistralai_dart,ollama_dart,openai_dart,vertex_ai,langchain_core,langchain_community +# melos_managed_dependency_overrides: chromadb,langchain,langchain_chroma,langchain_google,langchain_mistralai,langchain_ollama,langchain_openai,mistralai_dart,ollama_dart,openai_dart,vertex_ai,langchain_core,langchain_community,tavily_dart dependency_overrides: chromadb: path: ../../packages/chromadb @@ -24,5 +24,7 @@ dependency_overrides: path: ../../packages/ollama_dart openai_dart: path: ../../packages/openai_dart + tavily_dart: + path: ../../packages/tavily_dart vertex_ai: path: ../../packages/vertex_ai diff --git a/examples/hello_world_flutter/pubspec.lock b/examples/hello_world_flutter/pubspec.lock index d9c9c29f..9bbfa0f2 100644 --- a/examples/hello_world_flutter/pubspec.lock +++ b/examples/hello_world_flutter/pubspec.lock @@ -138,10 +138,10 @@ packages: dependency: transitive description: name: google_generative_ai - sha256: bb7d3480b05afb3b1f2459b52893cb22f69ded4e2fb853e212437123c457f1be + sha256: "76e35d93b8c1cd888f69a1a371f8c5dc54cec372b6c74a4c0a5d506e7cf82c1a" url: "https://pub.dev" source: hosted - version: "0.4.0" + version: "0.4.3" google_identity_services_web: dependency: transitive description: diff --git a/examples/wikivoyage_eu/pubspec.lock b/examples/wikivoyage_eu/pubspec.lock index 49dc9df4..18f2890b 100644 --- a/examples/wikivoyage_eu/pubspec.lock +++ b/examples/wikivoyage_eu/pubspec.lock @@ -292,6 +292,13 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + tavily_dart: + dependency: "direct overridden" + description: + path: "../../packages/tavily_dart" + relative: true + source: path + version: "0.0.1-dev.1" term_glyph: dependency: transitive description: diff --git a/examples/wikivoyage_eu/pubspec_overrides.yaml b/examples/wikivoyage_eu/pubspec_overrides.yaml index 075ddc4f..6f7e46d1 100644 --- a/examples/wikivoyage_eu/pubspec_overrides.yaml +++ b/examples/wikivoyage_eu/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: langchain,langchain_core,langchain_community,langchain_ollama,ollama_dart +# melos_managed_dependency_overrides: langchain,langchain_core,langchain_community,langchain_ollama,ollama_dart,tavily_dart dependency_overrides: langchain: path: ../../packages/langchain @@ -10,3 +10,5 @@ dependency_overrides: path: ../../packages/langchain_ollama ollama_dart: path: ../../packages/ollama_dart + tavily_dart: + path: ../../packages/tavily_dart diff --git a/packages/langchain/README.md b/packages/langchain/README.md index b86c0eae..83608f5a 100644 --- a/packages/langchain/README.md +++ b/packages/langchain/README.md @@ -68,25 +68,25 @@ Popular third-party integrations (e.g. [`langchain_openai`](https://pub.dev/pack

-| Package | Version | Description | -|---------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [langchain_core](https://pub.dev/packages/langchain_core) | [![langchain_core](https://img.shields.io/pub/v/langchain_core.svg)](https://pub.dev/packages/langchain_core) | Core abstractions and LCEL | -| [langchain](https://pub.dev/packages/langchain) | [![langchain](https://img.shields.io/pub/v/langchain.svg)](https://pub.dev/packages/langchain) | Higher-level and use-case specific chains, agents, and retrieval algorithms | -| [langchain_community](https://pub.dev/packages/langchain_community) | [![langchain_community](https://img.shields.io/pub/v/langchain_community.svg)](https://pub.dev/packages/langchain_community) | Third-party integrations (without specific packages) and community-contributed components | -| [langchain_openai](https://pub.dev/packages/langchain_openai) | [![langchain_openai](https://img.shields.io/pub/v/langchain_openai.svg)](https://pub.dev/packages/langchain_openai) | OpenAI integration (GPT-3.5 Turbo, GPT-4, GPT-4 Turbo, Embeddings, Tools, Vision, DALL·E 3, etc.) and OpenAI Compatible services (TogetherAI, Anyscale, OpenRouter, One API, Groq, Llamafile, GPT4All, etc.) | -| [langchain_google](https://pub.dev/packages/langchain_google) | [![langchain_google](https://img.shields.io/pub/v/langchain_google.svg)](https://pub.dev/packages/langchain_google) | Google integration (GoogleAI, VertexAI, Gemini, PaLM 2, Embeddings, Vector Search, etc.) | -| [langchain_firebase](https://pub.dev/packages/langchain_firebase) | [![langchain_firebase](https://img.shields.io/pub/v/langchain_firebase.svg)](https://pub.dev/packages/langchain_firebase) | Firebase integration (VertexAI for Firebase (Gemini 1.5 Pro, Gemini 1.5 Flash, etc.)) | -| [langchain_ollama](https://pub.dev/packages/langchain_ollama) | [![langchain_ollama](https://img.shields.io/pub/v/langchain_ollama.svg)](https://pub.dev/packages/langchain_ollama) | Ollama integration (Llama 3, Phi-3, WizardLM-2, Mistral 7B, Gemma, CodeGemma, Command R, LLaVA, DBRX, Qwen 1.5, Dolphin, DeepSeek Coder, Vicuna, Orca, etc.) | -| [langchain_mistralai](https://pub.dev/packages/langchain_mistralai) | [![langchain_mistralai](https://img.shields.io/pub/v/langchain_mistralai.svg)](https://pub.dev/packages/langchain_mistralai) | Mistral AI integration (Mistral-7B, Mixtral 8x7B, Mixtral 8x22B, Mistral Small, Mistral Large, embeddings, etc.). | -| [langchain_pinecone](https://pub.dev/packages/langchain_pinecone) | [![langchain_pinecone](https://img.shields.io/pub/v/langchain_pinecone.svg)](https://pub.dev/packages/langchain_pinecone) | Pinecone vector database integration | -| [langchain_chroma](https://pub.dev/packages/langchain_chroma) | [![langchain_chroma](https://img.shields.io/pub/v/langchain_chroma.svg)](https://pub.dev/packages/langchain_chroma) | Chroma vector database integration | -| [langchain_supabase](https://pub.dev/packages/langchain_supabase) | [![langchain_supabase](https://img.shields.io/pub/v/langchain_supabase.svg)](https://pub.dev/packages/langchain_supabase) | Supabase Vector database integration | +| Package | Version | Description | +|---------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [langchain_core](https://pub.dev/packages/langchain_core) | [![langchain_core](https://img.shields.io/pub/v/langchain_core.svg)](https://pub.dev/packages/langchain_core) | Core abstractions and LCEL | +| [langchain](https://pub.dev/packages/langchain) | [![langchain](https://img.shields.io/pub/v/langchain.svg)](https://pub.dev/packages/langchain) | Higher-level and use-case specific chains, agents, and retrieval algorithms | +| [langchain_community](https://pub.dev/packages/langchain_community) | [![langchain_community](https://img.shields.io/pub/v/langchain_community.svg)](https://pub.dev/packages/langchain_community) | Third-party integrations (without specific packages) and community-contributed components and utilities | +| [langchain_openai](https://pub.dev/packages/langchain_openai) | [![langchain_openai](https://img.shields.io/pub/v/langchain_openai.svg)](https://pub.dev/packages/langchain_openai) | OpenAI integration (GPT-3.5 Turbo, GPT-4, GPT-4o, Embeddings, Tools, Vision, DALL·E 3, etc.) and OpenAI Compatible services (TogetherAI, Anyscale, OpenRouter, One API, Groq, Llamafile, GPT4All, etc.) | +| [langchain_google](https://pub.dev/packages/langchain_google) | [![langchain_google](https://img.shields.io/pub/v/langchain_google.svg)](https://pub.dev/packages/langchain_google) | Google integration (GoogleAI, VertexAI, Gemini, PaLM 2, Embeddings, Vector Search, etc.) | +| [langchain_firebase](https://pub.dev/packages/langchain_firebase) | [![langchain_firebase](https://img.shields.io/pub/v/langchain_firebase.svg)](https://pub.dev/packages/langchain_firebase) | Firebase integration (VertexAI for Firebase (Gemini 1.5 Pro, Gemini 1.5 Flash, etc.)) | +| [langchain_ollama](https://pub.dev/packages/langchain_ollama) | [![langchain_ollama](https://img.shields.io/pub/v/langchain_ollama.svg)](https://pub.dev/packages/langchain_ollama) | Ollama integration (Llama 3, Phi-3, WizardLM-2, Mistral 7B, Gemma, CodeGemma, Command R, LLaVA, DBRX, Qwen 1.5, Dolphin, DeepSeek Coder, Vicuna, Orca, etc.) | +| [langchain_mistralai](https://pub.dev/packages/langchain_mistralai) | [![langchain_mistralai](https://img.shields.io/pub/v/langchain_mistralai.svg)](https://pub.dev/packages/langchain_mistralai) | Mistral AI integration (Mistral-7B, Mixtral 8x7B, Mixtral 8x22B, Mistral Small, Mistral Large, embeddings, etc.). | +| [langchain_pinecone](https://pub.dev/packages/langchain_pinecone) | [![langchain_pinecone](https://img.shields.io/pub/v/langchain_pinecone.svg)](https://pub.dev/packages/langchain_pinecone) | Pinecone vector database integration | +| [langchain_chroma](https://pub.dev/packages/langchain_chroma) | [![langchain_chroma](https://img.shields.io/pub/v/langchain_chroma.svg)](https://pub.dev/packages/langchain_chroma) | Chroma vector database integration | +| [langchain_supabase](https://pub.dev/packages/langchain_supabase) | [![langchain_supabase](https://img.shields.io/pub/v/langchain_supabase.svg)](https://pub.dev/packages/langchain_supabase) | Supabase Vector database integration | Functionality provided by each integration package: | Package | LLMs | Chat models | Embeddings | Vector stores | Chains | Agents | Tools | |---------------------------------------------------------------------|------|-------------|------------|---------------|--------|--------|-------| -| [langchain_community](https://pub.dev/packages/langchain_community) | | | | | | | | +| [langchain_community](https://pub.dev/packages/langchain_community) | | | | ✔ | | | ✔ | | [langchain_openai](https://pub.dev/packages/langchain_openai) | ✔ | ✔ | ✔ | | ✔ | ✔ | ✔ | | [langchain_google](https://pub.dev/packages/langchain_google) | ✔ | ✔ | ✔ | ✔ | | | | | [langchain_firebase](https://pub.dev/packages/langchain_firebase) | | ✔ | | | | | | @@ -98,15 +98,16 @@ Functionality provided by each integration package: The following packages are maintained (and used internally) by LangChain.dart, although they can also be used independently: -| Package | Version | Description | -|-------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|----------------------------------------------| -| [anthropic_sdk_dart](https://pub.dev/packages/anthropic_sdk_dart) | [![anthropic_sdk_dart](https://img.shields.io/pub/v/anthropic_sdk_dart.svg)](https://pub.dev/packages/anthropic_sdk_dart) | Anthropic (Claude API) client | -| [chromadb](https://pub.dev/packages/chromadb) | [![chromadb](https://img.shields.io/pub/v/chromadb.svg)](https://pub.dev/packages/chromadb) | Chroma DB API client | -| [googleai_dart](https://pub.dev/packages/googleai_dart) | [![googleai_dart](https://img.shields.io/pub/v/googleai_dart.svg)](https://pub.dev/packages/googleai_dart) | Google AI for Developers (Gemini API) client | -| [mistralai_dart](https://pub.dev/packages/mistralai_dart) | [![mistralai_dart](https://img.shields.io/pub/v/mistralai_dart.svg)](https://pub.dev/packages/mistralai_dart) | Mistral AI API client | -| [ollama_dart](https://pub.dev/packages/ollama_dart) | [![ollama_dart](https://img.shields.io/pub/v/ollama_dart.svg)](https://pub.dev/packages/ollama_dart) | Ollama API client | -| [openai_dart](https://pub.dev/packages/openai_dart) | [![openai_dart](https://img.shields.io/pub/v/openai_dart.svg)](https://pub.dev/packages/openai_dart) | OpenAI API client | -| [vertex_ai](https://pub.dev/packages/vertex_ai) | [![vertex_ai](https://img.shields.io/pub/v/vertex_ai.svg)](https://pub.dev/packages/vertex_ai) | GCP Vertex AI API client | +| Package | Version | Description | +|-------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------| +| [anthropic_sdk_dart](https://pub.dev/packages/anthropic_sdk_dart) | [![anthropic_sdk_dart](https://img.shields.io/pub/v/anthropic_sdk_dart.svg)](https://pub.dev/packages/anthropic_sdk_dart) | [Anthropic](https://docs.anthropic.com/en/api) API client | +| [chromadb](https://pub.dev/packages/chromadb) | [![chromadb](https://img.shields.io/pub/v/chromadb.svg)](https://pub.dev/packages/chromadb) | [Chroma DB](https://trychroma.com/) API client | +| [googleai_dart](https://pub.dev/packages/googleai_dart) | [![googleai_dart](https://img.shields.io/pub/v/googleai_dart.svg)](https://pub.dev/packages/googleai_dart) | [Google AI for Developers](https://ai.google.dev/) API client | +| [mistralai_dart](https://pub.dev/packages/mistralai_dart) | [![mistralai_dart](https://img.shields.io/pub/v/mistralai_dart.svg)](https://pub.dev/packages/mistralai_dart) | [Mistral AI](https://docs.mistral.ai/api) API client | +| [ollama_dart](https://pub.dev/packages/ollama_dart) | [![ollama_dart](https://img.shields.io/pub/v/ollama_dart.svg)](https://pub.dev/packages/ollama_dart) | [Ollama](https://ollama.ai/) API client | +| [openai_dart](https://pub.dev/packages/openai_dart) | [![openai_dart](https://img.shields.io/pub/v/openai_dart.svg)](https://pub.dev/packages/openai_dart) | [OpenAI](https://platform.openai.com/docs/api-reference) API client | +| [tavily_dart](https://pub.dev/packages/tavily_dart) | [![tavily_dart](https://img.shields.io/pub/v/tavily_dart.svg)](https://pub.dev/packages/tavily_dart) | [Tavily](https://tavily.com) API client | +| [vertex_ai](https://pub.dev/packages/vertex_ai) | [![vertex_ai](https://img.shields.io/pub/v/vertex_ai.svg)](https://pub.dev/packages/vertex_ai) | [GCP Vertex AI](https://cloud.google.com/vertex-ai) API client | ## Getting started diff --git a/packages/langchain_chroma/pubspec_overrides.yaml b/packages/langchain_chroma/pubspec_overrides.yaml index 4583d481..3470527c 100644 --- a/packages/langchain_chroma/pubspec_overrides.yaml +++ b/packages/langchain_chroma/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: chromadb,langchain_openai,openai_dart,langchain_core,langchain_community,langchain +# melos_managed_dependency_overrides: chromadb,langchain_openai,openai_dart,langchain_core,langchain_community,langchain,tavily_dart dependency_overrides: chromadb: path: ../chromadb @@ -12,3 +12,5 @@ dependency_overrides: path: ../langchain_openai openai_dart: path: ../openai_dart + tavily_dart: + path: ../tavily_dart diff --git a/packages/langchain_community/README.md b/packages/langchain_community/README.md index b76ee3c3..1dcb80e3 100644 --- a/packages/langchain_community/README.md +++ b/packages/langchain_community/README.md @@ -27,6 +27,10 @@ The most popular third-party integrations have their own packages (e.g. [langcha * `WebBaseLoader`: for web pages. - Tools: * `CalculatorTool`: to calculate math expressions. + * `TavilySearchResultsTool`: returns a list of results for a query using the [Tavily](https://tavily.com) search engine. + * `TavilyAnswerTool`: returns an answer for a query using the [Tavily](https://tavily.com) search engine. +- Vector stores: + * `ObjectBoxVectorStore`: [ObjectBox](https://objectbox.io/) on-device vector database. Check out the [API reference](https://pub.dev/documentation/langchain_community/latest) for more details. diff --git a/packages/langchain_community/lib/src/tools/tavily/mappers.dart b/packages/langchain_community/lib/src/tools/tavily/mappers.dart new file mode 100644 index 00000000..21e907e5 --- /dev/null +++ b/packages/langchain_community/lib/src/tools/tavily/mappers.dart @@ -0,0 +1,21 @@ +// ignore_for_file: public_member_api_docs +import 'package:tavily_dart/tavily_dart.dart'; + +import 'types.dart'; + +extension TavilySearchDepthX on TavilySearchDepth { + SearchRequestSearchDepth toSearchRequestSearchDepth() => switch (this) { + TavilySearchDepth.basic => SearchRequestSearchDepth.basic, + TavilySearchDepth.advanced => SearchRequestSearchDepth.advanced, + }; +} + +extension TavilySearchResultX on SearchResult { + TavilySearchResult toTavilySearchResult() => TavilySearchResult( + title: title, + url: url, + content: content, + rawContent: rawContent, + score: score, + ); +} diff --git a/packages/langchain_community/lib/src/tools/tavily/tavily.dart b/packages/langchain_community/lib/src/tools/tavily/tavily.dart new file mode 100644 index 00000000..64f26c5d --- /dev/null +++ b/packages/langchain_community/lib/src/tools/tavily/tavily.dart @@ -0,0 +1,3 @@ +export 'tavily_answer.dart'; +export 'tavily_search_results.dart'; +export 'types.dart'; diff --git a/packages/langchain_community/lib/src/tools/tavily/tavily_answer.dart b/packages/langchain_community/lib/src/tools/tavily/tavily_answer.dart new file mode 100644 index 00000000..a5ad637f --- /dev/null +++ b/packages/langchain_community/lib/src/tools/tavily/tavily_answer.dart @@ -0,0 +1,102 @@ +import 'dart:async'; + +import 'package:http/http.dart' as http; +import 'package:langchain_core/tools.dart'; +import 'package:tavily_dart/tavily_dart.dart'; + +import 'mappers.dart'; +import 'tavily_search_results.dart'; +import 'types.dart'; + +/// Tool that queries the [Tavily Search API](https://tavily.com) and +/// gets an answer to the search query. +/// +/// The Tavily API uses API keys for authentication. Visit the +/// [Tavily console](https://app.tavily.com/) to retrieve the API key you'll +/// use in your requests. +/// +/// If you want to get a list of search results instead, use the +/// [TavilySearchResultsTool] instead. +/// +/// Example: +/// ```dart +/// final tool = TavilyAnswerTool( +/// apiKey: Platform.environment['TAVILY_API_KEY']!, +/// ); +/// final res = await tool.invoke('What is the weather like in New York?'); +/// print(res); +/// // The current weather in New York is clear with a temperature of 22.8°C (73.0°F)... +/// ``` +final class TavilyAnswerTool extends StringTool { + /// Creates a [TavilyAnswerTool] instance. + /// + /// Main configuration options: + /// - `apiKey`: your Tavily API key. You can find your API key in the + /// [Tavily console](https://app.tavily.com/). + /// + /// Advance configuration options: + /// - `baseUrl`: the base URL to use. Defaults to Tavily's API URL. You can + /// override this to use a different API URL, or to use a proxy. + /// - `headers`: global headers to send with every request. You can use + /// this to set custom headers, or to override the default headers. + /// - `queryParams`: global query parameters to send with every request. You + /// can use this to set custom query parameters (e.g. Azure OpenAI API + /// required to attach a `version` query parameter to every request). + /// - `client`: the HTTP client to use. You can set your own HTTP client if + /// you need further customization (e.g. to use a Socks5 proxy). + TavilyAnswerTool({ + required this.apiKey, + final String? baseUrl, + final Map headers = const {}, + final Map queryParams = const {}, + final http.Client? client, + super.defaultOptions = const TavilyAnswerToolOptions(), + }) : _client = TavilyClient( + baseUrl: baseUrl, + headers: headers, + queryParams: queryParams, + client: client, + ), + super( + name: 'tavily_answer', + description: + 'A search engine optimized for comprehensive, accurate, and trusted answers. ' + 'Useful for when you need to answer questions about current events. ' + 'The tool returns an answer to the search query - not the search results.', + inputDescription: 'The search query to get an answer to. ' + 'Eg: "What is the weather like in New York?"', + ); + + /// A client for interacting with Tavily API. + final TavilyClient _client; + + /// Your Tavily API key. + String apiKey; + + @override + Future invokeInternal( + final String toolInput, { + final TavilyAnswerToolOptions? options, + }) async { + final res = await _client.search( + request: SearchRequest( + apiKey: apiKey, + query: toolInput, + includeAnswer: true, + searchDepth: (options?.searchDepth ?? defaultOptions.searchDepth) + .toSearchRequestSearchDepth(), + maxResults: options?.maxResults ?? defaultOptions.maxResults, + includeDomains: + options?.includeDomains ?? defaultOptions.includeDomains, + excludeDomains: + options?.excludeDomains ?? defaultOptions.excludeDomains, + ), + ); + return res.answer ?? ''; + } + + @override + void close() { + _client.endSession(); + } +} diff --git a/packages/langchain_community/lib/src/tools/tavily/tavily_search_results.dart b/packages/langchain_community/lib/src/tools/tavily/tavily_search_results.dart new file mode 100644 index 00000000..7e5693c7 --- /dev/null +++ b/packages/langchain_community/lib/src/tools/tavily/tavily_search_results.dart @@ -0,0 +1,130 @@ +import 'dart:async'; + +import 'package:http/http.dart' as http; +import 'package:langchain_core/tools.dart'; +import 'package:tavily_dart/tavily_dart.dart'; + +import 'mappers.dart'; +import 'tavily_answer.dart'; +import 'types.dart'; + +/// Tool that queries the [Tavily Search API](https://tavily.com) and +/// gets back a list of search results. +/// +/// The Tavily API uses API keys for authentication. Visit the +/// [Tavily console](https://app.tavily.com/) to retrieve the API key you'll +/// use in your requests. +/// +/// If you want to get directly an answer to a search query, use the +/// [TavilyAnswerTool] instead. +/// +/// Example: +/// ```dart +/// final tool = TavilySearchResultsTool( +/// apiKey: Platform.environment['TAVILY_API_KEY']!, +/// ); +/// final res = await tool.invoke('What is the weather like in New York?'); +/// print(res); +/// // [ +/// // { +/// // "title": "Weather in New York", +/// // "url": "https://www.weatherapi.com/", +/// // "content": "{'location': {'lat': 40.71, 'lon': -74.01}, 'current': {'last_updated': '2024-06-20 17:00', 'temp_c': 31.1, 'condition': {'text': 'Sunny', 'icon': '//cdn.weatherapi.com/weather/64x64/day/113.png'}, 'wind_mph': 2.2, 'wind_kph': 3.6, 'wind_degree': 161, 'wind_dir': 'SSE', 'pressure_mb': 1025.0, 'pressure_in': 30.26, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 48, 'cloud': 0, 'feelslike_c': 33.1, 'feelslike_f': 91.6, 'windchill_c': 29.5, 'windchill_f': 85.0, 'heatindex_c': 30.6, 'heatindex_f': 87.0, 'dewpoint_c': 17.7, 'dewpoint_f': 63.8, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 7.0, 'gust_mph': 16.4, 'gust_kph': 26.4}}", +/// // "score": 0.98855 +/// // }, +/// // ... +/// // ] +/// ``` +final class TavilySearchResultsTool + extends Tool { + /// Creates a [TavilySearchResultsTool] instance. + /// + /// Main configuration options: + /// - `apiKey`: your Tavily API key. You can find your API key in the + /// [Tavily console](https://app.tavily.com/). + /// + /// Advance configuration options: + /// - `baseUrl`: the base URL to use. Defaults to Tavily's API URL. You can + /// override this to use a different API URL, or to use a proxy. + /// - `headers`: global headers to send with every request. You can use + /// this to set custom headers, or to override the default headers. + /// - `queryParams`: global query parameters to send with every request. You + /// can use this to set custom query parameters (e.g. Azure OpenAI API + /// required to attach a `version` query parameter to every request). + /// - `client`: the HTTP client to use. You can set your own HTTP client if + /// you need further customization (e.g. to use a Socks5 proxy). + TavilySearchResultsTool({ + required this.apiKey, + final String? baseUrl, + final Map headers = const {}, + final Map queryParams = const {}, + final http.Client? client, + super.defaultOptions = const TavilySearchResultsToolOptions(), + }) : _client = TavilyClient( + baseUrl: baseUrl, + headers: headers, + queryParams: queryParams, + client: client, + ), + super( + name: 'tavily_search_results', + description: + 'A search engine optimized for comprehensive, accurate, and trusted results. ' + 'Useful for when you need to answer questions about current events. ' + 'The tool returns a JSON object with search results.', + inputJsonSchema: { + 'type': 'object', + 'properties': { + 'query': { + 'type': 'string', + 'description': 'The search query to look up. ' + 'Eg: "What is the weather like in New York?"', + }, + }, + 'required': ['query'], + }, + ); + + /// A client for interacting with Tavily API. + final TavilyClient _client; + + /// Your Tavily API key. + String apiKey; + + @override + Future invokeInternal( + final String input, { + final TavilySearchResultsToolOptions? options, + }) async { + final res = await _client.search( + request: SearchRequest( + apiKey: apiKey, + query: input, + searchDepth: (options?.searchDepth ?? defaultOptions.searchDepth) + .toSearchRequestSearchDepth(), + maxResults: options?.maxResults ?? defaultOptions.maxResults, + includeRawContent: + options?.includeRawContent ?? defaultOptions.includeRawContent, + includeDomains: + options?.includeDomains ?? defaultOptions.includeDomains, + excludeDomains: + options?.excludeDomains ?? defaultOptions.excludeDomains, + ), + ); + return TavilySearchResults( + results: res.results + .map((r) => r.toTavilySearchResult()) + .toList(growable: false), + ); + } + + @override + String getInputFromJson(final Map json) { + return json['query'] as String; + } + + @override + void close() { + _client.endSession(); + } +} diff --git a/packages/langchain_community/lib/src/tools/tavily/types.dart b/packages/langchain_community/lib/src/tools/tavily/types.dart new file mode 100644 index 00000000..d6dc9134 --- /dev/null +++ b/packages/langchain_community/lib/src/tools/tavily/types.dart @@ -0,0 +1,131 @@ +import 'dart:convert'; + +import 'package:langchain_core/tools.dart'; +import 'package:meta/meta.dart'; + +import 'tavily_answer.dart'; +import 'tavily_search_results.dart'; + +/// The depth of the search. +enum TavilySearchDepth { + /// Basic search depth. + basic, + + /// Advanced search depth. + advanced, +} + +/// {@template tavily_search_results} +/// A search results from the Tavily search engine. +/// {@endtemplate} +@immutable +class TavilySearchResults { + /// {@macro tavily_search_results} + const TavilySearchResults({ + required this.results, + }); + + /// The search results. + final List results; + + @override + String toString() { + return json.encode( + results + .map( + (result) => { + 'title': result.title, + 'url': result.url, + 'content': result.content, + 'rawContent': result.rawContent, + 'score': result.score, + }, + ) + .toList(growable: false), + ); + } +} + +/// {@template tavily_search_result} +/// A search result from the Tavily search engine. +/// {@endtemplate} +@immutable +class TavilySearchResult { + /// {@macro tavily_search_result} + const TavilySearchResult({ + required this.title, + required this.url, + required this.content, + this.rawContent, + required this.score, + }); + + /// The title of the search result url. + final String title; + + /// The url of the search result. + final String url; + + /// The most query related content from the scraped url. + final String content; + + /// The parsed and cleaned HTML of the site. For now includes parsed text only. + final String? rawContent; + + /// The relevance score of the search result. + final double score; +} + +/// {@template tavily_search_results_tool_options} +/// Generation options to pass into the [TavilySearchResultsTool]. +/// {@endtemplate} +class TavilySearchResultsToolOptions extends ToolOptions { + /// {@macro tavily_search_results_tool_options} + const TavilySearchResultsToolOptions({ + this.maxResults = 5, + this.searchDepth = TavilySearchDepth.basic, + this.includeRawContent = false, + this.includeDomains, + this.excludeDomains, + }); + + /// The number of maximum search results to return. + final int maxResults; + + /// The depth of the search. + final TavilySearchDepth searchDepth; + + /// Include raw content in the search results. + final bool includeRawContent; + + /// A list of domains to specifically include in the search results. + final List? includeDomains; + + /// A list of domains to specifically exclude from the search results. + final List? excludeDomains; +} + +/// {@template tavily_answer_tool_options} +/// Generation options to pass into the [TavilyAnswerTool]. +/// {@endtemplate} +class TavilyAnswerToolOptions extends ToolOptions { + /// {@macro tavily_answer_tool_options} + const TavilyAnswerToolOptions({ + this.maxResults = 5, + this.searchDepth = TavilySearchDepth.basic, + this.includeDomains, + this.excludeDomains, + }); + + /// The number of maximum search results to return. + final int maxResults; + + /// The depth of the search. + final TavilySearchDepth searchDepth; + + /// A list of domains to specifically include in the search results. + final List? includeDomains; + + /// A list of domains to specifically exclude from the search results. + final List? excludeDomains; +} diff --git a/packages/langchain_community/lib/src/tools/tools.dart b/packages/langchain_community/lib/src/tools/tools.dart index 9601880a..4aa306f8 100644 --- a/packages/langchain_community/lib/src/tools/tools.dart +++ b/packages/langchain_community/lib/src/tools/tools.dart @@ -1 +1,2 @@ export 'calculator.dart'; +export 'tavily/tavily.dart'; diff --git a/packages/langchain_community/pubspec.yaml b/packages/langchain_community/pubspec.yaml index e2286be4..b386fb9d 100644 --- a/packages/langchain_community/pubspec.yaml +++ b/packages/langchain_community/pubspec.yaml @@ -26,6 +26,7 @@ dependencies: math_expressions: ^2.4.0 meta: ^1.11.0 objectbox: ^4.0.1 + tavily_dart: ^0.0.1-dev.1 uuid: ^4.3.3 dev_dependencies: diff --git a/packages/langchain_community/pubspec_overrides.yaml b/packages/langchain_community/pubspec_overrides.yaml index de62cfcc..19febce5 100644 --- a/packages/langchain_community/pubspec_overrides.yaml +++ b/packages/langchain_community/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: langchain_core,langchain_openai,openai_dart +# melos_managed_dependency_overrides: langchain_core,langchain_openai,openai_dart,tavily_dart dependency_overrides: langchain_core: path: ../langchain_core @@ -6,3 +6,5 @@ dependency_overrides: path: ../langchain_openai openai_dart: path: ../openai_dart + tavily_dart: + path: ../tavily_dart diff --git a/packages/langchain_community/test/tools/tavily_test.dart b/packages/langchain_community/test/tools/tavily_test.dart new file mode 100644 index 00000000..85214c6c --- /dev/null +++ b/packages/langchain_community/test/tools/tavily_test.dart @@ -0,0 +1,31 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:langchain_community/langchain_community.dart'; +import 'package:test/test.dart'; + +void main() { + group('TavilySearchResultsTool tests', () { + test('Calculate expressions', () async { + final tool = TavilySearchResultsTool( + apiKey: Platform.environment['TAVILY_API_KEY']!, + ); + final res = await tool.invoke('What is the weather like in New York?'); + expect(res.results, isNotEmpty); + final jsonString = res.toString(); + expect(() => json.decode(jsonString), returnsNormally); + tool.close(); + }); + }); + + group('TavilyAnswerTool tests', () { + test('Invoke TavilyAnswerTool', () async { + final tool = TavilyAnswerTool( + apiKey: Platform.environment['TAVILY_API_KEY']!, + ); + final res = await tool.invoke('What is the weather like in New York?'); + expect(res, isNotEmpty); + tool.close(); + }); + }); +} diff --git a/packages/langchain_core/lib/src/tools/base.dart b/packages/langchain_core/lib/src/tools/base.dart index e676fc6b..37f9f9d2 100644 --- a/packages/langchain_core/lib/src/tools/base.dart +++ b/packages/langchain_core/lib/src/tools/base.dart @@ -12,7 +12,6 @@ import 'types.dart'; /// {@template tool_spec} /// The specification of a LangChain tool without the actual implementation. /// {@endtemplate} -@immutable class ToolSpec { /// {@macro tool_spec} const ToolSpec({ diff --git a/packages/langchain_openai/pubspec_overrides.yaml b/packages/langchain_openai/pubspec_overrides.yaml index 18a3bcaa..d4293e4f 100644 --- a/packages/langchain_openai/pubspec_overrides.yaml +++ b/packages/langchain_openai/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: openai_dart,langchain_core,langchain_community,langchain +# melos_managed_dependency_overrides: openai_dart,langchain_core,langchain_community,langchain,tavily_dart dependency_overrides: langchain: path: ../langchain @@ -8,3 +8,5 @@ dependency_overrides: path: ../langchain_core openai_dart: path: ../openai_dart + tavily_dart: + path: ../tavily_dart diff --git a/packages/langchain_supabase/pubspec_overrides.yaml b/packages/langchain_supabase/pubspec_overrides.yaml index 5eb34624..d5cb8df4 100644 --- a/packages/langchain_supabase/pubspec_overrides.yaml +++ b/packages/langchain_supabase/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: langchain_openai,openai_dart,langchain_core,langchain_community +# melos_managed_dependency_overrides: langchain_openai,openai_dart,langchain_core,langchain_community,tavily_dart # melos_managed_dependency_overrides: langchain dependency_overrides: langchain: @@ -11,3 +11,5 @@ dependency_overrides: path: ../langchain_openai openai_dart: path: ../openai_dart + tavily_dart: + path: ../tavily_dart