Skip to content

feat(agentflare-store): initial crate — kv, documents (CRUD+FTS+vector+hybrid), blobs, leases - #244

Merged
getappz merged 17 commits into
masterfrom
feat/agentflare-store-v1
Jul 18, 2026
Merged

feat(agentflare-store): initial crate — kv, documents (CRUD+FTS+vector+hybrid), blobs, leases#244
getappz merged 17 commits into
masterfrom
feat/agentflare-store-v1

Conversation

@getappz

@getappz getappz commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Summary

Lands the agentflare-store crate (work tracked as item #147/#148 in the item tracker), previously sitting unmerged and PR-less on feat/agentflare-store-v1, 45 commits behind master. Rebased onto current master, verified clean.

Modules:

  • kv — get/set/delete/exists/scan-by-prefix
  • documents — CRUD + FTS5 search + vector search (cosine sim) + hybrid fusion (alpha-weighted FTS/vector)
  • blobs — BLAKE3 content-addressed, chunked storage, ref-count GC
  • embed — cosine_similarity, normalize
  • embedding_pipeline — tokenizer (BPE + WordPiece dispatch by model.type), model download with SHA-256 verification (re-verifies already-present files, self-heals on corruption), pooling, model registry
  • leases — wrapper around db_kit::ClaimLedger
  • migrate/migrations — state.json→kv one-shot migration + SQLite schema

This closes the gap I flagged (and then corrected myself on, after re-verifying with lean-ctx's code-intelligence tools) in issues #148/#149 — those issues asked whether embeddings/hybrid-search existed; the engine now lands here. Not in scope for this PR: wiring this into src/memory's actual remember/recall MCP tools — that integration doesn't exist yet and is separate follow-up work (noted on #148/#149).

Also resolves two known bugs already fixed on this branch (items #152, #153 in the tracker):

  • Tokenizer now dispatches by model.type (WordPiece vs BPE) instead of assuming WordPiece for all custom models
  • Model download re-verifies size+SHA-256 of already-present files, not just freshly-downloaded ones

Item #155 ("crate is not cargo fmt-clean") was flagged as an open blocker but turned out to already be resolved on this branch's tip (cargo fmt --check passes clean) — no action needed there.

Test plan

  • cargo build --workspace clean
  • cargo test -p agentflare-store — 31/31 pass
  • cargo test --workspace — 609+ tests, 0 failed, 0 regressions from the rebase
  • cargo clippy -p agentflare-store --all-targets --all-features -- -D warnings clean
  • cargo fmt --check clean
  • Rebase conflicts (Cargo.lock only, both times) resolved by regenerating via cargo check rather than hand-merging the lockfile

Summary by CodeRabbit

  • New Features
    • Added a local SQLite-backed storage layer with content blobs (deduplicated), documents (including version history), key/value data, leases, and searchable documents (full-text, vector, and hybrid search).
    • Added embedding generation with model artifact download, verification, and feature-gated embedding pipeline support.
  • Bug Fixes
    • Automatically migrates legacy local state to the new store and avoids re-migrating on subsequent runs.
    • Improved model and backup fallback behavior when environment values are unset/blank, including legacy backup detection.
  • Documentation
    • Updated Flare skill names/commands and branding text.

getappz added 11 commits July 18, 2026 10:59
…r), blobs, leases

Imports the agentflare-store implementation for item #147, previously left as
uncommitted working-tree state with zero git history. Store skeleton, kv,
documents CRUD/FTS5/vector search/hybrid fusion, blob storage, and a leases
re-export of db_kit::claim. Wires the crate into the workspace members list.

Applies three plan-mandated fixes during import: drop deps unused anywhere in
the crate (agentflare-artifacts, sha2, hex, uuid, chrono, mime_guess), use
BLAKE3 instead of SHA-256 for blob hashing per the plan's global constraints,
and a clippy nit in the hybrid-search chain (redundant into_iter()).

Verified: cargo build --workspace --all-features, cargo clippy -p
agentflare-store -- -D warnings, cargo test --workspace (27/27 in this crate,
full workspace suite green).

Known gaps vs the 8-task plan, tracked as follow-up work:
- embeddings module is a 50-line stub (cosine_similarity/normalize only) -
  Task 5's vendoring of lean-ctx's model/tokenizer/download pipeline never
  happened, so doc_vec_search/doc_hybrid_search are untestable end-to-end
- blob storage chunks bytes into SQLite rather than content-addressed files
  on disk under a blobs dir, as the plan specified
- documents schema is missing title/doc_type/blob_hash/mime/tags/session_id/
  source/version/history and has no versioning API
- Store holds a bare rusqlite::Connection (not parking_lot::Mutex-wrapped),
  so it isn't Sync and can't be shared across threads as the plan's Arc<Store>
  design requires
- Task 8 (migrate state.json onto this crate's kv store) hasn't been started;
  src/state.rs is untouched and agentflare-store isn't yet a dependency of
  the main package
…b_hash/mime in history, fix broken embedding dimension probe

- doc_upsert_with_opts issued ~8 unwrapped statements against a WAL-mode,
  multi-process-shared SQLite file; wrap the whole upsert in a transaction
  so concurrent readers/crashes can't observe a half-written document.
- store_doc_history never captured blob_hash/mime, so doc_history()/
  doc_get_version() always returned blank metadata for old versions; capture
  and store them, add a regression test.
- doc_vec_search silently swallowed row-decode errors via filter_map(Result::ok),
  making a real DB error look like zero matches; propagate them instead.
- detect_dimensions() passed a remote https:// model URL into ort's
  commit_from_file (which expects a local path), so EmbeddingEngine::load()
  always failed when the embeddings feature was used; pass the local model
  path that load_model() already resolves.
- removed dead .meta sidecar file writes/deletes in blobs.rs (never read),
  a duplicate is_bert_punctuation() in embedding_pipeline/mod.rs, a
  no-op if/else in embed() with identical branches, and two warnings
  (unused import, unused mut).
- embedding_pipeline::pooling::normalize_l2/l2_norm duplicated
  embed::normalize with a looser epsilon (f32::EPSILON vs 1e-12) and
  l2_norm had zero callers. Removed both; embed::normalize is now the
  single L2-normalize implementation, used by embed() and embed_query().
- cargo fmt across the crate (documents.rs, mod.rs, model_registry.rs,
  pooling.rs, kv.rs -- download.rs/tokenizer.rs left as-is, in-flight
  elsewhere).
- clippy -D warnings clean: dead model_id field (added a model_id()
  accessor alongside the existing dimensions() getter), a manual index
  loop over sum flagged by clippy::needless_range_loop, and a
  let-and-return in model_directory().
…sk 8)

src/store.rs::open() previously cached the store behind a OnceLock -- dead
code (nothing called it) and would have broken test isolation the moment
something did, since AGENTFLARE_HOME_OVERRIDE changes per-test but a
cached singleton would keep pointing at whichever home dir opened it
first. Open fresh per call instead, matching memory::store::open()'s
existing pattern in this codebase.

state::load()/save() now read/write through agentflare-store's kv table
under the active/version_cache keys, with a one-time import of any
legacy state.json via agentflare_store::migrate::migrate_state_json on
first load against a store that has neither key yet. Public API
unchanged (State, load(), save(), state_path()), so no callers change.
… store.db

store_path() picked ~/.agentflare/agentflare.db -- the same file src/db.rs
already owns as its single source-of-truth relational store (claims,
handoffs, review_findings, gateway_secrets), with its own separate
migration list. Two independent migration systems targeting one file is
a real hazard, not just an aesthetic collision. agentflare-store is a
different kind of storage (blobs, FTS+vector docs, kv) so a separate
file is correct -- it just needed a name that doesn't collide.
@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 824c9be5-8706-46c1-83b4-f220f34f6e61

📥 Commits

Reviewing files that changed from the base of the PR and between fd4e92c and 2f0ab6f.

📒 Files selected for processing (1)
  • crates/flare-output/src/compress.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/flare-output/src/compress.rs

📝 Walkthrough

Walkthrough

Changes

The pull request adds a SQLite-backed agentflare-store crate with storage primitives, document search, migrations, and an optional embedding pipeline. Application state moves to store-backed persistence with one-time legacy JSON migration. Flare naming, prompts, backup paths, model selection, and ignore rules are updated.

Storage platform and state migration

Layer / File(s) Summary
Store foundation and schema
Cargo.toml, crates/agentflare-store/Cargo.toml, crates/agentflare-store/src/{lib.rs,migrations.rs}
Registers the crate, defines Store and errors, and creates the SQLite storage schema.
Storage primitives
crates/agentflare-store/src/{kv.rs,leases.rs,blobs.rs}
Adds key-value operations, lease lifecycle wrappers, and content-addressed blob storage with deduplication and reference counting.
Document versioning and retrieval
crates/agentflare-store/src/{documents.rs,embed.rs}
Adds document versioning, FTS search, embedding persistence, vector search, hybrid ranking, and cosine validation.
Embedding model pipeline
crates/agentflare-store/src/embedding_pipeline/*
Adds model resolution, verified downloads, tokenization, ONNX inference, pooling, normalization, and tests.
Application state migration
src/{main.rs,store.rs,state.rs}, crates/agentflare-store/src/migrate.rs
Wires store-backed state persistence and one-time migration from legacy JSON state.

Flare naming and local paths

Layer / File(s) Summary
Local artifact rules
.gitignore
Adds ignore rules for skills and transient machine-local paths.
Flare skill and output naming
crates/flare-code/src/*, crates/flare-output/src/*
Updates skill names, commands, prompt terminology, backup paths, compression-plugin expectations, and model environment-variable precedence.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant State
  participant LegacyJSON
  participant Store
  State->>Store: open store.db
  State->>Store: check migration marker
  State->>LegacyJSON: read legacy state.json
  LegacyJSON-->>State: JSON values
  State->>Store: write migrated key-value entries
  Store-->>State: persisted application state
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 59.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: a new agentflare-store crate with KV, documents, blobs, and leases.
Description check ✅ Passed The description is mostly complete: it has a detailed Summary, test plan, and reviewer notes, with only the exact template formatting missing.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/agentflare-store-v1

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 17

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/agentflare-store/src/blobs.rs`:
- Around line 68-85: Make the blob lifecycle operations failure-atomic across
the write path and the unref path: update the visible blob insertion logic and
the corresponding unref implementation around metadata deletion to use a
database transaction, avoid the separate existence-check race, and compensate by
removing disk payloads when metadata insertion or transaction commit fails.
Ensure payload cleanup failures are preserved for retry, such as through a
persistent GC tombstone, so neither orphaned data nor prematurely removed
metadata remains.
- Around line 20-22: Update read_disk_blob to return an I/O result rather than
Option, removing the .ok() conversion so std::fs::read preserves permission and
other failures. Propagate this Result through the related blob-loading code
covering the alternate path, while retaining “not found” handling only for an
actually missing blob.

In `@crates/agentflare-store/src/documents.rs`:
- Around line 213-223: Update doc_upsert_with_opts so the store_documents insert
and subsequent doc_sync_fts call execute within one SQLite transaction. Commit
only after both operations succeed, and ensure any doc_sync_fts failure rolls
back the document insert before returning the error.
- Around line 281-295: Update doc_hard_delete to perform all dependent cleanup
atomically in one transaction: delete matching rows from store_doc_history and
store_doc_vectors, remove the FTS row using the document rowid, then delete the
parent store_documents row. Preserve the existing boolean result and ensure the
transaction rolls back on any failure.
- Around line 602-633: Update the vec_search_ranks_by_similarity test to use
non-collinear embeddings for d1, d2, and d3, and choose a query whose cosine
similarities produce the expected d1-before-d2-before-d3 ordering. Keep the
ranking assertions intact while replacing the test_embed calls that currently
use uniform vectors.
- Around line 111-138: The document write flow should begin an immediate write
transaction before querying the existing row, so version reads and subsequent
updates are serialized; update the transaction usage around the existing lookup
and write logic in the document store method. Also add schema uniqueness
constraints for (project_id, path) and (doc_id, version), preserving the current
history and versioning behavior.

In `@crates/agentflare-store/src/embed.rs`:
- Around line 1-6: Update cosine_similarity to validate that input slices have
equal lengths before calculating dot products or norms, returning an error or
None for mismatches instead of silently truncating via zip. Propagate the
changed return type through callers and add test coverage confirming unequal
dimensions are rejected.

In `@crates/agentflare-store/src/embedding_pipeline/download.rs`:
- Around line 174-200: Update read_lockfile to return a Result and propagate
missing, unreadable, or malformed lockfile errors instead of defaulting to an
empty map. In file_passes_verification, require every required file to have a
matching lock pin and reject unpinned files so ensure_model triggers a fresh
download; add tests covering missing and malformed lockfiles.
- Around line 31-38: Handle the result of std::fs::remove_file in the
verification flow instead of ignoring it: propagate the deletion error so
download setup aborts when a corrupt artifact cannot be removed. Ensure the
existing any_corrupt path only continues when the failed file was successfully
deleted, preventing later readiness logic from accepting the mismatched
artifact.

In `@crates/agentflare-store/src/embedding_pipeline/mod.rs`:
- Around line 58-92: Update load_model and detect_dimensions to resolve ONNX
input and output bindings by tensor names and expected shapes rather than
positional indices. Explicitly locate input_ids, attention_mask, and optional
token_type_ids, validate required bindings, and select the embedding output by
its expected shape instead of session.outputs().first(). Preserve the existing
error behavior by returning clear failures when required bindings or a valid
embedding output are absent.

In `@crates/agentflare-store/src/embedding_pipeline/model_registry.rs`:
- Around line 43-62: Update ModelRegistry::storage_slug to append a stable
digest derived from the complete repository and revision values, rather than
relying only on sanitized text and the truncated revision. Keep the slug
filesystem-safe and ensure distinct repository/revision specifications produce
distinct cache directory names, including revisions longer than 16 characters.
- Around line 211-214: Update resolve_model so the default model is used only
when AGENTFLARE_EMBEDDING_MODEL is absent; when the variable is present,
validate its value with EmbeddingModel::from_str_name and propagate an error
containing the invalid model name instead of falling back to
EmbeddingModel::DEFAULT.

In `@crates/agentflare-store/src/embedding_pipeline/tokenizer.rs`:
- Around line 143-173: Update wordpiece_encode so any failed WordPiece
segmentation returns exactly one unk_id for the entire word, discarding
previously matched subword tokens. Keep successful complete segmentation
unchanged, but when matched is false return immediately with a single unknown
token instead of advancing start and continuing.
- Around line 83-106: The HfTokenizerWrapper implementation must not silently
emulate only a narrow tokenizer subset. Update the wrapper’s tokenizer
construction and encoding flow to use the Hugging Face tokenizer pipeline,
including normalizer, pre_tokenizer, added_tokens, and post_processor, so
tokenizer.json behavior and token IDs round-trip faithfully; alternatively,
explicitly reject unsupported configurations and add parity tests covering the
supported subset.

In `@crates/agentflare-store/src/migrate.rs`:
- Around line 27-34: Update migrate_state_json to persist all legacy entries and
MIGRATION_MARKER through one atomic transaction or batch write, so partial
imports cannot become visible when any write fails. Preserve the existing marker
semantics and add a test that injects a mid-migration failure, verifies no
migrated keys or marker remain, and confirms a later load can retry the import.

In `@crates/flare-output/src/compress.rs`:
- Line 147: Preserve backward compatibility in the backup namespace path around
the "flare-output" join by retaining a fallback lookup for the legacy "caveman"
namespace. Ensure BackupExists checks both namespaces so existing out-of-tree
backups still prevent creating a new backup; add migration or tests and
documentation only if intentionally removing the fallback.

In `@crates/flare-output/src/llm.rs`:
- Around line 29-31: Update the model environment-variable resolution around
FLARE_OUTPUT_MODEL and CAVEMAN_MODEL to treat blank values as unset before
applying precedence. Preserve the order of FLARE_OUTPUT_MODEL, then
CAVEMAN_MODEL, then the "claude-sonnet-4-5" default, while ensuring empty values
cannot be selected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9339df4e-f592-4b6a-b88f-f7fff0350a27

📥 Commits

Reviewing files that changed from the base of the PR and between 8d9692f and 6822d07.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (28)
  • .gitignore
  • Cargo.toml
  • crates/agentflare-store/Cargo.toml
  • crates/agentflare-store/src/blobs.rs
  • crates/agentflare-store/src/documents.rs
  • crates/agentflare-store/src/embed.rs
  • crates/agentflare-store/src/embedding_pipeline/download.rs
  • crates/agentflare-store/src/embedding_pipeline/mod.rs
  • crates/agentflare-store/src/embedding_pipeline/model_registry.rs
  • crates/agentflare-store/src/embedding_pipeline/pooling.rs
  • crates/agentflare-store/src/embedding_pipeline/tokenizer.rs
  • crates/agentflare-store/src/kv.rs
  • crates/agentflare-store/src/leases.rs
  • crates/agentflare-store/src/lib.rs
  • crates/agentflare-store/src/migrate.rs
  • crates/agentflare-store/src/migrations.rs
  • crates/flare-code/src/config.rs
  • crates/flare-code/src/instructions.rs
  • crates/flare-code/src/skill-no-hallucination.md
  • crates/flare-code/src/skill-playbook.md
  • crates/flare-code/src/skill-review.md
  • crates/flare-code/src/skill.md
  • crates/flare-output/src/compress.rs
  • crates/flare-output/src/llm.rs
  • crates/flare-output/src/prompt.rs
  • src/main.rs
  • src/state.rs
  • src/store.rs

Comment thread crates/agentflare-store/src/blobs.rs Outdated
Comment thread crates/agentflare-store/src/blobs.rs Outdated
Comment thread crates/agentflare-store/src/documents.rs Outdated
Comment thread crates/agentflare-store/src/documents.rs Outdated
Comment thread crates/agentflare-store/src/documents.rs Outdated
Comment on lines +83 to +106
fn pre_tokenize(&self, text: &str) -> Vec<String> {
let mut words = Vec::new();
let mut current = String::new();

for ch in text.chars() {
if ch.is_whitespace() {
if !current.is_empty() {
words.extend(self.split_identifier(&current));
current.clear();
}
} else if is_bert_punctuation(ch) {
if !current.is_empty() {
words.extend(self.split_identifier(&current));
current.clear();
}
words.push(ch.to_string());
} else {
current.push(ch);
}
}
if !current.is_empty() {
words.extend(self.split_identifier(&current));
}
words.iter().map(|w| w.to_lowercase()).collect()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🌐 Web query:

Using official Hugging Face Tokenizers documentation, which tokenizer.json sections define normalization, pre-tokenization, added special tokens, and post-processing, and can model.vocab/model.merges alone reproduce BPE tokenization?

💡 Result:

In the Hugging Face Tokenizers library, the tokenizer.json file acts as a serialized representation of the entire tokenization pipeline [1][2]. The following top-level sections of the JSON structure define the corresponding components: 1. Normalization: The normalizer section [1][3]. 2. Pre-tokenization: The pre_tokenizer section [1][3]. 3. Added special tokens: The added_tokens section [4][5]. 4. Post-processing: The post_processor section [1][3][5]. Regarding the BPE algorithm, model.vocab and model.merges alone cannot reproduce full BPE tokenization [1][6]. While the BPE model itself relies on these two components to map sequences to subword IDs [7][8], the complete tokenization pipeline requires additional steps defined in the tokenizer.json file [1][6]. Specifically, a functional tokenizer requires a pre-tokenizer to split text into word-level units before BPE can be applied, as well as a normalizer to handle input text transformations (e.g., Unicode normalization or lowercasing) [1][6]. Without these components, the BPE model would receive raw, unprocessed input, leading to inconsistent or incorrect tokenization results compared to the original pipeline [6]. Sources: [1] https://huggingface.co/docs/tokenizers/main/en/api/tokenizer [4] huggingface/tokenizers#1410 [3] https://huggingface.co/docs/tokenizers/en/api/tokenizer [5] https://github.com/huggingface/transformers/blob/v4.52.3/src/transformers/tokenization_utils_fast.py [6] https://huggingface.co/docs/tokenizers/python/latest/components.html [7] https://huggingface.co/docs/tokenizers/main/en/api/models [2] huggingface/tokenizers#521 [8] https://github.com/huggingface/transformers/blob/main/docs/source/en/custom_tokenizers.md

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the tokenizer implementation and related pipeline code.
git ls-files | grep -E '^crates/agentflare-store/src/embedding_pipeline/.*tokenizer\.rs$|^crates/agentflare-store/src/embedding_pipeline/'

# Show the relevant section with line numbers.
sed -n '1,240p' crates/agentflare-store/src/embedding_pipeline/tokenizer.rs

Repository: getappz/agentflare

Length of output: 7936


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect any references to tokenizer.json or HF tokenizer behavior in the crate.
grep -RIn --exclude-dir=.git --exclude='*.lock' --exclude='*.png' \
  -E 'tokenizer\.json|pre_tokenize|post_processor|added_tokens|normalizer|BPE|huggingface|tokenizers' \
  crates/agentflare-store/src || true

Repository: getappz/agentflare

Length of output: 2529


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check for the tokenizer pipeline construction and what config fields are consumed.
sed -n '1,220p' crates/agentflare-store/src/embedding_pipeline/mod.rs
sed -n '1,240p' crates/agentflare-store/src/embedding_pipeline/*.rs 2>/dev/null | sed -n '1,240p'

Repository: getappz/agentflare

Length of output: 15245


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Narrow read of the tokenizer file around the cited lines and related helpers.
nl -ba crates/agentflare-store/src/embedding_pipeline/tokenizer.rs | sed -n '1,420p'

Repository: getappz/agentflare

Length of output: 196


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the tokenizer implementation with line numbers.
if [ -f crates/agentflare-store/src/embedding_pipeline/tokenizer.rs ]; then
  nl -ba crates/agentflare-store/src/embedding_pipeline/tokenizer.rs | sed -n '1,420p'
fi

Repository: getappz/agentflare

Length of output: 196


🌐 Web query:

Official Hugging Face tokenizers docs: does tokenizer.json include normalizer, pre_tokenizer, added_tokens, and post_processor sections, and is a BPE model described by vocab and merges only?

💡 Result:

Yes, the official Hugging Face tokenizer.json file is a self-contained serialization of the entire tokenizer pipeline [1]. It includes sections for the normalizer, pre_tokenizer, model, post_processor, and added_tokens [2][1]. Specifically, the structure typically reflects the Tokenizer pipeline, which consists of the following components [3][4]: 1. Normalizer: Processes and normalizes raw input text [3][5]. 2. PreTokenizer: Splits text into word-level tokens [3][5]. 3. Model: Maps tokens to IDs using the specified algorithm (e.g., BPE) [3][5]. 4. PostProcessor: Performs final transformations, such as adding special tokens like [CLS] or [SEP] [3][5][1]. Regarding the BPE (Byte-Pair Encoding) model, it is described within the model section of the tokenizer.json file [1]. While the model's core logic is defined by its vocabulary (mapping tokens to IDs) and merge rules (how to combine tokens) [6][7], the model entry in tokenizer.json may contain additional parameters—such as unk_token, dropout, byte_fallback, and other configuration settings—depending on how the model was initialized and saved [8][9]. Therefore, while vocab and merges are the fundamental components of a BPE model, the serialized model section often includes these extra configuration parameters as well [8].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the tokenizer loader and wrapper implementation around the relevant lines.
sed -n '300,520p' crates/agentflare-store/src/embedding_pipeline/tokenizer.rs

Repository: getappz/agentflare

Length of output: 5891


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the tokenizer tests and any tokenizer.json fixtures for supported/unsupported fields.
sed -n '520,760p' crates/agentflare-store/src/embedding_pipeline/tokenizer.rs

Repository: getappz/agentflare

Length of output: 156


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the loader and tests around the tokenizer wrapper implementation.
sed -n '300,760p' crates/agentflare-store/src/embedding_pipeline/tokenizer.rs

Repository: getappz/agentflare

Length of output: 5891


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p = Path('crates/agentflare-store/src/embedding_pipeline/tokenizer.rs')
lines = p.read_text().splitlines()
for start, end in [(300, 520), (520, 760)]:
    print(f"\n--- {start}-{end} ---")
    for i in range(start-1, min(end, len(lines))):
        print(f"{i+1}: {lines[i]}")
PY

Repository: getappz/agentflare

Length of output: 6915


HfTokenizerWrapper only rebuilds a narrow WordPiece/BPE subset. It ignores normalizer, pre_tokenizer, added_tokens, and post_processor, so saved tokenizer.json pipelines won’t round-trip faithfully and can yield different token IDs. Use the Hugging Face tokenizer directly, or reject configs outside a documented subset and add parity tests.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/agentflare-store/src/embedding_pipeline/tokenizer.rs` around lines 83
- 106, The HfTokenizerWrapper implementation must not silently emulate only a
narrow tokenizer subset. Update the wrapper’s tokenizer construction and
encoding flow to use the Hugging Face tokenizer pipeline, including normalizer,
pre_tokenizer, added_tokens, and post_processor, so tokenizer.json behavior and
token IDs round-trip faithfully; alternatively, explicitly reject unsupported
configurations and add parity tests covering the supported subset.

Comment thread crates/agentflare-store/src/embedding_pipeline/tokenizer.rs
Comment thread crates/agentflare-store/src/migrate.rs Outdated
Comment thread crates/flare-output/src/compress.rs Outdated
Comment thread crates/flare-output/src/llm.rs Outdated
getappz added 4 commits July 18, 2026 12:28
- blob_store/blob_unref: wrap the exists-check + insert/decrement + cascade
  in an Immediate transaction so concurrent connections can't race on the
  same hash; compensate for orphaned disk writes on failure.
- doc_upsert_with_opts: open the transaction before reading the current
  version so concurrent upserts can't both read version N and both write
  N+1; also makes new-document insert + FTS sync atomic.
- doc_hard_delete: delete history/vector/FTS rows before the parent row,
  all in one transaction.
- migrate_state_json: one transaction for every key plus the completion
  marker, so a partial failure can't desync the marker from what migrated.
…them

- cosine_similarity: return None on mismatched vector lengths instead of
  letting zip() silently drop the excess coordinates.
- blob_get: propagate disk read I/O errors (permissions, disk failure)
  instead of folding them into 'blob not found'.
- read_lockfile: distinguish a missing lockfile (fine, first run) from an
  unreadable or malformed one (error) instead of treating both as 'no
  pins', which made every present file look unverified and skip the
  tamper check.
- ensure_model: abort if a corrupt model file can't be deleted, instead
  of proceeding while the corrupt file is still on disk.
- resolve_model: error on an invalid AGENTFLARE_EMBEDDING_MODEL instead
  of silently falling back to the default model.
…X I/O, correct WordPiece fallback

- CustomModelSpec::storage_slug: hash repo+revision into the cache dir
  name instead of truncating the revision to 16 chars, which let two
  different (repo, revision) pairs collide on the same cache directory.
- EmbeddingEngine::load_model: resolve ONNX input/output tensors by
  declared name (with a positional fallback for the two inputs every
  model has) instead of blind index 0/1/2, which breaks if a model
  export ever reorders its inputs/outputs.
- wordpiece_encode: an unsegmentable word now collapses to a single
  [UNK], matching standard WordPiece, instead of one UNK per unmatched
  character interleaved with whatever subwords did match.
- vec_search_ranks_by_similarity test: use directionally distinct
  embeddings; the old ones were collinear and scored identically
  regardless of magnitude, so the test wasn't exercising rank order.
…me backups discoverable

- call_via_api: a blank FLARE_OUTPUT_MODEL/CAVEMAN_MODEL value no longer
  wins over the next fallback in the chain.
- backup_path_for (OutOfTree): the backup namespace directory was renamed
  from 'caveman' to 'flare-output' with a hard rename and no fallback, so
  a user's pre-rename backups became invisible to both the 'backup
  already exists' guard and Report::original_path. Now resolves to an
  existing legacy path if the new one doesn't have one yet.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/flare-output/src/compress.rs`:
- Around line 360-364: Update the legacy path construction around the `legacy`
variable to avoid global string replacement. Derive the base path with
`out_of_tree_backup_dir("caveman")`, preserve the relative suffix from
`resolved`, and join them so only the namespace component changes while
unrelated parent-directory names remain intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7a9484bb-1800-49b0-b6ac-6ee6c2ea3b1e

📥 Commits

Reviewing files that changed from the base of the PR and between 6822d07 and fd4e92c.

📒 Files selected for processing (10)
  • crates/agentflare-store/src/blobs.rs
  • crates/agentflare-store/src/documents.rs
  • crates/agentflare-store/src/embed.rs
  • crates/agentflare-store/src/embedding_pipeline/download.rs
  • crates/agentflare-store/src/embedding_pipeline/mod.rs
  • crates/agentflare-store/src/embedding_pipeline/model_registry.rs
  • crates/agentflare-store/src/embedding_pipeline/tokenizer.rs
  • crates/agentflare-store/src/migrate.rs
  • crates/flare-output/src/compress.rs
  • crates/flare-output/src/llm.rs
🚧 Files skipped from review as they are similar to previous changes (8)
  • crates/flare-output/src/llm.rs
  • crates/agentflare-store/src/migrate.rs
  • crates/agentflare-store/src/embedding_pipeline/model_registry.rs
  • crates/agentflare-store/src/embedding_pipeline/tokenizer.rs
  • crates/agentflare-store/src/embedding_pipeline/download.rs
  • crates/agentflare-store/src/blobs.rs
  • crates/agentflare-store/src/embedding_pipeline/mod.rs
  • crates/agentflare-store/src/documents.rs

Comment thread crates/flare-output/src/compress.rs Outdated
@getappz
getappz enabled auto-merge (squash) July 18, 2026 08:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant