Skip to content

feat(client): add ConversationClient.batchGetEvents server-side batch endpoint#246

Open
VascoSch92 wants to merge 1 commit into
mainfrom
vasco/conversation-batch-events
Open

feat(client): add ConversationClient.batchGetEvents server-side batch endpoint#246
VascoSch92 wants to merge 1 commit into
mainfrom
vasco/conversation-batch-events

Conversation

@VascoSch92

Copy link
Copy Markdown
Member

Summary

Split from #231 (one feature per PR). Adds client coverage for the server-side conversation events batch endpoint that the audit reported as missing.

Endpoint Status before Change
GET /api/conversations/{id}/events (batch) missing new ConversationClient.batchGetEvents()

Details

  • This endpoint is declared GET-with-required-body, which fetch rejects (TypeError: Request with GET/HEAD method cannot have body). HttpClient now routes GET-with-body requests through Node's http/https module (requestWithBodyOnGet + parseNodeResponse), mirroring the fetch path's URL/header/error/parse behavior; every other request is untouched.
  • Unlike getEvents (which fans out one request per id), batchGetEvents calls the server-side batch endpoint and returns one entry per requested id, preserving input order.

Note: the GET-with-body HttpClient infrastructure here is shared with the bash batch-events PR (split from the same audit). The two are intentionally identical so they merge cleanly.

Testing

  • Unit (src/__tests__/api-clients.test.ts): mocks node:http (the GET-body transport) and asserts the request method/URL/body and the response mapping (real id resolved, missing slot null).
  • Integration (deterministic-api.integration.test.ts): round-trips a real event id through the batch endpoint and asserts the route resolves and preserves order. (The conversation endpoint raises on unknown ids rather than returning null, so this exercises the happy path with an id that exists.)
  • npm run build, lint (0 errors), and format:check pass; full unit suite green (270).

… endpoint

Adds coverage for the server-side conversation events batch endpoint:

- GET /api/conversations/{id}/events -> ConversationClient.batchGetEvents()

This endpoint is declared GET-with-required-body, which `fetch` rejects
("Request with GET/HEAD method cannot have body"). HttpClient now routes
GET-with-body requests through Node's http(s) module (requestWithBodyOnGet
+ parseNodeResponse), mirroring the fetch path's URL/header/error/parse
behavior; every other request is untouched. Unlike getEvents (one request
per id), batchGetEvents returns one entry per requested id, preserving
input order.

Includes a unit test (mocked node:http, asserting method/URL/body and
the response mapping) and an integration test that round-trips a real
event id through the batch endpoint.
@github-actions

Copy link
Copy Markdown
Contributor

Endpoint audit

❌ 8 off-contract call(s) — not on the agent-server · classifiers: cloud

Category Count
❌ Off-contract (not on agent-server) 8
  ⛔ no known backend 7
  ↗️ served by cloud 1
➕ Missing API (agent-server has, client lacks) 8
agent-server endpoints 112
client endpoints 110

❌ Not on agent-server (gated, 8)

⛔ (no known backend) — served by no backend we can see (7)

  • DELETE /api/meta-profiles/{}
  • GET /api/meta-profiles
  • GET /api/meta-profiles/{}
  • POST /api/cloud-proxy
  • POST /api/meta-profiles/{}
  • POST /api/meta-profiles/{}/activate
  • POST /api/skills/installed/{}/update

↗️ served by cloud (1)

  • GET /api/shared-events/search

➕ Missing API — agent-server exposes it, client does not implement (8)

  • GET /
  • GET /api/bash/bash_events
  • GET /api/conversations
  • GET /api/conversations/{}/workspace
  • GET /api/conversations/{}/workspace/{}
  • GET /api/init
  • POST /api/init
  • POST /api/skills/installed/{}/refresh

@VascoSch92 VascoSch92 requested a review from all-hands-bot June 29, 2026 10:37

all-hands-bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Review complete.

This review was performed through OpenHands Cloud Automation. You can log in and view the conversation here.

@all-hands-bot all-hands-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Taste Rating: Needs improvement — the endpoint wrapper is small, but the transport change cuts across the shared HTTP client and violates the repository's browser-compatibility contract.

[CRITICAL ISSUES]

  • The shared HttpClient now routes GET-with-body through Node http/https and Buffer. AGENTS.md explicitly says all src/ code must be browser-compatible and must not depend on Node built-ins, so this would break browser consumers of the SDK.

[IMPROVEMENT OPPORTUNITIES]

  • batchGetEvents() promises the same null-slot behavior as getEvents(), but the integration test documents that the real server endpoint raises on unknown IDs. Align the public type/docs/tests with the actual endpoint, or implement the promised fallback semantics.

[TESTING GAPS]

  • CI covers Node and the deterministic server route, but there is no browser/bundler guard that would catch node:http, node:https, or Buffer entering the exported SDK surface.

[RISK ASSESSMENT]

  • [Overall PR] ⚠️ Risk Assessment: 🔴 HIGH
    This modifies the central HTTP transport used by public clients and introduces Node-only APIs into a package whose repository contract requires browser-compatible src/ code. The blast radius is broad because HttpClient is shared across the SDK and exported directly. Recommendation: Do not auto-merge. Request human maintainer/architect review to decide how GET-with-body endpoints should be exposed without breaking browser consumers.

VERDICT:
Needs rework: The new endpoint should not land by adding Node-only transport into the shared browser-compatible client.

KEY INSIGHT:
The hard problem is not adding batchGetEvents(); it is deciding how this SDK represents a server API shape that browsers fundamentally cannot send with fetch.


Improve this review? If any feedback above seems incorrect or irrelevant to this repository, you can teach the reviewer to do better:

  1. Add a .agents/skills/custom-codereview-guide.md file to your branch (or edit it if one already exists) with the /codereview trigger and the context the reviewer is missing (e.g., "Security concerns about X do not apply here because Y"). See the customization docs for the required frontmatter format.
  2. Re-request a review - the reviewer reads guidelines from the PR branch, so your changes take effect immediately.
  3. When your PR is merged, the guideline file goes through normal code review by repository maintainers.

Resolve with AI? Install the iterate skill in your agent and run /iterate to automatically drive this PR through CI, review, and QA until it's merge-ready.

Was this review helpful? React with 👍 or 👎 to give feedback.

This review was generated by an AI agent (OpenHands) on behalf of the user through OpenHands Automation. View conversation

Comment thread src/client/http-client.ts
}

const transport =
url.protocol === 'https:' ? await import('node:https') : await import('node:http');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Critical: This introduces Node-only transport into src/, which violates the repository's hard browser-compatibility requirement in AGENTS.md (src/ must not depend on Node built-ins). Browser consumers and bundlers can fail on node:http/node:https, and this path also uses Buffer above. Please do not put a Node transport behind the shared HttpClient; either keep the exported client browser-safe and surface this server-contract limitation clearly, or isolate Node-only support behind a separate Node-specific entrypoint/adapter that browser builds never import.

*
* Unlike {@link getEvents} (which fans out one request per id), this calls the
* server-side batch endpoint and returns one entry per requested id, with
* `null` in the slots of any missing event — preserving input order.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Important: This promised null-slot contract does not match the real endpoint behavior documented by the new integration test, which says unknown conversation event IDs make the endpoint raise instead of returning null. The public type and unit test now teach consumers to expect getEvents() semantics, but a missing ID will reject the whole batch. Either change the docs/types/tests to state that this batch endpoint only succeeds for existing IDs, or add client logic that actually preserves the Array<Event | null> behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: feat A new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants