Merge pull request #864 from trheyi/main
Refactor tool call prompts and message handling
This commit is contained in:
commit
6d1a118236
3 changed files with 134 additions and 47 deletions
|
|
@ -561,7 +561,7 @@ func (ast *Assistant) saveChatHistory(ctx chatctx.Context, messages []chatMessag
|
||||||
{
|
{
|
||||||
"role": "assistant",
|
"role": "assistant",
|
||||||
"content": contents.JSON(),
|
"content": contents.JSON(),
|
||||||
"name": ctx.Sid,
|
"name": ast.ID,
|
||||||
"assistant_id": ast.ID,
|
"assistant_id": ast.ID,
|
||||||
"assistant_name": ast.Name,
|
"assistant_name": ast.Name,
|
||||||
"assistant_avatar": ast.Avatar,
|
"assistant_avatar": ast.Avatar,
|
||||||
|
|
@ -605,7 +605,7 @@ func (ast *Assistant) withOptions(options map[string]interface{}) map[string]int
|
||||||
func (ast *Assistant) withPrompts(messages []chatMessage.Message) []chatMessage.Message {
|
func (ast *Assistant) withPrompts(messages []chatMessage.Message) []chatMessage.Message {
|
||||||
if ast.Prompts != nil {
|
if ast.Prompts != nil {
|
||||||
for _, prompt := range ast.Prompts {
|
for _, prompt := range ast.Prompts {
|
||||||
name := ast.Name
|
name := strings.ReplaceAll(ast.ID, ".", "_") // OpenAI only supports underscore in the name
|
||||||
if prompt.Name != "" {
|
if prompt.Name != "" {
|
||||||
name = prompt.Name
|
name = prompt.Name
|
||||||
}
|
}
|
||||||
|
|
@ -618,43 +618,61 @@ func (ast *Assistant) withPrompts(messages []chatMessage.Message) []chatMessage.
|
||||||
settings, has := connectorSettings[ast.Connector]
|
settings, has := connectorSettings[ast.Connector]
|
||||||
if !has || !settings.Tools {
|
if !has || !settings.Tools {
|
||||||
raw, _ := jsoniter.MarshalToString(ast.Tools.Tools)
|
raw, _ := jsoniter.MarshalToString(ast.Tools.Tools)
|
||||||
messages = append(messages, *chatMessage.New().Map(map[string]interface{}{
|
|
||||||
"role": "system",
|
|
||||||
"name": "TOOL_CALLS_SCHEMA",
|
|
||||||
"content": raw,
|
|
||||||
}))
|
|
||||||
|
|
||||||
messages = append(messages, *chatMessage.New().Map(map[string]interface{}{
|
examples := []string{}
|
||||||
"role": "system",
|
for _, tool := range ast.Tools.Tools {
|
||||||
"name": "TOOL_CALLS",
|
example := tool.Example()
|
||||||
"content": "## Tool Response Format\n" +
|
examples = append(examples, example)
|
||||||
"1. If no matching function exists in TOOL_CALLS_SCHEMA, respond normally without using tool calls\n" +
|
}
|
||||||
"2. When using tools, wrap function calls in <tool> and </tool> tags\n" +
|
|
||||||
"3. The tool call must be a valid JSON object\n" +
|
|
||||||
"4. Follow the JSON Schema defined in TOOL_CALLS_SCHEMA\n" +
|
|
||||||
"5. One complete tool call per response\n" +
|
|
||||||
"6. Parameter values MUST strictly follow the descriptions and validation rules defined in properties\n" +
|
|
||||||
"7. For each parameter, carefully check and comply with:\n" +
|
|
||||||
" - Data type requirements\n" +
|
|
||||||
" - Format restrictions\n" +
|
|
||||||
" - Value range limitations\n" +
|
|
||||||
" - Pattern matching rules\n" +
|
|
||||||
" - Required field validations\n\n" +
|
|
||||||
"Example:\n" +
|
|
||||||
"<tool>\n" + `{"function":"<FunctionName>","arguments":{"<ArgumentName>":"<ArgumentValue>"}}` + "\n</tool>",
|
|
||||||
}))
|
|
||||||
messages = append(messages, *chatMessage.New().Map(map[string]interface{}{
|
|
||||||
"role": "system",
|
|
||||||
"name": "TOOL_CALLS",
|
|
||||||
"content": "## Tool Usage Guidelines\n" +
|
|
||||||
"1. Use functions defined in TOOL_CALLS_SCHEMA only when they match your needs\n" +
|
|
||||||
"2. If no matching function exists, respond normally as a helpful assistant\n" +
|
|
||||||
"3. When using tools, arguments must match the schema definition exactly\n" +
|
|
||||||
"4. All parameter values must strictly adhere to the validation rules specified in properties\n" +
|
|
||||||
"5. Never skip or ignore any validation requirements defined in the schema",
|
|
||||||
}))
|
|
||||||
|
|
||||||
// Add tool_calls prompts
|
examplesStr := ""
|
||||||
|
if len(examples) > 0 {
|
||||||
|
examplesStr = "Examples:\n" + strings.Join(examples, "\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
prompts := []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"name": "TOOL_CALLS_SCHEMA",
|
||||||
|
"content": raw,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"name": "TOOL_CALLS_SCHEMA",
|
||||||
|
"content": "## Tool Calls Schema Definition\n" +
|
||||||
|
"Each tool call is defined with:\n" +
|
||||||
|
" - type: always 'function'\n" +
|
||||||
|
" - function:\n" +
|
||||||
|
" - name: function name\n" +
|
||||||
|
" - description: function description\n" +
|
||||||
|
" - parameters: function parameters with type and validation rules\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"name": "TOOL_CALLS",
|
||||||
|
"content": "## Tool Response Format\n" +
|
||||||
|
"1. Only use tool calls when a function matches your task exactly\n" +
|
||||||
|
"2. Each tool call must be wrapped in <tool> and </tool> tags\n" +
|
||||||
|
"3. Tool call must be a valid JSON with:\n" +
|
||||||
|
" {\"function\": \"function_name\", \"arguments\": {parameters}}\n" +
|
||||||
|
"4. Return the function's result as your response\n" +
|
||||||
|
"5. One tool call per response\n" +
|
||||||
|
"6. Arguments must match parameter types, rules and description\n\n" +
|
||||||
|
examplesStr,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"name": "TOOL_CALLS",
|
||||||
|
"content": "## Tool Usage Guidelines\n" +
|
||||||
|
"1. Use functions defined in TOOL_CALLS_SCHEMA only when they match your needs\n" +
|
||||||
|
"2. If no matching function exists, respond normally as a helpful assistant\n" +
|
||||||
|
"3. When using tools, arguments must match the schema definition exactly\n" +
|
||||||
|
"4. All parameter values must strictly adhere to the validation rules specified in properties\n" +
|
||||||
|
"5. Never skip or ignore any validation requirements defined in the schema",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add tool_calls developer prompts
|
||||||
if ast.Tools.Prompts != nil && len(ast.Tools.Prompts) > 0 {
|
if ast.Tools.Prompts != nil && len(ast.Tools.Prompts) > 0 {
|
||||||
for _, prompt := range ast.Tools.Prompts {
|
for _, prompt := range ast.Tools.Prompts {
|
||||||
messages = append(messages, *chatMessage.New().Map(map[string]interface{}{
|
messages = append(messages, *chatMessage.New().Map(map[string]interface{}{
|
||||||
|
|
@ -664,6 +682,12 @@ func (ast *Assistant) withPrompts(messages []chatMessage.Message) []chatMessage.
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the prompts
|
||||||
|
for _, prompt := range prompts {
|
||||||
|
messages = append(messages, *chatMessage.New().Map(prompt))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
73
neo/assistant/tool.go
Normal file
73
neo/assistant/tool.go
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
package assistant
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
jsoniter "github.com/json-iterator/go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tool represents a tool
|
||||||
|
type Tool struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Function struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Parameters Parameter `json:"parameters"`
|
||||||
|
Strict bool `json:"strict,omitempty"`
|
||||||
|
} `json:"function"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SchemaProperty represents a JSON Schema property
|
||||||
|
type SchemaProperty struct {
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parameter represents the parameters field in function calling format
|
||||||
|
type Parameter struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Properties map[string]SchemaProperty `json:"properties,omitempty"`
|
||||||
|
Required []string `json:"required,omitempty"`
|
||||||
|
AdditionalProperties bool `json:"additionalProperties"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example returns a formatted example of how to use this tool
|
||||||
|
func (tool Tool) Example() string {
|
||||||
|
return fmt.Sprintf("<tool>\n{\"function\":\"%s\",\"arguments\":%s}\n</tool>",
|
||||||
|
tool.Function.Name,
|
||||||
|
jsoniter.Wrap(tool.ExampleArguments()).ToString())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExampleArguments generates example arguments for the tool based on parameter types
|
||||||
|
func (tool Tool) ExampleArguments() map[string]interface{} {
|
||||||
|
|
||||||
|
args := map[string]interface{}{}
|
||||||
|
|
||||||
|
// Handle the root parameter object
|
||||||
|
if tool.Function.Parameters.Type == "object" && tool.Function.Parameters.Properties != nil {
|
||||||
|
for name, prop := range tool.Function.Parameters.Properties {
|
||||||
|
args[name] = generateExampleValue(name, prop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateExampleValue creates an example value for a parameter
|
||||||
|
func generateExampleValue(name string, prop SchemaProperty) interface{} {
|
||||||
|
switch prop.Type {
|
||||||
|
case "string":
|
||||||
|
return fmt.Sprintf("<%s:string>", name)
|
||||||
|
case "number":
|
||||||
|
return fmt.Sprintf("<%s:number>", name)
|
||||||
|
case "integer":
|
||||||
|
return fmt.Sprintf("<%s:integer>", name)
|
||||||
|
case "boolean":
|
||||||
|
return fmt.Sprintf("<%s:boolean>", name)
|
||||||
|
case "object":
|
||||||
|
return fmt.Sprintf("<%s:object>", name)
|
||||||
|
case "array":
|
||||||
|
return fmt.Sprintf("<%s:array>", name)
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("<%s>", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -94,16 +94,6 @@ type Prompt struct {
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tool represents a tool
|
|
||||||
type Tool struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
Function struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Parameters map[string]interface{} `json:"parameters"`
|
|
||||||
} `json:"function"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryParam the assistant query param
|
// QueryParam the assistant query param
|
||||||
type QueryParam struct {
|
type QueryParam struct {
|
||||||
Limit uint `json:"limit"`
|
Limit uint `json:"limit"`
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue