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 ¶
const MaxErrorLength = 200
MaxErrorLength is the maximum length for the ErrorMsg field.
const MaxEventsPerRequest = 100
MaxEventsPerRequest is the maximum number of events per submission. Events beyond this limit are silently dropped.
const MaxInputLength = 500
MaxInputLength is the maximum length for the Input field.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
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 ¶
RetryAfter returns the time until which requests should be delayed. Returns zero time if no retry-after is active.
func (*Client) SampleRate ¶
SampleRate returns the current sample rate (0.0-1.0).
func (*Client) ShouldSend ¶
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.