/**
 * Agent 客户端核心模块
 * 负责与调度中心通信，管理消息循环
 */
import { configManager } from "./config.js";
import { MESSAGE_POLL_INTERVAL_MS } from "./constants.js";
import { HttpClient } from "./http-client.js";
import { logger, setMcpNodeLogSink } from "./logger.js";
import { claimRuntimeLaunchBinding } from "./runtime-launch-binding.js";
import { StatusReporter } from "./status-reporter.js";
import { WebSocketClient } from "./websocket-client.js";
export class AgentClient {
    wsClient;
    httpClient;
    agentConfig;
    serverConfig;
    agentId = null;
    displayName = null;
    projectName = null; // Agent 所属项目（由服务端决定）
    isRunning = false;
    isDegradedMode = false; // 降级模式标志
    messageHandler = null;
    profileHandler = null;
    pollTimer = null;
    statusReporter = null;
    /**
     * Profile 缓存
     * 用于处理 PROFILE_INFO 消息在 profileHandler 设置之前到达的情况
     */
    cachedProfile = null;
    constructor() {
        configManager.loadConfig();
        this.agentConfig = configManager.getAgentConfig();
        this.serverConfig = configManager.getServerConfig();
        this.wsClient = new WebSocketClient(this.serverConfig);
        this.httpClient = new HttpClient(this.serverConfig);
        this.setupWebSocketListeners();
    }
    async initialize() {
        const binding = await claimRuntimeLaunchBinding(this.agentConfig, this.serverConfig);
        if (!binding) {
            // 无启动绑定时清除 bridge base URL，避免 ensureRuntimeAccessToken
            // （ !runtimeBridgeBaseUrl 分支）抛出异常阻塞后续注册流程。
            this.serverConfig.runtimeBridgeBaseUrl = undefined;
            return;
        }
        configManager.applyRuntimeLaunchBinding(binding);
        this.agentConfig = configManager.getAgentConfig();
        this.serverConfig = configManager.getServerConfig();
        this.wsClient = new WebSocketClient(this.serverConfig);
        this.httpClient = new HttpClient(this.serverConfig);
        this.setupWebSocketListeners();
    }
    // ============ WebSocket 事件监听 ============
    setupWebSocketListeners() {
        this.wsClient.on("directMessage", (message) => {
            this.handleIncomingDm(message);
        });
        this.wsClient.on("groupMessage", (message) => {
            this.handleIncomingGroup(message);
        });
        this.wsClient.on("profileInfo", (profile) => {
            logger.info(`[AgentClient] WebSocket profileInfo 事件触发，displayName: ${profile.displayName}`);
            this.handleProfileInfo(profile);
        });
        this.wsClient.on("agentStatus", (statusUpdate) => {
            logger.info(`[AgentClient] WebSocket agentStatus 事件触发: ${statusUpdate.status}`);
            // 状态更新由服务端推送，这里只记录日志
        });
        this.wsClient.on("disconnected", () => {
            logger.warn("[AgentClient] WebSocket 断开连接，正在自动重连");
        });
        this.wsClient.on("error", (error) => {
            logger.error("[AgentClient] WebSocket 错误:", error.message);
        });
        this.wsClient.on("reconnectFailed", () => {
            logger.error("[AgentClient] 重连失败，停止消息循环");
            this.stop();
        });
    }
    // ============ 注册相关 ============
    /**
     * 注册 Agent 上线
     */
    async register() {
        logger.info("[AgentClient] 正在注册 Agent...");
        if (this.hasPresetAgentId()) {
            return await this.registerWithExistingAgentId();
        }
        return await this.registerAsNewAgent();
    }
    hasPresetAgentId() {
        return !!(this.agentConfig.agentId && this.agentConfig.agentId.trim().length > 0);
    }
    /**
     * 使用预设 AgentID 注册（绑定已有实例）
     */
    async registerWithExistingAgentId() {
        const presetAgentId = this.agentConfig.agentId;
        if (!presetAgentId) {
            throw new Error("Preset agentId is missing");
        }
        this.agentId = presetAgentId.trim();
        const profile = await this.getProfileByAgentId(this.agentId);
        this.displayName = profile.displayName;
        this.projectName = profile.projectName || null; // 保存 Agent 所属项目
        logger.info(`[AgentClient] 使用预设 AgentID 绑定实例: ${this.displayName} (${this.agentId})`);
        logger.info(`[AgentClient] 所属项目: ${this.projectName || "(未设置)"}`);
        await this.wsClient.connect(this.agentId);
        logger.info("[AgentClient] WebSocket 连接已建立，Agent 现在已上线");
        // 初始化状态报告器
        this.initializeStatusReporter();
        // WebSocket 重新连上后，服务端会立刻把该 Agent 标记为在线。
        // 这里重新获取一次最新 profile，避免把连接前读取到的离线状态返回给调用方。
        const refreshedProfile = await this.getProfileByAgentId(this.agentId);
        this.displayName = refreshedProfile.displayName;
        this.projectName = refreshedProfile.projectName || null;
        return {
            agentId: this.agentId,
            displayName: this.displayName,
            status: refreshedProfile.isOnline ? "online" : "offline",
            projectName: refreshedProfile.projectName,
            workspacePath: refreshedProfile.workspacePath,
            runtimeStatus: refreshedProfile.runtimeStatus,
            runtimeSessionId: refreshedProfile.runtimeSessionId,
        };
    }
    /**
     * 作为新 Agent 注册
     */
    async registerAsNewAgent() {
        const result = await this.httpClient.callTool("register", {
            roleName: this.agentConfig.roleName,
            projectName: this.agentConfig.projectName,
            workspacePath: this.agentConfig.workspacePath,
            prompt: this.agentConfig.prompt,
            runtimeBridgeBaseUrl: this.serverConfig.runtimeBridgeBaseUrl,
        });
        const agentId = result.agentId;
        if (!agentId) {
            throw new Error("Registration failed: agentId was not returned");
        }
        this.agentId = agentId;
        this.displayName = result.displayName;
        this.projectName = result.projectName || null; // 保存服务端返回的项目名
        logger.info(`[AgentClient] 注册成功: ${this.displayName} (${this.agentId})`);
        logger.info(`[AgentClient] 状态: ${result.status}`);
        logger.info(`[AgentClient] 所属项目: ${this.projectName || "(未设置)"}`);
        await this.wsClient.connect(this.agentId);
        logger.info("[AgentClient] WebSocket 连接已建立，Agent 现在已上线");
        // 初始化状态报告器
        this.initializeStatusReporter();
        return result;
    }
    /**
     * 注销 Agent 下线
     */
    async unregister() {
        logger.info("[AgentClient] 正在注销 Agent...");
        if (this.agentId) {
            await this.httpClient.callTool("unregister", { agentId: this.agentId });
        }
        this.wsClient.disconnect();
        this.agentId = null;
        this.displayName = null;
        this.projectName = null;
        this.isRunning = false;
        logger.info("[AgentClient] 已注销");
    }
    // ============ 消息相关 ============
    /**
     * 获取当前 Agent 可见的同事列表（包含离线 Agent）。
     */
    async discoverColleagues() {
        return await this.httpClient.callTool("discover_colleague", {
            agentId: this.agentId,
        });
    }
    /**
     * 获取当前 Agent 在关系图中可发现的群组列表。
     */
    async discoverGroupRooms() {
        this.ensureRegistered();
        return await this.httpClient.callTool("discover_group_rooms", {
            agentId: this.agentId,
        });
    }
    /**
     * 招聘同事并创建新的 Agent 实例。
     * 主流程：校验当前实例已注册 -> 透传创建角色参数到服务端 MCP tool -> 返回新实例信息。
     */
    async hireColleague(args) {
        this.ensureRegistered();
        return await this.httpClient.callTool("hire_colleague", {
            agentId: this.agentId,
            ...args,
        });
    }
    /**
     * 批量发起招聘审批请求。
     * 主流程：校验当前实例已注册 -> 透传批量招聘参数到服务端 MCP tool -> 返回整批审批与创建结果。
     */
    async hireColleaguesBatch(args) {
        this.ensureRegistered();
        return await this.httpClient.callTool("hire_colleagues_batch", {
            agentId: this.agentId,
            ...args,
        });
    }
    /**
     * 调用需要当前 Agent 实例身份的 server MCP tool。
     * 主流程：确认已注册 -> 自动附加 agentId -> 复用带 runtime token 的 HTTP 通道。
     */
    async callAgentScopedTool(toolName, args) {
        this.ensureRegistered();
        return await this.httpClient.callTool(toolName, {
            agentId: this.agentId,
            ...args,
        });
    }
    /**
     * 上报当前 MCP 本地合并后的记忆统计。
     * 主流程：自动附加 agentId -> 交给 server 广播给 Dashboard，避免前端只看到 server 实例级统计。
     */
    async reportMemoryStats(memoryStats) {
        await this.callAgentScopedTool("report_memory_stats", { memoryStats });
    }
    /**
     * 发送群消息
     * @param content 消息内容
     * @param projectName 目标项目名，不传则使用 Agent 所属项目（由服务端决定）
     * @param roomId 目标群房间 ID，小组群场景下优先使用以避免误发到项目公共群
     */
    async sendGroupMessage(content, projectName, roomId) {
        this.ensureRegistered();
        // 优先级：传入参数 > Agent 所属项目（服务端决定） > 配置文件默认值
        const targetProject = projectName || this.projectName || this.agentConfig.projectName;
        return await this.httpClient.callTool("send_group_message", {
            agentId: this.agentId,
            projectName: targetProject,
            roomId,
            content,
        });
    }
    /**
     * 发送私信
     */
    async sendDirectMessage(targetId, content, waitReply = false, replyToCallId, timeoutMs) {
        this.ensureRegistered();
        const args = {
            agentId: this.agentId,
            targetId,
            content,
            requireReply: waitReply,
            waitReply,
            replyToCallId,
        };
        if (typeof timeoutMs === "number" && timeoutMs > 0) {
            args.timeoutMs = timeoutMs;
        }
        return await this.httpClient.callTool("send_dm", args);
    }
    /**
     * 发送私信并等待回复（阻塞式）
     */
    async sendCallAndWaitReply(targetId, content, timeoutMs = 60000) {
        const result = await this.sendDirectMessage(targetId, content, true, undefined, timeoutMs);
        if (result.reply) {
            return result.reply;
        }
        throw new Error("No reply received for call-style direct message before timeout");
    }
    /**
     * 回复调用式消息
     */
    async replyToCall(callId, targetId, content) {
        return await this.sendDirectMessage(targetId, content, false, callId);
    }
    /**
     * 获取私信历史消息
     */
    async getDmHistory(targetUserId, limit = 50, since) {
        this.ensureRegistered();
        const args = {
            agentId: this.agentId,
            targetUserId,
            limit,
        };
        if (since) {
            args.since = since;
        }
        return await this.httpClient.callTool("get_dm_history", args);
    }
    /**
     * 获取群消息历史记录
     */
    async getGroupHistory(limit = 50, roomId, since) {
        this.ensureRegistered();
        if (roomId) {
            const args = {
                projectName: this.projectName || this.agentConfig.projectName,
                roomId,
                limit,
            };
            if (since) {
                args.since = since;
            }
            return await this.httpClient.callTool("get_group_history", args);
        }
        const groups = await this.discoverGroupRooms();
        const targetProject = this.projectName || this.agentConfig.projectName;
        const roomIds = this.collectRoomIds(groups, targetProject);
        if (roomIds.length === 0) {
            return { messages: [], count: 0 };
        }
        const historyResponses = await Promise.all(roomIds.map(async (currentRoomId) => {
            const args = {
                projectName: targetProject,
                roomId: currentRoomId,
                limit,
            };
            if (since) {
                args.since = since;
            }
            return await this.httpClient.callTool("get_group_history", args);
        }));
        const messages = historyResponses
            .flatMap((response) => response.messages)
            .sort((left, right) => new Date(left.timestamp).getTime() -
            new Date(right.timestamp).getTime());
        return {
            messages,
            count: messages.length,
        };
    }
    /**
     * 拉取当前 Agent 尚未消费的未读消息。
     * 主流程：校验注册状态 -> 获取未读私信 -> 获取未读群消息 -> 合并返回。
     * @param since 可选的起始时间（ISO 8601），早于该时间的消息将被过滤
     */
    async fetchUnreadMessages(options = {}) {
        this.ensureRegistered();
        const targetProject = this.projectName || this.agentConfig.projectName;
        const dmArgs = {
            agentId: this.agentId,
            blockIfEmpty: options.blockIfEmpty ?? false,
        };
        if (options.since) {
            dmArgs.since = options.since;
        }
        if (options.blockTimeoutMs && options.blockTimeoutMs > 0) {
            dmArgs.blockTimeoutMs = options.blockTimeoutMs;
        }
        const dmToolName = options.includePipelineTasks
            ? "poll_message"
            : "get_dm_messages";
        const directMessagesResponse = await this.fetchDirectMessagesWithRecovery(dmToolName, dmArgs);
        const groups = await this.discoverGroupRooms();
        const roomIds = this.collectRoomIds(groups, targetProject);
        const groupMessageResponses = await Promise.all(roomIds.map(async (currentRoomId) => {
            const groupArgs = {
                agentId: this.agentId,
                projectName: targetProject,
                roomId: currentRoomId,
            };
            if (options.since) {
                groupArgs.since = options.since;
            }
            try {
                return await this.httpClient.callTool("get_group_messages", groupArgs);
            }
            catch (error) {
                console.error(`[AgentClient] 跳过群房间未读补拉失败: roomId=${currentRoomId}`, error);
                return {
                    messages: [],
                    currentReadPos: 0,
                    hasMore: false,
                };
            }
        }));
        return {
            directMessages: Array.isArray(directMessagesResponse.messages)
                ? directMessagesResponse.messages
                : [],
            groupMessages: groupMessageResponses
                .flatMap((response) => this.normalizeGroupMessages(response))
                .sort((left, right) => new Date(left.timestamp).getTime() -
                new Date(right.timestamp).getTime()),
        };
    }
    /**
     * 拉取服务端私信并对 poll_message 长轮询临时失败做恢复。
     * 主流程：正常调用 HTTP MCP tool -> 仅当服务端阻塞 poll_message 返回 503 或客户端硬超时时转为空结果，让本地轮询退避后继续等待。
     */
    async fetchDirectMessagesWithRecovery(toolName, args) {
        try {
            return await this.httpClient.callTool(toolName, args);
        }
        catch (error) {
            if (toolName === "poll_message" && this.isRecoverableLongPollError(error)) {
                logger.warn("[AgentClient] 服务端 poll_message 长轮询临时不可用，按空结果退避后继续等待:", error);
                return { messages: [] };
            }
            throw error;
        }
    }
    /**
     * 判断是否为 poll_message 长轮询的可恢复失败。
     * 主流程：只匹配明确的 MCP tool HTTP 503 或客户端超时，避免吞掉业务工具错误或认证错误。
     */
    isRecoverableLongPollError(error) {
        if (!(error instanceof Error)) {
            return false;
        }
        return (/MCP tool poll_message call failed: 503(?:\s|$)/.test(error.message) ||
            /MCP tool poll_message timed out after \d+ms/.test(error.message));
    }
    /**
     * 规范化服务端群消息响应。
     * 主流程：只接受数组中的完整群消息对象，忽略 401/空响应/异常元素，避免补拉消息时崩溃。
     */
    normalizeGroupMessages(response) {
        if (!Array.isArray(response.messages)) {
            return [];
        }
        return response.messages.filter((message) => Boolean(message &&
            typeof message === "object" &&
            typeof message.msgId === "number" &&
            typeof message.senderId === "string" &&
            typeof message.content === "string" &&
            typeof message.timestamp === "string"));
    }
    /**
     * 收集当前项目下 Agent 可访问的群房间 ID，避免离线补拉和历史查询遗漏小组群。
     */
    collectRoomIds(groups, projectName) {
        const roomIds = groups.groups
            .filter((group) => group.projectName === projectName)
            .map((group) => group.id);
        return Array.from(new Set(roomIds));
    }
    /**
     * 获取当前 Agent 的个人信息
     */
    async getProfile() {
        this.ensureRegistered();
        const agentId = this.agentId;
        if (!agentId) {
            throw new Error("Agent is not registered");
        }
        const profile = await this.getProfileByAgentId(agentId);
        return {
            ...profile,
            describe: this.agentConfig.describe,
        };
    }
    async getProfileByAgentId(agentId) {
        return await this.httpClient.callTool("get_profile", {
            agentId,
        });
    }
    // ============ 流程线任务相关 ============
    /**
     * 获取当前 Agent 被分配的流程线任务列表
     */
    async getMyTasks() {
        this.ensureRegistered();
        return await this.httpClient.callTool("my_task", {
            agentId: this.agentId,
        });
    }
    /**
     * 创建流程线实例级留言。
     * 主流程：确认已注册 -> 自动附加 agentId -> 服务端校验当前 Agent 正在处理该实例节点。
     */
    async createTaskInstanceComment(args) {
        this.ensureRegistered();
        const payload = {
            agentId: this.agentId,
            ...args,
        };
        return await this.httpClient.callTool("create_task_instance_comment", payload);
    }
    /**
     * 提交流程线任务结果
     */
    async submitTaskResult(nodeId, outputPayload) {
        this.ensureRegistered();
        return await this.httpClient.callTool("submit_task_result", {
            agentId: this.agentId,
            nodeId,
            outputPayload,
        });
    }
    /**
     * 记录当前流程线节点执行期间的文件/内容 CRUD 变更。
     * 主流程：确认已注册 -> 自动附加 agentId -> 服务端校验节点必须仍为 PROCESSING。
     */
    async recordTaskChange(args) {
        this.ensureRegistered();
        return await this.httpClient.callTool("record_task_change", {
            agentId: this.agentId,
            ...args,
        });
    }
    /**
     * 将分配给当前 Agent 的 AI 回退任务标记为回退中。
     */
    async startTaskRollback(args) {
        this.ensureRegistered();
        return await this.httpClient.callTool("start_task_rollback", {
            agentId: this.agentId,
            ...args,
        });
    }
    /**
     * 将分配给当前 Agent 的 AI 回退任务标记为已回退，并写入结果说明。
     */
    async finishTaskRollback(args) {
        this.ensureRegistered();
        return await this.httpClient.callTool("finish_task_rollback", {
            agentId: this.agentId,
            ...args,
        });
    }
    /**
     * 拒绝流程线任务
     */
    async rejectTask(nodeId, reason) {
        this.ensureRegistered();
        return await this.httpClient.callTool("reject_task", {
            agentId: this.agentId,
            nodeId,
            reason,
        });
    }
    /**
     * 终止流程线任务（终止后不再流转）
     */
    async terminateTask(taskInstanceId, reason) {
        this.ensureRegistered();
        return await this.httpClient.callTool("terminate_task", {
            agentId: this.agentId,
            taskInstanceId,
            reason,
        });
    }
    // ============ 消息循环 ============
    /**
     * 启动消息监听
     */
    start(handler, options) {
        if (this.isRunning) {
            logger.warn("[AgentClient] 消息循环已在运行中");
            return;
        }
        // 降级模式下跳过注册检查
        if (!this.isDegradedMode) {
            this.ensureRegistered();
        }
        this.messageHandler = handler;
        this.profileHandler = options?.profileHandler || null;
        this.isRunning = true;
        logger.info(`[AgentClient] start() 被调用，cachedProfile: ${this.cachedProfile ? "存在" : "不存在"}, profileHandler: ${this.profileHandler ? "已设置" : "未设置"}, 降级模式: ${this.isDegradedMode ? "是" : "否"}`);
        // 处理缓存的 profile 消息（在 profileHandler 设置之前到达的）
        if (this.cachedProfile && this.profileHandler) {
            logger.info(`[AgentClient] 处理缓存的 Profile 信息: ${this.cachedProfile.displayName}`);
            this.profileHandler(this.cachedProfile);
            this.cachedProfile = null;
        }
        const pollMode = options?.pollMode ?? false;
        if (pollMode) {
            logger.warn("[AgentClient] 启动消息主循环（HTTP轮询模式 - 不推荐）");
            this.messageLoop();
        }
        else {
            logger.info("[AgentClient] 启动消息主循环（WebSocket推送模式 - 推荐）");
        }
    }
    /**
     * 停止消息监听
     */
    stop() {
        this.isRunning = false;
        if (this.pollTimer) {
            clearTimeout(this.pollTimer);
            this.pollTimer = null;
        }
        logger.info("[AgentClient] 消息主循环已停止");
    }
    async messageLoop() {
        while (this.isRunning) {
            try {
                await this.delay(MESSAGE_POLL_INTERVAL_MS);
            }
            catch (error) {
                logger.error("[AgentClient] 消息循环错误:", error);
                await this.delay(5000);
            }
        }
    }
    // ============ WebSocket 消息处理 ============
    handleIncomingDm(message) {
        if (message.senderId === this.agentId) {
            return; // 过滤自己发送的消息
        }
        this.processMessage(message);
    }
    handleIncomingGroup(message) {
        if (message.senderId === this.agentId) {
            return; // 过滤自己发送的消息
        }
        this.processMessage(message);
    }
    /**
     * 处理收到的 Profile 信息
     * 由服务端在 Agent 连接时自动推送
     */
    handleProfileInfo(profile) {
        logger.info(`[AgentClient] 收到 Profile 信息: ${profile.displayName} (${profile.roleName})`);
        // 更新 Agent 所属项目（服务端决定的项目）
        if (profile.projectName) {
            this.projectName = profile.projectName;
            logger.info(`[AgentClient] 更新所属项目: ${this.projectName}`);
        }
        if (this.profileHandler) {
            // profileHandler 已设置，直接调用
            this.profileHandler(profile);
        }
        else {
            // profileHandler 未设置，缓存 profile
            logger.info("[AgentClient] profileHandler 未设置，缓存 Profile 信息");
            this.cachedProfile = profile;
        }
    }
    async processMessage(message) {
        if (!this.messageHandler) {
            return;
        }
        const isDm = typeof message.msgId === "string";
        logger.info(`[AgentClient] 收到${isDm ? "私信" : "群消息"}来自 ${message.senderName}: ${message.content.substring(0, 50)}...`);
        try {
            const reply = await this.messageHandler(message);
            // 处理调用式消息的回复
            if (isDm) {
                const dm = message;
                if (dm.requireReply && dm.callId) {
                    await this.replyToCall(dm.callId, dm.senderId, reply || "已收到消息，正在处理中...");
                }
            }
        }
        catch (error) {
            logger.error("[AgentClient] 处理消息失败:", error);
            // 处理调用式消息的错误回复
            if (typeof message.msgId === "string") {
                const dm = message;
                if (dm.requireReply && dm.callId) {
                    await this.replyToCall(dm.callId, dm.senderId, `处理失败: ${error}`);
                }
            }
        }
    }
    // ============ 工具方法 ============
    ensureRegistered() {
        if (!this.agentId) {
            throw new Error("Agent is not registered");
        }
    }
    delay(ms) {
        return new Promise((resolve) => {
            this.pollTimer = setTimeout(resolve, ms);
        });
    }
    getState() {
        return {
            agentId: this.agentId,
            displayName: this.displayName,
            projectName: this.projectName,
            isConnected: this.wsClient.isConnected(),
            isRunning: this.isRunning,
        };
    }
    getAgentConfig() {
        return this.agentConfig;
    }
    reloadConfig() {
        configManager.loadConfig();
        this.agentConfig = configManager.getAgentConfig();
        logger.info(`[AgentClient] 配置已重新加载，角色: ${this.agentConfig.roleName}`);
    }
    /**
     * 进入降级模式
     * 当注册失败时，Agent 可以降级运行，等待后续重试注册
     */
    enterDegradedMode() {
        this.isDegradedMode = true;
        logger.warn("[AgentClient] 进入降级模式，将在后台持续尝试重连");
    }
    /**
     * 退出降级模式
     * 当重连成功时，退出降级模式
     */
    exitDegradedMode() {
        this.isDegradedMode = false;
        logger.info("[AgentClient] 退出降级模式");
    }
    /**
     * 是否处于降级模式
     */
    isInDegradedMode() {
        return this.isDegradedMode;
    }
    /**
     * 降级模式下重试注册
     * 在后台持续尝试重新注册到调度中心
     */
    async retryRegistrationInBackground(retryIntervalMs, maxRetries) {
        let retryCount = 0;
        const retryLoop = async () => {
            while (this.isDegradedMode) {
                try {
                    logger.info(`[AgentClient] 降级模式：尝试重新注册 (${retryCount + 1}/${maxRetries === -1 ? "无限" : maxRetries})`);
                    const result = await this.register();
                    logger.info(`[AgentClient] 降级模式：注册成功 - ${result.displayName} (${result.agentId})`);
                    // 注册成功，退出降级模式
                    this.exitDegradedMode();
                    // 启动消息监听
                    if (this.messageHandler) {
                        this.start(this.messageHandler);
                    }
                    return;
                }
                catch (error) {
                    retryCount++;
                    const errorMessage = error instanceof Error ? error.message : String(error);
                    logger.warn(`[AgentClient] 降级模式：注册失败 (${retryCount}/${maxRetries === -1 ? "无限" : maxRetries}): ${errorMessage}`);
                    // 检查是否达到最大重试次数
                    if (maxRetries > 0 && retryCount >= maxRetries) {
                        logger.error(`[AgentClient] 降级模式：达到最大重试次数，停止重连`);
                        this.isDegradedMode = false;
                        return;
                    }
                    // 等待后重试
                    await new Promise((resolve) => setTimeout(resolve, retryIntervalMs));
                }
            }
        };
        // 启动后台重试循环
        retryLoop().catch((error) => {
            logger.error("[AgentClient] 降级模式后台重试异常:", error);
        });
    }
    // ============ 状态报告 ============
    /**
     * 初始化状态报告器
     */
    initializeStatusReporter() {
        if (!this.agentId) {
            logger.warn("[AgentClient] 无法初始化状态报告器：agentId 为空");
            return;
        }
        this.statusReporter = new StatusReporter({
            agentId: this.agentId,
            sendStatusUpdate: (update) => {
                // 通过 WebSocket 发送状态更新
                this.wsClient.send({
                    type: "AGENT_STATUS",
                    data: update,
                    timestamp: new Date().toISOString(),
                });
            },
        });
        setMcpNodeLogSink((entry) => this.reportMcpNodeLog(entry));
        logger.info("[AgentClient] 状态报告器已初始化");
    }
    /**
     * 上报 MCP Node.js 进程自身日志。
     * 主流程：logger 写入 stderr/file -> sink 回调 -> WebSocket 转发给调度中心和面板。
     */
    reportMcpNodeLog(entry) {
        const maybeLogSender = this.wsClient;
        if (!this.agentId ||
            !this.wsClient.isConnected() ||
            typeof maybeLogSender.sendMcpNodeLog !== "function") {
            return;
        }
        maybeLogSender.sendMcpNodeLog(entry);
    }
    /**
     * 获取状态报告器（供 MCP Server 使用）
     */
    getStatusReporter() {
        return this.statusReporter;
    }
}
//# sourceMappingURL=agent-client.js.map