Skip to content

feat(client): add InitClient for the deferred-init endpoints - #243

Open
VascoSch92 wants to merge 2 commits into
mainfrom
vasco/init-client
Open

feat(client): add InitClient for the deferred-init endpoints#243
VascoSch92 wants to merge 2 commits into
mainfrom
vasco/init-client

Conversation

@VascoSch92

Copy link
Copy Markdown
Member

Summary

Split from #231 (one feature per PR). Adds client coverage for the warm-pool deferred-init endpoints that the audit reported as missing. Implementations follow the agent-server init router in OpenHands/software-agent-sdk (see software-agent-sdk#2523).

Endpoint Status before Change
GET /api/init missing new InitClient.getStatus()
POST /api/init missing new InitClient.initialize() (sends X-Init-API-Key)

Details

  • New src/client/init-client.ts wraps the deferred-init / warm-pool endpoints. POST /api/init authenticates with the bootstrap X-Init-API-Key header (distinct from the per-session X-Session-API-Key); it is omitted when no key is given.
  • Model types InitState / InitStatus / InitRequest added to models/api.ts and exported from index.ts.
  • InitClient exported from clients.ts and wired into ConversationManager as the init namespace (constructed and closed alongside the other clients).

Testing

  • Unit (src/__tests__/api-clients.test.ts, mocked fetch): init namespace wiring, getStatus GET, initialize POST (header + body present), and initialize omitting the header when no key is given.
  • Integration (deterministic-api.integration.test.ts): both routes return 404 on the non-deferred pinned image (get_init_service answers 404 when no InitService is registered) — proving the GET/POST routes exist on the image and the client targets the right path/method.
  • npm run build, lint (0 errors), and format:check pass; full unit suite green (273).

Adds coverage for the warm-pool deferred-init routes the client was
missing:

- GET /api/init  -> InitClient.getStatus()
- POST /api/init -> InitClient.initialize() (sends the bootstrap
  X-Init-API-Key header, distinct from the per-session key)

New src/client/init-client.ts, InitState/InitStatus/InitRequest model
types, exports from clients.ts and index.ts, and an `init` namespace on
ConversationManager. Includes unit tests (namespace wiring, getStatus,
initialize with and without the init key) and an integration contract
guard (both routes 404 on the non-deferred pinned image, proving the
paths/methods exist).
@github-actions github-actions Bot added the type: feat A new feature label Jun 29, 2026
@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Endpoint audit

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

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

❌ Not on agent-server (gated, 7)

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

  • 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

↗️ served by cloud (1)

  • GET /api/shared-events/search

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

  • GET /
  • GET /api/conversations
  • GET /api/conversations/{}/events
  • GET /api/conversations/{}/workspace
  • GET /api/conversations/{}/workspace/{}

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.

View the review on PR #243

@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.

Reviewed this end-to-end. The implementation is small, idiomatic, and follows the conventions established by BashClient, HooksClient, etc. — HttpClient wrapper, host.replace(/\/$/, '') normalization, close() parity, model types colocated in models/api.ts, exposed via clients.ts and index.ts. The deferred-init integration test is genuinely useful: asserting 404 (not 405/422) proves both that the routes exist on the pinned image and that the client targets the right path/method — that's a real contract test, not a mock-pile. CI is green across all 11 checks. Two minor doc clarifications below; otherwise ready to merge.


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

Comment thread src/client/init-client.ts
Comment thread src/client/init-client.ts
@VascoSch92

Copy link
Copy Markdown
Member Author

@OpenHands address the comments and fix the conflicts.

@openhands-ai

openhands-ai Bot commented Jun 29, 2026

Copy link
Copy Markdown

I'm on it! VascoSch92 can track my progress at all-hands.dev

Resolve conflicts with main and clarify InitClient header behavior.

Co-authored-by: openhands <[email protected]>
@openhands-ai

openhands-ai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Done — PR #243 is updated: #243

Summary:

  • Merged latest main into vasco/init-client and resolved conflicts.
  • Addressed both inline review comments by clarifying InitClient header behavior:
    • InitClientOptions.apiKey maps to X-Session-API-Key through HttpClient.
    • InitializeOptions.initApiKey maps to X-Init-API-Key.
    • getStatus() docs now warn to omit apiKey for dormant warm-pool polling that must not send a session header.
  • Kept both new main-branch tests and the init-client tests during conflict resolution.
  • Committed and pushed 8e347cf to vasco/init-client.
  • Replied to and resolved both review threads.

Validation:

  • npm test -- --runInBand src/__tests__/api-clients.test.ts passed.
  • npm run build passed.
  • npm run lint passed with existing warnings only.
  • npm run format:check passed.
  • Full npm test -- --runInBand passed: 275 tests.
  • GitHub PR checks all passed: 11/11 successful.

Current PR state: conflicts are fixed; merge is still blocked only by required review (REVIEW_REQUIRED).

@all-hands-bot

Copy link
Copy Markdown
Contributor

🤖 OpenHands is reviewing this PR.

Head commit: 8e347cf55b1087adba85aaa91e640858c6c1cac5
View the conversation: https://oss-agent-canvas.ngrok.dev/conversations/afd6b44a-2bc0-45f7-84d6-0734d3a70767

This comment was posted by an AI agent (OpenHands).

@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.

This review was created by an AI agent (OpenHands) on behalf of the repository maintainers.

Review: feat(client): add InitClient for the deferred-init endpoints

Verdict: No material findings — ready to merge.

Risk assessment: LOW.

The change adds InitClient covering GET /api/init and POST /api/init for the warm-pool deferred-init lifecycle. The implementation is small, idiomatic, and consistent with the existing client conventions:

  • HttpClient wrapper with host.replace(/\/$/, '') normalization and close() parity.
  • initialize() correctly sends X-Init-API-Key only when supplied and omits it otherwise (verified by a dedicated unit test). The header/body semantics match the agent-server init router.
  • Model types (InitState / InitStatus / InitRequest) are colocated in models/api.ts and exported from both clients.ts (class + options types) and index.ts (model types only) — consistent with how the other secondary clients are surfaced.
  • Wired into ConversationManager as the init namespace, constructed and closed alongside the other clients.
  • The deterministic integration test asserting 404 (not 405/422) on the non-deferred pinned image is a genuine contract guard — it proves both routes exist on the image and that the client targets the correct path/method, which mocked unit tests cannot catch.

Points verified, no action needed

  • Dual-header behavior on POST /api/init: when ConversationManager is constructed with an apiKey, HttpClient attaches X-Session-API-Key on every request including the init calls. This is harmless — the init router authenticates via X-Init-API-Key and ignores the session header — and the doc comment on getStatus/initialize already guides callers to omit apiKey for dormant polling. Not a bug.
  • secret_key in InitRequest: transmitted in the POST body over HTTPS and authenticated by X-Init-API-Key; matches the server's intended design.
  • Default-body initialize(): request = {} produces JSON.stringify({}), verified by the unit test.
  • Export surface: InitClient is exported from the ./clients subpath (like ServerClient, BashClient, etc.); the model types are additionally exported from the root entry point. Consistent with the existing pattern.

No bugs, security problems, or design flaws identified.

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.

3 participants