feat(coding-agent): added slow model role for comprehensive reasoning
- Added pi/smol alias for explore agent (fast/cheap model)
- Added pi/slow alias for reviewer agent (reasoning/codex model)
- Added L key binding in model selector to set slow model
- Added 🧠 marker for slow model in selector
- Slow model priority chain: gpt-5.2-codex > codex > gpt > opus > pro
This commit is contained in:
@@ -12,11 +12,12 @@
|
||||
|
||||
### Added
|
||||
|
||||
- Model roles: Configure different models for different purposes (default, small, etc.) via `/model` selector
|
||||
- Model selector dual-key binding: Enter sets default model, S sets small model, Escape closes
|
||||
- Model selector shows role markers: checkmark for default, lightning bolt for small
|
||||
- `pi/<role>` model aliases in Task tool agent definitions (e.g., `model: pi/small, haiku, flash, mini`)
|
||||
- Model roles: Configure different models for different purposes (default, small, slow) via `/model` selector
|
||||
- Model selector key bindings: Enter sets default, S sets small, L sets slow, Escape closes
|
||||
- Model selector shows role markers: ✓ for default, ⚡ for small, 🧠 for slow
|
||||
- `pi/<role>` model aliases in Task tool agent definitions (e.g., `model: pi/smol, haiku, flash, mini`)
|
||||
- Small model auto-discovery using priority chain: haiku > flash > mini
|
||||
- Slow model auto-discovery using priority chain: gpt-5.2-codex > codex > gpt > opus > pro
|
||||
- Title generation now uses configured small model from settings
|
||||
|
||||
- LSP diagnostics on edit: Edit tool can now return LSP diagnostics after editing code files. Disabled by default to avoid noise during multi-edit sequences. Enable via `lsp.diagnosticsOnEdit` setting.
|
||||
|
||||
@@ -33,6 +33,9 @@ export interface ScopedModel {
|
||||
/** Priority chain for auto-discovering small/fast models */
|
||||
export const SMALL_MODEL_PRIORITY = ["claude-haiku-4-5", "haiku", "flash", "mini"];
|
||||
|
||||
/** Priority chain for auto-discovering slow/comprehensive models (reasoning, codex) */
|
||||
export const SLOW_MODEL_PRIORITY = ["gpt-5.2-codex", "gpt-5.2", "codex", "gpt", "opus", "pro"];
|
||||
|
||||
/**
|
||||
* Parse a model string in "provider/modelId" format.
|
||||
* Returns undefined if the format is invalid.
|
||||
@@ -450,3 +453,42 @@ export async function findSmallModel(
|
||||
// 3. Fallback to first available (same as default)
|
||||
return availableModels[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a slow/comprehensive model using the priority chain.
|
||||
* Prioritizes reasoning and codex models for thorough analysis.
|
||||
*
|
||||
* @param modelRegistry The model registry to search
|
||||
* @param savedModel Optional saved model string from settings (provider/modelId)
|
||||
* @returns The best available slow model, or undefined if none found
|
||||
*/
|
||||
export async function findSlowModel(
|
||||
modelRegistry: ModelRegistry,
|
||||
savedModel?: string,
|
||||
): Promise<Model<Api> | undefined> {
|
||||
const availableModels = await modelRegistry.getAvailable();
|
||||
if (availableModels.length === 0) return undefined;
|
||||
|
||||
// 1. Try saved model from settings
|
||||
if (savedModel) {
|
||||
const parsed = parseModelString(savedModel);
|
||||
if (parsed) {
|
||||
const match = availableModels.find((m) => m.provider === parsed.provider && m.id === parsed.id);
|
||||
if (match) return match;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Try priority chain
|
||||
for (const pattern of SLOW_MODEL_PRIORITY) {
|
||||
// Try exact match first
|
||||
const exactMatch = availableModels.find((m) => m.id.toLowerCase() === pattern.toLowerCase());
|
||||
if (exactMatch) return exactMatch;
|
||||
|
||||
// Try fuzzy match (substring)
|
||||
const fuzzyMatch = availableModels.find((m) => m.id.toLowerCase().includes(pattern.toLowerCase()));
|
||||
if (fuzzyMatch) return fuzzyMatch;
|
||||
}
|
||||
|
||||
// 3. Fallback to first available (same as default)
|
||||
return availableModels[0];
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: explore
|
||||
description: Fast read-only codebase scout that returns compressed context for handoff
|
||||
tools: read, grep, glob, ls, bash
|
||||
model: pi/small, haiku, flash, mini
|
||||
model: pi/smol, haiku, flash, mini
|
||||
---
|
||||
|
||||
You are a file search specialist and codebase scout. Quickly investigate a codebase and return structured findings that another agent can use without re-reading everything.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: reviewer
|
||||
description: Expert code reviewer for PRs and implementation changes
|
||||
tools: read, grep, glob, ls, bash
|
||||
model: gpt-5.2-codex, gpt-5.2, codex, gpt
|
||||
model: pi/slow, gpt-5.2-codex, gpt-5.2, codex, gpt
|
||||
---
|
||||
|
||||
You are an expert code reviewer. Analyze code changes and provide thorough reviews.
|
||||
|
||||
@@ -33,6 +33,7 @@ export class ModelSelectorComponent extends Container {
|
||||
private currentModel?: Model<any>;
|
||||
private defaultModel?: Model<any>;
|
||||
private smallModel?: Model<any>;
|
||||
private slowModel?: Model<any>;
|
||||
private settingsManager: SettingsManager;
|
||||
private modelRegistry: ModelRegistry;
|
||||
private onSelectCallback: (model: Model<any>, role: string) => void;
|
||||
@@ -73,7 +74,7 @@ export class ModelSelectorComponent extends Container {
|
||||
? "Showing models from --models scope"
|
||||
: "Only showing models with configured API keys (see README for details)";
|
||||
this.addChild(new Text(theme.fg("warning", hintText), 0, 0));
|
||||
this.addChild(new Text(theme.fg("muted", "Enter: set default S: set small Esc: close"), 0, 0));
|
||||
this.addChild(new Text(theme.fg("muted", "Enter: default S: small L: slow Esc: close"), 0, 0));
|
||||
this.addChild(new Spacer(1));
|
||||
|
||||
// Create search input
|
||||
@@ -126,6 +127,15 @@ export class ModelSelectorComponent extends Container {
|
||||
this.smallModel = allModels.find((m) => m.provider === parsed.provider && m.id === parsed.id);
|
||||
}
|
||||
}
|
||||
|
||||
// Load slow model
|
||||
const slowStr = roles.slow;
|
||||
if (slowStr) {
|
||||
const parsed = parseModelString(slowStr);
|
||||
if (parsed) {
|
||||
this.slowModel = allModels.find((m) => m.provider === parsed.provider && m.id === parsed.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async loadModels(): Promise<void> {
|
||||
@@ -202,11 +212,13 @@ export class ModelSelectorComponent extends Container {
|
||||
const isSelected = i === this.selectedIndex;
|
||||
const isDefault = modelsAreEqual(this.defaultModel, item.model);
|
||||
const isSmall = modelsAreEqual(this.smallModel, item.model);
|
||||
const isSlow = modelsAreEqual(this.slowModel, item.model);
|
||||
|
||||
// Build role markers: ✓ for default, ⚡ for small
|
||||
// Build role markers: ✓ for default, ⚡ for small, 🧠 for slow
|
||||
let markers = "";
|
||||
if (isDefault) markers += theme.fg("success", " ✓");
|
||||
if (isSmall) markers += theme.fg("warning", " ⚡");
|
||||
if (isSlow) markers += theme.fg("accent", " 🧠");
|
||||
|
||||
let line = "";
|
||||
if (isSelected) {
|
||||
@@ -268,6 +280,13 @@ export class ModelSelectorComponent extends Container {
|
||||
this.handleSelect(selectedModel.model, "small");
|
||||
}
|
||||
}
|
||||
// L key - set as slow model (don't close)
|
||||
else if (keyData === "l" || keyData === "L") {
|
||||
const selectedModel = this.filteredModels[this.selectedIndex];
|
||||
if (selectedModel) {
|
||||
this.handleSelect(selectedModel.model, "slow");
|
||||
}
|
||||
}
|
||||
// Escape - close
|
||||
else if (isEscape(keyData)) {
|
||||
this.onCancelCallback();
|
||||
@@ -288,6 +307,8 @@ export class ModelSelectorComponent extends Container {
|
||||
this.defaultModel = model;
|
||||
} else if (role === "small") {
|
||||
this.smallModel = model;
|
||||
} else if (role === "slow") {
|
||||
this.slowModel = model;
|
||||
}
|
||||
|
||||
// Notify caller (for updating agent state if needed)
|
||||
|
||||
Reference in New Issue
Block a user