Skip to content

Commit ecf6f75

Browse files
committed
Merge branch 'main' into toolsets
2 parents b2aa894 + 72970c2 commit ecf6f75

39 files changed

+1037
-71
lines changed

.github/workflows/stale.yml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
1-
name: 'Close stale issues'
1+
name: 'Close stale issues and PRs'
22
on:
33
schedule:
44
- cron: '0 14 * * *'
55

66
permissions:
77
issues: write
8+
pull-requests: write
89

910
jobs:
1011
stale:
1112
runs-on: ubuntu-latest
1213
steps:
1314
- uses: actions/stale@v9
1415
with:
15-
stale-issue-message: 'This issue is stale, and will be closed in 3 days if no reply is received.'
16-
close-issue-message: 'Closing this issue as it has been inactive for 10 days.'
17-
any-of-labels: 'question,more info'
1816
days-before-stale: 7
1917
days-before-close: 3
18+
19+
any-of-issue-labels: 'question,more info'
20+
stale-issue-message: 'This issue is stale, and will be closed in 3 days if no reply is received.'
21+
close-issue-message: 'Closing this issue as it has been inactive for 10 days.'
22+
23+
any-of-pr-labels: 'awaiting author revision'
24+
stale-pr-message: 'This PR is stale, and will be closed in 3 days if no reply is received.'
25+
close-pr-message: 'Closing this PR as it has been inactive for 10 days.'

docs/agents.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@ This structure allows you to configure common parameters that influence the mode
467467
`timeout`, and more.
468468

469469
There are two ways to apply these settings:
470+
470471
1. Passing to `run{_sync,_stream}` functions via the `model_settings` argument. This allows for fine-tuning on a per-request basis.
471472
2. Setting during [`Agent`][pydantic_ai.agent.Agent] initialization via the `model_settings` argument. These settings will be applied by default to all subsequent run calls using said agent. However, `model_settings` provided during a specific run call will override the agent's default settings.
472473

docs/api/providers.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,6 @@
2828

2929
::: pydantic_ai.providers.heroku.HerokuProvider
3030

31+
::: pydantic_ai.providers.github.GitHubProvider
32+
3133
::: pydantic_ai.providers.openrouter.OpenRouterProvider

docs/direct.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ The following functions are available:
99
- [`model_request`][pydantic_ai.direct.model_request]: Make a non-streamed async request to a model
1010
- [`model_request_sync`][pydantic_ai.direct.model_request_sync]: Make a non-streamed synchronous request to a model
1111
- [`model_request_stream`][pydantic_ai.direct.model_request_stream]: Make a streamed async request to a model
12+
- [`model_request_stream_sync`][pydantic_ai.direct.model_request_stream_sync]: Make a streamed sync request to a model
1213

1314
## Basic Example
1415

docs/models/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ In addition, many providers are compatible with the OpenAI API, and can be used
2323
* [Together AI](openai.md#together-ai)
2424
* [Azure AI Foundry](openai.md#azure-ai-foundry)
2525
* [Heroku](openai.md#heroku-ai)
26+
* [GitHub Models](openai.md#github-models)
2627

2728
PydanticAI also comes with [`TestModel`](../api/models/test.md) and [`FunctionModel`](../api/models/function.md)
2829
for testing and development.

docs/models/openai.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,33 @@ agent = Agent(model)
366366
...
367367
```
368368

369+
### GitHub Models
370+
371+
To use [GitHub Models](https://docs.github.com/en/github-models), you'll need a GitHub personal access token with the `models: read` permission.
372+
373+
Once you have the token, you can use it with the [`GitHubProvider`][pydantic_ai.providers.github.GitHubProvider]:
374+
375+
```python
376+
from pydantic_ai import Agent
377+
from pydantic_ai.models.openai import OpenAIModel
378+
from pydantic_ai.providers.github import GitHubProvider
379+
380+
model = OpenAIModel(
381+
'xai/grok-3-mini', # GitHub Models uses prefixed model names
382+
provider=GitHubProvider(api_key='your-github-token'),
383+
)
384+
agent = Agent(model)
385+
...
386+
```
387+
388+
You can also set the `GITHUB_API_KEY` environment variable:
389+
390+
```bash
391+
export GITHUB_API_KEY='your-github-token'
392+
```
393+
394+
GitHub Models supports various model families with different prefixes. You can see the full list on the [GitHub Marketplace](https://github.com/marketplace?type=models) or the public [catalog endpoint](https://models.github.ai/catalog/models).
395+
369396
### Perplexity
370397

371398
Follow the Perplexity [getting started](https://docs.perplexity.ai/guides/getting-started)

docs/tools.md

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -721,11 +721,19 @@ def my_flaky_tool(query: str) -> str:
721721
```
722722
Raising `ModelRetry` also generates a `RetryPromptPart` containing the exception message, which is sent back to the LLM to guide its next attempt. Both `ValidationError` and `ModelRetry` respect the `retries` setting configured on the `Tool` or `Agent`.
723723

724-
## Use LangChain Tools {#langchain-tools}
724+
## Third-Party Tools
725725

726-
If you'd like to use a tool from LangChain's [community tool library](https://python.langchain.com/docs/integrations/tools/) with PydanticAI, you can use the `pydancic_ai.ext.langchain.tool_from_langchain` convenience method. Note that PydanticAI will not validate the arguments in this case -- it's up to the model to provide arguments matching the schema specified by the LangChain tool, and up to the LangChain tool to raise an error if the arguments are invalid.
726+
### MCP Tools {#mcp-tools}
727727

728-
Here is how you can use it to augment model responses using a LangChain web search tool. This tool will need you to install the `langchain-community` and `duckduckgo-search` dependencies to work properly.
728+
See the [MCP Client](./mcp/client.md) documentation for how to use MCP servers with Pydantic AI.
729+
730+
### LangChain Tools {#langchain-tools}
731+
732+
If you'd like to use a tool from LangChain's [community tool library](https://python.langchain.com/docs/integrations/tools/) with Pydantic AI, you can use the `pydancic_ai.ext.langchain.tool_from_langchain` convenience method. Note that Pydantic AI will not validate the arguments in this case -- it's up to the model to provide arguments matching the schema specified by the LangChain tool, and up to the LangChain tool to raise an error if the arguments are invalid.
733+
734+
You will need to install the `langchain-community` package and any others required by the tool in question.
735+
736+
Here is how you can use the LangChain `DuckDuckGoSearchRun` tool, which requires the `duckduckgo-search` package:
729737

730738
```python {test="skip"}
731739
from langchain_community.tools import DuckDuckGoSearchRun
@@ -737,15 +745,44 @@ search = DuckDuckGoSearchRun()
737745
search_tool = tool_from_langchain(search)
738746

739747
agent = Agent(
740-
'google-gla:gemini-2.0-flash', # (1)!
748+
'google-gla:gemini-2.0-flash',
741749
tools=[search_tool],
742750
)
743751

744-
result = agent.run_sync('What is the release date of Elden Ring Nightreign?') # (2)!
752+
result = agent.run_sync('What is the release date of Elden Ring Nightreign?') # (1)!
745753
print(result.output)
746754
#> Elden Ring Nightreign is planned to be released on May 30, 2025.
747755
```
748756

757+
1. The release date of this game is the 30th of May 2025, which is after the knowledge cutoff for Gemini 2.0 (August 2024).
758+
759+
### ACI.dev Tools {#aci-tools}
760+
761+
If you'd like to use a tool from the [ACI.dev tool library](https://www.aci.dev/tools) with Pydantic AI, you can use the `pydancic_ai.ext.aci.tool_from_aci` convenience method. Note that Pydantic AI will not validate the arguments in this case -- it's up to the model to provide arguments matching the schema specified by the ACI tool, and up to the ACI tool to raise an error if the arguments are invalid.
762+
763+
You will need to install the `aci-sdk` package, set your ACI API key in the `ACI_API_KEY` environment variable, and pass your ACI "linked account owner ID" to the function.
764+
765+
Here is how you can use the ACI.dev `TAVILY__SEARCH` tool:
766+
767+
```python {test="skip"}
768+
import os
769+
770+
from pydantic_ai import Agent
771+
from pydantic_ai.ext.aci import tool_from_aci
772+
773+
tavily_search = tool_from_aci(
774+
'TAVILY__SEARCH',
775+
linked_account_owner_id=os.getenv('LINKED_ACCOUNT_OWNER_ID')
776+
)
777+
778+
agent = Agent(
779+
'google-gla:gemini-2.0-flash',
780+
tools=[tavily_search]
781+
)
782+
783+
result = agent.run_sync('What is the release date of Elden Ring Nightreign?') # (1)!
784+
print(result.output)
785+
#> Elden Ring Nightreign is planned to be released on May 30, 2025.
786+
```
749787

750-
1. While this task is simple Gemini 1.5 didn't want to use the provided tool. Gemini 2.0 is still fast and cheap.
751-
2. The release date of this game is the 30th of May 2025, which was confirmed after the knowledge cutoff for Gemini 2.0 (August 2024).
788+
1. The release date of this game is the 30th of May 2025, which is after the knowledge cutoff for Gemini 2.0 (August 2024).

pydantic_ai_slim/pydantic_ai/agent.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ def __init__(
340340
if 'result_type' in _deprecated_kwargs:
341341
if output_type is not str: # pragma: no cover
342342
raise TypeError('`result_type` and `output_type` cannot be set at the same time.')
343-
warnings.warn('`result_type` is deprecated, use `output_type` instead', DeprecationWarning)
343+
warnings.warn('`result_type` is deprecated, use `output_type` instead', DeprecationWarning, stacklevel=2)
344344
output_type = _deprecated_kwargs.pop('result_type')
345345

346346
self.output_type = output_type
@@ -354,19 +354,23 @@ def __init__(
354354
warnings.warn(
355355
'`result_tool_name` is deprecated, use `output_type` with `ToolOutput` instead',
356356
DeprecationWarning,
357+
stacklevel=2,
357358
)
358359

359360
self._deprecated_result_tool_description = _deprecated_kwargs.pop('result_tool_description', None)
360361
if self._deprecated_result_tool_description is not None:
361362
warnings.warn(
362363
'`result_tool_description` is deprecated, use `output_type` with `ToolOutput` instead',
363364
DeprecationWarning,
365+
stacklevel=2,
364366
)
365367
result_retries = _deprecated_kwargs.pop('result_retries', None)
366368
if result_retries is not None:
367369
if output_retries is not None: # pragma: no cover
368370
raise TypeError('`output_retries` and `result_retries` cannot be set at the same time.')
369-
warnings.warn('`result_retries` is deprecated, use `max_result_retries` instead', DeprecationWarning)
371+
warnings.warn(
372+
'`result_retries` is deprecated, use `max_result_retries` instead', DeprecationWarning, stacklevel=2
373+
)
370374
output_retries = result_retries
371375

372376
if mcp_servers := _deprecated_kwargs.pop('mcp_servers', None):
@@ -540,7 +544,7 @@ async def main():
540544
if 'result_type' in _deprecated_kwargs: # pragma: no cover
541545
if output_type is not str:
542546
raise TypeError('`result_type` and `output_type` cannot be set at the same time.')
543-
warnings.warn('`result_type` is deprecated, use `output_type` instead.', DeprecationWarning)
547+
warnings.warn('`result_type` is deprecated, use `output_type` instead.', DeprecationWarning, stacklevel=2)
544548
output_type = _deprecated_kwargs.pop('result_type')
545549

546550
_utils.validate_empty_kwargs(_deprecated_kwargs)
@@ -714,7 +718,7 @@ async def main():
714718
if 'result_type' in _deprecated_kwargs: # pragma: no cover
715719
if output_type is not str:
716720
raise TypeError('`result_type` and `output_type` cannot be set at the same time.')
717-
warnings.warn('`result_type` is deprecated, use `output_type` instead.', DeprecationWarning)
721+
warnings.warn('`result_type` is deprecated, use `output_type` instead.', DeprecationWarning, stacklevel=2)
718722
output_type = _deprecated_kwargs.pop('result_type')
719723

720724
_utils.validate_empty_kwargs(_deprecated_kwargs)
@@ -977,7 +981,7 @@ def run_sync(
977981
if 'result_type' in _deprecated_kwargs: # pragma: no cover
978982
if output_type is not str:
979983
raise TypeError('`result_type` and `output_type` cannot be set at the same time.')
980-
warnings.warn('`result_type` is deprecated, use `output_type` instead.', DeprecationWarning)
984+
warnings.warn('`result_type` is deprecated, use `output_type` instead.', DeprecationWarning, stacklevel=2)
981985
output_type = _deprecated_kwargs.pop('result_type')
982986

983987
_utils.validate_empty_kwargs(_deprecated_kwargs)
@@ -1101,7 +1105,7 @@ async def main():
11011105
if 'result_type' in _deprecated_kwargs: # pragma: no cover
11021106
if output_type is not str:
11031107
raise TypeError('`result_type` and `output_type` cannot be set at the same time.')
1104-
warnings.warn('`result_type` is deprecated, use `output_type` instead.', DeprecationWarning)
1108+
warnings.warn('`result_type` is deprecated, use `output_type` instead.', DeprecationWarning, stacklevel=2)
11051109
output_type = _deprecated_kwargs.pop('result_type')
11061110

11071111
_utils.validate_empty_kwargs(_deprecated_kwargs)
@@ -1440,7 +1444,11 @@ async def output_validator_deps(ctx: RunContext[str], data: str) -> str:
14401444
return func
14411445

14421446
@deprecated('`result_validator` is deprecated, use `output_validator` instead.')
1443-
def result_validator(self, func: Any, /) -> Any: ...
1447+
def result_validator(self, func: Any, /) -> Any:
1448+
warnings.warn(
1449+
'`result_validator` is deprecated, use `output_validator` instead.', DeprecationWarning, stacklevel=2
1450+
)
1451+
return self.output_validator(func) # type: ignore
14441452

14451453
@overload
14461454
def tool(self, func: ToolFuncContext[AgentDepsT, ToolParams], /) -> ToolFuncContext[AgentDepsT, ToolParams]: ...

0 commit comments

Comments
 (0)