From 70cca2f96b8840a4878533d4373b3d33ac90bcbf Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Sat, 11 Jul 2026 23:42:56 -0700 Subject: [PATCH] fix: accept Grok ACP extension notifications without Method not found Grok emits `_x.ai/session_notification` / `_x.ai/session/update` for hook_execution status. The ACP SDK routes those to Client.extNotification; without it, every successful post_tool_use hook logged -32601 Method not found. Implement no-op extMethod/extNotification on default and bridging handlers in acp-runtime and the Grok vendored copy. --- .../src/__tests__/provider-handshake.test.ts | 31 +++++++++++++++++++ .../fusion-plugin-acp-runtime/src/provider.ts | 28 +++++++++++++++++ .../src/acp/provider.ts | 28 +++++++++++++++++ 3 files changed, 87 insertions(+) diff --git a/plugins/fusion-plugin-acp-runtime/src/__tests__/provider-handshake.test.ts b/plugins/fusion-plugin-acp-runtime/src/__tests__/provider-handshake.test.ts index c32013ce84..3ffe4db3a4 100644 --- a/plugins/fusion-plugin-acp-runtime/src/__tests__/provider-handshake.test.ts +++ b/plugins/fusion-plugin-acp-runtime/src/__tests__/provider-handshake.test.ts @@ -5,6 +5,7 @@ import { IncompatibleProtocolError, HandshakeTimeoutError, createDefaultClientHandler, + createBridgingClientHandler, } from "../provider.js"; import { killAllProcesses, activeProcessCount } from "../process-manager.js"; @@ -93,4 +94,34 @@ describe("connect() handshake", () => { const res = await handler.requestPermission({} as never); expect(res).toEqual({ outcome: { outcome: "cancelled" } }); }); + + /* + FNXC:GrokAcp 2026-07-12-07:00: + Grok sends `_x.ai/session_notification` for hook_execution; without + extNotification the ACP SDK logs Method not found (-32601). + */ + it("default and bridging handlers accept x.ai extension notifications without Method not found", async () => { + const defaultHandler = createDefaultClientHandler(); + await expect( + defaultHandler.extNotification?.("_x.ai/session_notification", { + sessionId: "s1", + update: { + sessionUpdate: "hook_execution", + event_name: "post_tool_use", + tool_name: "read_file", + runs: [{ name: "global/settings:post_tool_use[0].hooks[0]", status: { status: "success", elapsed_ms: 9 } }], + }, + }), + ).resolves.toBeUndefined(); + await expect(defaultHandler.extMethod?.("_x.ai/example", { a: 1 })).resolves.toEqual({}); + + const { handler } = createBridgingClientHandler({}); + await expect( + handler.extNotification?.("_x.ai/session/update", { + sessionId: "s1", + update: { sessionUpdate: "hook_execution", event_name: "stop", runs: [] }, + }), + ).resolves.toBeUndefined(); + await expect(handler.extMethod?.("x.ai/session_notification", {})).resolves.toEqual({}); + }); }); diff --git a/plugins/fusion-plugin-acp-runtime/src/provider.ts b/plugins/fusion-plugin-acp-runtime/src/provider.ts index 793d7120a0..b604535372 100644 --- a/plugins/fusion-plugin-acp-runtime/src/provider.ts +++ b/plugins/fusion-plugin-acp-runtime/src/provider.ts @@ -67,6 +67,30 @@ export class HandshakeTimeoutError extends Error { } } +/* +FNXC:GrokAcp 2026-07-12-07:00: +Grok ACP emits vendor extension notifications such as `_x.ai/session_notification` +and `_x.ai/session/update` for hook_execution status (post_tool_use, etc.). +@agentclientprotocol/sdk routes non-spec methods to Client.extNotification / +extMethod; when those are absent the SDK logs Method not found (-32601) for +every hook even though hooks themselves succeeded. Accept extensions as no-ops +so Fusion clients stay forward-compatible without claiming Grok-only features. +Do not forward into sessionUpdate: hook_execution is not a standard +sessionUpdate tag and would fail zSessionNotification validation. +*/ + +/** No-op ACP extension handlers so vendor notifications do not Method-not-found. */ +function acceptAcpExtensions(): Pick { + return { + async extMethod(_method: string, _params: Record) { + return {}; + }, + async extNotification(_method: string, _params: Record) { + // Intentionally empty — informational Grok hooks / x.ai session extensions. + }, + }; +} + /** * Minimal default client handler. Later units (U3/U4/U5/U7) supply the real one * that bridges `session/update` into Fusion callbacks and routes permission @@ -81,6 +105,7 @@ export function createDefaultClientHandler(): Client { async requestPermission() { return { outcome: { outcome: "cancelled" } }; }, + ...acceptAcpExtensions(), }; } @@ -182,6 +207,9 @@ export function createBridgingClientHandler( ); }); }, + // FNXC:GrokAcp 2026-07-12-07:00: swallow `_x.ai/*` extension notifications + // (hook_execution, session admin, …) so ACP SDK does not log -32601. + ...acceptAcpExtensions(), }; // Register fs handlers ONLY when enabled, so the advertised capability and the diff --git a/plugins/fusion-plugin-grok-runtime/src/acp/provider.ts b/plugins/fusion-plugin-grok-runtime/src/acp/provider.ts index ac820fb19e..538cc1a500 100644 --- a/plugins/fusion-plugin-grok-runtime/src/acp/provider.ts +++ b/plugins/fusion-plugin-grok-runtime/src/acp/provider.ts @@ -68,6 +68,30 @@ export class HandshakeTimeoutError extends Error { } } +/* +FNXC:GrokAcp 2026-07-12-07:00: +Grok ACP emits vendor extension notifications such as `_x.ai/session_notification` +and `_x.ai/session/update` for hook_execution status (post_tool_use, etc.). +@agentclientprotocol/sdk routes non-spec methods to Client.extNotification / +extMethod; when those are absent the SDK logs Method not found (-32601) for +every hook even though hooks themselves succeeded. Accept extensions as no-ops +so Fusion clients stay forward-compatible without claiming Grok-only features. +Do not forward into sessionUpdate: hook_execution is not a standard +sessionUpdate tag and would fail zSessionNotification validation. +*/ + +/** No-op ACP extension handlers so vendor notifications do not Method-not-found. */ +function acceptAcpExtensions(): Pick { + return { + async extMethod(_method: string, _params: Record) { + return {}; + }, + async extNotification(_method: string, _params: Record) { + // Intentionally empty — informational Grok hooks / x.ai session extensions. + }, + }; +} + /** * Minimal default client handler. Later units (U3/U4/U5/U7) supply the real one * that bridges `session/update` into Fusion callbacks and routes permission @@ -82,6 +106,7 @@ export function createDefaultClientHandler(): Client { async requestPermission() { return { outcome: { outcome: "cancelled" } }; }, + ...acceptAcpExtensions(), }; } @@ -183,6 +208,9 @@ export function createBridgingClientHandler( ); }); }, + // FNXC:GrokAcp 2026-07-12-07:00: swallow `_x.ai/*` extension notifications + // (hook_execution, session admin, …) so ACP SDK does not log -32601. + ...acceptAcpExtensions(), }; // Register fs handlers ONLY when enabled, so the advertised capability and the