pydantic-ai-examples 1.9.0__tar.gz → 1.49.0__tar.gz

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.
Files changed (52) hide show
  1. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/.gitignore +2 -0
  2. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/PKG-INFO +5 -5
  3. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/ag_ui/api/agentic_generative_ui.py +3 -1
  4. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/ag_ui/api/shared_state.py +3 -3
  5. pydantic_ai_examples-1.49.0/pydantic_ai_examples/bank_support.py +101 -0
  6. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/data_analyst.py +3 -3
  7. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/question_graph.py +4 -2
  8. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/rag.py +2 -2
  9. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/weather_agent_gradio.py +0 -1
  10. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pyproject.toml +2 -2
  11. pydantic_ai_examples-1.9.0/pydantic_ai_examples/bank_support.py +0 -95
  12. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/LICENSE +0 -0
  13. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/README.md +0 -0
  14. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/__main__.py +0 -0
  15. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/ag_ui/__init__.py +0 -0
  16. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/ag_ui/__main__.py +0 -0
  17. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/ag_ui/api/__init__.py +0 -0
  18. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/ag_ui/api/agentic_chat.py +0 -0
  19. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/ag_ui/api/human_in_the_loop.py +0 -0
  20. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/ag_ui/api/predictive_state_updates.py +0 -0
  21. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/ag_ui/api/tool_based_generative_ui.py +0 -0
  22. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/chat_app.html +0 -0
  23. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/chat_app.py +0 -0
  24. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/chat_app.ts +0 -0
  25. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/evals/__init__.py +0 -0
  26. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/evals/agent.py +0 -0
  27. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/evals/custom_evaluators.py +0 -0
  28. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/evals/datasets/time_range_v1.yaml +0 -0
  29. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/evals/datasets/time_range_v1_schema.json +0 -0
  30. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/evals/datasets/time_range_v2.yaml +0 -0
  31. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/evals/datasets/time_range_v2_schema.json +0 -0
  32. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/evals/example_01_generate_dataset.py +0 -0
  33. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/evals/example_02_add_custom_evaluators.py +0 -0
  34. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/evals/example_03_unit_testing.py +0 -0
  35. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/evals/example_04_compare_models.py +0 -0
  36. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/evals/models.py +0 -0
  37. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/flight_booking.py +0 -0
  38. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/py.typed +0 -0
  39. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/pydantic_model.py +0 -0
  40. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/roulette_wheel.py +0 -0
  41. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/slack_lead_qualifier/__init__.py +0 -0
  42. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/slack_lead_qualifier/agent.py +0 -0
  43. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/slack_lead_qualifier/app.py +0 -0
  44. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/slack_lead_qualifier/functions.py +0 -0
  45. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/slack_lead_qualifier/modal.py +0 -0
  46. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/slack_lead_qualifier/models.py +0 -0
  47. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/slack_lead_qualifier/slack.py +0 -0
  48. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/slack_lead_qualifier/store.py +0 -0
  49. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/sql_gen.py +0 -0
  50. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/stream_markdown.py +0 -0
  51. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/stream_whales.py +0 -0
  52. {pydantic_ai_examples-1.9.0 → pydantic_ai_examples-1.49.0}/pydantic_ai_examples/weather_agent.py +0 -0
@@ -21,3 +21,5 @@ node_modules/
21
21
  /test_tmp/
22
22
  .mcp.json
23
23
  .claude/
24
+ /.cursor/
25
+ /.devcontainer/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydantic-ai-examples
3
- Version: 1.9.0
3
+ Version: 1.49.0
4
4
  Summary: Examples of how to use Pydantic AI and what it can do.
5
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
@@ -29,13 +29,13 @@ Requires-Dist: datasets>=4.0.0
29
29
  Requires-Dist: devtools>=0.12.2
30
30
  Requires-Dist: duckdb>=1.3.2
31
31
  Requires-Dist: fastapi>=0.115.4
32
- Requires-Dist: gradio>=5.9.0
32
+ Requires-Dist: gradio>=5.31.0
33
33
  Requires-Dist: logfire[asyncpg,fastapi,httpx,sqlite3]>=3.14.1
34
- Requires-Dist: mcp[cli]>=1.4.1
34
+ Requires-Dist: mcp[cli]<2.0,>=1.25.0
35
35
  Requires-Dist: modal>=1.0.4
36
36
  Requires-Dist: pandas>=2.2.3
37
- Requires-Dist: pydantic-ai-slim[ag-ui,anthropic,groq,openai,vertexai]==1.9.0
38
- Requires-Dist: pydantic-evals==1.9.0
37
+ Requires-Dist: pydantic-ai-slim[ag-ui,anthropic,groq,openai,vertexai]==1.49.0
38
+ Requires-Dist: pydantic-evals==1.49.0
39
39
  Requires-Dist: python-multipart>=0.0.17
40
40
  Requires-Dist: rich>=13.9.2
41
41
  Requires-Dist: uvicorn>=0.32.0
@@ -27,7 +27,9 @@ class Step(BaseModel):
27
27
  class Plan(BaseModel):
28
28
  """Represents a plan with multiple steps."""
29
29
 
30
- steps: list[Step] = Field(default_factory=list, description='The steps in the plan')
30
+ steps: list[Step] = Field(
31
+ default_factory=list[Step], description='The steps in the plan'
32
+ )
31
33
 
32
34
 
33
35
  class JSONPatchOp(BaseModel):
@@ -62,18 +62,18 @@ class Recipe(BaseModel):
62
62
  description='The skill level required for the recipe',
63
63
  )
64
64
  special_preferences: list[SpecialPreferences] = Field(
65
- default_factory=list,
65
+ default_factory=list[SpecialPreferences],
66
66
  description='Any special preferences for the recipe',
67
67
  )
68
68
  cooking_time: CookingTime = Field(
69
69
  default=CookingTime.FIVE_MIN, description='The cooking time of the recipe'
70
70
  )
71
71
  ingredients: list[Ingredient] = Field(
72
- default_factory=list,
72
+ default_factory=list[Ingredient],
73
73
  description='Ingredients for the recipe',
74
74
  )
75
75
  instructions: list[str] = Field(
76
- default_factory=list, description='Instructions for the recipe'
76
+ default_factory=list[str], description='Instructions for the recipe'
77
77
  )
78
78
 
79
79
 
@@ -0,0 +1,101 @@
1
+ """Small but complete example of using Pydantic AI to build a support agent for a bank.
2
+
3
+ Run with:
4
+
5
+ uv run -m pydantic_ai_examples.bank_support
6
+ """
7
+
8
+ import sqlite3
9
+ from dataclasses import dataclass
10
+
11
+ from pydantic import BaseModel
12
+
13
+ from pydantic_ai import Agent, RunContext
14
+
15
+
16
+ @dataclass
17
+ class DatabaseConn:
18
+ """A wrapper over the SQLite connection."""
19
+
20
+ sqlite_conn: sqlite3.Connection
21
+
22
+ async def customer_name(self, *, id: int) -> str | None:
23
+ res = cur.execute('SELECT name FROM customers WHERE id=?', (id,))
24
+ row = res.fetchone()
25
+ if row:
26
+ return row[0]
27
+ return None
28
+
29
+ async def customer_balance(self, *, id: int) -> float:
30
+ res = cur.execute('SELECT balance FROM customers WHERE id=?', (id,))
31
+ row = res.fetchone()
32
+ if row:
33
+ return row[0]
34
+ else:
35
+ raise ValueError('Customer not found')
36
+
37
+
38
+ @dataclass
39
+ class SupportDependencies:
40
+ customer_id: int
41
+ db: DatabaseConn
42
+
43
+
44
+ class SupportOutput(BaseModel):
45
+ support_advice: str
46
+ """Advice returned to the customer"""
47
+ block_card: bool
48
+ """Whether to block their card or not"""
49
+ risk: int
50
+ """Risk level of query"""
51
+
52
+
53
+ support_agent = Agent(
54
+ 'openai:gpt-5',
55
+ deps_type=SupportDependencies,
56
+ output_type=SupportOutput,
57
+ instructions=(
58
+ 'You are a support agent in our bank, give the '
59
+ 'customer support and judge the risk level of their query. '
60
+ "Reply using the customer's name."
61
+ ),
62
+ )
63
+
64
+
65
+ @support_agent.instructions
66
+ async def add_customer_name(ctx: RunContext[SupportDependencies]) -> str:
67
+ customer_name = await ctx.deps.db.customer_name(id=ctx.deps.customer_id)
68
+ return f"The customer's name is {customer_name!r}"
69
+
70
+
71
+ @support_agent.tool
72
+ async def customer_balance(ctx: RunContext[SupportDependencies]) -> str:
73
+ """Returns the customer's current account balance."""
74
+ balance = await ctx.deps.db.customer_balance(
75
+ id=ctx.deps.customer_id,
76
+ )
77
+ return f'${balance:.2f}'
78
+
79
+
80
+ if __name__ == '__main__':
81
+ with sqlite3.connect(':memory:') as con:
82
+ cur = con.cursor()
83
+ cur.execute('CREATE TABLE customers(id, name, balance)')
84
+ cur.execute("""
85
+ INSERT INTO customers VALUES
86
+ (123, 'John', 123.45)
87
+ """)
88
+ con.commit()
89
+
90
+ deps = SupportDependencies(customer_id=123, db=DatabaseConn(sqlite_conn=con))
91
+ result = support_agent.run_sync('What is my balance?', deps=deps)
92
+ print(result.output)
93
+ """
94
+ support_advice='Hello John, your current account balance, including pending transactions, is $123.45.' block_card=False risk=1
95
+ """
96
+
97
+ result = support_agent.run_sync('I just lost my card!', deps=deps)
98
+ print(result.output)
99
+ """
100
+ support_advice="I'm sorry to hear that, John. We are temporarily blocking your card to prevent unauthorized transactions." block_card=True risk=8
101
+ """
@@ -9,7 +9,7 @@ from pydantic_ai import Agent, ModelRetry, RunContext
9
9
 
10
10
  @dataclass
11
11
  class AnalystAgentDeps:
12
- output: dict[str, pd.DataFrame] = field(default_factory=dict)
12
+ output: dict[str, pd.DataFrame] = field(default_factory=dict[str, pd.DataFrame])
13
13
 
14
14
  def store(self, value: pd.DataFrame) -> str:
15
15
  """Store the output in deps and return the reference such as Out[1] to be used by the LLM."""
@@ -47,7 +47,7 @@ def load_dataset(
47
47
  """
48
48
  # begin load data from hf
49
49
  builder = datasets.load_dataset_builder(path) # pyright: ignore[reportUnknownMemberType]
50
- splits: dict[str, datasets.SplitInfo] = builder.info.splits or {} # pyright: ignore[reportUnknownMemberType]
50
+ splits: dict[str, datasets.SplitInfo] = builder.info.splits or {}
51
51
  if split not in splits:
52
52
  raise ModelRetry(
53
53
  f'{split} is not valid for dataset {path}. Valid splits are {",".join(splits.keys())}'
@@ -87,7 +87,7 @@ def run_duckdb(ctx: RunContext[AnalystAgentDeps], dataset: str, sql: str) -> str
87
87
  data = ctx.deps.get(dataset)
88
88
  result = duckdb.query_df(df=data, virtual_table_name='dataset', sql_query=sql)
89
89
  # pass the result as ref (because DuckDB SQL can select many rows, creating another huge dataframe)
90
- ref = ctx.deps.store(result.df()) # pyright: ignore[reportUnknownMemberType]
90
+ ref = ctx.deps.store(result.df())
91
91
  return f'Executed SQL, result is `{ref}`'
92
92
 
93
93
 
@@ -32,8 +32,10 @@ ask_agent = Agent('openai:gpt-5', output_type=str)
32
32
  @dataclass
33
33
  class QuestionState:
34
34
  question: str | None = None
35
- ask_agent_messages: list[ModelMessage] = field(default_factory=list)
36
- evaluate_agent_messages: list[ModelMessage] = field(default_factory=list)
35
+ ask_agent_messages: list[ModelMessage] = field(default_factory=list[ModelMessage])
36
+ evaluate_agent_messages: list[ModelMessage] = field(
37
+ default_factory=list[ModelMessage]
38
+ )
37
39
 
38
40
 
39
41
  @dataclass
@@ -115,7 +115,7 @@ async def build_search_db():
115
115
  async with httpx.AsyncClient() as client:
116
116
  response = await client.get(DOCS_JSON)
117
117
  response.raise_for_status()
118
- sections = sessions_ta.validate_json(response.content)
118
+ sections = sections_ta.validate_json(response.content)
119
119
 
120
120
  openai = AsyncOpenAI()
121
121
  logfire.instrument_openai(openai)
@@ -183,7 +183,7 @@ class DocsSection:
183
183
  return '\n\n'.join((f'path: {self.path}', f'title: {self.title}', self.content))
184
184
 
185
185
 
186
- sessions_ta = TypeAdapter(list[DocsSection])
186
+ sections_ta = TypeAdapter(list[DocsSection])
187
187
 
188
188
 
189
189
  # pyright: reportUnknownMemberType=false
@@ -99,7 +99,6 @@ with gr.Blocks() as demo:
99
99
  past_messages = gr.State([])
100
100
  chatbot = gr.Chatbot(
101
101
  label='Packing Assistant',
102
- type='messages',
103
102
  avatar_images=(None, 'https://ai.pydantic.dev/img/logo-white.svg'),
104
103
  examples=[
105
104
  {'text': 'What is the weather like in Miami?'},
@@ -56,8 +56,8 @@ dependencies = [
56
56
  "rich>=13.9.2",
57
57
  "uvicorn>=0.32.0",
58
58
  "devtools>=0.12.2",
59
- "gradio>=5.9.0",
60
- "mcp[cli]>=1.4.1",
59
+ "gradio>=5.31.0",
60
+ "mcp[cli]>=1.25.0,<2.0",
61
61
  "modal>=1.0.4",
62
62
  "duckdb>=1.3.2",
63
63
  "datasets>=4.0.0",
@@ -1,95 +0,0 @@
1
- """Small but complete example of using Pydantic AI to build a support agent for a bank.
2
-
3
- Run with:
4
-
5
- uv run -m pydantic_ai_examples.bank_support
6
- """
7
-
8
- from dataclasses import dataclass
9
-
10
- from pydantic import BaseModel
11
-
12
- from pydantic_ai import Agent, RunContext
13
-
14
-
15
- class DatabaseConn:
16
- """This is a fake database for example purposes.
17
-
18
- In reality, you'd be connecting to an external database
19
- (e.g. PostgreSQL) to get information about customers.
20
- """
21
-
22
- @classmethod
23
- async def customer_name(cls, *, id: int) -> str | None:
24
- if id == 123:
25
- return 'John'
26
-
27
- @classmethod
28
- async def customer_balance(cls, *, id: int, include_pending: bool) -> float:
29
- if id == 123:
30
- if include_pending:
31
- return 123.45
32
- else:
33
- return 100.00
34
- else:
35
- raise ValueError('Customer not found')
36
-
37
-
38
- @dataclass
39
- class SupportDependencies:
40
- customer_id: int
41
- db: DatabaseConn
42
-
43
-
44
- class SupportOutput(BaseModel):
45
- support_advice: str
46
- """Advice returned to the customer"""
47
- block_card: bool
48
- """Whether to block their card or not"""
49
- risk: int
50
- """Risk level of query"""
51
-
52
-
53
- support_agent = Agent(
54
- 'openai:gpt-5',
55
- deps_type=SupportDependencies,
56
- output_type=SupportOutput,
57
- instructions=(
58
- 'You are a support agent in our bank, give the '
59
- 'customer support and judge the risk level of their query. '
60
- "Reply using the customer's name."
61
- ),
62
- )
63
-
64
-
65
- @support_agent.instructions
66
- async def add_customer_name(ctx: RunContext[SupportDependencies]) -> str:
67
- customer_name = await ctx.deps.db.customer_name(id=ctx.deps.customer_id)
68
- return f"The customer's name is {customer_name!r}"
69
-
70
-
71
- @support_agent.tool
72
- async def customer_balance(
73
- ctx: RunContext[SupportDependencies], include_pending: bool
74
- ) -> str:
75
- """Returns the customer's current account balance."""
76
- balance = await ctx.deps.db.customer_balance(
77
- id=ctx.deps.customer_id,
78
- include_pending=include_pending,
79
- )
80
- return f'${balance:.2f}'
81
-
82
-
83
- if __name__ == '__main__':
84
- deps = SupportDependencies(customer_id=123, db=DatabaseConn())
85
- result = support_agent.run_sync('What is my balance?', deps=deps)
86
- print(result.output)
87
- """
88
- support_advice='Hello John, your current account balance, including pending transactions, is $123.45.' block_card=False risk=1
89
- """
90
-
91
- result = support_agent.run_sync('I just lost my card!', deps=deps)
92
- print(result.output)
93
- """
94
- support_advice="I'm sorry to hear that, John. We are temporarily blocking your card to prevent unauthorized transactions." block_card=True risk=8
95
- """