feat: allow model selection in all single-agent sessions

Generalize the scratchpad-only model/reasoning-effort selector to work
in any session whose pattern has exactly one agent. This enables model
switching above the chat input for project 1-on-1 chats, not just
scratchpads.

- Rename ScratchpadSessionConfig -> SessionModelConfig across domain,
  contracts, IPC, preload, and renderer
- Replace isScratchpadProject guard with agents.length === 1 check in
  EryxAppService.updateSessionModelConfig and ChatPane pills gate
- Apply session model config in buildEffectivePattern whenever present,
  regardless of project type
- Seed sessionModelConfig on session creation for any single-agent
  pattern

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
David Kaya
2026-03-25 22:41:46 +01:00
co-authored by Copilot
parent 46b5de472e
commit 968ae37279
10 changed files with 76 additions and 74 deletions
+11 -11
View File
@@ -16,7 +16,7 @@ export type ChatRole = 'system' | 'user' | 'assistant';
export type SessionStatus = 'idle' | 'running' | 'error';
export type SessionTitleSource = 'auto' | 'manual';
export interface ScratchpadSessionConfig {
export interface SessionModelConfig {
model: string;
reasoningEffort?: ReasoningEffort;
}
@@ -43,7 +43,7 @@ export interface SessionRecord {
isArchived?: boolean;
messages: ChatMessageRecord[];
lastError?: string;
scratchpadConfig?: ScratchpadSessionConfig;
sessionModelConfig?: SessionModelConfig;
tooling?: SessionToolingSelection;
approvalSettings?: SessionApprovalSettings;
pendingApproval?: PendingApprovalRecord;
@@ -63,9 +63,9 @@ export function resolveSessionTitle(
return buildSessionTitle(pattern, messages);
}
export function createScratchpadSessionConfig(
export function createSessionModelConfig(
pattern: PatternDefinition,
): ScratchpadSessionConfig | undefined {
): SessionModelConfig | undefined {
const primaryAgent = pattern.agents[0];
if (!primaryAgent) {
return undefined;
@@ -89,27 +89,27 @@ export function resolveSessionApprovalSettings(
return normalizeSessionApprovalSettings(session.approvalSettings);
}
export function resolveScratchpadSessionConfig(
export function resolveSessionModelConfig(
session: SessionRecord,
pattern: PatternDefinition,
): ScratchpadSessionConfig | undefined {
const defaults = createScratchpadSessionConfig(pattern);
): SessionModelConfig | undefined {
const defaults = createSessionModelConfig(pattern);
if (!defaults) {
return undefined;
}
const overrideModel = session.scratchpadConfig?.model.trim();
const overrideModel = session.sessionModelConfig?.model.trim();
return {
model: overrideModel || defaults.model,
reasoningEffort: session.scratchpadConfig?.reasoningEffort ?? defaults.reasoningEffort,
reasoningEffort: session.sessionModelConfig?.reasoningEffort ?? defaults.reasoningEffort,
};
}
export function applyScratchpadSessionConfig(
export function applySessionModelConfig(
pattern: PatternDefinition,
session: SessionRecord,
): PatternDefinition {
const config = resolveScratchpadSessionConfig(session, pattern);
const config = resolveSessionModelConfig(session, pattern);
const primaryAgent = pattern.agents[0];
if (!config || !primaryAgent) {
return pattern;
+1 -1
View File
@@ -174,7 +174,7 @@ export function duplicateSessionRecord(
isPinned: false,
isArchived: false,
lastError: undefined,
scratchpadConfig: session.scratchpadConfig ? { ...session.scratchpadConfig } : undefined,
sessionModelConfig: session.sessionModelConfig ? { ...session.sessionModelConfig } : undefined,
tooling: session.tooling
? {
enabledMcpServerIds: [...session.tooling.enabledMcpServerIds],