Feat/truncate text and cross parent reads - #19
Merged
Conversation
…release 0.8.0 - FluxClient/AsyncFluxClient.search() accept a keyword-only `params` mapping, forwarded to the query string, so `truncate_text` (and any other query param) works on Search as it already did on list_resources(). - vector_search/vector_field_search/hybrid_search/boosted_search (sync and async) gain a `query_params` keyword forwarded the same way. Named `query_params` rather than `params` because `params` was already a meaningful **extra_body key (forwarded to the JSON body); an explicit `params` keyword would have silently rerouted an existing caller's body field to the query string. `_merge_extra` now raises if `truncate_text` is passed as a body field, naming `query_params` as the fix. - APIFolderSummary (APICollectionSummary) gains unscoped_levels, unscoped_ancestors, expose_owner, flat_route (new FlatRouteSummary model, undocumented) and flat_routes (new FlatRoute model per entry) to type the cross-parent (flat) read addressing already reachable via Flux's opaque folder-path strings. APIFolderSummary and both new models set extra="allow" so unrecognized fields are preserved, not dropped. - add_api_collection/update_api_collection and the deprecated add_api_folder/update_api_folder aliases (sync and async) accept unscoped_levels/unscoped_ancestors to configure the addresses. - Version bumped to 0.8.0 (additive). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…decisions docs/flux-client.md wrongly claimed FluxClient has no method that can target a flat address -- create_resource()/update_resource() accept the same opaque folder_path as the read methods and will happily interpolate a flat path; it is the server that rejects the write. Reworded to match the TS README. Also pins two "the server validates, not us" decisions with regression tests (sync + async): an out-of-range/non-integer truncate_text and a lone unscoped_levels or unscoped_ancestors must keep forwarding to the request unchanged, not raise, so client-side validation can't creep in unnoticed.
CI only runs 'ruff format --check src/', so tests/ has never been gated and had drifted. Formatting only; no behavioural change. 378 tests still pass.
CI linted src/ only, so tests/ drifted unchecked until it needed a repo-wide reformat. Both ruff commands now cover the repo. Two unused imports in tests/ are removed so the widened gate starts green. .githooks/pre-push runs the same checks locally. Opt in per clone with git config core.hooksPath .githooks It is skippable with --no-verify, so CI stays the real gate.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
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.
Types and plumbing for two Flux API features that shipped server-side: response truncation on reads, and cross-parent read addresses for strict-reference collections.
Flux
truncate_textis reachable fromsearch().FluxClient.search()/AsyncFluxClient.search()accept a keyword-onlyparamsmapping forwarded to the query string. The transport already supported query parameters; they were simply not plumbed throughsearch(). With the existing passthrough onlist_resources(), both List Resources and Search now support it.truncate_textis an integer ≥ 1 that caps everytext-typed field and is ignored whenraw=true. Truncated fields are marked under_sys.truncated(field,locale—nullfor non-localized — andoriginal_length); fields within the limit get no entry. No client-side validation: an invalid value surfaces as a server422 validation_error.query_paramson the four search wrappers —vector_search(),vector_field_search(),hybrid_search(),boosted_search(), sync and async. Namedquery_paramsrather thanparamsdeliberately:paramswas already meaningful inside**extra_body(forwarded to the JSON body), so an explicitparamskeyword would have silently rerouted it to the query string for any caller already passingparams={...}as a search-body field._merge_extranow raises if handedtruncate_textas a body field and namesquery_paramsas the right place for it.Management
Cross-parent (flat) read addressing for strict-reference collections.
add_api_collection/update_api_collection(and the deprecatedadd_api_folder/update_api_folder), sync and async, acceptunscoped_levels: list[int]andunscoped_ancestors: list[str]. These expose additional read-only addresses that drop the ancestor chain entirely (level == 0) or partially (level >= 1, keeping the root-most keys).The API requires both to be sent together. Not enforced client-side — the server owns that rule and may relax it.
Typed connection fields.
APIFolderSummary(aliasedAPICollectionSummary) gainsunscoped_levels,unscoped_ancestors,expose_owner— all defaulting to an empty/false value if the server omits them — plusflat_routeandflat_routes, both optional and nullable, sincenullwas observed on connections with no key-bearing ancestor. NewFlatRouteandFlatRouteSummarymodels.APIFolderSummaryand both new models setmodel_config = ConfigDict(extra="allow"), so unrecognised fields — present or future — are preserved rather than silently dropped.Not in scope: cross-parent writes.
FluxClienthas no create/update taking a folder path beyond the documented ones, and the server rejects writes on flat paths regardless. List, Get Resource and Schema already worked against these addresses, because the collection path is an opaque slash-trimmed string; this only adds typed support for the connection object and for configuring the addresses.Fixed
DEFAULT_USER_AGENTwas pinned tofoxnose-sdk/0.1.0regardless of the installed version — every request from every release reported0.1.0. The version now lives in a single_version.pyimported by bothfoxnose_sdk/__init__.py(sofoxnose_sdk.__version__keeps working) andconfig.py(so the User-Agent is real), which is what avoids the circular import that motivated the stale constant in the first place.Repo hygiene
ruff check ./ruff format --check .) instead ofsrc/only. Lintingsrc/alone lettests/drift until it needed a repo-wide reformat to get back in line — that reformat is thestyle:commit here..claude/is gitignored, as it already is in core, delivery-api, integration-tests and ts-sdk. Without it the repo-wide gate walks untracked tool directories and fails on code that is not in the repository.Review the formatting commit separately from the feature commits — it touches many files and changes nothing.
Known server-side discrepancies, typed as sent
Not worked around in the SDK, and raised with the API team:
flat_routes[].read_methodsreports["get_one", "get_many"]at level 0, though the docs describe Get Resource as available only atlevel >= 1.read_methodsnever includessearchat any level, though the docs list Search as available on flat addresses.read_methodsis typed as the server sends it rather than as documented.Tests
Full suite green;
ruff check .andruff format --check .clean.