Allow sending current conversation state

This commit is contained in:
dwrz
2026-06-13 00:44:01 +00:00
parent 0c1346bd77
commit 4b629a2bc7

View File

@@ -120,6 +120,7 @@ class Odidere {
this.#clearAttachments();
this.$textInput.value = '';
this.$textInput.style.height = 'auto';
this.#updateSendButtonState();
}
// ====================
@@ -258,6 +259,7 @@ class Odidere {
// Render the active path.
const activePath = this.getActivePath();
this.#renderMessages(activePath);
this.#updateSendButtonState();
} catch (e) {
console.error('failed to load history:', e);
this.messagesMap.clear();
@@ -349,6 +351,7 @@ class Odidere {
}
this.#saveToStorage();
this.#updateSendButtonState();
return messages;
}
@@ -449,6 +452,7 @@ class Odidere {
}
this.#saveToStorage();
this.#updateSendButtonState();
}
/**
@@ -572,6 +576,7 @@ class Odidere {
const maxHeight = parseFloat(computed.maxHeight);
const newHeight = Math.min(textarea.scrollHeight, maxHeight);
textarea.style.height = `${newHeight}px`;
this.#updateSendButtonState();
};
/**
@@ -592,6 +597,7 @@ class Odidere {
this.attachments.push(file);
}
this.#renderAttachments();
this.#updateSendButtonState();
this.$fileInput.value = '';
}
@@ -1025,9 +1031,6 @@ class Odidere {
*/
async #submitText() {
const text = this.$textInput.value.trim();
const hasContent = text || this.attachments.length > 0;
if (!hasContent) return;
if (this.isProcessing) return;
this.#stopCurrentAudio();
@@ -1060,20 +1063,25 @@ class Odidere {
this.currentController = new AbortController();
try {
// Build the user message with text and attachments.
const userMessage = await this.#buildUserMessage(text, this.attachments);
const hasContent = text || this.attachments.length > 0 || audio;
if (!hasContent) {
this.#setLoadingState(false);
return;
}
const hasNewInput = text || this.attachments.length > 0 || audio;
// Build messages array from active path + current user message.
const activePath = this.getActivePath();
const messages = [
...activePath.map(({ parent, children, id, meta, ...msg }) => msg),
userMessage,
];
let messages;
let userMessage;
if (hasNewInput) {
userMessage = await this.#buildUserMessage(text, this.attachments);
messages = [
...activePath.map(({ parent, children, id, meta, ...msg }) => msg),
userMessage,
];
} else {
// Continue conversation: send existing history without a new user message.
messages = activePath.map(
({ parent, children, id, meta, ...msg }) => msg,
);
}
const payload = {
messages,
@@ -1091,9 +1099,9 @@ class Odidere {
// Clear attachments after building payload (before async operations).
this.#clearAttachments();
// For text-only requests (no audio), add to history and render
// immediately. Use the returned messages (with IDs) for rendering.
if (!audio) {
// For text-only requests with new input, add to history and render
// immediately. Skip when continuing conversation (no new user message).
if (!audio && hasNewInput) {
const appended = this.#appendHistory([userMessage]);
this.#renderMessages(appended);
}
@@ -1310,6 +1318,23 @@ class Odidere {
// ====================
// STATE
// ====================
/**
* #updateSendButtonState enables the send button when there is text,
* attachments, or at least one message in the conversation history,
* and disables it otherwise.
*/
#updateSendButtonState() {
const hasText = this.$textInput.value.trim().length > 0;
const hasAttachments = this.attachments.length > 0;
const hasHistory = this.messagesMap.size > 0;
const enabled = hasText || hasAttachments || hasHistory;
this.$send.disabled = !enabled;
this.$send.setAttribute(
'aria-label',
enabled ? 'Send message' : 'Start a conversation to enable send',
);
}
/**
* #setLoadingState updates UI to reflect loading state.
* @param {boolean} loading
@@ -1813,6 +1838,7 @@ class Odidere {
#removeAttachment(index) {
this.attachments.splice(index, 1);
this.#renderAttachments();
this.#updateSendButtonState();
}
/**