From 51f127f47bb1bcf1ba9e31670f4a8a403a4e9200 Mon Sep 17 00:00:00 2001 From: LeonSGP <154585401+LeonSGP43@users.noreply.github.com> Date: Tue, 21 Apr 2026 04:54:14 +0800 Subject: [PATCH] fix(hermes): stop advertising unsupported instructions bundles (#3908) ## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies. > - Local adapter capability flags decide which configuration surfaces the UI and server expose for each adapter. > - `hermes_local` currently advertises managed instructions bundle support, so Paperclip exposes the AGENTS.md bundle flow for Hermes agents. > - The bundled `hermes-paperclip-adapter` only consumes `promptTemplate` at runtime and does not read `instructionsFilePath`, so that advertised bundle path silently does nothing. > - Issue #3833 reports exactly that mismatch: users configure AGENTS.md instructions, but Hermes only receives the built-in heartbeat prompt. > - This pull request stops advertising managed instructions bundles for `hermes_local` until the adapter actually consumes bundle files at runtime. ## What Changed - Changed the built-in `hermes_local` server adapter registration to report `supportsInstructionsBundle: false`. - Updated the UI's synchronous built-in capability fallback so Hermes no longer shows the managed instructions bundle affordance on first render. - Added regression coverage in `server/src/__tests__/adapter-routes.test.ts` to assert that `hermes_local` still reports skills + local JWT support, but not instructions bundle support. ## Verification - `git diff --check` - `node --experimental-strip-types --input-type=module -e "import { findActiveServerAdapter } from './server/src/adapters/index.ts'; const adapter = findActiveServerAdapter('hermes_local'); console.log(JSON.stringify({ type: adapter?.type, supportsInstructionsBundle: adapter?.supportsInstructionsBundle, supportsLocalAgentJwt: adapter?.supportsLocalAgentJwt, supportsSkills: Boolean(adapter?.listSkills || adapter?.syncSkills) }));"` - Observed `{"type":"hermes_local","supportsInstructionsBundle":false,"supportsLocalAgentJwt":true,"supportsSkills":true}` - Added adapter-routes regression assertions for the Hermes capability contract; CI should validate the full route path in a clean workspace. ## Risks - Low risk: this only changes the advertised capability surface for `hermes_local`. - Behavior change: Hermes agents will no longer show the broken managed instructions bundle UI until the underlying adapter actually supports `instructionsFilePath`. - Existing Hermes skill sync and local JWT behavior are unchanged. ## Model Used - OpenAI Codex, GPT-5.4 class coding agent, medium reasoning, terminal/git/gh tool use. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [ ] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots - [ ] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --- server/src/__tests__/adapter-routes.test.ts | 12 ++++++++++++ server/src/adapters/registry.ts | 3 +-- ui/src/adapters/use-adapter-capabilities.ts | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/server/src/__tests__/adapter-routes.test.ts b/server/src/__tests__/adapter-routes.test.ts index d67a4f9bf5..289e25c7c2 100644 --- a/server/src/__tests__/adapter-routes.test.ts +++ b/server/src/__tests__/adapter-routes.test.ts @@ -129,6 +129,18 @@ describe("adapter routes", () => { expect(cursorAdapter).toBeDefined(); expect(cursorAdapter.capabilities.requiresMaterializedRuntimeSkills).toBe(true); expect(cursorAdapter.capabilities.supportsInstructionsBundle).toBe(true); + + // hermes_local currently supports skills + local JWT, but not the managed + // instructions bundle flow because the bundled adapter does not consume + // instructionsFilePath at runtime. + const hermesAdapter = res.body.find((a: any) => a.type === "hermes_local"); + expect(hermesAdapter).toBeDefined(); + expect(hermesAdapter.capabilities).toMatchObject({ + supportsInstructionsBundle: false, + supportsSkills: true, + supportsLocalAgentJwt: true, + requiresMaterializedRuntimeSkills: false, + }); }); it("GET /api/adapters derives supportsSkills from listSkills/syncSkills presence", async () => { diff --git a/server/src/adapters/registry.ts b/server/src/adapters/registry.ts index f6a1afca1e..d3fa0fbec7 100644 --- a/server/src/adapters/registry.ts +++ b/server/src/adapters/registry.ts @@ -209,8 +209,7 @@ const hermesLocalAdapter: ServerAdapterModule = { syncSkills: hermesSyncSkills, models: hermesModels, supportsLocalAgentJwt: true, - supportsInstructionsBundle: true, - instructionsPathKey: "instructionsFilePath", + supportsInstructionsBundle: false, requiresMaterializedRuntimeSkills: false, agentConfigurationDoc: hermesAgentConfigurationDoc, detectModel: () => detectModelFromHermes(), diff --git a/ui/src/adapters/use-adapter-capabilities.ts b/ui/src/adapters/use-adapter-capabilities.ts index 281d3adcc0..7c16e1c973 100644 --- a/ui/src/adapters/use-adapter-capabilities.ts +++ b/ui/src/adapters/use-adapter-capabilities.ts @@ -21,7 +21,7 @@ const KNOWN_DEFAULTS: Record = { gemini_local: { supportsInstructionsBundle: true, supportsSkills: true, supportsLocalAgentJwt: true, requiresMaterializedRuntimeSkills: true }, opencode_local: { supportsInstructionsBundle: true, supportsSkills: true, supportsLocalAgentJwt: true, requiresMaterializedRuntimeSkills: true }, pi_local: { supportsInstructionsBundle: true, supportsSkills: true, supportsLocalAgentJwt: true, requiresMaterializedRuntimeSkills: true }, - hermes_local: { supportsInstructionsBundle: true, supportsSkills: true, supportsLocalAgentJwt: true, requiresMaterializedRuntimeSkills: false }, + hermes_local: { supportsInstructionsBundle: false, supportsSkills: true, supportsLocalAgentJwt: true, requiresMaterializedRuntimeSkills: false }, openclaw_gateway: ALL_FALSE, };