diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index aed24a98b..03fa88b3a 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -12,15 +12,15 @@ ### Added -- 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 +- Model roles: Configure different models for different purposes (default, smol, slow) via `/model` selector +- Model selector key bindings: Enter sets default, S sets smol, L sets slow, Escape closes +- Model selector shows role markers: ✓ for default, ⚡ for smol, 🧠 for slow - `pi/` 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 +- Smol model auto-discovery using priority chain: haiku > flash > mini - Slow model auto-discovery using priority chain: gpt-5.2-codex > codex > gpt > opus > pro - CLI args for model roles: `--smol ` and `--slow ` (ephemeral, not persisted) - Env var overrides: `PI_SMOL_MODEL` and `PI_SLOW_MODEL` -- Title generation now uses configured small model from settings +- Title generation now uses configured smol 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. - LSP workspace diagnostics: New `lsp action=workspace_diagnostics` command checks the entire project for errors. Auto-detects project type and uses appropriate checker (rust-analyzer/cargo for Rust, tsc for TypeScript, go build for Go, pyright for Python). diff --git a/packages/coding-agent/src/cli/args.ts b/packages/coding-agent/src/cli/args.ts index 96fa4ec8f..bda12c83e 100644 --- a/packages/coding-agent/src/cli/args.ts +++ b/packages/coding-agent/src/cli/args.ts @@ -154,7 +154,7 @@ ${chalk.bold("Usage:")} ${chalk.bold("Options:")} --provider Provider name (default: google) --model Model ID (default: gemini-2.5-flash) - --smol Small/fast model for lightweight tasks (or PI_SMOL_MODEL env) + --smol Smol/fast model for lightweight tasks (or PI_SMOL_MODEL env) --slow Slow/reasoning model for thorough analysis (or PI_SLOW_MODEL env) --api-key API key (defaults to env vars) --system-prompt System prompt (default: coding assistant prompt) diff --git a/packages/coding-agent/src/core/model-resolver.ts b/packages/coding-agent/src/core/model-resolver.ts index 36f8cb27a..7b784d8b4 100644 --- a/packages/coding-agent/src/core/model-resolver.ts +++ b/packages/coding-agent/src/core/model-resolver.ts @@ -30,8 +30,8 @@ export interface ScopedModel { thinkingLevel: ThinkingLevel; } -/** 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 smol/fast models */ +export const SMOL_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"]; @@ -416,14 +416,14 @@ export async function restoreModelFromSession( } /** - * Find a small/fast model using the priority chain. + * Find a smol/fast model using the priority chain. * Tries exact matches first, then fuzzy matches. * * @param modelRegistry The model registry to search * @param savedModel Optional saved model string from settings (provider/modelId) - * @returns The best available small model, or undefined if none found + * @returns The best available smol model, or undefined if none found */ -export async function findSmallModel( +export async function findSmolModel( modelRegistry: ModelRegistry, savedModel?: string, ): Promise | undefined> { @@ -440,7 +440,7 @@ export async function findSmallModel( } // 2. Try priority chain - for (const pattern of SMALL_MODEL_PRIORITY) { + for (const pattern of SMOL_MODEL_PRIORITY) { // Try exact match first const exactMatch = availableModels.find((m) => m.id.toLowerCase() === pattern.toLowerCase()); if (exactMatch) return exactMatch; diff --git a/packages/coding-agent/src/core/session-manager.ts b/packages/coding-agent/src/core/session-manager.ts index 18f465e7d..6c75e1909 100644 --- a/packages/coding-agent/src/core/session-manager.ts +++ b/packages/coding-agent/src/core/session-manager.ts @@ -59,7 +59,7 @@ export interface ModelChangeEntry extends SessionEntryBase { type: "model_change"; /** Model in "provider/modelId" format */ model: string; - /** Role: "default", "small", etc. Undefined treated as "default" */ + /** Role: "default", "smol", "slow", etc. Undefined treated as "default" */ role?: string; } diff --git a/packages/coding-agent/src/core/title-generator.ts b/packages/coding-agent/src/core/title-generator.ts index b1724db5c..c90d5964b 100644 --- a/packages/coding-agent/src/core/title-generator.ts +++ b/packages/coding-agent/src/core/title-generator.ts @@ -1,11 +1,11 @@ /** - * Generate session titles using a small, fast model. + * Generate session titles using a smol, fast model. */ import type { Model } from "@oh-my-pi/pi-ai"; import { completeSimple } from "@oh-my-pi/pi-ai"; import type { ModelRegistry } from "./model-registry.js"; -import { findSmallModel } from "./model-resolver.js"; +import { findSmolModel } from "./model-resolver.js"; const TITLE_SYSTEM_PROMPT = `Generate a very short title (3-6 words) for a coding session based on the user's first message. The title should capture the main task or topic. Output ONLY the title, nothing else. No quotes, no punctuation at the end. @@ -20,13 +20,13 @@ const MAX_INPUT_CHARS = 2000; /** * Find the best available model for title generation. - * Uses the configured small model if set, otherwise auto-discovers using priority chain. + * Uses the configured smol model if set, otherwise auto-discovers using priority chain. * * @param registry Model registry - * @param savedSmallModel Optional saved small model from settings (provider/modelId format) + * @param savedSmolModel Optional saved smol model from settings (provider/modelId format) */ -export async function findTitleModel(registry: ModelRegistry, savedSmallModel?: string): Promise | null> { - const model = await findSmallModel(registry, savedSmallModel); +export async function findTitleModel(registry: ModelRegistry, savedSmolModel?: string): Promise | null> { + const model = await findSmolModel(registry, savedSmolModel); return model ?? null; } @@ -35,14 +35,14 @@ export async function findTitleModel(registry: ModelRegistry, savedSmallModel?: * * @param firstMessage The first user message * @param registry Model registry - * @param savedSmallModel Optional saved small model from settings (provider/modelId format) + * @param savedSmolModel Optional saved smol model from settings (provider/modelId format) */ export async function generateSessionTitle( firstMessage: string, registry: ModelRegistry, - savedSmallModel?: string, + savedSmolModel?: string, ): Promise { - const model = await findTitleModel(registry, savedSmallModel); + const model = await findTitleModel(registry, savedSmolModel); if (!model) return null; const apiKey = await registry.getApiKey(model); diff --git a/packages/coding-agent/src/core/tools/task/model-resolver.ts b/packages/coding-agent/src/core/tools/task/model-resolver.ts index b9d064be6..fb905ed34 100644 --- a/packages/coding-agent/src/core/tools/task/model-resolver.ts +++ b/packages/coding-agent/src/core/tools/task/model-resolver.ts @@ -7,7 +7,7 @@ * - Comma fallback: "gpt, opus" → tries gpt first, then opus * - "default" → undefined (use system default) * - "pi/default" → configured default model from settings - * - "pi/small" or "pi/smol" → configured small model from settings + * - "pi/smol" → configured smol model from settings */ import { spawnSync } from "node:child_process"; diff --git a/packages/coding-agent/src/main.ts b/packages/coding-agent/src/main.ts index beb0e08ac..a4b640cdb 100644 --- a/packages/coding-agent/src/main.ts +++ b/packages/coding-agent/src/main.ts @@ -362,7 +362,7 @@ export async function main(args: string[]) { const slowModel = parsed.slow ?? process.env.PI_SLOW_MODEL; if (smolModel || slowModel) { const roleOverrides: Record = {}; - if (smolModel) roleOverrides.small = smolModel; + if (smolModel) roleOverrides.smol = smolModel; if (slowModel) roleOverrides.slow = slowModel; settingsManager.applyOverrides({ modelRoles: roleOverrides }); } diff --git a/packages/coding-agent/src/modes/interactive/components/model-selector.ts b/packages/coding-agent/src/modes/interactive/components/model-selector.ts index 363637faa..eb920806b 100644 --- a/packages/coding-agent/src/modes/interactive/components/model-selector.ts +++ b/packages/coding-agent/src/modes/interactive/components/model-selector.ts @@ -21,7 +21,8 @@ interface ScopedModelItem { /** * Component that renders a model selector with search. * - Enter: Set selected model as default - * - S: Set selected model as small + * - S: Set selected model as smol + * - L: Set selected model as slow * - Escape: Close selector */ export class ModelSelectorComponent extends Container { @@ -32,7 +33,7 @@ export class ModelSelectorComponent extends Container { private selectedIndex: number = 0; private currentModel?: Model; private defaultModel?: Model; - private smallModel?: Model; + private smolModel?: Model; private slowModel?: Model; private settingsManager: SettingsManager; private modelRegistry: ModelRegistry; @@ -74,7 +75,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: default S: small L: slow Esc: close"), 0, 0)); + this.addChild(new Text(theme.fg("muted", "Enter: default S: smol L: slow Esc: close"), 0, 0)); this.addChild(new Spacer(1)); // Create search input @@ -119,12 +120,12 @@ export class ModelSelectorComponent extends Container { } } - // Load small model - const smallStr = roles.small; - if (smallStr) { - const parsed = parseModelString(smallStr); + // Load smol model + const smolStr = roles.smol; + if (smolStr) { + const parsed = parseModelString(smolStr); if (parsed) { - this.smallModel = allModels.find((m) => m.provider === parsed.provider && m.id === parsed.id); + this.smolModel = allModels.find((m) => m.provider === parsed.provider && m.id === parsed.id); } } @@ -211,13 +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 isSmol = modelsAreEqual(this.smolModel, item.model); const isSlow = modelsAreEqual(this.slowModel, item.model); - // Build role markers: ✓ for default, ⚡ for small, 🧠 for slow + // Build role markers: ✓ for default, ⚡ for smol, 🧠 for slow let markers = ""; if (isDefault) markers += theme.fg("success", " ✓"); - if (isSmall) markers += theme.fg("warning", " ⚡"); + if (isSmol) markers += theme.fg("warning", " ⚡"); if (isSlow) markers += theme.fg("accent", " 🧠"); let line = ""; @@ -273,11 +274,11 @@ export class ModelSelectorComponent extends Container { this.handleSelect(selectedModel.model, "default"); } } - // S key - set as small model (don't close) + // S key - set as smol model (don't close) else if (keyData === "s" || keyData === "S") { const selectedModel = this.filteredModels[this.selectedIndex]; if (selectedModel) { - this.handleSelect(selectedModel.model, "small"); + this.handleSelect(selectedModel.model, "smol"); } } // L key - set as slow model (don't close) @@ -305,8 +306,8 @@ export class ModelSelectorComponent extends Container { // Update local state for UI if (role === "default") { this.defaultModel = model; - } else if (role === "small") { - this.smallModel = model; + } else if (role === "smol") { + this.smolModel = model; } else if (role === "slow") { this.slowModel = model; } diff --git a/packages/coding-agent/src/modes/interactive/interactive-mode.ts b/packages/coding-agent/src/modes/interactive/interactive-mode.ts index 1048be905..1d5b625f3 100644 --- a/packages/coding-agent/src/modes/interactive/interactive-mode.ts +++ b/packages/coding-agent/src/modes/interactive/interactive-mode.ts @@ -1609,8 +1609,8 @@ export class InteractiveMode { // Generate title in background const registry = this.session.modelRegistry; - const smallModel = this.settingsManager.getModelRole("small"); - generateSessionTitle(messageText, registry, smallModel) + const smolModel = this.settingsManager.getModelRole("smol"); + generateSessionTitle(messageText, registry, smolModel) .then((title) => { if (title) { this.sessionManager.setSessionTitle(title); @@ -1766,7 +1766,7 @@ export class InteractiveMode { this.updateEditorBorderColor(); } // For other roles (small), just show status - settings already updated by selector - const roleLabel = role === "default" ? "Default" : role === "small" ? "Small" : role; + const roleLabel = role === "default" ? "Default" : role === "smol" ? "Smol" : role; this.showStatus(`${roleLabel} model: ${model.id}`); } catch (error) { this.showError(error instanceof Error ? error.message : String(error));