ChatGPT умирает на длинных разговорах. Не AI-часть — модель отлично держит тысячи сообщений. Умирает фронтенд. Таб зависает, скролл лагает, иногда браузер просто крашится.

Самое обидное — именно длинные разговоры самые ценные. Чем дольше обсуждаешь, тем больше контекста у модели, тем полезнее ответы. А продукт ломается ровно в тот момент, когда начинается максимальная отдача.

Мне это надоело и я полез разбираться.

Что происходит под капотом

Когда вы открываете разговор, ChatGPT делает запрос на /backend-api/conversation/{id}. В ответе приходит JSON с полем mapping — объект, где каждый ключ это ID сообщения, а значение — нода с контентом, parent-ссылкой и списком children.

{
  "mapping": {
    "abc-123": {
      "message": { "content": { "parts": ["..."] }, "author": { "role": "user" } },
      "parent": "abc-122",
      "children": ["abc-124"]
    }
  },
  "current_node": "abc-999"
}

React получает этот объект целиком и рендерит все ноды в DOM. Каждое сообщение — это не один <div>, а дерево: аватар, контент, кнопки, подсветка кода, MathJax-формулы. Одно сообщение ≈ 250 DOM-нод.

Считаем:

  • 500 сообщений → ~125 000 DOM-нод

  • 2 000 сообщений → ~500 000 DOM-нод

Chrome начинает задыхаться на ~100K нод. При полумиллионе таб просто ложится. Виртуализации списка нет.

Решение

Идея тривиальная: перехватить ответ API до того как React его получит, и обрезать mapping до последних N сообщений.

1. Перехват fetch. Content script с "world": "MAIN" позволяет подменить window.fetch:

const originalFetch = window.fetch;

window.fetch = async function(...args) {
  const url = typeof args[0] === 'string' ? args[0] : args[0]?.url || '';
  
  if (!/\/backend-api\/conversation\/[0-9a-f-]{36}$/.test(url)) {
    return originalFetch.apply(this, args);
  }
  
  const response = await originalFetch.apply(this, args);
  const data = await response.clone().json();
  const truncated = truncateMapping(data, 100);
  
  return new Response(JSON.stringify(truncated), {
    status: response.status,
    headers: response.headers,
  });
};

2. Обрезка. Идём от current_node по цепочке parent, собираем последние N сообщений:

function truncateMapping(data, max) {
  const keep = new Set();
  let id = data.current_node;
  let count = 0;

  while (id && count < max) {
    const node = data.mapping[id];
    if (!node) break;
    keep.add(id);
    if (node.message?.content) count++;
    id = node.parent;
  }

  const result = {};
  for (const id of keep) {
    const node = { ...data.mapping[id] };
    node.children = node.children?.filter(c => keep.has(c)) || [];
    if (node.parent && !keep.has(node.parent)) node.parent = null;
    result[id] = node;
  }

  return { ...data, mapping: result };
}

3. Кэш. Полный JSON сохраняется в Map. Кнопка "загрузить ещё" увеличивает окно и пересобирает из кэша — без повторного запроса.

Результат

  • Разговор на 3000+ сообщений грузится мгновенно

  • AI видит полную историю (обрезка только на стороне рендеринга)

  • 30 КБ, ноль зависимостей, ноль внешних запросов

Задача уровня react-window — библиотеки на 6KB, которая существует с 2018 года. Чинится за вечер. Одним человеком. В Chrome extension.

Ссылки

Если у вас есть длинные разговоры в ChatGPT которые вы боитесь открывать — попробуйте.

* * *

А, чуть не забыл:

Как починить фронтенд продукта компании за $800B за вечер?

Да просто надо как следует разозлиться, упереться рогом, и разобраться как оно устроено. Код за вас напишет AI.

Комментарии (6)


  1. AllFiction
    28.02.2026 16:47

    раз пользуются - значит баг не критичный!

    у них фронт-енды другим полезным заняты, например как бы так оформить отказ от подписки что бы люди не отписывались? (спойлер, нужно отказаться дважды в одном и том же окне иначе в первый раз вам "бесплатно продлит" что бы за следующий списать деньги как время подойдет)

    вообще интересная тема, можно озадачить своего клода что бы написал для мозилы плагин как раз для такого. вообще очень интересная тематика написаний решений "под себя" прямо в момент нейронками, за этом будущее. У самого мелкая зарисовка на эту тему до сих пор в песочнице весит))


    1. nem Автор
      28.02.2026 16:47

      все так ;)


  1. frog
    28.02.2026 16:47

    У Gemini (тот, который "AI Mode" в поиске гугла) похожая история. На длинных чатах начинает игнорировать вопросы (просто молчит, иногда выдаёт странные ошибки), при этом на "hey" - отвечает так, как будто он уже давал ответ (и повторяет его). При этом если открыть новый чат, всё сразу опять работает без ошибок и молчаний (ну, разумеется с потерей всего контекста).


  1. mpetrunin
    28.02.2026 16:47

    Ужасно раздражающая штука и отличное дополнение!

    Готов PR для поддержки Firefox.


  1. albatross
    28.02.2026 16:47

    Спасибо за расширение!

    В файле background.js есть логирование в консоль метаданных чата и превью сообщений:
    https://github.com/inem/Unfreeze-for-ChatGPT/blob/main/background.js#L26-L29
    https://github.com/inem/Unfreeze-for-ChatGPT/blob/main/background.js#L49-L53

    Это может быть хорошо для дебага в процессе разработки, но не очень хорошо для расширения предлагаемого для установки пользователям, т.к. кроме бесполезного информационного шума в логах это так же потенциально может увеличить риск утечки чувствительной информации.
    Имеет смысл либо удалить логирование полностью, либо сделать его опциональным и выключенным по умолчанию.


  1. Kwentin3
    28.02.2026 16:47

    Гранд респект!!!!