diff --git a/README.md b/README.md
index 1b80650..ad3b216 100644
--- a/README.md
+++ b/README.md
@@ -230,12 +230,27 @@ Every constructor accepts:
| `timeout` | Timeout passed to the SerpApi SDK client |
| `name` | Tool name presented to the model |
| `mode` | Result detail level; compact mode is the default, while full mode keeps supporting sections and all fields on retained results |
+| `response_format` | Output serialization; Markdown is the default, while `SearchResultFormat.JSON` returns compact or full JSON text |
| `result_limit` | Maximum items kept in each result list in either mode; defaults vary by tool; use `None` for all results |
`web_search` and `shopping_search` also accept `allowed_engines` and `default_engine`. The tool offers only the engine values you configure.
Use `default_params` for documented SerpApi settings that should stay under your application's control, such as locale, currency, safe search, or pagination. Use `result_limit` to control how many results the tool returns. The agent continues to supply only the inputs described by its search tool.
+Tools return Markdown by default. Markdown keeps links and tables readable without JSON syntax overhead. Application code that needs structured fields can opt into JSON:
+
+```python
+import json
+
+from serpapi_search_tools import SearchResultFormat, web_search
+
+search = web_search(
+ provider="function",
+ response_format=SearchResultFormat.JSON,
+)
+result = json.loads(search(query="Python packaging"))
+```
+
```python
tool = news_search(
default_params={"hl": "en", "gl": "us"},
diff --git a/assets/docs-mobile.css b/assets/docs-mobile.css
index 4a79c7d..056db03 100644
--- a/assets/docs-mobile.css
+++ b/assets/docs-mobile.css
@@ -1,9 +1,5 @@
/* Mobile corrections layered over Great Docs 0.14. */
@media (max-width: 991.98px) {
- body.nav-sidebar:not(.gd-project-home) #quarto-header > .navbar {
- display: none;
- }
-
body.nav-sidebar:not(.gd-project-home) #quarto-header,
body.nav-sidebar:not(.gd-project-home) .quarto-secondary-nav {
transform: none !important;
@@ -17,47 +13,51 @@
display: none !important;
}
- body.gd-project-home .navbar-container {
+ body.nav-sidebar .navbar-container {
flex-wrap: nowrap;
}
- body.gd-project-home .navbar-toggler {
+ body.nav-sidebar .navbar-toggler {
order: 1;
flex: 0 0 auto;
}
- body.gd-project-home .navbar-brand-container {
+ body.nav-sidebar .navbar-brand-container {
order: 2;
+ flex: 1 1 auto !important;
+ width: auto !important;
min-width: 0;
- max-width: none;
+ max-width: none !important;
margin-left: 0 !important;
margin-right: auto !important;
+ overflow: hidden;
}
- body.gd-project-home .navbar-brand {
+ body.nav-sidebar .navbar-brand {
min-width: 0;
max-width: 100%;
margin-right: 0;
}
- body.gd-project-home .navbar-title {
+ body.nav-sidebar .navbar-title {
+ display: block;
font-size: 1rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
- body.gd-project-home .quarto-navbar-tools {
+ body.nav-sidebar .quarto-navbar-tools {
order: 3;
flex: 0 0 auto;
padding: 0;
}
- body.gd-project-home #gd-navbar-widgets {
+ body.nav-sidebar #gd-navbar-widgets {
width: auto;
}
- body.gd-project-home #github-widget,
+ body.nav-sidebar #github-widget,
body.gd-project-home .gd-meta-sidebar {
display: none;
}
diff --git a/assets/docs-mobile.js b/assets/docs-mobile.js
index 3952551..8de1aeb 100644
--- a/assets/docs-mobile.js
+++ b/assets/docs-mobile.js
@@ -10,11 +10,14 @@
function isProjectHomepage() {
var path = window.location.pathname;
- if (path.endsWith("/")) return true;
- if (!path.endsWith("/index.html")) return false;
- return !/(?:\/docs\/cookbook|\/user-guide|\/docs\/sdk-examples|\/reference)\/index\.html$/.test(
- path,
- );
+ if (
+ /(?:\/docs\/cookbook|\/user-guide|\/docs\/sdk-examples|\/reference)(?:\/|$)/.test(
+ path,
+ )
+ ) {
+ return false;
+ }
+ return path.endsWith("/") || path.endsWith("/index.html");
}
function currentArea() {
@@ -22,7 +25,10 @@
if (path.indexOf("/docs/cookbook/") !== -1) return "cookbook";
if (path.indexOf("/docs/sdk-examples/") !== -1) return "examples";
if (path.indexOf("/reference/") !== -1) return "reference";
- return "guide";
+ if (isProjectHomepage() || path.indexOf("/user-guide/") !== -1) {
+ return "guide";
+ }
+ return null;
}
function addUserGuideNavbarLink() {
diff --git a/assets/serpapi-logo.svg b/assets/serpapi-logo.svg
new file mode 100644
index 0000000..d54f664
--- /dev/null
+++ b/assets/serpapi-logo.svg
@@ -0,0 +1,34 @@
+
+
diff --git a/cookbook/README.md b/cookbook/README.md
index 0214230..7529bfd 100644
--- a/cookbook/README.md
+++ b/cookbook/README.md
@@ -4,6 +4,8 @@ Choose the SDK you use and run a complete agent with live SerpApi search.
Every entry includes setup instructions, an editable prompt, a runnable agent,
and a Markdown report you can inspect.
+Every cookbook agent receives compact Markdown from its SerpApi tools. The scripts rely on the package default and do not parse structured response fields.
+
| SDK | Agent | SerpApi capabilities |
| --- | --- | --- |
| [LangChain](langchain/) | Deep market research brief | Web and news |
diff --git a/cookbook/semantic-kernel/README.md b/cookbook/semantic-kernel/README.md
index 146bc01..abee66b 100644
--- a/cookbook/semantic-kernel/README.md
+++ b/cookbook/semantic-kernel/README.md
@@ -1,17 +1,13 @@
# Semantic Kernel plan-and-execute competitor brief
-This ChatCompletionAgent follows an explicit plan, resolves the plan with
-search plugins, and writes a competitor brief to
-`cookbook-output/semantic-kernel-competitor-brief.md`.
+The kernel follows an explicit plan, resolves it with automatic calls to search plugins, and writes a competitor brief to `cookbook-output/semantic-kernel-competitor-brief.md`.
## Original source
Inspired by Semantic Kernel's official Python
[plan-and-execute process](https://github.com/microsoft/semantic-kernel/blob/main/python/samples/concepts/processes/plan_and_execute.py).
-This adaptation was **enhanced with SerpApi** by replacing the sample's
-provider-native web search with typed web and news plugins and by applying the
-workflow to a concrete competitor-analysis artifact.
+This adaptation replaces the sample's provider-native web search with typed SerpApi web and news plugins. It applies the workflow to a concrete competitor-analysis artifact.
## Run
diff --git a/cookbook/semantic-kernel/main.py b/cookbook/semantic-kernel/main.py
index cb8bbff..dd0e558 100644
--- a/cookbook/semantic-kernel/main.py
+++ b/cookbook/semantic-kernel/main.py
@@ -7,9 +7,12 @@
from dotenv import load_dotenv
from semantic_kernel import Kernel
-from semantic_kernel.agents import ChatCompletionAgent
from semantic_kernel.connectors.ai import FunctionChoiceBehavior
-from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
+from semantic_kernel.connectors.ai.open_ai import (
+ OpenAIChatCompletion,
+ OpenAIChatPromptExecutionSettings,
+)
+from semantic_kernel.functions import KernelArguments
from serpapi_search_tools import news_search, web_search
@@ -50,7 +53,13 @@ def _write_report(text: str) -> Path:
async def main() -> None:
_require_serpapi_key()
kernel = Kernel()
- plugin = kernel.add_functions(
+ kernel.add_service(
+ OpenAIChatCompletion(
+ ai_model_id=MODEL,
+ api_key=_require_env("OPENAI_API_KEY"),
+ )
+ )
+ kernel.add_functions(
"serpapi",
[
web_search(
@@ -65,26 +74,21 @@ async def main() -> None:
),
],
)
- agent = ChatCompletionAgent(
- name="competitor_research_agent",
- instructions=(
+ settings = OpenAIChatPromptExecutionSettings(
+ function_choice_behavior=FunctionChoiceBehavior.Auto(),
+ )
+ response = await kernel.invoke_prompt(
+ (
"Follow a plan-and-execute process: state a short plan, search each open "
"question, inspect evidence quality, and then write the final competitor brief. "
- "Do not invent company facts or omit source URLs."
+ "Do not invent company facts or omit source URLs.\n\n"
+ f"{PROMPT}"
),
- service=OpenAIChatCompletion(
- ai_model_id=MODEL,
- api_key=_require_env("OPENAI_API_KEY"),
- ),
- plugins=[plugin],
- function_choice_behavior=FunctionChoiceBehavior.Auto(),
+ arguments=KernelArguments(settings=settings),
)
- responses: list[str] = []
- async for response in agent.invoke(messages=PROMPT):
- responses.append(str(response))
- if not responses:
+ if response is None:
raise RuntimeError("Semantic Kernel completed without a final report.")
- report = responses[-1]
+ report = str(response)
path = _write_report(report)
print(report)
print(f"\nSaved report to {path}")
diff --git a/docs/cookbook/index.qmd b/docs/cookbook/index.qmd
index 1eb4ca7..5e6ab36 100644
--- a/docs/cookbook/index.qmd
+++ b/docs/cookbook/index.qmd
@@ -9,6 +9,8 @@ Start with the SDK you already use. Every recipe turns an official framework
pattern into a complete, source-backed workflow and saves a Markdown artifact
you can inspect, edit, or share.
+The cookbook uses compact Markdown responses from each SerpApi tool. The agents pass search results directly to models and do not parse JSON fields.
+
## Choose a cookbook
| SDK | Outcome | Search capabilities |
diff --git a/docs/cookbook/semantic-kernel.qmd b/docs/cookbook/semantic-kernel.qmd
index 7be63b8..4b0338e 100644
--- a/docs/cookbook/semantic-kernel.qmd
+++ b/docs/cookbook/semantic-kernel.qmd
@@ -11,9 +11,7 @@ description: Apply a plan-and-execute loop to live competitor research.
## What you'll build
-A Semantic Kernel `ChatCompletionAgent` that states a research plan, resolves
-each open question with search plugins, checks the evidence quality, and writes
-a competitor brief with visible gaps.
+A Semantic Kernel prompt that states a research plan, resolves each open question with automatic calls to search plugins, checks the evidence quality, and writes a competitor brief with visible gaps.
**Default brief:** Compare three US residential solar-financing platforms using
company and product facts plus recent developments. Include source URLs and
@@ -30,13 +28,14 @@ unresolved evidence gaps.
## Core agent setup
-This excerpt shows how the SerpApi functions become one Semantic Kernel
-plugin. The complete script also configures the chat service, consumes the
-agent response stream, and saves the competitor brief.
+This excerpt shows how the SerpApi functions become one Semantic Kernel plugin. The complete script also configures the chat service, invokes the prompt, and saves the competitor brief.
```python
kernel = Kernel()
-plugin = kernel.add_functions(
+kernel.add_service(
+ OpenAIChatCompletion(ai_model_id=MODEL, api_key=api_key),
+)
+kernel.add_functions(
"serpapi",
[
web_search(
@@ -46,13 +45,13 @@ plugin = kernel.add_functions(
news_search(provider="semantic-kernel"),
],
)
-agent = ChatCompletionAgent(
- name="competitor_research_agent",
- instructions="Plan, search each open question, and inspect evidence quality.",
- service=OpenAIChatCompletion(ai_model_id=MODEL, api_key=api_key),
- plugins=[plugin],
+settings = OpenAIChatPromptExecutionSettings(
function_choice_behavior=FunctionChoiceBehavior.Auto(),
)
+response = await kernel.invoke_prompt(
+ prompt,
+ arguments=KernelArguments(settings=settings),
+)
```
[View the complete `main.py` →](https://github.com/serpapi/serpapi-search-tools-python/blob/main/cookbook/semantic-kernel/main.py)
@@ -70,9 +69,7 @@ uv run --isolated --no-project --with 'serpapi-search-tools[semantic-kernel]' --
Optional controls: `OPENAI_MODEL`, `COOKBOOK_PROMPT`, and
`COOKBOOK_OUTPUT_DIR`.
-**Native plugin shape:** The two search functions are registered with the
-Kernel as one plugin, while automatic function choice lets the agent select
-the right evidence surface.
+**Native plugin shape:** The two search functions are registered with the Kernel as one plugin. Automatic function choice lets the kernel select the right evidence surface.
## Inspect the result
diff --git a/docs/sdk_examples/openai_agents.qmd b/docs/sdk_examples/openai_agents.qmd
index 0ab5de6..d7b6e9c 100644
--- a/docs/sdk_examples/openai_agents.qmd
+++ b/docs/sdk_examples/openai_agents.qmd
@@ -52,8 +52,8 @@ async def main():
asyncio.run(main())
```
-The agent decides when to call the tool, receives the SerpApi JSON, and writes a
-final answer.
+The agent decides when to call the tool, receives compact SerpApi Markdown, and
+writes a final answer.
## Try it
diff --git a/docs/user_guide/01-introduction.qmd b/docs/user_guide/01-introduction.qmd
index 1d8007f..4c39b76 100644
--- a/docs/user_guide/01-introduction.qmd
+++ b/docs/user_guide/01-introduction.qmd
@@ -61,16 +61,14 @@ SDKs are installed, pass `provider=` to choose one explicitly.
For scripts, tests, or a framework that is not listed, request a callable:
```python
-import json
-
from serpapi_search_tools import web_search
search = web_search(provider="function")
-response = json.loads(search(query="Python packaging"))
-print(response.get("organic_results", []))
+response = search(query="Python packaging")
+print(response)
```
-Every tool returns compact JSON text by default, including its main result sections and useful web answer sections. `result_limit` controls how many items are kept in each result list in compact and full modes. Set `mode=SearchResultMode.FULL` and `result_limit=None` when application code needs every response section, field, and returned result.
+Every tool returns compact Markdown by default, including its main result sections and useful web answer sections. `result_limit` controls how many rows are kept in each result table in compact and full modes. Application code that needs structured fields can opt into `SearchResultFormat.JSON`. Set `mode=SearchResultMode.FULL` and `result_limit=None` when application code needs every response section, field, and returned result.
## Next steps
diff --git a/docs/user_guide/02-quickstart.qmd b/docs/user_guide/02-quickstart.qmd
index ad786d9..8d8c797 100644
--- a/docs/user_guide/02-quickstart.qmd
+++ b/docs/user_guide/02-quickstart.qmd
@@ -101,8 +101,8 @@ python search_agent.py
OpenAI `FunctionTool`.
2. The agent decided whether it needed the tool and supplied a text query plus
a supported web engine.
-3. The package validated the arguments, called SerpApi, and returned the
- structured search response to the agent as JSON text.
+3. The package validated the arguments, called SerpApi, and returned compact
+ Markdown search results to the agent.
4. The model used those results to write the final response.
The default web engine is `google_light`, which is a good fast starting point
diff --git a/docs/user_guide/04-configuration.qmd b/docs/user_guide/04-configuration.qmd
index 0753986..5deef62 100644
--- a/docs/user_guide/04-configuration.qmd
+++ b/docs/user_guide/04-configuration.qmd
@@ -46,6 +46,7 @@ All nine constructors accept these options:
| `default_params` | `None` | Set supported SerpApi options such as locale, currency, filters, or pagination in application code. |
| `timeout` | `None` | Set a request timeout on the built-in SerpApi client. |
| `mode` | `SearchResultMode.COMPACT` | Return the main result data; use `SearchResultMode.FULL` to keep supporting sections and all fields on retained results. |
+| `response_format` | `SearchResultFormat.MARKDOWN` | Return readable Markdown by default, or use `SearchResultFormat.JSON` for structured application data. |
| `result_limit` | tool-specific | Set the maximum number of items kept in each result list in either mode. Use `None` to keep all returned items. |
| `include_examples` | `True` | Keep or remove the short invocation hint in the tool description. |
| `name` | constructor name | Give separately configured tools distinct names the model can understand. |
@@ -108,9 +109,37 @@ The search inputs and useful SerpApi parameters depend on the capability:
Read the dedicated page before adding engine-specific `default_params`.
+## Choose Markdown or JSON
+
+Markdown is the default response format. It gives agents readable headings, links, and tables without JSON syntax overhead:
+
+```python
+from serpapi_search_tools import web_search
+
+search = web_search(provider="function")
+print(search(query="Python packaging"))
+```
+
+Use JSON when application code needs named fields:
+
+```python
+import json
+
+from serpapi_search_tools import SearchResultFormat, web_search
+
+search = web_search(
+ provider="function",
+ response_format=SearchResultFormat.JSON,
+)
+response = json.loads(search(query="Python packaging"))
+print(response.get("organic_results", []))
+```
+
+`response_format` is fixed when the tool is created. It is not exposed to the model.
+
## Choose compact or full results
-All tools default to `SearchResultMode.COMPACT`. Compact mode keeps the main result sections and omits metadata, request parameters, pagination, filters, and other supporting sections. Non-list answer sections such as `answer_box` are kept whole. If a successful response has no supported result section, the tool returns `no_results: true` with available status and search information.
+All tools default to `SearchResultMode.COMPACT`. Compact mode keeps the main result sections and omits metadata, request parameters, pagination, filters, and other supporting sections. Markdown keeps the corresponding result headings and tables. JSON also keeps non-list answer sections such as `answer_box` whole. If a successful JSON response has no supported result section, the tool returns `no_results: true` with available status and search information.
| Tool | Default `result_limit` |
| --- | ---: |
@@ -129,7 +158,7 @@ All tools default to `SearchResultMode.COMPACT`. Compact mode keeps the main res
| `web_search` with Yahoo | `answer_box`, `knowledge_graph`, `organic_results` |
| `web_search` with DuckDuckGo | `knowledge_graph`, `organic_results` |
| `news_search` | `news_results` |
-| `maps_search` | `local_results` |
+| `maps_search` | `local_results`; exact-place responses use `place_results` |
| `images_search` | `images_results` |
| `shopping_search` | `shopping_results` for Google Shopping; `organic_results` for Amazon, Walmart, and eBay |
| `videos_search` | `video_results`, `shorts_results`, `channel_results`, `playlist_results`, `movie_results`, `category_results` |
@@ -147,7 +176,7 @@ broader_web_search = web_search(
)
```
-`result_limit` changes the returned JSON, not the SerpApi request. It applies independently to each supported result list and does not shorten nested data such as flight legs, hotel amenities, or product offers. See the [`web_search`](web_search.html) and [`shopping_search`](shopping_search.html) pages for engine-specific retrieval and pagination options.
+`result_limit` changes the returned result, not the SerpApi request. It applies independently to each supported JSON result list or Markdown result table. It does not shorten nested data such as flight legs, hotel amenities, product offers, or a single exact-place result. See the [`web_search`](web_search.html) and [`shopping_search`](shopping_search.html) pages for engine-specific retrieval and pagination options.
Use full mode when application code needs supporting response sections or additional result fields. The tool's default result limit still applies:
@@ -253,7 +282,7 @@ HTTP wrapper. The object needs one synchronous `search(params)` method:
```python
import json
-from serpapi_search_tools import SearchResultMode, hotels_search
+from serpapi_search_tools import SearchResultFormat, SearchResultMode, hotels_search
class RecordingClient:
@@ -270,6 +299,7 @@ search = hotels_search(
provider="function",
client=client,
mode=SearchResultMode.FULL,
+ response_format=SearchResultFormat.JSON,
)
result = json.loads(
search(
diff --git a/docs/user_guide/05-usage.qmd b/docs/user_guide/05-usage.qmd
index 1ca925f..14ac38a 100644
--- a/docs/user_guide/05-usage.qmd
+++ b/docs/user_guide/05-usage.qmd
@@ -6,15 +6,14 @@ guide-section: Start Here
## Call a tool directly
```python
-import json
-
from serpapi_search_tools import web_search
search = web_search(provider="function")
-response = json.loads(search(query="Python packaging"))
+response = search(query="Python packaging")
+print(response)
```
-The returned callable has a narrow signature and returns compact JSON text.
+The returned callable has a narrow signature and returns compact Markdown by default. Pass `response_format=SearchResultFormat.JSON` when code needs to parse named fields.
## Add a specialized capability
diff --git a/docs/user_guide/08-examples.qmd b/docs/user_guide/08-examples.qmd
index 884794d..7ff4a45 100644
--- a/docs/user_guide/08-examples.qmd
+++ b/docs/user_guide/08-examples.qmd
@@ -39,7 +39,7 @@ uv run --isolated --no-project --with serpapi-search-tools --with python-dotenv
uv run --isolated --no-project --with serpapi-search-tools --with python-dotenv examples/direct_cached_search.py
```
-The direct scripts parse the compact JSON response and print bounded summaries.
+`direct_search.py` compares the default Markdown response with explicit JSON. The other direct scripts opt into JSON when they normalize fields into bounded summaries. Agent examples use the default compact Markdown response.
## Structured travel defaults
diff --git a/docs/user_guide/10-web_search.qmd b/docs/user_guide/10-web_search.qmd
index 3a377cc..e78fc24 100644
--- a/docs/user_guide/10-web_search.qmd
+++ b/docs/user_guide/10-web_search.qmd
@@ -51,6 +51,7 @@ Google, Google Light, Bing, and DuckDuckGo use `q`; Yahoo uses `p`.
| `default_engine` | `google_light` when allowed | Choose the engine used when the model omits `engine` |
| `default_params` | `None` | Fix engine parameters such as locale, filters, or pagination in application code |
| `mode` | `compact` | Return the main web result sections; use `SearchResultMode.FULL` to keep supporting sections and all fields on retained results |
+| `response_format` | `markdown` | Return Markdown by default, or use `SearchResultFormat.JSON` for structured fields |
| `result_limit` | `10` | Maximum items kept in each web result list in either mode |
| `api_key` | `None` | Override the environment-based SerpApi key |
| `timeout` | `None` | Set the built-in client's request timeout |
diff --git a/docs/user_guide/11-news_search.qmd b/docs/user_guide/11-news_search.qmd
index e1d20f9..fdee360 100644
--- a/docs/user_guide/11-news_search.qmd
+++ b/docs/user_guide/11-news_search.qmd
@@ -47,6 +47,7 @@ field or SerpApi's native `q` name.
| `provider` | `"auto"` | Auto-detect one installed SDK or select one explicitly |
| `default_params` | `None` | Fix locale, country, or supported query filters |
| `mode` | `compact` | Return the main news result section; use `SearchResultMode.FULL` to keep supporting sections and all fields on retained results |
+| `response_format` | `markdown` | Return Markdown by default, or use `SearchResultFormat.JSON` for structured fields |
| `result_limit` | `20` | Maximum `news_results` retained in either mode |
| `api_key` | `None` | Override `SERPAPI_API_KEY` / `SERPAPI_KEY` |
| `timeout` | `None` | Set the built-in client timeout |
diff --git a/docs/user_guide/12-maps_search.qmd b/docs/user_guide/12-maps_search.qmd
index cd87411..2427b15 100644
--- a/docs/user_guide/12-maps_search.qmd
+++ b/docs/user_guide/12-maps_search.qmd
@@ -52,7 +52,8 @@ field.
| `provider` | `"auto"` | Detect one installed SDK or choose an SDK explicitly |
| `default_params` | `None` | Fix Google Maps locale or supported search filters |
| `mode` | `compact` | Return the main local result section; use `SearchResultMode.FULL` to keep supporting sections and all fields on retained results |
-| `result_limit` | `10` | Maximum `local_results` retained in either mode |
+| `response_format` | `markdown` | Return Markdown by default, or use `SearchResultFormat.JSON` for structured fields |
+| `result_limit` | `10` | Maximum `local_results` retained in either mode; an exact `place_results` object is retained whole |
| `api_key` | `None` | Override environment key lookup |
| `timeout` | `None` | Set the built-in client timeout |
| `client` | `None` | Add deterministic tests, caching, or request logging |
@@ -79,7 +80,7 @@ this search-mode tool.
## What comes back
-Both modes return up to `result_limit` `local_results` (10 by default). Place entries may include a title, address, rating, review count, category, phone, website, hours, coordinates, thumbnail, and identifiers. Compact mode omits supporting sections. Use `result_limit=None` to keep every returned place. Availability varies by place and query.
+Both modes return up to `result_limit` `local_results` (10 by default). An exact-place response uses a single `place_results` object, which compact mode retains whole rather than treating it as a list. Place entries may include a title, address, rating, review count, category, phone, website, hours, coordinates, thumbnail, and identifiers. Compact mode omits supporting sections. Use `result_limit=None` to keep every returned place. Availability varies by place and query.
## Common mistakes
diff --git a/docs/user_guide/13-images_search.qmd b/docs/user_guide/13-images_search.qmd
index 0df33dc..de8d0bd 100644
--- a/docs/user_guide/13-images_search.qmd
+++ b/docs/user_guide/13-images_search.qmd
@@ -43,6 +43,7 @@ image query.
| `provider` | `"auto"` | Detect the installed agent SDK |
| `default_params` | `None` | Fix safe search, locale, or other supported image filters |
| `mode` | `compact` | Return the main image result section; use `SearchResultMode.FULL` to keep supporting sections and all fields on retained results |
+| `response_format` | `markdown` | Return Markdown by default, or use `SearchResultFormat.JSON` for structured fields |
| `result_limit` | `50` | Maximum `images_results` retained in either mode; use `None` for all returned images |
| `api_key` | `None` | Override environment key lookup |
| `timeout` | `None` | Set the built-in client timeout |
diff --git a/docs/user_guide/14-shopping_search.qmd b/docs/user_guide/14-shopping_search.qmd
index 412b64d..5a385eb 100644
--- a/docs/user_guide/14-shopping_search.qmd
+++ b/docs/user_guide/14-shopping_search.qmd
@@ -50,6 +50,7 @@ Google Shopping, `k` for Amazon, `query` for Walmart, and `_nkw` for eBay.
| `default_engine` | `google_shopping` when allowed | Select the marketplace used when `engine` is omitted |
| `default_params` | `None` | Fix engine-specific marketplace filters or pagination |
| `mode` | `compact` | Return the main product result section; use `SearchResultMode.FULL` to keep supporting sections and all fields on retained results |
+| `response_format` | `markdown` | Return Markdown by default, or use `SearchResultFormat.JSON` for structured fields |
| `result_limit` | `60` | Maximum primary product results retained in either mode |
| `api_key` | `None` | Override environment key lookup |
| `timeout` | `None` | Set the built-in client timeout |
diff --git a/docs/user_guide/15-videos_search.qmd b/docs/user_guide/15-videos_search.qmd
index 99feed3..4899790 100644
--- a/docs/user_guide/15-videos_search.qmd
+++ b/docs/user_guide/15-videos_search.qmd
@@ -43,6 +43,7 @@ YouTube's `search_query` parameter.
| `provider` | `"auto"` | Detect one installed SDK or select one explicitly |
| `default_params` | `None` | Fix locale or supported YouTube search filters |
| `mode` | `compact` | Return the main YouTube result sections; use `SearchResultMode.FULL` to keep supporting sections and all fields on retained results |
+| `response_format` | `markdown` | Return Markdown by default, or use `SearchResultFormat.JSON` for structured fields |
| `result_limit` | `10` | Maximum entries retained from each supported YouTube result list in either mode |
| `api_key` | `None` | Override environment key lookup |
| `timeout` | `None` | Set the built-in client timeout |
diff --git a/docs/user_guide/16-hotels_search.qmd b/docs/user_guide/16-hotels_search.qmd
index 917079c..4cdcfda 100644
--- a/docs/user_guide/16-hotels_search.qmd
+++ b/docs/user_guide/16-hotels_search.qmd
@@ -60,6 +60,7 @@ An agent invocation has a structured shape:
| `provider` | `"auto"` | Detect one installed SDK or select one explicitly |
| `default_params` | `None` | Fix currency, locale, country, or supported property filters |
| `mode` | `compact` | Return the main property result section; use `SearchResultMode.FULL` to keep supporting sections and all fields on retained results |
+| `response_format` | `markdown` | Return Markdown by default, or use `SearchResultFormat.JSON` for structured fields |
| `result_limit` | `20` | Maximum `properties` retained in either mode |
| `api_key` | `None` | Override environment key lookup |
| `timeout` | `None` | Set the built-in client timeout |
diff --git a/docs/user_guide/17-flights_search.qmd b/docs/user_guide/17-flights_search.qmd
index e2a949c..6090a7e 100644
--- a/docs/user_guide/17-flights_search.qmd
+++ b/docs/user_guide/17-flights_search.qmd
@@ -70,6 +70,7 @@ a round trip.
| `provider` | `"auto"` | Detect one installed SDK or select one explicitly |
| `default_params` | `None` | Fix currency, locale, stops, airline, bag, or time filters supported by SerpApi |
| `mode` | `compact` | Return the main flight result sections; use `SearchResultMode.FULL` to keep supporting sections and all fields on retained results |
+| `response_format` | `markdown` | Return Markdown by default, or use `SearchResultFormat.JSON` for structured fields |
| `result_limit` | `10` | Maximum entries retained independently from `best_flights` and `other_flights` in either mode |
| `api_key` | `None` | Override environment key lookup |
| `timeout` | `None` | Set the built-in client timeout |
diff --git a/docs/user_guide/18-travel_explore_search.qmd b/docs/user_guide/18-travel_explore_search.qmd
index e05d1ae..aab1893 100644
--- a/docs/user_guide/18-travel_explore_search.qmd
+++ b/docs/user_guide/18-travel_explore_search.qmd
@@ -57,6 +57,7 @@ Example broad invocation:
| `provider` | `"auto"` | Detect one installed SDK or select one explicitly |
| `default_params` | `None` | Fix currency, locale, price, stops, duration, or supported interest filters |
| `mode` | `compact` | Return the main destination result section; use `SearchResultMode.FULL` to keep supporting sections and all fields on retained results |
+| `response_format` | `markdown` | Return Markdown by default, or use `SearchResultFormat.JSON` for structured fields |
| `result_limit` | `50` | Maximum `destinations` retained in either mode |
| `api_key` | `None` | Override environment key lookup |
| `timeout` | `None` | Set the built-in client timeout |
diff --git a/docs/user_guide/19-managing_llm_context.qmd b/docs/user_guide/19-managing_llm_context.qmd
index e746203..a4e3dcb 100644
--- a/docs/user_guide/19-managing_llm_context.qmd
+++ b/docs/user_guide/19-managing_llm_context.qmd
@@ -5,15 +5,18 @@ guide-section: Advanced Usage
# Manage search response size
-Search responses can contain many results and supporting sections. Use `mode` and `result_limit` to control what the tool returns to the model.
+Search responses can contain many results and supporting sections. Use `response_format`, `mode`, and `result_limit` to control what the tool returns to the model.
-Two constructor options work together:
+Three constructor options work together:
| Option | What it controls | Default |
| --- | --- | --- |
+| `response_format` | Whether the response is Markdown or JSON | `SearchResultFormat.MARKDOWN` |
| `mode` | Which response sections and fields are kept | `SearchResultMode.COMPACT` |
| `result_limit` | Maximum items kept in each result list | Tool-specific |
+Markdown is the default because headings, tables, and links are concise and directly readable by a model. Choose `SearchResultFormat.JSON` when application code needs structured fields. The same compact/full and result-limit controls apply to both formats.
+
## Start with compact mode
Compact mode is the default:
@@ -40,7 +43,7 @@ full_search = web_search(
)
```
-Both tools keep at most five items in each supported result list. The full tool also keeps the response sections and fields omitted by compact mode.
+Both tools keep at most five items in each supported result list or Markdown table. The full tool also keeps the response sections and fields omitted by compact mode.
The option is application configuration. It is not visible to the model and does not change the number of results requested from SerpApi.
@@ -49,7 +52,7 @@ The option is application configuration. It is not visible to the model and does
The limit applies independently when a response contains more than one result list:
- Google Flights keeps up to the limit from both `best_flights` and
- `other_flights`.
+ `other_flights`, or from both corresponding Markdown tables.
- YouTube keeps up to the limit from videos, shorts, channels, playlists,
movies, and categories.
- Google Light applies it to organic results, related questions, related
@@ -57,6 +60,8 @@ The limit applies independently when a response contains more than one result li
Nested data such as flight legs, layovers, hotel amenities, and product offers is not shortened.
+An exact Google Maps place is a single object rather than a result list. It is retained in both compact formats and is not row-limited.
+
## Default result limits
Each tool has a default suited to its result type:
diff --git a/docs/user_guide/20-debugging.qmd b/docs/user_guide/20-debugging.qmd
index 5ef5939..85bc27a 100644
--- a/docs/user_guide/20-debugging.qmd
+++ b/docs/user_guide/20-debugging.qmd
@@ -14,7 +14,7 @@ behavior.
```python
import json
-from serpapi_search_tools import SearchResultMode, web_search
+from serpapi_search_tools import SearchResultFormat, SearchResultMode, web_search
search = web_search(
provider="function",
@@ -22,6 +22,7 @@ search = web_search(
default_params={"hl": "en", "gl": "us"},
result_limit=None,
mode=SearchResultMode.FULL,
+ response_format=SearchResultFormat.JSON,
)
response = json.loads(search(query="Python packaging tutorials"))
@@ -41,7 +42,7 @@ Compact mode returns these common result sections:
| --- | --- |
| `web_search` | `organic_results` |
| `news_search` | `news_results` |
-| `maps_search` | `local_results` |
+| `maps_search` | `local_results` or `place_results` for an exact place |
| `images_search` | `images_results` |
| `shopping_search` | `shopping_results` or engine-specific product results |
| `videos_search` | `video_results`, `shorts_results`, `channel_results`, `playlist_results`, `movie_results`, or `category_results` |
diff --git a/examples/README.md b/examples/README.md
index f95c525..ea17c68 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -18,7 +18,7 @@ to `.env`, or export values in your shell. You always need `SERPAPI_API_KEY` or
| Script | Scenario | Extra | Search tools demonstrated |
| --- | --- | --- | --- |
-| `direct_search.py` | First direct call | none | Web and news |
+| `direct_search.py` | Compare default Markdown with explicit JSON | none | Web and news |
| `direct_travel.py` | Structured travel calls | none | Hotels, flights, and travel explore |
| `direct_multi_search.py` | Multi-vertical research | none | Web, news, maps, and shopping |
| `direct_marketplace_comparison.py` | Normalize marketplace results | none | Google Shopping, Amazon, Walmart, and eBay |
@@ -61,4 +61,4 @@ The examples default to `gpt-5.4-mini`, `claude-sonnet-5`,
`gemini-flash-lite-latest`, and `grok-4.5`. Override the corresponding model
environment variable when needed.
-The two multi-tool OpenAI Agents scenarios use `_logging_client.py` to log safe request metadata and response structure. `result_limit` controls how many items are kept in each result list. Compact mode omits supporting response sections.
+The two multi-tool OpenAI Agents scenarios use `_logging_client.py` to log safe request metadata and response format. Agent examples use compact Markdown by default. Direct examples that inspect named response fields request JSON explicitly. `result_limit` controls how many rows or items are kept in each result section, and compact mode omits supporting sections.
diff --git a/examples/_logging_client.py b/examples/_logging_client.py
index fbd9628..0fffdc6 100644
--- a/examples/_logging_client.py
+++ b/examples/_logging_client.py
@@ -14,10 +14,24 @@ class LoggingClient:
def __init__(self, api_key: str) -> None:
self._client = serpapi.Client(api_key=api_key)
- def search(self, params: dict[str, Any]) -> Mapping[str, Any]:
+ def search(self, params: dict[str, Any]) -> Mapping[str, Any] | str:
safe_params = {key: value for key, value in params.items() if key != "api_key"}
print("SerpApi request:", json.dumps(safe_params, sort_keys=True, default=str))
- result = dict(self._client.search(params))
+ response = self._client.search(params)
+ if isinstance(response, str):
+ print(
+ "SerpApi response:",
+ json.dumps(
+ {
+ "engine": safe_params.get("engine"),
+ "format": "markdown",
+ "characters": len(response),
+ },
+ sort_keys=True,
+ ),
+ )
+ return response
+ result = dict(response)
metadata = result.get("search_metadata", {})
print(
"SerpApi response:",
diff --git a/examples/direct_cached_search.py b/examples/direct_cached_search.py
index 69feafc..51b5520 100644
--- a/examples/direct_cached_search.py
+++ b/examples/direct_cached_search.py
@@ -11,7 +11,7 @@
import serpapi
from dotenv import load_dotenv
-from serpapi_search_tools import web_search
+from serpapi_search_tools import SearchResultFormat, web_search
load_dotenv()
@@ -49,6 +49,7 @@ def main() -> None:
client=client,
allowed_engines=["google_light"],
default_params={"hl": "en"},
+ response_format=SearchResultFormat.JSON,
result_limit=3,
)
diff --git a/examples/direct_marketplace_comparison.py b/examples/direct_marketplace_comparison.py
index e8badf5..3fd00e3 100644
--- a/examples/direct_marketplace_comparison.py
+++ b/examples/direct_marketplace_comparison.py
@@ -9,7 +9,7 @@
from dotenv import load_dotenv
-from serpapi_search_tools import shopping_search
+from serpapi_search_tools import SearchResultFormat, shopping_search
load_dotenv()
@@ -43,6 +43,7 @@ def main() -> None:
search = shopping_search(
provider="function",
allowed_engines=[engine],
+ response_format=SearchResultFormat.JSON,
result_limit=3,
)
result = json.loads(search(query="noise cancelling headphones"))
diff --git a/examples/direct_multi_search.py b/examples/direct_multi_search.py
index 98bebd2..d2f527a 100644
--- a/examples/direct_multi_search.py
+++ b/examples/direct_multi_search.py
@@ -9,7 +9,13 @@
from dotenv import load_dotenv
-from serpapi_search_tools import maps_search, news_search, shopping_search, web_search
+from serpapi_search_tools import (
+ SearchResultFormat,
+ maps_search,
+ news_search,
+ shopping_search,
+ web_search,
+)
load_dotenv()
@@ -23,20 +29,24 @@ def main() -> None:
provider="function",
allowed_engines=["google_light"],
default_params={"hl": "en", "gl": "us"},
+ response_format=SearchResultFormat.JSON,
result_limit=3,
)
news = news_search(
provider="function",
default_params={"hl": "en", "gl": "us"},
+ response_format=SearchResultFormat.JSON,
)
maps = maps_search(
provider="function",
default_params={"hl": "en", "gl": "us"},
+ response_format=SearchResultFormat.JSON,
)
shopping = shopping_search(
provider="function",
allowed_engines=["google_shopping"],
default_params={"hl": "en", "gl": "us"},
+ response_format=SearchResultFormat.JSON,
result_limit=3,
)
diff --git a/examples/direct_regioned_search.py b/examples/direct_regioned_search.py
index 62ed0c2..3f78244 100644
--- a/examples/direct_regioned_search.py
+++ b/examples/direct_regioned_search.py
@@ -7,7 +7,7 @@
from dotenv import load_dotenv
-from serpapi_search_tools import web_search
+from serpapi_search_tools import SearchResultFormat, web_search
load_dotenv()
@@ -22,6 +22,7 @@ def main() -> None:
provider="function",
allowed_engines=["google_light"],
default_params={"gl": "us", "hl": "en"},
+ response_format=SearchResultFormat.JSON,
result_limit=3,
include_examples=False,
name="web_search_us",
@@ -30,6 +31,7 @@ def main() -> None:
provider="function",
allowed_engines=["google_light"],
default_params={"gl": "de", "hl": "de"},
+ response_format=SearchResultFormat.JSON,
result_limit=3,
include_examples=False,
name="web_search_de",
diff --git a/examples/direct_search.py b/examples/direct_search.py
index 57c567f..ab858fe 100644
--- a/examples/direct_search.py
+++ b/examples/direct_search.py
@@ -1,5 +1,5 @@
# Run: uv run --isolated --no-project --with serpapi-search-tools --with python-dotenv examples/direct_search.py # noqa: E501
-"""Call SerpApi tools directly without installing an agent framework."""
+"""Compare default Markdown output with explicit JSON output."""
from __future__ import annotations
@@ -7,7 +7,7 @@
from dotenv import load_dotenv
-from serpapi_search_tools import news_search, web_search
+from serpapi_search_tools import SearchResultFormat, news_search, web_search
load_dotenv()
@@ -21,13 +21,15 @@ def main() -> None:
news = news_search(
provider="function",
default_params={"hl": "en", "gl": "us"},
+ response_format=SearchResultFormat.JSON,
)
- web_result = json.loads(web(query="Python packaging"))
+ web_result = web(query="Python packaging")
news_result = json.loads(news(query="Python releases"))
- print("Web results:", len(web_result.get("organic_results", [])))
- print("News results:", len(news_result.get("news_results", [])))
+ print("Default Markdown response:\n")
+ print(web_result)
+ print("JSON news result count:", len(news_result.get("news_results", [])))
if __name__ == "__main__":
diff --git a/examples/direct_travel.py b/examples/direct_travel.py
index 626fe49..feb5212 100644
--- a/examples/direct_travel.py
+++ b/examples/direct_travel.py
@@ -8,7 +8,12 @@
from dotenv import load_dotenv
-from serpapi_search_tools import flights_search, hotels_search, travel_explore_search
+from serpapi_search_tools import (
+ SearchResultFormat,
+ flights_search,
+ hotels_search,
+ travel_explore_search,
+)
load_dotenv()
@@ -17,9 +22,9 @@ def main() -> None:
outbound = date.today() + timedelta(days=60)
returning = outbound + timedelta(days=4)
- hotels = hotels_search(provider="function")
- flights = flights_search(provider="function")
- explore = travel_explore_search(provider="function")
+ hotels = hotels_search(provider="function", response_format=SearchResultFormat.JSON)
+ flights = flights_search(provider="function", response_format=SearchResultFormat.JSON)
+ explore = travel_explore_search(provider="function", response_format=SearchResultFormat.JSON)
hotel_result = hotels(
query="hotels in Austin",
diff --git a/examples/semantic_kernel_openai.py b/examples/semantic_kernel_openai.py
index b6f0b11..d577af5 100644
--- a/examples/semantic_kernel_openai.py
+++ b/examples/semantic_kernel_openai.py
@@ -6,9 +6,12 @@
from dotenv import load_dotenv
from semantic_kernel import Kernel
-from semantic_kernel.agents import ChatCompletionAgent
from semantic_kernel.connectors.ai import FunctionChoiceBehavior
-from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
+from semantic_kernel.connectors.ai.open_ai import (
+ OpenAIChatCompletion,
+ OpenAIChatPromptExecutionSettings,
+)
+from semantic_kernel.functions import KernelArguments
from serpapi_search_tools import maps_search, web_search
@@ -30,26 +33,29 @@ async def main() -> None:
raise RuntimeError("Set SERPAPI_API_KEY or SERPAPI_KEY before running this example.")
kernel = Kernel()
- plugin = kernel.add_functions(
+ kernel.add_service(
+ OpenAIChatCompletion(
+ ai_model_id=MODEL,
+ api_key=_require_env("OPENAI_API_KEY"),
+ )
+ )
+ kernel.add_functions(
"serpapi",
[
maps_search(provider="semantic-kernel"),
web_search(provider="semantic-kernel", allowed_engines=["google_light"]),
],
)
- agent = ChatCompletionAgent(
- name="serpapi_search_agent",
- instructions="Use the SerpApi tools for current search data.",
- service=OpenAIChatCompletion(
- ai_model_id=MODEL,
- api_key=_require_env("OPENAI_API_KEY"),
- ),
- plugins=[plugin],
+ settings = OpenAIChatPromptExecutionSettings(
function_choice_behavior=FunctionChoiceBehavior.Auto(),
)
-
- async for response in agent.invoke(messages=PROMPT):
- print(response)
+ response = await kernel.invoke_prompt(
+ f"Use the SerpApi tools for current search data.\n\n{PROMPT}",
+ arguments=KernelArguments(settings=settings),
+ )
+ if response is None:
+ raise RuntimeError("Semantic Kernel completed without a response.")
+ print(response)
if __name__ == "__main__":
diff --git a/great-docs.yml b/great-docs.yml
index 0a769de..de106f2 100644
--- a/great-docs.yml
+++ b/great-docs.yml
@@ -26,15 +26,15 @@ parser: numpy
# Logo & Favicon
# ---------------
-# Point to a single logo file (replaces the text title in the navbar):
-# logo: assets/logo.svg
-#
-# For light/dark variants:
-# logo:
-# light: assets/logo-light.svg
-# dark: assets/logo-dark.svg
-#
-# To show the text title alongside the logo, add: show_title: true
+# Show the project title beside the official SerpApi mark.
+logo:
+ light: assets/serpapi-logo.svg
+ dark: assets/serpapi-logo.svg
+ show_title: true
+favicon: assets/serpapi-logo.svg
+
+# Keep the authored user-guide homepage instead of generating a logo hero.
+hero: false
# Author Information
# ------------------
@@ -58,37 +58,6 @@ authors:
# homepage: https://posit.co
# ror: https://ror.org/03wc8by49
-# API Reference Structure
-# -----------------------
-# Customize the sections below to organize your API documentation.
-# - Reorder items within a section to change their display order
-# - Move items between sections or create new sections
-# - Use 'members: false' to exclude methods from documentation
-# - Add 'desc:' to sections for descriptions
-
-reference:
- - title: Enumerations and errors
- desc: Supported engines, response modes, semantic travel values, and search failures
- contents:
- - WebSearchEngine
- - ShoppingSearchEngine
- - SearchResultMode
- - TravelClass
- - SerpApiSearchError
-
- - title: Functions
- desc: Create capability-specific search tools for Python and agent SDKs
- contents:
- - web_search
- - news_search
- - maps_search
- - images_search
- - shopping_search
- - videos_search
- - hotels_search
- - flights_search
- - travel_explore_search
-
# Site URL
# --------
# Canonical address of the deployed documentation site.
@@ -128,9 +97,9 @@ site:
# so the same assets work from the homepage and nested documentation pages.
include_in_header:
- text: >-
-
+
- text: >-
-
+
# Jupyter Kernel
# --------------
diff --git a/pyproject.toml b/pyproject.toml
index e863924..e00cb22 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -22,7 +22,7 @@ classifiers = [
"Programming Language :: Python :: 3.14",
"Typing :: Typed",
]
-dependencies = ["serpapi>=1.0.0,<2"]
+dependencies = ["mistune>=3.1.0,<4", "serpapi>=1.0.0,<2"]
[project.urls]
Documentation = "https://serpapi.github.io/serpapi-search-tools-python/"
@@ -86,8 +86,8 @@ dev = [
"uvicorn>=0.34.0,<1",
]
docs = [
- "great-docs>=0.14.0,<0.15; python_version >= '3.11'",
- "griffe>=0.35.0,<1; python_version >= '3.11'",
+ "great-docs>=0.15.0,<0.16; python_version >= '3.11'",
+ "griffe>=2.1.0,<2.2; python_version >= '3.11'",
]
openai-compat = [
"langchain-openai>=1.1.9,<2",
diff --git a/src/serpapi_search_tools/__init__.py b/src/serpapi_search_tools/__init__.py
index 34c0355..0eebebb 100644
--- a/src/serpapi_search_tools/__init__.py
+++ b/src/serpapi_search_tools/__init__.py
@@ -10,7 +10,11 @@
videos_search,
web_search,
)
-from serpapi_search_tools._shared import SearchResultMode, SerpApiSearchError
+from serpapi_search_tools._shared import (
+ SearchResultFormat,
+ SearchResultMode,
+ SerpApiSearchError,
+)
from serpapi_search_tools._travel_tools import (
TravelClass,
flights_search,
@@ -31,6 +35,7 @@
}
__all__ = [
+ "SearchResultFormat",
"SearchResultMode",
"SerpApiSearchError",
"ShoppingSearchEngine",
diff --git a/src/serpapi_search_tools/_query_tools.py b/src/serpapi_search_tools/_query_tools.py
index 503e3ef..6001f3e 100644
--- a/src/serpapi_search_tools/_query_tools.py
+++ b/src/serpapi_search_tools/_query_tools.py
@@ -8,6 +8,7 @@
from serpapi_search_tools._shared import (
ProviderName,
SearchClient,
+ SearchResultFormat,
SearchResultMode,
SearchRuntime,
ToolDefinition,
@@ -77,6 +78,7 @@ def _runtime(
default_params: Mapping[str, Any] | None,
timeout: float | None,
mode: SearchResultMode | str,
+ response_format: SearchResultFormat | str,
result_limit: int | None,
) -> SearchRuntime:
return SearchRuntime(
@@ -85,6 +87,7 @@ def _runtime(
default_params=default_params,
timeout=timeout,
mode=mode,
+ response_format=response_format,
result_limit=result_limit,
)
@@ -273,6 +276,7 @@ def web_search(
default_params: Mapping[str, Any] | None = None,
timeout: float | None = None,
mode: SearchResultMode | str = SearchResultMode.COMPACT,
+ response_format: SearchResultFormat | str = SearchResultFormat.MARKDOWN,
result_limit: int | None = 10,
name: str = "web_search",
) -> Any:
@@ -289,9 +293,9 @@ def web_search(
when it is allowed.
include_examples
Add a short call example to the model-facing description.
- api_key, client, default_params, timeout, mode
+ api_key, client, default_params, timeout, mode, response_format
Runtime authentication, custom client, application filters, timeout, and
- compact or full response selection.
+ response mode and serialization selection.
result_limit
Maximum items kept in each result list in both response modes; use
``None`` to keep all returned results.
@@ -306,7 +310,7 @@ def web_search(
definition = _multi_engine_query_definition(
name=name,
- description="Search general web pages and return focused SerpApi results as JSON.",
+ description="Search general web pages and return focused SerpApi results.",
catalog=WebSearchEngine,
query_params=WEB_QUERY_PARAM_BY_ENGINE,
allowed_engines=allowed_engines,
@@ -325,6 +329,7 @@ def web_search(
default_params=default_params,
timeout=timeout,
mode=mode,
+ response_format=response_format,
result_limit=result_limit,
),
include_examples=include_examples,
@@ -346,6 +351,7 @@ def shopping_search(
default_params: Mapping[str, Any] | None = None,
timeout: float | None = None,
mode: SearchResultMode | str = SearchResultMode.COMPACT,
+ response_format: SearchResultFormat | str = SearchResultFormat.MARKDOWN,
result_limit: int | None = 60,
name: str = "shopping_search",
) -> Any:
@@ -361,9 +367,9 @@ def shopping_search(
Marketplace used when the model omits ``engine``.
include_examples
Add a short call example to the model-facing description.
- api_key, client, default_params, timeout, mode
+ api_key, client, default_params, timeout, mode, response_format
Runtime authentication, custom client, application filters, timeout, and
- compact or full response selection.
+ response mode and serialization selection.
result_limit
Maximum items kept in each result list in both response modes; use
``None`` to keep all returned results.
@@ -378,9 +384,7 @@ def shopping_search(
definition = _multi_engine_query_definition(
name=name,
- description=(
- "Search products, prices, and merchants and return the SerpApi response as JSON."
- ),
+ description="Search products, prices, and merchants with SerpApi.",
catalog=ShoppingSearchEngine,
query_params=SHOPPING_QUERY_PARAM_BY_ENGINE,
allowed_engines=allowed_engines,
@@ -398,6 +402,7 @@ def shopping_search(
default_params=default_params,
timeout=timeout,
mode=mode,
+ response_format=response_format,
result_limit=result_limit,
),
include_examples=include_examples,
@@ -417,6 +422,7 @@ def _fixed_query_factory(
default_params: Mapping[str, Any] | None,
timeout: float | None,
mode: SearchResultMode | str,
+ response_format: SearchResultFormat | str,
result_limit: int | None,
name: str,
validator: Any = None,
@@ -432,6 +438,7 @@ def _fixed_query_factory(
default_params=default_params,
timeout=timeout,
mode=mode,
+ response_format=response_format,
result_limit=result_limit,
),
include_examples=include_examples,
@@ -498,6 +505,7 @@ def news_search(
default_params: Mapping[str, Any] | None = None,
timeout: float | None = None,
mode: SearchResultMode | str = SearchResultMode.COMPACT,
+ response_format: SearchResultFormat | str = SearchResultFormat.MARKDOWN,
result_limit: int | None = 20,
name: str = "news_search",
) -> Any:
@@ -509,9 +517,9 @@ def news_search(
Agent SDK adapter name, ``"auto"``, or ``"function"``.
include_examples
Add a short call example to the model-facing description.
- api_key, client, default_params, timeout, mode
+ api_key, client, default_params, timeout, mode, response_format
Runtime authentication, custom client, application filters, timeout, and
- compact or full response selection.
+ response mode and serialization selection.
result_limit
Maximum items kept in each result list in both response modes; use
``None`` to keep all returned results.
@@ -535,6 +543,7 @@ def news_search(
default_params=default_params,
timeout=timeout,
mode=mode,
+ response_format=response_format,
result_limit=result_limit,
name=name,
validator=_validate_news_query_mode,
@@ -550,6 +559,7 @@ def images_search(
default_params: Mapping[str, Any] | None = None,
timeout: float | None = None,
mode: SearchResultMode | str = SearchResultMode.COMPACT,
+ response_format: SearchResultFormat | str = SearchResultFormat.MARKDOWN,
result_limit: int | None = 50,
name: str = "images_search",
) -> Any:
@@ -561,9 +571,9 @@ def images_search(
Agent SDK adapter name, ``"auto"``, or ``"function"``.
include_examples
Add a short call example to the model-facing description.
- api_key, client, default_params, timeout, mode
+ api_key, client, default_params, timeout, mode, response_format
Runtime authentication, custom client, application filters, timeout, and
- compact or full response selection.
+ response mode and serialization selection.
result_limit
Maximum items kept in each result list in both response modes; use
``None`` to keep all returned results.
@@ -587,6 +597,7 @@ def images_search(
default_params=default_params,
timeout=timeout,
mode=mode,
+ response_format=response_format,
result_limit=result_limit,
name=name,
validator=_validate_images_query_mode,
@@ -602,6 +613,7 @@ def videos_search(
default_params: Mapping[str, Any] | None = None,
timeout: float | None = None,
mode: SearchResultMode | str = SearchResultMode.COMPACT,
+ response_format: SearchResultFormat | str = SearchResultFormat.MARKDOWN,
result_limit: int | None = 10,
name: str = "videos_search",
) -> Any:
@@ -613,9 +625,9 @@ def videos_search(
Agent SDK adapter name, ``"auto"``, or ``"function"``.
include_examples
Add a short call example to the model-facing description.
- api_key, client, default_params, timeout, mode
+ api_key, client, default_params, timeout, mode, response_format
Runtime authentication, custom client, application filters, timeout, and
- compact or full response selection.
+ response mode and serialization selection.
result_limit
Maximum items kept in each result list in both response modes; use
``None`` to keep all returned results.
@@ -639,6 +651,7 @@ def videos_search(
default_params=default_params,
timeout=timeout,
mode=mode,
+ response_format=response_format,
result_limit=result_limit,
name=name,
)
@@ -653,6 +666,7 @@ def maps_search(
default_params: Mapping[str, Any] | None = None,
timeout: float | None = None,
mode: SearchResultMode | str = SearchResultMode.COMPACT,
+ response_format: SearchResultFormat | str = SearchResultFormat.MARKDOWN,
result_limit: int | None = 10,
name: str = "maps_search",
) -> Any:
@@ -668,9 +682,9 @@ def maps_search(
Agent SDK adapter name, ``"auto"``, or ``"function"``.
include_examples
Add a short call example to the model-facing description.
- api_key, client, default_params, timeout, mode
+ api_key, client, default_params, timeout, mode, response_format
Runtime authentication, custom client, application filters, timeout, and
- compact or full response selection.
+ response mode and serialization selection.
result_limit
Maximum items kept in each result list in both response modes; use
``None`` to keep all returned results.
@@ -689,6 +703,7 @@ def maps_search(
default_params=default_params,
timeout=timeout,
mode=mode,
+ response_format=response_format,
result_limit=result_limit,
)
diff --git a/src/serpapi_search_tools/_shared.py b/src/serpapi_search_tools/_shared.py
index d0a1752..883563e 100644
--- a/src/serpapi_search_tools/_shared.py
+++ b/src/serpapi_search_tools/_shared.py
@@ -3,12 +3,16 @@
import json
import os
from collections.abc import Callable, Iterable, Mapping
+from copy import deepcopy
from dataclasses import dataclass, field
from datetime import date
from enum import Enum
from threading import RLock, local
from typing import Any, Protocol, TypeAlias, cast
+import mistune
+from mistune.renderers.markdown import MarkdownRenderer
+
from serpapi_search_tools._providers import (
PROVIDER_ALIASES,
ProviderName,
@@ -19,6 +23,7 @@
__all__ = [
"PROVIDER_ALIASES",
"ProviderName",
+ "SearchResultFormat",
"SearchResultMode",
"SerpApiSearchError",
"detect_provider",
@@ -92,7 +97,7 @@
"yahoo": ("answer_box", "knowledge_graph", "organic_results"),
"duckduckgo": ("knowledge_graph", "organic_results"),
"google_news": ("news_results",),
- "google_maps": ("local_results",),
+ "google_maps": ("local_results", "place_results"),
"google_images": ("images_results",),
"google_shopping": ("shopping_results",),
"amazon": ("organic_results",),
@@ -110,6 +115,72 @@
"google_flights": ("best_flights", "other_flights"),
"google_travel_explore": ("destinations",),
}
+_COMPACT_MARKDOWN_HEADINGS_BY_ENGINE: Mapping[str, tuple[str, ...]] = {
+ "google": ("Answer Box", "Knowledge Graph", "AI Overview", "Organic Results"),
+ "google_light": (
+ "Answer Box",
+ "Knowledge Graph",
+ "Organic Results",
+ "Related Questions",
+ "Related Searches",
+ "Top Stories",
+ ),
+ "bing": ("Answer Box", "Knowledge Graph", "Copilot Answer", "Organic Results"),
+ "yahoo": ("Answer Box", "Knowledge Graph", "Organic Results"),
+ "duckduckgo": ("Knowledge Graph", "Organic Results"),
+ "google_news": ("News Results",),
+ "google_maps": ("Local Results", "Place Results"),
+ "google_images": ("Images Results",),
+ "google_shopping": ("Shopping Results",),
+ "amazon": ("Organic Results",),
+ "walmart": ("Organic Results",),
+ "ebay": ("Organic Results",),
+ "youtube": (
+ "Video Results",
+ "Shorts Results",
+ "Channel Results",
+ "Playlist Results",
+ "Movie Results",
+ "Category Results",
+ ),
+ "google_hotels": ("Properties",),
+ "google_flights": ("Best Flights", "Other Flights"),
+ "google_travel_explore": ("Destinations",),
+}
+_LIMITED_MARKDOWN_HEADINGS_BY_ENGINE: Mapping[str, frozenset[str]] = {
+ "google": frozenset({"Organic Results"}),
+ "google_light": frozenset(
+ {"Organic Results", "Related Questions", "Related Searches", "Top Stories"}
+ ),
+ "bing": frozenset({"Organic Results"}),
+ "yahoo": frozenset({"Organic Results"}),
+ "duckduckgo": frozenset({"Organic Results"}),
+ "google_news": frozenset({"News Results"}),
+ "google_maps": frozenset({"Local Results"}),
+ "google_images": frozenset({"Images Results"}),
+ "google_shopping": frozenset({"Shopping Results"}),
+ "amazon": frozenset({"Organic Results"}),
+ "walmart": frozenset({"Organic Results"}),
+ "ebay": frozenset({"Organic Results"}),
+ "youtube": frozenset(
+ {
+ "Video Results",
+ "Shorts Results",
+ "Channel Results",
+ "Playlist Results",
+ "Movie Results",
+ "Category Results",
+ }
+ ),
+ "google_hotels": frozenset({"Properties"}),
+ "google_flights": frozenset({"Best Flights", "Other Flights"}),
+ "google_travel_explore": frozenset({"Destinations"}),
+}
+_COMPACT_MARKDOWN_DROPPED_COLUMNS_BY_ENGINE: Mapping[str, frozenset[str]] = {
+ "google_images": frozenset({"Related Content Id"}),
+ "walmart": frozenset({"Seller Id"}),
+ "ebay": frozenset({"Buying Format Text"}),
+}
class SerpApiSearchError(RuntimeError):
@@ -123,10 +194,17 @@ class SearchResultMode(str, Enum):
FULL = "full"
+class SearchResultFormat(str, Enum):
+ """Select the serialization returned by SerpApi and the tool."""
+
+ MARKDOWN = "markdown"
+ JSON = "json"
+
+
class SearchClient(Protocol):
"""Small client contract accepted by every search-tool factory."""
- def search(self, params: dict[str, Any]) -> Mapping[str, Any]: ...
+ def search(self, params: dict[str, Any]) -> Mapping[str, Any] | str: ...
@dataclass(frozen=True)
@@ -148,6 +226,7 @@ class SearchRuntime:
default_params: Mapping[str, Any] | None = None
timeout: float | None = None
mode: SearchResultMode | str = SearchResultMode.COMPACT
+ response_format: SearchResultFormat | str = SearchResultFormat.MARKDOWN
result_limit: int | None = _DEFAULT_RESULT_LIMIT
_builtin_clients: Any = field(init=False, default_factory=local, repr=False)
_builtin_client_lock: Any = field(init=False, default_factory=RLock, repr=False)
@@ -164,6 +243,11 @@ def __post_init__(self) -> None:
except ValueError as exc:
choices = ", ".join(member.value for member in SearchResultMode)
raise ValueError(f"mode must be one of: {choices}.") from exc
+ try:
+ self.response_format = SearchResultFormat(self.response_format)
+ except ValueError as exc:
+ choices = ", ".join(member.value for member in SearchResultFormat)
+ raise ValueError(f"response_format must be one of: {choices}.") from exc
if self.result_limit is not None:
if isinstance(self.result_limit, bool) or not isinstance(self.result_limit, int):
raise ValueError("result_limit must be a positive integer or None.")
@@ -186,6 +270,8 @@ def execute(
params["engine"] = engine
if validator is not None:
validator(params)
+ if self.response_format is SearchResultFormat.MARKDOWN:
+ params["output"] = "md"
client = self._client()
try:
@@ -196,6 +282,17 @@ def execute(
message = _sanitized_provider_error(exc, api_key=api_key)
raise SerpApiSearchError(f"SerpApi request failed: {message}") from None
raise SerpApiSearchError("Custom search client request failed.") from None
+ if self.response_format is SearchResultFormat.MARKDOWN:
+ if not isinstance(result, str):
+ raise TypeError("Search client must return str when response_format='markdown'.")
+ return _format_markdown_result(
+ result,
+ engine=engine,
+ mode=cast(SearchResultMode, self.mode),
+ result_limit=self.result_limit,
+ )
+ if not isinstance(result, Mapping):
+ raise TypeError("Search client must return a mapping when response_format='json'.")
plain_result = dict(result)
plain_result = _limit_result_lists(
plain_result,
@@ -264,6 +361,145 @@ def _sanitized_provider_error(exc: Exception, *, api_key: str | None) -> str:
return message
+def _format_markdown_result(
+ result: str,
+ *,
+ engine: str,
+ mode: SearchResultMode,
+ result_limit: int | None,
+) -> str:
+ if mode is SearchResultMode.FULL and result_limit is None:
+ return result
+
+ frontmatter, body = _split_markdown_frontmatter(result)
+ parser = mistune.create_markdown(renderer=None, plugins=["table"])
+ tokens, state = parser.parse(body)
+ if not isinstance(tokens, list):
+ raise TypeError("Markdown parser returned an unsupported token stream.")
+
+ transformed, found_compact_section = _transform_markdown_tokens(
+ tokens,
+ engine=engine,
+ compact=mode is SearchResultMode.COMPACT,
+ result_limit=result_limit,
+ )
+ if mode is SearchResultMode.COMPACT and not found_compact_section:
+ return body.lstrip("\n")
+
+ rendered = MarkdownRenderer()(transformed, state)
+ if mode is SearchResultMode.COMPACT:
+ compact = rendered.strip()
+ return f"{compact}\n" if compact else ""
+ return f"{frontmatter}{rendered}"
+
+
+def _split_markdown_frontmatter(result: str) -> tuple[str, str]:
+ if not result.startswith("---\n"):
+ return "", result
+ closing = result.find("\n---\n", 4)
+ if closing < 0:
+ return "", result
+ body_start = closing + len("\n---\n")
+ return result[:body_start], result[body_start:]
+
+
+def _transform_markdown_tokens(
+ source_tokens: list[dict[str, Any]],
+ *,
+ engine: str,
+ compact: bool,
+ result_limit: int | None,
+) -> tuple[list[dict[str, Any]], bool]:
+ wanted_headings = set(_COMPACT_MARKDOWN_HEADINGS_BY_ENGINE.get(engine, ()))
+ limited_headings = _LIMITED_MARKDOWN_HEADINGS_BY_ENGINE.get(engine, frozenset())
+ dropped_columns = _COMPACT_MARKDOWN_DROPPED_COLUMNS_BY_ENGINE.get(engine, frozenset())
+ transformed: list[dict[str, Any]] = []
+ current_heading: str | None = None
+ result_table_limited = False
+ inside_detail_section = False
+ keep = not compact
+ found_compact_section = False
+
+ for source_token in source_tokens:
+ token = deepcopy(source_token)
+ if token.get("type") == "heading":
+ heading_level = token.get("attrs", {}).get("level")
+ if heading_level == 2:
+ current_heading = _markdown_inline_text(token)
+ result_table_limited = False
+ inside_detail_section = False
+ if compact:
+ keep = current_heading in wanted_headings or current_heading == "Error"
+ found_compact_section = found_compact_section or keep
+ elif isinstance(heading_level, int) and heading_level > 2:
+ inside_detail_section = True
+ if not keep:
+ continue
+ if token.get("type") == "table":
+ if (
+ result_limit is not None
+ and current_heading in limited_headings
+ and not result_table_limited
+ and not inside_detail_section
+ ):
+ _limit_markdown_table(token, result_limit=result_limit)
+ result_table_limited = True
+ if compact and dropped_columns:
+ _drop_markdown_table_columns(token, dropped_columns=dropped_columns)
+ transformed.append(token)
+
+ return transformed, found_compact_section
+
+
+def _markdown_inline_text(token: Mapping[str, Any]) -> str:
+ raw = token.get("raw")
+ if raw is not None:
+ return str(raw)
+ children = token.get("children", [])
+ if not isinstance(children, list):
+ return ""
+ return "".join(_markdown_inline_text(child) for child in children if isinstance(child, Mapping))
+
+
+def _limit_markdown_table(token: dict[str, Any], *, result_limit: int) -> None:
+ for child in token.get("children", []):
+ if child.get("type") == "table_body":
+ child["children"] = child.get("children", [])[:result_limit]
+
+
+def _drop_markdown_table_columns(
+ token: dict[str, Any],
+ *,
+ dropped_columns: frozenset[str],
+) -> None:
+ children = token.get("children", [])
+ head = next(
+ (child for child in children if child.get("type") == "table_head"),
+ None,
+ )
+ if head is None:
+ return
+ dropped_indices = {
+ index
+ for index, cell in enumerate(head.get("children", []))
+ if _markdown_inline_text(cell) in dropped_columns
+ }
+ if not dropped_indices:
+ return
+ head["children"] = [
+ cell for index, cell in enumerate(head.get("children", [])) if index not in dropped_indices
+ ]
+ for child in children:
+ if child.get("type") != "table_body":
+ continue
+ for row in child.get("children", []):
+ row["children"] = [
+ cell
+ for index, cell in enumerate(row.get("children", []))
+ if index not in dropped_indices
+ ]
+
+
def _compact_result(
result: Mapping[str, Any],
*,
diff --git a/src/serpapi_search_tools/_travel_tools.py b/src/serpapi_search_tools/_travel_tools.py
index 5b16851..5eaf2d6 100644
--- a/src/serpapi_search_tools/_travel_tools.py
+++ b/src/serpapi_search_tools/_travel_tools.py
@@ -8,6 +8,7 @@
from serpapi_search_tools._shared import (
ProviderName,
SearchClient,
+ SearchResultFormat,
SearchResultMode,
SearchRuntime,
ToolDefinition,
@@ -43,6 +44,7 @@ def _runtime(
default_params: Mapping[str, Any] | None,
timeout: float | None,
mode: SearchResultMode | str,
+ response_format: SearchResultFormat | str,
result_limit: int | None,
) -> SearchRuntime:
return SearchRuntime(
@@ -51,6 +53,7 @@ def _runtime(
default_params=default_params,
timeout=timeout,
mode=mode,
+ response_format=response_format,
result_limit=result_limit,
)
@@ -164,6 +167,7 @@ def hotels_search(
default_params: Mapping[str, Any] | None = None,
timeout: float | None = None,
mode: SearchResultMode | str = SearchResultMode.COMPACT,
+ response_format: SearchResultFormat | str = SearchResultFormat.MARKDOWN,
result_limit: int | None = 20,
name: str = "hotels_search",
) -> Any:
@@ -178,9 +182,9 @@ def hotels_search(
Agent SDK adapter name, ``"auto"``, or ``"function"``.
include_examples
Add a short call example to the model-facing description.
- api_key, client, default_params, timeout, mode
+ api_key, client, default_params, timeout, mode, response_format
Runtime authentication, custom client, application filters, timeout, and
- compact or full response selection.
+ response mode and serialization selection.
result_limit
Maximum items kept in each result list in both response modes; use
``None`` to keep all returned results.
@@ -199,6 +203,7 @@ def hotels_search(
default_params=default_params,
timeout=timeout,
mode=mode,
+ response_format=response_format,
result_limit=result_limit,
)
@@ -303,6 +308,7 @@ def flights_search(
default_params: Mapping[str, Any] | None = None,
timeout: float | None = None,
mode: SearchResultMode | str = SearchResultMode.COMPACT,
+ response_format: SearchResultFormat | str = SearchResultFormat.MARKDOWN,
result_limit: int | None = 10,
name: str = "flights_search",
) -> Any:
@@ -318,9 +324,9 @@ def flights_search(
Agent SDK adapter name, ``"auto"``, or ``"function"``.
include_examples
Add a short call example to the model-facing description.
- api_key, client, default_params, timeout, mode
+ api_key, client, default_params, timeout, mode, response_format
Runtime authentication, custom client, application filters, timeout, and
- compact or full response selection.
+ response mode and serialization selection.
result_limit
Maximum items kept in each result list in both response modes; use
``None`` to keep all returned results.
@@ -339,6 +345,7 @@ def flights_search(
default_params=default_params,
timeout=timeout,
mode=mode,
+ response_format=response_format,
result_limit=result_limit,
)
@@ -462,6 +469,7 @@ def travel_explore_search(
default_params: Mapping[str, Any] | None = None,
timeout: float | None = None,
mode: SearchResultMode | str = SearchResultMode.COMPACT,
+ response_format: SearchResultFormat | str = SearchResultFormat.MARKDOWN,
result_limit: int | None = 50,
name: str = "travel_explore_search",
) -> Any:
@@ -477,9 +485,9 @@ def travel_explore_search(
Agent SDK adapter name, ``"auto"``, or ``"function"``.
include_examples
Add a short call example to the model-facing description.
- api_key, client, default_params, timeout, mode
+ api_key, client, default_params, timeout, mode, response_format
Runtime authentication, custom client, application filters, timeout, and
- compact or full response selection.
+ response mode and serialization selection.
result_limit
Maximum items kept in each result list in both response modes; use
``None`` to keep all returned results.
@@ -498,6 +506,7 @@ def travel_explore_search(
default_params=default_params,
timeout=timeout,
mode=mode,
+ response_format=response_format,
result_limit=result_limit,
)
diff --git a/tests/clean_install_smoke.py b/tests/clean_install_smoke.py
index 37a4d90..2d3714e 100644
--- a/tests/clean_install_smoke.py
+++ b/tests/clean_install_smoke.py
@@ -9,7 +9,7 @@
import serpapi
import serpapi.models
-from serpapi_search_tools import flights_search, web_search
+from serpapi_search_tools import SearchResultFormat, flights_search, web_search
AGENT_SDK_DISTRIBUTIONS = (
"agno",
@@ -30,12 +30,13 @@
class _Response:
- text = ""
-
- def __init__(self, result: dict[str, Any]) -> None:
+ def __init__(self, result: dict[str, Any] | str) -> None:
self._result = result
+ self.text = result if isinstance(result, str) else ""
def json(self) -> dict[str, Any]:
+ if isinstance(self._result, str):
+ raise ValueError("response is Markdown")
return self._result
@@ -51,6 +52,7 @@ def _fake_request(
assert method == "GET"
assert path == "/search"
assert params in (
+ {"engine": "google_light", "q": "coffee", "output": "md"},
{"engine": "google_light", "q": "coffee"},
{
"engine": "google_flights",
@@ -66,6 +68,18 @@ def _fake_request(
},
)
assert kwargs == {}
+ if params.get("output") == "md":
+ return _Response(
+ "---\nsearch_metadata:\n status: Success\n---\n\n"
+ "## Organic Results\n\n"
+ "| Position | Title | Link |\n"
+ "| --- | --- | --- |\n"
+ "| 1 | Coffee | https://example.com/coffee |\n\n"
+ "## Related Searches\n\n"
+ "| Query |\n"
+ "| --- |\n"
+ "| tea |\n"
+ )
if params["engine"] == "google_flights":
return _Response(
{
@@ -104,7 +118,19 @@ def main() -> None:
)
assert callable(tool), "provider='auto' must fall back to a plain callable"
- encoded = tool(query="coffee")
+ markdown = tool(query="coffee")
+
+ assert markdown.startswith("## Organic Results")
+ assert "| 1 | Coffee | https://example.com/coffee |" in markdown
+ assert "## Related Searches" in markdown
+ assert "search_metadata" not in markdown
+
+ json_tool = web_search(
+ allowed_engines=["google_light"],
+ api_key="not-a-real-key",
+ response_format=SearchResultFormat.JSON,
+ )
+ encoded = json_tool(query="coffee")
decoded = json.loads(encoded)
assert type(decoded) is dict
@@ -117,7 +143,11 @@ def main() -> None:
assert "\x1b[" not in encoded
assert "\n" not in encoded
- flight = flights_search(provider="function", api_key="not-a-real-key")
+ flight = flights_search(
+ provider="function",
+ api_key="not-a-real-key",
+ response_format=SearchResultFormat.JSON,
+ )
flight_encoded = flight(
departure_id="LAX",
arrival_id="AUS",
diff --git a/tests/integration_agents/conftest.py b/tests/integration_agents/conftest.py
index 31c2ab3..eb09d1e 100644
--- a/tests/integration_agents/conftest.py
+++ b/tests/integration_agents/conftest.py
@@ -18,7 +18,7 @@
class RecordingSearchClient:
calls: list[dict[str, Any]] = field(default_factory=list)
- def search(self, params: dict[str, Any]) -> Mapping[str, Any]:
+ def search(self, params: dict[str, Any]) -> Mapping[str, Any] | str:
call = dict(params)
self.calls.append(call)
primary_key = {
@@ -31,6 +31,24 @@ def search(self, params: dict[str, Any]) -> Mapping[str, Any]:
"google_flights": "best_flights",
"google_travel_explore": "destinations",
}.get(str(call["engine"]), "organic_results")
+ if call.get("output") == "md":
+ heading = {
+ "news_results": "News Results",
+ "local_results": "Local Results",
+ "images_results": "Images Results",
+ "shopping_results": "Shopping Results",
+ "video_results": "Video Results",
+ "properties": "Properties",
+ "best_flights": "Best Flights",
+ "destinations": "Destinations",
+ }.get(primary_key, "Organic Results")
+ return (
+ "---\nsearch_metadata:\n status: Success\n---\n\n"
+ f"## {heading}\n\n"
+ "| Title | Link |\n"
+ "| --- | --- |\n"
+ f"| Fake result for {call} | https://example.com/result |\n"
+ )
return {
"search_metadata": {"status": "Success"},
"search_parameters": call,
diff --git a/tests/integration_agents/provider_helpers.py b/tests/integration_agents/provider_helpers.py
index 2709076..0a4c4bf 100644
--- a/tests/integration_agents/provider_helpers.py
+++ b/tests/integration_agents/provider_helpers.py
@@ -32,6 +32,7 @@
"crewai",
"autogen",
"microsoft-agent-framework",
+ "semantic-kernel",
"haystack",
"llamaindex",
"google-adk",
@@ -47,6 +48,7 @@
"crewai": "crewai",
"autogen": "autogen_agentchat.agents",
"microsoft-agent-framework": "agent_framework",
+ "semantic-kernel": "semantic_kernel",
"haystack": "haystack.components.agents",
"llamaindex": "llama_index.core.agent.workflow",
"google-adk": "google.adk.agents",
@@ -165,6 +167,16 @@ def run_agent_provider(
client=client,
serpapi_api_key=serpapi_api_key,
)
+ if provider == "semantic-kernel":
+ return _run_semantic_kernel(
+ base_url=base_url,
+ api_key=api_key,
+ model=model,
+ prompt=prompt,
+ tool_names=tool_names,
+ client=client,
+ serpapi_api_key=serpapi_api_key,
+ )
if provider == "haystack":
return _run_haystack(
base_url=base_url,
@@ -532,6 +544,50 @@ def _run_microsoft_agent_framework(
return asyncio.run(agent.run(prompt))
+def _run_semantic_kernel(
+ *,
+ base_url: str,
+ api_key: str,
+ model: str,
+ prompt: str,
+ tool_names: Iterable[str],
+ client: Any | None,
+ serpapi_api_key: str | None,
+) -> Any:
+ semantic_kernel = import_optional("semantic_kernel")
+ semantic_ai = import_optional("semantic_kernel.connectors.ai")
+ semantic_openai = import_optional("semantic_kernel.connectors.ai.open_ai")
+ semantic_functions = import_optional("semantic_kernel.functions")
+ openai = import_optional("openai")
+
+ async def run_kernel() -> Any:
+ kernel = semantic_kernel.Kernel()
+ kernel.add_service(
+ semantic_openai.OpenAIChatCompletion(
+ ai_model_id=model,
+ async_client=openai.AsyncOpenAI(api_key=api_key, base_url=base_url),
+ )
+ )
+ kernel.add_functions(
+ "serpapi",
+ _tools(
+ "semantic-kernel",
+ tool_names=tool_names,
+ client=client,
+ serpapi_api_key=serpapi_api_key,
+ ),
+ )
+ settings = semantic_openai.OpenAIChatPromptExecutionSettings(
+ function_choice_behavior=semantic_ai.FunctionChoiceBehavior.Auto(),
+ )
+ return await kernel.invoke_prompt(
+ prompt,
+ arguments=semantic_functions.KernelArguments(settings=settings),
+ )
+
+ return asyncio.run(run_kernel())
+
+
def _run_haystack(
*,
base_url: str,
diff --git a/tests/integration_agents/test_agent_provider_smoke.py b/tests/integration_agents/test_agent_provider_smoke.py
index 0ef2b98..b05a5b3 100644
--- a/tests/integration_agents/test_agent_provider_smoke.py
+++ b/tests/integration_agents/test_agent_provider_smoke.py
@@ -42,6 +42,15 @@
{"query": "Python releases", "engine": "google_light"},
"google_light",
),
+ "semantic-kernel": (
+ "flights_search",
+ {
+ "departure_id": "LAX",
+ "arrival_id": "AUS",
+ "outbound_date": "2026-08-01",
+ },
+ "google_flights",
+ ),
"haystack": ("maps_search", {"query": "coffee", "location": "Austin, Texas"}, "google_maps"),
"llamaindex": ("travel_explore_search", {"departure_id": "JFK"}, "google_travel_explore"),
"google-adk": ("web_search", {"query": "coffee", "engine": "google_light"}, "google_light"),
@@ -56,13 +65,14 @@ def test_each_agent_sdk_invokes_a_dedicated_public_tool(
) -> None:
import_optional(PROVIDER_IMPORTS[provider])
tool_name, arguments, expected_engine = PROVIDER_CASES[provider]
+ model_tool_name = f"serpapi-{tool_name}" if provider == "semantic-kernel" else tool_name
result = run_agent_provider(
provider,
base_url=f"{fake_openai_server.url}/v1",
api_key="fake-key",
model="gpt-4o-mini",
- prompt=prompt_for_tool(tool_name, arguments),
+ prompt=prompt_for_tool(model_tool_name, arguments),
tool_names=[tool_name],
client=serpapi_client,
)
diff --git a/tests/integration_agents/test_non_openai_adapter_invocation.py b/tests/integration_agents/test_non_openai_adapter_invocation.py
index a1db651..bae68c4 100644
--- a/tests/integration_agents/test_non_openai_adapter_invocation.py
+++ b/tests/integration_agents/test_non_openai_adapter_invocation.py
@@ -1,7 +1,6 @@
from __future__ import annotations
import asyncio
-import json
import pytest
from optional_dependencies import import_optional
@@ -27,18 +26,20 @@ def test_claude_agent_sdk_handler_invokes_structured_hotel_tool(serpapi_client)
assert serpapi_client.calls[0]["engine"] == "google_hotels"
assert serpapi_client.calls[0]["check_in_date"] == "2026-08-01"
- payload = json.loads(result["content"][0]["text"])
- assert payload["properties"]
- assert "search_parameters" not in payload
+ output = result["content"][0]["text"]
+ assert output.startswith("## Properties")
+ assert "Fake result" in output
+ assert "search_metadata" not in output
def test_semantic_kernel_function_invokes_structured_flight_tool(serpapi_client) -> None:
import_optional("semantic_kernel.functions")
tool = flights_search(provider="semantic-kernel", client=serpapi_client)
- result = json.loads(tool(departure_id="LAX", arrival_id="AUS", outbound_date="2026-08-01"))
+ result = tool(departure_id="LAX", arrival_id="AUS", outbound_date="2026-08-01")
assert serpapi_client.calls[0]["engine"] == "google_flights"
assert "q" not in serpapi_client.calls[0]
- assert result["best_flights"]
- assert "search_parameters" not in result
+ assert result.startswith("## Best Flights")
+ assert "Fake result" in result
+ assert "search_metadata" not in result
diff --git a/tests/test_adapters.py b/tests/test_adapters.py
index b487700..97068dd 100644
--- a/tests/test_adapters.py
+++ b/tests/test_adapters.py
@@ -12,14 +12,16 @@
import serpapi_search_tools._adapters as adapters
from serpapi_search_tools import flights_search, hotels_search, maps_search, web_search
+MARKDOWN_RESULT = "## Result\n\nNo fixture data.\n"
+
class FakeClient:
def __init__(self) -> None:
self.calls: list[dict[str, object]] = []
- def search(self, params: dict[str, object]) -> dict[str, object]:
- self.calls.append(params)
- return {"params": params}
+ def search(self, params: dict[str, object]) -> str:
+ self.calls.append({key: value for key, value in params.items() if key != "output"})
+ return MARKDOWN_RESULT
class CoordinatedClient:
@@ -33,11 +35,11 @@ def __init__(
self.search_started = search_started
self.release_search = release_search
- def search(self, params: dict[str, object]) -> dict[str, object]:
+ def search(self, params: dict[str, object]) -> str:
self.search_started.set()
self.release_search.wait(timeout=1)
self.events.append("search-finished")
- return {"params": params}
+ return MARKDOWN_RESULT
class StructuredTool:
@@ -323,7 +325,7 @@ def decorate(func):
"check_out_date",
]
assert tool_value["schema"]["properties"]["children_ages"]["type"] == "array"
- assert json.loads(result["content"][0]["text"]) == {"no_results": True}
+ assert result["content"][0]["text"] == MARKDOWN_RESULT
assert client.calls[0]["children_ages"] == "8"
@@ -503,7 +505,7 @@ def __init__(self) -> None:
]
assert tool.inputs["return_date"]["nullable"] is True
assert tool.inputs["travel_class"]["nullable"] is True
- assert json.loads(encoded) == {"no_results": True}
+ assert encoded == MARKDOWN_RESULT
assert client.calls[0]["type"] == 2
diff --git a/tests/test_cookbook.py b/tests/test_cookbook.py
index fe2a634..3cacab4 100644
--- a/tests/test_cookbook.py
+++ b/tests/test_cookbook.py
@@ -64,21 +64,6 @@ def test_cookbook_covers_every_public_search_constructor() -> None:
assert calls == PUBLIC_FACTORIES
-def test_cookbook_environment_template_matches_the_scripts() -> None:
- sample = (COOKBOOK / "sample.env").read_text()
-
- for name in (
- "SERPAPI_API_KEY",
- "OPENAI_API_KEY",
- "XAI_API_KEY",
- "ANTHROPIC_API_KEY",
- "GEMINI_API_KEY",
- "COOKBOOK_PROMPT",
- "COOKBOOK_OUTPUT_DIR",
- ):
- assert f"{name}=" in sample
-
-
def test_cookbook_docs_cover_every_supported_provider() -> None:
assert (COOKBOOK_DOCS / "index.qmd").is_file()
pages = {path.stem for path in COOKBOOK_DOCS.glob("*.qmd") if path.name != "index.qmd"}
diff --git a/tests/test_live.py b/tests/test_live.py
index 9e977b1..c6777d3 100644
--- a/tests/test_live.py
+++ b/tests/test_live.py
@@ -10,6 +10,7 @@
import pytest
from serpapi_search_tools import (
+ SearchResultFormat,
SearchResultMode,
SerpApiSearchError,
TravelClass,
@@ -125,6 +126,25 @@
"travel-explore": (("name",), ("destination_id", "flight_price")),
}
+MARKDOWN_RESULT_HEADINGS: dict[str, tuple[str, ...]] = {
+ "web-google": ("Organic Results",),
+ "web-google-light": ("Organic Results",),
+ "web-bing": ("Organic Results",),
+ "web-yahoo": ("Organic Results",),
+ "web-duckduckgo": ("Organic Results",),
+ "news": ("News Results",),
+ "maps": ("Local Results",),
+ "images": ("Images Results",),
+ "shopping-google": ("Shopping Results",),
+ "shopping-amazon": ("Organic Results",),
+ "shopping-walmart": ("Organic Results",),
+ "shopping-ebay": ("Organic Results",),
+ "videos": ("Video Results", "Shorts Results"),
+ "hotels": ("Properties",),
+ "flights": ("Best Flights", "Other Flights"),
+ "travel-explore": ("Destinations",),
+}
+
@pytest.fixture(scope="session", autouse=True)
def _write_response_key_inventory() -> Iterable[None]:
@@ -178,9 +198,72 @@ def test_live_public_tool_request_contracts(
assert parameters["arrival_area_id"] == "/m/0852h"
+@pytest.mark.parametrize(
+ ("case", "engine", "native_field", "native_value", "result_key"), ENGINE_CASES
+)
+def test_live_default_compact_markdown_honors_result_limit(
+ case: str,
+ engine: str,
+ native_field: str,
+ native_value: str,
+ result_key: str,
+) -> None:
+ del engine, native_field, native_value, result_key
+ markdown = _call_live_case(
+ case,
+ response_format=None,
+ mode=SearchResultMode.COMPACT,
+ result_limit=2,
+ )
+
+ assert isinstance(markdown, str)
+ assert markdown.strip()
+ assert not markdown.lstrip().startswith("---")
+ present_headings = [
+ heading for heading in MARKDOWN_RESULT_HEADINGS[case] if f"## {heading}" in markdown
+ ]
+ assert present_headings, (case, markdown[:500])
+ for heading in present_headings:
+ row_count = _markdown_table_row_count(markdown, heading)
+ assert 1 <= row_count <= 2, (case, heading, row_count)
+
+
+@pytest.mark.parametrize(
+ ("case", "engine", "native_field", "native_value", "result_key"), ENGINE_CASES
+)
+def test_live_full_markdown_honors_result_limit_and_preserves_context(
+ case: str,
+ engine: str,
+ native_field: str,
+ native_value: str,
+ result_key: str,
+) -> None:
+ del engine, native_field, native_value, result_key
+ markdown = _call_live_case(
+ case,
+ response_format=None,
+ mode=SearchResultMode.FULL,
+ result_limit=2,
+ )
+
+ assert isinstance(markdown, str)
+ assert markdown.startswith("---\n")
+ present_headings = [
+ heading for heading in MARKDOWN_RESULT_HEADINGS[case] if f"## {heading}" in markdown
+ ]
+ assert present_headings, (case, markdown[:500])
+ for heading in present_headings:
+ row_count = _markdown_table_row_count(markdown, heading)
+ assert 1 <= row_count <= 2, (case, heading, row_count)
+
+
def test_live_one_way_flight_uses_type_two() -> None:
outbound, _ = _future_dates()
- encoded = flights_search(provider="function", mode=SearchResultMode.FULL)(
+ encoded = flights_search(
+ provider="function",
+ mode=SearchResultMode.FULL,
+ response_format=SearchResultFormat.JSON,
+ )(
departure_id="lax",
arrival_id="aus",
outbound_date=outbound,
@@ -201,6 +284,7 @@ def test_live_unicode_query_round_trips() -> None:
provider="function",
allowed_engines=["google_light"],
mode=SearchResultMode.FULL,
+ response_format=SearchResultFormat.JSON,
)(query=UNICODE_QUERY)
result = _decode_success(encoded, "unicode-google-light", expect_full=True)
@@ -208,6 +292,25 @@ def test_live_unicode_query_round_trips() -> None:
assert result["organic_results"]
+def test_live_exact_maps_place_is_preserved_in_both_compact_formats() -> None:
+ json_encoded = maps_search(
+ provider="function",
+ response_format=SearchResultFormat.JSON,
+ result_limit=1,
+ )(query="Eiffel Tower")
+ json_result = _decode_success(json_encoded, "maps-exact-place")
+
+ assert set(json_result) == {"place_results"}
+ assert isinstance(json_result["place_results"], dict)
+ assert json_result["place_results"]["title"] == "Eiffel Tower"
+
+ markdown = maps_search(provider="function", result_limit=1)(query="Eiffel Tower")
+
+ assert markdown.startswith("## Place Results")
+ assert "Eiffel Tower" in markdown
+ assert "search_metadata" not in markdown
+
+
@pytest.mark.parametrize("case", LIVE_PARAMETER_CASES, ids=lambda case: case.id)
def test_each_public_tool_returns_nonempty_compact_results_live(
case: LiveParameterCase,
@@ -233,6 +336,7 @@ def test_each_public_tool_returns_nonempty_compact_results_live(
tool = factories[case.factory](
provider="function",
default_params=case.default_params,
+ response_format=SearchResultFormat.JSON,
result_limit=case.result_limit,
)
result = _decode_success(tool(**arguments), f"docs-{case.id}")
@@ -325,99 +429,103 @@ def _future_dates() -> tuple[str, str]:
return outbound.isoformat(), returning.isoformat()
-def _call_live_case(case: str) -> str:
+def _call_live_case(
+ case: str,
+ *,
+ response_format: SearchResultFormat | None = SearchResultFormat.JSON,
+ mode: SearchResultMode = SearchResultMode.FULL,
+ result_limit: int | None = None,
+) -> str:
outbound, returning = _future_dates()
+ options: dict[str, Any] = {
+ "provider": "function",
+ "mode": mode,
+ "result_limit": result_limit,
+ }
+ if response_format is not None:
+ options["response_format"] = response_format
calls: dict[str, tuple[Any, dict[str, Any]]] = {
"web-google": (
web_search(
- provider="function",
allowed_engines=["google"],
- mode=SearchResultMode.FULL,
+ **options,
),
{"query": "SerpApi"},
),
"web-google-light": (
web_search(
- provider="function",
allowed_engines=["google_light"],
- mode=SearchResultMode.FULL,
+ **options,
),
{"query": "SerpApi"},
),
"web-yahoo": (
web_search(
- provider="function",
allowed_engines=["yahoo"],
- mode=SearchResultMode.FULL,
+ **options,
),
{"query": "SerpApi"},
),
"web-bing": (
web_search(
- provider="function",
allowed_engines=["bing"],
- mode=SearchResultMode.FULL,
+ **options,
),
{"query": "SerpApi"},
),
"web-duckduckgo": (
web_search(
- provider="function",
allowed_engines=["duckduckgo"],
- mode=SearchResultMode.FULL,
+ **options,
),
{"query": "SerpApi"},
),
"news": (
- news_search(provider="function", mode=SearchResultMode.FULL),
+ news_search(**options),
{"query": "technology"},
),
"maps": (
- maps_search(provider="function", mode=SearchResultMode.FULL),
+ maps_search(**options),
{"query": "coffee", "location": "Austin, Texas", "zoom": 12, "nearby": True},
),
"images": (
- images_search(provider="function", mode=SearchResultMode.FULL),
+ images_search(**options),
{"query": "latte art"},
),
"shopping-google": (
shopping_search(
- provider="function",
allowed_engines=["google_shopping"],
- mode=SearchResultMode.FULL,
+ **options,
),
{"query": "coffee grinder"},
),
"shopping-amazon": (
shopping_search(
- provider="function",
allowed_engines=["amazon"],
- mode=SearchResultMode.FULL,
+ **options,
),
{"query": "coffee grinder"},
),
"shopping-walmart": (
shopping_search(
- provider="function",
allowed_engines=["walmart"],
- mode=SearchResultMode.FULL,
+ **options,
),
{"query": "coffee grinder"},
),
"shopping-ebay": (
shopping_search(
- provider="function",
allowed_engines=["ebay"],
- mode=SearchResultMode.FULL,
+ **options,
),
{"query": "coffee grinder"},
),
"videos": (
- videos_search(provider="function", mode=SearchResultMode.FULL),
+ videos_search(**options),
{"query": "latte art"},
),
"hotels": (
- hotels_search(provider="function", mode=SearchResultMode.FULL),
+ hotels_search(**options),
{
"query": "hotels in Austin",
"check_in_date": outbound,
@@ -428,7 +536,7 @@ def _call_live_case(case: str) -> str:
},
),
"flights": (
- flights_search(provider="function", mode=SearchResultMode.FULL),
+ flights_search(**options),
{
"departure_id": "lax",
"arrival_id": "aus",
@@ -438,7 +546,7 @@ def _call_live_case(case: str) -> str:
},
),
"travel-explore": (
- travel_explore_search(provider="function", mode=SearchResultMode.FULL),
+ travel_explore_search(**options),
{
"departure_id": "LAX",
"arrival_area_id": "/m/0852h",
@@ -447,3 +555,11 @@ def _call_live_case(case: str) -> str:
}
tool, arguments = calls[case]
return tool(**arguments)
+
+
+def _markdown_table_row_count(markdown: str, heading: str) -> int:
+ section = markdown.split(f"## {heading}", maxsplit=1)[1]
+ section = section.split("\n## ", maxsplit=1)[0]
+ table_lines = [line.strip() for line in section.splitlines() if line.strip().startswith("|")]
+ assert len(table_lines) >= 3, (heading, section[:500])
+ return len(table_lines) - 2
diff --git a/tests/test_live_adapters.py b/tests/test_live_adapters.py
index ad860f5..ba83e17 100644
--- a/tests/test_live_adapters.py
+++ b/tests/test_live_adapters.py
@@ -7,7 +7,7 @@
import pytest
-from serpapi_search_tools import web_search
+from serpapi_search_tools import SearchResultFormat, web_search
pytestmark = pytest.mark.live
@@ -30,6 +30,7 @@ def test_native_sdk_adapter_executes_a_real_google_light_search() -> None:
provider=PROVIDER,
allowed_engines=["google_light"],
default_params={"hl": "en", "gl": "us"},
+ response_format=SearchResultFormat.JSON,
result_limit=3,
)
diff --git a/tests/test_markdown_output.py b/tests/test_markdown_output.py
new file mode 100644
index 0000000..ad6d89f
--- /dev/null
+++ b/tests/test_markdown_output.py
@@ -0,0 +1,401 @@
+from __future__ import annotations
+
+import json
+from collections.abc import Callable, Mapping
+from typing import Any
+
+import pytest
+
+from serpapi_search_tools import (
+ SearchResultFormat,
+ SearchResultMode,
+ flights_search,
+ hotels_search,
+ images_search,
+ maps_search,
+ news_search,
+ shopping_search,
+ travel_explore_search,
+ videos_search,
+ web_search,
+)
+from serpapi_search_tools._shared import SearchRuntime
+
+
+class MarkdownClient:
+ def __init__(self, response: str) -> None:
+ self.response = response
+ self.calls: list[dict[str, Any]] = []
+
+ def search(self, params: dict[str, Any]) -> str:
+ self.calls.append(params)
+ return self.response
+
+
+class JsonClient:
+ def __init__(self, response: Mapping[str, Any]) -> None:
+ self.response = response
+ self.calls: list[dict[str, Any]] = []
+
+ def search(self, params: dict[str, Any]) -> Mapping[str, Any]:
+ self.calls.append(params)
+ return self.response
+
+
+@pytest.mark.parametrize(
+ ("factory", "factory_kwargs", "call_kwargs", "heading"),
+ [
+ (web_search, {"allowed_engines": ["google_light"]}, {"query": "coffee"}, "Organic Results"),
+ (news_search, {}, {"query": "coffee"}, "News Results"),
+ (
+ maps_search,
+ {},
+ {"query": "coffee", "location": "Austin, Texas"},
+ "Local Results",
+ ),
+ (images_search, {}, {"query": "coffee"}, "Images Results"),
+ (
+ shopping_search,
+ {"allowed_engines": ["google_shopping"]},
+ {"query": "coffee"},
+ "Shopping Results",
+ ),
+ (videos_search, {}, {"query": "coffee"}, "Video Results"),
+ (
+ hotels_search,
+ {},
+ {
+ "query": "Austin hotels",
+ "check_in_date": "2030-08-01",
+ "check_out_date": "2030-08-04",
+ },
+ "Properties",
+ ),
+ (
+ flights_search,
+ {},
+ {
+ "departure_id": "LAX",
+ "arrival_id": "AUS",
+ "outbound_date": "2030-08-01",
+ },
+ "Best Flights",
+ ),
+ (
+ travel_explore_search,
+ {},
+ {"departure_id": "JFK"},
+ "Destinations",
+ ),
+ ],
+)
+def test_every_factory_requests_and_returns_markdown_by_default(
+ factory: Callable[..., Any],
+ factory_kwargs: dict[str, Any],
+ call_kwargs: dict[str, Any],
+ heading: str,
+) -> None:
+ response = f"## {heading}\n\n| Title |\n| --- |\n| Coffee |\n"
+ client = MarkdownClient(response)
+ tool = factory(provider="function", client=client, **factory_kwargs)
+
+ result = tool(**call_kwargs)
+
+ assert result == response
+ assert client.calls[0]["output"] == "md"
+
+
+def test_json_is_an_explicit_opt_in_and_keeps_the_existing_compact_contract() -> None:
+ client = JsonClient(
+ {
+ "search_metadata": {"status": "Success"},
+ "organic_results": [{"title": "Coffee"}],
+ }
+ )
+ tool = web_search(
+ provider="function",
+ allowed_engines=["google_light"],
+ client=client,
+ response_format=SearchResultFormat.JSON,
+ )
+
+ result = json.loads(tool(query="coffee"))
+
+ assert result == {"organic_results": [{"title": "Coffee"}]}
+ assert "output" not in client.calls[0]
+
+
+def test_compact_markdown_keeps_result_sections_and_limits_each_table() -> None:
+ response = """---
+engine: google_flights
+---
+## Search Information
+
+Private request metadata.
+
+## Best Flights
+
+| Route | Price |
+| --- | --- |
+| LAX to AUS | 100 |
+| LAX to AUS | 120 |
+| LAX to AUS | 140 |
+
+## Other Flights
+
+| Route | Price |
+| --- | --- |
+| LAX to AUS | 90 |
+| LAX to AUS | 110 |
+| LAX to AUS | 130 |
+
+## Price Insights
+
+Prices are typical.
+"""
+ runtime = SearchRuntime(client=MarkdownClient(response), result_limit=2)
+
+ result = runtime.execute(engine="google_flights", typed_params={})
+
+ assert "engine: google_flights" not in result
+ assert "Search Information" not in result
+ assert "Price Insights" not in result
+ assert "| LAX to AUS | 100 |" in result
+ assert "| LAX to AUS | 120 |" in result
+ assert "| LAX to AUS | 140 |" not in result
+ assert "| LAX to AUS | 90 |" in result
+ assert "| LAX to AUS | 110 |" in result
+ assert "| LAX to AUS | 130 |" not in result
+
+
+def test_compact_markdown_with_no_limit_keeps_every_result_row() -> None:
+ response = """## News Results
+
+| Title |
+| --- |
+| First story |
+| Second story |
+"""
+ runtime = SearchRuntime(client=MarkdownClient(response), result_limit=None)
+
+ result = runtime.execute(engine="google_news", typed_params={"q": "technology"})
+
+ assert "| First story |" in result
+ assert "| Second story |" in result
+
+
+def test_full_markdown_limits_results_but_preserves_supporting_sections() -> None:
+ response = """---
+engine: google
+---
+## Organic Results
+
+| Title |
+| --- |
+| Coffee |
+| Tea |
+
+## Related Searches
+
+Coffee beans
+"""
+ runtime = SearchRuntime(
+ client=MarkdownClient(response),
+ mode=SearchResultMode.FULL,
+ result_limit=1,
+ )
+
+ result = runtime.execute(engine="google", typed_params={"q": "coffee"})
+
+ assert result.startswith("---\nengine: google\n---\n")
+ assert "| Coffee |" in result
+ assert "| Tea |" not in result
+ assert "## Related Searches\n\nCoffee beans" in result
+
+
+@pytest.mark.parametrize("mode", [SearchResultMode.COMPACT, SearchResultMode.FULL])
+def test_markdown_result_limit_does_not_truncate_nested_detail_tables(
+ mode: SearchResultMode,
+) -> None:
+ response = """---
+engine: google_flights
+---
+## Best Flights
+
+| Route | Price |
+| --- | --- |
+| First itinerary | 100 |
+| Second itinerary | 120 |
+| Third itinerary | 140 |
+
+### First itinerary legs
+
+| Leg | From | To |
+| --- | --- | --- |
+| 1 | LAX | DFW |
+| 2 | DFW | LHR |
+| 3 | LHR | CDG |
+"""
+ runtime = SearchRuntime(
+ client=MarkdownClient(response),
+ mode=mode,
+ result_limit=2,
+ )
+
+ result = runtime.execute(engine="google_flights", typed_params={})
+
+ assert "| First itinerary | 100 |" in result
+ assert "| Second itinerary | 120 |" in result
+ assert "| Third itinerary | 140 |" not in result
+ assert "| 1 | LAX | DFW |" in result
+ assert "| 2 | DFW | LHR |" in result
+ assert "| 3 | LHR | CDG |" in result
+
+
+def test_full_markdown_with_no_limit_is_returned_byte_for_byte() -> None:
+ response = "---\nengine: google\n---\n## Organic Results\n\nOriginal spacing.\n"
+ runtime = SearchRuntime(
+ client=MarkdownClient(response),
+ mode=SearchResultMode.FULL,
+ result_limit=None,
+ )
+
+ assert runtime.execute(engine="google", typed_params={"q": "coffee"}) == response
+
+
+def test_compact_markdown_preserves_exact_place_results_without_row_truncation() -> None:
+ response = """## Place Results
+
+| Field | Value |
+| --- | --- |
+| Title | Eiffel Tower |
+| Address | Paris |
+
+## Search Information
+
+Metadata
+"""
+ runtime = SearchRuntime(client=MarkdownClient(response), result_limit=1)
+
+ result = runtime.execute(engine="google_maps", typed_params={"q": "Eiffel Tower"})
+
+ assert (
+ result
+ == """## Place Results
+
+| Field | Value |
+| --- | --- |
+| Title | Eiffel Tower |
+| Address | Paris |
+"""
+ )
+
+
+def test_compact_json_preserves_exact_place_results() -> None:
+ place = {
+ "title": "Eiffel Tower",
+ "address": "5 Avenue Anatole France, Paris",
+ "place_id": "ChIJLU7jZClu5kcR4PcOOO6p3I0",
+ }
+ runtime = SearchRuntime(
+ client=JsonClient(
+ {
+ "search_metadata": {"status": "Success"},
+ "place_results": place,
+ }
+ ),
+ response_format=SearchResultFormat.JSON,
+ result_limit=1,
+ )
+
+ result = json.loads(runtime.execute(engine="google_maps", typed_params={"q": "Eiffel Tower"}))
+
+ assert result == {"place_results": place}
+
+
+def test_compact_markdown_drops_followup_only_image_id_but_keeps_image_urls() -> None:
+ response = """## Images Results
+
+| Title | Thumbnail | Related Content Id | Original |
+| --- | --- | --- | --- |
+| Latte |  | follow-up-token | \
+https://images.test/original.jpg |
+"""
+ runtime = SearchRuntime(client=MarkdownClient(response))
+
+ result = runtime.execute(engine="google_images", typed_params={"q": "latte"})
+
+ assert "Related Content Id" not in result
+ assert "follow-up-token" not in result
+ assert "https://images.test/thumb.jpg" in result
+ assert "https://images.test/original.jpg" in result
+
+
+def test_compact_markdown_preserves_api_errors_instead_of_returning_blank_text() -> None:
+ response = """---
+engine: google_light
+---
+## Search Information
+
+No results.
+
+## Error
+
+Google Light returned no results for this query.
+"""
+ runtime = SearchRuntime(client=MarkdownClient(response))
+
+ result = runtime.execute(engine="google_light", typed_params={"q": "missing"})
+
+ assert (
+ result
+ == """## Error
+
+Google Light returned no results for this query.
+"""
+ )
+
+
+def test_compact_markdown_falls_back_to_unknown_server_sections() -> None:
+ response = """---
+engine: google
+---
+## New Result Family
+
+Server data that the installed library does not know yet.
+"""
+ runtime = SearchRuntime(client=MarkdownClient(response))
+
+ result = runtime.execute(engine="google", typed_params={"q": "coffee"})
+
+ assert (
+ result
+ == """## New Result Family
+
+Server data that the installed library does not know yet.
+"""
+ )
+
+
+@pytest.mark.parametrize(
+ ("response_format", "response", "message"),
+ [
+ (SearchResultFormat.MARKDOWN, {"organic_results": []}, "must return str"),
+ (SearchResultFormat.JSON, "## Organic Results", "must return a mapping"),
+ ],
+)
+def test_runtime_rejects_client_responses_that_do_not_match_the_selected_format(
+ response_format: SearchResultFormat,
+ response: Mapping[str, Any] | str,
+ message: str,
+) -> None:
+ client = JsonClient(response) if isinstance(response, Mapping) else MarkdownClient(response)
+ runtime = SearchRuntime(client=client, response_format=response_format)
+
+ with pytest.raises(TypeError, match=message):
+ runtime.execute(engine="google", typed_params={"q": "coffee"})
+
+
+def test_invalid_response_format_fails_when_the_tool_is_created() -> None:
+ with pytest.raises(ValueError, match="response_format must be one of: markdown, json"):
+ SearchRuntime(client=MarkdownClient(""), response_format="yaml")
diff --git a/tests/test_project_metadata.py b/tests/test_project_metadata.py
index f1bcba9..16f7df0 100644
--- a/tests/test_project_metadata.py
+++ b/tests/test_project_metadata.py
@@ -22,6 +22,7 @@ def test_public_package_exposes_intent_specific_tools_and_semantic_enums() -> No
assert set(package.__all__) == {
"ShoppingSearchEngine",
+ "SearchResultFormat",
"SearchResultMode",
"SerpApiSearchError",
"TravelClass",
@@ -39,13 +40,14 @@ def test_public_package_exposes_intent_specific_tools_and_semantic_enums() -> No
assert all(callable(getattr(package, name)) for name in package.__all__)
-def test_base_install_only_depends_on_serpapi() -> None:
+def test_base_install_declares_runtime_dependencies() -> None:
pyproject = tomllib.loads((ROOT / "pyproject.toml").read_text())
runtime_dependencies = pyproject["project"]["dependencies"]
dev_dependencies = pyproject["dependency-groups"]["dev"]
assert pyproject["project"]["requires-python"] == ">=3.10"
assert any(dependency.startswith("serpapi") for dependency in runtime_dependencies)
+ assert any(dependency.startswith("mistune") for dependency in runtime_dependencies)
assert all("dotenv" not in dependency for dependency in runtime_dependencies)
assert any(dependency.startswith("python-dotenv") for dependency in dev_dependencies)
@@ -98,15 +100,6 @@ def test_declared_major_version_bounds_match_tested_framework_branches() -> None
)
-def test_langgraph_extra_installs_langgraph_and_langchain_tool_dependencies() -> None:
- pyproject = tomllib.loads((ROOT / "pyproject.toml").read_text())
- dependencies = pyproject["project"]["optional-dependencies"]["langgraph"]
-
- assert any(dependency.startswith("langgraph>=1.2.6,<2") for dependency in dependencies)
- assert any(dependency.startswith("langchain-core") for dependency in dependencies)
- assert all(not dependency.startswith("langchain-openai") for dependency in dependencies)
-
-
def test_tox_has_a_fresh_environment_for_every_framework_extra() -> None:
pyproject = tomllib.loads((ROOT / "pyproject.toml").read_text())
tox_config = (ROOT / "tox.ini").read_text()
diff --git a/tests/test_query_tools.py b/tests/test_query_tools.py
index 9ba9fbb..fe46246 100644
--- a/tests/test_query_tools.py
+++ b/tests/test_query_tools.py
@@ -4,7 +4,7 @@
import pytest
-from serpapi_search_tools import SearchResultMode
+from serpapi_search_tools import SearchResultFormat, SearchResultMode
from serpapi_search_tools._query_tools import (
ShoppingSearchEngine,
WebSearchEngine,
@@ -21,9 +21,12 @@ class FakeClient:
def __init__(self) -> None:
self.calls: list[dict[str, object]] = []
- def search(self, params: dict[str, object]) -> dict[str, object]:
- self.calls.append(params)
- return {"params": params}
+ def search(self, params: dict[str, object]) -> dict[str, object] | str:
+ recorded = {key: value for key, value in params.items() if key != "output"}
+ self.calls.append(recorded)
+ if params.get("output") == "md":
+ return "## Organic Results\n\n| Title |\n| --- |\n| Coffee |\n"
+ return {"params": recorded}
class FailIfCalledClient:
@@ -73,6 +76,7 @@ def test_multi_engine_tools_route_query_to_native_parameter(
allowed_engines=[engine],
client=client,
mode=SearchResultMode.FULL,
+ response_format=SearchResultFormat.JSON,
)
payload = json.loads(tool(query="coffee"))
diff --git a/tests/test_result_limit.py b/tests/test_result_limit.py
index d9b9f0a..fd5c3dc 100644
--- a/tests/test_result_limit.py
+++ b/tests/test_result_limit.py
@@ -4,6 +4,7 @@
import pytest
from serpapi_search_tools import (
+ SearchResultFormat,
SearchResultMode,
flights_search,
hotels_search,
@@ -91,6 +92,7 @@ def test_every_factory_applies_the_result_limit_to_each_retained_list(
factory_kwargs: dict[str, object] = {
"provider": "function",
"client": ResultClient(),
+ "response_format": SearchResultFormat.JSON,
}
if result_limit_override is not USE_FACTORY_DEFAULT:
factory_kwargs["result_limit"] = result_limit_override
@@ -129,6 +131,7 @@ def search(self, params: dict[str, object]) -> dict[str, object]:
provider="function",
client=HotelsClient(),
mode=mode,
+ response_format=SearchResultFormat.JSON,
result_limit=2,
)
result = json.loads(
@@ -151,6 +154,7 @@ def test_result_limit_none_keeps_every_returned_result(mode: SearchResultMode) -
provider="function",
client=ResultClient(),
mode=mode,
+ response_format=SearchResultFormat.JSON,
result_limit=None,
)
@@ -224,6 +228,7 @@ def search(self, params: dict[str, object]) -> dict[str, object]:
client=MultiEngineClient(),
allowed_engines=[engine],
default_engine=engine,
+ response_format=SearchResultFormat.JSON,
result_limit=3,
)
@@ -278,6 +283,7 @@ def search(self, params: dict[str, object]) -> dict[str, object]:
tool = factory(
provider="function",
client=client,
+ response_format=SearchResultFormat.JSON,
result_limit=3,
**factory_kwargs,
)
diff --git a/tests/test_shared.py b/tests/test_shared.py
index 3852436..955de27 100644
--- a/tests/test_shared.py
+++ b/tests/test_shared.py
@@ -12,6 +12,7 @@
import serpapi_search_tools._shared as shared
from serpapi_search_tools._shared import (
PROVIDER_ALIASES,
+ SearchResultFormat,
SearchResultMode,
SearchRuntime,
detect_provider,
@@ -41,6 +42,7 @@ def test_runtime_merges_parameters_in_documented_precedence_order() -> None:
client=client,
default_params={"hl": "en", "gl": "gb", "location": "Austin"},
mode=SearchResultMode.FULL,
+ response_format=SearchResultFormat.JSON,
)
encoded = runtime.execute(
@@ -66,6 +68,7 @@ def test_runtime_copies_default_params_at_construction() -> None:
client=FakeClient(),
default_params=defaults,
mode=SearchResultMode.FULL,
+ response_format=SearchResultFormat.JSON,
)
defaults["hl"] = "fr"
@@ -242,7 +245,11 @@ def search(self, params: dict[str, object]) -> dict[str, object]:
serpapi_module.Client = Client
monkeypatch.setitem(sys.modules, "serpapi", serpapi_module)
- SearchRuntime(api_key="passed", timeout=2.5).execute(
+ SearchRuntime(
+ api_key="passed",
+ timeout=2.5,
+ response_format=SearchResultFormat.JSON,
+ ).execute(
engine="google_light",
typed_params={"q": "coffee"},
)
@@ -363,7 +370,7 @@ def search(self, params: dict[str, object]) -> dict[str, object]:
serpapi_module.Client = Client
monkeypatch.setitem(sys.modules, "serpapi", serpapi_module)
- runtime = SearchRuntime(api_key="passed")
+ runtime = SearchRuntime(api_key="passed", response_format=SearchResultFormat.JSON)
for query in ("coffee", "tea"):
runtime.execute(
@@ -415,7 +422,7 @@ def search(self, params: dict[str, object]) -> dict[str, object]:
serpapi_module.Client = Client
monkeypatch.setitem(sys.modules, "serpapi", serpapi_module)
- runtime = SearchRuntime(api_key="passed")
+ runtime = SearchRuntime(api_key="passed", response_format=SearchResultFormat.JSON)
start = threading.Barrier(2)
def search(query: str) -> None:
@@ -459,9 +466,11 @@ class MappingClient:
def search(self, params: dict[str, object]) -> UserDict[str, object]:
return UserDict({"params": params, "results": [{"title": "Coffee"}]})
- encoded = SearchRuntime(client=MappingClient(), mode=SearchResultMode.FULL).execute(
- engine="google", typed_params={"q": "coffee"}
- )
+ encoded = SearchRuntime(
+ client=MappingClient(),
+ mode=SearchResultMode.FULL,
+ response_format=SearchResultFormat.JSON,
+ ).execute(engine="google", typed_params={"q": "coffee"})
assert json.loads(encoded)["results"] == [{"title": "Coffee"}]
assert "\n" not in encoded
@@ -485,7 +494,7 @@ def search(self, params: dict[str, object]) -> dict[str, object]:
"serpapi_pagination": {"next": "https://example.test/next"},
}
- encoded = SearchRuntime(client=WebClient()).execute(
+ encoded = SearchRuntime(client=WebClient(), response_format=SearchResultFormat.JSON).execute(
engine="google",
typed_params={"q": "coffee"},
)
@@ -517,7 +526,7 @@ def search(self, params: dict[str, object]) -> dict[str, object]:
("yahoo", {"answer_box", "knowledge_graph", "organic_results"}),
("duckduckgo", {"knowledge_graph", "organic_results"}),
("google_news", {"news_results"}),
- ("google_maps", {"local_results"}),
+ ("google_maps", {"local_results", "place_results"}),
("google_images", {"images_results"}),
("google_shopping", {"shopping_results"}),
("amazon", {"organic_results"}),
@@ -551,6 +560,7 @@ def test_compact_mode_selects_primary_result_families(
"organic_results",
"news_results",
"local_results",
+ "place_results",
"images_results",
"shopping_results",
"video_results",
@@ -584,13 +594,14 @@ def search(self, params: dict[str, object]) -> dict[str, object]:
"knowledge_graph",
"ai_overview",
"copilot_answer",
+ "place_results",
}
else [{"value": key}]
)
return result
result = json.loads(
- SearchRuntime(client=ResultClient()).execute(
+ SearchRuntime(client=ResultClient(), response_format=SearchResultFormat.JSON).execute(
engine=engine,
typed_params={"q": "coffee"},
)
@@ -610,7 +621,7 @@ def search(self, params: dict[str, object]) -> dict[str, object]:
}
result = json.loads(
- SearchRuntime(client=GoogleLightClient()).execute(
+ SearchRuntime(client=GoogleLightClient(), response_format=SearchResultFormat.JSON).execute(
engine="google_light",
typed_params={"q": "coffee"},
)
@@ -630,7 +641,11 @@ def search(self, params: dict[str, object]) -> dict[str, object]:
}
result = json.loads(
- SearchRuntime(client=FlightsClient(), result_limit=3).execute(
+ SearchRuntime(
+ client=FlightsClient(),
+ response_format=SearchResultFormat.JSON,
+ result_limit=3,
+ ).execute(
engine="google_flights",
typed_params={"departure_id": "LAX", "arrival_id": "AUS"},
)
@@ -767,7 +782,7 @@ def search(self, params: dict[str, object]) -> dict[str, object]:
return {result_key: [item]}
result = json.loads(
- SearchRuntime(client=ProjectionClient()).execute(
+ SearchRuntime(client=ProjectionClient(), response_format=SearchResultFormat.JSON).execute(
engine=engine,
typed_params={"q": "coffee"},
)
@@ -792,7 +807,7 @@ def search(self, params: dict[str, object]) -> dict[str, object]:
}
result = json.loads(
- SearchRuntime(client=EmptyResultClient()).execute(
+ SearchRuntime(client=EmptyResultClient(), response_format=SearchResultFormat.JSON).execute(
engine="google_light",
typed_params={"q": "coffee"},
)
@@ -817,7 +832,7 @@ def search(self, params: dict[str, object]) -> dict[str, object]:
"error": "A bounded error message.",
}
- encoded = SearchRuntime(client=ErrorClient()).execute(
+ encoded = SearchRuntime(client=ErrorClient(), response_format=SearchResultFormat.JSON).execute(
engine="google_light",
typed_params={"q": "coffee"},
)
@@ -848,6 +863,7 @@ def search(self, params: dict[str, object]) -> dict[str, object]:
encoded = SearchRuntime(
client=FullClient(),
mode=mode,
+ response_format=SearchResultFormat.JSON,
result_limit=1,
).execute(engine="google_light", typed_params={"q": "coffee"})
diff --git a/tests/test_travel_tools.py b/tests/test_travel_tools.py
index 6b3f1f4..430dc9d 100644
--- a/tests/test_travel_tools.py
+++ b/tests/test_travel_tools.py
@@ -15,9 +15,12 @@ class FakeClient:
def __init__(self) -> None:
self.calls: list[dict[str, object]] = []
- def search(self, params: dict[str, object]) -> dict[str, object]:
- self.calls.append(params)
- return {"params": params}
+ def search(self, params: dict[str, object]) -> dict[str, object] | str:
+ recorded = {key: value for key, value in params.items() if key != "output"}
+ self.calls.append(recorded)
+ if params.get("output") == "md":
+ return "## Destinations\n\n| Name |\n| --- |\n| Austin |\n"
+ return {"params": recorded}
class FailIfCalledClient:
diff --git a/tox.ini b/tox.ini
index a2c50ca..4f17262 100644
--- a/tox.ini
+++ b/tox.ini
@@ -65,7 +65,7 @@ base_python =
py314: 3.14
extras = google-adk
deps =
- py310: litellm>=1.84,<2
+ py310: litellm>=1.84,<2,!=1.97.0
py310: orjson>=3.10,<4
set_env =
SERPAPI_SEARCH_TOOL_REQUIRED_PROVIDER = google-adk
diff --git a/uv.lock b/uv.lock
index cb7ff4e..6568f11 100644
--- a/uv.lock
+++ b/uv.lock
@@ -875,8 +875,8 @@ source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "deprecated" },
{ name = "filetype" },
- { name = "griffe", version = "0.49.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-llamaindex' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs')" },
- { name = "griffe", version = "1.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or extra == 'extra-20-serpapi-search-tools-agno' or extra == 'extra-20-serpapi-search-tools-autogen' or extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' or extra == 'extra-20-serpapi-search-tools-crewai' or extra == 'extra-20-serpapi-search-tools-frameworks' or extra == 'extra-20-serpapi-search-tools-google-adk' or extra == 'extra-20-serpapi-search-tools-haystack' or extra == 'extra-20-serpapi-search-tools-langchain' or extra == 'extra-20-serpapi-search-tools-langgraph' or extra == 'extra-20-serpapi-search-tools-llamaindex' or extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' or extra == 'extra-20-serpapi-search-tools-openai-agents' or extra == 'extra-20-serpapi-search-tools-pydantic-ai' or extra == 'extra-20-serpapi-search-tools-semantic-kernel' or extra == 'extra-20-serpapi-search-tools-smolagents' or extra != 'group-20-serpapi-search-tools-docs'" },
+ { name = "griffe", version = "1.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or extra == 'extra-20-serpapi-search-tools-frameworks' or extra == 'extra-20-serpapi-search-tools-google-adk' or extra == 'extra-20-serpapi-search-tools-langchain' or extra == 'extra-20-serpapi-search-tools-langgraph' or extra == 'extra-20-serpapi-search-tools-openai-agents' or extra == 'extra-20-serpapi-search-tools-semantic-kernel' or (extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-llamaindex' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs')" },
+ { name = "griffe", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-agno' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs')" },
{ name = "jinja2" },
{ name = "platformdirs" },
{ name = "pydantic", version = "2.11.10", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-20-serpapi-search-tools-frameworks' or extra == 'extra-20-serpapi-search-tools-semantic-kernel' or (extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-llamaindex' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs')" },
@@ -2228,11 +2228,11 @@ wheels = [
[[package]]
name = "great-docs"
-version = "0.14.0"
+version = "0.15.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click", marker = "python_full_version >= '3.11'" },
- { name = "griffe", version = "0.49.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
+ { name = "griffe", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
{ name = "jupyter", marker = "python_full_version >= '3.11'" },
{ name = "pillow", marker = "python_full_version >= '3.11'" },
{ name = "py-yaml12", marker = "python_full_version >= '3.11'" },
@@ -2240,9 +2240,9 @@ dependencies = [
{ name = "requests", marker = "python_full_version >= '3.11'" },
{ name = "ruff", marker = "python_full_version >= '3.11'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/d6/1b/1620d56583cd14b3398298f7f72ebc7d2fb68dd427c39d51a2eb6deef11f/great_docs-0.14.0.tar.gz", hash = "sha256:86df097ff11525d352664b7a1beca8f852bc2bae397edc7af46663e4517ad69c", size = 28353775, upload-time = "2026-06-16T14:09:19.67Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/25/37/3466f0064353554c5be4a70e29e946dac090c1ad614b00447148d86d22f2/great_docs-0.15.0.tar.gz", hash = "sha256:2fd4c8843723c913b70960aaaf4ccf23c0b0c54aa59cb856422363dd5d54baf1", size = 31035297, upload-time = "2026-07-10T18:31:02.618Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/75/46/662719f5aada86c51bee15da9638e8f4bf8ce746e9e4988dc7b9409b75ed/great_docs-0.14.0-py3-none-any.whl", hash = "sha256:06fb21a33dca4058d9e904df898bf320e811107177a5fba782c7cf0a5fb04f8f", size = 947386, upload-time = "2026-06-16T14:09:18.147Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/dd/c7460a23ae0a2483c6fd320bfd600dbc0ca802f4be0823cc8a775ad5c18e/great_docs-0.15.0-py3-none-any.whl", hash = "sha256:98ad7d9140fc90328db0638e16d6004e29717b372e063ca9cb38568662829a91", size = 980201, upload-time = "2026-07-10T18:31:00.767Z" },
]
[[package]]
@@ -2333,38 +2333,56 @@ wheels = [
[[package]]
name = "griffe"
-version = "0.49.0"
+version = "1.15.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.14'",
- "python_full_version >= '3.12' and python_full_version < '3.14'",
+ "python_full_version == '3.13.*'",
+ "python_full_version == '3.12.*'",
"python_full_version == '3.11.*'",
+ "python_full_version < '3.11'",
]
dependencies = [
- { name = "colorama", marker = "(python_full_version >= '3.11' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-llamaindex' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs')" },
+ { name = "colorama", marker = "python_full_version < '3.11' or extra == 'extra-20-serpapi-search-tools-frameworks' or extra == 'extra-20-serpapi-search-tools-google-adk' or extra == 'extra-20-serpapi-search-tools-langchain' or extra == 'extra-20-serpapi-search-tools-langgraph' or extra == 'extra-20-serpapi-search-tools-openai-agents' or extra == 'extra-20-serpapi-search-tools-semantic-kernel' or (extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-llamaindex' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs')" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/93/61/7ecb30d0f246f1fc378536e53d2fe523ee8e0a327e45a6cfc79ae1412a3e/griffe-0.49.0.tar.gz", hash = "sha256:a7e1235c27d8139e0fd24a5258deef6061bc876a9fda8117a5cf7b53ee940a91", size = 377276, upload-time = "2024-08-14T17:27:19.413Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/0d/0c/3a471b6e31951dce2360477420d0a8d1e00dea6cf33b70f3e8c3ab6e28e1/griffe-1.15.0.tar.gz", hash = "sha256:7726e3afd6f298fbc3696e67958803e7ac843c1cfe59734b6251a40cdbfb5eea", size = 424112, upload-time = "2025-11-10T15:03:15.52Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/a7/7e/79c1337f56a4124eec149aaf23819430632faedc247e902fe4b9ccf03f65/griffe-0.49.0-py3-none-any.whl", hash = "sha256:c0d505f2a444ac342b22f4647d6444c8db64964b6a379c14f401fc467c0741a3", size = 143668, upload-time = "2024-08-14T17:27:10.533Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl", hash = "sha256:6f6762661949411031f5fcda9593f586e6ce8340f0ba88921a0f2ef7a81eb9a3", size = 150705, upload-time = "2025-11-10T15:03:13.549Z" },
]
[[package]]
name = "griffe"
-version = "1.15.0"
+version = "2.1.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version == '3.13.*'",
- "python_full_version == '3.12.*'",
- "python_full_version == '3.11.*'",
- "python_full_version < '3.11'",
+ "python_full_version >= '3.14' and extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-pydantic-ai' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra != 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs'",
+ "python_full_version >= '3.12' and python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-pydantic-ai' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra != 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs'",
+ "python_full_version == '3.11.*' and extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-pydantic-ai' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra != 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs'",
+ "python_full_version >= '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra != 'group-20-serpapi-search-tools-docs'",
+ "python_full_version == '3.13.*' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra != 'group-20-serpapi-search-tools-docs'",
+ "python_full_version == '3.12.*' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra != 'group-20-serpapi-search-tools-docs'",
+ "python_full_version == '3.11.*' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra != 'group-20-serpapi-search-tools-docs'",
]
dependencies = [
- { name = "colorama", marker = "python_full_version < '3.11' or extra == 'extra-20-serpapi-search-tools-agno' or extra == 'extra-20-serpapi-search-tools-autogen' or extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' or extra == 'extra-20-serpapi-search-tools-crewai' or extra == 'extra-20-serpapi-search-tools-frameworks' or extra == 'extra-20-serpapi-search-tools-google-adk' or extra == 'extra-20-serpapi-search-tools-haystack' or extra == 'extra-20-serpapi-search-tools-langchain' or extra == 'extra-20-serpapi-search-tools-langgraph' or extra == 'extra-20-serpapi-search-tools-llamaindex' or extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' or extra == 'extra-20-serpapi-search-tools-openai-agents' or extra == 'extra-20-serpapi-search-tools-pydantic-ai' or extra == 'extra-20-serpapi-search-tools-semantic-kernel' or extra == 'extra-20-serpapi-search-tools-smolagents' or extra != 'group-20-serpapi-search-tools-docs'" },
+ { name = "griffecli", marker = "(python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-agno' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs')" },
+ { name = "griffelib", marker = "(python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-agno' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs')" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/0d/0c/3a471b6e31951dce2360477420d0a8d1e00dea6cf33b70f3e8c3ab6e28e1/griffe-1.15.0.tar.gz", hash = "sha256:7726e3afd6f298fbc3696e67958803e7ac843c1cfe59734b6251a40cdbfb5eea", size = 424112, upload-time = "2025-11-10T15:03:15.52Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/00/44/63913c007814cab5ba9d36f25ad40dfc640c2e2931d195bd2d05f774a5d6/griffe-2.1.0.tar.gz", hash = "sha256:c58845df5a364feaabd05ee8c767b97b03e478da8aa18b9923553c812fb0d955", size = 244879, upload-time = "2026-06-19T12:05:41.262Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl", hash = "sha256:6f6762661949411031f5fcda9593f586e6ce8340f0ba88921a0f2ef7a81eb9a3", size = 150705, upload-time = "2025-11-10T15:03:13.549Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/fb/3c65d392feae6c36dc2b55a14dd8270b7b35a3171c93b71a4d2ee4abf241/griffe-2.1.0-py3-none-any.whl", hash = "sha256:2ccdab17fb9cd76f278d7b5611cfc8f68cbe846d8d48df63dff80b62ecfa6f65", size = 5140, upload-time = "2026-06-19T12:05:39.913Z" },
+]
+
+[[package]]
+name = "griffecli"
+version = "2.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "(python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-agno' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs')" },
+ { name = "griffelib", marker = "(python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-agno' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.11' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs')" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/8e/c6/90f85d47af96300d629b38c25b71aad9467a620cac964a39280e822efc8a/griffecli-2.1.0.tar.gz", hash = "sha256:2ff68dbee9395fdb668b10374c51683392d697b226ac60159798f4add1ee716c", size = 56913, upload-time = "2026-06-19T12:05:43.119Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/80/2f/513232ec1d5f5da182e4ce45a11427e37dd210844a9e2bca451fc9661fb3/griffecli-2.1.0-py3-none-any.whl", hash = "sha256:6e22b1423d562ddc510997b4be1fe89de59e19dcff78831c0f4bfc3b8134a718", size = 9500, upload-time = "2026-06-19T12:05:37.517Z" },
]
[[package]]
@@ -3951,6 +3969,9 @@ wheels = [
name = "mistune"
version = "3.3.2"
source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions", marker = "python_full_version < '3.11' or (extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-llamaindex' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs')" },
+]
sdist = { url = "https://files.pythonhosted.org/packages/04/5f/007786743f962224423753b78f7d7acb0f2ade46d1604f2e0fa2bedf9020/mistune-3.3.2.tar.gz", hash = "sha256:e12ee4f1e74336e91aa1141e35f913b337c40bdf7c0cc49f21fb853a27e8b62f", size = 111284, upload-time = "2026-06-23T00:29:28.568Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/44/43/894c2cbbcbdf53b57d1257a249811abe2ee9ab7ef76af301b40f1c054533/mistune-3.3.2-py3-none-any.whl", hash = "sha256:a678a56387d487db7368ede4647cb2ba1deff22ce61f92343e4ebe0ddfce4f2d", size = 61554, upload-time = "2026-06-23T00:29:27.088Z" },
@@ -6186,7 +6207,8 @@ resolution-markers = [
dependencies = [
{ name = "exceptiongroup", marker = "(python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-agno') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-autogen') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-crewai') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-frameworks') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-google-adk') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-haystack') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-langchain') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-langgraph') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-llamaindex') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-pydantic-ai') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-smolagents') or (python_full_version < '3.11' and extra != 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-llamaindex' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs')" },
{ name = "genai-prices", marker = "(python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-agno') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-autogen') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-crewai') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-haystack') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-langchain') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-langgraph') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-llamaindex') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-pydantic-ai') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'extra-20-serpapi-search-tools-smolagents') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra != 'group-20-serpapi-search-tools-docs') or extra == 'extra-20-serpapi-search-tools-frameworks' or extra == 'extra-20-serpapi-search-tools-semantic-kernel' or (extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-llamaindex' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs')" },
- { name = "griffe", version = "1.15.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-agno') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-autogen') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-crewai') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-haystack') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-langchain') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-langgraph') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-llamaindex') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-pydantic-ai') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'extra-20-serpapi-search-tools-smolagents') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra != 'group-20-serpapi-search-tools-docs') or extra == 'extra-20-serpapi-search-tools-frameworks' or extra == 'extra-20-serpapi-search-tools-semantic-kernel' or (extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-llamaindex' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs')" },
+ { name = "griffe", version = "1.15.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-agno') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-autogen') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-crewai') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-google-adk') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-haystack') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-langchain') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-langgraph') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-llamaindex') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-pydantic-ai') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-smolagents') or (python_full_version < '3.11' and extra != 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-google-adk') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-langchain') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-langgraph') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-agno' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.14' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-llamaindex' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.14' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-llamaindex' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.14' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.14' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra == 'group-20-serpapi-search-tools-docs') or extra == 'extra-20-serpapi-search-tools-frameworks' or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs')" },
+ { name = "griffe", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.11' and python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.11' and python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.11' and python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.11' and python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.11' and python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.11' and python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.11' and python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.11' and python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'extra-20-serpapi-search-tools-smolagents') or (python_full_version >= '3.11' and python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra != 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-llamaindex' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-llamaindex' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.11' and extra == 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs')" },
{ name = "httpx", marker = "(python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-agno') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-autogen') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-crewai') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-haystack') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-langchain') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-langgraph') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-llamaindex') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-pydantic-ai') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'extra-20-serpapi-search-tools-smolagents') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra != 'group-20-serpapi-search-tools-docs') or extra == 'extra-20-serpapi-search-tools-frameworks' or extra == 'extra-20-serpapi-search-tools-semantic-kernel' or (extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-llamaindex' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs')" },
{ name = "opentelemetry-api", marker = "(python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-agno') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-autogen') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-crewai') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-haystack') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-langchain') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-langgraph') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-llamaindex') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-pydantic-ai') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'extra-20-serpapi-search-tools-smolagents') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra != 'group-20-serpapi-search-tools-docs') or extra == 'extra-20-serpapi-search-tools-frameworks' or extra == 'extra-20-serpapi-search-tools-semantic-kernel' or (extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-llamaindex' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs')" },
{ name = "pydantic", version = "2.11.10", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-20-serpapi-search-tools-frameworks' or extra == 'extra-20-serpapi-search-tools-semantic-kernel' or (extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-llamaindex' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs')" },
@@ -6270,7 +6292,8 @@ resolution-markers = [
]
dependencies = [
{ name = "genai-prices", marker = "(python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-google-adk') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (python_full_version >= '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-semantic-kernel')" },
- { name = "griffe", version = "1.15.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-google-adk') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (python_full_version >= '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-semantic-kernel')" },
+ { name = "griffe", version = "1.15.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-google-adk') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-agno' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-llamaindex' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs')" },
+ { name = "griffe", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-agno' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-autogen' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-crewai' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.14' and extra == 'extra-20-serpapi-search-tools-haystack' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version < '3.14' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'group-20-serpapi-search-tools-docs') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra == 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-pydantic-ai' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (python_full_version >= '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'extra-20-serpapi-search-tools-smolagents') or (python_full_version >= '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-google-adk' and extra != 'extra-20-serpapi-search-tools-langchain' and extra != 'extra-20-serpapi-search-tools-langgraph' and extra != 'extra-20-serpapi-search-tools-openai-agents' and extra != 'extra-20-serpapi-search-tools-semantic-kernel' and extra != 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langchain' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-langgraph' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'group-20-serpapi-search-tools-docs') or (extra == 'extra-20-serpapi-search-tools-semantic-kernel' and extra == 'group-20-serpapi-search-tools-docs') or (extra != 'extra-20-serpapi-search-tools-agno' and extra != 'extra-20-serpapi-search-tools-autogen' and extra != 'extra-20-serpapi-search-tools-claude-agent-sdk' and extra != 'extra-20-serpapi-search-tools-crewai' and extra != 'extra-20-serpapi-search-tools-haystack' and extra != 'extra-20-serpapi-search-tools-llamaindex' and extra != 'extra-20-serpapi-search-tools-microsoft-agent-framework' and extra != 'extra-20-serpapi-search-tools-pydantic-ai' and extra == 'extra-20-serpapi-search-tools-smolagents' and extra == 'group-20-serpapi-search-tools-docs')" },
{ name = "httpx", marker = "(python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-google-adk') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (python_full_version >= '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-semantic-kernel')" },
{ name = "opentelemetry-api", marker = "(python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-google-adk') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (python_full_version >= '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-semantic-kernel')" },
{ name = "pydantic", version = "2.12.5", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-google-adk') or (python_full_version >= '3.14' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (python_full_version >= '3.14' and extra != 'extra-20-serpapi-search-tools-frameworks' and extra != 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langchain') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-langgraph') or (extra == 'extra-20-serpapi-search-tools-google-adk' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-openai-agents' and extra == 'extra-20-serpapi-search-tools-semantic-kernel') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-google-adk') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-openai-agents') or (extra == 'extra-20-serpapi-search-tools-frameworks' and extra == 'extra-20-serpapi-search-tools-semantic-kernel')" },
@@ -8018,6 +8041,7 @@ name = "serpapi-search-tools"
version = "0.2.0"
source = { editable = "." }
dependencies = [
+ { name = "mistune" },
{ name = "serpapi" },
]
@@ -8106,7 +8130,7 @@ dev = [
]
docs = [
{ name = "great-docs", marker = "python_full_version >= '3.11'" },
- { name = "griffe", version = "0.49.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
+ { name = "griffe", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
]
openai-compat = [
{ name = "langchain-openai" },
@@ -8141,6 +8165,7 @@ requires-dist = [
{ name = "langgraph", marker = "extra == 'langgraph'", specifier = ">=1.2.6,<2" },
{ name = "llama-index-core", marker = "extra == 'frameworks'", specifier = ">=0.14.22,<0.15" },
{ name = "llama-index-core", marker = "extra == 'llamaindex'", specifier = ">=0.14.22,<0.15" },
+ { name = "mistune", specifier = ">=3.1.0,<4" },
{ name = "openai", marker = "extra == 'agno'", specifier = ">=1.0.0,<3" },
{ name = "openai", marker = "extra == 'frameworks'", specifier = ">=1.0.0,<3" },
{ name = "openai", marker = "extra == 'semantic-kernel'", specifier = ">=1.0.0,<3" },
@@ -8169,8 +8194,8 @@ dev = [
{ name = "uvicorn", specifier = ">=0.34.0,<1" },
]
docs = [
- { name = "great-docs", marker = "python_full_version >= '3.11'", specifier = ">=0.14.0,<0.15" },
- { name = "griffe", marker = "python_full_version >= '3.11'", specifier = ">=0.35.0,<1" },
+ { name = "great-docs", marker = "python_full_version >= '3.11'", specifier = ">=0.15.0,<0.16" },
+ { name = "griffe", marker = "python_full_version >= '3.11'", specifier = ">=2.1.0,<2.2" },
]
openai-compat = [
{ name = "langchain-openai", specifier = ">=1.1.9,<2" },