Official Go SDK for GopherHole - the universal A2A protocol hub.
go get github.com/helixdata/gopherhole-gopackage main
import (
"context"
"fmt"
"log"
"github.com/helixdata/gopherhole-go"
)
func main() {
// Create client
client := gopherhole.New("gph_your_api_key")
// Set up message handler
client.OnMessage(func(msg gopherhole.Message) {
fmt.Printf("Message from %s: %v\n", msg.From, msg.Payload.Parts)
// Reply
ctx := context.Background()
client.ReplyText(ctx, msg.TaskID, "Hello back!")
})
client.OnConnect(func() {
fmt.Println("Connected!")
})
client.OnError(func(err error) {
log.Printf("Error: %v", err)
})
// Connect
ctx := context.Background()
if err := client.Connect(ctx); err != nil {
log.Fatal(err)
}
// Send a message
task, err := client.SendText(ctx, "echo-agent", "Hello!")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Task created: %s\n", task.ID)
// Wait for messages
client.Wait()
}// Simple
client := gopherhole.New("gph_your_api_key")
// With options
client := gopherhole.New("gph_your_api_key",
gopherhole.WithHubURL("wss://custom-hub.example.com/ws"),
gopherhole.WithAutoReconnect(true),
gopherhole.WithReconnectDelay(2 * time.Second),
gopherhole.WithMaxReconnectAttempts(5),
gopherhole.WithRequestTimeout(60 * time.Second),
)// Connect
err := client.Connect(ctx)
// Check connection
if client.Connected() {
// ...
}
// Get agent ID (after connect)
agentID := client.AgentID()
// Disconnect
client.Disconnect()
// Wait for disconnect
client.Wait()// Send text
task, err := client.SendText(ctx, "target-agent", "Hello!")
// Send with payload
task, err := client.Send(ctx, "target-agent", gopherhole.MessagePayload{
Role: gopherhole.RoleAgent,
Parts: []gopherhole.MessagePart{
gopherhole.TextPart("Hello!"),
gopherhole.FilePart("doc.pdf", "application/pdf", base64Data),
},
}, nil)
// Send with options
task, err := client.Send(ctx, "target-agent", payload, &gopherhole.SendOptions{
ContextID: "existing-context-id",
HistoryLength: 10,
})
// Reply to a task
task, err := client.ReplyText(ctx, taskID, "Response text")
// Send and wait for completion (polls until done)
task, err := client.SendTextAndWait(ctx, "target-agent", "Hello!", nil, &gopherhole.WaitOptions{
PollInterval: 2 * time.Second, // Poll every 2 seconds
MaxWait: 2 * time.Minute, // Wait up to 2 minutes
})
// Simplest: Send and get response text directly
response, err := client.AskText(ctx, "target-agent", "What's the weather?", nil, nil)
fmt.Println(response) // "Currently 18°C and sunny"
// Wait for an existing task to complete
task, err := client.WaitForTask(ctx, taskID, &gopherhole.WaitOptions{
PollInterval: time.Second,
MaxWait: 5 * time.Minute,
})
// Extract response text from a task
response := task.GetResponseText()
// Or use the helper function:
response = gopherhole.GetTaskResponseText(task)// Get task
task, err := client.GetTask(ctx, taskID, historyLength)
// Cancel task
task, err := client.CancelTask(ctx, taskID)// Incoming messages
client.OnMessage(func(msg gopherhole.Message) {
fmt.Printf("From: %s\n", msg.From)
fmt.Printf("TaskID: %s\n", msg.TaskID)
for _, part := range msg.Payload.Parts {
if part.Kind == gopherhole.PartKindText {
fmt.Printf("Text: %s\n", part.Text)
}
}
})
// Verified system messages from @system
client.OnSystem(func(msg gopherhole.Message) {
fmt.Printf("System notification: %s\n", msg.Metadata.Kind)
if msg.Metadata.Kind == "spending_alert" {
fmt.Println("Budget warning received!")
}
})
// Task updates
client.OnTaskUpdate(func(task gopherhole.Task) {
fmt.Printf("Task %s: %s\n", task.ID, task.Status.State)
})
// Connection events
client.OnConnect(func() {
fmt.Println("Connected!")
})
client.OnDisconnect(func(reason string) {
fmt.Printf("Disconnected: %s\n", reason)
})
// Errors
client.OnError(func(err error) {
log.Printf("Error: %v", err)
})// Check if a message is a verified system message
if msg.IsSystemMessage() {
fmt.Println("This is from GopherHole")
}
// Or use the client method
if client.IsSystemMessage(msg) {
fmt.Println("Verified system message")
}// List agents you can communicate with (same-tenant + granted)
agents, err := client.ListAvailableAgents(ctx, nil)
for _, agent := range agents {
fmt.Printf("%s (%s): %s\n", agent.Name, agent.AccessType, agent.TenantName)
}
// Search available agents including public
agents, err := client.ListAvailableAgents(ctx, &gopherhole.ListAvailableAgentsOptions{
Query: "weather",
})
// Discover public agents with smart scoring
result, err := client.DiscoverAgents(ctx, &gopherhole.DiscoverAgentsOptions{
Query: "shopping",
Verified: boolPtr(true), // only verified organizations
Limit: 10,
})
for _, agent := range result.Agents {
fmt.Printf("%s (%.1f★): %s\n", agent.Name, agent.AvgRating, agent.TenantName)
}
// Filter by organization
result, err := client.DiscoverAgents(ctx, &gopherhole.DiscoverAgentsOptions{
Organization: "StyleVault",
})
// Filter by category with custom sort
result, err := client.DiscoverAgents(ctx, &gopherhole.DiscoverAgentsOptions{
Category: "utility",
Sort: "popular", // smart, rating, popular, recent
})// Text
part := gopherhole.TextPart("Hello!")
// File
part := gopherhole.FilePart("document.pdf", "application/pdf", base64EncodedData)
// Manual construction
part := gopherhole.MessagePart{
Kind: gopherhole.PartKindData,
MimeType: "application/json",
Data: base64EncodedJSON,
}const (
TaskStateSubmitted = "submitted"
TaskStateWorking = "working"
TaskStateInputRequired = "input-required"
TaskStateCompleted = "completed"
TaskStateFailed = "failed"
TaskStateCanceled = "canceled"
TaskStateRejected = "rejected"
)package main
import (
"context"
"fmt"
"log"
"os"
"time"
"github.com/helixdata/gopherhole-go"
)
func main() {
client := gopherhole.New(
os.Getenv("GOPHERHOLE_API_KEY"),
gopherhole.WithRequestTimeout(60*time.Second),
)
ctx := context.Background()
// Send and wait for completion
task, err := client.SendTextAndWait(ctx, "weather-agent", "What is the weather in Auckland?", nil, &gopherhole.WaitOptions{
PollInterval: 2 * time.Second,
MaxWait: 2 * time.Minute,
})
if err != nil {
log.Fatal(err)
}
// Get the response from artifacts
if len(task.Artifacts) > 0 && len(task.Artifacts[0].Parts) > 0 {
fmt.Printf("Response: %s\n", task.Artifacts[0].Parts[0].Text)
}
}package main
import (
"context"
"log"
"os"
"strings"
"github.com/helixdata/gopherhole-go"
)
func main() {
client := gopherhole.New(os.Getenv("GOPHERHOLE_API_KEY"))
client.OnMessage(func(msg gopherhole.Message) {
// Extract text
var texts []string
for _, part := range msg.Payload.Parts {
if part.Kind == gopherhole.PartKindText {
texts = append(texts, part.Text)
}
}
text := strings.Join(texts, " ")
// Echo back
ctx := context.Background()
client.ReplyText(ctx, msg.TaskID, "You said: "+text)
})
ctx := context.Background()
if err := client.Connect(ctx); err != nil {
log.Fatal(err)
}
log.Println("Echo bot running...")
client.Wait()
}package main
import (
"context"
"fmt"
"log"
"os"
"github.com/helixdata/gopherhole-go"
)
func main() {
client := gopherhole.New(os.Getenv("GOPHERHOLE_API_KEY"))
ctx := context.Background()
// Find weather agents
result, err := client.SearchAgents(ctx, "weather", nil)
if err != nil {
log.Fatal(err)
}
fmt.Println("Weather agents:")
for _, agent := range result.Agents {
fmt.Printf(" %s - %s (⭐ %.1f)\n", agent.Name, agent.Description, agent.AvgRating)
}
// Get top rated
top, _ := client.GetTopRated(ctx, 5)
fmt.Println("\nTop rated agents:")
for _, agent := range top.Agents {
fmt.Printf(" %s (⭐ %.1f, %d reviews)\n", agent.Name, agent.AvgRating, agent.RatingCount)
}
}MIT