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: Определение структуры агрегированной статистики