feat(api): auto-fetch Bonsai GGUF + GraphStore.ask/write surface#195
Merged
Conversation
Three small wins so `pip install graphstore[pro]` is the only command users
need to run, and so the agent-app surface (NL question -> answer, NL turn
-> ingest) doesn't require knowing the DSL.
- BonsaiIngestor: model_path now optional. When omitted, resolves via the
new graphstore._models.resolve_bonsai_gguf helper which scans the HF
cache and (by default) auto-downloads on miss. New optional `quant=`
kwarg, defaulting to $GRAPHSTORE_BONSAI_QUANT or "TQ1_0".
- store._locate_bonsai_gguf: was a duplicated scan_cache_dir block, now
delegates to the same helper. Single source of truth shared by the
ingestor and the calibration probe so the three call sites can never
drift on repo/filename.
- GraphStore.ask(question, *, limit=None, using=None) -> Result: thin
wrapper over the existing ANSWER DSL verb with proper string escaping.
Returns kind="answer". Requires a reader= callable.
- GraphStore.write(text, *, msg_id, session_id="default", role="user",
dry_run=False): NL turn -> DSL via a configured ingestor. Constructor
accepts `ingestor=<callable>` factory invoked lazily on first call so
the ingestor receives a fully-initialised GraphStore. Without a
factory, write() raises with a copy-pasteable example.
- README: the question example with dry_run=True was misleading because
preview mode never invokes the reader. Replaced with two lines (one
preview, one real) plus a one-liner note explaining the difference.
Verified end-to-end in container against the running playground:
ask path returns Result(kind="answer", data={answer, cited_slots, ...});
no-reader / empty-question / no-ingestor guards raise the right errors;
quoted-string escaping survives DSL parsing.
6 tasks
KailasMahavarkar
added a commit
that referenced
this pull request
May 7, 2026
…rite (#196) Two follow-ups to #195: - ANSWER's reader callable was previously unbounded - a hung local LLM would lock the executor thread indefinitely. Wrap the call in a daemon thread with `worker.join(timeout=N)`. On timeout the call returns with data["answer"] == "", data["error"] describing the timeout, and a meta["warnings"] entry; a warning is logged so the leak is visible. Threshold is configurable via `GraphStore(reader_timeout_seconds=...)`, default 60s. Constructor rejects non-positive values up-front. Trade-off: Python cannot cancel a running thread, so a genuinely stuck reader leaks one daemon per call. Acceptable - daemons don't block process exit, and demanding cancellable readers is too much to require from callers. - README: Replaced no docs for `g.ask` / `g.write` (added in #195) with a small section showing the chat-app shape: ingestor= factory for NL writes, reader= for synthesis, the new reader_timeout_seconds knob, and a pointer to dry-run for question-shape routing through Bonsai. Verified end-to-end in container: fast reader returns cleanly; slow reader (5s) is bounded at 0.3s with proper error + warning surfaced; exception readers are caught; reader_timeout_seconds=0 raises ValueError at construction.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three small wins so
pip install graphstore[pro]is the only command users need to run, and so the agent-app surface (NL question -> answer, NL turn -> ingest) doesn't require knowing the DSL.BonsaiIngestor: model_path now optional. When omitted, resolves via the new graphstore._models.resolve_bonsai_gguf helper which scans the HF cache and (by default) auto-downloads on miss. New optional
quant=kwarg, defaulting to $GRAPHSTORE_BONSAI_QUANT or "TQ1_0".store._locate_bonsai_gguf: was a duplicated scan_cache_dir block, now delegates to the same helper. Single source of truth shared by the ingestor and the calibration probe so the three call sites can never drift on repo/filename.
GraphStore.ask(question, *, limit=None, using=None) -> Result: thin wrapper over the existing ANSWER DSL verb with proper string escaping. Returns kind="answer". Requires a reader= callable.
GraphStore.write(text, *, msg_id, session_id="default", role="user", dry_run=False): NL turn -> DSL via a configured ingestor. Constructor accepts
ingestor=<callable>factory invoked lazily on first call so the ingestor receives a fully-initialised GraphStore. Without a factory, write() raises with a copy-pasteable example.README: the question example with dry_run=True was misleading because preview mode never invokes the reader. Replaced with two lines (one preview, one real) plus a one-liner note explaining the difference.
Verified end-to-end in container against the running playground: ask path returns Result(kind="answer", data={answer, cited_slots, ...}); no-reader / empty-question / no-ingestor guards raise the right errors; quoted-string escaping survives DSL parsing.