commit
b98af1bf11
18 changed files with 1758 additions and 1559 deletions
|
|
@ -1,6 +1,14 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Bump `docling>=2.93.0` and `docling-core>=2.75.0`.
|
||||||
|
- Bump `pydantic-ai-slim>=1.96.0`. Migrate off deprecated APIs: AG-UI imports use `pydantic_ai.ui.ag_ui`, docs/CLI examples use the explicit `openai-chat:` model prefix, and `Agent(retries=)` is split into `tool_retries=` + `output_retries=`.
|
||||||
|
- Bump `pydantic-monty>=0.0.17`. Migrate off deprecated `pydantic_monty.run_repl_async(repl, ...)` to `repl.feed_run_async(...)`.
|
||||||
|
- Cap `transformers<5.0.0` in the `mxbai` extra: `mxbai-rerank>=0.1.6` calls `tokenizer.prepare_for_model` which transformers 5 removed.
|
||||||
|
- Refresh the rest of the lockfile to latest within current constraints (pydantic, pydantic-ai, rich, ruff, ty, pytest, torch, textual, textual-image, watchfiles, pre-commit, datasets, and transitives).
|
||||||
|
|
||||||
## [0.47.0] - 2026-05-14
|
## [0.47.0] - 2026-05-14
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ from pathlib import Path
|
||||||
|
|
||||||
from dotenv import find_dotenv, load_dotenv
|
from dotenv import find_dotenv, load_dotenv
|
||||||
from pydantic_ai import Agent
|
from pydantic_ai import Agent
|
||||||
from pydantic_ai.ag_ui import AGUIAdapter
|
|
||||||
from pydantic_ai.ui import SSE_CONTENT_TYPE
|
from pydantic_ai.ui import SSE_CONTENT_TYPE
|
||||||
|
from pydantic_ai.ui.ag_ui import AGUIAdapter
|
||||||
from starlette.applications import Starlette
|
from starlette.applications import Starlette
|
||||||
from starlette.middleware import Middleware
|
from starlette.middleware import Middleware
|
||||||
from starlette.middleware.cors import CORSMiddleware
|
from starlette.middleware.cors import CORSMiddleware
|
||||||
|
|
|
||||||
|
|
@ -490,7 +490,7 @@ skill = create_skill(db_path=db_path, config=config)
|
||||||
toolset = SkillToolset(skills=[skill])
|
toolset = SkillToolset(skills=[skill])
|
||||||
|
|
||||||
agent = Agent(
|
agent = Agent(
|
||||||
"openai:gpt-4o",
|
"openai-chat:gpt-4o",
|
||||||
instructions=build_system_prompt(toolset.skill_catalog),
|
instructions=build_system_prompt(toolset.skill_catalog),
|
||||||
toolsets=[toolset],
|
toolsets=[toolset],
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ analysis = create_analysis_skill(db_path=db_path)
|
||||||
toolset = SkillToolset(skills=[rag, analysis])
|
toolset = SkillToolset(skills=[rag, analysis])
|
||||||
|
|
||||||
agent = Agent(
|
agent = Agent(
|
||||||
"openai:gpt-4o",
|
"openai-chat:gpt-4o",
|
||||||
instructions=build_system_prompt(toolset.skill_catalog),
|
instructions=build_system_prompt(toolset.skill_catalog),
|
||||||
toolsets=[toolset],
|
toolsets=[toolset],
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ skill = create_skill(db_path=db_path, config=config)
|
||||||
toolset = SkillToolset(skills=[skill])
|
toolset = SkillToolset(skills=[skill])
|
||||||
|
|
||||||
agent = Agent(
|
agent = Agent(
|
||||||
"openai:gpt-4o",
|
"openai-chat:gpt-4o",
|
||||||
instructions=build_system_prompt(toolset.skill_catalog),
|
instructions=build_system_prompt(toolset.skill_catalog),
|
||||||
toolsets=[toolset],
|
toolsets=[toolset],
|
||||||
)
|
)
|
||||||
|
|
@ -98,7 +98,7 @@ See the individual skill pages for state model details.
|
||||||
For web applications, use pydantic-ai's `AGUIAdapter` to stream tool calls, text, and state deltas:
|
For web applications, use pydantic-ai's `AGUIAdapter` to stream tool calls, text, and state deltas:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from pydantic_ai.ag_ui import AGUIAdapter
|
from pydantic_ai.ui.ag_ui import AGUIAdapter
|
||||||
|
|
||||||
adapter = AGUIAdapter(agent=agent, run_input=run_input)
|
adapter = AGUIAdapter(agent=agent, run_input=run_input)
|
||||||
event_stream = adapter.run_stream()
|
event_stream = adapter.run_stream()
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,8 @@ class LLMJudge:
|
||||||
model=model_obj,
|
model=model_obj,
|
||||||
output_type=LLMJudgeResponseSchema,
|
output_type=LLMJudgeResponseSchema,
|
||||||
system_prompt=ANSWER_EQUIVALENCE_RUBRIC,
|
system_prompt=ANSWER_EQUIVALENCE_RUBRIC,
|
||||||
retries=3,
|
tool_retries=3,
|
||||||
|
output_retries=3,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def judge_answers(
|
async def judge_answers(
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from pydantic_ai import Agent
|
from pydantic_ai import Agent
|
||||||
from pydantic_ai.ag_ui import AGUIAdapter
|
|
||||||
from pydantic_ai.ui import SSE_CONTENT_TYPE
|
from pydantic_ai.ui import SSE_CONTENT_TYPE
|
||||||
|
from pydantic_ai.ui.ag_ui import AGUIAdapter
|
||||||
from starlette.applications import Starlette
|
from starlette.applications import Starlette
|
||||||
from starlette.requests import Request
|
from starlette.requests import Request
|
||||||
from starlette.responses import JSONResponse, Response, StreamingResponse
|
from starlette.responses import JSONResponse, Response, StreamingResponse
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,8 @@ def create_analysis_agent(config: AppConfig) -> Agent[AnalysisDeps, RawAnalysisR
|
||||||
deps_type=AnalysisDeps,
|
deps_type=AnalysisDeps,
|
||||||
output_type=RawAnalysisResult,
|
output_type=RawAnalysisResult,
|
||||||
instructions=ANALYSIS_SYSTEM_PROMPT,
|
instructions=ANALYSIS_SYSTEM_PROMPT,
|
||||||
retries=3,
|
tool_retries=3,
|
||||||
|
output_retries=3,
|
||||||
)
|
)
|
||||||
|
|
||||||
@agent.tool
|
@agent.tool
|
||||||
|
|
|
||||||
|
|
@ -260,8 +260,7 @@ class Sandbox:
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if self._context.documents:
|
if self._context.documents:
|
||||||
await pydantic_monty.run_repl_async(
|
await self._repl.feed_run_async(
|
||||||
self._repl,
|
|
||||||
"pass",
|
"pass",
|
||||||
inputs={
|
inputs={
|
||||||
"documents": [
|
"documents": [
|
||||||
|
|
@ -296,8 +295,7 @@ class Sandbox:
|
||||||
max_chars = self._config.analysis.max_output_chars
|
max_chars = self._config.analysis.max_output_chars
|
||||||
|
|
||||||
try:
|
try:
|
||||||
output = await pydantic_monty.run_repl_async(
|
output = await repl.feed_run_async(
|
||||||
repl,
|
|
||||||
code,
|
code,
|
||||||
external_functions=external_fns,
|
external_functions=external_fns,
|
||||||
print_callback=print_callback,
|
print_callback=print_callback,
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,8 @@ class QuestionAnswerAgent:
|
||||||
output_type=RawSearchAnswer,
|
output_type=RawSearchAnswer,
|
||||||
instructions=system_prompt,
|
instructions=system_prompt,
|
||||||
toolsets=[search_toolset],
|
toolsets=[search_toolset],
|
||||||
retries=3,
|
tool_retries=3,
|
||||||
|
output_retries=3,
|
||||||
)
|
)
|
||||||
|
|
||||||
deps = _QARunDeps(client=self._client)
|
deps = _QARunDeps(client=self._client)
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,8 @@ async def _iterative_plan_logic(
|
||||||
model=model,
|
model=model,
|
||||||
output_type=IterativePlanResult,
|
output_type=IterativePlanResult,
|
||||||
instructions=effective_prompt,
|
instructions=effective_prompt,
|
||||||
retries=3,
|
tool_retries=3,
|
||||||
|
output_retries=3,
|
||||||
deps_type=ResearchDependencies,
|
deps_type=ResearchDependencies,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -120,7 +121,8 @@ async def _search_one_step_logic(
|
||||||
model=model,
|
model=model,
|
||||||
output_type=RawSearchAnswer,
|
output_type=RawSearchAnswer,
|
||||||
instructions=search_prompt,
|
instructions=search_prompt,
|
||||||
retries=3,
|
tool_retries=3,
|
||||||
|
output_retries=3,
|
||||||
deps_type=ResearchDependencies,
|
deps_type=ResearchDependencies,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -222,7 +224,8 @@ def build_research_graph(
|
||||||
model=model,
|
model=model,
|
||||||
output_type=ResearchReport,
|
output_type=ResearchReport,
|
||||||
instructions=synthesis_prompt,
|
instructions=synthesis_prompt,
|
||||||
retries=3,
|
tool_retries=3,
|
||||||
|
output_retries=3,
|
||||||
deps_type=ResearchDependencies,
|
deps_type=ResearchDependencies,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ from ag_ui.core import (
|
||||||
)
|
)
|
||||||
from jsonpatch import JsonPatch
|
from jsonpatch import JsonPatch
|
||||||
from pydantic_ai import Agent
|
from pydantic_ai import Agent
|
||||||
from pydantic_ai.ag_ui import AGUIAdapter
|
from pydantic_ai.ui.ag_ui import AGUIAdapter
|
||||||
from textual.app import App, SystemCommand
|
from textual.app import App, SystemCommand
|
||||||
from textual.binding import Binding
|
from textual.binding import Binding
|
||||||
from textual.widgets import Footer, Header, Input
|
from textual.widgets import Footer, Header, Input
|
||||||
|
|
|
||||||
|
|
@ -663,7 +663,7 @@ def chat( # pragma: no cover
|
||||||
model: str | None = typer.Option(
|
model: str | None = typer.Option(
|
||||||
None,
|
None,
|
||||||
"--model",
|
"--model",
|
||||||
help="Model to use for the chat (e.g. openai:gpt-4o)",
|
help="Model to use for the chat (e.g. openai-chat:gpt-4o)",
|
||||||
),
|
),
|
||||||
skill: list[str] | None = typer.Option(
|
skill: list[str] | None = typer.Option(
|
||||||
None,
|
None,
|
||||||
|
|
|
||||||
|
|
@ -393,6 +393,8 @@ async def _rebuild_embed_only(
|
||||||
embeddings.extend(batch_embeddings)
|
embeddings.extend(batch_embeddings)
|
||||||
|
|
||||||
for chunk, content_fts, embedding in zip(chunks, texts, embeddings):
|
for chunk, content_fts, embedding in zip(chunks, texts, embeddings):
|
||||||
|
assert chunk.id is not None
|
||||||
|
assert chunk.document_id is not None
|
||||||
pending_records.append(
|
pending_records.append(
|
||||||
client.store.ChunkRecord(
|
client.store.ChunkRecord(
|
||||||
id=chunk.id,
|
id=chunk.id,
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ async def _apply_compress_docling_document(store: Store) -> None: # pragma: no
|
||||||
"Recovering %d documents from failed migration", len(staging_ids)
|
"Recovering %d documents from failed migration", len(staging_ids)
|
||||||
)
|
)
|
||||||
# Create new documents table and copy from staging
|
# Create new documents table and copy from staging
|
||||||
store.documents_table = None
|
del store.documents_table
|
||||||
if "documents" in (await store.db.list_tables()).tables:
|
if "documents" in (await store.db.list_tables()).tables:
|
||||||
await store.db.drop_table("documents")
|
await store.db.drop_table("documents")
|
||||||
store.documents_table = await store.db.create_table(
|
store.documents_table = await store.db.create_table(
|
||||||
|
|
@ -137,7 +137,7 @@ async def _apply_compress_docling_document(store: Store) -> None: # pragma: no
|
||||||
return
|
return
|
||||||
|
|
||||||
# No documents and no staging to recover, just recreate table with new schema
|
# No documents and no staging to recover, just recreate table with new schema
|
||||||
store.documents_table = None
|
del store.documents_table
|
||||||
if "documents" in (await store.db.list_tables()).tables:
|
if "documents" in (await store.db.list_tables()).tables:
|
||||||
await store.db.drop_table("documents")
|
await store.db.drop_table("documents")
|
||||||
store.documents_table = await store.db.create_table(
|
store.documents_table = await store.db.create_table(
|
||||||
|
|
@ -177,7 +177,7 @@ async def _apply_compress_docling_document(store: Store) -> None: # pragma: no
|
||||||
)
|
)
|
||||||
|
|
||||||
# Replace old table with staging table
|
# Replace old table with staging table
|
||||||
store.documents_table = None
|
del store.documents_table
|
||||||
if "documents" in (await store.db.list_tables()).tables:
|
if "documents" in (await store.db.list_tables()).tables:
|
||||||
await store.db.drop_table("documents")
|
await store.db.drop_table("documents")
|
||||||
store.documents_table = await store.db.create_table(
|
store.documents_table = await store.db.create_table(
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ async def _apply_split_pages_zstd(store: Store) -> None: # pragma: no cover
|
||||||
logger.info(
|
logger.info(
|
||||||
"Recovering %d documents from failed migration", len(staging_ids)
|
"Recovering %d documents from failed migration", len(staging_ids)
|
||||||
)
|
)
|
||||||
store.documents_table = None
|
del store.documents_table
|
||||||
if "documents" in (await store.db.list_tables()).tables:
|
if "documents" in (await store.db.list_tables()).tables:
|
||||||
await store.db.drop_table("documents")
|
await store.db.drop_table("documents")
|
||||||
store.documents_table = await store.db.create_table(
|
store.documents_table = await store.db.create_table(
|
||||||
|
|
@ -144,7 +144,7 @@ async def _apply_split_pages_zstd(store: Store) -> None: # pragma: no cover
|
||||||
return
|
return
|
||||||
|
|
||||||
# No documents and no staging — recreate table with new schema
|
# No documents and no staging — recreate table with new schema
|
||||||
store.documents_table = None
|
del store.documents_table
|
||||||
if "documents" in (await store.db.list_tables()).tables:
|
if "documents" in (await store.db.list_tables()).tables:
|
||||||
await store.db.drop_table("documents")
|
await store.db.drop_table("documents")
|
||||||
store.documents_table = await store.db.create_table(
|
store.documents_table = await store.db.create_table(
|
||||||
|
|
@ -188,7 +188,7 @@ async def _apply_split_pages_zstd(store: Store) -> None: # pragma: no cover
|
||||||
)
|
)
|
||||||
|
|
||||||
# Replace old table with staging table
|
# Replace old table with staging table
|
||||||
store.documents_table = None
|
del store.documents_table
|
||||||
if "documents" in (await store.db.list_tables()).tables:
|
if "documents" in (await store.db.list_tables()).tables:
|
||||||
await store.db.drop_table("documents")
|
await store.db.drop_table("documents")
|
||||||
store.documents_table = await store.db.create_table(
|
store.documents_table = await store.db.create_table(
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ classifiers = [
|
||||||
]
|
]
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"docling-core>=2.74.1",
|
"docling-core>=2.75.0",
|
||||||
"haiku.skills>=0.16.0",
|
"haiku.skills>=0.16.0",
|
||||||
"httpx>=0.28.1",
|
"httpx>=0.28.1",
|
||||||
"jinja2>=3.1.0",
|
"jinja2>=3.1.0",
|
||||||
|
|
@ -30,8 +30,8 @@ dependencies = [
|
||||||
"lancedb==0.30.2",
|
"lancedb==0.30.2",
|
||||||
"pathspec>=1.0.4",
|
"pathspec>=1.0.4",
|
||||||
"pydantic>=2.12.5",
|
"pydantic>=2.12.5",
|
||||||
"pydantic-ai-slim[openai,fastmcp,logfire,ag-ui]>=1.81.0",
|
"pydantic-ai-slim[openai,fastmcp,logfire,ag-ui]>=1.96.0",
|
||||||
"pydantic-monty>=0.0.9",
|
"pydantic-monty>=0.0.17",
|
||||||
"python-dotenv>=1.2.2",
|
"python-dotenv>=1.2.2",
|
||||||
"pyyaml>=6.0.3",
|
"pyyaml>=6.0.3",
|
||||||
"rich>=14.3.3",
|
"rich>=14.3.3",
|
||||||
|
|
@ -42,13 +42,13 @@ dependencies = [
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
# Document processing
|
# Document processing
|
||||||
docling = ["docling>=2.91.0", "opencv-python-headless>=4.13.0.92"]
|
docling = ["docling>=2.93.0", "opencv-python-headless>=4.13.0.92"]
|
||||||
# S3 / object-storage monitoring
|
# S3 / object-storage monitoring
|
||||||
s3 = ["obstore>=0.9,<0.10"]
|
s3 = ["obstore>=0.9,<0.10"]
|
||||||
# Embedding providers
|
# Embedding providers
|
||||||
voyageai = ["pydantic-ai-slim[voyageai]"]
|
voyageai = ["pydantic-ai-slim[voyageai]"]
|
||||||
# Rerankers
|
# Rerankers
|
||||||
mxbai = ["mxbai-rerank>=0.1.6"]
|
mxbai = ["mxbai-rerank>=0.1.6", "transformers>=4.49.0,<5.0.0"]
|
||||||
cohere = ["cohere>=5.21.1"]
|
cohere = ["cohere>=5.21.1"]
|
||||||
zeroentropy = ["zeroentropy>=0.1.0a11"]
|
zeroentropy = ["zeroentropy>=0.1.0a11"]
|
||||||
jina = ["transformers>=4.40.0", "torch>=2.0.0"]
|
jina = ["transformers>=4.40.0", "torch>=2.0.0"]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue