"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generator = exports.generatorId = void 0;
const Generator = __importStar(require("@postxl/generator"));
const backend_core_1 = require("../backend-core");
const base_1 = require("../base");
const types_1 = require("../types");
const ai_agent_service_generator_1 = require("./generators/ai-agent-service.generator");
const ai_cache_service_generator_1 = require("./generators/ai-cache-service.generator");
const ai_config_generator_1 = require("./generators/ai-config.generator");
const ai_module_generator_1 = require("./generators/ai-module.generator");
const ai_route_generator_1 = require("./generators/ai-route.generator");
const ai_tools_service_generator_1 = require("./generators/ai-tools-service.generator");
const model_provider_interface_generator_1 = require("./generators/model-provider-interface.generator");
const openai_model_provider_service_generator_1 = require("./generators/openai-model-provider-service.generator");
const apiKeyDummyValue = 'sk-...';
exports.generatorId = Generator.toGeneratorInterfaceId('backend-ai');
exports.generator = {
    id: exports.generatorId,
    requires: [backend_core_1.backendGeneratorId, base_1.baseGeneratorId, types_1.typesGeneratorId],
    register: (context) => {
        const module = {
            name: Generator.toClassName('AiModule'),
            location: Generator.toBackendModuleLocation('@ai/ai.module'),
        };
        const agentService = {
            name: Generator.toClassName('AiAgentService'),
            location: Generator.toBackendModuleLocation('@ai/ai-agent.service'),
        };
        const aiModule = {
            name: Generator.toBackendModuleName('ai'),
            moduleClass: module,
            apiModuleRegistration: {
                code: Generator.ts('AiModule.forRoot(config.ai)'),
            },
            envConfig: {
                decoder: Generator.ts(`
AI_ENABLED: zEnvBoolean.optional().default(false),
AI_OPENAI_KEY: z.string().optional(),
AI_OPENAI_MODEL: z.string().optional().default('gpt-4.1-mini'),
AI_OPENAI_KEYS: z.string().optional(),
AI_OPENAI_TIMEOUT_MS: z.coerce.number().optional().default(20000),
AI_RATE_LIMIT_WINDOW_MS: z.coerce.number().optional().default(60000),
AI_RATE_LIMIT_MAX_REQUESTS: z.coerce.number().optional().default(120),
AI_CONVERSATION_TTL_MS: z.coerce.number().optional().default(900000),
AI_CONVERSATION_CACHE_MAX_SIZE: z.coerce.number().optional().default(500),
AI_MAX_INTERNAL_TOOL_STEPS: z.coerce.number().optional().default(12),
        `),
                transformer: Generator.ts(`
ai: {
  ...(() => {
    const singleKey = typeof val.AI_OPENAI_KEY === 'string' ? val.AI_OPENAI_KEY.trim() : ''
    const keyPool =
      typeof val.AI_OPENAI_KEYS === 'string'
        ? val.AI_OPENAI_KEYS
            .split(',')
            .map((key) => key.trim())
            .filter((key) => key.length > 0)
        : []

    const hasSingleKey = singleKey.length > 0
    const hasKeyPool = keyPool.length > 0
    const hasDummySingleKey = singleKey === '${apiKeyDummyValue}'
    const hasDummyKeyInPool = keyPool.includes('${apiKeyDummyValue}')

    if (val.AI_ENABLED && !hasSingleKey && !hasKeyPool) {
      throw new Error('AI_ENABLED=true requires AI_OPENAI_KEY or AI_OPENAI_KEYS')
    }
    if (val.AI_ENABLED && (hasDummySingleKey || hasDummyKeyInPool)) {
      throw new Error('AI_ENABLED=true requires a real OpenAI key, not the placeholder "${apiKeyDummyValue}"')
    }

    return {
      enabled: val.AI_ENABLED,
      openAIApiKey: val.AI_OPENAI_KEY,
      model: val.AI_OPENAI_MODEL,
      openAIApiKeys: val.AI_OPENAI_KEYS,
      timeoutMs: val.AI_OPENAI_TIMEOUT_MS,
      rateLimitWindowMs: val.AI_RATE_LIMIT_WINDOW_MS,
      rateLimitMaxRequests: val.AI_RATE_LIMIT_MAX_REQUESTS,
      conversationTtlMs: val.AI_CONVERSATION_TTL_MS,
      conversationCacheMaxSize: val.AI_CONVERSATION_CACHE_MAX_SIZE,
      maxInternalToolSteps: val.AI_MAX_INTERNAL_TOOL_STEPS,
    }
  })(),
},
        `),
                dotEnvExample: Generator.ts(`
# Enable or disable AI assistant features on the backend
AI_ENABLED=false
# Required when AI is enabled unless AI_OPENAI_KEYS is set
AI_OPENAI_KEY="${apiKeyDummyValue}"
# Optional: key pool for rotation (comma-separated); used before AI_OPENAI_KEY when set
# AI_OPENAI_KEYS="sk-key-1,sk-key-2"
# Optional model override
# AI_OPENAI_MODEL="gpt-4.1-mini"
# Optional request timeout in milliseconds
# AI_OPENAI_TIMEOUT_MS=20000
# Optional global backend AI request rate limit (window + max requests)
# AI_RATE_LIMIT_WINDOW_MS=60000
# AI_RATE_LIMIT_MAX_REQUESTS=120
# Optional in-memory conversation cache controls
# AI_CONVERSATION_TTL_MS=900000
# AI_CONVERSATION_CACHE_MAX_SIZE=500
# Optional max number of backend tool executions in one AI turn
# AI_MAX_INTERNAL_TOOL_STEPS=12
        `),
            },
        };
        context.backend.modules.push(aiModule);
        return {
            ...context,
            ai: {
                module,
                agentService,
                route: {
                    name: Generator.toFunctionName('ai'),
                    location: Generator.toBackendModuleLocation('@ai/ai.route'),
                    _filePath: Generator.toFilePath('./ai.route.ts'),
                },
            },
        };
    },
    generate: (context) => {
        const vfsSrc = new Generator.VirtualFileSystem();
        vfsSrc.write(Generator.toLocalFile(context.ai.module), (0, ai_module_generator_1.generateAiModule)(context));
        vfsSrc.write(Generator.toLocalFile(context.ai.agentService), (0, ai_agent_service_generator_1.generateAiAgentService)({ context }));
        vfsSrc.write(Generator.toFilePath('./ai.route.ts'), (0, ai_route_generator_1.generateAiRoute)());
        vfsSrc.write(Generator.toFilePath('./ai-cache.service.ts'), (0, ai_cache_service_generator_1.generateAiCacheService)());
        vfsSrc.write(Generator.toFilePath('./ai-config.ts'), (0, ai_config_generator_1.generateAiConfig)());
        vfsSrc.write(Generator.toFilePath('./ai-tools.service.ts'), (0, ai_tools_service_generator_1.generateAiToolsService)({ context }));
        vfsSrc.write(Generator.toFilePath('./model-provider/model-provider.interface.ts'), (0, model_provider_interface_generator_1.generateModelProviderInterface)());
        vfsSrc.write(Generator.toFilePath('./model-provider/openai-model-provider.service.ts'), (0, openai_model_provider_service_generator_1.generateOpenAiModelProviderService)());
        const vfs = new Generator.VirtualFileSystem();
        vfs.insertFromVfs({ targetPath: 'src', vfs: vfsSrc });
        vfs.write('/tsconfig.lib.json', Generator.generateTsConfig('ai'));
        context.vfs.insertFromVfs({ targetPath: 'backend/libs/ai', vfs });
        return Promise.resolve(context);
    },
};
//# sourceMappingURL=ai.generator.js.map