Documentation
¶
Overview ¶
Package decide is a Go client for decision models: TypeSafe's Jev, Cloudflare's Clef, and OpenAI's GPT-6 Luna. Client.SystemOne takes its name from TypeSafe's term for this kind of model, System One.
A decision model evaluates a piece of state (a ticket, a diff, a JSON record) against a set of typed questions and returns typed answers with probabilities that code can act on directly. It does not generate text. NewClient connects to TypeSafe; the backend package connects to any provider through the same API. The templates package holds the decide command's built-in questions.
Eval asks one typed question and returns an Evaluation. Pick selects an original candidate or abstains, returning a Decision. Both retain response evidence and apply no application thresholds.
Three primitives cover most questions:
- Noul: does a condition hold? The answer is P(yes) in [0,1].
- Choice: which one of these options? The answer is the chosen option, the full distribution, and a confidence.
- Score: where on this ordered scale? The answer is the probability-weighted level, the distribution, and a confidence.
Build a Request, add questions with Ask to get typed handles, send it with Client.SystemOne, and read answers back through the handles:
client, err := decide.NewClient() // reads TYPESAFE_API_KEY
if err != nil {
return err
}
req := decide.NewRequest(ticketText)
billing := decide.Ask(req, "billing", decide.Noul("Is this ticket about billing?"))
tone := decide.Ask(req, "tone", decide.Choice("What is the customer's tone?",
decide.Option("calm"), decide.Option("frustrated"), decide.Option("angry")))
resp, err := client.SystemOne(ctx, req)
if err != nil {
return err
}
b, _ := billing.From(resp) // *decide.NoulAnswer
t, _ := tone.From(resp) // *decide.ChoiceAnswer
fmt.Println(resp.Model, b.Noul, t.Choice, t.Confidence)
Every answer is checked against its question before it is returned: the keys match, required fields are present, a choice is one of the offered options, probabilities are finite and in range. On a failure SystemOne returns the response together with an *InvalidAnswersError, and Response.Invalid names the keys that failed; the other keys stay usable. Failures where the numbers merely disagree beyond tolerance (the choice is not the argmax, probabilities do not sum to about 1) also match ErrInconsistentAnswer, so a caller can choose to accept them.
Transient failures (408, 429, 5xx, and connection errors) are retried with backoff that honors Retry-After. Errors from the API are *APIError values that match sentinels such as ErrRateLimited and ErrAuth with errors.Is and carry the request ID.
Question and answer types are open. A question type from another package decodes into its own answer type when it implements AnswerMaker; answer types can also be registered with RegisterAnswerType; and an answer type nobody knows decodes to a *RawAnswer instead of failing the response. RawQuestion sends a question type this package does not model.
The decidetest package provides a fake server for tests and examples.
Example ¶
Ask a typed question and read its validated answer.
package main
import (
"context"
"fmt"
"log"
"github.com/deepnoodle-ai/decide"
"github.com/deepnoodle-ai/decide/decidetest"
)
// startFake starts a fake API with canned answers, standing in for
// https://api.typesafe.ai so the examples run without a key.
func startFake() *decidetest.Server {
srv, err := decidetest.Start()
if err != nil {
log.Fatal(err)
}
srv.Answer("billing", decidetest.NoulAnswer(0.93))
return srv
}
func main() {
srv := startFake()
defer srv.Close()
client, err := srv.NewClient() // in production: decide.NewClient()
if err != nil {
log.Fatal(err)
}
req := decide.NewRequest("I was charged twice this month and nobody answers my emails.")
billing := decide.Ask(req, "billing", decide.Noul("Is this ticket about billing?"))
resp, err := client.SystemOne(context.Background(), req)
if err != nil {
log.Fatal(err)
}
answer, err := billing.From(resp)
if err != nil {
log.Fatal(err)
}
fmt.Printf("billing: %.2f\n", answer.Noul)
}
Output: billing: 0.93
Index ¶
- Constants
- Variables
- func AnswerAs[A Answer](resp *Response, key string) (A, error)
- func Attempt(ctx context.Context) int
- func RegisterAnswerType(typ string, newAnswer func() Answer) error
- type APIError
- type Answer
- type AnswerError
- type AnswerMaker
- type AnswerValidator
- type CallOption
- type Candidate
- type ChoiceAnswer
- type ChoiceOption
- type ChoiceQuestion
- func (q *ChoiceQuestion) MakeAnswer() Answer
- func (q *ChoiceQuestion) MarshalJSON() ([]byte, error)
- func (q *ChoiceQuestion) NewAnswer() *ChoiceAnswer
- func (q *ChoiceQuestion) QuestionType() string
- func (q *ChoiceQuestion) UnmarshalJSON(data []byte) error
- func (q *ChoiceQuestion) ValidateAnswer(a Answer) error
- type Client
- type ClientOption
- func WithAPIKey(key string) ClientOption
- func WithAttemptTimeout(d time.Duration) ClientOption
- func WithBaseURL(url string) ClientOption
- func WithHTTPClient(hc *http.Client) ClientOption
- func WithLogBodies(on bool) ClientOption
- func WithLogger(l *slog.Logger) ClientOption
- func WithMaxRetries(n int) ClientOption
- func WithModel(name string) ClientOption
- func WithRetryBackoff(initial, max time.Duration) ClientOption
- func WithTransport(t Transport) ClientOption
- func WithUserAgent(product string) ClientOption
- func WithValidation(on bool) ClientOption
- func WithoutEnvironment() ClientOption
- type Decision
- type Evaluation
- type HTTPTransport
- type HTTPTransportConfig
- type Handle
- type InvalidAnswersError
- type Model
- type ModelList
- type ModelsService
- type NoulAnswer
- type NoulCriteria
- type NoulOption
- type NoulQuestion
- type Prob
- type Question
- type QuestionFor
- type RawAnswer
- type RawQuestion
- type Request
- type RequestOption
- type Response
- type ScoreAnswer
- func (a *ScoreAnswer) AnswerType() string
- func (a *ScoreAnswer) Level() int
- func (a *ScoreAnswer) LevelLabel(i int) any
- func (a *ScoreAnswer) Levels() int
- func (a *ScoreAnswer) MarshalJSON() ([]byte, error)
- func (a *ScoreAnswer) Normalized() float64
- func (a *ScoreAnswer) ProbabilityAt(i int) (float64, bool)
- func (a *ScoreAnswer) UnmarshalJSON(data []byte) error
- type ScoreQuestion
- func (q *ScoreQuestion) MakeAnswer() Answer
- func (q *ScoreQuestion) MarshalJSON() ([]byte, error)
- func (q *ScoreQuestion) NewAnswer() *ScoreAnswer
- func (q *ScoreQuestion) QuestionType() string
- func (q *ScoreQuestion) UnmarshalJSON(data []byte) error
- func (q *ScoreQuestion) ValidateAnswer(a Answer) error
- type Transport
- type Usage
- type ValidationDetail
Examples ¶
Constants ¶
const ( ReasonMissingField = "missing_field" ReasonMissingAnswer = "missing_answer" ReasonUnexpectedAnswer = "unexpected_answer" ReasonDecodeFailed = "decode_failed" ReasonTypeMismatch = "type_mismatch" ReasonNotFinite = "not_finite" ReasonOutOfRange = "out_of_range" ReasonProbabilityKeys = "probability_keys" ReasonChoiceNotOption = "choice_not_option" ReasonChoiceNotArgmax = "choice_not_argmax" ReasonLegendKeys = "legend_keys" ReasonProbabilitySum = "probability_sum" ReasonCustom = "custom" )
Answer validation reasons, used in AnswerError.Reason.
const Version = "0.0.0"
Version is the version of this SDK. It is sent in the User-Agent and X-TypeSafe-SDK headers.
Variables ¶
var ( ErrAuth = errors.New("decide: authentication failed") // 401, 403 ErrValidation = errors.New("decide: request validation failed") // 422 ErrRateLimited = errors.New("decide: rate limited") // 429 ErrOverloaded = errors.New("decide: overloaded") // 529 ErrServer = errors.New("decide: server error") // any 5xx, including 529 ErrNoAPIKey = errors.New("decide: no API key: set TYPESAFE_API_KEY or use WithAPIKey") ErrInvalidRequest = errors.New("decide: invalid request") ErrInvalidAnswer = errors.New("decide: invalid answer") // ErrInconsistentAnswer marks an answer that is well formed but whose // numbers disagree with each other beyond tolerance: the choice is not // the argmax, the score is outside its range, or the probabilities do not // sum to about 1. It is always accompanied by ErrInvalidAnswer. ErrInconsistentAnswer = errors.New("decide: inconsistent answer") ErrDecode = errors.New("decide: cannot decode response") )
Sentinel errors. Match them with errors.Is.
Functions ¶
func AnswerAs ¶
AnswerAs is the non-handle form of Handle.From, with the same rules: a zero A only for missing_answer and type_mismatch; for a key listed in resp.Invalid it returns the answer and that error together, so a caller who accepts ErrInconsistentAnswer can still use the answer.
func Attempt ¶
Attempt returns the zero-based attempt number the client is on, for transports that want to send a retry-count header. 0 outside the client.
func RegisterAnswerType ¶
RegisterAnswerType registers a constructor for an answer type, used when a response is decoded without its request (or the request's question does not implement AnswerMaker). It returns an error if typ is empty, newAnswer is nil, or typ is already registered, including the built-in types.
The constructor must return a pointer that encoding/json can unmarshal into.
Types ¶
type APIError ¶
type APIError struct {
StatusCode int
Type string // detail.error_type, or Details[0].Type, or ""
Message string // message extracted from the body
RequestID string // x-typesafe-request-id
RetryAfter time.Duration // parsed server delay; 0 if absent
Body []byte // raw body, key redacted
Details []ValidationDetail // 422 only
}
APIError is a non-2xx response from the API.
Example ¶
Branch on the kind of failure with errors.Is; every API error carries the request ID.
package main
import (
"context"
"errors"
"fmt"
"log"
"github.com/deepnoodle-ai/decide"
"github.com/deepnoodle-ai/decide/decidetest"
)
// startFake starts a fake API with canned answers, standing in for
// https://api.typesafe.ai so the examples run without a key.
func startFake() *decidetest.Server {
srv, err := decidetest.Start()
if err != nil {
log.Fatal(err)
}
srv.Answer("billing", decidetest.NoulAnswer(0.93))
return srv
}
func main() {
srv := startFake()
defer srv.Close()
srv.Overloaded(3) // more than the default two retries
client, err := srv.NewClient()
if err != nil {
log.Fatal(err)
}
req := decide.NewRequest("state")
decide.Ask(req, "billing", decide.Noul("About billing?"))
_, err = client.SystemOne(context.Background(), req)
if ae, ok := errors.AsType[*decide.APIError](err); ok {
fmt.Println(ae.StatusCode, errors.Is(err, decide.ErrOverloaded), errors.Is(err, decide.ErrServer), ae.RequestID)
}
}
Output: 529 true true req_3
func (*APIError) Unwrap ¶
Unwrap returns the sentinels for StatusCode: ErrAuth for 401 and 403, ErrValidation for 422, ErrRateLimited for 429, ErrOverloaded and ErrServer for 529, ErrServer for other 5xx, and none for 408 and other 4xx.
Discrepancy: /api says 401 for a missing or invalid key, but a live request without a key returned 403. Both map to ErrAuth. The OpenAPI spec lists only 422 as an error response; the docs list 401, 422, 429, and 529. We handle all of them.
type Answer ¶
type Answer interface {
AnswerType() string
}
Answer is one entry in Response.Answers. Implementations outside this package are allowed.
func DecodeAnswer ¶
DecodeAnswer reads "type", constructs the registered answer, and unmarshals into it. An unregistered type returns a *RawAnswer and nil error. A registered type that fails to unmarshal returns a *RawAnswer with Err set, and the same error. Input that is not an object with a string "type" returns a *RawAnswer with Type "" and Err set.
type AnswerError ¶
type AnswerError struct {
Key string // question key
Type string // question type; for unexpected_answer, the answer's AnswerType()
Reason string // one of the Reason constants
Detail string // human-readable specifics, e.g. `choice "x" not in options`
Err error // underlying error for decode_failed and custom
// contains filtered or unexported fields
}
AnswerError reports one answer that failed validation or could not be read through a handle.
func (*AnswerError) Error ¶
func (e *AnswerError) Error() string
Error returns `decide: answer "k" (choice): choice_not_option: ...`.
func (*AnswerError) Unwrap ¶
func (e *AnswerError) Unwrap() []error
Unwrap returns ErrInvalidAnswer, ErrInconsistentAnswer for consistency failures (choice_not_argmax, probability_sum, and a score out of range), and Err if non-nil.
type AnswerMaker ¶
type AnswerMaker interface {
MakeAnswer() Answer
}
AnswerMaker is optionally implemented by a Question so responses decode into the question's own answer type without registering it. MakeAnswer returns a new zero answer; it is the non-generic twin of QuestionFor.NewAnswer. When a response is decoded with its request, an answer whose wire type equals the question's type is made by MakeAnswer, before the registry is consulted.
type AnswerValidator ¶
AnswerValidator is optionally implemented by a Question. The client calls it during validation after the generic checks (answer present, no unexpected answers, decodable, matching type).
type CallOption ¶
type CallOption func(*callConfig)
CallOption overrides a client setting for one SystemOne call. Invalid values make SystemOne return an error wrapping ErrInvalidRequest.
func WithCallAttemptTimeout ¶
func WithCallAttemptTimeout(d time.Duration) CallOption
WithCallAttemptTimeout sets the per-attempt timeout for one call. d >= 0; 0 disables it.
func WithCallMaxRetries ¶
func WithCallMaxRetries(n int) CallOption
WithCallMaxRetries sets the retry count for one call. n >= 0.
func WithCallValidation ¶
func WithCallValidation(on bool) CallOption
WithCallValidation turns answer validation on or off for one call.
type Candidate ¶
Candidate pairs an original item with the JSON description sent to the model. Item is returned unchanged; only Description enters the question.
type ChoiceAnswer ¶
type ChoiceAnswer struct {
Choice string
Probabilities map[string]float64
Confidence float64
Extra map[string]json.RawMessage
// contains filtered or unexported fields
}
ChoiceAnswer is the answer to a ChoiceQuestion.
func (*ChoiceAnswer) AnswerType ¶
func (a *ChoiceAnswer) AnswerType() string
AnswerType returns "choice".
func (*ChoiceAnswer) Margin ¶
func (a *ChoiceAnswer) Margin() float64
Margin returns top P minus runner-up P; with one option it returns top P. With no probabilities it returns 0.
func (*ChoiceAnswer) MarshalJSON ¶
func (a *ChoiceAnswer) MarshalJSON() ([]byte, error)
MarshalJSON writes "type" first, then the fields, then Extra sorted by key. Probabilities are written with keys sorted, not in wire order (Go maps are unordered), so a round trip is equal semantically, not byte for byte.
func (*ChoiceAnswer) Ranked ¶
func (a *ChoiceAnswer) Ranked() []Prob
Ranked returns probabilities sorted by P descending, ties by Key ascending.
Example ¶
Rank a Choice answer's full distribution rather than only its top option.
package main
import (
"fmt"
"github.com/deepnoodle-ai/decide"
)
func main() {
a := &decide.ChoiceAnswer{
Choice: "refund",
Probabilities: map[string]float64{"refund": 0.55, "exchange": 0.35, "other": 0.10},
}
for _, p := range a.Ranked() {
fmt.Printf("%-8s %.2f\n", p.Key, p.P)
}
fmt.Printf("margin %.2f\n", a.Margin())
}
Output: refund 0.55 exchange 0.35 other 0.10 margin 0.20
func (*ChoiceAnswer) UnmarshalJSON ¶
func (a *ChoiceAnswer) UnmarshalJSON(data []byte) error
UnmarshalJSON decodes a choice answer. All three fields are required.
type ChoiceOption ¶
type ChoiceOption struct {
Key string
Description any // nil encodes as null: "interpreted by its name alone"
}
ChoiceOption is one option of a ChoiceQuestion. The model sees both the key and the description.
func Option ¶
func Option(key string, description ...any) ChoiceOption
Option builds a ChoiceOption. Zero descriptions means nil (null); more than one panics, because the variadic exists only to make the description optional.
func OptionsFromMap ¶
func OptionsFromMap[V any](m map[string]V) []ChoiceOption
OptionsFromMap converts a map to options sorted by key, for callers who hold criteria as a map and want deterministic order.
type ChoiceQuestion ¶
type ChoiceQuestion struct {
Instructions any
Criteria []ChoiceOption // encoded as a JSON object in slice order
Extra map[string]any
}
ChoiceQuestion asks which one of a set of options applies.
func Choice ¶
func Choice(instructions any, options ...ChoiceOption) *ChoiceQuestion
Choice builds a Choice question. Options are sent in the order given.
func (*ChoiceQuestion) MakeAnswer ¶
func (q *ChoiceQuestion) MakeAnswer() Answer
MakeAnswer returns q.NewAnswer().
func (*ChoiceQuestion) MarshalJSON ¶
func (q *ChoiceQuestion) MarshalJSON() ([]byte, error)
MarshalJSON encodes the question with options in slice order. It fails if an option key is empty or repeated.
func (*ChoiceQuestion) NewAnswer ¶
func (q *ChoiceQuestion) NewAnswer() *ChoiceAnswer
NewAnswer returns a new *ChoiceAnswer.
func (*ChoiceQuestion) QuestionType ¶
func (q *ChoiceQuestion) QuestionType() string
QuestionType returns "choice".
func (*ChoiceQuestion) UnmarshalJSON ¶
func (q *ChoiceQuestion) UnmarshalJSON(data []byte) error
UnmarshalJSON decodes a choice question, preserving option order.
func (*ChoiceQuestion) ValidateAnswer ¶
func (q *ChoiceQuestion) ValidateAnswer(a Answer) error
ValidateAnswer checks a choice answer against the options. Structural: fields present, values finite and in [0,1], probability keys equal the option keys, the choice is an option. Consistency: the choice is the argmax (ties allowed) and probabilities sum to about 1.
type Client ¶
type Client struct {
Models *ModelsService // set by NewClient, never reassigned
// contains filtered or unexported fields
}
Client calls the TypeSafe API. It is safe for concurrent use: every field is set by NewClient and only read afterwards, and retry jitter uses the math/rand/v2 top-level functions, which are safe for concurrent use.
func NewClient ¶
func NewClient(opts ...ClientOption) (*Client, error)
NewClient returns a client. Each setting resolves from its option, then its environment variable (unless WithoutEnvironment), then the default:
API key TYPESAFE_API_KEY none: ErrNoAPIKey Base URL TYPESAFE_BASE_URL https://api.typesafe.ai Default model TYPESAFE_DEFAULT_MODEL jev-latest Log level TYPESAFE_LOG_LEVEL silent
Environment values are trimmed; blank means unset. TYPESAFE_LOG_LEVEL accepts debug, info, warn, error, or off, and is ignored when WithLogger is given.
func (*Client) DefaultModel ¶
DefaultModel returns the model used when a request's Model is empty.
func (*Client) SystemOne ¶
func (c *Client) SystemOne(ctx context.Context, req *Request, opts ...CallOption) (*Response, error)
SystemOne sends req to POST /v1/systemone and returns the response.
A nil or invalid request, an invalid CallOption, or a request that cannot be encoded returns an error wrapping ErrInvalidRequest without a network call. If req.Model is empty the client's default model is sent; req itself is never modified. Transient failures are retried.
When validation is on (the default) and an answer does not match its question, SystemOne returns a non-nil response AND an *InvalidAnswersError, and resp.Invalid names the bad keys. Callers who treat any error as fatal stay safe; callers who want partial results use resp.Invalid or the handles, which fail only for the affected keys.
If ctx ends, the error satisfies errors.Is(err, ctx.Err()) and, when an attempt had already failed, errors.As still reaches that attempt's *APIError.
Example (PartialResults) ¶
A validation failure returns the response and an error. Keys that passed stay usable; resp.Invalid names the ones that failed.
package main
import (
"context"
"errors"
"fmt"
"log"
"github.com/deepnoodle-ai/decide"
"github.com/deepnoodle-ai/decide/decidetest"
)
// startFake starts a fake API with canned answers, standing in for
// https://api.typesafe.ai so the examples run without a key.
func startFake() *decidetest.Server {
srv, err := decidetest.Start()
if err != nil {
log.Fatal(err)
}
srv.Answer("billing", decidetest.NoulAnswer(0.93))
return srv
}
func main() {
srv := startFake()
defer srv.Close()
// A deliberately inconsistent answer: "calm" is not the most likely option.
srv.Answer("tone", &decide.ChoiceAnswer{
Choice: "calm",
Probabilities: map[string]float64{"calm": 0.2, "angry": 0.8},
Confidence: 0.6,
})
client, err := srv.NewClient()
if err != nil {
log.Fatal(err)
}
req := decide.NewRequest("You people are useless.")
billing := decide.Ask(req, "billing", decide.Noul("Is this ticket about billing?"))
tone := decide.Ask(req, "tone", decide.Choice("Tone?", decide.Option("calm"), decide.Option("angry")))
resp, err := client.SystemOne(context.Background(), req)
if resp == nil {
log.Fatal(err)
}
fmt.Println("error:", err)
for key, ae := range resp.Invalid {
fmt.Println("invalid:", key, ae.Reason, errors.Is(ae, decide.ErrInconsistentAnswer))
}
if b, err := billing.From(resp); err == nil {
fmt.Printf("billing still usable: %.2f\n", b.Noul)
}
t, err := tone.From(resp)
fmt.Println("tone:", t.Choice, "err:", err != nil)
}
Output: error: decide: 1 invalid answer: answer "tone" (choice): choice_not_argmax: choice "calm" has P=0.2, max is 0.8 invalid: tone choice_not_argmax true billing still usable: 0.93 tone: calm err: true
type ClientOption ¶
type ClientOption func(*clientConfig) error
ClientOption configures a Client. Options that receive invalid values make NewClient return an error.
func WithAPIKey ¶
func WithAPIKey(key string) ClientOption
WithAPIKey sets the API key. It overrides TYPESAFE_API_KEY. An empty key makes NewClient return ErrNoAPIKey.
func WithAttemptTimeout ¶
func WithAttemptTimeout(d time.Duration) ClientOption
WithAttemptTimeout sets the timeout for each attempt, which covers reading the body. Default 10s; 0 disables it. It bounds each attempt only; the overall bound for a call, including retries and sleeps, comes from ctx.
func WithBaseURL ¶
func WithBaseURL(url string) ClientOption
WithBaseURL sets the API base URL. It overrides TYPESAFE_BASE_URL. It must be an absolute http or https URL; a path prefix is kept.
func WithHTTPClient ¶
func WithHTTPClient(hc *http.Client) ClientOption
WithHTTPClient sets the *http.Client used by the native transport. Its Timeout, if any, applies in addition to WithAttemptTimeout.
func WithLogBodies ¶
func WithLogBodies(on bool) ClientOption
WithLogBodies adds request and response bodies to Debug records. Default false. Headers are never logged.
func WithLogger ¶
func WithLogger(l *slog.Logger) ClientOption
WithLogger sets the logger. It overrides TYPESAFE_LOG_LEVEL. The default discards everything.
func WithMaxRetries ¶
func WithMaxRetries(n int) ClientOption
WithMaxRetries sets how many times a failed attempt is retried. n >= 0; default 2.
func WithModel ¶
func WithModel(name string) ClientOption
WithModel sets the default model, used when Request.Model is empty. It overrides TYPESAFE_DEFAULT_MODEL.
func WithRetryBackoff ¶
func WithRetryBackoff(initial, max time.Duration) ClientOption
WithRetryBackoff sets the initial and maximum backoff. Defaults 500ms, 5s.
func WithTransport ¶
func WithTransport(t Transport) ClientOption
WithTransport replaces the native HTTP transport, for gateways and compatible servers. It cannot be combined with WithAPIKey, WithBaseURL, WithHTTPClient, or WithUserAgent, which configure the native transport. With it, TYPESAFE_API_KEY and TYPESAFE_BASE_URL are not read.
func WithUserAgent ¶
func WithUserAgent(product string) ClientOption
WithUserAgent prepends a product token such as "myapp/1.2" to the User-Agent header.
func WithValidation ¶
func WithValidation(on bool) ClientOption
WithValidation turns answer validation on or off. Default true.
func WithoutEnvironment ¶
func WithoutEnvironment() ClientOption
WithoutEnvironment makes NewClient read no TYPESAFE_* environment variables, so only options and defaults apply.
type Decision ¶
type Decision[T any] struct { Item T Index int Picked bool Answer *ChoiceAnswer Response *Response }
Decision contains an original candidate or an explicit abstention. Index is -1 and Item is zero when Picked is false. Answer preserves the original Choice evidence; Response preserves the complete client response. Inspect the error before using a selection: consistency-only errors retain a selected item, while structural failures do not.
func Pick ¶
func Pick[T any](ctx context.Context, client *Client, state any, instructions any, candidates []Candidate[T], opts ...RequestOption) (Decision[T], error)
Pick asks the model to choose one described candidate or abstain. It sends positional keys c1, c2, ... and the abstain key "none" under question "pick". At most 254 candidates are accepted. Empty candidates abstain without a network call, Answer, or Response. A canceled context still returns an error.
Pick always validates the complete response. Errors never become successful abstentions. No thresholds or application actions are applied.
Example ¶
package main
import (
"context"
"fmt"
"github.com/deepnoodle-ai/decide"
"github.com/deepnoodle-ai/decide/decidetest"
)
func main() {
srv, err := decidetest.Start()
if err != nil {
panic(err)
}
defer srv.Close()
client, err := srv.NewClient()
if err != nil {
panic(err)
}
srv.Answer("pick", decidetest.ChoiceAnswer(map[string]float64{"c1": .9, "c2": .05, "none": .05}))
d, err := decide.Pick(context.Background(), client, "Charged twice.", "Choose a queue.", []decide.Candidate[string]{
{Item: "billing", Description: "Payments and invoices"},
{Item: "engineering", Description: "Product defects"},
})
if err != nil {
panic(err)
}
fmt.Println(d.Item, d.Index, d.Picked)
}
Output: billing 0 true
type Evaluation ¶
Evaluation contains a typed judgment and the response that supplied it. Response retains model, usage, request ID, headers, and validation failures.
func Eval ¶
func Eval[A Answer](ctx context.Context, client *Client, state any, question QuestionFor[A], opts ...RequestOption) (Evaluation[A], error)
Eval asks one typed question under the key "eval". It always validates the answer, even when client-wide validation is disabled. External QuestionFor implementations need no answer registration.
Structural failures return no typed Answer. Consistency-only failures return the full Answer and an error matching ErrInconsistentAnswer. Every response returned by Client.SystemOne remains available in Response. Use NewRequest, Ask, and Client.SystemOne for multiple questions.
Example ¶
package main
import (
"context"
"fmt"
"github.com/deepnoodle-ai/decide"
"github.com/deepnoodle-ai/decide/decidetest"
)
func main() {
srv, err := decidetest.Start()
if err != nil {
panic(err)
}
defer srv.Close()
client, err := srv.NewClient()
if err != nil {
panic(err)
}
srv.Answer("eval", decidetest.NoulAnswer(.9))
e, err := decide.Eval(context.Background(), client, "Charged twice.", decide.Noul("Billing issue?"))
if err != nil {
panic(err)
}
fmt.Println(e.Answer.Noul, e.Response.Model)
}
Output: 0.9 jev-1.13.0
type HTTPTransport ¶
type HTTPTransport struct {
// contains filtered or unexported fields
}
HTTPTransport speaks TypeSafe's native HTTP API. It is safe for concurrent use.
func NewHTTPTransport ¶
func NewHTTPTransport(cfg HTTPTransportConfig) (*HTTPTransport, error)
NewHTTPTransport returns a transport for the native API. A missing API key is an error wrapping ErrNoAPIKey.
func (HTTPTransport) GoString ¶
func (t HTTPTransport) GoString() string
GoString describes the transport with the API key redacted, for %#v.
func (*HTTPTransport) ListModels ¶
func (t *HTTPTransport) ListModels(ctx context.Context) (*ModelList, error)
ListModels sends one GET /v1/models attempt.
func (HTTPTransport) LogValue ¶
func (t HTTPTransport) LogValue() slog.Value
LogValue implements slog.LogValuer with the API key redacted.
func (HTTPTransport) String ¶
func (t HTTPTransport) String() string
String describes the transport with the API key redacted. String, GoString, and LogValue have value receivers so that both HTTPTransport and *HTTPTransport print safely, including with %+v.
type HTTPTransportConfig ¶
type HTTPTransportConfig struct {
APIKey string
BaseURL string // default https://api.typesafe.ai
HTTPClient *http.Client // default: new client with http.DefaultTransport, no Timeout
UserAgent string // product token prepended to the SDK token
}
HTTPTransportConfig configures an HTTPTransport.
func (HTTPTransportConfig) GoString ¶
func (c HTTPTransportConfig) GoString() string
GoString describes the config with the API key redacted, for %#v.
func (HTTPTransportConfig) LogValue ¶
func (c HTTPTransportConfig) LogValue() slog.Value
LogValue implements slog.LogValuer with the API key redacted.
func (HTTPTransportConfig) String ¶
func (c HTTPTransportConfig) String() string
String describes the config with the API key redacted.
type Handle ¶
type Handle[A Answer] struct { // contains filtered or unexported fields }
Handle is a typed reference to one question in a request. It reads the matching answer from a response as the answer's concrete type.
func Ask ¶
func Ask[A Answer](req *Request, key string, q QuestionFor[A]) Handle[A]
Ask adds q under key and returns a typed handle. It panics if req is nil, key is empty, or key is already present: these are programming errors, like registering a duplicate route in net/http.
func (Handle[A]) From ¶
From returns the answer for h's key. In order: if resp is nil or the key is absent, it returns an *AnswerError with reason missing_answer; if resp.Invalid has an error for the key, it returns that error together with the answer when the stored answer is an A (so a caller who accepts ErrInconsistentAnswer can proceed); if the stored answer is not an A, it returns type_mismatch. Other keys of the same response stay usable.
type InvalidAnswersError ¶
type InvalidAnswersError struct{ Answers []*AnswerError }
InvalidAnswersError collects every answer that failed validation, sorted by key then reason. SystemOne returns it together with the response.
func (*InvalidAnswersError) Error ¶
func (e *InvalidAnswersError) Error() string
Error returns the count plus the first two failures.
func (*InvalidAnswersError) Unwrap ¶
func (e *InvalidAnswersError) Unwrap() []error
Unwrap returns each *AnswerError.
type Model ¶
type Model struct {
Name string // "name"
Description string // "description"
ReleaseDate string // "release_date"; YYYY-MM-DD, kept as a string
Extra map[string]json.RawMessage // unmodeled members, written back on marshal
}
Model is one entry from GET /v1/models. The list contains aliases such as "jev-latest"; versioned IDs are accepted by the API whether or not they are listed.
func (Model) MarshalJSON ¶
MarshalJSON writes name, description, release_date, then Extra. It has a value receiver so a Model marshals the same whether or not it is addressable.
func (*Model) UnmarshalJSON ¶
UnmarshalJSON decodes a model leniently; unknown members go to Extra.
type ModelList ¶
type ModelList struct {
Models []Model
RequestID string // x-typesafe-request-id
Header http.Header // response headers; nil if the transport has none
Raw []byte // response body; nil if the transport has none
Extra map[string]json.RawMessage // unmodeled top-level members
}
ModelList is the result of GET /v1/models.
func (*ModelList) MarshalJSON ¶
MarshalJSON writes {"models": [...]} then Extra.
func (*ModelList) UnmarshalJSON ¶
UnmarshalJSON decodes a model list. It fails if data is not a JSON object; a missing "models" becomes an empty list.
type ModelsService ¶
type ModelsService struct {
// contains filtered or unexported fields
}
ModelsService lists models. Use it through Client.Models.
func (*ModelsService) List ¶
func (s *ModelsService) List(ctx context.Context) (*ModelList, error)
List returns the models the API advertises. It uses the client's retry loop and logging. Results are not cached.
Example ¶
List the models the API advertises. Aliases such as jev-latest move; the resolved version is on every Response.
package main
import (
"context"
"fmt"
"log"
"github.com/deepnoodle-ai/decide/decidetest"
)
// startFake starts a fake API with canned answers, standing in for
// https://api.typesafe.ai so the examples run without a key.
func startFake() *decidetest.Server {
srv, err := decidetest.Start()
if err != nil {
log.Fatal(err)
}
srv.Answer("billing", decidetest.NoulAnswer(0.93))
return srv
}
func main() {
srv := startFake()
defer srv.Close()
client, err := srv.NewClient()
if err != nil {
log.Fatal(err)
}
list, err := client.Models.List(context.Background())
if err != nil {
log.Fatal(err)
}
for _, m := range list.Models {
fmt.Println(m.Name)
}
}
Output: jev-latest jev-preview
type NoulAnswer ¶
type NoulAnswer struct {
Noul float64
Extra map[string]json.RawMessage // unmodeled members, as received
// contains filtered or unexported fields
}
NoulAnswer is the answer to a NoulQuestion. Noul is P(yes) in [0,1]. There is no confidence field; the API does not return one.
func (*NoulAnswer) MarshalJSON ¶
func (a *NoulAnswer) MarshalJSON() ([]byte, error)
MarshalJSON writes "type" first, then the fields, then Extra sorted by key.
func (*NoulAnswer) UnmarshalJSON ¶
func (a *NoulAnswer) UnmarshalJSON(data []byte) error
UnmarshalJSON decodes a noul answer. "noul" is required.
type NoulCriteria ¶
type NoulCriteria struct {
True any // encoded as "true"; nil encodes as null (the spec allows it)
False any // encoded as "false"
}
NoulCriteria optionally describes what "true" and "false" mean.
type NoulOption ¶
type NoulOption func(*NoulQuestion)
NoulOption configures a NoulQuestion built by Noul.
func NoulFalse ¶
func NoulFalse(description any) NoulOption
NoulFalse sets Criteria.False, allocating Criteria.
func NoulTrue ¶
func NoulTrue(description any) NoulOption
NoulTrue sets Criteria.True, allocating Criteria.
type NoulQuestion ¶
type NoulQuestion struct {
Instructions any
Criteria *NoulCriteria // nil omits "criteria"
Extra map[string]any
}
NoulQuestion asks whether a condition holds. Its answer is P(yes).
Instructions and the criteria values may be a string, an object, an array, or nil (JSON null); they are encoded with encoding/json as given.
func Noul ¶
func Noul(instructions any, opts ...NoulOption) *NoulQuestion
Noul builds a Noul question.
func (*NoulQuestion) MakeAnswer ¶
func (q *NoulQuestion) MakeAnswer() Answer
MakeAnswer returns q.NewAnswer().
func (*NoulQuestion) MarshalJSON ¶
func (q *NoulQuestion) MarshalJSON() ([]byte, error)
MarshalJSON encodes the question with "type" first.
func (*NoulQuestion) NewAnswer ¶
func (q *NoulQuestion) NewAnswer() *NoulAnswer
NewAnswer returns a new *NoulAnswer.
func (*NoulQuestion) QuestionType ¶
func (q *NoulQuestion) QuestionType() string
QuestionType returns "noul".
func (*NoulQuestion) UnmarshalJSON ¶
func (q *NoulQuestion) UnmarshalJSON(data []byte) error
UnmarshalJSON decodes a noul question. Unknown members go to Extra.
func (*NoulQuestion) ValidateAnswer ¶
func (q *NoulQuestion) ValidateAnswer(a Answer) error
ValidateAnswer checks a noul answer: it is a *NoulAnswer with "noul" present, finite, and in [0,1].
type Question ¶
Question is one entry in Request.Questions. Implementations outside this package are allowed. MarshalJSON must emit a JSON object whose "type" member equals QuestionType().
func DecodeQuestion ¶
DecodeQuestion decodes one question object. Unknown types become *RawQuestion.
type QuestionFor ¶
QuestionFor binds a question to the Go type of its answer so Ask can infer the handle type. NewAnswer returns a new zero answer.
type RawAnswer ¶
type RawAnswer struct {
Type string
JSON json.RawMessage
Err error
}
RawAnswer holds an answer whose type is not registered, or a registered type that failed to decode (Err is then non-nil). JSON is the full answer object as received. AnswerType returns Type.
func (*RawAnswer) MarshalJSON ¶
MarshalJSON returns JSON as received, or {"type": Type} if JSON is empty.
func (*RawAnswer) UnmarshalJSON ¶
UnmarshalJSON keeps a copy of data and reads Type from it.
type RawQuestion ¶
type RawQuestion struct {
Type string
JSON json.RawMessage // the full question object, including "type"
}
RawQuestion sends a question type this package does not model.
func (*RawQuestion) MakeAnswer ¶
func (q *RawQuestion) MakeAnswer() Answer
MakeAnswer returns q.NewAnswer().
func (*RawQuestion) MarshalJSON ¶
func (q *RawQuestion) MarshalJSON() ([]byte, error)
MarshalJSON returns q.JSON unchanged after checking that it is an object whose "type" equals q.Type.
func (*RawQuestion) NewAnswer ¶
func (q *RawQuestion) NewAnswer() *RawAnswer
NewAnswer returns a new *RawAnswer with Type set.
func (*RawQuestion) QuestionType ¶
func (q *RawQuestion) QuestionType() string
QuestionType returns q.Type.
func (*RawQuestion) UnmarshalJSON ¶
func (q *RawQuestion) UnmarshalJSON(data []byte) error
UnmarshalJSON keeps a copy of data and reads Type from it.
type Request ¶
type Request struct {
State any // string, object, array, or json.RawMessage
Model string // empty: client default
Questions map[string]Question
Extra map[string]any // unmodeled top-level fields
}
Request is one call to POST /v1/systemone.
A Request is not safe for concurrent mutation. A fully built request may be sent concurrently by many goroutines; the client never mutates it.
func NewRequest ¶
func NewRequest(state any, opts ...RequestOption) *Request
NewRequest returns a request for state with a non-nil Questions map.
func (*Request) MarshalJSON ¶
MarshalJSON writes state, model (omitted when empty), questions sorted by key, then Extra sorted by key.
func (*Request) UnmarshalJSON ¶
UnmarshalJSON decodes a request. Questions are decoded with DecodeQuestion; unknown fields go to Extra with their raw bytes. A string state decodes to a Go string; any other state is kept as json.RawMessage so its bytes, including object member order, survive.
type RequestOption ¶
type RequestOption func(*Request)
RequestOption configures a Request built by NewRequest.
func WithRequestExtra ¶
func WithRequestExtra(key string, value any) RequestOption
WithRequestExtra sets an unmodeled top-level request field.
func WithRequestModel ¶
func WithRequestModel(name string) RequestOption
WithRequestModel sets the model for this request, overriding the client default. Aliases such as "jev-latest" and versioned IDs are both accepted.
type Response ¶
type Response struct {
Model string // resolved version, e.g. "jev-1.13.0"
Answers map[string]Answer
Usage Usage
RequestID string // x-typesafe-request-id
Header http.Header // response headers; nil if the transport has none
Raw []byte // response body; nil if the transport has none
Extra map[string]json.RawMessage // unmodeled top-level members
// Invalid holds the validation failure for each key that failed, set by
// the client after validation; nil when every answer is valid.
Invalid map[string]*AnswerError
}
Response is the result of POST /v1/systemone.
func DecodeResponse ¶
DecodeResponse decodes a response body using req to choose answer types, then the registry, then *RawAnswer. req may be nil. It fails only if data is not a JSON object or "answers" is not an object; a bad answer never fails the whole response.
Decoding is lenient: unknown top-level members go to Extra, a missing "answers" becomes an empty map, and a missing "usage" leaves zeros. If "model" or "usage" has the wrong JSON type, the field is left zero and its raw bytes are kept in Extra under the same key; MarshalJSON does not write them back, because the modeled field wins.
Discrepancy: usage is required by the docs and the OpenAPI spec but optional in the Python SDK. We decode a missing usage as zeros.
func (*Response) MarshalJSON ¶
MarshalJSON writes the wire form: model, answers sorted by key, usage, then Extra sorted by key. RequestID, Header, Raw, and Invalid are not part of the body and are not written.
func (*Response) UnmarshalJSON ¶
UnmarshalJSON decodes a response using the answer registry only; see DecodeResponse to decode with the request's question types.
type ScoreAnswer ¶
type ScoreAnswer struct {
Score float64
Legend map[string]any // keys "0".."n-1"
Probabilities map[string]float64 // keys "0".."n-1"
Confidence float64
Extra map[string]json.RawMessage
// contains filtered or unexported fields
}
ScoreAnswer is the answer to a ScoreQuestion. Score is the probability-weighted level, in [0, levels-1].
Discrepancy: the docs say legend values are strings; the OpenAPI spec allows string, object, or array. Legend therefore holds any.
func (*ScoreAnswer) AnswerType ¶
func (a *ScoreAnswer) AnswerType() string
AnswerType returns "score".
func (*ScoreAnswer) Level ¶
func (a *ScoreAnswer) Level() int
Level returns the index of the highest probability, lowest index on ties; -1 if there are no probabilities. Keys that are not integers are ignored.
Example ¶
Score is the expected zero-based level; Level selects the most likely level.
package main
import (
"fmt"
"github.com/deepnoodle-ai/decide/decidetest"
)
func main() {
a := decidetest.ScoreAnswer([]any{"can wait", "this week", "today"}, 0.1, 0.3, 0.6)
fmt.Printf("expected level: %.2f\n", a.Score)
fmt.Println("most likely:", a.LevelLabel(a.Level()))
}
Output: expected level: 1.50 most likely: today
func (*ScoreAnswer) LevelLabel ¶
func (a *ScoreAnswer) LevelLabel(i int) any
LevelLabel returns Legend[strconv.Itoa(i)], or nil.
func (*ScoreAnswer) Levels ¶
func (a *ScoreAnswer) Levels() int
Levels returns max(len(Legend), len(Probabilities)). Validation allows a legend with missing keys, so the legend alone can undercount.
func (*ScoreAnswer) MarshalJSON ¶
func (a *ScoreAnswer) MarshalJSON() ([]byte, error)
MarshalJSON writes "type" first, then the fields, then Extra sorted by key. Legend and probabilities are written with keys sorted, not in wire order.
func (*ScoreAnswer) Normalized ¶
func (a *ScoreAnswer) Normalized() float64
Normalized returns Score / (Levels()-1), or 0 when Levels() < 2.
func (*ScoreAnswer) ProbabilityAt ¶
func (a *ScoreAnswer) ProbabilityAt(i int) (float64, bool)
ProbabilityAt returns Probabilities[strconv.Itoa(i)].
func (*ScoreAnswer) UnmarshalJSON ¶
func (a *ScoreAnswer) UnmarshalJSON(data []byte) error
UnmarshalJSON decodes a score answer. All four fields are required.
type ScoreQuestion ¶
type ScoreQuestion struct {
Instructions any
Criteria []any // ordered levels; index is the level number
Extra map[string]any
}
ScoreQuestion asks where on an ordered scale the state falls.
func Score ¶
func Score(instructions any, levels ...any) *ScoreQuestion
Score builds a Score question. levels are ordered; the index of each level is its number.
func ScoreOf ¶
func ScoreOf[T any](instructions any, levels []T) *ScoreQuestion
ScoreOf is Score for a typed slice, e.g. ScoreOf("How urgent?", []string{...}).
func (*ScoreQuestion) MakeAnswer ¶
func (q *ScoreQuestion) MakeAnswer() Answer
MakeAnswer returns q.NewAnswer().
func (*ScoreQuestion) MarshalJSON ¶
func (q *ScoreQuestion) MarshalJSON() ([]byte, error)
MarshalJSON encodes the question with levels in order.
Discrepancy: the OpenAPI spec forbids null level entries (Choice allows null descriptions), while the JS builder docs say entries may be null. We send what the caller gave and let the server decide.
func (*ScoreQuestion) NewAnswer ¶
func (q *ScoreQuestion) NewAnswer() *ScoreAnswer
NewAnswer returns a new *ScoreAnswer.
func (*ScoreQuestion) QuestionType ¶
func (q *ScoreQuestion) QuestionType() string
QuestionType returns "score".
func (*ScoreQuestion) UnmarshalJSON ¶
func (q *ScoreQuestion) UnmarshalJSON(data []byte) error
UnmarshalJSON decodes a score question. Any number of levels is accepted.
func (*ScoreQuestion) ValidateAnswer ¶
func (q *ScoreQuestion) ValidateAnswer(a Answer) error
ValidateAnswer checks a score answer against the levels. Structural: fields present, values finite and in [0,1], probability keys are exactly "0".."n-1", every legend key is one of them (missing legend keys are allowed), score finite. Consistency: score within tolerance of [0, n-1] and probabilities sum to about 1.
type Transport ¶
type Transport interface {
SystemOne(ctx context.Context, req *Request) (*Response, error)
ListModels(ctx context.Context) (*ModelList, error)
}
Transport performs exactly one attempt of each API call. It must not retry, must be safe for concurrent use, and must not mutate req. req.Model is always set. Non-2xx outcomes return *APIError. Answers must be normalized to this package's answer types; dialect quirks stay inside.
The interface is frozen: it will never gain a method, because that would break every implementation outside this package. A new endpoint arrives as an optional interface that the client type-asserts, returning an error wrapping errors.ErrUnsupported when the transport lacks it.
type Usage ¶
type Usage struct {
InputTokens int // "input_tokens"
OutputTokens int // "output_tokens"
Extra map[string]json.RawMessage // unmodeled members, written back on marshal
}
Usage reports token counts for a request.
func (Usage) MarshalJSON ¶
MarshalJSON writes input_tokens, output_tokens, then Extra sorted by key. It has a value receiver so a Usage field marshals without being addressable.
func (*Usage) UnmarshalJSON ¶
UnmarshalJSON decodes usage leniently. Token counts are read as numbers and kept when integral (so 12.0 is 12); a count that is not an integral number is left at zero and its raw bytes go to Extra, as do unknown members. It fails only if data is not a JSON object.
type ValidationDetail ¶
type ValidationDetail struct {
Loc []any `json:"loc"` // strings and numbers (float64)
Msg string `json:"msg"`
Type string `json:"type"`
Input json.RawMessage `json:"input,omitempty"`
Ctx map[string]any `json:"ctx,omitempty"`
}
ValidationDetail is one entry of a 422 response's "detail" array.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package backend selects a decision provider during decide.Client construction.
|
Package backend selects a decision provider during decide.Client construction. |
|
Package cloudflare connects decide to the Clef and Clef-flash models on Cloudflare Workers AI.
|
Package cloudflare connects decide to the Clef and Clef-flash models on Cloudflare Workers AI. |
|
cmd
|
|
|
decide
command
Command decide asks typed questions about your data and saves every answer.
|
Command decide asks typed questions about your data and saves every answer. |
|
Package decidetest provides a fake TypeSafe API server and answer fixtures, so code built on package decide can be tested without an API key or a network.
|
Package decidetest provides a fake TypeSafe API server and answer fixtures, so code built on package decide can be tested without an API key or a network. |
|
examples
|
|
|
calibrate
command
Command calibrate fits a cutoff on saved, labeled answers and checks it on separate held-out cases.
|
Command calibrate fits a cutoff on saved, labeled answers and checks it on separate held-out cases. |
|
compact
command
Command compact trims an agent transcript before the next turn: it asks whether each tool call is still needed for the task, then keeps the most needed ones verbatim under a budget, using a short form where the full output is not needed.
|
Command compact trims an agent transcript before the next turn: it asks whether each tool call is still needed for the task, then keeps the most needed ones verbatim under a budget, using a short form where the full output is not needed. |
|
fanout
command
Command fanout asks whether each retrieved passage is relevant to a query, one request per passage, with at most four requests in flight.
|
Command fanout asks whether each retrieved passage is relevant to a query, one request per passage, with at most four requests in flight. |
|
funnel
command
Command funnel picks tools for a request in two stages: skim every tool's one-line summary in one request, then re-check up to two survivors with their full descriptions, one request each.
|
Command funnel picks tools for a request in two stages: skim every tool's one-line summary in one request, then re-check up to two survivors with their full descriptions, one request each. |
|
gate
command
Command gate asks what file operation a user requested and gates the agent's proposed delete with patterns/gate: allow, review, or escalate.
|
Command gate asks what file operation a user requested and gates the agent's proposed delete with patterns/gate: allow, review, or escalate. |
|
heads
command
Command heads triages a support ticket in one request: it asks which team owns the ticket and, speculatively, each team's follow-up question, then reads only the chosen team's answer.
|
Command heads triages a support ticket in one request: it asks which team owns the ticket and, speculatively, each team's follow-up question, then reads only the chosen team's answer. |
|
pick
command
Command pick finds candidate email addresses with a regex and asks the model which one the sender wants their receipt sent to.
|
Command pick finds candidate email addresses with a regex and asks the model which one the sender wants their receipt sent to. |
|
rank
command
Command rank reranks a retrieved shortlist by asking, for each passage, whether it answers the query, then sorting by the answers.
|
Command rank reranks a retrieved shortlist by asking, for each passage, whether it answers the query, then sorting by the answers. |
|
internal
|
|
|
cache
Package cache keeps the answers decide has received, so a run asks again only about what changed.
|
Package cache keeps the answers decide has received, so a run asks again only about what changed. |
|
cli
Package cli implements the decide command.
|
Package cli implements the decide command. |
|
runs
Package runs saves each evaluation of a dataset so it can be viewed again or resumed after an interruption.
|
Package runs saves each evaluation of a dataset so it can be viewed again or resumed after an interruption. |
|
source
Package source reads files, directories, and stdin as a stream of items for a template to evaluate.
|
Package source reads files, directories, and stdin as a stream of items for a template to evaluate. |
|
template
Package template loads templates: named sets of typed questions that the decide command asks about every item in a dataset.
|
Package template loads templates: named sets of typed questions that the decide command asks about every item in a dataset. |
|
Package openai connects decide to OpenAI's Decisions API, which runs on gpt-6-luna.
|
Package openai connects decide to OpenAI's Decisions API, which runs on gpt-6-luna. |
|
patterns
|
|
|
calibrate
Package calibrate fits one gate threshold and optional probability temperature from saved, labeled decision-model answers.
|
Package calibrate fits one gate threshold and optional probability temperature from saved, labeled decision-model answers. |
|
compact
Package compact shortens a long context by asking, for each segment, whether it is still needed, then keeping the highest-scoring segments verbatim under a budget.
|
Package compact shortens a long context by asking, for each segment, whether it is still needed, then keeping the highest-scoring segments verbatim under a budget. |
|
fanout
Package fanout runs independent decision requests over a collection of items with a bound on concurrent work.
|
Package fanout runs independent decision requests over a collection of items with a bound on concurrent work. |
|
funnel
Package funnel runs staged screening: cheap questions about many items, then narrower questions about the survivors, carrying each item's answers from stage to stage.
|
Package funnel runs staged screening: cheap questions about many items, then narrower questions about the survivors, carrying each item's answers from stage to stage. |
|
gate
Package gate turns decision-model answers into one of three outcomes: Allow, Review, or Escalate.
|
Package gate turns decision-model answers into one of three outcomes: Allow, Review, or Escalate. |
|
heads
Package heads builds one request with a Choice selector and questions for every possible branch, then reads only the selected branch's answers.
|
Package heads builds one request with a Choice selector and questions for every possible branch, then reads only the selected branch's answers. |
|
pick
Package pick asks a decision model to select an item from a caller's candidate list and returns the original item.
|
Package pick asks a decision model to select an item from a caller's candidate list and returns the original item. |
|
rank
Package rank orders caller-owned candidates from Noul observations and takes an ordered prefix under a caller-defined allowance.
|
Package rank orders caller-owned candidates from Noul observations and takes an ordered prefix under a caller-defined allowance. |
|
Package templates gives Go programs the decide command's built-in templates, the same ones decide templates lists.
|
Package templates gives Go programs the decide command's built-in templates, the same ones decide templates lists. |
