Download packages/node-sdk/test/session-approval-handler.test.ts from SaylorTwift/kimi-code: direct link, hf CLI and curl.
- Browser
- Download file 6.07 kB
-
https://huggingface.co/SaylorTwift/kimi-code/resolve/main/packages/node-sdk/test/session-approval-handler.test.ts
- Command line
-
hf download hf://SaylorTwift/kimi-code/packages/node-sdk/test/session-approval-handler.test.ts
-
curl -L -o session-approval-handler.test.ts https://huggingface.co/SaylorTwift/kimi-code/resolve/main/packages/node-sdk/test/session-approval-handler.test.ts
6.07 kB
| import { describe, expect, it, vi } from 'vitest'; | |
| import type { ApprovalHandler, ApprovalRequest, ApprovalResponse } from '#/index'; | |
| import { Session } from '#/index'; | |
| import type { SDKRpcClientBase } from '#/rpc'; | |
| describe('Session approval handler', () => { | |
| it('registers an approval handler and returns approved responses', async () => { | |
| const rpc = new FakeSDKRpcClient(); | |
| const session = new Session({ | |
| id: 'ses_approval_handler', | |
| workDir: '/tmp', | |
| rpc: rpc.asRpc(), | |
| }); | |
| const handler = vi.fn(async (request: ApprovalRequest) => { | |
| expect(request).toMatchObject({ | |
| toolCallId: 'tool_1', | |
| toolName: 'Bash', | |
| action: 'Run command', | |
| }); | |
| return { decision: 'approved' as const, selectedLabel: 'Approve once' }; | |
| }); | |
| session.setApprovalHandler(handler); | |
| await expect( | |
| rpc.requestApproval( | |
| session.id, | |
| 'main', | |
| approvalRequest({ | |
| toolCallId: 'tool_1', | |
| toolName: 'Bash', | |
| action: 'Run command', | |
| }), | |
| ), | |
| ).resolves.toEqual({ decision: 'approved', selectedLabel: 'Approve once' }); | |
| expect(handler).toHaveBeenCalledTimes(1); | |
| }); | |
| it('sends rejected responses with feedback', async () => { | |
| const rpc = new FakeSDKRpcClient(); | |
| const session = new Session({ | |
| id: 'ses_approval_rejected', | |
| workDir: '/tmp', | |
| rpc: rpc.asRpc(), | |
| }); | |
| session.setApprovalHandler(() => ({ decision: 'rejected', feedback: 'No writes.' })); | |
| await expect( | |
| rpc.requestApproval( | |
| session.id, | |
| 'main', | |
| approvalRequest({ | |
| toolCallId: 'tool_2', | |
| toolName: 'Write', | |
| action: 'Write file', | |
| }), | |
| ), | |
| ).resolves.toEqual({ decision: 'rejected', feedback: 'No writes.' }); | |
| }); | |
| it('sends session-scoped approved responses when requested', async () => { | |
| const rpc = new FakeSDKRpcClient(); | |
| const session = new Session({ | |
| id: 'ses_approval_scope', | |
| workDir: '/tmp', | |
| rpc: rpc.asRpc(), | |
| }); | |
| session.setApprovalHandler(() => ({ decision: 'approved', scope: 'session' })); | |
| await expect( | |
| rpc.requestApproval( | |
| session.id, | |
| 'main', | |
| approvalRequest({ | |
| toolCallId: 'tool_scope', | |
| toolName: 'Bash', | |
| action: 'Run command', | |
| }), | |
| ), | |
| ).resolves.toEqual({ decision: 'approved', scope: 'session' }); | |
| }); | |
| it('cancels approval requests when no handler is registered', async () => { | |
| const rpc = new FakeSDKRpcClient(); | |
| const session = new Session({ | |
| id: 'ses_approval_default', | |
| workDir: '/tmp', | |
| rpc: rpc.asRpc(), | |
| }); | |
| await expect( | |
| rpc.requestApproval( | |
| session.id, | |
| 'main', | |
| approvalRequest({ | |
| toolCallId: 'tool_3', | |
| toolName: 'Bash', | |
| action: 'Run command', | |
| }), | |
| ), | |
| ).resolves.toEqual({ | |
| decision: 'cancelled', | |
| feedback: 'No approval handler registered.', | |
| }); | |
| await session.close(); | |
| expect(rpc.closeSession).toHaveBeenCalledWith({ sessionId: session.id }); | |
| }); | |
| it('cancels approval requests when the handler throws', async () => { | |
| const rpc = new FakeSDKRpcClient(); | |
| const session = new Session({ | |
| id: 'ses_approval_throw', | |
| workDir: '/tmp', | |
| rpc: rpc.asRpc(), | |
| }); | |
| session.setApprovalHandler(() => { | |
| throw new Error('boom'); | |
| }); | |
| await expect( | |
| rpc.requestApproval( | |
| session.id, | |
| 'main', | |
| approvalRequest({ | |
| toolCallId: 'tool_4', | |
| toolName: 'Bash', | |
| action: 'Run command', | |
| }), | |
| ), | |
| ).resolves.toEqual({ | |
| decision: 'cancelled', | |
| feedback: 'Approval handler failed.', | |
| }); | |
| }); | |
| it('responds to the original subagent id', async () => { | |
| const rpc = new FakeSDKRpcClient(); | |
| const session = new Session({ | |
| id: 'ses_approval_subagent', | |
| workDir: '/tmp', | |
| rpc: rpc.asRpc(), | |
| }); | |
| const handler = vi.fn(() => ({ decision: 'approved' as const })); | |
| session.setApprovalHandler(handler); | |
| await expect( | |
| rpc.requestApproval( | |
| session.id, | |
| 'agent-1', | |
| approvalRequest({ | |
| toolCallId: 'tool_5', | |
| toolName: 'Read', | |
| action: 'Read file', | |
| }), | |
| ), | |
| ).resolves.toEqual({ decision: 'approved' }); | |
| expect(handler).toHaveBeenCalledWith( | |
| expect.objectContaining({ | |
| sessionId: session.id, | |
| agentId: 'agent-1', | |
| }), | |
| ); | |
| }); | |
| }); | |
| interface ApprovalRequestInput { | |
| readonly toolCallId: string; | |
| readonly toolName: string; | |
| readonly action: string; | |
| } | |
| function approvalRequest(input: ApprovalRequestInput): ApprovalRequest { | |
| return { | |
| toolCallId: input.toolCallId, | |
| toolName: input.toolName, | |
| action: input.action, | |
| display: { kind: 'generic', summary: input.action }, | |
| }; | |
| } | |
| class FakeSDKRpcClient { | |
| private readonly approvalHandlers = new Map<string, ApprovalHandler>(); | |
| readonly closeSession = vi.fn(async (_input: { readonly sessionId: string }) => {}); | |
| asRpc(): SDKRpcClientBase { | |
| return this as unknown as SDKRpcClientBase; | |
| } | |
| setApprovalHandler(sessionId: string, handler: ApprovalHandler | undefined): void { | |
| if (handler === undefined) { | |
| this.approvalHandlers.delete(sessionId); | |
| return; | |
| } | |
| this.approvalHandlers.set(sessionId, handler); | |
| } | |
| async requestApproval( | |
| sessionId: string, | |
| agentId: string, | |
| request: ApprovalRequest, | |
| ): Promise<ApprovalResponse> { | |
| const handler = this.approvalHandlers.get(sessionId); | |
| if (handler === undefined) { | |
| return { | |
| decision: 'cancelled', | |
| feedback: 'No approval handler registered.', | |
| }; | |
| } | |
| try { | |
| return await handler({ ...request, sessionId, agentId } as ApprovalRequest); | |
| } catch { | |
| return { | |
| decision: 'cancelled', | |
| feedback: 'Approval handler failed.', | |
| }; | |
| } | |
| } | |
| clearSessionHandlers(sessionId: string): void { | |
| this.approvalHandlers.delete(sessionId); | |
| } | |
| } | |