Merge pull request #162 from pydantic/infra/repo-setup

Set up repo infrastructure: CI, docs skeleton, conftest, dependency management
This commit is contained in:
Douwe Maan
2026-04-01 23:26:24 -06:00
committed by GitHub
9 changed files with 331 additions and 54 deletions
+11 -1
View File
@@ -8,12 +8,21 @@ on:
- '**'
pull_request: {}
env:
UV_FROZEN: '1'
permissions:
contents: read
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
with:
python-version: '3.13'
enable-cache: true
- run: uv sync --frozen --all-groups
- run: make lint
- run: make typecheck
@@ -23,12 +32,13 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ['3.10', '3.11', '3.12', '3.13']
python-version: ['3.10', '3.12', '3.13']
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
with:
python-version: ${{ matrix.python-version }}
enable-cache: true
- run: uv sync --frozen --all-groups
- run: make testcov
+61 -27
View File
@@ -1,41 +1,75 @@
TODOs and plan for this repo
# Pydantic Harness
## intro
Composable, reusable capabilities for [Pydantic AI](https://ai.pydantic.dev/) agents.
TODO
## What is it?
## glossary
Pydantic Harness provides a library of **capabilities** -- self-contained bundles of system prompts, tools, and lifecycle hooks -- that you can attach to any Pydantic AI agent to give it new powers without writing boilerplate.
AICA: AI Code Assistant
Research: AICAs are able to do research via WebFetching, WebSearching or using the `gh` CLI to look up issues, PRs and comments on github, as well as explore code they don't locally have access to.
Each capability is an [`AbstractCapability`](https://ai.pydantic.dev/capabilities/) subclass that plugs into the agent loop via Pydantic AI's capabilities API.
## mechanical
## Installation
- [ ] start a new python package (`pydantic-harness`)
- [ ] `uv init`
```bash
pip install pydantic-harness
```
Requires Python 3.10+ and `pydantic-ai-slim>=1.76.0`.
## automated code factory
## Quick start
- the optimal flow is issue gets opened and discussed -> when ready, AICA is triggered to open a PR to close the issue with only one file (`PLAN.md`)
- `PLAN.md` is reviewed (inline comments, PR discussion) -> AICA is triggered to update the plan
- when the plan is ready, AICA is triggered to implement the plan
- AICA must loop to review the changes are according to the plan, identify any new questions
- more about looping under [ralph loop](#ralph-loop) below.
```python
from pydantic_ai import Agent
from pydantic_harness import Memory, Skills, Compaction
### how does the AICA get triggered? via the label system
agent = Agent(
'openai:gpt-4o',
capabilities=[Memory(), Skills(), Compaction()],
)
We use labels to trigger AICA actions, at the end of each action AICA must remove the label that triggered it.
result = agent.run_sync('Remember that my favourite colour is blue.')
```
Labels:
- when an issue is labeled with `aica:research`, AICA is triggered to answer questions posed in the issue (body and/or comments) by researching and linking sources, emphasis on **linking sources** for every claim it makes
- when an issue is labeled with `aica:write-plan`, AICA is triggered to create a `PLAN.md` in the issue's branch
- when a PR is labeled with `aica:update-plan`, AICA is triggered to update the `PLAN.md` in the PR's branch according to the latest discussions in the PR
- note that AICA must be able to do research in this step as well before updating the plan, if any questions require it
- any findings and decisions made must be documented in a new PR comment, not as part of the thread
- the reason for this is so we can resolve threads. if we document decisions in threads, we have to keep the threads open, which bloats the PR page and creates noise for future fetches of the PR.
- when a PR is labeled with `aica:implement-plan`, AICA is triggered to implement the plan in `PLAN.md` in the PR's branch
## Available capabilities
### ralph loop
| Capability | Description |
|---|---|
| AdaptiveReasoning | Dynamically adjust reasoning effort based on task complexity |
| Approval | Require human approval before executing sensitive operations |
| Compaction | Compress conversation history to stay within context limits |
| FileSystem | Read, write, and navigate the local filesystem |
| Guardrails | Validate inputs/outputs and enforce cost and tool constraints |
| KnowsCurrentTime | Inject the current date and time into the system prompt |
| Memory | Persistent key-value memory across agent sessions |
| Planning | Break complex tasks into plans before execution |
| RepoContextInjection | Inject repository structure and context into the system prompt |
| SecretMasking | Detect and redact secrets in agent inputs and outputs |
| SessionPersistence | Save and restore full conversation sessions |
| Shell | Execute shell commands with safety controls |
| Skills | Progressive tool loading via search and activate |
| SlidingWindow | Keep conversation history within a sliding token window |
| StuckLoopDetection | Detect and break out of repetitive agent loops |
| SubAgent | Delegate subtasks to specialised child agents |
| SystemReminders | Inject periodic reminders into the conversation |
| ToolErrorRecovery | Automatically retry or recover from tool execution errors |
| ToolOrphanRepair | Repair orphaned tool calls in conversation history |
| ToolOutputManagement | Control and format tool output for the model |
TODO
## Documentation
- [Pydantic AI docs](https://ai.pydantic.dev/)
- [Capabilities API](https://ai.pydantic.dev/capabilities/)
## Development
```bash
make install # install dependencies
make lint # ruff format check + lint
make typecheck # pyright strict
make test # pytest
make testcov # pytest with coverage
```
## License
MIT
+29
View File
@@ -0,0 +1,29 @@
# Capabilities
Each capability is an `AbstractCapability` subclass that can be attached to any
Pydantic AI agent via the `capabilities` parameter.
| Capability | Description |
|---|---|
| AdaptiveReasoning | Dynamically adjust reasoning effort based on task complexity |
| Approval | Require human approval before executing sensitive operations |
| Compaction | Compress conversation history to stay within context limits |
| FileSystem | Read, write, and navigate the local filesystem |
| Guardrails | Validate inputs/outputs and enforce cost and tool constraints |
| KnowsCurrentTime | Inject the current date and time into the system prompt |
| Memory | Persistent key-value memory across agent sessions |
| Planning | Break complex tasks into plans before execution |
| RepoContextInjection | Inject repository structure and context into the system prompt |
| SecretMasking | Detect and redact secrets in agent inputs and outputs |
| SessionPersistence | Save and restore full conversation sessions |
| Shell | Execute shell commands with safety controls |
| Skills | Progressive tool loading via search and activate |
| SlidingWindow | Keep conversation history within a sliding token window |
| StuckLoopDetection | Detect and break out of repetitive agent loops |
| SubAgent | Delegate subtasks to specialised child agents |
| SystemReminders | Inject periodic reminders into the conversation |
| ToolErrorRecovery | Automatically retry or recover from tool execution errors |
| ToolOrphanRepair | Repair orphaned tool calls in conversation history |
| ToolOutputManagement | Control and format tool output for the model |
Detailed documentation for each capability will be added as they are merged.
+36
View File
@@ -0,0 +1,36 @@
# Pydantic Harness
Composable, reusable capabilities for [Pydantic AI](https://ai.pydantic.dev/) agents.
## What is it?
Pydantic Harness provides a library of **capabilities** -- self-contained bundles of
system prompts, tools, and lifecycle hooks -- that you can attach to any Pydantic AI
agent to give it new powers without writing boilerplate.
## Installation
```bash
pip install pydantic-harness
```
Or with `uv`:
```bash
uv add pydantic-harness
```
## Quick start
```python
from pydantic_ai import Agent
from pydantic_harness import Memory, Skills
agent = Agent('openai:gpt-4o', capabilities=[Memory(), Skills()])
```
## Learn more
- [Available capabilities](capabilities/index.md)
- [Pydantic AI documentation](https://ai.pydantic.dev/)
- [GitHub repository](https://github.com/pydantic/pydantic-harness)
+7 -2
View File
@@ -24,7 +24,7 @@ classifiers = [
'Topic :: Software Development :: Libraries',
'Typing :: Typed',
]
dependencies = ['pydantic-ai-slim>=0.1']
dependencies = ['pydantic-ai-slim>=1.76.0']
[project.urls]
Homepage = 'https://github.com/pydantic/pydantic-harness'
@@ -34,7 +34,8 @@ Issues = 'https://github.com/pydantic/pydantic-harness/issues'
[dependency-groups]
dev = [
'pytest',
'pytest-xdist',
'anyio[trio]',
'pytest-anyio',
'coverage',
]
lint = [
@@ -78,10 +79,14 @@ quote-style = 'single'
[tool.pyright]
pythonVersion = '3.10'
typeCheckingMode = 'strict'
executionEnvironments = [
{ root = 'tests', reportPrivateUsage = false },
]
[tool.pytest.ini_options]
xfail_strict = true
filterwarnings = ['error']
anyio_mode = 'auto'
[tool.coverage.run]
branch = true
+10 -1
View File
@@ -1 +1,10 @@
"""Agent harness for composable, reusable AI agent capabilities, built on PydanticAI."""
"""Agent harness for composable, reusable AI agent capabilities, built on PydanticAI.
Usage:
from pydantic_harness import Memory, Skills, Guardrails, ...
"""
# Each capability module is imported and re-exported here.
# Capabilities are listed alphabetically.
__all__: list[str] = []
+37
View File
@@ -0,0 +1,37 @@
from __future__ import annotations
from collections.abc import Iterator
from pathlib import Path
import pydantic_ai.models
import pytest
from pydantic_ai import Agent
from pydantic_ai.models.test import TestModel
# Prevent accidental real model requests during tests.
pydantic_ai.models.ALLOW_MODEL_REQUESTS = False
@pytest.fixture
def test_model() -> TestModel:
"""A fresh ``TestModel`` instance for each test."""
return TestModel()
@pytest.fixture
def test_agent(test_model: TestModel) -> Agent[None, str]:
"""A minimal agent wired to ``TestModel`` for capability tests."""
return Agent(test_model, name='test-agent')
@pytest.fixture
def tmp_dir(tmp_path: Path) -> Path:
"""Convenience alias for ``tmp_path`` (useful for store / session tests)."""
return tmp_path
@pytest.fixture
def allow_model_requests() -> Iterator[None]:
"""Temporarily allow real model requests within a test."""
with pydantic_ai.models.override_allow_model_requests(True):
yield
+24
View File
@@ -1,5 +1,29 @@
from pathlib import Path
from pydantic_ai import Agent
from pydantic_ai.models.test import TestModel
import pydantic_harness
def test_import():
assert pydantic_harness.__doc__ is not None
assert isinstance(pydantic_harness.__all__, list)
def test_test_model_fixture(test_model: TestModel):
assert isinstance(test_model, TestModel)
def test_test_agent_fixture(test_agent: Agent[None, str]):
assert test_agent.name == 'test-agent'
def test_tmp_dir_fixture(tmp_dir: Path):
assert tmp_dir.is_dir()
async def test_allow_model_requests(allow_model_requests: None):
import pydantic_ai.models
assert pydantic_ai.models.ALLOW_MODEL_REQUESTS is True
Generated
+116 -23
View File
@@ -25,6 +25,20 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" },
]
[package.optional-dependencies]
trio = [
{ name = "trio" },
]
[[package]]
name = "attrs"
version = "26.1.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" },
]
[[package]]
name = "certifi"
version = "2026.2.25"
@@ -34,6 +48,34 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" },
]
[[package]]
name = "cffi"
version = "2.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pycparser", marker = "implementation_name != 'PyPy'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" },
{ url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" },
{ url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" },
{ url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" },
{ url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" },
{ url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" },
{ url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" },
{ url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" },
{ url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" },
{ url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" },
{ url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" },
{ url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" },
{ url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" },
{ url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" },
{ url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" },
{ url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" },
{ url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
]
[[package]]
name = "colorama"
version = "0.4.6"
@@ -168,15 +210,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" },
]
[[package]]
name = "execnet"
version = "2.1.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/bf/89/780e11f9588d9e7128a3f87788354c7946a9cbb1401ad38a48c4db9a4f07/execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd", size = 166622, upload-time = "2025-11-12T09:56:37.75Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec", size = 40708, upload-time = "2025-11-12T09:56:36.333Z" },
]
[[package]]
name = "genai-prices"
version = "0.0.56"
@@ -194,6 +227,7 @@ wheels = [
name = "griffelib"
version = "2.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ad/06/eccbd311c9e2b3ca45dbc063b93134c57a1ccc7607c5e545264ad092c4a9/griffelib-2.0.0.tar.gz", hash = "sha256:e504d637a089f5cab9b5daf18f7645970509bf4f53eda8d79ed71cce8bd97934", size = 166312, upload-time = "2026-03-23T21:06:55.954Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/4d/51/c936033e16d12b627ea334aaaaf42229c37620d0f15593456ab69ab48161/griffelib-2.0.0-py3-none-any.whl", hash = "sha256:01284878c966508b6d6f1dbff9b6fa607bc062d8261c5c7253cb285b06422a7f", size = 142004, upload-time = "2026-02-09T19:09:40.561Z" },
]
@@ -296,6 +330,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/5f/bf/93795954016c522008da367da292adceed71cca6ee1717e1d64c83089099/opentelemetry_api-1.40.0-py3-none-any.whl", hash = "sha256:82dd69331ae74b06f6a874704be0cfaa49a1650e1537d4a813b86ecef7d0ecf9", size = 68676, upload-time = "2026-03-04T14:17:01.24Z" },
]
[[package]]
name = "outcome"
version = "1.3.0.post0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "attrs" },
]
sdist = { url = "https://files.pythonhosted.org/packages/98/df/77698abfac98571e65ffeb0c1fba8ffd692ab8458d617a0eed7d9a8d38f2/outcome-1.3.0.post0.tar.gz", hash = "sha256:9dcf02e65f2971b80047b377468e72a268e15c0af3cf1238e6ff14f7f91143b8", size = 21060, upload-time = "2023-10-26T04:26:04.361Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/55/8b/5ab7257531a5d830fc8000c476e63c935488d74609b50f9384a643ec0a62/outcome-1.3.0.post0-py2.py3-none-any.whl", hash = "sha256:e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b", size = 10692, upload-time = "2023-10-26T04:26:02.532Z" },
]
[[package]]
name = "packaging"
version = "26.0"
@@ -314,6 +360,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
]
[[package]]
name = "pycparser"
version = "3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
]
[[package]]
name = "pydantic"
version = "2.12.5"
@@ -331,7 +386,7 @@ wheels = [
[[package]]
name = "pydantic-ai-slim"
version = "1.70.0"
version = "1.76.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
@@ -343,9 +398,9 @@ dependencies = [
{ name = "pydantic-graph" },
{ name = "typing-inspection" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ac/97/d57ee44976c349658ea7c645c5c2e1a26830e4b60fdeeee2669d4aaef6eb/pydantic_ai_slim-1.70.0.tar.gz", hash = "sha256:3df0c0e92f72c35e546d24795bce1f4d38f81da2d10addd2e9f255b2d2c83c91", size = 445474, upload-time = "2026-03-18T04:24:34.393Z" }
sdist = { url = "https://files.pythonhosted.org/packages/a8/12/625331a88ea2db885e4cda4c2384f8dac9a876260ee3e6e982a950733e6c/pydantic_ai_slim-1.76.0.tar.gz", hash = "sha256:db82bc9a24f9c80d00be23f7a18e5cda8484d77c61a5cd8eedfc2fc8515657b2", size = 508214, upload-time = "2026-04-02T00:25:51.26Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/da/8c/8545d28d0b3a9957aa21393cfdab8280bb854362360b296cd486ed1713ec/pydantic_ai_slim-1.70.0-py3-none-any.whl", hash = "sha256:162907092a562b3160d9ef0418d317ec941c5c0e6dd6e0aa0dbb53b5a5cd3450", size = 576244, upload-time = "2026-03-18T04:24:27.301Z" },
{ url = "https://files.pythonhosted.org/packages/bd/c6/7801af6853502bd53f00e88560f60270d8a2ab3bd8e19732d5ae8f261503/pydantic_ai_slim-1.76.0-py3-none-any.whl", hash = "sha256:1932799ff46a03e83fca3fb194f580dcbf3b24c9d2571ef64d0789c950499e23", size = 651190, upload-time = "2026-04-02T00:25:43.987Z" },
]
[[package]]
@@ -468,7 +523,7 @@ wheels = [
[[package]]
name = "pydantic-graph"
version = "1.70.0"
version = "1.76.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpx" },
@@ -476,9 +531,9 @@ dependencies = [
{ name = "pydantic" },
{ name = "typing-inspection" },
]
sdist = { url = "https://files.pythonhosted.org/packages/07/27/f7a71ca2a3705e7c24fd777959cf5515646cc5f23b5b16c886a2ed373340/pydantic_graph-1.70.0.tar.gz", hash = "sha256:3f76d9137369ef8748b0e8a6df1a08262118af20a32bc139d23e5c0509c6b711", size = 58578, upload-time = "2026-03-18T04:24:37.007Z" }
sdist = { url = "https://files.pythonhosted.org/packages/b7/3c/6dc8c19c9eba073884b861d88cc96658d38bde4dd49f4b07e9a87f589eec/pydantic_graph-1.76.0.tar.gz", hash = "sha256:e0f8f85ab08b0f896aed50bc888f946f7c2ef3f032b78fefc8dc1fd77a49406e", size = 58716, upload-time = "2026-04-02T00:25:53.605Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/38/fd/19c42b60c37dfdbbf5b76c7b218e8309b43dac501f7aaf2025527ca05023/pydantic_graph-1.70.0-py3-none-any.whl", hash = "sha256:6083c1503a2587990ee1b8a15915106e3ddabc8f3f11fbc4a108a7d7496af4a5", size = 72351, upload-time = "2026-03-18T04:24:30.291Z" },
{ url = "https://files.pythonhosted.org/packages/56/4f/60b018568a33c907734613fb089ff288168faa6affb634e05e1a53f1f9e8/pydantic_graph-1.76.0-py3-none-any.whl", hash = "sha256:eda23a36bcaf4ab09ce10e7860818c6eeb2f42b3429ba9a575cc3b713ef3bbd6", size = 72502, upload-time = "2026-04-02T00:25:47.148Z" },
]
[[package]]
@@ -490,9 +545,10 @@ dependencies = [
[package.dev-dependencies]
dev = [
{ name = "anyio", extra = ["trio"] },
{ name = "coverage" },
{ name = "pytest" },
{ name = "pytest-xdist" },
{ name = "pytest-anyio" },
]
lint = [
{ name = "pyright" },
@@ -500,13 +556,14 @@ lint = [
]
[package.metadata]
requires-dist = [{ name = "pydantic-ai-slim", specifier = ">=0.1" }]
requires-dist = [{ name = "pydantic-ai-slim", specifier = ">=1.76.0" }]
[package.metadata.requires-dev]
dev = [
{ name = "anyio", extras = ["trio"] },
{ name = "coverage" },
{ name = "pytest" },
{ name = "pytest-xdist" },
{ name = "pytest-anyio" },
]
lint = [
{ name = "pyright", specifier = ">=1.1.408" },
@@ -554,16 +611,16 @@ wheels = [
]
[[package]]
name = "pytest-xdist"
version = "3.8.0"
name = "pytest-anyio"
version = "0.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "execnet" },
{ name = "anyio" },
{ name = "pytest" },
]
sdist = { url = "https://files.pythonhosted.org/packages/78/b4/439b179d1ff526791eb921115fca8e44e596a13efeda518b9d845a619450/pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1", size = 88069, upload-time = "2025-07-01T13:30:59.346Z" }
sdist = { url = "https://files.pythonhosted.org/packages/00/44/a02e5877a671b0940f21a7a0d9704c22097b123ed5cdbcca9cab39f17acc/pytest-anyio-0.0.0.tar.gz", hash = "sha256:b41234e9e9ad7ea1dbfefcc1d6891b23d5ef7c9f07ccf804c13a9cc338571fd3", size = 1560, upload-time = "2021-06-29T22:57:30.846Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88", size = 46396, upload-time = "2025-07-01T13:30:56.632Z" },
{ url = "https://files.pythonhosted.org/packages/c6/25/bd6493ae85d0a281b6a0f248d0fdb1d9aa2b31f18bcd4a8800cf397d8209/pytest_anyio-0.0.0-py2.py3-none-any.whl", hash = "sha256:dc8b5c4741cb16ff90be37fddd585ca943ed12bbeb563de7ace6cd94441d8746", size = 1999, upload-time = "2021-06-29T22:57:29.158Z" },
]
[[package]]
@@ -591,6 +648,24 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/8f/e8/726643a3ea68c727da31570bde48c7a10f1aa60eddd628d94078fec586ff/ruff-0.15.7-py3-none-win_arm64.whl", hash = "sha256:18e8d73f1c3fdf27931497972250340f92e8c861722161a9caeb89a58ead6ed2", size = 11023304, upload-time = "2026-03-19T16:26:51.669Z" },
]
[[package]]
name = "sniffio"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
]
[[package]]
name = "sortedcontainers"
version = "2.4.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" },
]
[[package]]
name = "tomli"
version = "2.4.0"
@@ -645,6 +720,24 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" },
]
[[package]]
name = "trio"
version = "0.33.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "attrs" },
{ name = "cffi", marker = "implementation_name != 'pypy' and os_name == 'nt'" },
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
{ name = "idna" },
{ name = "outcome" },
{ name = "sniffio" },
{ name = "sortedcontainers" },
]
sdist = { url = "https://files.pythonhosted.org/packages/52/b6/c744031c6f89b18b3f5f4f7338603ab381d740a7f45938c4607b2302481f/trio-0.33.0.tar.gz", hash = "sha256:a29b92b73f09d4b48ed249acd91073281a7f1063f09caba5dc70465b5c7aa970", size = 605109, upload-time = "2026-02-14T18:40:55.386Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1c/93/dab25dc87ac48da0fe0f6419e07d0bfd98799bed4e05e7b9e0f85a1a4b4b/trio-0.33.0-py3-none-any.whl", hash = "sha256:3bd5d87f781d9b0192d592aef28691f8951d6c2e41b7e1da4c25cde6c180ae9b", size = 510294, upload-time = "2026-02-14T18:40:53.313Z" },
]
[[package]]
name = "typing-extensions"
version = "4.15.0"