feat(x): gateway chat titles on gemini-3.5-flash with low thinking

3.5-flash reasons by default and starved the 50-token output cap
(finishReason: length, 44/50 tokens on thinking). Map reasoning effort
to low via the existing per-provider translation, raise the cap, and
keep only the first output line.
This commit is contained in:
Gagan 2026-07-23 16:30:53 +05:30
parent 3c3ae780e7
commit 1f308267c2
2 changed files with 9 additions and 3 deletions

View file

@ -1,6 +1,7 @@
import { generateText } from 'ai';
import { createLanguageModel } from '../models/models.js';
import { getChatTitleModel, resolveProviderConfig } from '../models/defaults.js';
import { mapReasoningEffort } from '../models/reasoning.js';
import { captureLlmUsage } from '../analytics/usage.js';
import { withUseCase } from '../analytics/use_case.js';
@ -37,11 +38,16 @@ export async function generateChatTitle(firstMessage: string): Promise<string |
const providerConfig = await resolveProviderConfig(providerName);
const model = createLanguageModel(providerConfig, modelId);
// Reasoning models (e.g. gateway gemini-3.5-flash) think by default and
// can starve a tight output cap — dial thinking to low and leave the cap
// roomy; the title itself is a handful of tokens either way.
const reasoning = mapReasoningEffort(providerConfig.flavor, modelId, 'low', undefined);
const result = await withUseCase({ useCase: 'copilot_chat', subUseCase: 'chat_title' }, () => generateText({
model,
system: SYSTEM_PROMPT,
prompt: text.slice(0, MAX_INPUT_CHARS),
maxOutputTokens: 50,
maxOutputTokens: 1000,
...(reasoning?.providerOptions ? { providerOptions: reasoning.providerOptions } : {}),
}));
captureLlmUsage({
@ -52,7 +58,7 @@ export async function generateChatTitle(firstMessage: string): Promise<string |
usage: result.usage,
});
const title = result.text
const title = (result.text.trim().split(/\r?\n/)[0] ?? '')
.trim()
.replace(/^["'“”‘’]+|["'“”‘’]+$/g, '')
.replace(/[.!。]+$/, '')

View file

@ -16,7 +16,7 @@ const SIGNED_IN_LIVE_NOTE_AGENT_MODEL = "google/gemini-3.1-flash-lite";
const SIGNED_IN_AUTO_PERMISSION_DECISION_MODEL = "google/gemini-3.1-flash-lite";
// 3.5-flash-lite is not on the gateway allowlist (only 3.1-flash-lite and
// full 3.5-flash are) — the gateway 403s "Model not allowed" otherwise.
const SIGNED_IN_CHAT_TITLE_MODEL = "google/gemini-3.1-flash-lite";
const SIGNED_IN_CHAT_TITLE_MODEL = "google/gemini-3.5-flash";
export type ModelSelection = z.infer<typeof ModelRef>;