RequestBuilder Pattern
File: /inc/Engine/AI/RequestBuilder.php
Since: 0.2.0
Centralized AI request construction ensuring consistent request structure across Pipeline AI and Chat API agents. Single source of truth for building standardized AI requests to prevent architectural drift between agent types.
Purpose
The RequestBuilder class consolidates all AI request building logic into a single, unified interface. This prevents behavioral differences between Pipeline and Chat agents by ensuring both use identical request construction, tool formatting, and directive application patterns.
Critical Rule: Data Machine runtime code should not bypass its own request assembly. Use RequestBuilder::build() for Data Machine chat and pipeline AI steps so directive application, metadata, request guardrails, and wp-ai-client dispatch stay consistent. This rule is not an Agents API boundary: plugins that only need one-shot AI operations may call wp-ai-client directly without routing through Data Machine or Agents API.
Architecture
Request Building Flow:
┌─────────────────────────────────────────────────────┐
│ RequestBuilder::build() │
│ │
│ 1. Initialize Request │
│ • Set model and messages │
│ │
│ 2. Restructure Tools │
│ • Normalize tool definitions │
│ • Ensure provider compatibility │
│ │
│ 3. Apply Directives via PromptBuilder │
│ • datamachine_directives filter collects configs │
│ • Priority-based sorting and agent targeting │
│ • Unified directive management │
│ │
│ 4. Send to wp-ai-client │
│ • RequestBuilder capability gate │
│ • Returns standardized AI response │
└─────────────────────────────────────────────────────┘Usage
Basic Usage
use DataMachineEngineAIRequestBuilder;
$ai_response = RequestBuilder::build(
$messages, // Messages array with role/content
$provider, // AI provider name (openai, anthropic, etc.)
$model, // Model identifier
$tools, // Raw tools array from filters
$agent_type, // 'chat' or 'pipeline'
$context // Agent-specific context (session_id, step_id, payload, etc)
);Pipeline Agent Example
use DataMachineEngineAIRequestBuilder;
// Build context for pipeline agent
$context = [
'step_id' => $flow_step_id,
'payload' => [
'job_id' => $job_id,
'flow_step_id' => $flow_step_id,
'data' => $data,
'flow_step_config' => $flow_step_config,
'engine_data' => $engine_data
]
];
// Build AI request
$ai_response = RequestBuilder::build(
$messages,
'openai',
'gpt-4',
$tools,
'pipeline',
$context
);
// Check response
if ($ai_response['success']) {
$tool_calls = $ai_response['data']['tool_calls'] ?? [];
$content = $ai_response['data']['content'] ?? '';
} else {
$error = $ai_response['error'] ?? 'Unknown error';
}Chat Agent Example
use DataMachineEngineAIRequestBuilder;
// Build context for chat agent
$context = [
'session_id' => $session_id
];
// Build AI request
$ai_response = RequestBuilder::build(
$messages,
'anthropic',
'claude-3-5-sonnet-20241022',
$tools,
'chat',
$context
);
// Check response
if ($ai_response['success']) {
$content = $ai_response['data']['content'] ?? '';
$tool_calls = $ai_response['data']['tool_calls'] ?? [];
}Directive Application System
The RequestBuilder integrates with PromptBuilder for unified directive management with priority-based ordering and agent-specific targeting.
Directive System (@since v0.2.5)
1. PromptBuilder Initialization
↓ RequestBuilder creates PromptBuilder instance
2. Directive Collection
↓ datamachine_directives filter returns directive configurations
3. Priority-Based Sorting
↓ Directives sorted by priority (ascending: low to high)
4. Agent-Specific Application
↓ Each directive applied based on agent type targetingDirective Registration
Directives are registered via the datamachine_directives filter with configuration arrays:
add_filter('datamachine_directives', function($directives) {
$directives[] = [
'class' => MyDirective::class,
'priority' => 20, // Lower numbers applied first
'modes' => ['all'] // 'all', 'pipeline', 'chat', 'system', or extension mode
];
return $directives;
});Priority Order (lower = applied first):
- 20: Registered memory files
- 22: Runtime agent-mode guidance
- 25-35: Caller, daily memory, and client-reported context
- 40-50: Pipeline, flow, chat inventory, and workflow-specific directives
Current Directive Implementations
CoreMemoryFilesDirective– Registered memory files from shared, agent, and user layers (priority 20)AgentModeDirective– Runtime mode guidance for chat, pipeline, system, and extension modes (priority 22)CallerContextDirective– Authenticated cross-site caller identity (priority 25)AgentDailyMemoryDirectiveandClientContextDirective– Optional daily memory and client context (priority 35)PipelineMemoryFilesDirective,FlowMemoryFilesDirective, andPipelineSystemPromptDirective– Pipeline-specific context (priorities 40, 45, 50)ChatPipelinesDirective– Pipeline and flow inventory for chat (priority 45)
Tool Restructuring
The RequestBuilder normalizes tool definitions to ensure consistent structure across all providers:
private static function restructure_tools(array $raw_tools): array
{
$structured = [];
foreach ($raw_tools as $tool_name => $tool_config) {
$structured[$tool_name] = [
'name' => $tool_name,
'description' => $tool_config['description'] ?? '',
'parameters' => $tool_config['parameters'] ?? [],
'handler' => $tool_config['handler'] ?? null,
'handler_config' => $tool_config['handler_config'] ?? []
];
}
return $structured;
}Purpose: Ensures all tools have explicit name, description, parameters, handler, and handler_config fields, preventing tool format mismatches with AI providers.
Example:
Input (raw tool from filter):
$tools['twitter_publish'] = [
'class' => 'DataMachine\Core\Steps\Publish\Handlers\Twitter\Twitter',
'method' => 'handle_tool_call',
'handler' => 'twitter',
'description' => 'Post content to Twitter',
'parameters' => [...]
];Output (structured tool):
$structured_tools['twitter_publish'] = [
'name' => 'twitter_publish',
'description' => 'Post content to Twitter',
'parameters' => [...],
'handler' => 'twitter',
'handler_config' => []
];Integration with wp-ai-client
The RequestBuilder gates runtime availability through WpAiClientCapability, then sends the finalized request through WpAiClientAdapter. The gate requires:
wp_ai_client_prompt()being defined.wp_supports_ai()being defined and returning true.- The requested provider, or its known alias, being registered in the wp-ai-client default provider registry.
If the gate fails, RequestBuilder returns a structured request error with request_metadata. It does not fall back to chubes_ai_request / ai-http-client.
Response Structure:
[
'success' => true,
'data' => [
'content' => 'AI text response',
'tool_calls' => [
[
'name' => 'tool_name',
'parameters' => [...]
]
]
],
'provider' => 'openai',
'model' => 'gpt-4',
'error' => 'Error message if success=false'
]Context Parameter
The $context array provides information to directives, logging, transcripts, and request metadata:
Pipeline Context
$context = [
'step_id' => $flow_step_id, // Used for logging and directive identification
'payload' => [ // Complete step execution context
'job_id' => $job_id,
'flow_step_id' => $flow_step_id,
'data' => $data,
'flow_step_config' => $flow_step_config,
'engine_data' => $engine_data
]
];Available to Directives:
$context['step_id']– Flow step identifier$context['payload']['job_id']– Job execution ID$context['payload']['data']– Data packets from previous steps$context['payload']['flow_step_config']– Step configuration$context['payload']['engine_data']– Engine parameters (source_url, image_url)
Chat Context
$context = [
'session_id' => $session_id // Chat session identifier
];Available to Directives:
$context['session_id']– Chat session ID for persistence
Response Format
The RequestBuilder returns a standardized response structure:
Success Response
[
'success' => true,
'data' => [
'content' => 'AI generated text response',
'tool_calls' => [
[
'name' => 'tool_name',
'parameters' => [
'param1' => 'value1',
'param2' => 'value2'
]
]
]
],
'provider' => 'openai',
'model' => 'gpt-4'
]Error Response
[
'success' => false,
'error' => 'Descriptive error message',
'provider' => 'anthropic',
'model' => 'claude-3-5-sonnet-20241022'
]Error Handling
Provider Errors
AI provider errors (API failures, rate limits, invalid credentials) are returned in the error response:
$ai_response = RequestBuilder::build(...);
if (!$ai_response['success']) {
$error = $ai_response['error'] ?? 'Unknown error';
$provider = $ai_response['provider'] ?? 'Unknown';
do_action('datamachine_log', 'error', 'RequestBuilder: AI request failed', [
'provider' => $provider,
'error' => $error
]);
}Configuration Errors
Missing or invalid runtime configuration (wp-ai-client unavailable, model not set, provider not configured) is returned in the standard response shape:
[
'success' => false,
'error' => 'wp-ai-client provider "openai" is not registered'
]Logging
The RequestBuilder logs request building details:
do_action('datamachine_log', 'debug', 'RequestBuilder: Built AI request', [
'agent_type' => $agent_type,
'provider' => $provider,
'model' => $model,
'message_count' => count($request['messages']),
'tool_count' => count($structured_tools)
]);Log Entry:
RequestBuilder: Built AI request
- agent_type: pipeline
- provider: openai
- model: gpt-4
- message_count: 5
- tool_count: 3Best Practices
Always Use RequestBuilder
Correct:
use DataMachineEngineAIRequestBuilder;
$ai_response = RequestBuilder::build(
$messages,
$provider,
$model,
$tools,
$agent_type,
$context
);Incorrect (bypasses directive system and tool restructuring):
// NEVER DO THIS
$ai_response = wp_ai_client_prompt()->generate_text_result();Provide Complete Context
Pipeline Agent:
$context = [
'step_id' => $flow_step_id,
'payload' => [
'job_id' => $job_id,
'flow_step_id' => $flow_step_id,
'data' => $data,
'flow_step_config' => $flow_step_config,
'engine_data' => $engine_data
]
];Chat Agent:
$context = [
'session_id' => $session_id
];Handle Errors Gracefully
$ai_response = RequestBuilder::build(...);
if (!$ai_response['success']) {
do_action('datamachine_log', 'error', 'AI request failed', [
'error' => $ai_response['error'],
'provider' => $ai_response['provider']
]);
// Return error to caller or retry
return [
'success' => false,
'error' => $ai_response['error']
];
}
// Process successful response
$content = $ai_response['data']['content'] ?? '';
$tool_calls = $ai_response['data']['tool_calls'] ?? [];Directive Registration
Register directives using the unified datamachine_directives filter with appropriate priorities:
// Register a global directive (applies to all modes)
add_filter('datamachine_directives', function($directives) {
$directives[] = [
'class' => MyGlobalDirective::class,
'priority' => 25,
'modes' => ['all']
];
return $directives;
});
// Register a pipeline-specific directive
add_filter('datamachine_directives', function($directives) {
$directives[] = [
'class' => MyPipelineDirective::class,
'priority' => 40,
'modes' => ['pipeline']
];
return $directives;
});Priority Guidelines:
- 20: Registered memory files
- 22: Runtime agent-mode guidance
- 25-35: Caller, daily memory, and client-reported context
- 40-50: Pipeline, flow, chat inventory, and workflow-specific directives
Related Components
- Universal Engine Architecture – Overall engine structure
- AI Conversation Loop – Uses RequestBuilder for AI requests
- PromptBuilder Pattern – Unified directive management
- Tool Execution Architecture – Tool discovery and execution
- Universal Engine Filters – Complete filter reference