pressgang-wp / helm
Provider-agnostic AI orchestration layer for the PressGang ecosystem.
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/pressgang-wp/helm
Requires
- php: ^8.3
Requires (Dev)
- phpunit/phpunit: ^11.0
Suggests
- pressgang-wp/pressgang: Required for the src/WP/ adapter layer (HelmServiceProvider, WpHttpTransport).
This package is auto-updated.
Last update: 2026-02-20 22:46:13 UTC
README
Helm is the AI orchestration layer for PressGang.
Provider-agnostic, WordPress-friendly, and built for production workflows: chat, tools, and schema-constrained output without locking your stack to a single model vendor.
Take the helm of your AI features without drifting into provider lock-in.
✅ Requirements
- PHP
^8.3
🚀 Installation
composer require pressgang-wp/helm
🌊 Why Helm
- ⚓ Provider-agnostic core (
OpenAI,Anthropic,Gemini,Fake) - 🧰 Tool execution loop with explicit contracts and max-step guardrails
- 🧱 Structured output with JSON schema validation + repair retries
- 🧪 High test coverage and deterministic DTO contracts
- 🧩 PressGang adapter: zero-setup boot from
config/helm.php - 🛟 Clear failure modes with typed exceptions for safer debugging
📦 Current Status
Implemented:
- Core public API:
Helm,ChatBuilder, DTOs, contracts - Providers:
OpenAiProvider,AnthropicProvider,GeminiProvider,FakeProvider - WordPress transport:
WpHttpTransport - Tool execution loop:
- register tools via
->tools([...])(ToolContractimplementations) - provider tool-call parsing (
ToolCall) - tool result replay into conversation (
ToolResult) ->maxSteps()guard
- register tools via
- Structured output:
->jsonSchema([...])validationStructuredResponsereturn typeSchemaValidationExceptionwith validation errors/raw output/request context->repair(n)retry with validation feedback
- PressGang adapter:
HelmServiceProviderboots Helm fromconfig/helm.phpHookAwareProviderfires lifecycle hooks (pressgang_helm_request,pressgang_helm_response,pressgang_helm_error)- Config-driven tool registration via
toolskey inconfig/helm.php - Dynamic tool collection via
pressgang_helm_toolsfilter - Instance access via
pressgang_helm_instancefilter
Not implemented yet (on roadmap):
- Streaming API
- Embeddings API
- Conversation memory store
- Agent abstraction
Provider failover/retry policy(implemented)
🗺️ What This Means Right Now
You can already build real provider-backed AI workflows in PHP with typed requests/responses, tool calls, and validated JSON outputs.
If you’re building AI features in PressGang, Helm gives you the stable orchestration surface now while the remaining adapter/runtime layers are finished.
In short: you can ship today, then chart the next leg as the roadmap lands.
⚡ Quickstart (Fake Provider)
New here? Start with FakeProvider to learn the API shape before wiring real credentials.
use PressGang\Helm\Helm; use PressGang\Helm\Providers\FakeProvider; $helm = Helm::make(new FakeProvider(), ['model' => 'gpt-4o']); $response = $helm ->chat() ->system('You are concise.') ->user('What is WordPress?') ->send(); echo $response->content;
🤖 Quickstart (OpenAI Provider)
When you’re ready for live responses, swap in a real provider and keep the same builder flow.
use PressGang\Helm\Helm; use PressGang\Helm\Providers\OpenAiProvider; use PressGang\Helm\WP\WpHttpTransport; $config = [ 'provider' => 'openai', 'model' => 'gpt-4o', 'api_key' => 'sk-...', 'timeout' => 30, 'openai' => [ 'base_url' => 'https://api.openai.com/v1', ], ]; $transport = new WpHttpTransport($config); $provider = new OpenAiProvider($transport, $config); $helm = Helm::make($provider, $config); $response = $helm->chat()->user('Say hello in one sentence.')->send(); echo $response->content;
🤖 Quickstart (Gemini Provider)
use PressGang\Helm\Helm; use PressGang\Helm\Providers\GeminiProvider; use PressGang\Helm\WP\WpHttpTransport; $config = [ 'provider' => 'gemini', 'model' => 'gemini-2.5-flash', 'api_key' => 'AIza...', 'timeout' => 30, 'gemini' => [ 'base_url' => 'https://generativelanguage.googleapis.com/v1beta', ], ]; $transport = new WpHttpTransport($config); $provider = new GeminiProvider($transport, $config); $helm = Helm::make($provider, $config); $response = $helm->chat()->user('Say hello in one sentence.')->send(); echo $response->content;
🛠️ Tool Loop Example
Tools are explicit and opt-in: you register them, Helm executes them, and the model gets the results fed back in.
use PressGang\Helm\Contracts\ToolContract; class WeatherTool implements ToolContract { public function name(): string { return 'get_weather'; } public function description(): string { return 'Get weather by city'; } public function inputSchema(): array { return [ 'type' => 'object', 'properties' => ['city' => ['type' => 'string']], 'required' => ['city'], ]; } public function handle(array $input): array { return ['city' => $input['city'] ?? '', 'temp_c' => 21]; } } $response = $helm ->chat() ->user('What is the weather in London?') ->tools([new WeatherTool()]) ->maxSteps(5) ->send();
🧾 Structured Output Example
Need reliable payloads for downstream code? Add a schema and keep your output on a steady heading.
$response = $helm ->chat() ->user('Rate this code from 1-10 and explain why.') ->jsonSchema([ 'type' => 'object', 'properties' => [ 'score' => ['type' => 'integer', 'minimum' => 1, 'maximum' => 10], 'feedback' => ['type' => 'string'], ], 'required' => ['score', 'feedback'], ]) ->repair(1) ->send(); // StructuredResponse echo $response['score']; echo $response['feedback'];
🧩 PressGang Integration
The src/WP/ adapter layer is intended for PressGang themes and expects PressGang runtime classes (for example ServiceProviderInterface and Config).
Helm core (src/ outside src/WP/) remains provider-agnostic and framework-agnostic.
Config
Add config/helm.php to your child theme. PressGang's FileConfigLoader picks it up automatically:
// config/helm.php return [ 'provider' => 'anthropic', 'model' => 'claude-sonnet-4-20250514', 'api_key' => defined('HELM_API_KEY') ? HELM_API_KEY : getenv('HELM_API_KEY'), 'timeout' => 30, 'tools' => [], ];
Service Provider Registration
Register Helm in your PressGang service provider config:
// config/service-providers.php return [ \PressGang\Helm\WP\HelmServiceProvider::class, ];
Usage
Retrieve the Helm instance anywhere in your theme:
$helm = apply_filters('pressgang_helm_instance', null); $response = $helm ->chat() ->user('Summarise this page for accessibility.') ->send(); echo $response->content;
Register Tools
For static theme-level tools, set classes in config/helm.php:
return [ 'provider' => 'anthropic', 'model' => 'claude-sonnet-4-20250514', 'api_key' => defined('HELM_API_KEY') ? HELM_API_KEY : getenv('HELM_API_KEY'), 'tools' => [ \App\Ai\Tools\SearchProducts::class, \App\Ai\Tools\GetOrderStatus::class, ], ];
For dynamic/plugin tools, use the pressgang_helm_tools filter:
add_filter('pressgang_helm_tools', function (array $tools) { $tools[] = new App\Ai\Tools\SearchProducts(); $tools[] = new App\Ai\Tools\GetOrderStatus(); return $tools; });
Retry & Provider Failover
Helm retries transient API failures (timeouts, 429 rate limits, 5xx server errors) with exponential backoff. Set retries in config or per-request:
// config/helm.php return [ 'provider' => 'openai', 'model' => 'gpt-4o', 'api_key' => defined('HELM_API_KEY') ? HELM_API_KEY : getenv('HELM_API_KEY'), 'retries' => 2, // retry transient failures up to 2 times 'fallback_providers' => ['anthropic', 'gemini'], // try Anthropic then Gemini if OpenAI exhausted 'anthropic' => [ 'api_key' => defined('HELM_ANTHROPIC_KEY') ? HELM_ANTHROPIC_KEY : getenv('HELM_ANTHROPIC_KEY'), 'base_url' => 'https://api.anthropic.com/v1', 'max_tokens' => 4096, 'api_version' => '2023-06-01', ], 'gemini' => [ 'api_key' => defined('HELM_GEMINI_KEY') ? HELM_GEMINI_KEY : getenv('HELM_GEMINI_KEY'), 'base_url' => 'https://generativelanguage.googleapis.com/v1beta', ], ];
Override per-request via the builder:
$response = $helm ->chat() ->retries(3) ->fallbackProviders([$backupProvider]) ->user('Hello') ->send();
Client errors (400, 401, 403, 404) are never retried — they skip directly to the next provider. All existing lifecycle hooks fire for each attempt, giving full observability.
Failure semantics:
- Retryable errors:
0(timeout/network),429, and500-599. - Non-retryable errors: client errors such as
400,401,403,404. - Fallback providers are tried in configured order after the primary is exhausted.
- Cross-provider fallback requires provider-specific credentials (for example
helm.anthropic.api_keywhen falling back from OpenAI to Anthropic).
Lifecycle Hooks
HookAwareProvider wraps every provider call with WordPress actions:
| Hook | Type | Payload |
|---|---|---|
pressgang_helm_request |
action | ChatRequest |
pressgang_helm_response |
action | Response, ChatRequest |
pressgang_helm_error |
action | Throwable, ChatRequest |
Use these for logging, metrics, or debugging:
add_action('pressgang_helm_response', function ($response, $request) { error_log("Helm: {$request->model} returned " . strlen($response->content) . " chars"); }, 10, 2);
🧪 Testing
Run test suite:
vendor/bin/phpunit -c phpunit.xml.dist --testdox
🧭 Roadmap
See docs/roadmap/ for milestone docs.
If you’re wondering what to build next, start with provider + schema-backed flows, then add adapter/runtime integrations.
📄 License
MIT