pydantic-ai-examples 0.1.2__py3-none-any.whl → 1.12.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pydantic_ai_examples/ag_ui/__init__.py +41 -0
- pydantic_ai_examples/ag_ui/__main__.py +9 -0
- pydantic_ai_examples/ag_ui/api/__init__.py +19 -0
- pydantic_ai_examples/ag_ui/api/agentic_chat.py +28 -0
- pydantic_ai_examples/ag_ui/api/agentic_generative_ui.py +120 -0
- pydantic_ai_examples/ag_ui/api/human_in_the_loop.py +27 -0
- pydantic_ai_examples/ag_ui/api/predictive_state_updates.py +78 -0
- pydantic_ai_examples/ag_ui/api/shared_state.py +139 -0
- pydantic_ai_examples/ag_ui/api/tool_based_generative_ui.py +12 -0
- pydantic_ai_examples/bank_support.py +16 -10
- pydantic_ai_examples/chat_app.py +8 -7
- pydantic_ai_examples/data_analyst.py +107 -0
- pydantic_ai_examples/evals/agent.py +1 -1
- pydantic_ai_examples/evals/custom_evaluators.py +5 -6
- pydantic_ai_examples/evals/example_01_generate_dataset.py +1 -2
- pydantic_ai_examples/evals/example_02_add_custom_evaluators.py +1 -2
- pydantic_ai_examples/evals/example_03_unit_testing.py +4 -2
- pydantic_ai_examples/evals/example_04_compare_models.py +3 -3
- pydantic_ai_examples/flight_booking.py +15 -10
- pydantic_ai_examples/py.typed +0 -0
- pydantic_ai_examples/pydantic_model.py +4 -3
- pydantic_ai_examples/question_graph.py +5 -5
- pydantic_ai_examples/rag.py +8 -7
- pydantic_ai_examples/roulette_wheel.py +1 -2
- pydantic_ai_examples/slack_lead_qualifier/__init__.py +0 -0
- pydantic_ai_examples/slack_lead_qualifier/agent.py +47 -0
- pydantic_ai_examples/slack_lead_qualifier/app.py +36 -0
- pydantic_ai_examples/slack_lead_qualifier/functions.py +85 -0
- pydantic_ai_examples/slack_lead_qualifier/modal.py +66 -0
- pydantic_ai_examples/slack_lead_qualifier/models.py +46 -0
- pydantic_ai_examples/slack_lead_qualifier/slack.py +30 -0
- pydantic_ai_examples/slack_lead_qualifier/store.py +31 -0
- pydantic_ai_examples/sql_gen.py +6 -7
- pydantic_ai_examples/stream_markdown.py +5 -4
- pydantic_ai_examples/stream_whales.py +4 -16
- pydantic_ai_examples/weather_agent.py +36 -88
- pydantic_ai_examples/weather_agent_gradio.py +10 -15
- {pydantic_ai_examples-0.1.2.dist-info → pydantic_ai_examples-1.12.0.dist-info}/METADATA +17 -13
- pydantic_ai_examples-1.12.0.dist-info/RECORD +50 -0
- pydantic_ai_examples-1.12.0.dist-info/licenses/LICENSE +21 -0
- pydantic_ai_examples-0.1.2.dist-info/RECORD +0 -30
- {pydantic_ai_examples-0.1.2.dist-info → pydantic_ai_examples-1.12.0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from typing import Annotated, Any
|
|
2
|
+
|
|
3
|
+
from annotated_types import Ge, Le
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
### [import-format_as_xml]
|
|
7
|
+
from pydantic_ai import format_as_xml ### [/import-format_as_xml]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### [profile,profile-intro]
|
|
11
|
+
class Profile(BaseModel): ### [/profile-intro]
|
|
12
|
+
first_name: str | None = None
|
|
13
|
+
last_name: str | None = None
|
|
14
|
+
display_name: str | None = None
|
|
15
|
+
email: str ### [/profile]
|
|
16
|
+
|
|
17
|
+
### [profile-as_prompt]
|
|
18
|
+
def as_prompt(self) -> str:
|
|
19
|
+
return format_as_xml(self, root_tag='profile') ### [/profile-as_prompt]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### [analysis,analysis-intro]
|
|
23
|
+
class Analysis(BaseModel): ### [/analysis-intro]
|
|
24
|
+
profile: Profile
|
|
25
|
+
organization_name: str
|
|
26
|
+
organization_domain: str
|
|
27
|
+
job_title: str
|
|
28
|
+
relevance: Annotated[int, Ge(1), Le(5)]
|
|
29
|
+
"""Estimated fit for Pydantic Logfire: 1 = low, 5 = high"""
|
|
30
|
+
summary: str
|
|
31
|
+
"""One-sentence welcome note summarising who they are and how we might help""" ### [/analysis]
|
|
32
|
+
|
|
33
|
+
### [analysis-as_slack_blocks]
|
|
34
|
+
def as_slack_blocks(self, include_relevance: bool = False) -> list[dict[str, Any]]:
|
|
35
|
+
profile = self.profile
|
|
36
|
+
relevance = f'({self.relevance}/5)' if include_relevance else ''
|
|
37
|
+
return [
|
|
38
|
+
{
|
|
39
|
+
'type': 'markdown',
|
|
40
|
+
'text': f'[{profile.display_name}](mailto:{profile.email}), {self.job_title} at [**{self.organization_name}**](https://{self.organization_domain}) {relevance}',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
'type': 'markdown',
|
|
44
|
+
'text': self.summary,
|
|
45
|
+
},
|
|
46
|
+
] ### [/analysis-as_slack_blocks]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import httpx
|
|
5
|
+
import logfire
|
|
6
|
+
|
|
7
|
+
### [send_slack_message]
|
|
8
|
+
API_KEY = os.getenv('SLACK_API_KEY')
|
|
9
|
+
assert API_KEY, 'SLACK_API_KEY is not set'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@logfire.instrument('Send Slack message')
|
|
13
|
+
async def send_slack_message(channel: str, blocks: list[dict[str, Any]]):
|
|
14
|
+
client = httpx.AsyncClient()
|
|
15
|
+
response = await client.post(
|
|
16
|
+
'https://slack.com/api/chat.postMessage',
|
|
17
|
+
json={
|
|
18
|
+
'channel': channel,
|
|
19
|
+
'blocks': blocks,
|
|
20
|
+
},
|
|
21
|
+
headers={
|
|
22
|
+
'Authorization': f'Bearer {API_KEY}',
|
|
23
|
+
},
|
|
24
|
+
timeout=5,
|
|
25
|
+
)
|
|
26
|
+
response.raise_for_status()
|
|
27
|
+
result = response.json()
|
|
28
|
+
if not result.get('ok', False):
|
|
29
|
+
error = result.get('error', 'Unknown error')
|
|
30
|
+
raise Exception(f'Failed to send to Slack: {error}') ### [/send_slack_message]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import logfire
|
|
2
|
+
|
|
3
|
+
### [import-modal]
|
|
4
|
+
import modal ### [/import-modal]
|
|
5
|
+
|
|
6
|
+
from .models import Analysis
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### [analysis_store]
|
|
10
|
+
class AnalysisStore:
|
|
11
|
+
@classmethod
|
|
12
|
+
@logfire.instrument('Add analysis to store')
|
|
13
|
+
async def add(cls, analysis: Analysis):
|
|
14
|
+
await cls._get_store().put.aio(analysis.profile.email, analysis.model_dump())
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
@logfire.instrument('List analyses from store')
|
|
18
|
+
async def list(cls) -> list[Analysis]:
|
|
19
|
+
return [
|
|
20
|
+
Analysis.model_validate(analysis)
|
|
21
|
+
async for analysis in cls._get_store().values.aio()
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
@logfire.instrument('Clear analyses from store')
|
|
26
|
+
async def clear(cls):
|
|
27
|
+
await cls._get_store().clear.aio()
|
|
28
|
+
|
|
29
|
+
@classmethod
|
|
30
|
+
def _get_store(cls) -> modal.Dict:
|
|
31
|
+
return modal.Dict.from_name('analyses', create_if_missing=True) # type: ignore ### [/analysis_store]
|
pydantic_ai_examples/sql_gen.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Example demonstrating how to use
|
|
1
|
+
"""Example demonstrating how to use Pydantic AI to generate SQL queries based on user input.
|
|
2
2
|
|
|
3
3
|
Run postgres with:
|
|
4
4
|
|
|
@@ -16,20 +16,20 @@ from collections.abc import AsyncGenerator
|
|
|
16
16
|
from contextlib import asynccontextmanager
|
|
17
17
|
from dataclasses import dataclass
|
|
18
18
|
from datetime import date
|
|
19
|
-
from typing import Annotated, Any,
|
|
19
|
+
from typing import Annotated, Any, TypeAlias
|
|
20
20
|
|
|
21
21
|
import asyncpg
|
|
22
22
|
import logfire
|
|
23
23
|
from annotated_types import MinLen
|
|
24
24
|
from devtools import debug
|
|
25
25
|
from pydantic import BaseModel, Field
|
|
26
|
-
from typing_extensions import TypeAlias
|
|
27
26
|
|
|
28
27
|
from pydantic_ai import Agent, ModelRetry, RunContext, format_as_xml
|
|
29
28
|
|
|
30
29
|
# 'if-token-present' means nothing will be sent (and the example will work) if you don't have logfire configured
|
|
31
30
|
logfire.configure(send_to_logfire='if-token-present')
|
|
32
31
|
logfire.instrument_asyncpg()
|
|
32
|
+
logfire.instrument_pydantic_ai()
|
|
33
33
|
|
|
34
34
|
DB_SCHEMA = """
|
|
35
35
|
CREATE TABLE records (
|
|
@@ -90,13 +90,12 @@ class InvalidRequest(BaseModel):
|
|
|
90
90
|
error_message: str
|
|
91
91
|
|
|
92
92
|
|
|
93
|
-
Response: TypeAlias =
|
|
94
|
-
agent
|
|
95
|
-
'google-gla:gemini-
|
|
93
|
+
Response: TypeAlias = Success | InvalidRequest
|
|
94
|
+
agent = Agent[Deps, Response](
|
|
95
|
+
'google-gla:gemini-2.5-flash',
|
|
96
96
|
# Type ignore while we wait for PEP-0747, nonetheless unions will work fine everywhere else
|
|
97
97
|
output_type=Response, # type: ignore
|
|
98
98
|
deps_type=Deps,
|
|
99
|
-
instrument=True,
|
|
100
99
|
)
|
|
101
100
|
|
|
102
101
|
|
|
@@ -20,13 +20,14 @@ from pydantic_ai.models import KnownModelName
|
|
|
20
20
|
|
|
21
21
|
# 'if-token-present' means nothing will be sent (and the example will work) if you don't have logfire configured
|
|
22
22
|
logfire.configure(send_to_logfire='if-token-present')
|
|
23
|
+
logfire.instrument_pydantic_ai()
|
|
23
24
|
|
|
24
|
-
agent = Agent(
|
|
25
|
+
agent = Agent()
|
|
25
26
|
|
|
26
27
|
# models to try, and the appropriate env var
|
|
27
28
|
models: list[tuple[KnownModelName, str]] = [
|
|
28
|
-
('google-gla:gemini-
|
|
29
|
-
('openai:gpt-
|
|
29
|
+
('google-gla:gemini-2.5-flash', 'GEMINI_API_KEY'),
|
|
30
|
+
('openai:gpt-5-mini', 'OPENAI_API_KEY'),
|
|
30
31
|
('groq:llama-3.3-70b-versatile', 'GROQ_API_KEY'),
|
|
31
32
|
]
|
|
32
33
|
|
|
@@ -41,7 +42,7 @@ async def main():
|
|
|
41
42
|
console.log(f'Using model: {model}')
|
|
42
43
|
with Live('', console=console, vertical_overflow='visible') as live:
|
|
43
44
|
async with agent.run_stream(prompt, model=model) as result:
|
|
44
|
-
async for message in result.
|
|
45
|
+
async for message in result.stream_output():
|
|
45
46
|
live.update(Markdown(message))
|
|
46
47
|
console.log(result.usage())
|
|
47
48
|
else:
|
|
@@ -11,7 +11,7 @@ Run with:
|
|
|
11
11
|
from typing import Annotated
|
|
12
12
|
|
|
13
13
|
import logfire
|
|
14
|
-
from pydantic import Field
|
|
14
|
+
from pydantic import Field
|
|
15
15
|
from rich.console import Console
|
|
16
16
|
from rich.live import Live
|
|
17
17
|
from rich.table import Table
|
|
@@ -21,6 +21,7 @@ from pydantic_ai import Agent
|
|
|
21
21
|
|
|
22
22
|
# 'if-token-present' means nothing will be sent (and the example will work) if you don't have logfire configured
|
|
23
23
|
logfire.configure(send_to_logfire='if-token-present')
|
|
24
|
+
logfire.instrument_pydantic_ai()
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
class Whale(TypedDict):
|
|
@@ -38,7 +39,7 @@ class Whale(TypedDict):
|
|
|
38
39
|
description: NotRequired[Annotated[str, Field(description='Short Description')]]
|
|
39
40
|
|
|
40
41
|
|
|
41
|
-
agent = Agent('openai:gpt-4', output_type=list[Whale]
|
|
42
|
+
agent = Agent('openai:gpt-4', output_type=list[Whale])
|
|
42
43
|
|
|
43
44
|
|
|
44
45
|
async def main():
|
|
@@ -50,20 +51,7 @@ async def main():
|
|
|
50
51
|
) as result:
|
|
51
52
|
console.print('Response:', style='green')
|
|
52
53
|
|
|
53
|
-
async for
|
|
54
|
-
try:
|
|
55
|
-
whales = await result.validate_structured_output(
|
|
56
|
-
message, allow_partial=not last
|
|
57
|
-
)
|
|
58
|
-
except ValidationError as exc:
|
|
59
|
-
if all(
|
|
60
|
-
e['type'] == 'missing' and e['loc'] == ('response',)
|
|
61
|
-
for e in exc.errors()
|
|
62
|
-
):
|
|
63
|
-
continue
|
|
64
|
-
else:
|
|
65
|
-
raise
|
|
66
|
-
|
|
54
|
+
async for whales in result.stream_output(debounce_by=0.01):
|
|
67
55
|
table = Table(
|
|
68
56
|
title='Species of Whale',
|
|
69
57
|
caption='Streaming Structured responses from GPT-4',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Example of
|
|
1
|
+
"""Example of Pydantic AI with multiple tools which the LLM needs to call in turn to answer a question.
|
|
2
2
|
|
|
3
3
|
In this case the idea is a "weather" agent — the user can ask for the weather in multiple cities,
|
|
4
4
|
the agent will use the `get_lat_lng` tool to get the latitude and longitude of the locations, then use
|
|
@@ -12,70 +12,55 @@ Run with:
|
|
|
12
12
|
from __future__ import annotations as _annotations
|
|
13
13
|
|
|
14
14
|
import asyncio
|
|
15
|
-
import os
|
|
16
15
|
from dataclasses import dataclass
|
|
17
16
|
from typing import Any
|
|
18
17
|
|
|
19
18
|
import logfire
|
|
20
|
-
from devtools import debug
|
|
21
19
|
from httpx import AsyncClient
|
|
20
|
+
from pydantic import BaseModel
|
|
22
21
|
|
|
23
|
-
from pydantic_ai import Agent,
|
|
22
|
+
from pydantic_ai import Agent, RunContext
|
|
24
23
|
|
|
25
24
|
# 'if-token-present' means nothing will be sent (and the example will work) if you don't have logfire configured
|
|
26
25
|
logfire.configure(send_to_logfire='if-token-present')
|
|
26
|
+
logfire.instrument_pydantic_ai()
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
@dataclass
|
|
30
30
|
class Deps:
|
|
31
31
|
client: AsyncClient
|
|
32
|
-
weather_api_key: str | None
|
|
33
|
-
geo_api_key: str | None
|
|
34
32
|
|
|
35
33
|
|
|
36
34
|
weather_agent = Agent(
|
|
37
|
-
'openai:gpt-
|
|
35
|
+
'openai:gpt-5-mini',
|
|
38
36
|
# 'Be concise, reply with one sentence.' is enough for some models (like openai) to use
|
|
39
37
|
# the below tools appropriately, but others like anthropic and gemini require a bit more direction.
|
|
40
|
-
|
|
41
|
-
'Be concise, reply with one sentence.'
|
|
42
|
-
'Use the `get_lat_lng` tool to get the latitude and longitude of the locations, '
|
|
43
|
-
'then use the `get_weather` tool to get the weather.'
|
|
44
|
-
),
|
|
38
|
+
instructions='Be concise, reply with one sentence.',
|
|
45
39
|
deps_type=Deps,
|
|
46
40
|
retries=2,
|
|
47
|
-
instrument=True,
|
|
48
41
|
)
|
|
49
42
|
|
|
50
43
|
|
|
44
|
+
class LatLng(BaseModel):
|
|
45
|
+
lat: float
|
|
46
|
+
lng: float
|
|
47
|
+
|
|
48
|
+
|
|
51
49
|
@weather_agent.tool
|
|
52
|
-
async def get_lat_lng(
|
|
53
|
-
ctx: RunContext[Deps], location_description: str
|
|
54
|
-
) -> dict[str, float]:
|
|
50
|
+
async def get_lat_lng(ctx: RunContext[Deps], location_description: str) -> LatLng:
|
|
55
51
|
"""Get the latitude and longitude of a location.
|
|
56
52
|
|
|
57
53
|
Args:
|
|
58
54
|
ctx: The context.
|
|
59
55
|
location_description: A description of a location.
|
|
60
56
|
"""
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
with logfire.span('calling geocode API', params=params) as span:
|
|
70
|
-
r = await ctx.deps.client.get('https://geocode.maps.co/search', params=params)
|
|
71
|
-
r.raise_for_status()
|
|
72
|
-
data = r.json()
|
|
73
|
-
span.set_attribute('response', data)
|
|
74
|
-
|
|
75
|
-
if data:
|
|
76
|
-
return {'lat': data[0]['lat'], 'lng': data[0]['lon']}
|
|
77
|
-
else:
|
|
78
|
-
raise ModelRetry('Could not find the location')
|
|
57
|
+
# NOTE: the response here will be random, and is not related to the location description.
|
|
58
|
+
r = await ctx.deps.client.get(
|
|
59
|
+
'https://demo-endpoints.pydantic.workers.dev/latlng',
|
|
60
|
+
params={'location': location_description},
|
|
61
|
+
)
|
|
62
|
+
r.raise_for_status()
|
|
63
|
+
return LatLng.model_validate_json(r.content)
|
|
79
64
|
|
|
80
65
|
|
|
81
66
|
@weather_agent.tool
|
|
@@ -87,69 +72,32 @@ async def get_weather(ctx: RunContext[Deps], lat: float, lng: float) -> dict[str
|
|
|
87
72
|
lat: Latitude of the location.
|
|
88
73
|
lng: Longitude of the location.
|
|
89
74
|
"""
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
r.raise_for_status()
|
|
104
|
-
data = r.json()
|
|
105
|
-
span.set_attribute('response', data)
|
|
106
|
-
|
|
107
|
-
values = data['data']['values']
|
|
108
|
-
# https://docs.tomorrow.io/reference/data-layers-weather-codes
|
|
109
|
-
code_lookup = {
|
|
110
|
-
1000: 'Clear, Sunny',
|
|
111
|
-
1100: 'Mostly Clear',
|
|
112
|
-
1101: 'Partly Cloudy',
|
|
113
|
-
1102: 'Mostly Cloudy',
|
|
114
|
-
1001: 'Cloudy',
|
|
115
|
-
2000: 'Fog',
|
|
116
|
-
2100: 'Light Fog',
|
|
117
|
-
4000: 'Drizzle',
|
|
118
|
-
4001: 'Rain',
|
|
119
|
-
4200: 'Light Rain',
|
|
120
|
-
4201: 'Heavy Rain',
|
|
121
|
-
5000: 'Snow',
|
|
122
|
-
5001: 'Flurries',
|
|
123
|
-
5100: 'Light Snow',
|
|
124
|
-
5101: 'Heavy Snow',
|
|
125
|
-
6000: 'Freezing Drizzle',
|
|
126
|
-
6001: 'Freezing Rain',
|
|
127
|
-
6200: 'Light Freezing Rain',
|
|
128
|
-
6201: 'Heavy Freezing Rain',
|
|
129
|
-
7000: 'Ice Pellets',
|
|
130
|
-
7101: 'Heavy Ice Pellets',
|
|
131
|
-
7102: 'Light Ice Pellets',
|
|
132
|
-
8000: 'Thunderstorm',
|
|
133
|
-
}
|
|
75
|
+
# NOTE: the responses here will be random, and are not related to the lat and lng.
|
|
76
|
+
temp_response, descr_response = await asyncio.gather(
|
|
77
|
+
ctx.deps.client.get(
|
|
78
|
+
'https://demo-endpoints.pydantic.workers.dev/number',
|
|
79
|
+
params={'min': 10, 'max': 30},
|
|
80
|
+
),
|
|
81
|
+
ctx.deps.client.get(
|
|
82
|
+
'https://demo-endpoints.pydantic.workers.dev/weather',
|
|
83
|
+
params={'lat': lat, 'lng': lng},
|
|
84
|
+
),
|
|
85
|
+
)
|
|
86
|
+
temp_response.raise_for_status()
|
|
87
|
+
descr_response.raise_for_status()
|
|
134
88
|
return {
|
|
135
|
-
'temperature': f'{
|
|
136
|
-
'description':
|
|
89
|
+
'temperature': f'{temp_response.text} °C',
|
|
90
|
+
'description': descr_response.text,
|
|
137
91
|
}
|
|
138
92
|
|
|
139
93
|
|
|
140
94
|
async def main():
|
|
141
95
|
async with AsyncClient() as client:
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
# create a free API key at https://geocode.maps.co/
|
|
145
|
-
geo_api_key = os.getenv('GEO_API_KEY')
|
|
146
|
-
deps = Deps(
|
|
147
|
-
client=client, weather_api_key=weather_api_key, geo_api_key=geo_api_key
|
|
148
|
-
)
|
|
96
|
+
logfire.instrument_httpx(client, capture_all=True)
|
|
97
|
+
deps = Deps(client=client)
|
|
149
98
|
result = await weather_agent.run(
|
|
150
99
|
'What is the weather like in London and in Wiltshire?', deps=deps
|
|
151
100
|
)
|
|
152
|
-
debug(result)
|
|
153
101
|
print('Response:', result.output)
|
|
154
102
|
|
|
155
103
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations as _annotations
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
-
import os
|
|
5
4
|
|
|
6
5
|
from httpx import AsyncClient
|
|
6
|
+
from pydantic import BaseModel
|
|
7
7
|
|
|
8
|
-
from pydantic_ai
|
|
8
|
+
from pydantic_ai import ToolCallPart, ToolReturnPart
|
|
9
9
|
from pydantic_ai_examples.weather_agent import Deps, weather_agent
|
|
10
10
|
|
|
11
11
|
try:
|
|
@@ -18,10 +18,7 @@ except ImportError as e:
|
|
|
18
18
|
TOOL_TO_DISPLAY_NAME = {'get_lat_lng': 'Geocoding API', 'get_weather': 'Weather API'}
|
|
19
19
|
|
|
20
20
|
client = AsyncClient()
|
|
21
|
-
|
|
22
|
-
# create a free API key at https://geocode.maps.co/
|
|
23
|
-
geo_api_key = os.getenv('GEO_API_KEY')
|
|
24
|
-
deps = Deps(client=client, weather_api_key=weather_api_key, geo_api_key=geo_api_key)
|
|
21
|
+
deps = Deps(client=client)
|
|
25
22
|
|
|
26
23
|
|
|
27
24
|
async def stream_from_agent(prompt: str, chatbot: list[dict], past_messages: list):
|
|
@@ -33,16 +30,12 @@ async def stream_from_agent(prompt: str, chatbot: list[dict], past_messages: lis
|
|
|
33
30
|
for message in result.new_messages():
|
|
34
31
|
for call in message.parts:
|
|
35
32
|
if isinstance(call, ToolCallPart):
|
|
36
|
-
call_args = (
|
|
37
|
-
call.args.args_json
|
|
38
|
-
if hasattr(call.args, 'args_json')
|
|
39
|
-
else json.dumps(call.args.args_dict)
|
|
40
|
-
)
|
|
33
|
+
call_args = call.args_as_json_str()
|
|
41
34
|
metadata = {
|
|
42
35
|
'title': f'🛠️ Using {TOOL_TO_DISPLAY_NAME[call.tool_name]}',
|
|
43
36
|
}
|
|
44
37
|
if call.tool_call_id is not None:
|
|
45
|
-
metadata['id'] =
|
|
38
|
+
metadata['id'] = call.tool_call_id
|
|
46
39
|
|
|
47
40
|
gr_message = {
|
|
48
41
|
'role': 'assistant',
|
|
@@ -56,9 +49,11 @@ async def stream_from_agent(prompt: str, chatbot: list[dict], past_messages: lis
|
|
|
56
49
|
gr_message.get('metadata', {}).get('id', '')
|
|
57
50
|
== call.tool_call_id
|
|
58
51
|
):
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
52
|
+
if isinstance(call.content, BaseModel):
|
|
53
|
+
json_content = call.content.model_dump_json()
|
|
54
|
+
else:
|
|
55
|
+
json_content = json.dumps(call.content)
|
|
56
|
+
gr_message['content'] += f'\nOutput: {json_content}'
|
|
62
57
|
yield gr.skip(), chatbot, gr.skip()
|
|
63
58
|
chatbot.append({'role': 'assistant', 'content': ''})
|
|
64
59
|
async for message in result.stream_text():
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pydantic-ai-examples
|
|
3
|
-
Version:
|
|
4
|
-
Summary: Examples of how to use
|
|
5
|
-
Author-email: Samuel Colvin <samuel@pydantic.dev>
|
|
3
|
+
Version: 1.12.0
|
|
4
|
+
Summary: Examples of how to use Pydantic AI and what it can do.
|
|
5
|
+
Author-email: Samuel Colvin <samuel@pydantic.dev>, Marcelo Trylesinski <marcelotryle@gmail.com>, David Montague <david@pydantic.dev>, Alex Hall <alex@pydantic.dev>, Douwe Maan <douwe@pydantic.dev>
|
|
6
6
|
License-Expression: MIT
|
|
7
|
-
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
8
9
|
Classifier: Environment :: Console
|
|
9
10
|
Classifier: Environment :: MacOS X
|
|
10
11
|
Classifier: Intended Audience :: Developers
|
|
@@ -16,28 +17,31 @@ Classifier: Operating System :: Unix
|
|
|
16
17
|
Classifier: Programming Language :: Python
|
|
17
18
|
Classifier: Programming Language :: Python :: 3
|
|
18
19
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
23
|
Classifier: Programming Language :: Python :: 3.13
|
|
24
24
|
Classifier: Topic :: Internet
|
|
25
25
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
26
|
-
Requires-Python: >=3.
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
27
|
Requires-Dist: asyncpg>=0.30.0
|
|
28
|
+
Requires-Dist: datasets>=4.0.0
|
|
28
29
|
Requires-Dist: devtools>=0.12.2
|
|
30
|
+
Requires-Dist: duckdb>=1.3.2
|
|
29
31
|
Requires-Dist: fastapi>=0.115.4
|
|
30
|
-
Requires-Dist: gradio>=5.9.0
|
|
31
|
-
Requires-Dist: logfire[asyncpg,fastapi,sqlite3]>=
|
|
32
|
-
Requires-Dist: mcp[cli]>=1.4.1
|
|
33
|
-
Requires-Dist:
|
|
34
|
-
Requires-Dist:
|
|
32
|
+
Requires-Dist: gradio>=5.9.0
|
|
33
|
+
Requires-Dist: logfire[asyncpg,fastapi,httpx,sqlite3]>=3.14.1
|
|
34
|
+
Requires-Dist: mcp[cli]>=1.4.1
|
|
35
|
+
Requires-Dist: modal>=1.0.4
|
|
36
|
+
Requires-Dist: pandas>=2.2.3
|
|
37
|
+
Requires-Dist: pydantic-ai-slim[ag-ui,anthropic,groq,openai,vertexai]==1.12.0
|
|
38
|
+
Requires-Dist: pydantic-evals==1.12.0
|
|
35
39
|
Requires-Dist: python-multipart>=0.0.17
|
|
36
40
|
Requires-Dist: rich>=13.9.2
|
|
37
41
|
Requires-Dist: uvicorn>=0.32.0
|
|
38
42
|
Description-Content-Type: text/markdown
|
|
39
43
|
|
|
40
|
-
#
|
|
44
|
+
# Pydantic AI Examples
|
|
41
45
|
|
|
42
46
|
[](https://github.com/pydantic/pydantic-ai/actions/workflows/ci.yml?query=branch%3Amain)
|
|
43
47
|
[](https://coverage-badge.samuelcolvin.workers.dev/redirect/pydantic/pydantic-ai)
|
|
@@ -45,6 +49,6 @@ Description-Content-Type: text/markdown
|
|
|
45
49
|
[](https://github.com/pydantic/pydantic-ai)
|
|
46
50
|
[](https://github.com/pydantic/pydantic-ai/blob/main/LICENSE)
|
|
47
51
|
|
|
48
|
-
Examples of how to use
|
|
52
|
+
Examples of how to use Pydantic AI and what it can do.
|
|
49
53
|
|
|
50
54
|
For full documentation of these examples and how to run them, see [ai.pydantic.dev/examples/](https://ai.pydantic.dev/examples/).
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
pydantic_ai_examples/__main__.py,sha256=i0LEo2JBOZ-gnHED0ou5Bya43gi7KmOyQ_jKN7M5Ces,1647
|
|
2
|
+
pydantic_ai_examples/bank_support.py,sha256=O9r6yQraDRPibWLOC1wyZu0n_Nr7Exg4u7wEHh25czk,2664
|
|
3
|
+
pydantic_ai_examples/chat_app.html,sha256=90XhxrpDAT09mPVTn9edEn8PqAD-tHxWkeeMz9r_okQ,2580
|
|
4
|
+
pydantic_ai_examples/chat_app.py,sha256=AX28rI0TR9lTPLDOd0uEkmirvfIZCRyCGr_VdGiOkHM,7053
|
|
5
|
+
pydantic_ai_examples/chat_app.ts,sha256=2KfZ2rJU2o0iCPjelyqEi5sH6vfemzWaa5Evx_VcAE4,3307
|
|
6
|
+
pydantic_ai_examples/data_analyst.py,sha256=sC6mcgfeWzfj4STB7J_7oAWC7T8Y0NWvlIeQ8XND9zA,3752
|
|
7
|
+
pydantic_ai_examples/flight_booking.py,sha256=x8FbztbAiqNdDACzal1O5M80syjt8UuGm_wqHpybeQM,7415
|
|
8
|
+
pydantic_ai_examples/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
pydantic_ai_examples/pydantic_model.py,sha256=4u_-sdpKSF_lRMLSI-WVYwsyIxgdOpq-8LSCJunoyvA,774
|
|
10
|
+
pydantic_ai_examples/question_graph.py,sha256=ERjlfHxKXswISed6TJtj60SFoTIYe-PyCTZoYR4OJkY,5073
|
|
11
|
+
pydantic_ai_examples/rag.py,sha256=t1um_C3EqX7dhbdopWFqYgHfnKUTyeVWxD3SK7AUdio,8010
|
|
12
|
+
pydantic_ai_examples/roulette_wheel.py,sha256=2YHKbGzYOkLsd98hO3ntjM6pChR1UpmsRrLD36Qh5f0,1654
|
|
13
|
+
pydantic_ai_examples/sql_gen.py,sha256=akgJv4TSImw6O4NRgQZh92QITSmDeEyvoGQcU3oUNFQ,5159
|
|
14
|
+
pydantic_ai_examples/stream_markdown.py,sha256=4uEK6dzC9jVcQTRaYBEDzYfYAJPYHZWfLJ-ZMtmI8y4,2453
|
|
15
|
+
pydantic_ai_examples/stream_whales.py,sha256=Yoa7IuqN_6fowfYSINW39uPCthYu9FKChF-QBmQqWb8,2721
|
|
16
|
+
pydantic_ai_examples/weather_agent.py,sha256=FZF7pgL2U24m-ymFUw6MnqASVpXOfl49ilrYAtZXlOo,3185
|
|
17
|
+
pydantic_ai_examples/weather_agent_gradio.py,sha256=MCoNp5TgWj628ABoZpTUVJYIeSV_C-ig08WfcssDH7A,4719
|
|
18
|
+
pydantic_ai_examples/ag_ui/__init__.py,sha256=ZZs2V-5e9RaLl_7hJAq9-0Juk_f0mk2Vr7a4QT2QB-k,1174
|
|
19
|
+
pydantic_ai_examples/ag_ui/__main__.py,sha256=PMycatJt8Abb-Q8HXRGZoEY6vnOcvRebH7iI9MxLknA,225
|
|
20
|
+
pydantic_ai_examples/ag_ui/api/__init__.py,sha256=Pe307_ET_ERKBP-8Vs4L1yZRkK3ILPpajwxDpeW8YiI,673
|
|
21
|
+
pydantic_ai_examples/ag_ui/api/agentic_chat.py,sha256=QGb7q4AMq5PD1-D-S-71GsMs3wAhH2niUeRryhjL12s,577
|
|
22
|
+
pydantic_ai_examples/ag_ui/api/agentic_generative_ui.py,sha256=RnkSjb8C_J9kXPuB7nFI1knkPF30OkOoSRXoAX2h2Ck,3531
|
|
23
|
+
pydantic_ai_examples/ag_ui/api/human_in_the_loop.py,sha256=Jb_0Sryb4mUOZmr1k9MVTciGUAcC8-tzuyNCaCTWZhc,807
|
|
24
|
+
pydantic_ai_examples/ag_ui/api/predictive_state_updates.py,sha256=PO3SZPCzmWowpEPnqez-oLlMRsPD3MnJArpdwDYThO4,2165
|
|
25
|
+
pydantic_ai_examples/ag_ui/api/shared_state.py,sha256=dr7vCTuZN2tyUrdroD25r69YBPjQFeAPaOt_NbenHyE,3843
|
|
26
|
+
pydantic_ai_examples/ag_ui/api/tool_based_generative_ui.py,sha256=rW0Inzd9_yDqdTE6HmnnF7M-LsR_l4woiwlGbJBHLSM,261
|
|
27
|
+
pydantic_ai_examples/evals/__init__.py,sha256=4f1v2o4F-gnUVtlkZU-dpwwwbLhqRxMcZv676atjNLg,115
|
|
28
|
+
pydantic_ai_examples/evals/agent.py,sha256=o_l6I4DF3HXh7fgsmyz7mViq1ckdFV1Hxq_B7KJPLa0,2041
|
|
29
|
+
pydantic_ai_examples/evals/custom_evaluators.py,sha256=siSpALUMrUGJ1DDrm0Ejniuxhmxhlvee_jubgXjOAeU,2244
|
|
30
|
+
pydantic_ai_examples/evals/example_01_generate_dataset.py,sha256=R-cV9bBHMA8EMIyveP5Yf2p3_VV-g_NSXtDa_zz0ODs,2368
|
|
31
|
+
pydantic_ai_examples/evals/example_02_add_custom_evaluators.py,sha256=pFX0bvVeyfbZGGb0LSajRW-g1ZiVID3e3-sEXZVcjv8,977
|
|
32
|
+
pydantic_ai_examples/evals/example_03_unit_testing.py,sha256=G4Ry7ykJfozaQ9GEXi6cnz0O-6pGBrZIkV4_6RNK194,1207
|
|
33
|
+
pydantic_ai_examples/evals/example_04_compare_models.py,sha256=4oPIeFgbk2vMkN7asN6LjWMYPatMpUFLkKhEzrioqJg,1199
|
|
34
|
+
pydantic_ai_examples/evals/models.py,sha256=QYe_fNv03fmF4ssgSqutHgGx2YX5NLKhhth8-0XFnWo,1776
|
|
35
|
+
pydantic_ai_examples/evals/datasets/time_range_v1.yaml,sha256=pSUawuDen4NQt2RqqJNmrVENgksTWxIFcw-Kkao_yo8,4193
|
|
36
|
+
pydantic_ai_examples/evals/datasets/time_range_v1_schema.json,sha256=xS-wRRSvcoG2FcQZGdL0i332mbjsZh9MOSJAND6VkWU,19932
|
|
37
|
+
pydantic_ai_examples/evals/datasets/time_range_v2.yaml,sha256=zIffxC5bR2l05MrrECJsTHiagFaz8nIPTH-YrmjJz8I,4326
|
|
38
|
+
pydantic_ai_examples/evals/datasets/time_range_v2_schema.json,sha256=GDbDtBH1skdbUzK5Wd_0-SNXTmEWHMTYhhshaLsq_1Q,21309
|
|
39
|
+
pydantic_ai_examples/slack_lead_qualifier/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
40
|
+
pydantic_ai_examples/slack_lead_qualifier/agent.py,sha256=kskE4RjlqeqAT51NDt7FoC1OIyQ47DqFcTDkCOvQS9k,1935
|
|
41
|
+
pydantic_ai_examples/slack_lead_qualifier/app.py,sha256=KALNxIV8hz0lGxFclZHxolqoH4MsiIYga_CmpidzONE,1036
|
|
42
|
+
pydantic_ai_examples/slack_lead_qualifier/functions.py,sha256=4LsYtPH_SBo_rJ7008DXvKq_SOwiGtweW_DfzJh8R0s,2196
|
|
43
|
+
pydantic_ai_examples/slack_lead_qualifier/modal.py,sha256=f464AaeyP-n3UIfvEVVc4DZ7FQQtsEX7-kUP3VqoPYo,1635
|
|
44
|
+
pydantic_ai_examples/slack_lead_qualifier/models.py,sha256=WTp6D2WCASXqrjPVT3vGgTSYATLPBM3_cjq9wvXMRao,1586
|
|
45
|
+
pydantic_ai_examples/slack_lead_qualifier/slack.py,sha256=VJVfMeUXYClWUJBLHNuaW8PB2sxjNzpTC-O_AJwcxQ4,833
|
|
46
|
+
pydantic_ai_examples/slack_lead_qualifier/store.py,sha256=04vB4eZWKk_Tx0b9K4QuVI1U24JEyJyBS4X76cui7OI,896
|
|
47
|
+
pydantic_ai_examples-1.12.0.dist-info/METADATA,sha256=vNTvNoFtwV9hR_ENchwD2xp8RaL6ofm-T-Q98u27mGg,2763
|
|
48
|
+
pydantic_ai_examples-1.12.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
49
|
+
pydantic_ai_examples-1.12.0.dist-info/licenses/LICENSE,sha256=vA6Jc482lEyBBuGUfD1pYx-cM7jxvLYOxPidZ30t_PQ,1100
|
|
50
|
+
pydantic_ai_examples-1.12.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) Pydantic Services Inc. 2024 to present
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
pydantic_ai_examples/__main__.py,sha256=i0LEo2JBOZ-gnHED0ou5Bya43gi7KmOyQ_jKN7M5Ces,1647
|
|
2
|
-
pydantic_ai_examples/bank_support.py,sha256=u_mkEPiUt3YDnlVvBgwUp2VShZ33Hdm0AASSL7_ymXY,2661
|
|
3
|
-
pydantic_ai_examples/chat_app.html,sha256=90XhxrpDAT09mPVTn9edEn8PqAD-tHxWkeeMz9r_okQ,2580
|
|
4
|
-
pydantic_ai_examples/chat_app.py,sha256=OsKy68EHFTKSDMH9Yo53txm7P7b4-b4LJnTvUUY0B78,7089
|
|
5
|
-
pydantic_ai_examples/chat_app.ts,sha256=2KfZ2rJU2o0iCPjelyqEi5sH6vfemzWaa5Evx_VcAE4,3307
|
|
6
|
-
pydantic_ai_examples/flight_booking.py,sha256=TAlotG4Hiuuaps6Pyfokbte4GXpVLo1TVep_ExaHAB4,7442
|
|
7
|
-
pydantic_ai_examples/pydantic_model.py,sha256=fQFPkulep9JQgICpEMrEaj3NpzBiz4OO8WAaeaw4U7c,758
|
|
8
|
-
pydantic_ai_examples/question_graph.py,sha256=ZFb1Z2XHLQy-VD5JGUtj8NCGFNQByg7f7YsBpwOCquY,5091
|
|
9
|
-
pydantic_ai_examples/rag.py,sha256=LYgJSJYSAYyVuIOvVYSvfzAhxVey0pY--hJ3gCk3Lw4,7989
|
|
10
|
-
pydantic_ai_examples/roulette_wheel.py,sha256=TFJAn0hnGSMB_LCAASfc5nKqeN8ImHBYCQStfq5Kp8E,1674
|
|
11
|
-
pydantic_ai_examples/sql_gen.py,sha256=rDvN7qm60Sq6J6rP7on8W7yE0x-fQCifC55N-RjQQnk,5195
|
|
12
|
-
pydantic_ai_examples/stream_markdown.py,sha256=-uNLQBAU7kpem16aMfLcAxdSG6jnqMFnofqqFc3Qv08,2429
|
|
13
|
-
pydantic_ai_examples/stream_whales.py,sha256=EuKdhc0G3kqXAeimpshU0_ThugG5r_ENxe2c0KYBVC4,3213
|
|
14
|
-
pydantic_ai_examples/weather_agent.py,sha256=WKljXL_mSbKguNvZmvmBI4SBi5e0qa5dQ28xJSIVZj4,4874
|
|
15
|
-
pydantic_ai_examples/weather_agent_gradio.py,sha256=0Of2pYrT1H-qt2NjBXzLovI-1D_nl-afRtIBPJ9xTZM,4893
|
|
16
|
-
pydantic_ai_examples/evals/__init__.py,sha256=4f1v2o4F-gnUVtlkZU-dpwwwbLhqRxMcZv676atjNLg,115
|
|
17
|
-
pydantic_ai_examples/evals/agent.py,sha256=KjCsUiL28RCNT6NwoQnQCwJ0xRw3EUGdIrYhlIjmVqI,2042
|
|
18
|
-
pydantic_ai_examples/evals/custom_evaluators.py,sha256=Uz37_wbT4uA6s9fl46nTsH3NQKyS1KamMPPP860stww,2245
|
|
19
|
-
pydantic_ai_examples/evals/example_01_generate_dataset.py,sha256=7fhTY4IMN0xEODGEKtrNlaEIYkqYRauC6w6NRIQnFWY,2369
|
|
20
|
-
pydantic_ai_examples/evals/example_02_add_custom_evaluators.py,sha256=mNPEIDnuE3RcfdMtBKhs5aGUdcDtDQD-v7KoSuE1ZDk,978
|
|
21
|
-
pydantic_ai_examples/evals/example_03_unit_testing.py,sha256=QNkfMQgBZrN8wWhj0ZRsq9XC46AgtFo9gklgh52e4iE,1151
|
|
22
|
-
pydantic_ai_examples/evals/example_04_compare_models.py,sha256=H00BaMEF6etK5497kFjWmdEFbNgVhhq25RDw8KPrLuw,1201
|
|
23
|
-
pydantic_ai_examples/evals/models.py,sha256=QYe_fNv03fmF4ssgSqutHgGx2YX5NLKhhth8-0XFnWo,1776
|
|
24
|
-
pydantic_ai_examples/evals/datasets/time_range_v1.yaml,sha256=pSUawuDen4NQt2RqqJNmrVENgksTWxIFcw-Kkao_yo8,4193
|
|
25
|
-
pydantic_ai_examples/evals/datasets/time_range_v1_schema.json,sha256=xS-wRRSvcoG2FcQZGdL0i332mbjsZh9MOSJAND6VkWU,19932
|
|
26
|
-
pydantic_ai_examples/evals/datasets/time_range_v2.yaml,sha256=zIffxC5bR2l05MrrECJsTHiagFaz8nIPTH-YrmjJz8I,4326
|
|
27
|
-
pydantic_ai_examples/evals/datasets/time_range_v2_schema.json,sha256=GDbDtBH1skdbUzK5Wd_0-SNXTmEWHMTYhhshaLsq_1Q,21309
|
|
28
|
-
pydantic_ai_examples-0.1.2.dist-info/METADATA,sha256=3RDsjVZVRHg7hkiX60r5tkKGYLWGvfcEbJOn9O4N0bM,2542
|
|
29
|
-
pydantic_ai_examples-0.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
30
|
-
pydantic_ai_examples-0.1.2.dist-info/RECORD,,
|
|
File without changes
|