Files
opencode2-context-panel/README.md
T
k.denisov 1eef73ec22 README со скриншотом панели
Что показывает вкладка «Токены», как устроен прокси внутри OpenCode, установка
без обёртки, переменные окружения, запуск server.mjs отдельно под Node.
2026-10-29 21:28:30 -07:00

124 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# context-panel
Панель «Токены» для веб-интерфейса OpenCode 2: что сейчас лежит в контексте сессии, как он рос и сколько
токенов ушло за сессию, за день и за всё время. Работает как плагин OpenCode и поднимается в его же процессе.
<img src="docs/panel.png" alt="Вкладка «Токены» в боковой панели OpenCode" width="600">
## Что на вкладке
В шапке сессии появляется кнопка с кружком и % заполнения контекста. Она открывает боковую панель на вкладке
**«Токены»** рядом с Review и Context; вкладку можно выбрать и вручную. Кнопка и вкладка повторяют разметку
OpenCode, поэтому стили у них родные. Если OpenCode перерисует интерфейс, `panel.js` вставит их заново.
- **Состав контекста.** Сколько токенов было в последнем запросе к модели (как в самом OpenCode) из лимита
модели. Разбивка по категориям: сообщения, ответы, reasoning, вывод каждого тула (MCP отдельно,
`gitlab: …`, `jira: …`; для Code Mode — какие MCP вызывал скрипт), сводка compaction. Учитывается только
то, что сейчас в контексте, — его отдаёт сам OpenCode (`/api/session/{id}/context`). Категории считаются как
символы/4, так же оценивает сам OpenCode. «Остаток» — это разница между реальным числом токенов и суммой
оценок: системный промпт, AGENTS.md, схемы тулов и MCP, плюс погрешность.
- **Рост контекста по шагам.** Токенов в каждом запросе к модели за всю сессию, линия лимита модели и отметки
compaction. Под графиком — список compaction: когда, авто или вручную, контекст до и после, размер сводки,
сколько заняло. Провал на графике без отметки compaction — это чистка вывода тулов (prune / DCP).
- **Самые тяжёлые вызовы в контексте.** Топ-10 вызовов тулов в текущем контексте: тул, что вызывали (файл,
команда, описание), токены входа и вывода.
- **Расход за сессию.** Input, cache read/write, output, reasoning, число шагов модели. Если были сабагенты,
рядом показан итог вместе с ними.
- **Скорость модели в сессии.** Генерация (output + reasoning за время потока, ток/с), среднее ожидание первого
токена, prefill (input без кэша за это время, ток/с) и среднее время модели на шаг. Начало потока — первая
часть ответа, конец — `time.streamed` сообщения. Выполнение тулов не считается.
- **Расход за сегодня / 7 дней / 30 дней / всё время**, по проекту или по всем проектам, плюс топ моделей
(со скоростью генерации и временем на шаг). Над таблицей — график с выбором периода: сегодня по часам, 7 и
30 дней по дням, всё время по дням или по неделям, если история длиннее 90 дней. Столбики разбиты по типу
токенов (Cache / Input / Output) или по моделям (топ-4 + «другие»).
Каждый раздел сворачивается кликом по заголовку; какие свёрнуты — запоминается в браузере (`localStorage`).
Данные обновляются раз в 3 секунды, пока вкладка выбрана, % на кнопке — раз в 10 секунд.
## Как устроено
У веб-интерфейса OpenCode нет точек расширения: он зашит в бинарник, слоты для плагинов есть только в TUI, а
своих HTTP-маршрутов серверный плагин добавить не может. Поэтому плагин `context-panel.v2.ts` поднимает внутри
процесса OpenCode прокси (`server.mjs`) на отдельном порту. Прокси пропускает HTTP, SSE и WebSocket как есть, а
в HTML-страницы вставляет `<script src="/__ctx/panel.js">`. CSP страницы (`script-src 'self'`) скрипт
пропускает: он с того же origin. Service worker веб-интерфейса прокси подменяет «гасящим», иначе тот отдавал бы
страницу из кэша без панели.
```
браузер → :4196 server.mjs (в процессе OpenCode) ─┬─ /__ctx/panel.js, /__ctx/api/* → opencode.db (только чтение) + API OpenCode
└─ всё остальное → :4197 opencode serve
```
`/__ctx/*` закрыт тем же паролем, что и сам OpenCode: прокси сверяет заголовок `Authorization` с OpenCode и с
ним же берёт из API лимит модели и текущий контекст сессии. Зависимостей нет: в OpenCode база читается через
`bun:sqlite`, под Node ≥ 22.5 — через `node:sqlite`.
Особенности плагинов OpenCode 2 (проверено на 2.1.3):
- **Плагин грузится лениво** — при первом запросе к API проекта, а не при старте `opencode serve`. Пока такого
запроса не было, порт панели пуст. Поэтому после старта нужно один раз дёрнуть API (см. «Установка»).
- **Модуль импортируется заново для каждого проекта.** Прокси один на процесс (флаг в `globalThis`).
- **При выгрузке проекта прокси не закрывается.** Браузер ходит через него, и без прокси OpenCode не получил
бы запрос, который загрузит плагин снова. Живёт, пока жив процесс.
## Установка
1. Положить ссылку на плагин в `plugins/` конфига OpenCode (в `"plugin"` в `opencode.jsonc` не добавлять:
имя там считается npm-пакетом). `server.mjs` и `panel.js` плагин ищет рядом с настоящим файлом:
```bash
ln -sfn "$PWD/context-panel.v2.ts" "${XDG_CONFIG_HOME:-$HOME/.config}/opencode/plugins/"
```
2. Запустить OpenCode на соседнем порту и сказать плагину, где слушать:
```bash
CTX_PANEL_LISTEN=4196 CTX_PANEL_TARGET=4197 opencode serve --hostname 127.0.0.1 --port 4197
```
3. Загрузить плагин первым запросом к API и открыть `http://127.0.0.1:4196/` (на 4197 панели нет):
```bash
curl -s -o /dev/null -u opencode:"$OPENCODE_SERVER_PASSWORD" http://127.0.0.1:4197/api/plugin
```
Переменные окружения плагина:
| Переменная | По умолчанию | Что |
| --- | --- | --- |
| `CTX_PANEL_LISTEN` | `4196` | порт прокси с панелью |
| `CTX_PANEL_TARGET` | `4197` | порт самого `opencode serve` |
| `CTX_PANEL_DB` | `$XDG_DATA_HOME/opencode/opencode.db` | база OpenCode |
| `OPENCODE_CONTEXT_PANEL` | — | `0` — не запускать |
Журнал плагина: `$XDG_DATA_HOME/opencode/log/context-panel.log` (на каком порту поднялся или почему нет).
В mms-challenge всё это делает обёртка `egress-filter/bin/opencode-web` (`make opencode`): кладёт ссылку,
передаёт порты, после старта дёргает API, ждёт порт 4196 и только потом открывает браузер. Выключить панель:
`OPENCODE_CONTEXT_PANEL=0 make opencode`.
### Без плагина
Тот же `server.mjs` можно запустить отдельным процессом под Node перед уже запущенным OpenCode:
```bash
node --disable-warning=ExperimentalWarning server.mjs --listen 4196 --target 4197 \
--db "${XDG_DATA_HOME:-$HOME/.local/share}/opencode/opencode.db"
```
### Проверка
```bash
curl -s -u opencode:"$OPENCODE_SERVER_PASSWORD" http://127.0.0.1:4196/ -H 'accept: text/html' | grep -c __ctx/panel.js
```
Должно вывести `1`. Если панели нет — смотреть `context-panel.log` и консоль браузера. Если открыта старая
вкладка, её нужно перезагрузить.
## Разработка
- Правки в `panel.js` применяются после перезагрузки страницы, правки в `server.mjs` и `context-panel.v2.ts` —
после перезапуска OpenCode.
- Панель читает внутреннюю схему `opencode.db` (таблицы `session_v2`, `session_message`). Если после обновления
OpenCode она перестанет показывать данные, смотреть надо в `sessionStatsV2` / `globalRowsV2` в `server.mjs`.