Go API server + Preact UI + Claude Code adapter. - App-centric model (ideas, not repos) - AgentProvider interface for multi-agent support - K8s pod lifecycle for sandboxed agent sessions - Gitea integration (create repos, push branches) - WebSocket streaming for live session output - Woodpecker CI/CD pipelines (kaniko build + kubectl deploy)
137 lines
3.8 KiB
Go
137 lines
3.8 KiB
Go
package api
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"github.com/agentsphere/agent-mgr/internal/store"
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type createSessionRequest struct {
|
|
Prompt string `json:"prompt"`
|
|
Provider string `json:"provider,omitempty"`
|
|
Config json.RawMessage `json:"config,omitempty"`
|
|
}
|
|
|
|
type sendMessageRequest struct {
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
func (s *Server) createSession(w http.ResponseWriter, r *http.Request) {
|
|
appID, err := uuid.Parse(chi.URLParam(r, "appID"))
|
|
if err != nil {
|
|
http.Error(w, `{"error":"invalid app id"}`, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var req createSessionRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, `{"error":"invalid request body"}`, http.StatusBadRequest)
|
|
return
|
|
}
|
|
if req.Prompt == "" {
|
|
http.Error(w, `{"error":"prompt required"}`, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
app, err := s.store.GetApp(r.Context(), appID)
|
|
if err != nil || app == nil {
|
|
http.Error(w, `{"error":"app not found"}`, http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
sess, err := s.app.StartSession(r.Context(), app, req.Prompt, req.Provider, req.Config)
|
|
if err != nil {
|
|
s.log.Error("create session failed", "err", err)
|
|
http.Error(w, `{"error":"failed to create session"}`, http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.WriteHeader(http.StatusCreated)
|
|
json.NewEncoder(w).Encode(map[string]any{"session": sess})
|
|
}
|
|
|
|
func (s *Server) listSessions(w http.ResponseWriter, r *http.Request) {
|
|
appID, err := uuid.Parse(chi.URLParam(r, "appID"))
|
|
if err != nil {
|
|
http.Error(w, `{"error":"invalid app id"}`, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
sessions, err := s.store.ListSessionsByApp(r.Context(), appID)
|
|
if err != nil {
|
|
http.Error(w, `{"error":"failed to list sessions"}`, http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if sessions == nil {
|
|
sessions = []store.Session{}
|
|
}
|
|
|
|
json.NewEncoder(w).Encode(map[string]any{"sessions": sessions})
|
|
}
|
|
|
|
func (s *Server) getSession(w http.ResponseWriter, r *http.Request) {
|
|
id, err := uuid.Parse(chi.URLParam(r, "sessionID"))
|
|
if err != nil {
|
|
http.Error(w, `{"error":"invalid session id"}`, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
sess, err := s.store.GetSession(r.Context(), id)
|
|
if err != nil || sess == nil {
|
|
http.Error(w, `{"error":"session not found"}`, http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
json.NewEncoder(w).Encode(map[string]any{"session": sess})
|
|
}
|
|
|
|
func (s *Server) stopSession(w http.ResponseWriter, r *http.Request) {
|
|
id, err := uuid.Parse(chi.URLParam(r, "sessionID"))
|
|
if err != nil {
|
|
http.Error(w, `{"error":"invalid session id"}`, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if err := s.app.StopSession(r.Context(), id); err != nil {
|
|
s.log.Error("stop session failed", "err", err)
|
|
http.Error(w, `{"error":"failed to stop session"}`, http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
json.NewEncoder(w).Encode(map[string]any{"status": "stopped"})
|
|
}
|
|
|
|
func (s *Server) sendMessage(w http.ResponseWriter, r *http.Request) {
|
|
id, err := uuid.Parse(chi.URLParam(r, "sessionID"))
|
|
if err != nil {
|
|
http.Error(w, `{"error":"invalid session id"}`, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var req sendMessageRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, `{"error":"invalid request body"}`, http.StatusBadRequest)
|
|
return
|
|
}
|
|
if req.Message == "" {
|
|
http.Error(w, `{"error":"message required"}`, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if err := s.app.SendMessage(r.Context(), id, req.Message); err != nil {
|
|
s.log.Error("send message failed", "err", err)
|
|
http.Error(w, `{"error":"failed to send message"}`, http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
json.NewEncoder(w).Encode(map[string]any{"status": "sent"})
|
|
}
|
|
|
|
func (s *Server) listProviders(w http.ResponseWriter, r *http.Request) {
|
|
infos := s.registry.List()
|
|
json.NewEncoder(w).Encode(map[string]any{"providers": infos})
|
|
}
|