diff --git a/api/types.go b/api/types.go index d84676297..83cb476c4 100644 --- a/api/types.go +++ b/api/types.go @@ -783,7 +783,7 @@ func (m *Metrics) Summary() { func (opts *Options) FromMap(m map[string]any) error { valueOpts := reflect.ValueOf(opts).Elem() // names of the fields in the options struct - typeOpts := reflect.TypeOf(opts).Elem() // types of the fields in the options struct + typeOpts := reflect.TypeFor[Options]() // types of the fields in the options struct // build map of json struct tags to their types jsonOpts := make(map[string]reflect.StructField) @@ -854,8 +854,7 @@ func (opts *Options) FromMap(m map[string]any) error { } field.Set(reflect.ValueOf(slice)) case reflect.Pointer: - var b bool - if field.Type() == reflect.TypeOf(&b) { + if field.Type() == reflect.TypeFor[*bool]() { val, ok := val.(bool) if !ok { return fmt.Errorf("option %q must be of type boolean", key) @@ -906,7 +905,7 @@ func DefaultOptions() Options { // ThinkValue represents a value that can be a boolean or a string ("high", "medium", "low") type ThinkValue struct { // Value can be a bool or string - Value interface{} + Value any } // IsValid checks if the ThinkValue is valid @@ -1055,7 +1054,7 @@ func (d *Duration) UnmarshalJSON(b []byte) (err error) { func FormatParams(params map[string][]string) (map[string]any, error) { opts := Options{} valueOpts := reflect.ValueOf(&opts).Elem() // names of the fields in the options struct - typeOpts := reflect.TypeOf(opts) // types of the fields in the options struct + typeOpts := reflect.TypeFor[Options]() // types of the fields in the options struct // build map of json struct tags to their types jsonOpts := make(map[string]reflect.StructField) @@ -1102,8 +1101,7 @@ func FormatParams(params map[string][]string) (map[string]any, error) { // TODO: only string slices are supported right now out[key] = vals case reflect.Pointer: - var b bool - if field.Type() == reflect.TypeOf(&b) { + if field.Type() == reflect.TypeFor[*bool]() { boolVal, err := strconv.ParseBool(vals[0]) if err != nil { return nil, fmt.Errorf("invalid bool value %s", vals) diff --git a/app/dialog/dlgs.go b/app/dialog/dlgs.go index 700f79fc4..fa99795e3 100644 --- a/app/dialog/dlgs.go +++ b/app/dialog/dlgs.go @@ -37,7 +37,7 @@ type MsgBuilder struct { } // Message initialises a MsgBuilder with the provided message. -func Message(format string, args ...interface{}) *MsgBuilder { +func Message(format string, args ...any) *MsgBuilder { return &MsgBuilder{Msg: fmt.Sprintf(format, args...)} } diff --git a/app/server/server_unix.go b/app/server/server_unix.go index 2c50716b2..8d365c1e5 100644 --- a/app/server/server_unix.go +++ b/app/server/server_unix.go @@ -67,8 +67,7 @@ func reapServers() error { return nil } - pids := strings.Split(pidsStr, "\n") - for _, pidStr := range pids { + for pidStr := range strings.SplitSeq(pidsStr, "\n") { pidStr = strings.TrimSpace(pidStr) if pidStr == "" { continue diff --git a/app/store/database_test.go b/app/store/database_test.go index 1b037a75d..36c7b3d6f 100644 --- a/app/store/database_test.go +++ b/app/store/database_test.go @@ -282,7 +282,7 @@ func countRows(t *testing.T, db *database, table string) int { return count } -func countRowsWithCondition(t *testing.T, db *database, table, condition string, args ...interface{}) int { +func countRowsWithCondition(t *testing.T, db *database, table, condition string, args ...any) int { t.Helper() var count int query := fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE %s", table, condition) @@ -296,7 +296,7 @@ func countRowsWithCondition(t *testing.T, db *database, table, condition string, // Test helpers for schema migration testing // schemaMap returns both tables/columns and indexes (ignoring order) -func schemaMap(db *database) map[string]interface{} { +func schemaMap(db *database) map[string]any { result := make(map[string]any) result["tables"] = columnMap(db) diff --git a/app/types/not/valids.go b/app/types/not/valids.go index d19894270..71e68817c 100644 --- a/app/types/not/valids.go +++ b/app/types/not/valids.go @@ -4,6 +4,7 @@ package not import ( "fmt" + "strings" ) type ValidError struct { @@ -44,12 +45,12 @@ func (b Valids) Error() string { return "" } - var result string + var sb strings.Builder for i, err := range b { if i > 0 { - result += "; " + sb.WriteString("; ") } - result += err.Error() + sb.WriteString(err.Error()) } - return result + return sb.String() } diff --git a/cmd/bench/bench.go b/cmd/bench/bench.go index 25df1817a..4fe35fbaa 100644 --- a/cmd/bench/bench.go +++ b/cmd/bench/bench.go @@ -149,7 +149,7 @@ func BenchmarkChat(fOpt flagOptions) error { for _, model := range models { for range *fOpt.epochs { - options := make(map[string]interface{}) + options := make(map[string]any) if *fOpt.maxTokens > 0 { options["num_predict"] = *fOpt.maxTokens } diff --git a/cmd/bench/bench_test.go b/cmd/bench/bench_test.go index bcd282d79..df57f7170 100644 --- a/cmd/bench/bench_test.go +++ b/cmd/bench/bench_test.go @@ -442,7 +442,7 @@ func TestReadImage_FileNotFound(t *testing.T) { func TestOptionsMapCreation(t *testing.T) { fOpt := createTestFlagOptions() - options := make(map[string]interface{}) + options := make(map[string]any) if *fOpt.maxTokens > 0 { options["num_predict"] = *fOpt.maxTokens } diff --git a/cmd/cmd.go b/cmd/cmd.go index a67299402..e12fbd8cb 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -11,6 +11,7 @@ import ( "fmt" "io" "log" + "maps" "math" "net" "net/http" @@ -1204,9 +1205,7 @@ func (r runOptions) Copy() runOptions { var opts map[string]any if r.Options != nil { opts = make(map[string]any, len(r.Options)) - for k, v := range r.Options { - opts[k] = v - } + maps.Copy(opts, r.Options) } var think *api.ThinkValue @@ -1952,13 +1951,13 @@ func inferThinkingOption(caps *[]model.Capability, runOpts *runOptions, explicit } func renderToolCalls(toolCalls []api.ToolCall, plainText bool) string { - out := "" + var sb strings.Builder formatExplanation := "" formatValues := "" if !plainText { formatExplanation = readline.ColorGrey + readline.ColorBold formatValues = readline.ColorDefault - out += formatExplanation + sb.WriteString(formatExplanation) } for i, toolCall := range toolCalls { argsAsJSON, err := json.Marshal(toolCall.Function.Arguments) @@ -1966,13 +1965,13 @@ func renderToolCalls(toolCalls []api.ToolCall, plainText bool) string { return "" } if i > 0 { - out += "\n" + sb.WriteString("\n") } // all tool calls are unexpected since we don't currently support registering any in the CLI - out += fmt.Sprintf(" Model called a non-existent function '%s()' with arguments: %s", formatValues+toolCall.Function.Name+formatExplanation, formatValues+string(argsAsJSON)+formatExplanation) + fmt.Fprintf(&sb, " Model called a non-existent function '%s()' with arguments: %s", formatValues+toolCall.Function.Name+formatExplanation, formatValues+string(argsAsJSON)+formatExplanation) } if !plainText { - out += readline.ColorDefault + sb.WriteString(readline.ColorDefault) } - return out + return sb.String() } diff --git a/cmd/cmd_test.go b/cmd/cmd_test.go index 1c9d19942..241f02b10 100644 --- a/cmd/cmd_test.go +++ b/cmd/cmd_test.go @@ -1322,8 +1322,8 @@ func TestRunOptions_Copy(t *testing.T) { // Test 2: Verify all fields are copied correctly tests := []struct { name string - got interface{} - want interface{} + got any + want any }{ {"Model", copied.Model, original.Model}, {"ParentModel", copied.ParentModel, original.ParentModel}, diff --git a/cmd/interactive.go b/cmd/interactive.go index cf0aced14..79f129ae0 100644 --- a/cmd/interactive.go +++ b/cmd/interactive.go @@ -410,7 +410,7 @@ func generateInteractive(cmd *cobra.Command, opts runOptions) error { if resp.Parameters == "" { fmt.Println(" No additional parameters were specified for this model.") } else { - for _, l := range strings.Split(resp.Parameters, "\n") { + for l := range strings.SplitSeq(resp.Parameters, "\n") { fmt.Printf(" %s\n", l) } } diff --git a/llm/server.go b/llm/server.go index 4eaa88df0..1eaccfe2d 100644 --- a/llm/server.go +++ b/llm/server.go @@ -846,14 +846,7 @@ nextOperation: func uniqueDeviceIDs(gpuLayers ml.GPULayersList) []ml.DeviceID { devices := []ml.DeviceID{} for _, layer := range gpuLayers { - new := true - for _, ID := range devices { - if layer.DeviceID == ID { - new = false - break - } - } - if new { + if !slices.Contains(devices, layer.DeviceID) { devices = append(devices, layer.DeviceID) } } @@ -1721,12 +1714,12 @@ func (s *llamaServer) Detokenize(ctx context.Context, tokens []int) (string, err return "", fmt.Errorf("no tokenizer configured") } - var resp string + var sb strings.Builder for _, token := range tokens { - resp += s.llamaModel.TokenToPiece(token) + sb.WriteString(s.llamaModel.TokenToPiece(token)) } - return resp, nil + return sb.String(), nil } func (s *ollamaServer) Detokenize(ctx context.Context, tokens []int) (string, error) { diff --git a/middleware/openai_encoding_format_test.go b/middleware/openai_encoding_format_test.go index 52107d6ef..d3797e1c1 100644 --- a/middleware/openai_encoding_format_test.go +++ b/middleware/openai_encoding_format_test.go @@ -68,7 +68,7 @@ func TestEmbeddingsMiddleware_EncodingFormats(t *testing.T) { switch tc.expectType { case "array": - if _, ok := result.Data[0].Embedding.([]interface{}); !ok { + if _, ok := result.Data[0].Embedding.([]any); !ok { t.Errorf("expected array, got %T", result.Data[0].Embedding) } case "string": diff --git a/ml/device.go b/ml/device.go index f06541275..0789b2969 100644 --- a/ml/device.go +++ b/ml/device.go @@ -414,14 +414,7 @@ func LibraryPaths(l []DeviceInfo) []string { gpuLibs := []string{LibOllamaPath} for _, gpu := range l { for _, dir := range gpu.LibraryPath { - needed := true - for _, existing := range gpuLibs { - if dir == existing { - needed = false - break - } - } - if needed { + if !slices.Contains(gpuLibs, dir) { gpuLibs = append(gpuLibs, dir) } } diff --git a/model/model.go b/model/model.go index 0af16da80..1e966b456 100644 --- a/model/model.go +++ b/model/model.go @@ -175,9 +175,10 @@ func populateFields(base Base, v reflect.Value, tags ...Tag) reflect.Value { tagsCopy = append(tagsCopy, parseTag(tag)) } - if tt == reflect.TypeOf((*Base)(nil)).Elem() { + switch { + case tt == reflect.TypeFor[Base](): vv.Set(reflect.ValueOf(base)) - } else if tt == reflect.TypeOf((*ml.Tensor)(nil)).Elem() { + case tt == reflect.TypeFor[ml.Tensor](): var fn func([]Tag, string, string) [][]string fn = func(tags []Tag, prefix, suffix string) (fullNames [][]string) { if len(tags) > 0 { @@ -217,9 +218,9 @@ func populateFields(base Base, v reflect.Value, tags ...Tag) reflect.Value { break } } - } else if tt.Kind() == reflect.Pointer || tt.Kind() == reflect.Interface { + case tt.Kind() == reflect.Pointer || tt.Kind() == reflect.Interface: setPointer(base, vv, tagsCopy) - } else if tt.Kind() == reflect.Slice || tt.Kind() == reflect.Array { + case tt.Kind() == reflect.Slice || tt.Kind() == reflect.Array: for i := range vv.Len() { vvv := vv.Index(i) if vvv.Kind() == reflect.Pointer || vvv.Kind() == reflect.Interface { diff --git a/model/sentencepiece.go b/model/sentencepiece.go index 2c178ec0c..4a1c3125c 100644 --- a/model/sentencepiece.go +++ b/model/sentencepiece.go @@ -205,12 +205,12 @@ func (q queue) Less(i, j int) bool { func (q queue) Swap(i, j int) { q[i], q[j] = q[j], q[i] } -func (q *queue) Push(x interface{}) { +func (q *queue) Push(x any) { item := x.(*candidate) *q = append(*q, item) } -func (q *queue) Pop() interface{} { +func (q *queue) Pop() any { old := *q n := len(old) item := old[n-1] diff --git a/openai/openai.go b/openai/openai.go index 4713d481b..ec6c351e6 100644 --- a/openai/openai.go +++ b/openai/openai.go @@ -487,19 +487,14 @@ func FromChatRequest(r ChatCompletionRequest) (*api.ChatRequest, error) { } } - types := []string{"jpeg", "jpg", "png", "webp"} - valid := false - // support blank mime type to match api/chat taking just unadorned base64 - if strings.HasPrefix(url, "data:;base64,") { - url = strings.TrimPrefix(url, "data:;base64,") - valid = true - } - for _, t := range types { - prefix := "data:image/" + t + ";base64," - if strings.HasPrefix(url, prefix) { - url = strings.TrimPrefix(url, prefix) - valid = true - break + url, valid := strings.CutPrefix(url, "data:;base64,") + if !valid { + for _, t := range []string{"jpeg", "jpg", "png", "webp"} { + prefix := "data:image/" + t + ";base64," + url, valid = strings.CutPrefix(url, prefix) + if valid { + break + } } } diff --git a/parser/parser.go b/parser/parser.go index 7d52c3387..3c260c3a3 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "io" + "maps" "net/http" "os" "os/user" @@ -78,9 +79,7 @@ func (f Modelfile) CreateRequest(relativeDir string) (*api.CreateRequest, error) if req.Files == nil { req.Files = digestMap } else { - for k, v := range digestMap { - req.Files[k] = v - } + maps.Copy(req.Files, digestMap) } case "adapter": path, err := expandPath(c.Args, relativeDir) diff --git a/readline/buffer.go b/readline/buffer.go index 52dc70526..25af4b9ae 100644 --- a/readline/buffer.go +++ b/readline/buffer.go @@ -3,6 +3,7 @@ package readline import ( "fmt" "os" + "strings" "github.com/emirpasic/gods/v2/lists/arraylist" "github.com/mattn/go-runewidth" @@ -515,13 +516,13 @@ func (b *Buffer) StringN(n int) string { } func (b *Buffer) StringNM(n, m int) string { - var s string + var sb strings.Builder if m == 0 { m = b.Buf.Size() } for cnt := n; cnt < m; cnt++ { c, _ := b.Buf.Get(cnt) - s += string(c) + sb.WriteRune(c) } - return s + return sb.String() } diff --git a/readline/readline.go b/readline/readline.go index 9252f3253..5e00ec24a 100644 --- a/readline/readline.go +++ b/readline/readline.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "os" + "strings" ) type Prompt struct { @@ -124,18 +125,18 @@ func (i *Instance) Readline() (string, error) { case KeyRight: buf.MoveRight() case CharBracketedPaste: - var code string + var code strings.Builder for range 3 { r, err = i.Terminal.Read() if err != nil { return "", io.EOF } - code += string(r) + code.WriteRune(r) } - if code == CharBracketedPasteStart { + if code.String() == CharBracketedPasteStart { i.Pasting = true - } else if code == CharBracketedPasteEnd { + } else if code.String() == CharBracketedPasteEnd { i.Pasting = false } case KeyDel: diff --git a/runner/common/logprob_test.go b/runner/common/logprob_test.go index c798f3f4b..9263651b3 100644 --- a/runner/common/logprob_test.go +++ b/runner/common/logprob_test.go @@ -459,10 +459,7 @@ func TestLogprobsWithStopSequences(t *testing.T) { origLogprobsLen := len(logprobs) numTokensRemoved := origLen - newLen - newLogprobsLen := origLogprobsLen - numTokensRemoved - if newLogprobsLen < 0 { - newLogprobsLen = 0 - } + newLogprobsLen := max(origLogprobsLen-numTokensRemoved, 0) logprobs = logprobs[:newLogprobsLen] // Verify responses were truncated correctly diff --git a/runner/llamarunner/runner.go b/runner/llamarunner/runner.go index a23ddd61a..c42da9b53 100644 --- a/runner/llamarunner/runner.go +++ b/runner/llamarunner/runner.go @@ -577,10 +577,7 @@ func (s *Server) processBatch(tokenBatch *llama.Batch, embedBatch *llama.Batch) if seq.logprobs { origLogprobsLen := len(seq.pendingLogprobs) numTokensRemoved := origLen - newLen - newLogprobsLen := origLogprobsLen - numTokensRemoved - if newLogprobsLen < 0 { - newLogprobsLen = 0 - } + newLogprobsLen := max(origLogprobsLen-numTokensRemoved, 0) seq.pendingLogprobs = seq.pendingLogprobs[:newLogprobsLen] } diff --git a/runner/ollamarunner/runner.go b/runner/ollamarunner/runner.go index 153390868..45804427e 100644 --- a/runner/ollamarunner/runner.go +++ b/runner/ollamarunner/runner.go @@ -801,10 +801,7 @@ func (s *Server) computeBatch(activeBatch batchState) { if seq.logprobs { origLogprobsLen := len(seq.pendingLogprobs) numTokensRemoved := origLen - newLen - newLogprobsLen := origLogprobsLen - numTokensRemoved - if newLogprobsLen < 0 { - newLogprobsLen = 0 - } + newLogprobsLen := max(origLogprobsLen-numTokensRemoved, 0) seq.pendingLogprobs = seq.pendingLogprobs[:newLogprobsLen] } diff --git a/server/auth.go b/server/auth.go index dcef5bf9c..51d370477 100644 --- a/server/auth.go +++ b/server/auth.go @@ -33,7 +33,7 @@ func (r registryChallenge) URL() (*url.URL, error) { values := redirectURL.Query() values.Add("service", r.Service) - for _, s := range strings.Split(r.Scope, " ") { + for s := range strings.SplitSeq(r.Scope, " ") { values.Add("scope", s) } @@ -57,7 +57,7 @@ func getAuthorizationToken(ctx context.Context, challenge registryChallenge) (st } sha256sum := sha256.Sum256(nil) - data := []byte(fmt.Sprintf("%s,%s,%s", http.MethodGet, redirectURL.String(), base64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(sha256sum[:]))))) + data := fmt.Appendf(nil, "%s,%s,%s", http.MethodGet, redirectURL.String(), base64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(sha256sum[:])))) headers := make(http.Header) signature, err := auth.Sign(ctx, data) diff --git a/server/internal/cache/blob/casecheck_test.go b/server/internal/cache/blob/casecheck_test.go index 5895d2cb6..2371bc523 100644 --- a/server/internal/cache/blob/casecheck_test.go +++ b/server/internal/cache/blob/casecheck_test.go @@ -84,8 +84,7 @@ func useCaseInsensitiveTempDir(t *testing.T) bool { // TODO(bmizerany): Print platform-specific instructions or // link to docs on that topic. - lines := strings.Split(volumeHint, "\n") - for _, line := range lines { + for line := range strings.SplitSeq(volumeHint, "\n") { t.Skip(line) } } diff --git a/server/internal/internal/names/name_test.go b/server/internal/internal/names/name_test.go index e3dc5fe3c..c68ad5d4c 100644 --- a/server/internal/internal/names/name_test.go +++ b/server/internal/internal/names/name_test.go @@ -142,7 +142,7 @@ var junkName Name func BenchmarkParseName(b *testing.B) { b.ReportAllocs() - for range b.N { + for b.Loop() { junkName = Parse("h/n/m:t") } } diff --git a/server/internal/registry/server.go b/server/internal/registry/server.go index f62a622a9..58517db75 100644 --- a/server/internal/registry/server.go +++ b/server/internal/registry/server.go @@ -251,7 +251,7 @@ func (s *Local) handleDelete(_ http.ResponseWriter, r *http.Request) error { type progressUpdateJSON struct { Error string `json:"error,omitempty,omitzero"` Status string `json:"status,omitempty,omitzero"` - Digest blob.Digest `json:"digest,omitempty,omitzero"` + Digest blob.Digest `json:"digest,omitzero"` Total int64 `json:"total,omitempty,omitzero"` Completed int64 `json:"completed,omitempty,omitzero"` } diff --git a/server/prompt.go b/server/prompt.go index 217591982..8b89454d5 100644 --- a/server/prompt.go +++ b/server/prompt.go @@ -74,7 +74,7 @@ func chatPrompt(ctx context.Context, m *Model, tokenize tokenizeFunc, opts *api. return "", nil, errors.New("this model only supports one image while more than one image requested") } - var prefix string + var prefix strings.Builder prompt := msg.Content for _, i := range msg.Images { @@ -85,14 +85,14 @@ func chatPrompt(ctx context.Context, m *Model, tokenize tokenizeFunc, opts *api. imgTag := fmt.Sprintf("[img-%d]", imgData.ID) if !strings.Contains(prompt, "[img]") { - prefix += imgTag + prefix.WriteString(imgTag) } else { prompt = strings.Replace(prompt, "[img]", imgTag, 1) } images = append(images, imgData) } - msgs[currMsgIdx+cnt].Content = prefix + prompt + msgs[currMsgIdx+cnt].Content = prefix.String() + prompt } // truncate any messages that do not fit into the context window diff --git a/server/routes.go b/server/routes.go index 16df3f4fc..0b659736a 100644 --- a/server/routes.go +++ b/server/routes.go @@ -12,6 +12,7 @@ import ( "io" "io/fs" "log/slog" + "maps" "math" "math/rand" "net" @@ -1139,9 +1140,7 @@ func GetModelInfo(req api.ShowRequest) (*api.ShowResponse, error) { if m.Options == nil { m.Options = make(map[string]any) } - for k, v := range req.Options { - m.Options[k] = v - } + maps.Copy(m.Options, req.Options) } var sb strings.Builder diff --git a/server/routes_generate_test.go b/server/routes_generate_test.go index a9931ea24..0a84267ff 100644 --- a/server/routes_generate_test.go +++ b/server/routes_generate_test.go @@ -41,7 +41,7 @@ func (m *mockRunner) Completion(ctx context.Context, r llm.CompletionRequest, fn } func (mockRunner) Tokenize(_ context.Context, s string) (tokens []int, err error) { - for range strings.Fields(s) { + for range strings.FieldsSeq(s) { tokens = append(tokens, len(tokens)) } diff --git a/server/routes_test.go b/server/routes_test.go index bb7e2b7c1..ae5aed36c 100644 --- a/server/routes_test.go +++ b/server/routes_test.go @@ -432,8 +432,7 @@ func TestRoutes(t *testing.T) { } var params []string - paramsSplit := strings.Split(showResp.Parameters, "\n") - for _, p := range paramsSplit { + for p := range strings.SplitSeq(showResp.Parameters, "\n") { params = append(params, strings.Join(strings.Fields(p), " ")) } sort.Strings(params) diff --git a/tools/tools.go b/tools/tools.go index 7b8d726b0..bcddc6fd7 100644 --- a/tools/tools.go +++ b/tools/tools.go @@ -274,7 +274,7 @@ func findArguments(tool *api.Tool, buffer []byte) (map[string]any, int) { return args, true } if argsStr, ok := obj[name].(string); ok { - var argsData map[string]interface{} + var argsData map[string]any if err := json.Unmarshal([]byte(argsStr), &argsData); err == nil { return argsData, ok }