Skip to content

fix(client): target the skills /refresh route instead of /update#242

Merged
VascoSch92 merged 1 commit into
mainfrom
vasco/skills-refresh-path
Jun 29, 2026
Merged

fix(client): target the skills /refresh route instead of /update#242
VascoSch92 merged 1 commit into
mainfrom
vasco/skills-refresh-path

Conversation

@VascoSch92

Copy link
Copy Markdown
Member

Summary

Split from #231 (one endpoint per PR). SkillsClient.refreshSkill() POSTed to /api/skills/installed/{name}/update, but the agent-server does not expose that route — the correct route is /refresh (verified against the agent-server skills router in OpenHands/software-agent-sdk).

Endpoint Status before Change
POST /api/skills/installed/{name}/refresh wrong path (/update) fixed SkillsClient.refreshSkill()/refresh

Testing

  • Unit (src/__tests__/api-clients.test.ts, mocked fetch): updated the existing combined-skills assertion from /update to /refresh, plus a new focused test asserting refreshSkill POSTs to the /refresh route.
  • Integration (deterministic-api.integration.test.ts, against the pinned agent-server image): a contract guard that a valid-but-uninstalled skill name reaches the handler and returns 404 — proving the route exists on the image and the client targets the corrected path (client↔server drift the mocked unit test cannot catch).
  • npm run build, lint (0 errors), and format:check pass; full unit suite green.

SkillsClient.refreshSkill POSTed to /api/skills/installed/{name}/update,
which the agent-server does not expose. The route is /refresh. Updates
the mocked unit assertion, adds a focused unit test for the corrected
path, and adds an integration contract guard (404 for an uninstalled
skill) that proves the route exists on the pinned image.
@github-actions github-actions Bot added the type: fix A bug fix label Jun 29, 2026
@github-actions

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) 8
agent-server endpoints 112
client endpoints 109

❌ 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 (8)

  • GET /
  • GET /api/bash/bash_events
  • GET /api/conversations
  • GET /api/conversations/{}/events
  • GET /api/conversations/{}/workspace
  • GET /api/conversations/{}/workspace/{}
  • GET /api/init
  • POST /api/init

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.

Verdict: ✅ Approved. One non-blocking 🟡 suggestion: the new SkillsClient.refreshSkill POSTs to the /refresh route unit test in src/__tests__/api-clients.test.ts mostly duplicates the URL assertion already pinned by the combined-skills test above (which you updated) and asserts against a mocked fetch — consider deleting it (the updated combined test + the live-server contract guard in deterministic-api.integration.test.ts are enough) or replacing the global.fetch mock with a real HttpClient so the assertion exercises actual URL building and response parsing.

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

🟢 Good taste — surgical one-line URL fix in skills-client.ts, with the test suite brought in line and a live-server contract guard added. No fundamental issues.

The fix matches the upstream route exactly (POST /api/skills/installed/{skill_name}/refresh, confirmed in software-agent-sdk/.../skills_router.py), and the new integration test pins the 404-for-uninstalled-skill contract end-to-end against the real agent-server image. CI is green across all 11 checks (including integration-test and endpoint-audit).

One non-blocking suggestion below.


What the PR actually changes (3 files, +19/-2 net):

  • src/client/skills-client.ts:80/update/refresh (the real bug).
  • src/__tests__/api-clients.test.ts:513 — existing combined test updated, plus a new dedicated unit test for refreshSkill.
  • src/__tests__/integration/deterministic-api.integration.test.ts — new live-server contract test that asserts the route exists and returns 404 for an uninstalled skill.

Why I like it:

  • Smallest possible diff to fix a real production 404.
  • Both halves are covered: a fast mocked test for the URL string, and a slow integration test that proves the route is actually wired up on the server side. The 404 path is the cheapest possible 'does this route exist?' probe — no fixtures to maintain.
  • No unrelated formatting, refactoring, or 'while I'm here' changes.

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

);
});

it('SkillsClient.refreshSkill POSTs to the /refresh route', async () => {

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.

🟡 Suggestion — the new unit test mostly duplicates the combined-skills test above.

This test mocks fetch and asserts that fetch was called with the expected URL — that's the 'mocks aren't tests' pattern: it will pass even if SkillsClient.refreshSkill is rewritten to use fetch directly, hard-coded URL, or anything else, as long as it happens to hit that string. It doesn't exercise the HttpClient.post<T> → URL-encoding → response-parse path that the combined test at ~L485 already exercises thoroughly (including the toHaveBeenNthCalledWith(6, ..., { method: 'POST' }) URL assertion you updated at L513).

Two cleaner options, pick whichever you prefer:

  1. Delete this new test — the updated assertion in the combined test already pins the URL + method. The standalone integration test in deterministic-api.integration.test.ts is what gives real coverage of the route.
  2. Make this test do real work — drop the global.fetch mock and pass a stub HttpClient (or a real one against an unfetch-style local adapter) so the assertion exercises actual URL building / response parsing, not just 'did you call fetch with this string.'

Not blocking — option 1 is fine if you want to keep the diff minimal.

@VascoSch92 VascoSch92 merged commit 3f09dc6 into main Jun 29, 2026
11 checks passed
@openhands-release-bot

Copy link
Copy Markdown
Contributor

🚀 Released in v1.32.0.

@openhands-release-bot openhands-release-bot Bot added the released: v1.32.0 Shipped in v1.32.0 label Jul 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

released: v1.32.0 Shipped in v1.32.0 type: fix A bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants