- Introduced a new global phase agent resolver to streamline agent ID retrieval for various robot pipeline phases, enhancing flexibility in agent configuration. - Updated existing phase agent retrieval logic to prioritize per-robot configurations, falling back to global settings when necessary. - Enhanced error handling to provide clearer messages when no agent is configured for specific phases. - Added tests to validate the new resolution logic and ensure proper functionality across different configurations.
122 lines
3.9 KiB
Go
122 lines
3.9 KiB
Go
package robot
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
robotstore "github.com/yaoapp/yao/agent/robot/store"
|
|
robottypes "github.com/yaoapp/yao/agent/robot/types"
|
|
"github.com/yaoapp/yao/openapi/chat"
|
|
"github.com/yaoapp/yao/openapi/response"
|
|
)
|
|
|
|
// resolveHostAssistantID resolves the host assistant ID from a robot member ID.
|
|
// It fetches the RobotRecord, parses its config, and returns the PhaseHost agent ID.
|
|
func resolveHostAssistantID(ctx context.Context, memberID string) (string, *robotstore.RobotRecord, error) {
|
|
store := robotstore.NewRobotStore()
|
|
record, err := store.Get(ctx, memberID)
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("failed to get robot: %w", err)
|
|
}
|
|
if record == nil {
|
|
return "", nil, fmt.Errorf("robot not found: %s", memberID)
|
|
}
|
|
|
|
config, err := robottypes.ParseConfig(record.RobotConfig)
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("failed to parse robot config: %w", err)
|
|
}
|
|
|
|
hostID := robottypes.ResolvePhaseAgent(config, robottypes.PhaseHost)
|
|
if hostID == "" {
|
|
return "", nil, fmt.Errorf("no Host Agent configured for robot %s (set uses.host in agent.yml or resources.phases in robot config)", memberID)
|
|
}
|
|
|
|
return hostID, record, nil
|
|
}
|
|
|
|
// injectAssistantID sets the assistant_id query parameter on the gin request,
|
|
// so that downstream GetCompletionRequest can pick it up.
|
|
func injectAssistantID(c *gin.Context, assistantID string) {
|
|
q := c.Request.URL.Query()
|
|
q.Set("assistant_id", assistantID)
|
|
c.Request.URL.RawQuery = q.Encode()
|
|
}
|
|
|
|
// RobotCompletions handles POST /v1/agent/robots/:id/completions
|
|
// Mirror API that resolves the robot's host assistant and delegates to standard chat completions.
|
|
func RobotCompletions(c *gin.Context) {
|
|
robotID := c.Param("id")
|
|
if robotID == "" {
|
|
response.RespondWithError(c, response.StatusBadRequest, &response.ErrorResponse{
|
|
Code: response.ErrInvalidRequest.Code,
|
|
ErrorDescription: "robot id is required",
|
|
})
|
|
return
|
|
}
|
|
|
|
hostID, _, err := resolveHostAssistantID(c.Request.Context(), robotID)
|
|
if err != nil {
|
|
response.RespondWithError(c, response.StatusInternalServerError, &response.ErrorResponse{
|
|
Code: response.ErrServerError.Code,
|
|
ErrorDescription: err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
injectAssistantID(c, hostID)
|
|
chat.GinCreateCompletions(c)
|
|
}
|
|
|
|
// RobotAppendMessages handles POST /v1/agent/robots/:id/completions/:context_id/append
|
|
// Mirror API that resolves the robot's host assistant and delegates to standard append.
|
|
func RobotAppendMessages(c *gin.Context) {
|
|
robotID := c.Param("id")
|
|
if robotID == "" {
|
|
response.RespondWithError(c, response.StatusBadRequest, &response.ErrorResponse{
|
|
Code: response.ErrInvalidRequest.Code,
|
|
ErrorDescription: "robot id is required",
|
|
})
|
|
return
|
|
}
|
|
|
|
hostID, _, err := resolveHostAssistantID(c.Request.Context(), robotID)
|
|
if err != nil {
|
|
response.RespondWithError(c, response.StatusInternalServerError, &response.ErrorResponse{
|
|
Code: response.ErrServerError.Code,
|
|
ErrorDescription: err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
injectAssistantID(c, hostID)
|
|
chat.GinAppendMessages(c)
|
|
}
|
|
|
|
// RobotHostID handles GET /v1/agent/robots/:id/host
|
|
// Returns the host assistant ID for a robot (used by frontend to know which assistant to chat with).
|
|
func RobotHostID(c *gin.Context) {
|
|
robotID := c.Param("id")
|
|
if robotID == "" {
|
|
response.RespondWithError(c, response.StatusBadRequest, &response.ErrorResponse{
|
|
Code: response.ErrInvalidRequest.Code,
|
|
ErrorDescription: "robot id is required",
|
|
})
|
|
return
|
|
}
|
|
|
|
hostID, _, err := resolveHostAssistantID(c.Request.Context(), robotID)
|
|
if err != nil {
|
|
response.RespondWithError(c, response.StatusInternalServerError, &response.ErrorResponse{
|
|
Code: response.ErrServerError.Code,
|
|
ErrorDescription: err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
response.RespondWithSuccess(c, response.StatusOK, gin.H{
|
|
"assistant_id": hostID,
|
|
"robot_id": robotID,
|
|
})
|
|
}
|