feat: opencode через HTTP API — пул serve-серверов вместо spawn/NDJSON
Runner теперь ходит к постоянным serve по HTTP API (v1.17+, /api):
- клиент Client (create/send/wait/abort/messages/verdict)
- Pool: по одному serve на каталог, ленивый подъём, root-сервер в worktree,
выделение портов, ReleaseTask при завершении задачи
- Run: CreateSession('ratatoskr-<агент>') -> Send -> поллинг Verdict из
text-частей assistant-сообщений; idle/hard таймауты дают RC=-1
- вердикт извлекается из последнего assistant text-парта (плоский text)
- тесты: unit на фейковом HTTP-сервере; e2e эмулирует serve через httptest,
агент определяется по title сессии
This commit is contained in:
@@ -31,6 +31,7 @@ type Server struct {
|
||||
Host string // hostname для прослушивания
|
||||
Port int // порт сервера
|
||||
Password string // basic auth (если непустой — сервер защищён)
|
||||
Dir string // каталог, в котором запускается serve (project сервера)
|
||||
|
||||
// URL задаёт внешний сервер. Пусто — супервайзер владеет процессом.
|
||||
URL string
|
||||
@@ -116,7 +117,10 @@ func (s *Server) Start(ctx context.Context) error {
|
||||
func (s *Server) serveCmd(ctx context.Context) *exec.Cmd {
|
||||
args := []string{"serve", "--hostname", s.Host, "--port", fmt.Sprintf("%d", s.Port)}
|
||||
cmd := exec.CommandContext(ctx, s.Bin, args...)
|
||||
cmd.Dir = "."
|
||||
cmd.Dir = s.Dir // project сервера — каталог, который обслуживает этот serve
|
||||
if cmd.Dir == "" {
|
||||
cmd.Dir = "."
|
||||
}
|
||||
// Своя process-group: чтобы killGroup (по pgid) убивал только сервер и его
|
||||
// дочерние процессы, а не чужой процесс (например, тест-реннер).
|
||||
setpgid(cmd)
|
||||
|
||||
Reference in New Issue
Block a user