Files
agent-mgr/internal/api/apps.go
Steven Hooker e5b07cc1d8 initial agent-mgr: app builder platform MVP
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)
2026-02-18 15:56:32 +01:00

106 lines
2.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 createAppRequest struct {
Name string `json:"name"`
Description string `json:"description"`
Provider string `json:"provider,omitempty"`
Config json.RawMessage `json:"config,omitempty"`
}
func (s *Server) createApp(w http.ResponseWriter, r *http.Request) {
var req createAppRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, `{"error":"invalid request body"}`, http.StatusBadRequest)
return
}
if req.Name == "" && req.Description == "" {
http.Error(w, `{"error":"name or description required"}`, http.StatusBadRequest)
return
}
if req.Name == "" {
// Auto-generate name from first few words of description
name := req.Description
if len(name) > 40 {
name = name[:40]
}
req.Name = name
}
app, sess, err := s.app.CreateApp(r.Context(), req.Name, req.Description, req.Provider, req.Config)
if err != nil {
s.log.Error("create app failed", "err", err)
http.Error(w, `{"error":"failed to create app"}`, http.StatusInternalServerError)
return
}
resp := map[string]any{"app": app}
if sess != nil {
resp["session"] = sess
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(resp)
}
func (s *Server) listApps(w http.ResponseWriter, r *http.Request) {
apps, err := s.store.ListApps(r.Context())
if err != nil {
s.log.Error("list apps failed", "err", err)
http.Error(w, `{"error":"failed to list apps"}`, http.StatusInternalServerError)
return
}
if apps == nil {
apps = []store.App{}
}
json.NewEncoder(w).Encode(map[string]any{"apps": apps})
}
func (s *Server) getApp(w http.ResponseWriter, r *http.Request) {
id, err := uuid.Parse(chi.URLParam(r, "appID"))
if err != nil {
http.Error(w, `{"error":"invalid app id"}`, http.StatusBadRequest)
return
}
app, err := s.store.GetApp(r.Context(), id)
if err != nil {
http.Error(w, `{"error":"failed to get app"}`, http.StatusInternalServerError)
return
}
if app == nil {
http.Error(w, `{"error":"app not found"}`, http.StatusNotFound)
return
}
sessions, _ := s.store.ListSessionsByApp(r.Context(), id)
if sessions == nil {
sessions = []store.Session{}
}
json.NewEncoder(w).Encode(map[string]any{"app": app, "sessions": sessions})
}
func (s *Server) deleteApp(w http.ResponseWriter, r *http.Request) {
id, err := uuid.Parse(chi.URLParam(r, "appID"))
if err != nil {
http.Error(w, `{"error":"invalid app id"}`, http.StatusBadRequest)
return
}
if err := s.store.DeleteApp(r.Context(), id); err != nil {
http.Error(w, `{"error":"failed to delete app"}`, http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusNoContent)
}