261 lines
7.4 KiB
PHP
261 lines
7.4 KiB
PHP
<?php
|
|
/**
|
|
* Model Registry
|
|
*
|
|
* Centralized source of truth for model defaults, labels,
|
|
* capabilities, and provider support across the plugin.
|
|
*
|
|
* @package WP_Agentic_Writer
|
|
*/
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Class WPAW_Model_Registry
|
|
*
|
|
* Single source of truth for model configuration.
|
|
*
|
|
* Usage:
|
|
* $defaults = WPAW_Model_Registry::get_task_defaults();
|
|
* $registry = WPAW_Model_Registry::get_registry();
|
|
*/
|
|
class WPAW_Model_Registry {
|
|
|
|
/**
|
|
* Task type constants.
|
|
*/
|
|
const TASK_CHAT = 'chat';
|
|
const TASK_CLARITY = 'clarity';
|
|
const TASK_PLANNING = 'planning';
|
|
const TASK_WRITING = 'writing';
|
|
const TASK_EXECUTION = 'execution';
|
|
const TASK_REFINEMENT = 'refinement';
|
|
const TASK_ANALYSIS = 'analysis';
|
|
const TASK_SUMMARIZE = 'summarize';
|
|
const TASK_IMAGE = 'image';
|
|
|
|
/**
|
|
* Get the complete model registry.
|
|
*
|
|
* Structure:
|
|
* 'task_type' => [
|
|
* 'default' => 'model_id',
|
|
* 'fallback' => 'model_id', // optional
|
|
* 'label' => 'Human-readable name',
|
|
* 'description' => 'What this model is used for',
|
|
* 'supported_providers' => ['openrouter', 'local', 'codex'], // optional
|
|
* 'capabilities' => ['chat', 'streaming', 'vision'], // optional
|
|
* ]
|
|
*
|
|
* @since 0.2.0
|
|
* @return array Model registry.
|
|
*/
|
|
public static function get_registry() {
|
|
return array(
|
|
'chat' => array(
|
|
'default' => 'google/gemini-2.5-flash',
|
|
'fallback' => 'google/gemini-2.0-flash-exp',
|
|
'label' => 'Chat Model',
|
|
'description' => 'Discussion, research, and recommendations',
|
|
'capabilities' => array( 'chat', 'streaming', 'reasoning' ),
|
|
),
|
|
'clarity' => array(
|
|
'default' => 'google/gemini-2.5-flash',
|
|
'fallback' => 'google/gemini-2.0-flash-exp',
|
|
'label' => 'Clarity Model',
|
|
'description' => 'Prompt analysis and quiz generation',
|
|
'capabilities' => array( 'chat', 'streaming' ),
|
|
),
|
|
'planning' => array(
|
|
'default' => 'google/gemini-2.5-flash',
|
|
'fallback' => 'google/gemini-2.0-flash-exp',
|
|
'label' => 'Planning Model',
|
|
'description' => 'Article outline and structure generation',
|
|
'capabilities' => array( 'chat', 'streaming' ),
|
|
),
|
|
'writing' => array(
|
|
'default' => 'anthropic/claude-3.5-haiku',
|
|
'fallback' => 'google/gemini-2.5-flash',
|
|
'label' => 'Writing Model',
|
|
'description' => 'Article content generation',
|
|
'capabilities' => array( 'chat', 'streaming', 'long_context' ),
|
|
),
|
|
'execution' => array(
|
|
'default' => 'anthropic/claude-3.5-haiku',
|
|
'fallback' => 'google/gemini-2.5-flash',
|
|
'label' => 'Execution Model',
|
|
'description' => 'Article section writing (alias for writing)',
|
|
'capabilities' => array( 'chat', 'streaming' ),
|
|
),
|
|
'refinement' => array(
|
|
'default' => 'anthropic/claude-3.5-sonnet',
|
|
'fallback' => 'anthropic/claude-3.5-haiku',
|
|
'label' => 'Refinement Model',
|
|
'description' => 'Paragraph edits, rewrites, and improvements',
|
|
'capabilities' => array( 'chat', 'streaming' ),
|
|
),
|
|
'analysis' => array(
|
|
'default' => 'google/gemini-2.5-flash',
|
|
'fallback' => 'anthropic/claude-3.5-haiku',
|
|
'label' => 'Analysis Model',
|
|
'description' => 'Content analysis and improvement suggestions',
|
|
'capabilities' => array( 'chat', 'streaming' ),
|
|
),
|
|
'summarize' => array(
|
|
'default' => 'google/gemini-2.5-flash',
|
|
'fallback' => 'anthropic/claude-3.5-haiku',
|
|
'label' => 'Summarization Model',
|
|
'description' => 'Context summarization and compression',
|
|
'capabilities' => array( 'chat' ),
|
|
),
|
|
'image' => array(
|
|
'default' => 'openai/gpt-4o',
|
|
'fallback' => 'openai/dall-e-3',
|
|
'label' => 'Image Generation Model',
|
|
'description' => 'Image generation for articles',
|
|
'capabilities' => array( 'image_generation' ),
|
|
'supported_providers' => array( 'openrouter' ),
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get default model for a task type.
|
|
*
|
|
* @since 0.2.0
|
|
* @param string $task Task type (chat, planning, execution, etc).
|
|
* @return string Default model ID.
|
|
*/
|
|
public static function get_default_model( $task ) {
|
|
$registry = self::get_registry();
|
|
$task_data = $registry[ $task ] ?? $registry['chat'];
|
|
return $task_data['default'];
|
|
}
|
|
|
|
/**
|
|
* Get fallback model for a task type.
|
|
*
|
|
* @since 0.2.0
|
|
* @param string $task Task type.
|
|
* @return string Fallback model ID.
|
|
*/
|
|
public static function get_fallback_model( $task ) {
|
|
$registry = self::get_registry();
|
|
$task_data = $registry[ $task ] ?? $registry['chat'];
|
|
return $task_data['fallback'] ?? $task_data['default'];
|
|
}
|
|
|
|
/**
|
|
* Get all task defaults as key-value pairs.
|
|
*
|
|
* @since 0.2.0
|
|
* @return array Task => default_model pairs.
|
|
*/
|
|
public static function get_task_defaults() {
|
|
$registry = self::get_registry();
|
|
$defaults = array();
|
|
|
|
foreach ( $registry as $task => $data ) {
|
|
$defaults[ $task ] = $data['default'];
|
|
}
|
|
|
|
return $defaults;
|
|
}
|
|
|
|
/**
|
|
* Get activation defaults (for plugin activation).
|
|
*
|
|
* This returns the format expected by the settings option.
|
|
*
|
|
* @since 0.2.0
|
|
* @return array Settings-compatible defaults.
|
|
*/
|
|
public static function get_activation_defaults() {
|
|
return array(
|
|
'planning_model' => self::get_default_model( 'planning' ),
|
|
'execution_model' => self::get_default_model( 'writing' ),
|
|
'image_model' => self::get_default_model( 'image' ),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Validate a model ID is in the registry.
|
|
*
|
|
* @since 0.2.0
|
|
* @param string $model Model ID.
|
|
* @return bool True if valid.
|
|
*/
|
|
public static function is_valid_model( $model ) {
|
|
foreach ( self::get_registry() as $task_data ) {
|
|
if ( $model === $task_data['default'] || $model === $task_data['fallback'] ) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get display name for a model ID.
|
|
*
|
|
* Extracts a human-readable name from model IDs like
|
|
* "google/gemini-2.5-flash" -> "Google Gemini 2.5 Flash"
|
|
*
|
|
* @since 0.2.0
|
|
* @param string $model_id Model ID.
|
|
* @return string Human-readable display name.
|
|
*/
|
|
public static function get_model_display_name( $model_id ) {
|
|
if ( empty( $model_id ) ) {
|
|
return 'Unknown Model';
|
|
}
|
|
|
|
// Handle known model ID patterns
|
|
$display_names = array(
|
|
'google/gemini-2.5-flash' => 'Google Gemini 2.5 Flash',
|
|
'google/gemini-2.0-flash-exp' => 'Google Gemini 2.0 Flash',
|
|
'google/gemini-2.0-flash-exp:free' => 'Google Gemini 2.0 Flash',
|
|
'anthropic/claude-3.5-sonnet' => 'Anthropic Claude 3.5 Sonnet',
|
|
'anthropic/claude-3.5-haiku' => 'Anthropic Claude 3.5 Haiku',
|
|
'openai/gpt-4o' => 'OpenAI GPT-4o',
|
|
'openai/dall-e-3' => 'OpenAI DALL-E 3',
|
|
'black-forest-labs/flux-schnell' => 'Black Forest Flux Schnell',
|
|
);
|
|
|
|
if ( isset( $display_names[ $model_id ] ) ) {
|
|
return $display_names[ $model_id ];
|
|
}
|
|
|
|
// Generate from model ID: "provider/model-name" -> "Provider Model Name"
|
|
$parts = explode( '/', $model_id );
|
|
if ( count( $parts ) >= 2 ) {
|
|
$provider = ucfirst( str_replace( '-', ' ', $parts[0] ) );
|
|
$name = ucwords( str_replace( '-', ' ', $parts[1] ) );
|
|
return trim( $provider . ' ' . $name );
|
|
}
|
|
|
|
return ucwords( str_replace( '-', ' ', $model_id ) );
|
|
}
|
|
|
|
/**
|
|
* Get JavaScript-compatible registry for frontend.
|
|
*
|
|
* @since 0.2.0
|
|
* @return array JS-safe registry data.
|
|
*/
|
|
public static function get_frontend_data() {
|
|
$registry = self::get_registry();
|
|
$result = array();
|
|
|
|
foreach ( $registry as $task => $data ) {
|
|
$result[ $task ] = array(
|
|
'default' => $data['default'],
|
|
'fallback' => $data['fallback'] ?? null,
|
|
'label' => $data['label'],
|
|
);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
} |