Skip to content
Merged
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
52 changes: 25 additions & 27 deletions server/restapi/services/agentloader.go → agent/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,47 +12,45 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package services
package agent

import (
"fmt"

"google.golang.org/adk/agent"
)

// AgentLoader allows to load a particular agent by name and get the root agent
type AgentLoader interface {
// Loader allows to load a particular agent by name and get the root agent
type Loader interface {
// ListAgents returns a list of names of all agents
ListAgents() []string
// LoadAgent returns an agent by its name. Returns error if there is no agent with such a name.
LoadAgent(name string) (agent.Agent, error)
LoadAgent(name string) (Agent, error)
// RootAgent returns the root agent
RootAgent() agent.Agent
RootAgent() Agent
}

// multiAgentLoader should be used when you have multiple agents
type multiAgentLoader struct {
agentMap map[string]agent.Agent
root agent.Agent
// multiLoader should be used when you have multiple agents
type multiLoader struct {
agentMap map[string]Agent
root Agent
}

// singleAgentLoader should be used when you have only one agent
type singleAgentLoader struct {
root agent.Agent
// singleLoader should be used when you have only one agent
type singleLoader struct {
root Agent
}

// NewSingleAgentLoader returns a loader with only one agent, which becomes the root agent
func NewSingleAgentLoader(a agent.Agent) AgentLoader {
return &singleAgentLoader{root: a}
// NewSingleLoader returns a loader with only one agent, which becomes the root agent
func NewSingleLoader(a Agent) Loader {
return &singleLoader{root: a}
}

// singleAgentLoader implements AgentLoader. Returns root agent's name
func (s *singleAgentLoader) ListAgents() []string {
func (s *singleLoader) ListAgents() []string {
return []string{s.root.Name()}
}

// singleAgentLoader implements AgentLoader. Returns root for empty name and for root.Name(), error otherwise.
func (s *singleAgentLoader) LoadAgent(name string) (agent.Agent, error) {
func (s *singleLoader) LoadAgent(name string) (Agent, error) {
if name == "" {
return s.root, nil
}
Expand All @@ -63,14 +61,14 @@ func (s *singleAgentLoader) LoadAgent(name string) (agent.Agent, error) {
}

// singleAgentLoader implements AgentLoader. Returns the root agent.
func (s *singleAgentLoader) RootAgent() agent.Agent {
func (s *singleLoader) RootAgent() Agent {
return s.root
}

// NewMultiAgentLoader returns a new AgentLoader with the given root Agent and other agents.
// NewMultiLoader returns a new AgentLoader with the given root Agent and other agents.
// Returns an error if more than one agent (including root) shares the same name
func NewMultiAgentLoader(root agent.Agent, agents ...agent.Agent) (AgentLoader, error) {
m := make(map[string]agent.Agent)
func NewMultiLoader(root Agent, agents ...Agent) (Loader, error) {
m := make(map[string]Agent)
m[root.Name()] = root
for _, a := range agents {
if _, ok := m[a.Name()]; ok {
Expand All @@ -79,14 +77,14 @@ func NewMultiAgentLoader(root agent.Agent, agents ...agent.Agent) (AgentLoader,
}
m[a.Name()] = a
}
return &multiAgentLoader{
return &multiLoader{
agentMap: m,
root: root,
}, nil
}

// multiAgentLoader implements AgentLoader. Returns the list of all agents' names (including root agent)
func (m *multiAgentLoader) ListAgents() []string {
func (m *multiLoader) ListAgents() []string {
agents := make([]string, 0, len(m.agentMap))
for name := range m.agentMap {
agents = append(agents, name)
Expand All @@ -95,7 +93,7 @@ func (m *multiAgentLoader) ListAgents() []string {
}

// multiAgentLoader implements LoadAgent. Returns an agent with given name or error if no such an agent is found
func (m *multiAgentLoader) LoadAgent(name string) (agent.Agent, error) {
func (m *multiLoader) LoadAgent(name string) (Agent, error) {
agent, ok := m.agentMap[name]
if !ok {
return nil, fmt.Errorf("agent %s not found. Please specify one of those: %v", name, m.ListAgents())
Expand All @@ -104,6 +102,6 @@ func (m *multiAgentLoader) LoadAgent(name string) (agent.Agent, error) {
}

// multiAgentLoader implements LoadAgent.
func (m *multiAgentLoader) RootAgent() agent.Agent {
func (m *multiLoader) RootAgent() Agent {
return m.root
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,83 +12,93 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package services
package agent

import (
"iter"
"testing"

"google.golang.org/adk/agent"
"google.golang.org/adk/agent/llmagent"
"google.golang.org/adk/session"
)

var _ Agent = (*testAgent)(nil)

type testAgent struct {
name string
}

func (a *testAgent) Name() string {
return a.name
}

func (a *testAgent) Description() string {
panic("not implemented")
}

func (a *testAgent) Run(InvocationContext) iter.Seq2[*session.Event, error] {
panic("not implemented")
}
func (a *testAgent) SubAgents() []Agent {
panic("not implemented")
}

func (a *testAgent) internal() *agent {
panic("not implemented")
}

func TestDuplicateName(t *testing.T) {
agent1, err := llmagent.New(llmagent.Config{
Name: "weather_time_agent",
})
if err != nil {
t.Fatalf("failed to create agent: %v", err)
}
agent1 := &testAgent{name: "weather_time_agent"}
// duplicate name
agent2, err := llmagent.New(llmagent.Config{
Name: "weather_time_agent",
})
if err != nil {
t.Fatalf("failed to create agent: %v", err)
}
agent3, err := llmagent.New(llmagent.Config{
Name: "unique",
})
if err != nil {
t.Fatalf("failed to create agent: %v", err)
}
agent2 := &testAgent{name: "weather_time_agent"}
agent3 := &testAgent{name: "unique"}

tests := []struct {
name string
root agent.Agent
agents []agent.Agent
root Agent
agents []Agent
wantErr bool
}{
{
name: "root only",
root: agent1,
agents: []agent.Agent{},
agents: []Agent{},
wantErr: false,
},
{
name: "root duplicate object",
root: agent1,
agents: []agent.Agent{agent1},
agents: []Agent{agent1},
wantErr: true,
},
{
name: "root duplicate name",
root: agent1,
agents: []agent.Agent{agent2},
agents: []Agent{agent2},
wantErr: true,
},
{
name: "non-root duplicate name",
root: agent3,
agents: []agent.Agent{agent1, agent2},
agents: []Agent{agent1, agent2},
wantErr: true,
},
{
name: "non-root duplicate object",
root: agent3,
agents: []agent.Agent{agent1, agent1},
agents: []Agent{agent1, agent1},
wantErr: true,
},
{
name: "no duplicates",
root: agent1,
agents: []agent.Agent{agent3},
agents: []Agent{agent3},
wantErr: false,
},
}
for _, tt := range tests {
_, err := NewMultiAgentLoader(tt.root, tt.agents...)
_, err := NewMultiLoader(tt.root, tt.agents...)
if (err != nil) != tt.wantErr {
t.Errorf("NewMultiAgentLoader() name=%v, error = %v, wantErr %v", tt.name, err, tt.wantErr)
t.Errorf("NewMultiLoader() name=%v, error = %v, wantErr %v", tt.name, err, tt.wantErr)
}
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/launcher/launcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ import (
"context"

"github.com/a2aproject/a2a-go/a2asrv"
"google.golang.org/adk/agent"
"google.golang.org/adk/artifact"
"google.golang.org/adk/memory"
"google.golang.org/adk/server/restapi/services"
"google.golang.org/adk/session"
)

Expand Down Expand Up @@ -56,6 +56,6 @@ type Config struct {
SessionService session.Service
ArtifactService artifact.Service
MemoryService memory.Service
AgentLoader services.AgentLoader
AgentLoader agent.Loader
A2AOptions []a2asrv.RequestHandlerOption
}
3 changes: 1 addition & 2 deletions cmd/launcher/web/a2a/a2a_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
"google.golang.org/adk/agent"
"google.golang.org/adk/cmd/launcher"
"google.golang.org/adk/cmd/launcher/web"
"google.golang.org/adk/server/restapi/services"
"google.golang.org/adk/session"
"google.golang.org/genai"
)
Expand Down Expand Up @@ -82,7 +81,7 @@ func TestWebLauncher_ServesA2A(t *testing.T) {
t.Fatalf("agent.New() error = %v", err)
}
config := &launcher.Config{
AgentLoader: services.NewSingleAgentLoader(agnt),
AgentLoader: agent.NewSingleLoader(agnt),
SessionService: session.InMemoryService(),
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/launcher/web/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
"google.golang.org/adk/cmd/launcher"
weblauncher "google.golang.org/adk/cmd/launcher/web"
"google.golang.org/adk/internal/cli/util"
restapiweb "google.golang.org/adk/server/restapi/web"
"google.golang.org/adk/server/adkrest"
)

// apiConfig contains parametres for lauching ADK REST API
Expand Down Expand Up @@ -68,7 +68,7 @@ func (a *apiLauncher) UserMessage(webURL string, printer func(v ...any)) {
// SetupSubrouters adds the API router to the parent router.
func (a *apiLauncher) SetupSubrouters(router *mux.Router, config *launcher.Config) error {
// Create the ADK REST API handler
apiHandler := restapiweb.NewHandler(config)
apiHandler := adkrest.NewHandler(config)

// Wrap it with CORS middleware
corsHandler := corsWithArgs(a.config.frontendAddress)(apiHandler)
Expand Down
4 changes: 2 additions & 2 deletions cmd/launcher/web/webui/webui.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (
"google.golang.org/adk/cmd/launcher"
weblauncher "google.golang.org/adk/cmd/launcher/web"
"google.golang.org/adk/internal/cli/util"
"google.golang.org/adk/server/restapi/handlers"
"google.golang.org/adk/server/adkrest/controllers"
)

// webUIConfig contains parametres for lauching ADK Web UI
Expand Down Expand Up @@ -96,7 +96,7 @@ func (w *webUILauncher) AddSubrouter(router *mux.Router, pathPrefix string, back
BackendUrl string `json:"backendUrl"`
}{BackendUrl: backendAddress}
rUI.Methods("GET").Path("/assets/config/runtime-config.json").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
handlers.EncodeJSONResponse(runtimeConfigResponse, http.StatusOK, w)
controllers.EncodeJSONResponse(runtimeConfigResponse, http.StatusOK, w)
})

// redirect the user from / to pathPrefix (/ui/)
Expand Down
3 changes: 1 addition & 2 deletions examples/a2a/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import (
"google.golang.org/adk/model/gemini"
"google.golang.org/adk/runner"
"google.golang.org/adk/server/adka2a"
"google.golang.org/adk/server/restapi/services"
"google.golang.org/adk/session"
"google.golang.org/adk/tool"
"google.golang.org/adk/tool/geminitool"
Expand Down Expand Up @@ -120,7 +119,7 @@ func main() {
}

config := &launcher.Config{
AgentLoader: services.NewSingleAgentLoader(remoteAgent),
AgentLoader: agent.NewSingleLoader(remoteAgent),
}

l := full.NewLauncher()
Expand Down
6 changes: 3 additions & 3 deletions examples/mcp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ import (

"github.com/modelcontextprotocol/go-sdk/mcp"
"golang.org/x/oauth2"
"google.golang.org/adk/agent"
"google.golang.org/adk/agent/llmagent"
"google.golang.org/adk/cmd/launcher"
"google.golang.org/adk/cmd/launcher/full"
"google.golang.org/adk/model/gemini"
"google.golang.org/adk/server/restapi/services"
"google.golang.org/adk/tool"
"google.golang.org/adk/tool/mcptoolset"
"google.golang.org/genai"
Expand Down Expand Up @@ -110,7 +110,7 @@ func main() {
}

// Create LLMAgent with MCP tool set
agent, err := llmagent.New(llmagent.Config{
a, err := llmagent.New(llmagent.Config{
Name: "helper_agent",
Model: model,
Description: "Helper agent.",
Expand All @@ -124,7 +124,7 @@ func main() {
}

config := &launcher.Config{
AgentLoader: services.NewSingleAgentLoader(agent),
AgentLoader: agent.NewSingleLoader(a),
}
l := full.NewLauncher()
if err = l.Execute(ctx, config, os.Args[1:]); err != nil {
Expand Down
6 changes: 3 additions & 3 deletions examples/quickstart/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ import (
"log"
"os"

"google.golang.org/adk/agent"
"google.golang.org/adk/agent/llmagent"
"google.golang.org/adk/cmd/launcher"
"google.golang.org/adk/cmd/launcher/full"
"google.golang.org/adk/model/gemini"
"google.golang.org/adk/server/restapi/services"
"google.golang.org/adk/tool"
"google.golang.org/adk/tool/geminitool"
"google.golang.org/genai"
Expand All @@ -39,7 +39,7 @@ func main() {
log.Fatalf("Failed to create model: %v", err)
}

agent, err := llmagent.New(llmagent.Config{
a, err := llmagent.New(llmagent.Config{
Name: "weather_time_agent",
Model: model,
Description: "Agent to answer questions about the time and weather in a city.",
Expand All @@ -53,7 +53,7 @@ func main() {
}

config := &launcher.Config{
AgentLoader: services.NewSingleAgentLoader(agent),
AgentLoader: agent.NewSingleLoader(a),
}

l := full.NewLauncher()
Expand Down
Loading