frictionapi

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Feb 18, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package frictionapi provides types and client for the friction telemetry API. This package is designed to be standalone with no internal dependencies to avoid import cycles between daemon, uxfriction, and other packages.

Index

Constants

View Source
const MaxErrorLength = 200

MaxErrorLength is the maximum length for the ErrorMsg field.

View Source
const MaxEventsPerRequest = 100

MaxEventsPerRequest is the maximum number of events per submission. Events beyond this limit are silently dropped.

View Source
const MaxInputLength = 500

MaxInputLength is the maximum length for the Input field.

Variables

This section is empty.

Functions

This section is empty.

Types

type Actor

type Actor string

Actor represents who triggered a friction event.

const (
	ActorHuman   Actor = "human"
	ActorAgent   Actor = "agent"
	ActorUnknown Actor = "unknown"
)

type CatalogData

type CatalogData struct {
	// Version is the catalog version identifier (e.g., "v2026-01-16-001").
	Version string `json:"version"`

	// Commands contains full command remapping rules for renamed/restructured commands.
	Commands []CommandMapping `json:"commands,omitempty"`

	// Tokens contains single-token correction rules (typos, aliases).
	Tokens []TokenMapping `json:"tokens,omitempty"`
}

CatalogData represents the friction catalog returned by the server. It contains learned corrections for common typos and command mistakes.

type Client

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

Client is the reference implementation for the friction API. It handles rate limiting via Retry-After and X-SageOx-Sample-Rate headers. Thread-safe for concurrent use.

func NewClient

func NewClient(cfg ClientConfig) *Client

NewClient creates a new friction client with the given configuration.

func (*Client) Reset

func (c *Client) Reset()

Reset clears rate limiting state (sample rate back to 1.0, retry-after cleared). Use this when the daemon restarts.

func (*Client) RetryAfter

func (c *Client) RetryAfter() time.Time

RetryAfter returns the time until which requests should be delayed. Returns zero time if no retry-after is active.

func (*Client) SampleRate

func (c *Client) SampleRate() float64

SampleRate returns the current sample rate (0.0-1.0).

func (*Client) ShouldSend

func (c *Client) ShouldSend() bool

ShouldSend returns true if events should be sent based on current rate limiting. Checks both Retry-After and sample rate.

Usage pattern:

if client.ShouldSend() {
    client.Submit(ctx, events, nil)
}

func (*Client) Submit

func (c *Client) Submit(ctx context.Context, events []FrictionEvent, opts *SubmitOptions) (*SubmitResponse, error)

Submit sends friction events to the API. Returns the response and any error. Network errors are returned as-is. The caller should check ShouldSend() before calling Submit to respect rate limiting.

Events are truncated to MaxEventsPerRequest (100) if more are provided.

type ClientConfig

type ClientConfig struct {
	// Endpoint is the base URL for the friction API (e.g., "https://api.sageox.ai").
	Endpoint string

	// Version is the CLI version included in the "v" field of requests.
	Version string

	// AuthFunc returns a bearer token for authentication.
	// Called on each request. Return empty string for unauthenticated requests.
	AuthFunc func() string

	// HTTPClient is the HTTP client to use. If nil, http.DefaultClient is used.
	HTTPClient *http.Client

	// Timeout is the request timeout. Default is 5 seconds.
	Timeout time.Duration
}

ClientConfig configures the friction client.

type CommandMapping

type CommandMapping struct {
	// Pattern is the normalized input pattern (no "ox" prefix, flags sorted).
	Pattern string `json:"pattern"`

	// Target is the correct command to suggest.
	Target string `json:"target"`

	// Count is how many times this pattern was seen.
	Count int `json:"count"`

	// Confidence is 0.0-1.0, derived from count and consistency.
	Confidence float64 `json:"confidence"`

	// Description is an optional explanation for humans.
	Description string `json:"description,omitempty"`
}

CommandMapping represents a full command remapping rule. Used for renamed or restructured commands.

type FailureKind

type FailureKind string

FailureKind represents types of CLI failures that create friction.

const (
	FailureUnknownCommand FailureKind = "unknown-command"
	FailureUnknownFlag    FailureKind = "unknown-flag"
	FailureInvalidArg     FailureKind = "invalid-arg"
	FailureParseError     FailureKind = "parse-error"
)

type FrictionEvent

type FrictionEvent struct {
	// Timestamp in ISO8601 UTC format.
	Timestamp string `json:"ts"`

	// Kind identifies the type of friction event.
	// Valid values: unknown-command, unknown-flag, invalid-arg, parse-error
	Kind string `json:"kind"`

	// Command is the top-level command (e.g., "agent" in "ox agent prime").
	Command string `json:"command,omitempty"`

	// Subcommand is the subcommand if applicable (e.g., "prime" in "ox agent prime").
	Subcommand string `json:"subcommand,omitempty"`

	// Actor identifies who triggered the event.
	// Valid values: human, agent
	Actor string `json:"actor"`

	// AgentType identifies the agent type when Actor is "agent".
	// Examples: claude-code, cursor
	AgentType string `json:"agent_type,omitempty"`

	// PathBucket categorizes the working directory (home, repo, other).
	PathBucket string `json:"path_bucket"`

	// Input is the redacted command input (max 500 chars).
	Input string `json:"input"`

	// ErrorMsg is the redacted error message (max 200 chars).
	ErrorMsg string `json:"error_msg"`

	// Suggestion is an optional suggested correction.
	Suggestion string `json:"suggestion,omitempty"`
}

FrictionEvent represents a single UX friction event. Events are anonymized and truncated before transmission.

func NewFrictionEvent

func NewFrictionEvent(kind string) FrictionEvent

NewFrictionEvent creates a new FrictionEvent with the given kind and current timestamp.

func (*FrictionEvent) Truncate

func (f *FrictionEvent) Truncate()

Truncate enforces maximum field lengths.

type FrictionResponse

type FrictionResponse struct {
	// Accepted is the number of events successfully processed.
	Accepted int `json:"accepted"`

	// Catalog contains catalog data if updated or client version is stale.
	// nil if catalog version matches X-Catalog-Version header.
	Catalog *CatalogData `json:"catalog,omitempty"`
}

FrictionResponse represents the API response from friction event submission.

type RingBuffer

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

RingBuffer is a thread-safe circular buffer for FrictionEvents. When full, new events overwrite the oldest.

func NewRingBuffer

func NewRingBuffer(capacity int) *RingBuffer

NewRingBuffer creates a RingBuffer with the given capacity.

func (*RingBuffer) Add

func (rb *RingBuffer) Add(event FrictionEvent)

Add inserts an event into the buffer, overwriting the oldest if full.

func (*RingBuffer) Count

func (rb *RingBuffer) Count() int

Count returns the current number of stored events.

func (*RingBuffer) Drain

func (rb *RingBuffer) Drain() []FrictionEvent

Drain returns all events in chronological order (oldest first) and clears the buffer.

type SubmitOptions

type SubmitOptions struct {
	// CatalogVersion is the current catalog version to send in X-Catalog-Version header.
	CatalogVersion string
}

SubmitOptions contains optional parameters for Submit.

type SubmitRequest

type SubmitRequest struct {
	// Version is the CLI version.
	Version string `json:"v"`

	// Events is the list of friction events to submit.
	Events []FrictionEvent `json:"events"`
}

SubmitRequest is the request body for friction event submission.

type SubmitResponse

type SubmitResponse struct {
	// StatusCode is the HTTP status code.
	StatusCode int

	// SampleRate is the updated sample rate from X-SageOx-Sample-Rate header.
	// -1 if not present in response.
	SampleRate float64

	// RetryAfter is the duration to wait before retrying, from Retry-After header.
	// Zero if not present in response.
	RetryAfter time.Duration

	// Catalog is catalog data from the response body, if present.
	Catalog *CatalogData
}

SubmitResponse contains the response from the friction API.

type TokenMapping

type TokenMapping struct {
	// Pattern is the typo/alias (lowercase).
	Pattern string `json:"pattern"`

	// Target is the correct token.
	Target string `json:"target"`

	// Kind specifies which failure kind this applies to.
	Kind string `json:"kind"`

	// Count is how many times this pattern was seen.
	Count int `json:"count"`

	// Confidence is 0.0-1.0, derived from count and consistency.
	Confidence float64 `json:"confidence"`
}

TokenMapping represents a single-token correction rule. Used for typos and aliases.

Jump to

Keyboard shortcuts

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