modernize

This commit is contained in:
Michael Yang 2025-11-16 12:49:48 -08:00
parent d70e935526
commit efd9f5e67e
31 changed files with 75 additions and 107 deletions

View File

@ -783,7 +783,7 @@ func (m *Metrics) Summary() {
func (opts *Options) FromMap(m map[string]any) error { func (opts *Options) FromMap(m map[string]any) error {
valueOpts := reflect.ValueOf(opts).Elem() // names of the fields in the options struct 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 // build map of json struct tags to their types
jsonOpts := make(map[string]reflect.StructField) jsonOpts := make(map[string]reflect.StructField)
@ -854,8 +854,7 @@ func (opts *Options) FromMap(m map[string]any) error {
} }
field.Set(reflect.ValueOf(slice)) field.Set(reflect.ValueOf(slice))
case reflect.Pointer: case reflect.Pointer:
var b bool if field.Type() == reflect.TypeFor[*bool]() {
if field.Type() == reflect.TypeOf(&b) {
val, ok := val.(bool) val, ok := val.(bool)
if !ok { if !ok {
return fmt.Errorf("option %q must be of type boolean", key) 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") // ThinkValue represents a value that can be a boolean or a string ("high", "medium", "low")
type ThinkValue struct { type ThinkValue struct {
// Value can be a bool or string // Value can be a bool or string
Value interface{} Value any
} }
// IsValid checks if the ThinkValue is valid // 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) { func FormatParams(params map[string][]string) (map[string]any, error) {
opts := Options{} opts := Options{}
valueOpts := reflect.ValueOf(&opts).Elem() // names of the fields in the options struct 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 // build map of json struct tags to their types
jsonOpts := make(map[string]reflect.StructField) 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 // TODO: only string slices are supported right now
out[key] = vals out[key] = vals
case reflect.Pointer: case reflect.Pointer:
var b bool if field.Type() == reflect.TypeFor[*bool]() {
if field.Type() == reflect.TypeOf(&b) {
boolVal, err := strconv.ParseBool(vals[0]) boolVal, err := strconv.ParseBool(vals[0])
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid bool value %s", vals) return nil, fmt.Errorf("invalid bool value %s", vals)

View File

@ -37,7 +37,7 @@ type MsgBuilder struct {
} }
// Message initialises a MsgBuilder with the provided message. // 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...)} return &MsgBuilder{Msg: fmt.Sprintf(format, args...)}
} }

View File

@ -67,8 +67,7 @@ func reapServers() error {
return nil return nil
} }
pids := strings.Split(pidsStr, "\n") for pidStr := range strings.SplitSeq(pidsStr, "\n") {
for _, pidStr := range pids {
pidStr = strings.TrimSpace(pidStr) pidStr = strings.TrimSpace(pidStr)
if pidStr == "" { if pidStr == "" {
continue continue

View File

@ -282,7 +282,7 @@ func countRows(t *testing.T, db *database, table string) int {
return count 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() t.Helper()
var count int var count int
query := fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE %s", table, condition) 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 // Test helpers for schema migration testing
// schemaMap returns both tables/columns and indexes (ignoring order) // 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 := make(map[string]any)
result["tables"] = columnMap(db) result["tables"] = columnMap(db)

View File

@ -4,6 +4,7 @@ package not
import ( import (
"fmt" "fmt"
"strings"
) )
type ValidError struct { type ValidError struct {
@ -44,12 +45,12 @@ func (b Valids) Error() string {
return "" return ""
} }
var result string var sb strings.Builder
for i, err := range b { for i, err := range b {
if i > 0 { if i > 0 {
result += "; " sb.WriteString("; ")
} }
result += err.Error() sb.WriteString(err.Error())
} }
return result return sb.String()
} }

View File

@ -149,7 +149,7 @@ func BenchmarkChat(fOpt flagOptions) error {
for _, model := range models { for _, model := range models {
for range *fOpt.epochs { for range *fOpt.epochs {
options := make(map[string]interface{}) options := make(map[string]any)
if *fOpt.maxTokens > 0 { if *fOpt.maxTokens > 0 {
options["num_predict"] = *fOpt.maxTokens options["num_predict"] = *fOpt.maxTokens
} }

View File

@ -442,7 +442,7 @@ func TestReadImage_FileNotFound(t *testing.T) {
func TestOptionsMapCreation(t *testing.T) { func TestOptionsMapCreation(t *testing.T) {
fOpt := createTestFlagOptions() fOpt := createTestFlagOptions()
options := make(map[string]interface{}) options := make(map[string]any)
if *fOpt.maxTokens > 0 { if *fOpt.maxTokens > 0 {
options["num_predict"] = *fOpt.maxTokens options["num_predict"] = *fOpt.maxTokens
} }

View File

@ -11,6 +11,7 @@ import (
"fmt" "fmt"
"io" "io"
"log" "log"
"maps"
"math" "math"
"net" "net"
"net/http" "net/http"
@ -1204,9 +1205,7 @@ func (r runOptions) Copy() runOptions {
var opts map[string]any var opts map[string]any
if r.Options != nil { if r.Options != nil {
opts = make(map[string]any, len(r.Options)) opts = make(map[string]any, len(r.Options))
for k, v := range r.Options { maps.Copy(opts, r.Options)
opts[k] = v
}
} }
var think *api.ThinkValue var think *api.ThinkValue
@ -1952,13 +1951,13 @@ func inferThinkingOption(caps *[]model.Capability, runOpts *runOptions, explicit
} }
func renderToolCalls(toolCalls []api.ToolCall, plainText bool) string { func renderToolCalls(toolCalls []api.ToolCall, plainText bool) string {
out := "" var sb strings.Builder
formatExplanation := "" formatExplanation := ""
formatValues := "" formatValues := ""
if !plainText { if !plainText {
formatExplanation = readline.ColorGrey + readline.ColorBold formatExplanation = readline.ColorGrey + readline.ColorBold
formatValues = readline.ColorDefault formatValues = readline.ColorDefault
out += formatExplanation sb.WriteString(formatExplanation)
} }
for i, toolCall := range toolCalls { for i, toolCall := range toolCalls {
argsAsJSON, err := json.Marshal(toolCall.Function.Arguments) argsAsJSON, err := json.Marshal(toolCall.Function.Arguments)
@ -1966,13 +1965,13 @@ func renderToolCalls(toolCalls []api.ToolCall, plainText bool) string {
return "" return ""
} }
if i > 0 { if i > 0 {
out += "\n" sb.WriteString("\n")
} }
// all tool calls are unexpected since we don't currently support registering any in the CLI // 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 { if !plainText {
out += readline.ColorDefault sb.WriteString(readline.ColorDefault)
} }
return out return sb.String()
} }

View File

@ -1322,8 +1322,8 @@ func TestRunOptions_Copy(t *testing.T) {
// Test 2: Verify all fields are copied correctly // Test 2: Verify all fields are copied correctly
tests := []struct { tests := []struct {
name string name string
got interface{} got any
want interface{} want any
}{ }{
{"Model", copied.Model, original.Model}, {"Model", copied.Model, original.Model},
{"ParentModel", copied.ParentModel, original.ParentModel}, {"ParentModel", copied.ParentModel, original.ParentModel},

View File

@ -410,7 +410,7 @@ func generateInteractive(cmd *cobra.Command, opts runOptions) error {
if resp.Parameters == "" { if resp.Parameters == "" {
fmt.Println(" No additional parameters were specified for this model.") fmt.Println(" No additional parameters were specified for this model.")
} else { } else {
for _, l := range strings.Split(resp.Parameters, "\n") { for l := range strings.SplitSeq(resp.Parameters, "\n") {
fmt.Printf(" %s\n", l) fmt.Printf(" %s\n", l)
} }
} }

View File

@ -846,14 +846,7 @@ nextOperation:
func uniqueDeviceIDs(gpuLayers ml.GPULayersList) []ml.DeviceID { func uniqueDeviceIDs(gpuLayers ml.GPULayersList) []ml.DeviceID {
devices := []ml.DeviceID{} devices := []ml.DeviceID{}
for _, layer := range gpuLayers { for _, layer := range gpuLayers {
new := true if !slices.Contains(devices, layer.DeviceID) {
for _, ID := range devices {
if layer.DeviceID == ID {
new = false
break
}
}
if new {
devices = append(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") return "", fmt.Errorf("no tokenizer configured")
} }
var resp string var sb strings.Builder
for _, token := range tokens { 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) { func (s *ollamaServer) Detokenize(ctx context.Context, tokens []int) (string, error) {

View File

@ -68,7 +68,7 @@ func TestEmbeddingsMiddleware_EncodingFormats(t *testing.T) {
switch tc.expectType { switch tc.expectType {
case "array": 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) t.Errorf("expected array, got %T", result.Data[0].Embedding)
} }
case "string": case "string":

View File

@ -414,14 +414,7 @@ func LibraryPaths(l []DeviceInfo) []string {
gpuLibs := []string{LibOllamaPath} gpuLibs := []string{LibOllamaPath}
for _, gpu := range l { for _, gpu := range l {
for _, dir := range gpu.LibraryPath { for _, dir := range gpu.LibraryPath {
needed := true if !slices.Contains(gpuLibs, dir) {
for _, existing := range gpuLibs {
if dir == existing {
needed = false
break
}
}
if needed {
gpuLibs = append(gpuLibs, dir) gpuLibs = append(gpuLibs, dir)
} }
} }

View File

@ -175,9 +175,10 @@ func populateFields(base Base, v reflect.Value, tags ...Tag) reflect.Value {
tagsCopy = append(tagsCopy, parseTag(tag)) tagsCopy = append(tagsCopy, parseTag(tag))
} }
if tt == reflect.TypeOf((*Base)(nil)).Elem() { switch {
case tt == reflect.TypeFor[Base]():
vv.Set(reflect.ValueOf(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 var fn func([]Tag, string, string) [][]string
fn = func(tags []Tag, prefix, suffix string) (fullNames [][]string) { fn = func(tags []Tag, prefix, suffix string) (fullNames [][]string) {
if len(tags) > 0 { if len(tags) > 0 {
@ -217,9 +218,9 @@ func populateFields(base Base, v reflect.Value, tags ...Tag) reflect.Value {
break break
} }
} }
} else if tt.Kind() == reflect.Pointer || tt.Kind() == reflect.Interface { case tt.Kind() == reflect.Pointer || tt.Kind() == reflect.Interface:
setPointer(base, vv, tagsCopy) 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() { for i := range vv.Len() {
vvv := vv.Index(i) vvv := vv.Index(i)
if vvv.Kind() == reflect.Pointer || vvv.Kind() == reflect.Interface { if vvv.Kind() == reflect.Pointer || vvv.Kind() == reflect.Interface {

View File

@ -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) 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) item := x.(*candidate)
*q = append(*q, item) *q = append(*q, item)
} }
func (q *queue) Pop() interface{} { func (q *queue) Pop() any {
old := *q old := *q
n := len(old) n := len(old)
item := old[n-1] item := old[n-1]

View File

@ -487,19 +487,14 @@ func FromChatRequest(r ChatCompletionRequest) (*api.ChatRequest, error) {
} }
} }
types := []string{"jpeg", "jpg", "png", "webp"} url, valid := strings.CutPrefix(url, "data:;base64,")
valid := false if !valid {
// support blank mime type to match api/chat taking just unadorned base64 for _, t := range []string{"jpeg", "jpg", "png", "webp"} {
if strings.HasPrefix(url, "data:;base64,") { prefix := "data:image/" + t + ";base64,"
url = strings.TrimPrefix(url, "data:;base64,") url, valid = strings.CutPrefix(url, prefix)
valid = true if valid {
} break
for _, t := range types { }
prefix := "data:image/" + t + ";base64,"
if strings.HasPrefix(url, prefix) {
url = strings.TrimPrefix(url, prefix)
valid = true
break
} }
} }

View File

@ -7,6 +7,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"maps"
"net/http" "net/http"
"os" "os"
"os/user" "os/user"
@ -78,9 +79,7 @@ func (f Modelfile) CreateRequest(relativeDir string) (*api.CreateRequest, error)
if req.Files == nil { if req.Files == nil {
req.Files = digestMap req.Files = digestMap
} else { } else {
for k, v := range digestMap { maps.Copy(req.Files, digestMap)
req.Files[k] = v
}
} }
case "adapter": case "adapter":
path, err := expandPath(c.Args, relativeDir) path, err := expandPath(c.Args, relativeDir)

View File

@ -3,6 +3,7 @@ package readline
import ( import (
"fmt" "fmt"
"os" "os"
"strings"
"github.com/emirpasic/gods/v2/lists/arraylist" "github.com/emirpasic/gods/v2/lists/arraylist"
"github.com/mattn/go-runewidth" "github.com/mattn/go-runewidth"
@ -515,13 +516,13 @@ func (b *Buffer) StringN(n int) string {
} }
func (b *Buffer) StringNM(n, m int) string { func (b *Buffer) StringNM(n, m int) string {
var s string var sb strings.Builder
if m == 0 { if m == 0 {
m = b.Buf.Size() m = b.Buf.Size()
} }
for cnt := n; cnt < m; cnt++ { for cnt := n; cnt < m; cnt++ {
c, _ := b.Buf.Get(cnt) c, _ := b.Buf.Get(cnt)
s += string(c) sb.WriteRune(c)
} }
return s return sb.String()
} }

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"strings"
) )
type Prompt struct { type Prompt struct {
@ -124,18 +125,18 @@ func (i *Instance) Readline() (string, error) {
case KeyRight: case KeyRight:
buf.MoveRight() buf.MoveRight()
case CharBracketedPaste: case CharBracketedPaste:
var code string var code strings.Builder
for range 3 { for range 3 {
r, err = i.Terminal.Read() r, err = i.Terminal.Read()
if err != nil { if err != nil {
return "", io.EOF return "", io.EOF
} }
code += string(r) code.WriteRune(r)
} }
if code == CharBracketedPasteStart { if code.String() == CharBracketedPasteStart {
i.Pasting = true i.Pasting = true
} else if code == CharBracketedPasteEnd { } else if code.String() == CharBracketedPasteEnd {
i.Pasting = false i.Pasting = false
} }
case KeyDel: case KeyDel:

View File

@ -459,10 +459,7 @@ func TestLogprobsWithStopSequences(t *testing.T) {
origLogprobsLen := len(logprobs) origLogprobsLen := len(logprobs)
numTokensRemoved := origLen - newLen numTokensRemoved := origLen - newLen
newLogprobsLen := origLogprobsLen - numTokensRemoved newLogprobsLen := max(origLogprobsLen-numTokensRemoved, 0)
if newLogprobsLen < 0 {
newLogprobsLen = 0
}
logprobs = logprobs[:newLogprobsLen] logprobs = logprobs[:newLogprobsLen]
// Verify responses were truncated correctly // Verify responses were truncated correctly

View File

@ -577,10 +577,7 @@ func (s *Server) processBatch(tokenBatch *llama.Batch, embedBatch *llama.Batch)
if seq.logprobs { if seq.logprobs {
origLogprobsLen := len(seq.pendingLogprobs) origLogprobsLen := len(seq.pendingLogprobs)
numTokensRemoved := origLen - newLen numTokensRemoved := origLen - newLen
newLogprobsLen := origLogprobsLen - numTokensRemoved newLogprobsLen := max(origLogprobsLen-numTokensRemoved, 0)
if newLogprobsLen < 0 {
newLogprobsLen = 0
}
seq.pendingLogprobs = seq.pendingLogprobs[:newLogprobsLen] seq.pendingLogprobs = seq.pendingLogprobs[:newLogprobsLen]
} }

View File

@ -801,10 +801,7 @@ func (s *Server) computeBatch(activeBatch batchState) {
if seq.logprobs { if seq.logprobs {
origLogprobsLen := len(seq.pendingLogprobs) origLogprobsLen := len(seq.pendingLogprobs)
numTokensRemoved := origLen - newLen numTokensRemoved := origLen - newLen
newLogprobsLen := origLogprobsLen - numTokensRemoved newLogprobsLen := max(origLogprobsLen-numTokensRemoved, 0)
if newLogprobsLen < 0 {
newLogprobsLen = 0
}
seq.pendingLogprobs = seq.pendingLogprobs[:newLogprobsLen] seq.pendingLogprobs = seq.pendingLogprobs[:newLogprobsLen]
} }

View File

@ -33,7 +33,7 @@ func (r registryChallenge) URL() (*url.URL, error) {
values := redirectURL.Query() values := redirectURL.Query()
values.Add("service", r.Service) values.Add("service", r.Service)
for _, s := range strings.Split(r.Scope, " ") { for s := range strings.SplitSeq(r.Scope, " ") {
values.Add("scope", s) values.Add("scope", s)
} }
@ -57,7 +57,7 @@ func getAuthorizationToken(ctx context.Context, challenge registryChallenge) (st
} }
sha256sum := sha256.Sum256(nil) 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) headers := make(http.Header)
signature, err := auth.Sign(ctx, data) signature, err := auth.Sign(ctx, data)

View File

@ -84,8 +84,7 @@ func useCaseInsensitiveTempDir(t *testing.T) bool {
// TODO(bmizerany): Print platform-specific instructions or // TODO(bmizerany): Print platform-specific instructions or
// link to docs on that topic. // link to docs on that topic.
lines := strings.Split(volumeHint, "\n") for line := range strings.SplitSeq(volumeHint, "\n") {
for _, line := range lines {
t.Skip(line) t.Skip(line)
} }
} }

View File

@ -142,7 +142,7 @@ var junkName Name
func BenchmarkParseName(b *testing.B) { func BenchmarkParseName(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
for range b.N { for b.Loop() {
junkName = Parse("h/n/m:t") junkName = Parse("h/n/m:t")
} }
} }

View File

@ -251,7 +251,7 @@ func (s *Local) handleDelete(_ http.ResponseWriter, r *http.Request) error {
type progressUpdateJSON struct { type progressUpdateJSON struct {
Error string `json:"error,omitempty,omitzero"` Error string `json:"error,omitempty,omitzero"`
Status string `json:"status,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"` Total int64 `json:"total,omitempty,omitzero"`
Completed int64 `json:"completed,omitempty,omitzero"` Completed int64 `json:"completed,omitempty,omitzero"`
} }

View File

@ -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") 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 prompt := msg.Content
for _, i := range msg.Images { 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) imgTag := fmt.Sprintf("[img-%d]", imgData.ID)
if !strings.Contains(prompt, "[img]") { if !strings.Contains(prompt, "[img]") {
prefix += imgTag prefix.WriteString(imgTag)
} else { } else {
prompt = strings.Replace(prompt, "[img]", imgTag, 1) prompt = strings.Replace(prompt, "[img]", imgTag, 1)
} }
images = append(images, imgData) 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 // truncate any messages that do not fit into the context window

View File

@ -12,6 +12,7 @@ import (
"io" "io"
"io/fs" "io/fs"
"log/slog" "log/slog"
"maps"
"math" "math"
"math/rand" "math/rand"
"net" "net"
@ -1139,9 +1140,7 @@ func GetModelInfo(req api.ShowRequest) (*api.ShowResponse, error) {
if m.Options == nil { if m.Options == nil {
m.Options = make(map[string]any) m.Options = make(map[string]any)
} }
for k, v := range req.Options { maps.Copy(m.Options, req.Options)
m.Options[k] = v
}
} }
var sb strings.Builder var sb strings.Builder

View File

@ -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) { 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)) tokens = append(tokens, len(tokens))
} }

View File

@ -432,8 +432,7 @@ func TestRoutes(t *testing.T) {
} }
var params []string var params []string
paramsSplit := strings.Split(showResp.Parameters, "\n") for p := range strings.SplitSeq(showResp.Parameters, "\n") {
for _, p := range paramsSplit {
params = append(params, strings.Join(strings.Fields(p), " ")) params = append(params, strings.Join(strings.Fields(p), " "))
} }
sort.Strings(params) sort.Strings(params)

View File

@ -274,7 +274,7 @@ func findArguments(tool *api.Tool, buffer []byte) (map[string]any, int) {
return args, true return args, true
} }
if argsStr, ok := obj[name].(string); ok { 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 { if err := json.Unmarshal([]byte(argsStr), &argsData); err == nil {
return argsData, ok return argsData, ok
} }