feat: Pipeline Settings M1 — per-step model picker, system instructions, agent prompts (#170, v0.23.0)

Additive per-step Pipeline Settings page. Reuses the existing model_select picker + versioned prompt registry; no migration. QA APPROVE for eea4968; CI green.

Agent-Session: pipeline-settings-m1-merge
This commit is contained in:
peptiderepo
2026-06-23 10:37:54 +07:00
committed by GitHub
parent 98eeb12274
commit 37cfb2f244
18 changed files with 1843 additions and 9 deletions

View File

@@ -9,12 +9,19 @@ declare(strict_types=1);
* What: a button showing the current model's name + pricing. Clicking it
* opens a JS-powered popup (model-picker.js) with a searchable list.
* Includes an estimated cost preview below based on historical usage.
* For image-generation steps the static cost-per-image price is shown
* in the trigger button; the per-generation cost-preview panel is
* intentionally omitted (image cost is a fixed $/image, not token-
* based, so the historical-token preview formula does not apply).
* Who calls it: PRAutoBlogger_Admin_Page::render_field() delegates here
* for fields with type 'model_select'.
* for fields with type 'model_select', and
* PRAutoBlogger_Pipeline_Settings_Renderer::render_model_picker()
* for the Pipeline Settings page.
* Dependencies: PRAutoBlogger_Model_Registry_Interface (cached registry lookup),
* PRAutoBlogger_Cost_Tracker (historical token averages).
*
* @see admin/class-admin-page.php — Calls render() from the main field switch.
* @see admin/class-pipeline-settings-renderer.php — Calls render_model_picker().
* @see assets/js/model-picker.js — JS popup that fetches + displays models.
* @see services/interface-model-registry.php — Registry interface for find_model().
* @see core/class-cost-tracker.php — get_avg_tokens_for_stages() for cost preview.
@@ -55,6 +62,9 @@ class PRAutoBlogger_OpenRouter_Model_Field {
}
// Hidden input carries the actual value for the form submission.
// The name attribute equals $id so that PRAutoBlogger_Pipeline_Settings_Save_Handler
// can read $_POST[$option_name] directly — model-picker.js writes the selected
// model id to this input by DOM id, and the browser posts it under this name.
printf(
'<input type="hidden" id="%s" name="%s" value="%s" />',
esc_attr( $id ),
@@ -75,7 +85,9 @@ class PRAutoBlogger_OpenRouter_Model_Field {
esc_html( $display_price )
);
// Cost preview panel — only for text→text models (not image).
// Per-generation cost-preview panel — text→text models only.
// Image steps show a static $/image price in the trigger button above;
// the token-based historical cost formula does not apply to image generation.
if ( 'image_generation' !== $capability && '' !== $value ) {
$cost_preview = self::get_cost_preview( $id, $value );
if ( $cost_preview ) {
@@ -130,7 +142,10 @@ class PRAutoBlogger_OpenRouter_Model_Field {
}
/**
* Map a setting ID to its constituent pipeline stages.
* Map a text→text setting ID to its constituent pipeline stages for the
* cost-preview calculation. Image-generation settings are not listed here
* because the cost preview is intentionally skipped for image steps
* (static $/image price is shown in the picker trigger instead).
*
* @param string $field_id Setting ID.
*
@@ -141,6 +156,9 @@ class PRAutoBlogger_OpenRouter_Model_Field {
'prautoblogger_analysis_model' => array( 'analysis' ),
'prautoblogger_writing_model' => array( 'outline', 'draft', 'polish' ),
'prautoblogger_editor_model' => array( 'review' ),
'prautoblogger_research_model' => array( 'research', 'llm_research' ),
// prautoblogger_image_model is intentionally absent: image cost is a
// fixed $/image (shown in the trigger button), not a token-based preview.
);
return $map[ $field_id ] ?? array();
}