README для новичка, ASCII в батнике, лицензия
README переписан под человека, который видит проект впервые: что это вообще такое (схемой), что понадобится, установка по шагам с проверкой на каждом, как пользоваться пультом и консолью, чего ожидать по времени, таблица "если не работает" на десять строк и отдельный раздел про безопасность. Замеры и выводы прошлых прогонов сохранены — это самое ценное, что тут есть, но убраны под "Что проверено вживую", а не вперемешку с инструкцией. Поправлено попутно: - start-deepwork.cmd стучался в порт 9333 и советовал запустить start-browser.cmd в ollama_orchestro; теперь проверяет deepseek-api на 11500. Заодно батник снова стал чисто ASCII, как ему и положено; - в USAGE --timeout и --check ссылались на мост, --chat не знал про vision; - добавлена LICENSE (MIT), на которую README ссылается, и .gitattributes: без него start-deepwork.cmd уехал бы в репозиторий с LF. Раздел про обрезанные ответы поправлен по существу: обе поломки лечатся в deepseek-api (отрисовка и кнопка Continue живут в его browser.mjs), а не в ollama_orchestro, как было написано. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
44f07c8af9
commit
f34e07e807
@@ -0,0 +1,11 @@
|
|||||||
|
# Батникам нужны CRLF: с LF cmd.exe способен повести себя странно —
|
||||||
|
# например, оборвать последнюю строку или неверно разобрать блок в скобках.
|
||||||
|
*.cmd text eol=crlf
|
||||||
|
*.bat text eol=crlf
|
||||||
|
|
||||||
|
# Остальному текстовому — LF в репозитории, нормализация при выгрузке.
|
||||||
|
*.mjs text
|
||||||
|
*.md text
|
||||||
|
*.html text
|
||||||
|
*.json text
|
||||||
|
.gitignore text
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Alex
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -1,33 +1,168 @@
|
|||||||
# deepwork
|
# deepwork
|
||||||
|
|
||||||
Цикл с инструментами поверх сервиса [deepseek-api](https://git.08h.ru/alex/deepseek-api).
|
**DeepSeek, который сам читает вашу папку с кодом.**
|
||||||
|
|
||||||
DeepSeek через веб-чат видит только то, что положили ему в вопрос. Здесь у него
|
Обычный веб-чат видит только то, что вы вставили в вопрос. Спросишь «почему
|
||||||
появляется обратное направление: он возвращает блок-запрос, программа его
|
падает вот эта функция» — и в ответ получишь три догадки, потому что остального
|
||||||
исполняет и досылает результат следующим сообщением в тот же чат. Обычный
|
кода он не видел.
|
||||||
агентский цикл, только транспорт — текст.
|
|
||||||
|
Здесь у него появляется обратное направление. DeepSeek отвечает не текстом,
|
||||||
|
а **запросом**: «пришлите мне файл `server.js`», «покажите, где встречается
|
||||||
|
`waitForAnswer`». Программа исполняет запрос, досылает данные, и так по кругу,
|
||||||
|
пока он не соберёт всё нужное и не ответит по существу.
|
||||||
|
|
||||||
|
```
|
||||||
|
вы: "почему падает загрузка?"
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
DeepSeek ──► "=== NEED: upload.js ==="
|
||||||
|
│ │
|
||||||
|
│ программа читает файл и досылает
|
||||||
|
│ │
|
||||||
|
▼ ▼
|
||||||
|
DeepSeek ──► "=== FIND: parseBody ==="
|
||||||
|
│ │
|
||||||
|
▼ ▼
|
||||||
|
DeepSeek ──► ответ по существу + исправленный файл
|
||||||
|
```
|
||||||
|
|
||||||
|
Читает он только вашу папку и только на чтение. Правки возвращает файлами,
|
||||||
|
которые вы записываете нажатием кнопки — или не записываете.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Оглавление
|
||||||
|
|
||||||
|
1. [Что понадобится](#что-понадобится)
|
||||||
|
2. [Установка по шагам](#установка-по-шагам)
|
||||||
|
3. [Как пользоваться](#как-пользоваться)
|
||||||
|
4. [Что он умеет запрашивать](#что-он-умеет-запрашивать)
|
||||||
|
5. [Правки файлов](#правки-файлов)
|
||||||
|
6. [Настройка](#настройка)
|
||||||
|
7. [Если не работает](#если-не-работает)
|
||||||
|
8. [Безопасность](#безопасность)
|
||||||
|
9. [Как это устроено внутри](#как-это-устроено-внутри)
|
||||||
|
10. [Что проверено вживую](#что-проверено-вживую)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Что понадобится
|
||||||
|
|
||||||
|
| Что | Зачем | Как проверить |
|
||||||
|
|---|---|---|
|
||||||
|
| **Windows** | скрипт запуска написан под неё | — |
|
||||||
|
| **Node.js 22 или новее** | на нём написана программа | `node --version` → `v22.…` и выше |
|
||||||
|
| **Сервис `deepseek-api`** | через него идёт разговор с DeepSeek | см. шаг 1 |
|
||||||
|
|
||||||
|
Node.js, если его нет, ставится с [nodejs.org](https://nodejs.org) — берите
|
||||||
|
версию LTS. После установки **закройте и откройте заново** командную строку,
|
||||||
|
иначе `node` в ней не найдётся.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Установка по шагам
|
||||||
|
|
||||||
|
### Шаг 1. Поднять deepseek-api
|
||||||
|
|
||||||
|
У веб-версии DeepSeek нет API — только вкладка в браузере. Разговором с ней
|
||||||
|
занимается отдельная программа
|
||||||
|
[deepseek-api](https://git.08h.ru/alex/deepseek-api): она держит вкладку
|
||||||
|
и отдаёт наружу обычный HTTP.
|
||||||
|
|
||||||
|
Поставьте и запустите её по инструкции в её README — это отдельные пять шагов,
|
||||||
|
включая вход в аккаунт DeepSeek. Возвращайтесь сюда, когда заработает.
|
||||||
|
|
||||||
|
> **Проверка:**
|
||||||
|
> ```cmd
|
||||||
|
> curl http://localhost:11500/api/tags
|
||||||
|
> ```
|
||||||
|
> должен вернуть список из трёх «моделей». Окно `deepseek-api` при этом
|
||||||
|
> остаётся открытым — пока оно живо, работает и сервис.
|
||||||
|
|
||||||
|
### Шаг 2. Скачать deepwork
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
cd C:\#Projects
|
||||||
|
git clone https://git.08h.ru/alex/deepwork.git
|
||||||
|
```
|
||||||
|
|
||||||
|
Без git — скачайте ZIP с той же страницы и распакуйте. Папка может лежать где
|
||||||
|
угодно; рядом с чем-то конкретным её класть не нужно.
|
||||||
|
|
||||||
|
> **Проверка:**
|
||||||
|
> ```cmd
|
||||||
|
> cd C:\#Projects\deepwork
|
||||||
|
> node deepwork.mjs --selftest
|
||||||
|
> ```
|
||||||
|
> Ответ `самопроверка пройдена`. Ничего никуда не отправляется.
|
||||||
|
|
||||||
|
### Шаг 3. Проверить связку
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
node deepwork.mjs --check
|
||||||
|
```
|
||||||
|
|
||||||
|
Три возможных ответа:
|
||||||
|
|
||||||
|
| Что видно | Что это значит |
|
||||||
|
|---|---|
|
||||||
|
| `готов: браузер поднят, вкладка DeepSeek открыта` | всё на месте, можно работать |
|
||||||
|
| `не готов (HTTP 503)` | сервис жив, но браузер ещё не поднят — встанет сам на первом вопросе |
|
||||||
|
| `не отвечает: …` | `deepseek-api` не запущен, вернитесь к шагу 1 |
|
||||||
|
|
||||||
|
**Готово.** Настраивать больше нечего: адрес `http://localhost:11500` вшит
|
||||||
|
как значение по умолчанию.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Как пользоваться
|
## Как пользоваться
|
||||||
|
|
||||||
Обычный путь — **пульт**: бросить папку проекта на `start-deepwork.cmd`.
|
### Способ 1: пульт (обычный путь)
|
||||||
Откроется страница: файлы галочками, поле вопроса, ход работы построчно,
|
|
||||||
кнопка «Записать» у каждого пришедшего файла.
|
|
||||||
|
|
||||||
Пульт открывается в браузере ПО УМОЛЧАНИЮ, а не в отладочном: там он занял бы
|
**Перетащите папку своего проекта мышкой на файл `start-deepwork.cmd`.**
|
||||||
вкладку, и мост перестал бы видеть DeepSeek. Порт 8787 — рядом с пультом
|
|
||||||
orchestro (8777), оба могут работать разом.
|
|
||||||
|
|
||||||
Тот же цикл из консоли:
|
Откроется страница в браузере:
|
||||||
|
|
||||||
```
|
- слева файлы папки — отметьте галочками те, что точно нужны (можно ни одного);
|
||||||
cd c:\мой\проект
|
- поле вопроса;
|
||||||
node c:\#Projects\deepwork\deepwork.mjs "вопрос" --files a.js,b.js --apply
|
- ход работы построчно: видно, что DeepSeek запросил и сколько это заняло;
|
||||||
node c:\#Projects\deepwork\deepwork.mjs ui тот же пульт вручную
|
- у каждого пришедшего файла кнопка «Записать».
|
||||||
|
|
||||||
|
Пульт открывается в браузере **по умолчанию**, а не в том, которым управляет
|
||||||
|
`deepseek-api`: иначе он занял бы там вкладку, и вкладка с чатом потерялась бы.
|
||||||
|
Порт 8787.
|
||||||
|
|
||||||
|
Остановить — `Ctrl+C` в чёрном окне.
|
||||||
|
|
||||||
|
### Способ 2: командная строка
|
||||||
|
|
||||||
|
Работает в **текущей** папке: её читает, в неё же пишет правки.
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
cd C:\мой\проект
|
||||||
|
node C:\#Projects\deepwork\deepwork.mjs "почему падает загрузка файла?"
|
||||||
```
|
```
|
||||||
|
|
||||||
Работает в текущей папке: её файлы показывает, в неё же пишет правки.
|
Полезные флаги:
|
||||||
|
|
||||||
## Инструменты
|
| Флаг | Что делает |
|
||||||
|
|---|---|
|
||||||
|
| `--files a.js,b.js` | положить эти файлы в вопрос сразу |
|
||||||
|
| `--steps 6` | сколько кругов позволить (по умолчанию 4) |
|
||||||
|
| `--apply` | записать пришедшие файлы на диск (без него только покажет) |
|
||||||
|
| `--chat search` | режим с поиском в интернете вместо обычного |
|
||||||
|
| `--check` | проверить связку и выйти |
|
||||||
|
| `--selftest` | внутренние проверки, ничего не отправляя |
|
||||||
|
|
||||||
|
### Чего ожидать по времени
|
||||||
|
|
||||||
|
Один круг — 7–15 секунд. Обычная задача укладывается в два-три круга, то есть
|
||||||
|
полминуты. Если DeepSeek запросил много файлов, вопрос на следующем круге
|
||||||
|
вырастает до десятков килобайт — это нормально.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Что он умеет запрашивать
|
||||||
|
|
||||||
Только чтение и только внутри текущей папки:
|
Только чтение и только внутри текущей папки:
|
||||||
|
|
||||||
@@ -37,147 +172,220 @@ node c:\#Projects\deepwork\deepwork.mjs ui тот же пульт вру
|
|||||||
| `=== LIST: **/*.mjs ===` | список файлов по маске |
|
| `=== LIST: **/*.mjs ===` | список файлов по маске |
|
||||||
| `=== FIND: текст ===` | где встречается текст, с номерами строк |
|
| `=== FIND: текст ===` | где встречается текст, с номерами строк |
|
||||||
|
|
||||||
Запуска команд (`RUN`) нет намеренно: исполнять строки из ответа, пришедшего
|
**Запуска команд (`RUN`) нет, и не будет.** Исполнять строки, пришедшие
|
||||||
из интернета, без белого списка и подтверждения нельзя.
|
из интернета, без белого списка и подтверждения нельзя — а белого списка,
|
||||||
|
который был бы и полезен, и безопасен, придумать не вышло.
|
||||||
|
|
||||||
Лимиты на результат шага: `NEED` — 200 000 символов суммарно, `FIND` — 100
|
Лимиты на один круг: `NEED` — 200 000 символов суммарно, `FIND` — 100
|
||||||
попаданий, `LIST` — 300 путей. Обрезанное помечается прямо в тексте.
|
попаданий, `LIST` — 300 путей. Обрезанное помечается прямо в тексте, чтобы
|
||||||
|
DeepSeek видел, что данные неполные.
|
||||||
|
|
||||||
## Как устроено
|
Цикл останавливается, когда запросов в ответе больше нет, когда кончились
|
||||||
|
круги или когда пришёл тот же самый запрос второй раз подряд — это петля,
|
||||||
|
данные ему уже присылали.
|
||||||
|
|
||||||
У веб-версии DeepSeek нет API — только вкладка в браузере. Разговором с ней
|
---
|
||||||
занимается отдельный сервис `deepseek-api`, а нам показывает протокол Ollama.
|
|
||||||
Здесь про браузер не знают вовсе: обычный `POST /api/chat`.
|
|
||||||
|
|
||||||
**Разговор помним мы, а не DeepSeek.** Сервис без памяти: каждый запрос он
|
## Правки файлов
|
||||||
кладёт в чат целиком, затирая прошлый. Поэтому стенограмма растёт здесь —
|
|
||||||
`growTranscript` подклеивает к отправленному тексту прошлый ответ модели
|
|
||||||
(между метками `=== ТВОЙ ПРЕДЫДУЩИЙ ОТВЕТ ===` и `=== END ===`) и результаты
|
|
||||||
запросов, и следующим шагом уезжает всё сразу.
|
|
||||||
|
|
||||||
Раньше эту роль играл флаг `--new` у моста, и помнил всё сам чат. Своя
|
Исправленный код DeepSeek возвращает блоками:
|
||||||
стенограмма надёжнее: видно в одном месте, что именно уедет модели, а чужой
|
|
||||||
потребитель, вклинившийся между нашими шагами, ничего не портит — мы всё
|
|
||||||
приносим заново. Плата — вопрос растёт на длину прошлого ответа; при `steps: 4`
|
|
||||||
это единицы килобайт против 22 КБ первого сообщения.
|
|
||||||
|
|
||||||
Цикл останавливается, когда запросов в ответе нет, когда кончились шаги или
|
```
|
||||||
когда пришёл тот же самый запрос второй раз подряд (петля).
|
=== FILE: src/upload.js ===
|
||||||
|
```
|
||||||
|
...содержимое целиком...
|
||||||
|
```
|
||||||
|
=== END FILE ===
|
||||||
|
```
|
||||||
|
|
||||||
|
Записываются они **только по вашей команде** — кнопкой «Записать» в пульте
|
||||||
|
или флагом `--apply` в консоли. Без этого программа просто перечислит, что
|
||||||
|
пришло.
|
||||||
|
|
||||||
|
**Прежняя версия не пропадает:** перед записью она уезжает в папку `backup/`
|
||||||
|
внутри проекта. Файлы вне рабочей папки не пишутся вовсе — путь проверяется.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Настройка
|
## Настройка
|
||||||
|
|
||||||
`config.json` (в репозиторий не попадает, образец — `config.example.json`):
|
Нужна редко. `config.json` рядом с программой (в репозиторий не попадает,
|
||||||
|
образец — `config.example.json`):
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{ "deepseekHost": "http://localhost:11500", "deepseekModel": "deepseek:think", "steps": 4 }
|
{
|
||||||
|
"deepseekHost": "http://localhost:11500",
|
||||||
|
"deepseekModel": "deepseek:think",
|
||||||
|
"steps": 4,
|
||||||
|
"timeout": 240
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Без файла берётся `http://localhost:11500`.
|
| Ключ | По умолчанию | Смысл |
|
||||||
|
|---|---|---|
|
||||||
|
| `deepseekHost` | `http://localhost:11500` | адрес сервиса `deepseek-api` |
|
||||||
|
| `deepseekModel` | `deepseek:think` | режим чата: `think`, `search` или `vision` |
|
||||||
|
| `steps` | `4` | сколько кругов позволить |
|
||||||
|
| `timeout` | `240` | секунд на один круг (сверх этого сервису дают ещё две минуты на очередь) |
|
||||||
|
| `uiPort` | `8787` | порт пульта |
|
||||||
|
|
||||||
## Проверка
|
Без файла всё работает на значениях по умолчанию. А вот **битый** `config.json`
|
||||||
|
не молчит: программа скажет об ошибке, а не откатится тихо к умолчаниям —
|
||||||
|
иначе правка в настройках не действует, и понять почему невозможно.
|
||||||
|
|
||||||
```
|
---
|
||||||
node deepwork.mjs --selftest внутренние проверки, ничего не отправляют
|
|
||||||
node deepwork.mjs --check сервис на месте, вкладка жива
|
|
||||||
```
|
|
||||||
|
|
||||||
`--check` различает три состояния: сервис отвечает и браузер поднят; сервис
|
## Если не работает
|
||||||
жив, но браузера ещё нет (встанет на первом же вопросе); сервис не запущен.
|
|
||||||
|
|
||||||
Запускается сервис своим `start.cmd` в папке `deepseek-api` — браузер он
|
| Что видно | В чём дело | Что делать |
|
||||||
поднимает сам.
|
|---|---|---|
|
||||||
|
| `deepseek-api не отвечает по адресу …` | сервис не запущен | Запустите `start.cmd` в папке `deepseek-api` |
|
||||||
|
| `--check` говорит `не готов (HTTP 503)` | сервис жив, браузера ещё нет | Ничего: браузер встанет на первом же вопросе |
|
||||||
|
| `deepseek-api ответил 500` | что-то со вкладкой | `curl http://localhost:11500/api/probe` покажет, что там видно |
|
||||||
|
| **Ответ пришёл обрезанным**, код оборван на середине | окно браузера свёрнуто | Разверните его. Свёрнутое окно Windows не отрисовывает, а DeepSeek рисует блоки кода лениво — см. [ниже](#обрезанные-ответы-причина-найдена) |
|
||||||
|
| `шаг 1: запросов нет, готово`, а ответ — догадки | DeepSeek поленился спросить и придумал | Спросите конкретнее либо дайте файл сразу через `--files`. Так бывает; напоминание в конце вопроса помогает, но не всегда |
|
||||||
|
| `тот же запрос повторно — петля, выхожу` | он не принял присланные данные | Обычно значит, что запрошенного файла нет или он пуст. Посмотрите журнал шагов |
|
||||||
|
| `шаги кончились, а запросы ещё идут` | задача крупнее четырёх кругов | `--steps 6`, но сначала подумайте, не проще ли разбить вопрос |
|
||||||
|
| `DeepSeek занят: «Server is busy»` | лимиты на стороне DeepSeek | Подождите минуту |
|
||||||
|
| `node не является внутренней или внешней командой` | Node не установлен или консоль открыта до установки | Поставьте Node, **закройте и откройте заново** консоль |
|
||||||
|
| Чаты в DeepSeek пропадают сами | тот же профиль браузера использует другая программа | Дайте `deepseek-api` отдельный профиль |
|
||||||
|
|
||||||
## Переезд на deepseek-api (26.08.2026)
|
---
|
||||||
|
|
||||||
Транспорт сменился: был дочерний процесс `ask.mjs` из `ollama_orchestro`
|
## Безопасность
|
||||||
с обменом через временные файлы, стал `POST /api/chat` к сервису
|
|
||||||
`deepseek-api`. Заодно ушли временные файлы шагов (и флаг `--keep-temp`),
|
|
||||||
проверка существования моста и запуск браузера — всё это теперь не наша забота.
|
|
||||||
|
|
||||||
Память шагов переехала из чата DeepSeek в `growTranscript` (см. «Как устроено»).
|
- **Ваш код уходит на серверы DeepSeek.** Не только присланные файлы: он сам
|
||||||
Проверено живым прогоном: шаг 1 — 2094 символа, ответ `NEED: deepwork.mjs`;
|
запрашивает то, что считает нужным, из всей рабочей папки. Для закрытых
|
||||||
шаг 2 — 28 447 символов стенограммы, ответ дословно верный и по вопросу
|
проектов это не годится.
|
||||||
из ПЕРВОГО сообщения. Два шага за 17 с.
|
- **Ключей и паролей в папке быть не должно.** `.env`, `config.json` с токенами,
|
||||||
|
приватные ключи — всё это он может запросить, и это уедет наружу. Убирайте
|
||||||
|
такое из рабочей папки заранее.
|
||||||
|
- **Правки не применяются сами.** Только кнопкой или флагом `--apply`,
|
||||||
|
и прежняя версия всегда сохраняется в `backup/`.
|
||||||
|
- **За пределы рабочей папки программа не пишет** и не читает: путь
|
||||||
|
проверяется, `..` не проходит.
|
||||||
|
- **Пульт слушает только этот компьютер** (`127.0.0.1`), из сети к нему
|
||||||
|
не подключиться.
|
||||||
|
|
||||||
## Что проверено
|
---
|
||||||
|
|
||||||
- `--selftest`: разбор запросов, отказ пути за пределы папки, маски `*` и `**`,
|
## Как это устроено внутри
|
||||||
снятие тройных кавычек и подписи языка. Строка вида `=== NEED: … ===`
|
|
||||||
**внутри** блока `=== FILE: ===` за запрос не принимается — иначе правка
|
|
||||||
файла с описанием формата запускала бы запрос сама.
|
|
||||||
- Цикл целиком на заглушке вместо моста: приставка едет в первом сообщении,
|
|
||||||
второй вызов уходит с `--new`, результаты `NEED` и `FIND` доезжают,
|
|
||||||
отступы в записанном файле сохраняются, прежняя версия уходит в `backup/`.
|
|
||||||
- Пропавший файл в `NEED` возвращает «файла нет» и цикл не роняет.
|
|
||||||
- `--steps 1` отдаёт ответ с пометкой «шаги кончились», а не зависает.
|
|
||||||
- Битый `config.json` — понятная ошибка, а не молчаливый откат к умолчаниям.
|
|
||||||
|
|
||||||
### Живые прогоны на DeepSeek, 11.08.2026
|
### Разговор помним мы, а не DeepSeek
|
||||||
|
|
||||||
Задача одна и та же: из папки `ollama_orchestro` спросить, где решается, что
|
Сервис `deepseek-api` **без памяти**: каждый запрос он кладёт в чат целиком,
|
||||||
ответ дописан до конца, дав в вопросе **только** `ui.html` — то есть заведомо
|
затирая прошлый. Поэтому стенограмму ведёт `deepwork` — функция
|
||||||
не тот файл. Правильный ответ (`waitForAnswer` в `ask.mjs`) достижим только
|
`growTranscript` подклеивает к отправленному тексту прошлый ответ модели
|
||||||
через инструменты.
|
(между метками `=== ТВОЙ ПРЕДЫДУЩИЙ ОТВЕТ ===` и `=== END ===`) и результаты
|
||||||
|
запросов, и следующим кругом уезжает всё сразу.
|
||||||
|
|
||||||
| Прогон | Шагов | Что вышло |
|
Раньше память держал сам чат DeepSeek. Своя стенограмма надёжнее: видно
|
||||||
|
в одном месте, что именно уедет модели, а чужая программа, вклинившаяся между
|
||||||
|
нашими кругами, ничего не портит — мы всё приносим заново. Плата — вопрос
|
||||||
|
растёт на длину прошлого ответа; при четырёх кругах это единицы килобайт
|
||||||
|
против 22 КБ первого сообщения.
|
||||||
|
|
||||||
|
### Что уезжает в первом сообщении
|
||||||
|
|
||||||
|
1. Приставка из `agent-prompt.md` — кто он и какие блоки может вернуть.
|
||||||
|
2. **Дерево рабочей папки.** Без него первый живой прогон ушёл на угадывание
|
||||||
|
имён файлов, см. замеры ниже.
|
||||||
|
3. Файлы, отмеченные галочками (или переданные через `--files`).
|
||||||
|
4. **Напоминание про инструменты — вплотную к вопросу.** Не в начале: между
|
||||||
|
приставкой и вопросом ложатся килобайты файлов, и инструкция теряется.
|
||||||
|
5. Сам вопрос.
|
||||||
|
|
||||||
|
### Файлы
|
||||||
|
|
||||||
|
| Файл | Что в нём |
|
||||||
|
|---|---|
|
||||||
|
| `deepwork.mjs` | всё: цикл, инструменты, разбор ответов, пульт |
|
||||||
|
| `agent-prompt.md` | приставка к первому сообщению |
|
||||||
|
| `ui.html` | страница пульта |
|
||||||
|
| `config.json` | настройки (не в репозитории) |
|
||||||
|
| `start-deepwork.cmd` | запуск пульта перетаскиванием папки |
|
||||||
|
|
||||||
|
Зависимостей нет — только то, что есть в Node 22.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Что проверено вживую
|
||||||
|
|
||||||
|
### Внутренние проверки (`--selftest`)
|
||||||
|
|
||||||
|
Разбор запросов, отказ пути за пределы папки, маски `*` и `**`, снятие тройных
|
||||||
|
кавычек и подписи языка. Строка вида `=== NEED: … ===` **внутри** блока
|
||||||
|
`=== FILE: ===` за запрос не принимается — иначе правка файла с описанием
|
||||||
|
формата запускала бы запрос сама. Пропавший файл в `NEED` возвращает «файла
|
||||||
|
нет» и цикл не роняет. `--steps 1` отдаёт ответ с пометкой «шаги кончились»,
|
||||||
|
а не зависает.
|
||||||
|
|
||||||
|
### Из чего выросли два правила, 11.08.2026
|
||||||
|
|
||||||
|
Задача одна и та же: спросить, где решается, что ответ дописан до конца, дав
|
||||||
|
в вопросе **заведомо не тот файл**. Правильный ответ достижим только через
|
||||||
|
инструменты.
|
||||||
|
|
||||||
|
| Прогон | Кругов | Что вышло |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 1. приставка только в начале сообщения | 1 | **запросов нет.** «Точный код в серверном файле» и три догадки |
|
| 1. приставка только в начале сообщения | 1 | **запросов нет.** «Точный код в серверном файле» и три догадки |
|
||||||
| 2. + напоминание вплотную к вопросу | 4 | нашёл, но 2 круга ушли на угадывание имён файлов |
|
| 2. + напоминание вплотную к вопросу | 4 | нашёл, но два круга ушли на угадывание имён файлов |
|
||||||
| 3. + дерево папки в первом сообщении | **2** | запросил `ask.mjs` сразу, ответил по существу |
|
| 3. + дерево папки в первом сообщении | **2** | запросил нужный файл сразу, ответил по существу |
|
||||||
|
|
||||||
Два вывода, оба стоили живого прогона:
|
|
||||||
|
|
||||||
- **Инструкция в начале сообщения не работает.** Между приставкой и вопросом
|
- **Инструкция в начале сообщения не работает.** Между приставкой и вопросом
|
||||||
легли 22 КБ файла, и DeepSeek инструменты просто не заметил. Помогло
|
легли 22 КБ файла, и DeepSeek инструменты просто не заметил.
|
||||||
дословное повторение перед самим вопросом (`TAIL_REMINDER`).
|
- **Дерево папки надо давать сразу.** Без него он угадывал имена (`server.js`,
|
||||||
- **Дерево папки надо давать сразу.** Без него DeepSeek угадывал имена
|
`bridge.js` — таких в проекте нет), потом просил `LIST *.js` (проект
|
||||||
(`server.js`, `bridge.js` — таких в проекте нет), потом просил `LIST *.js`
|
на `.mjs`, пусто), потом `LIST **/*`. Дерево — 600 символов против двух
|
||||||
(проект на `.mjs`, пусто), потом `LIST **/*`. Дерево — 600 символов против
|
кругов по минуте.
|
||||||
двух кругов по минуте.
|
|
||||||
|
|
||||||
### Пульт, 11.08.2026
|
### Пульт, 11.08.2026
|
||||||
|
|
||||||
Сквозной прогон через страницу: вопрос без единого приложенного файла —
|
Вопрос без единого приложенного файла — «какая функция решает, что ответ
|
||||||
«какая функция решает, что ответ дописан?». 36 секунд, три шага. DeepSeek
|
дописан?». 36 секунд, три круга: пять блоков `FIND` сразу, затем `NEED`
|
||||||
запросил пятью блоками `FIND` сразу (`waitForAnswer`, `streaming`, `done`,
|
на найденный файл, и точный ответ с номером строки. Журнал кругов обновлялся
|
||||||
`stop_reason`, `finish_reason`), затем `NEED: ask.mjs`, и ответил точно:
|
на странице по ходу.
|
||||||
`waitForAnswer`, строка 675. Журнал шагов обновлялся на странице по ходу.
|
|
||||||
|
|
||||||
## Обрезанные ответы: причина найдена и устранена в мосте (11.08.2026)
|
### Обрезанные ответы: причина найдена
|
||||||
|
|
||||||
В третьем прогоне ответ оборвался посреди блока кода на `// Бы`. Оказалось,
|
Один из прогонов оборвался посреди блока кода на `// Бы`. Это не «конец
|
||||||
это не «конец определён раньше времени» и не кнопка `Continue`.
|
определён раньше времени» и не кнопка `Continue`.
|
||||||
|
|
||||||
**Браузер работал в фоне.** У неактивного окна страница не отрисовывается, а
|
**Браузер работал в фоне.** У неактивного окна страница не отрисовывается,
|
||||||
DeepSeek рисует блоки кода лениво: пока блок не нарисован, в DOM от него
|
а DeepSeek рисует блоки кода лениво: пока блок не нарисован, в DOM от него
|
||||||
лежат первые две строки, а остального нет вовсе — его не достать ни
|
лежат первые две строки, а остального нет вовсе — его не достать ни
|
||||||
`innerText`, ни `textContent`. Прокрутка не помогает (проверено проходом по
|
`innerText`, ни `textContent`. Прокрутка не помогает.
|
||||||
всему ответу шагами: ни одного лишнего символа).
|
|
||||||
|
|
||||||
Помогает единственное — заставить браузер отрисовать страницу, и через CDP
|
Помогает единственное — заставить браузер отрисовать страницу. Замеры на живых
|
||||||
это делает `Page.captureScreenshot`. Замеры на живых ответах:
|
ответах:
|
||||||
|
|
||||||
| | до отрисовки | после |
|
| | до отрисовки | после |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| ответ про TaskQueue | 2068 | 24 362 |
|
| ответ про TaskQueue | 2068 | 24 362 |
|
||||||
| ответ про EventBus | 3136 | 30 817 |
|
| ответ про EventBus | 3136 | 30 817 |
|
||||||
| ответ про Router (уже с правкой) | 258 | **32 045** |
|
| ответ про Router | 258 | **32 045** |
|
||||||
|
|
||||||
Правка в `ollama_orchestro/ask.mjs`: `revealAnswer()` перед съёмом текста
|
Вторая причина обрезания — кнопка **Continue**: DeepSeek режет длинный ответ
|
||||||
делает дешёвый скриншот (jpeg, качество 1) и перечитывает ответ, до трёх раз,
|
по своему лимиту и предлагает дописать, а генерация при этом честно
|
||||||
пока текст растёт. Картинка выбрасывается.
|
завершается. Сквозная проверка после починки — ответ на 47 414 символов
|
||||||
|
с целыми кодом и тестами.
|
||||||
|
|
||||||
Вдобавок `browser-launch.ps1` запускает браузер развёрнутым и с запретом
|
Обе поломки лечатся в `deepseek-api`, а не здесь: отрисовка и кнопка `Continue`
|
||||||
фонового режима (`--disable-backgrounding-occluded-windows`,
|
живут в его `browser.mjs`. Отсюда остаётся одно требование — **не сворачивать
|
||||||
`--disable-renderer-backgrounding`, `--disable-background-timer-throttling`,
|
окно браузера**.
|
||||||
`--disable-features=CalculateNativeWinOcclusion`). Это не замена скриншоту:
|
|
||||||
свёрнутое окно Windows не рисует вообще.
|
|
||||||
|
|
||||||
Вторая причина обрезания, найденная там же, — кнопка **Continue**: DeepSeek
|
### Переезд на deepseek-api, 26.08.2026
|
||||||
режет длинный ответ по своему лимиту и предлагает дописать, а генерация при
|
|
||||||
этом честно завершается. Теперь `waitForAnswer` жмёт её и ждёт дальше;
|
|
||||||
продолжение уходит в тот же блок ответа. Сквозная проверка — ответ на 47 414
|
|
||||||
символов с целыми кодом и тестами.
|
|
||||||
|
|
||||||
Обе правки в `ollama_orchestro`, deepwork получает их даром — мост вызывается
|
Раньше `deepwork` вызывал мост `ask.mjs` из проекта DeepShim дочерним процессом
|
||||||
подпроцессом.
|
и гонял текст через временные файлы. Теперь это `POST /api/chat`, а память
|
||||||
|
кругов переехала из чата в стенограмму (см. выше).
|
||||||
|
|
||||||
|
Проверено живым прогоном: круг 1 — 2094 символа, ответ `NEED: deepwork.mjs`;
|
||||||
|
круг 2 — 28 447 символов стенограммы, ответ дословно верный и по вопросу
|
||||||
|
из **первого** сообщения. Два круга за 17 с.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Лицензия
|
||||||
|
|
||||||
|
MIT.
|
||||||
|
|||||||
+3
-3
@@ -44,9 +44,9 @@ deepwork — задать DeepSeek вопрос и дать ему дочита
|
|||||||
--steps N сколько кругов позволить (по умолчанию 4)
|
--steps N сколько кругов позволить (по умолчанию 4)
|
||||||
--apply применить пришедшие блоки === FILE: === на диск
|
--apply применить пришедшие блоки === FILE: === на диск
|
||||||
(прежняя версия уезжает в backup/)
|
(прежняя версия уезжает в backup/)
|
||||||
--chat роль think (по умолчанию) | search
|
--chat роль think (по умолчанию) | search | vision
|
||||||
--timeout сек максимум бездействия страницы, передаётся мосту
|
--timeout сек сколько секунд ждать ответа на один шаг
|
||||||
--check проверить, что мост на месте и вкладка жива
|
--check проверить, что сервис на месте и вкладка жива
|
||||||
--selftest прогнать внутренние проверки, ничего не отправляя
|
--selftest прогнать внутренние проверки, ничего не отправляя
|
||||||
|
|
||||||
Инструменты, которые может вернуть DeepSeek (только чтение, только внутри
|
Инструменты, которые может вернуть DeepSeek (только чтение, только внутри
|
||||||
|
|||||||
+7
-4
@@ -5,6 +5,7 @@ REM ============================================================
|
|||||||
REM deepwork web console. Drag and drop a project folder onto
|
REM deepwork web console. Drag and drop a project folder onto
|
||||||
REM this file: DeepSeek gets tools (NEED / LIST / FIND) and can
|
REM this file: DeepSeek gets tools (NEED / LIST / FIND) and can
|
||||||
REM read that folder himself, step by step.
|
REM read that folder himself, step by step.
|
||||||
|
REM Needs the deepseek-api service running (its own start.cmd).
|
||||||
REM ASCII only on purpose - cmd.exe mangles UTF-8 Cyrillic.
|
REM ASCII only on purpose - cmd.exe mangles UTF-8 Cyrillic.
|
||||||
REM ============================================================
|
REM ============================================================
|
||||||
|
|
||||||
@@ -43,10 +44,11 @@ if errorlevel 1 (
|
|||||||
)
|
)
|
||||||
echo [OK] Node.js found
|
echo [OK] Node.js found
|
||||||
|
|
||||||
powershell -NoProfile -Command "try { Invoke-RestMethod -Uri 'http://127.0.0.1:9333/json/version' -TimeoutSec 2 | Out-Null; exit 0 } catch { exit 1 }" >nul 2>&1
|
powershell -NoProfile -Command "try { Invoke-RestMethod -Uri 'http://localhost:11500/api/tags' -TimeoutSec 3 | Out-Null; exit 0 } catch { exit 1 }" >nul 2>&1
|
||||||
if errorlevel 1 (
|
if errorlevel 1 (
|
||||||
echo [WARN] Bridge is NOT available on port 9333.
|
echo [WARN] deepseek-api is NOT ready on port 11500.
|
||||||
echo Run start-browser.cmd in ollama_orchestro, then log in.
|
echo Run start.cmd in the deepseek-api folder - it starts the
|
||||||
|
echo browser by itself. Log in to DeepSeek in the window it opens.
|
||||||
echo The console will start anyway and show the same warning.
|
echo The console will start anyway and show the same warning.
|
||||||
echo.
|
echo.
|
||||||
)
|
)
|
||||||
@@ -54,7 +56,8 @@ if errorlevel 1 (
|
|||||||
cd /d "%~1"
|
cd /d "%~1"
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo Open the printed address in your DEFAULT browser, not the debug one.
|
echo Open the printed address in your DEFAULT browser, not the one
|
||||||
|
echo that deepseek-api drives.
|
||||||
echo Ctrl+C here stops it.
|
echo Ctrl+C here stops it.
|
||||||
echo.
|
echo.
|
||||||
node "%DW_DIR%deepwork.mjs" ui
|
node "%DW_DIR%deepwork.mjs" ui
|
||||||
|
|||||||
Reference in New Issue
Block a user