Skip to content

Commit

Permalink
Implement assistant call functionality in Neo API
Browse files Browse the repository at this point in the history
- Added a new endpoint for executing assistant calls via POST request, enhancing the API's capabilities.
- Introduced the handleAssistantCall method to process incoming requests, validate parameters, and execute the assistant's script.
- Updated the Assistant interface to include the Call method, allowing for dynamic method invocation based on the provided payload.
- Enhanced error handling for missing parameters and invalid requests, improving the robustness of the assistant's API interactions.

These changes significantly improve the Neo API assistant's functionality, enabling more interactive and dynamic assistant capabilities.
  • Loading branch information
trheyi committed Jan 23, 2025
1 parent 979d27b commit 1f9810c
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 0 deletions.
49 changes: 49 additions & 0 deletions neo/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/yaoapp/gou/connector"
"github.com/yaoapp/gou/process"
"github.com/yaoapp/yao/helper"
"github.com/yaoapp/yao/neo/assistant"
chatctx "github.com/yaoapp/yao/neo/context"
"github.com/yaoapp/yao/neo/message"
"github.com/yaoapp/yao/neo/store"
Expand Down Expand Up @@ -44,7 +45,9 @@ func (neo *DSL) API(router *gin.Engine, path string) error {
router.OPTIONS(path+"/dangerous/clear_chats", neo.optionsHandler)
router.OPTIONS(path+"/assistants", neo.optionsHandler)
router.OPTIONS(path+"/assistants/:id", neo.optionsHandler)
router.OPTIONS(path+"/assistants/:id/call", neo.optionsHandler)

// Chat endpoint
// Chat endpoint
// Example:
// curl -X GET 'http://localhost:5099/api/__yao/neo?content=Hello&chat_id=chat_123&context=previous_context&token=xxx'
Expand All @@ -71,6 +74,12 @@ func (neo *DSL) API(router *gin.Engine, path string) error {
// curl -X GET 'http://localhost:5099/api/__yao/neo/assistants/assistant_123?token=xxx'
router.GET(path+"/assistants/:id", append(middlewares, neo.handleAssistantDetail)...)

// Execute assistant API example:
// curl -X POST 'http://localhost:5099/api/__yao/neo/assistants/assistant_123/api' \
// -H 'Content-Type: application/json' \
// -d '{"name": "Test", "payload": {"name": "yao", "age": 18}}'
router.POST(path+"/assistants/:id/call", append(middlewares, neo.handleAssistantCall)...)

// Create/Update assistant example:
// curl -X POST 'http://localhost:5099/api/__yao/neo/assistants' \
// -H 'Content-Type: application/json' \
Expand Down Expand Up @@ -938,6 +947,46 @@ func parseBoolValue(value string) *bool {
}
}

// handleAssistantAPI handles the assistant API
func (neo *DSL) handleAssistantCall(c *gin.Context) {
assistantID := c.Param("id")
if assistantID == "" {
c.JSON(400, gin.H{"message": "assistant id is required", "code": 400})
c.Done()
return
}
ast, err := assistant.Get(assistantID)
if err != nil {
c.JSON(500, gin.H{"message": err.Error(), "code": 500})
c.Done()
return
}

sid := c.GetString("__sid")
if sid == "" {
c.JSON(400, gin.H{"message": "sid is required", "code": 400})
c.Done()
return
}

payload := assistant.APIPayload{Sid: sid}
if err := c.BindJSON(&payload); err != nil {
c.JSON(400, gin.H{"message": "invalid request body", "code": 400})
c.Done()
return
}

result, err := ast.Call(c, payload)
if err != nil {
c.JSON(500, gin.H{"message": err.Error(), "code": 500})
c.Done()
return
}

c.JSON(200, result)
c.Done()
}

// handleAssistantDetail handles getting a single assistant's details
func (neo *DSL) handleAssistantDetail(c *gin.Context) {
assistantID := c.Param("id")
Expand Down
19 changes: 19 additions & 0 deletions neo/assistant/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,25 @@ func (next *NextAction) Execute(c *gin.Context, ctx chatctx.Context) error {
}
}

// Call implements the call functionality
func (ast *Assistant) Call(c *gin.Context, payload APIPayload) (interface{}, error) {
scriptCtx, err := ast.Script.NewContext(payload.Sid, nil)
if err != nil {
return nil, err
}
defer scriptCtx.Close()
ctx := c.Request.Context()

method := fmt.Sprintf("%sAPI", payload.Name)

// Check if the method exists
if !scriptCtx.Global().Has(method) {
return nil, fmt.Errorf(HookErrorMethodNotFound)
}

return scriptCtx.CallWith(ctx, method, payload.Payload)
}

// handleChatStream manages the streaming chat interaction with the AI
func (ast *Assistant) handleChatStream(c *gin.Context, ctx chatctx.Context, messages []chatMessage.Message, options map[string]interface{}, contents *chatMessage.Contents) error {
clientBreak := make(chan bool, 1)
Expand Down
8 changes: 8 additions & 0 deletions neo/assistant/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ type API interface {
Download(ctx context.Context, fileID string) (*FileResponse, error)
ReadBase64(ctx context.Context, fileID string) (string, error)
Execute(c *gin.Context, ctx chatctx.Context, input string, options map[string]interface{}) error
Call(c *gin.Context, payload APIPayload) (interface{}, error)
}

// APIPayload the API payload
type APIPayload struct {
Sid string `json:"sid"`
Name string `json:"name"`
Payload map[string]interface{} `json:"payload"`
}

// ResHookInit the response of the init hook
Expand Down

0 comments on commit 1f9810c

Please sign in to comment.