Skip to content

Commit e1faf74

Browse files
authored
googleadk: wire workers through the integration's plugin (#517)
* googleadk: wire workers through the integration's plugin Switch the four sample workers from NewActivities + Register to googleadk.NewPlugin in worker.Options.Plugins, the integration's standard wiring as of contrib/googleadk v0.2.0 (the plugin also closes cached MCP toolsets at worker stop). Tests keep registering the Activities directly because the test environments run no plugins. go.mod temporarily pins the plugin branch pseudo-version; bump to v0.2.0 once the release is tagged. * googleadk: pin the released contrib/googleadk v0.2.0
1 parent 686e356 commit e1faf74

7 files changed

Lines changed: 60 additions & 51 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ require (
167167
go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect
168168
go.opentelemetry.io/proto/otlp v1.10.0 // indirect
169169
go.shabbyrobe.org/gocovmerge v0.0.0-20230507111327-fa4f82cfbf4d // indirect
170-
go.temporal.io/sdk/contrib/googleadk v0.1.0
170+
go.temporal.io/sdk/contrib/googleadk v0.2.0
171171
go.uber.org/atomic v1.11.0 // indirect
172172
go.yaml.in/yaml/v3 v3.0.4 // indirect
173173
go4.org/intern v0.0.0-20230525184215-6c62f75575cb // indirect

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -520,8 +520,8 @@ go.temporal.io/sdk/contrib/datadog v0.5.0 h1:GfiDiqWNzkHqxO00H3Inxv66H+KLwS8ifz/
520520
go.temporal.io/sdk/contrib/datadog v0.5.0/go.mod h1:MeHebmCM0ujSoNk2P4b+inyPmcR4IOZqygCVgpekAls=
521521
go.temporal.io/sdk/contrib/envconfig v1.0.1 h1:HZCcS6vNPJiUxJrkc5Wdeen+056LWmYe2dI0D6UuB5g=
522522
go.temporal.io/sdk/contrib/envconfig v1.0.1/go.mod h1:aCFIuADlPNv6bYK5Zp4YfB/PnGfpiSPVzJfvaSTCYtw=
523-
go.temporal.io/sdk/contrib/googleadk v0.1.0 h1:ICu1nswKKu3TlO2hzVHRjdliZIq7aiUegGBMP5aCWMc=
524-
go.temporal.io/sdk/contrib/googleadk v0.1.0/go.mod h1:blDAd6sIyExkjtPP1Q52mUXHNJCfkRyWaNPtr51977g=
523+
go.temporal.io/sdk/contrib/googleadk v0.2.0 h1:cAcwnRb86qf6pdBMYEWmcfP8d5aPSjiFWJw5ctGUZYI=
524+
go.temporal.io/sdk/contrib/googleadk v0.2.0/go.mod h1:blDAd6sIyExkjtPP1Q52mUXHNJCfkRyWaNPtr51977g=
525525
go.temporal.io/sdk/contrib/opentelemetry v0.7.0 h1:GSna1HP+1ibNXZ9xlVdQU2zFVqdt5VcdF0dzpeaYccQ=
526526
go.temporal.io/sdk/contrib/opentelemetry v0.7.0/go.mod h1:oQJC6UIl3FbSYh4f2MlUAIYSE6FPw02X1Tw8/bOvfxg=
527527
go.temporal.io/sdk/contrib/opentracing v0.3.0 h1:IKJgyvZiaOSFl0YHSxJpwXwQa08W3KaZCJkbx05rX7Q=

googleadk/README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@ and the whole run is replayable.
1111
Agents are built the native ADK way (`llmagent.New` + `runner.New`); the only
1212
Temporal-specific pieces are `googleadk.NewModel(...)` as the agent's model,
1313
`googleadk.NewContext(ctx)` passed to `Run`, and the worker-side
14-
`googleadk.NewActivities(...)` registry that holds the real Gemini client (so the
15-
API key stays worker-side, never crossing into the workflow).
14+
`googleadk.NewPlugin(...)` in `worker.Options.Plugins`, whose config holds the
15+
real Gemini client (so the API key stays worker-side, never crossing into the
16+
workflow). The tests register the integration's Activities directly with
17+
`googleadk.NewActivities(...)` instead, since the test environments run no
18+
plugins.
1619

1720
Every sample runs against a scripted `FakeModel` in its `*_test.go`, so
1821
`go test ./googleadk/...` needs no API key or network.

googleadk/chat/worker/main.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,9 @@ func main() {
2424
}
2525
defer c.Close()
2626

27-
w := worker.New(c, chat.TaskQueue, worker.Options{})
28-
29-
w.RegisterWorkflow(chat.ChatWorkflow)
30-
// The chat agent has no tools, so only the model Activity is registered.
31-
32-
acts, err := googleadk.NewActivities(googleadk.Config{
27+
// The plugin registers the integration's model Activity on the worker. The
28+
// chat agent has no tools, so that is the only registration it brings.
29+
adkPlugin, err := googleadk.NewPlugin(googleadk.Config{
3330
Models: map[string]googleadk.ModelFactory{
3431
chat.ModelName: func(ctx context.Context, name string) (model.LLM, error) {
3532
// nil config reads GEMINI_API_KEY / GOOGLE_API_KEY from the env.
@@ -38,9 +35,14 @@ func main() {
3835
},
3936
})
4037
if err != nil {
41-
log.Fatalln("Unable to build googleadk activities", err)
38+
log.Fatalln("Unable to build googleadk plugin", err)
4239
}
43-
acts.Register(w)
40+
41+
w := worker.New(c, chat.TaskQueue, worker.Options{
42+
Plugins: []worker.Plugin{adkPlugin},
43+
})
44+
45+
w.RegisterWorkflow(chat.ChatWorkflow)
4446

4547
if err := w.Run(worker.InterruptCh()); err != nil {
4648
log.Fatalln("Unable to start worker", err)

googleadk/humanintheloop/worker/main.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,10 @@ func main() {
2424
}
2525
defer c.Close()
2626

27-
w := worker.New(c, humanintheloop.TaskQueue, worker.Options{})
28-
29-
w.RegisterWorkflow(humanintheloop.ApprovalWorkflow)
30-
// The delete_resource tool is an in-workflow function tool (not an
31-
// ActivityAsTool), so there is no tool activity to register here — only the
32-
// model Activity below.
33-
34-
acts, err := googleadk.NewActivities(googleadk.Config{
27+
// The plugin registers the integration's model Activity on the worker. The
28+
// delete_resource tool is an in-workflow function tool (not an
29+
// ActivityAsTool), so there is no tool activity to register.
30+
adkPlugin, err := googleadk.NewPlugin(googleadk.Config{
3531
Models: map[string]googleadk.ModelFactory{
3632
humanintheloop.ModelName: func(ctx context.Context, name string) (model.LLM, error) {
3733
// nil config reads GEMINI_API_KEY / GOOGLE_API_KEY from the env.
@@ -40,9 +36,14 @@ func main() {
4036
},
4137
})
4238
if err != nil {
43-
log.Fatalln("Unable to build googleadk activities", err)
39+
log.Fatalln("Unable to build googleadk plugin", err)
4440
}
45-
acts.Register(w)
41+
42+
w := worker.New(c, humanintheloop.TaskQueue, worker.Options{
43+
Plugins: []worker.Plugin{adkPlugin},
44+
})
45+
46+
w.RegisterWorkflow(humanintheloop.ApprovalWorkflow)
4647

4748
if err := w.Run(worker.InterruptCh()); err != nil {
4849
log.Fatalln("Unable to start worker", err)

googleadk/multiagent/worker/main.go

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,32 +25,33 @@ func main() {
2525
}
2626
defer c.Close()
2727

28-
w := worker.New(c, multiagent.TaskQueue, worker.Options{})
29-
30-
w.RegisterWorkflow(multiagent.MultiAgentWorkflow)
31-
// Register GetWeather under the tool name the ActivityAsTool dispatches, so the
32-
// weather specialist's get_weather call resolves to this activity.
33-
w.RegisterActivityWithOptions(multiagent.GetWeather, activity.RegisterOptions{Name: multiagent.WeatherToolName})
34-
35-
// Register the integration's model Activity. Every agent in the tree uses a
36-
// distinct model name so they can be scripted independently in tests; here
37-
// they all resolve to the same real Gemini model. The API key is read
38-
// worker-side and never crosses into the workflow.
28+
// The plugin registers the integration's model Activity on the worker. Every
29+
// agent in the tree uses a distinct model name so they can be scripted
30+
// independently in tests; here they all resolve to the same real Gemini
31+
// model. The API key is read worker-side and never crosses into the workflow.
3932
gemModel := func(ctx context.Context, name string) (model.LLM, error) {
4033
// nil config reads GEMINI_API_KEY / GOOGLE_API_KEY from the env.
4134
return gemini.NewModel(ctx, "gemini-2.0-flash", nil)
4235
}
43-
acts, err := googleadk.NewActivities(googleadk.Config{
36+
adkPlugin, err := googleadk.NewPlugin(googleadk.Config{
4437
Models: map[string]googleadk.ModelFactory{
4538
multiagent.CoordinatorModelName: gemModel,
4639
multiagent.WeatherModelName: gemModel,
4740
multiagent.JokesModelName: gemModel,
4841
},
4942
})
5043
if err != nil {
51-
log.Fatalln("Unable to build googleadk activities", err)
44+
log.Fatalln("Unable to build googleadk plugin", err)
5245
}
53-
acts.Register(w)
46+
47+
w := worker.New(c, multiagent.TaskQueue, worker.Options{
48+
Plugins: []worker.Plugin{adkPlugin},
49+
})
50+
51+
w.RegisterWorkflow(multiagent.MultiAgentWorkflow)
52+
// Register GetWeather under the tool name the ActivityAsTool dispatches, so the
53+
// weather specialist's get_weather call resolves to this activity.
54+
w.RegisterActivityWithOptions(multiagent.GetWeather, activity.RegisterOptions{Name: multiagent.WeatherToolName})
5455

5556
if err := w.Run(worker.InterruptCh()); err != nil {
5657
log.Fatalln("Unable to start worker", err)

googleadk/worker/main.go

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,12 @@ func main() {
2626
defer c.Close()
2727

2828
// @@@SNIPSTART googleadk-hello-worker
29-
w := worker.New(c, adk.TaskQueue, worker.Options{})
30-
31-
w.RegisterWorkflow(adk.AgentWorkflow)
32-
// Register GetWeather under the tool name the ActivityAsTool dispatches, so the
33-
// agent's get_weather call resolves to this activity.
34-
w.RegisterActivityWithOptions(adk.GetWeather, activity.RegisterOptions{Name: adk.WeatherToolName})
35-
36-
// Register the integration's model Activity. The real Gemini model lives here,
37-
// behind the Activity boundary; the API key is read worker-side from the env
38-
// and never crosses into the workflow. Disable the model SDK's own retries so
39-
// Temporal's RetryPolicy is the single source of truth.
40-
acts, err := googleadk.NewActivities(googleadk.Config{
29+
// The plugin registers the integration's Activities on the worker (and closes
30+
// any cached MCP toolsets at worker stop). The real Gemini model lives in the
31+
// factory, behind the Activity boundary; the API key is read worker-side from
32+
// the env and never crosses into the workflow. Disable the model SDK's own
33+
// retries so Temporal's RetryPolicy is the single source of truth.
34+
adkPlugin, err := googleadk.NewPlugin(googleadk.Config{
4135
Models: map[string]googleadk.ModelFactory{
4236
adk.ModelName: func(ctx context.Context, name string) (model.LLM, error) {
4337
// nil config reads GEMINI_API_KEY / GOOGLE_API_KEY from the env.
@@ -46,9 +40,17 @@ func main() {
4640
},
4741
})
4842
if err != nil {
49-
log.Fatalln("Unable to build googleadk activities", err)
43+
log.Fatalln("Unable to build googleadk plugin", err)
5044
}
51-
acts.Register(w)
45+
46+
w := worker.New(c, adk.TaskQueue, worker.Options{
47+
Plugins: []worker.Plugin{adkPlugin},
48+
})
49+
50+
w.RegisterWorkflow(adk.AgentWorkflow)
51+
// Register GetWeather under the tool name the ActivityAsTool dispatches, so the
52+
// agent's get_weather call resolves to this activity.
53+
w.RegisterActivityWithOptions(adk.GetWeather, activity.RegisterOptions{Name: adk.WeatherToolName})
5254

5355
if err := w.Run(worker.InterruptCh()); err != nil {
5456
log.Fatalln("Unable to start worker", err)

0 commit comments

Comments
 (0)