jev

package module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 22, 2026 License: MIT Imports: 9 Imported by: 0

README

go-jev

Go
TypeSafe AI

Go Reference Go Report Card Go CI

Go client for the TypeSafe System One API. Standard library only, zero dependencies.

It sends a state and a set of typed questions, and returns calibrated answers: a choice from a list, a score on an ordered rubric, or the probability that a statement is true.

Install

go get github.com/shanehull/go-jev

Quick Start

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/shanehull/go-jev"
)

func main() {
	client, err := jev.New() // uses $TYPESAFE_API_KEY
	if err != nil {
		log.Fatal(err)
	}

	res, err := client.SystemOne(context.Background(),
		jev.State("I was charged twice, please fix this ASAP."),
		jev.Questions{
			"category": jev.Choice("What is this about", map[string]string{
				"billing":   "Payment or subscription issues",
				"technical": "Bugs or integration problems",
				"other":     "Anything else",
			}),
			"urgent": jev.Noul("The message conveys urgency"),
		},
	)
	if err != nil {
		log.Fatal(err)
	}

	category, _ := res.Choice("category")
	urgent, _ := res.Noul("urgent")
	fmt.Println(category.Choice, urgent.Noul)
}

API Key

Get a key from the TypeSafe dashboard.

// Environment variable (recommended)
client, _ := jev.New()

// Explicit option (overrides env)
client, _ := jev.New(jev.WithAPIKey("your-key"))

Usage

Primitives

A question is one of three primitives.

// Choice: the model picks one option and returns a probability for each.
jev.Choice("Which team should handle this", map[string]string{
    "billing":   "Payment or subscription issues",
    "technical": "Bugs or integration problems",
})

// Score: the model places the state on an ordered rubric.
jev.Score("How frustrated the customer appears", []string{
    "Calm, just stating facts",
    "Frustrated but civil",
    "Very angry, strong language",
})

// Noul: the model returns the probability that the statement is true.
jev.Noul("The message conveys urgency")
Answers

SystemOne returns a Response. Answers are typed. Use the accessors, or a type switch over the Answer interface.

res, err := client.SystemOne(ctx, jev.State(text), questions)

category, _ := res.Choice("category")       // ChoiceAnswer
frustration, _ := res.Score("frustration")  // ScoreAnswer
urgent, _ := res.Noul("urgent")             // NoulAnswer

category.Choice                 // "billing"
category.Confidence             // 0.78
category.Probabilities["billing"] // 0.85

frustration.Score               // 1.0
frustration.Legend["1"]         // "Frustrated but civil"

urgent.Noul                     // 1.0
States

State sends text. Value sends any JSON-marshalable value when the state is structured.

client.SystemOne(ctx, jev.State("plain text"), questions)
client.SystemOne(ctx, jev.Value(map[string]any{"text": "...", "region": "NSW1"}), questions)
Fan-out and batching

SystemOne answers every question for one state in a single request. Map evaluates the same questions against many states with bounded concurrency, retries, and optional rate limiting.

results := client.Map(ctx, states, questions,
    jev.WithConcurrency(8),
    jev.WithMaxRetries(2),
    jev.WithMinInterval(50*time.Millisecond),
)
for _, result := range results {
    if result.Err != nil {
        log.Print(result.Err)
        continue
    }
    // result.Response
}
Models

The default model is jev-latest. Override it per client or per call.

client, _ := jev.New(jev.WithModel("jev-latest"))
client.SystemOne(ctx, state, questions, jev.WithRequestModel("jev-latest"))
Low-level requests

SystemOne covers the common case. Evaluate sends a full Request when you need to build the state, model, and questions ahead of time.

req := jev.Request{
    State:     jev.Value(map[string]any{"text": text, "region": "NSW1"}),
    Model:     "jev-latest",
    Questions: questions,
}
res, err := client.Evaluate(ctx, req)
Retries

Transient failures are retried with exponential backoff. SystemOne and Evaluate retry HTTP 429, 529, and 5xx up to WithMaxAttempts times (default 3). Other 4xx responses are returned immediately.

client, _ := jev.New(jev.WithMaxAttempts(5))

APIError.Retryable reports whether a status code is worth retrying.

Error handling
_, err := client.SystemOne(ctx, state, questions)
var apiErr *jev.APIError
if errors.As(err, &apiErr) {
    fmt.Printf("TypeSafe error %d: %s\n", apiErr.StatusCode, apiErr.Message)
    if apiErr.Retryable() {
        // back off and try again
    }
}

API Coverage

Area Functions
Client New, WithAPIKey, WithBaseURL, WithHTTPClient, WithModel, WithMaxAttempts
Requests SystemOne, Evaluate, Request, WithRequestModel
Batching Map, WithConcurrency, WithMaxRetries, WithMinInterval, WithMapModel
Primitives Choice, Score, Noul, Questions
States State, Value
Answers Response.Choice, Response.Score, Response.Noul, ChoiceAnswer, ScoreAnswer, NoulAnswer

Examples

See examples/ for runnable programs:

  • systemone — classify a support ticket across all three primitives
  • choice — route a message to a team
  • score — rate severity on a rubric
  • noul — detect properties in text
  • batch — evaluate many states concurrently with Map
  • structured — send a JSON state with Value
  • verification — check a draft answer against its source

The package also carries godoc examples in example_test.go for every primitive and accessor. Run an example with:

TYPESAFE_API_KEY=... go run ./examples/systemone

Testing

Unit tests run offline with a mock server. Live API tests are opt-in.

go test ./...
TYPESAFE_API_KEY=... go test ./...

License

MIT. See LICENSE.

The TypeSafe AI logo is a trademark of TypeSafe AI, used only to identify the service this library calls.

Documentation

Overview

Package jev provides a client for the TypeSafe System One API.

It sends a state and a set of typed questions, and returns calibrated answers: a choice from a list, a score on an ordered rubric, or the probability that a statement is true.

Usage:

client, err := jev.New()
if err != nil {
	log.Fatal(err)
}
res, err := client.SystemOne(ctx, jev.State(text),
	jev.Questions{
		"material": jev.Noul("The text describes a material event"),
	})

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrNoQuestions = errors.New("jev: at least one question is required")

ErrNoQuestions is returned when a request has no questions.

Functions

This section is empty.

Types

type APIError

type APIError = internal.APIError

APIError represents a non-success response from the TypeSafe API. It is a type alias, so callers use errors.As.

type Answer

type Answer interface {
	Kind() string
}

Answer is a typed answer. Use a type switch, or the Choice, Score, and Noul accessors on Response.

type ChoiceAnswer

type ChoiceAnswer struct {
	Choice        string             `json:"choice"`
	Confidence    float64            `json:"confidence"`
	Probabilities map[string]float64 `json:"probabilities"`
}

ChoiceAnswer is the answer to a choice question.

func (ChoiceAnswer) Kind

func (ChoiceAnswer) Kind() string

Kind reports the answer type.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a TypeSafe System One client. Must be constructed via New. Safe for concurrent use by multiple goroutines.

API key resolution order:

  1. WithAPIKey("...")
  2. $TYPESAFE_API_KEY environment variable

func New

func New(opts ...ClientOption) (*Client, error)

New creates a System One client.

func (*Client) Evaluate

func (c *Client) Evaluate(ctx context.Context, req Request) (*Response, error)

Evaluate sends a request and returns the decoded response. Transient failures (HTTP 429, 529, and 5xx) are retried with exponential backoff.

func (*Client) Map

func (c *Client) Map(ctx context.Context, states []Input, questions Questions, opts ...MapOption) []MapResult

Map evaluates the same questions against many states with bounded concurrency, retries with exponential backoff on retryable failures, and optional rate limiting. Results are returned in input order.

Example
package main

import (
	"context"
	"fmt"

	"github.com/shanehull/go-jev"
)

func main() {
	client, _ := jev.New()
	states := []jev.Input{
		jev.State("The system is down"),
		jev.State("Thanks for the quick fix"),
	}
	results := client.Map(context.Background(), states,
		jev.Questions{"negative": jev.Noul("The text expresses a negative experience")},
		jev.WithConcurrency(2),
	)
	for _, result := range results {
		if result.Err == nil {
			noul, _ := result.Response.Noul("negative")
			fmt.Println(noul.Noul)
		}
	}
}

func (*Client) SystemOne

func (c *Client) SystemOne(ctx context.Context, state Input, questions Questions, opts ...RequestOption) (*Response, error)

SystemOne evaluates a set of questions against a state in a single request. This is the fan-out primitive: every question is answered in one round trip.

Example
package main

import (
	"context"
	"fmt"

	"github.com/shanehull/go-jev"
)

func main() {
	client, _ := jev.New()
	res, _ := client.SystemOne(context.Background(), jev.State("I was charged twice, please fix this ASAP."),
		jev.Questions{
			"category": jev.Choice("What is this about", map[string]string{
				"billing":   "Payment or subscription issues",
				"technical": "Bugs or integration problems",
				"other":     "Anything else",
			}),
			"urgent": jev.Noul("The message conveys urgency"),
		},
	)

	category, _ := res.Choice("category")
	urgent, _ := res.Noul("urgent")
	fmt.Println(category.Choice, urgent.Noul)
}

type ClientOption

type ClientOption func(*Client) error

ClientOption configures a Client.

func WithAPIKey

func WithAPIKey(key string) ClientOption

WithAPIKey sets the API key.

func WithBaseURL

func WithBaseURL(baseURL string) ClientOption

WithBaseURL sets a custom base URL.

func WithHTTPClient

func WithHTTPClient(hc *http.Client) ClientOption

WithHTTPClient sets a custom HTTP client.

func WithMaxAttempts

func WithMaxAttempts(n int) ClientOption

WithMaxAttempts sets the number of attempts made for a single request, including the first. It defaults to 3. Transient failures (HTTP 429, 529, and 5xx) are retried with exponential backoff.

func WithModel

func WithModel(model string) ClientOption

WithModel sets the default model. It defaults to jev-latest.

type Input

type Input struct {
	// contains filtered or unexported fields
}

Input is the state evaluated by the model. Construct it with State or Value.

func State

func State(text string) Input

State returns a text input.

func Value

func Value(v any) Input

Value returns a structured input, which is sent as JSON.

Example
package main

import (
	"context"
	"fmt"

	"github.com/shanehull/go-jev"
)

func main() {
	client, _ := jev.New()
	state := jev.Value(map[string]any{"text": "The build failed.", "env": "production"})
	res, _ := client.SystemOne(context.Background(), state,
		jev.Questions{"failure": jev.Noul("The text describes a failure")},
	)

	failure, _ := res.Noul("failure")
	fmt.Println(failure.Noul)
}

type MapOption

type MapOption func(*mapParams)

MapOption configures a Map call.

func WithConcurrency

func WithConcurrency(n int) MapOption

WithConcurrency sets the number of in-flight requests. It defaults to 4.

func WithMapModel

func WithMapModel(model string) MapOption

WithMapModel overrides the model for a Map call.

func WithMaxRetries

func WithMaxRetries(n int) MapOption

WithMaxRetries sets the number of retries after the first attempt for retryable failures. It defaults to 2.

func WithMinInterval

func WithMinInterval(d time.Duration) MapOption

WithMinInterval sets the minimum spacing between requests, a simple rate limit.

type MapResult

type MapResult struct {
	Response *Response
	Err      error
}

MapResult is the outcome of evaluating one state in a Map call.

type NoulAnswer

type NoulAnswer struct {
	Noul float64 `json:"noul"`
}

NoulAnswer is the answer to a noul question.

func (NoulAnswer) Kind

func (NoulAnswer) Kind() string

Kind reports the answer type.

type Question

type Question struct {
	Type         string          `json:"type"`
	Instructions string          `json:"instructions"`
	Criteria     json.RawMessage `json:"criteria,omitempty"`
}

Question is a typed question for the model. Construct it with Choice, Score, or Noul.

func Choice

func Choice(instructions string, criteria map[string]string) Question

Choice builds a choice question. The model picks one option and returns a probability for each option.

Example
package main

import (
	"context"
	"fmt"

	"github.com/shanehull/go-jev"
)

func main() {
	client, _ := jev.New()
	res, _ := client.SystemOne(context.Background(), jev.State("I was charged twice."),
		jev.Questions{
			"category": jev.Choice("What is this about", map[string]string{
				"billing":   "Payment or invoice issues",
				"technical": "Bugs or integration problems",
			}),
		})

	category, _ := res.Choice("category")
	fmt.Println(category.Choice, category.Confidence, category.Probabilities)
}

func Noul

func Noul(instructions string) Question

Noul builds a noul question. The model returns the probability that the statement is true.

Example
package main

import (
	"context"
	"fmt"

	"github.com/shanehull/go-jev"
)

func main() {
	client, _ := jev.New()
	res, _ := client.SystemOne(context.Background(), jev.State("Please fix this now, customers are blocked."),
		jev.Questions{
			"urgent": jev.Noul("The message conveys urgency"),
		})

	urgent, _ := res.Noul("urgent")
	fmt.Println(urgent.Noul)
}

func Score

func Score(instructions string, criteria []string) Question

Score builds a score question. The model places the state on an ordered rubric.

Example
package main

import (
	"context"
	"fmt"

	"github.com/shanehull/go-jev"
)

func main() {
	client, _ := jev.New()
	res, _ := client.SystemOne(context.Background(), jev.State("The site is completely down."),
		jev.Questions{
			"severity": jev.Score("How severe is the incident", []string{
				"Minor", "Degraded", "Major", "Outage",
			}),
		})

	severity, _ := res.Score("severity")
	fmt.Println(severity.Score, severity.Legend)
}

type Questions

type Questions map[string]Question

Questions maps a question name to its definition.

type Request

type Request struct {
	State     any
	Model     string
	Questions Questions
}

Request is a full System One request. Send it directly with Evaluate, or use SystemOne for the common case.

type RequestOption

type RequestOption func(*requestParams)

RequestOption configures a single SystemOne call.

func WithRequestModel

func WithRequestModel(model string) RequestOption

WithRequestModel overrides the model for one call.

type Response

type Response struct {
	Model   string            `json:"model"`
	Answers map[string]Answer `json:"answers"`
	Usage   Usage             `json:"usage"`
}

Response is the model's set of answers for one state.

func (*Response) Choice

func (r *Response) Choice(name string) (ChoiceAnswer, bool)

Choice returns the choice answer stored under name.

func (*Response) Noul

func (r *Response) Noul(name string) (NoulAnswer, bool)

Noul returns the noul answer stored under name.

func (*Response) Score

func (r *Response) Score(name string) (ScoreAnswer, bool)

Score returns the score answer stored under name.

func (*Response) UnmarshalJSON

func (r *Response) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes answers by their wire type discriminator.

type ScoreAnswer

type ScoreAnswer struct {
	Score         float64            `json:"score"`
	Confidence    float64            `json:"confidence"`
	Legend        map[string]string  `json:"legend"`
	Probabilities map[string]float64 `json:"probabilities"`
}

ScoreAnswer is the answer to a score question.

func (ScoreAnswer) Kind

func (ScoreAnswer) Kind() string

Kind reports the answer type.

type Usage

type Usage struct {
	InputTokens  int `json:"input_tokens"`
	OutputTokens int `json:"output_tokens"`
}

Usage reports token consumption for a request.

Directories

Path Synopsis
examples
batch command
Command batch evaluates many states concurrently with Map.
Command batch evaluates many states concurrently with Map.
choice command
Command choice routes a message to a team with a choice question.
Command choice routes a message to a team with a choice question.
noul command
Command noul returns the probability that a statement about a text is true.
Command noul returns the probability that a statement about a text is true.
score command
Command score rates an incident note on an ordered severity rubric.
Command score rates an incident note on an ordered severity rubric.
structured command
Command structured sends a JSON state with Value.
Command structured sends a JSON state with Value.
systemone command
Command systemone classifies a support ticket across the three primitives.
Command systemone classifies a support ticket across the three primitives.
verification command
Command verification checks a draft answer against its source, a guardrail pattern that catches unsupported or fabricated claims.
Command verification checks a draft answer against its source, a guardrail pattern that catches unsupported or fabricated claims.
Package internal provides the HTTP transport shared by the client.
Package internal provides the HTTP transport shared by the client.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL