Merge pull request #1233 from trheyi/main
Refactor API handler functions for assistants in Neo package
This commit is contained in:
commit
7230f62532
6 changed files with 220 additions and 19 deletions
36
neo/api.go
36
neo/api.go
|
|
@ -67,30 +67,30 @@ func (neo *DSL) API(router *gin.Engine, path string) error {
|
||||||
// Assistant API endpoints
|
// Assistant API endpoints
|
||||||
// List assistants example:
|
// List assistants example:
|
||||||
// curl -X GET 'http://localhost:5099/api/__yao/neo/assistants?page=1&pagesize=20&tags=tag1,tag2&token=xxx'
|
// curl -X GET 'http://localhost:5099/api/__yao/neo/assistants?page=1&pagesize=20&tags=tag1,tag2&token=xxx'
|
||||||
router.GET(path+"/assistants", append(middlewares, neo.handleAssistantList)...)
|
router.GET(path+"/assistants", append(middlewares, neo.HandleAssistantList)...)
|
||||||
// Get all assistant tags example:
|
// Get all assistant tags example:
|
||||||
// curl -X GET 'http://localhost:5099/api/__yao/neo/assistants/tags?token=xxx'
|
// curl -X GET 'http://localhost:5099/api/__yao/neo/assistants/tags?token=xxx'
|
||||||
router.GET(path+"/assistants/tags", append(middlewares, neo.handleAssistantTags)...)
|
router.GET(path+"/assistants/tags", append(middlewares, neo.HandleAssistantTags)...)
|
||||||
|
|
||||||
// Get assistant details example:
|
// Get assistant details example:
|
||||||
// curl -X GET 'http://localhost:5099/api/__yao/neo/assistants/assistant_123?token=xxx'
|
// curl -X GET 'http://localhost:5099/api/__yao/neo/assistants/assistant_123?token=xxx'
|
||||||
router.GET(path+"/assistants/:id", append(middlewares, neo.handleAssistantDetail)...)
|
router.GET(path+"/assistants/:id", append(middlewares, neo.HandleAssistantDetail)...)
|
||||||
|
|
||||||
// Execute assistant API example:
|
// Execute assistant API example:
|
||||||
// curl -X POST 'http://localhost:5099/api/__yao/neo/assistants/assistant_123/api' \
|
// curl -X POST 'http://localhost:5099/api/__yao/neo/assistants/assistant_123/api' \
|
||||||
// -H 'Content-Type: application/json' \
|
// -H 'Content-Type: application/json' \
|
||||||
// -d '{"name": "Test", "payload": {"name": "yao", "age": 18}}'
|
// -d '{"name": "Test", "payload": {"name": "yao", "age": 18}}'
|
||||||
router.POST(path+"/assistants/:id/call", append(middlewares, neo.handleAssistantCall)...)
|
router.POST(path+"/assistants/:id/call", append(middlewares, neo.HandleAssistantCall)...)
|
||||||
|
|
||||||
// Create/Update assistant example:
|
// Create/Update assistant example:
|
||||||
// curl -X POST 'http://localhost:5099/api/__yao/neo/assistants' \
|
// curl -X POST 'http://localhost:5099/api/__yao/neo/assistants' \
|
||||||
// -H 'Content-Type: application/json' \
|
// -H 'Content-Type: application/json' \
|
||||||
// -d '{"name": "My Assistant", "type": "chat", "tags": ["tag1", "tag2"], "mentionable": true, "avatar": "path/to/avatar.png", "token": "xxx"}'
|
// -d '{"name": "My Assistant", "type": "chat", "tags": ["tag1", "tag2"], "mentionable": true, "avatar": "path/to/avatar.png", "token": "xxx"}'
|
||||||
router.POST(path+"/assistants", append(middlewares, neo.handleAssistantSave)...)
|
router.POST(path+"/assistants", append(middlewares, neo.HandleAssistantSave)...)
|
||||||
|
|
||||||
// Delete assistant example:
|
// Delete assistant example:
|
||||||
// curl -X DELETE 'http://localhost:5099/api/__yao/neo/assistants/assistant_123?token=xxx'
|
// curl -X DELETE 'http://localhost:5099/api/__yao/neo/assistants/assistant_123?token=xxx'
|
||||||
router.DELETE(path+"/assistants/:id", append(middlewares, neo.handleAssistantDelete)...)
|
router.DELETE(path+"/assistants/:id", append(middlewares, neo.HandleAssistantDelete)...)
|
||||||
|
|
||||||
// Chat management endpoints
|
// Chat management endpoints
|
||||||
// List chats example:
|
// List chats example:
|
||||||
|
|
@ -1070,8 +1070,8 @@ func (neo *DSL) handleGeneratePrompts(c *gin.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleAssistantList handles listing assistants
|
// HandleAssistantList handles listing assistants (exported for use in openapi/agent)
|
||||||
func (neo *DSL) handleAssistantList(c *gin.Context) {
|
func (neo *DSL) HandleAssistantList(c *gin.Context) {
|
||||||
// Parse filter parameters
|
// Parse filter parameters
|
||||||
filter := store.AssistantFilter{
|
filter := store.AssistantFilter{
|
||||||
Type: "assistant",
|
Type: "assistant",
|
||||||
|
|
@ -1173,8 +1173,8 @@ func parseBoolValue(value string) *bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleAssistantAPI handles the assistant API
|
// HandleAssistantCall handles the assistant API call (exported for use in openapi/agent)
|
||||||
func (neo *DSL) handleAssistantCall(c *gin.Context) {
|
func (neo *DSL) HandleAssistantCall(c *gin.Context) {
|
||||||
assistantID := c.Param("id")
|
assistantID := c.Param("id")
|
||||||
if assistantID == "" {
|
if assistantID == "" {
|
||||||
c.JSON(400, gin.H{"message": "assistant id is required", "code": 400})
|
c.JSON(400, gin.H{"message": "assistant id is required", "code": 400})
|
||||||
|
|
@ -1213,8 +1213,8 @@ func (neo *DSL) handleAssistantCall(c *gin.Context) {
|
||||||
c.Done()
|
c.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleAssistantDetail handles getting a single assistant's details
|
// HandleAssistantDetail handles getting a single assistant's details (exported for use in openapi/agent)
|
||||||
func (neo *DSL) handleAssistantDetail(c *gin.Context) {
|
func (neo *DSL) HandleAssistantDetail(c *gin.Context) {
|
||||||
assistantID := c.Param("id")
|
assistantID := c.Param("id")
|
||||||
if assistantID == "" {
|
if assistantID == "" {
|
||||||
c.JSON(400, gin.H{"message": "assistant id is required", "code": 400})
|
c.JSON(400, gin.H{"message": "assistant id is required", "code": 400})
|
||||||
|
|
@ -1252,8 +1252,8 @@ func (neo *DSL) handleAssistantDetail(c *gin.Context) {
|
||||||
c.Done()
|
c.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleAssistantSave handles creating or updating an assistant
|
// HandleAssistantSave handles creating or updating an assistant (exported for use in openapi/agent)
|
||||||
func (neo *DSL) handleAssistantSave(c *gin.Context) {
|
func (neo *DSL) HandleAssistantSave(c *gin.Context) {
|
||||||
var assistantData map[string]interface{}
|
var assistantData map[string]interface{}
|
||||||
if err := c.BindJSON(&assistantData); err != nil {
|
if err := c.BindJSON(&assistantData); err != nil {
|
||||||
c.JSON(400, gin.H{"message": "invalid request body", "code": 400})
|
c.JSON(400, gin.H{"message": "invalid request body", "code": 400})
|
||||||
|
|
@ -1290,8 +1290,8 @@ func (neo *DSL) handleAssistantSave(c *gin.Context) {
|
||||||
c.Done()
|
c.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleAssistantDelete handles deleting an assistant
|
// HandleAssistantDelete handles deleting an assistant (exported for use in openapi/agent)
|
||||||
func (neo *DSL) handleAssistantDelete(c *gin.Context) {
|
func (neo *DSL) HandleAssistantDelete(c *gin.Context) {
|
||||||
assistantID := c.Param("id")
|
assistantID := c.Param("id")
|
||||||
if assistantID == "" {
|
if assistantID == "" {
|
||||||
c.JSON(400, gin.H{"message": "assistant id is required", "code": 400})
|
c.JSON(400, gin.H{"message": "assistant id is required", "code": 400})
|
||||||
|
|
@ -1342,8 +1342,8 @@ func (neo *DSL) handleConnectors(c *gin.Context) {
|
||||||
c.Done()
|
c.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleAssistantTags handles getting all assistant tags
|
// HandleAssistantTags handles getting all assistant tags (exported for use in openapi/agent)
|
||||||
func (neo *DSL) handleAssistantTags(c *gin.Context) {
|
func (neo *DSL) HandleAssistantTags(c *gin.Context) {
|
||||||
sid := c.GetString("__sid")
|
sid := c.GetString("__sid")
|
||||||
if sid == "" {
|
if sid == "" {
|
||||||
c.JSON(400, gin.H{"message": "sid is required", "code": 400})
|
c.JSON(400, gin.H{"message": "sid is required", "code": 400})
|
||||||
|
|
|
||||||
29
openapi/agent/agent.go
Normal file
29
openapi/agent/agent.go
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
package agent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/yaoapp/yao/neo"
|
||||||
|
"github.com/yaoapp/yao/openapi/oauth/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Attach attaches the agent (assistant) API handlers to the router with OAuth protection
|
||||||
|
// This provides OAuth-protected endpoints for assistant management, mirroring the neo assistant API
|
||||||
|
func Attach(group *gin.RouterGroup, oauth types.OAuth) {
|
||||||
|
|
||||||
|
// Get the Neo instance
|
||||||
|
n := neo.GetNeo()
|
||||||
|
|
||||||
|
// Create agents group with OAuth guard
|
||||||
|
agents := group.Group("/agents")
|
||||||
|
agents.Use(oauth.Guard)
|
||||||
|
|
||||||
|
// Agent CRUD - Standard REST endpoints
|
||||||
|
agents.GET("/", n.HandleAssistantList) // GET /agents - List agents
|
||||||
|
agents.POST("/", n.HandleAssistantSave) // POST /agents - Create/Update agent
|
||||||
|
agents.GET("/tags", n.HandleAssistantTags) // GET /agents/tags - Get all agent tags
|
||||||
|
agents.GET("/:id", n.HandleAssistantDetail) // GET /agents/:id - Get agent details
|
||||||
|
agents.DELETE("/:id", n.HandleAssistantDelete) // DELETE /agents/:id - Delete agent
|
||||||
|
|
||||||
|
// Agent Actions
|
||||||
|
agents.POST("/:id/call", n.HandleAssistantCall) // POST /agents/:id/call - Execute agent API
|
||||||
|
}
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
package agent
|
|
||||||
|
|
@ -1 +1,95 @@
|
||||||
package llm
|
package llm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/yaoapp/gou/connector"
|
||||||
|
oauthTypes "github.com/yaoapp/yao/openapi/oauth/types"
|
||||||
|
"github.com/yaoapp/yao/openapi/response"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Provider represents an LLM provider option
|
||||||
|
type Provider struct {
|
||||||
|
Label string `json:"label"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
Type string `json:"type"` // "openai"
|
||||||
|
Builtin bool `json:"builtin"` // true for system built-in, false for user-defined
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach attaches the LLM management handlers to the router with OAuth protection
|
||||||
|
func Attach(group *gin.RouterGroup, oauth oauthTypes.OAuth) {
|
||||||
|
|
||||||
|
// Create providers group with OAuth guard
|
||||||
|
providers := group.Group("/providers")
|
||||||
|
providers.Use(oauth.Guard)
|
||||||
|
|
||||||
|
// LLM Providers endpoints
|
||||||
|
providers.GET("/", listProviders) // GET /providers - List all LLM providers
|
||||||
|
}
|
||||||
|
|
||||||
|
// listProviders lists all available LLM providers (built-in + user-defined)
|
||||||
|
func listProviders(c *gin.Context) {
|
||||||
|
allProviders := make([]Provider, 0)
|
||||||
|
|
||||||
|
// Track which connectors we've already added (to avoid duplicates)
|
||||||
|
added := make(map[string]bool)
|
||||||
|
|
||||||
|
// 1. Get system built-in OpenAI-compatible LLM connectors
|
||||||
|
for _, opt := range connector.AIConnectors {
|
||||||
|
connType := getConnectorType(opt.Value)
|
||||||
|
// Only include OpenAI-compatible LLM connectors
|
||||||
|
if connType == "openai" {
|
||||||
|
allProviders = append(allProviders, Provider{
|
||||||
|
Label: opt.Label,
|
||||||
|
Value: opt.Value,
|
||||||
|
Type: connType,
|
||||||
|
Builtin: true,
|
||||||
|
})
|
||||||
|
added[opt.Value] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Get user-defined OpenAI-compatible LLM connectors from the global connector registry
|
||||||
|
// This includes all loaded connectors, both built-in and user-defined
|
||||||
|
// Only include OpenAI-compatible connectors (standard openai format)
|
||||||
|
for id, conn := range connector.Connectors {
|
||||||
|
// Skip if already added
|
||||||
|
if added[id] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only include OpenAI-compatible LLM connectors
|
||||||
|
connType := getConnectorType(id)
|
||||||
|
if connType == "openai" {
|
||||||
|
meta := conn.GetMetaInfo()
|
||||||
|
label := meta.Label
|
||||||
|
if label == "" {
|
||||||
|
label = id
|
||||||
|
}
|
||||||
|
|
||||||
|
allProviders = append(allProviders, Provider{
|
||||||
|
Label: label,
|
||||||
|
Value: id,
|
||||||
|
Type: connType,
|
||||||
|
Builtin: meta.Builtin,
|
||||||
|
})
|
||||||
|
added[id] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response.RespondWithSuccess(c, response.StatusOK, allProviders)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getConnectorType retrieves the connector type by checking the global connector map
|
||||||
|
func getConnectorType(id string) string {
|
||||||
|
conn, ok := connector.Connectors[id]
|
||||||
|
if !ok {
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only return openai type (OpenAI-compatible format)
|
||||||
|
if conn.Is(connector.OPENAI) {
|
||||||
|
return "openai"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1,68 @@
|
||||||
package mcp
|
package mcp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/yaoapp/gou/mcp"
|
||||||
|
oauthTypes "github.com/yaoapp/yao/openapi/oauth/types"
|
||||||
|
"github.com/yaoapp/yao/openapi/response"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Server represents an MCP server option (from user perspective)
|
||||||
|
type Server struct {
|
||||||
|
Label string `json:"label"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Transport string `json:"transport,omitempty"` // "stdio", "sse", "http"
|
||||||
|
Builtin bool `json:"builtin"` // true for system built-in, false for user-defined
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach attaches the MCP server management handlers to the router with OAuth protection
|
||||||
|
func Attach(group *gin.RouterGroup, oauth oauthTypes.OAuth) {
|
||||||
|
|
||||||
|
// Create servers group with OAuth guard
|
||||||
|
servers := group.Group("/servers")
|
||||||
|
servers.Use(oauth.Guard)
|
||||||
|
|
||||||
|
// MCP Servers endpoints
|
||||||
|
servers.GET("/", listServers) // GET /servers - List all MCP servers
|
||||||
|
}
|
||||||
|
|
||||||
|
// listServers lists all available MCP servers (loaded clients from user perspective)
|
||||||
|
func listServers(c *gin.Context) {
|
||||||
|
allServers := make([]Server, 0)
|
||||||
|
|
||||||
|
// Get all loaded MCP clients (they are servers from user perspective)
|
||||||
|
clientIDs := mcp.ListClients()
|
||||||
|
|
||||||
|
for _, id := range clientIDs {
|
||||||
|
client, err := mcp.Select(id)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get metadata
|
||||||
|
meta := client.GetMetaInfo()
|
||||||
|
|
||||||
|
label := meta.Label
|
||||||
|
if label == "" {
|
||||||
|
label = id
|
||||||
|
}
|
||||||
|
|
||||||
|
name := id
|
||||||
|
|
||||||
|
// Get transport type (if available from DSL or client info)
|
||||||
|
transport := "" // Could extract from client implementation if needed
|
||||||
|
|
||||||
|
allServers = append(allServers, Server{
|
||||||
|
Label: label,
|
||||||
|
Value: id,
|
||||||
|
Name: name,
|
||||||
|
Description: meta.Description,
|
||||||
|
Transport: transport,
|
||||||
|
Builtin: meta.Builtin,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
response.RespondWithSuccess(c, response.StatusOK, allServers)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yaoapp/gou/application"
|
"github.com/yaoapp/gou/application"
|
||||||
"github.com/yaoapp/yao/config"
|
"github.com/yaoapp/yao/config"
|
||||||
|
"github.com/yaoapp/yao/openapi/agent"
|
||||||
"github.com/yaoapp/yao/openapi/captcha"
|
"github.com/yaoapp/yao/openapi/captcha"
|
||||||
"github.com/yaoapp/yao/openapi/chat"
|
"github.com/yaoapp/yao/openapi/chat"
|
||||||
"github.com/yaoapp/yao/openapi/dsl"
|
"github.com/yaoapp/yao/openapi/dsl"
|
||||||
|
|
@ -13,6 +14,8 @@ import (
|
||||||
"github.com/yaoapp/yao/openapi/hello"
|
"github.com/yaoapp/yao/openapi/hello"
|
||||||
"github.com/yaoapp/yao/openapi/job"
|
"github.com/yaoapp/yao/openapi/job"
|
||||||
"github.com/yaoapp/yao/openapi/kb"
|
"github.com/yaoapp/yao/openapi/kb"
|
||||||
|
"github.com/yaoapp/yao/openapi/llm"
|
||||||
|
"github.com/yaoapp/yao/openapi/mcp"
|
||||||
"github.com/yaoapp/yao/openapi/messenger"
|
"github.com/yaoapp/yao/openapi/messenger"
|
||||||
"github.com/yaoapp/yao/openapi/oauth"
|
"github.com/yaoapp/yao/openapi/oauth"
|
||||||
"github.com/yaoapp/yao/openapi/oauth/acl"
|
"github.com/yaoapp/yao/openapi/oauth/acl"
|
||||||
|
|
@ -128,6 +131,15 @@ func (openapi *OpenAPI) Attach(router *gin.Engine) {
|
||||||
// Messenger webhook handlers
|
// Messenger webhook handlers
|
||||||
messenger.Attach(group.Group("/messenger"), openapi.OAuth)
|
messenger.Attach(group.Group("/messenger"), openapi.OAuth)
|
||||||
|
|
||||||
|
// Agent handlers
|
||||||
|
agent.Attach(group.Group("/agent"), openapi.OAuth)
|
||||||
|
|
||||||
|
// LLM Provider handlers
|
||||||
|
llm.Attach(group.Group("/llm"), openapi.OAuth)
|
||||||
|
|
||||||
|
// MCP Server handlers
|
||||||
|
mcp.Attach(group.Group("/mcp"), openapi.OAuth)
|
||||||
|
|
||||||
// Custom handlers (Defined by developer)
|
// Custom handlers (Defined by developer)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue