Documentation
¶
Overview ¶
Package jev is a client for the Jev judgement API.
Give it a piece of state and a set of questions; it returns one structured answer per question, keyed the way you asked them.
client, err := jev.New(os.Getenv("JEV_API_KEY"))
if err != nil {
log.Fatal(err)
}
resp, err := client.Request(ctx, ticket,
jev.Choice("department", "Which team should handle this?", map[string]string{
"billing": "Payment or subscription issues",
"technical": "Bugs or integration problems",
}),
jev.Score("frustration", "How frustrated does the customer appear?",
"Calm", "Frustrated but civil", "Very angry"),
jev.Noul("is_urgent", "The message conveys urgency"),
)
Questions ¶
Noul asks a yes/no question, Choice picks one key out of a set of described answers, and Score picks one point on an ordered scale. Those cover the common case on their own; the With* methods on Question add instruction context to the questions that need it and leave the rest alone. Question.Set is the escape hatch for context keys with no typed helper yet, and unrecognized keys survive a decode and re-encode untouched.
Answers ¶
Answers come back under the keys they were asked with, in github.com/leonardjke/go-jev/data.Response.Answers, alongside the confidence, the probability spread the answer was drawn from and, for a score, the legend mapping positions back to labels. Score, Noul and Confidence are pointers, so a returned 0 is distinguishable from "not returned".
Configuration ¶
New takes the API key plus any number of Option values: WithModel, WithEndpoint, WithClient and WithLogger. The key is held in a type that redacts itself through fmt, JSON and encoding.TextMarshaler, so printing a client or logging it never discloses the credential.
Non-2xx responses come back as *APIError, matchable with errors.As.
Example (Context) ¶
Example_context adds instruction context to the questions that need it. The call is the same one as above — only the questions carrying extra context grow, and the plain ones stay plain.
package main
import (
"context"
"fmt"
"log"
"github.com/leonardjke/go-jev"
)
func main() {
client, err := jev.New("...")
if err != nil {
log.Fatal(err)
}
resp, err := client.Request(context.Background(), invoice,
jev.Noul("invoice_number_matches",
"Does `extracted_value` match the `field` as it appears in `source_text`?").
WithField(jev.Field{
Name: "invoice_number",
Type: "string",
Description: "The identifier printed on the invoice.",
}).
WithExtractedValue("4471"),
jev.Score("amount_due_size", "How large is the `field` value in `source_text`?",
"Small", "Typical", "Unusually large").
WithField(jev.Field{Name: "amount_due", Type: "number", Unit: "USD"}),
jev.Noul("sender_mismatch", "Does the claimed sender identity conflict with the sending domain?").
WithCompare("ticket.sender.display_name", "ticket.sender.email").
WithFocus("Compare the named organization with the email domain."),
// Set is the escape hatch for instruction keys with no typed helper.
jev.Noul("within_tolerance", "Is `extracted_value` within tolerance of the `field`?").
WithExtractedValue(4471).
Set("tolerance", map[string]float64{"percent": 0.5}),
)
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Answers["invoice_number_matches"].Noul)
}
var invoice = "..."
Output:
Example (Simple) ¶
Example_simple is the everyday shape: build the client once, then ask. Questions that need no context are a single call each.
package main
import (
"context"
"fmt"
"log"
"github.com/leonardjke/go-jev"
)
func main() {
client, err := jev.New("...")
if err != nil {
log.Fatal(err)
}
resp, err := client.Request(context.Background(), ticket,
jev.Choice("department", "Which team should handle this?", map[string]string{
"billing": "Payment or subscription issues",
"technical": "Bugs or integration problems",
}),
jev.Score("frustration", "How frustrated does the customer appear?",
"Calm", "Frustrated but civil", "Very angry"),
jev.Noul("is_urgent", "The message conveys urgency"),
)
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Answers["department"].Choice)
}
var ticket = "..."
Output:
Index ¶
- type APIError
- type Field
- type Jev
- type Logger
- type Option
- type Question
- func (q Question) Key() string
- func (q Question) Set(key string, value any) Question
- func (q Question) Validate() error
- func (q Question) WithCompare(paths ...string) Question
- func (q Question) WithCriteria(criteria map[string]string) Question
- func (q Question) WithExtractedValue(value any) Question
- func (q Question) WithField(f Field) Question
- func (q Question) WithFocus(focus string) Question
- func (q Question) WithNote(note string) Question
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Jev ¶
type Jev struct {
// contains filtered or unexported fields
}
func (Jev) Format ¶
Format keeps the client printable without printing the credential. The receiver is a value so that a copied Jev is covered too, rather than falling back to reflection over its fields.
func (*Jev) Request ¶
func (j *Jev) Request(ctx context.Context, state string, questions ...Question) (*data.Response, error)
Request judges state against questions, using the model the client was built with.
resp, err := client.Request(ctx, ticket,
jev.Choice("department", "Which team should handle this?", map[string]string{
"billing": "Payment or subscription issues",
"technical": "Bugs or integration problems",
}),
jev.Score("frustration", "How frustrated is the customer?",
"Calm", "Frustrated but civil", "Very angry"),
)
Every question needs a key of its own; the answers come back under those keys in Response.Answers.
type Option ¶
type Option func(j *Jev)
func WithClient ¶
func WithEndpoint ¶
WithEndpoint points the client at another URL: a proxy, a gateway or a compatible service. It is the full endpoint the request is posted to, path included, not just a host -- nothing is appended to it.
func WithLogger ¶
WithLogger sends the client's debug output to l. The default logger discards it. A nil logger is rejected by New rather than ignored.
type Question ¶
type Question struct {
// contains filtered or unexported fields
}
Question is one question to ask, along with the key its answer comes back under in Response.Answers.
Build one with Noul, Choice or Score. Those cover the common case on their own; the With* methods add context to the questions that need it, and leave the ones that don't alone:
jev.Noul("is_urgent", "The message conveys urgency")
jev.Score("amount_due_size", "How large is the `field` value in `source_text`?",
"Small", "Typical", "Unusually large").
WithField(jev.Field{Name: "amount_due", Type: "number", Unit: "USD"})
The zero Question is not usable; Request rejects one with an empty key.
func Choice ¶
Choice asks the judge to pick one key out of criteria, which maps each possible answer to the description that qualifies it.
func Noul ¶
Noul asks a yes/no question. Criteria are optional — a plain check needs none, WithCriteria describes what makes each answer true or false.
func Score ¶
Score asks the judge to pick one point on an ordered scale. The scale labels run lowest to highest, e.g. "Calm", "Frustrated", "Very angry".
func (Question) Set ¶
Set stores value under an arbitrary instruction key. It is the escape hatch for context keys this library has no typed helper for yet.
func (Question) WithCompare ¶
WithCompare sets "compare": the state paths the question weighs against each other, e.g. "ticket.sender.display_name".
func (Question) WithCriteria ¶
WithCriteria describes what makes each answer of a Noul question true or false. It replaces any criteria already set.
func (Question) WithExtractedValue ¶
WithExtractedValue sets "extracted_value": the candidate value to check the field against.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
internal
|
|
|
privacy
Package privacy holds the types that keep credentials out of logs, error messages and anything else that formats or marshals a value.
|
Package privacy holds the types that keep credentials out of logs, error messages and anything else that formats or marshals a value. |