diff --git a/.gitignore b/.gitignore
index aa8ae16..54ff5d9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,3 +45,6 @@ test/coverage.lcov
.playwright-mcp/
/tiktok
/.cuckoo/skills
+# cookie/agents — НЕ игнорируем: агенты проекта должны попадать в git.
+# Пользовательские агенты лежат в ~/cookie/agents (вне репозитория).
+# Ранее здесь был /cookie/agents — убрано, иначе новые агенты untracked.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b771b3b..5b7ae5e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,90 +1,40 @@
# Changelog
-## [5.0.0] - 2024-10-05
-
-### 🎉 Major Release — Cookie Code
-
-**Breaking Changes:**
-- 🍪 **Rebrand: Cuckoo Code → Cookie Code** — новое название, новая идентичность:
- - все пользовательские строки обновлены на "Cookie Code";
- - внутренние API и техническая терминология остались без изменений для совместимости.
+## [5.0.2] - 2026-10-06
### Added
-- 📚 **Билингвальная документация** — теперь три README для разных аудиторий:
- - `README.md` (12K, русский) — краткая версия для русских пользователей;
- - `README.en.md` (12K, английский) — полная версия с чётким value proposition для международной аудитории;
- - `README.ru.md` (25K, русский) — полная техническая документация на русском.
-- 🎨 **SVG-иконки вместо эмодзи** — заменили 🔄 на чистые SVG:
- - кнопка "Изменить" (проект) — иконка карандаша/редактирования;
- - кнопка "Обновить" (сессии, окна, MCP, diff) — иконка круговой стрелки;
- - `stroke="currentColor"` — автоматическая адаптация к цвету текста;
- - компактные 14×14px иконки с чёткими линиями.
-- 🔧 **Улучшенный diff viewer** — 8 крупных апгрейдов:
- - навигация по hunks с кнопками ◀/▶ и хоткеями `n`/`p`;
- - внутристроковый diff (алгоритм Myers) — подсветка изменённых символов;
- - копирование — кнопка Copy для всего diff, клик на строку копирует без префикса;
- - фильтры — чекбоксы Added/Deleted/Context для скрытия ненужных строк;
- - мини-карта — вертикальная полоса с цветными сегментами изменений;
- - статистика — `📊 +234 -89 в 12 файлах` в списке;
- - кэширование — результаты git-команд сохраняются в Map;
- - перетаскиваемое окно — захват за шапку, сохранение позиции в localStorage.
-- 📱 **Построчный diff в Telegram-уведомлениях** — операции `edit` теперь показывают реальные изменения:
- - вместо "было/стало" — unified diff с префиксами `+`/`-`/` `;
- - до 30 строк diff, затем `…(обрезано)`;
- - используется тот же `buildLineDiff` из `tools/line-diff.js`, что и в UI.
+- 🚀 **Субагенты — теперь у AI есть свои помощники!** 😎 Представьте: просите AI «разберись с этим куском проекта», а он не тонет в тысяче файлов сам, а зовёт специалиста. Каждый субагент работает в **отдельном окне** со своим контекстом — весь его рабочий шум (поиски, чтения, пробы) остаётся там, а вам прилетает только чистый итог. Основной чат не пухнет, голова не кругом:
+ - 🎯 `run_agent(name, task)` — «эй, explore, найди все вызовы apiFetch». Открывается второе окно (тот же логин DeepSeek — ничего заново вводить не надо), субагент делает дело, окно само закрывается, родителю уходит резюме;
+ - 📋 `list_agents` — глянуть, кто вообще у нас в команде: имя, описание, какие инструменты разрешены, сколько шагов максимум;
+ - 🔍 `read_agent(name)` — подсмотреть полный промпт агента (удобно для отладки);
+ - 🧬 `create_agent({...})` — а вот самое интересное: **AI может вырастить себе специалиста прямо из чата!** «Создай агента для ревью SQL-миграций» — и через секунду файл готов, можно сразу делегировать;
+ - 📂 агенты лежат в `cookie/agents/*.md` (проектные — едут с репо, команда видит) или в `~/cookie/agents/*.md` (личные, для всех проектов). Формат — обычный markdown с frontmatter (`name`, `description`, `tools`, `maxTurns`);
+ - 🎁 из коробки уже есть четверо: `explore` (разведчик), `code-reviewer` (ревьюер), `git-committer` (гит-мастер), `changelog-writer` (летописец).
+- 🔒 **Whitelist инструментов — субагент делает только то, что ему разрешили** 🛡️ Написали в frontmatter `tools: read, grep` — и всё, `bash`, `mysql`, `deleteFile` для него закрыты наглухо:
+ - проверка происходит **до** запуска инструмента — не «а потом откатим», а «даже не начнём»;
+ - попробует запрещённое — получит чёткое «Инструмент X не разрешён этому агенту, разрешены: read, grep»;
+ - а ещё субагент не может позвать другого субагента — никаких бесконечных матрёшек 🪆.
+- 🤖 **Субагенты теперь болтают с вами в Telegram** 📱 Полный жизненный цикл на экране телефона:
+ - 🚀 при делегировании сразу прилетает карточка «кому и что поручили»;
+ - 🛠 каждое действие агента помечено «🤖 Агент: <имя>» — сразу видно, кто работает;
+ - 🎯 когда агент закончил — отдельное сообщение с итогом;
+ - 🔇 и никаких дублей: ответы из окна субагента не спамят в чат-фид;
+ - ⏱ финал определяется по «текст устоялся» (а не по старой ненадёжной проверке), с учётом лимита шагов и таймаута.
+- 🧠 **Память AI — теперь AI вас помнит** 💭 Скажите «Запомни, что меня зовут Ваня» или «Сохрани в память: у меня Windows 11 и RTX 3060» — и он запомнит. В следующей сессии уже будет знать контекст, не придётся повторять:
+ - 💾 `memory_save(text)` — сохранить одну мысль (одна запись = одна строчка с датой);
+ - 📖 `memory_read()` — прочитать всё, что накопилось;
+ - 🗑 `memory_clear()` — стереть всё (только по прямой просьбе — AI сначала предупредит);
+ - 📁 всё живёт в одном файлике `/memory.md`, можно открыть или очистить прямо из настроек;
+ - 🎯 содержимое памяти **не** подмешивается в промпт автоматически — читается только когда реально нужно, чтобы не жечь токены зря;
+ - 🔒 в plan-mode любые изменения памяти заблокированы — на этапе планирования AI ничего не перепишет.
+- 📚 **Новый раздел в README про субагентов** — как делегировать, три способа завести агента, что его защищает (whitelist, anti-recursion, `maxTurns`, timeout) и готовый пример файла агента. Читайте и заводите своих! 📖
### Changed
-- 📖 **Новая структура README** — English-first для GitHub-аудитории:
- - чёткая проблема → решение в первых строках;
- - value proposition: "Zero token cost + Real agent loop + Git integration";
- - конкретные примеры использования вместо технического описания;
- - призыв к действию — скачать бинарники.
-
-### Removed
-
-- 🗑️ **Устаревшие документы удалены из репозитория**:
- - `ROADMAP.ru.md` и `Roadmap.md` — 3-недельной давности, больше не актуальны;
- - `.cuckooCode/AUTO_UPDATE_RELEASE.md` — документация по auto-update на китайском;
- - `DIFF_IMPROVEMENTS.md` — временный документ с описанием улучшений (все реализованы).
-
-### Added (EN)
-
-- 📚 **Bilingual documentation** — three README files for different audiences:
- - `README.md` (12K, Russian) — concise version for Russian users;
- - `README.en.md` (12K, English) — full version with clear value proposition for international audience;
- - `README.ru.md` (25K, Russian) — complete technical documentation in Russian.
-- 🎨 **SVG icons instead of emoji** — replaced 🔄 with clean SVG:
- - "Change" button (project) — pencil/edit icon;
- - "Refresh" button (sessions, windows, MCP, diff) — circular arrow icon;
- - `stroke="currentColor"` — automatic adaptation to text color;
- - compact 14×14px icons with sharp lines.
-- 🔧 **Enhanced diff viewer** — 8 major upgrades:
- - hunk navigation with ◀/▶ buttons and `n`/`p` hotkeys;
- - intra-line diff (Myers algorithm) — highlights changed characters;
- - copy — Copy button for full diff, click on line copies without prefix;
- - filters — Added/Deleted/Context checkboxes to hide unwanted lines;
- - mini-map — vertical bar with colored change segments;
- - statistics — `📊 +234 -89 in 12 files` in the list;
- - caching — git command results saved in Map;
- - draggable window — grab by header, position saved in localStorage.
-- 📱 **Line-by-line diff in Telegram notifications** — `edit` operations now show real changes:
- - instead of "before/after" — unified diff with `+`/`-`/` ` prefixes;
- - up to 30 lines of diff, then `…(truncated)`;
- - uses the same `buildLineDiff` from `tools/line-diff.js` as the UI.
-
-### Changed (EN)
-
-- 📖 **New README structure** — English-first for GitHub audience:
- - clear problem → solution in the first lines;
- - value proposition: "Zero token cost + Real agent loop + Git integration";
- - concrete usage examples instead of technical description;
- - call to action — download binaries.
+- 📁 **Агенты переехали: `.cuckoo/agents` → `cookie/agents`** — теперь проектные агенты лежат в репозитории рядышком с кодом (команда видит и использует), а личные — в `~/cookie/agents` (вне репо). Сканер, типы и документация обновлены. 🚚
+- 🎛 **Окно субагента получает полный системный промпт Cookie Code** — тот же набор инструментов и формат `cuckoo`, что у основного ассистента. То есть субагент работает ровно так же умело, просто в своей песочнице. 🧰
-### Removed (EN)
+### Fixed
-- 🗑️ **Obsolete documents removed from repository**:
- - `ROADMAP.ru.md` and `Roadmap.md` — 3 weeks old, no longer relevant;
- - `.cuckooCode/AUTO_UPDATE_RELEASE.md` — auto-update documentation in Chinese;
- - `DIFF_IMPROVEMENTS.md` — temporary document describing improvements (all implemented).
+- 🐛 **Рабочая папка субагента больше не теряется** — была хитрая бага: при загрузке домашней DeepSeek (когда `sessionId` ещё не появился) выбранная папка проекта сбрасывалась в `null`, и агент начинал искать файлы «в никуда». Теперь папка кэшируется (`pendingProjectDir`) до готовности сессии и привязывается сама — относительные пути работают с первой секунды. ✅
diff --git a/README.en.md b/README.en.md
index 0e0b267..5a3aa85 100644
--- a/README.en.md
+++ b/README.en.md
@@ -27,9 +27,10 @@
✅ **Zero token cost** — uses your free DeepSeek web account, no API keys
✅ **Real agent loop** — AI reads files → writes code → runs tests → commits changes
+✅ **Subagents** — AI delegates tasks to isolated agents (own context, own tool whitelist)
✅ **Git integration** — see diffs, browse history, review changes in a visual panel
✅ **Telegram control** — code from your phone, get notifications, approve commands remotely
-✅ **Beautiful UI** — glass effects, custom themes, animated pets, dark mode
+✅ **Beautiful UI** — glass effects, custom themes, animated pets, dark mode
---
@@ -38,6 +39,7 @@
### 🤖 **AI Agent That Actually Does Things**
The AI can now:
+
- 📖 **Read your files** — entire project structure, grep patterns, file contents
- ✏️ **Write & edit code** — create files, apply patches, delete old code
- 💻 **Run commands** — bash, PowerShell, database queries, any shell script
@@ -47,11 +49,57 @@ The AI can now:
- 🔧 **MCP tools** — connect any MCP server for extended capabilities
**How it works:**
+
1. You ask: "Show me recent changes in auth.js"
2. AI emits: `` `cuckoo const r = await grep('auth.js', 'login');` ``
3. Cookie Code intercepts, executes, streams result back to AI
4. AI sees the output and continues working
+### 🚀 **Subagents — AI Builds Its Own Helpers**
+
+
+
+
+
+
+Cookie Code can **delegate tasks to isolated AI agents**, each in its own window with its own context. The subagent's drafts, searches, and tool calls **never pollute the main conversation** — only the final summary comes back to the parent.
+
+**How it works:**
+
+1. You: _"Delegate to explore: find all calls to apiFetch"_
+2. AI calls `run_agent("explore", "find all calls to apiFetch")`
+3. A **separate window** opens using the same DeepSeek login
+4. The subagent works in isolation: `glob → read → grep → ...`
+5. When done, the window closes and **only the summary** appears in the chat
+
+**Three ways to create an agent:**
+
+- **Manually** — drop `cookie/agents/.md` with frontmatter into your project
+- **Via AI** — say _"Create an agent for SQL migration review"_ → AI calls `create_agent` and uses it immediately
+- **Built-in** — `explore`, `code-reviewer`, `git-committer`, `changelog-writer` ship with the project
+
+**Safety rails:**
+
+- 🔒 **Tool whitelist** — put `tools: read, grep` in the agent's frontmatter → it **physically cannot** call `bash` or `mysql`
+- 🚫 **Anti-recursion** — a subagent cannot spawn another subagent
+- ⏱ **maxTurns** — breaks infinite loops (e.g., 40 steps for the committer)
+- ⏲ **10-min timeout** — force-closes a hung window
+
+**Agent example:**
+
+```markdown
+---
+name: code-reviewer
+description: Review code quality. Use after writing code.
+tools: read, grep, glob
+maxTurns: 20
+---
+
+You are an experienced code review expert...
+```
+
+---
+
### 🎨 **Beautiful & Customizable**
@@ -94,6 +142,7 @@ Control everything from your phone:
Built-in diff viewer:
+
- **Changes tab** — see uncommitted changes, file-by-file diffs
- **History tab** — browse commits, click to see full diff
- **Navigation** — jump between hunks, filter added/deleted lines
@@ -103,6 +152,7 @@ Built-in diff viewer:
### 📈 **Statistics Dashboard**
Track your productivity:
+
- **Activity heatmap** — GitHub-style contribution graph
- **Token usage** — daily/weekly trends
- **Favorite models** — which AI you use most
@@ -114,12 +164,14 @@ Track your productivity:
### Option 1: Download Binary (Recommended)
-**Windows:**
+**Windows:**
+
1. Download [CookieCode-Setup.exe](https://github.com/merfiDEV/Cookie-code/releases/latest)
2. Run installer
3. Launch Cookie Code
-**macOS:**
+**macOS:**
+
1. Download [CookieCode.dmg](https://github.com/merfiDEV/Cookie-code/releases/latest)
2. Drag to Applications
3. Open (right-click → Open if Gatekeeper blocks)
@@ -178,6 +230,7 @@ AI: [runs git add + git commit]
### 3️⃣ **Explore Tools**
Open the side panel (Cookie Code logo) to:
+
- 🗂️ **Browse sessions** — switch between project contexts
- 📝 **Manage todos** — see AI-created task lists
- 🔄 **View git diff** — visual file changes
@@ -192,6 +245,7 @@ Open the side panel (Cookie Code logo) to:
**Current limitation:** AI only knows files it explicitly reads.
**Planned feature:** Full project indexing
+
- Embed all source files into a vector database
- AI can semantic search: "Where's the auth logic?"
- Instant jump-to-definition for any symbol
@@ -222,13 +276,13 @@ Drop `.js` files into `tools/custom/` to extend Cookie Code:
```javascript
// tools/custom/deploy.js
module.exports = {
- name: 'deploy',
- description: 'Deploy to production',
- params: { target: 'string' },
+ name: "deploy",
+ description: "Deploy to production",
+ params: { target: "string" },
async execute({ target }) {
// Your deployment logic
- return { success: true, url: '...' };
- }
+ return { success: true, url: "..." };
+ },
};
```
@@ -240,20 +294,20 @@ AI can now call `deploy` like any built-in tool.
Cookie Code ships with 20+ tools out of the box:
-| Tool | Description | Example |
-|------|-------------|---------|
-| `read` | Read file contents | `read('src/auth.js')` |
-| `write` | Create or overwrite file | `write('test.js', code)` |
-| `edit` | Apply targeted patch | `edit('app.js', oldCode, newCode)` |
-| `glob` | Find files by pattern | `glob('**/*.test.js')` |
-| `grep` | Search file contents | `grep('TODO', { include: '*.js' })` |
-| `bash` | Run shell command | `bash('npm test')` |
-| `pwsh` | Run PowerShell script | `pwsh('Get-Process')` |
-| `git` | Git operations | `git('status')` |
-| `mysql` | SQL queries | `mysql('SELECT * FROM users')` |
-| `webFetch` | HTTP requests | `webFetch('https://api.example.com')` |
-| `todoWrite` | Manage task lists | `todoWrite([{content: 'Fix bug'}])` |
-| `mcpCall` | Call MCP server tool | `mcpCall('github', 'create_pr', {...})` |
+| Tool | Description | Example |
+| ----------- | ------------------------ | --------------------------------------- |
+| `read` | Read file contents | `read('src/auth.js')` |
+| `write` | Create or overwrite file | `write('test.js', code)` |
+| `edit` | Apply targeted patch | `edit('app.js', oldCode, newCode)` |
+| `glob` | Find files by pattern | `glob('**/*.test.js')` |
+| `grep` | Search file contents | `grep('TODO', { include: '*.js' })` |
+| `bash` | Run shell command | `bash('npm test')` |
+| `pwsh` | Run PowerShell script | `pwsh('Get-Process')` |
+| `git` | Git operations | `git('status')` |
+| `mysql` | SQL queries | `mysql('SELECT * FROM users')` |
+| `webFetch` | HTTP requests | `webFetch('https://api.example.com')` |
+| `todoWrite` | Manage task lists | `todoWrite([{content: 'Fix bug'}])` |
+| `mcpCall` | Call MCP server tool | `mcpCall('github', 'create_pr', {...})` |
[Full tool reference →](docs/TOOLS.md)
@@ -316,12 +370,14 @@ Free to use, modify, and distribute. Commercial use allowed.
## 🙏 Credits
Built with:
+
- [Electron](https://www.electronjs.org/) — desktop app framework
- [DeepSeek](https://www.deepseek.com/) — AI chat interface
- [Telegraf](https://github.com/telegraf/telegraf) — Telegram bot framework
- [gifenc](https://github.com/mattdesl/gifenc) — GIF processing
Inspired by:
+
- [Aider](https://github.com/paul-gauthier/aider) — AI pair programming in terminal
- [Claude Desktop](https://claude.ai/download) — MCP protocol pioneer
- [Cursor](https://cursor.sh/) — AI-first code editor
@@ -341,8 +397,8 @@ If Cookie Code saves you time, consider giving it a star! It helps others discov
- **Documentation:** [docs/](docs/)
- **Changelog:** [CHANGELOG.md](CHANGELOG.md)
- **Roadmap:** [GitHub Projects](https://github.com/merfiDEV/Cookie-code/projects)
-- **Discord:** [Join the community](https://discord.gg/...) *(coming soon)*
-- **Twitter:** [@CookieCodeAI](https://twitter.com/...) *(coming soon)*
+- **Discord:** [Join the community](https://discord.gg/...) _(coming soon)_
+- **Twitter:** [@CookieCodeAI](https://twitter.com/...) _(coming soon)_
---
diff --git a/README.md b/README.md
index dd73361..ca278b4 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@
-
+
**Превратите DeepSeek в настоящего помощника по коду.** Cookie Code соединяет AI-чат с вашей реальной кодовой базой — без API-токенов, без копипасты, только чистая автоматизация.
@@ -27,9 +27,10 @@
✅ **Нулевая стоимость токенов** — использует ваш бесплатный веб-аккаунт DeepSeek, без API-ключей
✅ **Настоящий агентный цикл** — AI читает файлы → пишет код → запускает тесты → коммитит изменения
+✅ **Субагенты** — AI делегирует задачи изолированным агентам (свой контекст, свой whitelist инструментов)
✅ **Интеграция Git** — смотрите diff, листайте историю, проверяйте изменения визуально
✅ **Управление через Telegram** — пишите код с телефона, получайте уведомления, подтверждайте команды удалённо
-✅ **Красивый UI** — стеклянные эффекты, кастомные темы, анимированные петы, тёмная тема
+✅ **Красивый UI** — стеклянные эффекты, кастомные темы, анимированные петы, тёмная тема
---
@@ -38,6 +39,7 @@
### 🤖 **AI-агент, который реально работает**
Теперь AI умеет:
+
- 📖 **Читать файлы** — структура проекта, grep-паттерны, содержимое
- ✏️ **Писать и редактировать код** — создавать файлы, применять патчи, удалять старый код
- 💻 **Запускать команды** — bash, PowerShell, SQL-запросы, любые shell-скрипты
@@ -45,13 +47,60 @@
- 📊 **Управлять задачами** — создавать, отслеживать и завершать todo-списки
- 🌐 **Получать данные** — HTTP-запросы, API-вызовы, веб-скрапинг
- 🔧 **MCP-инструменты** — подключать любой MCP-сервер для расширенных возможностей
+- 🧠 **Память** — AI запоминает факты о вас и вашей системе («Сохрани в память, что…»), читает их в следующих сессиях через `memoryRead()`. Файл памяти лежит в папке пользователя, открывается и очищается в настройках.
**Как это работает:**
+
1. Вы спрашиваете: "Покажи последние изменения в auth.js"
2. AI генерирует: `` `cuckoo const r = await grep('auth.js', 'login');` ``
3. Cookie Code перехватывает, выполняет, стримит результат обратно в AI
4. AI видит вывод и продолжает работать
+### 🚀 **Субагенты — AI создаёт своих помощников**
+
+
+
+
+
+
+Cookie Code умеет **делегировать задачи изолированным AI-агентам**, каждый в своём окне и со своим контекстом. Черновики, поиски и tool-вызовы субагента **не засоряют основной диалог** — родителю возвращается только финальное резюме.
+
+**Как это работает:**
+
+1. Вы: _«Делегируй explore: найди все вызовы apiFetch»_
+2. AI вызывает `run_agent("explore", "...", "...")`
+3. Открывается **отдельное окно** с тем же логином DeepSeek
+4. Субагент работает в изоляции: `glob → read → grep → ...`
+5. Когда закончит — окно закрывается, в чат приходит **только резюме**
+
+**Три способа завести агента:**
+
+- **Вручную** — положите `cookie/agents/<имя>.md` с frontmatter в проект
+- **Через AI** — скажите _«Создай агента для ревью SQL-миграций»_ → AI вызовет `create_agent` и сразу его использует
+- **Готовые** — `explore`, `code-reviewer`, `git-committer`, `changelog-writer` уже в проекте
+
+**Что защищает:**
+
+- 🔒 **Whitelist инструментов** — в frontmatter агента указываете `tools: read, grep` → агент **физически не сможет** вызвать `bash` или `mysql`
+- 🚫 **Anti-recursion** — субагент не может запустить ещё одного субагента
+- ⏱ **maxTurns** — обрубает зацикливание (например, 40 шагов для коммиттера)
+- ⏲ **Timeout 10 мин** — принудительно закрывает зависшее окно
+
+**Пример агента:**
+
+```markdown
+---
+name: code-reviewer
+description: Проверка качества кода. Использовать после написания кода.
+tools: read, grep, glob
+maxTurns: 20
+---
+
+Ты — опытный эксперт по ревью кода...
+```
+
+---
+
### 🎨 **Красиво и настраиваемо**
- **Стеклянный UI** — матовое стекло с настраиваемым размытием и прозрачностью
@@ -86,6 +135,7 @@
### 📊 **Интеграция Git**
Встроенный просмотрщик diff:
+
- **Вкладка "Изменения"** — незакоммиченные изменения, построчные diff
- **Вкладка "История"** — листайте коммиты, кликайте для просмотра полного diff
- **Навигация** — прыгайте между hunks, фильтруйте добавленные/удалённые строки
@@ -95,6 +145,7 @@
### 📈 **Дашборд статистики**
Отслеживайте продуктивность:
+
- **Тепловая карта активности** — график вкладов в стиле GitHub
- **Использование токенов** — тренды по дням/неделям
- **Любимые модели** — какой AI вы используете чаще
@@ -151,6 +202,7 @@ AI: [git commit] Закоммичено: "feat(auth): добавлены тес
### Исследуйте
Откройте боковую панель для:
+
- 🗂️ Просмотра сессий
- 📝 Управления задачами
- 🔄 Просмотра git diff
@@ -162,19 +214,19 @@ AI: [git commit] Закоммичено: "feat(auth): добавлены тес
20+ инструментов из коробки:
-| Инструмент | Описание |
-|------|-------------|
-| `read` | Прочитать содержимое файла |
-| `write` | Создать/перезаписать файл |
-| `edit` | Применить патч |
-| `glob` | Найти файлы по паттерну |
-| `grep` | Поиск по содержимому |
-| `bash` / `pwsh` | Запуск shell-команд |
-| `git` | Git-операции |
-| `mysql` | SQL-запросы |
-| `webFetch` | HTTP-запросы |
-| `todoWrite` | Списки задач |
-| `mcpCall` | Инструменты MCP-сервера |
+| Инструмент | Описание |
+| --------------- | -------------------------- |
+| `read` | Прочитать содержимое файла |
+| `write` | Создать/перезаписать файл |
+| `edit` | Применить патч |
+| `glob` | Найти файлы по паттерну |
+| `grep` | Поиск по содержимому |
+| `bash` / `pwsh` | Запуск shell-команд |
+| `git` | Git-операции |
+| `mysql` | SQL-запросы |
+| `webFetch` | HTTP-запросы |
+| `todoWrite` | Списки задач |
+| `mcpCall` | Инструменты MCP-сервера |
---
@@ -182,7 +234,7 @@ AI: [git commit] Закоммичено: "feat(auth): добавлены тес
**Темы:** Размытие фона, прозрачность панелей, стеклянные цвета
**Петы:** Бросьте PNG/GIF в `userData/pets/`, выберите из сетки
-**Шрифты:** Бросьте `.ttf`/`.woff` в `userData/fonts/`, выберите из выпадающего списка
+**Шрифты:** Бросьте `.ttf`/`.woff` в `userData/fonts/`, выберите из выпадающего списка
---
@@ -196,6 +248,7 @@ AI: [git commit] Закоммичено: "feat(auth): добавлены тес
6. Пушьте и открывайте PR
**Области, где нужна помощь:**
+
- 🌍 Переводы
- 📚 Документация
- 🐛 Отчёты об ошибках
diff --git a/README.ru.md b/README.ru.md
index f30c0b8..7b8b5b4 100644
--- a/README.ru.md
+++ b/README.ru.md
@@ -143,6 +143,69 @@
Поместите папку в `.cuckoo/skills//` с файлом `SKILL.md` (и опциональным `tool.js`) — она станет вызываемой через `skillList`, `skillLoad`, `skillExecute`.
+### Субагенты
+
+
+
+
+
+
+Cookie Code умеет **делегировать задачи изолированным AI-агентам**. Каждый субагент работает в **отдельном окне** с тем же partition (общий логин DeepSeek), в **своём контексте**, и возвращает родителю **только финальное резюме** — черновики, поиски и tool-вызовы не засоряют основной диалог.
+
+**Пример:**
+
+1. Вы: _«Делегируй explore: найди все вызовы apiFetch»_
+2. AI вызывает `run_agent("explore", "найди все вызовы apiFetch")`
+3. Открывается второе окно, туда автоматически уходит системный промпт + задача
+4. Субагент работает: `glob → read → grep → ...`
+5. Когда напишет финал **без** `cuckoo`-блоков — окно закрывается, в родительский чат приходит только резюме
+
+**Три способа завести агента:**
+
+- **Вручную** — положите `cookie/agents/.md` с frontmatter в проект
+- **Через AI** — попросите: _«Создай агента для ревью SQL-миграций»_ — AI вызовет `create_agent` и сможет его сразу использовать
+- **Готовые** — в проекте уже есть `explore`, `code-reviewer`, `git-committer`, `changelog-writer`
+
+**Формат файла агента** (`<проект>/cookie/agents/<имя>.md`):
+
+```markdown
+---
+name: code-reviewer
+description: Проверка качества кода. Использовать после написания кода.
+tools: read, grep, glob
+maxTurns: 20
+---
+
+Ты — опытный эксперт по ревью кода. Проверь указанный код, найди
+реальные проблемы и дай рекомендации.
+```
+
+**Поля frontmatter:**
+
+| Поле | Обязательно | Описание |
+| ------------- | ----------- | ---------------------------------------------------------- |
+| `name` | нет | Имя агента (по умолчанию — имя файла без `.md`) |
+| `description` | **да** | Когда делегировать. Без него агент игнорируется |
+| `tools` | нет | Список разрешённых инструментов через запятую. Пусто = все |
+| `maxTurns` | нет | Лимит шагов 1..1000 (защита от зацикливания) |
+
+**Изоляция и защита:**
+
+- 🔒 **Whitelist инструментов** — `tools: read, grep` → агент **физически не сможет** вызвать `bash`, `mysql`, `deleteFile` — блокировка на двух уровнях (JsRunner + main IPC)
+- 🚫 **Anti-recursion** — субагент не может вызвать `run_agent`
+- ⏱ **maxTurns** — обрубает бесконечные циклы
+- ⏲ **Timeout 10 мин** — принудительно закрывает зависшее окно
+- 📁 **Общий projectDir** — субагент видит ту же рабочую папку, что родитель
+- 🎯 **Прогрессивное раскрытие** — в системный промпт родителя идут только `name` + `description` каждого агента, полный `systemPrompt` читается только при запуске
+
+**Уведомления в Telegram:**
+
+При делегировании в TG приходят:
+
+1. Карточка запуска: `🚀 ИИ делегирует задачу субагенту` + имя + задача
+2. Каждый tool-вызов агента: `🤖 Агент: explore` + `📖 Reading file.js`
+3. Финальный результат: `🎯 Субагент вернул результат` + резюме
+
### Авто-форматтеры
Каждый `write` и `edit` прогоняет файл через форматтер для конкретного языка — код AI автоматически приводится к стилю вашего проекта. Не нужно вручную запускать `prettier --write`, стиль не мешает в diff.
@@ -248,6 +311,10 @@ Cookie Code перехватывает его, выполняет в песоч
| `mysql` | SQL-запросы |
| `mcpCall`, `mcpListServers`, `mcpGetTools` | MCP-инструменты |
| `skillList`, `skillLoad`, `skillExecute` | Пользовательские скиллы |
+| `run_agent` | Делегировать задачу субагенту (отдельное окно, изолированный контекст) |
+| `create_agent` | Создать нового субагента (файл `cookie/agents/<имя>.md`) |
+| `list_agents` | Список доступных субагентов (проект + пользователь) |
+| `read_agent` | Полный systemPrompt субагента по имени |
| `openBrowserWindow`, `injectJS` | Окно браузера Electron + инъекция JS |
Полные TypeScript-декларации — в `tools/cuckoo-tools.d.ts`.
diff --git a/assets/photo_2026-10-06_18-24-20.jpg b/assets/photo_2026-10-06_18-24-20.jpg
new file mode 100644
index 0000000..f302498
Binary files /dev/null and b/assets/photo_2026-10-06_18-24-20.jpg differ
diff --git a/assets/photo_2026-10-06_18-24-55.jpg b/assets/photo_2026-10-06_18-24-55.jpg
new file mode 100644
index 0000000..b6da867
Binary files /dev/null and b/assets/photo_2026-10-06_18-24-55.jpg differ
diff --git a/botsrc/i18n.js b/botsrc/i18n.js
index b138418..ca973a0 100644
--- a/botsrc/i18n.js
+++ b/botsrc/i18n.js
@@ -44,6 +44,7 @@ const STRINGS = {
"help.cmd.show": "/show <hash> — diff коммита",
"help.cmd.files": "/files <hash> — файлы коммита",
"help.cmd.todos": "/todos — список задач активного окна",
+ "help.cmd.agents": "/agents — список субагентов проекта",
"help.cmd.screen": "/screen — скриншот активного окна",
"help.cmd.cancel": "/cancel — отменить ввод / подтверждение",
"help.cmd.help": "/help — эта справка",
@@ -250,6 +251,54 @@ const STRINGS = {
"tool.items": " пункт(ов)",
"tool.allDone": "🎉 Все задачи выполнены ({n}/{n})",
+ // ===== Память (memory_save/read/clear) =====
+ "mem.readTitle": "🧠 ИИ читает память",
+ "mem.saveTitle": "🧠 ИИ сохраняет в память",
+ "mem.clearTitle": "🧠 ИИ очищает память",
+ "mem.readEmpty": "🧠 Память пуста",
+ "mem.saved": "Записано:",
+ "mem.cleared": "🗑 Память очищена",
+ "mem.content": "Содержимое памяти:",
+ "mem.count": "записей: {n}",
+
+ // ===== Время/локация (city_time) =====
+ "city.title": "🕒 Время и местоположение",
+ "city.time": "Время",
+ "city.tz": "Часовой пояс",
+ "city.place": "Город / страна",
+
+ // ===== Субагенты (run_agent / create_agent / list_agents / read_agent) =====
+ "agent.runTitle": "🚀 ИИ делегирует задачу субагенту",
+ "agent.resultTitle": "🎯 Субагент вернул результат",
+ "agent.createTitle": "🧬 ИИ создаёт нового субагента",
+ "agent.listTitle": "📋 ИИ смотрит список субагентов",
+ "agent.readTitle": "🔍 ИИ читает описание субагента",
+ "agent.name": "Агент",
+ "agent.task": "Задача",
+ "agent.tools": "Инструменты",
+ "agent.maxTurns": "Лимит шагов",
+ "agent.noTools": "все разрешены",
+ "agent.noLimit": "без лимита",
+ "agent.noResult": "(пустой результат)",
+ "agent.failed": "❌ Субагент завершился с ошибкой",
+ "agent.created": "Агент создан",
+ "agent.existing": "Агент обновлён",
+ "agent.prompt": "Системный промпт",
+ "agents.cmd.title": "🤖 Субагенты проекта",
+ "agents.cmd.empty":
+ "🤖 Субагентов нет\n\nДобавьте .md-файл в cookie/agents/ или попросите AI: «Создай агента для …».",
+ "agents.cmd.noProject":
+ "📂 Проект не выбран\n\nСначала выберите проект в главном окне — субагенты привязаны к проекту.",
+ "agents.cmd.header": "🤖 Субагенты проекта — {n} шт.",
+ "agents.cmd.itemTools": "🧰 Инструменты",
+ "agents.cmd.itemTurns": "🔁 Шагов",
+ "agents.cmd.itemSource": "📍 Источник",
+ "agents.cmd.itemNoTools": "все разрешены",
+ "agents.cmd.itemNoLimit": "без лимита",
+ "agents.cmd.hint":
+ '💡 Делегируйте задачу: run_agent("name", "задача")',
+ "agents.cmd.more": "…и ещё {n}",
+
// ===== Approval =====
"approval.title": "🔐 Подтверждение команды",
"approval.jsScript": "JS-скрипт",
@@ -338,6 +387,7 @@ const STRINGS = {
"help.cmd.show": "/show <hash> — commit diff",
"help.cmd.files": "/files <hash> — commit files",
"help.cmd.todos": "/todos — tasks of the active window",
+ "help.cmd.agents": "/agents — project subagents list",
"help.cmd.screen": "/screen — screenshot of the active window",
"help.cmd.cancel": "/cancel — cancel input / approval",
"help.cmd.help": "/help — this help",
@@ -545,6 +595,54 @@ const STRINGS = {
"tool.items": " item(s)",
"tool.allDone": "🎉 All tasks completed ({n}/{n})",
+ // ===== Memory (memory_save/read/clear) =====
+ "mem.readTitle": "🧠 AI reads memory",
+ "mem.saveTitle": "🧠 AI saves to memory",
+ "mem.clearTitle": "🧠 AI clears memory",
+ "mem.readEmpty": "🧠 Memory is empty",
+ "mem.saved": "Saved:",
+ "mem.cleared": "🗑 Memory cleared",
+ "mem.content": "Memory content:",
+ "mem.count": "entries: {n}",
+
+ // ===== Time/location (city_time) =====
+ "city.title": "🕒 Time & location",
+ "city.time": "Time",
+ "city.tz": "Timezone",
+ "city.place": "City / country",
+
+ // ===== Subagents (run_agent / create_agent / list_agents / read_agent) =====
+ "agent.runTitle": "🚀 AI delegates a task to a subagent",
+ "agent.resultTitle": "🎯 Subagent returned a result",
+ "agent.createTitle": "🧬 AI creates a new subagent",
+ "agent.listTitle": "📋 AI views the subagent list",
+ "agent.readTitle": "🔍 AI reads subagent details",
+ "agent.name": "Agent",
+ "agent.task": "Task",
+ "agent.tools": "Tools",
+ "agent.maxTurns": "Max turns",
+ "agent.noTools": "all allowed",
+ "agent.noLimit": "no limit",
+ "agent.noResult": "(empty result)",
+ "agent.failed": "❌ Subagent failed",
+ "agent.created": "Agent created",
+ "agent.existing": "Agent updated",
+ "agent.prompt": "System prompt",
+ "agents.cmd.title": "🤖 Project subagents",
+ "agents.cmd.empty":
+ '🤖 No subagents\n\nAdd a .md file to cookie/agents/ or ask the AI: "Create an agent for …".',
+ "agents.cmd.noProject":
+ "📂 No project selected\n\nPick a project in the main window first — subagents are project-scoped.",
+ "agents.cmd.header": "🤖 Project subagents — {n} total",
+ "agents.cmd.itemTools": "🧰 Tools",
+ "agents.cmd.itemTurns": "🔁 Steps",
+ "agents.cmd.itemSource": "📍 Source",
+ "agents.cmd.itemNoTools": "all allowed",
+ "agents.cmd.itemNoLimit": "no limit",
+ "agents.cmd.hint":
+ '💡 Delegate a task: run_agent("name", "task")',
+ "agents.cmd.more": "…and {n} more",
+
// ===== Approval =====
"approval.title": "🔐 Command approval",
"approval.jsScript": "JS script",
diff --git a/botsrc/index.js b/botsrc/index.js
index d941277..f3d71a7 100644
--- a/botsrc/index.js
+++ b/botsrc/index.js
@@ -124,7 +124,12 @@ function _log(level, ...args) {
*/
async function _sendToChat(text) {
try {
- const win = windowState.getMainWindow();
+ // ВАЖНО: шлём в родительское (не-субагентское) окно. Если открыто
+ // окно субагента, оно могло стать «активным» — но команды пользователя
+ // из TG всегда должны попадать в главный чат.
+ const win = windowState.getParentWindow
+ ? windowState.getParentWindow()
+ : windowState.getMainWindow();
if (!win || win.isDestroyed())
return { success: false, error: "нет активного окна" };
@@ -165,9 +170,11 @@ async function _sendToChat(text) {
}
}
-/** Выполнить JS в активном окне и вернуть результат. */
+/** Выполнить JS в родительском (не-субагентском) окне. */
async function _evalInWindow(script) {
- const win = windowState.getMainWindow();
+ const win = windowState.getParentWindow
+ ? windowState.getParentWindow()
+ : windowState.getMainWindow();
if (!win || win.isDestroyed())
return { success: false, error: "нет активного окна" };
try {
@@ -178,10 +185,12 @@ async function _evalInWindow(script) {
}
}
-/** Получить контекст активного окна (профиль/сессия/projectDir). */
+/** Получить контекст родительского (не-субагентского) окна. */
function _activeContext() {
try {
- const win = windowState.getMainWindow();
+ const win = windowState.getParentWindow
+ ? windowState.getParentWindow()
+ : windowState.getMainWindow();
if (win && !win.isDestroyed() && win.webContents) {
return windowState.getContextByWebContents(win.webContents);
}
@@ -189,10 +198,12 @@ function _activeContext() {
return null;
}
-/** Получить id активного окна (для доступа к его todo-списку). */
+/** Получить id родительского (не-субагентского) окна (для todo-списка). */
function _activeSenderId() {
try {
- const win = windowState.getMainWindow();
+ const win = windowState.getParentWindow
+ ? windowState.getParentWindow()
+ : windowState.getMainWindow();
if (win && !win.isDestroyed() && win.webContents) return win.webContents.id;
} catch (_) {}
return null;
@@ -1473,7 +1484,9 @@ async function _handleSettingsCallback(data, cbq) {
async function _cmdStop() {
let count = 0;
try {
- const win = windowState.getMainWindow();
+ const win = windowState.getParentWindow
+ ? windowState.getParentWindow()
+ : windowState.getMainWindow();
if (
win &&
!win.isDestroyed() &&
@@ -1506,7 +1519,9 @@ async function _cmdScreen() {
if (!cfg.enabled || !cfg.token || !cfg.chatId)
return { success: false, skipped: true };
- const win = windowState.getMainWindow();
+ const win = windowState.getParentWindow
+ ? windowState.getParentWindow()
+ : windowState.getMainWindow();
if (!win || win.isDestroyed()) {
await telegramBot.sendMessage(_t("screen.noWindow"));
return { success: false, error: "noWindow" };
@@ -1546,7 +1561,9 @@ async function _cmdStatus() {
} catch (_) {}
lines.push(_t("status.version", { v: escapeHtml(version) }));
- const win = windowState.getMainWindow();
+ const win = windowState.getParentWindow
+ ? windowState.getParentWindow()
+ : windowState.getMainWindow();
const winOk = !!(win && !win.isDestroyed());
lines.push(
_t("status.window") +
@@ -1614,7 +1631,9 @@ async function _cmdStatus() {
async function _cmdNew() {
const win = (() => {
try {
- return windowState.getMainWindow();
+ return windowState.getParentWindow
+ ? windowState.getParentWindow()
+ : windowState.getMainWindow();
} catch (_) {
return null;
}
@@ -1761,6 +1780,73 @@ async function _cmdTodos(chatId, page) {
});
}
+/** /agents — список субагентов проекта (из cookie/agents/*.md). */
+async function _cmdAgents() {
+ let agents = [];
+ let projectDir = null;
+ try {
+ projectDir = _projectDir();
+ if (projectDir) {
+ const { scanAgents } = require("../src/main/agents");
+ agents = scanAgents(projectDir);
+ }
+ } catch (err) {
+ _log("error", "/agents error:", err.message);
+ }
+
+ // Проект не выбран — подсказываем.
+ if (!projectDir) {
+ return telegramBot.sendMessage(_t("agents.cmd.noProject"), {
+ parseMode: "HTML",
+ });
+ }
+
+ // Проект есть, но агентов нет.
+ if (!Array.isArray(agents) || agents.length === 0) {
+ return telegramBot.sendMessage(_t("agents.cmd.empty"), {
+ parseMode: "HTML",
+ });
+ }
+
+ const lines = [];
+ lines.push(_t("agents.cmd.header", { n: agents.length }));
+ lines.push("");
+
+ const MAX = 15; // ограничим вывод, чтобы не улететь за лимит TG
+ const shown = agents.slice(0, MAX);
+ for (let i = 0; i < shown.length; i++) {
+ const a = shown[i];
+ const tools =
+ a.tools && a.tools.length
+ ? a.tools.map((x) => "" + escapeHtml(x) + "").join(", ")
+ : "" + escapeHtml(_t("agents.cmd.itemNoTools")) + "";
+ const turns = a.maxTurns
+ ? escapeHtml(String(a.maxTurns))
+ : "" + escapeHtml(_t("agents.cmd.itemNoLimit")) + "";
+ const sourceEmoji = a.source === "project" ? "📦" : "🏠";
+ lines.push(
+ "" + (i + 1) + ". " + escapeHtml(a.name) + " " + sourceEmoji,
+ );
+ if (a.description) {
+ lines.push(escapeHtml(a.description));
+ }
+ lines.push(" " + escapeHtml(_t("agents.cmd.itemTools")) + ": " + tools);
+ lines.push(" " + escapeHtml(_t("agents.cmd.itemTurns")) + ": " + turns);
+ lines.push("");
+ }
+ if (agents.length > MAX) {
+ lines.push(
+ "" +
+ escapeHtml(_t("agents.cmd.more", { n: agents.length - MAX })) +
+ "",
+ );
+ lines.push("");
+ }
+ lines.push(_t("agents.cmd.hint"));
+
+ return telegramBot.sendMessage(lines.join("\n"), { parseMode: "HTML" });
+}
+
/** Текущий projectDir активного окна. */
function _projectDir() {
const ctx = _activeContext();
@@ -1887,7 +1973,9 @@ function _projectKeyboard() {
async function _setProject(chatId, dir) {
const win = (() => {
try {
- return windowState.getMainWindow();
+ return windowState.getParentWindow
+ ? windowState.getParentWindow()
+ : windowState.getMainWindow();
} catch (_) {
return null;
}
@@ -2210,6 +2298,7 @@ async function _cmdHelp() {
_t("help.cmd.show"),
_t("help.cmd.files"),
_t("help.cmd.todos"),
+ _t("help.cmd.agents"),
_t("help.cmd.screen"),
_t("help.cmd.cancel"),
_t("help.cmd.help"),
@@ -2350,7 +2439,9 @@ async function _sendInWindow(win) {
async function _insertImageToWindow(absPath, caption, send) {
try {
const { clipboard, nativeImage } = require("electron");
- const win = windowState.getMainWindow();
+ const win = windowState.getParentWindow
+ ? windowState.getParentWindow()
+ : windowState.getMainWindow();
if (!win || win.isDestroyed())
return { success: false, error: _t("common.noWindow") };
const img = nativeImage.createFromPath(absPath);
@@ -2402,7 +2493,9 @@ async function _attachFileToWindow(absPath, caption, send) {
UPLOAD_TIMEOUT_MS,
MAX_FILE_SIZE,
} = require("../tools/AttachFileTool");
- const win = windowState.getMainWindow();
+ const win = windowState.getParentWindow
+ ? windowState.getParentWindow()
+ : windowState.getMainWindow();
if (!win || win.isDestroyed())
return { success: false, error: _t("common.noWindow") };
const stat = fs.statSync(absPath);
@@ -2698,6 +2791,11 @@ async function _handleIncoming(chatId, text, msg) {
await _cmdScreen();
return;
}
+ // Команда /agents — список субагентов проекта.
+ if (cmd === "/agents" || cmd === "/agent") {
+ await _cmdAgents();
+ return;
+ }
// ---- Ожидание ввода значения настройки ----
if (_settingsWaiting.has(chatId)) {
@@ -2772,7 +2870,7 @@ function formatToolArgs(toolName, args) {
const old = a.old_string != null ? String(a.old_string) : "";
let s = "";
if (file) s += "📄 " + file + "\n";
-
+
// Построчный diff вместо двух больших блоков.
if (old || neu) {
try {
@@ -2780,14 +2878,14 @@ function formatToolArgs(toolName, args) {
const rows = buildLineDiff(old, neu);
const MAX_LINES = 30; // показываем до 30 строк diff
const slice = rows.slice(0, MAX_LINES);
- const lines = slice.map(r => {
- if (r.type === 'added') return '+ ' + r.text;
- if (r.type === 'removed') return '- ' + r.text;
- return ' ' + r.text;
+ const lines = slice.map((r) => {
+ if (r.type === "added") return "+ " + r.text;
+ if (r.type === "removed") return "- " + r.text;
+ return " " + r.text;
});
- s += lines.join('\n');
+ s += lines.join("\n");
if (rows.length > MAX_LINES) {
- s += '\n' + _t("tool.truncatedTotal", { n: rows.length });
+ s += "\n" + _t("tool.truncatedTotal", { n: rows.length });
}
} catch (err) {
// Fallback на старый формат при ошибке.
@@ -2970,10 +3068,19 @@ function _techFlush() {
if (!b) return null;
const suffix = b.count > 1 ? " (×" + b.count + ")" : "";
- // Заголовок: «🔧 Editing path (×N)» либо «💻 terminal (×N)» без детали.
- const header = b.command
+ // Заголовок: «🤖 Агент: explore // 🔧 Editing path (×N)» — если из субагента.
+ // Иначе просто «🔧 Editing path (×N)».
+ const body_line = b.command
? b.emoji + " " + b.label + suffix
: b.emoji + " " + b.label + " " + _techTrunc(b.detail) + suffix;
+ const agentLine = b.agentName
+ ? "🤖 " +
+ escapeHtml(_t("agent.name")) +
+ ": " +
+ escapeHtml(b.agentName) +
+ "\n"
+ : "";
+ const header = agentLine + body_line;
// Тело: 1) команда/путь, 2) результат — каждый блок своей цитатой.
let msg = header;
@@ -3015,11 +3122,24 @@ const TECH_SERVICE_TOOLS = new Set([
"exitplanmode",
]);
+// Агентские инструменты: имеют собственное оформление (см. _render*Agent),
+// в общий батч «🔧 tool ×N» не идут, но уведомления им нужны.
+const AGENT_TOOLS = new Set([
+ "run_agent",
+ "runagent",
+ "create_agent",
+ "createagent",
+ "list_agents",
+ "listagents",
+ "read_agent",
+ "readagent",
+]);
+
/**
* Поставить уведомление в батч: если пришло такое же действие в течение
* TECH_BATCH_MS — увеличиваем счётчик (×N), иначе шлём предыдущее и начинаем новое.
*/
-function _techQueue(toolName, args, preview) {
+function _techQueue(toolName, args, preview, agentName) {
const icon = _techIcon(toolName);
const detail = _techDetail(toolName, args);
const name = String(toolName || "").toLowerCase();
@@ -3028,13 +3148,15 @@ function _techQueue(toolName, args, preview) {
? String((args && args.command) || "")
: "";
const result = String(preview || "");
+ const agent = agentName ? String(agentName).trim() : null;
if (
_techBatch &&
_techBatch.emoji === icon.emoji &&
_techBatch.label === icon.label &&
_techBatch.detail === detail &&
- _techBatch.command === command
+ _techBatch.command === command &&
+ _techBatch.agentName === agent
) {
_techBatch.count++;
// Результат последнего вызова в серии — показываем его.
@@ -3049,6 +3171,7 @@ function _techQueue(toolName, args, preview) {
preview: result,
args,
count: 1,
+ agentName: agent,
};
if (prev) _techFlush();
if (_techBatchTimer) clearTimeout(_techBatchTimer);
@@ -3060,25 +3183,419 @@ function _techQueue(toolName, args, preview) {
return null;
}
+// ==================== Спец-оформление для memory/city_time ====================
+//
+// Память и время/локация получают собственный «человеческий» формат вместо
+// общего 🔧 " +
" " +
"" +
+ // ===== Память AI =====
+ '