/**
 * @license
 * Copyright 2026 HopCode Team Team
 * SPDX-License-Identifier: Apache-2.0
 */
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { ToolErrorType, MCPServerStatus, getMCPServerStatus, OutputFormat, } from '@hoptrendy/hopcode-core';
import { normalizePartList, extractPartsFromUserMessage, extractUsageFromGeminiClient, computeUsageFromMetrics, buildSystemMessage, createToolProgressHandler, createAgentToolProgressHandler, functionResponsePartsToString, toolResultContent, } from './nonInteractiveHelpers.js';
// Mock dependencies
vi.mock('../nonInteractiveCliCommands.js', () => ({
    getAvailableCommands: vi
        .fn()
        .mockImplementation(async (_config, _signal, mode = 'acp') => {
        const allCommands = [
            {
                name: 'help',
                supportedModes: ['interactive'],
            },
            {
                name: 'commit',
                supportedModes: ['interactive', 'non_interactive', 'acp'],
            },
            {
                name: 'memory',
                supportedModes: ['interactive'],
            },
            {
                name: 'init',
                supportedModes: ['interactive', 'non_interactive', 'acp'],
            },
            {
                name: 'summary',
                supportedModes: ['interactive', 'non_interactive', 'acp'],
            },
            {
                name: 'compress',
                supportedModes: ['interactive', 'non_interactive', 'acp'],
            },
        ];
        return allCommands.filter((cmd) => cmd.supportedModes.includes(mode));
    }),
}));
vi.mock('../ui/utils/computeStats.js', () => ({
    computeSessionStats: vi.fn().mockReturnValue({
        totalPromptTokens: 100,
        totalCachedTokens: 20,
    }),
}));
vi.mock('@hoptrendy/hopcode-core', async (importOriginal) => {
    const actual = await importOriginal();
    return {
        ...actual,
        getMCPServerStatus: vi.fn(),
    };
});
describe('normalizePartList', () => {
    it('should return empty array for null input', () => {
        expect(normalizePartList(null)).toEqual([]);
    });
    it('should return empty array for undefined input', () => {
        expect(normalizePartList(undefined)).toEqual([]);
    });
    it('should convert string to Part array', () => {
        const result = normalizePartList('test string');
        expect(result).toEqual([{ text: 'test string' }]);
    });
    it('should convert array of strings to Part array', () => {
        const result = normalizePartList(['hello', 'world']);
        expect(result).toEqual([{ text: 'hello' }, { text: 'world' }]);
    });
    it('should convert array of mixed strings and Parts to Part array', () => {
        const part = { text: 'existing' };
        const result = normalizePartList(['new', part]);
        expect(result).toEqual([{ text: 'new' }, part]);
    });
    it('should convert single Part object to array', () => {
        const part = { text: 'single part' };
        const result = normalizePartList(part);
        expect(result).toEqual([part]);
    });
    it('should handle empty array', () => {
        expect(normalizePartList([])).toEqual([]);
    });
});
describe('extractPartsFromUserMessage', () => {
    it('should return null for undefined message', () => {
        expect(extractPartsFromUserMessage(undefined)).toBeNull();
    });
    it('should return null for null message', () => {
        expect(extractPartsFromUserMessage(null)).toBeNull();
    });
    it('should extract string content', () => {
        const message = {
            type: 'user',
            session_id: 'test-session',
            message: {
                role: 'user',
                content: 'test message',
            },
            parent_tool_use_id: null,
        };
        expect(extractPartsFromUserMessage(message)).toBe('test message');
    });
    it('should extract text blocks from content array', () => {
        const message = {
            type: 'user',
            session_id: 'test-session',
            message: {
                role: 'user',
                content: [
                    { type: 'text', text: 'hello' },
                    { type: 'text', text: 'world' },
                ],
            },
            parent_tool_use_id: null,
        };
        const result = extractPartsFromUserMessage(message);
        expect(result).toEqual([{ text: 'hello' }, { text: 'world' }]);
    });
    it('should skip invalid blocks in content array', () => {
        const message = {
            type: 'user',
            session_id: 'test-session',
            message: {
                role: 'user',
                content: [
                    { type: 'text', text: 'valid' },
                    null,
                    { type: 'text', text: 'also valid' },
                ],
            },
            parent_tool_use_id: null,
        };
        const result = extractPartsFromUserMessage(message);
        expect(result).toEqual([{ text: 'valid' }, { text: 'also valid' }]);
    });
    it('should convert non-text blocks to JSON strings', () => {
        const message = {
            type: 'user',
            session_id: 'test-session',
            message: {
                role: 'user',
                content: [
                    { type: 'text', text: 'text block' },
                    { type: 'tool_use', id: '123', name: 'tool', input: {} },
                ],
            },
            parent_tool_use_id: null,
        };
        const result = extractPartsFromUserMessage(message);
        expect(result).toEqual([
            { text: 'text block' },
            {
                text: JSON.stringify({
                    type: 'tool_use',
                    id: '123',
                    name: 'tool',
                    input: {},
                }),
            },
        ]);
    });
    it('should return null for empty content array', () => {
        const message = {
            type: 'user',
            session_id: 'test-session',
            message: {
                role: 'user',
                content: [],
            },
            parent_tool_use_id: null,
        };
        expect(extractPartsFromUserMessage(message)).toBeNull();
    });
    it('should return null when message has no content', () => {
        const message = {
            type: 'user',
            session_id: 'test-session',
            message: {
                role: 'user',
                content: undefined,
            },
            parent_tool_use_id: null,
        };
        expect(extractPartsFromUserMessage(message)).toBeNull();
    });
});
describe('extractUsageFromGeminiClient', () => {
    it('should return undefined for null client', () => {
        expect(extractUsageFromGeminiClient(null)).toBeUndefined();
    });
    it('should return undefined for non-object client', () => {
        expect(extractUsageFromGeminiClient('not an object')).toBeUndefined();
    });
    it('should return undefined when getChat is not a function', () => {
        const client = { getChat: 'not a function' };
        expect(extractUsageFromGeminiClient(client)).toBeUndefined();
    });
    it('should return undefined when chat does not have getDebugResponses', () => {
        const client = {
            getChat: vi.fn().mockReturnValue({}),
        };
        expect(extractUsageFromGeminiClient(client)).toBeUndefined();
    });
    it('should extract usage from latest response with usageMetadata', () => {
        const client = {
            getChat: vi.fn().mockReturnValue({
                getDebugResponses: vi.fn().mockReturnValue([
                    { usageMetadata: { promptTokenCount: 50 } },
                    {
                        usageMetadata: {
                            promptTokenCount: 100,
                            candidatesTokenCount: 200,
                            totalTokenCount: 300,
                            cachedContentTokenCount: 10,
                        },
                    },
                ]),
            }),
        };
        const result = extractUsageFromGeminiClient(client);
        expect(result).toEqual({
            input_tokens: 100,
            output_tokens: 200,
            total_tokens: 300,
            cache_read_input_tokens: 10,
        });
    });
    it('should return default values when metadata values are not numbers', () => {
        const client = {
            getChat: vi.fn().mockReturnValue({
                getDebugResponses: vi.fn().mockReturnValue([
                    {
                        usageMetadata: {
                            promptTokenCount: 'not a number',
                            candidatesTokenCount: null,
                        },
                    },
                ]),
            }),
        };
        const result = extractUsageFromGeminiClient(client);
        expect(result).toEqual({
            input_tokens: 0,
            output_tokens: 0,
        });
    });
    it('should handle errors gracefully', () => {
        const client = {
            getChat: vi.fn().mockImplementation(() => {
                throw new Error('Test error');
            }),
        };
        const result = extractUsageFromGeminiClient(client);
        expect(result).toBeUndefined();
    });
    it('should skip responses without usageMetadata', () => {
        const client = {
            getChat: vi.fn().mockReturnValue({
                getDebugResponses: vi.fn().mockReturnValue([
                    { someOtherData: 'value' },
                    {
                        usageMetadata: {
                            promptTokenCount: 50,
                            candidatesTokenCount: 75,
                        },
                    },
                ]),
            }),
        };
        const result = extractUsageFromGeminiClient(client);
        expect(result).toEqual({
            input_tokens: 50,
            output_tokens: 75,
        });
    });
});
describe('computeUsageFromMetrics', () => {
    it('should compute usage from SessionMetrics with single model', () => {
        const metrics = {
            models: {
                'model-1': {
                    api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 100 },
                    tokens: {
                        prompt: 50,
                        candidates: 100,
                        total: 150,
                        cached: 10,
                        thoughts: 0,
                    },
                    bySource: {},
                },
            },
            tools: {
                totalCalls: 0,
                totalSuccess: 0,
                totalFail: 0,
                totalDurationMs: 0,
                totalDecisions: {
                    accept: 0,
                    reject: 0,
                    modify: 0,
                    auto_accept: 0,
                },
                byName: {},
            },
            files: {
                totalLinesAdded: 0,
                totalLinesRemoved: 0,
            },
        };
        const result = computeUsageFromMetrics(metrics);
        expect(result).toEqual({
            input_tokens: 100,
            output_tokens: 100,
            cache_read_input_tokens: 20,
            total_tokens: 150,
        });
    });
    it('should aggregate usage across multiple models', () => {
        const metrics = {
            models: {
                'model-1': {
                    api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 100 },
                    tokens: {
                        prompt: 50,
                        candidates: 100,
                        total: 150,
                        cached: 10,
                        thoughts: 0,
                    },
                    bySource: {},
                },
                'model-2': {
                    api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 100 },
                    tokens: {
                        prompt: 75,
                        candidates: 125,
                        total: 200,
                        cached: 15,
                        thoughts: 0,
                    },
                    bySource: {},
                },
            },
            tools: {
                totalCalls: 0,
                totalSuccess: 0,
                totalFail: 0,
                totalDurationMs: 0,
                totalDecisions: {
                    accept: 0,
                    reject: 0,
                    modify: 0,
                    auto_accept: 0,
                },
                byName: {},
            },
            files: {
                totalLinesAdded: 0,
                totalLinesRemoved: 0,
            },
        };
        const result = computeUsageFromMetrics(metrics);
        expect(result).toEqual({
            input_tokens: 100,
            output_tokens: 225,
            cache_read_input_tokens: 20,
            total_tokens: 350,
        });
    });
    it('should not include total_tokens when it is 0', () => {
        const metrics = {
            models: {
                'model-1': {
                    api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 100 },
                    tokens: {
                        prompt: 50,
                        candidates: 100,
                        total: 0,
                        cached: 10,
                        thoughts: 0,
                    },
                    bySource: {},
                },
            },
            tools: {
                totalCalls: 0,
                totalSuccess: 0,
                totalFail: 0,
                totalDurationMs: 0,
                totalDecisions: {
                    accept: 0,
                    reject: 0,
                    modify: 0,
                    auto_accept: 0,
                },
                byName: {},
            },
            files: {
                totalLinesAdded: 0,
                totalLinesRemoved: 0,
            },
        };
        const result = computeUsageFromMetrics(metrics);
        expect(result).not.toHaveProperty('total_tokens');
        expect(result).toEqual({
            input_tokens: 100,
            output_tokens: 100,
            cache_read_input_tokens: 20,
        });
    });
    it('should handle empty models', () => {
        const metrics = {
            models: {},
            tools: {
                totalCalls: 0,
                totalSuccess: 0,
                totalFail: 0,
                totalDurationMs: 0,
                totalDecisions: {
                    accept: 0,
                    reject: 0,
                    modify: 0,
                    auto_accept: 0,
                },
                byName: {},
            },
            files: {
                totalLinesAdded: 0,
                totalLinesRemoved: 0,
            },
        };
        const result = computeUsageFromMetrics(metrics);
        expect(result).toEqual({
            input_tokens: 100,
            output_tokens: 0,
            cache_read_input_tokens: 20,
        });
    });
});
describe('buildSystemMessage', () => {
    let mockConfig;
    beforeEach(() => {
        vi.clearAllMocks();
        // Mock getMCPServerStatus to return CONNECTED by default
        vi.mocked(getMCPServerStatus).mockReturnValue(MCPServerStatus.CONNECTED);
        mockConfig = {
            getToolRegistry: vi.fn().mockReturnValue({
                getAllToolNames: vi.fn().mockReturnValue(['tool1', 'tool2']),
            }),
            getMcpServers: vi.fn().mockReturnValue({
                'mcp-server-1': {},
                'mcp-server-2': {},
            }),
            getTargetDir: vi.fn().mockReturnValue('/test/dir'),
            getModel: vi.fn().mockReturnValue('test-model'),
            getCliVersion: vi.fn().mockReturnValue('1.0.0'),
            getDebugMode: vi.fn().mockReturnValue(false),
        };
    });
    it('should build system message with all fields', async () => {
        const result = await buildSystemMessage(mockConfig, 'test-session-id', 'auto');
        expect(result).toEqual({
            type: 'system',
            subtype: 'init',
            uuid: 'test-session-id',
            session_id: 'test-session-id',
            cwd: '/test/dir',
            tools: ['tool1', 'tool2'],
            mcp_servers: [
                { name: 'mcp-server-1', status: 'connected' },
                { name: 'mcp-server-2', status: 'connected' },
            ],
            model: 'test-model',
            permission_mode: 'auto',
            slash_commands: ['commit', 'compress', 'init', 'summary'],
            HOPCODE_version: '1.0.0',
            agents: [],
        });
    });
    it('should handle empty tool registry', async () => {
        const config = {
            ...mockConfig,
            getToolRegistry: vi.fn().mockReturnValue(null),
        };
        const result = await buildSystemMessage(config, 'test-session-id', 'auto');
        expect(result.tools).toEqual([]);
    });
    it('should handle empty MCP servers', async () => {
        const config = {
            ...mockConfig,
            getMcpServers: vi.fn().mockReturnValue(null),
        };
        const result = await buildSystemMessage(config, 'test-session-id', 'auto');
        expect(result.mcp_servers).toEqual([]);
    });
    it('should use unknown version when getCliVersion returns null', async () => {
        const config = {
            ...mockConfig,
            getCliVersion: vi.fn().mockReturnValue(null),
        };
        const result = await buildSystemMessage(config, 'test-session-id', 'auto');
        expect(result.HOPCODE_version).toBe('unknown');
    });
    it('should include local commands with ACP supportedModes and prompt commands', async () => {
        const result = await buildSystemMessage(mockConfig, 'test-session-id', 'auto');
        // Should include: 'commit' (prompt), 'compress', 'init', 'summary' (local+ACP)
        // Should NOT include: 'help' (local-jsx), 'memory' (local without ACP supportedModes)
        expect(result.slash_commands).toEqual([
            'commit',
            'compress',
            'init',
            'summary',
        ]);
    });
    it('should exclude interactive-only commands from system message', async () => {
        const result = await buildSystemMessage(mockConfig, 'test-session-id', 'auto');
        // 'help' (local-jsx) and 'memory' (local without ACP) should be excluded
        expect(result.slash_commands).not.toContain('help');
        expect(result.slash_commands).not.toContain('memory');
    });
});
describe('createToolProgressHandler', () => {
    const mockRequest = {
        callId: 'tool-call-1',
        name: 'mcp__echo-test__echo',
        args: {},
        isClientInitiated: false,
        prompt_id: '',
    };
    it('should call emitToolProgress with request and McpToolProgressData', () => {
        const mockAdapter = {
            emitToolProgress: vi.fn(),
        };
        const { handler } = createToolProgressHandler(mockRequest, mockAdapter);
        const progressData = {
            type: 'mcp_tool_progress',
            progress: 1,
            total: 10,
            message: 'Echo: 1',
        };
        handler('tool-call-1', progressData);
        expect(mockAdapter.emitToolProgress).toHaveBeenCalledWith(mockRequest, progressData);
    });
    it('should not call emitToolProgress for non-McpToolProgressData output', () => {
        const mockAdapter = {
            emitToolProgress: vi.fn(),
        };
        const { handler } = createToolProgressHandler({ ...mockRequest, name: 'test_tool' }, mockAdapter);
        // Pass a non-McpToolProgressData ToolResultDisplay (e.g., FileDiff)
        handler('tool-call-1', {
            fileDiff: 'diff',
            fileName: 'test.ts',
            originalContent: null,
            newContent: 'new',
        });
        expect(mockAdapter.emitToolProgress).not.toHaveBeenCalled();
        // Also test with a plain string � should not emit
        handler('tool-call-1', 'plain string progress');
        expect(mockAdapter.emitToolProgress).not.toHaveBeenCalled();
    });
    it('should forward multiple progress updates', () => {
        const mockAdapter = {
            emitToolProgress: vi.fn(),
        };
        const browserRequest = {
            ...mockRequest,
            name: 'mcp__browser__navigate',
        };
        const { handler } = createToolProgressHandler(browserRequest, mockAdapter);
        const progress1 = {
            type: 'mcp_tool_progress',
            progress: 1,
            total: 3,
            message: 'Navigating...',
        };
        const progress2 = {
            type: 'mcp_tool_progress',
            progress: 2,
            total: 3,
            message: 'Loading page...',
        };
        const progress3 = {
            type: 'mcp_tool_progress',
            progress: 3,
            total: 3,
            message: 'Complete',
        };
        handler('tool-call-1', progress1);
        handler('tool-call-1', progress2);
        handler('tool-call-1', progress3);
        expect(mockAdapter.emitToolProgress).toHaveBeenCalledTimes(3);
        expect(mockAdapter.emitToolProgress).toHaveBeenNthCalledWith(1, browserRequest, progress1);
        expect(mockAdapter.emitToolProgress).toHaveBeenNthCalledWith(2, browserRequest, progress2);
        expect(mockAdapter.emitToolProgress).toHaveBeenNthCalledWith(3, browserRequest, progress3);
    });
});
describe('createAgentToolProgressHandler', () => {
    let mockAdapter;
    let mockConfig;
    beforeEach(() => {
        mockConfig = {
            getDebugMode: vi.fn().mockReturnValue(false),
            isInteractive: vi.fn().mockReturnValue(false),
            getOutputFormat: vi.fn().mockReturnValue(OutputFormat.JSON),
        };
        mockAdapter = {
            processSubagentToolCall: vi.fn(),
            emitSubagentErrorResult: vi.fn(),
            emitToolResult: vi.fn(),
            emitUserMessage: vi.fn(),
        };
    });
    it('should create handler that processes task tool calls', () => {
        const { handler } = createAgentToolProgressHandler(mockConfig, 'parent-tool-id', mockAdapter);
        const taskDisplay = {
            type: 'task_execution',
            subagentName: 'test-agent',
            taskDescription: 'Test task',
            taskPrompt: 'Test prompt',
            status: 'running',
            toolCalls: [
                {
                    callId: 'tool-1',
                    name: 'test_tool',
                    args: { arg1: 'value1' },
                    status: 'executing',
                },
            ],
        };
        handler('task-call-id', taskDisplay);
        expect(mockAdapter.processSubagentToolCall).toHaveBeenCalledWith(expect.objectContaining({
            callId: 'tool-1',
            name: 'test_tool',
            status: 'executing',
        }), 'parent-tool-id');
    });
    it('should emit tool_result when tool call completes', () => {
        const { handler } = createAgentToolProgressHandler(mockConfig, 'parent-tool-id', mockAdapter);
        const taskDisplay = {
            type: 'task_execution',
            subagentName: 'test-agent',
            taskDescription: 'Test task',
            taskPrompt: 'Test prompt',
            status: 'running',
            toolCalls: [
                {
                    callId: 'tool-1',
                    name: 'test_tool',
                    args: { arg1: 'value1' },
                    status: 'success',
                    resultDisplay: 'Success result',
                },
            ],
        };
        handler('task-call-id', taskDisplay);
        expect(mockAdapter.emitToolResult).toHaveBeenCalledWith(expect.objectContaining({
            callId: 'tool-1',
            name: 'test_tool',
        }), expect.objectContaining({
            callId: 'tool-1',
            resultDisplay: 'Success result',
        }), 'parent-tool-id');
    });
    it('should not duplicate tool_use emissions', () => {
        const { handler } = createAgentToolProgressHandler(mockConfig, 'parent-tool-id', mockAdapter);
        const taskDisplay = {
            type: 'task_execution',
            subagentName: 'test-agent',
            taskDescription: 'Test task',
            taskPrompt: 'Test prompt',
            status: 'running',
            toolCalls: [
                {
                    callId: 'tool-1',
                    name: 'test_tool',
                    args: {},
                    status: 'executing',
                },
            ],
        };
        // Call handler twice with same tool call
        handler('task-call-id', taskDisplay);
        handler('task-call-id', taskDisplay);
        expect(mockAdapter.processSubagentToolCall).toHaveBeenCalledTimes(1);
    });
    it('should not duplicate tool_result emissions', () => {
        const { handler } = createAgentToolProgressHandler(mockConfig, 'parent-tool-id', mockAdapter);
        const taskDisplay = {
            type: 'task_execution',
            subagentName: 'test-agent',
            taskDescription: 'Test task',
            taskPrompt: 'Test prompt',
            status: 'running',
            toolCalls: [
                {
                    callId: 'tool-1',
                    name: 'test_tool',
                    args: {},
                    status: 'success',
                    resultDisplay: 'Result',
                },
            ],
        };
        // Call handler twice with same completed tool call
        handler('task-call-id', taskDisplay);
        handler('task-call-id', taskDisplay);
        expect(mockAdapter.emitToolResult).toHaveBeenCalledTimes(1);
    });
    it('should handle status transitions from executing to completed', () => {
        const { handler } = createAgentToolProgressHandler(mockConfig, 'parent-tool-id', mockAdapter);
        // First: executing state
        const executingDisplay = {
            type: 'task_execution',
            subagentName: 'test-agent',
            taskDescription: 'Test task',
            taskPrompt: 'Test prompt',
            status: 'running',
            toolCalls: [
                {
                    callId: 'tool-1',
                    name: 'test_tool',
                    args: {},
                    status: 'executing',
                },
            ],
        };
        // Second: completed state
        const completedDisplay = {
            type: 'task_execution',
            subagentName: 'test-agent',
            taskDescription: 'Test task',
            taskPrompt: 'Test prompt',
            status: 'running',
            toolCalls: [
                {
                    callId: 'tool-1',
                    name: 'test_tool',
                    args: {},
                    status: 'success',
                    resultDisplay: 'Done',
                },
            ],
        };
        handler('task-call-id', executingDisplay);
        handler('task-call-id', completedDisplay);
        expect(mockAdapter.processSubagentToolCall).toHaveBeenCalledTimes(1);
        expect(mockAdapter.emitToolResult).toHaveBeenCalledTimes(1);
    });
    it('should emit error result for failed task status', () => {
        const { handler } = createAgentToolProgressHandler(mockConfig, 'parent-tool-id', mockAdapter);
        const runningDisplay = {
            type: 'task_execution',
            subagentName: 'test-agent',
            taskDescription: 'Test task',
            taskPrompt: 'Test prompt',
            status: 'running',
            toolCalls: [],
        };
        const failedDisplay = {
            type: 'task_execution',
            subagentName: 'test-agent',
            taskDescription: 'Test task',
            taskPrompt: 'Test prompt',
            status: 'failed',
            terminateReason: 'Task failed with error',
            toolCalls: [],
        };
        handler('task-call-id', runningDisplay);
        handler('task-call-id', failedDisplay);
        expect(mockAdapter.emitSubagentErrorResult).toHaveBeenCalledWith('Task failed with error', 0, 'parent-tool-id');
    });
    it('should emit error result for cancelled task status', () => {
        const { handler } = createAgentToolProgressHandler(mockConfig, 'parent-tool-id', mockAdapter);
        const runningDisplay = {
            type: 'task_execution',
            subagentName: 'test-agent',
            taskDescription: 'Test task',
            taskPrompt: 'Test prompt',
            status: 'running',
            toolCalls: [],
        };
        const cancelledDisplay = {
            type: 'task_execution',
            subagentName: 'test-agent',
            taskDescription: 'Test task',
            taskPrompt: 'Test prompt',
            status: 'cancelled',
            toolCalls: [],
        };
        handler('task-call-id', runningDisplay);
        handler('task-call-id', cancelledDisplay);
        expect(mockAdapter.emitSubagentErrorResult).toHaveBeenCalledWith('Task was cancelled', 0, 'parent-tool-id');
    });
    it('should not process non-task-execution displays', () => {
        const { handler } = createAgentToolProgressHandler(mockConfig, 'parent-tool-id', mockAdapter);
        const nonTaskDisplay = {
            type: 'other',
            content: 'some content',
        };
        handler('call-id', nonTaskDisplay);
        expect(mockAdapter.processSubagentToolCall).not.toHaveBeenCalled();
        expect(mockAdapter.emitToolResult).not.toHaveBeenCalled();
    });
    it('should handle tool calls with failed status', () => {
        const { handler } = createAgentToolProgressHandler(mockConfig, 'parent-tool-id', mockAdapter);
        const taskDisplay = {
            type: 'task_execution',
            subagentName: 'test-agent',
            taskDescription: 'Test task',
            taskPrompt: 'Test prompt',
            status: 'running',
            toolCalls: [
                {
                    callId: 'tool-1',
                    name: 'test_tool',
                    args: {},
                    status: 'failed',
                    error: 'Tool execution failed',
                },
            ],
        };
        handler('task-call-id', taskDisplay);
        expect(mockAdapter.emitToolResult).toHaveBeenCalledWith(expect.anything(), expect.objectContaining({
            callId: 'tool-1',
            error: expect.any(Error),
            errorType: ToolErrorType.EXECUTION_FAILED,
        }), 'parent-tool-id');
    });
    it('should handle tool calls without result content', () => {
        const { handler } = createAgentToolProgressHandler(mockConfig, 'parent-tool-id', mockAdapter);
        const taskDisplay = {
            type: 'task_execution',
            subagentName: 'test-agent',
            taskDescription: 'Test task',
            taskPrompt: 'Test prompt',
            status: 'running',
            toolCalls: [
                {
                    callId: 'tool-1',
                    name: 'test_tool',
                    args: {},
                    status: 'success',
                    resultDisplay: '',
                    responseParts: [],
                },
            ],
        };
        handler('task-call-id', taskDisplay);
        // Should not emit tool_result if no content
        expect(mockAdapter.emitToolResult).not.toHaveBeenCalled();
    });
    it('should work with adapter that does not support subagent APIs', () => {
        const limitedAdapter = {
            emitToolResult: vi.fn(),
        };
        const { handler } = createAgentToolProgressHandler(mockConfig, 'parent-tool-id', limitedAdapter);
        const taskDisplay = {
            type: 'task_execution',
            subagentName: 'test-agent',
            taskDescription: 'Test task',
            taskPrompt: 'Test prompt',
            status: 'running',
            toolCalls: [],
        };
        // Should not throw
        expect(() => handler('task-call-id', taskDisplay)).not.toThrow();
    });
});
describe('functionResponsePartsToString', () => {
    it('should extract output from functionResponse parts', () => {
        const parts = [
            {
                functionResponse: {
                    response: {
                        output: 'function output',
                    },
                },
            },
        ];
        expect(functionResponsePartsToString(parts)).toBe('function output');
    });
    it('should handle multiple functionResponse parts', () => {
        const parts = [
            {
                functionResponse: {
                    response: {
                        output: 'output1',
                    },
                },
            },
            {
                functionResponse: {
                    response: {
                        output: 'output2',
                    },
                },
            },
        ];
        expect(functionResponsePartsToString(parts)).toBe('output1output2');
    });
    it('should return empty string for missing output', () => {
        const parts = [
            {
                functionResponse: {
                    response: {},
                },
            },
        ];
        expect(functionResponsePartsToString(parts)).toBe('');
    });
    it('should JSON.stringify non-functionResponse parts', () => {
        const parts = [
            { text: 'text part' },
            {
                functionResponse: {
                    response: {
                        output: 'function output',
                    },
                },
            },
        ];
        const result = functionResponsePartsToString(parts);
        expect(result).toContain('function output');
        expect(result).toContain('text part');
    });
    it('should handle empty array', () => {
        expect(functionResponsePartsToString([])).toBe('');
    });
    it('should handle functionResponse with null response', () => {
        const parts = [
            {
                functionResponse: {
                    response: null,
                },
            },
        ];
        expect(functionResponsePartsToString(parts)).toBe('');
    });
});
describe('toolResultContent', () => {
    it('should return resultDisplay string when available', () => {
        const response = {
            callId: 'test-call',
            resultDisplay: 'Result content',
            responseParts: [],
            error: undefined,
            errorType: undefined,
        };
        expect(toolResultContent(response)).toBe('Result content');
    });
    it('should return undefined for empty resultDisplay string', () => {
        const response = {
            callId: 'test-call',
            resultDisplay: '   ',
            responseParts: [],
            error: undefined,
            errorType: undefined,
        };
        expect(toolResultContent(response)).toBeUndefined();
    });
    it('should use functionResponsePartsToString for responseParts', () => {
        const response = {
            callId: 'test-call',
            resultDisplay: undefined,
            responseParts: [
                {
                    functionResponse: {
                        response: {
                            output: 'function output',
                        },
                    },
                },
            ],
            error: undefined,
            errorType: undefined,
        };
        expect(toolResultContent(response)).toBe('function output');
    });
    it('should return error message when error is present', () => {
        const response = {
            callId: 'test-call',
            resultDisplay: undefined,
            responseParts: [],
            error: new Error('Test error message'),
            errorType: undefined,
        };
        expect(toolResultContent(response)).toBe('Test error message');
    });
    it('should prefer resultDisplay over responseParts', () => {
        const response = {
            callId: 'test-call',
            resultDisplay: 'Direct result',
            responseParts: [
                {
                    functionResponse: {
                        response: {
                            output: 'function output',
                        },
                    },
                },
            ],
            error: undefined,
            errorType: undefined,
        };
        expect(toolResultContent(response)).toBe('Direct result');
    });
    it('should prefer responseParts over error', () => {
        const response = {
            callId: 'test-call',
            resultDisplay: undefined,
            error: new Error('Error message'),
            responseParts: [
                {
                    functionResponse: {
                        response: {
                            output: 'function output',
                        },
                    },
                },
            ],
            errorType: undefined,
        };
        expect(toolResultContent(response)).toBe('function output');
    });
    it('should return undefined when no content is available', () => {
        const response = {
            callId: 'test-call',
            resultDisplay: undefined,
            responseParts: [],
            error: undefined,
            errorType: undefined,
        };
        expect(toolResultContent(response)).toBeUndefined();
    });
});
//# sourceMappingURL=nonInteractiveHelpers.test.js.map