Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add transparent conversion for "tools" to "functions" in v1/chat/completions endpoint #1712

Closed
stippi2 opened this issue Feb 15, 2024 · 5 comments
Labels

Comments

@stippi2
Copy link
Contributor

stippi2 commented Feb 15, 2024

Is your feature request related to a problem? Please describe.

Yes. I got LocalAI running, both with Docker and building on my Mac. I tested with the Mistral model, but noticed that it didn't use functions. The reason is that 'functions' is actually already deprecated and there is now a 'tools' array instead. And my client is already using that.

Describe the solution you'd like
The tools array is a layer above functions. Each tool has a 'type', and the only supported type is 'function'. So if the type is function, there is a second field named function, which is then the Function object that used to be directly contained in the old functions array. So I imaging a simple conversion can be done, and I've actually tried to implement that:

diff --git a/api/schema/openai.go b/api/schema/openai.go
index 6355ff6..abf5dff 100644
--- a/api/schema/openai.go
+++ b/api/schema/openai.go
@@ -2,6 +2,7 @@ package schema
 
 import (
        "context"
+       "encoding/json"
 
        config "github.com/go-skynet/LocalAI/api/config"
 
@@ -114,8 +115,8 @@ type OpenAIRequest struct {
        Messages []Message `json:"messages" yaml:"messages"`
 
        // A list of available functions to call
-       Functions    []grammar.Function `json:"functions" yaml:"functions"`
-       FunctionCall interface{}        `json:"function_call" yaml:"function_call"` // might be a string or an object
+       Functions    []grammar.Function `json:"functions,omitempty" yaml:"functions"`
+       FunctionCall interface{}        `json:"function_call,omitempty" yaml:"function_call"` // might be a string or an object
 
        Stream bool `json:"stream"`
 
@@ -133,3 +134,34 @@ type OpenAIRequest struct {
        // AutoGPTQ
        ModelBaseName string `json:"model_base_name" yaml:"model_base_name"`
 }
+
+// UnmarshalJSON implements the json.Unmarshaler interface and maps "tools" and "tool_call" to "functions" and "function_call".
+func (r *OpenAIRequest) UnmarshalJSON(data []byte) error {
+       type Alias OpenAIRequest
+
+       // Define an auxiliary struct with additional fields to avoid infinite recursion when using the standard JSON unmarshalling.
+       var aux struct {
+               Alias
+               Tools    []grammar.Tool `json:"tools,omitempty" yaml:"tools"`
+               ToolCall interface{}    `json:"tool_call,omitempty" yaml:"tool_call"`
+       }
+
+       if err := json.Unmarshal(data, &aux); err != nil {
+               return err
+       }
+
+       // Copy the deserialized data back into the original request.
+       *r = OpenAIRequest(aux.Alias)
+
+       // Map "tools" and "tool_call".
+       if len(aux.Tools) > 0 {
+               for _, tool := range aux.Tools {
+                       r.Functions = append(r.Functions, tool.Function)
+               }
+       }
+       if aux.ToolCall != nil {
+               r.FunctionCall = aux.ToolCall
+       }
+
+       return nil
+}
diff --git a/pkg/grammar/tools.go b/pkg/grammar/tools.go
index ef56662..5b3e497 100644
--- a/pkg/grammar/tools.go
+++ b/pkg/grammar/tools.go
+ package grammar
+ 
+type Tool struct {
+       Type     string   `json:"type"`
+       Function Function `json:"function,omitempty"`
 }
+type Tools []Tool

... but it crashes. Unfortunately, I only get a 500 and a nil panic in the log, but not actually where it happens. With some guidance, maybe I can provide a PR.

@stippi2 stippi2 added the enhancement New feature or request label Feb 15, 2024
@mudler
Copy link
Owner

mudler commented Feb 15, 2024

Hey @stippi2 thanks for the heads up and the initial work!

To get more debugging informations you could comment out this line:

app.Use(recover.New())
(even if we should gate that with the --debug flag, currently it's not the case).

It will avoid the server to recovery so you should be able to see the full stack trace of the error

@mudler mudler added the roadmap label Feb 15, 2024
@stippi2
Copy link
Contributor Author

stippi2 commented Feb 15, 2024

Thanks for the hint!

@stippi2
Copy link
Contributor Author

stippi2 commented Feb 15, 2024

The panic is because at some point the ctx context.Context is nil. If I do not provide the custom UnmarshalJSON() method, that problem goes away.
I then tried to just convert my local version to support "tools" unconditionally, and later stumbled across the fact, that function calls are not supported in streaming mode. Turning off streaming mode would require a bunch more changes in my client, so I put this on hold for now.

@mudler
Copy link
Owner

mudler commented Feb 15, 2024

@stippi2 going to help here, see #1715 - still missing streaming support

@stippi2 stippi2 changed the title Add transparent convertion for "tools" to "functions" in v1/completions endpoint Add transparent conversion for "tools" to "functions" in v1/completions endpoint Feb 15, 2024
@stippi2 stippi2 changed the title Add transparent conversion for "tools" to "functions" in v1/completions endpoint Add transparent conversion for "tools" to "functions" in v1/chat/completions endpoint Feb 15, 2024
@mudler
Copy link
Owner

mudler commented Feb 19, 2024

closing as handled in #1715

@mudler mudler closed this as completed Feb 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants