diff --git a/internal/service/static/icons.svg b/internal/service/static/icons.svg
index f1bdf43..c06351b 100644
--- a/internal/service/static/icons.svg
+++ b/internal/service/static/icons.svg
@@ -140,4 +140,10 @@
+
+
+
+
+
+
diff --git a/internal/service/static/main.css b/internal/service/static/main.css
index dce9059..8d155f8 100644
--- a/internal/service/static/main.css
+++ b/internal/service/static/main.css
@@ -1229,3 +1229,15 @@ body {
white-space: pre-wrap;
word-break: break-word;
}
+
+.message--system .message__icon {
+ color: var(--color-text-muted);
+}
+
+.message--system .message__icon--system {
+ color: var(--color-text-muted);
+}
+
+.message__placeholder {
+ color: var(--color-text-muted);
+}
diff --git a/internal/service/static/main.js b/internal/service/static/main.js
index 7325f25..440f176 100644
--- a/internal/service/static/main.js
+++ b/internal/service/static/main.js
@@ -83,6 +83,7 @@ class Odidere {
this._currentRun = null;
this.currentController = null;
this.totalTokens = 0;
+ this.systemMessage = '';
// Attachments & location
this.attachments = [];
@@ -122,6 +123,8 @@ class Odidere {
init() {
this.conversation.load();
+ this.systemMessage = localStorage.getItem(SYSTEM_MESSAGE_KEY) || '';
+ this.renderer.renderSystemMessage(this.systemMessage);
if (this.conversation.size > 0) {
this.renderer.renderMessages(this.conversation.getActivePath());
}
@@ -172,6 +175,8 @@ class Odidere {
this.conversation.clear();
this.renderer.setAutoScroll(true);
this.renderer.clearChat();
+ this.systemMessage = localStorage.getItem(SYSTEM_MESSAGE_KEY) || '';
+ this.renderer.renderSystemMessage(this.systemMessage);
this.clearAttachments();
this.clearLocation();
this.$textInput.value = '';
@@ -628,9 +633,8 @@ class Odidere {
const { provider, model } = this.settings.getModel();
const payload = { messages, provider, model };
- const systemMessage = localStorage.getItem(SYSTEM_MESSAGE_KEY);
- if (systemMessage) {
- payload.system_message = systemMessage;
+ if (this.systemMessage) {
+ payload.system_message = this.systemMessage;
}
const maxTurns = this._getMaxTurns();
if (maxTurns > 0) {
@@ -1342,10 +1346,67 @@ class Odidere {
// ====================
async _openEdit(messageId, field, toolCallId) {
+ if (messageId === 'system') {
+ const saved = await this._openSystemEdit();
+ if (saved) {
+ this.renderer.reRenderSystemMessage(this.systemMessage);
+ }
+ return;
+ }
const saved = await this.editModal.open(messageId, field, toolCallId);
if (saved) this.renderer.reRenderActivePath();
}
+ async _openSystemEdit() {
+ return new Promise((resolve) => {
+ const $tpl = this.document.getElementById('tpl-edit-modal');
+ if (!$tpl) return resolve(false);
+
+ const $modal = $tpl.content.cloneNode(true).firstElementChild;
+ const $overlay = this.document.createElement('div');
+ $overlay.className = 'modal-overlay';
+ $overlay.appendChild($modal);
+
+ $modal.querySelector('h2').textContent = 'Edit System Message';
+
+ const textarea = $modal.querySelector('#edit-textarea');
+ textarea.value = this.systemMessage || '';
+
+ const saveBtn = $modal.querySelector('#edit-save');
+ const closeBtn = $modal.querySelector('.modal__close');
+
+ const close = () => {
+ $overlay.remove();
+ this.document.removeEventListener('keydown', handleEscape);
+ resolve(false);
+ };
+
+ const save = () => {
+ const newText = textarea.value.trim();
+ const settingsDefault = localStorage.getItem(SYSTEM_MESSAGE_KEY) || '';
+ this.systemMessage = newText || settingsDefault;
+ $overlay.remove();
+ this.document.removeEventListener('keydown', handleEscape);
+ resolve(true);
+ };
+
+ closeBtn.addEventListener('click', close);
+ saveBtn.addEventListener('click', save);
+
+ $overlay.addEventListener('click', (e) => {
+ if (e.target === $overlay) close();
+ });
+
+ const handleEscape = (e) => {
+ if (e.key === 'Escape') close();
+ };
+ this.document.addEventListener('keydown', handleEscape);
+
+ this.document.body.appendChild($overlay);
+ textarea.focus();
+ });
+ }
+
// ====================
// STOP CONVERSATION
// ====================
diff --git a/internal/service/static/render.js b/internal/service/static/render.js
index ebfc6e4..0508834 100644
--- a/internal/service/static/render.js
+++ b/internal/service/static/render.js
@@ -41,6 +41,7 @@ export class Renderer {
'tpl-reasoning-message',
);
this.$tplToolMessage = document.getElementById('tpl-tool-message');
+ this.$tplSystemMessage = document.getElementById('tpl-system-message');
}
// --- Full / incremental render ---
@@ -611,6 +612,57 @@ export class Renderer {
this.scrollToBottom();
}
+ /**
+ * renderSystemMessage renders the system message block.
+ * @param {string} content
+ */
+ renderSystemMessage(content) {
+ this._renderSystemMessage(content);
+ }
+
+ /**
+ * reRenderSystemMessage replaces the system message block in the DOM.
+ * @param {string} content
+ */
+ reRenderSystemMessage(content) {
+ const $old = this.$chat.querySelector('[data-id="system"]');
+ if (!$old) return;
+
+ const $msg =
+ this.$tplSystemMessage.content.cloneNode(true).firstElementChild;
+ $msg.dataset.id = 'system';
+
+ const $content = $msg.querySelector('.message__content');
+ if (content?.trim()) {
+ $content.textContent = content;
+ $msg.dataset.copyText = content;
+ } else {
+ $content.innerHTML =
+ 'System Default';
+ $msg.dataset.copyText = '';
+ }
+
+ $old.replaceWith($msg);
+ }
+
+ _renderSystemMessage(content, _meta = null) {
+ const $msg =
+ this.$tplSystemMessage.content.cloneNode(true).firstElementChild;
+ $msg.dataset.id = 'system';
+
+ const $content = $msg.querySelector('.message__content');
+ if (content?.trim()) {
+ $content.textContent = content;
+ $msg.dataset.copyText = content;
+ } else {
+ $content.innerHTML =
+ 'System Default';
+ $msg.dataset.copyText = '';
+ }
+
+ this.$chat.insertBefore($msg, this.$chatLoading);
+ }
+
_populateDebugPanel($dl, meta) {
if (meta?.voice) this._appendDebugRow($dl, 'Voice', meta.voice);
if (meta?.usage) {
diff --git a/internal/service/templates/static/templates.gohtml b/internal/service/templates/static/templates.gohtml
index 68ea0e5..f6bb369 100644
--- a/internal/service/templates/static/templates.gohtml
+++ b/internal/service/templates/static/templates.gohtml
@@ -275,4 +275,39 @@
+
+
+
+
{{ end }}