function formatHistoryForDisplay()

in codex-cli/src/components/history-overlay.tsx [101:168]


function formatHistoryForDisplay(items: Array<ResponseItem>): {
  commands: Array<string>;
  files: Array<string>;
} {
  const commands: Array<string> = [];
  const filesSet = new Set<string>();

  for (const item of items) {
    const userPrompt = processUserMessage(item);
    if (userPrompt) {
      commands.push(userPrompt);
      continue;
    }

    // ------------------------------------------------------------------
    // We are interested in tool calls which – for the OpenAI client – are
    // represented as `function_call` response items. Skip everything else.
    if (item.type !== "function_call") {
      continue;
    }

    const { name: toolName, arguments: argsString } = item as unknown as {
      name: unknown;
      arguments: unknown;
    };

    if (typeof argsString !== "string") {
      // Malformed – still record the tool name to give users maximal context.
      if (typeof toolName === "string" && toolName.length > 0) {
        commands.push(toolName);
      }
      continue;
    }

    // Best‑effort attempt to parse the JSON arguments. We never throw on parse
    // failure – the history view must be resilient to bad data.
    let argsJson: unknown = undefined;
    try {
      argsJson = JSON.parse(argsString);
    } catch {
      argsJson = undefined;
    }

    // 1) Shell / exec‑like tool calls expose a `cmd` or `command` property
    //    that is an array of strings. These are rendered as the joined command
    //    line for familiarity with traditional shells.
    const argsObj = argsJson as Record<string, unknown> | undefined;
    const cmdArray: Array<string> | undefined = Array.isArray(argsObj?.["cmd"])
      ? (argsObj!["cmd"] as Array<string>)
      : Array.isArray(argsObj?.["command"])
        ? (argsObj!["command"] as Array<string>)
        : undefined;

    if (cmdArray && cmdArray.length > 0) {
      commands.push(processCommandArray(cmdArray, filesSet));
      continue; // We processed this as a command; no need to treat as generic tool call.
    }

    // 2) Non‑exec tool calls – we fall back to recording the tool name plus a
    //    short argument representation to give users an idea of what
    //    happened.
    if (typeof toolName === "string" && toolName.length > 0) {
      commands.push(processNonExecTool(toolName, argsJson, filesSet));
    }
  }

  return { commands, files: Array.from(filesSet) };
}