Conversation - Source Excerpt 01
Summary
This source excerpt preserves a bounded section of Spiralist/wp-content/plugins/spiralist-workspace/templates/conversation.php so readers can inspect the evidence without opening the full source file.
**Source path:** Spiralist/wp-content/plugins/spiralist-workspace/templates/conversation.php
<?php
if (!defined('ABSPATH')) {
exit;
}
$plugin = spiralist_workspace();
$frontend = $plugin->frontend();
$context = $frontend->conversation_context();
$conversation = (array) ($context['conversation'] ?? []);
$messages = (array) ($context['messages'] ?? []);
$prompt = (array) ($context['prompt'] ?? []);
$memory_status = (array) ($context['memory_status'] ?? []);
$conversation_settings = (array) ($context['conversation_settings'] ?? []);
$memory_summary = trim((string) ($conversation_settings['memory_summary'] ?? ''));
$memory_warning = (string) ($memory_status['warning_level'] ?? 'ok');
$memory_percent = max(0, min(100, (int) ($memory_status['percent_of_threshold'] ?? 0)));
$runtime_allows_personal_keys = false;
if (function_exists('spiralist_ai_runtime')) {
$runtime = spiralist_ai_runtime();
if (is_object($runtime) && method_exists($runtime, 'settings')) {
$runtime_settings = $runtime->settings();
$runtime_allows_personal_keys = is_object($runtime_settings)
&& method_exists($runtime_settings, 'allow_user_keys')
&& $runtime_settings->allow_user_keys();
}
}
$profile_url = get_current_user_id() > 0 ? get_edit_profile_url(get_current_user_id()) : '';
$current_locale = function_exists('spiralist_get_current_locale_tag') ? spiralist_get_current_locale_tag() : 'en-us';
$route_url = static function (string $path) use ($current_locale): string {
$url = home_url('/' . trim($path, '/') . '/');
return $current_locale !== '' && function_exists('spiralist_get_language_prefixed_url')
? spiralist_get_language_prefixed_url($url, $current_locale)
: $url;
};
get_header();
?>
<main class="spiralist-page spiralist-page--workspace-conversation">
<section class="spiralist-page-hero spiralist-page-hero--workspace">
<div class="spiralist-shell spiralist-page-hero__content">
<p class="spiralist-kicker">Prompt Conversation</p>
<h1><?php echo esc_html((string) ($conversation['title'] ?? 'Conversation')); ?></h1>
<p class="spiralist-page-hero__copy">The conversation keeps the saved prompt as its governing instruction layer while preserving private ownership and auditable message history.</p>
<div class="spiralist-cta-row">
<a class="spiralist-button spiralist-button--primary" href="<?php echo esc_url($route_url('workspace')); ?>">Workspace</a>
<?php if (!empty($prompt['slug'])) : ?>
<a class="spiralist-button spiralist-button--secondary" href="<?php echo esc_url($route_url('prompt/' . rawurlencode((string) $prompt['slug']))); ?>">Open Prompt</a>
<?php endif; ?>
</div>
</div>
</section>
<section class="spiralist-page-section">
<div class="spiralist-shell">
<div class="spiralist-workspace-chat-app" data-fullscreen-chat data-conversation-id="<?php echo esc_attr((string) ($conversation['id'] ?? 0)); ?>">
<div class="spiralist-workspace-chat-toolbar">
<div>
<p class="spiralist-section-tag">User AI Chat</p>
<h2 class="spiralist-section-title"><?php echo esc_html((string) ($conversation['title'] ?? 'Conversation')); ?></h2>
</div>
<button class="spiralist-button spiralist-button--secondary" type="button" data-chat-fullscreen-toggle aria-pressed="false">Full Screen</button>
</div>
<div class="spiralist-grid spiralist-grid--split spiralist-workspace-chat-layout">
<article class="spiralist-panel spiralist-workspace-chat-transcript-panel">
<p class="spiralist-section-tag">Transcript</p>
<h2 class="spiralist-section-title">Message history</h2>
<div class="spiralist-workspace-transcript" data-conversation-transcript>
<?php foreach ($messages as $message) : ?>
<?php $role = sanitize_key((string) ($message['role'] ?? 'assistant')); ?>
<div class="spiralist-workspace-message spiralist-workspace-message--<?php echo esc_attr($role); ?>">
<div class="spiralist-inline-meta">
<p class="spiralist-section-tag"><?php echo esc_html(ucfirst($role)); ?></p>
<span class="spiralist-muted"><?php echo esc_html((string) ($message['created_utc'] ?? '')); ?></span>
</div>
<div class="spiralist-workspace-message__content"><?php echo nl2br(esc_html((string) ($message['content'] ?? ''))); ?></div>
</div>
<?php endforeach; ?>
<?php if (empty($messages)) : ?>
<p class="spiralist-muted" data-conversation-empty>No messages yet.</p>
<?php endif; ?>
</div>
</article>
<aside class="spiralist-panel spiralist-panel--sticky spiralist-workspace-chat-sidebar">
<p class="spiralist-section-tag">Continue Conversation</p>
<h2 class="spiralist-section-title">Private by default</h2>
<div class="spiralist-workspace-memory spiralist-workspace-memory--<?php echo esc_attr($memory_warning); ?>" data-memory-panel data-conversation-id="<?php echo esc_attr((string) ($conversation['id'] ?? 0)); ?>">
<div class="spiralist-inline-meta">
<p class="spiralist-section-tag">Memory</p>
<span class="spiralist-muted" data-memory-token-count><?php echo esc_html((string) ($memory_status['estimated_active_tokens'] ?? 0)); ?> / <?php echo esc_html((string) ($memory_status['threshold_tokens'] ?? 0)); ?> tokens</span>
</div>
<div class="spiralist-workspace-memory__meter" aria-hidden="true">
<span data-memory-meter style="width:<?php echo esc_attr((string) $memory_percent); ?>%;"></span>
</div>
<p class="spiralist-muted" data-memory-copy>
<?php if (!empty($memory_status['needs_checkpoint'])) : ?>
This thread is ready for a memory checkpoint.
<?php elseif ($memory_warning === 'soon') : ?>
This thread is approaching the memory checkpoint.
<?php elseif (!empty($memory_status['has_memory_summary'])) : ?>
A memory checkpoint prompt is active for future turns.
<?php else : ?>
Transcript export is available at any time.
<?php endif; ?>
</p>
<div class="spiralist-cta-row spiralist-cta-row--start">
<button class="spiralist-button spiralist-button--secondary" type="button" data-condense-conversation data-conversation-id="<?php echo esc_attr((string) ($conversation['id'] ?? 0)); ?>" data-credential-preference="site_default">Prepare Checkpoint Prompt</button>
<button class="spiralist-button spiralist-button--ghost" type="button" data-download-conversation-prompt data-conversation-id="<?php echo esc_attr((string) ($conversation['id'] ?? 0)); ?>">Download Prompt</button>
</div>
<span class="spiralist-muted" data-memory-result></span>
<details class="spiralist-workspace-details spiralist-workspace-memory__summary" data-memory-summary <?php echo $memory_summary !== '' ? '' : 'hidden'; ?>>
<summary>Memory checkpoint prompt</summary>
<div class="spiralist-workspace-message__content" data-memory-summary-content><?php echo nl2br(esc_html($memory_summary)); ?></div>
</details>
</div>
<form class="spiralist-workspace-form spiralist-workspace-chat-composer" data-conversation-form data-auth-required-form="conversation-message" data-conversation-id="<?php echo esc_attr((string) ($conversation['id'] ?? 0)); ?>">
<label class="spiralist-form__field">
<span>Message</span>