Repository navigation
fix(sdk): TypeScript SDK request/response parity + missing /api prefix (#15528, #16495) - #16497
Conversation
…#15528, #16495) sessions.list sends scope/team_id, knowledge.search is a POST with a JSON body, analytics.usage/performance take no arguments, and several response types now match the flat documents or DataResponse envelopes the backend actually returns instead of invented shapes. agents.updateConfig is removed -- no PUT route for it exists on either mount -- and setModel/ setEnabled are added to match the Python SDK. Every request was also missing the /api prefix entirely (#16495), the same defect #15053 already found once in the Python package; buildUrl now applies it the same way Python's api_path() does. repo_tests/sdk_ts_request_contract_test.py is a new static-analysis guard that pins both the TS source's own requests and the real backend route table (reusing sdk_request_url_test.py's oracle fixtures) since this checker cannot execute TypeScript.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
✅ SSOT Configuration Compliance: Passing🎉 No new hardcoded values of either class — Known backlog in |
|
Independent review: changes requested.
Verified correct:
Non-blocking:
|
… the file-coverage guard (#15528, #16495) HIGH: the static guard text-scanned each method's relative path literal but never touched client.ts, so nothing proved the /api prefix actually reaches a request -- exactly what #16495's AC2 asks for. Added libs/autobot-sdk-ts/tests/apiPrefix.test.ts: mocks global.fetch, calls one method per resource plus setEnabled's runtime-chosen segment, and asserts the captured URL starts with /api (plus one case proving apiPath() doesn't double-prefix a path that already carries it). MEDIUM: test_the_table_covers_every_resource_file_that_exists used Path.glob and asserted pinned <= on_disk, so a new resource file with unpinned methods would pass silently, and the parametrize list for the completeness test was a hardcoded 4 files. Both now derive from tools.lint._scan_helpers.tracked_paths, and the coverage assertion is on_disk == pinned in both directions. Also added, since it was sitting right next to the fields check the oracle already gave media type for: every POST/PUT row now asserts the route publishes application/json, not just that the field names match -- the same defect class #15527 fixed on the route side (a Form field beside a dict body publishes as x-www-form-urlencoded, which no JSON body can satisfy). Verified statically against agent.py's current execute_command that #15527's fix already makes this hold before adding the assertion. Non-blocking items: changelog fragment now names agents.getConfig's new required agentId and the removed updateConfig. The category-field gap in knowledge.search was filed separately (#16543, already open) and isn't touched here.
|
Both blocking items addressed, pushed at abed6aa:
Also added a media-type assertion next to the existing field-name check (every POST/PUT row now asserts the route publishes Re-ran the guard via the pre-push hook (this checker has no Node runtime, so the new Jest file couldn't be exercised locally the same way -- it's real for the first time in CI): |
|
Delta
|
… this package's ESM preset, and record the new TS-tree glob dependency NPM Package Tests failed with "ReferenceError: jest is not defined" on every test in apiPrefix.test.ts. describe/test/expect are ambient globals under ts-jest/presets/default-esm + --experimental-vm-modules, but the jest mock-utility object is not -- it has to come from @jest/globals explicitly, unlike the CJS preset every other file in this package predates. Fixed by importing it and typing the mock as ReturnType<typeof jest.fn> instead of the CJS-only jest.Mock. Separately, python-suite shard 8/12 failed glob_declared_reads_15900_test.py: sdk_ts_request_contract_test.py's new tracked_paths(_REPO, "libs/autobot-sdk-ts/src/resources/*.ts") is a glob into a tree the python path-filter does not cover, and #15900's guard requires that dependency be written down rather than silently invisible to the filter. Added the entry to GLOB_DECLARED_UNCOVERED.
|
Two red-CI issues found and fixed at 406c76d:
Re-ran both via the pre-push hook where possible (the glob-coverage one for real; the Jest fix can't run locally here, no Node runtime — CI is its first real execution). |
|
Delta
|
… an inferred one (#16495) The ESM-globals fix in the last commit cleared "jest is not defined", but NPM Package Tests then failed to even compile: TS2345, because jest.fn() called with no type argument infers Mock<never>, so mockResolvedValue(...) rejected the real response object outright. Spelled out the call signature -- jest.fn<(...args: unknown[]) => Promise<FakeFetchResponse>>(impl) -- and passed the implementation alongside it instead of chaining mockResolvedValue, so there is one generic instantiation to satisfy rather than an inferred one meeting a separate call. .mock.calls[0]'s cast to [string] is a widen from unknown[], not a narrow from a concrete tuple, for the same reason.
|
Follow-up fix at c60eb2d: the ESM-globals fix cleared the ReferenceError, but then NPM Package Tests failed to compile -- TS2345, because |
|
Delta |
Thinking Path
The Python SDK's request/response shapes were already fixed against the real
routes; the TypeScript package still sent the old, wrong ones (#15528 lists
sessions.list's positionallimit/offset,knowledge.search's GET+query-params call,
analytics.usage/performance's ignoredperiodargument, andseveral invented response fields, among others). Fixing the request shapes
required rewriting
types.tsagainst the real backend models rather than theSDK's own prior (wrong) assumptions, since the two had diverged together.
While tracing every resource method against the real routes,
agents.ts'sgetConfig/updateConfigturned out to call a bare/agent/configwith noagent id at all -- confirmed against
autobot-backend/api/agent_config.py'sactual route table that per-agent config lives under
/agent_config/agents/{agent_id}/..., and that no PUT route exists forupdateConfigon either mount.updateConfigis removed;setModel/setEnabledare added to reach parity with the Python SDK's already-correctsurface.
Also discovered mid-work: every TypeScript SDK request was missing the
/apiprefix entirely, so no request built by this package could reach a real
backend regardless of path or body correctness. This is the same defect
#15053 already found and fixed once in the Python package, filed here as its
own issue (#16495) for traceability and fixed in this PR since shipping
#15528 without it would leave the SDK still fully non-functional.
This checker cannot execute TypeScript, so verification is a new static-
analysis guard (
repo_tests/sdk_ts_request_contract_test.py) rather than aruntime test: it text-scans each resource method's source for its HTTP verb,
path template and sent field names, and checks both that the source matches
its own pinned table and that the table matches the real backend route
table -- reusing the same
route_query_params/route_request_bodiesoracle fixtures the existing Python SDK guards already use, so there is only
one source of truth for what the backend actually accepts.
What Changed
libs/autobot-sdk-ts/src/client.ts— addedAPI_PREFIX/apiPath(),mirroring the Python SDK's
api_path();buildUrl()now applies it (bug(sdk): every TypeScript SDK request omits the /api prefix — 404 against a real backend #16495).libs/autobot-sdk-ts/src/types.ts— rewritten to match the backend's realresponse shapes for sessions, chat messages, agent health/config, knowledge
entries/stats/search, and analytics usage/performance.
libs/autobot-sdk-ts/src/resources/sessions.ts—list(scope?, teamId?),get(sessionId, page?, perPage?).libs/autobot-sdk-ts/src/resources/knowledge.ts—search()is now a POSTwith a JSON body;
getEntries()is cursor-paginated, not offset-paginated.libs/autobot-sdk-ts/src/resources/analytics.ts—usage()/performance()take no arguments and hit the routes' real paths.
libs/autobot-sdk-ts/src/resources/agents.ts—health()'s path gained itsmissing
/agentsegment;getConfig(agentId)now targets the per-agentroute;
updateConfig()removed (no backend route);setModel/setEnabledadded.
libs/autobot-sdk-ts/src/index.ts— export list extended with the newnested types.
libs/autobot-sdk-ts/tests/live/backend.test.ts— updated one call site forsessions.list()'s new signature.repo_tests/sdk_ts_request_contract_test.py(new) — static contract guardfor the TS SDK, pinned against the same backend-derived oracle the Python
SDK guards use.
docs/sdk/README.md— feature-coverage table and defect notes broughtcurrent.
changelog/unreleased/15528-sdk-ts-parity.md(new).Verification
repo_tests/sdk_ts_request_contract_test.py: ran via the repo's pre-pushhook (this checker does not execute product code directly) — passed.
black,isort,flake8 --max-line-length=120,ruff check, andpython3 -c "import ast; ast.parse(...)"all pass clean on the new guardfile.
.tschange was manually traced against the actual backend routedecorators (
autobot-backend/api/agent_config.py,autobot-backend/api/knowledge*.py,autobot-backend/api/analytics.py,autobot-backend/api/chat_sessions.py) rather than executed, since thischecker has no TypeScript runtime available.
green on the full diff.
Closes #15528
Closes #16495
Model Used
Claude Sonnet 5
🤖 Generated with Claude Code