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!