"use strict";
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2024-2026 Gracker (Chris)
// This file is part of SmartPerfetto. See LICENSE for details.
Object.defineProperty(exports, "__esModule", { value: true });
exports.createOpenAIToolsFromMcpDefinitions = createOpenAIToolsFromMcpDefinitions;
const agents_1 = require("@openai/agents");
const zod_1 = require("zod");
function isClaudeSdkToolLike(value) {
    const toolLike = value;
    return !!toolLike
        && typeof toolLike.name === 'string'
        && typeof toolLike.description === 'string'
        && typeof toolLike.inputSchema === 'object'
        && typeof toolLike.handler === 'function';
}
function stringifyToolResult(result) {
    const maybeResult = result;
    if (Array.isArray(maybeResult?.content)) {
        return maybeResult.content.map((block) => {
            if (block.type === 'text' && typeof block.text === 'string')
                return block.text;
            if (typeof block.text === 'string')
                return block.text;
            return JSON.stringify(block);
        }).join('\n');
    }
    return typeof result === 'string' ? result : JSON.stringify(result);
}
/** 判断 schema 是否来自 z.record(z.string(), z.any()) 这类开放参数对象。 */
function isOpenRecordAnySchema(entries) {
    const record = Object.fromEntries(entries);
    const additionalProperties = record.additionalProperties;
    return record.type === 'object'
        && (!('properties' in record) || Object.keys(record.properties || {}).length === 0)
        && !!additionalProperties
        && typeof additionalProperties === 'object'
        && !Array.isArray(additionalProperties)
        && Object.keys(additionalProperties).length === 0;
}
/** 清理 Zod 生成但 OpenAI function schema 不接受的 JSON Schema 片段。 */
function sanitizeJsonSchema(value, parentKey) {
    if (Array.isArray(value)) {
        return value.map((item) => sanitizeJsonSchema(item));
    }
    if (!value || typeof value !== 'object') {
        return value;
    }
    const entries = Object.entries(value);
    if (isOpenRecordAnySchema(entries)) {
        const description = value.description;
        return {
            type: 'string',
            ...(typeof description === 'string'
                ? { description: `${description} Pass as a JSON object string.` }
                : { description: 'JSON object string.' }),
        };
    }
    const sanitized = {};
    for (const [key, nested] of Object.entries(value)) {
        // The OpenAI structured-output/tool schema subset does not need these
        // metadata/validation keywords here. `additionalProperties` already
        // carries the useful record-value constraint for z.record(...).
        if (key === '$schema' || key === 'propertyNames') {
            continue;
        }
        const sanitizedNested = sanitizeJsonSchema(nested, key);
        if (sanitizedNested !== undefined) {
            sanitized[key] = sanitizedNested;
        }
    }
    return sanitized;
}
function createOpenAIParameters(inputSchema) {
    const zodObject = zod_1.z.object(inputSchema);
    const jsonSchema = zod_1.z.toJSONSchema(zodObject);
    return sanitizeJsonSchema(jsonSchema);
}
function parseJsonContainerString(value) {
    const trimmed = value.trim();
    if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {
        return value;
    }
    try {
        return JSON.parse(trimmed);
    }
    catch {
        return value;
    }
}
function normalizeOpenAIToolArgs(value) {
    if (typeof value === 'string') {
        const parsed = parseJsonContainerString(value);
        return parsed === value ? value : normalizeOpenAIToolArgs(parsed);
    }
    if (Array.isArray(value)) {
        return value.map((item) => normalizeOpenAIToolArgs(item));
    }
    if (!value || typeof value !== 'object') {
        return value;
    }
    return Object.fromEntries(Object.entries(value).map(([key, nested]) => [key, normalizeOpenAIToolArgs(nested)]));
}
/**
 * Adapts SmartPerfetto's existing in-process Claude MCP tool registry to
 * OpenAI Agents SDK function tools. The SmartPerfetto tool contract remains
 * the single source of truth; only the SDK adapter changes.
 */
function createOpenAIToolsFromMcpDefinitions(definitions) {
    return definitions.map((definition) => {
        if (!isClaudeSdkToolLike(definition.tool)) {
            throw new Error(`Cannot adapt MCP tool ${definition.name}: unsupported SDK descriptor shape`);
        }
        const sdkTool = definition.tool;
        return (0, agents_1.tool)({
            name: definition.name,
            description: sdkTool.description,
            parameters: createOpenAIParameters(sdkTool.inputSchema),
            strict: true,
            execute: async (args) => {
                const normalizedArgs = normalizeOpenAIToolArgs(args);
                const result = await sdkTool.handler(normalizedArgs, {});
                return stringifyToolResult(result);
            },
            errorFunction: (_context, error) => {
                const message = error instanceof Error ? error.message : String(error);
                return JSON.stringify({
                    success: false,
                    error: message,
                    tool: definition.name,
                });
            },
        });
    });
}
//# sourceMappingURL=openAiToolAdapter.js.map