Skip to content

Commit 110a065

Browse files
authored
Uprev pydantic AI (#6)
* uprev pydantic-ai * slugify * add typechecking * add ci for pre-commit
1 parent 42c763e commit 110a065

File tree

8 files changed

+671
-113
lines changed

8 files changed

+671
-113
lines changed

.github/workflows/ci.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: CI
2+
on:
3+
push:
4+
branches:
5+
- main
6+
tags:
7+
- "**"
8+
pull_request: {}
9+
10+
env:
11+
COLUMNS: 150
12+
UV_PYTHON: 3.13
13+
UV_FROZEN: "1"
14+
15+
jobs:
16+
pre-commit:
17+
runs-on: ubuntu-latest
18+
steps:
19+
- uses: actions/checkout@v4
20+
- uses: astral-sh/setup-uv@v6
21+
with:
22+
enable-cache: true
23+
- run: uv sync --all-packages
24+
- uses: actions/cache@v4
25+
with:
26+
path: ~/.cache/pre-commit
27+
key: pre-commit|${{ env.UV_PYTHON }}|${{ hashFiles('.pre-commit-config.yaml') }}
28+
- run: uvx pre-commit run --color=always --all-files --verbose

.pre-commit-config.yaml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@ repos:
1919
hooks:
2020
- id: format
2121
name: Format Python
22-
entry: uv
23-
args: [run, ruff, format]
22+
entry: make
23+
args: [format]
2424
language: system
2525
types: [python]
2626
pass_filenames: false
27-
- id: lint
28-
name: lint Python
29-
entry: uv
30-
args: [run, ruff, check, --fix]
27+
- id: typecheck
28+
name: Typecheck Python
29+
entry: make
30+
args: [typecheck]
3131
language: system
3232
types: [python]
3333
pass_filenames: false

Makefile

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
.DEFAULT_GOAL := all
2+
3+
.PHONY: .uv
4+
.uv: ## Check that uv is installed
5+
@uv --version || echo 'Please install uv: https://docs.astral.sh/uv/getting-started/installation/'
6+
7+
.PHONY: .pre-commit
8+
.pre-commit: ## Check that pre-commit is installed
9+
@pre-commit -V || echo 'Please install pre-commit: https://pre-commit.com/'
10+
11+
.PHONY: install
12+
install: .uv .pre-commit ## Install the package, dependencies, and pre-commit for local development
13+
uv sync --frozen --all-packages --all-extras
14+
pre-commit install --install-hooks
15+
16+
.PHONY: format
17+
format: ## Format the code
18+
uv run ruff format
19+
uv run ruff check --fix --fix-only
20+
21+
.PHONY: lint
22+
lint: ## Lint the code
23+
uv run ruff format --check
24+
uv run ruff check
25+
26+
.PHONY: typecheck
27+
typecheck:
28+
uv run basedpyright
29+
30+
31+
.PHONY: help
32+
help: ## Show this help (usage: make help)
33+
@echo "Usage: make [recipe]"
34+
@echo "Recipes:"
35+
@awk '/^[a-zA-Z0-9_-]+:.*?##/ { \
36+
helpMessage = match($$0, /## (.*)/); \
37+
if (helpMessage) { \
38+
recipe = $$1; \
39+
sub(/:/, "", recipe); \
40+
printf " \033[36m%-20s\033[0m %s\n", recipe, substr($$0, RSTART + 3, RLENGTH); \
41+
} \
42+
}' $(MAKEFILE_LIST)

distributed-frontend-example/main.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from pathlib import Path
44
from uuid import uuid4
55

6-
import httpx
76
import logfire
87
from fastapi import FastAPI, Request
98
from fastapi.middleware.cors import CORSMiddleware
@@ -80,13 +79,14 @@ async def generate_image(prompt: str) -> GenerateResponse:
8079
# Proxy to Logfire for client traces from the browser
8180
@app.post('/client-traces')
8281
async def client_traces(request: Request):
83-
async with httpx.AsyncClient() as client:
84-
response = await client.request(
85-
method=request.method,
86-
url=f'{logfire_base_url}v1/traces',
87-
headers=dict(Authorization=logfire_token),
88-
json=await request.json(),
89-
)
82+
assert logfire_token is not None, 'Logfire token is not set'
83+
response = await http_client.request(
84+
method=request.method,
85+
url=f'{logfire_base_url}v1/traces',
86+
headers={'Authorization': logfire_token},
87+
json=await request.json(),
88+
)
89+
response.raise_for_status()
9090

9191
return {
9292
'status_code': response.status_code,

pai-mcp-sampling/client.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99
logfire.instrument_mcp()
1010

1111
server = MCPServerStdio(command='python', args=[str(Path(__file__).parent / 'generate_svg.py')])
12-
agent = Agent('openai:gpt-4.1-mini', mcp_servers=[server])
12+
agent = Agent('openai:gpt-4.1-mini', toolsets=[server])
13+
agent.set_mcp_sampling_model()
1314

1415

1516
async def main():
16-
async with agent.run_mcp_servers():
17+
async with agent:
1718
result = await agent.run('Create an image of a robot in a punk style, it should be pink.')
1819
print(result.output)
1920

pai-mcp-sampling/generate_svg.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ async def image_generator(ctx: Context[ServerSessionT, LifespanContextT, Request
2121
# run the agent, using MCPSamplingModel to proxy the LLM call through the client.
2222
svg_result = await svg_agent.run(f'{subject=} {style=}', model=MCPSamplingModel(ctx.session))
2323

24-
path = Path(f'{subject}_{style}.svg')
24+
path = Path(f'{slugify(subject)}_{slugify(style)}.svg')
25+
logfire.info(f'writing file to {path}')
2526
# remove triple backticks if the svg was returned within markdown
2627
if m := re.search(r'^```\w*$(.+?)```$', svg_result.output, re.S | re.M):
2728
path.write_text(m.group(1))
@@ -30,6 +31,10 @@ async def image_generator(ctx: Context[ServerSessionT, LifespanContextT, Request
3031
return f'See {path}'
3132

3233

34+
def slugify(text: str) -> str:
35+
return re.sub(r'\W+', '-', text.lower())
36+
37+
3338
if __name__ == '__main__':
3439
# run the server via stdio
3540
app.run()

pyproject.toml

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,17 @@ dependencies = [
88
"asyncpg>=0.30.0",
99
"devtools>=0.12.2",
1010
"fastapi>=0.115.14",
11-
"logfire[asyncpg,fastapi,httpx]==4.3.6",
12-
"pydantic-ai>=0.3.6",
11+
"logfire[asyncpg,fastapi,httpx]>=4.10",
12+
"mcp>=1.15.0",
13+
"pydantic-ai>=1",
1314
]
1415

1516
[dependency-groups]
16-
dev = ["ruff>=0.12.2", "asyncpg-stubs>=0.30.2"]
17+
dev = [
18+
"ruff>=0.12.2",
19+
"asyncpg-stubs>=0.30.2",
20+
"basedpyright>=1.31.6",
21+
]
1722

1823
[tool.ruff]
1924
line-length = 120
@@ -32,3 +37,13 @@ convention = "google"
3237
# don't format python in docstrings, pytest-examples takes care of it
3338
docstring-code-format = false
3439
quote-style = "single"
40+
41+
[tool.pyright]
42+
pythonVersion = "3.12"
43+
typeCheckingMode = "strict"
44+
reportUnnecessaryTypeIgnoreComment = true
45+
reportIgnoreCommentWithoutRule = true
46+
reportUnusedParameter = true
47+
reportIncompatibleUnannotatedOverride = true
48+
reportImplicitAbstractClass = true
49+
venv = ".venv"

0 commit comments

Comments
 (0)