Skip to content
wiki.fftac.org

Promptrunner - Source Excerpt 02

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 ?: null, 'prompt_system_packet_rendered', 'prompt_run', $run_id, ['prompt_id' => (int) ($system_prompt['id'] ?? 0)]);

        return $this->runs->get($run_id);
    }

    /**
     * Starts a prompt-governed conversation.
     *
     * @return array|WP_Error
     */
    public function start_conversation(int $prompt_id, int $user_id, array $variables = [], string $opening_message = '')
    {
        $prompt = $this->prompts->get($prompt_id, $user_id);
        if (empty($prompt) || !$this->permissions->can_run_prompt($prompt, $user_id)) {
            return new WP_Error('spiralist_workspace_prompt_forbidden', 'Prompt not found.', ['status' => 404]);
        }

        $conversation_id = $this->conversations->create(
            [
                'prompt_post_id' => $prompt_id,
                'owner_user_id' => $user_id,
                'title' => $prompt['title'] . ' Conversation',
                'visibility' => 'private',
                'conversation_settings_json' => ['variables' => $variables],
            ]
        );

        if ($opening_message !== '') {
            $reply = $this->post_message($conversation_id, $user_id, $opening_message, $variables);
            if (is_wp_error($reply)) {
                return $reply;
            }
        }

        $conversation = $this->conversations->get($conversation_id);
        $messages = $this->conversations->get_messages($conversation_id);

        return [
            'conversation' => $conversation,
            'messages' => $messages,
            'memory_status' => $this->conversation_memory_status($conversation, $messages),
        ];
    }

    /**
     * Continues a saved prompt conversation.
     *
     * @return array|WP_Error
     */
    public function post_message(int $conversation_id, int $user_id, string $message, array $variables = [])
    {
        $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]);
        }

        $conversation_settings = $this->conversations->decode_settings($conversation);
        if (empty($variables) && !empty($conversation_settings['variables']) && is_array($conversation_settings['variables'])) {
            $variables = (array) $conversation_settings['variables'];
        }

        if (!$this->rate_limiter->assert_can_message($user_id)) {
            return new WP_Error('spiralist_workspace_rate_limited', 'Daily message limit reached.', ['status' => 429]);
        }

        $prompt = $this->prompts->get((int) $conversation['prompt_post_id'], $user_id);
        if (empty($prompt)) {
            return new WP_Error('spiralist_workspace_prompt_forbidden', 'Prompt not found.', ['status' => 404]);
        }

        $this->conversations->add_message($conversation_id, 'user', $message);

        $conversation_messages = $this->conversations->get_messages($conversation_id);

        $payload = $this->build_request_payload(
            $prompt,
            $variables,
            $message,
            (string) ($conversation['openai_reference'] ?? ''),
            true,
            $conversation_messages,
            $conversation_settings
        );

        $run_id = $this->runs->create(
            [
                'prompt_post_id' => (int) $conversation['prompt_post_id'],
                'user_id' => $user_id,
                'conversation_id' => $conversation_id,
                'version_number_used' => (int) $prompt['version_number'],
                'model_used' => (string) $payload['model'],
                'request_payload_json' => $payload,
                'input_text' => $message,
                'status' => 'running',
            ]
        );

        $assistant_text = $this->build_conversation_prompt_packet($conversation, $prompt, $conversation_messages, $payload, $variables);
        $usage = $this->local_packet_usage($assistant_text);

        $this->conversations->add_message(
            $conversation_id,
            'assistant',
            $assistant_text,
            null,
            [
                'mode' => 'prompt_art_only',
                'usage' => $usage,
            ]
        );
        $this->conversations->update_openai_reference($conversation_id, null);

        $this->runs->complete(
            $run_id,
            [
                'response_payload_json' => [
                    'mode' => 'prompt_art_only',
                    'network' => 'none',
                    'packet_type' => 'conversation_prompt',
                ],
                'output_text' => $assistant_text,
                'status' => 'completed',
                'token_usage_json' => $usage,
                'error_message' => '',
            ]
        );