Refactor toolbox and function handling to support synthetic fields and improve type definitions
This commit is contained in:
65
function.go
65
function.go
@@ -4,11 +4,10 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/sashabaranov/go-openai"
|
||||
|
||||
"gitea.stevedudenhoeffer.com/steve/go-llm/schema"
|
||||
)
|
||||
|
||||
@@ -29,16 +28,63 @@ type Function struct {
|
||||
paramType reflect.Type
|
||||
}
|
||||
|
||||
func (f *Function) Execute(ctx *Context, input string) (any, error) {
|
||||
func (f Function) WithSyntheticField(name string, description string) Function {
|
||||
if obj, o := f.Parameters.(schema.Object); o {
|
||||
f.Parameters = obj.WithSyntheticField(name, description)
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (f Function) WithSyntheticFields(fieldsAndDescriptions map[string]string) Function {
|
||||
if obj, o := f.Parameters.(schema.Object); o {
|
||||
for k, v := range fieldsAndDescriptions {
|
||||
obj = obj.WithSyntheticField(k, v)
|
||||
}
|
||||
f.Parameters = obj
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (f Function) Execute(ctx *Context, input string) (any, error) {
|
||||
if !f.fn.IsValid() {
|
||||
return "", fmt.Errorf("function %s is not implemented", f.Name)
|
||||
}
|
||||
|
||||
slog.Info("Function.Execute", "name", f.Name, "input", input, "f", f.paramType)
|
||||
// first, we need to parse the input into the struct
|
||||
p := reflect.New(f.paramType)
|
||||
fmt.Println("Function.Execute", f.Name, "input:", input)
|
||||
//m := map[string]any{}
|
||||
err := json.Unmarshal([]byte(input), p.Interface())
|
||||
|
||||
var vals map[string]any
|
||||
err := json.Unmarshal([]byte(input), &vals)
|
||||
|
||||
var syntheticFields map[string]string
|
||||
|
||||
// first eat up any synthetic fields
|
||||
if obj, o := f.Parameters.(schema.Object); o {
|
||||
for k := range obj.SyntheticFields() {
|
||||
key := schema.SyntheticFieldPrefix + k
|
||||
if val, ok := vals[key]; ok {
|
||||
if syntheticFields == nil {
|
||||
syntheticFields = map[string]string{}
|
||||
}
|
||||
|
||||
syntheticFields[k] = fmt.Sprint(val)
|
||||
delete(vals, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now for any remaining fields, re-marshal them into json and then unmarshal into the struct
|
||||
b, err := json.Marshal(vals)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to marshal input: %w (input: %s)", err, input)
|
||||
}
|
||||
|
||||
// now we can unmarshal the input into the struct
|
||||
err = json.Unmarshal(b, p.Interface())
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to unmarshal input: %w (input: %s)", err, input)
|
||||
}
|
||||
@@ -67,15 +113,6 @@ func (f *Function) Execute(ctx *Context, input string) (any, error) {
|
||||
return exec(ctx)
|
||||
}
|
||||
|
||||
func (f *Function) toOpenAIFunction() *openai.FunctionDefinition {
|
||||
return &openai.FunctionDefinition{
|
||||
Name: f.Name,
|
||||
Description: f.Description,
|
||||
Strict: f.Strict,
|
||||
Parameters: f.Parameters,
|
||||
}
|
||||
}
|
||||
|
||||
type FunctionCall struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Arguments string `json:"arguments,omitempty"`
|
||||
|
Reference in New Issue
Block a user