diff --git a/src/telegram/bot-handlers.ts b/src/telegram/bot-handlers.ts index 2d1327bcd5f..67284656588 100644 --- a/src/telegram/bot-handlers.ts +++ b/src/telegram/bot-handlers.ts @@ -20,6 +20,7 @@ import { loadSessionStore, resolveSessionStoreEntry, resolveStorePath, + updateSessionStore, } from "../config/sessions.js"; import type { DmPolicy } from "../config/types.base.js"; import type { @@ -33,6 +34,7 @@ import { MediaFetchError } from "../media/fetch.js"; import { readChannelAllowFromStore } from "../pairing/pairing-store.js"; import { resolveAgentRoute } from "../routing/resolve-route.js"; import { resolveThreadSessionKeys } from "../routing/session-key.js"; +import { applyModelOverrideToSessionEntry } from "../sessions/model-overrides.js"; import { withTelegramApiErrorLogging } from "./api-logging.js"; import { isSenderAllowed, @@ -300,6 +302,7 @@ export const registerTelegramHandlers = ({ }): { agentId: string; sessionEntry: ReturnType[string] | undefined; + sessionKey: string; model?: string; } => { const resolvedThreadId = @@ -339,6 +342,7 @@ export const registerTelegramHandlers = ({ return { agentId: route.agentId, sessionEntry: entry, + sessionKey, model: storedOverride.provider ? `${storedOverride.provider}/${storedOverride.model}` : storedOverride.model, @@ -350,6 +354,7 @@ export const registerTelegramHandlers = ({ return { agentId: route.agentId, sessionEntry: entry, + sessionKey, model: `${provider}/${model}`, }; } @@ -357,6 +362,7 @@ export const registerTelegramHandlers = ({ return { agentId: route.agentId, sessionEntry: entry, + sessionKey, model: typeof modelCfg === "string" ? modelCfg : modelCfg?.primary, }; }; @@ -1374,16 +1380,69 @@ export const registerTelegramHandlers = ({ ); return; } - // Process model selection as a synthetic message with /model command - const syntheticMessage = buildSyntheticTextMessage({ - base: callbackMessage, - from: callback.from, - text: `/model ${selection.provider}/${selection.model}`, - }); - await processMessage(buildSyntheticContext(ctx, syntheticMessage), [], storeAllowFrom, { - forceWasMentioned: true, - messageIdOverride: callback.id, - }); + + const modelSet = byProvider.get(selection.provider); + if (!modelSet?.has(selection.model)) { + await editMessageWithButtons( + `❌ Model "${selection.provider}/${selection.model}" is not allowed.`, + [], + ); + return; + } + + // Directly set model override in session + try { + // Get session store path + const storePath = resolveStorePath(cfg.session?.store, { + agentId: sessionState.agentId, + }); + + const agentConfig = cfg.agents?.list?.find((a) => a.id === sessionState.agentId); + const agentModelConfig = agentConfig?.model ?? cfg.agents?.defaults?.model; + const rawModelRef = + typeof agentModelConfig === "string" ? agentModelConfig : agentModelConfig?.primary; + + let resolvedDefaultRef = sessionState.model; + if (rawModelRef) { + const trimmed = rawModelRef.trim(); + if (trimmed.includes("/")) { + resolvedDefaultRef = trimmed; + } else { + const currentProvider = sessionState.model?.split("/")[0]; + resolvedDefaultRef = currentProvider + ? `${currentProvider}/${trimmed}` + : sessionState.model; + } + } + + const isDefaultSelection = + `${selection.provider}/${selection.model}` === resolvedDefaultRef; + + await updateSessionStore(storePath, (store) => { + const sessionKey = sessionState.sessionKey; + const entry = store[sessionKey] ?? {}; + store[sessionKey] = entry; + applyModelOverrideToSessionEntry({ + entry, + selection: { + provider: selection.provider, + model: selection.model, + isDefault: isDefaultSelection, + }, + }); + }); + + // Update message to show success with visual feedback + const actionText = isDefaultSelection + ? "reset to default" + : `changed to **${selection.provider}/${selection.model}**`; + await editMessageWithButtons( + `✅ Model ${actionText}\n\nThis model will be used for your next message.`, + [], // Empty buttons = remove inline keyboard + ); + } catch (err) { + await editMessageWithButtons(`❌ Failed to change model: ${String(err)}`, []); + } return; }