import { randomUUID } from "node:crypto"; import type { ApprovalRequest, ApprovalResponse as CoreApprovalResponse, QuestionRequest, QuestionResult, } from "@moonshot-ai/kimi-code-sdk"; import type { ApprovalResponse, QuestionRequest as LegacyQuestionRequest } from "../../shared/legacy-sdk"; import { describeToolDisplay, toLegacyDisplay } from "./tool-display"; export type ReverseRpcEvent = | { type: "ApprovalRequest"; payload: ReturnType } | { type: "QuestionRequest"; payload: LegacyQuestionRequest }; export class ReverseRpcController { private readonly approvals = new Map void>(); private readonly questions = new Map void>(); constructor(private readonly emit: (event: ReverseRpcEvent) => void) {} requestApproval(request: ApprovalRequest): Promise { const id = randomUUID(); return new Promise((resolve) => { this.approvals.set(id, resolve); this.emit({ type: "ApprovalRequest", payload: approvalPayload(id, request) }); }); } requestQuestion(request: QuestionRequest): Promise { const id = randomUUID(); return new Promise((resolve) => { this.questions.set(id, resolve); this.emit({ type: "QuestionRequest", payload: { id, tool_call_id: request.toolCallId ?? "", questions: request.questions.map((question) => ({ question: question.question, header: question.header, options: question.options.map((option) => ({ label: option.label, description: option.description, })), multi_select: question.multiSelect, })), }, }); }); } respondApproval(id: string, response: ApprovalResponse): boolean { const resolve = this.approvals.get(id); if (!resolve) return false; this.approvals.delete(id); if (response === "approve_for_session") { resolve({ decision: "approved", scope: "session" }); } else if (response === "approve") { resolve({ decision: "approved" }); } else { resolve({ decision: "rejected" }); } return true; } respondQuestion(id: string, answers: Record): boolean { const resolve = this.questions.get(id); if (!resolve) return false; this.questions.delete(id); resolve({ answers }); return true; } cancelAll(reason: string): void { for (const resolve of this.approvals.values()) { resolve({ decision: "cancelled", feedback: reason }); } for (const resolve of this.questions.values()) { resolve(null); } this.approvals.clear(); this.questions.clear(); } } function approvalPayload(id: string, request: ApprovalRequest) { return { id, tool_call_id: request.toolCallId, sender: request.toolName, action: request.action, description: describeToolDisplay(request.display), display: toLegacyDisplay(request.display), }; }