Skip to content

Go adk#1261

Closed
yanivmn wants to merge 4 commits intokagent-dev:mainfrom
yanivmn:go-adk
Closed

Go adk#1261
yanivmn wants to merge 4 commits intokagent-dev:mainfrom
yanivmn:go-adk

Conversation

@yanivmn
Copy link
Contributor

@yanivmn yanivmn commented Feb 3, 2026

This feature branch introduce a new declarative agent base image.
Image is based on https://github.com/google/adk-go
Test cases:

Multiple MCP calles
Azure OpenAI Model
Streaming & None Streaming agent card

Testing:
Build image: make build-app-go
Change Agent CR:
...
deployment:
image: kagent-dev/kagent/app-go

Signed-off-by: Yaniv Marom Nachumi <yanivmar@amdocs.com>
Signed-off-by: Yaniv Marom Nachumi <yanivmar@amdocs.com>
Signed-off-by: Yaniv Marom Nachumi <yanivmar@amdocs.com>
Signed-off-by: Yaniv Marom Nachumi <yanivmar@amdocs.com>
@dimetron
Copy link
Contributor

dimetron commented Feb 3, 2026

Thanks @yanivmn as discussed here https://discord.com/channels/1346225185166065826/1468206497556332556
we need to move common SDK under go/pkg to support BYO scenario with reuse of the same Go in both app runtime and BYO. Also there is a concern about some duplication from the upstream adk-go library. Maybe we can reuse existing instead, WDYT ?

@yanivmn
Copy link
Contributor Author

yanivmn commented Feb 4, 2026

Two main differences in conversion

1) Direct use of SDK types

Python (kagent-adk): Uses google.genai.types and a2a.types directly. Events have clear attributes (event.content, event.error_code), and you use isinstance(event, RunItemStreamEvent) and then work with event.item.

Go: The runner yields interface{} and we get *adksession.Event from the Google ADK. To avoid coupling everywhere we use reflection to get Content, Parts, ErrorCode, etc. (see extractContent, extractContentParts, extractStringField in converters.go). That adds a lot of generic, type-unsafe conversion code.

2) More layers and dual paths in Go

Python: Roughly: SDK events → A2A events (and for ADK: GenAI parts ↔ A2A parts). Few layers, each with a clear type.

Go: We sit between:
A2A (trpc protocol structs)
Google ADK (genai, adksession)
Our own internal types (e.g. models.LLMRequest, models.FunctionResponse)
So we have:

  • converters.go: ADK event → A2A events (with reflection to pull Content/Parts off events).
  • part_converter.go: A2A Part ↔ GenAI Part (manual field mapping and map handling).
  • google_adk_adapter.go: Internal LLMResponse / FunctionResponse → GenAI request/response (another full adapter layer).
  • google_adk_runner_wrapper.go: Protocol message or map (e.g. from Python or A2A) → genai.Content; so we need both convertProtocolMessageToGenAIContent and convertMapToGenAIContent, plus content → events.

We can prepare a version which Dropped internal event types; use only A2A and Google ADK.
Any comments?

}

// BaseLLM is the interface that all LLM implementations must satisfy
type BaseLLM interface {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why aren't we re-using the upstream model interface so we can also use gemini? https://github.com/google/adk-go/blob/21332faeb1b52a089d32450540edcff4d8f2518f/model/llm.go#L26-L29

"time"

"github.com/go-logr/logr"
"github.com/sashabaranov/go-openai"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use the official openai library: https://github.com/openai/openai-go

GetType() string
}

type BaseModel struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did we mirror this code, can't we just reuse go/internal/adk/types.go?

@EItanya
Copy link
Contributor

EItanya commented Feb 4, 2026

Go: The runner yields interface{} and we get *adksession.Event from the Google ADK. To avoid coupling everywhere we use reflection to get Content, Parts, ErrorCode, etc. (see extractContent, extractContentParts, extractStringField in converters.go). That adds a lot of generic, type-unsafe conversion code.

Coupling is fine, the point here is that we are using the adk-go library, if we have fears about that library in general then that's a whole separate issue. Also I try to avoid reflection whenever possible because the code is not readable, and the performance is terrible. Although interestingly AI seems to love using reflection

Python: Roughly: SDK events → A2A events (and for ADK: GenAI parts ↔ A2A parts). Few layers, each with a clear type.

Go: We sit between: A2A (trpc protocol structs) Google ADK (genai, adksession) Our own internal types (e.g. models.LLMRequest, models.FunctionResponse) So we have:

  • converters.go: ADK event → A2A events (with reflection to pull Content/Parts off events).
  • part_converter.go: A2A Part ↔ GenAI Part (manual field mapping and map handling).
  • google_adk_adapter.go: Internal LLMResponse / FunctionResponse → GenAI request/response (another full adapter layer).
  • google_adk_runner_wrapper.go: Protocol message or map (e.g. from Python or A2A) → genai.Content; so we need both convertProtocolMessageToGenAIContent and convertMapToGenAIContent, plus content → events.

We can prepare a version which Dropped internal event types; use only A2A and Google ADK. Any comments?

To be honest, I don't completely understand what you mean by all of this. I think we should try and model the code off of the Python as much as possible. We should endeavor to use the upstream library as much as possible, and insert our own code as plugins and extensions. If there are points where that won't work for specific reasons let's discuss those specifically and we can come up with a plan. The purpose here should be to bring adk-go support to kagent, not build a new version of it that we need to maintain.

@yanivmn
Copy link
Contributor Author

yanivmn commented Feb 4, 2026

Go: The runner yields interface{} and we get *adksession.Event from the Google ADK. To avoid coupling everywhere we use reflection to get Content, Parts, ErrorCode, etc. (see extractContent, extractContentParts, extractStringField in converters.go). That adds a lot of generic, type-unsafe conversion code.

Coupling is fine, the point here is that we are using the adk-go library, if we have fears about that library in general then that's a whole separate issue. Also I try to avoid reflection whenever possible because the code is not readable, and the performance is terrible. Although interestingly AI seems to love using reflection

Python: Roughly: SDK events → A2A events (and for ADK: GenAI parts ↔ A2A parts). Few layers, each with a clear type.
Go: We sit between: A2A (trpc protocol structs) Google ADK (genai, adksession) Our own internal types (e.g. models.LLMRequest, models.FunctionResponse) So we have:

  • converters.go: ADK event → A2A events (with reflection to pull Content/Parts off events).
  • part_converter.go: A2A Part ↔ GenAI Part (manual field mapping and map handling).
  • google_adk_adapter.go: Internal LLMResponse / FunctionResponse → GenAI request/response (another full adapter layer).
  • google_adk_runner_wrapper.go: Protocol message or map (e.g. from Python or A2A) → genai.Content; so we need both convertProtocolMessageToGenAIContent and convertMapToGenAIContent, plus content → events.

We can prepare a version which Dropped internal event types; use only A2A and Google ADK. Any comments?

To be honest, I don't completely understand what you mean by all of this. I think we should try and model the code off of the Python as much as possible. We should endeavor to use the upstream library as much as possible, and insert our own code as plugins and extensions. If there are points where that won't work for specific reasons let's discuss those specifically and we can come up with a plan. The purpose here should be to bring adk-go support to kagent, not build a new version of it that we need to maintain.

@yanivmn yanivmn closed this Feb 4, 2026
@yanivmn
Copy link
Contributor Author

yanivmn commented Feb 4, 2026

Im.working on a new branch without an extra layer.
Will be ready tomorrow. So lets close this for now

Controller packages not in use to prevent any changes in go folder for now

@yanivmn yanivmn deleted the go-adk branch February 9, 2026 15:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants