Merge pull request #830 from trheyi/main
Add Placeholder support for Assistants in Neo API
This commit is contained in:
commit
ee09cfeb23
5 changed files with 69 additions and 4 deletions
|
|
@ -136,6 +136,7 @@ func (ast *Assistant) Map() map[string]interface{} {
|
||||||
"tags": ast.Tags,
|
"tags": ast.Tags,
|
||||||
"mentionable": ast.Mentionable,
|
"mentionable": ast.Mentionable,
|
||||||
"automated": ast.Automated,
|
"automated": ast.Automated,
|
||||||
|
"placeholder": ast.Placeholder,
|
||||||
"created_at": timeToMySQLFormat(ast.CreatedAt),
|
"created_at": timeToMySQLFormat(ast.CreatedAt),
|
||||||
"updated_at": timeToMySQLFormat(ast.UpdatedAt),
|
"updated_at": timeToMySQLFormat(ast.UpdatedAt),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -294,6 +294,41 @@ func loadMap(data map[string]interface{}) (*Assistant, error) {
|
||||||
assistant.Type = v
|
assistant.Type = v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Placeholder
|
||||||
|
if v, ok := data["placeholder"]; ok {
|
||||||
|
|
||||||
|
switch vv := v.(type) {
|
||||||
|
case string:
|
||||||
|
placeholder, err := jsoniter.Marshal(vv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
assistant.Placeholder = &Placeholder{}
|
||||||
|
err = jsoniter.Unmarshal(placeholder, assistant.Placeholder)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
case map[string]interface{}:
|
||||||
|
raw, err := jsoniter.Marshal(vv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
assistant.Placeholder = &Placeholder{}
|
||||||
|
err = jsoniter.Unmarshal(raw, assistant.Placeholder)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
case *Placeholder:
|
||||||
|
assistant.Placeholder = vv
|
||||||
|
|
||||||
|
case nil:
|
||||||
|
assistant.Placeholder = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Mentionable
|
// Mentionable
|
||||||
if v, ok := data["mentionable"].(bool); ok {
|
if v, ok := data["mentionable"].(bool); ok {
|
||||||
assistant.Mentionable = v
|
assistant.Mentionable = v
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,7 @@ type Assistant struct {
|
||||||
Prompts []Prompt `json:"prompts,omitempty"` // AI Prompts
|
Prompts []Prompt `json:"prompts,omitempty"` // AI Prompts
|
||||||
Functions []Function `json:"functions,omitempty"` // Assistant Functions
|
Functions []Function `json:"functions,omitempty"` // Assistant Functions
|
||||||
Flows []map[string]interface{} `json:"flows,omitempty"` // Assistant Flows
|
Flows []map[string]interface{} `json:"flows,omitempty"` // Assistant Flows
|
||||||
|
Placeholder *Placeholder `json:"placeholder,omitempty"` // Assistant Placeholder
|
||||||
Script *v8.Script `json:"-" yaml:"-"` // Assistant Script
|
Script *v8.Script `json:"-" yaml:"-"` // Assistant Script
|
||||||
CreatedAt int64 `json:"created_at"` // Creation timestamp
|
CreatedAt int64 `json:"created_at"` // Creation timestamp
|
||||||
UpdatedAt int64 `json:"updated_at"` // Last update timestamp
|
UpdatedAt int64 `json:"updated_at"` // Last update timestamp
|
||||||
|
|
@ -137,6 +138,13 @@ type Assistant struct {
|
||||||
initHook bool // Whether this assistant has an init hook
|
initHook bool // Whether this assistant has an init hook
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Placeholder the assistant placeholder
|
||||||
|
type Placeholder struct {
|
||||||
|
Title string `json:"title,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Prompts []string `json:"prompts,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// VisionCapableModels list of LLM models that support vision capabilities
|
// VisionCapableModels list of LLM models that support vision capabilities
|
||||||
var VisionCapableModels = map[string]bool{
|
var VisionCapableModels = map[string]bool{
|
||||||
// OpenAI Models
|
// OpenAI Models
|
||||||
|
|
|
||||||
|
|
@ -232,6 +232,7 @@ func (conv *Xun) initAssistantTable() error {
|
||||||
table.String("path", 200).Null() // assistant storage path
|
table.String("path", 200).Null() // assistant storage path
|
||||||
table.Integer("sort").SetDefault(9999).Index() // assistant sort order
|
table.Integer("sort").SetDefault(9999).Index() // assistant sort order
|
||||||
table.Boolean("built_in").SetDefault(false).Index() // whether this is a built-in assistant
|
table.Boolean("built_in").SetDefault(false).Index() // whether this is a built-in assistant
|
||||||
|
table.JSON("placeholder").Null() // assistant placeholder
|
||||||
table.JSON("options").Null() // assistant options
|
table.JSON("options").Null() // assistant options
|
||||||
table.JSON("prompts").Null() // assistant prompts
|
table.JSON("prompts").Null() // assistant prompts
|
||||||
table.JSON("flows").Null() // assistant flows
|
table.JSON("flows").Null() // assistant flows
|
||||||
|
|
@ -258,7 +259,7 @@ func (conv *Xun) initAssistantTable() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fields := []string{"id", "assistant_id", "type", "name", "avatar", "connector", "description", "path", "sort", "built_in", "options", "prompts", "flows", "files", "functions", "tags", "mentionable", "created_at", "updated_at"}
|
fields := []string{"id", "assistant_id", "type", "name", "avatar", "connector", "description", "path", "sort", "built_in", "placeholder", "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)
|
||||||
|
|
@ -766,7 +767,7 @@ func (conv *Xun) SaveAssistant(assistant map[string]interface{}) (interface{}, e
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process JSON fields
|
// Process JSON fields
|
||||||
jsonFields := []string{"tags", "options", "prompts", "flows", "files", "functions", "permissions"}
|
jsonFields := []string{"tags", "options", "prompts", "flows", "files", "functions", "permissions", "placeholder"}
|
||||||
for _, field := range jsonFields {
|
for _, field := range jsonFields {
|
||||||
if val, ok := assistantCopy[field]; ok && val != nil {
|
if val, ok := assistantCopy[field]; ok && val != nil {
|
||||||
// If it's a string, try to parse it first
|
// If it's a string, try to parse it first
|
||||||
|
|
@ -948,7 +949,7 @@ func (conv *Xun) GetAssistants(filter AssistantFilter) (*AssistantResponse, erro
|
||||||
|
|
||||||
// Convert rows to map slice and parse JSON fields
|
// Convert rows to map slice and parse JSON fields
|
||||||
data := make([]map[string]interface{}, len(rows))
|
data := make([]map[string]interface{}, len(rows))
|
||||||
jsonFields := []string{"tags", "options", "prompts", "flows", "files", "functions", "permissions"}
|
jsonFields := []string{"tags", "options", "prompts", "flows", "files", "functions", "permissions", "placeholder"}
|
||||||
for i, row := range rows {
|
for i, row := range rows {
|
||||||
data[i] = row
|
data[i] = row
|
||||||
// Only parse JSON fields if they are selected or no select filter is provided
|
// Only parse JSON fields if they are selected or no select filter is provided
|
||||||
|
|
@ -1002,7 +1003,7 @@ func (conv *Xun) GetAssistant(assistantID string) (map[string]interface{}, error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse JSON fields
|
// Parse JSON fields
|
||||||
jsonFields := []string{"tags", "options", "prompts", "flows", "files", "functions", "permissions"}
|
jsonFields := []string{"tags", "options", "prompts", "flows", "files", "functions", "permissions", "placeholder"}
|
||||||
conv.parseJSONFields(data, jsonFields)
|
conv.parseJSONFields(data, jsonFields)
|
||||||
|
|
||||||
return data, nil
|
return data, nil
|
||||||
|
|
|
||||||
|
|
@ -465,6 +465,7 @@ func TestXunAssistantCRUD(t *testing.T) {
|
||||||
// Test case 1: JSON fields as strings
|
// Test case 1: JSON fields as strings
|
||||||
tagsJSON := `["tag1", "tag2", "tag3"]`
|
tagsJSON := `["tag1", "tag2", "tag3"]`
|
||||||
optionsJSON := `{"model": "gpt-4"}`
|
optionsJSON := `{"model": "gpt-4"}`
|
||||||
|
placeholderJSON := `{"title": "Test Title", "description": "Test Description", "prompts": ["prompt1", "prompt2"]}`
|
||||||
assistant := map[string]interface{}{
|
assistant := map[string]interface{}{
|
||||||
"name": "Test Assistant",
|
"name": "Test Assistant",
|
||||||
"type": "assistant",
|
"type": "assistant",
|
||||||
|
|
@ -476,6 +477,7 @@ func TestXunAssistantCRUD(t *testing.T) {
|
||||||
"built_in": true,
|
"built_in": true,
|
||||||
"tags": tagsJSON,
|
"tags": tagsJSON,
|
||||||
"options": optionsJSON,
|
"options": optionsJSON,
|
||||||
|
"placeholder": placeholderJSON,
|
||||||
"mentionable": true,
|
"mentionable": true,
|
||||||
"automated": true,
|
"automated": true,
|
||||||
}
|
}
|
||||||
|
|
@ -500,6 +502,11 @@ func TestXunAssistantCRUD(t *testing.T) {
|
||||||
assert.Equal(t, int64(1), assistantData["built_in"])
|
assert.Equal(t, int64(1), assistantData["built_in"])
|
||||||
assert.Equal(t, []interface{}{"tag1", "tag2", "tag3"}, assistantData["tags"])
|
assert.Equal(t, []interface{}{"tag1", "tag2", "tag3"}, assistantData["tags"])
|
||||||
assert.Equal(t, map[string]interface{}{"model": "gpt-4"}, assistantData["options"])
|
assert.Equal(t, map[string]interface{}{"model": "gpt-4"}, assistantData["options"])
|
||||||
|
assert.Equal(t, map[string]interface{}{
|
||||||
|
"title": "Test Title",
|
||||||
|
"description": "Test Description",
|
||||||
|
"prompts": []interface{}{"prompt1", "prompt2"},
|
||||||
|
}, assistantData["placeholder"])
|
||||||
assert.Equal(t, int64(1), assistantData["mentionable"])
|
assert.Equal(t, int64(1), assistantData["mentionable"])
|
||||||
assert.Equal(t, int64(1), assistantData["automated"])
|
assert.Equal(t, int64(1), assistantData["automated"])
|
||||||
|
|
||||||
|
|
@ -520,6 +527,11 @@ func TestXunAssistantCRUD(t *testing.T) {
|
||||||
"files": []string{"file1", "file2"},
|
"files": []string{"file1", "file2"},
|
||||||
"functions": []map[string]interface{}{{"name": "func1"}, {"name": "func2"}},
|
"functions": []map[string]interface{}{{"name": "func1"}, {"name": "func2"}},
|
||||||
"permissions": map[string]interface{}{"read": true, "write": true},
|
"permissions": map[string]interface{}{"read": true, "write": true},
|
||||||
|
"placeholder": map[string]interface{}{
|
||||||
|
"title": "Test Title 2",
|
||||||
|
"description": "Test Description 2",
|
||||||
|
"prompts": []string{"prompt3", "prompt4"},
|
||||||
|
},
|
||||||
"mentionable": true,
|
"mentionable": true,
|
||||||
"automated": true,
|
"automated": true,
|
||||||
}
|
}
|
||||||
|
|
@ -545,6 +557,11 @@ func TestXunAssistantCRUD(t *testing.T) {
|
||||||
map[string]interface{}{"name": "func2"},
|
map[string]interface{}{"name": "func2"},
|
||||||
}, assistant2Data["functions"])
|
}, assistant2Data["functions"])
|
||||||
assert.Equal(t, map[string]interface{}{"read": true, "write": true}, assistant2Data["permissions"])
|
assert.Equal(t, map[string]interface{}{"read": true, "write": true}, assistant2Data["permissions"])
|
||||||
|
assert.Equal(t, map[string]interface{}{
|
||||||
|
"title": "Test Title 2",
|
||||||
|
"description": "Test Description 2",
|
||||||
|
"prompts": []interface{}{"prompt3", "prompt4"},
|
||||||
|
}, assistant2Data["placeholder"])
|
||||||
assert.Equal(t, int64(1), assistant2Data["mentionable"])
|
assert.Equal(t, int64(1), assistant2Data["mentionable"])
|
||||||
assert.Equal(t, int64(1), assistant2Data["automated"])
|
assert.Equal(t, int64(1), assistant2Data["automated"])
|
||||||
|
|
||||||
|
|
@ -564,6 +581,7 @@ func TestXunAssistantCRUD(t *testing.T) {
|
||||||
"files": nil,
|
"files": nil,
|
||||||
"functions": nil,
|
"functions": nil,
|
||||||
"permissions": nil,
|
"permissions": nil,
|
||||||
|
"placeholder": nil,
|
||||||
"mentionable": true,
|
"mentionable": true,
|
||||||
"automated": true,
|
"automated": true,
|
||||||
}
|
}
|
||||||
|
|
@ -586,6 +604,7 @@ func TestXunAssistantCRUD(t *testing.T) {
|
||||||
assert.Nil(t, assistant3Data["files"])
|
assert.Nil(t, assistant3Data["files"])
|
||||||
assert.Nil(t, assistant3Data["functions"])
|
assert.Nil(t, assistant3Data["functions"])
|
||||||
assert.Nil(t, assistant3Data["permissions"])
|
assert.Nil(t, assistant3Data["permissions"])
|
||||||
|
assert.Nil(t, assistant3Data["placeholder"])
|
||||||
assert.Equal(t, int64(1), assistant3Data["mentionable"])
|
assert.Equal(t, int64(1), assistant3Data["mentionable"])
|
||||||
assert.Equal(t, int64(1), assistant3Data["automated"])
|
assert.Equal(t, int64(1), assistant3Data["automated"])
|
||||||
|
|
||||||
|
|
@ -655,6 +674,7 @@ func TestXunAssistantCRUD(t *testing.T) {
|
||||||
assert.Nil(t, item["files"])
|
assert.Nil(t, item["files"])
|
||||||
assert.Nil(t, item["functions"])
|
assert.Nil(t, item["functions"])
|
||||||
assert.Nil(t, item["permissions"])
|
assert.Nil(t, item["permissions"])
|
||||||
|
assert.Nil(t, item["placeholder"])
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue