Skip to content
wiki.fftac.org

Promptrunner - Source Excerpt 04

Back to Promptrunner

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]);