Go SDK
The Go SDK (github.com/memoturn/memoturn/sdks/go) is dependency-free (stdlib only). Install
with go get github.com/memoturn/memoturn/sdks/go. Configure it via New(...) options or the
env vars MEMOTURN_BASE_URL, MEMOTURN_PUBLIC_KEY, MEMOTURN_SECRET_KEY,
MEMOTURN_ENVIRONMENT, MEMOTURN_MAX_BUFFER_SIZE (buffered-event cap, default 10000),
and MEMOTURN_ALLOW_HTTP (suppress the cleartext-http warning) — options win over
env vars.
Flushing is request-sized: a large buffer (e.g. after an outage) is sent as several
POST /v1/ingest calls of at most 1000 events / ~10 MB each (WithMaxBatchSize), never one
over-limit request the API would reject. After a transient failure the background flusher
backs off exponentially with jitter (honouring Retry-After); an explicit Flush() always
tries.
Tracing
Section titled “Tracing”mt := memoturn.New( memoturn.WithBaseURL("http://localhost:3001"), memoturn.WithCredentials("pk-mt-dev", "sk-mt-dev"),)defer mt.Shutdown() // flush remaining events before exit
tr := mt.Trace(memoturn.TraceInput{Name: "support-chat", UserID: "u_123", SessionID: "s_1", SessionPath: "/support/chat"})
gen := tr.Generation(memoturn.GenerationInput{ Model: "gpt-4o", Provider: "openai", SpanInput: memoturn.SpanInput{Input: "How do I reset my password?"},})gen.End(memoturn.GenerationInput{ SpanInput: memoturn.SpanInput{Output: "Click 'Forgot password'…"}, Usage: &memoturn.Usage{PromptTokens: 12, CompletionTokens: 20, TotalTokens: 32},})
tr.Score(memoturn.ScoreInput{Name: "quality", Value: memoturn.Float(0.9)})The client buffers events and flushes as batches to POST /v1/ingest (size-, interval-, and
shutdown-triggered). Spans nest via span.Span({...}); Tool/Agent helpers classify a span
as a TOOL/AGENT observation, and any kind can be set explicitly via SpanInput.ObservationType.
Prompts
Section titled “Prompts”p, err := mt.GetPrompt("support-reply", memoturn.WithBucketKey("s_1")) // A/B-stable bucketingtext := p.CompileText(map[string]any{"name": "Ada"}) // TEXT promptsmsgs := p.CompileChat(map[string]any{"name": "Ada"}) // CHAT promptsGetPrompt resolves the "production" channel by default; pick another with
memoturn.WithPromptChannel("staging").
Caching and outage behavior
Section titled “Caching and outage behavior”Prompt resolution sits on your request path, so GetPrompt caches on the client and degrades
instead of failing:
| Situation | Behavior |
|---|---|
| Within the TTL (default 60s) | Served from memory, no network call |
| Past the TTL | Stale value returned immediately, refreshed in a background goroutine |
| Fetch fails, something cached | Keeps serving the cached value — a memoturn outage won’t take down your app |
| Fetch fails, nothing cached | WithPromptFallback if you gave one, otherwise the error |
p, err := mt.GetPrompt("support-reply", memoturn.WithPromptCacheTTL(5*time.Minute), memoturn.WithPromptFallback(&memoturn.CompiledPrompt{Name: "support-reply", Type: "TEXT", Content: "…"}),)Concurrent resolves of the same prompt are coalesced into one request, and the cache is bounded
(500 entries) so a per-user A/B split can’t grow it without limit. Pass
memoturn.WithPromptCacheTTL(0) to disable caching, or call mt.ClearPromptCache() to force the
next resolve to refetch.
Datasets, experiment runs & CI quality gates
Section titled “Datasets, experiment runs & CI quality gates”mt.CreateDataset("qa-golden", "golden questions")added, _ := mt.AddDatasetItems("qa-golden", []memoturn.DatasetItem{ {Input: "What is memoturn?", ExpectedOutput: "An open-source AI engineering platform."},})
ds, _ := mt.GetDataset("qa-golden")// … run your model against ds.Items, build []memoturn.RunLink …mt.RecordRun("qa-golden", "run-42", links, nil)
res, _ := mt.EvaluateGate("qa-golden", "run-42", map[string]memoturn.GateThreshold{ "faithfulness": {Min: memoturn.Float(0.8)}, "quality": {MaxRegression: memoturn.Float(0.05)}, // vs a baseline run}, "main")if !res.Passed { log.Fatalf("quality gate failed: %v", res.Failures)}EvaluateGate is built for CI: fail the pipeline when a dataset run’s evaluator scores regress
past a threshold or baseline.
Guardrails
Section titled “Guardrails”v, _ := mt.CheckGuardrails("My email is ada@example.com")switch v.Verdict {case "block": log.Fatal("input blocked by guardrails")case "redact": fmt.Println("proceeding with redacted input:", v.RedactedText)}Scans text against the project’s runtime guardrails (PII, prompt injection, blocked terms) before sending user content to an LLM, or before returning a model’s output.
OpenTelemetry
Section titled “OpenTelemetry”Already instrumented with OTel? mt.OTLPConfig() returns the endpoint and Basic-auth header for
the official exporter (go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp) — the
SDK itself stays dependency-free.
endpoint, headers := mt.OTLPConfig()exp, _ := otlptracehttp.New(ctx, otlptracehttp.WithEndpointURL(endpoint), otlptracehttp.WithHeaders(headers))provider := sdktrace.NewTracerProvider(sdktrace.WithBatcher(exp))No OpenAI-wrapper or LangChain-callback equivalent today (no widely-used Go clients to wrap the
same way as the JS/Python SDKs) — instrument Go LLM calls via Generation/Span directly, or
via the OTel path above.
See sdks/go/README.md for
the full API and
BEST_PRACTICES.md
for failure semantics, buffer sizing, and PII masking.