// @ts-nocheck
import { debugLog } from './common';

const debugNotifyLog = (...args: any[]) => {
  void args;
};
const keyNotifyLog = (...args: any[]) => {
  console.log(...args);
};
const jsonDebug = (...args: any[]) => {
  console.log('[JSONDEBUG]', ...args);
};
const userMDebug = (...args: any[]) => {
  console.log('[USERMDEBUG]', ...args);
};
const RESTORE_DEBUG_PREFIX = '[RESTORE_DEBUG]';
let restoreDebugCount = 0;
const RESTORE_DEBUG_MAX = 800;
const RESTORE_DEBUG_EVENTS = new Set([
  'restore:start',
  'restore:running-task-found',
  'restore:history-empty',
  'restore:task-detail-events',
  'restore:rebuild-decision',
  'restore:rebuild-polling-started',
  'restore:polling-started-follow',
  'restore:thinking-chunk-auto-start',
  'restore:text-chunk-auto-start',
  'restore:error',
  'event:drop-duplicate',
  'event:drop-conversation-mismatch'
]);

function isRestoreDebugEnabled() {
  if (typeof window === 'undefined') return true;
  try {
    const explicit = (window as any).__RESTORE_DEBUG__;
    if (explicit === false || explicit === '0') return false;
    if (explicit === true || explicit === '1') return true;
    const localFlag = window.localStorage?.getItem('restoreDebug');
    if (localFlag === '0' || localFlag === 'false') return false;
    if (localFlag === '1' || localFlag === 'true') return true;
    return true;
  } catch {
    return true;
  }
}

function restoreDebugLog(event: string, payload: Record<string, any> = {}) {
  if (!isRestoreDebugEnabled()) return;
  if (!RESTORE_DEBUG_EVENTS.has(event)) return;
  if (restoreDebugCount >= RESTORE_DEBUG_MAX) return;
  restoreDebugCount += 1;
  if (restoreDebugCount === RESTORE_DEBUG_MAX) {
    console.warn(RESTORE_DEBUG_PREFIX, 'log-limit-reached', { max: RESTORE_DEBUG_MAX });
    return;
  }
  console.log(RESTORE_DEBUG_PREFIX, event, payload);
}

function isSystemAutoUserMessagePayload(data: any): boolean {
  if (!data || typeof data !== 'object') {
    return false;
  }
  const meta = data.metadata || {};
  return !!(
    data.is_auto_generated ||
    meta.is_auto_generated ||
    data.auto_message_type ||
    meta.auto_message_type ||
    data.sub_agent_notice ||
    meta.sub_agent_notice ||
    data.background_command_notice ||
    meta.background_command_notice ||
    data.runtime_guidance ||
    meta.runtime_guidance ||
    data.runtime_mode_notice ||
    meta.runtime_mode_notice
  );
}

function isRuntimeModeNoticePayload(data: any): boolean {
  if (!data || typeof data !== 'object') {
    return false;
  }
  const meta = data.metadata || {};
  return !!(
    data.runtime_guidance ||
    meta.runtime_guidance ||
    data.runtime_mode_notice ||
    meta.runtime_mode_notice
  );
}

function resolveUserMessageSource(data: any): string {
  if (!data || typeof data !== 'object') {
    return 'user';
  }
  const meta = data.metadata || {};
  const explicit = String(data.message_source || meta.message_source || '')
    .trim()
    .toLowerCase();
  if (explicit) {
    return explicit;
  }
  if (data.runtime_mode_notice || meta.runtime_mode_notice) {
    return 'notify';
  }
  if (data.runtime_guidance || meta.runtime_guidance) {
    return 'guidance';
  }
  if (data.background_command_notice || meta.background_command_notice) {
    return 'background_command';
  }
  if (data.sub_agent_notice || meta.sub_agent_notice) {
    return 'sub_agent';
  }
  return 'user';
}

function isEmptyAssistantPlaceholderMessage(message: any): boolean {
  if (!message || message.role !== 'assistant') {
    return false;
  }
  const actions = Array.isArray(message.actions) ? message.actions : [];
  return actions.length === 0 && !!message.awaitingFirstContent;
}

function getOptimisticUserEchoTarget(messages: any[]): any | null {
  if (!Array.isArray(messages) || messages.length === 0) {
    return null;
  }
  const lastIndex = messages.length - 1;
  const last = messages[lastIndex];
  if (last?.role === 'user') {
    return last;
  }
  if (isEmptyAssistantPlaceholderMessage(last) && lastIndex > 0) {
    const prev = messages[lastIndex - 1];
    if (prev?.role === 'user') {
      return prev;
    }
  }
  return null;
}

/**
 * 任务轮询事件处理器
 * 将从 REST API 轮询获取的事件转换为前端状态更新
 */
export const taskPollingMethods = {
  scheduleTodoListRefresh(delayMs = 120) {
    const delay = Number.isFinite(delayMs) ? Math.max(0, Number(delayMs)) : 120;
    if (this._todoRefreshTimer) {
      clearTimeout(this._todoRefreshTimer);
      this._todoRefreshTimer = null;
    }
    this._todoRefreshTimer = setTimeout(() => {
      this._todoRefreshTimer = null;
      if (typeof this.fetchTodoList === 'function') {
        Promise.resolve(this.fetchTodoList()).catch(() => {});
      }
    }, delay);
  },

  cleanupTrailingEmptyAssistantPlaceholder(reason = 'unspecified') {
    if (!Array.isArray(this.messages) || !this.messages.length) {
      return false;
    }
    const last = this.messages[this.messages.length - 1];
    if (!isEmptyAssistantPlaceholderMessage(last)) {
      return false;
    }
    this.messages.pop();
    if (typeof this.currentMessageIndex === 'number') {
      this.currentMessageIndex = this.messages.length - 1;
    }
    userMDebug('taskPolling.cleanupTrailingEmptyAssistantPlaceholder:removed', {
      reason,
      messagesLengthAfter: this.messages.length,
      currentMessageIndex: this.currentMessageIndex
    });
    return true;
  },

  stopWaitingTaskProbe() {
    if (this.waitingTaskProbeTimer) {
      debugNotifyLog('[DEBUG_NOTIFY][ui] stopWaitingTaskProbe');
      clearInterval(this.waitingTaskProbeTimer);
      this.waitingTaskProbeTimer = null;
    }
    this._waitingProbeStableEmptyCount = 0;
  },

  async inspectWaitingCompletionState() {
    const terminalStatuses = new Set(['completed', 'failed', 'timeout', 'terminated', 'cancelled']);
    let hasSubAgentPending = false;
    let hasBackgroundPending = false;
    let resolved = true;

    try {
      const [subResp, bgResp] = await Promise.all([
        fetch('/api/sub_agents'),
        fetch('/api/background_commands?limit=200')
      ]);

      if (subResp.ok) {
        const subResult = await subResp.json().catch(() => ({}));
        const tasks = Array.isArray(subResult?.data) ? subResult.data : [];
        const relevantTasks = tasks.filter((task: any) => {
          if (!task) return false;
          if (task.conversation_id && task.conversation_id !== this.currentConversationId)
            return false;
          return true;
        });
        hasSubAgentPending = relevantTasks.some((task: any) => {
          if (!task?.run_in_background) return false;
          const status = String(task?.status || '').toLowerCase();
          return !terminalStatuses.has(status) || !!task?.notice_pending;
        });
      } else {
        resolved = false;
      }

      if (bgResp.ok) {
        const bgResult = await bgResp.json().catch(() => ({}));
        const commands = Array.isArray(bgResult?.data) ? bgResult.data : [];
        hasBackgroundPending = commands.some((command: any) => {
          if (!command) return false;
          const status = String(command?.status || '').toLowerCase();
          return !terminalStatuses.has(status) || !!command?.notice_pending;
        });
      } else {
        resolved = false;
      }
    } catch (error) {
      debugNotifyLog('[DEBUG_NOTIFY][ui] inspectWaitingCompletionState:error', {
        error: error?.message || String(error)
      });
      return {
        resolved: false,
        hasPending: true,
        hasBackgroundPending: this.waitingForBackgroundCommand
      };
    }

    return {
      resolved,
      hasPending: !resolved || hasSubAgentPending || hasBackgroundPending,
      hasBackgroundPending
    };
  },

  async tryResumeWaitingNoticeTask() {
    if (!this.waitingForSubAgent || !this.currentConversationId) {
      debugNotifyLog('[DEBUG_NOTIFY][ui] tryResumeWaitingNoticeTask:skip', {
        waitingForSubAgent: this.waitingForSubAgent,
        currentConversationId: this.currentConversationId
      });
      return false;
    }
    try {
      const { useTaskStore } = await import('../../stores/task');
      const taskStore = useTaskStore();
      if (taskStore.hasActiveTask) {
        debugNotifyLog('[DEBUG_NOTIFY][ui] tryResumeWaitingNoticeTask:already-active', {
          taskId: taskStore.currentTaskId,
          status: taskStore.taskStatus
        });
        return true;
      }

      const resp = await fetch('/api/tasks');
      if (!resp.ok) {
        debugNotifyLog('[DEBUG_NOTIFY][ui] tryResumeWaitingNoticeTask:tasks-api-not-ok', {
          status: resp.status
        });
        return false;
      }
      const result = await resp.json().catch(() => ({}));
      const tasks = Array.isArray(result?.data) ? result.data : [];
      debugNotifyLog('[DEBUG_NOTIFY][ui] tryResumeWaitingNoticeTask:tasks', {
        currentConversationId: this.currentConversationId,
        count: tasks.length,
        running: tasks
          .filter((t: any) => t?.status === 'running')
          .map((t: any) => ({
            task_id: t?.task_id,
            conversation_id: t?.conversation_id,
            status: t?.status
          }))
      });
      const runningTask = tasks.find(
        (task: any) =>
          task?.status === 'running' && task?.conversation_id === this.currentConversationId
      );
      if (!runningTask?.task_id) {
        debugNotifyLog('[DEBUG_NOTIFY][ui] tryResumeWaitingNoticeTask:no-matched-task');
        return false;
      }

      debugNotifyLog('[DEBUG_NOTIFY][ui] tryResumeWaitingNoticeTask:resume', {
        task_id: runningTask.task_id
      });
      keyNotifyLog('[DEBUG_NOTIFY_KEY][ui] tryResumeWaitingNoticeTask:resume', {
        task_id: runningTask.task_id,
        conversationId: this.currentConversationId
      });
      // 关键修复：切到新的通知任务前，清空旧任务事件去重索引。
      // 否则新任务 event idx 与旧任务重叠时会被误判为“重复事件”而丢失 user_message。
      if (typeof this.clearProcessedEvents === 'function') {
        this.clearProcessedEvents();
      }
      taskStore.resumeTask(runningTask.task_id, {
        status: 'running',
        resetOffset: true,
        eventHandler: (event: any) => this.handleTaskEvent(event)
      });
      return true;
    } catch (error) {
      console.warn('[TaskPolling] 接管等待任务失败:', error);
      return false;
    }
  },

  startWaitingTaskProbe() {
    if (this.waitingTaskProbeTimer) {
      debugNotifyLog('[DEBUG_NOTIFY][ui] startWaitingTaskProbe:already-started');
      return;
    }
    debugNotifyLog('[DEBUG_NOTIFY][ui] startWaitingTaskProbe');
    keyNotifyLog('[DEBUG_NOTIFY_KEY][ui] startWaitingTaskProbe', {
      conversationId: this.currentConversationId
    });
    this.waitingTaskProbeTimer = setInterval(async () => {
      if (!this.waitingForSubAgent) {
        this.stopWaitingTaskProbe();
        return;
      }
      const resumed = await this.tryResumeWaitingNoticeTask();
      if (resumed) {
        debugNotifyLog('[DEBUG_NOTIFY][ui] waitingTaskProbe:resumed-and-stop');
        keyNotifyLog('[DEBUG_NOTIFY_KEY][ui] waitingTaskProbe:resumed-and-stop');
        this.stopWaitingTaskProbe();
        return;
      }

      const state = await this.inspectWaitingCompletionState();
      if (state.hasPending) {
        this._waitingProbeStableEmptyCount = 0;
        this.waitingForBackgroundCommand = !!state.hasBackgroundPending;
        return;
      }

      this._waitingProbeStableEmptyCount = (this._waitingProbeStableEmptyCount || 0) + 1;
      if (this._waitingProbeStableEmptyCount >= 2) {
        debugLog('[TaskPolling] 等待态兜底清理：未发现运行中的后台子智能体/后台指令');
        this.streamingMessage = false;
        this.taskInProgress = false;
        this.stopRequested = false;
        this.waitingForSubAgent = false;
        this.waitingForBackgroundCommand = false;
        if (typeof this.clearPendingTools === 'function') {
          this.clearPendingTools('waiting_probe_auto_clear');
        }
        this.clearTaskState();
        this.stopWaitingTaskProbe();
        this.$forceUpdate();
      }
    }, 1000);
  },

  /**
   * 处理任务事件（从轮询获取）
   */
  handleTaskEvent(event: any) {
    if (!event || !event.type) {
      return;
    }

    const eventType = event.type;
    const eventData = event.data || {};
    const eventIdx = event.idx;
    if (eventType === 'task_complete' || eventType === 'task_stopped' || eventType === 'error') {
      jsonDebug('task-event', {
        eventType,
        eventIdx,
        currentConversationId: this.currentConversationId,
        eventConversationId: eventData?.conversation_id,
        taskInProgress: this.taskInProgress,
        streamingMessage: this.streamingMessage,
        stopRequested: this.stopRequested,
        waitingForSubAgent: this.waitingForSubAgent,
        waitingForBackgroundCommand: this.waitingForBackgroundCommand,
        errorType: eventData?.error_type,
        errorMessage: eventData?.message
      });
    }
    if (
      eventType === 'system_message' ||
      eventType === 'sub_agent_waiting' ||
      (eventType === 'user_message' && eventData?.sub_agent_notice)
    ) {
      debugNotifyLog('[DEBUG_NOTIFY][event] 捕获关键事件', {
        eventType,
        eventIdx,
        eventData
      });
      keyNotifyLog('[DEBUG_NOTIFY_KEY][event] key-event', {
        eventType,
        idx: eventIdx,
        task_id: eventData?.task_id,
        sub_agent_notice: !!eventData?.sub_agent_notice,
        has_running_sub_agents: eventData?.has_running_sub_agents,
        has_running_background_commands: eventData?.has_running_background_commands
      });
    }

    // 事件去重检查
    if (typeof eventIdx === 'number') {
      if (!this._processedEventIndices) {
        this._processedEventIndices = new Set();
      }

      if (this._processedEventIndices.has(eventIdx)) {
        if (
          [
            'ai_message_start',
            'thinking_start',
            'thinking_chunk',
            'thinking_end',
            'text_start',
            'text_chunk',
            'text_end'
          ].includes(eventType)
        ) {
          restoreDebugLog('event:drop-duplicate', {
            eventType,
            eventIdx,
            currentConversationId: this.currentConversationId
          });
        }
        debugLog(`[TaskPolling] 跳过重复事件 #${eventIdx}`);
        return;
      }

      this._processedEventIndices.add(eventIdx);

      // 限制 Set 大小（保留最近 1000 个）
      if (this._processedEventIndices.size > 1000) {
        const firstIdx = Math.min(...this._processedEventIndices);
        this._processedEventIndices.delete(firstIdx);
      }
    }

    // 检查事件的 conversation_id 是否匹配当前对话
    // 如果不匹配，忽略该事件（避免切换对话后旧任务的事件显示到新对话中）
    const crossConversationAllowed = new Set([
      'shallow_compression',
      'conversation_resolved',
      'compression_finished'
    ]);
    if (
      !crossConversationAllowed.has(eventType) &&
      eventData.conversation_id &&
      this.currentConversationId
    ) {
      if (eventData.conversation_id !== this.currentConversationId) {
        if (
          [
            'ai_message_start',
            'thinking_start',
            'thinking_chunk',
            'thinking_end',
            'text_start',
            'text_chunk',
            'text_end'
          ].includes(eventType)
        ) {
          restoreDebugLog('event:drop-conversation-mismatch', {
            eventType,
            eventIdx,
            eventConversationId: eventData.conversation_id,
            currentConversationId: this.currentConversationId
          });
        }
        console.log(`[DEBUG_AWAITING] 忽略不匹配的事件`, {
          eventType,
          eventIdx,
          eventConversationId: eventData.conversation_id,
          currentConversationId: this.currentConversationId
        });
        debugLog(
          `[TaskPolling] 忽略不匹配的事件 #${eventIdx}: ${eventType}, 事件对话=${eventData.conversation_id}, 当前对话=${this.currentConversationId}`
        );
        return;
      }
    }

    debugLog(`[TaskPolling] 处理事件 #${eventIdx}: ${eventType}`, eventData);

    console.log(`[DEBUG_AWAITING] 处理事件`, {
      eventType,
      eventIdx,
      eventConversationId: eventData.conversation_id,
      currentConversationId: this.currentConversationId
    });

    // 根据事件类型调用对应的处理方法
    switch (eventType) {
      case 'ai_message_start':
        this.handleAiMessageStart(eventData, eventIdx);
        break;

      case 'thinking_start':
        this.handleThinkingStart(eventData, eventIdx);
        break;

      case 'thinking_chunk':
        this.handleThinkingChunk(eventData, eventIdx);
        break;

      case 'thinking_end':
        this.handleThinkingEnd(eventData, eventIdx);
        break;

      case 'text_start':
        this.handleTextStart(eventData, eventIdx);
        break;

      case 'text_chunk':
        this.handleTextChunk(eventData, eventIdx);
        break;

      case 'text_end':
        this.handleTextEnd(eventData, eventIdx);
        break;

      case 'tool_preparing':
        this.handleToolPreparing(eventData, eventIdx);
        break;

      case 'tool_start':
        this.handleToolStart(eventData, eventIdx);
        break;

      case 'tool_intent':
        this.handleToolIntent(eventData, eventIdx);
        break;

      case 'tool_update_action':
      case 'update_action':
        this.handleToolUpdateAction(eventData, eventIdx);
        break;
      case 'tool_approval_required':
        this.handleToolApprovalRequired(eventData, eventIdx);
        break;
      case 'tool_approval_resolved':
        this.handleToolApprovalResolved(eventData, eventIdx);
        break;
      case 'auto_approval_progress':
        this.handleAutoApprovalProgress(eventData, eventIdx);
        break;

      case 'append_payload':
        this.handleAppendPayload(eventData, eventIdx);
        break;

      case 'modify_payload':
        this.handleModifyPayload(eventData, eventIdx);
        break;

      case 'task_complete':
        this.handleTaskComplete(eventData, eventIdx);
        break;

      case 'task_stopped':
        this.handleTaskStopped(eventData, eventIdx);
        break;

      case 'error':
        this.handleTaskError(eventData, eventIdx);
        break;

      case 'token_update':
        this.handleTokenUpdate(eventData, eventIdx);
        break;

      case 'conversation_changed':
        this.handleConversationChanged(eventData, eventIdx);
        break;

      case 'conversation_resolved':
        this.handleConversationResolved(eventData, eventIdx);
        break;
      case 'compression_state':
        this.handleCompressionState(eventData, eventIdx);
        break;
      case 'compression_finished':
        this.handleCompressionFinished(eventData, eventIdx);
        break;
      case 'shallow_compression':
        this.handleShallowCompression(eventData, eventIdx);
        break;

      case 'user_message':
        debugNotifyLog('[DEBUG_NOTIFY][event] dispatch:user_message', {
          idx: eventIdx,
          data: eventData
        });
        this.handleUserMessage(eventData, eventIdx);
        break;

      case 'system_message':
        this.handleSystemMessage(eventData, eventIdx);
        break;
      case 'runtime_queue_sync':
        this.handleRuntimeQueueSync(eventData);
        break;

      default:
        debugLog(`[TaskPolling] 未知事件类型: ${eventType}`);
    }

    // 注意：不要在这里清除 _rebuildingFromScratch 标记
    // 该标记应该在恢复完所有历史事件后才清除
  },

  handleAiMessageStart(data: any, eventIdx: number) {
    const lastMessage = this.messages[this.messages.length - 1];
    console.log('[DEBUG_AWAITING] ===== handleAiMessageStart =====', {
      eventIdx,
      lastMessageRole: lastMessage?.role,
      lastMessageAwaitingFirstContent: lastMessage?.awaitingFirstContent,
      lastMessageGeneratingLabel: lastMessage?.generatingLabel
    });

    debugLog('[TaskPolling] AI消息开始, idx:', eventIdx);
    console.log('[AiMessageStart] 开始处理', {
      eventIdx,
      messagesLength: this.messages.length,
      lastMessageRole: this.messages[this.messages.length - 1]?.role,
      streamingMessage: this.streamingMessage,
      taskInProgress: this.taskInProgress,
      currentConversationId: this.currentConversationId
    });

    if (this.waitingForSubAgent) {
      this.waitingForSubAgent = false;
    }

    // 检查是否已经有 assistant 消息
    const hasAssistantMessage = lastMessage && lastMessage.role === 'assistant';

    console.log('[AiMessageStart] 最后一条消息状态', {
      hasAssistantMessage,
      lastMessageActionsLength: lastMessage?.actions?.length || 0,
      lastMessageAwaitingFirstContent: lastMessage?.awaitingFirstContent,
      lastMessageGeneratingLabel: lastMessage?.generatingLabel
    });

    // 判断是否是刷新恢复的情况：
    // 1. 有assistant消息
    // 2. 且最后一条 assistant 仍处于“未完成流式状态”（而不是普通已完成消息）
    // 3. 且任务确实仍在进行中
    const lastActions = Array.isArray(lastMessage?.actions) ? lastMessage.actions : [];
    const hasUnfinishedAction = lastActions.some((action: any) => {
      if (!action) return false;
      if (action.streaming) return true;
      if (action.type === 'tool' && action.tool) {
        const status = String(action.tool.status || '').toLowerCase();
        return ['preparing', 'running', 'pending', 'queued', 'awaiting_approval'].includes(status);
      }
      return false;
    });
    const hasNoActionsYet = !lastActions.length;
    const isRefreshRestore =
      hasAssistantMessage &&
      (hasNoActionsYet || hasUnfinishedAction || lastMessage.awaitingFirstContent === true) &&
      (this.taskInProgress || this.streamingMessage);

    userMDebug('taskPolling.handleAiMessageStart:decision', {
      eventIdx,
      hasAssistantMessage,
      hasNoActionsYet,
      hasUnfinishedAction,
      awaitingFirstContent: !!lastMessage?.awaitingFirstContent,
      taskInProgress: this.taskInProgress,
      streamingMessage: this.streamingMessage,
      isRefreshRestore
    });

    console.log('[AiMessageStart] 场景判断', {
      isRefreshRestore,
      streamingMessage: this.streamingMessage,
      hasActions: !!(lastMessage?.actions && lastMessage.actions.length > 0),
      awaitingFirstContent: lastMessage?.awaitingFirstContent,
      taskInProgress: this.taskInProgress
    });

    if (isRefreshRestore) {
      console.log('[AiMessageStart] 场景=刷新恢复，复用现有assistant消息');
      debugLog('[TaskPolling] 刷新恢复场景，复用现有 assistant 消息');
      // 只更新状态，不创建新消息
      this.taskInProgress = true;
      this.stopRequested = false;
      this.streamingMessage = true;

      // 确保 awaitingFirstContent 被正确设置
      const hasContent = lastMessage.actions && lastMessage.actions.length > 0;
      if (!hasContent) {
        lastMessage.awaitingFirstContent = true;
        lastMessage.generatingLabel = lastMessage.generatingLabel || '思考中...';
        console.log('[AiMessageStart] 设置等待动画', {
          awaitingFirstContent: true,
          generatingLabel: lastMessage.generatingLabel
        });
      } else {
        // 如果已有内容，确保等待动画不显示
        lastMessage.awaitingFirstContent = false;
        lastMessage.generatingLabel = '';
        console.log('[AiMessageStart] 关闭等待动画（已有内容）');
      }
      return;
    }

    // 其他情况：创建新的 assistant 消息
    console.log('[AiMessageStart] 场景=创建新消息');
    debugLog('[TaskPolling] 创建新的 assistant 消息');
    this.monitorResetSpeech();
    this.cleanupStaleToolActions();
    this.taskInProgress = true;
    this.chatStartAssistantMessage();
    this.stopRequested = false;
    this.streamingMessage = true;

    const newMessage = this.messages[this.messages.length - 1];
    console.log('[AiMessageStart] 新消息创建完成', {
      role: newMessage?.role,
      awaitingFirstContent: newMessage?.awaitingFirstContent,
      generatingLabel: newMessage?.generatingLabel,
      actionsLength: newMessage?.actions?.length || 0,
      messagesLength: this.messages.length
    });

    // 如果是从头重建，标记消息为静默恢复
    if (this._rebuildingFromScratch) {
      if (newMessage && newMessage.role === 'assistant') {
        debugLog('[TaskPolling] 标记消息为静默恢复（从头重建）');
        newMessage.awaitingFirstContent = false;
        newMessage.generatingLabel = '';
        console.log('[AiMessageStart] 从头重建，关闭等待动画');
      }
    }

    // 强制触发Vue响应式更新
    this.$forceUpdate();
    console.log('[AiMessageStart] 已调用$forceUpdate');

    this.$nextTick(() => {
      console.log('[AiMessageStart] nextTick回调执行');
      this.conditionalScrollToBottom();
    });
  },

  handleThinkingStart(data: any, eventIdx: number) {
    console.log('[ThinkingStart] 开始处理', { eventIdx });
    debugLog('[TaskPolling] 思考开始, idx:', eventIdx);
    const ignoreThinking = this.runMode === 'fast' || this.thinkingMode === false;
    if (ignoreThinking) {
      this.monitorEndModelOutput();
      console.log('[ThinkingStart] 忽略思考（fast模式或关闭思考）');
      return;
    }

    // 防御性检查：如果没有assistant消息，先创建一个
    const lastMessage = this.messages[this.messages.length - 1];
    if (!lastMessage || lastMessage.role !== 'assistant') {
      console.log('[DEBUG_AWAITING] ThinkingStart 检测到缺少assistant消息，自动创建');
      this.chatStartAssistantMessage();
    }

    this.monitorShowThinking();

    const result = this.chatStartThinkingAction();

    if (result && result.blockId) {
      const blockId = result.blockId;

      const lastMessage = this.messages[this.messages.length - 1];

      // 有内容了，关闭等待动画
      if (lastMessage && lastMessage.role === 'assistant') {
        console.log('[ThinkingStart] 关闭等待动画', {
          beforeAwaitingFirstContent: lastMessage.awaitingFirstContent,
          beforeGeneratingLabel: lastMessage.generatingLabel
        });
        lastMessage.awaitingFirstContent = false;
        lastMessage.generatingLabel = '';
      }

      // 只在非历史恢复时展开思考块
      if (!this._rebuildingFromScratch) {
        this.chatExpandBlock(blockId);
      }

      this.conditionalScrollToBottom();
      this.chatSetThinkingLock(blockId, true);

      // 强制触发 actions 数组的响应式更新
      if (lastMessage && lastMessage.actions) {
        lastMessage.actions = [...lastMessage.actions];
      }

      this.$forceUpdate();
    }
  },

  handleThinkingChunk(data: any) {
    if (this.runMode === 'fast' || this.thinkingMode === false) {
      return;
    }
    let thinkingAction = this.chatAppendThinkingChunk(data.content);
    // 兜底：刷新恢复时可能只能拿到 chunk 事件（start 事件已被服务端窗口截断）
    // 此时补建一个 thinking action，避免思考内容丢失。
    if (!thinkingAction && data?.content) {
      const started = this.chatStartThinkingAction();
      thinkingAction = this.chatAppendThinkingChunk(data.content);
      restoreDebugLog('restore:thinking-chunk-auto-start', {
        startedBlockId: started?.blockId || null,
        contentLength: String(data.content || '').length,
        currentConversationId: this.currentConversationId
      });
    }
    if (thinkingAction) {
      this.$forceUpdate();
      this.$nextTick(() => {
        if (thinkingAction && thinkingAction.blockId) {
          this.scrollThinkingToBottom(thinkingAction.blockId);
        }
        this.conditionalScrollToBottom();
      });
    }
    this.monitorShowThinking();
  },

  handleThinkingEnd(data: any) {
    debugLog('[TaskPolling] 思考结束');
    if (this.runMode === 'fast' || this.thinkingMode === false) {
      return;
    }
    const blockId = this.chatCompleteThinkingAction(data.full_content);
    if (blockId) {
      // 解锁思考块
      this.chatSetThinkingLock(blockId, false);

      // 只在非历史恢复时延迟折叠思考块
      if (!this._rebuildingFromScratch) {
        // 延迟折叠思考块（给用户一点时间看到思考完成）
        setTimeout(() => {
          this.chatCollapseBlock(blockId);
          this.$forceUpdate();
        }, 1000);
      } else {
        // 历史恢复时立即折叠，不需要动画
        this.chatCollapseBlock(blockId);
      }

      this.$nextTick(() => this.scrollThinkingToBottom(blockId));
    }
    this.$forceUpdate();
    this.monitorEndModelOutput();
  },

  handleTextStart() {
    console.log('[TextStart] 开始处理');
    debugLog('[TaskPolling] 文本开始');

    // 防御性检查：如果没有assistant消息，先创建一个
    const lastMessage = this.messages[this.messages.length - 1];
    if (!lastMessage || lastMessage.role !== 'assistant') {
      console.log('[DEBUG_AWAITING] TextStart 检测到缺少assistant消息，自动创建');
      this.chatStartAssistantMessage();
    }

    this.chatStartTextAction();

    // 有内容了，关闭等待动画
    const currentMessage = this.messages[this.messages.length - 1];
    if (currentMessage && currentMessage.role === 'assistant') {
      console.log('[TextStart] 关闭等待动画', {
        beforeAwaitingFirstContent: currentMessage.awaitingFirstContent,
        beforeGeneratingLabel: currentMessage.generatingLabel
      });
      currentMessage.awaitingFirstContent = false;
      currentMessage.generatingLabel = '';
    }

    this.$forceUpdate();
  },

  handleTextChunk(data: any) {
    if (data && typeof data.content === 'string' && data.content.length) {
      let textAction = this.chatAppendTextChunk(data.content);
      // 兜底：刷新恢复时可能只有 text_chunk（缺少 text_start），需要自动补建 text action
      if (!textAction) {
        this.chatStartTextAction();
        textAction = this.chatAppendTextChunk(data.content);
        restoreDebugLog('restore:text-chunk-auto-start', {
          contentLength: data.content.length,
          appendedAfterStart: !!textAction,
          currentConversationId: this.currentConversationId
        });
      }
      this.$forceUpdate();
      this.conditionalScrollToBottom();
      const speech = data.content.replace(/\r/g, '');
      if (speech) {
        this.monitorShowSpeech(speech);
      }
    }
  },

  handleTextEnd(data: any) {
    debugLog('[TaskPolling] 文本结束');
    const full = data?.full_content || '';
    this.chatCompleteTextAction(full);
    this.$forceUpdate();
    this.monitorEndModelOutput();
  },

  handleToolPreparing(data: any) {
    console.log('[ToolPreparing] 开始处理', { name: data.name, id: data.id });
    debugLog('[TaskPolling] 工具准备中:', data.name);

    if (this.dropToolEvents) {
      console.log('[ToolPreparing] dropToolEvents=true，跳过');
      return;
    }

    const msg = this.chatEnsureAssistantMessage();
    if (!msg) {
      console.log('[ToolPreparing] 无法获取assistant消息');
      return;
    }

    if (msg.awaitingFirstContent) {
      console.log('[ToolPreparing] 关闭等待动画', {
        beforeAwaitingFirstContent: msg.awaitingFirstContent,
        beforeGeneratingLabel: msg.generatingLabel
      });
      msg.awaitingFirstContent = false;
      msg.generatingLabel = '';
    }

    const action = {
      id: data.id,
      type: 'tool',
      tool: {
        id: data.id,
        name: data.name,
        arguments: {},
        argumentSnapshot: null,
        argumentLabel: '',
        status: 'preparing',
        result: null,
        message: data.message || `准备调用 ${data.name}...`,
        intent_full: data.intent || '',
        intent_rendered: data.intent || ''
      },
      timestamp: Date.now()
    };

    msg.actions.push(action);
    this.preparingTools.set(data.id, action);
    this.toolRegisterAction(action, data.id);
    this.toolTrackAction(data.name, action);

    this.$forceUpdate();
    this.conditionalScrollToBottom();

    if (this.monitorPreviewTool) {
      this.monitorPreviewTool(data);
    }
  },

  handleToolStart(data: any) {
    debugLog('[TaskPolling] 工具开始:', data.name);

    if (this.dropToolEvents) {
      return;
    }

    let action = null;
    if (data.preparing_id && this.preparingTools.has(data.preparing_id)) {
      action = this.preparingTools.get(data.preparing_id);
      this.preparingTools.delete(data.preparing_id);
    } else {
      action = this.toolFindAction(data.id, data.preparing_id, data.execution_id);
    }

    if (!action) {
      const msg = this.chatEnsureAssistantMessage();
      if (!msg) {
        return;
      }
      action = {
        id: data.id,
        type: 'tool',
        tool: {
          id: data.id,
          name: data.name,
          arguments: {},
          argumentSnapshot: null,
          argumentLabel: '',
          status: 'running',
          result: null
        },
        timestamp: Date.now()
      };
      msg.actions.push(action);
    }

    action.tool.status = 'running';
    action.tool.arguments = data.arguments;
    action.tool.argumentSnapshot = this.cloneToolArguments(data.arguments);
    action.tool.argumentLabel = this.buildToolLabel(action.tool.argumentSnapshot);
    action.tool.message = null;
    action.tool.id = data.id;
    action.tool.executionId = data.id;

    this.toolRegisterAction(action, data.id);
    this.toolTrackAction(data.name, action);
    this.$forceUpdate();
    this.conditionalScrollToBottom();

    if (this.monitorQueueTool) {
      this.monitorQueueTool(data);
    }
  },

  handleToolIntent(data: any) {
    debugLog('[TaskPolling] 工具意图:', data.name, data.intent);

    if (this.dropToolEvents) {
      return;
    }

    // 查找对应的工具 action
    const action = this.toolFindAction(data.id, data.preparing_id, data.execution_id);

    if (action && action.tool) {
      const newIntent = data.intent || '';

      // 如果 intent 没有变化，跳过
      if (action.tool.intent_full === newIntent) {
        return;
      }

      // 停止之前的打字机效果
      if (action.tool._intentTyping) {
        action.tool._intentTyping = false;
        if (action.tool._intentTimer) {
          clearTimeout(action.tool._intentTimer);
          action.tool._intentTimer = null;
        }
      }

      // 更新完整 intent
      action.tool.intent_full = newIntent;

      // 判断是否是历史恢复：只有从头重建时才直接显示
      const isHistoryRestore = this._rebuildingFromScratch;

      if (isHistoryRestore) {
        // 历史恢复，直接显示完整 intent
        action.tool.intent_rendered = newIntent;
        debugLog('[TaskPolling] 历史恢复，直接显示 intent');
      } else {
        // 新工具块，逐字符显示
        debugLog('[TaskPolling] 新工具块，开始打字机效果');
        action.tool.intent_rendered = '';
        action.tool._intentTyping = true;

        // 计算每个字符的间隔时间
        // 总时长1秒，但最少0.5秒
        const totalDuration = Math.max(500, Math.min(1000, newIntent.length * 50));
        const charInterval = totalDuration / newIntent.length;

        let charIndex = 0;
        const typeNextChar = () => {
          if (charIndex < newIntent.length && action.tool._intentTyping) {
            action.tool.intent_rendered += newIntent[charIndex];
            charIndex++;
            this.$forceUpdate();
            action.tool._intentTimer = setTimeout(typeNextChar, charInterval);
          } else {
            action.tool._intentTyping = false;
            action.tool.intent_rendered = newIntent; // 确保完整
            action.tool._intentTimer = null;
            this.$forceUpdate();
          }
        };

        action.tool._intentTimer = setTimeout(typeNextChar, 50); // 延迟50ms开始
      }

      // 更新 arguments 和 label
      if (action.tool.arguments) {
        action.tool.arguments.intent = newIntent;
        action.tool.argumentSnapshot = this.cloneToolArguments(action.tool.arguments);
        action.tool.argumentLabel = this.buildToolLabel(action.tool.argumentSnapshot);
      }

      this.$forceUpdate();
      debugLog('[TaskPolling] 已更新工具意图:', data.name);
    } else {
      debugLog('[TaskPolling] 未找到对应的工具 action:', data.id);
    }
  },

  handleToolUpdateAction(data: any) {
    if (this.dropToolEvents) {
      return;
    }

    debugLog('[TaskPolling] 更新action:', data.id, 'status:', data.status);

    let targetAction = this.toolFindAction(data.id, data.preparing_id, data.execution_id);
    if (!targetAction && data.preparing_id && this.preparingTools.has(data.preparing_id)) {
      targetAction = this.preparingTools.get(data.preparing_id);
    }

    if (!targetAction) {
      return;
    }

    if (data.status) {
      targetAction.tool.status = data.status;
    }
    if (data.result !== undefined) {
      targetAction.tool.result = data.result;

      // 处理个性化设置工具 - 刷新个人空间数据
      if (targetAction.tool && targetAction.tool.name === 'manage_personalization') {
        let result = data.result;
        if (typeof result === 'string') {
          try {
            result = JSON.parse(result);
          } catch (e) {
            /* ignore */
          }
        }
        // 处理主题变更
        if (result?.theme_changed === true && result.new_theme) {
          const theme = result.new_theme;
          if (typeof window !== 'undefined' && window.localStorage) {
            window.localStorage.setItem('agents_ui_theme', theme);
          }
          document.documentElement.setAttribute('data-theme', theme);
          document.body.setAttribute('data-theme', theme);
        }
        // 任何字段更新后都刷新个人空间数据
        (async () => {
          try {
            const { usePersonalizationStore } = await import('../../stores/personalization');
            const personalizationStore = usePersonalizationStore();
            // 强制刷新个人空间数据
            await personalizationStore.fetchPersonalization();
          } catch (e) {
            // 静默处理，不影响主流程
            console.debug('[TaskPolling] 刷新个人空间数据失败:', e);
          }
        })();
      }
    }
    if (data.message !== undefined) {
      targetAction.tool.message = data.message;
    }
    if (data.content !== undefined) {
      targetAction.tool.content = data.content;
    }

    // 待办工具执行完成后主动刷新左侧待办列表（网页端不再依赖 websocket todo_updated）
    if (data.status === 'completed') {
      const toolName = String(targetAction?.tool?.name || '').toLowerCase();
      if (
        toolName.startsWith('todo_') ||
        toolName === 'todo_create' ||
        toolName === 'todo_update_task'
      ) {
        this.scheduleTodoListRefresh(80);
      }
    }

    this.$forceUpdate();
    this.conditionalScrollToBottom();

    if (this.monitorResolveTool && data.status === 'completed') {
      this.monitorResolveTool(data);
    }
  },

  handleToolApprovalRequired(data: any) {
    const approval = data?.approval;
    if (!approval || !approval.approval_id) {
      return;
    }
    if (!Array.isArray(this.pendingToolApprovals)) {
      this.pendingToolApprovals = [];
    }
    const idx = this.pendingToolApprovals.findIndex(
      (item: any) => item && item.approval_id === approval.approval_id
    );
    if (idx >= 0) {
      this.pendingToolApprovals.splice(idx, 1, approval);
    } else {
      this.pendingToolApprovals.push(approval);
    }
    if (this.approvalAutoCloseTimer) {
      clearTimeout(this.approvalAutoCloseTimer);
      this.approvalAutoCloseTimer = null;
    }
    if ((this.autoApprovalFeedLines || []).length === 0) {
      this.autoApprovalFinalMessage = '';
    }
    this.rightCollapsed = false;
    if (this.rightWidth < this.minPanelWidth) {
      this.rightWidth = this.minPanelWidth;
    }
    if (this.isMobileViewport && this.activeMobileOverlay !== 'approval') {
      this.openMobileOverlay('approval');
    }
    this.$forceUpdate();
  },

  handleToolApprovalResolved(data: any) {
    const approvalId = data?.approval_id;
    if (!approvalId || !Array.isArray(this.pendingToolApprovals)) {
      return;
    }
    this.pendingToolApprovals = this.pendingToolApprovals.filter(
      (item: any) => item && item.approval_id !== approvalId
    );
    const decision = String(data?.decision || '').trim().toLowerCase();
    const reason = String(data?.reason || '').trim();
    if (decision === 'approved' || decision === 'rejected') {
      const decisionText = decision === 'approved' ? '批准通过' : '拒绝';
      this.autoApprovalFinalMessage = `${decisionText}\n原因：${reason || '未提供'}`;
    }
    // 电脑端：审批完成后延迟折叠面板（给用户留出查看结果时间）
    if (!this.pendingToolApprovals.length && !this.isMobileViewport) {
      if (this.approvalAutoCloseTimer) {
        clearTimeout(this.approvalAutoCloseTimer);
      }
      this.approvalAutoCloseTimer = setTimeout(() => {
        this.rightCollapsed = true;
      }, 3000);
    }
    this.$forceUpdate();
  },

  handleAutoApprovalProgress(data: any) {
    const progress = data?.progress;
    if (!progress || typeof progress !== 'object') {
      return;
    }
    if (!Array.isArray(this.autoApprovalFeedLines)) {
      this.autoApprovalFeedLines = [];
    }
    if (progress.stage === 'start') {
      this.autoApprovalFeedLines = ['自动审批开始'];
      this.autoApprovalFinalMessage = '';
    } else if (progress.stage === 'run_command' && progress.command) {
      this.autoApprovalFeedLines.push(String(progress.command));
    }
    this.autoApprovalFeedLines = this.autoApprovalFeedLines.slice(-20);
    this.$forceUpdate();
  },

  handleAppendPayload(data: any) {
    debugLog('[TaskPolling] 文件追加:', data.path);
    this.chatAddAppendPayloadAction(data);
    this.$forceUpdate();
    this.conditionalScrollToBottom();
  },

  handleModifyPayload(data: any) {
    debugLog('[TaskPolling] 文件修改:', data.path);
    this.chatAddModifyPayloadAction(data);
    this.$forceUpdate();
    this.conditionalScrollToBottom();
  },

  markLatestUserWorkCompleted() {
    if (!Array.isArray(this.messages) || this.messages.length === 0) {
      return;
    }
    for (let i = this.messages.length - 1; i >= 0; i -= 1) {
      const msg = this.messages[i];
      if (!msg || msg.role !== 'user') {
        continue;
      }
      msg.metadata = msg.metadata || {};
      const timer = msg.metadata.work_timer;
      if (!timer || typeof timer !== 'object') {
        continue;
      }
      if (timer.status === 'completed' && typeof timer.duration_ms === 'number') {
        return;
      }
      const nowIso = new Date().toISOString();
      const startedAt = timer.started_at || msg.timestamp || nowIso;
      const startMs = Date.parse(startedAt);
      const endMs = Date.now();
      const durationMs = Number.isFinite(startMs) ? Math.max(0, endMs - startMs) : 0;
      timer.status = 'completed';
      timer.started_at = startedAt;
      timer.finished_at = nowIso;
      timer.duration_ms = durationMs;
      return;
    }
  },

  handleTaskComplete(data: any) {
    const pendingToolsBefore =
      typeof this.hasPendingToolActions === 'function' ? this.hasPendingToolActions() : null;
    const pendingRuntimeGuidance = Array.isArray(data?.pending_runtime_guidance_messages)
      ? data.pending_runtime_guidance_messages
          .map((item: any) => String(item || '').trim())
          .filter((item: string) => item.length > 0)
      : [];
    if (pendingRuntimeGuidance.length > 0) {
      const limit = Math.max(1, Number(this.runtimeQueueLimit || 5));
      const mergedGuidance = [
        ...(this.runtimeGuidanceFallbackQueue || []),
        ...pendingRuntimeGuidance
      ]
        .map((item: any) => String(item || '').trim())
        .filter((item: string) => item.length > 0)
        .slice(0, limit);
      const queueAllowance = Math.max(0, limit - mergedGuidance.length);
      if (
        Array.isArray(this.runtimeQueuedMessages) &&
        this.runtimeQueuedMessages.length > queueAllowance
      ) {
        this.runtimeQueuedMessages = this.runtimeQueuedMessages.slice(0, queueAllowance);
      }
      this.runtimeGuidanceFallbackQueue = mergedGuidance;
    }
    jsonDebug('handleTaskComplete:before', {
      data,
      taskInProgress: this.taskInProgress,
      streamingMessage: this.streamingMessage,
      stopRequested: this.stopRequested,
      pendingToolsBefore,
      preparingToolsSize: this.preparingTools?.size ?? null,
      activeToolsSize: this.activeTools?.size ?? null,
      waitingForSubAgent: this.waitingForSubAgent,
      waitingForBackgroundCommand: this.waitingForBackgroundCommand
    });
    const hasRunningSubAgents = !!data?.has_running_sub_agents;
    const hasRunningBackgroundCommands = !!data?.has_running_background_commands;
    if (hasRunningSubAgents) {
      debugLog('[TaskPolling] 任务完成，但仍有后台子智能体运行');
    } else {
      debugLog('[TaskPolling] 任务完成');
    }

    // 同步处理状态更新
    this.streamingMessage = false;
    this.stopRequested = false;
    if (!hasRunningSubAgents) {
      this.markLatestUserWorkCompleted();
    }

    if (hasRunningSubAgents) {
      this.taskInProgress = true;
      this.waitingForSubAgent = true;
      this.waitingForBackgroundCommand = hasRunningBackgroundCommands;
      // 关键修复：主任务结束后将切到新的通知任务，先清空旧任务事件索引去重表。
      this.clearProcessedEvents();
      this.startWaitingTaskProbe();
    } else {
      this.cleanupTrailingEmptyAssistantPlaceholder('task_complete');
      // 主任务已结束：若有遗留工具块处于 running/preparing，会导致发送按钮继续显示“停止”。
      // 这里统一清理遗留中的工具状态，避免前端忙碌态卡死。
      if (typeof this.clearPendingTools === 'function') {
        this.clearPendingTools('task_complete');
      }
      this.taskInProgress = false;
      this.waitingForSubAgent = false;
      this.waitingForBackgroundCommand = false;
      this.stopWaitingTaskProbe();
      this.clearTaskState(); // 清理任务状态
      this.$nextTick(() => {
        if (typeof this.tryAutoSendRuntimeQueuedMessages === 'function') {
          this.tryAutoSendRuntimeQueuedMessages('task_complete');
        }
      });
    }

    this.$forceUpdate();

    // 只更新统计，不重新加载历史
    if (this.currentConversationId) {
      setTimeout(() => {
        this.fetchConversationTokenStatistics();
        this.updateCurrentContextTokens();
      }, 500);
    }
    this.scheduleTodoListRefresh(100);
    const pendingToolsAfter =
      typeof this.hasPendingToolActions === 'function' ? this.hasPendingToolActions() : null;
    jsonDebug('handleTaskComplete:after', {
      taskInProgress: this.taskInProgress,
      streamingMessage: this.streamingMessage,
      stopRequested: this.stopRequested,
      pendingToolsAfter,
      preparingToolsSize: this.preparingTools?.size ?? null,
      activeToolsSize: this.activeTools?.size ?? null,
      waitingForSubAgent: this.waitingForSubAgent,
      waitingForBackgroundCommand: this.waitingForBackgroundCommand
    });
  },

  handleTaskStopped(data: any, eventIdx: number) {
    jsonDebug('handleTaskStopped:before', {
      eventIdx,
      data,
      taskInProgress: this.taskInProgress,
      streamingMessage: this.streamingMessage,
      stopRequested: this.stopRequested
    });
    debugLog('[TaskPolling] 任务已停止, idx:', eventIdx, data);

    this.markLatestUserWorkCompleted();
    this.cleanupTrailingEmptyAssistantPlaceholder('task_stopped');
    this.streamingMessage = false;
    this.taskInProgress = false;
    this.stopRequested = false;
    this.waitingForSubAgent = false;
    this.waitingForBackgroundCommand = false;
    this.stopWaitingTaskProbe();

    if (typeof this.clearPendingTools === 'function') {
      this.clearPendingTools('task_stopped');
    }
    this.scheduleTodoListRefresh(100);
    this.$forceUpdate();

    this.clearTaskState();
    this.$nextTick(() => {
      if (typeof this.tryAutoSendRuntimeQueuedMessages === 'function') {
        this.tryAutoSendRuntimeQueuedMessages('task_stopped');
      }
    });
    jsonDebug('handleTaskStopped:after', {
      taskInProgress: this.taskInProgress,
      streamingMessage: this.streamingMessage,
      stopRequested: this.stopRequested
    });
  },

  handleRuntimeQueueSync(data: any) {
    const messages = Array.isArray(data?.messages) ? data.messages : [];
    const buildSnapshotKey =
      typeof this.buildRuntimeQueueSnapshotKey === 'function'
        ? this.buildRuntimeQueueSnapshotKey
        : (list: any[]) =>
            JSON.stringify(
              (Array.isArray(list) ? list : []).map((item: any) => [
                String(item?.id || ''),
                String(item?.text || ''),
                Number(item?.createdAt ?? item?.created_at ?? 0)
              ])
            );
    const incomingPreview = (Array.isArray(messages) ? messages : []).map((item: any) => ({
      id: String(item?.id || '').trim(),
      text: String(item?.text || '').trim(),
      createdAt: Number(item?.created_at ?? item?.createdAt ?? 0)
    }));
    const incomingKey = buildSnapshotKey(incomingPreview);
    const now = Date.now();
    const lockKey = String(this.runtimeQueueSyncLockKey || '');
    const lockUntil = Number(this.runtimeQueueSyncLockUntil || 0);
    if (lockKey && now < lockUntil && incomingKey !== lockKey) {
      debugLog('[RuntimeQueue] 忽略可能过期的轮询同步', {
        now,
        lockUntil,
        incomingSize: incomingPreview.length
      });
      return;
    }
    if (lockKey && incomingKey === lockKey) {
      this.runtimeQueueSyncLockKey = '';
      this.runtimeQueueSyncLockUntil = 0;
    }
    if (typeof this.applyRuntimeQueuedMessages === 'function') {
      this.applyRuntimeQueuedMessages(messages);
      return;
    }
    const limit = Math.max(1, Number(this.runtimeQueueLimit || 5));
    this.runtimeQueuedMessages = messages
      .map((item: any) => ({
        id: String(item?.id || '').trim(),
        text: String(item?.text || '').trim(),
        createdAt: Number(item?.created_at ?? item?.createdAt ?? Date.now())
      }))
      .filter((item: any) => item.id && item.text)
      .slice(0, limit);
  },

  // 新增统一清理方法
  clearTaskState() {
    this.stopWaitingTaskProbe();
    (async () => {
      const { useTaskStore } = await import('../../stores/task');
      const taskStore = useTaskStore();
      taskStore.clearTask(); // 使用 clearTask 而不是 stopPolling
    })();

    if (typeof this.clearProcessedEvents === 'function') {
      this.clearProcessedEvents();
    }
  },

  handleUserMessage(data: any) {
    const message = (data?.message || data?.content || '').trim();
    if (!message) {
      debugNotifyLog('[DEBUG_NOTIFY][ui] handleUserMessage:empty', { data });
      return;
    }
    debugLog('[TaskPolling] 收到用户消息事件');
    debugNotifyLog('[DEBUG_NOTIFY][ui] handleUserMessage', {
      messagePreview: message.slice(0, 120),
      sub_agent_notice: !!data?.sub_agent_notice,
      background_command_notice: !!data?.background_command_notice,
      task_id: data?.task_id,
      has_running_sub_agents: data?.has_running_sub_agents,
      has_running_background_commands: data?.has_running_background_commands
    });
    keyNotifyLog('[DEBUG_NOTIFY_KEY][ui] handleUserMessage', {
      messagePreview: message.slice(0, 80),
      task_id: data?.task_id,
      sub_agent_notice: !!data?.sub_agent_notice,
      background_command_notice: !!data?.background_command_notice
    });
    const isAutoUserMessage = isSystemAutoUserMessagePayload(data);
    const isRuntimeModeNotice = isRuntimeModeNoticePayload(data);
    if (!isAutoUserMessage) {
      const incomingImages = Array.isArray(data?.images) ? data.images : [];
      const incomingVideos = Array.isArray(data?.videos) ? data.videos : [];
      const incomingMediaRefs = Array.isArray(data?.media_refs)
        ? data.media_refs
        : Array.isArray(data?.mediaRefs)
          ? data.mediaRefs
          : [];
      const last = getOptimisticUserEchoTarget(this.messages || []);
      const isLikelyOptimisticEcho = !!(
        last &&
        last.role === 'user' &&
        String(last.content || '').trim() === message &&
        JSON.stringify(last.images || []) === JSON.stringify(incomingImages || []) &&
        JSON.stringify(last.videos || []) === JSON.stringify(incomingVideos || [])
      );
      if (isLikelyOptimisticEcho) {
        last.media_refs = incomingMediaRefs;
        last.metadata = {
          ...(last.metadata || {}),
          media_refs: incomingMediaRefs
        };
      } else {
        this.chatAddUserMessage(
          message,
          incomingImages,
          incomingVideos,
          incomingMediaRefs,
          resolveUserMessageSource(data)
        );
      }
      this.taskInProgress = true;
      this.streamingMessage = false;
      this.stopRequested = false;
    } else if (isRuntimeModeNotice) {
      this.chatAddUserMessage(message, [], [], [], 'notify');
    } else {
      debugLog('[TaskPolling] 跳过自动代发 user_message 渲染', {
        messagePreview: message.slice(0, 80),
        data
      });
    }
    if (data?.sub_agent_notice) {
      if (typeof data?.has_running_sub_agents === 'boolean') {
        this.waitingForSubAgent = data.has_running_sub_agents;
      } else if (typeof data?.remaining_count === 'number') {
        this.waitingForSubAgent = data.remaining_count > 0;
      }
      if (typeof data?.has_running_background_commands === 'boolean') {
        this.waitingForBackgroundCommand = data.has_running_background_commands;
      } else if (data?.background_command_notice) {
        this.waitingForBackgroundCommand = this.waitingForSubAgent;
      }
      if (this.waitingForSubAgent) {
        this.startWaitingTaskProbe();
      } else {
        this.stopWaitingTaskProbe();
      }
    }
    this.$forceUpdate();
    this.conditionalScrollToBottom();
  },

  handleSystemMessage(data: any) {
    const content = (data?.content || data?.message || '').trim();
    userMDebug('taskPolling.handleSystemMessage:incoming', {
      raw: data,
      normalizedContent: content,
      currentConversationId: this.currentConversationId,
      currentMessagesLength: Array.isArray(this.messages) ? this.messages.length : -1
    });
    if (!content) {
      userMDebug('taskPolling.handleSystemMessage:empty-skip');
      return;
    }
    this.cleanupTrailingEmptyAssistantPlaceholder('before_system_message_append');
    this.appendSystemAction(content);
    userMDebug('taskPolling.handleSystemMessage:after-append', {
      currentMessagesLength: Array.isArray(this.messages) ? this.messages.length : -1,
      lastRole: this.messages?.[this.messages.length - 1]?.role || null,
      lastActions:
        this.messages?.[this.messages.length - 1]?.actions?.map((a: any) => a?.type) || []
    });
  },

  handleTaskError(data: any) {
    jsonDebug('handleTaskError:incoming', {
      data,
      taskInProgress: this.taskInProgress,
      streamingMessage: this.streamingMessage,
      stopRequested: this.stopRequested
    });
    const shouldRetry = Boolean(data?.retry);
    if (shouldRetry) {
      const retryIn = Number(data?.retry_in) || 5;
      const attempt = Number(data?.attempt) || 1;
      const maxAttempts = Number(data?.max_attempts) || attempt;

      debugLog('[TaskPolling] API错误，等待自动重试', {
        retryIn,
        attempt,
        maxAttempts,
        message: data?.message
      });

      this.stopRequested = false;
      this.taskInProgress = true;
      this.streamingMessage = true;
      this.$forceUpdate();

      this.uiPushToast({
        title: '即将重试',
        message: `将在 ${retryIn} 秒后重试（第 ${attempt}/${maxAttempts} 次）`,
        type: 'info',
        duration: Math.max(retryIn, 1) * 1000
      });
      return;
    }

    const errorMessage = data.message || '未知错误';
    const errorType = data.error_type || 'unknown';
    const isToolArgumentParseError =
      errorType === 'parameter_format_error' || /工具参数解析失败/.test(String(errorMessage || ''));

    // 工具参数解析失败属于“单个工具调用失败”，后端会继续执行主任务。
    // 这里不能停止轮询，否则会出现“后端继续跑、前端不再更新”的假死状态。
    if (isToolArgumentParseError) {
      console.warn('[TaskPolling] 工具参数解析失败（非致命），继续轮询任务:', data);
      jsonDebug('handleTaskError:tool-args-parse-error-ignored', {
        errorType,
        errorMessage,
        taskInProgress: this.taskInProgress,
        streamingMessage: this.streamingMessage,
        stopRequested: this.stopRequested
      });
      this.uiPushToast({
        title: '工具调用失败',
        message: errorMessage,
        type: 'warning',
        duration: 6000
      });
      // 保持当前运行态，不在这里强制置为“工作中”，避免后续任务结束时状态粘住
      this.stopRequested = false;
      this.$forceUpdate();
      return;
    }

    let title = '任务执行失败';
    let message = errorMessage;

    // 根据错误类型提供友好提示
    if (errorType === 'api_error') {
      title = 'API 调用失败';
      message = `模型服务异常：${errorMessage}`;
    } else if (errorType === 'timeout') {
      title = '任务超时';
      message = '任务执行时间过长，已自动停止';
    } else if (errorType === 'quota_exceeded') {
      title = '配额不足';
      message = '您的使用配额已用尽';
    }

    console.error('[TaskPolling] 任务错误:', data.message);
    this.uiPushToast({
      title,
      message,
      type: 'error',
      duration: 8000
    });

    // 清理状态
    this.markLatestUserWorkCompleted();
    this.streamingMessage = false;
    this.taskInProgress = false;
    this.stopRequested = false;
    this.$forceUpdate();
    jsonDebug('handleTaskError:fatal-after-state-update', {
      errorType,
      errorMessage,
      taskInProgress: this.taskInProgress,
      streamingMessage: this.streamingMessage,
      stopRequested: this.stopRequested
    });

    // 停止轮询
    (async () => {
      const { useTaskStore } = await import('../../stores/task');
      const taskStore = useTaskStore();
      taskStore.stopPolling();
    })();
    this.$nextTick(() => {
      if (typeof this.tryAutoSendRuntimeQueuedMessages === 'function') {
        this.tryAutoSendRuntimeQueuedMessages('task_error');
      }
    });
  },

  handleTokenUpdate(data: any) {
    if (data.conversation_id === this.currentConversationId) {
      this.currentConversationTokens.cumulative_input_tokens = data.cumulative_input_tokens || 0;
      this.currentConversationTokens.cumulative_output_tokens = data.cumulative_output_tokens || 0;
      this.currentConversationTokens.cumulative_total_tokens = data.cumulative_total_tokens || 0;

      if (typeof data.current_context_tokens === 'number') {
        this.resourceSetCurrentContextTokens(data.current_context_tokens);
      } else {
        this.updateCurrentContextTokens();
      }

      this.$forceUpdate();
    }
  },

  handleConversationChanged(data: any, eventIdx: number) {
    debugLog('[TaskPolling] 对话标题已更新, idx:', eventIdx, data);

    if (data && data.conversation_id === this.currentConversationId) {
      // 更新当前对话标题
      if (data.title) {
        this.currentConversationTitle = data.title;
        debugLog('[TaskPolling] 更新当前对话标题:', data.title);
      }

      // 更新对话列表中的标题
      if (data.title && Array.isArray(this.conversations)) {
        const conv = this.conversations.find((c) => c && c.id === data.conversation_id);
        if (conv) {
          conv.title = data.title;
          debugLog('[TaskPolling] 更新对话列表中的标题:', data.title);
        }
      }

      this.$forceUpdate();
    }
  },

  handleConversationResolved(data: any) {
    if (data && data.conversation_id) {
      this.currentConversationId = data.conversation_id;
      if (data.title) {
        this.currentConversationTitle = data.title;
      }
      this.promoteConversationToTop(data.conversation_id);

      const pathFragment = this.stripConversationPrefix(data.conversation_id);
      const currentPath = window.location.pathname.replace(/^\/+/, '');
      if (data.created) {
        history.pushState({ conversationId: data.conversation_id }, '', `/${pathFragment}`);
      } else if (currentPath !== pathFragment) {
        history.replaceState({ conversationId: data.conversation_id }, '', `/${pathFragment}`);
      }
    }
  },

  handleCompressionState(data: any) {
    if (!data || typeof data !== 'object') {
      return;
    }
    const wasInProgress = !!this.compressionInProgress;
    this.compressionInProgress = !!data.in_progress;
    this.compressionMode = data.mode || '';
    this.compressionStage = data.stage || '';
    if (this.compressionInProgress && !wasInProgress) {
      const modeLabel = this.compressionMode === 'manual' ? '手动' : '自动';
      if (this.compressionToastId) {
        this.uiDismissToast(this.compressionToastId);
        this.compressionToastId = null;
      }
      this.compressionToastId = this.uiPushToast({
        title: '压缩中',
        message: `对话正在${modeLabel}压缩，请稍候…`,
        type: 'info',
        duration: null,
        closable: false
      });
    }
    if (!this.compressionInProgress) {
      this.compressionError = data.error || '';
      if (this.compressionToastId) {
        this.uiDismissToast(this.compressionToastId);
        this.compressionToastId = null;
      }
    }
  },

  async handleCompressionFinished(data: any) {
    if (this.compressionToastId) {
      this.uiDismissToast(this.compressionToastId);
      this.compressionToastId = null;
    }
    this.compressionInProgress = false;
    this.compressionMode = '';
    this.compressionStage = '';
    this.compressionError = '';
    const newId = data?.conversation_id;
    if (newId && newId !== this.currentConversationId) {
      await this.loadConversation(newId, { force: true });
    }
    this.conversationsOffset = 0;
    if (typeof this.loadConversationsList === 'function') {
      await this.loadConversationsList();
    }
    this.uiPushToast({
      title: '压缩完成',
      message: '已自动切换到压缩后的新对话',
      type: 'success',
      duration: 2400
    });
  },

  handleShallowCompression(data: any, eventIdx?: number) {
    const count = Number(data?.compressed_count || 0);
    if (count <= 0) {
      return;
    }
    debugLog('[TaskPolling] 自动浅层压缩触发, idx:', eventIdx, data);
    this.uiPushToast({
      title: '自动浅层压缩',
      message: `已自动压缩 ${count} 条较早工具结果`,
      type: 'info',
      duration: 2500
    });
  },

  /**
   * 清理已处理的事件索引
   */
  clearProcessedEvents() {
    if (this._processedEventIndices) {
      this._processedEventIndices.clear();
    }
  },

  /**
   * 恢复任务状态（页面刷新后调用）
   */
  async restoreTaskState() {
    // 清理已处理的事件索引
    this.clearProcessedEvents();
    restoreDebugLog('restore:start', {
      currentConversationId: this.currentConversationId,
      streamingMessage: this.streamingMessage,
      taskInProgress: this.taskInProgress,
      historyLoading: this.historyLoading,
      historyLoadingFor: this.historyLoadingFor,
      messagesLen: Array.isArray(this.messages) ? this.messages.length : -1
    });

    try {
      const { useTaskStore } = await import('../../stores/task');
      const taskStore = useTaskStore();

      // 如果已经在流式输出中，不重复恢复
      if (this.streamingMessage || this.taskInProgress) {
        restoreDebugLog('restore:skip-already-running', {
          streamingMessage: this.streamingMessage,
          taskInProgress: this.taskInProgress,
          currentConversationId: this.currentConversationId
        });
        debugLog('[TaskPolling] 任务已在进行中，跳过恢复', {
          streamingMessage: this.streamingMessage,
          taskInProgress: this.taskInProgress,
          currentConversationId: this.currentConversationId
        });
        return;
      }

      // 查找运行中的任务
      const runningTask = await taskStore.loadRunningTask(this.currentConversationId);

      if (!runningTask) {
        restoreDebugLog('restore:no-running-task', {
          currentConversationId: this.currentConversationId
        });
        debugLog('[TaskPolling] 没有运行中的任务', {
          currentConversationId: this.currentConversationId
        });
        this._restoreTaskStateWaitCount = 0;
        await this.restoreSubAgentWaitingState();
        return;
      }

      debugLog('[TaskPolling] 发现运行中的任务，开始恢复状态', {
        taskId: runningTask?.task_id,
        status: runningTask?.status,
        conversationId: runningTask?.conversation_id
      });
      restoreDebugLog('restore:running-task-found', {
        taskId: runningTask?.task_id,
        status: runningTask?.status,
        taskConversationId: runningTask?.conversation_id,
        currentConversationId: this.currentConversationId
      });

      // 检查历史是否已加载
      const hasMessages = Array.isArray(this.messages) && this.messages.length > 0;
      const historyLoadingSameConversation =
        !!this.historyLoading && this.historyLoadingFor === this.currentConversationId;

      if (!hasMessages) {
        this._restoreTaskStateWaitCount = (this._restoreTaskStateWaitCount || 0) + 1;
        const waitedTooLong = this._restoreTaskStateWaitCount >= 8; // ~4s
        restoreDebugLog('restore:history-empty', {
          waitCount: this._restoreTaskStateWaitCount,
          waitedTooLong,
          historyLoading: this.historyLoading,
          historyLoadingFor: this.historyLoadingFor,
          currentConversationId: this.currentConversationId
        });
        if (historyLoadingSameConversation && !waitedTooLong) {
          debugLog('[TaskPolling] 历史未加载，等待历史加载完成', {
            waitCount: this._restoreTaskStateWaitCount,
            historyLoading: this.historyLoading,
            historyLoadingFor: this.historyLoadingFor
          });
          setTimeout(() => {
            this.restoreTaskState();
          }, 500);
          return;
        }
        // 兜底：即使历史未成功拉取，也允许直接通过任务事件重放恢复界面，
        // 避免 show_html 流式阶段刷新后“本次请求内容完全消失”。
        debugLog('[TaskPolling] 历史为空，启用事件重放兜底恢复', {
          waitCount: this._restoreTaskStateWaitCount,
          historyLoading: this.historyLoading,
          historyLoadingFor: this.historyLoadingFor
        });
      } else {
        this._restoreTaskStateWaitCount = 0;
      }

      debugLog('[TaskPolling] 开始精细恢复', {
        hasMessages,
        historyLoading: this.historyLoading,
        historyLoadingFor: this.historyLoadingFor
      });

      // 获取任务的所有事件
      const detailResponse = await fetch(`/api/tasks/${taskStore.currentTaskId}`);
      if (!detailResponse.ok) {
        debugLog('[TaskPolling] 获取任务详情失败');
        return;
      }

      const detailResult = await detailResponse.json();
      if (!detailResult.success || !detailResult.data.events) {
        restoreDebugLog('restore:task-detail-invalid', {
          ok: !!detailResult?.success,
          hasData: !!detailResult?.data,
          hasEvents: !!detailResult?.data?.events
        });
        debugLog('[TaskPolling] 任务详情无效');
        return;
      }

      const allEvents = detailResult.data.events;
      debugLog(`[TaskPolling] 获取到 ${allEvents.length} 个事件`);
      restoreDebugLog('restore:task-detail-events', {
        total: allEvents.length,
        firstIdx: allEvents[0]?.idx,
        firstType: allEvents[0]?.type,
        lastIdx: allEvents[allEvents.length - 1]?.idx,
        lastType: allEvents[allEvents.length - 1]?.type
      });

      // 找到最后一条消息
      const lastMessage = this.messages[this.messages.length - 1];
      const isAssistantMessage = lastMessage && lastMessage.role === 'assistant';

      // console.log('[TaskPolling] 最后一条消息:', {
      //     exists: !!lastMessage,
      //     role: lastMessage?.role,
      //     actionsCount: lastMessage?.actions?.length || 0,
      //     isAssistant: isAssistantMessage
      // });

      // 先分析事件状态（用于判定是否强制重建）
      let inThinking = false;
      let inText = false;
      let hasTextChunkEvent = false;

      for (let i = 0; i < allEvents.length; i++) {
        const event = allEvents[i];
        if (event.type === 'thinking_start') {
          inThinking = true;
        } else if (event.type === 'thinking_end') {
          inThinking = false;
        }
        if (event.type === 'text_start') {
          inText = true;
        } else if (event.type === 'text_end') {
          inText = false;
        }
        if (event.type === 'text_chunk') {
          hasTextChunkEvent = true;
        }
      }

      // 检查是否需要从头重建
      // 1. 最后一条不是 assistant 消息
      // 2. 最后一条是空的 assistant 消息
      // 3. 事件数量远大于历史中的 actions 数量（说明历史不完整）
      // 4. 任务正处于文本流式阶段（刷新时易丢分段内容，强制重放全部事件）
      const historyActionsCount = lastMessage?.actions?.length || 0;
      const eventCount = allEvents.length;
      const historyIncomplete = eventCount > historyActionsCount + 5; // 允许5个事件的误差
      const forceRebuildForStreamingText = inText || hasTextChunkEvent;

      // 刷新恢复场景下，优先强制从头重放当前任务事件，避免“有运行中任务但界面无输出”
      const forceRebuildOnRefresh = true;

      const needsRebuild =
        forceRebuildOnRefresh ||
        !isAssistantMessage ||
        (isAssistantMessage && (!lastMessage.actions || lastMessage.actions.length === 0)) ||
        historyIncomplete ||
        forceRebuildForStreamingText;
      restoreDebugLog('restore:rebuild-decision', {
        needsRebuild,
        forceRebuildOnRefresh,
        isAssistantMessage,
        historyActionsCount,
        eventCount,
        historyIncomplete,
        inText,
        hasTextChunkEvent,
        forceRebuildForStreamingText
      });

      if (needsRebuild) {
        // if (historyIncomplete) {
        //     console.log('[TaskPolling] 历史不完整，从头重建:', {
        //         historyActionsCount,
        //         eventCount,
        //         diff: eventCount - historyActionsCount
        //     });
        // }
        debugLog('[TaskPolling] 需要从头重建 assistant 响应');

        // 清空所有消息，准备从头重建
        // 保留用户消息，只删除最后的 assistant 消息
        if (isAssistantMessage) {
          debugLog('[TaskPolling] 删除不完整的 assistant 消息');
          this.messages.pop();
        }

        this.streamingMessage = true;
        this.taskInProgress = true;
        this.$forceUpdate();

        // 重置偏移量为 0，从头获取所有事件来重建 assistant 消息
        taskStore.lastEventIndex = 0;
        debugLog('[TaskPolling] 重置偏移量为 0，从头开始轮询');

        // 标记正在从头重建，用于后续处理
        this._rebuildingFromScratch = true;
        this._rebuildingEventCount = allEvents.length; // 记录当前事件总数

        (window as any).__taskEventHandler = (event: any) => {
          this.handleTaskEvent(event);
        };

        taskStore.startPolling((event: any) => {
          this.handleTaskEvent(event);
        });
        restoreDebugLog('restore:rebuild-polling-started', {
          lastEventIndex: taskStore.lastEventIndex,
          currentConversationId: this.currentConversationId
        });

        // 延迟清除重建标记，确保所有历史事件都处理完毕
        setTimeout(() => {
          debugLog('[TaskPolling] 历史事件处理完毕，清除重建标记');
          this._rebuildingFromScratch = false;
          this._rebuildingEventCount = 0;
        }, 2000);

        return;
      }

      // console.log('[TaskPolling] 分析结果:', {
      //     inThinking,
      //     inText,
      //     totalEvents: allEvents.length,
      //     lastEventType: allEvents[allEvents.length - 1]?.type,
      //     lastEventIdx: allEvents[allEvents.length - 1]?.idx
      // });

      // 恢复思考块状态
      if (lastMessage.actions) {
        // console.log('[TaskPolling] 历史中的 actions 详情:', lastMessage.actions.map((a, idx) => ({
        //     index: idx,
        //     type: a.type,
        //     id: a.id,
        //     hasContent: !!a.content,
        //     contentLength: a.content?.length || 0,
        //     toolName: a.tool?.name,
        //     hasBlockId: !!a.blockId,
        //     blockId: a.blockId,
        //     collapsed: a.collapsed,
        //     streaming: a.streaming
        // })));

        const thinkingActions = lastMessage.actions.filter((a) => a.type === 'thinking');
        // console.log('[TaskPolling] 思考块数量:', thinkingActions.length);

        if (inThinking && thinkingActions.length > 0) {
          // 正在思考中，检查最后一个思考块是否正在流式输出
          const lastThinking = thinkingActions[thinkingActions.length - 1];

          // 只有当思考块正在流式输出时才设置锁定状态（但不展开）
          if (lastThinking.streaming && lastThinking.blockId) {
            // console.log('[TaskPolling] 找到正在流式输出的思考块，设置锁定状态:', lastThinking.blockId);
            this.$nextTick(() => {
              this.chatSetThinkingLock(lastThinking.blockId, true);
            });
          }
        }

        // 确保所有思考块都是折叠状态
        for (const thinking of thinkingActions) {
          if (thinking.blockId) {
            thinking.collapsed = true;
          }
        }

        // 检查思考块状态（在设置之后）（已禁用）
        // thinkingActions.forEach((thinking, idx) => {
        //     console.log(`[TaskPolling] 思考块 ${idx} (设置后):`, {
        //         hasBlockId: !!thinking.blockId,
        //         blockId: thinking.blockId,
        //         collapsed: thinking.collapsed,
        //         contentLength: thinking.content?.length || 0
        //     });
        // });

        // 恢复文本块状态
        const textActions = lastMessage.actions.filter((a) => a.type === 'text');
        // console.log('[TaskPolling] 文本块数量:', textActions.length);

        if (inText && textActions.length > 0) {
          const lastText = textActions[textActions.length - 1];
          // console.log('[TaskPolling] 标记文本块为流式状态');
          lastText.streaming = true;
        }

        // 注册历史中的工具块到 toolActionIndex
        // 这样后续的 update_action 事件可以找到对应的块进行状态更新
        const toolActions = lastMessage.actions.filter((a) => a.type === 'tool');
        // console.log('[TaskPolling] 工具块数量:', toolActions.length);

        for (const toolAction of toolActions) {
          if (toolAction.tool && toolAction.tool.id) {
            // console.log('[TaskPolling] 注册工具块:', {
            //     id: toolAction.tool.id,
            //     name: toolAction.tool.name,
            //     status: toolAction.tool.status
            // });
            // 注册到 toolActionIndex
            this.toolRegisterAction(toolAction, toolAction.tool.id);
            // 如果有 executionId，也注册
            if (toolAction.tool.executionId) {
              this.toolRegisterAction(toolAction, toolAction.tool.executionId);
            }
            // 追踪工具调用
            if (toolAction.tool.name) {
              this.toolTrackAction(toolAction.tool.name, toolAction);
            }
          }
        }
      }

      // 标记状态为进行中
      this.streamingMessage = true;
      this.taskInProgress = true;

      // 设置 currentMessageIndex 指向最后一条 assistant 消息
      // 这样后续添加的 action 会添加到正确的消息中
      const lastMessageIndex = this.messages.length - 1;
      if (lastMessage && lastMessage.role === 'assistant') {
        this.currentMessageIndex = lastMessageIndex;
        // console.log('[TaskPolling] 设置 currentMessageIndex 为:', lastMessageIndex);
      }

      // 强制更新界面
      this.$forceUpdate();

      // 滚动到底部
      this.$nextTick(() => {
        this.conditionalScrollToBottom();
      });

      // 注册事件处理器到全局
      (window as any).__taskEventHandler = (event: any) => {
        this.handleTaskEvent(event);
      };

      // 启动轮询（从当前偏移量开始，只处理新事件）
      debugLog('[TaskPolling] 启动轮询，起始偏移量:', taskStore.lastEventIndex);

      taskStore.startPolling((event: any) => {
        this.handleTaskEvent(event);
      });
      restoreDebugLog('restore:polling-started-follow', {
        lastEventIndex: taskStore.lastEventIndex,
        currentConversationId: this.currentConversationId
      });

      this.uiPushToast({
        title: '任务恢复',
        message: '检测到进行中的任务，已恢复连接',
        type: 'info',
        duration: 3000
      });
    } catch (error) {
      restoreDebugLog('restore:error', {
        message: error?.message || String(error)
      });
      console.error('[TaskPolling] 恢复任务状态失败:', error);
    }
  },

  /**
   * 恢复子智能体等待状态（页面刷新后调用）
   */
  async restoreSubAgentWaitingState(retry = 0) {
    try {
      if (!this.currentConversationId) {
        if (retry < 5) {
          setTimeout(() => {
            this.restoreSubAgentWaitingState(retry + 1);
          }, 300);
        }
        return;
      }

      const response = await fetch('/api/sub_agents');
      if (!response.ok) {
        debugLog('[TaskPolling] 获取子智能体状态失败');
        return;
      }
      const result = await response.json();
      if (!result.success) {
        debugLog('[TaskPolling] 子智能体状态响应无效');
        return;
      }

      const tasks = Array.isArray(result.data) ? result.data : [];
      debugLog('[TaskPolling] 子智能体状态响应', {
        total: tasks.length,
        currentConversationId: this.currentConversationId,
        tasks: tasks.map((task: any) => ({
          task_id: task?.task_id,
          status: task?.status,
          run_in_background: task?.run_in_background,
          notice_pending: task?.notice_pending,
          conversation_id: task?.conversation_id
        }))
      });
      const terminalStatuses = new Set(['completed', 'failed', 'timeout', 'terminated']);
      const relevant = tasks.filter((task: any) => {
        if (task && task.conversation_id && task.conversation_id !== this.currentConversationId) {
          return false;
        }
        return true;
      });

      const running = relevant.filter(
        (task: any) => task?.run_in_background && !terminalStatuses.has(task?.status)
      );
      const pendingNotice = relevant.filter((task: any) => task?.notice_pending);
      let backgroundPending = false;
      try {
        const bgResp = await fetch('/api/background_commands?limit=200');
        if (bgResp.ok) {
          const bgResult = await bgResp.json().catch(() => ({}));
          const bgCommands = Array.isArray(bgResult?.data) ? bgResult.data : [];
          backgroundPending = bgCommands.some((command: any) => {
            if (!command) return false;
            const status = String(command?.status || '').toLowerCase();
            return !terminalStatuses.has(status) || !!command?.notice_pending;
          });
        }
      } catch (bgErr) {
        console.warn('[TaskPolling] 获取后台指令状态失败:', bgErr);
      }

      if (running.length || pendingNotice.length || backgroundPending) {
        debugLog('[TaskPolling] 恢复子智能体等待状态', {
          running: running.length,
          pendingNotice: pendingNotice.length,
          backgroundPending,
          runningTasks: running.map((task: any) => ({
            task_id: task?.task_id,
            status: task?.status
          })),
          pendingTasks: pendingNotice.map((task: any) => ({
            task_id: task?.task_id,
            status: task?.status
          }))
        });
        this.waitingForSubAgent = true;
        this.waitingForBackgroundCommand = backgroundPending;
        this.taskInProgress = true;
        this.streamingMessage = false;
        this.stopRequested = false;
        this.startWaitingTaskProbe();
        this.$forceUpdate();
      } else {
        this.waitingForSubAgent = false;
        this.waitingForBackgroundCommand = false;
        this.stopWaitingTaskProbe();
        if (!this.streamingMessage) {
          this.taskInProgress = false;
        }
        this.$forceUpdate();
      }
    } catch (error) {
      console.error('[TaskPolling] 恢复子智能体等待状态失败:', error);
    }
  }
};
