Files
Ed1s0nZandCursor 38b96ec67a feat: add TypeSafe Jev as HITL audit backend
Let audit_agent approve or reject with one System One call instead of chat JSON, while keeping the OpenAI-compatible backend as an option.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 21:15:53 +08:00

197 lines
4.6 KiB
Go

package typesafe
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"time"
)
const (
DefaultBaseURL = "https://api.typesafe.ai"
DefaultModel = "jev-latest"
)
// Client calls TypeSafe System One (Jev).
type Client struct {
httpClient *http.Client
baseURL string
apiKey string
model string
}
// APIError is a non-2xx TypeSafe HTTP response.
type APIError struct {
StatusCode int
Body string
}
func (e *APIError) Error() string {
return fmt.Sprintf("typesafe api error: status=%d body=%s", e.StatusCode, e.Body)
}
// NewClient builds a System One client. Empty baseURL/model use TypeSafe defaults.
func NewClient(baseURL, apiKey, model string, httpClient *http.Client) *Client {
if httpClient == nil {
httpClient = &http.Client{Timeout: 90 * time.Second}
}
baseURL = strings.TrimSuffix(strings.TrimSpace(baseURL), "/")
if baseURL == "" {
baseURL = DefaultBaseURL
}
model = strings.TrimSpace(model)
if model == "" {
model = DefaultModel
}
return &Client{
httpClient: httpClient,
baseURL: baseURL,
apiKey: strings.TrimSpace(apiKey),
model: model,
}
}
// Question is a typed System One question (noul / choice / score).
type Question map[string]any
// Noul builds a yes/no question.
func Noul(instructions string, trueMean, falseMean string) Question {
q := Question{
"type": "noul",
"instructions": instructions,
}
if strings.TrimSpace(trueMean) != "" || strings.TrimSpace(falseMean) != "" {
q["criteria"] = map[string]string{
"true": trueMean,
"false": falseMean,
}
}
return q
}
// Choice builds a closed-set question.
func Choice(instructions string, criteria map[string]string) Question {
return Question{
"type": "choice",
"instructions": instructions,
"criteria": criteria,
}
}
// Result is a System One evaluation response.
type Result struct {
Model string `json:"model"`
Answers map[string]map[string]any `json:"answers"`
Usage Usage `json:"usage"`
}
// Usage reports token counts.
type Usage struct {
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
}
// Noul returns the probability that question id is yes.
func (r *Result) Noul(id string) float64 {
if r == nil {
return 0
}
ans, ok := r.Answers[id]
if !ok || ans == nil {
return 0
}
switch v := ans["noul"].(type) {
case float64:
return v
case json.Number:
f, _ := v.Float64()
return f
default:
return 0
}
}
// Choice returns the selected option and confidence.
func (r *Result) Choice(id string) (choice string, confidence float64) {
if r == nil {
return "", 0
}
ans, ok := r.Answers[id]
if !ok || ans == nil {
return "", 0
}
choice, _ = ans["choice"].(string)
switch v := ans["confidence"].(type) {
case float64:
confidence = v
case json.Number:
confidence, _ = v.Float64()
}
return strings.TrimSpace(choice), confidence
}
type systemOneRequest struct {
State any `json:"state"`
Model string `json:"model"`
Questions map[string]Question `json:"questions"`
}
// SystemOne evaluates state against questions.
func (c *Client) SystemOne(ctx context.Context, state any, questions map[string]Question) (*Result, error) {
if c == nil {
return nil, fmt.Errorf("typesafe client is not initialized")
}
if strings.TrimSpace(c.apiKey) == "" {
return nil, fmt.Errorf("typesafe api key is empty")
}
if len(questions) == 0 {
return nil, fmt.Errorf("typesafe questions are empty")
}
if ctx == nil {
ctx = context.Background()
}
body, err := json.Marshal(systemOneRequest{
State: state,
Model: c.model,
Questions: questions,
})
if err != nil {
return nil, fmt.Errorf("marshal typesafe payload: %w", err)
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL+"/v1/systemone", bytes.NewReader(body))
if err != nil {
return nil, fmt.Errorf("build typesafe request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+c.apiKey)
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("call typesafe api: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("read typesafe response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, &APIError{StatusCode: resp.StatusCode, Body: string(respBody)}
}
var out Result
if err := json.Unmarshal(respBody, &out); err != nil {
return nil, fmt.Errorf("decode typesafe response: %w", err)
}
if out.Answers == nil {
out.Answers = map[string]map[string]any{}
}
return &out, nil
}