From 2c8b4846437747bd23e7a176f83011e39ec2128b Mon Sep 17 00:00:00 2001 From: Patrick Devine Date: Sat, 15 Mar 2025 12:09:02 -0700 Subject: [PATCH] fix: correctly save in interactive mode (#9788) This fixes the case where a FROM line in previous modelfile points to a file which may/may not be present in a different ollama instance. We shouldn't be relying on the filename though and instead just check if the FROM line was instead a valid model name and point to that instead. --- cmd/cmd_test.go | 129 +++++++++++++++++++++++++++++++++++++++++++++ cmd/interactive.go | 12 ++++- 2 files changed, 139 insertions(+), 2 deletions(-) diff --git a/cmd/cmd_test.go b/cmd/cmd_test.go index f21a8f50b..41b03e1bd 100644 --- a/cmd/cmd_test.go +++ b/cmd/cmd_test.go @@ -757,3 +757,132 @@ func TestCreateHandler(t *testing.T) { }) } } + +func TestNewCreateRequest(t *testing.T) { + tests := []struct { + name string + from string + opts runOptions + expected *api.CreateRequest + }{ + { + "basic test", + "newmodel", + runOptions{ + Model: "mymodel", + ParentModel: "", + Prompt: "You are a fun AI agent", + Messages: []api.Message{}, + WordWrap: true, + }, + &api.CreateRequest{ + From: "mymodel", + Model: "newmodel", + }, + }, + { + "parent model test", + "newmodel", + runOptions{ + Model: "mymodel", + ParentModel: "parentmodel", + Messages: []api.Message{}, + WordWrap: true, + }, + &api.CreateRequest{ + From: "parentmodel", + Model: "newmodel", + }, + }, + { + "parent model as filepath test", + "newmodel", + runOptions{ + Model: "mymodel", + ParentModel: "/some/file/like/etc/passwd", + Messages: []api.Message{}, + WordWrap: true, + }, + &api.CreateRequest{ + From: "mymodel", + Model: "newmodel", + }, + }, + { + "parent model as windows filepath test", + "newmodel", + runOptions{ + Model: "mymodel", + ParentModel: "D:\\some\\file\\like\\etc\\passwd", + Messages: []api.Message{}, + WordWrap: true, + }, + &api.CreateRequest{ + From: "mymodel", + Model: "newmodel", + }, + }, + { + "options test", + "newmodel", + runOptions{ + Model: "mymodel", + ParentModel: "parentmodel", + Options: map[string]any{ + "temperature": 1.0, + }, + }, + &api.CreateRequest{ + From: "parentmodel", + Model: "newmodel", + Parameters: map[string]any{ + "temperature": 1.0, + }, + }, + }, + { + "messages test", + "newmodel", + runOptions{ + Model: "mymodel", + ParentModel: "parentmodel", + System: "You are a fun AI agent", + Messages: []api.Message{ + { + Role: "user", + Content: "hello there!", + }, + { + Role: "assistant", + Content: "hello to you!", + }, + }, + WordWrap: true, + }, + &api.CreateRequest{ + From: "parentmodel", + Model: "newmodel", + System: "You are a fun AI agent", + Messages: []api.Message{ + { + Role: "user", + Content: "hello there!", + }, + { + Role: "assistant", + Content: "hello to you!", + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual := NewCreateRequest(tt.from, tt.opts) + if !cmp.Equal(actual, tt.expected) { + t.Errorf("expected output %#v, got %#v", tt.expected, actual) + } + }) + } +} diff --git a/cmd/interactive.go b/cmd/interactive.go index f3489b652..d85510d45 100644 --- a/cmd/interactive.go +++ b/cmd/interactive.go @@ -18,6 +18,7 @@ import ( "github.com/ollama/ollama/envconfig" "github.com/ollama/ollama/readline" "github.com/ollama/ollama/types/errtypes" + "github.com/ollama/ollama/types/model" ) type MultilineState int @@ -459,9 +460,16 @@ func generateInteractive(cmd *cobra.Command, opts runOptions) error { } func NewCreateRequest(name string, opts runOptions) *api.CreateRequest { + parentModel := opts.ParentModel + + modelName := model.ParseName(parentModel) + if !modelName.IsValid() { + parentModel = "" + } + req := &api.CreateRequest{ - Name: name, - From: cmp.Or(opts.ParentModel, opts.Model), + Model: name, + From: cmp.Or(parentModel, opts.Model), } if opts.System != "" {