From 573d5f296e904cd31c118eb527013dd53b7faa1c Mon Sep 17 00:00:00 2001 From: Montana Flynn Date: Fri, 24 Apr 2026 11:08:46 -0500 Subject: [PATCH 1/2] feat: update defaults to latest OpenAI and Gemini models - OpenAI text: gpt-5.4 (best), gpt-5.4-mini (fast) - OpenAI image: gpt-image-2 (best) - Gemini text: gemini-3.1-pro-preview (best, replaces deprecated gemini-3-pro-preview) - Gemini image: gemini-3.1-flash-image-preview (fast, Nano Banana 2) Previous models retained as exported variables for explicit pinning. Also bumps openai-go to v3.32.0 and genai to v1.54.0, and refreshes Quick Start in README. --- .env.example | 3 + .gitignore | 3 + README.md | 160 +++++++++++------------------- go.mod | 45 +++++---- go.sum | 197 ++++++++++++++----------------------- grail.go | 2 +- providers/gemini/gemini.go | 10 +- providers/gemini/models.go | 47 ++++++--- providers/openai/models.go | 64 ++++++++++-- providers/openai/openai.go | 23 ++--- 10 files changed, 278 insertions(+), 276 deletions(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..ceee17f --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +OPENAI_API_KEY=sk-... +GEMINI_API_KEY=... +MODELSLAB_API_KEY=... diff --git a/.gitignore b/.gitignore index 66938e4..d137202 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ examples-output/ +.env +.env.* +!.env.example # macOS .DS_Store diff --git a/README.md b/README.md index 1653b60..a29d39f 100644 --- a/README.md +++ b/README.md @@ -22,101 +22,61 @@ go get github.com/montanaflynn/grail ## Quick Start ```go -// Create a provider (automatically uses OPENAI_API_KEY if not provided) -provider, _ := openai.New() - -// Create a client -client := grail.NewClient(provider) - -// Generate text -res, _ := client.Generate(ctx, grail.Request{ - Inputs: []grail.Input{grail.InputText("Create a haiku")}, - Output: grail.OutputText(), -}) -text, _ := res.Text() -fmt.Println(text) - -// Generate image -imgRes, _ := client.Generate(ctx, grail.Request{ - Inputs: []grail.Input{grail.InputText("A beautiful sunset")}, - Output: grail.OutputImage(grail.ImageSpec{Count: 1}), -}) -imgs, _ := imgRes.Images() -os.WriteFile("sunset.png", imgs[0], 0644) - -// Generate image with provider-specific options -import "github.com/montanaflynn/grail/providers/gemini" -imgRes2, _ := client.Generate(ctx, grail.Request{ - Inputs: []grail.Input{grail.InputText("A landscape photo")}, - Output: grail.OutputImage(grail.ImageSpec{Count: 1}), - ProviderOptions: []grail.ProviderOption{ - gemini.WithImageAspectRatio(gemini.ImageAspectRatio16_9), - gemini.WithImageSize(gemini.ImageSize2K), - }, -}) - -// Image understanding (text from image) -imgData, _ := os.ReadFile("photo.jpg") -imgInput := grail.InputImage(imgData) -textRes, _ := client.Generate(ctx, grail.Request{ - Inputs: []grail.Input{ - grail.InputText("Describe this image"), - imgInput, - }, - Output: grail.OutputText(), -}) -text, _ := textRes.Text() -fmt.Println(text) - -// Multimodal image generation (image from text + image) -imgRes3, _ := client.Generate(ctx, grail.Request{ - Inputs: []grail.Input{ - grail.InputText("Create a variation of this image"), - imgInput, - grail.InputText("but make it more colorful"), - }, - Output: grail.OutputImage(grail.ImageSpec{Count: 1}), -}) -imgs, _ := imgRes3.Images() -os.WriteFile("variation.png", imgs[0], 0644) - -// PDF understanding (text from PDF) -pdfData, _ := os.ReadFile("document.pdf") -pdfRes, _ := client.Generate(ctx, grail.Request{ - Inputs: []grail.Input{ - grail.InputText("Summarize this document"), - grail.InputPDF(pdfData), - }, - Output: grail.OutputText(), -}) -text, _ := pdfRes.Text() -fmt.Println(text) - -// Model selection: explicit model name -res, _ := client.Generate(ctx, grail.Request{ - Inputs: []grail.Input{grail.InputText("Hello")}, - Output: grail.OutputText(), - Model: "gpt-4o", // Use this specific model -}) - -// Model selection: tier-based (provider picks the right model) -res, _ := client.Generate(ctx, grail.Request{ - Inputs: []grail.Input{grail.InputText("Hello")}, - Output: grail.OutputText(), - Tier: grail.ModelTierFast, // Let provider pick the fast text model -}) - -// Query available models -models, _ := client.ListModels(ctx) -for _, m := range models { - fmt.Printf("%s: role=%s tier=%s\n", m.Name, m.Role, m.Tier) -} +package main + +import ( + "context" + "fmt" + "log" + "os" + + "github.com/montanaflynn/grail" + "github.com/montanaflynn/grail/providers/openai" + // Swap providers by importing another one instead: + // "github.com/montanaflynn/grail/providers/gemini" + // "github.com/montanaflynn/grail/providers/modelslab" +) -// Get specific model by role and tier -model, _ := client.GetModel(ctx, grail.ModelRoleText, grail.ModelTierBest) -fmt.Printf("Best text model: %s\n", model.Name) +func main() { + ctx := context.Background() + + // Uses OPENAI_API_KEY from the environment. + // For Gemini: provider, err := gemini.New(ctx) (uses GEMINI_API_KEY) + // For ModelsLab: provider, err := modelslab.New() (uses MODELSLAB_API_KEY) + provider, err := openai.New() + if err != nil { + log.Fatal(err) + } + client := grail.NewClient(provider) + + // Generate text. + textRes, err := client.Generate(ctx, grail.Request{ + Inputs: []grail.Input{grail.InputText("Write a haiku about Go.")}, + Output: grail.OutputText(), + }) + if err != nil { + log.Fatal(err) + } + text, _ := textRes.Text() + fmt.Println(text) + + // Generate an image. + imgRes, err := client.Generate(ctx, grail.Request{ + Inputs: []grail.Input{grail.InputText("A beautiful sunset over the ocean.")}, + Output: grail.OutputImage(grail.ImageSpec{Count: 1}), + }) + if err != nil { + log.Fatal(err) + } + imgs, _ := imgRes.Images() + if err := os.WriteFile("sunset.png", imgs[0], 0644); err != nil { + log.Fatal(err) + } +} ``` +See the [`examples/`](examples/) directory for more — image understanding, PDF input, multimodal generation, provider-specific options, and model selection. + ## Examples See the [`examples/`](examples/) directory for complete, runnable examples: @@ -143,8 +103,8 @@ provider, err := openai.New() // With options provider, err := openai.New( openai.WithAPIKey("sk-..."), - openai.WithTextModel("gpt-4"), - openai.WithImageModel("gpt-image-1"), + openai.WithTextModel("gpt-5.4"), + openai.WithImageModel("gpt-image-2"), openai.WithLogger(logger), ) ``` @@ -152,8 +112,8 @@ provider, err := openai.New( **Options:** - `WithAPIKey(key string)` - Set API key explicitly - `WithAPIKeyFromEnv(env string)` - Read API key from environment variable -- `WithTextModel(model string)` - Override default text model (default: `gpt-5.2`) -- `WithImageModel(model string)` - Override default image model (default: `gpt-image-1`) +- `WithTextModel(model string)` - Override default text model (default: `gpt-5.4`) +- `WithImageModel(model string)` - Override default image model (default: `gpt-image-2`) - `WithLogger(logger *slog.Logger)` - Set custom logger **Image Options:** @@ -177,8 +137,8 @@ provider, err := gemini.New(ctx) // With options provider, err := gemini.New(ctx, gemini.WithAPIKey("..."), - gemini.WithTextModel("gemini-3-flash-preview"), - gemini.WithImageModel("gemini-2.5-flash-image"), + gemini.WithTextModel("gemini-3.1-pro-preview"), + gemini.WithImageModel("gemini-3.1-flash-image-preview"), gemini.WithLogger(logger), ) ``` @@ -186,8 +146,8 @@ provider, err := gemini.New(ctx, **Options:** - `WithAPIKey(key string)` - Set API key explicitly - `WithAPIKeyFromEnv(env string)` - Read API key from environment variable -- `WithTextModel(model string)` - Override default text model (default: `gemini-3-flash-preview`) -- `WithImageModel(model string)` - Override default image model (default: `gemini-2.5-flash-image`) +- `WithTextModel(model string)` - Override default text model (default: `gemini-3.1-pro-preview`) +- `WithImageModel(model string)` - Override default image model (default: `gemini-3-pro-image-preview`) - `WithLogger(logger *slog.Logger)` - Set custom logger **Image Options:** diff --git a/go.mod b/go.mod index b80e44b..b60c787 100644 --- a/go.mod +++ b/go.mod @@ -1,31 +1,40 @@ module github.com/montanaflynn/grail -go 1.24.0 +go 1.25.0 require ( - github.com/openai/openai-go/v3 v3.26.0 - google.golang.org/genai v1.49.0 + github.com/openai/openai-go/v3 v3.32.0 + google.golang.org/genai v1.54.0 ) require ( - cloud.google.com/go v0.116.0 // indirect - cloud.google.com/go/auth v0.9.5 // indirect - cloud.google.com/go/compute/metadata v0.5.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/google/go-cmp v0.6.0 // indirect - github.com/google/s2a-go v0.1.8 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect + cloud.google.com/go v0.123.0 // indirect + cloud.google.com/go/auth v0.20.0 // indirect + cloud.google.com/go/compute/metadata v0.9.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/google/s2a-go v0.1.9 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.15 // indirect + github.com/googleapis/gax-go/v2 v2.22.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/tidwall/gjson v1.18.0 // indirect github.com/tidwall/match v1.2.0 // indirect github.com/tidwall/pretty v1.2.1 // indirect github.com/tidwall/sjson v1.2.5 // indirect - go.opencensus.io v0.24.0 // indirect - golang.org/x/crypto v0.45.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/text v0.31.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/grpc v1.67.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 // indirect + go.opentelemetry.io/otel v1.43.0 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/otel/trace v1.43.0 // indirect + golang.org/x/crypto v0.50.0 // indirect + golang.org/x/net v0.53.0 // indirect + golang.org/x/sys v0.43.0 // indirect + golang.org/x/text v0.36.0 // indirect + google.golang.org/api v0.276.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260420184626-e10c466a9529 // indirect + google.golang.org/grpc v1.80.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect ) diff --git a/go.sum b/go.sum index cb003e1..e41e65d 100644 --- a/go.sum +++ b/go.sum @@ -1,59 +1,40 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= -cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= -cloud.google.com/go/auth v0.9.5 h1:4CTn43Eynw40aFVr3GpPqsQponx2jv0BQpjvajsbbzw= -cloud.google.com/go/auth v0.9.5/go.mod h1:Xo0n7n66eHyOWWCnitop6870Ilwo3PiZyodVkkH1xWM= -cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= -cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= +cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= +cloud.google.com/go/auth v0.20.0 h1:kXTssoVb4azsVDoUiF8KvxAqrsQcQtB53DcSgta74CA= +cloud.google.com/go/auth v0.20.0/go.mod h1:942/yi/itH1SsmpyrbnTMDgGfdy2BUqIKyd0cyYLc5Q= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= -github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= -github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.15 h1:xolVQTEXusUcAA5UgtyRLjelpFFHWlPQ4XfWGc7MBas= +github.com/googleapis/enterprise-certificate-proxy v0.3.15/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg= +github.com/googleapis/gax-go/v2 v2.22.0 h1:PjIWBpgGIVKGoCXuiCoP64altEJCj3/Ei+kSU5vlZD4= +github.com/googleapis/gax-go/v2 v2.22.0/go.mod h1:irWBbALSr0Sk3qlqb9SyJ1h68WjgeFuiOzI4Rqw5+aY= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/openai/openai-go/v3 v3.26.0 h1:bRt6H/ozMNt/dDkN4gobnLqaEGrRGBzmbVs0xxJEnQE= -github.com/openai/openai-go/v3 v3.26.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo= +github.com/openai/openai-go/v3 v3.32.0 h1:aHp/3wkX1W6jB8zTtf9xV0aK0qPFSVDqS7AHmlJ4hXs= +github.com/openai/openai-go/v3 v3.32.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -65,75 +46,45 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genai v1.49.0 h1:Se+QJaH2GYK1aaR1o5S38mlU2GD5FnVvP76nfkV7LH0= -google.golang.org/genai v1.49.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= -google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 h1:CqXxU8VOmDefoh0+ztfGaymYbhdB/tT3zs79QaZTNGY= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0/go.mod h1:BuhAPThV8PBHBvg8ZzZ/Ok3idOdhWIodywz2xEcRbJo= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= +golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= +golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= +golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= +golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/api v0.276.0 h1:nVArUtfLEihtW+b0DdcqRGK1xoEm2+ltAihyztq7MKY= +google.golang.org/api v0.276.0/go.mod h1:Fnag/EWUPIcJXuIkP1pjoTgS5vdxlk3eeemL7Do6bvw= +google.golang.org/genai v1.54.0 h1:ZQCa70WMTJDI11FdqWCzGvZ5PanpcpfoO6jl/lrSnGU= +google.golang.org/genai v1.54.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk= +google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 h1:XzmzkmB14QhVhgnawEVsOn6OFsnpyxNPRY9QV01dNB0= +google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:L43LFes82YgSonw6iTXTxXUX1OlULt4AQtkik4ULL/I= +google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7 h1:41r6JMbpzBMen0R/4TZeeAmGXSJC7DftGINUodzTkPI= +google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:EIQZ5bFCfRQDV4MhRle7+OgjNtZ6P1PiZBgAKuxXu/Y= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260420184626-e10c466a9529 h1:XF8+t6QQiS0o9ArVan/HW8Q7cycNPGsJf6GA2nXxYAg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260420184626-e10c466a9529/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= +google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/grail.go b/grail.go index 9220736..65470fb 100644 --- a/grail.go +++ b/grail.go @@ -212,7 +212,7 @@ const ( // Model describes a model and its capabilities. // Providers export these as package-level variables for easy reference. type Model struct { - Name string // Model identifier (e.g., "gpt-5.2", "gemini-3-flash-preview") + Name string // Model identifier (e.g., "gpt-5.4", "gemini-3.1-pro-preview") Role ModelRole // text or image Tier ModelTier // best or fast Capabilities ModelCapabilities // What the model can do diff --git a/providers/gemini/gemini.go b/providers/gemini/gemini.go index c26f179..4fae7dc 100644 --- a/providers/gemini/gemini.go +++ b/providers/gemini/gemini.go @@ -17,8 +17,8 @@ // if no API key is explicitly provided via WithAPIKey or WithAPIKeyFromEnv. // // Default models: -// - Text: gemini-3-flash-preview -// - Image: gemini-2.5-flash-image +// - Text: gemini-3.1-pro-preview +// - Image: gemini-3-pro-image-preview package gemini import ( @@ -37,7 +37,7 @@ import ( const ( // DefaultTextModelName is the Gemini text model used when no override is provided. - DefaultTextModelName = "gemini-3-pro-preview" + DefaultTextModelName = "gemini-3.1-pro-preview" // DefaultImageModelName is the Gemini image model used when no override is provided. DefaultImageModelName = "gemini-3-pro-image-preview" ) @@ -255,10 +255,10 @@ func New(ctx context.Context, opts ...Option) (*Provider, error) { imageModel: cfg.imageModel, log: cfg.logger, // Initialize model catalog with defaults - bestTextModel: Gemini3Pro, + bestTextModel: Gemini3_1Pro, fastTextModel: Gemini3Flash, bestImageModel: Gemini3ProImage, - fastImageModel: Gemini25FlashImage, + fastImageModel: Gemini3_1FlashImage, }, nil } diff --git a/providers/gemini/models.go b/providers/gemini/models.go index 2e960ae..c52169d 100644 --- a/providers/gemini/models.go +++ b/providers/gemini/models.go @@ -3,13 +3,14 @@ package gemini import "github.com/montanaflynn/grail" // Model constants for Gemini models. -// Use these directly in requests: grail.Request{Model: gemini.Gemini3Pro.Name} +// Use these directly in requests: grail.Request{Model: gemini.Gemini3_1Pro.Name} // Best models - highest quality var ( - // Gemini3Pro is the best quality text generation model. - Gemini3Pro = grail.Model{ - Name: "gemini-3-pro-preview", + // Gemini3_1Pro is the best quality text generation model, with advanced + // reasoning and 1M-token context. Replaces the deprecated gemini-3-pro-preview. + Gemini3_1Pro = grail.Model{ + Name: "gemini-3.1-pro-preview", Role: grail.ModelRoleText, Tier: grail.ModelTierBest, Capabilities: grail.ModelCapabilities{ @@ -34,7 +35,7 @@ var ( // Fast models - speed/cost optimized var ( - // Gemini3Flash is a fast text generation model. + // Gemini3Flash is the fast text generation model in the Gemini 3 series. Gemini3Flash = grail.Model{ Name: "gemini-3-flash-preview", Role: grail.ModelRoleText, @@ -47,9 +48,10 @@ var ( }, } - // Gemini25FlashImage is a fast image generation model. - Gemini25FlashImage = grail.Model{ - Name: "gemini-2.5-flash-image", + // Gemini3_1FlashImage (Nano Banana 2) is a fast image generation model + // with Pro-tier quality, 512px–4K output, and extended aspect ratios. + Gemini3_1FlashImage = grail.Model{ + Name: "gemini-3.1-flash-image-preview", Role: grail.ModelRoleImage, Tier: grail.ModelTierFast, Capabilities: grail.ModelCapabilities{ @@ -61,11 +63,35 @@ var ( // Other models - available but not set as default best/fast var ( - // Gemini25Flash is a balanced text generation model. + // Gemini3Pro is the previous best text model. Deprecated and shut down + // on 2026-03-09 — kept as a symbol for backwards-compat; callers should + // migrate to Gemini3_1Pro. + Gemini3Pro = grail.Model{ + Name: "gemini-3-pro-preview", + Role: grail.ModelRoleText, + Capabilities: grail.ModelCapabilities{ + TextGeneration: true, + ImageUnderstanding: true, + PDFUnderstanding: true, + JSONOutput: true, + }, + } + + // Gemini25FlashImage (Nano Banana) is the previous-generation fast image + // model, retained for callers that want to pin to it explicitly. + Gemini25FlashImage = grail.Model{ + Name: "gemini-2.5-flash-image", + Role: grail.ModelRoleImage, + Capabilities: grail.ModelCapabilities{ + ImageGeneration: true, + ImageUnderstanding: true, + }, + } + + // Gemini25Flash is a balanced text generation model from the 2.5 series. Gemini25Flash = grail.Model{ Name: "gemini-2.5-flash", Role: grail.ModelRoleText, - Tier: "", // Not categorized as best or fast Capabilities: grail.ModelCapabilities{ TextGeneration: true, ImageUnderstanding: true, @@ -78,7 +104,6 @@ var ( Gemini25FlashLite = grail.Model{ Name: "gemini-2.5-flash-lite", Role: grail.ModelRoleText, - Tier: "", // Not categorized as best or fast Capabilities: grail.ModelCapabilities{ TextGeneration: true, ImageUnderstanding: true, diff --git a/providers/openai/models.go b/providers/openai/models.go index 7204357..5af0d62 100644 --- a/providers/openai/models.go +++ b/providers/openai/models.go @@ -8,13 +8,52 @@ import ( ) // Model constants for OpenAI models. -// Use these directly in requests: grail.Request{Model: openai.GPT5_2.Name} +// Use these directly in requests: grail.Request{Model: openai.GPT5_4.Name} var ( - // GPT5_2 is the latest GPT-5 model for text generation. + // GPT5_4 is the frontier GPT-5.4 text model, with built-in computer use + // and 1M-token context. + GPT5_4 = grail.Model{ + Name: shared.ChatModelGPT5_4, + Role: grail.ModelRoleText, + Tier: grail.ModelTierBest, + Capabilities: grail.ModelCapabilities{ + TextGeneration: true, + ImageUnderstanding: true, + PDFUnderstanding: true, + JSONOutput: true, + }, + } + + // GPT5_4Mini is the cost-optimized GPT-5.4 text model. + GPT5_4Mini = grail.Model{ + Name: shared.ChatModelGPT5_4Mini, + Role: grail.ModelRoleText, + Tier: grail.ModelTierFast, + Capabilities: grail.ModelCapabilities{ + TextGeneration: true, + ImageUnderstanding: true, + PDFUnderstanding: true, + JSONOutput: true, + }, + } + + // GPT5_4Nano is the smallest GPT-5.4 text model. + GPT5_4Nano = grail.Model{ + Name: shared.ChatModelGPT5_4Nano, + Role: grail.ModelRoleText, + Capabilities: grail.ModelCapabilities{ + TextGeneration: true, + ImageUnderstanding: true, + PDFUnderstanding: true, + JSONOutput: true, + }, + } + + // GPT5_2 is the previous-generation GPT-5.2 text model, retained for + // callers that want to pin to it explicitly. GPT5_2 = grail.Model{ Name: shared.ChatModelGPT5_2, Role: grail.ModelRoleText, - Tier: grail.ModelTierBest, Capabilities: grail.ModelCapabilities{ TextGeneration: true, ImageUnderstanding: true, @@ -23,11 +62,10 @@ var ( }, } - // GPT4o is the GPT-4o model, optimized for speed. + // GPT4o is the GPT-4o model, retained for callers that want to pin to it. GPT4o = grail.Model{ Name: shared.ChatModelGPT4o, Role: grail.ModelRoleText, - Tier: grail.ModelTierFast, Capabilities: grail.ModelCapabilities{ TextGeneration: true, ImageUnderstanding: true, @@ -36,11 +74,23 @@ var ( }, } - // GPTImage1 is the best quality image generation model. + // GPTImage2 is the best quality image generation model, with reasoning, + // 2K output, multi-image coherence, and improved multilingual text rendering. + GPTImage2 = grail.Model{ + Name: "gpt-image-2", + Role: grail.ModelRoleImage, + Tier: grail.ModelTierBest, + Capabilities: grail.ModelCapabilities{ + ImageGeneration: true, + ImageUnderstanding: true, + }, + } + + // GPTImage1 is the previous-generation image model, retained for callers + // that want to pin to it explicitly. GPTImage1 = grail.Model{ Name: openai.ImageModelGPTImage1, Role: grail.ModelRoleImage, - Tier: grail.ModelTierBest, Capabilities: grail.ModelCapabilities{ ImageGeneration: true, ImageUnderstanding: true, diff --git a/providers/openai/openai.go b/providers/openai/openai.go index e2541ac..30a3bad 100644 --- a/providers/openai/openai.go +++ b/providers/openai/openai.go @@ -17,11 +17,12 @@ // if no API key is explicitly provided via WithAPIKey or WithAPIKeyFromEnv. // // Default models: -// - Text: gpt-5.2 -// - Image: gpt-image-1 +// - Text: gpt-5.4 +// - Image: gpt-image-2 // // Available image models: -// - gpt-image-1 (default) +// - gpt-image-2 (default) +// - gpt-image-1 // - gpt-image-1-mini package openai @@ -47,9 +48,9 @@ import ( const ( // DefaultTextModelName is the OpenAI text model used when no override is provided. - DefaultTextModelName = shared.ChatModelGPT5_2 + DefaultTextModelName = shared.ChatModelGPT5_4 // DefaultImageModelName is the OpenAI image model used when no override is provided. - DefaultImageModelName = openai.ImageModelGPTImage1 + DefaultImageModelName = "gpt-image-2" ) var ( @@ -87,13 +88,13 @@ func WithAPIKeyFromEnv(env string) Option { } } -// WithTextModel overrides the default text model (default: gpt-5.2). +// WithTextModel overrides the default text model (default: gpt-5.4). func WithTextModel(model string) Option { return func(s *settings) { s.textModel = model } } -// WithImageModel overrides the default image model (default: gpt-image-1). -// Available models: gpt-image-1, gpt-image-1-mini +// WithImageModel overrides the default image model (default: gpt-image-2). +// Available models: gpt-image-2, gpt-image-1, gpt-image-1-mini func WithImageModel(model string) Option { return func(s *settings) { s.imageModel = model } } @@ -328,9 +329,9 @@ func New(opts ...Option) (*Provider, error) { log: cfg.logger, imgFormat: cfg.imgFormat, // Initialize model catalog with defaults - bestTextModel: GPT5_2, - fastTextModel: GPT4o, - bestImageModel: GPTImage1, + bestTextModel: GPT5_4, + fastTextModel: GPT5_4Mini, + bestImageModel: GPTImage2, fastImageModel: GPTImage1Mini, }, nil } From 720ff757510fcf1ad8747548d61761200f1967ec Mon Sep 17 00:00:00 2001 From: Montana Flynn Date: Fri, 24 Apr 2026 11:31:10 -0500 Subject: [PATCH 2/2] =?UTF-8?q?docs:=20tidy=20README=20=E2=80=94=20drop=20?= =?UTF-8?q?modelslab=20comments,=20duplicate=20examples=20blurb,=20and=20l?= =?UTF-8?q?inks=20section?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/README.md b/README.md index a29d39f..d16ae33 100644 --- a/README.md +++ b/README.md @@ -34,15 +34,13 @@ import ( "github.com/montanaflynn/grail/providers/openai" // Swap providers by importing another one instead: // "github.com/montanaflynn/grail/providers/gemini" - // "github.com/montanaflynn/grail/providers/modelslab" ) func main() { ctx := context.Background() // Uses OPENAI_API_KEY from the environment. - // For Gemini: provider, err := gemini.New(ctx) (uses GEMINI_API_KEY) - // For ModelsLab: provider, err := modelslab.New() (uses MODELSLAB_API_KEY) + // For Gemini: provider, err := gemini.New(ctx) (uses GEMINI_API_KEY) provider, err := openai.New() if err != nil { log.Fatal(err) @@ -75,8 +73,6 @@ func main() { } ``` -See the [`examples/`](examples/) directory for more — image understanding, PDF input, multimodal generation, provider-specific options, and model selection. - ## Examples See the [`examples/`](examples/) directory for complete, runnable examples: @@ -157,13 +153,6 @@ provider, err := gemini.New(ctx, **Text Options:** - `TextOptions{Model, MaxTokens, Temperature, TopP, SystemPrompt}` - Provider-specific text generation options -## Links - -- [API Reference](https://pkg.go.dev/github.com/montanaflynn/grail) -- [Providers](https://pkg.go.dev/github.com/montanaflynn/grail/providers) -- [Examples](https://github.com/montanaflynn/grail/tree/main/examples) -- [Changelog](https://github.com/montanaflynn/grail/blob/main/CHANGELOG.md) - ## Development ```bash