Fix missing timezone info on ingested docs. mcp schema requires TZ

This commit is contained in:
Lawrence Akka 2026-09-01 17:00:08 +02:00 committed by Yiorgis Gozadinos
parent f4c657e094
commit 9c56f56660
No known key found for this signature in database
3 changed files with 23 additions and 12 deletions

View file

@ -2,7 +2,7 @@ import asyncio
import json import json
import logging import logging
from collections.abc import AsyncGenerator from collections.abc import AsyncGenerator
from datetime import datetime from datetime import UTC, datetime
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from docling_core.types.doc.document import DescriptionMetaField, PictureMeta from docling_core.types.doc.document import DescriptionMetaField, PictureMeta
@ -531,7 +531,7 @@ async def _flush_rebuild_batch(
if not documents: if not documents:
return return
now = datetime.now().isoformat() now = datetime.now(UTC).isoformat()
# Batch update documents and document_meta using merge_insert (one LanceDB # Batch update documents and document_meta using merge_insert (one LanceDB
# version per table). Content+blobs go to documents; mutable attributes go # version per table). Content+blobs go to documents; mutable attributes go

View file

@ -1,8 +1,8 @@
import json import json
from datetime import datetime from datetime import UTC, datetime
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from pydantic import BaseModel, Field from pydantic import BaseModel, Field, field_validator
from haiku.rag.store.compression import compress_docling_split, decompress_json from haiku.rag.store.compression import compress_docling_split, decompress_json
@ -29,8 +29,19 @@ class Document(BaseModel):
docling_document: bytes | None = Field(default=None, exclude=True) docling_document: bytes | None = Field(default=None, exclude=True)
docling_pages: bytes | None = Field(default=None, exclude=True) docling_pages: bytes | None = Field(default=None, exclude=True)
docling_version: str | None = Field(default=None, exclude=True) docling_version: str | None = Field(default=None, exclude=True)
created_at: datetime = Field(default_factory=datetime.now) created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
updated_at: datetime = Field(default_factory=datetime.now) updated_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
@field_validator("created_at", "updated_at")
@classmethod
def _assume_utc(cls, value: datetime) -> datetime:
"""Attach UTC to a timezone-less timestamp instead of leaving it ambiguous.
A row written before timestamps carried an explicit offset parses back
with no tzinfo. Treat it as UTC rather than pass it on naive, which the
MCP tools' declared JSON schema rejects as an invalid date-time.
"""
return value if value.tzinfo else value.replace(tzinfo=UTC)
def set_docling(self, docling_doc: "DoclingDocument") -> None: def set_docling(self, docling_doc: "DoclingDocument") -> None:
"""Serialize and store a DoclingDocument, splitting structure and pages. """Serialize and store a DoclingDocument, splitting structure and pages.

View file

@ -1,5 +1,5 @@
import json import json
from datetime import datetime from datetime import UTC, datetime
from typing import overload from typing import overload
from uuid import uuid4 from uuid import uuid4
@ -77,8 +77,8 @@ class DocumentRepository:
docling_document=doc.docling_document, docling_document=doc.docling_document,
docling_pages=doc.docling_pages, docling_pages=doc.docling_pages,
docling_version=doc.docling_version, docling_version=doc.docling_version,
created_at=datetime.fromisoformat(created) if created else datetime.now(), created_at=datetime.fromisoformat(created) if created else datetime.now(UTC),
updated_at=datetime.fromisoformat(updated) if updated else datetime.now(), updated_at=datetime.fromisoformat(updated) if updated else datetime.now(UTC),
) )
def _to_documents_record(self, entity: Document, doc_id: str) -> DocumentRecord: def _to_documents_record(self, entity: Document, doc_id: str) -> DocumentRecord:
@ -138,7 +138,7 @@ class DocumentRepository:
# document_meta) would surface. # document_meta) would surface.
if isinstance(entity, Document): if isinstance(entity, Document):
doc_id = str(uuid4()) doc_id = str(uuid4())
now = datetime.now().isoformat() now = datetime.now(UTC).isoformat()
await self.store.document_meta_table.add( await self.store.document_meta_table.add(
[self._to_meta_record(entity, doc_id, now, now)] [self._to_meta_record(entity, doc_id, now, now)]
) )
@ -159,7 +159,7 @@ class DocumentRepository:
if not documents: if not documents:
return [] return []
now = datetime.now().isoformat() now = datetime.now(UTC).isoformat()
created_at = datetime.fromisoformat(now) created_at = datetime.fromisoformat(now)
doc_records = [] doc_records = []
meta_records = [] meta_records = []
@ -272,7 +272,7 @@ class DocumentRepository:
self.store._assert_writable() self.store._assert_writable()
assert entity.id, "Document ID is required for update" assert entity.id, "Document ID is required for update"
now = datetime.now().isoformat() now = datetime.now(UTC).isoformat()
entity.updated_at = datetime.fromisoformat(now) entity.updated_at = datetime.fromisoformat(now)
created = entity.created_at.isoformat() if entity.created_at else now created = entity.created_at.isoformat() if entity.created_at else now
record = self._to_meta_record(entity, entity.id, created, now) record = self._to_meta_record(entity, entity.id, created, now)