Add assistant management functionality in conversation module
- Introduced SaveAssistant, DeleteAssistant, and GetAssistants methods across Mongo, Redis, and Weaviate implementations to manage assistant records. - Enhanced the AssistantFilter and AssistantResponse types for improved pagination and filtering capabilities. - Updated the conversation interface to include new assistant-related methods, ensuring consistent functionality across different storage backends. - Added tests for assistant CRUD operations and pagination, ensuring robust functionality and reliability in managing assistants.
This commit is contained in:
parent
8166503058
commit
b17778afea
6 changed files with 465 additions and 36 deletions
|
|
@ -1,5 +1,7 @@
|
||||||
package conversation
|
package conversation
|
||||||
|
|
||||||
|
import "github.com/yaoapp/xun"
|
||||||
|
|
||||||
// Mongo conversation
|
// Mongo conversation
|
||||||
type Mongo struct{}
|
type Mongo struct{}
|
||||||
|
|
||||||
|
|
@ -58,3 +60,29 @@ func (conv *Mongo) DeleteChat(sid string, cid string) error {
|
||||||
func (conv *Mongo) DeleteAllChats(sid string) error {
|
func (conv *Mongo) DeleteAllChats(sid string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SaveAssistant creates or updates an assistant
|
||||||
|
func (conv *Mongo) SaveAssistant(assistant map[string]interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteAssistant deletes an assistant by assistant_id
|
||||||
|
func (conv *Mongo) DeleteAssistant(assistantID string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAssistants retrieves assistants with pagination and tag filtering
|
||||||
|
func (conv *Mongo) GetAssistants(filter AssistantFilter) (*AssistantResponse, error) {
|
||||||
|
return &AssistantResponse{
|
||||||
|
P: xun.P{
|
||||||
|
Items: []interface{}{},
|
||||||
|
Total: 0,
|
||||||
|
TotalPages: 0,
|
||||||
|
PageSize: filter.PageSize,
|
||||||
|
CurrentPage: filter.Page,
|
||||||
|
NextPage: 0,
|
||||||
|
PreviousPage: 0,
|
||||||
|
LastPage: 0,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package conversation
|
package conversation
|
||||||
|
|
||||||
|
import "github.com/yaoapp/xun"
|
||||||
|
|
||||||
// Redis conversation
|
// Redis conversation
|
||||||
type Redis struct{}
|
type Redis struct{}
|
||||||
|
|
||||||
|
|
@ -58,3 +60,29 @@ func (conv *Redis) DeleteChat(sid string, cid string) error {
|
||||||
func (conv *Redis) DeleteAllChats(sid string) error {
|
func (conv *Redis) DeleteAllChats(sid string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SaveAssistant creates or updates an assistant
|
||||||
|
func (conv *Redis) SaveAssistant(assistant map[string]interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteAssistant deletes an assistant by assistant_id
|
||||||
|
func (conv *Redis) DeleteAssistant(assistantID string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAssistants retrieves assistants with pagination and tag filtering
|
||||||
|
func (conv *Redis) GetAssistants(filter AssistantFilter) (*AssistantResponse, error) {
|
||||||
|
return &AssistantResponse{
|
||||||
|
P: xun.P{
|
||||||
|
Items: []interface{}{},
|
||||||
|
Total: 0,
|
||||||
|
TotalPages: 0,
|
||||||
|
PageSize: filter.PageSize,
|
||||||
|
CurrentPage: filter.Page,
|
||||||
|
NextPage: 0,
|
||||||
|
PreviousPage: 0,
|
||||||
|
LastPage: 0,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package conversation
|
package conversation
|
||||||
|
|
||||||
|
import "github.com/yaoapp/xun"
|
||||||
|
|
||||||
// Setting the conversation config
|
// Setting the conversation config
|
||||||
type Setting struct {
|
type Setting struct {
|
||||||
Connector string `json:"connector,omitempty"`
|
Connector string `json:"connector,omitempty"`
|
||||||
|
|
@ -38,6 +40,18 @@ type ChatGroupResponse struct {
|
||||||
LastPage int `json:"last_page"` // 最后一页页码
|
LastPage int `json:"last_page"` // 最后一页页码
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AssistantFilter represents the filter parameters for GetAssistants
|
||||||
|
type AssistantFilter struct {
|
||||||
|
Tags []string `json:"tags,omitempty"`
|
||||||
|
Page int `json:"page,omitempty"` // Page number, starting from 1
|
||||||
|
PageSize int `json:"pagesize,omitempty"` // Items per page
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssistantResponse represents paginated assistant results
|
||||||
|
type AssistantResponse struct {
|
||||||
|
xun.P
|
||||||
|
}
|
||||||
|
|
||||||
// Conversation the store interface
|
// Conversation the store interface
|
||||||
type Conversation interface {
|
type Conversation interface {
|
||||||
GetChats(sid string, filter ChatFilter) (*ChatGroupResponse, error)
|
GetChats(sid string, filter ChatFilter) (*ChatGroupResponse, error)
|
||||||
|
|
@ -47,4 +61,7 @@ type Conversation interface {
|
||||||
DeleteChat(sid string, cid string) error
|
DeleteChat(sid string, cid string) error
|
||||||
DeleteAllChats(sid string) error
|
DeleteAllChats(sid string) error
|
||||||
UpdateChatTitle(sid string, cid string, title string) error
|
UpdateChatTitle(sid string, cid string, title string) error
|
||||||
|
SaveAssistant(assistant map[string]interface{}) error
|
||||||
|
DeleteAssistant(assistantID string) error
|
||||||
|
GetAssistants(filter AssistantFilter) (*AssistantResponse, error)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package conversation
|
package conversation
|
||||||
|
|
||||||
|
import "github.com/yaoapp/xun"
|
||||||
|
|
||||||
// Weaviate Database conversation
|
// Weaviate Database conversation
|
||||||
type Weaviate struct{}
|
type Weaviate struct{}
|
||||||
|
|
||||||
|
|
@ -58,3 +60,29 @@ func (conv *Weaviate) DeleteChat(sid string, cid string) error {
|
||||||
func (conv *Weaviate) DeleteAllChats(sid string) error {
|
func (conv *Weaviate) DeleteAllChats(sid string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SaveAssistant creates or updates an assistant
|
||||||
|
func (conv *Weaviate) SaveAssistant(assistant map[string]interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteAssistant deletes an assistant by assistant_id
|
||||||
|
func (conv *Weaviate) DeleteAssistant(assistantID string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAssistants retrieves assistants with pagination and tag filtering
|
||||||
|
func (conv *Weaviate) GetAssistants(filter AssistantFilter) (*AssistantResponse, error) {
|
||||||
|
return &AssistantResponse{
|
||||||
|
P: xun.P{
|
||||||
|
Items: []interface{}{},
|
||||||
|
Total: 0,
|
||||||
|
TotalPages: 0,
|
||||||
|
PageSize: filter.PageSize,
|
||||||
|
CurrentPage: filter.Page,
|
||||||
|
NextPage: 0,
|
||||||
|
PreviousPage: 0,
|
||||||
|
LastPage: 0,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -217,6 +217,7 @@ func (conv *Xun) initAssistantTable() error {
|
||||||
table.JSON("flows").Null() // assistant flows
|
table.JSON("flows").Null() // assistant flows
|
||||||
table.JSON("files").Null() // assistant files
|
table.JSON("files").Null() // assistant files
|
||||||
table.JSON("functions").Null() // assistant functions
|
table.JSON("functions").Null() // assistant functions
|
||||||
|
table.JSON("tags").Null() // assistant tags
|
||||||
table.Boolean("readonly").SetDefault(false).Index() // assistant readonly
|
table.Boolean("readonly").SetDefault(false).Index() // assistant readonly
|
||||||
table.JSON("permissions").Null() // assistant permissions
|
table.JSON("permissions").Null() // assistant permissions
|
||||||
table.Boolean("automated").SetDefault(true).Index() // assistant autoable
|
table.Boolean("automated").SetDefault(true).Index() // assistant autoable
|
||||||
|
|
@ -237,7 +238,7 @@ func (conv *Xun) initAssistantTable() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fields := []string{"id", "assistant_id", "type", "name", "avatar", "connector", "description", "options", "prompts", "flows", "files", "functions", "mentionable", "created_at", "updated_at"}
|
fields := []string{"id", "assistant_id", "type", "name", "avatar", "connector", "description", "options", "prompts", "flows", "files", "functions", "tags", "mentionable", "created_at", "updated_at"}
|
||||||
for _, field := range fields {
|
for _, field := range fields {
|
||||||
if !tab.HasColumn(field) {
|
if !tab.HasColumn(field) {
|
||||||
return fmt.Errorf("%s is required", field)
|
return fmt.Errorf("%s is required", field)
|
||||||
|
|
@ -648,3 +649,83 @@ func (conv *Xun) DeleteAllChats(sid string) error {
|
||||||
Delete()
|
Delete()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SaveAssistant creates or updates an assistant
|
||||||
|
func (conv *Xun) SaveAssistant(assistant map[string]interface{}) error {
|
||||||
|
assistantID, ok := assistant["assistant_id"].(string)
|
||||||
|
if !ok || assistantID == "" {
|
||||||
|
assistantID = uuid.New().String()
|
||||||
|
assistant["assistant_id"] = assistantID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if assistant exists
|
||||||
|
exists, err := conv.query.New().
|
||||||
|
Table(conv.getAssistantTable()).
|
||||||
|
Where("assistant_id", assistantID).
|
||||||
|
Exists()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
assistant["updated_at"] = now
|
||||||
|
|
||||||
|
if exists {
|
||||||
|
// Update existing assistant
|
||||||
|
_, err = conv.query.New().
|
||||||
|
Table(conv.getAssistantTable()).
|
||||||
|
Where("assistant_id", assistantID).
|
||||||
|
Update(assistant)
|
||||||
|
} else {
|
||||||
|
// Create new assistant
|
||||||
|
assistant["created_at"] = now
|
||||||
|
err = conv.query.New().
|
||||||
|
Table(conv.getAssistantTable()).
|
||||||
|
Insert(assistant)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteAssistant deletes an assistant by assistant_id
|
||||||
|
func (conv *Xun) DeleteAssistant(assistantID string) error {
|
||||||
|
_, err := conv.query.New().
|
||||||
|
Table(conv.getAssistantTable()).
|
||||||
|
Where("assistant_id", assistantID).
|
||||||
|
Delete()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAssistants retrieves assistants with pagination and tag filtering
|
||||||
|
func (conv *Xun) GetAssistants(filter AssistantFilter) (*AssistantResponse, error) {
|
||||||
|
qb := conv.query.New().
|
||||||
|
Table(conv.getAssistantTable())
|
||||||
|
|
||||||
|
// Apply tag filter if provided
|
||||||
|
if filter.Tags != nil && len(filter.Tags) > 0 {
|
||||||
|
for i, tag := range filter.Tags {
|
||||||
|
if i == 0 {
|
||||||
|
qb.Where("tags", "like", fmt.Sprintf("%%\"%s\"%%", tag))
|
||||||
|
} else {
|
||||||
|
qb.OrWhere("tags", "like", fmt.Sprintf("%%\"%s\"%%", tag))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set defaults for pagination
|
||||||
|
if filter.PageSize <= 0 {
|
||||||
|
filter.PageSize = 20
|
||||||
|
}
|
||||||
|
if filter.Page <= 0 {
|
||||||
|
filter.Page = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get paginated results
|
||||||
|
paginator, err := qb.OrderBy("created_at", "desc").
|
||||||
|
Paginate(filter.PageSize, filter.Page)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &AssistantResponse{P: paginator}, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,10 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
jsoniter "github.com/json-iterator/go"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/yaoapp/gou/connector"
|
"github.com/yaoapp/gou/connector"
|
||||||
|
"github.com/yaoapp/xun"
|
||||||
"github.com/yaoapp/xun/capsule"
|
"github.com/yaoapp/xun/capsule"
|
||||||
"github.com/yaoapp/yao/config"
|
"github.com/yaoapp/yao/config"
|
||||||
"github.com/yaoapp/yao/test"
|
"github.com/yaoapp/yao/test"
|
||||||
|
|
@ -15,9 +17,21 @@ import (
|
||||||
func TestNewXunDefault(t *testing.T) {
|
func TestNewXunDefault(t *testing.T) {
|
||||||
test.Prepare(t, config.Conf)
|
test.Prepare(t, config.Conf)
|
||||||
defer test.Clean()
|
defer test.Clean()
|
||||||
defer capsule.Schema().DropTableIfExists("__unit_test_conversation")
|
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_history")
|
||||||
|
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_chat")
|
||||||
|
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_assistant")
|
||||||
|
|
||||||
err := capsule.Schema().DropTableIfExists("__unit_test_conversation")
|
err := capsule.Schema().DropTableIfExists("__unit_test_conversation_history")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = capsule.Schema().DropTableIfExists("__unit_test_conversation_chat")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = capsule.Schema().DropTableIfExists("__unit_test_conversation_assistant")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -32,15 +46,29 @@ func TestNewXunDefault(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
has, err := capsule.Schema().HasTable("__unit_test_conversation")
|
// Check history table
|
||||||
|
has, err := capsule.Schema().HasTable("__unit_test_conversation_history")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, true, has)
|
assert.Equal(t, true, has)
|
||||||
|
|
||||||
// validate the table
|
// Check chat table
|
||||||
tab, err := conv.schema.GetTable(conv.setting.Table)
|
has, err = capsule.Schema().HasTable("__unit_test_conversation_chat")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, true, has)
|
||||||
|
|
||||||
|
// Check assistant table
|
||||||
|
has, err = capsule.Schema().HasTable("__unit_test_conversation_assistant")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, true, has)
|
||||||
|
|
||||||
|
// validate the history table
|
||||||
|
tab, err := conv.schema.GetTable(conv.getHistoryTable())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -50,17 +78,27 @@ func TestNewXunDefault(t *testing.T) {
|
||||||
assert.Equal(t, true, tab.HasColumn(field))
|
assert.Equal(t, true, tab.HasColumn(field))
|
||||||
}
|
}
|
||||||
|
|
||||||
conv, err = NewXun(Setting{
|
// validate the chat table
|
||||||
Connector: "default",
|
tab, err = conv.schema.GetTable(conv.getChatTable())
|
||||||
Table: "__unit_test_conversation",
|
|
||||||
})
|
|
||||||
|
|
||||||
has, err = capsule.Schema().HasTable("__unit_test_conversation")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, true, has)
|
chatFields := []string{"id", "chat_id", "title", "sid", "created_at", "updated_at"}
|
||||||
|
for _, field := range chatFields {
|
||||||
|
assert.Equal(t, true, tab.HasColumn(field))
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate the assistant table
|
||||||
|
tab, err = conv.schema.GetTable(conv.getAssistantTable())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assistantFields := []string{"id", "assistant_id", "type", "name", "avatar", "connector", "description", "options", "prompts", "flows", "files", "functions", "tags", "readonly", "permissions", "automated", "mentionable", "created_at", "updated_at"}
|
||||||
|
for _, field := range assistantFields {
|
||||||
|
assert.Equal(t, true, tab.HasColumn(field))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewXunConnector(t *testing.T) {
|
func TestNewXunConnector(t *testing.T) {
|
||||||
|
|
@ -77,9 +115,14 @@ func TestNewXunConnector(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer sch.DropTableIfExists("__unit_test_conversation")
|
defer sch.DropTableIfExists("__unit_test_conversation_history")
|
||||||
|
defer sch.DropTableIfExists("__unit_test_conversation_chat")
|
||||||
|
defer sch.DropTableIfExists("__unit_test_conversation_assistant")
|
||||||
|
|
||||||
|
sch.DropTableIfExists("__unit_test_conversation_history")
|
||||||
|
sch.DropTableIfExists("__unit_test_conversation_chat")
|
||||||
|
sch.DropTableIfExists("__unit_test_conversation_assistant")
|
||||||
|
|
||||||
sch.DropTableIfExists("__unit_test_conversation")
|
|
||||||
conv, err := NewXun(Setting{
|
conv, err := NewXun(Setting{
|
||||||
Connector: "mysql",
|
Connector: "mysql",
|
||||||
Table: "__unit_test_conversation",
|
Table: "__unit_test_conversation",
|
||||||
|
|
@ -90,15 +133,29 @@ func TestNewXunConnector(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
has, err := sch.HasTable("__unit_test_conversation")
|
// Check history table
|
||||||
|
has, err := sch.HasTable("__unit_test_conversation_history")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, true, has)
|
assert.Equal(t, true, has)
|
||||||
|
|
||||||
// validate the table
|
// Check chat table
|
||||||
tab, err := conv.schema.GetTable(conv.setting.Table)
|
has, err = sch.HasTable("__unit_test_conversation_chat")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, true, has)
|
||||||
|
|
||||||
|
// Check assistant table
|
||||||
|
has, err = sch.HasTable("__unit_test_conversation_assistant")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, true, has)
|
||||||
|
|
||||||
|
// validate the history table
|
||||||
|
tab, err := conv.schema.GetTable(conv.getHistoryTable())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -108,26 +165,41 @@ func TestNewXunConnector(t *testing.T) {
|
||||||
assert.Equal(t, true, tab.HasColumn(field))
|
assert.Equal(t, true, tab.HasColumn(field))
|
||||||
}
|
}
|
||||||
|
|
||||||
conv, err = NewXun(Setting{
|
// validate the chat table
|
||||||
Connector: "default",
|
tab, err = conv.schema.GetTable(conv.getChatTable())
|
||||||
Table: "__unit_test_conversation",
|
|
||||||
})
|
|
||||||
|
|
||||||
has, err = sch.HasTable("__unit_test_conversation")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, true, has)
|
chatFields := []string{"id", "chat_id", "title", "sid", "created_at", "updated_at"}
|
||||||
|
for _, field := range chatFields {
|
||||||
|
assert.Equal(t, true, tab.HasColumn(field))
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate the assistant table
|
||||||
|
tab, err = conv.schema.GetTable(conv.getAssistantTable())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assistantFields := []string{"id", "assistant_id", "type", "name", "avatar", "connector", "description", "options", "prompts", "flows", "files", "functions", "tags", "readonly", "permissions", "automated", "mentionable", "created_at", "updated_at"}
|
||||||
|
for _, field := range assistantFields {
|
||||||
|
assert.Equal(t, true, tab.HasColumn(field))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestXunSaveAndGetHistory(t *testing.T) {
|
func TestXunSaveAndGetHistory(t *testing.T) {
|
||||||
|
|
||||||
test.Prepare(t, config.Conf)
|
test.Prepare(t, config.Conf)
|
||||||
defer test.Clean()
|
defer test.Clean()
|
||||||
defer capsule.Schema().DropTableIfExists("__unit_test_conversation")
|
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_history")
|
||||||
|
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_chat")
|
||||||
|
|
||||||
err := capsule.Schema().DropTableIfExists("__unit_test_conversation")
|
err := capsule.Schema().DropTableIfExists("__unit_test_conversation_history")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = capsule.Schema().DropTableIfExists("__unit_test_conversation_chat")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -157,9 +229,15 @@ func TestXunSaveAndGetHistory(t *testing.T) {
|
||||||
func TestXunSaveAndGetHistoryWithCID(t *testing.T) {
|
func TestXunSaveAndGetHistoryWithCID(t *testing.T) {
|
||||||
test.Prepare(t, config.Conf)
|
test.Prepare(t, config.Conf)
|
||||||
defer test.Clean()
|
defer test.Clean()
|
||||||
defer capsule.Schema().DropTableIfExists("__unit_test_conversation")
|
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_history")
|
||||||
|
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_chat")
|
||||||
|
|
||||||
err := capsule.Schema().DropTableIfExists("__unit_test_conversation")
|
err := capsule.Schema().DropTableIfExists("__unit_test_conversation_history")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = capsule.Schema().DropTableIfExists("__unit_test_conversation_chat")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -220,11 +298,11 @@ func TestXunSaveAndGetHistoryWithCID(t *testing.T) {
|
||||||
func TestXunGetChats(t *testing.T) {
|
func TestXunGetChats(t *testing.T) {
|
||||||
test.Prepare(t, config.Conf)
|
test.Prepare(t, config.Conf)
|
||||||
defer test.Clean()
|
defer test.Clean()
|
||||||
defer capsule.Schema().DropTableIfExists("__unit_test_conversation")
|
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_history")
|
||||||
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_chat")
|
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_chat")
|
||||||
|
|
||||||
// Drop both tables before test
|
// Drop both tables before test
|
||||||
err := capsule.Schema().DropTableIfExists("__unit_test_conversation")
|
err := capsule.Schema().DropTableIfExists("__unit_test_conversation_history")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -293,7 +371,7 @@ func TestXunGetChats(t *testing.T) {
|
||||||
func TestXunDeleteChat(t *testing.T) {
|
func TestXunDeleteChat(t *testing.T) {
|
||||||
test.Prepare(t, config.Conf)
|
test.Prepare(t, config.Conf)
|
||||||
defer test.Clean()
|
defer test.Clean()
|
||||||
defer capsule.Schema().DropTableIfExists("__unit_test_conversation")
|
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_history")
|
||||||
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_chat")
|
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_chat")
|
||||||
|
|
||||||
conv, err := NewXun(Setting{
|
conv, err := NewXun(Setting{
|
||||||
|
|
@ -333,7 +411,7 @@ func TestXunDeleteChat(t *testing.T) {
|
||||||
func TestXunDeleteAllChats(t *testing.T) {
|
func TestXunDeleteAllChats(t *testing.T) {
|
||||||
test.Prepare(t, config.Conf)
|
test.Prepare(t, config.Conf)
|
||||||
defer test.Clean()
|
defer test.Clean()
|
||||||
defer capsule.Schema().DropTableIfExists("__unit_test_conversation")
|
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_history")
|
||||||
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_chat")
|
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_chat")
|
||||||
|
|
||||||
conv, err := NewXun(Setting{
|
conv, err := NewXun(Setting{
|
||||||
|
|
@ -371,3 +449,172 @@ func TestXunDeleteAllChats(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, int64(0), response.Total)
|
assert.Equal(t, int64(0), response.Total)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestXunAssistantCRUD(t *testing.T) {
|
||||||
|
test.Prepare(t, config.Conf)
|
||||||
|
defer test.Clean()
|
||||||
|
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_history")
|
||||||
|
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_assistant")
|
||||||
|
|
||||||
|
// Drop assistant table before test
|
||||||
|
err := capsule.Schema().DropTableIfExists("__unit_test_conversation_assistant")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conv, err := NewXun(Setting{
|
||||||
|
Connector: "default",
|
||||||
|
Table: "__unit_test_conversation",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test creating a new assistant
|
||||||
|
tagsJSON, err := jsoniter.MarshalToString([]string{"tag1", "tag2", "tag3"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
optionsJSON, err := jsoniter.MarshalToString(map[string]interface{}{
|
||||||
|
"model": "gpt-4",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assistant := map[string]interface{}{
|
||||||
|
"name": "Test Assistant",
|
||||||
|
"type": "assistant",
|
||||||
|
"avatar": "https://example.com/avatar.png",
|
||||||
|
"connector": "openai",
|
||||||
|
"description": "Test Description",
|
||||||
|
"tags": tagsJSON,
|
||||||
|
"options": optionsJSON,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test SaveAssistant (Create)
|
||||||
|
err = conv.SaveAssistant(assistant)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assistantID := assistant["assistant_id"].(string)
|
||||||
|
assert.NotEmpty(t, assistantID)
|
||||||
|
|
||||||
|
// Test GetAssistants with no filter
|
||||||
|
resp, err := conv.GetAssistants(AssistantFilter{})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 1, len(resp.P.Items))
|
||||||
|
|
||||||
|
// Test GetAssistants with tag filter (single tag)
|
||||||
|
resp, err = conv.GetAssistants(AssistantFilter{
|
||||||
|
Tags: []string{"tag1"},
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 1, len(resp.P.Items))
|
||||||
|
|
||||||
|
// Test GetAssistants with tag filter (multiple tags)
|
||||||
|
resp, err = conv.GetAssistants(AssistantFilter{
|
||||||
|
Tags: []string{"tag1", "tag4"},
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 1, len(resp.P.Items))
|
||||||
|
|
||||||
|
// Test GetAssistants with non-existent tag
|
||||||
|
resp, err = conv.GetAssistants(AssistantFilter{
|
||||||
|
Tags: []string{"nonexistent"},
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 0, len(resp.P.Items))
|
||||||
|
|
||||||
|
// Test SaveAssistant (Update)
|
||||||
|
assistant["name"] = "Updated Assistant"
|
||||||
|
err = conv.SaveAssistant(assistant)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
resp, err = conv.GetAssistants(AssistantFilter{})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 1, len(resp.P.Items))
|
||||||
|
item := resp.P.Items[0].(xun.R)
|
||||||
|
assert.Equal(t, "Updated Assistant", item["name"])
|
||||||
|
|
||||||
|
// Test DeleteAssistant
|
||||||
|
err = conv.DeleteAssistant(assistantID)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
resp, err = conv.GetAssistants(AssistantFilter{})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 0, len(resp.P.Items))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXunAssistantPagination(t *testing.T) {
|
||||||
|
test.Prepare(t, config.Conf)
|
||||||
|
defer test.Clean()
|
||||||
|
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_history")
|
||||||
|
defer capsule.Schema().DropTableIfExists("__unit_test_conversation_assistant")
|
||||||
|
|
||||||
|
// Drop assistant table before test
|
||||||
|
err := capsule.Schema().DropTableIfExists("__unit_test_conversation_assistant")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conv, err := NewXun(Setting{
|
||||||
|
Connector: "default",
|
||||||
|
Table: "__unit_test_conversation",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create multiple assistants for pagination testing
|
||||||
|
for i := 0; i < 25; i++ {
|
||||||
|
tagsJSON, err := jsoniter.MarshalToString([]string{fmt.Sprintf("tag%d", i%5)})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assistant := map[string]interface{}{
|
||||||
|
"name": fmt.Sprintf("Assistant %d", i),
|
||||||
|
"type": "assistant",
|
||||||
|
"connector": "openai",
|
||||||
|
"description": fmt.Sprintf("Description %d", i),
|
||||||
|
"tags": tagsJSON,
|
||||||
|
}
|
||||||
|
err = conv.SaveAssistant(assistant)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test first page
|
||||||
|
resp, err := conv.GetAssistants(AssistantFilter{
|
||||||
|
Page: 1,
|
||||||
|
PageSize: 10,
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 10, len(resp.P.Items))
|
||||||
|
assert.Equal(t, 25, resp.P.Total)
|
||||||
|
assert.Equal(t, 3, resp.P.LastPage)
|
||||||
|
|
||||||
|
// Test second page
|
||||||
|
resp, err = conv.GetAssistants(AssistantFilter{
|
||||||
|
Page: 2,
|
||||||
|
PageSize: 10,
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 10, len(resp.P.Items))
|
||||||
|
|
||||||
|
// Test last page
|
||||||
|
resp, err = conv.GetAssistants(AssistantFilter{
|
||||||
|
Page: 3,
|
||||||
|
PageSize: 10,
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 5, len(resp.P.Items))
|
||||||
|
|
||||||
|
// Test filtering with tags
|
||||||
|
resp, err = conv.GetAssistants(AssistantFilter{
|
||||||
|
Tags: []string{"tag0"},
|
||||||
|
Page: 1,
|
||||||
|
PageSize: 10,
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 5, len(resp.P.Items))
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue