From e9f89a0b2902f40caf3edcce9a5ee8f8331ab140 Mon Sep 17 00:00:00 2001 From: Rhett Garber Date: Thu, 17 Aug 2023 21:19:00 +0000 Subject: [PATCH 1/2] Add support for function calling As described in https://platform.openai.com/docs/guides/gpt/function-calling some models have been fine tuned to call functions based on their JSON representations. --- chat/chat.go | 10 +++++++--- chat/function.go | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 chat/function.go diff --git a/chat/chat.go b/chat/chat.go index ad8a2f3..ecf3373 100644 --- a/chat/chat.go +++ b/chat/chat.go @@ -42,6 +42,9 @@ type CreateCompletionParams struct { Stop []string `json:"stop,omitempty"` Stream bool `json:"stream,omitempty"` + Functions []Function `json:"functions,omitempty"` + FunctionCall string `json:"function_call,omitempty"` + N int `json:"n,omitempty"` TopP float64 `json:"top_p,omitempty"` Temperature float64 `json:"temperature,omitempty"` @@ -70,9 +73,10 @@ type Choice struct { } type Message struct { - Role string `json:"role,omitempty"` - Content string `json:"content,omitempty"` - Name string `json:"name,omitempty"` + Role string `json:"role,omitempty"` + Content string `json:"content,omitempty"` + Name string `json:"name,omitempty"` + FunctionCall *FunctionCall `json:"function_call,omitempty"` } func (c *Client) CreateCompletion(ctx context.Context, p *CreateCompletionParams) (*CreateCompletionResponse, error) { diff --git a/chat/function.go b/chat/function.go new file mode 100644 index 0000000..d95499e --- /dev/null +++ b/chat/function.go @@ -0,0 +1,41 @@ +package chat + +// EmptyParameters is an empty parameter object used for a Function that accepts no arguments. +var EmptyParameters = Schema{ + Type: "object", + Properties: map[string]Schema{}, +} + +const ( + // FunctionCallAuto indicates the model should decide whether to call the function. + // This is default when Functions are provided. + FunctionCallAuto = "auto" + + // FunctionCallNone indicates the mode should not call any functions. + // This is the default when no Functions are provided. + FunctionCallNone = "none" +) + +// Schema defines a schema for a JSON object. +// +// See https://json-schema.org/understanding-json-schema/ +type Schema struct { + Type string `json:"type"` + Description string `json:"description,omitempty"` + Properties map[string]Schema `json:"properties,omitempty"` + Required []string `json:"required,omitempty"` +} + +// Function is a function the model may generate JSON inputs for +type Function struct { + Name string `json:"name"` + Description string `json:"description,omitempty"` + Parameters Schema `json:"parameters"` +} + +// FunctionCall is the name and arguments of a function that should be called, +// as generated by the model. +type FunctionCall struct { + Name string `json:"name"` + Arguments string `json:"arguments"` +} From fec2047620a29eb836430a6e383639be72768948 Mon Sep 17 00:00:00 2001 From: Rhett Garber Date: Thu, 17 Aug 2023 22:33:20 +0000 Subject: [PATCH 2/2] Support empty parameter objects To indicate an empty parameter, the properties must be emitted as `{}`. But we also need a nil properties field to not be emitted at all. This is not handled by `omitempty` because it treats nil and empty as the same. --- chat/function.go | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/chat/function.go b/chat/function.go index d95499e..3c4cc45 100644 --- a/chat/function.go +++ b/chat/function.go @@ -1,5 +1,7 @@ package chat +import "encoding/json" + // EmptyParameters is an empty parameter object used for a Function that accepts no arguments. var EmptyParameters = Schema{ Type: "object", @@ -22,8 +24,32 @@ const ( type Schema struct { Type string `json:"type"` Description string `json:"description,omitempty"` - Properties map[string]Schema `json:"properties,omitempty"` + Properties map[string]Schema `json:"properties"` Required []string `json:"required,omitempty"` + + // NOTE adding new fields may require updating the MarshalJSON method. +} + +func (s Schema) MarshalJSON() ([]byte, error) { + type Alias Schema + + // If Properties is nil marshal it without the Properties field. This, + // rather than relying on omitempty, allows us to distinguish between an + // empty map (which is needed for valid API requests) and a nil map (which + // is needed for the default value). + if s.Properties == nil { + return json.Marshal(&struct { + Type string `json:"type"` + Description string `json:"description,omitempty"` + Required []string `json:"required,omitempty"` + }{ + Type: s.Type, + Description: s.Description, + Required: s.Required, + }) + } + + return json.Marshal((*Alias)(&s)) } // Function is a function the model may generate JSON inputs for