Go SDK

Go 1.22+, zero-dependency (stdlib only). Functional options for config, http.RoundTripper instrumentation, and non-blocking background delivery. Run IDs are available immediately.

Install

go get github.com/agent-ping/agent-ping-go

Package is agentping.

Quickstart

package main

import (
    "context"
    "os"

    "github.com/agent-ping/agent-ping-go"
)

func main() {
    _ = agentping.Init(agentping.WithAPIKey(os.Getenv("AGENTPING_API_KEY")))
    defer agentping.Shutdown(context.Background())

    run := agentping.NewRun("support-triage",
        agentping.WithCustomerID("acme-corp"),
    )
    _ = run.Event("log", map[string]any{"message": "classifying ticket"})
    _ = run.Event("llm_call", map[string]any{
        "provider":      "anthropic",
        "model":         "claude-sonnet-4-5",
        "input_tokens":  1024,
        "output_tokens": 312,
        "latency_ms":    1430,
    })
    _ = run.Finish(agentping.FinishStatusSuccess,
        agentping.WithScores(map[string]any{"confidence": 0.93}),
    )
}

run.ID is populated synchronously on return. POST /v1/runs dispatches in the background.

Auto-instrumentation

Go has no equivalent global-rewrite mechanism. The SDK ships http.RoundTripper wrappers and helpers that build a ready-to-use *http.Client:

import (
    "net/http"

    "github.com/agent-ping/agent-ping-go"
    "github.com/agent-ping/agent-ping-go/instrumentation"
)

run := agentping.NewRun("answer-bot")

httpClient := instrumentation.AnthropicHTTPClient(http.DefaultTransport, run)
openaiClient := instrumentation.OpenAIHTTPClient(http.DefaultTransport, run)

Pass the client to the Anthropic or OpenAI SDK. For finer control, use the raw transport:

client := anthropic.NewClient(
    option.WithHTTPClient(&http.Client{
        Transport: instrumentation.NewAnthropicTransport(http.DefaultTransport, run),
    }),
)

The transport captures provider, model, token counts from the response body and emits llm_call. Cost is computed server-side.

Heartbeats

_ = agentping.Heartbeat("daily-summary", agentping.HeartbeatStatusOK,
    agentping.WithCostUSD(0.084),
    agentping.WithDurationMs(12_300),
    agentping.WithHeartbeatMetadata(map[string]any{"rows": 421}),
)

Same table as full runs.

Streaming

Streaming is wrapped at the http.RoundTripper layer. The wrapper installs an io.ReadCloser that observes chunks, accumulates token counts, and emits a single llm_call on body close. Reads are never delayed.

A mid-stream error emits a failed event with partial counts.

Context propagation

// Env var, picked up by agentping.NewRun automatically:
// AGENTPING_PARENT_RUN=run_eu_018f3a2b9c1d7e8fa4b9c2d7e8f1a3b6

// Explicit option:
run := agentping.NewRun("price-fetcher",
    agentping.WithParentRunID("run_eu_018f3a2b9c1d7e8fa4b9c2d7e8f1a3b6"),
)

Explicit option wins.

Configuration

Option Default Description
WithAPIKey AGENTPING_API_KEY env apk_<region>_<32 hex>
WithBaseURL derived from the key region (https://<region>.ingest.agentping.io); AGENTPING_BASE_URL also overrides Override for self-hosting or testing
WithQueueSize 1000 Max envelopes in memory
WithFlushInterval 2s Background drain interval
WithBatchSize 50 Max events per HTTP POST
WithHTTPClient &http.Client{} Inject your own (useful for tests)

Shutdown

No atexit-style hook (not idiomatic Go). Shutdown(ctx) drains the queue under the caller's context:

func main() {
    _ = agentping.Init(agentping.WithAPIKey(os.Getenv("AGENTPING_API_KEY")))
    defer agentping.Shutdown(context.Background())

    // your agent code
}

Skip Shutdown and in-flight events may be lost on process exit.

Source

github.com/agent-ping/agent-ping-go. Public surface in agentping.go.