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
50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ Google's generative models into their Go applications. It supports the
[Gemini Enterprise Agent Platform](https://docs.cloud.google.com/gemini-enterprise-agent-platform)
APIs.

> [!NOTE]
> The GenAI SDK now supports the [Interactions API](#interactions) (Experimental).


The Google Gen AI Go SDK enables developers to use Google's state-of-the-art
generative AI models (like Gemini) to build AI-powered features and applications.
This SDK supports use cases like:
Expand Down Expand Up @@ -80,6 +84,52 @@ export GOOGLE_CLOUD_LOCATION='us-central1'
client, err := genai.NewClient(ctx, &genai.ClientConfig{})
```

## Interactions

The Interactions API allows you to interact with agents and models in a multi-turn conversation.

Here is a simple example of creating a new interaction with a model:

```go
package main

import (
"context"
"log"

"google.golang.org/genai"
"google.golang.org/genai/interactions"
)

func main() {
ctx := context.Background()
client, err := genai.NewClient(ctx, nil)
if err != nil {
log.Fatal(err)
}

params := interactions.NewModelParams{
Model: "gemini-2.5-flash",
Input: interactions.Input{String: ptr("Tell me a short joke about programming.")},
}

interaction, err := client.Interactions.NewModel(ctx, params)
if err != nil {
log.Fatal(err)
}

for _, output := range interaction.Outputs {
if output.Text != nil {
println(output.Text.Text)
}
}
}

func ptr[T any](v T) *T {
return &v
}
```

## License

The contents of this repository are licensed under the
Expand Down
47 changes: 47 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ import (
"log"
"net/http"
"os"

"strings"
"sync"

"google.golang.org/genai/interactions"
interactionsopt "google.golang.org/genai/interactions/option"

"cloud.google.com/go/auth"
"cloud.google.com/go/auth/credentials"
Expand Down Expand Up @@ -50,6 +55,11 @@ type Client struct {
Tunings *Tunings
// Tokens provides access to the Tokens service.
AuthTokens *Tokens

// Interactions provides access to the Interactions service.
//
// Experimental: This field is experimental and may change in future versions.
Interactions *interactions.InteractionService
}

// Backend is the GenAI backend to use for the client.
Expand Down Expand Up @@ -387,6 +397,41 @@ func NewInternalAPIClient(ctx context.Context, cc *ClientConfig) (*InternalAPICl
}
return &apiClient{clientConfig: cc}, nil
}
var experimentalWarningInteractions sync.Once

func newInteractionsClient(apiClient *InternalAPIClient) interactions.Client {
experimentalWarningInteractions.Do(func() {
log.Println("Warning: The Interactions service is experimental and may change in future versions.")
})
cc := apiClient.clientConfig

var opts []interactionsopt.RequestOption
if cc.APIKey != "" {
opts = append(opts, interactionsopt.WithAPIKey(cc.APIKey))
}
if cc.HTTPClient != nil {
opts = append(opts, interactionsopt.WithHTTPClient(cc.HTTPClient))
}
if cc.HTTPOptions.BaseURL != "" {
opts = append(opts, interactionsopt.WithBaseURL(cc.HTTPOptions.BaseURL))
}
if cc.HTTPOptions.APIVersion != "" {
opts = append(opts, interactionsopt.WithAPIVersion(cc.HTTPOptions.APIVersion))
}
if cc.HTTPOptions.Headers != nil {
for key, values := range cc.HTTPOptions.Headers {
for _, value := range values {
opts = append(opts, interactionsopt.WithHeaderAdd(key, value))
}
}
}
if cc.HTTPOptions.Timeout != nil {
opts = append(opts, interactionsopt.WithRequestTimeout(*cc.HTTPOptions.Timeout))
}

return interactions.NewClient(opts...)

}

// NewClient creates a new GenAI client.
//
Expand Down Expand Up @@ -422,6 +467,7 @@ func NewClient(ctx context.Context, cc *ClientConfig) (*Client, error) {
if err != nil {
return nil, err
}
interactionsClient := newInteractionsClient(ac)
c := &Client{
clientConfig: *cc,
Models: &Models{apiClient: ac},
Expand All @@ -434,6 +480,7 @@ func NewClient(ctx context.Context, cc *ClientConfig) (*Client, error) {
Batches: &Batches{apiClient: ac},
Tunings: &Tunings{apiClient: ac},
AuthTokens: &Tokens{apiClient: ac},
Interactions: &interactionsClient.Interactions,
}
return c, nil
}
Expand Down
60 changes: 60 additions & 0 deletions examples/interactions/interactions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build ignore_vet

package main

import (
"context"
"log"

"github.com/sanity-io/litter"
"google.golang.org/genai"
"google.golang.org/genai/interactions"
)

func main() {
ctx := context.Background()
client, err := genai.NewClient(ctx, &genai.ClientConfig{HTTPOptions: genai.HTTPOptions{BaseURL: "https://staging-generativelanguage.sandbox.googleapis.com/"}})
if err != nil {
log.Fatal(err)
}

litter.Config.HideZeroValues = true // cleaner output

params := interactions.NewModelParams{
Model: "gemini-2.5-flash",
Input: interactions.Input{String: ptr("Tell me a short joke about programming.")},
}

interaction, err := client.Interactions.NewModel(ctx, params)
if err != nil {
log.Fatal(err)
}

litter.Dump(interaction)

for _, output := range interaction.Outputs {
if output.Text != nil {
println(output.Text.Text)
}
}
}

func ptr[T any](v T) *T {
return &v
}

}
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,18 @@ require (
github.com/eliben/go-sentencepiece v0.6.0
github.com/google/go-cmp v0.6.0
github.com/gorilla/websocket v1.5.3
github.com/tidwall/gjson v1.18.0
github.com/tidwall/sjson v1.2.5
)

require (
cloud.google.com/go/compute/metadata v0.5.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/s2a-go v0.1.8 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
github.com/sanity-io/litter v1.5.8
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/net v0.38.0 // indirect
Expand Down
19 changes: 19 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
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 v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/eliben/go-sentencepiece v0.6.0 h1:wbnefMCxYyVYmeTVtiMJet+mS9CVwq5klveLpfQLsnk=
github.com/eliben/go-sentencepiece v0.6.0/go.mod h1:nNYk4aMzgBoI6QFp4LUG8Eu1uO9fHD9L5ZEre93o9+c=
Expand Down Expand Up @@ -46,14 +48,30 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gT
github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
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/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
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/sanity-io/litter v1.5.8 h1:uM/2lKrWdGbRXDrIq08Lh9XtVYoeGtcQxk9rtQ7+rYg=
github.com/sanity-io/litter v1.5.8/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
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 v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
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 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
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=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
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=
Expand Down Expand Up @@ -121,6 +139,7 @@ google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6h
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=
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=
86 changes: 86 additions & 0 deletions interaction_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package genai

import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"

"google.golang.org/genai/interactions"
)

func TestInteractionsWorkflow(t *testing.T) {
// Create a mock server
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/v1beta/interactions" {
t.Errorf("Path unexpected: %s", r.URL.Path)
}
if r.Method != "POST" {
t.Errorf("Method unexpected: %s", r.Method)
}

// Return a mock response
resp := map[string]any{
"id": "mock_interaction_id",
"created": "2026-03-30T22:20:00Z",
"updated": "2026-03-30T22:20:00Z",
"status": "completed",
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(resp); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}))
defer ts.Close()

// Create client pointing to the mock server
client, err := NewClient(context.Background(), &ClientConfig{
Backend: BackendGeminiAPI,
HTTPOptions: HTTPOptions{
BaseURL: ts.URL,
},
APIKey: "dummy_key",
})
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}

if client.Interactions == nil {
t.Fatalf("client.Interactions is nil")
}

// Call NewModel
res, err := client.Interactions.NewModel(context.Background(), interactions.NewModelParams{
Model: "gemini-2.5-flash",
Input: interactions.Input{
ContentList: []interactions.Content{{
Text: &interactions.TextContent{
Text: "Hello",
},
}},
},
})
if err != nil {
t.Fatalf("Failed to call NewModel: %v", err)
}

if res.ID != "mock_interaction_id" {
t.Errorf("Expected ID 'mock_interaction_id', got '%s'", res.ID)
}
}
27 changes: 27 additions & 0 deletions interactions/aliases.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

package interactions

import (
"google.golang.org/genai/interactions/internal/apierror"
"google.golang.org/genai/interactions/internal/apijson/unmarshalinfo"
)

// aliased to make [unmarshalinfo.Metadata] private when embedding
type metadata = unmarshalinfo.Metadata

type Error = apierror.Error
Loading
Loading