Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 35 additions & 11 deletions go/plugins/googlegenai/gemini.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,10 @@ func generate(
if err != nil {
return nil, err
}
r := translateResponse(resp)
r, err := translateResponse(resp)
if err != nil {
return nil, err
}

r.Request = input
if cache != nil {
Expand All @@ -298,8 +301,11 @@ func generate(
return nil, err
}
for i, c := range chunk.Candidates {
tc := translateCandidate(c)
err := cb(ctx, &ai.ModelResponseChunk{
tc, err := translateCandidate(c)
if err != nil {
return nil, err
}
err = cb(ctx, &ai.ModelResponseChunk{
Content: tc.Message.Content,
})
if err != nil {
Expand All @@ -322,7 +328,10 @@ func generate(
},
}
resp.Candidates = merged
r = translateResponse(resp)
r, err = translateResponse(resp)
if err != nil {
return nil, fmt.Errorf("failed to generate contents: %w", err)
}
r.Request = input
if cache != nil {
r.Message.Metadata = cacheMetadata(r.Message.Metadata, cache)
Expand All @@ -339,11 +348,17 @@ func toGeminiRequest(input *ai.ModelRequest, cache *genai.CachedContent) (*genai
return nil, err
}

// only one candidate is supported by default
gcc.CandidateCount = 1
// candidate count might not be set to 1 and will keep its zero value if not set
// e.g. default value from reflection server is 0
if gcc.CandidateCount == 0 {
gcc.CandidateCount = 1
}

// Genkit primitive fields must be used instead of go-genai fields
// i.e.: system prompt, tools, cached content, response schema, etc
if gcc.CandidateCount != 1 {
return nil, errors.New("multiple candidates is not supported")
}
if gcc.SystemInstruction != nil {
return nil, errors.New("system instruction must be set using Genkit feature: ai.WithSystemPrompt()")
}
Expand Down Expand Up @@ -596,7 +611,7 @@ func toGeminiToolChoice(toolChoice ai.ToolChoice, tools []*ai.ToolDefinition) (*
}

// translateCandidate translates from a genai.GenerateContentResponse to an ai.ModelResponse.
func translateCandidate(cand *genai.Candidate) *ai.ModelResponse {
func translateCandidate(cand *genai.Candidate) (*ai.ModelResponse, error) {
m := &ai.ModelResponse{}
switch cand.FinishReason {
case genai.FinishReasonStop:
Expand All @@ -613,6 +628,10 @@ func translateCandidate(cand *genai.Candidate) *ai.ModelResponse {
m.FinishReason = ai.FinishReasonUnknown
}
msg := &ai.Message{}
if cand.Content == nil {
return nil, fmt.Errorf("no valid candidates were found in the generate response")
}

msg.Role = ai.Role(cand.Content.Role)

// iterate over the candidate parts, only one struct member
Expand Down Expand Up @@ -668,14 +687,19 @@ func translateCandidate(cand *genai.Candidate) *ai.ModelResponse {
msg.Content = append(msg.Content, p)
}
m.Message = msg
return m
return m, nil
}

// Translate from a genai.GenerateContentResponse to a ai.ModelResponse.
func translateResponse(resp *genai.GenerateContentResponse) *ai.ModelResponse {
func translateResponse(resp *genai.GenerateContentResponse) (*ai.ModelResponse, error) {
var r *ai.ModelResponse
var err error
if len(resp.Candidates) > 0 {
r = translateCandidate(resp.Candidates[0])
r, err = translateCandidate(resp.Candidates[0])
if err != nil {
return nil, err
}

} else {
r = &ai.ModelResponse{}
}
Expand All @@ -691,7 +715,7 @@ func translateResponse(resp *genai.GenerateContentResponse) *ai.ModelResponse {
r.Usage.CachedContentTokens = int(u.CachedContentTokenCount)
r.Usage.ThoughtsTokens = int(u.ThoughtsTokenCount)
}
return r
return r, nil
}

// toGeminiParts converts a slice of [ai.Part] to a slice of [genai.Part].
Expand Down
18 changes: 9 additions & 9 deletions go/plugins/googlegenai/vertexai_live_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@ func TestVertexAILive(t *testing.T) {
if !ok {
t.Skipf("GOOGLE_CLOUD_PROJECT env var not set")
}
location, ok := requireEnv("GOOGLE_CLOUD_LOCATION")
region, ok := requireEnv("GOOGLE_CLOUD_LOCATION")
if !ok {
t.Log("GOOGLE_CLOUD_LOCATION env var not set, defaulting to us-central1")
location = "us-central1"
region = "us-central1"
}

ctx := context.Background()
g := genkit.Init(ctx,
genkit.WithDefaultModel("vertexai/gemini-2.0-flash"),
genkit.WithPlugins(&googlegenai.VertexAI{ProjectID: projectID, Location: location}),
genkit.WithPlugins(&googlegenai.VertexAI{ProjectID: projectID, Location: region}),
)

embedder := googlegenai.VertexAIEmbedder(g, "textembedding-gecko@003")
Expand Down Expand Up @@ -264,8 +264,8 @@ func TestVertexAILive(t *testing.T) {
}
})
t.Run("image generation", func(t *testing.T) {
if location != "global" {
t.Skipf("image generation in Vertex AI is only supported in region: global, got: %s", location)
if region != "global" {
t.Skipf("image generation in Vertex AI is only supported in region: global, got: %s", region)
}
m := googlegenai.VertexAIModel(g, "gemini-2.0-flash-preview-image-generation")
resp, err := genkit.Generate(ctx, g,
Expand Down Expand Up @@ -328,8 +328,8 @@ func TestVertexAILive(t *testing.T) {
}
})
t.Run("thinking enabled", func(t *testing.T) {
if location != "global" && location != "us-central1" {
t.Skipf("thinking in Vertex AI is only supported in these regions: [global, us-central1], got: %q", location)
if region != "global" && region != "us-central1" {
t.Skipf("thinking in Vertex AI is only supported in these regions: [global, us-central1], got: %q", region)
}

m := googlegenai.VertexAIModel(g, "gemini-2.5-flash-preview-05-20")
Expand Down Expand Up @@ -360,8 +360,8 @@ func TestVertexAILive(t *testing.T) {
}
})
t.Run("thinking disabled", func(t *testing.T) {
if location != "global" && location != "us-central1" {
t.Skipf("thinking in Vertex AI is only supported in these regions: [global, us-central1], got: %q", location)
if region != "global" && region != "us-central1" {
t.Skipf("thinking in Vertex AI is only supported in these regions: [global, us-central1], got: %q", region)
}

m := googlegenai.VertexAIModel(g, "gemini-2.5-flash-preview-05-20")
Expand Down
9 changes: 5 additions & 4 deletions go/plugins/ollama/ollama_live_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,17 @@ import (
ollamaPlugin "github.com/firebase/genkit/go/plugins/ollama"
)

var serverAddress = flag.String("server-address", "http://localhost:11434", "Ollama server address")
var modelName = flag.String("model-name", "tinyllama", "model name")
var testLive = flag.Bool("test-live", false, "run live tests")
var (
serverAddress = flag.String("server-address", "http://localhost:11434", "Ollama server address")
modelName = flag.String("model-name", "tinyllama", "model name")
testLive = flag.Bool("test-live", false, "run live tests")
)

/*
To run this test, you need to have the Ollama server running. You can set the server address using the OLLAMA_SERVER_ADDRESS environment variable.
If the environment variable is not set, the test will default to http://localhost:11434 (the default address for the Ollama server).
*/
func TestLive(t *testing.T) {

if !*testLive {
t.Skip("skipping go/plugins/ollama live test")
}
Expand Down
96 changes: 79 additions & 17 deletions go/plugins/vertexai/modelgarden/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,51 +18,113 @@ package modelgarden

import (
"github.com/firebase/genkit/go/ai"
"github.com/firebase/genkit/go/plugins/internal"
)

const provider = "vertexai"

// supported anthropic models
var anthropicModels = map[string]ai.ModelOptions{
"claude-3-5-sonnet-v2": {
Label: "Vertex AI Model Garden - Claude 3.5 Sonnet",
Supports: &internal.Multimodal,
Label: "Vertex AI Model Garden - Claude 3.5 Sonnet",
Supports: &ai.ModelSupports{
Multiturn: true,
Tools: true,
ToolChoice: true,
SystemRole: true,
Media: true,
Constrained: ai.ConstrainedSupportNone,
},
Versions: []string{"claude-3-5-sonnet-v2@20241022"},
},
"claude-3-5-sonnet": {
Label: "Vertex AI Model Garden - Claude 3.5 Sonnet",
Supports: &internal.Multimodal,
Label: "Vertex AI Model Garden - Claude 3.5 Sonnet",
Supports: &ai.ModelSupports{
Multiturn: true,
Tools: true,
ToolChoice: true,
SystemRole: true,
Media: true,
Constrained: ai.ConstrainedSupportNone,
},

Versions: []string{"claude-3-5-sonnet@20240620"},
},
"claude-3-sonnet": {
Label: "Vertex AI Model Garden - Claude 3 Sonnet",
Supports: &internal.Multimodal,
Label: "Vertex AI Model Garden - Claude 3 Sonnet",
Supports: &ai.ModelSupports{
Multiturn: true,
Tools: true,
ToolChoice: true,
SystemRole: true,
Media: true,
Constrained: ai.ConstrainedSupportNone,
},

Versions: []string{"claude-3-sonnet@20240229"},
},
"claude-3-haiku": {
Label: "Vertex AI Model Garden - Claude 3 Haiku",
Supports: &internal.Multimodal,
Label: "Vertex AI Model Garden - Claude 3 Haiku",
Supports: &ai.ModelSupports{
Multiturn: true,
Tools: true,
ToolChoice: true,
SystemRole: true,
Media: true,
Constrained: ai.ConstrainedSupportNone,
},

Versions: []string{"claude-3-haiku@20240307"},
},
"claude-3-opus": {
Label: "Vertex AI Model Garden - Claude 3 Opus",
Supports: &internal.Multimodal,
Label: "Vertex AI Model Garden - Claude 3 Opus",
Supports: &ai.ModelSupports{
Multiturn: true,
Tools: true,
ToolChoice: true,
SystemRole: true,
Media: true,
Constrained: ai.ConstrainedSupportNone,
},

Versions: []string{"claude-3-opus@20240229"},
},
"claude-3-7-sonnet": {
Label: "Vertex AI Model Garden - Claude 3.7 Sonnet",
Supports: &internal.Multimodal,
Label: "Vertex AI Model Garden - Claude 3.7 Sonnet",
Supports: &ai.ModelSupports{
Multiturn: true,
Tools: true,
ToolChoice: true,
SystemRole: true,
Media: true,
Constrained: ai.ConstrainedSupportNone,
},

Versions: []string{"claude-3-7-sonnet@20250219"},
},
"claude-opus-4": {
Label: "Vertex AI Model Garden - Claude Opus 4",
Supports: &internal.Multimodal,
Label: "Vertex AI Model Garden - Claude Opus 4",
Supports: &ai.ModelSupports{
Multiturn: true,
Tools: true,
ToolChoice: true,
SystemRole: true,
Media: true,
Constrained: ai.ConstrainedSupportNone,
},

Versions: []string{"claude-opus-4@20250514"},
},
"claude-sonnet-4": {
Label: "Vertex AI Model Garden - Claude Sonnet 4",
Supports: &internal.Multimodal,
Label: "Vertex AI Model Garden - Claude Sonnet 4",
Supports: &ai.ModelSupports{
Multiturn: true,
Tools: true,
ToolChoice: true,
SystemRole: true,
Media: true,
Constrained: ai.ConstrainedSupportNone,
},

Versions: []string{"claude-sonnet-4@20250514"},
},
}
54 changes: 0 additions & 54 deletions go/samples/basic-gemini-with-context/main.go

This file was deleted.

Loading
Loading