# deepwork Цикл с инструментами поверх моста `ollama_orchestro/ask.mjs`. DeepSeek через веб-чат видит только то, что положили ему в вопрос. Здесь у него появляется обратное направление: он возвращает блок-запрос, программа его исполняет и досылает результат следующим сообщением в тот же чат. Обычный агентский цикл, только транспорт — текст. ## Как пользоваться Обычный путь — **пульт**: бросить папку проекта на `start-deepwork.cmd`. Откроется страница: файлы галочками, поле вопроса, ход работы построчно, кнопка «Записать» у каждого пришедшего файла. Пульт открывается в браузере ПО УМОЛЧАНИЮ, а не в отладочном: там он занял бы вкладку, и мост перестал бы видеть DeepSeek. Порт 8787 — рядом с пультом orchestro (8777), оба могут работать разом. Тот же цикл из консоли: ``` cd c:\мой\проект node c:\#Projects\deepwork\deepwork.mjs "вопрос" --files a.js,b.js --apply node c:\#Projects\deepwork\deepwork.mjs ui тот же пульт вручную ``` Работает в текущей папке: её файлы показывает, в неё же пишет правки. ## Инструменты Только чтение и только внутри текущей папки: | Блок в ответе | Что делает | |---|---| | `=== NEED: путь, путь ===` | прислать файлы целиком | | `=== LIST: **/*.mjs ===` | список файлов по маске | | `=== FIND: текст ===` | где встречается текст, с номерами строк | Запуска команд (`RUN`) нет намеренно: исполнять строки из ответа, пришедшего из интернета, без белого списка и подтверждения нельзя. Лимиты на результат шага: `NEED` — 200 000 символов суммарно, `FIND` — 100 попаданий, `LIST` — 300 путей. Обрезанное помечается прямо в тексте. ## Как устроено Мост **не импортируется и не копируется**. `ask.mjs` разбирает `process.argv` и исполняет команду на верхнем уровне — `import` немедленно запустил бы её. Поэтому мост вызывается подпроцессом теми флагами, которые у него уже есть: ``` node ask.mjs ask --chat think --file step1.txt --out ans1.txt --quiet node ask.mjs ask --chat think --new --file step2.txt --out ans2.txt --quiet ``` Шаг 1 идёт без `--new`: мост правит первое сообщение, и чат остаётся из одного обмена. Шаги 2..N — с `--new`, обычной отправкой: только так DeepSeek помнит предыдущий шаг. Цена — переподключение к браузеру на каждом шаге, 1–2 секунды. Взамен `ollama_orchestro` не меняется ни на строку, а его правки прилетают сюда даром. Чат берётся тот же, что у orchestro (`think` из его `chats.json`). Своя роль не заводится: `chats.json` принадлежит мосту. Цикл останавливается, когда запросов в ответе нет, когда кончились шаги или когда пришёл тот же самый запрос второй раз подряд (петля). ## Настройка `config.json` (в репозиторий не попадает, образец — `config.example.json`): ```json { "bridge": "C:/#Projects/ollama_orchestro/ask.mjs", "chat": "think", "steps": 4 } ``` Без файла мост ищется рядом: `../ollama_orchestro/ask.mjs`. ## Проверка ``` node deepwork.mjs --selftest внутренние проверки, ничего не отправляют node deepwork.mjs --check мост на месте, вкладка жива ``` Браузер должен быть запущен `start-browser.cmd` из `ollama_orchestro` — с отладочным портом 9333. ## Что проверено - `--selftest`: разбор запросов, отказ пути за пределы папки, маски `*` и `**`, снятие тройных кавычек и подписи языка. Строка вида `=== NEED: … ===` **внутри** блока `=== FILE: ===` за запрос не принимается — иначе правка файла с описанием формата запускала бы запрос сама. - Цикл целиком на заглушке вместо моста: приставка едет в первом сообщении, второй вызов уходит с `--new`, результаты `NEED` и `FIND` доезжают, отступы в записанном файле сохраняются, прежняя версия уходит в `backup/`. - Пропавший файл в `NEED` возвращает «файла нет» и цикл не роняет. - `--steps 1` отдаёт ответ с пометкой «шаги кончились», а не зависает. - Битый `config.json` — понятная ошибка, а не молчаливый откат к умолчаниям. ### Живые прогоны на DeepSeek, 11.08.2026 Задача одна и та же: из папки `ollama_orchestro` спросить, где решается, что ответ дописан до конца, дав в вопросе **только** `ui.html` — то есть заведомо не тот файл. Правильный ответ (`waitForAnswer` в `ask.mjs`) достижим только через инструменты. | Прогон | Шагов | Что вышло | |---|---|---| | 1. приставка только в начале сообщения | 1 | **запросов нет.** «Точный код в серверном файле» и три догадки | | 2. + напоминание вплотную к вопросу | 4 | нашёл, но 2 круга ушли на угадывание имён файлов | | 3. + дерево папки в первом сообщении | **2** | запросил `ask.mjs` сразу, ответил по существу | Два вывода, оба стоили живого прогона: - **Инструкция в начале сообщения не работает.** Между приставкой и вопросом легли 22 КБ файла, и DeepSeek инструменты просто не заметил. Помогло дословное повторение перед самим вопросом (`TAIL_REMINDER`). - **Дерево папки надо давать сразу.** Без него DeepSeek угадывал имена (`server.js`, `bridge.js` — таких в проекте нет), потом просил `LIST *.js` (проект на `.mjs`, пусто), потом `LIST **/*`. Дерево — 600 символов против двух кругов по минуте. ### Пульт, 11.08.2026 Сквозной прогон через страницу: вопрос без единого приложенного файла — «какая функция решает, что ответ дописан?». 36 секунд, три шага. DeepSeek запросил пятью блоками `FIND` сразу (`waitForAnswer`, `streaming`, `done`, `stop_reason`, `finish_reason`), затем `NEED: ask.mjs`, и ответил точно: `waitForAnswer`, строка 675. Журнал шагов обновлялся на странице по ходу. ## Обрезанные ответы: причина найдена и устранена в мосте (11.08.2026) В третьем прогоне ответ оборвался посреди блока кода на `// Бы`. Оказалось, это не «конец определён раньше времени» и не кнопка `Continue`. **Браузер работал в фоне.** У неактивного окна страница не отрисовывается, а DeepSeek рисует блоки кода лениво: пока блок не нарисован, в DOM от него лежат первые две строки, а остального нет вовсе — его не достать ни `innerText`, ни `textContent`. Прокрутка не помогает (проверено проходом по всему ответу шагами: ни одного лишнего символа). Помогает единственное — заставить браузер отрисовать страницу, и через CDP это делает `Page.captureScreenshot`. Замеры на живых ответах: | | до отрисовки | после | |---|---|---| | ответ про TaskQueue | 2068 | 24 362 | | ответ про EventBus | 3136 | 30 817 | | ответ про Router (уже с правкой) | 258 | **32 045** | Правка в `ollama_orchestro/ask.mjs`: `revealAnswer()` перед съёмом текста делает дешёвый скриншот (jpeg, качество 1) и перечитывает ответ, до трёх раз, пока текст растёт. Картинка выбрасывается. Вдобавок `browser-launch.ps1` запускает браузер развёрнутым и с запретом фонового режима (`--disable-backgrounding-occluded-windows`, `--disable-renderer-backgrounding`, `--disable-background-timer-throttling`, `--disable-features=CalculateNativeWinOcclusion`). Это не замена скриншоту: свёрнутое окно Windows не рисует вообще. Вторая причина обрезания, найденная там же, — кнопка **Continue**: DeepSeek режет длинный ответ по своему лимиту и предлагает дописать, а генерация при этом честно завершается. Теперь `waitForAnswer` жмёт её и ждёт дальше; продолжение уходит в тот же блок ответа. Сквозная проверка — ответ на 47 414 символов с целыми кодом и тестами. Обе правки в `ollama_orchestro`, deepwork получает их даром — мост вызывается подпроцессом.