fix: the .env search ends at the cwd tree; a local client with a blank chat_model refuses at the chat door; storage_path is typed PathLike - #428
Merged
Conversation
… a blank chat_model refuses at the chat door; storage_path is typed PathLike find_dotenv(usecwd=True) returns '' when nothing is reachable from the cwd, and `or None` turned that into load_dotenv's own upward walk from utils.py — the install-dir leak the cwd search was added to replace. A pip-installed SDK could load another project's .env from above site-packages, silently. _local_chat treats a blank chat_model as "managed chat", which a client without an api_key does not have: chat_completions() then reached for LocalAPI.chat_completions and raised a bare AttributeError. The managed branch now refuses as a PageIndexAPIError naming chat_model. py.typed made the annotations authoritative while storage_path was typed str; _ARG_TYPES accepts os.PathLike, so Path(...) ran fine and failed the user's type check. Both signatures and LocalIndexConfig now say so. Claude-Session: https://claude.ai/code/session_017Fd7jVm366S2Xamzhxv6yb
… two docstrings stop overclaiming The slots were annotated dict[str, Any]. A TypedDict is consistent with Mapping[str, object], never with dict (PEP 589: a dict-typed receiver could write arbitrary keys through it), so the four shapes types.py exports — and py.typed advertises to installed callers' checkers — could not be passed to the one place they describe. pyright on a probe that does exactly that: 9 errors before, 0 after. The constructor only reads the slot (items(), then a fresh conf dict), so Mapping is the honest bound; a plain dict is a Mapping, and TypedDict instances are plain dicts at runtime, so nothing moves at runtime. The _ARG_TYPES comment said "every value" is shape-checked; api_key is not in the table (its empty check is separate, its type check stays unchecked by ruling), so the comment now speaks for the table only. _local_doc_scope and _require_local_scope still explained the cloud drop as "scoping is server-side" — true of the managed chat, which never reaches either function. What reaches them on a cloud client is own-model chat and the config helpers, whose cloud tools take no allowlist: targeting there is prompt-level only, as the error message between them already said. 434 passed; pyright on pageindex/ unchanged at 235 (0 in the touched files, before and after). Claude-Session: https://claude.ai/code/session_01TxG8u8x29XRnK4yscZVCch
rejojer
added a commit
that referenced
this pull request
Aug 26, 2026
Two post-0.2.11 follow-up squashes (b9a9a3b, 174f95f) land on the review branch the same way f6fa99b did: main's tree recorded as merged, history kept, so PR #400 keeps spanning 0.2.9 → current main. Claude-Session: https://claude.ai/code/session_01VQ6mruXZBgw9Hjii8KPbQP
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 follow-ups to #424, on the shipped v0.2.11.
.envsearch ends at the cwd tree.find_dotenv(usecwd=True)returns''when nothing is reachable from the cwd, andor Noneturned that intoload_dotenv's own upward walk fromutils.py— the install-dir search the cwd search was added to replace. A pip-installed SDK could silently load another project's.envfrom above site-packages. Test plants a.envabove a symlinked package and runs from a tree that has none.A local client with a blank
chat_modelrefuses at the chat door._local_chatreads blank as "managed chat", which a client without anapi_keydoes not have:chat_completions()reached forLocalAPI.chat_completionsand raised a bareAttributeError. The managed branch now raises aPageIndexAPIErrornamingchat_model.storage_pathis typedstr | os.PathLike[str]._ARG_TYPESacceptsos.PathLike, soPath(...)ran fine, andpy.typedmade theOptional[str]annotation authoritative for callers' type checkers. Both signatures andLocalIndexConfignow agree with the runtime check.Also on the branch:
index=/chat=typedMapping[str, Any]so the exported config shapes pass, plus a comment and two docstrings that stop overclaiming.434 tests (432 + 2, both red on main). A review view of #424 + these follow-ups together is open against
pre-424-main.https://claude.ai/code/session_017Fd7jVm366S2Xamzhxv6yb