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:
@@ -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({});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user