fix: ACP client permission handling and process cleanup
Two bugs fixed: 1. request_permission messages (JSON-RPC requests with both id+method) were silently swallowed by the response handler, causing hermes to hang waiting for permission approval. Now properly distinguish responses (id only) from server requests (id+method). 2. uwf-hermes process never exited after completing because the hermes ACP subprocess was still alive. Now explicitly close the ACP client after agent completion so the subprocess terminates. 小橘 <xiaoju@shazhou.work>
This commit is contained in:
@@ -226,8 +226,11 @@ export class HermesAcpClient {
|
||||
|
||||
const msg = parsed as Record<string, unknown>;
|
||||
|
||||
// JSON-RPC response (has "id")
|
||||
if ("id" in msg && msg.id !== undefined && msg.id !== null) {
|
||||
const hasId = "id" in msg && msg.id !== undefined && msg.id !== null;
|
||||
const hasMethod = typeof msg.method === "string";
|
||||
|
||||
// JSON-RPC response to one of our requests (has "id" but no "method")
|
||||
if (hasId && !hasMethod) {
|
||||
const response = msg as unknown as JsonRpcResponse;
|
||||
const handler = this.pending.get(response.id);
|
||||
if (handler !== undefined) {
|
||||
@@ -237,7 +240,22 @@ export class HermesAcpClient {
|
||||
return;
|
||||
}
|
||||
|
||||
// JSON-RPC notification — session/update
|
||||
// Server-initiated JSON-RPC request: session/request_permission (has "id" + "method")
|
||||
if (msg.method === "session/request_permission" && hasId) {
|
||||
const params = msg.params as Record<string, unknown> | undefined;
|
||||
const options = (params?.options ?? []) as Array<{ optionId?: string }>;
|
||||
const firstOptionId = options[0]?.optionId ?? "";
|
||||
this.writeLine(
|
||||
JSON.stringify({
|
||||
jsonrpc: "2.0",
|
||||
id: msg.id,
|
||||
result: { outcome: { outcome: "selected", optionId: firstOptionId } },
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// JSON-RPC notification — session/update (no "id")
|
||||
if (msg.method === "session/update") {
|
||||
const params = msg.params as Record<string, unknown> | undefined;
|
||||
const update = params?.update as Record<string, unknown> | undefined;
|
||||
@@ -246,20 +264,6 @@ export class HermesAcpClient {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// session/request_permission — auto-approve (yolo mode)
|
||||
if (msg.method === "session/request_permission") {
|
||||
const params = msg.params as Record<string, unknown> | undefined;
|
||||
const options = (params?.options ?? []) as Array<{ optionId?: string }>;
|
||||
const firstOptionId = options[0]?.optionId ?? "";
|
||||
// Respond with the selected option
|
||||
const responseMsg = {
|
||||
jsonrpc: "2.0",
|
||||
id: (msg as Record<string, unknown>).id,
|
||||
result: { outcome: { outcome: "selected", optionId: firstOptionId } },
|
||||
};
|
||||
this.writeLine(JSON.stringify(responseMsg));
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Session update → structured messages ----
|
||||
|
||||
@@ -82,9 +82,19 @@ export function createHermesAgent(): () => Promise<void> {
|
||||
return { output: text, detailHash, sessionId };
|
||||
}
|
||||
|
||||
return createAgent({
|
||||
const agentMain = createAgent({
|
||||
name: "hermes",
|
||||
run: runHermes,
|
||||
continue: continueHermes,
|
||||
});
|
||||
|
||||
// Wrap to ensure ACP client is closed after agent completes,
|
||||
// so the hermes subprocess exits and bun can terminate.
|
||||
return async () => {
|
||||
try {
|
||||
await agentMain();
|
||||
} finally {
|
||||
await client.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user