✨ Fully support agent args

feat #128
This commit is contained in:
OpenWaygate committed 2026-01-21 22:36:55 +08:00
1 parent 9371d0d6b4
commit fa3426588a
7 files changed
+190 -64

No files matched your search

-1
View File
@@ -3,7 +3,6 @@
*.json
*.mp4
*.jpg
*.md
.mcpregistry_github_token
.mcpregistry_registry_token
.env
+1
View File
@@ -18,6 +18,7 @@ go_library(
deps = [
"//cmd",
"//cmd/activity",
"//cmd/agent",
"//cmd/caption",
"//cmd/channel",
"//cmd/channelBanner",
-10
View File
@@ -3,13 +3,11 @@ load("@rules_go//go:def.bzl", "go_library")
go_library(
name = "cmd",
srcs = [
"agent.go",
"auth.go",
"mcp.go",
"root.go",
"version.go",
],
embedsrcs = ["INSTRUCTION.md"],
importpath = "github.com/eat-pray-ai/yutu/cmd",
visibility = ["//visibility:public"],
x_defs = {
@@ -27,13 +25,5 @@ go_library(
"@com_github_savioxavier_termlink//:termlink",
"@com_github_spf13_cobra//:cobra",
"@com_github_spf13_viper//:viper",
"@org_golang_google_adk//agent",
"@org_golang_google_adk//agent/llmagent",
"@org_golang_google_adk//cmd/launcher",
"@org_golang_google_adk//cmd/launcher/full",
"@org_golang_google_adk//model/gemini",
"@org_golang_google_adk//tool",
"@org_golang_google_adk//tool/mcptoolset",
"@org_golang_google_genai//:genai",
],
)
+26
View File
@@ -0,0 +1,26 @@
load("@rules_go//go:def.bzl", "go_library")
go_library(
name = "agent",
srcs = [
"agent.go",
"console.go",
"web.go",
],
embedsrcs = ["INSTRUCTION.md"],
importpath = "github.com/eat-pray-ai/yutu/cmd/agent",
visibility = ["//visibility:public"],
deps = [
"//cmd",
"@com_github_modelcontextprotocol_go_sdk//mcp",
"@com_github_spf13_cobra//:cobra",
"@org_golang_google_adk//agent",
"@org_golang_google_adk//agent/llmagent",
"@org_golang_google_adk//cmd/launcher",
"@org_golang_google_adk//cmd/launcher/full",
"@org_golang_google_adk//model/gemini",
"@org_golang_google_adk//tool",
"@org_golang_google_adk//tool/mcptoolset",
"@org_golang_google_genai//:genai",
],
)
+69 -53
View File
@@ -4,9 +4,11 @@
package agent
import (
"context"
_ "embed"
"log/slog"
"os"
"time"
rootCmd "github.com/eat-pray-ai/yutu/cmd"
"github.com/modelcontextprotocol/go-sdk/mcp"
@@ -29,74 +31,88 @@ const (
var (
//go:embed INSTRUCTION.md
instruction string
streamingMode string
idleTimeout time.Duration
port int
readTimeout time.Duration
writeTimeout time.Duration
sublaunchers []string
sseWriteTimeout time.Duration
webuiAddress string
a2aAgentURL string
apiServerAddress string
)
var agentCmd = &cobra.Command{
Use: "agent",
Short: agentShort,
Long: agentLong,
PreRun: func(cmd *cobra.Command, args []string) {
PersistentPreRun: func(cmd *cobra.Command, args []string) {
envInstruction, ok := os.LookupEnv("YUTU_AGENT_INSTRUCTION")
if ok && envInstruction != "" {
instruction = envInstruction
}
},
Run: func(cmd *cobra.Command, args []string) {
ctx := cmd.Context()
m, err := gemini.NewModel(
ctx, os.Getenv("GEMINI_MODEL"), &genai.ClientConfig{
APIKey: os.Getenv("GEMINI_API_KEY"),
Backend: genai.BackendGeminiAPI,
},
)
if err != nil {
slog.ErrorContext(ctx, "failed to create Gemini model", "error", err)
os.Exit(1)
}
clientTransport, serverTransport := mcp.NewInMemoryTransports()
_, err = rootCmd.Server.Connect(ctx, serverTransport, nil)
if err != nil {
slog.ErrorContext(ctx, "failed to connect to MCP server", "error", err)
os.Exit(1)
}
mcpToolSet, err := mcptoolset.New(
mcptoolset.Config{
Transport: clientTransport,
},
)
if err != nil {
slog.ErrorContext(ctx, "failed to create MCP tool set", "error", err)
}
a, err := llmagent.New(
llmagent.Config{
Model: m,
Name: "YouTube Copilot",
Instruction: instruction,
Toolsets: []tool.Toolset{mcpToolSet},
},
)
if err != nil {
slog.ErrorContext(ctx, "failed to create LLM agent", "error", err)
os.Exit(1)
}
config := &launcher.Config{
AgentLoader: agent.NewSingleLoader(a),
}
l := full.NewLauncher()
if err := l.Execute(ctx, config, os.Args[2:]); err != nil {
slog.ErrorContext(
ctx, "failed to launch agent",
"launch", l.CommandLineSyntax(), "error", err,
)
os.Exit(1)
}
_ = cmd.Help()
},
}
func init() {
rootCmd.RootCmd.AddCommand(agentCmd)
}
func launch(ctx context.Context, args []string) {
m, err := gemini.NewModel(
ctx, os.Getenv("GEMINI_MODEL"), &genai.ClientConfig{
APIKey: os.Getenv("GEMINI_API_KEY"),
Backend: genai.BackendGeminiAPI,
},
)
if err != nil {
slog.ErrorContext(ctx, "failed to create Gemini model", "error", err)
os.Exit(1)
}
clientTransport, serverTransport := mcp.NewInMemoryTransports()
_, err = rootCmd.Server.Connect(ctx, serverTransport, nil)
if err != nil {
slog.ErrorContext(ctx, "failed to connect to MCP server", "error", err)
os.Exit(1)
}
mcpToolSet, err := mcptoolset.New(
mcptoolset.Config{
Transport: clientTransport,
},
)
if err != nil {
slog.ErrorContext(ctx, "failed to create MCP tool set", "error", err)
}
a, err := llmagent.New(
llmagent.Config{
Model: m,
Name: "YouTube Copilot",
Instruction: instruction,
Toolsets: []tool.Toolset{mcpToolSet},
},
)
if err != nil {
slog.ErrorContext(ctx, "failed to create LLM agent", "error", err)
os.Exit(1)
}
config := &launcher.Config{
AgentLoader: agent.NewSingleLoader(a),
}
l := full.NewLauncher()
if err := l.Execute(ctx, config, args); err != nil {
slog.ErrorContext(
ctx, "failed to launch agent",
"launch", l.CommandLineSyntax(), "error", err,
)
os.Exit(1)
}
}
+31
View File
@@ -0,0 +1,31 @@
// Copyright 2026 eat-pray-ai & OpenWaygate
// SPDX-License-Identifier: Apache-2.0
package agent
import (
"github.com/spf13/cobra"
)
const (
consoleShort = "Start agent in console mode"
consoleLong = "Start agent in console mode"
)
var consoleCmd = &cobra.Command{
Use: "console",
Short: consoleShort,
Long: consoleLong,
Run: func(cmd *cobra.Command, args []string) {
launcherArgs := []string{"console"}
if streamingMode != "" {
launcherArgs = append(launcherArgs, "-streaming_mode", streamingMode)
}
launch(cmd.Context(), launcherArgs)
},
}
func init() {
agentCmd.AddCommand(consoleCmd)
consoleCmd.Flags().StringVarP(&streamingMode, "streamingMode", "m", "sse", "defines streaming mode: none|sse")
}
+63
View File
@@ -0,0 +1,63 @@
// Copyright 2026 eat-pray-ai & OpenWaygate
// SPDX-License-Identifier: Apache-2.0
package agent
import (
"slices"
"strconv"
"time"
"github.com/spf13/cobra"
)
var webCmd = &cobra.Command{
Use: "web",
Short: "Start agent in web mode",
Long: "start agent in web mode with additional sub-servers specified by sublaunchers",
Run: func(cmd *cobra.Command, args []string) {
launcherArgs := []string{"web"}
launcherArgs = append(launcherArgs, "-idle-timeout", idleTimeout.String())
launcherArgs = append(launcherArgs, "-port", strconv.Itoa(port))
launcherArgs = append(launcherArgs, "-read-timeout", readTimeout.String())
launcherArgs = append(launcherArgs, "-write-timeout", writeTimeout.String())
if slices.Contains(sublaunchers, "api") {
launcherArgs = append(
launcherArgs, "api",
"-sse-write-timeout", sseWriteTimeout.String(),
"-webui_address", webuiAddress,
)
}
if slices.Contains(sublaunchers, "a2a") {
launcherArgs = append(launcherArgs, "a2a", "-a2a_agent_url", a2aAgentURL)
}
if slices.Contains(sublaunchers, "webui") {
launcherArgs = append(launcherArgs, "webui", "-api_server_address", apiServerAddress)
}
launch(cmd.Context(), launcherArgs)
},
}
func init() {
agentCmd.AddCommand(webCmd)
// web flags
webCmd.Flags().DurationVarP(&idleTimeout, "idleTimeout", "i", time.Minute, "Server idle timeout")
webCmd.Flags().IntVarP(&port, "port", "p", 8080, "Localhost port for the server")
webCmd.Flags().DurationVarP(&readTimeout, "readTimeout", "r", 15*time.Second, "Server read timeout")
webCmd.Flags().DurationVarP(&writeTimeout, "writeTimeout", "w", 15*time.Second, "Server write timeout")
webCmd.Flags().StringSliceVarP(&sublaunchers, "sublaunchers", "l", []string{"api"}, "One or more sublaunchers: api, a2a, and webui")
// api flags
webCmd.Flags().DurationVarP(&sseWriteTimeout, "sseWriteTimeout", "s", 2*time.Minute, "SSE server write timeout")
webCmd.Flags().StringVarP(&webuiAddress, "webuiAddress", "W", "localhost:8080", "ADK WebUI address")
// a2a flags
webCmd.Flags().StringVarP(&a2aAgentURL, "a2aAgentUrl", "u", "http://localhost:8080", "A2A host URL")
// webui flags
webCmd.Flags().StringVarP(&apiServerAddress, "apiServerAddress", "U", "http://localhost:8080/api", "ADK REST API server address")
}