Add conversation and message model selection
This commit is contained in:
@@ -55,8 +55,15 @@ class Odidere {
|
||||
);
|
||||
},
|
||||
onComposeSubmit: () => this.submit(),
|
||||
onModelChange: ({ provider, model }) => {
|
||||
this.storage.setModelSelection({ provider, model });
|
||||
onDefaultModelChange: ({ provider, model }) =>
|
||||
this.storage.setModelSelection({ provider, model }),
|
||||
onComposeModelChange: ({ provider, model }) => {
|
||||
if (this.conversationId) {
|
||||
this.storage.setConversationModel(this.conversationId, {
|
||||
provider,
|
||||
model,
|
||||
});
|
||||
}
|
||||
this.ui.updateContext(
|
||||
this.totalTokens,
|
||||
this.ui.getSelectedModel().contextSize,
|
||||
@@ -583,7 +590,15 @@ class Odidere {
|
||||
try {
|
||||
const body = { stream: true };
|
||||
if (message) body.message = message;
|
||||
// Read the selected model once. Save it for this conversation,
|
||||
// which always has an ID here, and send it with the request.
|
||||
const { provider, model } = this.ui.getSelectedModel();
|
||||
if (provider && model) {
|
||||
this.storage.setConversationModel(this.conversationId, {
|
||||
provider,
|
||||
model,
|
||||
});
|
||||
}
|
||||
if (provider) body.provider = provider;
|
||||
if (model) body.model = model;
|
||||
const maxIterations = this.storage.getMaxIterations();
|
||||
@@ -707,6 +722,7 @@ class Odidere {
|
||||
if (id) {
|
||||
try {
|
||||
await this.api.deleteConversation(id);
|
||||
this.storage.deleteConversationModel(id);
|
||||
} catch (error) {
|
||||
// The conversation survives on the server, but the local
|
||||
// selection is still cleared.
|
||||
@@ -732,6 +748,7 @@ class Odidere {
|
||||
this.ui.clearChat();
|
||||
this.ui.setPendingApprovals([]);
|
||||
this.ui.renderSystemDefault(this.storage.getSystemMessage());
|
||||
this.ui.selectComposeModel(this.resolveConversationModel(null));
|
||||
this.ui.updateContext(0, null);
|
||||
this.updateSendEnabled();
|
||||
}
|
||||
@@ -778,6 +795,9 @@ class Odidere {
|
||||
this.ui.closeConversations();
|
||||
return;
|
||||
}
|
||||
// Remove model entries for conversations deleted in other tabs
|
||||
// or on other devices.
|
||||
this.storage.pruneConversationModels(this.conversations.map((c) => c.id));
|
||||
this.ui.renderConversationList(this.conversations, {
|
||||
currentId: this.conversationId,
|
||||
});
|
||||
@@ -850,6 +870,7 @@ class Odidere {
|
||||
this.ui.setPendingApprovals([]);
|
||||
this.ui.updateContext(0, null);
|
||||
this.conversationId = id;
|
||||
this.ui.selectComposeModel(this.resolveConversationModel(id));
|
||||
await this.resync();
|
||||
this.updateSendEnabled();
|
||||
}
|
||||
@@ -890,6 +911,7 @@ class Odidere {
|
||||
this.ui.renderError(`Failed to delete conversation: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
this.storage.deleteConversationModel(id);
|
||||
this.conversations = this.conversations.filter((c) => c.id !== id);
|
||||
if (id === this.conversationId) {
|
||||
// The server-side delete cancels an ongoing inference.
|
||||
@@ -1009,6 +1031,9 @@ class Odidere {
|
||||
* request. Used when the server reports the conversation gone.
|
||||
*/
|
||||
async clearSelection() {
|
||||
if (this.conversationId) {
|
||||
this.storage.deleteConversationModel(this.conversationId);
|
||||
}
|
||||
this.messages.clear();
|
||||
this.drafts.clear();
|
||||
this.storage.clearConversation();
|
||||
@@ -1018,6 +1043,7 @@ class Odidere {
|
||||
this.ui.clearChat();
|
||||
this.ui.setPendingApprovals([]);
|
||||
this.ui.renderSystemDefault(this.storage.getSystemMessage());
|
||||
this.ui.selectComposeModel(this.resolveConversationModel(null));
|
||||
this.ui.updateContext(0, null);
|
||||
this.updateSendEnabled();
|
||||
}
|
||||
@@ -1567,10 +1593,29 @@ class Odidere {
|
||||
// MODELS AND VOICES
|
||||
// ====================
|
||||
|
||||
/**
|
||||
* resolveConversationModel returns the provider and model stored
|
||||
* for the given conversation ID, falling back to the default
|
||||
* model selection when none is stored.
|
||||
* @param {string | null} [id]
|
||||
* @returns {{provider: string | null, model: string | null}}
|
||||
*/
|
||||
resolveConversationModel(id = this.conversationId) {
|
||||
if (id) {
|
||||
const stored = this.storage.getConversationModel(id);
|
||||
if (stored.provider && stored.model) return stored;
|
||||
}
|
||||
return this.storage.getModelSelection();
|
||||
}
|
||||
|
||||
async loadModels() {
|
||||
try {
|
||||
const data = await this.api.getModels();
|
||||
this.ui.populateModels(data, this.storage.getModelSelection());
|
||||
this.ui.populateModels(
|
||||
data,
|
||||
this.storage.getModelSelection(),
|
||||
this.resolveConversationModel(),
|
||||
);
|
||||
this.ui.updateContext(
|
||||
this.totalTokens,
|
||||
this.ui.getSelectedModel().contextSize,
|
||||
|
||||
Reference in New Issue
Block a user