Skip to content

Сохранение состояния: история обрезки между сессиями

Чему вы научитесь

  • Понимать, как DCP сохраняет состояние обрезки между перезапусками OpenCode
  • Знать расположение и формат файлов персистентности
  • Освоить логику управления состоянием при переключении сессий и сжатии контекста
  • Просматривать накопленную экономию токенов по всем сессиям через /dcp stats

Ваша текущая проблема

Вы закрыли OpenCode, открыли его снова и обнаружили, что предыдущие записи об обрезке исчезли? Или хотите узнать, откуда берётся «накопленная экономия по всем сессиям» в /dcp stats?

Механизм сохранения состояния DCP автоматически сохраняет историю обрезки и статистику в фоновом режиме, обеспечивая их доступность после перезапуска.

Когда это пригодится

  • Когда нужна накопительная статистика экономии токенов между сессиями
  • Когда нужно продолжить историю обрезки после перезапуска OpenCode
  • При длительном использовании DCP для оценки общего эффекта

Основная концепция

Что такое сохранение состояния

Сохранение состояния — это механизм, при котором DCP записывает историю обрезки и статистику на диск, гарантируя, что эта информация не потеряется после перезапуска OpenCode или переключения сессий.

Зачем нужна персистентность?

Без персистентности при каждом закрытии OpenCode:

  • Список ID обрезанных инструментов теряется
  • Статистика экономии токенов обнуляется
  • ИИ может повторно обрезать один и тот же инструмент

С персистентностью DCP может:

  • Помнить, какие инструменты уже обрезаны
  • Накапливать экономию токенов по всем сессиям
  • Продолжать работу после перезапуска

Два типа сохраняемых данных

Состояние, сохраняемое DCP, включает два типа информации:

ТипСодержимоеНазначение
Состояние обрезкиСписок ID обрезанных инструментовИзбежание повторной обрезки, отслеживание между сессиями
СтатистикаКоличество сэкономленных токенов (текущая сессия + накопленное)Демонстрация эффективности DCP, анализ долгосрочных тенденций

Эти данные хранятся отдельно для каждой сессии OpenCode — каждая сессия соответствует отдельному JSON-файлу.

Поток данных

mermaid
graph TD
    subgraph "Операции обрезки"
        A1[ИИ вызывает discard/extract]
        A2[Пользователь выполняет /dcp sweep]
    end

    subgraph "Состояние в памяти"
        B1[SessionState.prune.toolIds]
        B2[SessionState.stats]
    end

    subgraph "Персистентное хранилище"
        C1[~/.local/share/opencode/storage/plugin/dcp/]
        C2[{sessionId}.json]
    end

    A1 --> B1
    A2 --> B1
    B1 -->|Асинхронное сохранение| C1
    B2 -->|Асинхронное сохранение| C1
    C1 --> C2

    C2 -->|Загрузка при переключении сессии| B1
    C2 -->|Загрузка при переключении сессии| B2

    D[Сообщение summary от OpenCode] -->|Очистка кэша| B1

Пошаговое руководство

Шаг 1: Узнайте расположение хранилища

Зачем Зная, где хранятся данные, вы сможете проверить или удалить их вручную (при необходимости)

DCP сохраняет состояние в локальной файловой системе, данные не загружаются в облако.

bash
# Расположение директории персистентности
~/.local/share/opencode/storage/plugin/dcp/

# Каждая сессия — отдельный JSON-файл в формате: {sessionId}.json

Ожидаемый результат: В директории может быть несколько файлов .json, каждый соответствует отдельной сессии OpenCode

Конфиденциальность данных

DCP сохраняет локально только состояние обрезки и статистику, без какой-либо конфиденциальной информации. Файлы персистентности содержат:

  • Список ID инструментов (числовые идентификаторы)
  • Количество сэкономленных токенов (статистика)
  • Время последнего обновления (временная метка)

Содержимое диалогов, вывод инструментов или пользовательский ввод не сохраняются.

Шаг 2: Изучите формат файлов персистентности

Зачем Понимание структуры файлов поможет при ручной проверке или отладке

bash
# Список всех файлов персистентности
ls -la ~/.local/share/opencode/storage/plugin/dcp/

# Просмотр содержимого персистентности конкретной сессии
cat ~/.local/share/opencode/storage/plugin/dcp/{sessionId}.json

Ожидаемый результат: JSON-структура примерно такого вида

json
{
  "sessionName": "Название моей сессии",
  "prune": {
    "toolIds": ["12345", "12346", "12347"]
  },
  "stats": {
    "pruneTokenCounter": 0,
    "totalPruneTokens": 15420
  },
  "lastUpdated": "2026-01-23T10:30:45.123Z"
}

Описание полей:

ПолеТипЗначение
sessionNamestring (опционально)Название сессии для удобства идентификации
prune.toolIdsstring[]Список ID обрезанных инструментов
stats.pruneTokenCounternumberТокены, сэкономленные в текущей сессии (не архивированы)
stats.totalPruneTokensnumberНакопленная историческая экономия токенов
lastUpdatedstringВремя последнего обновления в формате ISO 8601

Шаг 3: Просмотр накопленной статистики

Зачем Оценить накопленный эффект по всем сессиям и долгосрочную ценность DCP

bash
# Выполните в OpenCode
/dcp stats

Ожидаемый результат: Панель статистики

╭───────────────────────────────────────────────────────────╮
│                    DCP Statistics                         │
╰───────────────────────────────────────────────────────────╯

Session:
────────────────────────────────────────────────────────────
  Tokens pruned: ~15.4K
  Tools pruned:   3

All-time:
────────────────────────────────────────────────────────────
  Tokens saved:  ~154.2K
  Tools pruned:   47
  Sessions:       12

Значение статистики:

ПоказательИсточникОписание
SessionТекущее состояние в памятиЭффект обрезки в текущей сессии
All-timeВсе файлы персистентностиНакопленный эффект по всем историческим сессиям

Как рассчитывается статистика All-time

DCP перебирает все JSON-файлы в директории ~/.local/share/opencode/storage/plugin/dcp/ и суммирует:

  • totalPruneTokens: Общее количество сэкономленных токенов по всем сессиям
  • toolIds.length: Общее количество обрезанных инструментов по всем сессиям
  • Количество файлов: Общее число сессий

Так вы можете видеть общий эффект DCP при длительном использовании.

Шаг 4: Понимание механизма автосохранения

Зачем Знание того, когда DCP сохраняет состояние, поможет избежать случайной потери данных

DCP автоматически сохраняет состояние на диск в следующих случаях:

ТриггерСохраняемые данныеМесто вызова
После вызова ИИ инструментов discard/extractОбновлённое состояние обрезки + статистикаlib/strategies/tools.ts:148-150
После выполнения пользователем команды /dcp sweepОбновлённое состояние обрезки + статистикаlib/commands/sweep.ts:234-236
После завершения операции обрезкиАсинхронное сохранение, не блокирует основной потокsaveSessionState()

Процесс сохранения:

typescript
// 1. Обновление состояния в памяти
state.stats.totalPruneTokens += state.stats.pruneTokenCounter
state.stats.pruneTokenCounter = 0

// 2. Асинхронное сохранение на диск
await saveSessionState(state, logger)

Преимущества асинхронного сохранения

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

При неудаче записывается предупреждение в лог ~/.config/opencode/logs/dcp/.

Шаг 5: Понимание механизма автозагрузки

Зачем Знание того, когда DCP загружает персистентное состояние, поможет понять поведение при переключении сессий

DCP автоматически загружает персистентное состояние в следующих случаях:

ТриггерЗагружаемые данныеМесто вызова
При запуске OpenCode или переключении сессииИсторическое состояние обрезки + статистика этой сессииlib/state/state.ts:104 (внутри функции ensureSessionInitialized)

Процесс загрузки:

typescript
// 1. Обнаружение изменения ID сессии
if (state.sessionId !== lastSessionId) {
    await ensureSessionInitialized(client, state, lastSessionId, logger, messages)
}

// 2. Сброс состояния в памяти
resetSessionState(state)
state.sessionId = lastSessionId

// 3. Загрузка персистентного состояния с диска
const persisted = await loadSessionState(sessionId, logger)
if (persisted) {
    state.prune = { toolIds: persisted.prune.toolIds }
    state.stats = {
        pruneTokenCounter: persisted.stats.pruneTokenCounter,
        totalPruneTokens: persisted.stats.totalPruneTokens
    }
}

Ожидаемый результат: После переключения на предыдущую сессию /dcp stats показывает сохранённую историческую статистику

Шаг 6: Понимание очистки состояния при сжатии контекста

Зачем Понять, как DCP обрабатывает состояние при автоматическом сжатии контекста OpenCode

Когда OpenCode обнаруживает слишком длинный диалог, он автоматически генерирует сообщение summary для сжатия контекста. DCP обнаруживает это сжатие и очищает соответствующее состояние.

typescript
// Обработка при обнаружении сообщения summary
if (lastCompactionTimestamp > state.lastCompaction) {
    state.lastCompaction = lastCompactionTimestamp
    state.toolParameters.clear()  // Очистка кэша инструментов
    state.prune.toolIds = []       // Очистка состояния обрезки
    logger.info("Detected compaction from messages - cleared tool cache")
}

Зачем нужна очистка?

Сообщение summary от OpenCode сжимает всю историю диалога, при этом:

  • Старые вызовы инструментов уже объединены в summary
  • Сохранение списка ID инструментов теряет смысл (инструменты больше не существуют)
  • Очистка состояния предотвращает ссылки на недействительные ID инструментов

Это проектный компромисс: жертвуем частью истории обрезки ради согласованности состояния.

Контрольные точки ✅

Убедитесь, что вы понимаете следующие ключевые моменты:

  • [ ] Файлы персистентности DCP хранятся в ~/.local/share/opencode/storage/plugin/dcp/
  • [ ] Каждая сессия соответствует файлу {sessionId}.json
  • [ ] Персистентные данные включают состояние обрезки (toolIds) и статистику (totalPruneTokens)
  • [ ] Статистика «All-time» в /dcp stats — это сумма данных из всех файлов персистентности
  • [ ] После операций обрезки выполняется автоматическое асинхронное сохранение без блокировки основного потока
  • [ ] При переключении сессии автоматически загружается историческое состояние этой сессии
  • [ ] При обнаружении сообщения summary от OpenCode очищается кэш инструментов и состояние обрезки

Типичные ошибки

❌ Случайное удаление файлов персистентности

Проблема: Вручную удалены файлы в директории ~/.local/share/opencode/storage/plugin/dcp/

Последствия:

  • Потеря исторического состояния обрезки
  • Обнуление накопленной статистики
  • Но функция обрезки в текущей сессии не затрагивается

Решение: Начните использование заново, DCP автоматически создаст новые файлы персистентности

❌ Состояние субагента не видно

Проблема: Инструменты обрезаны в субагенте, но при возврате к главному агенту эти записи не видны

Причина: Субагент имеет собственный sessionId, состояние обрезки сохраняется в отдельный файл. При переключении обратно на главный агент, поскольку его sessionId отличается, персистентное состояние субагента не загружается

Решение: Это проектное поведение. Состояние сессии субагента независимо и не разделяется с главным агентом. Если вы хотите видеть все записи обрезки (включая субагенты), используйте статистику «All-time» в /dcp stats (она суммирует данные из всех файлов персистентности)

❌ Ошибка сохранения из-за нехватки места на диске

Проблема: Статистика «All-time» в /dcp stats не растёт

Причина: Возможно, недостаточно места на диске, сохранение не удалось

Решение: Проверьте файлы логов ~/.config/opencode/logs/dcp/ на наличие ошибки «Failed to save session state»

Итоги урока

Ключевая ценность сохранения состояния:

  1. Память между сессиями: Запоминает, какие инструменты уже обрезаны, избегая повторной работы
  2. Накопительная статистика: Долгосрочное отслеживание эффекта экономии токенов DCP
  3. Восстановление после перезапуска: Продолжение работы после перезапуска OpenCode

Сводка потока данных:

Операция обрезки → Обновление состояния в памяти → Асинхронное сохранение на диск

Переключение сессии → Загрузка с диска → Восстановление состояния в памяти

Сжатие контекста → Очистка состояния в памяти (файлы на диске не удаляются)

Ключевые моменты:

  • Персистентность — это локальная файловая операция, не влияющая на производительность обрезки
  • «All-time» в /dcp stats — это сумма данных всех исторических сессий
  • Сессии субагентов не персистируются — это проектное поведение
  • При сжатии контекста кэш очищается для обеспечения согласованности состояния

Анонс следующего урока

В следующем уроке мы изучим Влияние на кэширование промптов.

Вы узнаете:

  • Как обрезка DCP влияет на Prompt Caching
  • Как балансировать между попаданием в кэш и экономией токенов
  • Механизм тарификации кэширования Anthropic

Приложение: Справочник по исходному коду

Нажмите, чтобы развернуть расположение исходного кода

Дата обновления: 2026-01-23

ФункцияПуть к файлуСтроки
Определение интерфейса персистентностиlib/state/persistence.ts14-19
Сохранение состояния сессииlib/state/persistence.ts33-66
Загрузка состояния сессииlib/state/persistence.ts68-101
Загрузка статистики всех сессийlib/state/persistence.ts109-146
Константа директории хранилищаlib/state/persistence.ts21
Инициализация состояния сессииlib/state/state.ts80-116
Обнаружение сжатия контекстаlib/state/state.ts118-126
Обработка команды статистикиlib/commands/stats.ts46-67
Сохранение состояния при обрезкеlib/strategies/tools.ts144-150

Ключевые константы:

  • STORAGE_DIR = ~/.local/share/opencode/storage/plugin/dcp: Корневая директория хранилища файлов персистентности

Ключевые функции:

  • saveSessionState(state, logger): Асинхронное сохранение состояния сессии на диск
  • loadSessionState(sessionId, logger): Загрузка состояния указанной сессии с диска
  • loadAllSessionStats(logger): Агрегация статистики всех сессий
  • ensureSessionInitialized(client, state, sessionId, logger, messages): Обеспечение инициализации сессии с загрузкой персистентного состояния

Ключевые интерфейсы:

  • PersistedSessionState: Определение структуры персистентного состояния
  • AggregatedStats: Определение структуры агрегированной статистики