Files
sundynix-agentix/sundynix-gateway/internal/handler/agent.go
T
Blizzard 4bf614a07c feat(studio): Agent 编排服务端保存 + 我的编排列表(owner 隔离)
编排好的 Agent 现在可命名保存到服务端、跨会话可见;左侧「我的编排」列出本人全部。

- store: sundynix_agent 表(owner+name 唯一,Graph=React Flow {nodes,edges} JSON 含布局,
  UpdatedAt);ListAgents(最近在前)/SaveAgent(OnConflict 覆盖图+时间)/DeleteAgent。AutoMigrate +Agent。
- gateway: GET/POST/DELETE /api/v1/agents(owner 隔离,身份取自 X-User-ID)。
- 前端:api listAgents/saveAgent/deleteAgent;StudioView 左面板下半区「我的编排(N)」列出本人编排,
  点击载入(含布局)、悬停删除;工具栏 编排名+保存(服务端),去掉 localStorage 模板。

验证:curl 保存「合同审查流程」→ wt 列表含之,alice 列表为空(隔离)。Preview:示例图填名「尽调问答
Agent」保存 → 左「我的编排(2)」即时出现两条、可点载入。tsc+vite+gateway build 通过;重建 .app。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 16:23:03 +08:00

54 lines
1.7 KiB
Go

package handler
import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
// AgentList: GET /api/v1/agents —— 当前用户保存的全部 Agent 编排(owner 隔离,最近在前)。
func (h *Handler) AgentList(c *gin.Context) {
rows, err := h.db.ListAgents(c.Request.Context(), userID(c))
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
return
}
out := make([]gin.H, 0, len(rows))
for _, r := range rows {
out = append(out, gin.H{"name": r.Name, "graph": r.Graph, "updated_at": r.UpdatedAt})
}
c.JSON(http.StatusOK, gin.H{"agents": out})
}
// AgentSave: POST /api/v1/agents {name, graph} —— 保存/更新一份编排(graph 为 {nodes,edges} JSON)。
func (h *Handler) AgentSave(c *gin.Context) {
var body struct {
Name string `json:"name"`
Graph string `json:"graph"`
}
if err := c.ShouldBindJSON(&body); err != nil || strings.TrimSpace(body.Name) == "" || strings.TrimSpace(body.Graph) == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "name/graph required"})
return
}
if err := h.db.SaveAgent(c.Request.Context(), userID(c), strings.TrimSpace(body.Name), body.Graph); err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"name": strings.TrimSpace(body.Name)})
}
// AgentDelete: DELETE /api/v1/agents?name= —— 删除一份编排。
func (h *Handler) AgentDelete(c *gin.Context) {
name := strings.TrimSpace(c.Query("name"))
if name == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "name required"})
return
}
if err := h.db.DeleteAgent(c.Request.Context(), userID(c), name); err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"status": "ok"})
}