client

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Jan 8, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package client provides a unified HTTP client for AINative platform API interactions.

The client package implements:

  • JWT bearer token authentication
  • Automatic token refresh on 401 Unauthorized responses
  • Request/response logging for observability
  • Configurable retry logic with exponential backoff
  • Timeout configuration per request
  • Base URL configuration for different AINative services

Basic Usage:

authClient := auth.NewClient(authConfig)
tokens, err := authClient.GetStoredTokens(ctx)

client := client.New(
    client.WithAuthClient(authClient),
    client.WithBaseURL("https://api.ainative.studio"),
    client.WithTimeout(30 * time.Second),
)

resp, err := client.Get(ctx, "/api/v1/resource")

The client automatically:

  • Injects JWT bearer tokens into requests
  • Refreshes expired tokens when receiving 401 responses
  • Logs all requests and responses
  • Retries failed requests with exponential backoff
  • Respects context cancellation and timeouts
Example (CustomOptions)

Example_customOptions demonstrates advanced client configuration

// Create auth client
authClient := &mockAuthClient{
	tokens: &auth.TokenPair{
		AccessToken: &auth.AccessToken{
			Raw:       "your-access-token",
			ExpiresAt: time.Now().Add(1 * time.Hour),
			UserID:    "user-123",
			Email:     "user@example.com",
			Issuer:    "ainative-auth",
			Audience:  "ainative-code",
		},
	},
}

// Create client with custom HTTP client and options
apiClient := client.New(
	client.WithBaseURL("https://api.ainative.studio"),
	client.WithAuthClient(authClient),
	client.WithTimeout(60*time.Second),
	client.WithMaxRetries(5), // More retries for flaky networks
)

ctx := context.Background()

// Example: Make request with custom headers
resp, err := apiClient.Get(ctx, "/api/v1/users/me",
	client.WithHeader("X-Request-ID", "unique-request-id"),
	client.WithHeader("X-Client-Version", "1.0.0"),
)
if err != nil {
	fmt.Printf("Failed to get user: %v\n", err)
	return
}

var user map[string]interface{}
json.Unmarshal(resp, &user)
fmt.Printf("User: %v\n", user)

// Example: Make unauthenticated request (public endpoint)
resp, err = apiClient.Get(ctx, "/api/v1/public/status",
	client.WithSkipAuth(), // Don't inject JWT token
)
if err != nil {
	fmt.Printf("Failed to get status: %v\n", err)
	return
}

var status map[string]interface{}
json.Unmarshal(resp, &status)
fmt.Printf("Status: %v\n", status)

// Example: Make request with multiple query parameters
resp, err = apiClient.Get(ctx, "/api/v1/search",
	client.WithQueryParam("q", "golang"),
	client.WithQueryParam("type", "repository"),
	client.WithQueryParam("sort", "stars"),
	client.WithQueryParam("order", "desc"),
)
if err != nil {
	fmt.Printf("Failed to search: %v\n", err)
	return
}

var searchResults map[string]interface{}
json.Unmarshal(resp, &searchResults)
fmt.Printf("Search results: %v\n", searchResults)
Example (DesignServiceClient)

Example_designServiceClient demonstrates using the API client for Design Service

// Create auth client
authClient := &mockAuthClient{
	tokens: &auth.TokenPair{
		AccessToken: &auth.AccessToken{
			Raw:       "your-access-token",
			ExpiresAt: time.Now().Add(1 * time.Hour),
			UserID:    "user-123",
			Email:     "user@example.com",
			Issuer:    "ainative-auth",
			Audience:  "ainative-code",
		},
	},
}

// Create API client configured for Design Service
apiClient := client.New(
	client.WithBaseURL("https://design.ainative.studio"),
	client.WithAuthClient(authClient),
	client.WithTimeout(60*time.Second), // Longer timeout for design operations
	client.WithMaxRetries(3),
)

ctx := context.Background()

// Example: Generate a design from prompt
designPayload := map[string]interface{}{
	"prompt":      "Create a modern login page with dark mode",
	"style":       "minimalist",
	"colorScheme": "blue",
	"framework":   "tailwind",
}

resp, err := apiClient.Post(ctx, "/api/v1/generate", designPayload)
if err != nil {
	fmt.Printf("Failed to generate design: %v\n", err)
	return
}

var designResult map[string]interface{}
json.Unmarshal(resp, &designResult)
fmt.Printf("Design generated: %v\n", designResult)

// Example: Get design by ID
designID := "design-123"
resp, err = apiClient.Get(ctx, fmt.Sprintf("/api/v1/designs/%s", designID))
if err != nil {
	fmt.Printf("Failed to get design: %v\n", err)
	return
}

var design map[string]interface{}
json.Unmarshal(resp, &design)
fmt.Printf("Design details: %v\n", design)
Example (ErrorHandling)

Example_errorHandling demonstrates error handling patterns

authClient := &mockAuthClient{
	tokens: &auth.TokenPair{
		AccessToken: &auth.AccessToken{
			Raw:       "your-access-token",
			ExpiresAt: time.Now().Add(1 * time.Hour),
			UserID:    "user-123",
			Email:     "user@example.com",
			Issuer:    "ainative-auth",
			Audience:  "ainative-code",
		},
	},
}

apiClient := client.New(
	client.WithBaseURL("https://api.ainative.studio"),
	client.WithAuthClient(authClient),
	client.WithTimeout(30*time.Second),
	client.WithMaxRetries(3),
)

ctx := context.Background()

// Example: Handle different error types
resp, err := apiClient.Get(ctx, "/api/v1/resource")
if err != nil {
	// Check for specific error types
	if client.IsAuthError(err) {
		fmt.Println("Authentication error - please re-authenticate")
		// Re-authenticate user
		return
	}

	if client.IsRetryable(err) {
		fmt.Println("Retryable error - the client already retried automatically")
		// You could implement additional retry logic here
		return
	}

	// Check for HTTP errors
	var httpErr *client.HTTPError
	if httpError, ok := err.(*client.HTTPError); ok {
		httpErr = httpError
		switch {
		case httpErr.StatusCode == 404:
			fmt.Println("Resource not found")
		case httpErr.StatusCode == 403:
			fmt.Println("Access forbidden - check permissions")
		case httpErr.StatusCode >= 500:
			fmt.Println("Server error - try again later")
		default:
			fmt.Printf("HTTP error %d: %s\n", httpErr.StatusCode, httpErr.Message)
		}
		return
	}

	// Generic error handling
	fmt.Printf("Request failed: %v\n", err)
	return
}

// Success - process response
var result map[string]interface{}
json.Unmarshal(resp, &result)
fmt.Printf("Success: %v\n", result)
Example (RlhfClient)

Example_rlhfClient demonstrates using the API client for RLHF (Reinforcement Learning from Human Feedback)

// Create auth client
authClient := &mockAuthClient{
	tokens: &auth.TokenPair{
		AccessToken: &auth.AccessToken{
			Raw:       "your-access-token",
			ExpiresAt: time.Now().Add(1 * time.Hour),
			UserID:    "user-123",
			Email:     "user@example.com",
			Issuer:    "ainative-auth",
			Audience:  "ainative-code",
		},
	},
}

// Create API client configured for RLHF service
apiClient := client.New(
	client.WithBaseURL("https://rlhf.ainative.studio"),
	client.WithAuthClient(authClient),
	client.WithTimeout(30*time.Second),
)

ctx := context.Background()

// Example: Submit feedback for a model response
feedbackPayload := map[string]interface{}{
	"sessionID":  "session-123",
	"responseID": "resp-456",
	"feedback": map[string]interface{}{
		"rating":     5,
		"helpful":    true,
		"comment":    "This response was very helpful and accurate",
		"categories": []string{"accuracy", "clarity", "helpfulness"},
	},
	"context": map[string]interface{}{
		"userQuery":     "How do I implement OAuth 2.0?",
		"modelResponse": "OAuth 2.0 is an authorization framework...",
	},
}

resp, err := apiClient.Post(ctx, "/api/v1/feedback", feedbackPayload)
if err != nil {
	fmt.Printf("Failed to submit feedback: %v\n", err)
	return
}

var feedbackResult map[string]interface{}
json.Unmarshal(resp, &feedbackResult)
fmt.Printf("Feedback submitted: %v\n", feedbackResult)

// Example: Get feedback analytics
resp, err = apiClient.Get(ctx, "/api/v1/analytics/feedback",
	client.WithQueryParam("startDate", "2026-01-01"),
	client.WithQueryParam("endDate", "2026-01-31"),
	client.WithQueryParam("aggregateBy", "day"),
)
if err != nil {
	fmt.Printf("Failed to get analytics: %v\n", err)
	return
}

var analytics map[string]interface{}
json.Unmarshal(resp, &analytics)
fmt.Printf("Analytics: %v\n", analytics)

// Example: Submit a preference comparison (A/B testing)
comparisonPayload := map[string]interface{}{
	"sessionID": "session-789",
	"prompt":    "Explain dependency injection",
	"responseA": map[string]interface{}{
		"id":      "resp-a-1",
		"content": "Dependency injection is a design pattern...",
	},
	"responseB": map[string]interface{}{
		"id":      "resp-b-1",
		"content": "DI is when you pass dependencies to a class...",
	},
	"preferred": "A",
	"reason":    "More detailed and professional explanation",
}

resp, err = apiClient.Post(ctx, "/api/v1/comparisons", comparisonPayload)
if err != nil {
	fmt.Printf("Failed to submit comparison: %v\n", err)
	return
}

var comparison map[string]interface{}
json.Unmarshal(resp, &comparison)
fmt.Printf("Comparison submitted: %v\n", comparison)
Example (StrapiCMSClient)

Example_strapiCMSClient demonstrates using the API client for Strapi CMS

// Create auth client
authClient := &mockAuthClient{
	tokens: &auth.TokenPair{
		AccessToken: &auth.AccessToken{
			Raw:       "your-access-token",
			ExpiresAt: time.Now().Add(1 * time.Hour),
			UserID:    "user-123",
			Email:     "user@example.com",
			Issuer:    "ainative-auth",
			Audience:  "ainative-code",
		},
	},
}

// Create API client configured for Strapi
apiClient := client.New(
	client.WithBaseURL("https://cms.ainative.studio"),
	client.WithAuthClient(authClient),
	client.WithTimeout(30*time.Second),
)

ctx := context.Background()

// Example: Create a blog post
blogPostPayload := map[string]interface{}{
	"data": map[string]interface{}{
		"title":   "Getting Started with AINative Code",
		"content": "AINative Code is a powerful CLI tool...",
		"author":  "John Doe",
		"tags":    []string{"tutorial", "getting-started"},
		"status":  "draft",
	},
}

resp, err := apiClient.Post(ctx, "/api/blog-posts", blogPostPayload)
if err != nil {
	fmt.Printf("Failed to create blog post: %v\n", err)
	return
}

var post map[string]interface{}
json.Unmarshal(resp, &post)
fmt.Printf("Blog post created: %v\n", post)

// Example: Query blog posts with filters and pagination
resp, err = apiClient.Get(ctx, "/api/blog-posts",
	client.WithQueryParam("filters[status][$eq]", "published"),
	client.WithQueryParam("sort", "publishedAt:desc"),
	client.WithQueryParam("pagination[page]", "1"),
	client.WithQueryParam("pagination[pageSize]", "10"),
)
if err != nil {
	fmt.Printf("Failed to query blog posts: %v\n", err)
	return
}

var posts map[string]interface{}
json.Unmarshal(resp, &posts)
fmt.Printf("Blog posts: %v\n", posts)

// Example: Update a blog post
postID := "1"
updatePayload := map[string]interface{}{
	"data": map[string]interface{}{
		"status": "published",
	},
}

resp, err = apiClient.Put(ctx, fmt.Sprintf("/api/blog-posts/%s", postID), updatePayload)
if err != nil {
	fmt.Printf("Failed to update blog post: %v\n", err)
	return
}

var updatedPost map[string]interface{}
json.Unmarshal(resp, &updatedPost)
fmt.Printf("Blog post updated: %v\n", updatedPost)
Example (ZeroDBClient)

Example_zeroDBClient demonstrates using the API client for ZeroDB NoSQL operations

// Create auth client (simplified for example)
authClient := &mockAuthClient{
	tokens: &auth.TokenPair{
		AccessToken: &auth.AccessToken{
			Raw:       "your-access-token",
			ExpiresAt: time.Now().Add(1 * time.Hour),
			UserID:    "user-123",
			Email:     "user@example.com",
			Issuer:    "ainative-auth",
			Audience:  "ainative-code",
		},
	},
}

// Create API client configured for ZeroDB
apiClient := client.New(
	client.WithBaseURL("https://api.ainative.studio"),
	client.WithAuthClient(authClient),
	client.WithTimeout(30*time.Second),
	client.WithMaxRetries(3),
)

ctx := context.Background()

// Example: Create a NoSQL table
createTablePayload := map[string]interface{}{
	"name": "users",
	"schema": map[string]interface{}{
		"type": "object",
		"properties": map[string]interface{}{
			"name":  map[string]string{"type": "string"},
			"email": map[string]string{"type": "string"},
			"age":   map[string]string{"type": "number"},
		},
	},
}

resp, err := apiClient.Post(ctx, "/api/v1/projects/my-project/nosql/tables", createTablePayload)
if err != nil {
	fmt.Printf("Failed to create table: %v\n", err)
	return
}

var createResult map[string]interface{}
json.Unmarshal(resp, &createResult)
fmt.Printf("Table created: %v\n", createResult)

// Example: Insert a document
insertPayload := map[string]interface{}{
	"table": "users",
	"data": map[string]interface{}{
		"name":  "John Doe",
		"email": "john@example.com",
		"age":   30,
	},
}

resp, err = apiClient.Post(ctx, "/api/v1/projects/my-project/nosql/documents", insertPayload)
if err != nil {
	fmt.Printf("Failed to insert document: %v\n", err)
	return
}

var insertResult map[string]interface{}
json.Unmarshal(resp, &insertResult)
fmt.Printf("Document inserted: %v\n", insertResult)

// Example: Query documents with MongoDB-style filter
queryPayload := map[string]interface{}{
	"table": "users",
	"filter": map[string]interface{}{
		"age": map[string]interface{}{
			"$gte": 18,
			"$lt":  65,
		},
	},
	"limit":  10,
	"offset": 0,
}

resp, err = apiClient.Post(ctx, "/api/v1/projects/my-project/nosql/query", queryPayload)
if err != nil {
	fmt.Printf("Failed to query documents: %v\n", err)
	return
}

var queryResult map[string]interface{}
json.Unmarshal(resp, &queryResult)
fmt.Printf("Query results: %v\n", queryResult)

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrHTTPRequest indicates an HTTP request failed.
	ErrHTTPRequest = errors.New("HTTP request failed")

	// ErrHTTPResponse indicates an HTTP response error.
	ErrHTTPResponse = errors.New("HTTP response error")

	// ErrUnauthorized indicates a 401 Unauthorized response.
	ErrUnauthorized = errors.New("unauthorized")

	// ErrForbidden indicates a 403 Forbidden response.
	ErrForbidden = errors.New("forbidden")

	// ErrNotFound indicates a 404 Not Found response.
	ErrNotFound = errors.New("not found")

	// ErrRateLimited indicates a 429 Too Many Requests response.
	ErrRateLimited = errors.New("rate limited")

	// ErrServerError indicates a 5xx server error response.
	ErrServerError = errors.New("server error")

	// ErrNoAuthClient indicates no auth client is configured.
	ErrNoAuthClient = errors.New("no auth client configured")

	// ErrTokenRefreshFailed indicates token refresh failed.
	ErrTokenRefreshFailed = errors.New("token refresh failed")

	// ErrMaxRetriesExceeded indicates maximum retry attempts exceeded.
	ErrMaxRetriesExceeded = errors.New("maximum retry attempts exceeded")

	// ErrInvalidURL indicates an invalid URL.
	ErrInvalidURL = errors.New("invalid URL")

	// ErrInvalidRequest indicates an invalid request.
	ErrInvalidRequest = errors.New("invalid request")
)

Functions

func FormatThinkingBlock

func FormatThinkingBlock(block *ThinkingBlock, showDepth bool) string

FormatThinkingBlock formats a thinking block for display

func GetMaxDepth

func GetMaxDepth(blocks []ThinkingBlock) int

GetMaxDepth returns the maximum depth found in thinking blocks

func GetThinkingDuration

func GetThinkingDuration(state *ThinkingState) time.Duration

GetThinkingDuration calculates the duration of a thinking session

func IsAuthError

func IsAuthError(err error) bool

IsAuthError returns true if the error is an authentication error.

func IsRetryable

func IsRetryable(err error) bool

IsRetryable returns true if the error is retryable.

func MergeThinkingBlocks

func MergeThinkingBlocks(blocks []ThinkingBlock) string

MergeThinkingBlocks combines multiple thinking blocks into a single text

func ThinkingEventFromJSON

func ThinkingEventFromJSON(jsonData string) (*providers.Event, error)

ThinkingEventFromJSON parses a thinking event from JSON string

func ValidateThinkingEvent

func ValidateThinkingEvent(event *providers.Event) error

ValidateThinkingEvent validates that a thinking event has required fields

Types

type Client

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

Client represents an HTTP client for AINative platform API interactions.

func New

func New(opts ...Option) *Client

New creates a new API client with the specified options.

func (*Client) Delete

func (c *Client) Delete(ctx context.Context, path string, opts ...RequestOption) ([]byte, error)

Delete performs a DELETE request to the specified path.

func (*Client) Get

func (c *Client) Get(ctx context.Context, path string, opts ...RequestOption) ([]byte, error)

Get performs a GET request to the specified path.

func (*Client) Patch

func (c *Client) Patch(ctx context.Context, path string, body interface{}, opts ...RequestOption) ([]byte, error)

Patch performs a PATCH request to the specified path with the given body.

func (*Client) Post

func (c *Client) Post(ctx context.Context, path string, body interface{}, opts ...RequestOption) ([]byte, error)

Post performs a POST request to the specified path with the given body.

func (*Client) Put

func (c *Client) Put(ctx context.Context, path string, body interface{}, opts ...RequestOption) ([]byte, error)

Put performs a PUT request to the specified path with the given body.

type HTTPError

type HTTPError struct {
	StatusCode int
	Message    string
	Body       []byte
	Err        error
}

HTTPError represents an HTTP error with status code and message.

func NewHTTPError

func NewHTTPError(statusCode int, message string, body []byte, err error) *HTTPError

NewHTTPError creates a new HTTP error.

func (*HTTPError) Error

func (e *HTTPError) Error() string

Error implements the error interface.

func (*HTTPError) Unwrap

func (e *HTTPError) Unwrap() error

Unwrap returns the underlying error.

type Option

type Option func(*Client)

Option is a functional option for configuring the Client.

func WithAuthClient

func WithAuthClient(authClient auth.Client) Option

WithAuthClient sets the authentication client for JWT token management.

func WithBaseURL

func WithBaseURL(baseURL string) Option

WithBaseURL sets the base URL for API requests.

func WithHTTPClient

func WithHTTPClient(httpClient *http.Client) Option

WithHTTPClient sets a custom HTTP client.

func WithMaxRetries

func WithMaxRetries(maxRetries int) Option

WithMaxRetries sets the maximum number of retry attempts for failed requests.

func WithTimeout

func WithTimeout(timeout time.Duration) Option

WithTimeout sets the HTTP request timeout.

type Options

type Options struct {
	// BaseURL is the base URL for all API requests
	BaseURL string

	// Timeout is the default timeout for HTTP requests
	Timeout time.Duration

	// MaxRetries is the maximum number of retry attempts
	MaxRetries int

	// RetryBackoff is the initial backoff duration for retries
	RetryBackoff time.Duration

	// EnableLogging enables request/response logging
	EnableLogging bool

	// HTTPClient is the underlying HTTP client (optional)
	HTTPClient *http.Client

	// UserAgent is the User-Agent header value
	UserAgent string
}

Options contains configuration options for the HTTP client.

func DefaultOptions

func DefaultOptions() *Options

DefaultOptions returns the default client options.

type RequestOption

type RequestOption func(*requestOptions)

RequestOption is a functional option for per-request configuration.

func WithDisableRetry

func WithDisableRetry() RequestOption

WithDisableRetry disables retry logic for this request.

func WithHeader

func WithHeader(key, value string) RequestOption

WithHeader adds a custom header to the request.

func WithHeaders

func WithHeaders(headers map[string]string) RequestOption

WithHeaders adds multiple custom headers to the request.

func WithQueryParam

func WithQueryParam(key, value string) RequestOption

WithQueryParam adds a query parameter to the request.

func WithQueryParams

func WithQueryParams(params map[string]string) RequestOption

WithQueryParams adds multiple query parameters to the request.

func WithSkipAuth

func WithSkipAuth() RequestOption

WithSkipAuth skips JWT token injection for this request.

type RequestOptions

type RequestOptions struct {
	// Headers are additional headers to include in the request
	Headers map[string]string

	// QueryParams are query parameters to include in the request
	QueryParams map[string]string

	// Timeout overrides the default client timeout for this request
	Timeout time.Duration

	// SkipAuth skips JWT token injection for this request
	SkipAuth bool

	// DisableRetry disables retry logic for this request
	DisableRetry bool
}

RequestOptions contains per-request options.

type Response

type Response struct {
	// StatusCode is the HTTP status code
	StatusCode int

	// Headers are the response headers
	Headers http.Header

	// Body is the raw response body
	Body []byte

	// Duration is the time taken for the request
	Duration time.Duration
}

Response represents an HTTP response with parsed data.

type ThinkingBlock

type ThinkingBlock struct {
	Content   string                 `json:"content"`
	Depth     int                    `json:"depth"`
	Timestamp time.Time              `json:"timestamp"`
	Index     int                    `json:"index"`
	Type      string                 `json:"type"` // "start", "delta", "end"
	Metadata  map[string]interface{} `json:"metadata,omitempty"`
}

ThinkingBlock represents a single thinking event block

func FilterThinkingBlocks

func FilterThinkingBlocks(blocks []ThinkingBlock, blockType string) []ThinkingBlock

FilterThinkingBlocks filters thinking blocks by type

type ThinkingEventParser

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

ThinkingEventParser handles parsing and processing of thinking events

func NewThinkingEventParser

func NewThinkingEventParser() *ThinkingEventParser

NewThinkingEventParser creates a new thinking event parser

func (*ThinkingEventParser) GetState

func (p *ThinkingEventParser) GetState() *ThinkingState

GetState returns the current thinking state

func (*ThinkingEventParser) ParseEvent

func (p *ThinkingEventParser) ParseEvent(event *providers.Event) (*ThinkingBlock, error)

ParseEvent parses a provider event and extracts thinking information

func (*ThinkingEventParser) Reset

func (p *ThinkingEventParser) Reset()

Reset resets the parser state

type ThinkingState

type ThinkingState struct {
	Blocks        []ThinkingBlock
	CurrentDepth  int
	TotalEvents   int
	IsThinking    bool
	StartTime     time.Time
	LastEventTime time.Time
}

ThinkingState tracks the current state of thinking events

Directories

Path Synopsis
Package design provides a client for interacting with the AINative Design API.
Package design provides a client for interacting with the AINative Design API.
Package rlhf provides a client for AINative RLHF (Reinforcement Learning from Human Feedback) operations.
Package rlhf provides a client for AINative RLHF (Reinforcement Learning from Human Feedback) operations.
Package strapi provides a client for interacting with Strapi CMS API.
Package strapi provides a client for interacting with Strapi CMS API.
Package zerodb provides a client for ZeroDB NoSQL table operations.
Package zerodb provides a client for ZeroDB NoSQL table operations.

Jump to

Keyboard shortcuts

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