mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-21 03:04:28 +00:00
fix(coding-agent): preserve session thinking for scoped model cycling
closes #1789
This commit is contained in:
parent
4cb1a56b53
commit
e64cd15c25
6 changed files with 22 additions and 17 deletions
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
- Changed scoped model thinking semantics. Scoped entries without an explicit `:<thinking>` suffix now inherit the current session thinking level when selected, instead of applying a startup-captured default.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fixed IME hardware cursor positioning in the custom extension editor (`ctx.ui.editor()` / extension editor dialog) by propagating focus to the internal `Editor`, preventing the terminal cursor from getting stuck at the bottom-right during composition.
|
- Fixed IME hardware cursor positioning in the custom extension editor (`ctx.ui.editor()` / extension editor dialog) by propagating focus to the internal `Editor`, preventing the terminal cursor from getting stuck at the bottom-right during composition.
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ export interface AgentSessionConfig {
|
||||||
settingsManager: SettingsManager;
|
settingsManager: SettingsManager;
|
||||||
cwd: string;
|
cwd: string;
|
||||||
/** Models to cycle through with Ctrl+P (from --models flag) */
|
/** Models to cycle through with Ctrl+P (from --models flag) */
|
||||||
scopedModels?: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;
|
scopedModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>;
|
||||||
/** Resource loader for skills, prompts, themes, context files, system prompt */
|
/** Resource loader for skills, prompts, themes, context files, system prompt */
|
||||||
resourceLoader: ResourceLoader;
|
resourceLoader: ResourceLoader;
|
||||||
/** SDK custom tools registered outside extensions */
|
/** SDK custom tools registered outside extensions */
|
||||||
|
|
@ -215,7 +215,7 @@ export class AgentSession {
|
||||||
readonly sessionManager: SessionManager;
|
readonly sessionManager: SessionManager;
|
||||||
readonly settingsManager: SettingsManager;
|
readonly settingsManager: SettingsManager;
|
||||||
|
|
||||||
private _scopedModels: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;
|
private _scopedModels: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>;
|
||||||
|
|
||||||
// Event subscription state
|
// Event subscription state
|
||||||
private _unsubscribeAgent?: () => void;
|
private _unsubscribeAgent?: () => void;
|
||||||
|
|
@ -717,12 +717,12 @@ export class AgentSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Scoped models for cycling (from --models flag) */
|
/** Scoped models for cycling (from --models flag) */
|
||||||
get scopedModels(): ReadonlyArray<{ model: Model<any>; thinkingLevel: ThinkingLevel }> {
|
get scopedModels(): ReadonlyArray<{ model: Model<any>; thinkingLevel?: ThinkingLevel }> {
|
||||||
return this._scopedModels;
|
return this._scopedModels;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update scoped models for cycling */
|
/** Update scoped models for cycling */
|
||||||
setScopedModels(scopedModels: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>): void {
|
setScopedModels(scopedModels: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>): void {
|
||||||
this._scopedModels = scopedModels;
|
this._scopedModels = scopedModels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1338,9 +1338,9 @@ export class AgentSession {
|
||||||
return this._cycleAvailableModel(direction);
|
return this._cycleAvailableModel(direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _getScopedModelsWithApiKey(): Promise<Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>> {
|
private async _getScopedModelsWithApiKey(): Promise<Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>> {
|
||||||
const apiKeysByProvider = new Map<string, string | undefined>();
|
const apiKeysByProvider = new Map<string, string | undefined>();
|
||||||
const result: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }> = [];
|
const result: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }> = [];
|
||||||
|
|
||||||
for (const scoped of this._scopedModels) {
|
for (const scoped of this._scopedModels) {
|
||||||
const provider = scoped.model.provider;
|
const provider = scoped.model.provider;
|
||||||
|
|
@ -1377,8 +1377,11 @@ export class AgentSession {
|
||||||
this.sessionManager.appendModelChange(next.model.provider, next.model.id);
|
this.sessionManager.appendModelChange(next.model.provider, next.model.id);
|
||||||
this.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);
|
this.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);
|
||||||
|
|
||||||
// Apply thinking level (setThinkingLevel clamps to model capabilities)
|
// Apply thinking level.
|
||||||
this.setThinkingLevel(next.thinkingLevel);
|
// - Explicit scoped model thinking level overrides current session level
|
||||||
|
// - Undefined scoped model thinking level inherits current session level
|
||||||
|
// setThinkingLevel clamps to model capabilities.
|
||||||
|
this.setThinkingLevel(next.thinkingLevel ?? this.thinkingLevel);
|
||||||
|
|
||||||
await this._emitModelSelect(next.model, currentModel, "cycle");
|
await this._emitModelSelect(next.model, currentModel, "cycle");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ export interface CreateAgentSessionOptions {
|
||||||
/** Thinking level. Default: from settings, else 'medium' (clamped to model capabilities) */
|
/** Thinking level. Default: from settings, else 'medium' (clamped to model capabilities) */
|
||||||
thinkingLevel?: ThinkingLevel;
|
thinkingLevel?: ThinkingLevel;
|
||||||
/** Models available for cycling (Ctrl+P in interactive mode) */
|
/** Models available for cycling (Ctrl+P in interactive mode) */
|
||||||
scopedModels?: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;
|
scopedModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>;
|
||||||
|
|
||||||
/** Built-in tools to use. Default: codingTools [read, bash, edit, write] */
|
/** Built-in tools to use. Default: codingTools [read, bash, edit, write] */
|
||||||
tools?: Tool[];
|
tools?: Tool[];
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ import { listModels } from "./cli/list-models.js";
|
||||||
import { selectSession } from "./cli/session-picker.js";
|
import { selectSession } from "./cli/session-picker.js";
|
||||||
import { APP_NAME, getAgentDir, getModelsPath, VERSION } from "./config.js";
|
import { APP_NAME, getAgentDir, getModelsPath, VERSION } from "./config.js";
|
||||||
import { AuthStorage } from "./core/auth-storage.js";
|
import { AuthStorage } from "./core/auth-storage.js";
|
||||||
import { DEFAULT_THINKING_LEVEL } from "./core/defaults.js";
|
|
||||||
import { exportFromFile } from "./core/export-html/index.js";
|
import { exportFromFile } from "./core/export-html/index.js";
|
||||||
import type { LoadExtensionsResult } from "./core/extensions/index.js";
|
import type { LoadExtensionsResult } from "./core/extensions/index.js";
|
||||||
import { KeybindingsManager } from "./core/keybindings.js";
|
import { KeybindingsManager } from "./core/keybindings.js";
|
||||||
|
|
@ -488,12 +487,13 @@ function buildSessionOptions(
|
||||||
options.thinkingLevel = parsed.thinking;
|
options.thinkingLevel = parsed.thinking;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scoped models for Ctrl+P cycling - fill in default thinking level for models without explicit level
|
// Scoped models for Ctrl+P cycling
|
||||||
|
// Keep thinking level undefined when not explicitly set in the model pattern.
|
||||||
|
// Undefined means "inherit current session thinking level" during cycling.
|
||||||
if (scopedModels.length > 0) {
|
if (scopedModels.length > 0) {
|
||||||
const defaultThinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;
|
|
||||||
options.scopedModels = scopedModels.map((sm) => ({
|
options.scopedModels = scopedModels.map((sm) => ({
|
||||||
model: sm.model,
|
model: sm.model,
|
||||||
thinkingLevel: sm.thinkingLevel ?? defaultThinkingLevel,
|
thinkingLevel: sm.thinkingLevel,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ interface ModelItem {
|
||||||
|
|
||||||
interface ScopedModelItem {
|
interface ScopedModelItem {
|
||||||
model: Model<any>;
|
model: Model<any>;
|
||||||
thinkingLevel: string;
|
thinkingLevel?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ModelScope = "all" | "scoped";
|
type ModelScope = "all" | "scoped";
|
||||||
|
|
|
||||||
|
|
@ -3307,13 +3307,11 @@ export class InteractiveMode {
|
||||||
// Helper to update session's scoped models (session-only, no persist)
|
// Helper to update session's scoped models (session-only, no persist)
|
||||||
const updateSessionModels = async (enabledIds: Set<string>) => {
|
const updateSessionModels = async (enabledIds: Set<string>) => {
|
||||||
if (enabledIds.size > 0 && enabledIds.size < allModels.length) {
|
if (enabledIds.size > 0 && enabledIds.size < allModels.length) {
|
||||||
// Use current session thinking level, not settings default
|
|
||||||
const currentThinkingLevel = this.session.thinkingLevel;
|
|
||||||
const newScopedModels = await resolveModelScope(Array.from(enabledIds), this.session.modelRegistry);
|
const newScopedModels = await resolveModelScope(Array.from(enabledIds), this.session.modelRegistry);
|
||||||
this.session.setScopedModels(
|
this.session.setScopedModels(
|
||||||
newScopedModels.map((sm) => ({
|
newScopedModels.map((sm) => ({
|
||||||
model: sm.model,
|
model: sm.model,
|
||||||
thinkingLevel: sm.thinkingLevel ?? currentThinkingLevel,
|
thinkingLevel: sm.thinkingLevel,
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue