package go_llm import ( "context" "encoding/json" "fmt" "gitea.stevedudenhoeffer.com/steve/go-llm/schema" "github.com/sashabaranov/go-openai" "github.com/sashabaranov/go-openai/jsonschema" "reflect" "time" ) type Function struct { Name string `json:"name"` Description string `json:"description,omitempty"` Strict bool `json:"strict,omitempty"` Parameters schema.Type `json:"parameters"` Forced bool `json:"forced,omitempty"` // Timeout is the maximum time to wait for the function to complete Timeout time.Duration `json:"-"` // fn is the function to call, only set if this is constructed with NewFunction fn reflect.Value paramType reflect.Type // definition is a cache of the openaiImpl jsonschema definition definition *jsonschema.Definition } func (f *Function) Execute(ctx context.Context, input string) (string, error) { if !f.fn.IsValid() { return "", fmt.Errorf("function %s is not implemented", f.Name) } // first, we need to parse the input into the struct p := reflect.New(f.paramType).Elem() //m := map[string]any{} err := json.Unmarshal([]byte(input), p.Addr().Interface()) if err != nil { return "", fmt.Errorf("failed to unmarshal input: %w", err) } // now we can call the function exec := func(ctx context.Context) (string, error) { out := f.fn.Call([]reflect.Value{reflect.ValueOf(ctx), p}) if len(out) != 2 { return "", fmt.Errorf("function %s must return two values, got %d", f.Name, len(out)) } if out[1].IsNil() { return out[0].String(), nil } return "", out[1].Interface().(error) } var cancel context.CancelFunc if f.Timeout > 0 { ctx, cancel = context.WithTimeout(ctx, f.Timeout) defer cancel() } return exec(ctx) } func (f *Function) toOpenAIFunction() *openai.FunctionDefinition { return &openai.FunctionDefinition{ Name: f.Name, Description: f.Description, Strict: f.Strict, Parameters: f.Parameters, } } func (f *Function) toOpenAIDefinition() jsonschema.Definition { if f.definition == nil { def := f.Parameters.Definition() f.definition = &def } return *f.definition } type FunctionCall struct { Name string `json:"name,omitempty"` Arguments any `json:"arguments,omitempty"` }