/**
 * @license
 * Copyright 2025 Vybestack LLC
 * SPDX-License-Identifier: Apache-2.0
 *
 * Portions of this code are derived from opencode (https://github.com/sst/opencode)
 * Copyright (c) 2025 opencode
 * Licensed under the MIT License.
 */
import { BaseDeclarativeTool, Kind, } from './tools.js';
import { ToolErrorType } from './tool-error.js';
import { BaseToolInvocation } from './tools.js';
import fetch from 'node-fetch';
const API_CONFIG = {
    BASE_URL: 'https://mcp.exa.ai',
    ENDPOINTS: {
        CONTEXT: '/mcp',
    },
};
export class CodeSearchTool extends BaseDeclarativeTool {
    config;
    static Name = 'codesearch';
    constructor(config) {
        super(CodeSearchTool.Name, 'CodeSearch', 'Search for relevant code snippets, APIs, Libraries, and SDKs documentation. Use this to find examples and usage patterns.', Kind.Search, {
            type: 'object',
            properties: {
                query: {
                    type: 'string',
                    description: "Search query to find relevant context. For example, 'React useState hook examples', 'Python pandas dataframe filtering'.",
                },
                tokensNum: {
                    type: 'number',
                    description: 'Number of tokens to return (1000-50000). Default is 5000 tokens.',
                    default: 5000,
                    minimum: 1000,
                    maximum: 50000,
                },
            },
            required: ['query'],
        });
        this.config = config;
    }
    createInvocation(params) {
        return new CodeSearchToolInvocation(this.config, params);
    }
}
class CodeSearchToolInvocation extends BaseToolInvocation {
    config;
    constructor(config, params) {
        super(params);
        this.config = config;
    }
    getDescription() {
        return `Search code for: ${this.params.query}`;
    }
    async execute(signal, _updateOutput) {
        const codeRequest = {
            jsonrpc: '2.0',
            id: 1,
            method: 'tools/call',
            params: {
                name: 'get_code_context_exa',
                arguments: {
                    query: this.params.query,
                    tokensNum: this.getEffectiveTokensNum(),
                },
            },
        };
        try {
            const headers = {
                accept: 'application/json, text/event-stream',
                'content-type': 'application/json',
            };
            const response = await fetch(`${API_CONFIG.BASE_URL}${API_CONFIG.ENDPOINTS.CONTEXT}`, {
                method: 'POST',
                headers,
                body: JSON.stringify(codeRequest),
                signal,
            });
            if (!response.ok) {
                const errorText = await response.text();
                throw new Error(`Code search error (${response.status}): ${errorText}`);
            }
            const responseText = await response.text();
            // Parse SSE response
            // The response from mcp.exa.ai seems to be SSE format "data: {...}"
            const lines = responseText.split('\n');
            for (const line of lines) {
                if (line.startsWith('data: ')) {
                    try {
                        const data = JSON.parse(line.substring(6));
                        if (data.result &&
                            data.result.content &&
                            data.result.content.length > 0) {
                            const content = data.result.content[0].text;
                            return {
                                llmContent: content,
                                returnDisplay: content,
                            };
                        }
                    }
                    catch (_e) {
                        // Ignore parse errors for intermediate lines
                    }
                }
            }
            return {
                llmContent: 'No code snippets or documentation found. Please try a different query.',
                returnDisplay: 'No results found.',
            };
        }
        catch (error) {
            const errorMessage = error instanceof Error ? error.message : String(error);
            return {
                llmContent: `Error performing code search: ${errorMessage}`,
                returnDisplay: `Error: ${errorMessage}`,
                error: {
                    message: errorMessage,
                    type: ToolErrorType.SEARCH_ERROR,
                },
            };
        }
    }
    getEffectiveTokensNum() {
        // Limits from: https://github.com/exa-labs/exa-mcp-server/blob/1ec2078b59d5e4503696fecf9ce40701ccef85cc/src/tools/exaCode.ts#L14
        const LIMITS = {
            DEFAULT: 5000,
            MIN: 1000,
            MAX: 50000,
        };
        const settingMaxTokens = this.config
            .getSettingsService()
            .get('tool-output-max-tokens');
        // 1. Determine requested tokens (Param > Default)
        let tokens = this.params.tokensNum ?? LIMITS.DEFAULT;
        // 2. Apply setting as a hard cap if present
        if (settingMaxTokens !== undefined &&
            typeof settingMaxTokens === 'number') {
            tokens = Math.min(tokens, settingMaxTokens);
        }
        // 3. Clamp to absolute API limits
        return Math.max(LIMITS.MIN, Math.min(tokens, LIMITS.MAX));
    }
}
//# sourceMappingURL=codesearch.js.map