OpenClaw architecture review — what to borrow for Team Board agents
This commit is contained in:
parent
10babfce66
commit
6fbd6348f5
166
OPENCLAW-ARCHITECTURE-REVIEW.md
Normal file
166
OPENCLAW-ARCHITECTURE-REVIEW.md
Normal file
@ -0,0 +1,166 @@
|
||||
# Обзор архитектуры OpenClaw — что можно позаимствовать
|
||||
|
||||
## 1. Agent Loop (Agentic Loop)
|
||||
|
||||
**Как работает в OpenClaw:**
|
||||
- Gateway получает сообщение → резолвит сессию → запускает `runEmbeddedPiAgent`
|
||||
- Runs сериализуются per-session (queue) — нет race conditions
|
||||
- Pi Agent Core внутри: `session.prompt()` → LLM → tool calls → results → LLM → ...
|
||||
- События стримятся: `text_delta`, `tool_execution_start/end`, `message_end`, `agent_end`
|
||||
- Timeout enforcement — если агент завис, run абортится
|
||||
|
||||
**Что забрать:**
|
||||
- ✅ **Run queue per session** — сериализация запросов, нет параллельных runs в одной сессии
|
||||
- ✅ **Timeout на run** — агент не может зависнуть навечно
|
||||
- ✅ **Event streaming** — стримить text deltas, tool calls, reasoning в реальном времени
|
||||
|
||||
---
|
||||
|
||||
## 2. Память (Memory)
|
||||
|
||||
**Как работает в OpenClaw:**
|
||||
- Два слоя: `memory/YYYY-MM-DD.md` (daily, append-only) + `MEMORY.md` (curated long-term)
|
||||
- **Memory flush перед компакцией** — silent agentic turn: "запиши важное прежде чем контекст сожмётся"
|
||||
- **Semantic search** (memory_search) — hybrid BM25 + vector, по чанкам ~400 токенов
|
||||
- **memory_get** — точечное чтение файла по path + line range
|
||||
- Агент **сам пишет** в файлы через read/write/edit tools
|
||||
|
||||
**Что забрать:**
|
||||
- ✅ **Memory flush перед компакцией** — критично для long-running агентов
|
||||
- ✅ **Semantic search** — когда памяти станет много (>50K chars), нужен поиск
|
||||
- ✅ **Двухуровневая память** — уже решили (agent.md + projects/{uuid}/)
|
||||
- 🔜 **Vector search** — отложить до масштаба
|
||||
|
||||
---
|
||||
|
||||
## 3. Контекстное окно и компакция
|
||||
|
||||
**Как работает в OpenClaw:**
|
||||
- Каждая модель имеет `contextWindow` (макс токенов)
|
||||
- **Auto-compaction**: когда сессия близка к лимиту → суммаризация старых сообщений → compact entry
|
||||
- **Session pruning**: обрезка старых tool results (in-memory, не трогает JSONL)
|
||||
- **Cache-TTL pruning** (Anthropic): если кэш протух — обрезать перед re-cache
|
||||
- `reserveTokensFloor` — всегда оставлять N токенов для ответа
|
||||
|
||||
**Компакция:**
|
||||
1. Определить что session близка к лимиту (token estimate)
|
||||
2. Запустить memory flush (silent turn — "запиши важное")
|
||||
3. Суммаризировать старые сообщения через LLM → compact summary
|
||||
4. Заменить старые сообщения на summary в истории
|
||||
5. Персистить в JSONL
|
||||
|
||||
**Что забрать:**
|
||||
- ✅ **Auto-compaction** — обязательно для long-running агентов
|
||||
- ✅ **Token estimation** — считать примерный размер контекста перед каждым вызовом
|
||||
- ✅ **Reserve tokens** — не заполнять окно до упора
|
||||
- ✅ **Memory flush trigger** — перед компакцией напоминать агенту записать важное
|
||||
- 🔜 **Session pruning** — обрезка tool results (для Anthropic cache optimization)
|
||||
|
||||
---
|
||||
|
||||
## 4. Streaming и доставка ответов
|
||||
|
||||
**Как работает в OpenClaw:**
|
||||
- **Block streaming** — отправка завершённых блоков текста по мере генерации
|
||||
- **Token streaming** (Telegram) — обновление draft-bubble частичным текстом
|
||||
- **Reasoning streaming** — отдельный поток для thinking/reasoning блоков
|
||||
- Chunking: min/max chars, break preference (text_end vs message_end)
|
||||
|
||||
**Что забрать для Team Board:**
|
||||
- ✅ **Streaming через WS** — агент стримит text deltas через WebSocket
|
||||
- ✅ **Reasoning blocks** — отдельный тип сообщения `thinking` в WS protocol
|
||||
- ✅ **Block replies** — отправлять частичные ответы (не ждать завершения)
|
||||
|
||||
### Как реализовать в Team Board:
|
||||
|
||||
**Новые WS event types:**
|
||||
```
|
||||
agent.stream.start → агент начал генерацию
|
||||
agent.stream.delta → { text: "частичный текст", type: "text"|"thinking" }
|
||||
agent.stream.tool → { tool: "update_task", status: "running"|"done" }
|
||||
agent.stream.end → генерация завершена, финальное сообщение
|
||||
```
|
||||
|
||||
**Frontend:**
|
||||
- Показывать typing indicator + streaming text в ChatPanel
|
||||
- Раскрывающийся блок `<details>` для thinking/reasoning
|
||||
- Tool calls показывать как "🔧 Обновляет задачу..." inline
|
||||
|
||||
---
|
||||
|
||||
## 5. Ответ агента через WS (не REST)
|
||||
|
||||
**Текущая проблема:** агент вызывает REST `POST /messages` чтобы ответить → broadcast через WS. Лишний round-trip.
|
||||
|
||||
**Как должно быть:**
|
||||
1. Tracker получает message.new → отправляет агенту через WS
|
||||
2. Агент генерирует ответ → стримит через WS (`agent.stream.delta`)
|
||||
3. Tracker принимает `agent.reply` через WS → сохраняет в БД → broadcast всем
|
||||
4. Или: агент отправляет `chat.send` через WS (уже поддерживается!)
|
||||
|
||||
**Минимальное изменение:**
|
||||
- Router при auto-reply использует WS `chat.send` вместо REST POST
|
||||
- Для explicit send_message tool — тоже через WS
|
||||
- REST send_message остаётся для внешних клиентов
|
||||
|
||||
---
|
||||
|
||||
## 6. Что НЕ нужно забирать
|
||||
|
||||
- ❌ **Multi-channel routing** (WhatsApp, Telegram, Discord) — у нас один канал (WebSocket)
|
||||
- ❌ **Node/device pairing** — не наш use case
|
||||
- ❌ **Canvas/A2UI** — пока не нужно
|
||||
- ❌ **OAuth proxy** — решается через litellm или провайдер SDK
|
||||
- ❌ **Plugin system** — оверинжиниринг для наших масштабов
|
||||
|
||||
---
|
||||
|
||||
## 7. Roadmap заимствований
|
||||
|
||||
### Phase 1 (сейчас)
|
||||
- [ ] Agent отвечает через WS вместо REST
|
||||
- [ ] Streaming text deltas через WS events
|
||||
- [ ] Reasoning/thinking block в UI (раскрывающийся)
|
||||
|
||||
### Phase 2 (скоро)
|
||||
- [ ] Auto-compaction для длинных сессий
|
||||
- [ ] Memory flush перед компакцией
|
||||
- [ ] Token estimation (считать размер контекста)
|
||||
- [ ] Run timeout (kill зависших агентов)
|
||||
|
||||
### Phase 3 (позже)
|
||||
- [ ] Semantic memory search (vector + BM25)
|
||||
- [ ] Session pruning (обрезка tool results)
|
||||
- [ ] Block streaming (частичные ответы до завершения)
|
||||
|
||||
---
|
||||
|
||||
## 8. Thinking/Reasoning в UI
|
||||
|
||||
**Реализация раскрывающегося блока:**
|
||||
|
||||
**Backend (Tracker WS protocol):**
|
||||
```json
|
||||
{"type": "agent.stream.delta", "data": {"agent_id": "...", "block_type": "thinking", "text": "Думаю..."}}
|
||||
{"type": "agent.stream.delta", "data": {"agent_id": "...", "block_type": "text", "text": "Ответ"}}
|
||||
```
|
||||
|
||||
**Frontend (ChatPanel):**
|
||||
```tsx
|
||||
{message.thinking && (
|
||||
<details className="text-gray-400 text-sm">
|
||||
<summary>💭 Размышления агента</summary>
|
||||
<pre>{message.thinking}</pre>
|
||||
</details>
|
||||
)}
|
||||
```
|
||||
|
||||
**Хранение в БД:**
|
||||
- Поле `thinking` в Message модели (nullable text)
|
||||
- Или отдельная таблица reasoning_blocks
|
||||
- Проще: JSON поле `metadata` с ключом `thinking`
|
||||
|
||||
**Что нужно от LLM:**
|
||||
- Anthropic: `thinking` parameter в API request → возвращает `thinking` блоки
|
||||
- OpenAI: `reasoning_effort` → скрытый reasoning (не доступен)
|
||||
- Только Anthropic (Claude) реально отдаёт thinking content
|
||||
Loading…
Reference in New Issue
Block a user