Summary
frictionax currently assumes a self-hosted frictionax-server. To support SageOx AgentX as a hosted option, several components need updates to handle different URL paths, authentication, and response formats.
Gaps
1. HTTPSource URL path is hardcoded
source.go:34 constructs:
{baseURL}/api/v1/friction/patterns?min_count={N}&limit={N}
SageOx AgentX patterns endpoint is:
{baseURL}/api/v1/agentx/{app_id}/friction/patterns?min_count={N}&limit={N}&start_date={}&end_date={}
Fix: Accept a full URL or make the path configurable. Suggested approach — add NewHTTPSourceWithURL(fullURL) that takes the complete endpoint URL, or add options:
source := frictionax.NewHTTPSource(baseURL,
frictionax.WithSourcePath("/api/v1/agentx/myapp/friction/patterns"),
frictionax.WithSourceAuth(func() string { return bearerToken }),
frictionax.WithSourceParams(map[string]string{"start_date": "2026-01-01"}),
)
2. HTTPSource has no auth support
HTTPSource creates a bare http.Client{} with no authorization headers. SageOx AgentX requires JWT Authorization: Bearer headers on all authenticated endpoints.
Fix: Add auth option to HTTPSource (bearer token function, same pattern as WithAuth on the telemetry client).
3. No url redirect handling in PatternsResponse
Our AgentX endpoint may return a url field pointing to a pre-signed S3 URL for the full patterns JSON (for scale). Current HTTPSource.FetchPatterns() ignores this field.
Fix: After decoding PatternsResponse, check if url is set. If so, follow the redirect and decode the full response from S3. This is optional behavior — the inline patterns array is always valid when url is absent.
type PatternsResponse struct {
Patterns []PatternDetail `json:"patterns"`
Total int `json:"total"`
URL string `json:"url,omitempty"` // pre-signed S3 URL
ExpiresAt string `json:"expires_at,omitempty"` // URL expiry
}
4. Telemetry submission path is hardcoded to ox-cli
client.go:88 hardcodes:
url := c.config.Endpoint + "/api/v1/cli/friction"
Third-party CLI tools using SageOx AgentX would submit to:
POST /api/v1/agentx/capture
with API key auth (X-API-Key header) and a different event envelope format (AgentX CaptureRequest wraps events differently from SubmitRequest).
Fix: This is the bigger lift. Options:
- Option A: Add a
WithSubmitPath(path) option to override the path
- Option B (recommended): Add a
SageOxSource / SageOxCollector that knows AgentX's API shape — translates FrictionEvent → AgentX CaptureEvent, uses API key auth, hits /capture
5. No "SageOx hosted" convenience constructor
Users who want the hosted SageOx backend should have a simple entry point:
f := frictionax.New(adapter,
frictionax.WithSageOx("your-api-key"), // sets endpoint, auth, paths
frictionax.WithCatalog("mycli"),
)
This would configure:
- Telemetry endpoint →
https://api.sageox.ai with API key auth
- Submit path →
/api/v1/agentx/capture
- Event translation →
FrictionEvent → AgentX CaptureEvent format
- Patterns source →
/api/v1/agentx/{app_id}/friction/patterns
And the CLI equivalent:
# Fetch patterns from SageOx hosted backend
frictionax catalog build \
--sageox-api-key sk_... \
--sageox-app-id myapp \
--catalog hand-crafted.json \
--output catalog.json
Proposed Implementation Order
- HTTPSource auth + configurable path (unblocks pattern fetching from AgentX)
- PatternsResponse
url redirect handling (future-proofs for S3 cached catalogs)
- WithSageOx convenience constructor (ergonomic hosted experience)
- AgentX capture adapter (telemetry submission to hosted backend)
Context
- AgentX patterns endpoint:
GET /api/v1/agentx/{app_id}/friction/patterns
- AgentX capture endpoint:
POST /api/v1/agentx/capture (API key in X-API-Key header)
- Response format is wire-compatible with
PatternsResponse (same PatternDetail fields)
- See sageox-mono
apps/api-go/internal/handlers/agentx/analytics.go for endpoint implementation
Summary
frictionax currently assumes a self-hosted frictionax-server. To support SageOx AgentX as a hosted option, several components need updates to handle different URL paths, authentication, and response formats.
Gaps
1. HTTPSource URL path is hardcoded
source.go:34constructs:SageOx AgentX patterns endpoint is:
Fix: Accept a full URL or make the path configurable. Suggested approach — add
NewHTTPSourceWithURL(fullURL)that takes the complete endpoint URL, or add options:2. HTTPSource has no auth support
HTTPSourcecreates a barehttp.Client{}with no authorization headers. SageOx AgentX requires JWTAuthorization: Bearerheaders on all authenticated endpoints.Fix: Add auth option to HTTPSource (bearer token function, same pattern as
WithAuthon the telemetry client).3. No
urlredirect handling in PatternsResponseOur AgentX endpoint may return a
urlfield pointing to a pre-signed S3 URL for the full patterns JSON (for scale). CurrentHTTPSource.FetchPatterns()ignores this field.Fix: After decoding
PatternsResponse, check ifurlis set. If so, follow the redirect and decode the full response from S3. This is optional behavior — the inlinepatternsarray is always valid whenurlis absent.4. Telemetry submission path is hardcoded to ox-cli
client.go:88hardcodes:Third-party CLI tools using SageOx AgentX would submit to:
with API key auth (
X-API-Keyheader) and a different event envelope format (AgentXCaptureRequestwraps events differently fromSubmitRequest).Fix: This is the bigger lift. Options:
WithSubmitPath(path)option to override the pathSageOxSource/SageOxCollectorthat knows AgentX's API shape — translatesFrictionEvent→ AgentXCaptureEvent, uses API key auth, hits/capture5. No "SageOx hosted" convenience constructor
Users who want the hosted SageOx backend should have a simple entry point:
This would configure:
https://api.sageox.aiwith API key auth/api/v1/agentx/captureFrictionEvent→ AgentXCaptureEventformat/api/v1/agentx/{app_id}/friction/patternsAnd the CLI equivalent:
# Fetch patterns from SageOx hosted backend frictionax catalog build \ --sageox-api-key sk_... \ --sageox-app-id myapp \ --catalog hand-crafted.json \ --output catalog.jsonProposed Implementation Order
urlredirect handling (future-proofs for S3 cached catalogs)Context
GET /api/v1/agentx/{app_id}/friction/patternsPOST /api/v1/agentx/capture(API key inX-API-Keyheader)PatternsResponse(samePatternDetailfields)apps/api-go/internal/handlers/agentx/analytics.gofor endpoint implementation