fix: idle-таймер сбрасывается по live-стриму LLM + дефолт 5м; агенты opencode в agents/ с mode: primary
All checks were successful
CI / test (push) Successful in 56s
CI / build-and-package (amd64, linux) (push) Successful in 42s
CI / build-and-package (amd64, windows) (push) Successful in 40s

- opencode ищет кастомных агентов в поддиректории agents/ (как .opencode),
  а не в корне OPENCODE_CONFIG_DIR → распаковка теперь в <dir>/agents/*.md
- markdown-агентам добавлен mode: primary (иначе subagent по умолчанию)
- idle-детекция сбрасывает таймер при live-строках (text/tool/agent/reasoning),
  а не только по росту БД → «LLM думает и стримит» не считается зависанием
- дефолт idle_timeout поднят с 2м до 5м
This commit is contained in:
Hermes
2026-08-17 10:57:19 +05:00
parent da775ac227
commit 9c5f38698c
10 changed files with 75 additions and 12 deletions

View File

@@ -3,9 +3,16 @@
// Агенты зашиты в бинарь через go:embed и распаковываются при запуске
// в каталог OPENCODE_CONFIG_DIR (по умолчанию ./agents рядом с бинарём),
// чтобы opencode находил их независимо от того, где запущен ratatoskr.
//
// opencode сканирует OPENCODE_CONFIG_DIR как каталог .opencode: агенты
// ищутся в поддиректории agents/ (мн.ч.), а не в корне. Поэтому распаковка
// идёт в <dir>/agents/*.md.
package agents
import "embed"
import (
"embed"
"path/filepath"
)
//go:embed *.md
var FS embed.FS
@@ -16,15 +23,16 @@ var FS embed.FS
// в FS, но для детерминированной распаковки список лучше дополнять здесь.
var Names = []string{"analyst", "dev", "reviewer"}
// WriteTo распаковывает всех встроенных агентов в каталог dir (создаёт его).
// Файлы перезаписываются — встроенная копия всегда актуальна.
// WriteTo распаковывает всех встроенных агентов в каталог dir/agents
// (создаёт его). Файлы перезаписываются — встроенная копия всегда актуальна.
func WriteTo(dir string) error {
agentsDir := filepath.Join(dir, "agents")
for _, name := range Names {
data, err := FS.ReadFile(name + ".md")
if err != nil {
return err
}
if err := writeFile(dir, name+".md", data); err != nil {
if err := writeFile(agentsDir, name+".md", data); err != nil {
return err
}
}

View File

@@ -13,7 +13,8 @@ func TestWriteTo(t *testing.T) {
t.Fatalf("WriteTo: %v", err)
}
for _, name := range Names {
p := filepath.Join(dir, name+".md")
// opencode ищет агентов в поддиректории agents/, как у .opencode
p := filepath.Join(dir, "agents", name+".md")
data, err := os.ReadFile(p)
if err != nil {
t.Fatalf("read %s: %v", p, err)

View File

@@ -1,6 +1,7 @@
---
name: analyst
description: Аналитик Ratatoskr — помогает сформулировать задачу разработки и возвращает структурированное решение в JSON
mode: primary
---
Ты — аналитик в конвейере Ratatoskr. Пользователь ставит задачу разработки. Ты помогаешь

View File

@@ -1,6 +1,7 @@
---
name: dev
description: Разработчик Ratatoskr — реализует задачу в репозитории по готовым критериям
mode: primary
---
Ты — dev-агент в конвейере Ratatoskr. Получаешь готовое задание и реализуешь его в коде.

View File

@@ -1,6 +1,7 @@
---
name: reviewer
description: Ревьюер Ratatoskr — строго проверяет ветку работы dev-агента (качество, безопасность, SOLID) и возвращает вердикт в JSON
mode: primary
---
Ты — ревьюер в конвейере Ratatoskr. Проверяешь работу dev-агента в feature-ветке **жёстко и придирчиво**. Твоя цель — не дать плохому коду попасть в основную ветку.