// Force strict mode and setup for ESM
"use strict";
import {
  handleAtCommand,
  resolveAtCommandQuery
} from "./chunk-J4TMCUCZ.js";
import {
  isAtCommand,
  isBtwCommand,
  isSlashCommand,
  normalizePartList,
  recordGoalStatusItem
} from "./chunk-H2S47HYW.js";
import {
  SHELL_COMMAND_NAME,
  useSessionStats
} from "./chunk-AR4VP4WD.js";
import {
  require_react
} from "./chunk-KYMBIKIW.js";
import {
  themeManager
} from "./chunk-HTWHAN44.js";
import {
  formatMemoryUsage
} from "./chunk-KHDZHZMH.js";
import {
  isInlineModelOverrideAllowed
} from "./chunk-A76FGLIX.js";
import {
  t
} from "./chunk-RYT2ET4O.js";
import {
  AutonomousLoopTickResolver,
  CoreToolScheduler,
  ShellExecutionService,
  activeGoalEquals,
  clearActiveGoal,
  compactToolResultDisplayForHistory,
  createDuplicateProviderToolCallResponse,
  detectAutonomousSentinel,
  findRepeatedDuplicateProviderToolCall,
  generateToolUseSummary,
  getActiveGoal,
  hasImageParts,
  isBinary,
  markDuplicateProviderToolCallResponseSent,
  parseAndFormatApiError,
  promptIdContext,
  runVisionBridge,
  setActiveGoal,
  shouldRunVisionBridge,
  splitImageParts
} from "./chunk-IQ7FOOIH.js";
import {
  ApiCancelEvent,
  ConversationFinishedEvent,
  UserPromptEvent,
  UserRetryEvent,
  logApiCancel,
  logConversationFinishedEvent,
  logUserPrompt,
  logUserRetry
} from "./chunk-4IUH45NF.js";
import {
  isAnyAutoMemPath
} from "./chunk-MOUXUCXQ.js";
import {
  ToolNames
} from "./chunk-MJKMIQMK.js";
import {
  getUnsupportedImageFormatWarning,
  isSupportedImageMimeType
} from "./chunk-KYTQOCDE.js";
import {
  FinishReason
} from "./chunk-55ZMG67I.js";
import {
  UnauthorizedError,
  createDebugLogger,
  getErrorMessage,
  isNodeError
} from "./chunk-AVQDCKNF.js";
import {
  init_esbuild_shims
} from "./chunk-A4BMJM77.js";
import {
  __name,
  __toESM
} from "./chunk-J2S4EL5Y.js";

// packages/cli/src/dualOutput/DualOutputContext.tsx
init_esbuild_shims();
var import_react = __toESM(require_react(), 1);
var DualOutputContext = (0, import_react.createContext)(null);
function useDualOutput() {
  return (0, import_react.useContext)(DualOutputContext);
}
__name(useDualOutput, "useDualOutput");

// packages/cli/src/utils/midTurnUserMessage.ts
init_esbuild_shims();
var MID_TURN_USER_MESSAGE_PREFIX = "\n[User message received during tool execution]: ";
function prefixMidTurnUserMessageParts(parts, displayText) {
  const partArray = normalizePartList(parts);
  if (partArray.length === 0) {
    return [{ text: `${MID_TURN_USER_MESSAGE_PREFIX}${displayText}` }];
  }
  const [firstPart, ...rest] = partArray;
  if ("text" in firstPart && typeof firstPart.text === "string") {
    return [
      {
        ...firstPart,
        text: `${MID_TURN_USER_MESSAGE_PREFIX}${firstPart.text}`
      },
      ...rest
    ];
  }
  return [
    { text: `${MID_TURN_USER_MESSAGE_PREFIX}${displayText}` },
    ...partArray
  ];
}
__name(prefixMidTurnUserMessageParts, "prefixMidTurnUserMessageParts");

// packages/cli/src/ui/hooks/useGeminiStream.ts
init_esbuild_shims();
var import_react5 = __toESM(require_react(), 1);

// packages/cli/src/ui/hooks/shellCommandProcessor.ts
init_esbuild_shims();
var import_react2 = __toESM(require_react(), 1);
import crypto from "node:crypto";
import path from "node:path";
import os from "node:os";
import fs from "node:fs";
var OUTPUT_UPDATE_INTERVAL_MS = 1e3;
var MAX_OUTPUT_LENGTH = 1e4;
var debugLogger = createDebugLogger("SHELL_COMMAND_PROCESSOR");
function copyString(value) {
  return value.split("").join("");
}
__name(copyString, "copyString");
function addShellCommandToGeminiHistory(geminiClient, rawQuery, resultText) {
  const modelContent = resultText.length > MAX_OUTPUT_LENGTH ? copyString(resultText.substring(0, MAX_OUTPUT_LENGTH)) + "\n... (truncated)" : resultText;
  geminiClient.addHistory({
    role: "user",
    parts: [
      {
        text: `I ran the following shell command:
\`\`\`sh
${rawQuery}
\`\`\`

This produced the following result:
\`\`\`
${modelContent}
\`\`\``
      }
    ]
  });
}
__name(addShellCommandToGeminiHistory, "addShellCommandToGeminiHistory");
var useShellCommandProcessor = /* @__PURE__ */ __name((addItemToHistory, setPendingHistoryItem, onExec, onDebugMessage, config, geminiClient, setShellInputFocused, terminalWidth, terminalHeight) => {
  const [activeShellPtyId, setActiveShellPtyId] = (0, import_react2.useState)(null);
  const handleShellCommand = (0, import_react2.useCallback)(
    (rawQuery, abortSignal) => {
      if (typeof rawQuery !== "string" || rawQuery.trim() === "") {
        return false;
      }
      const userMessageTimestamp = Date.now();
      const callId = `shell-${userMessageTimestamp}`;
      addItemToHistory(
        { type: "user_shell", text: rawQuery },
        userMessageTimestamp
      );
      const isWindows = os.platform() === "win32";
      const targetDir = config.getTargetDir();
      let commandToExecute = rawQuery;
      let pwdFilePath;
      if (!isWindows) {
        let command = rawQuery.trim();
        const pwdFileName = `shell_pwd_${crypto.randomBytes(6).toString("hex")}.tmp`;
        pwdFilePath = path.join(os.tmpdir(), pwdFileName);
        if (!command.endsWith(";") && !command.endsWith("&")) {
          command += ";";
        }
        commandToExecute = `{ ${command} }; __code=$?; pwd > "${pwdFilePath}"; exit $__code`;
      }
      const executeCommand = /* @__PURE__ */ __name(async (resolve2) => {
        let lastUpdateTime = Date.now();
        let cumulativeStdout = "";
        let isBinaryStream = false;
        let binaryBytesReceived = 0;
        const initialToolDisplay = {
          callId,
          name: SHELL_COMMAND_NAME,
          description: rawQuery,
          status: "Executing" /* Executing */,
          resultDisplay: "",
          confirmationDetails: void 0
        };
        setPendingHistoryItem({
          type: "tool_group",
          tools: [initialToolDisplay],
          isUserInitiated: true
        });
        let executionPid;
        const abortHandler = /* @__PURE__ */ __name(() => {
          onDebugMessage(
            `Aborting shell command (PID: ${executionPid ?? "unknown"})`
          );
        }, "abortHandler");
        abortSignal.addEventListener("abort", abortHandler, { once: true });
        onDebugMessage(`Executing in ${targetDir}: ${commandToExecute}`);
        try {
          const activeTheme = themeManager.getActiveTheme();
          const shellExecutionConfig = {
            ...config.getShellExecutionConfig(),
            terminalWidth,
            terminalHeight,
            defaultFg: activeTheme.colors.Foreground,
            defaultBg: activeTheme.colors.Background
          };
          const { pid, result } = await ShellExecutionService.execute(
            commandToExecute,
            targetDir,
            (event) => {
              let shouldUpdate = false;
              switch (event.type) {
                case "data":
                  if (isBinaryStream) break;
                  if (config.getShouldUseNodePtyShell()) {
                    cumulativeStdout = event.chunk;
                    shouldUpdate = true;
                  } else if (typeof event.chunk === "string" && typeof cumulativeStdout === "string") {
                    cumulativeStdout += event.chunk;
                  }
                  break;
                case "binary_detected":
                  isBinaryStream = true;
                  shouldUpdate = true;
                  break;
                case "binary_progress":
                  isBinaryStream = true;
                  binaryBytesReceived = event.bytesReceived;
                  break;
                default: {
                  throw new Error("An unhandled ShellOutputEvent was found.");
                }
              }
              let currentDisplayOutput;
              if (isBinaryStream) {
                if (binaryBytesReceived > 0) {
                  currentDisplayOutput = `[Receiving binary output... ${formatMemoryUsage(
                    binaryBytesReceived
                  )} received]`;
                } else {
                  currentDisplayOutput = "[Binary output detected. Halting stream...]";
                }
              } else {
                currentDisplayOutput = cumulativeStdout;
              }
              if (shouldUpdate || Date.now() - lastUpdateTime > OUTPUT_UPDATE_INTERVAL_MS) {
                setPendingHistoryItem((prevItem) => {
                  if (prevItem?.type === "tool_group") {
                    return {
                      ...prevItem,
                      tools: prevItem.tools.map(
                        (tool) => tool.callId === callId ? {
                          ...tool,
                          resultDisplay: typeof currentDisplayOutput === "string" ? compactToolResultDisplayForHistory(
                            currentDisplayOutput
                          ) : compactToolResultDisplayForHistory({
                            ansiOutput: currentDisplayOutput
                          })
                        } : tool
                      )
                    };
                  }
                  return prevItem;
                });
                lastUpdateTime = Date.now();
              }
            },
            abortSignal,
            config.getShouldUseNodePtyShell(),
            shellExecutionConfig
          );
          debugLogger.debug(terminalHeight, terminalWidth);
          executionPid = pid;
          if (pid) {
            setActiveShellPtyId(pid);
            setPendingHistoryItem((prevItem) => {
              if (prevItem?.type === "tool_group") {
                return {
                  ...prevItem,
                  tools: prevItem.tools.map(
                    (tool) => tool.callId === callId ? { ...tool, ptyId: pid } : tool
                  )
                };
              }
              return prevItem;
            });
          }
          result.then((result2) => {
            setPendingHistoryItem(null);
            let mainContent;
            if (isBinary(result2.rawOutput)) {
              mainContent = "[Command produced binary output, which is not shown.]";
            } else {
              mainContent = result2.output.trim() || "(Command produced no output)";
            }
            let finalOutput = mainContent;
            let finalStatus = "Success" /* Success */;
            if (result2.error) {
              finalStatus = "Error" /* Error */;
              finalOutput = `${result2.error.message}
${finalOutput}`;
            } else if (result2.aborted) {
              finalStatus = "Canceled" /* Canceled */;
              finalOutput = `Command was cancelled.
${finalOutput}`;
            } else if (result2.signal) {
              finalStatus = "Error" /* Error */;
              finalOutput = `Command terminated by signal: ${result2.signal}.
${finalOutput}`;
            } else if (result2.exitCode !== 0) {
              finalStatus = "Error" /* Error */;
              finalOutput = `Command exited with code ${result2.exitCode}.
${finalOutput}`;
            }
            if (pwdFilePath && fs.existsSync(pwdFilePath)) {
              const finalPwd = fs.readFileSync(pwdFilePath, "utf8").trim();
              if (finalPwd && finalPwd !== targetDir) {
                const warning = `WARNING: shell mode is stateless; the directory change to '${finalPwd}' will not persist.`;
                finalOutput = `${warning}

${finalOutput}`;
              }
            }
            const finalToolDisplay = {
              ...initialToolDisplay,
              status: finalStatus,
              resultDisplay: compactToolResultDisplayForHistory(finalOutput)
            };
            addItemToHistory(
              {
                type: "tool_group",
                tools: [finalToolDisplay],
                isUserInitiated: true
              },
              userMessageTimestamp
            );
            addShellCommandToGeminiHistory(
              geminiClient,
              rawQuery,
              finalOutput
            );
          }).catch((err) => {
            setPendingHistoryItem(null);
            const errorMessage = err instanceof Error ? err.message : String(err);
            addItemToHistory(
              {
                type: "error",
                text: `An unexpected error occurred: ${errorMessage}`
              },
              userMessageTimestamp
            );
          }).finally(() => {
            abortSignal.removeEventListener("abort", abortHandler);
            if (pwdFilePath && fs.existsSync(pwdFilePath)) {
              fs.unlinkSync(pwdFilePath);
            }
            setActiveShellPtyId(null);
            setShellInputFocused(false);
            resolve2();
          });
        } catch (err) {
          setPendingHistoryItem(null);
          const errorMessage = err instanceof Error ? err.message : String(err);
          addItemToHistory(
            {
              type: "error",
              text: `An unexpected error occurred: ${errorMessage}`
            },
            userMessageTimestamp
          );
          if (pwdFilePath && fs.existsSync(pwdFilePath)) {
            fs.unlinkSync(pwdFilePath);
          }
          setActiveShellPtyId(null);
          setShellInputFocused(false);
          resolve2();
        }
      }, "executeCommand");
      const execPromise = new Promise((resolve2) => {
        executeCommand(resolve2);
      });
      onExec(execPromise);
      return true;
    },
    [
      config,
      onDebugMessage,
      addItemToHistory,
      setPendingHistoryItem,
      onExec,
      geminiClient,
      setShellInputFocused,
      terminalHeight,
      terminalWidth
    ]
  );
  return { handleShellCommand, activeShellPtyId };
}, "useShellCommandProcessor");

// packages/cli/src/ui/utils/markdownUtilities.ts
init_esbuild_shims();
var isIndexInsideCodeBlock = /* @__PURE__ */ __name((content, indexToTest) => {
  let fenceCount = 0;
  let searchPos = 0;
  while (searchPos < content.length) {
    const nextFence = content.indexOf("```", searchPos);
    if (nextFence === -1 || nextFence >= indexToTest) {
      break;
    }
    fenceCount++;
    searchPos = nextFence + 3;
  }
  return fenceCount % 2 === 1;
}, "isIndexInsideCodeBlock");
var findEnclosingCodeBlockStart = /* @__PURE__ */ __name((content, index) => {
  if (!isIndexInsideCodeBlock(content, index)) {
    return -1;
  }
  let currentSearchPos = 0;
  while (currentSearchPos < index) {
    const blockStartIndex = content.indexOf("```", currentSearchPos);
    if (blockStartIndex === -1 || blockStartIndex >= index) {
      break;
    }
    const blockEndIndex = content.indexOf("```", blockStartIndex + 3);
    if (blockStartIndex < index) {
      if (blockEndIndex === -1 || index < blockEndIndex + 3) {
        return blockStartIndex;
      }
    }
    if (blockEndIndex === -1) break;
    currentSearchPos = blockEndIndex + 3;
  }
  return -1;
}, "findEnclosingCodeBlockStart");
var findLastSafeSplitPoint = /* @__PURE__ */ __name((content, idealMaxLength) => {
  const hasLengthCap = idealMaxLength !== void 0;
  const searchEnd = hasLengthCap ? Math.min(Math.max(idealMaxLength, 0), content.length) : content.length;
  if (hasLengthCap && content.length <= searchEnd) {
    return content.length;
  }
  const enclosingBlockStart = findEnclosingCodeBlockStart(content, searchEnd);
  if (enclosingBlockStart !== -1) {
    return hasLengthCap && enclosingBlockStart === 0 ? searchEnd : enclosingBlockStart;
  }
  let searchStartIndex = searchEnd;
  while (searchStartIndex >= 0) {
    const dnlIndex = content.lastIndexOf("\n\n", searchStartIndex);
    if (dnlIndex === -1) {
      break;
    }
    const potentialSplitPoint = dnlIndex + 2;
    if (potentialSplitPoint <= searchEnd && !isIndexInsideCodeBlock(content, potentialSplitPoint)) {
      return potentialSplitPoint;
    }
    searchStartIndex = dnlIndex - 1;
  }
  if (hasLengthCap) {
    searchStartIndex = searchEnd;
    while (searchStartIndex >= 0) {
      const nlIndex = content.lastIndexOf("\n", searchStartIndex);
      if (nlIndex === -1) {
        break;
      }
      const potentialSplitPoint = nlIndex + 1;
      if (potentialSplitPoint <= searchEnd && !isIndexInsideCodeBlock(content, potentialSplitPoint)) {
        return potentialSplitPoint;
      }
      searchStartIndex = nlIndex - 1;
    }
  }
  return hasLengthCap ? searchEnd : content.length;
}, "findLastSafeSplitPoint");

// packages/cli/src/ui/hooks/useStateAndRef.ts
init_esbuild_shims();
var import_react3 = __toESM(require_react(), 1);
var useStateAndRef = /* @__PURE__ */ __name((initialValue) => {
  const [state, setState] = import_react3.default.useState(initialValue);
  const ref = import_react3.default.useRef(initialValue);
  const setStateInternal = import_react3.default.useCallback(
    (newStateOrCallback) => {
      let newValue;
      if (typeof newStateOrCallback === "function") {
        newValue = newStateOrCallback(ref.current);
      } else {
        newValue = newStateOrCallback;
      }
      setState(newValue);
      ref.current = newValue;
    },
    []
  );
  return [state, ref, setStateInternal];
}, "useStateAndRef");

// packages/cli/src/ui/hooks/useReactToolScheduler.ts
init_esbuild_shims();
var import_react4 = __toESM(require_react(), 1);
import * as path2 from "node:path";
var debugLogger2 = createDebugLogger("REACT_TOOL_SCHEDULER");
function useReactToolScheduler(onComplete, config, getPreferredEditor, onEditorClose) {
  const [toolCallsForDisplay, setToolCallsForDisplay] = (0, import_react4.useState)([]);
  const outputUpdateHandler = (0, import_react4.useCallback)(
    (toolCallId, outputChunk) => {
      const compactOutput = compactToolResultDisplayForHistory(outputChunk);
      setToolCallsForDisplay(
        (prevCalls) => prevCalls.map((tc) => {
          if (tc.request.callId === toolCallId && tc.status === "executing") {
            const executingTc = tc;
            return { ...executingTc, liveOutput: compactOutput };
          }
          return tc;
        })
      );
    },
    []
  );
  const allToolCallsCompleteHandler = (0, import_react4.useCallback)(
    async (completedToolCalls) => {
      await onComplete(completedToolCalls);
    },
    [onComplete]
  );
  const toolCallsUpdateHandler = (0, import_react4.useCallback)(
    (updatedCoreToolCalls) => {
      setToolCallsForDisplay(
        (prevTrackedCalls) => updatedCoreToolCalls.map((coreTc) => {
          const existingTrackedCall = prevTrackedCalls.find(
            (ptc) => ptc.request.callId === coreTc.request.callId
          );
          const responseSubmittedToGemini = existingTrackedCall?.responseSubmittedToGemini ?? false;
          if (coreTc.status === "executing") {
            return {
              ...coreTc,
              responseSubmittedToGemini,
              liveOutput: existingTrackedCall?.liveOutput
            };
          }
          return {
            ...coreTc,
            responseSubmittedToGemini,
            liveOutput: void 0,
            pid: void 0,
            promoteAbortController: void 0
          };
        })
      );
    },
    [setToolCallsForDisplay]
  );
  const scheduler = (0, import_react4.useMemo)(
    () => new CoreToolScheduler({
      config,
      chatRecordingService: config.getChatRecordingService(),
      outputUpdateHandler,
      onAllToolCallsComplete: allToolCallsCompleteHandler,
      onToolCallsUpdate: toolCallsUpdateHandler,
      getPreferredEditor,
      onEditorClose
    }),
    [
      config,
      outputUpdateHandler,
      allToolCallsCompleteHandler,
      toolCallsUpdateHandler,
      getPreferredEditor,
      onEditorClose
    ]
  );
  const schedule = (0, import_react4.useCallback)(
    (request, signal) => {
      void scheduler.schedule(request, signal);
    },
    [scheduler]
  );
  const markToolsAsSubmitted = (0, import_react4.useCallback)(
    (callIdsToMark) => {
      setToolCallsForDisplay(
        (prevCalls) => prevCalls.map(
          (tc) => callIdsToMark.includes(tc.request.callId) ? { ...tc, responseSubmittedToGemini: true } : tc
        )
      );
    },
    []
  );
  return [toolCallsForDisplay, schedule, markToolsAsSubmitted];
}
__name(useReactToolScheduler, "useReactToolScheduler");
function mapCoreStatusToDisplayStatus(coreStatus) {
  switch (coreStatus) {
    case "validating":
      return "Executing" /* Executing */;
    case "awaiting_approval":
      return "Confirming" /* Confirming */;
    case "executing":
      return "Executing" /* Executing */;
    case "success":
      return "Success" /* Success */;
    case "cancelled":
      return "Canceled" /* Canceled */;
    case "error":
      return "Error" /* Error */;
    case "scheduled":
      return "Pending" /* Pending */;
    default: {
      const exhaustiveCheck = coreStatus;
      debugLogger2.warn(`Unknown core status encountered: ${exhaustiveCheck}`);
      return "Error" /* Error */;
    }
  }
}
__name(mapCoreStatusToDisplayStatus, "mapCoreStatusToDisplayStatus");
function detectMemoryOp(toolName, args, projectRoot) {
  const WRITE_TOOLS = /* @__PURE__ */ new Set(["write_file", "edit"]);
  const READ_TOOLS = /* @__PURE__ */ new Set(["read_file"]);
  const filePath = args?.["file_path"];
  if (!filePath) return void 0;
  const resolved = path2.resolve(filePath);
  if (!isAnyAutoMemPath(resolved, projectRoot)) return void 0;
  if (WRITE_TOOLS.has(toolName)) return "write";
  if (READ_TOOLS.has(toolName)) return "read";
  return void 0;
}
__name(detectMemoryOp, "detectMemoryOp");
function mapToDisplay(toolOrTools, projectRoot) {
  const toolCalls = Array.isArray(toolOrTools) ? toolOrTools : [toolOrTools];
  const toolDisplays = toolCalls.map(
    (trackedCall) => {
      let displayName;
      let description;
      let renderOutputAsMarkdown = false;
      if (trackedCall.status === "error") {
        displayName = trackedCall.tool === void 0 ? trackedCall.request.name : trackedCall.tool.displayName;
        description = JSON.stringify(trackedCall.request.args);
      } else {
        displayName = trackedCall.tool.displayName;
        description = trackedCall.invocation.getDescription();
        renderOutputAsMarkdown = trackedCall.tool.isOutputMarkdown;
      }
      const baseDisplayProperties = {
        callId: trackedCall.request.callId,
        name: displayName,
        description,
        renderOutputAsMarkdown,
        isMemoryOp: projectRoot && trackedCall.status !== "error" ? detectMemoryOp(
          trackedCall.request.name,
          trackedCall.request.args,
          projectRoot
        ) : void 0
      };
      switch (trackedCall.status) {
        case "success":
          return {
            ...baseDisplayProperties,
            status: mapCoreStatusToDisplayStatus(trackedCall.status),
            resultDisplay: compactToolResultDisplayForHistory(
              trackedCall.response.resultDisplay
            ),
            confirmationDetails: void 0
          };
        case "error":
          return {
            ...baseDisplayProperties,
            status: mapCoreStatusToDisplayStatus(trackedCall.status),
            resultDisplay: compactToolResultDisplayForHistory(
              trackedCall.response.resultDisplay
            ),
            confirmationDetails: void 0
          };
        case "cancelled":
          return {
            ...baseDisplayProperties,
            status: mapCoreStatusToDisplayStatus(trackedCall.status),
            resultDisplay: compactToolResultDisplayForHistory(
              trackedCall.response.resultDisplay
            ),
            confirmationDetails: void 0
          };
        case "awaiting_approval":
          return {
            ...baseDisplayProperties,
            status: mapCoreStatusToDisplayStatus(trackedCall.status),
            resultDisplay: void 0,
            confirmationDetails: trackedCall.confirmationDetails
          };
        case "executing":
          return {
            ...baseDisplayProperties,
            status: mapCoreStatusToDisplayStatus(trackedCall.status),
            resultDisplay: trackedCall.liveOutput ?? void 0,
            confirmationDetails: void 0,
            ptyId: trackedCall.pid,
            executionStartTime: trackedCall.executionStartTime
          };
        case "validating":
        // Fallthrough
        case "scheduled":
          return {
            ...baseDisplayProperties,
            status: mapCoreStatusToDisplayStatus(trackedCall.status),
            resultDisplay: void 0,
            confirmationDetails: void 0
          };
        default: {
          const exhaustiveCheck = trackedCall;
          return {
            callId: exhaustiveCheck.request.callId,
            name: "Unknown Tool",
            description: "Encountered an unknown tool call state.",
            status: "Error" /* Error */,
            resultDisplay: "Unknown tool call state",
            confirmationDetails: void 0,
            renderOutputAsMarkdown: false
          };
        }
      }
    }
  );
  return {
    type: "tool_group",
    tools: toolDisplays,
    memoryWriteCount: toolDisplays.filter((t2) => t2.isMemoryOp === "write").length || void 0,
    memoryReadCount: toolDisplays.filter((t2) => t2.isMemoryOp === "read").length || void 0
  };
}
__name(mapToDisplay, "mapToDisplay");

// packages/cli/src/ui/hooks/useGeminiStream.ts
import { promises as fs2 } from "node:fs";
import path3 from "node:path";
import process from "node:process";
var debugLogger3 = createDebugLogger("GEMINI_STREAM");
function applyModelOverride(modelOverrideRef, inlineActiveRef, value, isInline) {
  modelOverrideRef.current = value;
  inlineActiveRef.current = isInline;
  debugLogger3.debug(
    `model override ${value === void 0 ? "cleared" : `set to ${value}`} (inline=${isInline})`
  );
}
__name(applyModelOverride, "applyModelOverride");
function clearModelOverride(modelOverrideRef, inlineActiveRef) {
  applyModelOverride(modelOverrideRef, inlineActiveRef, void 0, false);
}
__name(clearModelOverride, "clearModelOverride");
var MID_TURN_AT_COMMAND_RESOLVE_TIMEOUT_MS = 1e4;
var MID_TURN_AT_COMMAND_RESOLVE_TIMEOUT_MESSAGE = "Mid-turn @ command resolution timed out";
function formatVisionBridgeNotice(result) {
  const modelName = result.modelId ?? "vision model";
  const target = result.modelEndpoint ? `${modelName} (${result.modelEndpoint})` : modelName;
  const egressNote = result.egressOccurred ? ` Your image and prompt/context were sent to ${target}.` : "";
  if (result.status === "failed") {
    const reason = result.egressOccurred ? "the vision model request failed" : "the vision bridge could not run";
    return `Vision bridge (${modelName}) failed: ${reason}.${egressNote} The image was not interpreted.`;
  }
  if (result.status === "skipped") {
    return `Vision bridge cancelled.${egressNote}`;
  }
  const omitted = result.omittedCount > 0 ? ` (${result.omittedCount} image(s) omitted)` : "";
  const header = `Converted ${result.convertedCount} image(s)${omitted} to text via ${target}. Your image and prompt/context were sent to that model.`;
  return header;
}
__name(formatVisionBridgeNotice, "formatVisionBridgeNotice");
function extractLastAssistantText(history) {
  for (let i = history.length - 1; i >= 0; i--) {
    const item = history[i];
    if ((item.type === "gemini" || item.type === "gemini_content") && typeof item.text === "string" && item.text.trim().length > 0) {
      return item.text;
    }
  }
  return void 0;
}
__name(extractLastAssistantText, "extractLastAssistantText");
function stripLeadingBlankLines(text) {
  return text.replace(/^(?:[ \t]*\r?\n)+/, "");
}
__name(stripLeadingBlankLines, "stripLeadingBlankLines");
async function resolveWithAbort(signal, run) {
  let onAbort;
  const abortPromise = new Promise((_, reject) => {
    onAbort = /* @__PURE__ */ __name(() => {
      reject(
        signal.reason instanceof Error ? signal.reason : new Error("Mid-turn @ command resolution aborted")
      );
    }, "onAbort");
    if (signal.aborted) {
      onAbort();
      return;
    }
    signal.addEventListener("abort", onAbort, { once: true });
  });
  try {
    return await Promise.race([run(), abortPromise]);
  } finally {
    if (onAbort) {
      signal.removeEventListener("abort", onAbort);
    }
  }
}
__name(resolveWithAbort, "resolveWithAbort");
function extractToolResultText(parts) {
  if (!parts) return "";
  const list = Array.isArray(parts) ? parts : [parts];
  const chunks = [];
  for (const part of list) {
    if ("functionResponse" in part && part.functionResponse) {
      const response = part.functionResponse.response;
      if (response !== void 0) chunks.push(response);
    } else if ("text" in part && typeof part.text === "string") {
      chunks.push(part.text);
    }
  }
  if (chunks.length === 0) return "";
  if (chunks.length === 1) return chunks[0];
  return chunks;
}
__name(extractToolResultText, "extractToolResultText");
function classifyApiError(error) {
  const status = error.status;
  const message = error.message?.toLowerCase() ?? "";
  if (status === 429 || message.includes("rate limit")) {
    return "rate_limit";
  }
  if (status === 401 || message.includes("unauthorized")) {
    return "authentication_failed";
  }
  if (status === 402 || status === 403 || message.includes("billing") || message.includes("quota")) {
    return "billing_error";
  }
  if (status === 400 || message.includes("invalid")) {
    return "invalid_request";
  }
  if (status !== void 0 && status >= 500) {
    return "server_error";
  }
  if (message.includes("max_tokens") || message.includes("token limit")) {
    return "max_output_tokens";
  }
  return "unknown";
}
__name(classifyApiError, "classifyApiError");
function checkImageFormatsSupport(parts) {
  const unsupportedMimeTypes = [];
  let hasImages = false;
  if (typeof parts === "string") {
    return {
      hasImages: false,
      hasUnsupportedFormats: false,
      unsupportedMimeTypes: []
    };
  }
  const partsArray = Array.isArray(parts) ? parts : [parts];
  for (const part of partsArray) {
    if (typeof part === "string") continue;
    let mimeType;
    if ("inlineData" in part && part.inlineData?.mimeType?.startsWith("image/")) {
      hasImages = true;
      mimeType = part.inlineData.mimeType;
    }
    if ("fileData" in part && part.fileData?.mimeType?.startsWith("image/")) {
      hasImages = true;
      mimeType = part.fileData.mimeType;
    }
    if (mimeType && !isSupportedImageMimeType(mimeType)) {
      unsupportedMimeTypes.push(mimeType);
    }
  }
  return {
    hasImages,
    hasUnsupportedFormats: unsupportedMimeTypes.length > 0,
    unsupportedMimeTypes
  };
}
__name(checkImageFormatsSupport, "checkImageFormatsSupport");
var EDIT_TOOL_NAMES = /* @__PURE__ */ new Set([
  ToolNames.EDIT,
  "replace",
  // legacy alias, may still arrive from older providers
  ToolNames.WRITE_FILE,
  ToolNames.NOTEBOOK_EDIT
]);
var STREAM_UPDATE_THROTTLE_MS = 60;
var STREAM_PENDING_ITEM_MAX_CHARS = 16384;
var LOADING_THOUGHT_DESCRIPTION_MAX_CHARS = 4096;
function showCitations(settings) {
  const enabled = settings?.merged?.ui?.showCitations;
  if (enabled !== void 0) {
    return enabled;
  }
  return true;
}
__name(showCitations, "showCitations");
function clampLoadingThoughtDescription(description) {
  if (description.length <= LOADING_THOUGHT_DESCRIPTION_MAX_CHARS) {
    return description;
  }
  return description.slice(0, LOADING_THOUGHT_DESCRIPTION_MAX_CHARS);
}
__name(clampLoadingThoughtDescription, "clampLoadingThoughtDescription");
var useGeminiStream = /* @__PURE__ */ __name((geminiClient, history, addItem, config, isConfigInitialized, settings, onDebugMessage, handleSlashCommand, shellModeActive, getPreferredEditor, onAuthError, performMemoryRefresh, modelSwitchedFromQuotaError, setModelSwitchedFromQuotaError, onEditorClose, onCancelSubmit, setShellInputFocused, terminalWidth, terminalHeight, midTurnDrainRef, logger) => {
  const [initError, setInitError] = (0, import_react5.useState)(null);
  const abortControllerRef = (0, import_react5.useRef)(null);
  const flushBufferedStreamEventsRef = (0, import_react5.useRef)(/* @__PURE__ */ new Set());
  const turnCancelledRef = (0, import_react5.useRef)(false);
  const isSubmittingQueryRef = (0, import_react5.useRef)(false);
  const lastPromptRef = (0, import_react5.useRef)(null);
  const lastTurnUserItemRef = (0, import_react5.useRef)(null);
  const turnSawContentEventRef = (0, import_react5.useRef)(false);
  const lastPromptErroredRef = (0, import_react5.useRef)(false);
  const commitItem = (0, import_react5.useCallback)(
    (item, userMessageTimestamp) => {
      if (item.type === "gemini" && !item.timestamp) {
        item.timestamp = Date.now();
      }
      return addItem(item, userMessageTimestamp);
    },
    [addItem]
  );
  const dualOutput = useDualOutput();
  const [isResponding, setIsResponding] = (0, import_react5.useState)(false);
  const activeModelStreamsRef = (0, import_react5.useRef)(0);
  const [thought, setThought] = (0, import_react5.useState)(null);
  const historyRef = (0, import_react5.useRef)(history);
  (0, import_react5.useLayoutEffect)(() => {
    historyRef.current = history;
  }, [history]);
  const auxiliaryAbortRefsRef = (0, import_react5.useRef)(/* @__PURE__ */ new Set());
  const [pendingHistoryItem, pendingHistoryItemRef, setPendingHistoryItem] = useStateAndRef(null);
  const [pendingThoughtItem, pendingThoughtItemRef, setPendingThoughtItem] = useStateAndRef(null);
  const thoughtStartTimeRef = (0, import_react5.useRef)(null);
  const [
    pendingRetryErrorItem,
    pendingRetryErrorItemRef,
    setPendingRetryErrorItem
  ] = useStateAndRef(null);
  const [
    pendingRetryCountdownItem,
    pendingRetryCountdownItemRef,
    setPendingRetryCountdownItem
  ] = useStateAndRef(null);
  const retryCountdownTimerRef = (0, import_react5.useRef)(
    null
  );
  const processedMemoryToolsRef = (0, import_react5.useRef)(/* @__PURE__ */ new Set());
  const submitPromptOnCompleteRef = (0, import_react5.useRef)(null);
  const modelOverrideRef = (0, import_react5.useRef)(void 0);
  const inlineModelOverrideActiveRef = (0, import_react5.useRef)(false);
  const handledProviderToolCallIdsRef = (0, import_react5.useRef)(/* @__PURE__ */ new Set());
  const duplicateProviderToolCallResponseIdsRef = (0, import_react5.useRef)(
    /* @__PURE__ */ new Set()
  );
  const pendingDuplicateToolResponsesRef = (0, import_react5.useRef)([]);
  const immediateDuplicateToolResponsesRef = (0, import_react5.useRef)(null);
  const streamingResponseLengthRef = (0, import_react5.useRef)(0);
  const [isReceivingContent, setIsReceivingContent] = (0, import_react5.useState)(false);
  const {
    startNewPrompt,
    getPromptCount,
    stats: sessionStates
  } = useSessionStats();
  const storage = config.storage;
  const [toolCalls, scheduleToolCalls, markToolsAsSubmitted] = useReactToolScheduler(
    async (completedToolCallsFromScheduler) => {
      if (completedToolCallsFromScheduler.length > 0) {
        const projectRoot = config.getProjectRoot();
        const toolGroupDisplay = mapToDisplay(
          completedToolCallsFromScheduler,
          projectRoot
        );
        addItem(toolGroupDisplay, Date.now());
        await handleCompletedTools(
          completedToolCallsFromScheduler
        );
      }
    },
    config,
    getPreferredEditor,
    onEditorClose
  );
  const pendingToolCallGroupDisplay = (0, import_react5.useMemo)(
    () => toolCalls.length ? mapToDisplay(toolCalls, config.getProjectRoot()) : void 0,
    [toolCalls, config]
  );
  const activeToolPtyId = (0, import_react5.useMemo)(() => {
    const executingShellTool = toolCalls?.find(
      (tc) => tc.status === "executing" && tc.request.name === "run_shell_command"
    );
    if (executingShellTool) {
      return executingShellTool.pid;
    }
    return void 0;
  }, [toolCalls]);
  const loopDetectedRef = (0, import_react5.useRef)(false);
  const [
    loopDetectionConfirmationRequest,
    setLoopDetectionConfirmationRequest
  ] = (0, import_react5.useState)(null);
  const stopRetryCountdownTimer = (0, import_react5.useCallback)(() => {
    if (retryCountdownTimerRef.current) {
      clearInterval(retryCountdownTimerRef.current);
      retryCountdownTimerRef.current = null;
    }
  }, []);
  const clearRetryCountdown = (0, import_react5.useCallback)(() => {
    stopRetryCountdownTimer();
    skipRetryDelayRef.current = null;
    setPendingRetryErrorItem(null);
    setPendingRetryCountdownItem(null);
  }, [
    setPendingRetryErrorItem,
    setPendingRetryCountdownItem,
    stopRetryCountdownTimer
  ]);
  const skipRetryDelayRef = (0, import_react5.useRef)(null);
  const startRetryCountdown = (0, import_react5.useCallback)(
    (retryInfo) => {
      stopRetryCountdownTimer();
      skipRetryDelayRef.current = retryInfo.skipDelay;
      const startTime = Date.now();
      const { message, attempt, maxRetries, delayMs } = retryInfo;
      const retryReasonText = message ?? t("Rate limit exceeded. Please wait and try again.");
      const updateCountdown = /* @__PURE__ */ __name(() => {
        const elapsedMs = Date.now() - startTime;
        const remainingMs = Math.max(0, delayMs - elapsedMs);
        const remainingSec = Math.ceil(remainingMs / 1e3);
        const hintText = `Retrying in ${remainingSec}s\u2026 (attempt ${attempt}/${maxRetries})`;
        setPendingRetryErrorItem({
          type: "error" /* ERROR */,
          text: retryReasonText,
          hint: hintText
        });
        setPendingRetryCountdownItem({
          type: "retry_countdown",
          text: t(
            "Retrying in {{seconds}} seconds\u2026 (attempt {{attempt}}/{{maxRetries}})",
            {
              seconds: String(remainingSec),
              attempt: String(attempt),
              maxRetries: String(maxRetries)
            }
          )
        });
        if (remainingMs <= 0) {
          stopRetryCountdownTimer();
        }
      }, "updateCountdown");
      updateCountdown();
      retryCountdownTimerRef.current = setInterval(updateCountdown, 1e3);
    },
    [
      setPendingRetryErrorItem,
      setPendingRetryCountdownItem,
      stopRetryCountdownTimer
    ]
  );
  (0, import_react5.useEffect)(() => () => stopRetryCountdownTimer(), [stopRetryCountdownTimer]);
  const onExec = (0, import_react5.useCallback)(async (done) => {
    setIsResponding(true);
    await done;
    setIsResponding(false);
  }, []);
  const { handleShellCommand, activeShellPtyId } = useShellCommandProcessor(
    addItem,
    setPendingHistoryItem,
    onExec,
    onDebugMessage,
    config,
    geminiClient,
    setShellInputFocused,
    terminalWidth,
    terminalHeight
  );
  const activePtyId = activeShellPtyId || activeToolPtyId;
  (0, import_react5.useEffect)(() => {
    if (!activePtyId) {
      setShellInputFocused(false);
    }
  }, [activePtyId, setShellInputFocused]);
  const streamingState = (0, import_react5.useMemo)(() => {
    if (toolCalls.some((tc) => tc.status === "awaiting_approval")) {
      return "waiting_for_confirmation" /* WaitingForConfirmation */;
    }
    if (toolCalls.some((tc) => {
      if (tc.status !== "executing") return false;
      const liveOutput = tc.liveOutput;
      return typeof liveOutput === "object" && liveOutput !== null && "type" in liveOutput && liveOutput.type === "task_execution" && "pendingConfirmation" in liveOutput && liveOutput.pendingConfirmation != null;
    })) {
      return "waiting_for_confirmation" /* WaitingForConfirmation */;
    }
    if (isResponding || toolCalls.some(
      (tc) => tc.status === "executing" || tc.status === "scheduled" || tc.status === "validating" || (tc.status === "success" || tc.status === "error" || tc.status === "cancelled") && !tc.responseSubmittedToGemini
    )) {
      return "responding" /* Responding */;
    }
    return "idle" /* Idle */;
  }, [isResponding, toolCalls]);
  (0, import_react5.useEffect)(() => {
    if (config.getApprovalMode() === "yolo" /* YOLO */ && streamingState === "idle" /* Idle */) {
      const lastUserMessageIndex = history.findLastIndex(
        (item) => item.type === "user" /* USER */
      );
      const turnCount = lastUserMessageIndex === -1 ? 0 : history.length - lastUserMessageIndex;
      if (turnCount > 0) {
        logConversationFinishedEvent(
          config,
          new ConversationFinishedEvent(config.getApprovalMode(), turnCount)
        );
      }
    }
  }, [streamingState, config, history]);
  const cancelOngoingRequest = (0, import_react5.useCallback)(() => {
    if (streamingState !== "responding" /* Responding */) {
      return;
    }
    if (turnCancelledRef.current) {
      return;
    }
    for (const flushBufferedStreamEvents of flushBufferedStreamEventsRef.current) {
      flushBufferedStreamEvents();
    }
    const pendingItemAtCancel = pendingHistoryItemRef.current;
    turnCancelledRef.current = true;
    isSubmittingQueryRef.current = false;
    abortControllerRef.current?.abort();
    const loopWakeupsCancelled = config.getCronScheduler()?.cancelAllWakeups() ?? 0;
    for (const ac of auxiliaryAbortRefsRef.current) {
      ac.abort();
    }
    auxiliaryAbortRefsRef.current.clear();
    config.getArenaAgentClient()?.reportCancelled();
    const prompt_id = config.getSessionId() + "########" + getPromptCount();
    const cancellationEvent = new ApiCancelEvent(
      modelOverrideRef.current ?? config.getModel(),
      prompt_id,
      config.getContentGeneratorConfig()?.authType,
      loopWakeupsCancelled > 0 ? loopWakeupsCancelled : void 0
    );
    logApiCancel(config, cancellationEvent);
    if (pendingHistoryItemRef.current) {
      commitItem(pendingHistoryItemRef.current, Date.now());
    }
    addItem(
      {
        type: "info" /* INFO */,
        text: "Request cancelled."
      },
      Date.now()
    );
    if (loopWakeupsCancelled > 0) {
      addItem(
        {
          type: "info" /* INFO */,
          text: `Stopped the self-paced loop: cancelled ${loopWakeupsCancelled} pending wakeup${loopWakeupsCancelled === 1 ? "" : "s"}.`
        },
        Date.now()
      );
    }
    setPendingHistoryItem(null);
    clearRetryCountdown();
    try {
      onCancelSubmit({
        pendingItem: pendingItemAtCancel,
        lastTurnUserItem: lastTurnUserItemRef.current,
        turnProducedMeaningfulContent: turnSawContentEventRef.current
      });
    } finally {
      setIsResponding(false);
      setShellInputFocused(false);
    }
  }, [
    streamingState,
    addItem,
    commitItem,
    setPendingHistoryItem,
    onCancelSubmit,
    pendingHistoryItemRef,
    setShellInputFocused,
    clearRetryCountdown,
    config,
    getPromptCount
  ]);
  const applyVisionBridgeIfNeeded = (0, import_react5.useCallback)(
    async (parts, timestamp, signal) => {
      if (parts === null || !hasImageParts(parts) || !shouldRunVisionBridge(config)) {
        return { parts, shouldProceed: true };
      }
      debugLogger3.debug("vision bridge: gate matched, running conversion");
      const bridgeResult = await runVisionBridge({ config, parts, signal });
      debugLogger3.debug(
        `vision bridge: status=${bridgeResult.status} applied=${bridgeResult.applied} model=${bridgeResult.modelId ?? "(none)"}`
      );
      if (bridgeResult.status !== "skipped" || bridgeResult.egressOccurred) {
        addItem(
          {
            type: bridgeResult.status === "failed" ? "error" /* ERROR */ : "vision_notice" /* VISION_NOTICE */,
            text: formatVisionBridgeNotice(bridgeResult)
          },
          timestamp
        );
      }
      if (signal.aborted) {
        return { parts: null, shouldProceed: false };
      }
      if (bridgeResult.applied && bridgeResult.parts != null) {
        return { parts: bridgeResult.parts, shouldProceed: true };
      }
      const textOnly = splitImageParts(parts).nonImageParts;
      return textOnly.length > 0 ? { parts: textOnly, shouldProceed: true } : { parts: null, shouldProceed: false };
    },
    [addItem, config]
  );
  const prepareQueryForGemini = (0, import_react5.useCallback)(
    async (query, userMessageTimestamp, abortSignal, prompt_id, submitType) => {
      if (turnCancelledRef.current) {
        return { queryToSend: null, shouldProceed: false };
      }
      if (typeof query === "string" && query.trim().length === 0) {
        return { queryToSend: null, shouldProceed: false };
      }
      lastTurnUserItemRef.current = null;
      let localQueryToSendToGemini = null;
      if (typeof query === "string") {
        const trimmedQuery = query.trim();
        if (submitType === "notification" /* Notification */) {
          onDebugMessage(
            `Received notification (${trimmedQuery.length} chars)`
          );
          return { queryToSend: trimmedQuery, shouldProceed: true };
        }
        if (submitType === "teammate" /* Teammate */) {
          onDebugMessage(
            `Received teammate message (${trimmedQuery.length} chars)`
          );
          return { queryToSend: trimmedQuery, shouldProceed: true };
        }
        onDebugMessage(`Received user query (${trimmedQuery.length} chars)`);
        await logger?.logMessage("user" /* USER */, trimmedQuery);
        const slashCommandResult = isSlashCommand(trimmedQuery) ? await handleSlashCommand(trimmedQuery) : false;
        if (slashCommandResult) {
          switch (slashCommandResult.type) {
            case "schedule_tool": {
              const { toolName, toolArgs } = slashCommandResult;
              const toolCallRequest = {
                callId: `${toolName}-${Date.now()}-${Math.random().toString(16).slice(2)}`,
                name: toolName,
                args: toolArgs,
                isClientInitiated: true,
                prompt_id
              };
              scheduleToolCalls([toolCallRequest], abortSignal);
              return { queryToSend: null, shouldProceed: false };
            }
            case "submit_prompt": {
              localQueryToSendToGemini = slashCommandResult.content;
              submitPromptOnCompleteRef.current = slashCommandResult.onComplete ?? null;
              if (slashCommandResult.modelOverride) {
                if (isInlineModelOverrideAllowed(
                  config,
                  slashCommandResult.modelOverride
                )) {
                  applyModelOverride(
                    modelOverrideRef,
                    inlineModelOverrideActiveRef,
                    slashCommandResult.modelOverride,
                    true
                  );
                } else {
                  debugLogger3.warn(
                    `ignoring model override '${slashCommandResult.modelOverride}': not a model on the active provider`
                  );
                }
              }
              return {
                queryToSend: localQueryToSendToGemini,
                shouldProceed: true
              };
            }
            case "handled": {
              return { queryToSend: null, shouldProceed: false };
            }
            default: {
              const unreachable = slashCommandResult;
              throw new Error(
                `Unhandled slash command result type: ${unreachable}`
              );
            }
          }
        }
        if (shellModeActive && handleShellCommand(trimmedQuery, abortSignal)) {
          return { queryToSend: null, shouldProceed: false };
        }
        localQueryToSendToGemini = trimmedQuery;
        if (submitType !== "cron" /* Cron */) {
          const insertedId = addItem(
            {
              type: "user" /* USER */,
              text: trimmedQuery,
              promptId: prompt_id
            },
            userMessageTimestamp
          );
          lastTurnUserItemRef.current = {
            id: insertedId,
            text: trimmedQuery
          };
          await new Promise((r) => setImmediate(r));
        }
        if (isAtCommand(trimmedQuery)) {
          const atCommandResult = await handleAtCommand({
            query: trimmedQuery,
            config,
            onDebugMessage,
            messageId: userMessageTimestamp,
            signal: abortSignal,
            addItem
          });
          if (!atCommandResult.shouldProceed) {
            return { queryToSend: null, shouldProceed: false };
          }
          localQueryToSendToGemini = atCommandResult.processedQuery;
        }
        const bridgeResult = await applyVisionBridgeIfNeeded(
          localQueryToSendToGemini,
          userMessageTimestamp,
          abortSignal
        );
        if (!bridgeResult.shouldProceed) {
          return { queryToSend: null, shouldProceed: false };
        }
        localQueryToSendToGemini = bridgeResult.parts;
      } else {
        localQueryToSendToGemini = query;
      }
      if (localQueryToSendToGemini === null) {
        onDebugMessage(
          "Query processing resulted in null, not sending to Gemini."
        );
        return { queryToSend: null, shouldProceed: false };
      }
      return { queryToSend: localQueryToSendToGemini, shouldProceed: true };
    },
    [
      config,
      addItem,
      onDebugMessage,
      handleShellCommand,
      handleSlashCommand,
      logger,
      shellModeActive,
      scheduleToolCalls,
      applyVisionBridgeIfNeeded
    ]
  );
  const handleContentEvent = (0, import_react5.useCallback)(
    (eventValue, currentGeminiMessageBuffer, userMessageTimestamp) => {
      if (turnCancelledRef.current) {
        return "";
      }
      streamingResponseLengthRef.current += eventValue.length;
      setIsReceivingContent(true);
      turnSawContentEventRef.current = true;
      let newGeminiMessageBuffer = currentGeminiMessageBuffer + eventValue;
      if (pendingHistoryItemRef.current?.type !== "gemini" && pendingHistoryItemRef.current?.type !== "gemini_content") {
        if (newGeminiMessageBuffer.trim().length === 0) {
          return newGeminiMessageBuffer;
        }
        if (pendingHistoryItemRef.current) {
          commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
        }
        setPendingHistoryItem({
          type: "gemini",
          text: "",
          timestamp: Date.now()
        });
        newGeminiMessageBuffer = stripLeadingBlankLines(newGeminiMessageBuffer);
      }
      let nextPendingType = pendingHistoryItemRef.current?.type;
      while (newGeminiMessageBuffer.length > STREAM_PENDING_ITEM_MAX_CHARS) {
        const splitPoint = findLastSafeSplitPoint(
          newGeminiMessageBuffer,
          STREAM_PENDING_ITEM_MAX_CHARS
        );
        const safeSplitPoint = splitPoint > 0 && splitPoint < newGeminiMessageBuffer.length ? splitPoint : STREAM_PENDING_ITEM_MAX_CHARS;
        const beforeText = newGeminiMessageBuffer.substring(0, safeSplitPoint);
        const afterText = newGeminiMessageBuffer.substring(safeSplitPoint);
        commitItem(
          {
            type: nextPendingType,
            text: beforeText
          },
          userMessageTimestamp
        );
        nextPendingType = "gemini_content";
        newGeminiMessageBuffer = afterText;
      }
      setPendingHistoryItem((item) => {
        const base = {
          type: nextPendingType,
          text: newGeminiMessageBuffer
        };
        if (item && "timestamp" in item) {
          base.timestamp = item.timestamp;
        }
        return base;
      });
      return newGeminiMessageBuffer;
    },
    [commitItem, pendingHistoryItemRef, setPendingHistoryItem]
  );
  const mergeThought = (0, import_react5.useCallback)(
    (incoming) => {
      setThought((prev) => {
        const incomingDescription = incoming.description ? clampLoadingThoughtDescription(incoming.description) : incoming.description;
        if (!prev) {
          if (debugLogger3.isEnabled()) {
            debugLogger3.debug(
              `[THOUGHT_MERGE] New thought: subjectLength=${incoming.subject?.length ?? 0}, description length=${incomingDescription?.length ?? 0}`
            );
          }
          return {
            ...incoming,
            description: incomingDescription
          };
        }
        const subject = incoming.subject || prev.subject;
        const description = clampLoadingThoughtDescription(
          `${prev.description ?? ""}${incomingDescription ?? ""}`
        );
        if (debugLogger3.isEnabled()) {
          debugLogger3.debug(
            `[THOUGHT_MERGE] Accumulating thought: prev length=${prev.description?.length ?? 0}, incoming length=${incomingDescription?.length ?? 0}, total length=${description.length}`
          );
        }
        return { subject, description };
      });
    },
    [setThought]
  );
  const handleThoughtEvent = (0, import_react5.useCallback)(
    (eventValue, currentThoughtBuffer, userMessageTimestamp) => {
      if (turnCancelledRef.current) {
        return "";
      }
      const thoughtText = eventValue.description ?? "";
      if (!thoughtText) {
        return currentThoughtBuffer;
      }
      let newThoughtBuffer = currentThoughtBuffer + thoughtText;
      if (newThoughtBuffer.trim().length === 0) {
        return newThoughtBuffer;
      }
      streamingResponseLengthRef.current += thoughtText.length;
      const startingNewThought = currentThoughtBuffer.trim().length === 0;
      const description = startingNewThought ? stripLeadingBlankLines(newThoughtBuffer) : thoughtText;
      if (startingNewThought) {
        thoughtStartTimeRef.current = Date.now();
        newThoughtBuffer = description;
      }
      mergeThought({
        ...eventValue,
        description
      });
      let pendingThoughtType = startingNewThought ? "gemini_thought" : pendingThoughtItemRef.current?.type === "gemini_thought_content" ? "gemini_thought_content" : "gemini_thought";
      const getThoughtDurationMs = /* @__PURE__ */ __name(() => thoughtStartTimeRef.current ? Date.now() - thoughtStartTimeRef.current : 0, "getThoughtDurationMs");
      const buildThoughtItem = /* @__PURE__ */ __name((type, text) => type === "gemini_thought" ? {
        type,
        text,
        durationMs: getThoughtDurationMs()
      } : {
        type,
        text
      }, "buildThoughtItem");
      let splitPoint = findLastSafeSplitPoint(
        newThoughtBuffer,
        STREAM_PENDING_ITEM_MAX_CHARS
      );
      while (newThoughtBuffer.length > STREAM_PENDING_ITEM_MAX_CHARS) {
        const safeSplitPoint = splitPoint > 0 && splitPoint < newThoughtBuffer.length ? splitPoint : STREAM_PENDING_ITEM_MAX_CHARS;
        const beforeText = newThoughtBuffer.substring(0, safeSplitPoint);
        const afterText = newThoughtBuffer.substring(safeSplitPoint);
        addItem(
          buildThoughtItem(pendingThoughtType, beforeText),
          userMessageTimestamp
        );
        pendingThoughtType = "gemini_thought_content";
        newThoughtBuffer = afterText;
        splitPoint = findLastSafeSplitPoint(
          newThoughtBuffer,
          STREAM_PENDING_ITEM_MAX_CHARS
        );
      }
      setPendingThoughtItem(
        buildThoughtItem(pendingThoughtType, newThoughtBuffer)
      );
      return newThoughtBuffer;
    },
    [addItem, mergeThought, pendingThoughtItemRef, setPendingThoughtItem]
  );
  const commitPendingThought = (0, import_react5.useCallback)(
    (userMessageTimestamp) => {
      if (pendingThoughtItemRef.current) {
        const item = { ...pendingThoughtItemRef.current };
        if (item.type === "gemini_thought" && thoughtStartTimeRef.current) {
          item.durationMs = Date.now() - thoughtStartTimeRef.current;
        }
        addItem(item, userMessageTimestamp);
      }
      setPendingThoughtItem(null);
      thoughtStartTimeRef.current = null;
    },
    [addItem, pendingThoughtItemRef, setPendingThoughtItem]
  );
  const handleUserCancelledEvent = (0, import_react5.useCallback)(
    (userMessageTimestamp) => {
      if (turnCancelledRef.current) {
        return;
      }
      lastPromptErroredRef.current = false;
      commitPendingThought(userMessageTimestamp);
      if (pendingHistoryItemRef.current) {
        if (pendingHistoryItemRef.current.type === "tool_group") {
          const updatedTools = pendingHistoryItemRef.current.tools.map(
            (tool) => tool.status === "Pending" /* Pending */ || tool.status === "Confirming" /* Confirming */ || tool.status === "Executing" /* Executing */ ? { ...tool, status: "Canceled" /* Canceled */ } : tool
          );
          const pendingItem = {
            ...pendingHistoryItemRef.current,
            tools: updatedTools
          };
          addItem(pendingItem, userMessageTimestamp);
        } else {
          commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
        }
        setPendingHistoryItem(null);
      }
      addItem(
        { type: "info" /* INFO */, text: "User cancelled the request." },
        userMessageTimestamp
      );
      clearRetryCountdown();
      setIsResponding(false);
      setThought(null);
    },
    [
      addItem,
      commitPendingThought,
      commitItem,
      pendingHistoryItemRef,
      setPendingHistoryItem,
      setThought,
      clearRetryCountdown
    ]
  );
  const handleErrorEvent = (0, import_react5.useCallback)(
    (eventValue, userMessageTimestamp) => {
      lastPromptErroredRef.current = true;
      commitPendingThought(userMessageTimestamp);
      if (pendingHistoryItemRef.current) {
        commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
        setPendingHistoryItem(null);
      }
      const isShowingAutoRetry = retryCountdownTimerRef.current !== null;
      clearRetryCountdown();
      const formattedErrorText = parseAndFormatApiError(
        eventValue.error,
        config.getContentGeneratorConfig()?.authType
      );
      if (!isShowingAutoRetry) {
        const retryHint = t("Press Ctrl+Y to retry");
        setPendingRetryErrorItem({
          type: "error",
          text: formattedErrorText,
          hint: retryHint
        });
      }
      setThought(null);
      const errorType = classifyApiError(eventValue.error);
      config.getHookSystem()?.fireStopFailureEvent(
        errorType,
        eventValue.error.message,
        formattedErrorText
      ).catch((err) => {
        debugLogger3.warn(`StopFailure hook failed: ${err}`);
      });
    },
    [
      commitPendingThought,
      commitItem,
      pendingHistoryItemRef,
      setPendingHistoryItem,
      setPendingRetryErrorItem,
      config,
      setThought,
      clearRetryCountdown
    ]
  );
  const handleCitationEvent = (0, import_react5.useCallback)(
    (text, userMessageTimestamp) => {
      if (!showCitations(settings)) {
        return;
      }
      if (pendingHistoryItemRef.current) {
        commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
        setPendingHistoryItem(null);
      }
      addItem({ type: "info" /* INFO */, text }, userMessageTimestamp);
    },
    [
      addItem,
      commitItem,
      pendingHistoryItemRef,
      setPendingHistoryItem,
      settings
    ]
  );
  const handleFinishedEvent = (0, import_react5.useCallback)(
    (event, userMessageTimestamp) => {
      const finishReason = event.value.reason;
      if (!finishReason) {
        return;
      }
      const finishReasonMessages = {
        [FinishReason.FINISH_REASON_UNSPECIFIED]: void 0,
        [FinishReason.STOP]: void 0,
        [FinishReason.MAX_TOKENS]: "Response truncated due to token limits.",
        [FinishReason.SAFETY]: "Response stopped due to safety reasons.",
        [FinishReason.RECITATION]: "Response stopped due to recitation policy.",
        [FinishReason.LANGUAGE]: "Response stopped due to unsupported language.",
        [FinishReason.BLOCKLIST]: "Response stopped due to forbidden terms.",
        [FinishReason.PROHIBITED_CONTENT]: "Response stopped due to prohibited content.",
        [FinishReason.SPII]: "Response stopped due to sensitive personally identifiable information.",
        [FinishReason.OTHER]: "Response stopped for other reasons.",
        [FinishReason.MALFORMED_FUNCTION_CALL]: "Response stopped due to malformed function call.",
        [FinishReason.IMAGE_SAFETY]: "Response stopped due to image safety violations.",
        [FinishReason.IMAGE_PROHIBITED_CONTENT]: "Response stopped due to image prohibited content.",
        [FinishReason.IMAGE_RECITATION]: "Response stopped due to image recitation policy.",
        [FinishReason.IMAGE_OTHER]: "Response stopped due to other image-related reasons.",
        [FinishReason.NO_IMAGE]: "Response stopped due to no image.",
        [FinishReason.UNEXPECTED_TOOL_CALL]: "Response stopped due to unexpected tool call."
      };
      const message = finishReasonMessages[finishReason];
      if (message) {
        addItem(
          {
            type: "info",
            text: `\u26A0  ${message}`
          },
          userMessageTimestamp
        );
      }
      if (retryCountdownTimerRef.current) {
        clearRetryCountdown();
      }
    },
    [addItem, clearRetryCountdown]
  );
  const autonomousLoopTickResolverRef = (0, import_react5.useRef)(null);
  const handleChatCompressionEvent = (0, import_react5.useCallback)(
    (eventValue, userMessageTimestamp) => {
      autonomousLoopTickResolverRef.current?.resetCache();
      if (pendingHistoryItemRef.current) {
        commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
        setPendingHistoryItem(null);
      }
      const activeModel = modelOverrideRef.current ?? config.getModel();
      const reasonClause = eventValue?.triggerReason === "image_overflow" ? `accumulated enough tool screenshots to trigger compaction for ${activeModel}` : `approached the input token limit for ${activeModel}`;
      return addItem(
        {
          type: "info",
          text: `IMPORTANT: This conversation ${reasonClause}. A compressed context will be sent for future messages (compressed from: ${eventValue?.originalTokenCount ?? "unknown"} to ${eventValue?.newTokenCount ?? "unknown"} tokens).`
        },
        Date.now()
      );
    },
    [addItem, commitItem, config, pendingHistoryItemRef, setPendingHistoryItem]
  );
  const handleMaxSessionTurnsEvent = (0, import_react5.useCallback)(
    () => addItem(
      {
        type: "info",
        text: `The session has reached the maximum number of turns: ${config.getMaxSessionTurns()}. Please update this limit in your setting.json file.`
      },
      Date.now()
    ),
    [addItem, config]
  );
  const handleSessionTokenLimitExceededEvent = (0, import_react5.useCallback)(
    (value) => addItem(
      {
        type: "error",
        text: `\u2717 Session token limit exceeded: ${value.currentTokens.toLocaleString()} tokens > ${value.limit.toLocaleString()} limit.

\u2605 Solutions:
   \u2022 Start a new session: Use /clear command
   \u2022 Increase limit: Add "sessionTokenLimit": (e.g., 128000) to your settings.json
   \u2022 Compress history: Use /compress command to compress history`
      },
      Date.now()
    ),
    [addItem]
  );
  const handleLoopDetectionConfirmation = (0, import_react5.useCallback)(
    (result) => {
      setLoopDetectionConfirmationRequest(null);
      if (result.userSelection === "disable") {
        config.getGeminiClient().getLoopDetectionService().disableForSession();
        addItem(
          {
            type: "info",
            text: `Loop detection has been disabled for this session. Please try your request again.`
          },
          Date.now()
        );
      } else {
        addItem(
          {
            type: "info",
            text: `A potential loop was detected. This can happen due to repetitive tool calls or other model behavior. The request has been halted.`
          },
          Date.now()
        );
      }
    },
    [config, addItem]
  );
  const handleLoopDetectedEvent = (0, import_react5.useCallback)(() => {
    setLoopDetectionConfirmationRequest({
      onComplete: handleLoopDetectionConfirmation
    });
  }, [handleLoopDetectionConfirmation]);
  const handleUserPromptSubmitBlockedEvent = (0, import_react5.useCallback)(
    (value, userMessageTimestamp) => {
      if (pendingHistoryItemRef.current) {
        commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
        setPendingHistoryItem(null);
      }
      addItem(
        {
          type: "user_prompt_submit_blocked",
          reason: value.reason,
          originalPrompt: value.originalPrompt
        },
        userMessageTimestamp
      );
    },
    [addItem, commitItem, pendingHistoryItemRef, setPendingHistoryItem]
  );
  const handleStopHookLoopEvent = (0, import_react5.useCallback)(
    (value, userMessageTimestamp) => {
      if (pendingHistoryItemRef.current) {
        commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
        setPendingHistoryItem(null);
      }
      const activeGoal = getActiveGoal(config.getSessionId());
      if (activeGoal && activeGoal.condition) {
        const item = {
          type: "goal_status" /* GOAL_STATUS */,
          kind: "checking",
          condition: activeGoal.condition,
          iterations: activeGoal.iterations,
          lastReason: activeGoal.lastReason ?? value.reasons[value.reasons.length - 1]
        };
        addItem(item, userMessageTimestamp);
        recordGoalStatusItem(config, item);
        return;
      }
      addItem(
        {
          type: "stop_hook_loop",
          iterationCount: value.iterationCount,
          reasons: value.reasons,
          stopHookCount: value.stopHookCount
        },
        userMessageTimestamp
      );
    },
    [addItem, commitItem, config, pendingHistoryItemRef, setPendingHistoryItem]
  );
  const handleActiveGoalEvent = (0, import_react5.useCallback)(
    (activeGoal) => {
      const sessionId = config.getSessionId();
      const currentActiveGoal = getActiveGoal(sessionId);
      if (activeGoal) {
        if (activeGoalEquals(currentActiveGoal, activeGoal)) {
          return;
        }
        setActiveGoal(sessionId, activeGoal);
        return;
      }
      if (!currentActiveGoal) {
        return;
      }
      clearActiveGoal(sessionId);
    },
    [config]
  );
  const processGeminiStreamEvents = (0, import_react5.useCallback)(
    async (stream, userMessageTimestamp, signal) => {
      let geminiMessageBuffer = "";
      let thoughtBuffer = "";
      const toolCallRequests = [];
      const bufferedEvents = [];
      let flushTimer = null;
      const discardBufferedStreamEvents = /* @__PURE__ */ __name(() => {
        if (flushTimer) {
          clearTimeout(flushTimer);
          flushTimer = null;
        }
        bufferedEvents.length = 0;
      }, "discardBufferedStreamEvents");
      const flushBufferedStreamEvents = /* @__PURE__ */ __name(() => {
        if (flushTimer) {
          clearTimeout(flushTimer);
          flushTimer = null;
        }
        if (bufferedEvents.length === 0) {
          return;
        }
        while (bufferedEvents.length > 0) {
          const nextEvent = bufferedEvents.shift();
          if (nextEvent.kind === "content") {
            const contentParts = [nextEvent.value];
            while (bufferedEvents[0]?.kind === "content") {
              const queuedContent = bufferedEvents.shift();
              if (queuedContent?.kind !== "content") {
                break;
              }
              contentParts.push(queuedContent.value);
            }
            geminiMessageBuffer = handleContentEvent(
              contentParts.join(""),
              geminiMessageBuffer,
              userMessageTimestamp
            );
            continue;
          }
          let subject = nextEvent.value.subject;
          const thoughtDescriptions = [];
          if (nextEvent.value.description) {
            thoughtDescriptions.push(nextEvent.value.description);
          }
          while (bufferedEvents[0]?.kind === "thought") {
            const queuedThought = bufferedEvents.shift();
            if (queuedThought?.kind !== "thought") {
              break;
            }
            subject = queuedThought.value.subject || subject;
            if (queuedThought.value.description) {
              thoughtDescriptions.push(queuedThought.value.description);
            }
          }
          thoughtBuffer = handleThoughtEvent(
            {
              subject,
              description: thoughtDescriptions.join("")
            },
            thoughtBuffer,
            userMessageTimestamp
          );
        }
      }, "flushBufferedStreamEvents");
      const scheduleBufferedStreamFlush = /* @__PURE__ */ __name(() => {
        if (flushTimer) {
          return;
        }
        flushTimer = setTimeout(() => {
          flushBufferedStreamEvents();
        }, STREAM_UPDATE_THROTTLE_MS);
      }, "scheduleBufferedStreamFlush");
      flushBufferedStreamEventsRef.current.add(flushBufferedStreamEvents);
      dualOutput?.startAssistantMessage();
      try {
        for await (const event of stream) {
          dualOutput?.processEvent(event);
          switch (event.type) {
            case "thought" /* Thought */:
              if (event.value.subject && !event.value.description) {
                flushBufferedStreamEvents();
                setThought(event.value);
              } else {
                bufferedEvents.push({ kind: "thought", value: event.value });
                scheduleBufferedStreamFlush();
              }
              break;
            case "content" /* Content */:
              if (pendingThoughtItemRef.current || bufferedEvents.some((e) => e.kind === "thought")) {
                flushBufferedStreamEvents();
                commitPendingThought(userMessageTimestamp);
                thoughtBuffer = "";
              }
              setThought((prev) => prev ? null : prev);
              bufferedEvents.push({ kind: "content", value: event.value });
              scheduleBufferedStreamFlush();
              break;
            case "tool_call_request" /* ToolCallRequest */:
              flushBufferedStreamEvents();
              commitPendingThought(userMessageTimestamp);
              thoughtBuffer = "";
              setThought((prev) => prev ? null : prev);
              toolCallRequests.push(event.value);
              try {
                const argsJson = JSON.stringify(event.value.args);
                streamingResponseLengthRef.current += argsJson.length;
              } catch {
              }
              break;
            case "user_cancelled" /* UserCancelled */:
              flushBufferedStreamEvents();
              toolCallRequests.length = 0;
              handleUserCancelledEvent(userMessageTimestamp);
              break;
            case "error" /* Error */:
              flushBufferedStreamEvents();
              handleErrorEvent(event.value, userMessageTimestamp);
              break;
            case "chat_compressed" /* ChatCompressed */:
              flushBufferedStreamEvents();
              handleChatCompressionEvent(event.value, userMessageTimestamp);
              break;
            case "tool_call_confirmation" /* ToolCallConfirmation */:
            case "tool_call_response" /* ToolCallResponse */:
              flushBufferedStreamEvents();
              break;
            case "max_session_turns" /* MaxSessionTurns */:
              flushBufferedStreamEvents();
              handleMaxSessionTurnsEvent();
              break;
            case "session_token_limit_exceeded" /* SessionTokenLimitExceeded */:
              flushBufferedStreamEvents();
              handleSessionTokenLimitExceededEvent(event.value);
              break;
            case "finished" /* Finished */:
              flushBufferedStreamEvents();
              commitPendingThought(userMessageTimestamp);
              handleFinishedEvent(
                event,
                userMessageTimestamp
              );
              if (pendingHistoryItemRef.current) {
                commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
                setPendingHistoryItem(null);
              }
              geminiMessageBuffer = "";
              thoughtBuffer = "";
              setThought(null);
              break;
            case "citation" /* Citation */:
              flushBufferedStreamEvents();
              handleCitationEvent(event.value, userMessageTimestamp);
              break;
            case "loop_detected" /* LoopDetected */:
              flushBufferedStreamEvents();
              loopDetectedRef.current = true;
              break;
            case "retry" /* Retry */:
              if (!event.isContinuation) {
                discardBufferedStreamEvents();
                if (pendingHistoryItemRef.current) {
                  setPendingHistoryItem(null);
                }
                commitPendingThought(userMessageTimestamp);
                thoughtBuffer = "";
                setThought(null);
                geminiMessageBuffer = "";
              } else {
                flushBufferedStreamEvents();
              }
              toolCallRequests.length = 0;
              if (event.retryInfo) {
                startRetryCountdown(event.retryInfo);
              } else {
                clearRetryCountdown();
              }
              break;
            case "hook_system_message" /* HookSystemMessage */:
              flushBufferedStreamEvents();
              if (pendingHistoryItemRef.current) {
                commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
                setPendingHistoryItem(null);
              }
              addItem(
                {
                  type: "stop_hook_system_message",
                  message: event.value
                },
                userMessageTimestamp
              );
              break;
            case "user_prompt_submit_blocked" /* UserPromptSubmitBlocked */:
              flushBufferedStreamEvents();
              handleUserPromptSubmitBlockedEvent(
                event.value,
                userMessageTimestamp
              );
              break;
            case "stop_hook_loop" /* StopHookLoop */:
              flushBufferedStreamEvents();
              handleStopHookLoopEvent(event.value, userMessageTimestamp);
              break;
            case "active_goal" /* ActiveGoal */:
              handleActiveGoalEvent(event.value);
              break;
            default: {
              const unreachable = event;
              return unreachable;
            }
          }
        }
      } finally {
        flushBufferedStreamEvents();
        commitPendingThought(userMessageTimestamp);
        discardBufferedStreamEvents();
        flushBufferedStreamEventsRef.current.delete(flushBufferedStreamEvents);
      }
      dualOutput?.finalizeAssistantMessage();
      if (toolCallRequests.length > 0 && !signal.aborted && !loopDetectedRef.current) {
        const executableToolCallRequests = [];
        const duplicateResponseParts = [];
        let duplicatePromptId;
        const historyCallIdsWithResponse = geminiClient ? geminiClient.getHistoryFunctionResponseIds() : /* @__PURE__ */ new Set();
        const handledProviderIds = /* @__PURE__ */ new Set([
          ...handledProviderToolCallIdsRef.current,
          ...historyCallIdsWithResponse
        ]);
        const repeatedDuplicateRequest = findRepeatedDuplicateProviderToolCall(
          toolCallRequests,
          (request) => request.providerCallId,
          handledProviderIds,
          duplicateProviderToolCallResponseIdsRef.current
        );
        if (repeatedDuplicateRequest?.providerCallId) {
          debugLogger3.debug(
            `[processGeminiStreamEvents] Dropping batch after repeated duplicate provider tool-call id: ${repeatedDuplicateRequest.providerCallId} (tool: ${repeatedDuplicateRequest.name})`
          );
          loopDetectedRef.current = true;
          return 0 /* Completed */;
        }
        for (const request of toolCallRequests) {
          const providerCallId = request.providerCallId;
          if (!providerCallId) {
            executableToolCallRequests.push(request);
            continue;
          }
          if (handledProviderToolCallIdsRef.current.has(providerCallId) || historyCallIdsWithResponse.has(providerCallId)) {
            markDuplicateProviderToolCallResponseSent(
              providerCallId,
              duplicateProviderToolCallResponseIdsRef.current
            );
            const response = createDuplicateProviderToolCallResponse(request);
            debugLogger3.debug(
              `[processGeminiStreamEvents] Suppressing duplicate provider tool-call id: ${providerCallId} (tool: ${request.name})`
            );
            dualOutput?.emitToolResult(request, response);
            duplicateResponseParts.push(...response.responseParts);
            duplicatePromptId ??= request.prompt_id;
            continue;
          }
          handledProviderToolCallIdsRef.current.add(providerCallId);
          executableToolCallRequests.push(request);
        }
        if (duplicateResponseParts.length > 0) {
          if (executableToolCallRequests.length > 0) {
            pendingDuplicateToolResponsesRef.current.push({
              executableCallIds: new Set(
                executableToolCallRequests.map((request) => request.callId)
              ),
              promptId: duplicatePromptId ?? executableToolCallRequests[0]?.prompt_id,
              responseParts: duplicateResponseParts
            });
          } else {
            immediateDuplicateToolResponsesRef.current = {
              promptId: duplicatePromptId,
              responseParts: duplicateResponseParts
            };
          }
        }
        if (executableToolCallRequests.length > 0) {
          scheduleToolCalls(executableToolCallRequests, signal);
        }
      }
      return 0 /* Completed */;
    },
    [
      handleContentEvent,
      handleThoughtEvent,
      handleUserCancelledEvent,
      handleErrorEvent,
      scheduleToolCalls,
      geminiClient,
      handleChatCompressionEvent,
      handleFinishedEvent,
      handleMaxSessionTurnsEvent,
      handleSessionTokenLimitExceededEvent,
      handleCitationEvent,
      startRetryCountdown,
      clearRetryCountdown,
      setThought,
      commitPendingThought,
      pendingHistoryItemRef,
      pendingThoughtItemRef,
      setPendingHistoryItem,
      handleUserPromptSubmitBlockedEvent,
      handleStopHookLoopEvent,
      handleActiveGoalEvent,
      addItem,
      commitItem,
      dualOutput
    ]
  );
  const submitQuery = (0, import_react5.useCallback)(
    async (query, submitType = "userQuery" /* UserQuery */, prompt_id, metadata) => {
      const allowConcurrentBtwDuringResponse = submitType === "userQuery" /* UserQuery */ && streamingState === "responding" /* Responding */ && typeof query === "string" && isBtwCommand(query);
      if (isSubmittingQueryRef.current && submitType !== "toolResult" /* ToolResult */ && !allowConcurrentBtwDuringResponse) {
        metadata?.onDeliveryFailed?.();
        return;
      }
      if ((streamingState === "responding" /* Responding */ || streamingState === "waiting_for_confirmation" /* WaitingForConfirmation */) && submitType !== "toolResult" /* ToolResult */ && !allowConcurrentBtwDuringResponse) {
        metadata?.onDeliveryFailed?.();
        return;
      }
      isSubmittingQueryRef.current = true;
      loopDetectedRef.current = false;
      if (submitType !== "toolResult" /* ToolResult */ && !allowConcurrentBtwDuringResponse) {
        lastTurnUserItemRef.current = null;
        turnSawContentEventRef.current = false;
        handledProviderToolCallIdsRef.current.clear();
        duplicateProviderToolCallResponseIdsRef.current.clear();
        pendingDuplicateToolResponsesRef.current = [];
        immediateDuplicateToolResponsesRef.current = null;
      }
      const userMessageTimestamp = Date.now();
      if (submitType !== "toolResult" /* ToolResult */ && !allowConcurrentBtwDuringResponse) {
        setModelSwitchedFromQuotaError(false);
        const droppingInlineOverrideOnRetry = submitType === "retry" /* Retry */ && inlineModelOverrideActiveRef.current;
        if (submitType !== "retry" /* Retry */ || inlineModelOverrideActiveRef.current) {
          if (droppingInlineOverrideOnRetry) {
            addItem(
              {
                type: "info",
                text: `Inline model override cleared on retry \u2014 retrying on the session model (${config.getModel()}).`
              },
              userMessageTimestamp
            );
          }
          clearModelOverride(modelOverrideRef, inlineModelOverrideActiveRef);
        }
        if (pendingRetryCountdownItemRef.current || pendingRetryErrorItemRef.current) {
          const pendingError = pendingRetryErrorItemRef.current;
          if (pendingError && pendingError.type === "error") {
            const { hint: _hint, ...errorWithoutHint } = pendingError;
            addItem(errorWithoutHint, userMessageTimestamp);
          }
          clearRetryCountdown();
        }
      }
      const abortController = new AbortController();
      const abortSignal = abortController.signal;
      if (!allowConcurrentBtwDuringResponse) {
        abortControllerRef.current = abortController;
        turnCancelledRef.current = false;
      }
      if (!prompt_id) {
        prompt_id = config.getSessionId() + "########" + getPromptCount();
      }
      return promptIdContext.run(prompt_id, async () => {
        const { queryToSend, shouldProceed } = submitType === "retry" /* Retry */ ? { queryToSend: query, shouldProceed: true } : await prepareQueryForGemini(
          query,
          userMessageTimestamp,
          abortSignal,
          prompt_id,
          submitType
        );
        if (!shouldProceed || queryToSend === null) {
          isSubmittingQueryRef.current = false;
          metadata?.onDeliveryFailed?.();
          return;
        }
        if (submitType === "userQuery" /* UserQuery */ || submitType === "cron" /* Cron */ || submitType === "teammate" /* Teammate */) {
          const formatCheck = checkImageFormatsSupport(queryToSend);
          if (formatCheck.hasUnsupportedFormats) {
            addItem(
              {
                type: "info" /* INFO */,
                text: getUnsupportedImageFormatWarning()
              },
              userMessageTimestamp
            );
          }
        }
        const finalQueryToSend = queryToSend;
        lastPromptRef.current = finalQueryToSend;
        lastPromptErroredRef.current = false;
        if (submitType === "userQuery" /* UserQuery */ || submitType === "cron" /* Cron */ || submitType === "teammate" /* Teammate */) {
          startNewPrompt();
          if (typeof queryToSend === "string") {
            logUserPrompt(
              config,
              new UserPromptEvent(
                queryToSend.length,
                prompt_id,
                config.getContentGeneratorConfig()?.authType,
                queryToSend,
                modelOverrideRef.current ?? config.getModel()
              )
            );
          }
          setThought(null);
          setPendingThoughtItem(null);
        }
        if (submitType === "retry" /* Retry */) {
          logUserRetry(config, new UserRetryEvent(prompt_id));
        }
        activeModelStreamsRef.current += 1;
        setIsResponding(true);
        setInitError(null);
        setIsReceivingContent(false);
        if (submitType !== "toolResult" /* ToolResult */) {
          streamingResponseLengthRef.current = 0;
        }
        try {
          if (dualOutput && submitType !== "toolResult" /* ToolResult */) {
            const rawParts = typeof finalQueryToSend === "string" ? [finalQueryToSend] : Array.isArray(finalQueryToSend) ? finalQueryToSend : [finalQueryToSend];
            const userParts = rawParts.map(
              (p) => typeof p === "string" ? { text: p } : p
            );
            dualOutput.emitUserMessage(userParts);
          }
          const stream = geminiClient.sendMessageStream(
            finalQueryToSend,
            abortSignal,
            prompt_id,
            {
              type: submitType,
              notificationDisplayText: metadata?.notificationDisplayText,
              modelOverride: modelOverrideRef.current
            }
          );
          const processingStatus = await processGeminiStreamEvents(
            stream,
            userMessageTimestamp,
            abortSignal
          );
          if (processingStatus === 1 /* UserCancelled */) {
            submitPromptOnCompleteRef.current = null;
            isSubmittingQueryRef.current = false;
            metadata?.onDeliveryFailed?.();
            return;
          }
          if (pendingHistoryItemRef.current) {
            commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
            setPendingHistoryItem(null);
          }
          const immediateDuplicateToolResponses = immediateDuplicateToolResponsesRef.current;
          if (immediateDuplicateToolResponses) {
            immediateDuplicateToolResponsesRef.current = null;
            await submitQuery(
              immediateDuplicateToolResponses.responseParts,
              "toolResult" /* ToolResult */,
              immediateDuplicateToolResponses.promptId
            );
          }
          if (retryCountdownTimerRef.current) {
            clearRetryCountdown();
          }
          if (loopDetectedRef.current) {
            loopDetectedRef.current = false;
            handleLoopDetectedEvent();
          }
          if (lastPromptErroredRef.current) {
            metadata?.onDeliveryFailed?.();
          } else {
            metadata?.onDelivered?.();
          }
          const onComplete = submitPromptOnCompleteRef.current;
          if (onComplete) {
            submitPromptOnCompleteRef.current = null;
            void onComplete().catch((err) => {
              debugLogger3.error("onComplete callback failed:", err);
            });
          }
          if (geminiClient) {
            const memoryTaskPromises = geminiClient.consumePendingMemoryTaskPromises();
            for (const p of memoryTaskPromises) {
              void p.then((count) => {
                if (count > 0) {
                  addItem(
                    {
                      type: "memory_saved",
                      writtenCount: count,
                      verb: "Updated"
                    },
                    Date.now()
                  );
                }
              });
            }
          }
        } catch (error) {
          metadata?.onDeliveryFailed?.();
          if (error instanceof UnauthorizedError) {
            onAuthError("Session expired or is unauthorized.");
          } else if (!isNodeError(error) || error.name !== "AbortError") {
            lastPromptErroredRef.current = true;
            const retryHint = t("Press Ctrl+Y to retry");
            setPendingRetryErrorItem({
              type: "error",
              text: parseAndFormatApiError(
                getErrorMessage(error) || "Unknown error",
                config.getContentGeneratorConfig()?.authType
              ),
              hint: retryHint
            });
          }
        } finally {
          submitPromptOnCompleteRef.current = null;
          activeModelStreamsRef.current = Math.max(
            0,
            activeModelStreamsRef.current - 1
          );
          if (activeModelStreamsRef.current === 0) {
            setIsResponding(false);
          }
          isSubmittingQueryRef.current = false;
        }
      });
    },
    [
      streamingState,
      setModelSwitchedFromQuotaError,
      prepareQueryForGemini,
      processGeminiStreamEvents,
      pendingHistoryItemRef,
      addItem,
      commitItem,
      setPendingHistoryItem,
      setInitError,
      geminiClient,
      onAuthError,
      config,
      startNewPrompt,
      getPromptCount,
      handleLoopDetectedEvent,
      clearRetryCountdown,
      pendingRetryCountdownItemRef,
      pendingRetryErrorItemRef,
      setPendingRetryErrorItem,
      setPendingThoughtItem,
      dualOutput
    ]
  );
  const retryLastPrompt = (0, import_react5.useCallback)(async () => {
    if (skipRetryDelayRef.current) {
      skipRetryDelayRef.current();
      skipRetryDelayRef.current = null;
      clearRetryCountdown();
      return;
    }
    if (streamingState === "responding" /* Responding */ || streamingState === "waiting_for_confirmation" /* WaitingForConfirmation */) {
      return;
    }
    const lastPrompt = lastPromptRef.current;
    if (!lastPrompt || !lastPromptErroredRef.current) {
      addItem(
        {
          type: "info" /* INFO */,
          text: t("No failed request to retry.")
        },
        Date.now()
      );
      return;
    }
    clearRetryCountdown();
    await submitQuery(lastPrompt, "retry" /* Retry */);
  }, [streamingState, addItem, clearRetryCountdown, submitQuery]);
  const handleApprovalModeChange = (0, import_react5.useCallback)(
    async (newApprovalMode) => {
      if (newApprovalMode === "yolo" /* YOLO */ || newApprovalMode === "auto-edit" /* AUTO_EDIT */) {
        let awaitingApprovalCalls = toolCalls.filter(
          (call) => call.status === "awaiting_approval"
        );
        if (newApprovalMode === "auto-edit" /* AUTO_EDIT */) {
          awaitingApprovalCalls = awaitingApprovalCalls.filter(
            (call) => EDIT_TOOL_NAMES.has(call.request.name)
          );
        }
        for (const call of awaitingApprovalCalls) {
          if (call.confirmationDetails?.onConfirm) {
            try {
              await call.confirmationDetails.onConfirm(
                "proceed_once" /* ProceedOnce */
              );
            } catch (error) {
              debugLogger3.error(
                `Failed to auto-approve tool call ${call.request.callId}:`,
                error
              );
            }
          }
        }
      }
    },
    [toolCalls]
  );
  const handleCompletedTools = (0, import_react5.useCallback)(
    async (completedToolCallsFromScheduler) => {
      const completedAndReadyToSubmitTools = completedToolCallsFromScheduler.filter(
        (tc) => {
          const isTerminalState = tc.status === "success" || tc.status === "error" || tc.status === "cancelled";
          if (isTerminalState) {
            const completedOrCancelledCall = tc;
            return completedOrCancelledCall.response?.responseParts !== void 0;
          }
          return false;
        }
      );
      const historyCallIdsWithResponse = geminiClient ? geminiClient.getHistoryFunctionResponseIds() : /* @__PURE__ */ new Set();
      const dedupedTools = completedAndReadyToSubmitTools.filter(
        (tc) => historyCallIdsWithResponse.has(tc.request.callId)
      );
      const dedupedCallIds = dedupedTools.map((tc) => tc.request.callId);
      if (dedupedCallIds.length > 0) {
        debugLogger3.warn(
          `[REPAIR] Dropping ${dedupedCallIds.length} late tool result(s) whose callId already has a functionResponse in history: ${dedupedCallIds.join(", ")}`
        );
        for (const tc of dedupedTools) {
          if (tc.request.isClientInitiated) continue;
          if (tc.status === "cancelled") continue;
          geminiClient?.recordCompletedToolCall(
            tc.request.name,
            tc.request.args
          );
        }
        markToolsAsSubmitted(dedupedCallIds);
      }
      if (activeModelStreamsRef.current > 0) {
        return;
      }
      const clientTools = completedAndReadyToSubmitTools.filter(
        (t2) => t2.request.isClientInitiated && !historyCallIdsWithResponse.has(t2.request.callId)
      );
      if (clientTools.length > 0) {
        markToolsAsSubmitted(clientTools.map((t2) => t2.request.callId));
      }
      const newSuccessfulMemorySaves = completedAndReadyToSubmitTools.filter(
        (t2) => t2.request.name === "save_memory" && t2.status === "success" && !processedMemoryToolsRef.current.has(t2.request.callId)
      );
      if (newSuccessfulMemorySaves.length > 0) {
        void performMemoryRefresh();
        newSuccessfulMemorySaves.forEach(
          (t2) => processedMemoryToolsRef.current.add(t2.request.callId)
        );
      }
      const geminiTools = completedAndReadyToSubmitTools.filter(
        (t2) => !t2.request.isClientInitiated && !historyCallIdsWithResponse.has(t2.request.callId)
      );
      const completedCallIds = new Set(
        completedAndReadyToSubmitTools.map(
          (toolCall) => toolCall.request.callId
        )
      );
      const readyDuplicateBatches = [];
      pendingDuplicateToolResponsesRef.current = pendingDuplicateToolResponsesRef.current.filter((batch) => {
        const isReady = [...batch.executableCallIds].some(
          (callId) => completedCallIds.has(callId)
        );
        if (isReady) {
          readyDuplicateBatches.push(batch);
        }
        return !isReady;
      });
      const pendingDuplicateResponseParts = readyDuplicateBatches.flatMap(
        (batch) => batch.responseParts
      );
      const pendingDuplicatePromptId = readyDuplicateBatches[0]?.promptId;
      for (const toolCall of geminiTools) {
        geminiClient?.recordCompletedToolCall(
          toolCall.request.name,
          toolCall.request.args
        );
      }
      if (geminiTools.length === 0 && pendingDuplicateResponseParts.length === 0) {
        return;
      }
      if (turnCancelledRef.current || abortControllerRef.current?.signal.aborted) {
        markToolsAsSubmitted(
          geminiTools.map((toolCall) => toolCall.request.callId)
        );
        return;
      }
      const allToolsCancelled = geminiTools.every(
        (tc) => tc.status === "cancelled"
      );
      if (allToolsCancelled && pendingDuplicateResponseParts.length === 0) {
        if (geminiClient) {
          const combinedParts = geminiTools.flatMap(
            (toolCall) => toolCall.response.responseParts
          );
          geminiClient.addHistory({
            role: "user",
            parts: combinedParts
          });
          config.getArenaAgentClient()?.reportCancelled();
        }
        const callIdsToMarkAsSubmitted2 = geminiTools.map(
          (toolCall) => toolCall.request.callId
        );
        markToolsAsSubmitted(callIdsToMarkAsSubmitted2);
        return;
      }
      const responsesToSend = geminiTools.flatMap(
        (toolCall) => toolCall.response.responseParts
      );
      responsesToSend.push(...pendingDuplicateResponseParts);
      const callIdsToMarkAsSubmitted = geminiTools.map(
        (toolCall) => toolCall.request.callId
      );
      const prompt_ids = geminiTools.map(
        (toolCall) => toolCall.request.prompt_id
      );
      const promptId = prompt_ids[0] ?? pendingDuplicatePromptId;
      for (const toolCall of geminiTools) {
        if ("modelOverride" in toolCall.response) {
          if (inlineModelOverrideActiveRef.current) {
            debugLogger3.debug(
              `skill-tool model override (${String(
                toolCall.response.modelOverride
              )}) blocked: inline override active`
            );
          } else {
            applyModelOverride(
              modelOverrideRef,
              inlineModelOverrideActiveRef,
              toolCall.response.modelOverride,
              false
            );
          }
        }
      }
      if (dualOutput) {
        for (const toolCall of geminiTools) {
          dualOutput.emitToolResult(toolCall.request, toolCall.response);
        }
      }
      markToolsAsSubmitted(callIdsToMarkAsSubmitted);
      if (config.getEmitToolUseSummaries()) {
        const successfulTools = geminiTools.filter(
          (tc) => tc.status === "success"
        );
        if (successfulTools.length > 0) {
          const toolInfoForSummary = successfulTools.map((tc) => ({
            name: tc.request.name,
            input: tc.request.args,
            output: extractToolResultText(tc.response.responseParts)
          }));
          const toolUseIds = successfulTools.map((tc) => tc.request.callId);
          const lastAssistantText = extractLastAssistantText(
            historyRef.current
          );
          const summaryAbort = new AbortController();
          auxiliaryAbortRefsRef.current.add(summaryAbort);
          const anchorCallId = toolUseIds[0];
          void generateToolUseSummary({
            config,
            tools: toolInfoForSummary,
            signal: summaryAbort.signal,
            lastAssistantText
          }).then((summary) => {
            auxiliaryAbortRefsRef.current.delete(summaryAbort);
            const cancelled = turnCancelledRef.current || abortControllerRef.current?.signal.aborted || summaryAbort.signal.aborted;
            if (!summary || cancelled) return;
            const currentHistory = historyRef.current;
            const ourIdx = currentHistory.findIndex(
              (h) => h.type === "tool_group" && h.tools.some((t2) => t2.callId === anchorCallId)
            );
            if (ourIdx < 0) return;
            const laterToolGroupExists = currentHistory.slice(ourIdx + 1).some((h) => h.type === "tool_group");
            if (laterToolGroupExists) return;
            if (summary && !cancelled) {
              addItem(
                {
                  type: "tool_use_summary",
                  summary,
                  precedingToolUseIds: toolUseIds
                },
                Date.now()
              );
            }
          }).catch(() => {
            auxiliaryAbortRefsRef.current.delete(summaryAbort);
          });
        }
      }
      if (modelSwitchedFromQuotaError) {
        return;
      }
      const drained = turnCancelledRef.current || abortControllerRef.current?.signal.aborted ? [] : midTurnDrainRef?.current?.() ?? [];
      if (drained.length > 0) {
        const midTurnTimestamp = Date.now();
        const midTurnAbort = abortControllerRef.current ?? new AbortController();
        const shouldTrackMidTurnAbort = !abortControllerRef.current;
        if (shouldTrackMidTurnAbort) {
          auxiliaryAbortRefsRef.current.add(midTurnAbort);
        }
        try {
          for (let index = 0; index < drained.length; index += 1) {
            if (midTurnAbort.signal.aborted) {
              break;
            }
            const msg = drained[index];
            let resolvedMidTurnQuery = [{ text: msg }];
            if (isAtCommand(msg)) {
              const atCommandTimeout = new AbortController();
              const atCommandSignal = AbortSignal.any([
                midTurnAbort.signal,
                atCommandTimeout.signal
              ]);
              const atCommandTimeoutId = setTimeout(() => {
                atCommandTimeout.abort(
                  new Error(MID_TURN_AT_COMMAND_RESOLVE_TIMEOUT_MESSAGE)
                );
              }, MID_TURN_AT_COMMAND_RESOLVE_TIMEOUT_MS);
              try {
                const atCommandResult = await resolveWithAbort(
                  atCommandSignal,
                  () => resolveAtCommandQuery({
                    query: msg,
                    config,
                    onDebugMessage,
                    messageId: midTurnTimestamp + index,
                    signal: atCommandSignal
                  })
                );
                const shouldSkipMidTurnMessage = !atCommandResult.shouldProceed && (atCommandResult.toolDisplays?.length ?? 0) > 0;
                if (atCommandResult.shouldProceed && atCommandResult.processedQuery !== null) {
                  resolvedMidTurnQuery = atCommandResult.processedQuery;
                } else if (atCommandResult.toolDisplays?.length) {
                  addItem(
                    { type: "tool_group", tools: atCommandResult.toolDisplays },
                    midTurnTimestamp + index
                  );
                }
                if (atCommandResult.recording) {
                  config.getChatRecordingService?.()?.recordAtCommand?.({
                    filesRead: atCommandResult.recording.filesRead,
                    status: atCommandResult.recording.status,
                    ...atCommandResult.recording.message ? { message: atCommandResult.recording.message } : {},
                    userText: msg
                  });
                }
                if (shouldSkipMidTurnMessage) {
                  continue;
                }
              } catch (error) {
                const errorMessage = getErrorMessage(error);
                onDebugMessage(
                  `Failed to resolve mid-turn @ command: ${errorMessage}`
                );
                if (!midTurnAbort.signal.aborted) {
                  addItem(
                    {
                      type: "warning" /* WARNING */,
                      text: `Could not attach file: ${errorMessage}`
                    },
                    Date.now()
                  );
                }
                continue;
              } finally {
                clearTimeout(atCommandTimeoutId);
              }
              if (midTurnAbort.signal.aborted) {
                break;
              }
            }
            const bridgeResult = await applyVisionBridgeIfNeeded(
              resolvedMidTurnQuery,
              midTurnTimestamp + index,
              midTurnAbort.signal
            );
            if (!bridgeResult.shouldProceed) {
              if (midTurnAbort.signal.aborted) {
                break;
              }
              continue;
            }
            resolvedMidTurnQuery = bridgeResult.parts ?? resolvedMidTurnQuery;
            const midTurnUserMessageParts = prefixMidTurnUserMessageParts(
              resolvedMidTurnQuery,
              msg
            );
            const formatCheck = checkImageFormatsSupport(
              midTurnUserMessageParts
            );
            if (formatCheck.hasUnsupportedFormats) {
              addItem(
                {
                  type: "info" /* INFO */,
                  text: getUnsupportedImageFormatWarning()
                },
                Date.now()
              );
            }
            responsesToSend.push(...midTurnUserMessageParts);
            config.getChatRecordingService?.()?.recordMidTurnUserMessage(midTurnUserMessageParts, msg);
            addItem({ type: "notification" /* NOTIFICATION */, text: msg }, Date.now());
          }
        } finally {
          if (shouldTrackMidTurnAbort) {
            auxiliaryAbortRefsRef.current.delete(midTurnAbort);
            midTurnAbort.abort();
          }
        }
      }
      if (turnCancelledRef.current || abortControllerRef.current?.signal.aborted) {
        return;
      }
      submitQuery(responsesToSend, "toolResult" /* ToolResult */, promptId);
    },
    [
      submitQuery,
      markToolsAsSubmitted,
      geminiClient,
      performMemoryRefresh,
      modelSwitchedFromQuotaError,
      config,
      midTurnDrainRef,
      addItem,
      dualOutput,
      onDebugMessage,
      applyVisionBridgeIfNeeded
    ]
  );
  const pendingHistoryItems = (0, import_react5.useMemo)(
    () => [
      // Reasoning renders above the streaming answer.
      pendingThoughtItem,
      pendingHistoryItem,
      pendingRetryErrorItem,
      pendingRetryCountdownItem,
      pendingToolCallGroupDisplay
    ].filter((i) => i !== void 0 && i !== null),
    [
      pendingThoughtItem,
      pendingHistoryItem,
      pendingRetryErrorItem,
      pendingRetryCountdownItem,
      pendingToolCallGroupDisplay
    ]
  );
  (0, import_react5.useEffect)(() => {
    const saveRestorableToolCalls = /* @__PURE__ */ __name(async () => {
      if (!config.getFileCheckpointingEnabled()) {
        return;
      }
      const restorableToolCalls = toolCalls.filter(
        (toolCall) => EDIT_TOOL_NAMES.has(toolCall.request.name) && toolCall.status === "awaiting_approval" && !toolCall.request.isClientInitiated
      );
      if (restorableToolCalls.length > 0) {
        const checkpointDir = storage.getProjectTempCheckpointsDir();
        if (!checkpointDir) {
          return;
        }
        try {
          await fs2.mkdir(checkpointDir, { recursive: true });
        } catch (error) {
          if (!isNodeError(error) || error.code !== "EEXIST") {
            onDebugMessage(
              `Failed to create checkpoint directory: ${getErrorMessage(error)}`
            );
            return;
          }
        }
        for (const toolCall of restorableToolCalls) {
          const filePath = toolCall.request.args["file_path"] ?? toolCall.request.args["notebook_path"];
          if (!filePath) {
            onDebugMessage(
              `Skipping restorable tool call due to missing file_path: ${toolCall.request.name}`
            );
            continue;
          }
          try {
            const promptId = toolCall.request.prompt_id;
            const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-").replace(/\./g, "_");
            const toolName = toolCall.request.name;
            const fileName = path3.basename(filePath);
            const toolCallWithSnapshotFileName = `${timestamp}-${fileName}-${toolName}.json`;
            const clientHistory = geminiClient?.getHistoryShallow();
            const toolCallWithSnapshotFilePath = path3.join(
              checkpointDir,
              toolCallWithSnapshotFileName
            );
            await fs2.writeFile(
              toolCallWithSnapshotFilePath,
              JSON.stringify(
                {
                  history,
                  clientHistory,
                  toolCall: {
                    name: toolCall.request.name,
                    args: toolCall.request.args
                  },
                  promptId,
                  filePath
                },
                null,
                2
              )
            );
          } catch (error) {
            onDebugMessage(
              `Failed to create checkpoint for ${filePath}: ${getErrorMessage(
                error
              )}. This may indicate a problem with file system permissions.`
            );
          }
        }
      }
    }, "saveRestorableToolCalls");
    saveRestorableToolCalls();
  }, [toolCalls, config, onDebugMessage, history, geminiClient, storage]);
  const notificationQueueRef = (0, import_react5.useRef)([]);
  const [notificationTrigger, setNotificationTrigger] = (0, import_react5.useState)(0);
  const getAutonomousLoopTickResolver = (0, import_react5.useCallback)(() => {
    autonomousLoopTickResolverRef.current ??= new AutonomousLoopTickResolver();
    return autonomousLoopTickResolverRef.current;
  }, []);
  const notificationQueueSessionIdRef = (0, import_react5.useRef)(sessionStates.sessionId);
  (0, import_react5.useEffect)(() => {
    if (notificationQueueSessionIdRef.current === sessionStates.sessionId) {
      return;
    }
    notificationQueueSessionIdRef.current = sessionStates.sessionId;
    notificationQueueRef.current = [];
    autonomousLoopTickResolverRef.current?.resetCache();
  }, [sessionStates.sessionId]);
  const cronSessionIdRef = (0, import_react5.useRef)(sessionStates.sessionId);
  cronSessionIdRef.current = sessionStates.sessionId;
  (0, import_react5.useEffect)(() => {
    if (!isConfigInitialized) return;
    if (!config.isCronEnabled()) return;
    const scheduler = config.getCronScheduler();
    let stopped = false;
    void (async () => {
      try {
        await scheduler.enableDurable(cronSessionIdRef.current);
      } catch (err) {
        debugLogger3.warn(
          `Durable cron init failed \u2014 persistent tasks will not fire in this session: ${err}`
        );
      }
      if (stopped) return;
      scheduler.start(
        (job) => {
          const source = job.cronExpr === "@wakeup" ? "Loop" : "Cron";
          const autonomousMode = detectAutonomousSentinel(job.prompt);
          let label = job.prompt.slice(0, 40);
          let modelText = job.prompt;
          if (autonomousMode) {
            if (job.missed) return;
            const resolver = getAutonomousLoopTickResolver();
            const tick = resolver.resolveAutonomous(autonomousMode);
            label = "Autonomous loop tick";
            modelText = tick.modelText;
            notificationQueueRef.current.push({
              displayText: `${job.missed ? "Missed" : source}: ${label}`,
              modelText,
              sendMessageType: "cron" /* Cron */,
              onDelivered: /* @__PURE__ */ __name(() => resolver.markDelivered(), "onDelivered")
            });
            setNotificationTrigger((n) => n + 1);
            return;
          }
          notificationQueueRef.current.push({
            displayText: `${job.missed ? "Missed" : source}: ${label}`,
            modelText,
            sendMessageType: "cron" /* Cron */
          });
          setNotificationTrigger((n) => n + 1);
        }
      );
    })();
    return () => {
      stopped = true;
      const summary = scheduler.getExitSummary();
      scheduler.stop();
      if (summary) {
        process.stderr.write(summary + "\n");
      }
    };
  }, [config, getAutonomousLoopTickResolver, isConfigInitialized]);
  (0, import_react5.useEffect)(() => {
    const registry = config.getBackgroundTaskRegistry();
    registry.setNotificationCallback((displayText, modelText) => {
      notificationQueueRef.current.push({
        displayText,
        modelText,
        sendMessageType: "notification" /* Notification */
      });
      setNotificationTrigger((n) => n + 1);
    });
    return () => {
      registry.setNotificationCallback(void 0);
    };
  }, [config]);
  (0, import_react5.useEffect)(() => {
    const registry = config.getBackgroundShellRegistry();
    registry.setNotificationCallback((displayText, modelText) => {
      notificationQueueRef.current.push({
        displayText,
        modelText,
        sendMessageType: "notification" /* Notification */
      });
      setNotificationTrigger((n) => n + 1);
    });
    return () => {
      registry.setNotificationCallback(void 0);
    };
  }, [config]);
  (0, import_react5.useEffect)(() => {
    const registry = config.getMonitorRegistry();
    registry.setNotificationCallback((displayText, modelText, meta) => {
      if (meta.status === "running" && typeof registry.get === "function") {
        const entry = registry.get(meta.monitorId);
        if (!entry || entry.status !== "running") return;
      }
      notificationQueueRef.current.push({
        displayText,
        modelText,
        sendMessageType: "notification" /* Notification */
      });
      setNotificationTrigger((n) => n + 1);
    });
    return () => {
      registry.setNotificationCallback(void 0);
    };
  }, [config]);
  (0, import_react5.useEffect)(() => {
    if (streamingState === "idle" /* Idle */ && !isSubmittingQueryRef.current && notificationQueueRef.current.length > 0) {
      const queue = notificationQueueRef.current;
      const targetType = queue[0].sendMessageType;
      if (targetType === "cron" /* Cron */) {
        const item = queue.shift();
        addItem(
          { type: "notification", text: item.displayText },
          Date.now()
        );
        submitQuery(item.modelText, item.sendMessageType, void 0, {
          notificationDisplayText: item.displayText,
          onDelivered: item.onDelivered,
          onDeliveryFailed: item.onDeliveryFailed
        });
        return;
      }
      let splitIdx = 0;
      while (splitIdx < queue.length && queue[splitIdx].sendMessageType === targetType) {
        splitIdx++;
      }
      const batch = queue.splice(0, splitIdx);
      const now = Date.now();
      for (const item of batch) {
        addItem({ type: "notification", text: item.displayText }, now);
      }
      const combinedModelText = batch.map((e) => e.modelText).join("\n\n");
      const combinedDisplayText = batch.map((e) => e.displayText).join("; ");
      submitQuery(combinedModelText, targetType, void 0, {
        notificationDisplayText: combinedDisplayText
      });
    }
  }, [streamingState, submitQuery, notificationTrigger, addItem]);
  const teammateQueueRef = (0, import_react5.useRef)([]);
  const [teammateTrigger, setTeammateTrigger] = (0, import_react5.useState)(0);
  (0, import_react5.useEffect)(() => {
    let boundManager = null;
    const handleManagerChange = /* @__PURE__ */ __name((manager) => {
      if (boundManager && boundManager !== manager) {
        boundManager.setLeaderMessageCallback(null);
        teammateQueueRef.current.length = 0;
      }
      boundManager = manager;
      if (manager) {
        manager.setLeaderMessageCallback(
          (modelText, display) => {
            teammateQueueRef.current.push({ modelText, display });
            setTeammateTrigger((n) => n + 1);
          }
        );
      }
    }, "handleManagerChange");
    config.onTeamManagerChange(handleManagerChange);
    const current = config.getTeamManager();
    if (current) {
      handleManagerChange(current);
    }
    return () => {
      config.onTeamManagerChange(null, handleManagerChange);
      if (boundManager) {
        boundManager.setLeaderMessageCallback(null);
        boundManager = null;
      }
    };
  }, [config]);
  (0, import_react5.useEffect)(() => {
    if (streamingState === "idle" /* Idle */ && !isSubmittingQueryRef.current && teammateQueueRef.current.length > 0) {
      const batch = teammateQueueRef.current.splice(0);
      for (const entry of batch) {
        addItem(
          { type: "notification", text: entry.display },
          Date.now()
        );
      }
      const modelText = batch.map((e) => e.modelText).join("\n\n");
      const display = batch.map((e) => e.display).join("; ");
      submitQuery(modelText, "teammate" /* Teammate */, void 0, {
        notificationDisplayText: display
      });
    }
  }, [streamingState, submitQuery, teammateTrigger, addItem]);
  return {
    streamingState,
    submitQuery,
    initError,
    pendingHistoryItems,
    thought,
    cancelOngoingRequest,
    retryLastPrompt,
    pendingToolCalls: toolCalls,
    handleApprovalModeChange,
    activePtyId,
    loopDetectionConfirmationRequest,
    streamingResponseLengthRef,
    isReceivingContent
  };
}, "useGeminiStream");

export {
  prefixMidTurnUserMessageParts,
  DualOutputContext,
  useDualOutput,
  classifyApiError,
  useGeminiStream
};
/**
 * @license
 * Copyright 2025 Qwen Team
 * SPDX-License-Identifier: Apache-2.0
 */
/**
 * @license
 * Copyright 2026 Qwen
 * SPDX-License-Identifier: Apache-2.0
 */
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
