В первой части, «Kimi Code, MiniMax Code и ZCode в OpenResearch: форк за один вечер вместе с Claude», мы добавили в OpenResearch три новых coding-агента. Статья вышла 25 сентября вместе с релизом v0.3.2. Эта часть о том, что было дальше. Форк нужно было сопровождать: чинить ошибки, о которых написали читатели, догонять upstream и переделывать интеграцию ZCode под его новые версии.

Итоги в цифрах:

  • 8 релизов, от v0.3.3 до v0.3.10, за три недели, с 28 сентября по 16 октября;

  • около 11 ч 16 мин чистой работы агента, растянутых на 18 дней (в первой части было 1 ч 51 мин);

  • 33 коммита Claude, +5258/−1090 строк в 61 файле (без собранного ui/dist), 28 новых тестов;

  • четыре слияния с upstream, в сумме 121 его коммит;

  • два PR в upstream: #600 с тремя агентами и #650 с русской локализацией;

  • $32 реальных затрат, по ценам API это стоило бы больше $230. Подробности в конце.

Форк OpenResearch, от v0.3.2 до v0.3.10
Форк OpenResearch, от v0.3.2 до v0.3.10

С чего всё началось: комментарий читателя

Через два дня после публикации пришёл комментарий:

Не знаю, что ты там навайбкодил, друже, но с ZCode твой форк работать отказывается - выдает ошибку выбора модели.

Позже @OnAdmin продублировал его в личку, уже с подробностью: у него был Max-план. Ни там, ни в комментариях на мои ответы он больше не отвечал. Но и одной фразы хватило, чтобы найти настоящую проблему: в первой части ZCode работал только у меня.

Хронология

Хронология: восемь релизов с 28 сентября по 16 октября
Хронология: восемь релизов с 28 сентября по 16 октября

Версия

Дата (UTC)

Что вошло

v0.3.3

28.09

Вход в ZCode из дашборда, понятные ошибки ZCode. Kimi показывает команду в карточке подтверждения. Upstream 0.2.11

v0.3.4

06.10

Выбор модели для ZCode и проверка аккаунта. Upstream 0.2.16, это 57 коммитов

v0.3.5

06.10

Собственное десктоп-приложение форка для Windows и Linux

v0.3.6

08.10

Исправления по первому ревью Greptile в upstream. Upstream 0.2.17

v0.3.7

08.10

Ещё одна порция исправлений по ревью Greptile

v0.3.8

13.10

Вход в ZCode 3.15, русская локализация, новая иконка MiniMax

v0.3.9

15.10

ZCode через app-server: подтверждения, Plan, переключатель провайдера

v0.3.10

16.10

Исправления по второму ревью Greptile

Работа шла так же, как в первой части. Claude работал в облачном Linux-контейнере, а я проверял каждую сборку на своей Windows 10 с настоящими аккаунтами. Перед каждым релизом я ставил установщик из CI и писал «ок» или присылал скриншот с ошибкой. Без моего «ок» Claude PR не сливал.

Сложности и как мы их решали

На этот раз почти все сбои пришли от ZCode. Три недели этот агент менялся быстрее, чем мы успевали под него подстраиваться.

Диаграмма Исикавы: сбои после первой статьи по пяти источникам – вход в ZCode, новые версии ZCode, Windows, модели и ключи, наши тесты и ревью
Диаграмма Исикавы: сбои после первой статьи по пяти источникам – вход в ZCode, новые версии ZCode, Windows, модели и ключи, наши тесты и ревью

ZCode: вход и модели

1. «Ошибка выбора модели» у читателя. Ход ZCode в таком случае падает с сообщением Select a model before continuing. Причина в том, что вход в десктоп-приложение ZCode не даёт моделей рантайму, которым пользуется orx. Командной строке нужен свой вход, zcode login, а в первой части orx про него не знал.

Исправление в v0.3.3:

  • в Settings → Harnesses → ZCode появилась кнопка Sign in, она запускает zcode login --no-browser через рантайм десктопа;

  • ссылку для входа orx открывает сам: собственный cmd /c start ZCode обрезал URL на первом &;

  • ZCode считается подключённым только после zcode login или если есть провайдер с API-ключом;

  • ошибки Select a model и Z.ai 1113 объясняют, что делать.

Выяснилось и неприятное: тариф Start Plan вне приложения не работает вообще. Его эндпоинт требует капчу, которую проходит только приложение (код 3007), а эндпоинты Coding Plan отвечают такому аккаунту 1113.

2. Ключ чужого аккаунта. Следующая ловушка давала ту же Select a model, хотя orx показывал «Вход выполнен». ZCode хранит в credentials.json два значения: identity аккаунта и ключ плана. Если войти в приложение под другим аккаунтом, ключ заменится, а identity останется от zcode login. Такой ключ рантайм не использует.

Чтобы это отличать, orx научился расшифровывать credentials.json собственным ключом ZCode (AES-256-GCM). Для теста взят вектор, зашифрованный настоящим Node.js. Теперь при чужом ключе orx просит снова выполнить zcode login, а не показывает «вход выполнен».

3. Модель для каждого чата. В режиме печати у ZCode нет флага --model. Единственный способ выбрать модель – записать её в defaultModelSelection в общем provider_config.json, тот самый, который читает приложение. В v0.3.4 orx стал так делать. Greptile в ревью upstream нашёл гонку: два чата, запущенные одновременно, перезаписывают друг другу модель. Исправление в v0.3.7: чат держит блокировку от записи до момента, когда рантайм сообщил, на какой модели работает.

4. ZCode 3.15 сломал вход заново. Версия ZCode 3.15.1 вышла 12 октября, 3.15.3 – 13 октября. Я обновился до 3.15.3, и 13 октября у меня вдруг снова появилось «Вход не выполнен», а zcode login в терминале дашборда висел без вывода.

В списке изменений ZCode об этом почти ничего нет. У 3.15.3 есть одна строка про вход: «Fixed an issue where login authentication could fail in certain scenarios» – исправлена ошибка входа, из-за которой не подключался план на странице настроек. Что способ входа изменился, там не сказано. Claude нашёл это сам, в коде рантайма 3.15.3. Причин оказалось две.

  • В 3.15 Coding Plan входит по OAuth-токену, а не по ключу плана. Какой из них использовать, говорит новая запись account-provider:<id>:auth-source. orx знал только про ключ.

  • ZCode.exe – GUI-программа Windows. К псевдоконсоли (ConPTY), в которой orx запускает команды настройки, она не подключается, и её вывод пропадает. Решение: zcode login теперь запускается через PowerShell с конвейером, который заставляет ждать GUI-процесс и отдаёт его вывод построчно. Заодно выяснилось, что терминал переносил длинную ссылку для входа, и orx открывал её обрезанной перед &state=.

Блок-схема: как orx определяет вход в ZCode 3.15 по записи auth-source – ключ плана, OAuth-токен или любой из них для входа до 3.15
Блок-схема: как orx определяет вход в ZCode 3.15 по записи auth-source – ключ плана, OAuth-токен или любой из них для входа до 3.15

ZCode: переход на app-server

В первой части я написал, что app-server ZCode «говорит на закрытом протоколе», поэтому мы взяли режим печати zcode -p --output-format stream-json.

Точнее было бы так: исходники были, протокол не описан. У открытых исходников ZCode своя предыстория. 18 сентября независимые разработчики обнаружили, что ZCode скрыто выгружает файлы рабочей папки в облако, и предали это огласке. 20 сентября исходный код ZCode официально открыли, а 20–21 сентября появились анонс репозитория zai-org/ZCode на GitHub и публичные заявления компании. Когда через несколько дней мы писали первую часть, Claude видел этот репозиторий: README и список пакетов. Описания протокола app-server там не было.

Без описания протокол пришлось изучать опытным путём: Claude запускал настоящий zcode app-server 3.15.3 на фиктивном провайдере модели и записывал, что тот отвечает на каждый запрос. Ради этого стоило постараться: у режима печати было три ограничения, которые я чувствовал каждый день:

  • нет канала подтверждений, поэтому режим Ask невозможен: ZCode сам отклоняет рискованные действия;

  • нет своей модели у каждого чата, только общий defaultModelSelection;

  • нет настоящего режима Plan, только build с инструкцией.

zcode app-server --stdio даёт всё это сразу. Это JSON-RPC по stdio, почти как ACP у Kimi и MiniMax, но со своими особенностями. Например, сообщение с полем "jsonrpc": "2.0" сервер отвергает.

Схема из второго ревью Greptile: ход ZCode через app-server, от выбора агента, модели и режима до ответа на карточку подтверждения
Схема из второго ревью Greptile: ход ZCode через app-server, от выбора агента, модели и режима до ответа на карточку подтверждения

Схема построена ботом Greptile во втором ревью, подписи на русский перевёл я.

Один ход выглядит так: session/create или session/resume, затем setMode, setModel и subscribe. После send идут события session/event. Когда ZCode нужно решение пользователя, он сам присылает запрос:

  • interaction/requestPermission становится карточкой подтверждения в orx;

  • interaction/requestUserInput – карточкой вопроса или карточкой плана;

  • ответ пользователя уходит обратно в ZCode, и ход продолжается.

Записанные обмены с рантаймом Claude положил в тесты как фикстуры, как делал для первой части.

5. «Модели нет в реестре провайдеров». В контейнере всё работало, а у меня первый же ход упал. ZCode не смог переключиться на модель account:zai-individual-coding-plan/GLM-5.3-Flash: в его реестре провайдеров такой модели не оказалось. Часть сообщения ZCode выдаёт по-китайски, поэтому сырой лог здесь не привожу.

В контейнере Claude тестировал на неофициальном npm-пакете zcode-app-cli, а у меня был официальный рантайм из приложения. В официальном рантайме app-server работает в режиме host: аккаунт Coding Plan и учётные данные для каждого запроса ему передаёт хост, то есть само приложение ZCode. orx таким хостом не является, поэтому моделей Coding Plan в реестре просто не было. В npm-пакете есть патч app-server-standalone-auth, который включает самостоятельный режим. Тот же режим использует zcode -p: он читает вход zcode login из хранилища ZCode.

Решение – маленький загрузчик на JavaScript (zcode_app_server.cjs). orx запускает рантайм ZCode через него. Загрузчик в памяти вносит в минифицированный код те же правки, что и патч npm-пакета; файлы приложения не меняются. ZCode распространяется под Apache-2.0, такие изменения лицензия разрешает. Если в новой сборке ZCode загрузчик не найдёт нужное место, он запустит рантайм без изменений и напишет об этом в лог. Модели с API-ключом при этом продолжат работать.

Схема: режимы host и standalone. Откуда рантайм берёт учётные данные Coding Plan
Схема: режимы host и standalone. Откуда рантайм берёт учётные данные Coding Plan

6. Половина патча. Следующая сборка упала с другой ошибкой:

OpenResearch does not provide ZCode account credentials

Это orx честно отвечал на запрос interaction/requestProviderRuntimeHeaders: ZCode снова просил учётные данные у хоста. Я запустил присланную Claude команду диагностики в PowerShell. Она показала status: patched, то есть загрузчик нужное место нашёл. Значит, дело было не в нём.

Claude прочитал исходник патча npm-пакета и нашёл причину. Правок там две:

  1. реестр провайдеров запускается в самостоятельном режиме;

  2. источник учётных данных этого реестра передаётся в фабрику сессий app-server.

Загрузчик делал только первую. Хуже того, эмуляцию официального рантайма Claude тоже собирал из npm-пакета, откатив только первую правку. Поэтому у него в контейнере всё работало, а у меня нет. После исправления эмуляции ошибка воспроизвелась, а с обеими правками исчезла.

7. Ложный след: project_token_login_failed. Следующий ход дошёл до Z.ai и упал с project_token_login_failed. Код ошибки звучал как очередная проблема orx. Claude предложил проверить ту же операцию вообще без orx, командой zcode -p в PowerShell. Она упала так же. Токен, который когда-то сохранил zcode login, протух, а orx по-прежнему показывал «Вход выполнен», потому что файл с токеном на месте. После zcode login всё заработало. В карточке ZCode появилась кнопка Войти снова, а ошибка теперь прямо говорит, что Z.ai не принял вход.

Две дорожки, я на Windows и Claude в контейнере: путь от первой ошибки app-server до рабочего хода с Coding Plan
Две дорожки, я на Windows и Claude в контейнере: путь от первой ошибки app-server до рабочего хода с Coding Plan

8. Где хранить API-ключ. Для провайдеров с API-ключом Claude сначала сделал так же, как у других агентов upstream: ключ ZAI_API_KEY в Settings → Environment. Модели не появились. В настройках приложения ZCode уже было правило для этого провайдера, но без ключа, и orx его пропускал. Тут я задумался: для остальных агентов orx ключи их моделей не хранит. Мы убрали этот путь целиком. Теперь ключ задаётся в провайдере самого приложения ZCode, а orx показывает модели таких провайдеров в группе «API-ключ».

Пикер ZCode: слева меню «Провайдер» с Coding Plan и API-ключом, справа меню «Режим» с пунктом «План»
Пикер ZCode: слева меню «Провайдер» с Coding Plan и API-ключом, справа меню «Режим» с пунктом «План»
Карточка ZCode в настройках: строка «Провайдеры» показывает, есть ли вход в Coding Plan и провайдеры с ключом
Карточка ZCode в настройках: строка «Провайдеры» показывает, есть ли вход в Coding Plan и провайдеры с ключом

Ревью в upstream

Форк я отправил в upstream. Первая попытка, PR #441 из main форка, тащила за собой всё, что нужно только форку: релизы, удалённые workflow, бейджи README. Поэтому Claude сделал чистую ветку, из неё вышел PR #600. Оба PR посмотрел бот Greptile, а мейнтейнеры пока молчат.

Greptile ревьюил дважды: старую логику в режиме печати и новую через app-server. В первый раз он нашёл реальные ошибки, которые пропустили и Claude, и я:

  • если Kimi или MiniMax отказывались переключить режим, ход всё равно шёл в старом режиме, который мог разрешать больше выбранного;

  • последнее session/update хода иногда терялось;

  • новые чаты ZCode открывались в YOLO;

  • та самая гонка моделей из пункта 3.

Схема из первого ревью Greptile: ход через print-режим. Для Kimi и MiniMax ход останавливается, если не удалось сменить режим; для ZCode выбор модели держится под блокировкой
Схема из первого ревью Greptile: ход через print-режим. Для Kimi и MiniMax ход останавливается, если не удалось сменить режим; для ZCode выбор модели держится под блокировкой

Схема построена ботом Greptile в первом ревью, подписи на русский перевёл я.

9. Второе ревью: 3/5. После перехода на app-server Greptile поставил 3/5 и нашёл две ошибки уровня P1:

  • Одобренный план не мог править файлы. После «Accept plan» ход продолжается, но токен, по которому orx решает о подтверждениях, оставался помеченным как режим плана. Правки Write и Edit отклонялись автоматически: «File edits are blocked in plan mode».

  • Потеря контекста. Если ZCode не мог продолжить сессию, orx молча открывал новую и отправлял туда только последнее сообщение. Остальные агенты в orx в таком случае подкладывают снимок переписки, у ZCode этого не было.

Ещё одно замечание уровня P2: пункт Plan в меню «Режим» не выключался при выборе обычного режима. После исправлений Greptile поставил 5/5 и ни одного нового замечания. Исправление первой ошибки Claude проверил сквозным ходом на фиктивном провайдере: план, «Accept plan», и правка файла показала карточку подтверждения вместо отказа. А я проверил вручную на своей Windows-машине, уже с настоящим ZCode.

Десктоп-приложение форка

В upstream тем временем появились десктоп-приложения, но приложение alphaXiv запускает свой orx, без трёх новых агентов. Поэтому в v0.3.5 у форка появилось своё:

  • для Windows – OpenResearch-Setup.exe, оно не подписано, и SmartScreen предупреждает об этом;

  • для Linux – AppImage для x86_64 и ARM64.

Сборки форка остаются в канале development, поэтому в телеметрию alphaXiv ничего не уходит.

Русская локализация и жизнь рядом с upstream

Пока шли исправления, по моей просьбе Claude перевёл интерфейс OpenResearch на русский: 1288 строк, README.ru.md и выбор языка в настройках. Названия продуктов и команды остались как есть. Локализация вошла в v0.3.8 и ушла отдельным PR в upstream: #650, к нему пришлось заранее открыть issue #649, без него проверка linked issue не пропускает PR из форков.

У сопровождения форка есть своя цена, и она регулярная. Upstream активно развивается, и при каждом обновлении повторяется одно и то же:

  • при каждом слиянии конфликтует собранный дашборд ui/dist, его приходится пересобирать;

  • в русской локализации каждый раз нужно догонять новые строки upstream. В последний раз их было 13, про настройки GitHub и Overleaf;

  • изменения README upstream нужно переносить в README.ru.md.

Цикл сопровождения: релиз upstream, слияние, конфликт ui/dist, новые строки в ru.json, README.ru.md, релиз форка и синхронизация PR
Цикл сопровождения: релиз upstream, слияние, конфликт ui/dist, новые строки в ru.json, README.ru.md, релиз форка и синхронизация PR

Что получилось

Чат ZCode в режиме Ask: карточка подтверждения команды
Чат ZCode в режиме Ask: карточка подтверждения команды

Агент

Как подключён

Режимы

Модели

Kimi Code

ACP, kimi acp

Ask, Auto, YOLO, Plan

K2.8 Preview, K2.7, K3; thinking по модели

MiniMax Code

ACP, mcode acp

Auto, Full access, Plan

MiniMax-M3 (± thinking), M2.7

ZCode

zcode app-server, рантайм из десктопа

Ask, Edit, Auto, Full access, Plan

Coding Plan после zcode login или провайдеры с ключом из приложения ZCode

Режим Plan теперь можно включить и в меню «Режим», и командой /plan. У ZCode в пикере есть отдельная строка «Провайдер»: Coding Plan или API-ключ.

Сравнение с тем, чем закончилась первая часть:

Было: часть 1, v0.3.2

Стало: v0.3.10

Как подключён ZCode

Режим печати zcode -p, поток stream-json в одну сторону

zcode app-server --stdio, двусторонний обмен

Режимы ZCode

Edit, YOLO, /plan

Ask, Edit, Auto, Full access, Plan

Подтверждения в ZCode

Нет канала: рискованные действия ZCode отклонял сам

Карточки подтверждения, вопроса и плана в дашборде

Модель ZCode

Из настроек приложения ZCode, общая для всех чатов

Своя у каждого чата, выбирается в пикере

Plan у Kimi, MiniMax, ZCode

Только командой /plan

В меню «Режим» и командой /plan

Вход в ZCode

Только через приложение ZCode, без кнопок в дашборде

Кнопки «Войти» и «Войти снова», вход по OAuth в ZCode 3.15

Провайдеры ZCode

Не различались

Coding Plan или провайдеры с API-ключом из приложения ZCode

Десктоп-приложение форка

Нет, только orx

Установщик для Windows, AppImage для Linux

Русский язык интерфейса

Нет

1288 строк, README.ru.md

PR в upstream

#441 с агентами

#600 с агентами, #650 с локализацией

Релизы форка

v0.3.0–v0.3.2 за один день

Ещё 8, от v0.3.3 до v0.3.10 за 19 дней

Сколько стоило

Здесь всё не так просто, как в первой части.

  • Первую часть я оплачивал с баланса API: $62 ушло до того, как Claude приступил к подготовке материалов для первой статьи. Отрисовка схем для первой статьи с использованием плагина diagram-design, съёмка скриншотов в контейнере Linux и подготовка версии релиза v0.3.2 с исправлением ошибки про заголовки чатов обошлись ещё в $26 (2208 руб. по курсу ЦБ).

  • На сопровождение ушли остаток баланса, 12, и подписка за $20 в месяц, месяц ещё не кончился. Итого **32**.

Чтобы понять, сколько это стоило бы по API, Claude посчитал токены по журналу сессии и умножил на текущие цены модели Opus 5.5. Метод проверили на первой части: он дал $49 вместо реальных $62 и $24 вместо $26, то есть занижает в 1,1–1,26 раза. Но по факту, если бы я сразу делал всё через подписку, а не через API, мне бы хватило $20 на всё, включая первые релизы из предыдущей статьи.

Период

Оценка по API

Реально

Первая часть до статьи

$49

$62

Подготовка материалов для первой статьи и v0.3.2

$24

$26

Сопровождение, 27.09–16.10

$234 (с поправкой ≈ $260–295)

$32

Оценка по ценам API и реальные затраты по трём периодам; из чего сложились $234 сопровождения
Оценка по ценам API и реальные затраты по трём периодам; из чего сложились $234 сопровождения

Главная статья расходов – не ответы модели, а повторное чтение длинного контекста из кеша: около $130 из $234. Сам вывод модели, около миллиона токенов, стоил всего около $20. В многодневной сессии дорого не писать, а помнить. Самыми дорогими днями стали 13 и 14 октября, переход на app-server и история с загрузчиком.

Выводы

Что агент сделал хорошо. Claude разобрался в минифицированном рантайме ZCode, нашёл в нём режимы host и standalone и повторил чужой патч в памяти. Он ни разу не слил PR без моего «ок» и каждое продуктовое решение выносил ко мне: хранить ли ключи, как показывать провайдера, делать ли загрузчик. Когда автоматическая проверка безопасности Claude Code заблокировала встраивание загрузчика, он не стал её обходить и спросил разрешения у меня.

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

Где без человека никак:

  • Живые аккаунты: протухший токен, чужой ключ, тариф Start Plan.

  • Настоящая Windows: GUI-программы в псевдоконсоли и обрезанные ссылки.

  • Живые люди: первую ошибку нашёл читатель в комментариях, не я и не Claude.

  • Продуктовые решения: где хранить ключи и что делать с режимом Plan.

ИИ для open source. Я создал новые Pull Request для всех доработок форка и для локализации и новый Issue для русской локализации (см. Post Scriptum).

Ссылки

Текст написан вместе с Claude: он собрал факты из истории сессии, PR и релизов, я проверил и поправил. Схемы нарисованы плагином diagram-design, кроме двух схем из ревью Greptile. Скриншоты чатов сняты в контейнере на фиктивном провайдере модели.

P.S. Вопрос к читателям. Мои PR в upstream до сих пор ждут мейнтейнеров:

  • PR с тремя агентами я открыл 25 сентября, это был #441. 8 октября я заменил его чистым #600. Ревью в обоих оставлял только бот Greptile, мейнтейнеры пока не написали ни строчки.

  • Русскую локализацию я предложил 13 октября: issue #649 и PR #650. 14 октября мейнтейнер поставил на issue метку feature, и на этом пока всё.

Для сравнения: польскую локализацию предложили 11 октября, issue #625 и PR #626. Уже 12 октября мейнтейнер влил PR, примерно через 20 часов после открытия, и закрыл issue.

Справедливости ради: #600 большой, в нём три новых агента и отдельный протокол для ZCode, такой PR смотреть дольше. Но #650 устроен так же, как польский #626: файл переводов, подключение языка в настройках и собранный дашборд. Сверху только README.ru.md.

Как вы считаете, почему мейнтейнеры тянут с приёмкой моих PR? Может ли задержка с русской локализацией, когда такую же польскую приняли меньше чем за сутки, быть проявлением русофобии? Или есть объяснение проще? Пишите в комментариях.

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