mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-15 00:21:09 -07:00
144 lines
3.8 KiB
TypeScript
144 lines
3.8 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2026 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import { describe, it, expect } from 'vitest';
|
|
import { z } from 'zod';
|
|
import { SdkTool, tool, ModelVisibleError } from './tool.js';
|
|
import type { MessageBus } from '@google/gemini-cli-core';
|
|
|
|
// Mock MessageBus
|
|
const mockMessageBus = {} as unknown as MessageBus;
|
|
|
|
describe('tool()', () => {
|
|
it('creates a tool definition with defaults', () => {
|
|
const definition = tool(
|
|
{
|
|
name: 'testTool',
|
|
description: 'A test tool',
|
|
inputSchema: z.object({ foo: z.string() }),
|
|
},
|
|
async () => 'result',
|
|
);
|
|
|
|
expect(definition.name).toBe('testTool');
|
|
expect(definition.description).toBe('A test tool');
|
|
expect(definition.sendErrorsToModel).toBeUndefined();
|
|
});
|
|
|
|
it('creates a tool definition with explicit configuration', () => {
|
|
const definition = tool(
|
|
{
|
|
name: 'testTool',
|
|
description: 'A test tool',
|
|
inputSchema: z.object({ foo: z.string() }),
|
|
sendErrorsToModel: true,
|
|
},
|
|
async () => 'result',
|
|
);
|
|
|
|
expect(definition.sendErrorsToModel).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('SdkTool Execution', () => {
|
|
it('executes successfully', async () => {
|
|
const definition = tool(
|
|
{
|
|
name: 'successTool',
|
|
description: 'Always succeeds',
|
|
inputSchema: z.object({ val: z.string() }),
|
|
},
|
|
async ({ val }) => `Success: ${val}`,
|
|
);
|
|
|
|
const sdkTool = new SdkTool(definition, mockMessageBus);
|
|
const invocation = sdkTool.createInvocationWithContext(
|
|
{ val: 'test' },
|
|
mockMessageBus,
|
|
undefined,
|
|
);
|
|
const result = await invocation.execute(new AbortController().signal);
|
|
|
|
expect(result.llmContent).toBe('Success: test');
|
|
expect(result.error).toBeUndefined();
|
|
});
|
|
|
|
it('throws standard Error by default', async () => {
|
|
const definition = tool(
|
|
{
|
|
name: 'failTool',
|
|
description: 'Always fails',
|
|
inputSchema: z.object({}),
|
|
},
|
|
async () => {
|
|
throw new Error('Standard error');
|
|
},
|
|
);
|
|
|
|
const sdkTool = new SdkTool(definition, mockMessageBus);
|
|
const invocation = sdkTool.createInvocationWithContext(
|
|
{},
|
|
mockMessageBus,
|
|
undefined,
|
|
);
|
|
|
|
await expect(
|
|
invocation.execute(new AbortController().signal),
|
|
).rejects.toThrow('Standard error');
|
|
});
|
|
|
|
it('catches ModelVisibleError and returns ToolResult error', async () => {
|
|
const definition = tool(
|
|
{
|
|
name: 'visibleErrorTool',
|
|
description: 'Fails with visible error',
|
|
inputSchema: z.object({}),
|
|
},
|
|
async () => {
|
|
throw new ModelVisibleError('Visible error');
|
|
},
|
|
);
|
|
|
|
const sdkTool = new SdkTool(definition, mockMessageBus);
|
|
const invocation = sdkTool.createInvocationWithContext(
|
|
{},
|
|
mockMessageBus,
|
|
undefined,
|
|
);
|
|
const result = await invocation.execute(new AbortController().signal);
|
|
|
|
expect(result.error).toBeDefined();
|
|
expect(result.error?.message).toBe('Visible error');
|
|
expect(result.llmContent).toContain('Error: Visible error');
|
|
});
|
|
|
|
it('catches standard Error when sendErrorsToModel is true', async () => {
|
|
const definition = tool(
|
|
{
|
|
name: 'catchAllTool',
|
|
description: 'Catches all errors',
|
|
inputSchema: z.object({}),
|
|
sendErrorsToModel: true,
|
|
},
|
|
async () => {
|
|
throw new Error('Standard error');
|
|
},
|
|
);
|
|
|
|
const sdkTool = new SdkTool(definition, mockMessageBus);
|
|
const invocation = sdkTool.createInvocationWithContext(
|
|
{},
|
|
mockMessageBus,
|
|
undefined,
|
|
);
|
|
const result = await invocation.execute(new AbortController().signal);
|
|
|
|
expect(result.error).toBeDefined();
|
|
expect(result.error?.message).toBe('Standard error');
|
|
expect(result.llmContent).toContain('Error: Standard error');
|
|
});
|
|
});
|