Refactor assistant settings to use 'Uses' instead of 'Use' for improved clarity
- Updated the Load function and API handlers to replace 'Use' with 'Uses' for assistant configuration, enhancing consistency across the codebase. - Modified related structures and functions to reflect the new naming convention, ensuring better alignment with the intended functionality. - Added a new Skip struct to manage request skip configurations, improving request handling flexibility. - Implemented tests for the GetSkip function to validate skip parameter extraction from both request body and query parameters.
This commit is contained in:
parent
b1d19a2d79
commit
bc3dd567b5
7 changed files with 282 additions and 38 deletions
|
|
@ -397,7 +397,7 @@ func (agent *API) handleChatLatest(c *gin.Context) {
|
|||
// Create a new chat
|
||||
if len(chats.Groups) == 0 || len(chats.Groups[0].Chats) == 0 {
|
||||
|
||||
assistantID := agent.Use.Default
|
||||
assistantID := agent.Uses.Default
|
||||
queryAssistantID := c.Query("assistant_id")
|
||||
if queryAssistantID != "" {
|
||||
assistantID = queryAssistantID
|
||||
|
|
@ -416,7 +416,7 @@ func (agent *API) handleChatLatest(c *gin.Context) {
|
|||
"assistant_id": ast.ID,
|
||||
"assistant_name": ast.GetName(locale),
|
||||
"assistant_avatar": ast.Avatar,
|
||||
"assistant_deleteable": agent.Use.Default != ast.ID,
|
||||
"assistant_deleteable": agent.Uses.Default != ast.ID,
|
||||
}})
|
||||
c.Done()
|
||||
return
|
||||
|
|
@ -439,10 +439,10 @@ func (agent *API) handleChatLatest(c *gin.Context) {
|
|||
|
||||
// assistant_id is nil return the default assistant
|
||||
if chat.Chat["assistant_id"] == nil {
|
||||
chat.Chat["assistant_id"] = agent.Use.Default
|
||||
chat.Chat["assistant_id"] = agent.Uses.Default
|
||||
|
||||
// Get the assistant info
|
||||
ast, err := assistant.Get(agent.Use.Default)
|
||||
ast, err := assistant.Get(agent.Uses.Default)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{"message": err.Error(), "code": 500})
|
||||
c.Done()
|
||||
|
|
@ -452,7 +452,7 @@ func (agent *API) handleChatLatest(c *gin.Context) {
|
|||
chat.Chat["assistant_avatar"] = ast.Avatar
|
||||
}
|
||||
|
||||
chat.Chat["assistant_deleteable"] = agent.Use.Default != chat.Chat["assistant_id"]
|
||||
chat.Chat["assistant_deleteable"] = agent.Uses.Default != chat.Chat["assistant_id"]
|
||||
c.JSON(200, map[string]interface{}{"data": chat})
|
||||
c.Done()
|
||||
}
|
||||
|
|
@ -488,10 +488,10 @@ func (agent *API) handleChatDetail(c *gin.Context) {
|
|||
|
||||
// assistant_id is nil return the default assistant
|
||||
if chat.Chat["assistant_id"] == nil {
|
||||
chat.Chat["assistant_id"] = agent.Use.Default
|
||||
chat.Chat["assistant_id"] = agent.Uses.Default
|
||||
|
||||
// Get the assistant info
|
||||
ast, err := assistant.Get(agent.Use.Default)
|
||||
ast, err := assistant.Get(agent.Uses.Default)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{"message": err.Error(), "code": 500})
|
||||
c.Done()
|
||||
|
|
@ -501,7 +501,7 @@ func (agent *API) handleChatDetail(c *gin.Context) {
|
|||
chat.Chat["assistant_avatar"] = ast.Avatar
|
||||
}
|
||||
|
||||
chat.Chat["assistant_deleteable"] = agent.Use.Default != chat.Chat["assistant_id"]
|
||||
chat.Chat["assistant_deleteable"] = agent.Uses.Default != chat.Chat["assistant_id"]
|
||||
c.JSON(200, map[string]interface{}{"data": chat})
|
||||
c.Done()
|
||||
}
|
||||
|
|
@ -674,7 +674,7 @@ func (agent *API) handleGenerateTitle(c *gin.Context) {
|
|||
|
||||
// // Set the assistant ID
|
||||
// ctx = chatctx.WithHistoryVisible(ctx, false)
|
||||
// ctx = chatctx.WithAssistantID(ctx, agent.Use.Title)
|
||||
// ctx = chatctx.WithAssistantID(ctx, agent.Uses.Title)
|
||||
|
||||
err := agent.Answer(ctx, content, c)
|
||||
|
||||
|
|
@ -714,7 +714,7 @@ func (agent *API) handleGeneratePrompts(c *gin.Context) {
|
|||
|
||||
// // Set the assistant ID
|
||||
// ctx = chatctx.WithHistoryVisible(ctx, false)
|
||||
// ctx = chatctx.WithAssistantID(ctx, agent.Use.Prompt)
|
||||
// ctx = chatctx.WithAssistantID(ctx, agent.Uses.Prompt)
|
||||
err := agent.Answer(ctx, content, c)
|
||||
|
||||
// Error handling
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ func GetCompletionRequest(c *gin.Context, cache store.Store) (*CompletionRequest
|
|||
},
|
||||
Route: GetRoute(c, completionReq),
|
||||
Metadata: GetMetadata(c, completionReq),
|
||||
Skip: GetSkip(c, completionReq),
|
||||
}
|
||||
|
||||
// Initialize interrupt controller
|
||||
|
|
@ -360,6 +361,30 @@ func GetRoute(c *gin.Context, req *CompletionRequest) string {
|
|||
return ""
|
||||
}
|
||||
|
||||
// GetSkip extracts skip configuration from request with priority:
|
||||
// 1. CompletionRequest.Skip (from payload body) - Priority
|
||||
// 2. Individual query parameters: "skip_history", "skip_trace"
|
||||
func GetSkip(c *gin.Context, req *CompletionRequest) *Skip {
|
||||
// Priority 1: From CompletionRequest body (most direct)
|
||||
if req != nil && req.Skip != nil {
|
||||
return req.Skip
|
||||
}
|
||||
|
||||
// Priority 2: Individual query parameters (recommended for query usage)
|
||||
skipHistory := c.Query("skip_history") == "true" || c.Query("skip_history") == "1"
|
||||
skipTrace := c.Query("skip_trace") == "true" || c.Query("skip_trace") == "1"
|
||||
|
||||
// Check if any skip parameter is set
|
||||
if c.Query("skip_history") != "" || c.Query("skip_trace") != "" {
|
||||
return &Skip{
|
||||
History: skipHistory,
|
||||
Trace: skipTrace,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetMetadata extracts metadata from request with priority:
|
||||
// 1. Query parameter "metadata" (JSON string)
|
||||
// 2. Header "X-Yao-Metadata" (Base64 encoded JSON string)
|
||||
|
|
|
|||
|
|
@ -930,3 +930,208 @@ func TestGetCompletionRequest_ChatIDFallback(t *testing.T) {
|
|||
t.Errorf("Expected ChatID to be at least 8 characters, got %d", len(ctx.ChatID))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSkip_FromBody(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
req := httptest.NewRequest("POST", "/chat/completions", nil)
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
|
||||
completionReq := &CompletionRequest{
|
||||
Skip: &Skip{
|
||||
History: true,
|
||||
Trace: false,
|
||||
},
|
||||
}
|
||||
|
||||
skip := GetSkip(c, completionReq)
|
||||
if skip == nil {
|
||||
t.Fatal("Expected skip to be returned")
|
||||
}
|
||||
|
||||
if !skip.History {
|
||||
t.Error("Expected skip.History to be true")
|
||||
}
|
||||
|
||||
if skip.Trace {
|
||||
t.Error("Expected skip.Trace to be false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSkip_FromQueryParams(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
req := httptest.NewRequest("GET", "/chat/completions?skip_history=true&skip_trace=false", nil)
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
|
||||
skip := GetSkip(c, nil)
|
||||
if skip == nil {
|
||||
t.Fatal("Expected skip to be returned")
|
||||
}
|
||||
|
||||
if !skip.History {
|
||||
t.Error("Expected skip.History to be true from query param")
|
||||
}
|
||||
|
||||
if skip.Trace {
|
||||
t.Error("Expected skip.Trace to be false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSkip_FromQueryParams_ShortForm(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
req := httptest.NewRequest("GET", "/chat/completions?skip_history=1&skip_trace=1", nil)
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
|
||||
skip := GetSkip(c, nil)
|
||||
if skip == nil {
|
||||
t.Fatal("Expected skip to be returned")
|
||||
}
|
||||
|
||||
if !skip.History {
|
||||
t.Error("Expected skip.History to be true from query param (1)")
|
||||
}
|
||||
|
||||
if !skip.Trace {
|
||||
t.Error("Expected skip.Trace to be true from query param (1)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSkip_Priority(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
// Body should take priority over query
|
||||
req := httptest.NewRequest("POST", "/chat/completions?skip_history=false&skip_trace=false", nil)
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
|
||||
completionReq := &CompletionRequest{
|
||||
Skip: &Skip{
|
||||
History: true,
|
||||
Trace: true,
|
||||
},
|
||||
}
|
||||
|
||||
skip := GetSkip(c, completionReq)
|
||||
if skip == nil {
|
||||
t.Fatal("Expected skip to be returned")
|
||||
}
|
||||
|
||||
// Body should take priority
|
||||
if !skip.History {
|
||||
t.Error("Expected body parameter to take priority, skip.History should be true")
|
||||
}
|
||||
|
||||
if !skip.Trace {
|
||||
t.Error("Expected body parameter to take priority, skip.Trace should be true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSkip_Nil(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
req := httptest.NewRequest("GET", "/chat/completions", nil)
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
|
||||
skip := GetSkip(c, nil)
|
||||
if skip != nil {
|
||||
t.Errorf("Expected skip to be nil, got %v", skip)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSkip_OnlyHistorySet(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
req := httptest.NewRequest("GET", "/chat/completions?skip_history=true", nil)
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
|
||||
skip := GetSkip(c, nil)
|
||||
if skip == nil {
|
||||
t.Fatal("Expected skip to be returned")
|
||||
}
|
||||
|
||||
if !skip.History {
|
||||
t.Error("Expected skip.History to be true")
|
||||
}
|
||||
|
||||
if skip.Trace {
|
||||
t.Error("Expected skip.Trace to be false (default)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSkip_FromBodyViaParseRequest(t *testing.T) {
|
||||
test.Prepare(t, config.Conf)
|
||||
defer test.Clean()
|
||||
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
// Test parsing Skip from full request body
|
||||
messages := []Message{
|
||||
{
|
||||
Role: RoleUser,
|
||||
Content: "Generate a title for this chat",
|
||||
},
|
||||
}
|
||||
|
||||
requestBody := map[string]interface{}{
|
||||
"model": "workers.system.title-yao_test",
|
||||
"messages": messages,
|
||||
"skip": map[string]interface{}{
|
||||
"history": true,
|
||||
"trace": false,
|
||||
},
|
||||
}
|
||||
|
||||
bodyBytes, _ := json.Marshal(requestBody)
|
||||
|
||||
req := httptest.NewRequest("POST", "/chat/completions", bytes.NewBuffer(bodyBytes))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
|
||||
// Parse the request
|
||||
completionReq, err := parseCompletionRequestData(c)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse completion request: %v", err)
|
||||
}
|
||||
|
||||
// Verify Skip was parsed correctly
|
||||
if completionReq.Skip == nil {
|
||||
t.Fatal("Expected Skip to be parsed from body, got nil")
|
||||
}
|
||||
|
||||
if !completionReq.Skip.History {
|
||||
t.Error("Expected Skip.History to be true from body")
|
||||
}
|
||||
|
||||
if completionReq.Skip.Trace {
|
||||
t.Error("Expected Skip.Trace to be false from body")
|
||||
}
|
||||
|
||||
// Now test GetSkip function with the parsed request
|
||||
skip := GetSkip(c, completionReq)
|
||||
if skip == nil {
|
||||
t.Fatal("Expected GetSkip to return skip configuration")
|
||||
}
|
||||
|
||||
if !skip.History {
|
||||
t.Error("Expected GetSkip to return History=true")
|
||||
}
|
||||
|
||||
if skip.Trace {
|
||||
t.Error("Expected GetSkip to return Trace=false")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,18 +186,25 @@ type AssistantInfo struct {
|
|||
Description string `json:"description,omitempty"` // Assistant Description
|
||||
}
|
||||
|
||||
// Skip configuration for what to skip in this request
|
||||
type Skip struct {
|
||||
History bool `json:"history"` // Skip saving chat history (for internal calls like title/prompt generation)
|
||||
Trace bool `json:"trace"` // Skip trace logging
|
||||
}
|
||||
|
||||
// Context the context
|
||||
type Context struct {
|
||||
|
||||
// Context
|
||||
context.Context
|
||||
ID string `json:"id"` // Context ID for external interrupt identification
|
||||
Space plan.Space `json:"-"` // Shared data space, it will be used to share data between the request and the call
|
||||
Cache store.Store `json:"-"` // Cache store, it will be used to store the message cache, default is "__yao.agent.cache"
|
||||
Stack *Stack `json:"-"` // Stack, current active stack of the request
|
||||
Stacks map[string]*Stack `json:"-"` // Stacks, all stacks in this request (for trace logging)
|
||||
Writer Writer `json:"-"` // Writer, it will be used to write response data to the client
|
||||
trace traceTypes.Manager `json:"-"` // Trace manager, lazy initialized on first access
|
||||
ID string `json:"id"` // Context ID for external interrupt identification
|
||||
Space plan.Space `json:"-"` // Shared data space, it will be used to share data between the request and the call
|
||||
Cache store.Store `json:"-"` // Cache store, it will be used to store the message cache, default is "__yao.agent.cache"
|
||||
Stack *Stack `json:"-"` // Stack, current active stack of the request
|
||||
Stacks map[string]*Stack `json:"-"` // Stacks, all stacks in this request (for trace logging)
|
||||
Writer Writer `json:"-"` // Writer, it will be used to write response data to the client
|
||||
Skip *Skip `json:"skip,omitempty"` // Skip configuration (history, trace, etc.), nil means don't skip anything
|
||||
trace traceTypes.Manager `json:"-"` // Trace manager, lazy initialized on first access
|
||||
|
||||
// Model capabilities (set by assistant, used by output adapters)
|
||||
Capabilities *ModelCapabilities `json:"-"` // Model capabilities for the current connector
|
||||
|
|
@ -443,6 +450,7 @@ type CompletionRequest struct {
|
|||
// CUI Context information
|
||||
Route string `json:"route,omitempty"` // Optional: route of the request for CUI context
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"` // Optional: metadata to pass to the page for CUI context
|
||||
Skip *Skip `json:"skip,omitempty"` // Optional: skip configuration (history, trace, etc.)
|
||||
}
|
||||
|
||||
// AudioConfig represents the audio output configuration for models that support audio
|
||||
|
|
|
|||
|
|
@ -45,18 +45,18 @@ func Load(cfg config.Config) error {
|
|||
}
|
||||
|
||||
// Default Assistant, Agent is the developer name, Mohe is the brand name of the assistant
|
||||
if setting.Use == nil {
|
||||
setting.Use = &types.Use{Default: "mohe"} // Agent is the developer name, Mohe is the brand name of the assistant
|
||||
if setting.Uses == nil {
|
||||
setting.Uses = &types.Uses{Default: "mohe"} // Agent is the developer name, Mohe is the brand name of the assistant
|
||||
}
|
||||
|
||||
// Title Assistant
|
||||
if setting.Use.Title == "" {
|
||||
setting.Use.Title = setting.Use.Default
|
||||
if setting.Uses.Title == "" {
|
||||
setting.Uses.Title = setting.Uses.Default
|
||||
}
|
||||
|
||||
// Prompt Assistant
|
||||
if setting.Use.Prompt == "" {
|
||||
setting.Use.Prompt = setting.Use.Default
|
||||
if setting.Uses.Prompt == "" {
|
||||
setting.Uses.Prompt = setting.Uses.Default
|
||||
}
|
||||
|
||||
// Initialize Agent API
|
||||
|
|
@ -173,12 +173,12 @@ func initAssistant() error {
|
|||
}
|
||||
|
||||
// Set global Uses configuration
|
||||
if api.Agent.DSL.Use != nil {
|
||||
if api.Agent.DSL.Uses != nil {
|
||||
globalUses := &context.Uses{
|
||||
Vision: api.Agent.DSL.Use.Vision,
|
||||
Audio: api.Agent.DSL.Use.Audio,
|
||||
Search: api.Agent.DSL.Use.Search,
|
||||
Fetch: api.Agent.DSL.Use.Fetch,
|
||||
Vision: api.Agent.DSL.Uses.Vision,
|
||||
Audio: api.Agent.DSL.Uses.Audio,
|
||||
Search: api.Agent.DSL.Uses.Search,
|
||||
Fetch: api.Agent.DSL.Uses.Fetch,
|
||||
}
|
||||
assistant.SetGlobalUses(globalUses)
|
||||
}
|
||||
|
|
@ -205,8 +205,8 @@ func initAssistant() error {
|
|||
|
||||
// defaultAssistant get the default assistant
|
||||
func defaultAssistant() (*assistant.Assistant, error) {
|
||||
if api.Agent.DSL.Use == nil || api.Agent.DSL.Use.Default == "" {
|
||||
if api.Agent.DSL.Uses == nil || api.Agent.DSL.Uses.Default == "" {
|
||||
return nil, fmt.Errorf("default assistant not found")
|
||||
}
|
||||
return assistant.Get(api.Agent.DSL.Use.Default)
|
||||
return assistant.Get(api.Agent.DSL.Uses.Default)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ type DSL struct {
|
|||
|
||||
// Agent Global Settings
|
||||
// ===============================
|
||||
Use *Use `json:"use,omitempty" yaml:"use,omitempty"` // Which assistant to use default, title, prompt
|
||||
StoreSetting store.Setting `json:"store" yaml:"store"` // The store setting of the assistant
|
||||
Cache string `json:"cache" yaml:"cache"` // The cache store of the assistant, if not set, default is "__yao.agent.cache"
|
||||
Uses *Uses `json:"uses,omitempty" yaml:"uses,omitempty"` // Which assistant to use default, title, prompt
|
||||
StoreSetting store.Setting `json:"store" yaml:"store"` // The store setting of the assistant
|
||||
Cache string `json:"cache" yaml:"cache"` // The cache store of the assistant, if not set, default is "__yao.agent.cache"
|
||||
|
||||
// AuthSetting *Auth `json:"auth,omitempty" yaml:"auth,omitempty"` // Authenticate Settings
|
||||
// UploadSetting *Upload `json:"upload,omitempty" yaml:"upload,omitempty"` // Upload Settings
|
||||
|
|
@ -38,9 +38,9 @@ type DSL struct {
|
|||
GuardHandlers []gin.HandlerFunc `json:"-" yaml:"-"`
|
||||
}
|
||||
|
||||
// Use the default assistant settings
|
||||
// Uses the default assistant settings
|
||||
// ===============================
|
||||
type Use struct {
|
||||
type Uses struct {
|
||||
Default string `json:"default,omitempty" yaml:"default,omitempty"` // The default assistant to use
|
||||
Title string `json:"title,omitempty" yaml:"title,omitempty"` // The assistant for generating the topic title.
|
||||
Prompt string `json:"prompt,omitempty" yaml:"prompt,omitempty"` // The assistant for generating the prompt.
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import (
|
|||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/yaoapp/gou/api"
|
||||
"github.com/yaoapp/gou/application"
|
||||
"github.com/yaoapp/gou/connector"
|
||||
"github.com/yaoapp/gou/process"
|
||||
v8 "github.com/yaoapp/gou/runtime/v8"
|
||||
"github.com/yaoapp/gou/session"
|
||||
|
|
@ -552,6 +551,13 @@ func processXgen(process *process.Process) interface{} {
|
|||
// The default assistant
|
||||
agentConfig := map[string]interface{}{}
|
||||
if agent.Agent != nil {
|
||||
|
||||
// Add Uses Settings
|
||||
if agent.Agent.DSL != nil && agent.Agent.DSL.Uses != nil {
|
||||
agentConfig["uses"] = agent.Agent.DSL.Uses
|
||||
}
|
||||
|
||||
// Add Default Assistant Settings ( Will be removed later )
|
||||
if ast, ok := agent.Agent.Assistant.(*assistant.Assistant); ok {
|
||||
agentConfig["default"] = map[string]interface{}{
|
||||
"assistant_id": ast.ID,
|
||||
|
|
@ -562,8 +568,8 @@ func processXgen(process *process.Process) interface{} {
|
|||
}
|
||||
}
|
||||
|
||||
// Available connectors
|
||||
agentConfig["connectors"] = connector.AIConnectors
|
||||
// Available connectors Removed later, It not be used yet, use the openapi instead.
|
||||
// agentConfig["connectors"] = connector.AIConnectors
|
||||
}
|
||||
|
||||
// OpenAPI Settings
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue