mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 13:03:42 +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]
|
||||
|
||||
### 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 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;
|
||||
cwd: string;
|
||||
/** 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 */
|
||||
resourceLoader: ResourceLoader;
|
||||
/** SDK custom tools registered outside extensions */
|
||||
|
|
@ -215,7 +215,7 @@ export class AgentSession {
|
|||
readonly sessionManager: SessionManager;
|
||||
readonly settingsManager: SettingsManager;
|
||||
|
||||
private _scopedModels: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;
|
||||
private _scopedModels: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>;
|
||||
|
||||
// Event subscription state
|
||||
private _unsubscribeAgent?: () => void;
|
||||
|
|
@ -717,12 +717,12 @@ export class AgentSession {
|
|||
}
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
|
|
@ -1338,9 +1338,9 @@ export class AgentSession {
|
|||
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 result: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }> = [];
|
||||
const result: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }> = [];
|
||||
|
||||
for (const scoped of this._scopedModels) {
|
||||
const provider = scoped.model.provider;
|
||||
|
|
@ -1377,8 +1377,11 @@ export class AgentSession {
|
|||
this.sessionManager.appendModelChange(next.model.provider, next.model.id);
|
||||
this.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);
|
||||
|
||||
// Apply thinking level (setThinkingLevel clamps to model capabilities)
|
||||
this.setThinkingLevel(next.thinkingLevel);
|
||||
// Apply thinking level.
|
||||
// - 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");
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ export interface CreateAgentSessionOptions {
|
|||
/** Thinking level. Default: from settings, else 'medium' (clamped to model capabilities) */
|
||||
thinkingLevel?: ThinkingLevel;
|
||||
/** 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] */
|
||||
tools?: Tool[];
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import { listModels } from "./cli/list-models.js";
|
|||
import { selectSession } from "./cli/session-picker.js";
|
||||
import { APP_NAME, getAgentDir, getModelsPath, VERSION } from "./config.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 type { LoadExtensionsResult } from "./core/extensions/index.js";
|
||||
import { KeybindingsManager } from "./core/keybindings.js";
|
||||
|
|
@ -488,12 +487,13 @@ function buildSessionOptions(
|
|||
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) {
|
||||
const defaultThinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;
|
||||
options.scopedModels = scopedModels.map((sm) => ({
|
||||
model: sm.model,
|
||||
thinkingLevel: sm.thinkingLevel ?? defaultThinkingLevel,
|
||||
thinkingLevel: sm.thinkingLevel,
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ interface ModelItem {
|
|||
|
||||
interface ScopedModelItem {
|
||||
model: Model<any>;
|
||||
thinkingLevel: string;
|
||||
thinkingLevel?: string;
|
||||
}
|
||||
|
||||
type ModelScope = "all" | "scoped";
|
||||
|
|
|
|||
|
|
@ -3307,13 +3307,11 @@ export class InteractiveMode {
|
|||
// Helper to update session's scoped models (session-only, no persist)
|
||||
const updateSessionModels = async (enabledIds: Set<string>) => {
|
||||
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);
|
||||
this.session.setScopedModels(
|
||||
newScopedModels.map((sm) => ({
|
||||
model: sm.model,
|
||||
thinkingLevel: sm.thinkingLevel ?? currentThinkingLevel,
|
||||
thinkingLevel: sm.thinkingLevel,
|
||||
})),
|
||||
);
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue