mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-16 17:01:02 +00:00
Add --models parameter for quick model cycling with Ctrl+P
- Add --models CLI arg accepting comma-separated patterns - Implement smart matching: prefers aliases over dated versions - Add Ctrl+P to cycle through scoped models (or all if no scope) - Show model scope hint at startup - Update help text with examples Co-authored-by: Tino Ehrich <tino.ehrich@hey.com>
This commit is contained in:
parent
097ff25ed4
commit
fecf9734b0
3 changed files with 170 additions and 3 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import type { Agent, AgentEvent, AgentState, ThinkingLevel } from "@mariozechner/pi-agent";
|
||||
import type { AssistantMessage, Message } from "@mariozechner/pi-ai";
|
||||
import type { AssistantMessage, Message, Model } from "@mariozechner/pi-ai";
|
||||
import type { SlashCommand } from "@mariozechner/pi-tui";
|
||||
import {
|
||||
CombinedAutocompleteProvider,
|
||||
|
|
@ -16,7 +16,7 @@ import chalk from "chalk";
|
|||
import { exec } from "child_process";
|
||||
import { getChangelogPath, parseChangelog } from "../changelog.js";
|
||||
import { exportSessionToHtml } from "../export-html.js";
|
||||
import { getApiKeyForModel } from "../model-config.js";
|
||||
import { getApiKeyForModel, getAvailableModels } from "../model-config.js";
|
||||
import { listOAuthProviders, login, logout } from "../oauth/index.js";
|
||||
import type { SessionManager } from "../session-manager.js";
|
||||
import type { SettingsManager } from "../settings-manager.js";
|
||||
|
|
@ -74,6 +74,9 @@ export class TuiRenderer {
|
|||
// Track if this is the first user message (to skip spacer)
|
||||
private isFirstUserMessage = true;
|
||||
|
||||
// Model scope for quick cycling
|
||||
private scopedModels: Model<any>[] = [];
|
||||
|
||||
constructor(
|
||||
agent: Agent,
|
||||
sessionManager: SessionManager,
|
||||
|
|
@ -81,6 +84,7 @@ export class TuiRenderer {
|
|||
version: string,
|
||||
changelogMarkdown: string | null = null,
|
||||
newVersion: string | null = null,
|
||||
scopedModels: Model<any>[] = [],
|
||||
) {
|
||||
this.agent = agent;
|
||||
this.sessionManager = sessionManager;
|
||||
|
|
@ -88,6 +92,7 @@ export class TuiRenderer {
|
|||
this.version = version;
|
||||
this.newVersion = newVersion;
|
||||
this.changelogMarkdown = changelogMarkdown;
|
||||
this.scopedModels = scopedModels;
|
||||
this.ui = new TUI(new ProcessTerminal());
|
||||
this.chatContainer = new Container();
|
||||
this.statusContainer = new Container();
|
||||
|
|
@ -175,6 +180,9 @@ export class TuiRenderer {
|
|||
chalk.dim("shift+tab") +
|
||||
chalk.gray(" to cycle thinking") +
|
||||
"\n" +
|
||||
chalk.dim("ctrl+p") +
|
||||
chalk.gray(" to cycle models") +
|
||||
"\n" +
|
||||
chalk.dim("/") +
|
||||
chalk.gray(" for commands") +
|
||||
"\n" +
|
||||
|
|
@ -236,6 +244,10 @@ export class TuiRenderer {
|
|||
this.cycleThinkingLevel();
|
||||
};
|
||||
|
||||
this.editor.onCtrlP = () => {
|
||||
this.cycleModel();
|
||||
};
|
||||
|
||||
// Handle editor submission
|
||||
this.editor.onSubmit = async (text: string) => {
|
||||
text = text.trim();
|
||||
|
|
@ -656,6 +668,61 @@ export class TuiRenderer {
|
|||
this.ui.requestRender();
|
||||
}
|
||||
|
||||
private async cycleModel(): Promise<void> {
|
||||
// Use scoped models if available, otherwise all available models
|
||||
let modelsToUse: Model<any>[];
|
||||
if (this.scopedModels.length > 0) {
|
||||
modelsToUse = this.scopedModels;
|
||||
} else {
|
||||
const { models: availableModels, error } = await getAvailableModels();
|
||||
if (error) {
|
||||
this.showError(`Failed to load models: ${error}`);
|
||||
return;
|
||||
}
|
||||
modelsToUse = availableModels;
|
||||
}
|
||||
|
||||
if (modelsToUse.length === 0) {
|
||||
this.showError("No models available to cycle");
|
||||
return;
|
||||
}
|
||||
|
||||
if (modelsToUse.length === 1) {
|
||||
this.chatContainer.addChild(new Spacer(1));
|
||||
this.chatContainer.addChild(new Text(chalk.dim("Only one model in scope"), 1, 0));
|
||||
this.ui.requestRender();
|
||||
return;
|
||||
}
|
||||
|
||||
const currentModel = this.agent.state.model;
|
||||
let currentIndex = modelsToUse.findIndex(
|
||||
(m) => m.id === currentModel?.id && m.provider === currentModel?.provider,
|
||||
);
|
||||
|
||||
// If current model not in scope, start from first
|
||||
if (currentIndex === -1) {
|
||||
currentIndex = 0;
|
||||
}
|
||||
|
||||
const nextIndex = (currentIndex + 1) % modelsToUse.length;
|
||||
const nextModel = modelsToUse[nextIndex];
|
||||
|
||||
// Validate API key
|
||||
const apiKey = await getApiKeyForModel(nextModel);
|
||||
if (!apiKey) {
|
||||
this.showError(`No API key for ${nextModel.provider}/${nextModel.id}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Switch model
|
||||
this.agent.setModel(nextModel);
|
||||
|
||||
// Show notification
|
||||
this.chatContainer.addChild(new Spacer(1));
|
||||
this.chatContainer.addChild(new Text(chalk.dim(`Switched to ${nextModel.name || nextModel.id}`), 1, 0));
|
||||
this.ui.requestRender();
|
||||
}
|
||||
|
||||
clearEditor(): void {
|
||||
this.editor.setText("");
|
||||
this.ui.requestRender();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue