OGuardAI
Integrations

Go SDK

A dependency-free Go client for the OGuardAI API with context-first methods, fail-closed guarded calls, and streaming

The sdk-go module provides a Go client for the OGuardAI API. It has no third-party dependencies, every network method takes a context.Context, and it enforces the runtime's trust boundary on the client side.

Install

go get github.com/oronts/oronts-guardai/sdk-go
import oguardai "github.com/oronts/oronts-guardai/sdk-go"

Requires Go 1.21 or newer.

Transform and Rehydrate

client, err := oguardai.NewClient(oguardai.Config{
    BaseURL: "http://localhost:3000",
    APIKey:  os.Getenv("GUARDAI_API_KEY"), // only if the server runs with auth
})
if err != nil {
    log.Fatal(err)
}
ctx := context.Background()

result, err := client.Transform(ctx, oguardai.TransformRequest{
    Input:  "Contact Julia Schneider at julia@example.com",
    Policy: "default",
})
// result.SafeText: "Contact {{person:p_001:e14c8b26f3a7}} at {{email:e_001:90d3f7a25c1b}}"

llmReply := callYourLLM(result.SafeText) // sees tokens only

restored, err := client.Rehydrate(ctx, oguardai.RehydrateRequest{
    Output:        llmReply,
    SessionState:  result.SessionState,
    OutputChannel: oguardai.ChannelCustomerEmail,
    RestoreMode:   oguardai.RestoreFormatted,
})
// restored.RestoredText: "Dear Frau Julia Schneider, ..."

Guarded Call and Chat

GuardedCall wraps any string -> string step: it transforms the input, runs your function on the tokenized text, and rehydrates the output. It fails closed, so if the transform returns no session state the function is never run and no unrestored output is returned.

answer, err := client.GuardedCall(ctx, func(safe string) (string, error) {
    return callYourLLM(safe), nil
}, "Draft a reply to Julia Schneider", oguardai.GuardedCallOptions{
    Policy:        "default",
    OutputChannel: oguardai.ChannelCustomerEmail,
})

GuardedChat tokenizes a whole conversation in one call and returns the safe messages plus the session state needed to restore the reply.

safeMessages, sessionState, err := client.GuardedChat(ctx, []oguardai.ChatMessage{
    {"role": "system", "content": "You are a support agent."},
    {"role": "user", "content": "I am Julia Schneider, julia@example.com"},
}, oguardai.GuardedChatOptions{Policy: "german-support"})

reply := callYourChatLLM(safeMessages) // sees tokens only
restored, err := client.RehydrateReply(ctx, reply, sessionState, oguardai.ChannelCustomerEmail)

Detect, Health, Capabilities

detected, err := client.Detect(ctx, oguardai.DetectRequest{
    Input: "Email test@example.com, SSN 123-45-6789",
})
for _, e := range detected.Entities {
    fmt.Printf("%s: %s (%.2f)\n", e.Type, e.Value, e.Confidence)
}

// IncludeValues is a pointer, so a false is transmitted verbatim to keep raw
// values out of a value-free caller (a plain bool would be dropped and default to true).
no := false
_, _ = client.Detect(ctx, oguardai.DetectRequest{Input: "SSN 123-45-6789", IncludeValues: &no})

health, _ := client.Health(ctx)      // health.Status == oguardai.HealthHealthy
caps, _ := client.Capabilities(ctx)  // caps.EntityTypes, caps.Languages, caps.Detectors

Sessions

Session carries session state across a multi-turn exchange. Use one per conversation; it is not safe for concurrent use.

session := client.NewSession("german-support")

turn1, _ := session.Transform(ctx, "Ich bin Anna Mueller, Kundennummer 948221", nil)
reply := callYourLLM(turn1.SafeText)
restored, _ := session.Rehydrate(ctx, reply, oguardai.ChannelCustomerEmail)

// Turn 2: entities are deduplicated across turns, so Anna Mueller stays p_001.
turn2, _ := session.Transform(ctx, "Meine E-Mail ist anna@example.com", nil)

Streaming

Streaming runs the full pipeline then streams the safe (transform) or restored (rehydrate) text. The terminal event carries the session state needed to rehydrate a streamed transform. The *Stream iterator spawns no goroutine and is bounded by the context, so cancelling ctx or calling Close stops it cleanly.

stream, err := client.TransformStream(ctx, "Contact Julia Schneider", oguardai.TransformStreamOptions{Policy: "default"})
if err != nil {
    log.Fatal(err)
}
defer stream.Close()

var sessionState string
for stream.Next() {
    ev := stream.Event()
    switch ev.Kind {
    case oguardai.EventText:
        fmt.Print(ev.Text)
    case oguardai.EventComplete:
        sessionState = ev.SessionState
    }
}
if err := stream.Err(); err != nil { // a terminal server error surfaces here
    log.Fatal(err)
}

Error Handling

Every failure is an *APIError. Match it with errors.As, read Code for the specific failure, or use the predicate helpers.

_, err := client.Transform(ctx, oguardai.TransformRequest{Input: "..."})
switch {
case oguardai.IsPolicyDenied(err):
    // 403: a redacted entity's rule set on_redact: reject
case oguardai.IsSessionExpired(err):
    // 410: session TTL elapsed
case oguardai.IsOutputBlocked(err):
    // 422: the output guard blocked newly generated PII
case oguardai.IsRateLimited(err):
    var apiErr *oguardai.APIError
    errors.As(err, &apiErr)
    fmt.Println("retry after:", apiErr.RetryAfter)
case err != nil:
    var apiErr *oguardai.APIError
    if errors.As(err, &apiErr) {
        fmt.Printf("error [%s] status=%d\n", apiErr.Code, apiErr.StatusCode)
    }
}

Predicates: IsAuth, IsValidation, IsPolicyDenied, IsSessionExpired, IsOutputBlocked, IsTokenRepair, IsRateLimited, IsTimeout.

Configuration

client, err := oguardai.NewClient(oguardai.Config{
    BaseURL: "http://localhost:3000", // required
    APIKey:  "your-api-key",          // optional: sent as X-API-Key
    Timeout: 30 * time.Second,        // optional per-attempt timeout (default 30s)
    Retry:   &oguardai.RetryConfig{MaxRetries: 3}, // optional; retries 429/503, honors Retry-After
})

Scope

This release covers Transform, Rehydrate, RehydrateFile (the JSON /v1/rehydrate/file route, same body as Rehydrate), Detect, Health, Capabilities, EvaluatePolicy, BatchTransform and BatchDetect, revocation (Revoke, BulkRevoke, RevocationCount), session lifecycle (SessionStatus, DeleteSession), the GuardedCall, GuardedChat, and RehydrateReply helpers, a stateful Session, and streaming. The RAG pipeline, the multipart transform file and image upload routes, and the admin endpoints (diagnostics, metrics, policy validate and reload) are served by the HTTP API and the TypeScript and Python SDKs; they are not yet wrapped in the Go client.