Skip to content

Visual Elements

This page collects key diagrams, tables, and code snippets that illustrate the structure and operation of the MFO Client component. These elements are often referenced or embedded in other documentation pages.


🖼️ Mermaid Diagrams

1️⃣ Overall Architecture (High-Level)

This diagram shows the MFO Client's place in the broader MindFlight AI ecosystem.

graph TD
    A[External Systems / Event Sources] --> B(MFO Client)
    B -- Forwards Events / Executes Tasks --> C(MFO Server API)
    C -- Orchestrates --> D(LLM Providers / Other Services)

    style B fill:#lightgreen,stroke:#333,stroke-width:2px
    style C fill:#lightblue,stroke:#333,stroke-width:2px

2️⃣ Event Lifecycle with Structured API Client

Illustrates how an incoming webhook event is processed and forwarded to the MFO Server using the client's structured API components.

sequenceDiagram
    participant ExtSystem as External System
    participant Listener as MFO Client Webhook Listener
    participant AppLogic as Client Application Logic
    participant EventClient as MFO EventClient (API Component)
    participant BaseClient as MFO BaseClient (API Component)
    participant AuthProv as AuthProvider (API Component)
    participant MFOServer as MFO Server API

    ExtSystem->>+Listener: POST /webhook (Raw Event + Signature)
    Listener->>+AppLogic: Raw Event, Headers
    AppLogic->>AppLogic: Verify Signature & Parse Event
    AppLogic->>+EventClient: SendEvent(parsedEvent)
    EventClient->>+BaseClient: Post("/api/events", MFOEvent)
    BaseClient->>+AuthProv: GetAuthHeader()
    AuthProv-->>-BaseClient: Authorization Token
    BaseClient->>+MFOServer: POST /api/events (Authenticated, w/ Retries, Circuit Breaker)
    MFOServer-->>-BaseClient: API Response (e.g., EventID, Ack)
    BaseClient-->>-EventClient: Result / Error
    EventClient-->>-AppLogic: Forwarding Result
    AppLogic-->>-Listener: Processing Acknowledged
    Listener-->>-ExtSystem: HTTP 202 Accepted (or error)

3️⃣ Multi-Client Deployment

Shows how multiple MFO Client instances can be deployed, potentially for different purposes or tenants, all interacting with a central MFO Server.

graph TD
    Source1[Webhook Source A => CRM] --> ClientA[MFO Client Instance A]
    Source2[Webhook Source B => IoT] --> ClientB[MFO Client Instance B]
    Source3[Custom App Events] --> ClientC[MFO Client Instance C]
    ClientA --> MFOSrv[MFO Server API]
    ClientB --> MFOSrv
    ClientC --> MFOSrv

    style ClientA fill:#lightgreen,stroke:#333
    style ClientB fill:#lightgreen,stroke:#333
    style ClientC fill:#lightgreen,stroke:#333
    style MFOSrv fill:#lightblue,stroke:#333

4️⃣ Conceptual MFO Taskflow Example

Illustrates a taskflow that might involve interaction with the MFO server via the API client (e.g., for creating a resource or sending a chat message).

graph TD
    A[Event Trigger: e.g., New Data Received] --> B{Run Local Taskflow};
    subgraph Local MFO Client Taskflow
        direction LR
        T1[Parse Input Data] --> T2[Validate Data];
        T2 -- Valid --> T3[Prepare MFO Resource Request];
        T3 --> T4[Call MFO ResourceClient: CreateResource];
        T4 -- Success --> T5[Log Success & ResourceID];
        T4 -- Failure --> T6[Handle API Error / Retry];
        T5 --> T7[Optional: Send MFO Chat Message via ChatClient];
    end
    B --> T1;
    style T4 fill:#e6e6fa,stroke:#333
    style T7 fill:#e6e6fa,stroke:#333

5️⃣ API Client Initialization and Usage Flow

This diagram shows the typical steps involved in initializing the MFO API client components based on configuration, and how an application logic component would then use these clients to interact with the MFO Server.

graph TD
    subgraph Initialization Phase
        ConfigFile[config.yaml] -- Loads --> AppConfig[App Config Structs]
        AppConfig -- Provides Auth Details --> AuthProviderInit{Initialize AuthProvider}

        subgraph "AuthProvider (e.g., JWTAuth, TokenAuth)"
            AuthProviderInit --> AP[auth.AuthProvider Instance]
            AppConfig -- Provides API Config --> BaseClientInit{Initialize BaseClient}
        end

        HttpClientInit{Initialize http.Client} --> HTTPC[http.Client Instance]

        BaseClientInit -- Uses --> AP
        BaseClientInit -- Uses --> HTTPC
        BaseClientInit --> BC[client.BaseClient Instance]

        BC -- Used by --> SCInit{Initialize Specialized Clients}
        SCInit --> EC[api.EventClient]
        SCInit --> CC[api.ChatClient]
        SCInit --> RC[api.ResourceClient]
    end

    subgraph Operational Phase
        AppLogic[Application Logic e.g., WebhookHandler, TaskFunc] -- Uses --> EC
        AppLogic -- Uses --> CC
        AppLogic -- Uses --> RC

        EC -- Delegates to --> BC
        CC -- Delegates to --> BC
        RC -- Delegates to --> BC

        BC -- Makes Call --> MFOServer[MFO Server API]
    end

    classDef config fill:#f9f,stroke:#333,stroke-width:2px;
    class ConfigFile,AppConfig config;
    classDef clientcomp fill:#90EE90,stroke:#333,stroke-width:2px;
    class AP,HTTPC,BC,EC,CC,RC clientcomp;
    classDef applogic fill:#ADD8E6,stroke:#333,stroke-width:2px;
    class AppLogic applogic;

6️⃣ Authentication Flow within API Call

This sequence diagram illustrates how authentication is handled when a specialized API client makes a call. It shows the BaseClient interacting with an AuthProvider to obtain an authentication header, potentially involving a login or token refresh if necessary.

sequenceDiagram
    participant AppLogic as "Application Logic"
    participant SpecClient as "Specialized Client"
    participant BaseClient as "client.BaseClient"
    participant AuthProv as "auth.AuthProvider"
    participant MFOServer as "MFO Server API"
    participant MFOAuthSvc as "MFO Auth Service"

    AppLogic->>SpecClient: Call API Method (SendEvent)
    SpecClient->>BaseClient: Call HTTP Method (Post)
    BaseClient->>AuthProv: GetAuthHeader()

    alt Token Valid or Pre-set
        AuthProv-->>BaseClient: "Bearer <token>"
    else Token Missing or Needs Refresh
        AuthProv->>MFOAuthSvc: LoginRequest/RefreshToken
        MFOAuthSvc-->>AuthProv: LoginResponse(token)
        AuthProv->>AuthProv: Store new token
        AuthProv-->>BaseClient: "Bearer <new_token>"
    end

    alt Auth Header Obtained
        BaseClient->>MFOServer: HTTP Request with Auth
        MFOServer-->>BaseClient: HTTP Response
    else Auth Failed
        BaseClient-->>SpecClient: Error
        SpecClient-->>AppLogic: Error
    end
    BaseClient-->>SpecClient: Result / Error
    SpecClient-->>AppLogic: Result / Error

📊 Tables

🔑 Client Configuration Keys (config.yaml)

This table outlines the main sections and keys in the MFO Client's YAML configuration file, reflecting the structure for client (API communication) and webhook_listener components.

Path (section.subsection.key) Description Example Value
client.base_url Base URL for MFO server API endpoints. https://api.mfo.example.com
client.auth_base_url (Optional) Base URL for authentication service if different from base_url. https://auth.mfo.example.com
client.auth_token API token for simple authentication (used by SimpleAuthProvider). Securely manage. your-secure-api-token
client.timeout Global HTTP request timeout for API calls (e.g., "30s", "1m"). 30s
client.retry.max_attempts Max number of retry attempts for failed API calls. 3
client.retry.initial_backoff Initial delay before the first retry (e.g., "1s", "500ms"). 1s
client.retry.max_backoff Maximum delay between retries. 30s
client.retry.backoff_multiplier Multiplier for exponential backoff calculation. 2.0
client.circuit_breaker.failure_threshold Number of consecutive failures to open the circuit. 5
client.circuit_breaker.reset_timeout Duration the circuit stays open before attempting to half-open (e.g., "1m"). 1m
webhook_listener.host Host for the webhook listener to bind to. 0.0.0.0 or localhost
webhook_listener.port Port for the webhook listener. 8080
webhook_listener.path URL path to listen for incoming webhooks. /webhook
webhook_listener.secret_key Secret key for verifying incoming webhook signatures. Securely manage. your-webhook-secret
logging.level Logging level (e.g., debug, info, warn, error). info
logging.format Logging output format (e.g., text, json). json

Refer to mfo_client_4_usage_examples.md for the full Go struct definitions for this configuration._doc_manus


🗂️ Key Internal Folder/File Roles

This table outlines the primary roles of key directories and example files within the /internal structure of the MFO Client.

Path (/internal/...) Purpose
client/client.go Contains the BaseClient for core HTTP communication, applying auth, retries, circuit breakers.
auth/auth_provider.go Defines the AuthProvider interface for different authentication strategies.
auth/..._auth.go Implementations of AuthProvider (e.g., for JWT, API tokens).
api/interfaces.go Defines interfaces for specialized MFO API clients (e.g., EventClientInterface, ChatClientInterface).
api/*_client.go Implementations of specialized API clients (e.g., EventClient, ResourceClient).
handlers/webhook_handler.go Handles incoming HTTP webhooks, parses events, and initiates processing (e.g., calls an API client).
models/... Defines Go data structures for API requests/responses, taskflow elements, internal entities, errors.
taskflow/registry.go TaskRegistry for mapping YAML task types to Go task factory functions.
taskflow/builder.go Builder to construct executable go-taskflow graphs from definitions.
taskflow/executor.go FlowExecutor to manage the execution of taskflows, including context and MFO client injection.
taskflow/loader.go Utilities to load and parse YAML taskflow definitions into Go structs.
config/config.go Defines Go structs for application configuration and provides loading logic (e.g., LoadConfig).

💻 Go Code Snippets

🔰 Initializing and Starting the Client Service (Conceptual main.go)

package main

import (
    "log"
    "net/http"
    "time"

    "your_project_path/internal/api"
    "your_project_path/internal/auth"
    "your_project_path/internal/client"
    "your_project_path/internal/config"
    "your_project_path/internal/handlers"
)

func main() {
    cfg, err := config.LoadConfig("config.yaml") // Or path from env var
    if err != nil {
        log.Fatalf("Failed to load configuration: %v", err)
    }

    // Initialize AuthProvider (example: simple token)
    // For production, use a more secure provider or one that handles token refresh.
    var authProvider auth.AuthProvider
    if cfg.Client.AuthToken != "" {
        authProvider = auth.NewSimpleTokenAuthProvider(cfg.Client.AuthToken)
    } else {
        // Potentially initialize a more complex auth provider, e.g., OAuth2 or JWT with login
        log.Println("Warning: No auth_token configured, using nil AuthProvider or fallback.")
        // authProvider = auth.NewOAuthProvider(...) 
    }

    httpClient := &http.Client{Timeout: time.Duration(cfg.Client.Timeout)}

    // Initialize BaseClient with config for retries and circuit breaker
    baseClient := client.NewBaseClient(
        cfg.Client.BaseURL,
        httpClient,
        authProvider,
        client.WithRetryPolicy(cfg.Client.Retry), // Assuming WithRetryPolicy takes your RetryConfig struct
        client.WithCircuitBreakerPolicy(cfg.Client.CircuitBreaker), // Assuming WithCBPolicy
    )

    // Initialize specialized clients
    eventApiClient := api.NewEventClient(baseClient)
    // chatApiClient := api.NewChatClient(baseClient)
    // ... other clients

    // Setup webhook handler with the Event API client
    http.HandleFunc(cfg.WebhookListener.Path, handlers.WebhookHandler(eventApiClient, cfg.WebhookListener.SecretKey))

    serverAddr := cfg.WebhookListener.Host + ":" + cfg.WebhookListener.Port
    log.Printf("MFO Client listening on %s%s", serverAddr, cfg.WebhookListener.Path)
    if err := http.ListenAndServe(serverAddr, nil); err != nil {
        log.Fatalf("Server failed to start: %v", err)
    }
}

🛎️ Webhook Handler with API Client Usage

This snippet shows a handler using an injected EventClientInterface to forward an event.

// From internal/handlers/webhook_handler.go
package handlers

import (
    "context"
    "encoding/json"
    "log"
    "net/http"
    "time"

    "your_project_path/internal/api"    // For EventClientInterface
    "your_project_path/internal/models" // For your Event struct
)

func WebhookHandler(eventClient api.EventClientInterface, webhookSecret string) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        // IMPORTANT: Implement robust signature verification using webhookSecret first!
        // if !auth.VerifySignature(r, webhookSecret) {
        //    http.Error(w, "Invalid signature", http.StatusUnauthorized)
        //    return
        // }

        var receivedEvent models.Event // Adjust to your specific event model
        if err := json.NewDecoder(r.Body).Decode(&receivedEvent); err != nil {
            http.Error(w, "Invalid event payload", http.StatusBadRequest)
            log.Printf("Error decoding webhook event: %v", err)
            return
        }
        defer r.Body.Close()

        log.Printf("Received webhook: Type '%s'", receivedEvent.Type)

        // Asynchronously forward the event using the structured API client
        go func(eventToForward models.Event) {
            ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) // Example timeout
            defer cancel()

            // The EventClient handles authentication, retries, etc., via BaseClient
            apiResponse, err := eventClient.SendEvent(ctx, eventToForward)
            if err != nil {
                log.Printf("Error forwarding event to MFO server via EventClient: %v", err)
                // Implement more sophisticated error handling here if needed (e.g., dead-letter queue)
            } else {
                log.Printf("Event forwarded successfully by EventClient. MFO Response ID: %s", apiResponse.ID) // Assuming apiResponse has an ID
            }
        }(receivedEvent)

        w.WriteHeader(http.StatusAccepted)
        fmt.Fprintln(w, "Event received and is being processed.")
    }
}

🚀 Forwarding Logic using Specialized Client (Conceptual)

This illustrates how a specialized client (e.g., EventClient) uses the BaseClient.

// From internal/api/event_client.go (Conceptual)
package api

import (
    "context"
    "your_project_path/internal/models"
)

type EventClient struct {
    base BaseClientInterface // Injected BaseClient
}

func NewEventClient(base BaseClientInterface) *EventClient {
    return &EventClient{base: base}
}

func (c *EventClient) SendEvent(ctx context.Context, eventData models.Event) (*models.EventResponse, error) {
    var response models.EventResponse
    // Path should be a constant or from config
    err := c.base.Post(ctx, "/api/v1/events", eventData, &response)
    if err != nil {
        return nil, err // BaseClient handles APIError creation, retries, etc.
    }
    return &response, nil
}

🗄️ API Error Handling Example

Shows how to check for specific APIError types returned from client calls.

import (
    "errors"
    "log"
    "your_project_path/internal/models" // Where APIError is defined
)

func handleSomeApiCall() {
    // response, err := someApiClient.SomeOperation(context.Background(), requestData)
    var err error // Placeholder for an actual API call error
    if err != nil {
        var apiErr *models.APIError
        var retryableErr *models.RetryableError // Assuming you have this wrapper
        var cbErr *models.CircuitBreakerError // Assuming you have this

        if errors.As(err, &apiErr) {
            log.Printf("MFO API Error: Status %d, Code '%s', Message: %s", apiErr.StatusCode, apiErr.Code, apiErr.Message)
            if apiErr.StatusCode == http.StatusUnauthorized {
                log.Println("Authentication failed. Token might be expired or invalid.")
                // Trigger re-authentication or alert
            } else if apiErr.StatusCode >= 500 {
                log.Println("MFO Server error. This might have been retried based on policy.")
            }
        } else if errors.As(err, &retryableErr) {
            log.Printf("Operation failed but was deemed retryable. Original error: %v. Retry After: %v", 
                retryableErr.OriginalError, retryableErr.RetryAfter)
        } else if errors.As(err, &cbErr) {
            log.Printf("Circuit Breaker is open for service '%s'. State: %s", cbErr.ServiceName, cbErr.State)
        } else {
            // Network error or other non-API specific error that might have exhausted retries
            log.Printf("Operation failed due to an unexpected error: %v", err)
        }
        return
    }
    // log.Printf("Operation successful: %v", response)
}

⚙️ Configuration Parsing (Structs)

Reflects the new multi-level Config structure for YAML, including ClientConfig with RetryConfig and CBConfig.

// From internal/config/config.go
package config

import (
    "os"
    "time"
    "gopkg.in/yaml.v3"
)

// Duration is a helper for unmarshalling time.Duration from strings like "30s".
type Duration time.Duration

func (d *Duration) UnmarshalYAML(value *yaml.Node) error {
    dur, err := time.ParseDuration(value.Value)
    if err != nil { return err }
    *d = Duration(dur)
    return nil
}

// ClientConfig holds settings for API client communication.
type ClientConfig struct {
    BaseURL        string        `yaml:"base_url"`
    AuthBaseURL    string        `yaml:"auth_base_url,omitempty"`
    AuthToken      string        `yaml:"auth_token,omitempty"`
    Timeout        Duration      `yaml:"timeout"`
    Retry          RetryConfig   `yaml:"retry"`
    CircuitBreaker CBConfig      `yaml:"circuit_breaker"`
}

// RetryConfig defines the retry policy.
type RetryConfig struct {
    MaxAttempts       int      `yaml:"max_attempts"`
    InitialBackoff    Duration `yaml:"initial_backoff"`
    MaxBackoff        Duration `yaml:"max_backoff"`
    BackoffMultiplier float64  `yaml:"backoff_multiplier"`
}

// CBConfig defines the circuit breaker policy.
type CBConfig struct {
    FailureThreshold int      `yaml:"failure_threshold"`
    ResetTimeout     Duration `yaml:"reset_timeout"`
}

// WebhookListenerConfig holds settings for the webhook listener.
type WebhookListenerConfig struct {
    Host      string `yaml:"host"`
    Port      string `yaml:"port"`
    Path      string `yaml:"path"`
    SecretKey string `yaml:"secret_key"`
}

// LoggingConfig holds settings for logging.
type LoggingConfig struct {
    Level  string `yaml:"level"`
    Format string `yaml:"format"`
}

// Config is the top-level configuration structure.
type Config struct {
    Client           ClientConfig          `yaml:"client"`
    WebhookListener  WebhookListenerConfig `yaml:"webhook_listener"`
    Logging          LoggingConfig         `yaml:"logging,omitempty"`
}

// LoadConfig loads YAML configuration from file, expanding environment variables.
func LoadConfig(filePath string) (*Config, error) {
    data, err := os.ReadFile(filePath)
    if err != nil { return nil, err }
    expandedData := os.ExpandEnv(string(data))
    var cfg Config
    if err := yaml.Unmarshal([]byte(expandedData), &cfg); err != nil { return nil, err }
    return &cfg, nil
}

These visual elements provide a clear, illustrated guide to understanding how the Client MindFlight AI component works—covering architecture, workflows, configuration, and implementation!