Commit graph

209 commits

Author SHA1 Message Date
Lawrence Akka
09ff101349 Expose all chunk metadata on search results and citations through SearchResult.chunk_meta and Citation.chunk_meta 2026-08-17 19:42:23 +02:00
Yiorgis Gozadinos
8e93b639bc
Migrate existing databases to the full index set
Adds the 0.75.0 upgrade, which brings a pre-existing database up to the index
set `_init_tables` now creates. It rewrites no table data, so unlike the earlier
data migrations its cost is the index builds alone, each of which reads the
column it indexes.

`ensure_indexes` ensures an index of the declared *type* covers each declared
column, rather than checking that the column is indexed at all. The distinction
is what makes it safe to run against a database of unknown provenance:

- A wrong-typed index no longer satisfies the check. A BTree on `label` covers
  the column while losing the low-cardinality equality lookup the Bitmap is for.
- Nothing is dropped or converted away from. Two index types over one column can
  be deliberate, serving different query shapes, so an index this function did
  not declare survives even on a column it does. The one thing it overwrites is
  an index at LanceDB's default name, `{column}_idx`, which is the name it
  creates itself.
- A column already carrying the declared type is skipped, so a database with the
  full set migrates instantly rather than re-sorting every indexed column.
- Undeclared columns are untouched, so a vector index on `chunks` survives.

It returns the columns it acted on, because a change is not always visible from
outside: adding a Bitmap beside an existing BTree leaves the column indexed
before and after.

The version bump to 0.75.0 is required, not incidental: `_set_initial_version`
stamps a new database with the installed package version, so a migration
numbered above it would be pending the moment the database was created.

`test_client_update_document_replaces_rows_with_bounded_versions` turns
auto_vacuum off. Indexing `documents` means a background vacuum now has an index
to maintain on that table, so `optimize()` writes a version where it previously
had nothing to do, and it landed inside the window the test measures. The
document update itself is still one version, so the bound stays exact.
2026-08-17 16:34:58 +03:00
Yiorgis Gozadinos
c184a25d68
Index every hot lookup key from one shared definition
`_init_tables` left `chunks.id`, `chunks.document_id` and `documents.id`
unindexed, so those lookups scanned the column. On object storage that is
network I/O per query, on paths that run per document: citation lookup,
delete-by-document, the re-ingest merge, and every dedup probe.

Declare the index set per table in `index_specs()` and apply it through
`ensure_indexes()`, which skips a column only when it is already indexed with
the declared type. Both halves of that are load-bearing. Skipping is required
because `create_index(replace=True)` rebuilds an identical index, writing a new
index and a new table version and orphaning the old files until the next vacuum.
Comparing the type is required because column coverage alone would let a
wrong-typed index stand, and a BTree on `label` silently loses the
low-cardinality equality lookup the Bitmap is there for.

Columns not declared for a table are left alone, so an externally created index
such as a vector index on `chunks` survives.

`_init_tables`, `recreate_embeddings_table`, `ChunkRepository.delete_all` and
`DocumentRepository.delete_all` now all route through it instead of repeating
their own subsets.

Also recreate `document_items` from `get_document_items_arrow_schema()` in
`DocumentRepository.delete_all`, which was using the LanceModel and so returned
`picture_data` as 32-bit `binary`.

Existing databases are unchanged; the migration follows separately.
2026-08-17 15:05:37 +03:00
Yiorgis Gozadinos
46f7ab8d97
Name the search result each page image belongs to
ToolReturn.content reaches the model as a user-role message and the pictures
arrive bare, so nothing connects a figure to the chunk it came from:
BinaryContent.identifier does not survive serialization to the vision API, and
the captions in the result text correlate only by position.

Precede each picture with its position, source chunk id and self_ref.
build_binary_parts_from_results becomes build_image_content_from_results and
returns the labels interleaved with the pictures, so both attachment sites emit
them the same way.

This does not stop a model narrating retrieved pictures as user-supplied.
Measured on gemma4-26b with a single note ahead of the batch, and again with
per-image labels: it quotes the label and still says the user provided them.
The message role wins over its text.
2026-08-13 13:00:01 +03:00
Lawrence Akka
5e6284fd02 Stop eagerly importing Store from haiku.rag.store
Import Store from haiku.rag.store.engine directly instead of re-exporting it
through the package __init__, and defer HaikuRAGApp's import in cli.py behind
TYPE_CHECKING/lazy imports, avoiding an eager import at CLI startup.
2026-08-11 17:26:51 +01:00
Yiorgis Gozadinos
eb11a165b8
Stop loading page rasters on the title and update paths 2026-08-06 13:04:51 +03:00
Yiorgis Gozadinos
ac9b2cbf81
Load document blobs only when asked 2026-08-06 13:04:51 +03:00
Yiorgis Gozadinos
8b45f81464
Load only content when listing documents with include_content 2026-07-31 10:12:19 +03:00
Yiorgis Gozadinos
7ba78fdde3
Normalize pragma comments to the codebase's single-line form 2026-07-26 20:18:19 +03:00
Yiorgis Gozadinos
f6acb65e95
Reach and enforce 100% coverage
Cover the remaining paths in the client, context, downloads, title
generation, document tools and store models, and add fail_under=100 so
uncovered lines fail CI.

Six lines that no test can reach get a pragma with its reason: the docling
import guard, the nameless PDF attachment, the FS symlink OSError guard that
resolve(strict=False) absorbs, the docling bbox and LanceDB document-id
shape guards, the tag-retention branch vacuum makes unreachable, and Monty's
Rust-thread print callback.

Fix test_find_config_file_user_config, which wrote its config into the cwd it
had chdir'd to, so the cwd branch answered first and the user-directory
lookup it names was never exercised.
2026-07-26 20:11:02 +03:00
Yiorgis Gozadinos
dddaf0f84c
Remove unreachable code and fix two defects it surfaced
Delete repository methods with no callers (SettingsRepository CRUD,
ChunkRepository.update/delete/get_chunks_in_range), the DataFrame branch of
_process_search_results whose only caller always passes a query, and guards
that cannot be reached from their call sites: the rebuild mode=None default,
the staging drop already performed by _resolve_rebuild_recovery, the empty
batch skip, two context fast paths, the doctor prefix guard, the poller
_task attribute that is never assigned, and a docling caption fallback for
a field name no item class defines.

set_haiku_version built a recreated settings row from the process-global
Config rather than the store's own, so a store opened with a custom config
stamped global settings into the database.

check_source_accessible called urlparse outside its try block, so a stored
URI with a malformed IPv6 host raised ValueError instead of reporting the
source as inaccessible, aborting the whole rebuild sweep.
2026-07-26 18:45:48 +03:00
Yiorgis Gozadinos
9deb1f2bd4
replace haiku.skills with native Pydantic AI capabilities 2026-07-24 15:26:17 +03:00
Yiorgis Gozadinos
75a21c82c2
Search results and citations carry document metadata 2026-07-23 10:23:48 +03:00
Yiorgis Gozadinos
f02cde5ddf
Fix same-tick cancellation losing recovery results in _wait_protected 2026-07-16 13:11:35 +03:00
Yiorgis Gozadinos
dd2817ff6d
Protect tag-creation cleanup from cancellation 2026-07-16 13:11:35 +03:00
Yiorgis Gozadinos
1f88944ada
Protect restore rollback from cancellation; report delete_tag listing failures 2026-07-16 13:11:34 +03:00
Yiorgis Gozadinos
f41ec379df
Add Store.restore_tag 2026-07-16 13:11:34 +03:00
Yiorgis Gozadinos
a1f3435df3
Vacuum suppresses OSError only 2026-07-16 13:11:34 +03:00
Yiorgis Gozadinos
f997d7adc9
Consolidate tag primitives 2026-07-16 13:11:34 +03:00
Yiorgis Gozadinos
0e271eaf4b
Remove --before/--at time travel 2026-07-16 13:11:33 +03:00
Yiorgis Gozadinos
0813a1c980
Add tag CLI commands and history tag annotations 2026-07-16 13:11:27 +03:00
Yiorgis Gozadinos
0cbde6b7a2
Serialize tag operations, vacuum, and metadata refresh with writes 2026-07-16 12:32:57 +03:00
Yiorgis Gozadinos
69319c9390
Grow vacuum retention to protect tagged versions 2026-07-16 12:32:57 +03:00
Yiorgis Gozadinos
ae603d9b4d
Add database-level tag primitives to Store 2026-07-16 12:32:56 +03:00
Yiorgis Gozadinos
aa620aeb60
Bump lancedb to 0.34.0 2026-07-16 12:32:56 +03:00
Yiorgis Gozadinos
995d081aa1
Visualize the exact context the model saw via Citation.doc_item_refs
visualize_chunk re-expanded chunks from scratch to recover their refs,
which could not faithfully reproduce the original merge, scores, and
clip — so a visualization could highlight different pages than the
citation covered. Carry the cited items on Citation.doc_item_refs and
resolve bounding boxes from them directly; re-expansion remains only as
the fallback for callers with no stored context (CLI, inspector). Chat,
inspector, the app endpoint, and the frontend pass the refs through.
2026-07-09 11:51:37 +03:00
Yiorgis Gozadinos
0bcf34363a
Carry merged chunk ids on SearchResult and Citation 2026-07-09 11:05:41 +03:00
Yiorgis Gozadinos
a1cf405cae
Rename document_meta identity column document_id to id 2026-07-08 16:32:55 +03:00
Yiorgis Gozadinos
d2593304c5
Attach figure bytes when a result matches its caption 2026-07-03 13:22:02 +03:00
Yiorgis Gozadinos
b61134b747
Log FTS index build failures at WARNING 2026-06-25 13:00:29 +03:00
Yiorgis Gozadinos
9f4dda9254
Reuse one MarkdownDocSerializer per document in item extraction 2026-06-24 12:02:13 +03:00
Yiorgis Gozadinos
2b2b475279
Collapse docling compression to a single function 2026-06-24 10:43:27 +03:00
bryan davis
e95ac2e25d
remove redundant serialization 2026-06-24 10:42:58 +03:00
Yiorgis Gozadinos
62d2326933
Use single-threaded zstd compressor 2026-06-24 10:08:25 +03:00
bryan davis
2ca12c0096
adjust zstd handling to avoid possible core dumps with concurrency 2026-06-23 15:26:33 -05:00
Yiorgis Gozadinos
885e7b7ce7
coverage 2026-06-12 10:17:19 +03:00
Yiorgis Gozadinos
bfc51b8b28
urface document_meta in info, history, and the inspector 2026-06-12 10:17:18 +03:00
Yiorgis Gozadinos
df8af54298
rebase from main 2026-06-12 10:17:18 +03:00
Yiorgis Gozadinos
3366a6d383
Split meta document attributes into a document_meta table 2026-06-12 10:17:17 +03:00
Yiorgis Gozadinos
4bc52f0710
Serialize multi-table document writes and bound update version churn 2026-06-12 10:16:39 +03:00
Yiorgis Gozadinos
0be2e5b24f
Extract gather_database_info shared by the info command 2026-06-09 11:09:28 +03:00
Yiorgis Gozadinos
b43843f862
Batch-capable document and document-item repositories 2026-06-09 10:01:20 +03:00
Yiorgis Gozadinos
213569601b
Stop rewriting stored embedding settings on database open 2026-06-05 10:35:50 +03:00
Yiorgis Gozadinos
b6bbea3d64
Stop writing the schema version on database open 2026-06-05 10:32:30 +03:00
Yiorgis Gozadinos
083ff401d5
vacuum db after migration 2026-05-26 11:44:47 +03:00
Yiorgis Gozadinos
ef9cacf981
Harden FS source against symlink escape; surface pool/poller liveness in /health, additional auth tests 2026-05-26 11:44:47 +03:00
Yiorgis Gozadinos
5affe70eae
Cover unparseable-metadata path 2026-05-26 11:44:47 +03:00
Yiorgis Gozadinos
c2f681dd78
constant-time auth, migration short-circuit 2026-05-26 11:44:46 +03:00
Yiorgis Gozadinos
13cbadeb6f
canonical metadata keys: source_revision + content_type, bump to 0.50.0 2026-05-26 11:43:30 +03:00
Yiorgis Gozadinos
260b8e8b09
Merge pull request #382 from ggozad/chore/updates
Prepare for pydantic-ai 2.0, update haiku.skills
2026-05-21 14:30:55 +03:00
Yiorgis Gozadinos
80e3ae0280
clean up deprecation warnings: docling annotations + haiku.skills 0.17.1 2026-05-21 13:45:40 +03:00
Yiorgis Gozadinos
d14bf88096
fix migration failures on pre-v0.48.0 document_items schemas 2026-05-21 10:53:21 +03:00
Yiorgis Gozadinos
8c57a3ca99
Drop the multi-agent research workflow 2026-05-20 12:46:48 +03:00
Yiorgis Gozadinos
04eeec77d2
per-doc lazy items/toc cache; index document_items for fast per-doc lookup 2026-05-20 10:08:25 +03:00
Yiorgis Gozadinos
e8c61ad0c6
items.jsonl exposes chunk_ids per row; drops position and tree_depth 2026-05-19 14:20:11 +03:00
Yiorgis Gozadinos
87c551c892
Cover 0.48.0 migration 2026-05-18 16:49:44 +03:00
Yiorgis Gozadinos
3b6bef3bfb
Rename get_captions_for_chunk() to get_text_for_refs() 2026-05-18 16:49:44 +03:00
Yiorgis Gozadinos
514b0c51f8
surface figure captions in search results, lower search.limit to 5 2026-05-18 16:49:43 +03:00
Yiorgis Gozadinos
68388032be
consolidate #/pictures/ prefix, tighten CHANGELOG, log migration exc_info 2026-05-18 16:49:43 +03:00
Yiorgis Gozadinos
1360303edf
persist docling heading hierarchy on document_items 2026-05-18 16:48:34 +03:00
Yiorgis Gozadinos
f208730a5b
Merge pull request #374 from tseaver/feat-cli-search_type
feat: add '--search-type' option to CLI 'search'
2026-05-18 16:39:28 +03:00
Tres Seaver
ad0161e6da
chore: isort 2026-05-18 09:31:12 -04:00
Tres Seaver
f9ce3bc401
refactor: move 'SearchType' to 'store.models.chunk' 2026-05-18 09:27:34 -04:00
Yiorgis Gozadinos
04415a9d09
bump pydantic-monty, refresh deps, cap transformers<5 2026-05-18 16:02:55 +03:00
Tres Seaver
5079205d3d
fix: use 'SearchType' for 'ChunkRepository.search' 2026-05-18 06:50:49 -04:00
Yiorgis Gozadinos
701e9d3632
Relax embedding compat check to vector_dim only 2026-05-13 14:44:18 +03:00
Yiorgis Gozadinos
387032511e
Simplify 2026-05-08 12:11:25 +03:00
Yiorgis Gozadinos
788fac422e
Clean up migration 2026-05-08 11:52:57 +03:00
Yiorgis Gozadinos
4478b7ce2b
test v0.45.0 migration 2026-05-05 16:06:14 +03:00
Yiorgis Gozadinos
ee41bc676f
remove defensive code 2026-05-04 15:12:27 +03:00
Yiorgis Gozadinos
ff656504d3
make client.search() polymorphic on query type: str | bytes | PIL.Image.Image. Bytes/PIL queries embed via embed_image_query and run vector-only against the chunks table 2026-05-04 11:22:22 +03:00
Yiorgis Gozadinos
c9227c649f
emit synthetic picture chunks at ingest under multimodal embedders.
processing.chunk() merges text chunks with one synthetic Chunk per PictureItem-with-bytes,
sorted by iterate_items() position so chunk.order is structural.
embed_chunks dispatches on a Chunk._picture_data PrivateAttr
(text through embed_documents, picture through embed_image_query)
2026-05-03 17:04:43 +03:00
Yiorgis Gozadinos
4c9ef81fc6
drop the existing-row-not-found guard from the 0.45.0 picture-bytes migration. 2026-04-30 15:48:03 +03:00
Yiorgis Gozadinos
b290bbe82d
rename document_items repository's _LIGHT_COLUMNS to _METADATA_COLUMNS 2026-04-30 15:43:03 +03:00
Yiorgis Gozadinos
b01c649684
surface picture image bytes in SearchResult and emit multimodal ToolReturn from the agent search tool 2026-04-30 12:43:05 +03:00
Yiorgis Gozadinos
6a77ce92a9
extract picture bytes to document_items.picture_data at ingest, strip them from the docling_document blob, and add 0.45.0 migration to backfill existing
databases
2026-04-30 11:26:37 +03:00
Yiorgis Gozadinos
dc16f74b58
add picture_data column to document_items 2026-04-30 11:23:29 +03:00
Tres Seaver
0d70f4aec6
fix: pass absolute 'db_path' to 'lancedb.connect_async'
Closes #354.
2026-04-24 17:59:01 -04:00
Yiorgis Gozadinos
821b7361e9
Push document-id filter into chunk search query 2026-04-24 16:07:07 +03:00
Yiorgis Gozadinos
31fc22ce9d
List tables consistently 2026-04-24 15:57:07 +03:00
Yiorgis Gozadinos
cd4224a727
drop private title/embedding forwarders from HaikuRAG 2026-04-24 15:52:50 +03:00
Yiorgis Gozadinos
b23bad32c3
Check table_names() before dropping chunks in recreate_embeddings_table 2026-04-24 15:32:06 +03:00
Yiorgis Gozadinos
aca3ccc29f
Close connections if __aenter__ fails mid-initialization 2026-04-24 14:43:59 +03:00
Yiorgis Gozadinos
d0ed9e213f
Pin FTS search column to content_fts 2026-04-24 14:42:53 +03:00
Yiorgis Gozadinos
a74c3a6f9e
Satisfy ty by adding a typed to_pydantic helper 2026-04-24 14:42:53 +03:00
Yiorgis Gozadinos
57385506c1
Fix is_new_db detection when create=True is passed on an existing DB 2026-04-24 14:42:53 +03:00
Yiorgis Gozadinos
82fd10e0ee
Migrate LanceDB to native async API
Convert all LanceDB operations from sync calls wrapped in async
functions to the native async API (connect_async, AsyncConnection,
AsyncTable, AsyncQuery). Database I/O no longer blocks the event loop.

- Store and HaikuRAG use async context managers (async with). Store
  initialization is deferred to __aenter__; direct construction
  without async with is no longer supported.
- Index creation uses config objects (FTS, BTree, IvfPq) instead of
  string-based index_type parameter.
- Upgrade callbacks are async.
- HaikuRAG tracks background vacuum tasks and awaits them in __aexit__
  and before destructive rebuild operations to avoid races with
  concurrent table mutations.
- temp_db_path fixture uses pytest's tmp_path for reliable async
  cleanup.
2026-04-24 14:42:52 +03:00
Yiorgis Gozadinos
af7731f4e1
bulk-fetch items.jsonl via lazy cache to avoid per-document query timeout 2026-04-20 14:25:16 +03:00
Yiorgis Gozadinos
167c837514
repository methods, module-level executor, read-only VFS 2026-04-20 11:57:39 +03:00
Yiorgis Gozadinos
a1181ff52d
extract get_database_stats and share it across info, inspector, and backend 2026-04-17 15:33:30 +03:00
Yiorgis Gozadinos
d3c8ed62a8
preserve original chunk when expansion produces less content 2026-04-16 12:11:54 +03:00
Yiorgis Gozadinos
e2bac1e887
deduplicate escape_sql_string into utils 2026-04-16 12:11:53 +03:00
Yiorgis Gozadinos
b6113bf8ab
replace fixed-radius expansion with section-bounded algorithm
Context expansion is now automatic and structure-aware. For structured
documents, expands within the section containing the match. For sections
that exceed the budget or are too small, expands item-by-item outward
skipping noise labels. Unstructured documents use budget-based outward
expansion. Results sorted by relevance score.
2026-04-16 12:11:53 +03:00
Yiorgis Gozadinos
364b1bc509
add document_items table for fast context expansion 2026-04-16 12:11:53 +03:00
Yiorgis Gozadinos
a118ee7aaa
Cleanup 2026-04-08 14:19:33 +03:00
Yiorgis Gozadinos
8e876ef28d
For remote stores, detect new db by checking if tables exist 2026-04-08 14:19:10 +03:00
Yiorgis Gozadinos
110accb8e7
Add ConnectionMode enum (LOCAL/CLOUD/OBJECT_STORAGE) and connect_lancedb() utility to support S3, GCS, Azure, and HDFS backends via storage_options. 2026-04-08 14:19:09 +03:00
Yiorgis Gozadinos
3fe953eccb
Minor fixes 2026-04-08 14:04:32 +03:00
Yiorgis Gozadinos
9c5bef163e
Use zstandard get_frame_parameters for max_output_size 2026-04-08 14:04:32 +03:00
Yiorgis Gozadinos
89e2a303e6
migration to split pages and re-compress with zstd 2026-04-08 14:04:32 +03:00