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.
This commit is contained in:
gsxdsm
2026-07-11 23:42:56 -07:00
parent a850cb7ead
commit 70cca2f96b
3 changed files with 87 additions and 0 deletions

View File

@@ -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({});
});
});

View File

@@ -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<Client, "extMethod" | "extNotification"> {
return {
async extMethod(_method: string, _params: Record<string, unknown>) {
return {};
},
async extNotification(_method: string, _params: Record<string, unknown>) {
// 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

View File

@@ -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<Client, "extMethod" | "extNotification"> {
return {
async extMethod(_method: string, _params: Record<string, unknown>) {
return {};
},
async extNotification(_method: string, _params: Record<string, unknown>) {
// 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