CoolFace
Datasetpublic

basant307/AI_Governance_Project

sourceHugging Faceapache-2.0updated 2mo agoView on Hugging Face
0likes48downloads
enterPlanMode.test.ts200 linesDownload Raw Back to tools
1/**2 * @license3 * Copyright 2025 Qwen4 * SPDX-License-Identifier: Apache-2.05 */6 7import { describe, it, expect, vi, beforeEach } from 'vitest';8import { EnterPlanModeTool } from './enterPlanMode.js';9import { ApprovalMode, type Config } from '../config/config.js';10import { runWithAgentContext } from '../agents/runtime/agent-context.js';11import { runWithTeammateIdentity } from '../agents/team/identity.js';12 13describe('EnterPlanModeTool', () => {14  let tool: EnterPlanModeTool;15  let mockConfig: Config;16  let approvalMode: ApprovalMode;17  let savedPrePlanMode: ApprovalMode | undefined;18 19  beforeEach(() => {20    approvalMode = ApprovalMode.DEFAULT;21    savedPrePlanMode = undefined;22    mockConfig = {23      getApprovalMode: vi.fn(() => approvalMode),24      getPrePlanMode: vi.fn(() => savedPrePlanMode ?? ApprovalMode.DEFAULT),25      setApprovalMode: vi.fn((mode: ApprovalMode) => {26        if (mode === ApprovalMode.PLAN && approvalMode !== ApprovalMode.PLAN) {27          savedPrePlanMode = approvalMode;28        }29        approvalMode = mode;30      }),31      isInteractive: vi.fn(() => true),32      getExperimentalZedIntegration: vi.fn(() => false),33      getInputFormat: vi.fn(() => undefined),34    } as unknown as Config;35 36    tool = new EnterPlanModeTool(mockConfig);37  });38 39  describe('constructor and metadata', () => {40    it('should have correct tool name', () => {41      expect(tool.name).toBe('enter_plan_mode');42      expect(EnterPlanModeTool.Name).toBe('enter_plan_mode');43    });44 45    it('should have correct display name', () => {46      expect(tool.displayName).toBe('EnterPlanMode');47    });48 49    it('should have correct kind', () => {50      expect(tool.kind).toBe('think');51    });52 53    it('should require user opt-in in the tool description', () => {54      expect(tool.description).toContain(55        'only after the user explicitly asks to switch into plan mode',56      );57      expect(tool.description).toContain(58        'If plan mode seems helpful but the user has not asked for it, ask first',59      );60      expect(tool.description).not.toContain(61        'before doing uncertain or complex work',62      );63      expect(tool.description).not.toContain('if complexity rises');64    });65 66    it('should not defer (always visible)', () => {67      expect(tool.shouldDefer).toBe(false);68    });69 70    it('should have empty-object schema', () => {71      expect(tool.schema.parametersJsonSchema).toEqual({72        type: 'object',73        properties: {},74        additionalProperties: false,75        $schema: 'http://json-schema.org/draft-07/schema#',76      });77    });78  });79 80  describe('getDefaultPermission', () => {81    it('should always return allow', async () => {82      const invocation = tool.build({});83      const permission = await invocation.getDefaultPermission();84      expect(permission).toBe('allow');85    });86  });87 88  describe('execute', () => {89    it('should switch from DEFAULT to PLAN and save prePlanMode', async () => {90      approvalMode = ApprovalMode.DEFAULT;91      const invocation = tool.build({});92      const result = await invocation.execute(new AbortController().signal);93 94      expect(mockConfig.setApprovalMode).toHaveBeenCalledWith(95        ApprovalMode.PLAN,96        { enteredByModel: true },97      );98      expect(approvalMode).toBe(ApprovalMode.PLAN);99      expect(savedPrePlanMode).toBe(ApprovalMode.DEFAULT);100      expect(result.llmContent).toContain('Plan mode is now active');101    });102 103    it('should switch from AUTO_EDIT to PLAN', async () => {104      approvalMode = ApprovalMode.AUTO_EDIT;105      const invocation = tool.build({});106      await invocation.execute(new AbortController().signal);107 108      expect(mockConfig.setApprovalMode).toHaveBeenCalledWith(109        ApprovalMode.PLAN,110        { enteredByModel: true },111      );112      expect(savedPrePlanMode).toBe(ApprovalMode.AUTO_EDIT);113    });114 115    it('should switch from AUTO to PLAN', async () => {116      approvalMode = ApprovalMode.AUTO;117      const invocation = tool.build({});118      await invocation.execute(new AbortController().signal);119 120      expect(mockConfig.setApprovalMode).toHaveBeenCalledWith(121        ApprovalMode.PLAN,122        { enteredByModel: true },123      );124      expect(savedPrePlanMode).toBe(ApprovalMode.AUTO);125    });126 127    it('should switch from YOLO to PLAN', async () => {128      approvalMode = ApprovalMode.YOLO;129      const invocation = tool.build({});130      await invocation.execute(new AbortController().signal);131 132      expect(mockConfig.setApprovalMode).toHaveBeenCalledWith(133        ApprovalMode.PLAN,134        { enteredByModel: true },135      );136      expect(savedPrePlanMode).toBe(ApprovalMode.YOLO);137    });138 139    it('should be idempotent: already in PLAN does not call setApprovalMode', async () => {140      approvalMode = ApprovalMode.PLAN;141      savedPrePlanMode = ApprovalMode.AUTO;142      const invocation = tool.build({});143      const result = await invocation.execute(new AbortController().signal);144 145      expect(mockConfig.setApprovalMode).not.toHaveBeenCalled();146      expect(savedPrePlanMode).toBe(ApprovalMode.AUTO);147      expect(result.llmContent).toContain('Plan mode is now active');148    });149 150    it('should return error when setApprovalMode throws', async () => {151      (152        mockConfig.setApprovalMode as ReturnType<typeof vi.fn>153      ).mockImplementation(() => {154        throw new Error('trust gate');155      });156      const invocation = tool.build({});157      const result = await invocation.execute(new AbortController().signal);158 159      expect(result.llmContent).toContain('Failed to enter plan mode');160      expect(result.llmContent).toContain('trust gate');161    });162 163    it('rejects inside subagent context without changing approval mode', async () => {164      approvalMode = ApprovalMode.DEFAULT;165      const invocation = tool.build({});166 167      const result = await runWithAgentContext('agent-1', () =>168        invocation.execute(new AbortController().signal),169      );170 171      expect(result.llmContent).toContain('not available inside subagents');172      expect(result.llmContent).toContain('return your plan');173      expect(result.error?.message).toBe(result.llmContent);174      expect(mockConfig.setApprovalMode).not.toHaveBeenCalled();175      expect(approvalMode).toBe(ApprovalMode.DEFAULT);176    });177 178    it('rejects inside teammate context without changing approval mode', async () => {179      approvalMode = ApprovalMode.AUTO_EDIT;180      const invocation = tool.build({});181 182      const result = await runWithTeammateIdentity(183        {184          agentId: 'agent@test',185          agentName: 'agent',186          teamName: 'test',187          isTeamLead: false,188        },189        () => invocation.execute(new AbortController().signal),190      );191 192      expect(result.llmContent).toContain('not available inside subagents');193      expect(result.llmContent).toContain('return your plan');194      expect(result.error?.message).toBe(result.llmContent);195      expect(mockConfig.setApprovalMode).not.toHaveBeenCalled();196      expect(approvalMode).toBe(ApprovalMode.AUTO_EDIT);197    });198  });199});200 
basant307/AI_Governance_Project · CoolFace