Path: blob/main/src/vs/workbench/contrib/chat/test/common/chatHandoffs.test.ts
13406 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import assert from 'assert';6import { constObservable, observableValue } from '../../../../../base/common/observable.js';7import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';8import { buildCustomAgentHandoffsInfo, getHandoffId, IChatMode } from '../../common/chatModes.js';9import { ChatModeKind } from '../../common/constants.js';10import { IHandOff } from '../../common/promptSyntax/promptFileParser.js';11import { Target } from '../../common/promptSyntax/promptTypes.js';1213function createMockMode(overrides: Partial<IChatMode> & { id: string; kind: ChatModeKind }): IChatMode {14return {15name: constObservable(overrides.id),16label: constObservable(overrides.id),17icon: constObservable(undefined),18description: constObservable(undefined),19isBuiltin: overrides.isBuiltin ?? false,20target: constObservable(Target.Undefined),21...overrides,22} as IChatMode;23}2425suite('getHandoffId', () => {26ensureNoDisposablesAreLeakedInTestSuite();2728test('should generate a stable id from agent and label', () => {29const handoff: IHandOff = { agent: 'agent', label: 'Start Implementation', prompt: 'go' };30assert.strictEqual(getHandoffId(handoff), 'agent:start-implementation');31});3233test('should handle special characters in label', () => {34const handoff: IHandOff = { agent: 'edit', label: 'Open in Editor!', prompt: '' };35assert.strictEqual(getHandoffId(handoff), 'edit:open-in-editor');36});3738test('should handle single-word label', () => {39const handoff: IHandOff = { agent: 'agent', label: 'Continue', prompt: '' };40assert.strictEqual(getHandoffId(handoff), 'agent:continue');41});42});4344suite('buildCustomAgentHandoffsInfo', () => {45ensureNoDisposablesAreLeakedInTestSuite();4647test('should return empty handoffs for modes without handOffs', () => {48const mode = createMockMode({49id: 'ask',50kind: ChatModeKind.Ask,51isBuiltin: true,52});5354const result = buildCustomAgentHandoffsInfo([mode]);55assert.deepStrictEqual(result, [{56id: 'ask',57name: 'ask',58isBuiltin: true,59visibility: { userInvocable: true, agentInvocable: true },60handoffs: [],61}]);62});6364test('should map handoffs with all fields', () => {65const handoffs: IHandOff[] = [66{ agent: 'agent', label: 'Start Implementation', prompt: 'Start implementation', send: true, model: 'gpt-4o' },67{ agent: 'agent', label: 'Open in Editor', prompt: 'Open the plan', showContinueOn: false },68];69const mode = createMockMode({70id: 'plan-mode',71kind: ChatModeKind.Agent,72handOffs: observableValue('handOffs', handoffs),73visibility: observableValue('visibility', { userInvocable: true, agentInvocable: false }),74});7576const result = buildCustomAgentHandoffsInfo([mode]);77assert.deepStrictEqual(result, [{78id: 'plan-mode',79name: 'plan-mode',80isBuiltin: false,81visibility: { userInvocable: true, agentInvocable: false },82handoffs: [83{ id: 'agent:start-implementation', label: 'Start Implementation', agent: 'agent', prompt: 'Start implementation', send: true, model: 'gpt-4o' },84{ id: 'agent:open-in-editor', label: 'Open in Editor', agent: 'agent', prompt: 'Open the plan', showContinueOn: false },85],86}]);87});8889test('should handle multiple modes', () => {90const askMode = createMockMode({ id: 'ask', kind: ChatModeKind.Ask, isBuiltin: true });91const agentMode = createMockMode({ id: 'agent', kind: ChatModeKind.Agent, isBuiltin: true });9293const result = buildCustomAgentHandoffsInfo([askMode, agentMode]);94assert.deepStrictEqual(result, [95{96id: 'ask',97name: 'ask',98isBuiltin: true,99visibility: { userInvocable: true, agentInvocable: true },100handoffs: [],101},102{103id: 'agent',104name: 'agent',105isBuiltin: true,106visibility: { userInvocable: true, agentInvocable: true },107handoffs: [],108},109]);110});111112test('should omit optional handoff fields when undefined', () => {113const handoffs: IHandOff[] = [114{ agent: 'agent', label: 'Go', prompt: 'do it' },115];116const mode = createMockMode({117id: 'test',118kind: ChatModeKind.Agent,119handOffs: observableValue('handOffs', handoffs),120});121122const result = buildCustomAgentHandoffsInfo([mode]);123const info = result[0].handoffs[0];124assert.strictEqual(info.id, 'agent:go');125assert.strictEqual(info.send, undefined);126assert.strictEqual(info.showContinueOn, undefined);127assert.strictEqual(info.model, undefined);128});129});130131132