Skip to content

Commit c9dceb8

Browse files
authored
Add tracing library for ADK (#37)
* Add tracing library for ADK Add a library to help trace Google's Agent Development Kit. The built in tracing is not consistent, google/adk-go#479, so implement our own tracing and also skip exporting the built in traces to Braintrust. Since ADK already has callbacks at every stage, this is relatively straightforward, we just have to do some manual bookkeeping in order to set the parent and child relationships correctly rather than relying on context propagation in the ADK library. Also implemented autoinstrumentation for the ADK library, using the same helper functions. ADK's minimum supported Go version is 1.24.4, so I did have to bump this SDK's minimum version as well, from 1.24.0.
1 parent 81ffd6d commit c9dceb8

33 files changed

Lines changed: 2794 additions & 149 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ Complete working examples are available in [`examples/`](./examples/):
243243
- **[genai](./examples/genai/main.go)** - Google Gemini tracing
244244
- **[langchaingo](./examples/langchaingo/main.go)** - LangChainGo integration
245245
- **[datasets](./examples/datasets/main.go)** - Using Braintrust datasets
246+
- **[adk-go](./examples/adk/main.go)** - ADK integration
246247

247248
## Features
248249

client.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,14 @@ func New(tp *trace.TracerProvider, opts ...Option) (*Client, error) {
116116
func (c *Client) setupTracing() error {
117117
// Build trace config from client config
118118
traceConfig := bttrace.Config{
119-
DefaultProjectID: c.config.DefaultProjectID,
120-
DefaultProjectName: c.config.DefaultProjectName,
121-
FilterAISpans: c.config.FilterAISpans,
122-
SpanFilterFuncs: convertSpanFilters(c.config.SpanFilterFuncs),
123-
EnableConsoleLog: false,
124-
Exporter: c.config.Exporter,
125-
Logger: c.logger,
119+
DefaultProjectID: c.config.DefaultProjectID,
120+
DefaultProjectName: c.config.DefaultProjectName,
121+
FilterAISpans: c.config.FilterAISpans,
122+
EnableBuiltinAdkTraces: c.config.EnableBuiltinAdkTraces,
123+
SpanFilterFuncs: convertSpanFilters(c.config.SpanFilterFuncs),
124+
EnableConsoleLog: false,
125+
Exporter: c.config.Exporter,
126+
Logger: c.logger,
126127
}
127128

128129
// Add Braintrust span processor to the provided TracerProvider

config/config.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ type Config struct {
2222
BlockingLogin bool
2323

2424
// Tracing configuration
25-
FilterAISpans bool
26-
SpanFilterFuncs []SpanFilterFunc
27-
Exporter trace.SpanExporter
25+
FilterAISpans bool
26+
EnableBuiltinAdkTraces bool // if false (default), drop Google ADK native spans to avoid duplicates
27+
SpanFilterFuncs []SpanFilterFunc
28+
Exporter trace.SpanExporter
2829

2930
// Logger
3031
Logger logger.Logger
@@ -45,16 +46,18 @@ type SpanFilterFunc func(span trace.ReadOnlySpan) int
4546
// - BRAINTRUST_DEFAULT_PROJECT: Default project name (default: "default-go-project")
4647
// - BRAINTRUST_BLOCKING_LOGIN: Enable blocking login (default: false)
4748
// - BRAINTRUST_OTEL_FILTER_AI_SPANS: Filter to keep only AI-related spans (default: false)
49+
// - BRAINTRUST_OTEL_ENABLE_BUILTIN_ADK_TRACES: Enable exporting spans from Google ADK's built-in telemetry (default: false)
4850
func FromEnv() *Config {
4951
return &Config{
50-
APIKey: getEnvString("BRAINTRUST_API_KEY", ""),
51-
APIURL: getEnvString("BRAINTRUST_API_URL", "https://api.braintrust.dev"),
52-
AppURL: getEnvString("BRAINTRUST_APP_URL", "https://www.braintrust.dev"),
53-
OrgName: getEnvString("BRAINTRUST_ORG_NAME", ""),
54-
DefaultProjectID: getEnvString("BRAINTRUST_DEFAULT_PROJECT_ID", ""),
55-
DefaultProjectName: getEnvString("BRAINTRUST_DEFAULT_PROJECT", "default-go-project"),
56-
BlockingLogin: getEnvBool("BRAINTRUST_BLOCKING_LOGIN", false),
57-
FilterAISpans: getEnvBool("BRAINTRUST_OTEL_FILTER_AI_SPANS", false),
52+
APIKey: getEnvString("BRAINTRUST_API_KEY", ""),
53+
APIURL: getEnvString("BRAINTRUST_API_URL", "https://api.braintrust.dev"),
54+
AppURL: getEnvString("BRAINTRUST_APP_URL", "https://www.braintrust.dev"),
55+
OrgName: getEnvString("BRAINTRUST_ORG_NAME", ""),
56+
DefaultProjectID: getEnvString("BRAINTRUST_DEFAULT_PROJECT_ID", ""),
57+
DefaultProjectName: getEnvString("BRAINTRUST_DEFAULT_PROJECT", "default-go-project"),
58+
BlockingLogin: getEnvBool("BRAINTRUST_BLOCKING_LOGIN", false),
59+
FilterAISpans: getEnvBool("BRAINTRUST_OTEL_FILTER_AI_SPANS", false),
60+
EnableBuiltinAdkTraces: getEnvBool("BRAINTRUST_OTEL_ENABLE_BUILTIN_ADK_TRACES", false),
5861
}
5962
}
6063

examples/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Examples for other AI providers and client libraries:
2626
- **[sashabaranov-openai/](sashabaranov-openai/)** - OpenAI tracing with sashabaranov/go-openai library
2727
- **[openrouter/](openrouter/)** - Trace OpenRouter requests
2828
- **[langchaingo/](langchaingo/)** - Trace LangChainGo multi-turn conversations
29+
- **[adk-go/](adk/)** - Trace agents built with the ADK framework
2930

3031
## Advanced Features (30 minutes)
3132

examples/adk/go.mod

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
module main.go
2+
3+
go 1.24.11
4+
5+
require (
6+
github.com/braintrustdata/braintrust-sdk-go v0.2.0
7+
go.opentelemetry.io/otel v1.38.0
8+
go.opentelemetry.io/otel/sdk v1.38.0
9+
google.golang.org/adk v0.4.0
10+
google.golang.org/genai v1.43.0
11+
)
12+
13+
require (
14+
cloud.google.com/go v0.123.0 // indirect
15+
cloud.google.com/go/auth v0.17.0 // indirect
16+
cloud.google.com/go/compute/metadata v0.9.0 // indirect
17+
github.com/a2aproject/a2a-go v0.3.3 // indirect
18+
github.com/awalterschulze/gographviz v2.0.3+incompatible // indirect
19+
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
20+
github.com/felixge/httpsnoop v1.0.4 // indirect
21+
github.com/go-logr/logr v1.4.3 // indirect
22+
github.com/go-logr/stdr v1.2.2 // indirect
23+
github.com/google/go-cmp v0.7.0 // indirect
24+
github.com/google/jsonschema-go v0.3.0 // indirect
25+
github.com/google/s2a-go v0.1.9 // indirect
26+
github.com/google/safehtml v0.1.0 // indirect
27+
github.com/google/uuid v1.6.0 // indirect
28+
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
29+
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
30+
github.com/gorilla/mux v1.8.1 // indirect
31+
github.com/gorilla/websocket v1.5.3 // indirect
32+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
33+
github.com/mitchellh/mapstructure v1.5.0 // indirect
34+
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
35+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect
36+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
37+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect
38+
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0 // indirect
39+
go.opentelemetry.io/otel/metric v1.38.0 // indirect
40+
go.opentelemetry.io/otel/trace v1.38.0 // indirect
41+
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
42+
golang.org/x/crypto v0.45.0 // indirect
43+
golang.org/x/net v0.47.0 // indirect
44+
golang.org/x/sync v0.18.0 // indirect
45+
golang.org/x/sys v0.38.0 // indirect
46+
golang.org/x/text v0.31.0 // indirect
47+
google.golang.org/genproto/googleapis/api v0.0.0-20251014184007-4626949a642f // indirect
48+
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect
49+
google.golang.org/grpc v1.76.0 // indirect
50+
google.golang.org/protobuf v1.36.10 // indirect
51+
rsc.io/omap v1.2.0 // indirect
52+
rsc.io/ordered v1.1.1 // indirect
53+
)
54+
55+
replace github.com/braintrustdata/braintrust-sdk-go => ../..

examples/adk/go.sum

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE=
2+
cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU=
3+
cloud.google.com/go/auth v0.17.0 h1:74yCm7hCj2rUyyAocqnFzsAYXgJhrG26XCFimrc/Kz4=
4+
cloud.google.com/go/auth v0.17.0/go.mod h1:6wv/t5/6rOPAX4fJiRjKkJCvswLwdet7G8+UGXt7nCQ=
5+
cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
6+
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
7+
github.com/a2aproject/a2a-go v0.3.3 h1:NqGDw2c8hCSW3/9MakeeRpw5yCZUUmW2Y/yINV15GwQ=
8+
github.com/a2aproject/a2a-go v0.3.3/go.mod h1:8C0O6lsfR7zWFEqVZz/+zWCoxe8gSWpknEpqm/Vgj3E=
9+
github.com/awalterschulze/gographviz v2.0.3+incompatible h1:9sVEXJBJLwGX7EQVhLm2elIKCm7P2YHFC8v6096G09E=
10+
github.com/awalterschulze/gographviz v2.0.3+incompatible/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs=
11+
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
12+
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
13+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
14+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
15+
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
16+
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
17+
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
18+
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
19+
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
20+
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
21+
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
22+
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
23+
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
24+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
25+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
26+
github.com/google/jsonschema-go v0.3.0 h1:6AH2TxVNtk3IlvkkhjrtbUc4S8AvO0Xii0DxIygDg+Q=
27+
github.com/google/jsonschema-go v0.3.0/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
28+
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
29+
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
30+
github.com/google/safehtml v0.1.0 h1:EwLKo8qawTKfsi0orxcQAZzu07cICaBeFMegAU9eaT8=
31+
github.com/google/safehtml v0.1.0/go.mod h1:L4KWwDsUJdECRAEpZoBn3O64bQaywRscowZjJAzjHnU=
32+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
33+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
34+
github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
35+
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
36+
github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=
37+
github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=
38+
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
39+
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
40+
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
41+
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
42+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
43+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
44+
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
45+
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
46+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
47+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
48+
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
49+
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
50+
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
51+
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
52+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18=
53+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg=
54+
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
55+
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
56+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
57+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
58+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
59+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
60+
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0 h1:G8Xec/SgZQricwWBJF/mHZc7A02YHedfFDENwJEdRA0=
61+
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0/go.mod h1:PD57idA/AiFD5aqoxGxCvT/ILJPeHy3MjqU/NS7KogY=
62+
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
63+
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
64+
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
65+
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
66+
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
67+
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
68+
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
69+
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
70+
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
71+
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
72+
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
73+
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
74+
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
75+
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
76+
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
77+
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
78+
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
79+
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
80+
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
81+
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
82+
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
83+
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
84+
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
85+
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
86+
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
87+
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
88+
google.golang.org/adk v0.4.0 h1:CJ31nyxkqRfEgKuttR4h3o6QFok94Ty4UpbefUn21h8=
89+
google.golang.org/adk v0.4.0/go.mod h1:jVeb7Ir53+3XKTncdY7k3pVdPneKcm5+60sXpxHQnao=
90+
google.golang.org/genai v1.43.0 h1:8vhqhzJNZu1U94e2m+KvDq/TUUjSmDrs1aKkvTa8SoM=
91+
google.golang.org/genai v1.43.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk=
92+
google.golang.org/genproto/googleapis/api v0.0.0-20251014184007-4626949a642f h1:OiFuztEyBivVKDvguQJYWq1yDcfAHIID/FVrPR4oiI0=
93+
google.golang.org/genproto/googleapis/api v0.0.0-20251014184007-4626949a642f/go.mod h1:kprOiu9Tr0JYyD6DORrc4Hfyk3RFXqkQ3ctHEum3ZbM=
94+
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk=
95+
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
96+
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
97+
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
98+
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
99+
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
100+
gopkg.in/dnaeon/go-vcr.v3 v3.2.0 h1:Rltp0Vf+Aq0u4rQXgmXgtgoRDStTnFN83cWgSGSoRzM=
101+
gopkg.in/dnaeon/go-vcr.v3 v3.2.0/go.mod h1:2IMOnnlx9I6u9x+YBsM3tAMx6AlOxnJ0pWxQAzZ79Ag=
102+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
103+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
104+
rsc.io/omap v1.2.0 h1:c1M8jchnHbzmJALzGLclfH3xDWXrPxSUHXzH5C+8Kdw=
105+
rsc.io/omap v1.2.0/go.mod h1:C8pkI0AWexHopQtZX+qiUeJGzvc8HkdgnsWK4/mAa00=
106+
rsc.io/ordered v1.1.1 h1:1kZM6RkTmceJgsFH/8DLQvkCVEYomVDJfBRLT595Uak=
107+
rsc.io/ordered v1.1.1/go.mod h1:evAi8739bWVBRG9aaufsjVc202+6okf8u2QeVL84BCM=

examples/adk/main.go

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
"os"
8+
"time"
9+
10+
"go.opentelemetry.io/otel"
11+
"go.opentelemetry.io/otel/sdk/trace"
12+
"google.golang.org/adk/agent"
13+
"google.golang.org/adk/agent/llmagent"
14+
"google.golang.org/adk/model/gemini"
15+
"google.golang.org/adk/runner"
16+
"google.golang.org/adk/session"
17+
"google.golang.org/adk/tool"
18+
"google.golang.org/adk/tool/functiontool"
19+
"google.golang.org/genai"
20+
21+
"github.com/braintrustdata/braintrust-sdk-go"
22+
traceadk "github.com/braintrustdata/braintrust-sdk-go/trace/contrib/adk"
23+
)
24+
25+
// getTimeArgs defines the input arguments for the time tool
26+
type getTimeArgs struct {
27+
Timezone string `json:"timezone" jsonschema:"IANA timezone identifier (e.g., 'America/New_York', 'Europe/London', 'Asia/Tokyo')."`
28+
}
29+
30+
// getTimeResult defines the output of the time tool
31+
type getTimeResult struct {
32+
Time string `json:"time"`
33+
Timezone string `json:"timezone"`
34+
}
35+
36+
// getTime is the handler function for the time tool
37+
func getTime(ctx tool.Context, args getTimeArgs) (getTimeResult, error) {
38+
// Load the timezone
39+
loc, err := time.LoadLocation(args.Timezone)
40+
if err != nil {
41+
return getTimeResult{}, fmt.Errorf("invalid timezone '%s': %w", args.Timezone, err)
42+
}
43+
44+
// Get current time in the timezone
45+
currentTime := time.Now().In(loc)
46+
47+
return getTimeResult{
48+
Time: currentTime.Format("2006-01-02 15:04:05 MST"),
49+
Timezone: args.Timezone,
50+
}, nil
51+
}
52+
53+
func main() {
54+
tp := trace.NewTracerProvider()
55+
defer tp.Shutdown(context.Background()) //nolint:errcheck
56+
otel.SetTracerProvider(tp)
57+
58+
// Initialize Braintrust tracing
59+
bt, err := braintrust.New(tp,
60+
braintrust.WithProject("go-sdk-examples"),
61+
braintrust.WithBlockingLogin(true),
62+
)
63+
if err != nil {
64+
log.Fatal(err)
65+
}
66+
67+
// Set up top-level span
68+
// Get a tracer instance from the global TracerProvider
69+
tracer := otel.Tracer("adk-example")
70+
71+
// Create a parent span to wrap the ADK runner
72+
ctx, span := tracer.Start(context.Background(), "examples/adk/main.go")
73+
defer span.End()
74+
75+
// Set up ADK
76+
model, err := gemini.NewModel(ctx, "gemini-2.5-flash", &genai.ClientConfig{
77+
APIKey: os.Getenv("GOOGLE_API_KEY"),
78+
})
79+
if err != nil {
80+
log.Fatalf("Failed to create model: %v", err)
81+
}
82+
83+
// Create time tool using functiontool
84+
timeTool, err := functiontool.New(
85+
functiontool.Config{
86+
Name: "get_time",
87+
Description: "Get the current time for a specific timezone. Provide a timezone in IANA format like 'America/New_York', 'Europe/London', or 'Asia/Tokyo'.",
88+
},
89+
getTime,
90+
)
91+
if err != nil {
92+
log.Fatalf("Failed to create time tool: %v", err)
93+
}
94+
95+
cfg := llmagent.Config{
96+
Name: "helper_agent",
97+
Model: model,
98+
Description: "Helper agent.",
99+
Instruction: "You are a helpful assistant that helps users with various tasks. You can tell the current time in any timezone using the get_time tool.",
100+
Tools: []tool.Tool{timeTool},
101+
}
102+
traceadk.AddLLMAgentCallbacks(&cfg)
103+
a, err := llmagent.New(cfg)
104+
if err != nil {
105+
log.Fatalf("Failed to create agent: %v", err)
106+
}
107+
108+
sessionSvc := session.InMemoryService()
109+
_, err = sessionSvc.Create(ctx, &session.CreateRequest{
110+
AppName: "adk-example",
111+
UserID: "user",
112+
SessionID: "session",
113+
})
114+
if err != nil {
115+
log.Fatalf("Failed to create session: %v", err)
116+
}
117+
runner, err := runner.New(runner.Config{
118+
AppName: "adk-example",
119+
Agent: a,
120+
SessionService: sessionSvc,
121+
})
122+
msg := genai.NewContentFromText("What is the time in San Francisco?", genai.RoleUser)
123+
for ev, err := range runner.Run(ctx, "user", "session", msg, agent.RunConfig{}) {
124+
if err != nil {
125+
log.Printf(" ADK error: %v", err)
126+
return
127+
}
128+
if ev.Content != nil {
129+
for _, p := range ev.Content.Parts {
130+
if p.Text != "" {
131+
fmt.Printf(" Response: %s\n", p.Text)
132+
}
133+
}
134+
}
135+
}
136+
137+
fmt.Printf("View trace: %s\n", bt.Permalink(span))
138+
}

0 commit comments

Comments
 (0)