"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
var LlmTurnProcessorService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.LlmTurnProcessorService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const typeorm_2 = require("typeorm");
const core_entities_1 = require("../core-entities");
const llm_output_parser_service_1 = require("./parser/llm-output-parser.service");
const llm_orchestration_interfaces_1 = require("./llm-orchestration.interfaces");
const mcp_tool_action_handler_1 = require("./action-handlers/mcp-tool-action.handler");
const ai_actions_service_1 = require("../ai-actions/ai-actions.service");
const application_state_service_1 = require("../application-state/application-state.service");
const execution_logs_service_1 = require("../execution-logs/execution-logs.service");
const tool_hooks_service_1 = require("../tool-hooks/tool-hooks.service");
const mcp_service_1 = require("../mcp/mcp.service");
let LlmTurnProcessorService = LlmTurnProcessorService_1 = class LlmTurnProcessorService {
    constructor(parser, handlerRegistry, postExecutionHooks, aiActionsRepository, sessionInputsRepository, sessionsRepository, applicationStateService, executionLogsService, toolHooksService, mcpService) {
        this.parser = parser;
        this.handlerRegistry = handlerRegistry;
        this.postExecutionHooks = postExecutionHooks;
        this.aiActionsRepository = aiActionsRepository;
        this.sessionInputsRepository = sessionInputsRepository;
        this.sessionsRepository = sessionsRepository;
        this.applicationStateService = applicationStateService;
        this.executionLogsService = executionLogsService;
        this.toolHooksService = toolHooksService;
        this.mcpService = mcpService;
        this.logger = new common_1.Logger(LlmTurnProcessorService_1.name);
    }
    async processTurn(sessionInput) {
        this.logger.log(`Starting new orchestration for input ${sessionInput.id}`);
        const session = await this.sessionsRepository.findOne({
            where: { id: sessionInput.session_id },
            select: ['id', 'system_prompt_id'],
        });
        const toolCalls = sessionInput.tool_calls
            ? JSON.parse(sessionInput.tool_calls)
            : null;
        const { explanation, actions: parsedActions } = await this.parser.parse(sessionInput.raw_llm_response, toolCalls);
        const actionOrder = [
            'create_file',
            'quick_edit',
            'patch',
            'overwrite_file',
            'delete_file',
            'final',
            'html_final',
            'ask_user',
            'new-session',
            'run_command',
            'request_context',
        ];
        parsedActions.sort((a, b) => {
            const indexA = actionOrder.indexOf(a.tool_name);
            const indexB = actionOrder.indexOf(b.tool_name);
            const effectiveIndexA = indexA === -1 ? Infinity : indexA;
            const effectiveIndexB = indexB === -1 ? Infinity : indexB;
            if (effectiveIndexA === effectiveIndexB) {
                return 0;
            }
            return effectiveIndexA - effectiveIndexB;
        });
        sessionInput.llm_response_explanation = explanation;
        await this.sessionInputsRepository.save(sessionInput);
        const executionContext = new llm_orchestration_interfaces_1.PlanExecutionContext();
        executionContext.session_id = sessionInput.session_id;
        executionContext.system_prompt_id = session?.system_prompt_id || null;
        executionContext.originalParsedActions = parsedActions;
        const createdActions = [];
        for (const action of parsedActions) {
            let handler = this.handlerRegistry.get(action.tool_name);
            let result;
            const beforeHooks = await this.toolHooksService.findByTrigger(action.tool_name, 'before');
            let hookHalted = false;
            for (const hook of beforeHooks) {
                try {
                    this.logger.log(`Running BEFORE hook: ${hook.script_filename} for tool ${action.tool_name}`);
                    const hookResult = await this.toolHooksService.executeHook(hook.script_filename, {
                        hook_type: 'before',
                        action: { tool_name: action.tool_name, args: action.arguments },
                        plan_context: executionContext,
                    });
                    if (hookResult.should_halt_plan) {
                        this.logger.warn(`Hook ${hook.script_filename} halted execution.`);
                        executionContext.flags.should_halt = true;
                        executionContext.flags.halt_reason = `Hook ${hook.script_filename} returned halt signal.`;
                        hookHalted = true;
                        break;
                    }
                }
                catch (e) {
                    this.logger.error(`Before-hook failed: ${e.message}`);
                }
            }
            if (hookHalted) {
                const aiActionEntity = this.aiActionsRepository.create({
                    input_id: sessionInput.id,
                    sessionInput: { id: sessionInput.id },
                    action_type: action.tool_name,
                    status: ai_actions_service_1.AIActionStatus.EXECUTION_FAILED,
                    order_of_execution: createdActions.length,
                    original_content_for_revert: null,
                });
                const savedAction = await this.aiActionsRepository.save(aiActionEntity);
                createdActions.push(savedAction);
                await this.executionLogsService.createLog({
                    action_id: savedAction.id,
                    error_message: executionContext.flags.halt_reason || 'Blocked by tool hook.',
                    output: 'Action execution prevented by a "before" hook.',
                });
                break;
            }
            if (!handler) {
                const mcpMatch = action.tool_name.match(/^([^_]+)__(.+)$/);
                if (mcpMatch) {
                    const [, serverName, toolName] = mcpMatch;
                    handler = new mcp_tool_action_handler_1.McpToolActionHandler(serverName, toolName, this.mcpService, '');
                }
            }
            if (!handler) {
                this.logger.warn(`No handler found for tool: ${action.tool_name}. Skipping.`);
                executionContext.feedback.invalidToolErrors.push({
                    tool_name: action.tool_name,
                    arguments: action.arguments,
                });
                result = {
                    status: 'FAILURE',
                    summary: `Tool '${action.tool_name}' is not a valid tool.`,
                    error_message: `No handler registered for tool name '${action.tool_name}'.`,
                    persisted_args: action.arguments,
                    execution_log: {
                        output: '',
                        error_message: `No handler registered for tool name '${action.tool_name}'.`,
                    },
                };
                if (action.toolCallId) {
                    executionContext.toolResults.push({
                        toolCallId: action.toolCallId,
                        toolName: action.tool_name,
                        result: `Error: Tool '${action.tool_name}' does not exist. Please use a valid tool.`,
                    });
                }
            }
            else {
                try {
                    result = await handler.execute(action.arguments, executionContext);
                }
                catch (error) {
                    this.logger.error(`Handler for ${action.tool_name} failed during execution: ${error.message}`, error.stack);
                    result = {
                        status: 'FAILURE',
                        summary: `An unexpected error occurred: ${error.message}`,
                        error_message: error.message,
                        persisted_args: action.arguments,
                        execution_log: { output: '', error_message: error.message },
                    };
                }
            }
            if (result) {
                const afterHooks = await this.toolHooksService.findByTrigger(action.tool_name, 'after');
                for (const hook of afterHooks) {
                    try {
                        this.logger.log(`Running AFTER hook: ${hook.script_filename} for tool ${action.tool_name}`);
                        await this.toolHooksService.executeHook(hook.script_filename, {
                            hook_type: 'after',
                            action: {
                                tool_name: action.tool_name,
                                args: action.arguments,
                                result: {
                                    status: result.status,
                                    output: result.execution_log?.output,
                                    error: result.error_message,
                                },
                            },
                            plan_context: executionContext,
                        });
                    }
                    catch (e) {
                        this.logger.error(`After-hook failed: ${e.message}`);
                    }
                }
            }
            const executionStrategy = await this.applicationStateService.getExecutionStrategy();
            this.logger.log(`Using execution strategy: ${executionStrategy}`);
            const successStatus = this.getSuccessStatusForStrategy(executionStrategy);
            const aiActionEntity = this.aiActionsRepository.create({
                input_id: sessionInput.id,
                sessionInput: { id: sessionInput.id },
                action_type: action.tool_name,
                status: result.status === 'SUCCESS'
                    ? successStatus
                    : ai_actions_service_1.AIActionStatus.EXECUTION_FAILED,
                order_of_execution: createdActions.length,
                original_content_for_revert: result.original_content_for_revert,
                tool_call_id: action.toolCallId || null,
                ...result.persisted_args,
            });
            const savedAction = await this.aiActionsRepository.save(aiActionEntity);
            createdActions.push(savedAction);
            await this.executionLogsService.createLog({
                action_id: savedAction.id,
                output: result.execution_log.output,
                error_message: result.execution_log.error_message,
            });
            if (action.toolCallId && handler) {
                const output = result.execution_log?.output || '';
                const error = result.execution_log?.error_message || result.error_message || '';
                const combinedResult = error
                    ? `${output}\n\nError: ${error}`.trim()
                    : output;
                executionContext.toolResults.push({
                    toolCallId: action.toolCallId,
                    toolName: action.tool_name,
                    result: combinedResult,
                });
            }
            if (executionContext.flags.should_halt) {
                this.logger.log(`Execution context flagged to halt. Reason: ${executionContext.flags.halt_reason}. Ending plan execution early.`);
                break;
            }
        }
        sessionInput.aiActions = createdActions;
        this.logger.log(`Running ${this.postExecutionHooks.length} post-execution hooks.`);
        for (const hook of this.postExecutionHooks) {
            try {
                await hook.run(sessionInput, executionContext);
            }
            catch (error) {
                this.logger.error(`Post-execution hook ${hook.constructor.name} failed: ${error.message}`, error.stack);
            }
            if (executionContext.flags.should_halt_hooks) {
                this.logger.log(`Hook chain halted by ${hook.constructor.name}. Skipping subsequent hooks.`);
                break;
            }
        }
        this.logger.log(`Orchestration finished for input ${sessionInput.id}.`);
        return this.sessionInputsRepository.save(sessionInput);
    }
    getSuccessStatusForStrategy(strategy) {
        switch (strategy) {
            case 'auto_apply':
                return ai_actions_service_1.AIActionStatus.CONFIRMED_KEPT;
            case 'review_first':
            case 'apply_revert':
                return ai_actions_service_1.AIActionStatus.APPLIED_PENDING_REVIEW;
            default:
                this.logger.warn(`Unknown execution strategy: '${strategy}'. Defaulting to APPLIED_PENDING_REVIEW.`);
                return ai_actions_service_1.AIActionStatus.APPLIED_PENDING_REVIEW;
        }
    }
};
exports.LlmTurnProcessorService = LlmTurnProcessorService;
exports.LlmTurnProcessorService = LlmTurnProcessorService = LlmTurnProcessorService_1 = __decorate([
    (0, common_1.Injectable)(),
    __param(1, (0, common_1.Inject)('ACTION_HANDLER_REGISTRY')),
    __param(2, (0, common_1.Inject)('POST_EXECUTION_HOOKS')),
    __param(3, (0, typeorm_1.InjectRepository)(core_entities_1.AIAction)),
    __param(4, (0, typeorm_1.InjectRepository)(core_entities_1.SessionInput)),
    __param(5, (0, typeorm_1.InjectRepository)(core_entities_1.Session)),
    __metadata("design:paramtypes", [llm_output_parser_service_1.LlmOutputParserService,
        Map, Array, typeorm_2.Repository,
        typeorm_2.Repository,
        typeorm_2.Repository,
        application_state_service_1.ApplicationStateService,
        execution_logs_service_1.ExecutionLogsService,
        tool_hooks_service_1.ToolHooksService,
        mcp_service_1.McpService])
], LlmTurnProcessorService);
//# sourceMappingURL=llm-turn-processor.service.js.map