Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

adk-go-pkg

Go Reference Go Report Card

Extension library for Google's ADK-Go.

adk-go-pkg provides production-ready building blocks that complement ADK-Go with capabilities it does not ship out of the box.

Features

Feature Description
OpenAI Model Provider Drop-in model.LLM adapter for any OpenAI-compatible API (OpenAI, Ollama, LiteLLM, OpenRouter, vLLM, Together AI). Supports both /v1/chat/completions and /v1/responses endpoints.
Anthropic Model Provider Drop-in model.LLM adapter for Anthropic's Messages API. Supports streaming, tool calling, images, structured output, thinking blocks, and prompt caching. Bedrock and Vertex AI are only supported through gateways that expose the Anthropic /v1/messages endpoint.
Generic AG-UI Server Framework-agnostic AG-UI protocol server (agui/) with event emitter, state management (RFC 6902 JSON Patch via evanphx/json-patch), predictive state tracker, tool orchestration, middleware, encrypted-value scrubbing, and SSE handler. Zero ADK dependency.
ADK-Go AG-UI Bridge Translates ADK-Go session events to AG-UI events (aguiadk/). Thread-to-session mapping, state/message snapshots, streaming tool calls, client tool hand-back (NextRun, Inline, and HandBack modes), HITL runstore & resume, tool call validation, activity snapshots, suppressed tool mode, and preset configurations.
Prompt Templating text/template-based prompt rendering engine with agent context data (state, user, session, artifacts, memory), 12 built-in functions, template registry, loader (files/embed.FS), and llmagent.InstructionProvider integration.
Planners Structured plan generation (ReAct JSON and free-form Thinking) that separates reasoning from execution.
File Artifact Service Filesystem-backed artifact.Service with automatic versioning and metadata sidecars.
Session Rewind Roll a session back to any prior event, recalculating state from replayed deltas.
Config Agent Loader Declare entire agent trees in YAML/JSON and build them at runtime via a factory registry. Now includes Agent Skills support.
Agent Skills Config Declarative skill integration via YAML/JSON. Supports filesystem sources with preload optimization and specific skill loading (wildcard or filtered by name).
Test Utilities Complete fake implementations of all ADK-Go interfaces for deterministic testing without external LLM providers. Includes FakeLLM, FakeAgent, FakeSession, FakeArtifactService, FakeMemoryService, FakeSessionService, and RunnerBuilder.
Evaluation Framework Evaluate agent performance with eval sets, built-in metrics (trajectory, response match, rubrics, safety, hallucinations), LLM-as-judge auto-raters, user simulation, and a local eval service. Mirrors ADK Python's eval package.
AG-UI MCP Support Inject MCP (Model Context Protocol) server tools into AG-UI agents. Two integration paths: MCPMiddleware for generic tool injection + server-side execution, and MCPAppsMiddleware for UI-enabled tools + proxied MCP requests. Bridge wiring via aguiadk.BuildMCPServerToolsets using ADK-Go's mcptoolset.

Installation

go get github.com/ieshan/adk-go-pkg

Quick Start

OpenAI Model Provider

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/ieshan/adk-go-pkg/model/openai"
	"google.golang.org/adk/v2/model"
	"google.golang.org/genai"
)

func main() {
	m, err := openai.New(openai.Config{
		Model:  "gpt-4o",
		APIKey: os.Getenv("OPENAI_API_KEY"),
	})
	if err != nil {
		log.Fatal(err)
	}

	req := &model.LLMRequest{
		Contents: []*genai.Content{
			genai.NewContentFromText("Hello!", "user"),
		},
	}

	for resp, err := range m.GenerateContent(context.Background(), req, false) {
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(resp.Content.Parts[0].Text)
	}
}

Detailed docs →

Anthropic Model Provider

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/ieshan/adk-go-pkg/model/anthropic"
	"google.golang.org/adk/v2/model"
	"google.golang.org/genai"
)

func main() {
	m, err := anthropic.New(anthropic.Config{
		Model:  "claude-sonnet-4-20250514",
		APIKey: os.Getenv("ANTHROPIC_API_KEY"),
	})
	if err != nil {
		log.Fatal(err)
	}

	req := &model.LLMRequest{
		Contents: []*genai.Content{
			genai.NewContentFromText("Hello!", "user"),
		},
	}

	for resp, err := range m.GenerateContent(context.Background(), req, false) {
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(resp.Content.Parts[0].Text)
	}
}

Detailed docs →

Generic AG-UI Server (agui/)

package main

import (
	"context"
	"iter"
	"log"
	"net/http"

	"github.com/ag-ui-protocol/ag-ui/sdks/community/go/pkg/core/events"
	"github.com/ag-ui-protocol/ag-ui/sdks/community/go/pkg/core/types"
	"github.com/ieshan/adk-go-pkg/agui"
)

func main() {
	agent := agui.AgentFunc(func(ctx context.Context, input types.RunAgentInput) iter.Seq2[events.Event, error] {
		ch := make(chan events.Event, 64)
		emitter := agui.NewEventEmitter(ch)
		go func() {
			defer close(ch)
			emitter.RunStarted(input.ThreadID, input.RunID)
			msgID := emitter.GenerateMessageID()
			role := "assistant"
			emitter.TextMessageStart(msgID, &role)
			emitter.TextMessageContent(msgID, "Hello from AG-UI!")
			emitter.TextMessageEnd(msgID)
			emitter.RunFinishedWithOptions(input.ThreadID, input.RunID)
		}()
		return agui.ChanToIter(ctx, ch)
	})

	handler, err := agui.Handler(agui.Config{Agent: agent})
	if err != nil {
		log.Fatal(err)
	}
	log.Fatal(http.ListenAndServe(":8080", handler))
}

Detailed docs →

ADK-Go AG-UI Bridge (aguiadk/)

package main

import (
	"iter"
	"log"
	"net/http"

	"github.com/ieshan/adk-go-pkg/agui"
	"github.com/ieshan/adk-go-pkg/aguiadk"
	"google.golang.org/adk/v2/agent"
	"google.golang.org/adk/v2/session"
	"google.golang.org/genai"
)

func main() {
	myAgent, err := agent.New(agent.Config{
		Name: "greeter",
		Run: func(ctx agent.InvocationContext) iter.Seq2[*session.Event, error] {
			return func(yield func(*session.Event, error) bool) {
				content := genai.NewContentFromText("Hello from ADK!", genai.RoleModel)
				yield(&session.Event{Author: "greeter", Content: content}, nil)
			}
		},
	})
	if err != nil {
		log.Fatal(err)
	}

	handler, err := aguiadk.Handler(
		aguiadk.Config{
			Agent:   myAgent,
			AppName: "my-chatbot",
			UserID:  "default-user",
		},
		agui.Config{},
	)
	if err != nil {
		log.Fatal(err)
	}
	http.Handle("/api/agent", handler)
	log.Fatal(http.ListenAndServe(":8080", nil))
}

Detailed docs →

Prompt Templating

package main

import (
	"fmt"
	"log"

	"github.com/ieshan/adk-go-pkg/prompt"
)

func main() {
	engine := prompt.New()
	tmpl, err := engine.Parse("greeting", "Hello {{.Input.name}}!")
	if err != nil {
		log.Fatal(err)
	}

	data := prompt.BuildData(map[string]any{"name": "world"})
	rendered, err := tmpl.Execute(data)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(rendered)
}

For llmagent.InstructionProvider integration:

provider, err := prompt.NewInstructionProvider(
	"You are {{.Agent.Name}}. User: {{.User.Text}}. Country: {{.State.Get \"country\"}}",
)
// Pass to llmagent.Config{InstructionProvider: provider}

Detailed docs →

Planners

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/ieshan/adk-go-pkg/planner"
	"google.golang.org/adk/v2/model"
)

func main() {
	var myLLM model.LLM // your model

	p := planner.NewPlanReAct(planner.PlanReActConfig{
		Model:    myLLM,
		MaxSteps: 5,
	})

	plan, err := p.GeneratePlan(context.Background(), &planner.PlanRequest{
		UserMessage: "Book a flight and send a confirmation email",
		ToolDescriptions: []planner.ToolDescription{
			{Name: "book_flight", Description: "Books a flight"},
			{Name: "send_email", Description: "Sends an email"},
		},
	})
	if err != nil {
		log.Fatal(err)
	}
	for i, step := range plan.Steps {
		fmt.Printf("Step %d: %s\n", i+1, step.Description)
	}
}

Detailed docs →

File Artifact Service

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/ieshan/adk-go-pkg/artifact/file"
	"google.golang.org/adk/v2/artifact"
	"google.golang.org/genai"
)

func main() {
	svc, err := file.New(file.Config{RootDir: "/tmp/artifacts"})
	if err != nil {
		log.Fatal(err)
	}
	defer svc.Close()

	resp, err := svc.Save(context.Background(), &artifact.SaveRequest{
		AppName:   "myapp",
		UserID:    "alice",
		SessionID: "session-1",
		FileName:  "report.txt",
		Part:      &genai.Part{Text: "quarterly report"},
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("saved version:", resp.Version)

	// Get artifact version metadata without loading content
	versionResp, err := svc.GetArtifactVersion(context.Background(), &artifact.GetArtifactVersionRequest{
		AppName:   "myapp",
		UserID:    "alice",
		SessionID: "session-1",
		FileName:  "report.txt",
		Version:   0, // 0 means latest
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("MIME type:", versionResp.ArtifactVersion.MimeType)
}

Detailed docs →

Session Rewind

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/ieshan/adk-go-pkg/session/rewind"
	"google.golang.org/adk/v2/session"
)

func main() {
	ctx := context.Background()
	svc := session.InMemoryService()

	// ... create session, append events ...

	rewound, err := rewind.RewindToIndex(ctx, svc, "my-app", "user-1", "session-abc", 2)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("events remaining:", rewound.Events().Len())
}

Detailed docs →

Config Agent Loader

package main

import (
	"context"
	"log"
	"os"

	"github.com/ieshan/adk-go-pkg/config"
	"google.golang.org/adk/v2/model"
	"google.golang.org/adk/v2/tool"
)

func main() {
	reg := config.NewRegistry()

	reg.RegisterModel("openai", func(cfg map[string]any) (model.LLM, error) {
		// build your model from cfg["model"] and other keys
		return nil, nil
	})
	reg.RegisterTool("search", func(cfg map[string]any) (tool.Tool, error) {
		// build your tool
		return nil, nil
	})

	root, err := os.OpenRoot(".")
	if err != nil {
		log.Fatal(err)
	}
	defer root.Close()

	agent, runCfg, liveRunCfg, ctxCacheCfg, err := config.LoadAndBuild(context.Background(), root, "agents/root.yaml", reg)
	if err != nil {
		log.Fatal(err)
	}
	_ = agent
	_ = runCfg       // *agent.RunConfig (may be nil)
	_ = liveRunCfg   // *agent.LiveRunConfig (may be nil)
	_ = ctxCacheCfg  // *config.ContextCacheConfig (may be nil)
}

Detailed docs →

Agent Skills Config

package main

import (
	"context"
	"log"
	"os"

	"github.com/ieshan/adk-go-pkg/config"
)

func main() {
	reg := config.NewRegistry()
	// Filesystem skill factory is built-in, no registration needed

	root, err := os.OpenRoot(".")
	if err != nil {
		log.Fatal(err)
	}
	defer root.Close()

	// Load agent with skills from YAML
	agent, _, _, _, err := config.LoadAndBuild(context.Background(), root, "agents/skills-agent.yaml", reg)
	if err != nil {
		log.Fatal(err)
	}
	// Agent now has access to skills defined in ./skills/
	_ = agent
}

Example YAML configuration:

name: skills-agent
agent_class: LlmAgent
model: openai/gpt-4o
instruction: "You are a helpful assistant with access to specialized skills."
skill_sets:
  - name: filesystem
    config:
      path: "./skills"
    preload: complete
    # Optional: load only specific skills instead of all
    # names: ["weather", "cooking"]

Detailed docs →

Test Utilities

package main

import (
    "context"
    "testing"

    "github.com/ieshan/adk-go-pkg/testutil"
    "google.golang.org/adk/v2/agent"
    "google.golang.org/adk/v2/agent/llmagent"
    "google.golang.org/adk/v2/runner"
    "google.golang.org/genai"
)

func TestMyAgent(t *testing.T) {
    ctx := context.Background()

    // Create fake LLM with preconfigured responses
    llm := testutil.NewFakeLLM(
        testutil.NewTextResponse("I'll help you!"),
    )

    // Build agent with fake LLM
    ag, _ := llmagent.New(llmagent.Config{
        Name:  "test-agent",
        Model: llm,
        Instruction: "You are helpful.",
    })

    // Use RunnerBuilder for end-to-end testing
    r, fakes, _ := testutil.NewRunnerBuilder().
        WithAgent(ag).
        BuildWithFakes()

    // Run and collect events
    events, _ := testutil.CollectEvents(r.Run(ctx, "user-1", "session-1",
        genai.NewContentFromText("Hello", "user"), agent.RunConfig{}))

    // Assert on results and calls
    if len(events) == 0 {
        t.Error("expected events")
    }
    if fakes.SessionService.AppendEventCount() == 0 {
        t.Error("expected events to be appended")
    }
}

Detailed docs →

Evaluation Framework

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"

	"github.com/ieshan/adk-go-pkg/eval"
	"google.golang.org/adk/v2/model"
	"google.golang.org/genai"
)

func main() {
	ctx := context.Background()

	// Create an in-memory eval sets manager and add a case.
	setsMgr := eval.NewInMemoryEvalSetsManager()
	if _, err := setsMgr.CreateEvalSet(ctx, "my-app", "basic-eval"); err != nil {
		log.Fatal(err)
	}
	if err := setsMgr.AddEvalCase(ctx, "my-app", "basic-eval", eval.EvalCase{
		EvalID: "case-1",
		Conversation: []eval.Invocation{
			{UserContent: genai.NewContentFromText("Hello", "user")},
		},
	}); err != nil {
		log.Fatal(err)
	}

	// Create an agent evaluator with your agent runner and LLM.
	var agentRunner eval.AgentRunner // your agent runner
	var llm model.LLM               // your judge LLM (optional)

	evaluator := eval.NewAgentEvaluator(
		agentRunner, setsMgr, nil, eval.DefaultMetricEvaluatorRegistry(),
		llm,
	)

	// Configure metrics with thresholds.
	config := eval.EvalConfig{
		Criteria: map[string]json.RawMessage{
			"tool_trajectory_avg_score": json.RawMessage(`{"threshold": 0.8}`),
		},
	}

	result, err := evaluator.Evaluate(ctx, "my-app", "basic-eval", config)
	if err != nil {
		log.Fatal(err)
	}
	for _, cr := range result.EvalCaseResults {
		fmt.Printf("Case %s: %s\n", cr.EvalID, cr.FinalEvalStatus)
	}
}

Detailed docs →

AG-UI MCP Support

Inject MCP server tools into any AG-UI agent and execute them server-side:

package main

import (
	"context"
	"iter"
	"log"
	"net/http"

	"github.com/ag-ui-protocol/ag-ui/sdks/community/go/pkg/core/events"
	"github.com/ag-ui-protocol/ag-ui/sdks/community/go/pkg/core/types"
	"github.com/ieshan/adk-go-pkg/agui"
)

func main() {
	agent := agui.AgentFunc(func(ctx context.Context, input types.RunAgentInput) iter.Seq2[events.Event, error] {
		// your agent logic
		return func(yield func(events.Event, error) bool) {}
	})

	mcpMW := agui.NewMCPMiddleware([]agui.MCPClientConfig{
		{Type: "http", URL: "https://example.com/mcp", ServerID: "srv1"},
	}, agui.MCPMiddlewareOptions{MaxIterations: 32})

	handler, err := agui.Handler(agui.Config{Agent: mcpMW(agent)})
	if err != nil {
		log.Fatal(err)
	}
	log.Fatal(http.ListenAndServe(":8080", handler))
}

For ADK-Go native integration, use aguiadk.BuildMCPServerToolsets to create mcptoolset.Toolset instances from MCP configs. See docs/agui-mcp.md for both integration paths, MCPAppsMiddleware for UI-enabled tools, and proxied MCP request handling.

Compatibility

  • Go 1.27+ — Uses iter.Seq2 and range-over-func.
  • ADK-Go v2.3.0+ (google.golang.org/adk/v2) — Required for Agent Skills support
  • GenAI v1.71.0 (google.golang.org/genai)

Recent Changes

  • OpenAI Responses API: The model/openai package now supports both /v1/chat/completions and /v1/responses endpoints. Select via Config.API. The Responses path supports reasoning items (Thought:true), flat tool declarations, function_call/function_call_output items, and typed SSE streaming events. See docs/openai-model.md.
  • Prompt Templating: New prompt package with text/template-based rendering engine, agent context data (state, user, session, artifacts, memory), 12 built-in functions, thread-safe TemplateRegistry, TemplateLoader (files/embed.FS), TemplateRef tagged union, and llmagent.InstructionProvider integration. Config loader supports InstructionTemplate field for declarative templated instructions. See docs/prompt.md.
  • AG-UI ADK Bridge Gap Fix: Closed all 10 AG-UI protocol feature gaps between the agui/aguiadk packages and the AG-UI example server. New features: disconnect cancellation, client tool hand-back (NextRun, Inline, and HandBack modes via ClientToolset), streaming tool calls (progressive TOOL_CALL_* from partial FunctionCall parts), HITL runstore & resume (RunStore with TTL, atomic claim, approval interrupts), tool call validation (synthetic IDs, error TOOL_CALL_RESULT for malformed calls), suppressed tool mode (Config.SuppressToolEvents + Config.ToolToStateMapper emits STATE_DELTA instead of TOOL_CALL_*), predictive state tracker (agui.PredictiveStateTracker for ghosted /_predictive deltas), activity snapshots (tool_use and approval_request), encrypted value scrubbing in MessagesSnapshot, and preset configurations (AgenticChatPreset, HumanInTheLoopPreset, GenerativeUIPreset, SharedStatePreset, InlineToolsPreset, HandBackPreset, PredictiveStatePreset, AgenticGenerativeUIPreset). StateManager.Apply now uses evanphx/json-patch/v5 for RFC 6902 compliance. See docs/aguiadk-bridge.md.
  • Evaluation Framework: New eval package with eval sets, 13 built-in metrics, LLM-as-judge evaluators, user simulation, and local eval service. Mirrors ADK Python eval package. See docs/eval.md.
  • Anthropic Model Provider: Drop-in model.LLM adapter for Anthropic's Messages API. Supports streaming, tool calling, images, structured output, thinking blocks, and prompt caching. See docs/anthropic-model.md.
  • Test Utilities: New testutil package with fake implementations of all ADK-Go interfaces (FakeLLM, FakeAgent, FakeSession, FakeArtifactService, FakeMemoryService, FakeSessionService, RunnerBuilder). Enables fast, deterministic testing without external LLM providers. See docs/testutil.md.
  • Agent Skills Config: Skillset support in config loader. Define skills in YAML/JSON with filesystem sources, preload optimization, and specific skill loading (wildcard or filtered by name).
  • OpenAI Model Provider: Supports genai FunctionResponse.Parts structure for function calling.
  • AG-UI MCP Support: MCP (Model Context Protocol) integration for AG-UI agents. MCPMiddleware injects MCP server tools and executes them server-side in an agentic loop. MCPAppsMiddleware handles UI-enabled tools (SEP-1865) and proxied MCP requests from frontends. aguiadk.BuildMCPServerToolsets bridges MCP servers to ADK-Go's native mcptoolset. See docs/agui-mcp.md.
  • File Artifact Service: GetArtifactVersion method for metadata retrieval without loading full content.

Dependencies

Beyond ADK-Go and google.golang.org/genai, the only additional direct dependencies are:

License

TBD

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages