"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.BaseSubAgent = void 0;
/**
 * SmartPerfetto Base SubAgent
 *
 * SubAgent 基类，提供：
 * 1. 通用的 Think-Act 循环框架
 * 2. 工具注册和调用
 * 3. 与 ModelRouter 的集成
 * 4. 结果提取和格式化
 * 5. 生命周期钩子支持
 */
const events_1 = require("events");
const hooks_1 = require("../../hooks");
const llmJson_1 = require("../../../utils/llmJson");
const THINK_RESULT_JSON_SCHEMA = {
    name: 'think_json@1.1.0',
    validate: (value) => {
        if (!(0, llmJson_1.isPlainObject)(value))
            return false;
        if (typeof value.observation !== 'string')
            return false;
        if (typeof value.reasoning !== 'string')
            return false;
        if (!['continue', 'conclude', 'delegate'].includes(String(value.decision)))
            return false;
        const nextActions = value.nextActions;
        if (!Array.isArray(nextActions))
            return false;
        for (const action of nextActions) {
            if (typeof action === 'string')
                continue;
            if (!(0, llmJson_1.isPlainObject)(action))
                return false;
            if (typeof action.toolName !== 'string')
                return false;
            const params = action.params;
            if (params !== undefined && params !== null && !(0, llmJson_1.isPlainObject)(params))
                return false;
        }
        if (typeof value.confidence !== 'number')
            return false;
        return true;
    },
};
/**
 * SubAgent 基类
 */
class BaseSubAgent extends events_1.EventEmitter {
    constructor(config, modelRouter, hookRegistry) {
        super();
        this.currentIteration = 0;
        this.hookContext = null;
        this.config = config;
        this.modelRouter = modelRouter;
        this.tools = new Map();
        this.hookRegistry = hookRegistry || (0, hooks_1.getHookRegistry)();
    }
    // ==========================================================================
    // 核心执行逻辑
    // ==========================================================================
    /**
     * 执行分析（实现 StageExecutor 接口）
     */
    async execute(stage, context) {
        const startTime = Date.now();
        this.currentIteration = 0;
        // 初始化 hook context
        this.hookContext = (0, hooks_1.createHookContext)(context.sessionId, context.traceId || '', stage.id // phase 使用 stageId
        );
        // 存储 agent 信息到 metadata
        this.hookContext.set('agentId', this.config.id);
        this.hookContext.set('stageId', stage.id);
        try {
            // 发射开始事件
            this.emit('start', { agentId: this.config.id, stage: stage.id });
            // 执行 Think-Act 循环
            const result = await this.runThinkActLoop(context);
            // 计算执行时间
            result.executionTimeMs = Date.now() - startTime;
            // 发射完成事件
            this.emit('complete', { agentId: this.config.id, result });
            return result;
        }
        catch (error) {
            this.emit('error', { agentId: this.config.id, error: error.message });
            return {
                agentId: this.config.id,
                success: false,
                findings: [],
                suggestions: [],
                confidence: 0,
                executionTimeMs: Date.now() - startTime,
                error: error.message,
            };
        }
        finally {
            // 清理 hook context
            this.hookContext = null;
        }
    }
    /**
     * Think-Act 循环
     */
    async runThinkActLoop(context) {
        const findings = [];
        const suggestions = [];
        let confidence = 0;
        while (this.currentIteration < this.config.maxIterations) {
            this.currentIteration++;
            // === Iteration Pre-Hook ===
            const iterationData = {
                iterationNumber: this.currentIteration,
                maxIterations: this.config.maxIterations,
                currentFindings: findings,
            };
            const iterPreResult = await this.hookRegistry.executePre('iteration:start', context.sessionId, iterationData, this.hookContext || undefined);
            if (!iterPreResult.continue) {
                // Hook 要求中止迭代
                break;
            }
            // Think: 思考下一步
            const thought = await this.think(context, findings);
            this.emit('thought', { agentId: this.config.id, thought });
            // 检查是否应该结束
            if (thought.decision === 'conclude' || thought.confidence >= this.config.confidenceThreshold) {
                confidence = thought.confidence;
                // === Iteration Post-Hook (结束) ===
                await this.hookRegistry.executePost('iteration:end', context.sessionId, { ...iterationData, thought, decision: 'conclude' }, this.hookContext || undefined);
                break;
            }
            // Act: 执行动作
            for (const action of thought.nextActions) {
                const result = await this.act(action, context);
                if (result) {
                    // 提取发现
                    const newFindings = this.extractFindings(result);
                    findings.push(...newFindings);
                    this.emit('finding', { agentId: this.config.id, findings: newFindings });
                }
            }
            // === Iteration Post-Hook ===
            await this.hookRegistry.executePost('iteration:end', context.sessionId, { ...iterationData, thought, decision: 'continue' }, this.hookContext || undefined);
            // 检查是否有足够的发现
            if (findings.length >= 3) {
                confidence = Math.min(thought.confidence + 0.1, 1.0);
                break;
            }
        }
        // 生成建议
        const generatedSuggestions = await this.generateSuggestions(findings, context);
        suggestions.push(...generatedSuggestions);
        return {
            agentId: this.config.id,
            success: true,
            findings,
            suggestions,
            confidence,
            executionTimeMs: 0, // 由调用者填充
        };
    }
    /**
     * 思考步骤
     */
    async think(context, currentFindings) {
        const prompt = this.buildThinkPrompt(context, currentFindings);
        const taskType = this.config.preferredModel || 'general';
        const response = await this.modelRouter.callWithFallback(prompt, taskType, {
            sessionId: context.sessionId,
            traceId: context.traceId,
            jsonMode: true,
            promptId: `agent.${this.config.id}.think`,
            promptVersion: '1.0.0',
            contractVersion: THINK_RESULT_JSON_SCHEMA.name,
        });
        return this.parseThinkResponse(response.response);
    }
    /**
     * 执行动作
     */
    async act(action, context) {
        const startTime = Date.now();
        let toolName = '';
        let params = {};
        let parseError;
        if (typeof action === 'string') {
            const cleaned = (action || '').trim().replace(/^[-•*]\s*/, '').trim();
            const colonIndex = cleaned.indexOf(':');
            if (colonIndex < 0) {
                toolName = cleaned;
            }
            else {
                toolName = cleaned.slice(0, colonIndex).trim();
                const paramsText = cleaned.slice(colonIndex + 1).trim();
                if (paramsText) {
                    try {
                        const parsedParams = (0, llmJson_1.parseLlmJson)(paramsText);
                        if (!(0, llmJson_1.isPlainObject)(parsedParams)) {
                            throw new Error('params must be a JSON object');
                        }
                        params = parsedParams;
                    }
                    catch (error) {
                        parseError = error?.message || String(error);
                    }
                }
            }
        }
        else if (action && typeof action === 'object') {
            toolName = String(action.toolName || '').trim();
            const candidateParams = action.params;
            if (candidateParams !== undefined && candidateParams !== null) {
                if (!(0, llmJson_1.isPlainObject)(candidateParams)) {
                    parseError = 'params must be a JSON object';
                }
                else {
                    params = candidateParams;
                }
            }
        }
        if (!toolName) {
            const result = {
                success: false,
                error: 'Invalid nextActions entry: missing toolName',
                executionTimeMs: Date.now() - startTime,
            };
            this.emit('warning', { message: result.error });
            return result;
        }
        const tool = this.tools.get(toolName);
        if (!tool) {
            const result = {
                success: false,
                error: `Unknown tool: ${toolName}`,
                executionTimeMs: Date.now() - startTime,
            };
            this.emit('warning', { message: result.error });
            return result;
        }
        // === Tool Use Pre-Hook ===
        const toolUseData = {
            toolName,
            params,
            agentId: this.config.id,
            ...(parseError ? { error: `Invalid params JSON: ${parseError}` } : {}),
        };
        const preResult = await this.hookRegistry.executePre('tool:use', context.sessionId, toolUseData, this.hookContext || undefined);
        if (!preResult.continue) {
            // Hook 要求中止此工具调用
            this.emit('toolSkipped', { toolName, reason: 'Hook prevented execution' });
            return preResult.substituteResult ?? null;
        }
        // 应用可能被 hook 修改的参数
        const finalParams = preResult.modifiedData
            ? preResult.modifiedData.params ?? params
            : params;
        // Strict: if params cannot be parsed AND hooks didn't replace it, do not execute with silent "{}".
        const repairedByHook = !!parseError &&
            preResult.modifiedData !== undefined &&
            preResult.modifiedData.params !== params;
        if (parseError && !repairedByHook) {
            const result = {
                success: false,
                error: `Invalid tool params for ${toolName}: ${parseError}`,
                executionTimeMs: Date.now() - startTime,
            };
            await this.hookRegistry.executePost('tool:use', context.sessionId, { ...toolUseData, params: finalParams, result }, this.hookContext || undefined);
            this.emit('toolCall', { toolName, params: finalParams, result });
            this.emit('warning', { message: result.error });
            return result;
        }
        try {
            const result = await tool.execute(finalParams, context);
            // === Tool Use Post-Hook ===
            await this.hookRegistry.executePost('tool:use', context.sessionId, { ...toolUseData, params: finalParams, result }, this.hookContext || undefined);
            this.emit('toolCall', { toolName, params: finalParams, result });
            return result;
        }
        catch (error) {
            // === Tool Use Error - 也触发 post hook ===
            await this.hookRegistry.executePost('tool:use', context.sessionId, { ...toolUseData, params: finalParams, error: error.message }, this.hookContext || undefined);
            this.emit('error', { message: `Tool ${toolName} failed: ${error.message}` });
            return null;
        }
    }
    // ==========================================================================
    // 提示词构建
    // ==========================================================================
    /**
     * 构建思考提示词
     */
    buildThinkPrompt(context, currentFindings) {
        const systemPrompt = this.buildSystemPrompt(context);
        const taskPrompt = this.buildTaskPrompt(context);
        const findingsSummary = currentFindings.length > 0
            ? `\n\n已有发现:\n${currentFindings.map(f => `- ${f.title}: ${f.description}`).join('\n')}`
            : '';
        const toolsDescription = this.getToolsDescription();
        return `${systemPrompt}

## 可用工具
${toolsDescription}

## 当前任务
${taskPrompt}
${findingsSummary}

## 指令
基于当前状态，决定下一步行动。
如果已经有足够的信息，可以选择结束分析。
如果需要更多数据，选择合适的工具并指定参数。

	请以 JSON 格式回复：
	{
	  "observation": "观察到的情况",
	  "reasoning": "推理过程",
	  "decision": "continue | conclude",
	  "nextActions": [
	    { "toolName": "tool1", "params": { "k": "v" } },
	    { "toolName": "tool2", "params": {} }
	  ],
	  "confidence": 0.0-1.0
	}`;
    }
    /**
     * 获取工具描述
     */
    getToolsDescription() {
        const descriptions = [];
        for (const tool of this.tools.values()) {
            descriptions.push(`- ${tool.name}: ${tool.description}`);
        }
        return descriptions.join('\n');
    }
    // ==========================================================================
    // 响应解析
    // ==========================================================================
    /**
     * 解析思考响应
     */
    parseThinkResponse(response) {
        try {
            const parsed = (0, llmJson_1.parseLlmJson)(response, THINK_RESULT_JSON_SCHEMA);
            return {
                observation: parsed.observation || '',
                reasoning: parsed.reasoning || '',
                decision: parsed.decision || 'continue',
                nextActions: parsed.nextActions || [],
                confidence: typeof parsed.confidence === 'number' ? parsed.confidence : 0,
            };
        }
        catch (error) {
            // 解析失败
        }
        // 默认返回继续
        return {
            observation: response,
            reasoning: 'Unable to parse structured response',
            decision: 'continue',
            nextActions: [],
            confidence: 0.3,
        };
    }
    // ==========================================================================
    // 发现提取
    // ==========================================================================
    /**
     * 从工具结果中提取发现
     */
    extractFindings(result) {
        if (!result.success || !result.data) {
            return [];
        }
        // 如果结果已经包含发现
        if (result.data.findings && Array.isArray(result.data.findings)) {
            return result.data.findings;
        }
        // 默认实现：子类可以覆盖
        return [];
    }
    /**
     * 生成建议
     */
    async generateSuggestions(findings, context) {
        if (findings.length === 0) {
            return ['未发现明显问题'];
        }
        const prompt = `基于以下分析发现，生成 2-3 条改进建议：

发现：
${findings.map(f => `- [${f.severity}] ${f.title}: ${f.description}`).join('\n')}

请直接列出建议，每条一行：`;
        try {
            const response = await this.modelRouter.callWithFallback(prompt, 'synthesis', {
                sessionId: context.sessionId,
                traceId: context.traceId,
                promptId: `agent.${this.config.id}.suggestions`,
                promptVersion: '1.0.0',
                contractVersion: 'suggestions_text@1.0.0',
            });
            return response.response
                .split('\n')
                .filter(line => line.trim().length > 0)
                .map(line => line.replace(/^[-•*]\s*/, '').trim())
                .slice(0, 3);
        }
        catch (error) {
            return findings
                .filter(f => f.severity === 'critical' || f.severity === 'warning')
                .map(f => `关注: ${f.title}`);
        }
    }
    // ==========================================================================
    // 工具管理
    // ==========================================================================
    /**
     * 注册工具
     */
    registerTool(tool) {
        this.tools.set(tool.name, tool);
    }
    /**
     * 注册多个工具
     */
    registerTools(tools) {
        for (const tool of tools) {
            this.registerTool(tool);
        }
    }
    /**
     * 获取工具
     */
    getTool(name) {
        return this.tools.get(name);
    }
    /**
     * 列出工具
     */
    listTools() {
        return Array.from(this.tools.keys());
    }
    // ==========================================================================
    // 配置和状态
    // ==========================================================================
    /**
     * 获取配置
     */
    getConfig() {
        return { ...this.config };
    }
    /**
     * 获取 ID
     */
    get id() {
        return this.config.id;
    }
    /**
     * 获取类型
     */
    get type() {
        return this.config.type;
    }
    /**
     * 获取名称
     */
    get name() {
        return this.config.name;
    }
    /**
     * 重置状态
     */
    reset() {
        this.currentIteration = 0;
    }
}
exports.BaseSubAgent = BaseSubAgent;
exports.default = BaseSubAgent;
//# sourceMappingURL=baseSubAgent.js.map