Merge pull request #382 from ggozad/chore/updates
Prepare for pydantic-ai 2.0, update haiku.skills
This commit is contained in:
commit
260b8e8b09
11 changed files with 57 additions and 61 deletions
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
### Changed
|
||||
|
||||
- Bump `haiku.skills>=0.17.1` and `pydantic-ai-slim>=1.100.0` (the last pre-2.0 release). Migrate off two APIs slated for removal in pydantic-ai 2.0: `Agent(tool_retries=, output_retries=)` → `Agent(retries={"tools": …, "output": …})` in the LLM-as-judge evaluator, and `Evaluator.evaluation_name` class attribute → overriding `get_default_evaluation_name()` on `CitationMRREvaluator` / `CitationMAPEvaluator`.
|
||||
- Drop the `item.annotations` fallback in `_picture_description_text`. Docling's `PictureItem` runs a `@model_validator(mode="after")` on load that migrates the deprecated `annotations` field into `meta.description`, so reading `meta.description.text` covers both legacy and current blobs. Tests in `test_converters.py` switched to `meta.description.text` for the same reason.
|
||||
- Chat TUI now generates a stable per-launch `thread_id` (rotated on "Clear chat") instead of hardcoding `"tui"`. AGUIAdapter forwards it as the `gen_ai.conversation.id` OTel attribute, so multi-turn TUI sessions group into one Logfire conversation instead of collapsing every launch into a single bucket.
|
||||
- Documentation generator swapped from `mkdocs-material` to `zensical`. Drops `mkdocs` / `mkdocs-material` dev deps, replaces `mkdocs.yml` with `zensical.toml`, adds `overrides/main.html` (OG/Twitter share meta) and `docs/stylesheets/extra.css`. `build-docs` workflow now runs `uv run zensical build` and publishes via the GitHub Pages artifact actions instead of `mkdocs gh-deploy`.
|
||||
|
||||
### Fixed
|
||||
|
|
|
|||
|
|
@ -175,12 +175,9 @@ Two approaches are benchmarked separately:
|
|||
|
||||
| Embedding Model | VLM | Skill model | QA accuracy | Mean `cited_map` |
|
||||
|------------------------|----------------------|------------------------------|-------------|------------------|
|
||||
| `qwen3-embedding:4b` | Ollama / ministral-3 | `ollama:gpt-oss` | 0.94 | 0.86 |
|
||||
| `qwen3-embedding:4b` | Ollama / ministral-3 | `vllm:Gemma-4-26B-A4B-NVFP4` | 0.90 | 0.89 |
|
||||
| `qwen3-embedding:4b` | Ollama / ministral-3 | `vllm:Gemma-4-26B-A4B-NVFP4` | 0.88 | 0.89 |
|
||||
|
||||
*`ollama:gpt-oss` row measured on haiku.rag v0.44.0, on 2992 of 3044 completed cases.*
|
||||
*`vllm:Gemma-4-26B-A4B-NVFP4` row measured on haiku.rag v0.47.0, with `mxbai-rerank-base-v2`, stopped at 674 of 3045 cases (cumulative means stable from case ~200).*
|
||||
*Both judged by `ollama:qwen3.6` (current default).*
|
||||
*Measured on haiku.rag v0.48.0, with `mxbai-rerank-base-v2`, on all 3045 cases. Judged by `vllm:Qwen3.6-35B-A3B-NVFP4`.*
|
||||
|
||||
## Inactive datasets
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ class CitationMRREvaluator(Evaluator):
|
|||
Use for single-document datasets, mirroring :class:`MRREvaluator`.
|
||||
"""
|
||||
|
||||
evaluation_name: str = "cited_mrr"
|
||||
def get_default_evaluation_name(self) -> str:
|
||||
return "cited_mrr"
|
||||
|
||||
def evaluate(self, ctx: EvaluatorContext) -> float:
|
||||
relevant = _relevant_uris(ctx)
|
||||
|
|
@ -43,7 +44,8 @@ class CitationMAPEvaluator(Evaluator):
|
|||
datasets, mirroring :class:`MAPEvaluator`.
|
||||
"""
|
||||
|
||||
evaluation_name: str = "cited_map"
|
||||
def get_default_evaluation_name(self) -> str:
|
||||
return "cited_map"
|
||||
|
||||
def evaluate(self, ctx: EvaluatorContext) -> float:
|
||||
relevant = _relevant_uris(ctx)
|
||||
|
|
|
|||
|
|
@ -51,8 +51,7 @@ class LLMJudge:
|
|||
model=model_obj,
|
||||
output_type=LLMJudgeResponseSchema,
|
||||
system_prompt=ANSWER_EQUIVALENCE_RUBRIC,
|
||||
tool_retries=3,
|
||||
output_retries=3,
|
||||
retries={"tools": 3, "output": 3},
|
||||
)
|
||||
|
||||
async def judge_answers(
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class TestCitationMRREvaluator:
|
|||
assert self.evaluator.evaluate(ctx) == 0.0
|
||||
|
||||
def test_evaluation_name(self) -> None:
|
||||
assert self.evaluator.evaluation_name == "cited_mrr"
|
||||
assert self.evaluator.get_default_evaluation_name() == "cited_mrr"
|
||||
|
||||
|
||||
class TestCitationMAPEvaluator:
|
||||
|
|
@ -79,4 +79,4 @@ class TestCitationMAPEvaluator:
|
|||
assert self.evaluator.evaluate(ctx) == 0.0
|
||||
|
||||
def test_evaluation_name(self) -> None:
|
||||
assert self.evaluator.evaluation_name == "cited_map"
|
||||
assert self.evaluator.get_default_evaluation_name() == "cited_map"
|
||||
|
|
|
|||
|
|
@ -108,6 +108,10 @@ class ChatApp(App):
|
|||
self._is_processing = False
|
||||
self._current_worker: Worker[None] | None = None
|
||||
self._document_filter: list[str] = []
|
||||
# Stable per-launch id so multi-turn chats land in one Logfire
|
||||
# conversation. AGUIAdapter reads run_input.thread_id and exports it
|
||||
# as the `gen_ai.conversation.id` OTel attribute on every agent run.
|
||||
self._conversation_id = str(uuid.uuid4())
|
||||
|
||||
def compose(self) -> "ComposeResult":
|
||||
"""Compose the UI layout."""
|
||||
|
|
@ -207,7 +211,7 @@ class ChatApp(App):
|
|||
await chat_history.show_thinking()
|
||||
|
||||
run_input = RunAgentInput(
|
||||
thread_id="tui",
|
||||
thread_id=self._conversation_id,
|
||||
run_id=str(uuid.uuid4()),
|
||||
messages=self._messages,
|
||||
state=self._state,
|
||||
|
|
@ -375,6 +379,8 @@ class ChatApp(App):
|
|||
# Reset state
|
||||
if self._toolset:
|
||||
self._state = self._toolset.build_state_snapshot()
|
||||
# Cleared chat starts a fresh Logfire conversation.
|
||||
self._conversation_id = str(uuid.uuid4())
|
||||
|
||||
def action_focus_input(self) -> None:
|
||||
"""Focus the input field, or cancel if processing."""
|
||||
|
|
|
|||
|
|
@ -25,19 +25,15 @@ class DocumentItem(BaseModel):
|
|||
def _picture_description_text(item: "PictureItem") -> str | None:
|
||||
"""Return the VLM-generated description text for a PictureItem, if any.
|
||||
|
||||
Tries the modern ``meta.description`` location first (docling 2.91+) and
|
||||
falls back to ``annotations`` entries that carry a ``text`` field
|
||||
(PictureDescriptionData and similar).
|
||||
Reads ``meta.description.text``. Pre-2.91 blobs that stored the
|
||||
description under the deprecated ``annotations`` field are migrated to
|
||||
``meta`` by ``PictureItem``'s own ``@model_validator(mode="after")`` at
|
||||
load time, so this single check covers both formats.
|
||||
"""
|
||||
if item.meta and item.meta.description:
|
||||
text = item.meta.description.text
|
||||
if text and text.strip():
|
||||
return text
|
||||
# Annotations is a tagged union; only some variants carry `text`.
|
||||
for ann in item.annotations:
|
||||
text = getattr(ann, "text", None)
|
||||
if isinstance(text, str) and text.strip():
|
||||
return text
|
||||
return None
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -23,14 +23,14 @@ classifiers = [
|
|||
|
||||
dependencies = [
|
||||
"docling-core>=2.75.0",
|
||||
"haiku.skills>=0.16.0",
|
||||
"haiku.skills>=0.17.1",
|
||||
"httpx>=0.28.1",
|
||||
"jinja2>=3.1.0",
|
||||
"jsonpatch>=1.33",
|
||||
"lancedb==0.30.2",
|
||||
"pathspec>=1.0.4",
|
||||
"pydantic>=2.12.5",
|
||||
"pydantic-ai-slim[openai,fastmcp,logfire,ag-ui]>=1.96.0",
|
||||
"pydantic-ai-slim[openai,fastmcp,logfire,ag-ui]>=1.100.0",
|
||||
"pydantic-monty>=0.0.17",
|
||||
"python-dotenv>=1.2.2",
|
||||
"pyyaml>=6.0.3",
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ async def test_chat_history_thinking_indicator(temp_db_path: Path):
|
|||
|
||||
@pytest.mark.asyncio
|
||||
async def test_clear_chat_resets_state(temp_db_path: Path):
|
||||
"""Test that clearing chat resets state and messages."""
|
||||
"""Test that clearing chat resets state, messages, and conversation id."""
|
||||
from haiku.rag.chat.widgets.chat_history import ChatHistory
|
||||
|
||||
app, mock_client = _make_app(temp_db_path)
|
||||
|
|
@ -232,10 +232,12 @@ async def test_clear_chat_resets_state(temp_db_path: Path):
|
|||
await chat_history.add_message("assistant", "Hi there")
|
||||
assert len(chat_history.messages) == 2
|
||||
|
||||
previous_conversation_id = app._conversation_id
|
||||
await app.action_clear_chat()
|
||||
await pilot.pause()
|
||||
|
||||
assert len(chat_history.messages) == 0
|
||||
assert app._conversation_id != previous_conversation_id
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
|
|
@ -829,19 +829,14 @@ class TestDoclingLocalConverter:
|
|||
# The document should have pictures with descriptions
|
||||
assert doc.pictures, "Document should have pictures"
|
||||
|
||||
# Check that at least one picture has a description annotation
|
||||
from docling_core.types.doc.document import PictureDescriptionData
|
||||
|
||||
# Check that at least one picture carries a VLM description.
|
||||
pictures_with_descriptions = []
|
||||
for pic in doc.pictures:
|
||||
for ann in pic.annotations:
|
||||
if isinstance(ann, PictureDescriptionData):
|
||||
pictures_with_descriptions.append(pic)
|
||||
# Description should appear in markdown output
|
||||
assert ann.text in markdown, (
|
||||
f"Picture description '{ann.text[:50]}...' should be in markdown"
|
||||
)
|
||||
break
|
||||
if pic.meta and pic.meta.description and pic.meta.description.text:
|
||||
pictures_with_descriptions.append(pic)
|
||||
assert pic.meta.description.text in markdown, (
|
||||
f"Picture description '{pic.meta.description.text[:50]}...' should be in markdown"
|
||||
)
|
||||
|
||||
assert pictures_with_descriptions, (
|
||||
"At least one picture should have a VLM description"
|
||||
|
|
@ -1349,18 +1344,14 @@ class TestDoclingServeConverterIntegration:
|
|||
|
||||
assert doc.pictures, "Document should have pictures"
|
||||
|
||||
from docling_core.types.doc.document import PictureDescriptionData
|
||||
|
||||
pictures_with_descriptions = []
|
||||
markdown = doc.export_to_markdown()
|
||||
for pic in doc.pictures:
|
||||
for ann in pic.annotations:
|
||||
if isinstance(ann, PictureDescriptionData):
|
||||
pictures_with_descriptions.append(pic)
|
||||
assert ann.text in markdown, (
|
||||
f"Picture description '{ann.text[:50]}...' should be in markdown"
|
||||
)
|
||||
break
|
||||
if pic.meta and pic.meta.description and pic.meta.description.text:
|
||||
pictures_with_descriptions.append(pic)
|
||||
assert pic.meta.description.text in markdown, (
|
||||
f"Picture description '{pic.meta.description.text[:50]}...' should be in markdown"
|
||||
)
|
||||
|
||||
assert pictures_with_descriptions, (
|
||||
"At least one picture should have a VLM description"
|
||||
|
|
|
|||
36
uv.lock
36
uv.lock
|
|
@ -40,14 +40,14 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "ag-ui-protocol"
|
||||
version = "0.1.15"
|
||||
version = "0.1.18"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pydantic" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/57/71/96c21ae7e2fb9b610c1a90d38bd2de8b6e5b2900a63001f3882f43e519af/ag_ui_protocol-0.1.15.tar.gz", hash = "sha256:5e23c1042c7d4e364d685e68d2fb74d37c16bc83c66d270102d8eaedce56ad82", size = 6269, upload-time = "2026-04-01T15:44:33.136Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/4c/d7/5711eada86da9bd7684e58645653a1693ef20b66cc3efbb1deeafef80f8d/ag_ui_protocol-0.1.18.tar.gz", hash = "sha256:b37c672c3fd6bac12b316c39f45ad9db9f137bbb885489c79f268507029a22ff", size = 9937, upload-time = "2026-04-21T20:44:59.151Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/a0/a73398d30bb0f9ad70cd70426151a4a19527a7296e48a3a16a50e1d5db05/ag_ui_protocol-0.1.15-py3-none-any.whl", hash = "sha256:85cde077023ccbc37b5ce2ad953537883c262d210320f201fc2ec4e85408b06a", size = 8661, upload-time = "2026-04-01T15:44:32.079Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/74/913c9b8fc566c6da650aecbddf25a5d8186b54138df265eb9eb546f56141/ag_ui_protocol-0.1.18-py3-none-any.whl", hash = "sha256:d151c0f0a34160647f1571163f7185746f4326b15a56d1560de5082a7a0e7a12", size = 12607, upload-time = "2026-04-21T20:45:00.097Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1599,7 +1599,7 @@ requires-dist = [
|
|||
{ name = "cohere", marker = "extra == 'cohere'", specifier = ">=5.21.1" },
|
||||
{ name = "docling", marker = "extra == 'docling'", specifier = ">=2.93.0" },
|
||||
{ name = "docling-core", specifier = ">=2.75.0" },
|
||||
{ name = "haiku-skills", specifier = ">=0.16.0" },
|
||||
{ name = "haiku-skills", specifier = ">=0.17.1" },
|
||||
{ name = "httpx", specifier = ">=0.28.1" },
|
||||
{ name = "jinja2", specifier = ">=3.1.0" },
|
||||
{ name = "jsonpatch", specifier = ">=1.33" },
|
||||
|
|
@ -1614,7 +1614,7 @@ requires-dist = [
|
|||
{ name = "pydantic-ai-slim", extras = ["google"], marker = "extra == 'google'" },
|
||||
{ name = "pydantic-ai-slim", extras = ["groq"], marker = "extra == 'groq'" },
|
||||
{ name = "pydantic-ai-slim", extras = ["mistral"], marker = "extra == 'mistral'" },
|
||||
{ name = "pydantic-ai-slim", extras = ["openai", "fastmcp", "logfire", "ag-ui"], specifier = ">=1.96.0" },
|
||||
{ name = "pydantic-ai-slim", extras = ["openai", "fastmcp", "logfire", "ag-ui"], specifier = ">=1.100.0" },
|
||||
{ name = "pydantic-ai-slim", extras = ["vertexai"], marker = "extra == 'vertexai'" },
|
||||
{ name = "pydantic-ai-slim", extras = ["voyageai"], marker = "extra == 'voyageai'" },
|
||||
{ name = "pydantic-monty", specifier = ">=0.0.17" },
|
||||
|
|
@ -1638,19 +1638,19 @@ provides-extras = ["docling", "s3", "voyageai", "mxbai", "cohere", "zeroentropy"
|
|||
|
||||
[[package]]
|
||||
name = "haiku-skills"
|
||||
version = "0.16.0"
|
||||
version = "0.17.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "ag-ui-protocol" },
|
||||
{ name = "jsonpatch" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "pydantic-ai-slim", extra = ["mcp", "openai"] },
|
||||
{ name = "pydantic-ai-slim", extra = ["ag-ui", "mcp", "openai"] },
|
||||
{ name = "pyyaml" },
|
||||
{ name = "skills-ref" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8c/12/98ea5ee4ca14d4053019b4ec4b22e39af8ae1bc054aea107c87f5ecb025e/haiku_skills-0.16.0.tar.gz", hash = "sha256:e7bfa8141523912f3eb4469bf0b611408fa1e1e54707c9b475d0b3e04ea7ffbc", size = 256020, upload-time = "2026-04-28T08:44:23.347Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/01/90/7eb6c20aada4e861589ecc300bcf5c827335d803c4e225a79b0924dd9793/haiku_skills-0.17.1.tar.gz", hash = "sha256:062385ae67f61e37a9790721da50f7b38ed0b903e9a8efb2bd76b4b9fcf94651", size = 187965, upload-time = "2026-05-21T10:37:45.242Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/55/ca/4cc0b026ee3e25d4b7f85267a210d1248988079fcac73649a09e9f9a5873/haiku_skills-0.16.0-py3-none-any.whl", hash = "sha256:50dec4e24594dceadc781242cafb20ced3b1fe743fdb7035a081756fbb402aa1", size = 32794, upload-time = "2026-04-28T08:44:21.855Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c9/86/ff441d3c5fba2e66d29c135659d536dd47a5e920e4b351c9621a89599510/haiku_skills-0.17.1-py3-none-any.whl", hash = "sha256:7bdcafc5f184bb765eb9c86e0147d535272dc42c1dc8cef4ce1a4d1464376ff0", size = 32965, upload-time = "2026-05-21T10:37:44.192Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3624,7 +3624,7 @@ email = [
|
|||
|
||||
[[package]]
|
||||
name = "pydantic-ai-slim"
|
||||
version = "1.97.0"
|
||||
version = "1.100.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "genai-prices" },
|
||||
|
|
@ -3635,9 +3635,9 @@ dependencies = [
|
|||
{ name = "pydantic-graph" },
|
||||
{ name = "typing-inspection" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/50/b3/3cd6067bc6bc524a6a7374db49f954170c9c108e63462c881759ed404c14/pydantic_ai_slim-1.97.0.tar.gz", hash = "sha256:f7da3bc68cefa43819e744223bb024f7ff7921d99aefce791e00e33eae84597b", size = 716656, upload-time = "2026-05-15T22:28:41.919Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/68/db/3eb296369e3001f82d7552060c3811307809954b7c7ec30499f383d3c87a/pydantic_ai_slim-1.100.0.tar.gz", hash = "sha256:cc755c7970b2e041764b9d2f74d50cbad3cf7989b14cdbf62d356f25eb2a1222", size = 726289, upload-time = "2026-05-21T04:04:59.061Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/f1/fdd17bdd00c3562ebef7bf5dc04287679bfe7143ebb9bf75aa831f1a0bdf/pydantic_ai_slim-1.97.0-py3-none-any.whl", hash = "sha256:f4e086f6b2141f841aacfdc3a5825a3632bac463e2d49261aaad5789700e93ef", size = 890563, upload-time = "2026-05-15T22:28:32.509Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/a6/164b070c59f7c69e81cb5fd38225da24c4587a8fe629af49c72709182ffc/pydantic_ai_slim-1.100.0-py3-none-any.whl", hash = "sha256:422a721b7a7157daff749a6eec9a4ba2e3e7efc28ae5a2bdfe468529eaf81aaf", size = 901788, upload-time = "2026-05-21T04:04:49.147Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
|
|
@ -3757,7 +3757,7 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "pydantic-evals"
|
||||
version = "1.97.0"
|
||||
version = "1.100.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
|
|
@ -3767,14 +3767,14 @@ dependencies = [
|
|||
{ name = "pyyaml" },
|
||||
{ name = "rich" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ab/80/34c8b3a7623add32431978ef64774c22437a5752b7c19c6c8041c4933e50/pydantic_evals-1.97.0.tar.gz", hash = "sha256:6ecf3d32a4f18ac009bd8e0685497c45dcb15a226b9047e094cd2f18ca9db535", size = 77307, upload-time = "2026-05-15T22:28:43.377Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b6/c9/6d6299fa7e50dd51d7c03e7e8bcf32810f100f234cc6cf8ca35cedf01f0a/pydantic_evals-1.100.0.tar.gz", hash = "sha256:e536bf3b2d6351be797cdd1aab9797d034fbaf7a056873256cef06e1e80ac696", size = 78523, upload-time = "2026-05-21T04:05:00.621Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/07/ac/cd06b456a986ca59d7a98441a3caa67ac48aacbfa247014c134fc815de99/pydantic_evals-1.97.0-py3-none-any.whl", hash = "sha256:1781927b2e5610a15b37574c0222704a979ca6ae7d7db235dd70684b7d4a84f0", size = 92267, upload-time = "2026-05-15T22:28:34.084Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1f/8e/3b4161b016c676cab1d19f9d1b3672cb61e8f56315fb61bb3367123760d4/pydantic_evals-1.100.0-py3-none-any.whl", hash = "sha256:67f6e2467d5fc300d965118ef46b5cebb07e07227419ee64da9b381c28e34f47", size = 93526, upload-time = "2026-05-21T04:04:51.527Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-graph"
|
||||
version = "1.97.0"
|
||||
version = "1.100.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "httpx" },
|
||||
|
|
@ -3782,9 +3782,9 @@ dependencies = [
|
|||
{ name = "pydantic" },
|
||||
{ name = "typing-inspection" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/2b/03/a3f01a12155f16b5699e5b399df8ca88db1f5032264c52aff1cbefce3557/pydantic_graph-1.97.0.tar.gz", hash = "sha256:26dade3f9a3a090325f9bc52c72c6fe48470c8d18c746ffd577b7202a72c656b", size = 62551, upload-time = "2026-05-15T22:28:44.856Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/90/8b/eee672fa01eec3ea34e7d8962d54aa16d658ad0723466122a7ba2828caa1/pydantic_graph-1.100.0.tar.gz", hash = "sha256:7651fa6ccce9d88a35b1d2cfe79d5d1dbb2415457503009195014bf31f6075bd", size = 62559, upload-time = "2026-05-21T04:05:01.682Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3a/0b/317ffa52272ed3157733aaefa60e7a6337332dff08d9c5e3077042b2ca5b/pydantic_graph-1.97.0-py3-none-any.whl", hash = "sha256:db0c95e1686e0fd9843b558ff608fa90ed2cdc56d8b8a7249180216ad56ad764", size = 80091, upload-time = "2026-05-15T22:28:35.678Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/12/21d6a68743229553c8ba9ca19da73c2d7e18dc6f8fbfd56c8c12c5587cb6/pydantic_graph-1.100.0-py3-none-any.whl", hash = "sha256:ba0b0a70bfd320b58b7012614b857f4b12dbb95b233da7127a6ff973c03d24e7", size = 80101, upload-time = "2026-05-21T04:04:53.635Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
Loading…
Reference in a new issue