fix: the exported config shapes pass into index=/chat=; a comment and 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
This commit is contained in:
Ray
2026-08-26 14:36:25 +08:00
parent 5e2dc9bc56
commit 4e9c56c6c8
2 changed files with 13 additions and 12 deletions
+2 -2
View File
@@ -1486,8 +1486,8 @@ def _require_doc_selection(doc_ids) -> None:
def _require_local_scope(client, doc_ids) -> None:
"""The allowlist is enforced in-process; cloud lookups run server-side,
so accepting doc_ids there would be advisory-only — refuse loudly."""
"""The allowlist is enforced in-process; cloud tools take none, so
accepting doc_ids there would be advisory-only — refuse loudly."""
_require_doc_selection(doc_ids)
if doc_ids is not None and getattr(client, "api_key", None):
raise PageIndexAPIError(
+11 -10
View File
@@ -6,7 +6,7 @@ import re
import threading
import time
import warnings
from typing import Any, Callable, Iterator, Optional, Union, cast
from typing import Any, Callable, Iterator, Mapping, Optional, Union, cast
from .errors import PageIndexAPIError
@@ -78,7 +78,7 @@ def _env_cloud_key(spelling: str, inline: str = "api_key=...") -> str:
return key
# One argument vocabulary regardless of spelling: every value is shape-
# One argument vocabulary regardless of spelling: these values are shape-
# checked in the constructor, so a wrong type or an empty value refuses
# there as a PageIndexAPIError — never later, never silently.
_ARG_TYPES: "dict[str, tuple[type, ...]]" = {
@@ -338,8 +338,8 @@ class PageIndexClient:
self,
api_key: Optional[str] = None,
*,
index: Optional[Union[dict[str, Any], str]] = None,
chat: Optional[Union[dict[str, Any], str]] = None,
index: Optional[Union[Mapping[str, Any], str]] = None,
chat: Optional[Union[Mapping[str, Any], str]] = None,
mode: Optional[str] = None,
index_model: Optional[str] = None,
chat_model: Optional[str] = None,
@@ -1254,8 +1254,9 @@ class PageIndexClient:
def _local_doc_scope(self, doc_id):
"""doc_id for the tool layer: passed through locally (structural
allowlist), dropped on cloud where scoping is server-side and the
config helpers keep prompt-level targeting."""
allowlist), dropped on cloud — its tools take no allowlist, so
own-model chat and the config helpers target at the prompt level
only."""
from .agent_tools import _require_doc_selection
_require_doc_selection(doc_id)
if not getattr(self, "api_key", None):
@@ -1617,8 +1618,8 @@ class PageIndexCloudClient(PageIndexClient):
self,
api_key: Optional[str] = None,
*,
index: Optional[Union[dict[str, Any], str]] = None,
chat: Optional[Union[dict[str, Any], str]] = None,
index: Optional[Union[Mapping[str, Any], str]] = None,
chat: Optional[Union[Mapping[str, Any], str]] = None,
chat_model: Optional[str] = None,
retrieve_model: Optional[str] = None,
chat_backend: Optional[dict[str, Any]] = None,
@@ -1647,8 +1648,8 @@ class PageIndexLocalClient(PageIndexClient):
def __init__(
self,
*,
index: Optional[Union[dict[str, Any], str]] = None,
chat: Optional[Union[dict[str, Any], str]] = None,
index: Optional[Union[Mapping[str, Any], str]] = None,
chat: Optional[Union[Mapping[str, Any], str]] = None,
index_model: Optional[str] = None,
chat_model: Optional[str] = None,
model: Optional[str] = None,