feat(server): provider switching API, WS/REST cancel, summarize endpoints
This commit is contained in:
parent
f1b2093b22
commit
49fdc5a189
7 changed files with 463 additions and 28 deletions
146
internal/server/extra.go
Normal file
146
internal/server/extra.go
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/crypto/byteclaw/internal/providers"
|
||||
"github.com/crypto/byteclaw/internal/store"
|
||||
)
|
||||
|
||||
func (s *Server) info(w http.ResponseWriter, _ *http.Request) {
|
||||
in := s.Info
|
||||
if s.Providers != nil {
|
||||
a := s.Providers.Active()
|
||||
in.Provider, in.Model, in.BaseURL = a.Provider, a.Model, s.Providers.BaseURL(a.Provider)
|
||||
}
|
||||
writeJSON(w, 200, in)
|
||||
}
|
||||
|
||||
func (s *Server) needProviders(w http.ResponseWriter) bool {
|
||||
if s.Providers == nil {
|
||||
writeErr(w, http.StatusNotImplemented, "provider switching not enabled")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func providerErr(w http.ResponseWriter, err error) {
|
||||
switch {
|
||||
case errors.Is(err, providers.ErrUnknown):
|
||||
writeErr(w, http.StatusNotFound, err.Error())
|
||||
default:
|
||||
writeErr(w, http.StatusBadRequest, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
type providerReq struct {
|
||||
Provider string `json:"provider"`
|
||||
Model string `json:"model"`
|
||||
}
|
||||
|
||||
// GET /api/providers -> {"active":{...},"providers":[...]} (never contains keys).
|
||||
func (s *Server) listProviders(w http.ResponseWriter, _ *http.Request) {
|
||||
if !s.needProviders(w) {
|
||||
return
|
||||
}
|
||||
writeJSON(w, 200, map[string]any{"active": s.Providers.Active(), "providers": s.Providers.List()})
|
||||
}
|
||||
|
||||
func (s *Server) setActiveProvider(w http.ResponseWriter, r *http.Request) {
|
||||
if !s.needProviders(w) {
|
||||
return
|
||||
}
|
||||
var b providerReq
|
||||
if !decode(w, r, &b) {
|
||||
return
|
||||
}
|
||||
a, err := s.Providers.SetActive(r.Context(), b.Provider, b.Model)
|
||||
if err != nil {
|
||||
providerErr(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, 200, a)
|
||||
}
|
||||
|
||||
func (s *Server) listModels(w http.ResponseWriter, r *http.Request) {
|
||||
if !s.needProviders(w) {
|
||||
return
|
||||
}
|
||||
ids, err := s.Providers.Models(r.Context(), r.PathValue("name"))
|
||||
if errors.Is(err, providers.ErrUnknown) {
|
||||
providerErr(w, err)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
s.Log.Warn("list models", "err", err)
|
||||
writeErr(w, http.StatusBadGateway, "provider does not offer a model list")
|
||||
return
|
||||
}
|
||||
writeJSON(w, 200, map[string]any{"models": ids})
|
||||
}
|
||||
|
||||
// PUT /api/sessions/{id}/provider: per-session override; empty provider clears it.
|
||||
func (s *Server) setSessionProvider(w http.ResponseWriter, r *http.Request) {
|
||||
if !s.needProviders(w) {
|
||||
return
|
||||
}
|
||||
var b providerReq
|
||||
if !decode(w, r, &b) {
|
||||
return
|
||||
}
|
||||
id := r.PathValue("id")
|
||||
if _, err := s.Store.GetSession(r.Context(), id); err != nil {
|
||||
s.storeErr(w, err)
|
||||
return
|
||||
}
|
||||
var a providers.Active
|
||||
if b.Provider != "" {
|
||||
var err error
|
||||
if a, err = s.Providers.Validate(b.Provider, b.Model); err != nil {
|
||||
providerErr(w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if err := s.Store.SetSessionProvider(r.Context(), id, a.Provider, a.Model); err != nil {
|
||||
s.storeErr(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, 200, a)
|
||||
}
|
||||
|
||||
func (s *Server) cancel(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, 200, map[string]bool{"cancelled": s.Agent.Cancel(r.PathValue("id"))})
|
||||
}
|
||||
|
||||
func (s *Server) summarize(w http.ResponseWriter, r *http.Request) {
|
||||
id := r.PathValue("id")
|
||||
if _, err := s.Store.GetSession(r.Context(), id); err != nil {
|
||||
s.storeErr(w, err)
|
||||
return
|
||||
}
|
||||
sm, err := s.Agent.SummarizeNow(r.Context(), id)
|
||||
if err != nil {
|
||||
s.Log.Warn("summarize", "err", err)
|
||||
writeErr(w, http.StatusBadGateway, err.Error())
|
||||
return
|
||||
}
|
||||
if sm == nil {
|
||||
writeJSON(w, 200, map[string]any{"summary": nil, "note": "nothing to summarize yet"})
|
||||
return
|
||||
}
|
||||
writeJSON(w, 200, map[string]any{"summary": sm})
|
||||
}
|
||||
|
||||
func (s *Server) getSummary(w http.ResponseWriter, r *http.Request) {
|
||||
sm, err := s.Store.LatestSummary(r.Context(), r.PathValue("id"))
|
||||
if err != nil {
|
||||
if errors.Is(err, store.ErrNotFound) {
|
||||
writeErr(w, http.StatusNotFound, "no summary")
|
||||
return
|
||||
}
|
||||
s.storeErr(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, 200, sm)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue