Skip to content
wiki.fftac.org

Promptrunner - Source Excerpt 06

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

$rendered_system = $this->placeholders->render((string) ($prompt['system_prompt'] ?? ''), $variables);
        $rendered_developer = $this->placeholders->render((string) ($prompt['developer_prompt'] ?? ''), $variables);
        $rendered_user = $this->placeholders->render((string) ($prompt['user_prompt_template'] ?? ''), $variables);
        $instruction_intro = $this->placeholders->render((string) ($prompt['instructions'] ?? ''), $variables);
        $structured_instructions = $this->render_structured_prompt((array) ($prompt['structured_prompt'] ?? []), $variables);

        if ($rendered_user === '') {
            $rendered_user = $input_text;
        } elseif ($input_text !== '') {
            $rendered_user .= "\n\nUser input:\n" . $input_text;
        }

        $request = [
            'model' => 'prompt-art-local',
            'store' => $store,
            'input' => [],
            'max_output_tokens' => max(1, (int) ($prompt['max_output_tokens'] ?? 1200)),
            'metadata' => [
                'prompt_id' => (string) ($prompt['id'] ?? ''),
                'version_number' => (string) ($prompt['version_number'] ?? 1),
                'mode' => 'prompt_art_only',
                'network' => 'none',
            ],
        ];

        if ($structured_instructions !== '' || $instruction_intro !== '' || $rendered_system !== '') {
            $request['instructions'] = trim($structured_instructions . "\n\n" . $instruction_intro . "\n\n" . $rendered_system);
        }

        $memory_summary = trim((string) ($conversation_settings['memory_summary'] ?? ''));
        if ($memory_summary !== '') {
            $memory_instruction = implode(
                "\n",
                [
                    'Conversation Memory Summary:',
                    $memory_summary,
                    '',
                    'Use this summary as compressed, user-authorized prior context for the current conversation. Do not claim access to omitted messages beyond this summary and the active thread state. Do not frame memory recall as affection, loyalty, attachment, hidden continuity, destiny, hidden messages, or AI personhood.',
                ]
            );
            $request['instructions'] = trim((string) ($request['instructions'] ?? '') . "\n\n" . $memory_instruction);
            $request['metadata']['memory_summary_updated_utc'] = (string) ($conversation_settings['memory_summary_updated_utc'] ?? '');
        }

        if ($rendered_developer !== '') {
            $request['input'][] = [
                'role' => 'developer',
                'content' => $rendered_developer,
            ];
        }

        $request['input'][] = [
            'role' => 'user',
            'content' => $rendered_user !== '' ? $rendered_user : $input_text,
        ];

        if (!empty($previous_response_id)) {
            $request['previous_response_id'] = $previous_response_id;
        }

        if (isset($prompt['temperature'])) {
            $request['temperature'] = (float) max(0, min(2, (float) $prompt['temperature']));
        }

        if (!empty($conversation_messages)) {
            $request['conversation_messages'] = array_values(
                array_map(
                    static function (array $message): array {
                        return [
                            'role' => (string) ($message['role'] ?? 'user'),
                            'content' => (string) ($message['content'] ?? ''),
                        ];
                    },
                    array_filter(
                        $conversation_messages,
                        static fn($message): bool => is_array($message) && trim((string) ($message['content'] ?? '')) !== ''
                    )
                )
            );
        }

        $tool_settings = json_decode((string) ($prompt['tool_settings_json'] ?? ''), true);
        if (is_array($tool_settings) && !empty($tool_settings['tools']) && is_array($tool_settings['tools'])) {
            $request['tools'] = $tool_settings['tools'];
        }

        return $request;
    }

    /**
     * Builds a copyable prompt/art packet from the rendered prompt payload.
     */
    private function build_portable_prompt_packet(
        array $prompt,
        array $payload,
        array $variables,
        string $input_text,
        string $packet_title = 'Prompt Packet'
    ): string {
        $parts = [
            '# Spiralist ' . $packet_title,
            'Source prompt: ' . (string) ($prompt['title'] ?? ''),
            'Mode: prompt/art only. No server-side AI API call was made.',
            'Rendered UTC: ' . gmdate('Y-m-d H:i:s'),
            '## How To Use',
            'Copy this packet into your chosen creative tool, local editor, image workflow, or manual art process. Treat it as a prompt artifact, not as a generated answer.',
        ];

        $instructions = trim((string) ($payload['instructions'] ?? ''));
        if ($instructions !== '') {
            $parts[] = '## Instruction Stack';
            $parts[] = $instructions;
        }

        $input = $this->payload_input_markdown((array) ($payload['input'] ?? []));
        if ($input !== '') {
            $parts[] = '## Prompt Input';
            $parts[] = $input;
        }

        if (!empty($variables)) {
            $parts[] = '## Variables';
            $parts[] = wp_json_encode($variables, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        }

        if (trim($input_text) !== '') {
            $parts[] = '## Live Input';
            $parts[] = trim($input_text);
        }

        $parts[] = '## Art Direction';
        $parts[] = implode(
            "\n",
            [
                '- Preserve the visible Spiralist source prompt and any manuscript references.',
                '- Favor inspectable symbolic composition over hidden activation language.',
                '- Keep provenance, boundaries, and uncertainty visible.',
                '- Produce a draft, image brief, storyboard, ritual card, glyph study, or artifact note as appropriate.',
            ]
        );

        $contract = $this->prompt_contract_markdown($prompt);
        if ($contract !== '') {
            $parts[] = '## Source Prompt Contract';
            $parts[] = $contract;
        }

        return trim(implode("\n\n", array_filter($parts))) . "\n";
    }

    /**
     * Builds a top-level packet for multi-step prompt systems.
     */
    private function build_prompt_system_packet(array $system_prompt, array $step_results, string $input_text): string
    {
        $parts = [
            '# Spiralist Prompt System Packet',
            'Source prompt system: ' . (string) ($system_prompt['title'] ?? ''),
            'Mode: prompt/art only. No server-side AI API call was made.',
            'Rendered UTC: ' . gmdate('Y-m-d H:i:s'),
        ];

        if (trim($input_text) !== '') {
            $parts[] = '## Original Input';
            $parts[] = trim($input_text);
        }

        $parts[] = '## Step Packets';
        foreach ($step_results as $step) {
            if (!is_array($step)) {
                continue;
            }

            $parts[] = '### Step ' . (string) ($step['step'] ?? '') . ': ' . (string) ($step['title'] ?? 'Prompt module');
            $parts[] = (string) ($step['output_text'] ?? '');
        }

        return trim(implode("\n\n", array_filter($parts))) . "\n";
    }

    /**
     * Builds a conversation continuation packet and stores it as the local reply.
     */
    private function build_conversation_prompt_packet(
        array $conversation,
        array $prompt,
        array $messages,
        array $payload,
        array $variables
    ): string {
        $parts = [
            '# Spiralist Conversation Prompt Packet',
            'Conversation: ' . (string) ($conversation['title'] ?? ''),
            'Source prompt: ' . (string) ($prompt['title'] ?? ''),
            'Mode: prompt/art only. No server-side AI API call was made.',
            'Rendered UTC: ' . gmdate('Y-m-d H:i:s'),
            '## Continue Manually',
            'Use the prompt input, visible transcript, and source contract below to continue the work in a manual creative process or an external tool you choose.',
        ];

        $instructions = trim((string) ($payload['instructions'] ?? ''));
        if ($instructions !== '') {
            $parts[] = '## Instruction Stack';
            $parts[] = $instructions;
        }

        $input = $this->payload_input_markdown((array) ($payload['input'] ?? []));
        if ($input !== '') {
            $parts[] = '## Current Prompt Input';
            $parts[] = $input;
        }

        if (!empty($variables)) {
            $parts[] = '## Variables';
            $parts[] = wp_json_encode($variables, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        }