Documentation
¶
Overview ¶
Package typesafe provides a Go client for the TypeSafe AI System One API.
Create a client with NewClient, then ask named Noul, Choice, and Score questions with Client.SystemOne. Clients may be shared by concurrent goroutines. Each call accepts a context that controls the entire operation, including retries.
Index ¶
- Constants
- type APIError
- type Choice
- type ChoiceAnswer
- type Client
- func (c *Client) Classify(ctx context.Context, state any, instructions any, options []string) (ChoiceAnswer, error)
- func (c *Client) IsTrue(ctx context.Context, state any, instructions any) (float64, error)
- func (c *Client) ListModels(ctx context.Context) (*ListModelsResponse, error)
- func (c *Client) Pick(ctx context.Context, state any, instructions any, candidates []string) (ChoiceAnswer, error)
- func (c *Client) SystemOne(ctx context.Context, state any, questions Questions) (*SystemOneResponse, error)
- type ClientOption
- type ListModelsResponse
- type ModelMetadata
- type Noul
- type NoulAnswer
- type NoulCriteria
- type Questions
- type ResponseError
- type Score
- type ScoreAnswer
- type SystemOneResponse
- type Usage
Examples ¶
Constants ¶
const ( DefaultBaseURL = "https://api.typesafe.ai" DefaultModel = "jev-latest" Version = "0.1.0" )
const NoneChoice = "none"
NoneChoice is Pick's fallback when none of the candidate spans fits.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type APIError ¶
type APIError struct {
StatusCode int
Body any
Headers http.Header
RequestID string
Endpoint string
Message string
}
APIError describes an unsuccessful HTTP response. Use errors.As to inspect it and StatusCode to distinguish authentication, rate limits, and other failures.
Example ¶
package main
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"log"
"net/http"
"github.com/RadixILS-Dev/typesafe-sdk-go"
)
// stubTransport returns canned JSON so these examples run offline and print
// deterministic output. Real programs can omit WithHTTPClient and use the
// SDK's default client, or supply their own for timeouts and instrumentation.
type stubTransport struct {
status int
body string
headers http.Header
}
func (s stubTransport) RoundTrip(request *http.Request) (*http.Response, error) {
headers := s.headers.Clone()
if headers == nil {
headers = http.Header{}
}
status := s.status
if status == 0 {
status = http.StatusOK
}
return &http.Response{
StatusCode: status,
Status: fmt.Sprintf("%d %s", status, http.StatusText(status)),
Header: headers,
Body: io.NopCloser(bytes.NewBufferString(s.body)),
Request: request,
}, nil
}
func stubClient(status int, headers http.Header, body string) *http.Client {
return &http.Client{Transport: stubTransport{status: status, body: body, headers: headers}}
}
func main() {
responseHeaders := http.Header{}
responseHeaders.Set("X-TypeSafe-Request-ID", "req-42")
responseHeaders.Set("Retry-After", "2")
client, err := typesafe.NewClient(
typesafe.WithAPIKey("your-api-key"),
typesafe.WithMaxAttempts(1), // Disable retries to inspect the first response.
typesafe.WithHTTPClient(stubClient(http.StatusTooManyRequests, responseHeaders,
`{"message":"Rate limit exceeded"}`)),
)
if err != nil {
log.Fatal(err)
}
_, err = client.ListModels(context.Background())
var api *typesafe.APIError
switch {
case errors.As(err, &api) && api.StatusCode == http.StatusTooManyRequests:
fmt.Printf("%d %s (request %s, retry after %ss)\n",
api.StatusCode, api.Message, api.RequestID, api.Headers.Get("Retry-After"))
case err != nil:
log.Fatal(err)
}
}
Output: 429 Rate limit exceeded (request req-42, retry after 2s)
type Choice ¶
type Choice struct {
Instructions any `json:"instructions,omitempty"`
Criteria any `json:"criteria"`
}
Choice selects a named option. Criteria accepts map[string]string for simple descriptions or map[string]any for structured descriptions and nil values. Empty strings are sent as empty strings, not converted to JSON null.
func (Choice) MarshalJSON ¶
type ChoiceAnswer ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client can be reused by concurrent goroutines. Configuration is fixed at construction.
func NewClient ¶
func NewClient(options ...ClientOption) (*Client, error)
NewClient creates a client using environment variables and SDK defaults. Options override those settings in order; the last option for a setting wins. It does not mutate or close a supplied HTTP client, or make network requests.
Example ¶
package main
import (
"fmt"
"log"
"github.com/RadixILS-Dev/typesafe-sdk-go"
)
func main() {
client, err := typesafe.NewClient(typesafe.WithAPIKey("your-api-key"))
if err != nil {
log.Fatal(err)
}
// Configuration is fixed at construction; the client is safe to share.
fmt.Println("client ready:", client != nil)
}
Output: client ready: true
func (*Client) Classify ¶
func (c *Client) Classify(ctx context.Context, state any, instructions any, options []string) (ChoiceAnswer, error)
Classify selects one of the supplied labels without adding a no-match option. State and instructions may be text or structured JSON.
func (*Client) IsTrue ¶
IsTrue returns the probability of yes, not a thresholded boolean. State and instructions may be text or structured JSON.
Example ¶
package main
import (
"bytes"
"context"
"fmt"
"io"
"log"
"net/http"
"github.com/RadixILS-Dev/typesafe-sdk-go"
)
// stubTransport returns canned JSON so these examples run offline and print
// deterministic output. Real programs can omit WithHTTPClient and use the
// SDK's default client, or supply their own for timeouts and instrumentation.
type stubTransport struct {
status int
body string
headers http.Header
}
func (s stubTransport) RoundTrip(request *http.Request) (*http.Response, error) {
headers := s.headers.Clone()
if headers == nil {
headers = http.Header{}
}
status := s.status
if status == 0 {
status = http.StatusOK
}
return &http.Response{
StatusCode: status,
Status: fmt.Sprintf("%d %s", status, http.StatusText(status)),
Header: headers,
Body: io.NopCloser(bytes.NewBufferString(s.body)),
Request: request,
}, nil
}
func stubClient(status int, headers http.Header, body string) *http.Client {
return &http.Client{Transport: stubTransport{status: status, body: body, headers: headers}}
}
func main() {
client, err := typesafe.NewClient(
typesafe.WithAPIKey("your-api-key"),
typesafe.WithHTTPClient(stubClient(http.StatusOK, nil,
`{"model":"jev-latest","usage":{},"answers":{"q":{"type":"noul","noul":0.77}}}`)),
)
if err != nil {
log.Fatal(err)
}
probability, err := client.IsTrue(context.Background(), "Invoice total: USD 42.00", "Does this state an invoice total?")
if err != nil {
log.Fatal(err)
}
// IsTrue returns a probability, not a thresholded boolean.
fmt.Printf("%.2f\n", probability)
}
Output: 0.77
func (*Client) ListModels ¶
func (c *Client) ListModels(ctx context.Context) (*ListModelsResponse, error)
ListModels lists the models available to the account.
Example ¶
package main
import (
"bytes"
"context"
"fmt"
"io"
"log"
"net/http"
"github.com/RadixILS-Dev/typesafe-sdk-go"
)
// stubTransport returns canned JSON so these examples run offline and print
// deterministic output. Real programs can omit WithHTTPClient and use the
// SDK's default client, or supply their own for timeouts and instrumentation.
type stubTransport struct {
status int
body string
headers http.Header
}
func (s stubTransport) RoundTrip(request *http.Request) (*http.Response, error) {
headers := s.headers.Clone()
if headers == nil {
headers = http.Header{}
}
status := s.status
if status == 0 {
status = http.StatusOK
}
return &http.Response{
StatusCode: status,
Status: fmt.Sprintf("%d %s", status, http.StatusText(status)),
Header: headers,
Body: io.NopCloser(bytes.NewBufferString(s.body)),
Request: request,
}, nil
}
func stubClient(status int, headers http.Header, body string) *http.Client {
return &http.Client{Transport: stubTransport{status: status, body: body, headers: headers}}
}
func main() {
client, err := typesafe.NewClient(
typesafe.WithAPIKey("your-api-key"),
typesafe.WithHTTPClient(stubClient(http.StatusOK, nil,
`{"models":[{"name":"jev-latest","description":"Fastest model","release_date":"2026-09-14"}]}`)),
)
if err != nil {
log.Fatal(err)
}
models, err := client.ListModels(context.Background())
if err != nil {
log.Fatal(err)
}
for _, model := range models.Models {
fmt.Printf("%s released %s\n", model.Name, model.ReleaseDate)
}
}
Output: jev-latest released 2026-09-14
func (*Client) Pick ¶
func (c *Client) Pick(ctx context.Context, state any, instructions any, candidates []string) (ChoiceAnswer, error)
Pick selects a candidate span verbatim, or NoneChoice if none fits. Candidates must not include the reserved NoneChoice label. It does not find spans in state; the caller supplies them. State and instructions may be text or structured JSON.
Example ¶
package main
import (
"bytes"
"context"
"fmt"
"io"
"log"
"net/http"
"github.com/RadixILS-Dev/typesafe-sdk-go"
)
// stubTransport returns canned JSON so these examples run offline and print
// deterministic output. Real programs can omit WithHTTPClient and use the
// SDK's default client, or supply their own for timeouts and instrumentation.
type stubTransport struct {
status int
body string
headers http.Header
}
func (s stubTransport) RoundTrip(request *http.Request) (*http.Response, error) {
headers := s.headers.Clone()
if headers == nil {
headers = http.Header{}
}
status := s.status
if status == 0 {
status = http.StatusOK
}
return &http.Response{
StatusCode: status,
Status: fmt.Sprintf("%d %s", status, http.StatusText(status)),
Header: headers,
Body: io.NopCloser(bytes.NewBufferString(s.body)),
Request: request,
}, nil
}
func stubClient(status int, headers http.Header, body string) *http.Client {
return &http.Client{Transport: stubTransport{status: status, body: body, headers: headers}}
}
func main() {
client, err := typesafe.NewClient(
typesafe.WithAPIKey("your-api-key"),
typesafe.WithHTTPClient(stubClient(http.StatusOK, nil,
`{"model":"jev-latest","usage":{},"answers":{"q":{"type":"choice","choice":"USD 42.00","confidence":0.91,"probabilities":{"USD 42.00":0.91,"USD 21.00":0.09,"none":0.00}}}}`)),
)
if err != nil {
log.Fatal(err)
}
answer, err := client.Pick(context.Background(), "Invoice total: USD 42.00",
"Which amount is the invoice total?", []string{"USD 42.00", "USD 21.00"})
if err != nil {
log.Fatal(err)
}
if answer.Choice == typesafe.NoneChoice {
fmt.Println("no candidate matched")
return
}
// The winning candidate is returned verbatim, without trimming or rewriting.
fmt.Printf("%s (%.2f)\n", answer.Choice, answer.Confidence)
}
Output: USD 42.00 (0.91)
func (*Client) SystemOne ¶
func (c *Client) SystemOne(ctx context.Context, state any, questions Questions) (*SystemOneResponse, error)
SystemOne evaluates named questions against JSON-serializable state. Question validation belongs to the API. The context bounds the entire call, including retry waits; each attempt sends the same encoded body.
Example ¶
package main
import (
"bytes"
"context"
"fmt"
"io"
"log"
"net/http"
"github.com/RadixILS-Dev/typesafe-sdk-go"
)
// stubTransport returns canned JSON so these examples run offline and print
// deterministic output. Real programs can omit WithHTTPClient and use the
// SDK's default client, or supply their own for timeouts and instrumentation.
type stubTransport struct {
status int
body string
headers http.Header
}
func (s stubTransport) RoundTrip(request *http.Request) (*http.Response, error) {
headers := s.headers.Clone()
if headers == nil {
headers = http.Header{}
}
status := s.status
if status == 0 {
status = http.StatusOK
}
return &http.Response{
StatusCode: status,
Status: fmt.Sprintf("%d %s", status, http.StatusText(status)),
Header: headers,
Body: io.NopCloser(bytes.NewBufferString(s.body)),
Request: request,
}, nil
}
func stubClient(status int, headers http.Header, body string) *http.Client {
return &http.Client{Transport: stubTransport{status: status, body: body, headers: headers}}
}
const systemOneBody = `{"model":"jev-latest","usage":{"input_tokens":12,"output_tokens":3},"answers":{
"billing":{"type":"noul","noul":0.98},
"tone":{"type":"choice","choice":"angry","confidence":0.9,"probabilities":{"calm":0.1,"angry":0.9}},
"urgency":{"type":"score","score":1.7,"confidence":0.8,"legend":{"0":"low","1":"medium","2":"high"},"probabilities":{"0":0.1,"1":0.1,"2":0.8}}}}`
func main() {
client, err := typesafe.NewClient(
typesafe.WithAPIKey("your-api-key"),
typesafe.WithHTTPClient(stubClient(http.StatusOK, nil, systemOneBody)),
)
if err != nil {
log.Fatal(err)
}
result, err := client.SystemOne(context.Background(), "I was charged twice. Please help ASAP.", typesafe.Questions{
"billing": typesafe.Noul{Instructions: "Is this about billing?"},
"tone": typesafe.Choice{
Instructions: "What is the tone?",
Criteria: map[string]string{"calm": "", "angry": ""},
},
"urgency": typesafe.Score{
Instructions: "How urgent is this?",
Criteria: []string{"low", "medium", "high"},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("billing %.2f\n", result.Nouls["billing"].Noul)
fmt.Printf("tone %s\n", result.Choices["tone"].Choice)
fmt.Printf("urgency %.1f\n", result.Scores["urgency"].Score)
fmt.Printf("tokens %d in / %d out\n", *result.Usage.InputTokens, *result.Usage.OutputTokens)
}
Output: billing 0.98 tone angry urgency 1.7 tokens 12 in / 3 out
type ClientOption ¶
type ClientOption func(*clientConfig)
ClientOption configures a client at construction.
func WithBaseURL ¶
func WithBaseURL(url string) ClientOption
WithBaseURL overrides TYPESAFE_BASE_URL and the default API URL.
func WithHTTPClient ¶
func WithHTTPClient(client *http.Client) ClientOption
WithHTTPClient uses the supplied non-nil client unchanged, including its timeout and redirect policy. The SDK does not mutate or close it.
func WithMaxAttempts ¶
func WithMaxAttempts(attempts int) ClientOption
WithMaxAttempts sets the total number of attempts, including the initial request. The default is three; one disables retries. Must be positive.
func WithModel ¶
func WithModel(model string) ClientOption
WithModel overrides TYPESAFE_DEFAULT_MODEL and the default model.
type ListModelsResponse ¶
type ListModelsResponse struct {
RequestID string
Models []ModelMetadata
}
type ModelMetadata ¶
type Noul ¶
type Noul struct {
Instructions any `json:"instructions,omitempty"`
Criteria any `json:"criteria,omitempty"`
}
Noul asks a yes/no question. Instructions may be a string, JSON object, or array. Nil optional fields are omitted; explicit empty strings are preserved.
func (Noul) MarshalJSON ¶
type NoulAnswer ¶
type NoulAnswer struct{ Noul float64 }
type NoulCriteria ¶
NoulCriteria describes the "true" and "false" outcomes. Values may be strings, JSON objects, arrays, or nil. Extra keys are passed through to the API.
type Questions ¶
Questions maps names to Noul, Choice, Score, or raw JSON question objects. Values are serialized unchanged; the API validates their shape.
Example ¶
Questions are plain Go values: typed questions add their own "type" tag, and descriptions may be structured JSON. The API validates the result.
package main
import (
"encoding/json"
"fmt"
"log"
"github.com/RadixILS-Dev/typesafe-sdk-go"
)
func main() {
questions := typesafe.Questions{
"fraud": typesafe.Noul{
Instructions: map[string]any{"question": "Is this refund suspicious?", "rules": []string{"Ignore tone."}},
Criteria: typesafe.NoulCriteria{"true": "Suspicious", "false": "Ordinary"},
},
"queue": typesafe.Choice{
Instructions: "Which team should handle this?",
Criteria: map[string]any{"billing": nil, "chargeback": "Disputed card payment"},
},
}
data, err := json.Marshal(questions)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(data))
}
Output: {"fraud":{"type":"noul","instructions":{"question":"Is this refund suspicious?","rules":["Ignore tone."]},"criteria":{"false":"Ordinary","true":"Suspicious"}},"queue":{"type":"choice","instructions":"Which team should handle this?","criteria":{"billing":null,"chargeback":"Disputed card payment"}}}
type ResponseError ¶
ResponseError identifies missing or malformed required data in a successful response. Err preserves the underlying JSON error when available.
func (*ResponseError) Error ¶
func (e *ResponseError) Error() string
func (*ResponseError) Unwrap ¶
func (e *ResponseError) Unwrap() error
type Score ¶
type Score struct {
Instructions any `json:"instructions,omitempty"`
Criteria any `json:"criteria"`
}
Score evaluates an ordered rubric, with levels starting at zero. Criteria accepts []string or a slice/array of JSON descriptions (for example []any). The API validates the rubric.
func (Score) MarshalJSON ¶
type ScoreAnswer ¶
type SystemOneResponse ¶
type SystemOneResponse struct {
Model string
Usage Usage
RequestID string
RawAnswers map[string]json.RawMessage
Nouls map[string]NoulAnswer
Choices map[string]ChoiceAnswer
Scores map[string]ScoreAnswer
}
SystemOneResponse groups recognized answers by type. RawAnswers contains every answer, including unknown types and extra fields, without silently dropping data.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
basic
command
|
|
|
claims
command
This example adjudicates an auto-insurance claim: fourteen grounded yes/no questions go to SystemOne in a single call over one JSON claim file, and the answers are then cross-checked against arithmetic computed offline from that same file.
|
This example adjudicates an auto-insurance claim: fourteen grounded yes/no questions go to SystemOne in a single call over one JSON claim file, and the answers are then cross-checked against arithmetic computed offline from that same file. |
|
extraction
command
This example finds candidate strings in code, then asks TypeSafe which role each candidate plays.
|
This example finds candidate strings in code, then asks TypeSafe which role each candidate plays. |
|
phone
command
This example selects a phone number with Pick and an office country with Classify.
|
This example selects a phone number with Pick and an office country with Classify. |