- Introduced Effort enum and ThinkingConfig metadata for per-model reasoning capabilities with min/max effort levels. - Migrated thinking level API from string-based ThinkingLevel to structured Effort enum across agent and AI packages. - Added model-thinking module with effort mapping, policy application, and semantic versioning utilities for provider-specific thinking modes. - Removed supportsXhigh() function and replaced effort clamping with model-aware validation using ThinkingConfig metadata. - Expanded models.json with thinking configuration objects for 50+ models including Claude, Gemini, and OpenAI variants. - Added Python analysis scripts for edit tool usage patterns and tool invocation stream processing.
90 lines
2.8 KiB
TypeScript
90 lines
2.8 KiB
TypeScript
/**
|
|
* List available models with optional fuzzy search
|
|
*/
|
|
import { type Api, getSupportedEfforts, type Model } from "@oh-my-pi/pi-ai";
|
|
import { formatNumber } from "@oh-my-pi/pi-utils";
|
|
import type { ModelRegistry } from "../config/model-registry";
|
|
import { fuzzyFilter } from "../utils/fuzzy";
|
|
|
|
/**
|
|
* List available models, optionally filtered by search pattern
|
|
*/
|
|
export async function listModels(modelRegistry: ModelRegistry, searchPattern?: string): Promise<void> {
|
|
const models = modelRegistry.getAvailable();
|
|
|
|
if (models.length === 0) {
|
|
console.log("No models available. Set API keys in environment variables.");
|
|
return;
|
|
}
|
|
|
|
// Apply fuzzy filter if search pattern provided
|
|
let filteredModels: Model<Api>[] = models;
|
|
if (searchPattern) {
|
|
filteredModels = fuzzyFilter(models, searchPattern, m => `${m.provider} ${m.id}`);
|
|
}
|
|
|
|
if (filteredModels.length === 0) {
|
|
console.log(`No models matching "${searchPattern}"`);
|
|
return;
|
|
}
|
|
|
|
// Sort by provider, then by model id
|
|
filteredModels.sort((a, b) => {
|
|
const providerCmp = a.provider.localeCompare(b.provider);
|
|
if (providerCmp !== 0) return providerCmp;
|
|
return a.id.localeCompare(b.id);
|
|
});
|
|
|
|
// Calculate column widths
|
|
const rows = filteredModels.map(m => ({
|
|
provider: m.provider,
|
|
model: m.id,
|
|
context: formatNumber(m.contextWindow),
|
|
maxOut: formatNumber(m.maxTokens),
|
|
thinking: m.thinking ? getSupportedEfforts(m).join(",") : m.reasoning ? "yes" : "-",
|
|
images: m.input.includes("image") ? "yes" : "no",
|
|
}));
|
|
|
|
const headers = {
|
|
provider: "provider",
|
|
model: "model",
|
|
context: "context",
|
|
maxOut: "max-out",
|
|
thinking: "thinking",
|
|
images: "images",
|
|
};
|
|
|
|
const widths = {
|
|
provider: Math.max(headers.provider.length, ...rows.map(r => r.provider.length)),
|
|
model: Math.max(headers.model.length, ...rows.map(r => r.model.length)),
|
|
context: Math.max(headers.context.length, ...rows.map(r => r.context.length)),
|
|
maxOut: Math.max(headers.maxOut.length, ...rows.map(r => r.maxOut.length)),
|
|
thinking: Math.max(headers.thinking.length, ...rows.map(r => r.thinking.length)),
|
|
images: Math.max(headers.images.length, ...rows.map(r => r.images.length)),
|
|
};
|
|
|
|
// Print header
|
|
const headerLine = [
|
|
headers.provider.padEnd(widths.provider),
|
|
headers.model.padEnd(widths.model),
|
|
headers.context.padEnd(widths.context),
|
|
headers.maxOut.padEnd(widths.maxOut),
|
|
headers.thinking.padEnd(widths.thinking),
|
|
headers.images.padEnd(widths.images),
|
|
].join(" ");
|
|
console.log(headerLine);
|
|
|
|
// Print rows
|
|
for (const row of rows) {
|
|
const line = [
|
|
row.provider.padEnd(widths.provider),
|
|
row.model.padEnd(widths.model),
|
|
row.context.padEnd(widths.context),
|
|
row.maxOut.padEnd(widths.maxOut),
|
|
row.thinking.padEnd(widths.thinking),
|
|
row.images.padEnd(widths.images),
|
|
].join(" ");
|
|
console.log(line);
|
|
}
|
|
}
|