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: Never call ai-http-client directly. Always use RequestBuilder::build() to ensure consistent request structure and directive application.
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 ai-http-client │
│ • chubes_ai_request filter │
│ • 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 targeting
Directive 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
'agent_types' => ['all'] // 'all', 'pipeline', 'chat', or array
];
return $directives;
});
Priority Order (lower = applied first):
- 10: Core agent identity and foundational instructions
- 20: Global system prompts (user-configured)
- 30: Pipeline-specific system prompts
- 40: Context and workflow-specific directives
- 50: Site context and environmental directives
Current Directive Implementations
Global Directives (apply to all agents):
GlobalSystemPromptDirective– User-configured global AI behavior (priority 20)SiteContextDirective– WordPress site context injection (priority 50)
Pipeline Directives:
PipelineCoreDirective– Foundational pipeline agent identity (priority 10)PipelineSystemPromptDirective– User-defined pipeline prompts (priority 30)PipelineContextDirective– Pipeline context files (priority 40)
Chat Directives:
ChatAgentDirective– Chat agent identity and capabilities (priority 10)
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 ai-http-client
The RequestBuilder sends the finalized request to the ai-http-client library via the chubes_ai_request filter:
return apply_filters(
'chubes_ai_request',
$request,
$provider,
null, // streaming_callback
$structured_tools,
$context['step_id'] ?? $context['session_id'] ?? null,
[
'agent_type' => $agent_type,
'context' => $context
]
);
Parameters:
$request– Complete request array (model, messages, tools)$provider– AI provider name (openai, anthropic, google, grok, openrouter)null– Streaming callback (not used in current implementation)$structured_tools– Restructured tools array$context['step_id'] ?? $context['session_id']– Identifier for logging['agent_type' => ..., 'context' => ...]– Additional metadata
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 and the ai-http-client:
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 configuration (model not set, provider not configured) are handled by ai-http-client:
[
'success' => false,
'error' => 'Invalid provider configuration'
]
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: 3
Best 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 = apply_filters('chubes_ai_request', $request, $provider, null, $tools);
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 agents)
add_filter('datamachine_directives', function($directives) {
$directives[] = [
'class' => MyGlobalDirective::class,
'priority' => 25, // Between global prompt (20) and pipeline prompts (30)
'agent_types' => ['all']
];
return $directives;
});
// Register a pipeline-specific directive
add_filter('datamachine_directives', function($directives) {
$directives[] = [
'class' => MyPipelineDirective::class,
'priority' => 35, // After pipeline system prompts
'agent_types' => ['pipeline']
];
return $directives;
});
Priority Guidelines:
- 10-19: Core agent identity and foundational instructions
- 20-29: Global system prompts and universal behavior
- 30-39: Agent-specific system prompts and context
- 40-49: Workflow and execution context directives
- 50+: Environmental and site-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