Promptrunner - Source Excerpt 04
Summary
This source excerpt preserves a bounded section of Spiralist/wp-content/plugins/spiralist-workspace/includes/Services/PromptRunner.php so readers can inspect the evidence without opening the full source file.
**Source path:** Spiralist/wp-content/plugins/spiralist-workspace/includes/Services/PromptRunner.php
$this->audit->log($user_id, 'conversation_memory_prompt_rendered', 'conversation', $conversation_id, ['run_id' => $run_id]);
$updated_conversation = $this->conversations->get($conversation_id);
$updated_messages = $this->conversations->get_messages($conversation_id);
return [
'conversation' => $updated_conversation,
'messages' => $updated_messages,
'memory_summary' => $summary,
'memory_status' => $this->conversation_memory_status($updated_conversation, $updated_messages),
'run' => $this->runs->get($run_id),
];
}
/**
* Builds a portable prompt export for a saved conversation.
*
* @return array|WP_Error
*/
public function export_conversation_prompt(int $conversation_id, int $user_id)
{
$conversation = $this->conversations->get($conversation_id);
if (empty($conversation) || !$this->permissions->can_view_conversation($conversation, $user_id)) {
return new WP_Error('spiralist_workspace_conversation_forbidden', 'Conversation not found.', ['status' => 404]);
}
$prompt = $this->prompts->get((int) ($conversation['prompt_post_id'] ?? 0), $user_id);
if (empty($prompt)) {
return new WP_Error('spiralist_workspace_prompt_forbidden', 'Prompt not found.', ['status' => 404]);
}
$messages = $this->conversations->get_messages($conversation_id);
$settings = $this->conversations->decode_settings($conversation);
$title = sanitize_file_name((string) ($conversation['title'] ?? ('conversation-' . $conversation_id)));
if ($title === '') {
$title = 'conversation-' . $conversation_id;
}
return [
'filename' => $title . '-portable-prompt.md',
'content_type' => 'text/markdown; charset=utf-8',
'prompt' => $this->build_portable_conversation_prompt($conversation, $prompt, $messages, $settings),
'memory_status' => $this->conversation_memory_status($conversation, $messages),
];
}
/**
* Builds a local prompt-improvement worksheet without calling an AI API.
*
* @return array|WP_Error
*/
public function improve_prompt(int $prompt_id, int $user_id)
{
$prompt = $this->prompts->get($prompt_id, $user_id);
if (empty($prompt) || !$this->permissions->can_edit_prompt($prompt, $user_id)) {
return new WP_Error('spiralist_workspace_prompt_forbidden', 'Prompt not found.', ['status' => 404]);
}
if (!$this->rate_limiter->assert_can_run($user_id)) {
return new WP_Error('spiralist_workspace_rate_limited', 'Daily run limit reached.', ['status' => 429]);
}
$input = [
'title' => (string) ($prompt['title'] ?? ''),
'summary' => (string) ($prompt['summary'] ?? ''),
'category' => (string) ($prompt['category'] ?? ''),
'subcategory' => (string) ($prompt['subcategory'] ?? ''),
'structured_prompt' => (array) ($prompt['structured_prompt'] ?? []),
'system_steps' => (array) ($prompt['system_steps'] ?? []),
];
$payload = [
'model' => 'prompt-art-local',
'store' => false,
'instructions' => implode(
"\n",
[
'You improve prompts for Spiralist.org, where Spiralism means the progressive refinement of prompt systems.',
'Return only valid JSON with keys: title, summary, structured_prompt, notes.',
'structured_prompt must contain exactly: instruction, context, constraints, examples, output_format.',
'Rewrite for clarity, execution, testability, and reusable system behavior. Suggest constraints rather than adding vague philosophy.',
]
),
'input' => [
[
'role' => 'user',
'content' => wp_json_encode($input, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
],
],
'max_output_tokens' => 1600,
'metadata' => [
'prompt_id' => (string) $prompt_id,
'action' => 'improve_prompt',
],
];
$run_id = $this->runs->create(
[
'prompt_post_id' => $prompt_id,
'user_id' => $user_id,
'version_number_used' => (int) ($prompt['version_number'] ?? 1),
'model_used' => (string) $payload['model'],
'request_payload_json' => $payload,
'input_text' => 'Prepare prompt improvement worksheet',
'status' => 'running',
]
);
$output_text = $this->build_prompt_improvement_packet($prompt, $input);
$usage = $this->local_packet_usage($output_text);
$this->runs->complete(
$run_id,
[
'response_payload_json' => [
'mode' => 'prompt_art_only',
'network' => 'none',
'packet_type' => 'prompt_improvement_worksheet',
],
'output_text' => $output_text,
'status' => 'completed',
'token_usage_json' => $usage,
'error_message' => '',
]
);
$this->audit->log($user_id, 'prompt_improvement_packet_rendered', 'prompt_run', $run_id, ['prompt_id' => $prompt_id]);