import type {
  ApprovalRequest,
  Message,
  ToolCall,
  ToolPermission,
  ToolResult,
} from "#cli/core/model";
import type {
  AgentContent,
  AgentContentPart,
  AgentEvent,
  AskUserQuestion,
  ResumeInput,
  RuntimeConfig,
  ToolApprovalMode,
} from "#cli/compat/runtime";
import type { McpServerConfig } from "#cli/compat/mcp";
import { readFile, stat } from "node:fs/promises";
import path from "node:path";
import type { CliAgentBridge } from "../../agent-bridge";
import { debugLog } from "#cli/core/debug-log";
import { renderFocusFilesMarkdownLinks } from "#cli/core/focus-files";
import { createLocalThinkingPartId } from "#cli/core/transcript-part-id";
import {
  canonicalToolName,
  isEditLikeToolName,
  isExecLikeToolName,
  isReadLikeToolName,
  isSearchLikeToolName,
  isWriteLikeToolName,
} from "#cli/core/tool-metadata";
import { formatAgentErrorForUi } from "#cli/core/store/errors";
import { isDelegationRecordedFinalMessage } from "#cli/compat/runtime-host";
import {
  getBuiltinProvider,
  isBuiltinProviderBaseUrlEditable,
  isLegacyCustomProviderId,
  resolveBuiltinProviderBaseUrl,
  resolveProviderSelectionContextWindow,
  shouldIgnoreLegacyStoredContextWindow,
} from "#cli/compat/providers";
import { t } from "#cli/i18n";
import { toMcpServerConfigs } from "#cli/commands/server-helpers";
import { normalizeAskUserQuestions as normalizeDimSdkAskUserQuestions } from "../../ask-user";
import { readCliRuntimeConfig } from "../../cli/runtime-host";

type ToolApprovalResult = Readonly<{ approved: boolean; reason?: string }>;
type CompressionEventLike = Extract<AgentEvent, { type: "context.compression" }>;
type CompressionEventDiagnosticsLike = NonNullable<CompressionEventLike["diagnostics"]>;
type CompressionAutoCompactAttemptLike = NonNullable<
  CompressionEventDiagnosticsLike["autoCompactAttempt"]
>;
type CompressionNotificationLike = NonNullable<CompressionEventDiagnosticsLike["notification"]>;
type NoticeTone = "success" | "warning" | "danger";

type PendingActionState = Readonly<{
  kind: "tool_approval" | "ask_user";
  actionId: string;
  toolCallId?: string;
  toolName?: string;
  questions?: readonly AskUserQuestion[];
  assistantId: string;
}>;

export type AgentRoundResult = Readonly<{
  assistantId: string;
  toolCalls: ToolCall[];
  success: boolean;
  error?: Error;
}>;

export type ToolExecutionContextInput = Readonly<{
  requiresAction?: Readonly<{
    actionId?: string;
    toolCallId?: string;
    kind?: "tool_approval" | "ask_user";
  }>;
  approval?: Readonly<{
    autoApprove?: boolean;
    alwaysAllowForConversation?: boolean;
    decisions?: Readonly<Record<string, ToolApprovalResult>>;
  }>;
  askUser?: Readonly<{
    answers: Readonly<Record<string, Readonly<Record<string, string | string[]>>>>;
    rejected?: Readonly<Record<string, string>>;
  }>;
}>;

type ResumeTarget = Readonly<{
  kind: "tool_approval" | "ask_user";
  actionId: string;
  toolCallId?: string;
}>;

type ActionRequiredEvent = Extract<AgentEvent, { type: "action.required" }>;
type ToolApprovalRequiredEvent = ActionRequiredEvent &
  Readonly<{
    kind: "tool_approval";
  }>;
type AskUserRequiredEvent = ActionRequiredEvent &
  Readonly<{
    kind: "ask_user";
  }>;

const maxInlinePlanMarkdownBytes = 256 * 1024;
const PROPOSED_PLAN_OPEN_TAG = "<proposed_plan>";
const PROPOSED_PLAN_CLOSE_TAG = "</proposed_plan>";

function isLlmDebugEnabled(): boolean {
  const raw = String(process.env.BEST_AGENT_LLM_DEBUG ?? "")
    .trim()
    .toLowerCase();
  return raw === "1" || raw === "true" || raw === "yes" || raw === "on";
}

function logLlmDebug(eventName: string, payload?: unknown): void {
  if (!isLlmDebugEnabled()) return;
  debugLog(eventName, payload);
  try {
    const timestamp = new Date().toISOString();
    const suffix = payload === undefined ? "" : ` ${JSON.stringify(payload)}`;
    console.warn(`[best-agent][llm][${timestamp}] ${eventName}${suffix}`);
  } catch {
    console.warn(`[best-agent][llm] ${eventName}`);
  }
}

function normalizeText(value: unknown): string {
  return String(value ?? "").trim();
}

function parsePositiveInt(value: unknown): number | undefined {
  const n = Number(value);
  if (!Number.isFinite(n) || n <= 0) return undefined;
  return Math.floor(n);
}

function normalizeAutoBudgetOutcome(
  value: unknown,
): "budget-unknown" | "compacted" | "failed-to-fit" | "not-needed" | undefined {
  return value === "budget-unknown" ||
    value === "compacted" ||
    value === "failed-to-fit" ||
    value === "not-needed"
    ? value
    : undefined;
}

function buildRequestBudgetSnapshotFromLegacyRunEvent(
  event: Record<string, unknown>,
): Record<string, unknown> {
  const inputBudgetTokens = parsePositiveInt(event.inputBudgetTokens ?? event.maxInputTokens);
  const maxInputTokens = parsePositiveInt(event.maxInputTokens) ?? inputBudgetTokens;
  const thresholdTokens = parsePositiveInt(event.thresholdTokens) ?? inputBudgetTokens;
  const explicitOutcome = normalizeAutoBudgetOutcome(event.autoBudgetOutcome);
  const autoBudgetOutcome =
    explicitOutcome ??
    (inputBudgetTokens == null && maxInputTokens == null && thresholdTokens == null
      ? "budget-unknown"
      : event.usedAutoCompaction === true
        ? "compacted"
        : "not-needed");

  return {
    runId: normalizeText(event.runId) || undefined,
    requestId: normalizeText(event.requestId) || undefined,
    autoBudgetOutcome,
    autoBudgetReasonCode: normalizeText(event.autoBudgetReasonCode) || undefined,
    budgetSource: normalizeText(event.budgetSource) || undefined,
    contextWindowTokens: parsePositiveInt(event.contextWindowTokens),
    estimatedInputTokens: event.estimatedInputTokens,
    inputBudgetTokens,
    maxOutputTokens: normalizeNonNegativeNumber(event.maxOutputTokens),
    protocolReserveTokens: normalizeNonNegativeNumber(event.protocolReserveTokens),
    reservedOutputTokens: normalizeNonNegativeNumber(event.reservedOutputTokens),
    thresholdTokens,
    maxInputTokens,
    triggerRatio: normalizeNonNegativeNumber(event.triggerRatio),
    usedAutoCompaction: event.usedAutoCompaction === true,
    updatedAt: normalizeText(event.updatedAt) || undefined,
    updatedAtMs: parsePositiveInt(event.updatedAtMs) ?? Date.now(),
  };
}

function summarizeSubagentActivity(text: unknown, max = 80): string {
  const normalized = String(text ?? "")
    .replace(/\r/g, "")
    .replace(/\s+/g, " ")
    .trim();
  if (!normalized) return "";
  if (normalized.length <= max) return normalized;
  if (max <= 1) return normalized.slice(0, max);
  return `${normalized.slice(0, max - 1).trimEnd()}…`;
}

function asRecord(value: unknown): Record<string, unknown> {
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
  return value as Record<string, unknown>;
}

function serializeUnknown(value: unknown): string {
  if (typeof value === "string") return value;
  try {
    return JSON.stringify(value, null, 2);
  } catch {
    return String(value);
  }
}

function extractTextParts(value: unknown): string[] {
  if (!Array.isArray(value)) return [];
  return value
    .map((part) => {
      const record = asRecord(part);
      return typeof record.text === "string" ? record.text : "";
    })
    .filter(Boolean);
}

function extractTextContent(content: AgentContent): string {
  if (typeof content === "string") return content;
  if (!Array.isArray(content)) return "";
  return extractTextParts(content).join("");
}

function hasThinkingBlockWithId(
  messages: readonly Message[],
  assistantId: string,
  partId: string,
): boolean {
  const normalizedPartId = String(partId ?? "").trim();
  if (!normalizedPartId) return false;
  const message = messages.find((entry) => entry?.id === assistantId);
  if (!message || message.role !== "assistant") return false;
  return message.parts.some(
    (part) => part.type === "thinking" && String(part.partId ?? "").trim() === normalizedPartId,
  );
}

function readThinkingBlockContent(
  messages: readonly Message[],
  assistantId: string,
  partId: string,
): string | undefined {
  const normalizedPartId = String(partId ?? "").trim();
  if (!normalizedPartId) return undefined;
  const message = messages.find((entry) => entry?.id === assistantId);
  if (!message || message.role !== "assistant") return undefined;
  const part = message.parts.find(
    (entry) => entry.type === "thinking" && String(entry.partId ?? "").trim() === normalizedPartId,
  );
  return part?.type === "thinking" ? String(part.content ?? "") : undefined;
}

const IMAGE_EXTS = new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp", ".ico", ".svg"]);
const EXT_MIME: Record<string, string> = {
  ".png": "image/png",
  ".jpg": "image/jpeg",
  ".jpeg": "image/jpeg",
  ".gif": "image/gif",
  ".webp": "image/webp",
  ".bmp": "image/bmp",
  ".ico": "image/x-icon",
  ".svg": "image/svg+xml",
};
const MAX_IMAGE_BYTES = 10 * 1024 * 1024;
const MD_IMAGE_LINK_RE = /\[([^\]]*)\]\(((?:\\\)|[^)])+)\)/g;

function hasVisionCapability(state: any): boolean {
  const config = state?.config;
  if (!config) return false;
  const caps = config.modelCapabilities ?? config.model_capabilities;
  if (caps && typeof caps === "object") return Boolean((caps as any).vision);
  return true;
}

async function resolveTextToContentParts(text: string): Promise<AgentContentPart[] | null> {
  const links: Array<{ label: string; target: string; start: number; end: number }> = [];
  MD_IMAGE_LINK_RE.lastIndex = 0;
  let m: RegExpExecArray | null = MD_IMAGE_LINK_RE.exec(text);
  while (m) {
    const target = m[2]!.replace(/\\\)/g, ")").trim();
    if (
      (target.startsWith("/") || /^[A-Z]:[\\/]/i.test(target)) &&
      IMAGE_EXTS.has(path.extname(target).toLowerCase())
    ) {
      links.push({ label: m[1]!, target, start: m.index, end: m.index + m[0].length });
    }
    m = MD_IMAGE_LINK_RE.exec(text);
  }
  if (links.length === 0) return null;

  const parts: AgentContentPart[] = [];
  let lastIdx = 0;
  for (const link of links) {
    const before = text.slice(lastIdx, link.start);
    if (before.trim()) parts.push({ type: "text", text: before });
    try {
      const st = await stat(link.target);
      if (st.isFile() && st.size > 0 && st.size <= MAX_IMAGE_BYTES) {
        const data = await readFile(link.target);
        const ext = path.extname(link.target).toLowerCase();
        parts.push({
          type: "file",
          data: new Uint8Array(data.buffer, data.byteOffset, data.byteLength),
          mediaType: EXT_MIME[ext] ?? "application/octet-stream",
        });
      } else {
        parts.push({ type: "text", text: text.slice(link.start, link.end) });
      }
    } catch {
      parts.push({ type: "text", text: text.slice(link.start, link.end) });
    }
    lastIdx = link.end;
  }
  const tail = text.slice(lastIdx);
  if (tail.trim()) parts.push({ type: "text", text: tail });
  return parts.length > 0 ? parts : null;
}

async function buildUserTurnContent(
  message: Extract<Message, { role: "user" }>,
  state: any,
): Promise<AgentContent> {
  const focusLinks = renderFocusFilesMarkdownLinks(message.focusFiles);
  const content = String(message.content ?? "");
  const fullText = focusLinks && content.trim() ? `${focusLinks}${content}` : focusLinks || content;

  if (hasVisionCapability(state)) {
    const parts = await resolveTextToContentParts(fullText);
    if (parts) return parts;
  }
  return fullText;
}

function normalizeNonNegativeNumber(value: unknown): number | undefined {
  const numeric = Number(value);
  if (!Number.isFinite(numeric) || numeric < 0) return undefined;
  return numeric;
}

function normalizeCompressionAttemptStatus(
  value: unknown,
): CompressionAutoCompactAttemptLike["status"] | null {
  return value === "planned" || value === "skipped" || value === "compacted" || value === "failed"
    ? value
    : null;
}

function normalizeCompressionAttemptTrigger(
  value: unknown,
): CompressionAutoCompactAttemptLike["trigger"] | null {
  return value === "manual" || value === "threshold" ? value : null;
}

function normalizeCompressionAttemptDiagnostics(
  value: unknown,
): CompressionAutoCompactAttemptLike | null {
  const record = asRecord(value);
  const trigger = normalizeCompressionAttemptTrigger(record.trigger);
  const status = normalizeCompressionAttemptStatus(record.status);
  const estimatedInputTokens = normalizeNonNegativeNumber(record.estimatedInputTokens) ?? null;
  const thresholdTokens = normalizeNonNegativeNumber(record.thresholdTokens) ?? null;
  const maxInputTokens = normalizeNonNegativeNumber(record.maxInputTokens) ?? null;
  const cursor = normalizeNonNegativeNumber(record.cursor) ?? null;
  const startedAt = normalizeNonNegativeNumber(record.startedAt) ?? null;
  const completedAt = normalizeNonNegativeNumber(record.completedAt) ?? null;
  const reasonCode = normalizeText(record.reasonCode) || null;
  const reasonMessage = normalizeText(record.reasonMessage) || null;
  const checkpointId = normalizeText(record.checkpointId) || null;
  const compactedMessageCount = normalizeNonNegativeNumber(record.compactedMessageCount) ?? null;
  const retainedMessageCount = normalizeNonNegativeNumber(record.retainedMessageCount) ?? null;
  const estimatedInputTokensAfter =
    normalizeNonNegativeNumber(record.estimatedInputTokensAfter) ?? null;
  const estimatedSavedTokens = normalizeNonNegativeNumber(record.estimatedSavedTokens) ?? null;

  if (!trigger || !status) {
    return null;
  }

  if (
    estimatedInputTokens == null &&
    thresholdTokens == null &&
    maxInputTokens == null &&
    cursor == null &&
    startedAt == null &&
    completedAt == null &&
    !reasonCode &&
    !reasonMessage &&
    !checkpointId &&
    compactedMessageCount == null &&
    retainedMessageCount == null &&
    estimatedInputTokensAfter == null &&
    estimatedSavedTokens == null
  ) {
    return null;
  }

  return {
    trigger,
    status,
    ...(estimatedInputTokens != null ? { estimatedInputTokens } : {}),
    ...(thresholdTokens != null ? { thresholdTokens } : {}),
    ...(maxInputTokens != null ? { maxInputTokens } : {}),
    ...(cursor != null ? { cursor } : {}),
    ...(startedAt != null ? { startedAt } : {}),
    ...(completedAt != null ? { completedAt } : {}),
    ...(reasonCode ? { reasonCode } : {}),
    ...(reasonMessage ? { reasonMessage } : {}),
    ...(checkpointId ? { checkpointId } : {}),
    ...(compactedMessageCount != null ? { compactedMessageCount } : {}),
    ...(retainedMessageCount != null ? { retainedMessageCount } : {}),
    ...(estimatedInputTokensAfter != null ? { estimatedInputTokensAfter } : {}),
    ...(estimatedSavedTokens != null ? { estimatedSavedTokens } : {}),
  };
}

function normalizeCompressionNotificationDiagnostics(
  value: unknown,
): CompressionNotificationLike | null {
  const record = asRecord(value);
  const requestId = normalizeText(record.requestId) || null;
  const pluginId = normalizeText(record.pluginId) || null;
  const checkpointId = normalizeText(record.checkpointId) || null;
  const reason = normalizeText(record.reason) || null;
  const cursor = normalizeNonNegativeNumber(record.cursor) ?? null;
  const estimatedInputTokensBefore =
    normalizeNonNegativeNumber(record.estimatedInputTokensBefore) ?? null;
  const estimatedInputTokensAfter =
    normalizeNonNegativeNumber(record.estimatedInputTokensAfter) ?? null;
  const estimatedSavedTokens = normalizeNonNegativeNumber(record.estimatedSavedTokens) ?? null;
  const thresholdTokens = normalizeNonNegativeNumber(record.thresholdTokens) ?? null;
  const maxInputTokens = normalizeNonNegativeNumber(record.maxInputTokens) ?? null;
  const compactedMessageCount = normalizeNonNegativeNumber(record.compactedMessageCount) ?? null;
  const retainedMessageCount = normalizeNonNegativeNumber(record.retainedMessageCount) ?? null;
  const recoveryKind = normalizeText(record.recoveryKind) || null;
  const recoveryAttempt = normalizeNonNegativeNumber(record.recoveryAttempt) ?? null;
  const toolName = normalizeText(record.toolName) || null;
  const toolCallId = normalizeText(record.toolCallId) || null;
  const originalEstimatedChars = normalizeNonNegativeNumber(record.originalEstimatedChars) ?? null;

  if (
    !requestId &&
    !pluginId &&
    !checkpointId &&
    !reason &&
    cursor == null &&
    estimatedInputTokensBefore == null &&
    estimatedInputTokensAfter == null &&
    estimatedSavedTokens == null &&
    thresholdTokens == null &&
    maxInputTokens == null &&
    compactedMessageCount == null &&
    retainedMessageCount == null &&
    !recoveryKind &&
    recoveryAttempt == null &&
    !toolName &&
    !toolCallId &&
    originalEstimatedChars == null
  ) {
    return null;
  }

  return {
    ...(requestId ? { requestId } : {}),
    ...(pluginId ? { pluginId } : {}),
    ...(checkpointId ? { checkpointId } : {}),
    ...(reason ? { reason } : {}),
    ...(cursor != null ? { cursor } : {}),
    ...(estimatedInputTokensBefore != null ? { estimatedInputTokensBefore } : {}),
    ...(estimatedInputTokensAfter != null ? { estimatedInputTokensAfter } : {}),
    ...(estimatedSavedTokens != null ? { estimatedSavedTokens } : {}),
    ...(thresholdTokens != null ? { thresholdTokens } : {}),
    ...(maxInputTokens != null ? { maxInputTokens } : {}),
    ...(compactedMessageCount != null ? { compactedMessageCount } : {}),
    ...(retainedMessageCount != null ? { retainedMessageCount } : {}),
    ...(recoveryKind ? { recoveryKind } : {}),
    ...(recoveryAttempt != null ? { recoveryAttempt } : {}),
    ...(toolName ? { toolName } : {}),
    ...(toolCallId ? { toolCallId } : {}),
    ...(originalEstimatedChars != null ? { originalEstimatedChars } : {}),
  };
}

function normalizeCompressionDiagnostics(value: unknown): CompressionEventDiagnosticsLike | null {
  const record = asRecord(value);
  const autoCompactAttempt = normalizeCompressionAttemptDiagnostics(record.autoCompactAttempt);
  const notification = normalizeCompressionNotificationDiagnostics(record.notification);
  if (!autoCompactAttempt && !notification) return null;
  return {
    ...(autoCompactAttempt ? { autoCompactAttempt } : {}),
    ...(notification ? { notification } : {}),
  };
}

function resolveCompressionSavedTokens(
  event: CompressionEventLike,
  diagnostics: CompressionEventDiagnosticsLike | null,
): number | null {
  const notification = diagnostics?.notification;
  const autoCompactAttempt = diagnostics?.autoCompactAttempt;
  const explicitSaved =
    notification?.estimatedSavedTokens ?? autoCompactAttempt?.estimatedSavedTokens ?? null;
  if (explicitSaved != null) return explicitSaved;

  const tokensBefore =
    notification?.estimatedInputTokensBefore ??
    autoCompactAttempt?.estimatedInputTokens ??
    normalizeNonNegativeNumber(event.tokensBefore) ??
    null;
  const tokensAfter =
    notification?.estimatedInputTokensAfter ??
    autoCompactAttempt?.estimatedInputTokensAfter ??
    normalizeNonNegativeNumber(event.tokensAfter) ??
    null;
  if (tokensBefore == null || tokensAfter == null) return null;
  return Math.max(0, tokensBefore - tokensAfter);
}

function formatInteger(value: number): string {
  return Math.max(0, Math.floor(value)).toLocaleString("en-US");
}

function formatCompressionSummary(
  event: CompressionEventLike,
): Readonly<{ text: string; tone: NoticeTone }> {
  const diagnostics = normalizeCompressionDiagnostics(event.diagnostics);
  const notification = diagnostics?.notification;
  const autoCompactAttempt = diagnostics?.autoCompactAttempt;

  if (event.trigger === "result" && event.state === "completed") {
    const toolName = normalizeText(notification?.toolName) || null;
    const recoveryAttempt = normalizeNonNegativeNumber(notification?.recoveryAttempt) ?? null;
    if (toolName && recoveryAttempt != null)
      return {
        text: `Recovered tool result ${toolName} (attempt ${recoveryAttempt})`,
        tone: "success",
      };
    if (toolName) return { text: `Recovered tool result ${toolName}`, tone: "success" };
    return { text: "Context recovery completed (result)", tone: "success" };
  }

  if (event.trigger === "auto" && event.state === "required") {
    const estimatedInputTokens =
      notification?.estimatedInputTokensBefore ??
      normalizeNonNegativeNumber(event.tokensBefore) ??
      null;
    const thresholdTokens =
      notification?.thresholdTokens ?? normalizeNonNegativeNumber(event.threshold) ?? null;
    if (estimatedInputTokens != null && thresholdTokens != null) {
      return {
        text: t("chatStatus.autoCompactionRequiredDetailed", {
          estimated: formatInteger(estimatedInputTokens),
          threshold: formatInteger(thresholdTokens),
        }),
        tone: "warning",
      };
    }
    return { text: t("chatStatus.autoCompactionRequired"), tone: "warning" };
  }

  if (event.trigger === "auto" && event.state === "completed") {
    const compactedMessageCount =
      notification?.compactedMessageCount ??
      autoCompactAttempt?.compactedMessageCount ??
      normalizeNonNegativeNumber(event.removedMessages) ??
      null;
    const estimatedInputTokensBefore =
      notification?.estimatedInputTokensBefore ??
      autoCompactAttempt?.estimatedInputTokens ??
      normalizeNonNegativeNumber(event.tokensBefore) ??
      null;
    const estimatedInputTokensAfter =
      notification?.estimatedInputTokensAfter ??
      autoCompactAttempt?.estimatedInputTokensAfter ??
      normalizeNonNegativeNumber(event.tokensAfter) ??
      null;
    const estimatedSavedTokens = resolveCompressionSavedTokens(event, diagnostics);
    if (
      compactedMessageCount != null &&
      estimatedInputTokensBefore != null &&
      estimatedInputTokensAfter != null &&
      estimatedSavedTokens != null
    ) {
      if (estimatedInputTokensAfter < estimatedInputTokensBefore) {
        return {
          text: t("chatStatus.autoCompactedDetailed", {
            removed: formatInteger(compactedMessageCount),
            before: formatInteger(estimatedInputTokensBefore),
            after: formatInteger(estimatedInputTokensAfter),
            saved: formatInteger(estimatedSavedTokens),
          }),
          tone: "success",
        };
      }
      return {
        text: t("chatStatus.autoCompactedNotReduced", {
          removed: formatInteger(compactedMessageCount),
          before: formatInteger(estimatedInputTokensBefore),
          after: formatInteger(estimatedInputTokensAfter),
        }),
        tone: "warning",
      };
    }
    if (compactedMessageCount != null && estimatedSavedTokens != null) {
      return {
        text: t("chatStatus.autoCompactedSaved", {
          removed: formatInteger(compactedMessageCount),
          saved: formatInteger(estimatedSavedTokens),
        }),
        tone: estimatedSavedTokens > 0 ? "success" : "warning",
      };
    }
    if (compactedMessageCount != null)
      return {
        text: t("chatStatus.autoCompactedCountOnly", {
          removed: formatInteger(compactedMessageCount),
        }),
        tone: "success",
      };
    return { text: "Context compression completed (auto)", tone: "success" };
  }

  if (event.trigger === "auto" && event.state === "failed") {
    const status = autoCompactAttempt?.status ?? null;
    const reasonCode =
      normalizeText(autoCompactAttempt?.reasonCode) || normalizeText(event.reasonCode) || null;
    if (status === "skipped") {
      return {
        text: reasonCode ? `Auto compact skipped: ${reasonCode}` : "Auto compact skipped",
        tone: "warning",
      };
    }
    return {
      text: reasonCode ? `Auto compact failed: ${reasonCode}` : "Auto compact failed",
      tone: "danger",
    };
  }

  if (event.trigger === "result")
    return {
      text: `Context recovery ${event.state} (${event.trigger})`,
      tone: event.state === "failed" ? "danger" : "success",
    };
  return {
    text: `Context compression ${event.state} (${event.trigger})`,
    tone: event.state === "failed" ? "danger" : "warning",
  };
}

function formatReasoningDiagnostics(
  diagnostics: unknown,
): Readonly<{ state: "visible" | "tokens_only" | "none"; text: string; tone?: NoticeTone }> | null {
  const state = normalizeText((diagnostics as { state?: unknown } | null)?.state);
  if (state === "visible") {
    return {
      state,
      text: "",
      tone: "success",
    };
  }
  if (state === "tokens_only") {
    return {
      state,
      text: "",
      tone: "warning",
    };
  }
  if (state === "none") {
    return {
      state,
      text: "",
    };
  }
  return null;
}

function inferApprovalPermission(
  toolName: string,
  payload: Record<string, unknown>,
): ToolPermission {
  const kind = normalizeText(payload.kind).toLowerCase();
  if (kind === "read" || isReadLikeToolName(toolName) || isSearchLikeToolName(toolName))
    return "pass" as ToolPermission;
  return "require_action" as ToolPermission;
}

function inferApprovalRiskLevel(
  permission: ToolPermission,
  toolName: string,
  payload: Record<string, unknown>,
): ApprovalRequest["riskLevel"] {
  if (permission === "pass") return "safe";
  const kind = normalizeText(payload.kind).toLowerCase();
  if (kind === "edit" || isWriteLikeToolName(toolName) || isEditLikeToolName(toolName))
    return "high";
  if (kind === "execute" || isExecLikeToolName(toolName)) return "critical";
  return "medium";
}

function buildApprovalRequest(event: ToolApprovalRequiredEvent): ApprovalRequest {
  const payload = asRecord(event.payload);
  const acpToolCall = asRecord(payload.acpToolCall);
  const toolName = canonicalToolName(
    normalizeText(event.toolName) ||
      normalizeText(acpToolCall.title) ||
      normalizeText(acpToolCall.toolCallId) ||
      "tool",
  );
  const args = asRecord(acpToolCall.rawInput);
  const permission =
    (event as any).permission === "pass" || (event as any).permission === "require_action"
      ? ((event as any).permission as ToolPermission)
      : inferApprovalPermission(toolName, acpToolCall);
  const reason =
    normalizeText((event as any).reason) ||
    normalizeText(payload.message) ||
    normalizeText(acpToolCall.title) ||
    `Approval required to execute ${toolName}`;
  const riskLevel =
    normalizeText((event as any).riskLevel) ||
    inferApprovalRiskLevel(permission, toolName, acpToolCall);
  const eventArgs = asRecord((event as any).args);
  const resolvedArgs = Object.keys(eventArgs).length > 0 ? eventArgs : args;
  return {
    id: event.actionId,
    ...(normalizeText((event as any).subagentId)
      ? { subagentId: normalizeText((event as any).subagentId) }
      : {}),
    toolCallId:
      normalizeText(event.toolCallId) || normalizeText(acpToolCall.toolCallId) || event.actionId,
    tool: toolName as any,
    permission,
    reason,
    ...(Object.keys(resolvedArgs).length > 0 ? { args: resolvedArgs } : {}),
    source: "goatchain",
    riskLevel: riskLevel as ApprovalRequest["riskLevel"],
    status: "pending",
  };
}

function buildToolResult(event: Extract<AgentEvent, { type: "tool.finished" }>): ToolResult {
  const outputRecord = asRecord(event.output);
  const structuredContent =
    outputRecord.structuredContent && typeof outputRecord.structuredContent === "object"
      ? (outputRecord.structuredContent as Record<string, unknown>)
      : undefined;
  const textFromContent = extractTextParts(outputRecord.content).join("\n");
  const output =
    normalizeText(outputRecord.output) ||
    normalizeText(textFromContent) ||
    serializeUnknown(event.output);

  return {
    toolCallId: event.toolCallId,
    output,
    ...(event.subagentId ? { subagentId: event.subagentId } : {}),
    status: event.isError ? "error" : "success",
    ...(structuredContent ? { structuredContent } : {}),
  };
}

function isTodoToolName(toolName: string): boolean {
  return toolName === "todowrite";
}

function isPlanToolName(toolName: string): boolean {
  return toolName === "todoplan" || toolName === "plan_mode_todoplan";
}

function isInlinePlanMarkdownToolName(toolName: string): boolean {
  return isPlanToolName(toolName);
}

function wrapInlinePlanMarkdown(markdown: string): string {
  const body = String(markdown ?? "")
    .replace(/\r/g, "")
    .trim();
  if (!body) return "";
  return `${PROPOSED_PLAN_OPEN_TAG}\n${body}\n${PROPOSED_PLAN_CLOSE_TAG}`;
}

function normalizeInlineMarkdownPreviewPath(value: unknown): string | null {
  const candidate = normalizeText(value);
  if (!candidate || candidate.includes("\n") || candidate.includes("\0")) return null;
  if (!path.isAbsolute(candidate)) return null;
  if (path.extname(candidate).toLowerCase() !== ".md") return null;
  return path.normalize(candidate);
}

function extractInlinePlanMarkdownPath(
  event: Extract<AgentEvent, { type: "tool.finished" }>,
  result: ToolResult,
): string | null {
  const outputRecord = asRecord(event.output);
  const structuredContent = asRecord(outputRecord.structuredContent);
  const candidates = [
    outputRecord.markdownPath,
    outputRecord.markdown_path,
    outputRecord.filePath,
    outputRecord.file_path,
    outputRecord.path,
    structuredContent.markdownPath,
    structuredContent.markdown_path,
    structuredContent.filePath,
    structuredContent.file_path,
    structuredContent.path,
    result.output,
    ...extractTextParts(outputRecord.content),
  ];

  for (const candidate of candidates) {
    const normalized = normalizeInlineMarkdownPreviewPath(candidate);
    if (normalized) return normalized;
  }
  return null;
}

async function readInlinePlanMarkdown(filePath: string): Promise<string | null> {
  const normalizedPath = normalizeInlineMarkdownPreviewPath(filePath);
  if (!normalizedPath) return null;

  try {
    const fileInfo = await stat(normalizedPath);
    if (!fileInfo.isFile() || fileInfo.size <= 0 || fileInfo.size > maxInlinePlanMarkdownBytes)
      return null;
    const markdown = await readFile(normalizedPath, "utf-8");
    return markdown.trim() ? markdown : null;
  } catch {
    return null;
  }
}

function assistantHasMarkdownContent(messages: readonly Message[], assistantId: string): boolean {
  const assistant = messages.find(
    (message) => message?.id === assistantId && message.role === "assistant",
  ) as Extract<Message, { role: "assistant" }> | undefined;

  if (!assistant) return false;

  return assistant.parts.some((part) => {
    if (part.type !== "markdown") return false;
    return normalizeText((part as { markdown?: string }).markdown).length > 0;
  });
}

function readAssistantMarkdownText(messages: readonly Message[], assistantId: string): string {
  const assistant = messages.find(
    (message) => message?.id === assistantId && message.role === "assistant",
  ) as Extract<Message, { role: "assistant" }> | undefined;

  if (!assistant) return "";

  return assistant.parts
    .filter(
      (part): part is Extract<(typeof assistant.parts)[number], { type: "markdown" }> =>
        part.type === "markdown",
    )
    .map((part) => String(part.markdown ?? ""))
    .join("");
}

function isAbortLikeError(error: unknown): boolean {
  const text = error instanceof Error ? `${error.name} ${error.message}` : String(error);
  return /\babort|cancel/i.test(text);
}

function resolveProviderAdapter(state: any, providerId: string): RuntimeConfig["adapter"] {
  const customProviders = Array.isArray(state?.provider?.customProviders)
    ? state.provider.customProviders
    : [];
  const customProvider = customProviders.find(
    (provider: any) => normalizeText(provider?.id) === providerId,
  );
  const customAdapter = normalizeText(customProvider?.adapter);
  if (
    customAdapter === "openai" ||
    customAdapter === "openai-responses" ||
    customAdapter === "gemini" ||
    customAdapter === "anthropic"
  ) {
    return customAdapter;
  }

  const builtinAdapter = normalizeText(getBuiltinProvider(providerId)?.adapter);
  if (
    builtinAdapter === "openai" ||
    builtinAdapter === "openai-responses" ||
    builtinAdapter === "gemini" ||
    builtinAdapter === "anthropic"
  ) {
    return builtinAdapter;
  }

  if (providerId === "google") return "gemini";
  if (providerId === "anthropic") return "anthropic";
  return "openai";
}

function buildRuntimeConfigFromState(state: any): RuntimeConfig {
  const env = asRecord(state?.context?.env) as Record<string, string | undefined>;
  const base = readCliRuntimeConfig(env);
  const providerId = normalizeText(state?.provider?.activeId);
  const activeModel =
    normalizeText(state?.config?.model) ||
    normalizeText(state?.provider?.activeModelByProvider?.[providerId]) ||
    base.modelId;
  const connection = asRecord(state?.provider?.connections?.[providerId]);
  const customProviders = Array.isArray(state?.provider?.customProviders)
    ? state.provider.customProviders
    : [];
  const customProvider = customProviders.find(
    (provider: any) => normalizeText(provider?.id) === providerId,
  );
  const legacyCustomProvider = asRecord(state?.provider?.custom);
  const builtin =
    providerId && !customProvider && !isLegacyCustomProviderId(providerId)
      ? getBuiltinProvider(providerId)
      : undefined;
  const adapter = providerId ? resolveProviderAdapter(state, providerId) : base.adapter;
  const baseUrl = customProvider
    ? normalizeText(customProvider?.baseUrl) || base.baseUrl
    : isLegacyCustomProviderId(providerId)
      ? normalizeText(legacyCustomProvider.baseUrl) || base.baseUrl
      : providerId === "next-api-oauth"
        ? normalizeText(connection.baseUrl as string | undefined) || base.baseUrl
        : builtin && !isBuiltinProviderBaseUrlEditable(providerId)
          ? normalizeText(resolveBuiltinProviderBaseUrl(builtin))
          : normalizeText(
              resolveBuiltinProviderBaseUrl(builtin, connection.baseUrl as string | undefined),
            ) || base.baseUrl;
  const apiKey = customProvider
    ? normalizeText(customProvider?.apiKey) || base.apiKey
    : isLegacyCustomProviderId(providerId)
      ? normalizeText(legacyCustomProvider.apiKey) || base.apiKey
      : normalizeText(connection.apiKey) || base.apiKey;
  const provider = providerId || base.provider || adapter;
  const storedContextWindow = parsePositiveInt(state?.config?.context_window);
  const resolvedContextWindow = resolveProviderSelectionContextWindow({
    providerId,
    modelId: activeModel,
    connections: state?.provider?.connections,
    customProviders,
    legacyCustomModels: Array.isArray(legacyCustomProvider.models)
      ? legacyCustomProvider.models
      : [],
  });
  const maxInputTokens = shouldIgnoreLegacyStoredContextWindow(
    storedContextWindow,
    resolvedContextWindow,
  )
    ? resolvedContextWindow
    : (storedContextWindow ?? resolvedContextWindow ?? base.maxInputTokens);
  const maxOutputTokens = base.maxOutputTokens;

  return {
    ...base,
    modelId: activeModel || base.modelId,
    ...(adapter ? { adapter } : {}),
    ...(provider ? { provider } : {}),
    ...(baseUrl ? { baseUrl } : {}),
    ...(apiKey ? { apiKey } : {}),
    ...(typeof maxInputTokens === "number" ? { maxInputTokens } : {}),
    ...(typeof maxOutputTokens === "number" ? { maxOutputTokens } : {}),
    ...(providerId === "next-api-oauth" || base.nextApiOAuth === true
      ? { nextApiOAuth: true }
      : {}),
    env: { ...(base.env ?? env) },
  };
}

function buildToolApprovalModeFromState(state: any): ToolApprovalMode {
  const mode = state?.approval?.mode;
  if (mode === "auto" || mode === "normal" || mode === "strict") return mode;
  return "normal";
}

function buildMcpServersFromState(state: any): McpServerConfig[] {
  return toMcpServerConfigs(Array.isArray(state?.mcp?.servers) ? state.mcp.servers : []);
}

function asToolApprovalRequiredEvent(event: ActionRequiredEvent): ToolApprovalRequiredEvent {
  return event as ToolApprovalRequiredEvent;
}

function asAskUserRequiredEvent(event: ActionRequiredEvent): AskUserRequiredEvent {
  return event as AskUserRequiredEvent;
}

function normalizeAskUserQuestions(raw: unknown): readonly AskUserQuestion[] {
  return normalizeDimSdkAskUserQuestions(raw).map((question) => ({
    allowCustom: question.allowCustom,
    id: question.id,
    kind: question.kind,
    multiline: question.multiline,
    placeholder: question.placeholder,
    question: question.question,
    ...(question.header ? { header: question.header } : {}),
    ...(question.options.length > 0 ? { options: [...question.options] } : {}),
    ...(question.multiSelect ? { multiSelect: true } : {}),
  }));
}

export function createNativeStreamRunner(
  opts: Readonly<{
    state: any;
    agent: CliAgentBridge;
    id: (prefix: string) => string;
    pushMessage: (m: Message) => void;
    updateAssistant: (
      messageId: string,
      fn: (m: Extract<Message, { role: "assistant" }>) => Extract<Message, { role: "assistant" }>,
    ) => void;
    setAssistantStatus: (messageId: string, text: string) => void;
    setAssistantThinking: (assistantId: string, content: string, partId: string) => void;
    startNewThinkingBlock: (assistantId: string, partId: string) => void;
    endThinkingBlock: (assistantId: string, partId: string, content?: string) => void;
    appendAssistantMarkdown: (assistantId: string, delta: string) => void;
    pushAssistantMarkdownPart: (assistantId: string, markdown: string) => void;
    appendInfoPart: (
      assistantId: string,
      text: string,
      meta?: Readonly<Record<string, unknown>>,
    ) => void;
    upsertSubagentInfo: (
      assistantId: string,
      subagentId: string,
      kind: "header" | "activity" | "finished",
      text: string,
    ) => void;
    tickSubagentFrame: (assistantId: string) => void;
    upsertToolCallDelta: (
      assistantId: string,
      callId: string,
      toolName: string | undefined,
      argsTextDelta: string | undefined,
      linesWritten?: number,
      meta?: Readonly<{ subagentId?: string }>,
    ) => void;
    upsertToolCallEnd: (
      assistantId: string,
      callId: string,
      toolName: string,
      args: Record<string, unknown>,
      thoughtSignature?: string,
      meta?: Readonly<{ subagentId?: string }>,
    ) => void;
    upsertToolOutputStart: (
      assistantId: string,
      toolCallId: string,
      toolName: string,
      meta?: Readonly<{ subagentId?: string }>,
    ) => void;
    appendToolOutputDelta: (
      assistantId: string,
      toolCallId: string,
      toolName: string,
      delta: string,
      meta?: Readonly<{ subagentId?: string }>,
    ) => void;
    insertApprovalPart: (assistantId: string, request: ApprovalRequest) => void;
    attachToolResultPart: (
      assistantId: string,
      result: ToolResult,
      meta?: Readonly<{ subagentId?: string }>,
    ) => void;
    scheduleToolResultHighlight: (assistantId: string, result: ToolResult) => void;
    upsertChecklistPartFromDimSdk: (
      assistantId: string,
      kind: "todo" | "plan",
      toolCallId: string,
      structured: any,
    ) => void;
    flushPendingAssistantOutput?: (assistantId?: string) => void;
    applyLastRequestBudget: (budget: unknown) => void;
    applyUsageFromSession: (usage: unknown) => void;
    ensureErrorVisibleInTranscript: (assistantId: string, errorMeta: unknown) => void;
  }>,
): Readonly<{
  runAgentRound: (opts?: {
    toolContext?: ToolExecutionContextInput;
    baseMessages?: Message[];
    steer?: boolean;
  }) => Promise<AgentRoundResult>;
  cancelActiveAgentStream: () => void;
  cancelActiveAgentStreamAndWaitWithTimeout: (timeoutMs?: number) => Promise<void>;
  abortActiveAgentRound: () => void;
}> {
  let activeAbortController: AbortController | null = null;
  let activeRunPromise: Promise<void> | null = null;
  let pendingAction: PendingActionState | null = null;

  const resetActiveRun = () => {
    activeAbortController = null;
    activeRunPromise = null;
  };

  const clearPendingAction = () => {
    pendingAction = null;
  };

  const cancelActiveAgentStream = () => {
    activeAbortController?.abort("cancelled");
  };

  const cancelActiveAgentStreamAndWaitWithTimeout = async (timeoutMs = 200) => {
    const waitPromise = activeRunPromise;
    activeAbortController?.abort("cancelled");
    if (!waitPromise) return;
    const timeout = Math.max(0, Math.floor(timeoutMs));
    await Promise.race([
      waitPromise.catch(() => {}),
      new Promise<void>((resolve) => {
        const handle = setTimeout(resolve, timeout);
        (handle as any)?.unref?.();
      }),
    ]);
  };

  const abortActiveAgentRound = () => {
    activeAbortController?.abort("aborted");
  };

  const clearThinkingState = () => {
    opts.state.thinking.active = false;
    opts.state.thinking.assistantId = null;
    opts.state.thinking.partId = null;
  };

  const resolveResumeTarget = (
    toolContext: ToolExecutionContextInput | undefined,
  ): ResumeTarget | null => {
    const required = toolContext?.requiresAction;
    const requiredActionId = normalizeText(required?.actionId);
    const requiredKind = required?.kind;
    if (requiredActionId && (requiredKind === "tool_approval" || requiredKind === "ask_user")) {
      return {
        kind: requiredKind,
        actionId: requiredActionId,
        toolCallId: normalizeText(required?.toolCallId) || undefined,
      };
    }

    const current = pendingAction;
    if (!current) return null;

    return {
      kind: current.kind,
      actionId: current.actionId,
      toolCallId: current.toolCallId,
    };
  };

  const findAssistantIdForResume = (resumeTarget: ResumeTarget | null): string | null => {
    const explicitAssistantId = pendingAction?.assistantId;
    if (explicitAssistantId) return explicitAssistantId;

    const messages = opts.state.messages as Message[];
    const findAssistant = (
      matcher: (message: Extract<Message, { role: "assistant" }>) => boolean,
    ): string | null => {
      for (let index = messages.length - 1; index >= 0; index -= 1) {
        const message = messages[index];
        if (message?.role !== "assistant") continue;
        if (matcher(message)) return message.id;
      }
      return null;
    };

    const toolCallId = normalizeText(resumeTarget?.toolCallId);
    if (toolCallId) {
      const matchedAssistantId = findAssistant((message) =>
        message.parts.some(
          (part) => part.type === "tool_call" && normalizeText(part.call.id) === toolCallId,
        ),
      );
      if (matchedAssistantId) return matchedAssistantId;
    }

    if (resumeTarget?.kind === "ask_user") {
      const askUserAssistantId = findAssistant((message) =>
        message.parts.some(
          (part) =>
            part.type === "tool_call" && normalizeText(part.call.name).toLowerCase() === "ask-user",
        ),
      );
      if (askUserAssistantId) return askUserAssistantId;
    }

    return findAssistant(() => true);
  };

  const pickSingleRecordValue = <T>(
    record: Readonly<Record<string, T>> | undefined,
  ): T | undefined => {
    if (!record) return undefined;
    const entries = Object.entries(record);
    if (entries.length !== 1) return undefined;
    return entries[0]?.[1];
  };

  const resolveApprovalDecision = (
    toolContext: ToolExecutionContextInput | undefined,
    resumeTarget: ResumeTarget,
  ): ToolApprovalResult | undefined => {
    const decisions = toolContext?.approval?.decisions;
    if (!decisions) return undefined;
    const toolCallId = normalizeText(resumeTarget.toolCallId);
    if (toolCallId) return decisions[toolCallId];
    return pickSingleRecordValue(decisions);
  };

  const resolveAskUserResumePayload = (
    toolContext: ToolExecutionContextInput | undefined,
    resumeTarget: ResumeTarget,
  ): Readonly<{
    answers?: Readonly<Record<string, string | string[]>>;
    rejectedReason?: string;
  }> => {
    const answersByToolCall = toolContext?.askUser?.answers;
    const rejectedByToolCall = toolContext?.askUser?.rejected;
    const toolCallId = normalizeText(resumeTarget.toolCallId);
    const actionId = normalizeText(resumeTarget.actionId);

    if (toolCallId) {
      return {
        answers: answersByToolCall?.[toolCallId],
        rejectedReason: rejectedByToolCall?.[toolCallId],
      };
    }

    return {
      answers:
        (actionId ? answersByToolCall?.[actionId] : undefined) ??
        pickSingleRecordValue(answersByToolCall),
      rejectedReason:
        (actionId ? rejectedByToolCall?.[actionId] : undefined) ??
        pickSingleRecordValue(rejectedByToolCall),
    };
  };

  const buildResumeInput = (
    toolContext: ToolExecutionContextInput | undefined,
  ): ResumeInput | null => {
    const current = resolveResumeTarget(toolContext);
    if (!current) return null;

    if (current.kind === "tool_approval") {
      const decision = resolveApprovalDecision(toolContext, current);
      if (!decision) {
        throw new Error(`Missing approval decision for ${current.toolCallId ?? current.actionId}`);
      }
      return {
        kind: "tool_approval",
        actionId: current.actionId,
        ...(current.toolCallId ? { toolCallId: current.toolCallId } : {}),
        approved: decision.approved,
        ...(decision.reason ? { reason: decision.reason } : {}),
        ...(toolContext?.approval?.alwaysAllowForConversation
          ? { alwaysAllowForConversation: true }
          : {}),
      };
    }

    const { answers, rejectedReason } = resolveAskUserResumePayload(toolContext, current);

    if (!answers && !rejectedReason) {
      throw new Error(`Missing ask-user answers for ${current.toolCallId ?? current.actionId}`);
    }

    return {
      kind: "ask_user",
      actionId: current.actionId,
      ...(current.toolCallId ? { toolCallId: current.toolCallId } : {}),
      answers: { ...answers },
      ...(rejectedReason ? { reason: rejectedReason, rejected: true } : {}),
    } as ResumeInput;
  };

  return {
    async runAgentRound(runOpts) {
      const toolCalls: ToolCall[] = [];
      const baseMessages = (runOpts?.baseMessages ?? opts.state.messages) as Message[];
      const resumeTarget = resolveResumeTarget(runOpts?.toolContext);
      const resumeInput = buildResumeInput(runOpts?.toolContext);
      const existingAssistantId = resumeInput ? findAssistantIdForResume(resumeTarget) : null;
      const assistantId = existingAssistantId ?? opts.id("m");

      if (!resumeInput || !existingAssistantId) {
        clearThinkingState();
        const modelId = String(opts.state.config?.model ?? "").trim() || undefined;
        opts.pushMessage({
          id: assistantId,
          role: "assistant",
          parts: [{ type: "status", text: "" }],
          createdAtMs: Date.now(),
          ...(modelId ? { modelId } : {}),
        });
      }

      const latestUserMessage = resumeInput
        ? null
        : ([...baseMessages]
            .reverse()
            .find(
              (message): message is Extract<Message, { role: "user" }> => message?.role === "user",
            ) ?? null);

      if (!resumeInput && !latestUserMessage) {
        return {
          assistantId,
          toolCalls,
          success: false,
          error: new Error("No user message found for native agent run"),
        };
      }

      const sessionId = normalizeText(opts.state.sessionId);
      const openSession = opts.agent.openSession;
      const ensureSession = opts.agent.ensureSession;
      const modeId =
        normalizeText(opts.agent.getMode?.() ?? opts.state.ui?.mode) === "plan" ? "plan" : "agent";
      const runtimeConfig = buildRuntimeConfigFromState(opts.state);
      const session = resumeInput
        ? typeof openSession === "function"
          ? await openSession(sessionId)
          : null
        : typeof ensureSession === "function"
          ? await ensureSession({
              sessionId: sessionId || undefined,
              cwd: normalizeText(opts.state.context?.cwd) || process.cwd(),
              modeId,
              runtimeConfig,
              toolApprovalMode: buildToolApprovalModeFromState(opts.state),
              mcpServers: buildMcpServersFromState(opts.state),
            })
          : null;

      if (!session) {
        return {
          assistantId,
          toolCalls,
          success: false,
          error: new Error("Native runtime session bridge is unavailable"),
        };
      }

      if (normalizeText(opts.state.sessionId) !== session.id) opts.state.sessionId = session.id;

      const currentPendingAction = pendingAction;
      if (resumeInput) {
        clearPendingAction();
        opts.updateAssistant(assistantId, (message) => ({
          ...message,
          parts: message.parts.map((part) =>
            part.type === "status" ? ({ type: "status", text: "" } as const) : part,
          ),
        }));
      }

      opts.state.runningAgentRound = true;
      activeAbortController = new AbortController();

      const stream = resumeInput
        ? session.resume(resumeInput, { signal: activeAbortController.signal })
        : session.run(
            {
              content: await buildUserTurnContent(latestUserMessage!, opts.state),
              metadata: runOpts?.steer ? { steer: true } : {},
            },
            { signal: activeAbortController.signal },
          );

      let sawAssistantDelta = false;
      let sawToolOutput = false;
      const toolCallStarted = new Set<string>();
      const toolOutputStarted = new Set<string>();
      const placeholderThinkingPartIds = new Set<string>();
      let roundError: Error | null = null;
      let pendingInlinePlanMarkdownPath: string | null = null;
      const streamedThinkingContentByPartId = new Map<string, string>();
      const reusedPlaceholderThinkingContentByPartId = new Map<string, string>();

      const subagentSpinnerTimers = new Map<string, ReturnType<typeof setInterval>>();
      const clearSubagentSpinner = (subagentId?: string) => {
        if (subagentId) {
          const timer = subagentSpinnerTimers.get(subagentId);
          if (timer) {
            clearInterval(timer);
            subagentSpinnerTimers.delete(subagentId);
          }
        } else {
          for (const timer of subagentSpinnerTimers.values()) clearInterval(timer);
          subagentSpinnerTimers.clear();
        }
      };

      const removeDelegationPlaceholderMarkdown = (): void => {
        opts.flushPendingAssistantOutput?.(assistantId);
        opts.updateAssistant(assistantId, (message) => {
          const nextParts = message.parts.filter((part) => {
            if (part.type !== "markdown") return true;
            return !isDelegationRecordedFinalMessage(part.markdown);
          });
          if (nextParts.length === message.parts.length) return message;
          return {
            ...message,
            parts: nextParts,
          };
        });
      };

      const replaceAssistantMarkdownWithFinalMessage = (content: string): void => {
        const finalContent = String(content ?? "");
        if (!finalContent) return;
        opts.flushPendingAssistantOutput?.(assistantId);
        const previousText = readAssistantMarkdownText(
          opts.state.messages as Message[],
          assistantId,
        );
        if (previousText === finalContent) return;
        opts.updateAssistant(assistantId, (message) => {
          const nextParts = message.parts.filter((part) => part.type !== "markdown");
          return nextParts.length === message.parts.length
            ? message
            : {
                ...message,
                parts: nextParts,
              };
        });
        opts.appendAssistantMarkdown(assistantId, finalContent);
      };

      const findReusablePlaceholderThinkingPartId = (): string | undefined => {
        for (const placeholderPartId of placeholderThinkingPartIds) {
          if (
            hasThinkingBlockWithId(opts.state.messages as Message[], assistantId, placeholderPartId)
          ) {
            return placeholderPartId;
          }
          placeholderThinkingPartIds.delete(placeholderPartId);
        }
        return undefined;
      };

      const retargetThinkingBlockPartId = (fromPartId: string, toPartId: string): boolean => {
        const normalizedFromPartId = String(fromPartId ?? "").trim();
        const normalizedToPartId = String(toPartId ?? "").trim();
        if (!normalizedFromPartId || !normalizedToPartId) return false;
        let retargeted = false;
        opts.updateAssistant(assistantId, (message) => {
          const parts = message.parts.slice();
          const fromIndex = parts.findIndex(
            (part) =>
              part.type === "thinking" && String(part.partId ?? "").trim() === normalizedFromPartId,
          );
          if (fromIndex < 0) return message;
          if (
            parts.some(
              (part) =>
                part.type === "thinking" && String(part.partId ?? "").trim() === normalizedToPartId,
            )
          ) {
            return message;
          }
          const previous = parts[fromIndex];
          if (previous?.type !== "thinking") return message;
          parts[fromIndex] = {
            ...previous,
            partId: normalizedToPartId,
          };
          retargeted = true;
          return { ...message, parts };
        });
        return retargeted;
      };

      const consumeStream = async () => {
        try {
          for await (const event of stream) {
            if (event.type === "thinking.started") {
              const existingLiveBlock = hasThinkingBlockWithId(
                opts.state.messages as Message[],
                assistantId,
                event.partId,
              );
              let reusesPlaceholder = false;
              if (!existingLiveBlock) {
                const reusablePlaceholderPartId = findReusablePlaceholderThinkingPartId();
                if (reusablePlaceholderPartId) {
                  const placeholderContent = readThinkingBlockContent(
                    opts.state.messages as Message[],
                    assistantId,
                    reusablePlaceholderPartId,
                  );
                  reusesPlaceholder = retargetThinkingBlockPartId(
                    reusablePlaceholderPartId,
                    event.partId,
                  );
                  if (reusesPlaceholder) {
                    placeholderThinkingPartIds.delete(reusablePlaceholderPartId);
                    if (placeholderContent) {
                      reusedPlaceholderThinkingContentByPartId.set(
                        event.partId,
                        placeholderContent,
                      );
                    }
                  }
                }
              }
              if (!reusesPlaceholder && !existingLiveBlock)
                opts.startNewThinkingBlock(assistantId, event.partId);
              streamedThinkingContentByPartId.set(event.partId, "");
              opts.state.thinking.active = true;
              opts.state.thinking.assistantId = assistantId;
              opts.state.thinking.partId = event.partId;
              continue;
            }

            if (event.type === "thinking.delta") {
              const nextThinking = `${streamedThinkingContentByPartId.get(event.partId) ?? ""}${event.delta}`;
              streamedThinkingContentByPartId.set(event.partId, nextThinking);
              const reusedPlaceholderContent = reusedPlaceholderThinkingContentByPartId.get(
                event.partId,
              );
              const resolvedThinking = reusedPlaceholderContent?.startsWith(nextThinking)
                ? reusedPlaceholderContent
                : nextThinking;
              if (resolvedThinking !== reusedPlaceholderContent)
                reusedPlaceholderThinkingContentByPartId.delete(event.partId);
              opts.setAssistantThinking(assistantId, resolvedThinking, event.partId);
              opts.state.thinking.active = true;
              opts.state.thinking.assistantId = assistantId;
              opts.state.thinking.partId = event.partId;
              continue;
            }

            if (event.type === "thinking.finished") {
              const finalThinking =
                typeof event.content === "string"
                  ? event.content
                  : streamedThinkingContentByPartId.get(event.partId);
              if (typeof finalThinking === "string") {
                opts.setAssistantThinking(assistantId, finalThinking, event.partId);
              }
              opts.endThinkingBlock(assistantId, event.partId, finalThinking);
              placeholderThinkingPartIds.delete(event.partId);
              streamedThinkingContentByPartId.delete(event.partId);
              reusedPlaceholderThinkingContentByPartId.delete(event.partId);
              clearThinkingState();
              continue;
            }

            if (event.type === "assistant.delta") {
              if (isDelegationRecordedFinalMessage(event.delta)) continue;
              sawAssistantDelta = true;
              opts.appendAssistantMarkdown(assistantId, event.delta);
              continue;
            }

            if (event.type === "assistant.message") {
              if (typeof event.message.thinking === "string") {
                const thinking = event.message.thinking;
                const hasThinkingPart = opts.state.messages.some(
                  (message: Message) =>
                    message?.id === assistantId &&
                    message.role === "assistant" &&
                    message.parts.some((part) => part.type === "thinking"),
                );
                logLlmDebug("native_stream_runner.assistant_thinking", {
                  assistantId,
                  hasThinkingPart,
                  thinking,
                });
                if (!hasThinkingPart && thinking) {
                  const partId = createLocalThinkingPartId(assistantId, 0);
                  opts.startNewThinkingBlock(assistantId, partId);
                  opts.setAssistantThinking(assistantId, thinking, partId);
                  opts.endThinkingBlock(assistantId, partId, thinking);
                  placeholderThinkingPartIds.add(partId);
                }
              }
              const content = extractTextContent(event.message.content);
              if (content && !isDelegationRecordedFinalMessage(content)) {
                if (sawAssistantDelta) {
                  replaceAssistantMarkdownWithFinalMessage(content);
                } else {
                  opts.appendAssistantMarkdown(assistantId, content);
                }
              }
              continue;
            }

            if (event.type === "tool.started") {
              const args = asRecord(event.input);
              if (!event.subagentId) {
                toolCalls.push({
                  toolCallId: event.toolCallId,
                  name: event.toolName,
                  arguments: args,
                });
              }
              if (!toolCallStarted.has(event.toolCallId)) {
                toolCallStarted.add(event.toolCallId);
                opts.upsertToolCallDelta(
                  assistantId,
                  event.toolCallId,
                  event.toolName,
                  "",
                  undefined,
                  event.subagentId ? { subagentId: event.subagentId } : undefined,
                );
              }
              opts.upsertToolCallEnd(
                assistantId,
                event.toolCallId,
                event.toolName,
                args,
                undefined,
                event.subagentId ? { subagentId: event.subagentId } : undefined,
              );
              continue;
            }

            if (event.type === "tool.delta") {
              if (event.kind === "input") {
                opts.upsertToolCallDelta(
                  assistantId,
                  event.toolCallId,
                  event.toolName,
                  event.delta,
                  event.linesWritten,
                  event.subagentId ? { subagentId: event.subagentId } : undefined,
                );
                continue;
              }
              const toolName = normalizeText(event.toolName) || event.toolCallId;
              if (!toolOutputStarted.has(event.toolCallId)) {
                toolOutputStarted.add(event.toolCallId);
                opts.upsertToolOutputStart(
                  assistantId,
                  event.toolCallId,
                  toolName,
                  event.subagentId ? { subagentId: event.subagentId } : undefined,
                );
              }
              opts.appendToolOutputDelta(
                assistantId,
                event.toolCallId,
                toolName,
                event.delta,
                event.subagentId ? { subagentId: event.subagentId } : undefined,
              );
              sawToolOutput = true;
              continue;
            }

            if (event.type === "tool.finished") {
              const result = buildToolResult(event);
              opts.attachToolResultPart(
                assistantId,
                result,
                event.subagentId ? { subagentId: event.subagentId } : undefined,
              );
              opts.scheduleToolResultHighlight(assistantId, result);
              const toolNameLower = normalizeText(event.toolName).toLowerCase();
              if (result.structuredContent) {
                if (isTodoToolName(toolNameLower)) {
                  opts.upsertChecklistPartFromDimSdk(
                    assistantId,
                    "todo",
                    event.toolCallId,
                    result.structuredContent,
                  );
                } else if (isPlanToolName(toolNameLower)) {
                  opts.upsertChecklistPartFromDimSdk(
                    assistantId,
                    "plan",
                    event.toolCallId,
                    result.structuredContent,
                  );
                }
              }
              if (isInlinePlanMarkdownToolName(toolNameLower)) {
                pendingInlinePlanMarkdownPath = extractInlinePlanMarkdownPath(event, result);
              }
              continue;
            }

            if (event.type === "action.required" && event.kind === "tool_approval") {
              const approvalEvent = asToolApprovalRequiredEvent(event);
              const request = buildApprovalRequest(approvalEvent);
              const nextPending: PendingActionState = {
                kind: "tool_approval",
                actionId: approvalEvent.actionId,
                toolCallId: request.toolCallId,
                toolName: approvalEvent.toolName,
                assistantId,
              };
              pendingAction = nextPending;
              if (!opts.state.approval.active) {
                opts.state.approval.active = request;
                opts.state.approval.pendingAutoRun = {
                  assistantId,
                  toolCallId: request.toolCallId,
                };
              } else if (opts.state.approval.active.toolCallId !== request.toolCallId) {
                opts.state.approval.queue.push({ request, assistantId });
              }
              opts.state.paused = {
                kind: "tool_approval",
                toolCallId: request.toolCallId,
                actionId: approvalEvent.actionId,
              };
              opts.insertApprovalPart(assistantId, request);
              opts.setAssistantStatus(assistantId, t("chatStatus.awaitingApproval"));
              opts.state.runningAgentRound = false;
              continue;
            }

            if (event.type === "action.required" && event.kind === "ask_user") {
              const askUserEvent = asAskUserRequiredEvent(event);
              const normalizedQuestions = normalizeAskUserQuestions(askUserEvent.questions);
              const nextPending: PendingActionState = {
                kind: "ask_user",
                actionId: askUserEvent.actionId,
                toolCallId: normalizeText(askUserEvent.toolCallId) || undefined,
                toolName: askUserEvent.toolName,
                questions: normalizedQuestions,
                assistantId,
              };
              pendingAction = nextPending;
              opts.state.paused = {
                kind: "ask_user",
                ...(nextPending.toolCallId ? { toolCallId: nextPending.toolCallId } : {}),
                actionId: askUserEvent.actionId,
                ...(nextPending.questions?.length ? { questions: [...nextPending.questions] } : {}),
                ...(typeof askUserEvent.error !== "undefined" ? { error: askUserEvent.error } : {}),
              };
              opts.setAssistantStatus(assistantId, t("chatStatus.awaitingAnswers"));
              opts.state.runningAgentRound = false;
              continue;
            }

            if (event.type === "steer_injected") {
              const steerContent = String((event as any).content ?? "");
              if (steerContent) {
                const currentAssistantIdx = opts.state.messages.findIndex(
                  (m: Message) => m.id === assistantId && m.role === "assistant",
                );
                const currentAssistant =
                  currentAssistantIdx >= 0
                    ? (opts.state.messages[currentAssistantIdx] as Extract<
                        Message,
                        { role: "assistant" }
                      >)
                    : null;

                const userMsg: Extract<Message, { role: "user" }> = {
                  id: opts.id("m"),
                  role: "user",
                  content: steerContent,
                  createdAtMs: Date.now(),
                  metadata: {
                    originalEventType: "steer_injected",
                    steer: true,
                    ...(typeof (event as any).count === "number"
                      ? { steerCount: (event as any).count }
                      : {}),
                  },
                };

                if (currentAssistant && currentAssistantIdx >= 0) {
                  const hasContent = currentAssistant.parts.some(
                    (p: any) => p.type !== "status" || String(p.text ?? "").trim(),
                  );
                  if (hasContent) {
                    const historicalAssistant: Extract<Message, { role: "assistant" }> = {
                      ...currentAssistant,
                      id: opts.id("m"),
                      parts: [...currentAssistant.parts],
                    };
                    const modelId = currentAssistant.modelId;
                    const continuedAssistant: Extract<Message, { role: "assistant" }> = {
                      id: assistantId,
                      role: "assistant",
                      parts: [{ type: "status", text: "" }],
                      createdAtMs: Date.now(),
                      ...(modelId ? { modelId } : {}),
                    };
                    opts.state.messages.splice(
                      currentAssistantIdx,
                      1,
                      historicalAssistant,
                      userMsg,
                      continuedAssistant,
                    );
                  } else {
                    opts.state.messages.splice(currentAssistantIdx, 0, userMsg);
                  }
                } else {
                  opts.pushMessage(userMsg);
                }

                sawAssistantDelta = false;
              }
              continue;
            }

            if (event.type === "subagent.started") {
              removeDelegationPlaceholderMarkdown();
              const desc = normalizeText(event.taskDescription) || normalizeText(event.subagentId);
              if (desc) opts.upsertSubagentInfo(assistantId, event.subagentId, "header", desc);
              // Drive spinner animation on the header while the subagent runs
              clearSubagentSpinner(event.subagentId);
              const timer = setInterval(() => {
                opts.tickSubagentFrame(assistantId);
              }, 150);
              subagentSpinnerTimers.set(event.subagentId, timer);
              continue;
            }

            if (event.type === "subagent.output") {
              let label = "";
              if (event.stream === "tool") {
                // Extract tool name + brief arg summary from "toolName {...args}" format
                const toolNameMatch = /^(\S+)\s+\{/.exec(event.delta);
                if (toolNameMatch) {
                  label = toolNameMatch[1];
                  // Try to extract a short argument summary (e.g. file path)
                  try {
                    const jsonStr = event.delta.slice(toolNameMatch[1].length).trim();
                    const args = JSON.parse(jsonStr);
                    const summary =
                      args.file_path ??
                      args.path ??
                      args.pattern ??
                      args.command ??
                      args.query ??
                      args.file ??
                      args.url;
                    if (typeof summary === "string") {
                      const short = summary.length > 60 ? `…${summary.slice(-57)}` : summary;
                      label = `${label} ${short}`;
                    }
                  } catch {
                    /* ignore parse errors */
                  }
                } else {
                  label = summarizeSubagentActivity(event.delta);
                }
              } else if (event.stream === "error") {
                const summary = summarizeSubagentActivity(event.delta);
                label = summary ? `error: ${summary}` : "error";
              } else {
                label = summarizeSubagentActivity(event.delta);
              }
              if (label) opts.upsertSubagentInfo(assistantId, event.subagentId, "activity", label);
              continue;
            }

            if (event.type === "subagent.finished") {
              clearSubagentSpinner(event.subagentId);
              const stateLabel = event.state === "completed" ? "done" : event.state;
              opts.upsertSubagentInfo(assistantId, event.subagentId, "finished", stateLabel);
              continue;
            }

            if (event.type === "usage.updated") {
              if (typeof event.usage !== "undefined") opts.applyUsageFromSession(event.usage);
              if (typeof event.lastRequestBudget !== "undefined")
                opts.applyLastRequestBudget(event.lastRequestBudget);
              continue;
            }

            if (event.type === "run.budget") {
              opts.applyLastRequestBudget(
                buildRequestBudgetSnapshotFromLegacyRunEvent(
                  event as unknown as Record<string, unknown>,
                ),
              );
              continue;
            }

            if (event.type === "context.compression") {
              const compressionSummary = formatCompressionSummary(event);
              opts.appendInfoPart(assistantId, compressionSummary.text, {
                _tone: compressionSummary.tone,
              });
              continue;
            }

            if (event.type === "run.finished") {
              if (typeof event.usage !== "undefined") opts.applyUsageFromSession(event.usage);
              const reasoningDiagnostics = formatReasoningDiagnostics(
                (event as { reasoningDiagnostics?: unknown }).reasoningDiagnostics,
              );
              if (reasoningDiagnostics) {
                opts.appendInfoPart(assistantId, reasoningDiagnostics.text, {
                  ...(reasoningDiagnostics.tone ? { _tone: reasoningDiagnostics.tone } : {}),
                  _reasoning: reasoningDiagnostics.state,
                });
              }
              clearThinkingState();
              if (event.status === "interrupted") {
                const interruptedMarkdown = t("chatStatus.interruptedMarkdown");
                opts.appendAssistantMarkdown(
                  assistantId,
                  assistantHasMarkdownContent(opts.state.messages as Message[], assistantId)
                    ? `\n\n${interruptedMarkdown}`
                    : interruptedMarkdown,
                );
                opts.setAssistantStatus(assistantId, t("chatStatus.interrupted"));
              } else {
                opts.setAssistantStatus(assistantId, t("chatStatus.done"));
              }
              opts.state.runningAgentRound = false;
              clearPendingAction();
              continue;
            }

            if (event.type === "run.error") {
              if (typeof event.usage !== "undefined") opts.applyUsageFromSession(event.usage);
              const reasoningDiagnostics = formatReasoningDiagnostics(
                (event as { reasoningDiagnostics?: unknown }).reasoningDiagnostics,
              );
              if (reasoningDiagnostics) {
                opts.appendInfoPart(assistantId, reasoningDiagnostics.text, {
                  ...(reasoningDiagnostics.tone ? { _tone: reasoningDiagnostics.tone } : {}),
                  _reasoning: reasoningDiagnostics.state,
                });
              }
              clearThinkingState();
              opts.ensureErrorVisibleInTranscript(assistantId, event.error);
              opts.setAssistantStatus(assistantId, t("chatStatus.error"));
              opts.state.runningAgentRound = false;
              clearPendingAction();
              roundError = new Error(formatAgentErrorForUi(event.error));
            }
          }
        } catch (error) {
          if (!isAbortLikeError(error)) {
            roundError = error instanceof Error ? error : new Error(String(error));
            clearThinkingState();
            opts.ensureErrorVisibleInTranscript(assistantId, error);
            opts.setAssistantStatus(assistantId, t("chatStatus.error"));
          }
        } finally {
          clearSubagentSpinner();
          if (!opts.state.thinking.active || opts.state.thinking.assistantId === assistantId)
            clearThinkingState();
          if (!opts.state.paused && !opts.state.approval.active)
            opts.state.runningAgentRound = false;
          resetActiveRun();
        }
      };

      activeRunPromise = consumeStream();
      await activeRunPromise;
      opts.flushPendingAssistantOutput?.(assistantId);
      if (
        pendingInlinePlanMarkdownPath &&
        !assistantHasMarkdownContent(opts.state.messages as Message[], assistantId)
      ) {
        const inlineMarkdown = await readInlinePlanMarkdown(pendingInlinePlanMarkdownPath);
        const proposedPlanMarkdown = wrapInlinePlanMarkdown(inlineMarkdown ?? "");
        if (proposedPlanMarkdown) opts.appendAssistantMarkdown(assistantId, proposedPlanMarkdown);
      }

      if (roundError) {
        return {
          assistantId,
          toolCalls,
          success: false,
          error: roundError,
        };
      }

      if (
        currentPendingAction &&
        !pendingAction &&
        !opts.state.paused &&
        !sawAssistantDelta &&
        !sawToolOutput
      ) {
        opts.setAssistantStatus(assistantId, t("chatStatus.done"));
      }

      return {
        assistantId,
        toolCalls,
        success: true,
      };
    },
    cancelActiveAgentStream,
    cancelActiveAgentStreamAndWaitWithTimeout,
    abortActiveAgentRound,
  };
}
