refactor: added default generic type parameter to Model interface

- Added default generic type parameter to Model interface, allowing Model to be used without explicit type argument.
- Removed explicit <any> generic type parameters from Model type annotations throughout codebase, leveraging new default parameter.
This commit is contained in:
can1357
2026-02-05 00:10:18 +01:00
parent 92b93d87e0
commit d5790b5414
25 changed files with 166 additions and 77 deletions
+2 -2
View File
@@ -133,7 +133,7 @@ const agent = new Agent({
// Initial state
initialState: {
systemPrompt: string,
model: Model<any>,
model: Model,
thinkingLevel: "off" | "minimal" | "low" | "medium" | "high" | "xhigh",
tools: AgentTool<any>[],
messages: AgentMessage[],
@@ -164,7 +164,7 @@ const agent = new Agent({
```typescript
interface AgentState {
systemPrompt: string;
model: Model<any>;
model: Model;
thinkingLevel: ThinkingLevel;
tools: AgentTool<any>[];
messages: AgentMessage[];
+1 -1
View File
@@ -246,7 +246,7 @@ export class Agent {
this._state.systemPrompt = v;
}
setModel(m: Model<any>) {
setModel(m: Model) {
this._state.model = m;
}
+1 -1
View File
@@ -81,7 +81,7 @@ export interface ProxyStreamOptions extends SimpleStreamOptions {
* });
* ```
*/
export function streamProxy(model: Model<any>, context: Context, options: ProxyStreamOptions): ProxyMessageEventStream {
export function streamProxy(model: Model, context: Context, options: ProxyStreamOptions): ProxyMessageEventStream {
const stream = new ProxyMessageEventStream();
(async () => {
+2 -2
View File
@@ -20,7 +20,7 @@ export type StreamFn = (
* Configuration for the agent loop.
*/
export interface AgentLoopConfig extends SimpleStreamOptions {
model: Model<any>;
model: Model;
/**
* When to interrupt tool execution for steering messages.
@@ -155,7 +155,7 @@ export type AgentMessage = Message | CustomAgentMessages[keyof CustomAgentMessag
*/
export interface AgentState {
systemPrompt: string;
model: Model<any>;
model: Model;
thinkingLevel: ThinkingLevel;
tools: AgentTool<any>[];
messages: AgentMessage[]; // Can include attachments + custom message types
+9 -9
View File
@@ -52,13 +52,13 @@ const COPILOT_STATIC_HEADERS = {
const AI_GATEWAY_MODELS_URL = "https://ai-gateway.vercel.sh/v1";
const AI_GATEWAY_BASE_URL = "https://ai-gateway.vercel.sh";
async function fetchOpenRouterModels(): Promise<Model<any>[]> {
async function fetchOpenRouterModels(): Promise<Model[]> {
try {
console.log("Fetching models from OpenRouter API...");
const response = await fetch("https://openrouter.ai/api/v1/models");
const data = await response.json();
const models: Model<any>[] = [];
const models: Model[] = [];
for (const model of data.data) {
// Only include models that support tools
@@ -84,7 +84,7 @@ async function fetchOpenRouterModels(): Promise<Model<any>[]> {
// Check if model supports tool_choice parameter
const supportsToolChoice = model.supported_parameters?.includes("tool_choice") ?? false;
const normalizedModel: Model<any> = {
const normalizedModel: Model = {
id: modelKey,
name: model.name,
api: "openai-completions",
@@ -114,12 +114,12 @@ async function fetchOpenRouterModels(): Promise<Model<any>[]> {
}
}
async function fetchAiGatewayModels(): Promise<Model<any>[]> {
async function fetchAiGatewayModels(): Promise<Model[]> {
try {
console.log("Fetching models from Vercel AI Gateway API...");
const response = await fetch(`${AI_GATEWAY_MODELS_URL}/models`);
const data = await response.json();
const models: Model<any>[] = [];
const models: Model[] = [];
const toNumber = (value: string | number | undefined): number => {
if (typeof value === "number") {
@@ -331,13 +331,13 @@ function getKimiCodeFallbackModels(): Model<"openai-completions">[] {
];
}
async function loadModelsDevData(): Promise<Model<any>[]> {
async function loadModelsDevData(): Promise<Model[]> {
try {
console.log("Fetching models from models.dev API...");
const response = await fetch("https://models.dev/api.json");
const data = await response.json();
const models: Model<any>[] = [];
const models: Model[] = [];
// Process Amazon Bedrock models
if (data["amazon-bedrock"]?.models) {
@@ -700,7 +700,7 @@ async function loadModelsDevData(): Promise<Model<any>[]> {
// gpt-5 models require responses API, others use completions
const needsResponsesApi = modelId.startsWith("gpt-5") || modelId.startsWith("oswe");
const copilotModel: Model<any> = {
const copilotModel: Model = {
id: modelId,
name: m.name || modelId,
api: needsResponsesApi ? "openai-responses" : "openai-completions",
@@ -1433,7 +1433,7 @@ async function generateModels() {
allModels.push(...cursorModels);
// Group by provider and deduplicate by model ID
const providers: Record<string, Record<string, Model<any>>> = {};
const providers: Record<string, Record<string, Model>> = {};
for (const model of allModels) {
if (!providers[model.provider]) {
providers[model.provider] = {};
+1 -1
View File
@@ -349,7 +349,7 @@ export interface VercelGatewayRouting {
}
// Model interface for the unified model system
export interface Model<TApi extends Api> {
export interface Model<TApi extends Api = any> {
id: string;
name: string;
api: TApi;
+1 -1
View File
@@ -52,7 +52,7 @@ interface OverflowResult {
response: AssistantMessage;
}
async function testContextOverflow(model: Model<any>, apiKey: string): Promise<OverflowResult> {
async function testContextOverflow(model: Model, apiKey: string): Promise<OverflowResult> {
const overflowContent = generateOverflowContent(model.contextWindow);
const context: Context = {
+1 -1
View File
@@ -9,7 +9,7 @@ describe.skipIf(!e2eApiKey("OPENCODE_API_KEY"))("OpenCode Zen Models Smoke Test"
zenModels.forEach(model => {
it(`${model.id}`, async () => {
const response = await complete(model as Model<any>, {
const response = await complete(model as Model, {
messages: [{ role: "user", content: "Say hello.", timestamp: Date.now() }],
});
@@ -6,7 +6,8 @@ import { type Api, type KnownProvider, type Model, modelsAreEqual } from "@oh-my
import chalk from "chalk";
import { isValidThinkingLevel } from "../cli/args";
import { fuzzyMatch } from "../utils/fuzzy";
import type { ModelRegistry } from "./model-registry";
import { MODEL_ROLE_IDS, type ModelRegistry } from "./model-registry";
import type { Settings } from "./settings";
/** Default model IDs for each known provider */
export const defaultModelPerProvider: Record<KnownProvider, string> = {
@@ -310,6 +311,94 @@ export function parseModelPattern(
return parseModelPatternWithContext(pattern, availableModels, context);
}
const MODEL_ROLE_ALIAS_PREFIX = "pi/";
const DEFAULT_MODEL_ROLE = "default";
const DEFAULT_MODEL_ALIASES = new Set([DEFAULT_MODEL_ROLE, `${MODEL_ROLE_ALIAS_PREFIX}${DEFAULT_MODEL_ROLE}`]);
/**
* Check if a model override value is effectively the default role.
*/
export function isDefaultModelAlias(value: string | string[] | undefined): boolean {
if (!value) return true;
const values = Array.isArray(value) ? value : [value];
if (values.length === 0) return true;
return values.every(entry => DEFAULT_MODEL_ALIASES.has(entry.trim().toLowerCase()));
}
/**
* Expand a role alias like "pi/smol" to the configured model string.
*/
export function expandRoleAlias(value: string, settings?: Settings): string {
const normalized = value.trim().toLowerCase();
if (!normalized.startsWith(MODEL_ROLE_ALIAS_PREFIX)) return value;
const role = normalized.slice(MODEL_ROLE_ALIAS_PREFIX.length);
if (!MODEL_ROLE_IDS.includes(role as (typeof MODEL_ROLE_IDS)[number])) return value;
return settings?.getModelRole(role) ?? value;
}
/**
* Resolve a model identifier or pattern to a Model instance.
*/
export function resolveModelFromString(
value: string,
available: Model<Api>[],
matchPreferences?: ModelMatchPreferences,
): Model<Api> | undefined {
const parsed = parseModelString(value);
if (parsed) {
return available.find(model => model.provider === parsed.provider && model.id === parsed.id);
}
return parseModelPattern(value, available, matchPreferences).model;
}
/**
* Resolve a model from configured roles, honoring order and overrides.
*/
export function resolveModelFromSettings(options: {
settings: Settings;
availableModels: Model<Api>[];
matchPreferences?: ModelMatchPreferences;
roleOrder?: string[];
}): Model<Api> | undefined {
const { settings, availableModels, matchPreferences, roleOrder } = options;
const roles = roleOrder ?? MODEL_ROLE_IDS;
for (const role of roles) {
const configured = settings.getModelRole(role);
if (!configured) continue;
const resolved = resolveModelFromString(expandRoleAlias(configured, settings), availableModels, matchPreferences);
if (resolved) return resolved;
}
return availableModels[0];
}
/**
* Resolve a list of override patterns to the first matching model.
*/
export function resolveModelOverride(
modelPatterns: string[],
modelRegistry: ModelRegistry,
settings?: Settings,
): { model?: Model<Api>; thinkingLevel?: ThinkingLevel } {
if (modelPatterns.length === 0) return {};
const matchPreferences = { usageOrder: settings?.getStorage()?.getModelUsageOrder() };
for (const pattern of modelPatterns) {
const normalized = pattern.trim().toLowerCase();
if (!normalized || DEFAULT_MODEL_ALIASES.has(normalized)) {
continue;
}
const effectivePattern = expandRoleAlias(pattern, settings);
const { model, thinkingLevel } = parseModelPattern(
effectivePattern,
modelRegistry.getAvailable(),
matchPreferences,
);
if (model) {
return { model, thinkingLevel: thinkingLevel !== "off" ? thinkingLevel : undefined };
}
}
return {};
}
/**
* Resolve model patterns to actual Model objects with optional thinking levels
* Format: "pattern:level" where :level is optional
+4 -3
View File
@@ -13,6 +13,7 @@
import * as fs from "node:fs";
import * as path from "node:path";
import type { ModelRole } from "@oh-my-pi/pi-coding-agent/config/model-registry";
import { isEnoent, logger, procmgr } from "@oh-my-pi/pi-utils";
import { YAML } from "bun";
import { type Settings as SettingsCapabilityItem, settingsCapability } from "../capability/settings";
@@ -387,7 +388,7 @@ export class Settings {
/**
* Set a model role (helper for modelRoles record).
*/
setModelRole(role: string, modelId: string): void {
setModelRole(role: ModelRole | string, modelId: string): void {
const current = this.get("modelRoles");
this.set("modelRoles", { ...current, [role]: modelId });
}
@@ -395,7 +396,7 @@ export class Settings {
/**
* Get a model role (helper for modelRoles record).
*/
getModelRole(role: string): string | undefined {
getModelRole(role: ModelRole | string): string | undefined {
const roles = this.get("modelRoles");
return roles[role];
}
@@ -410,7 +411,7 @@ export class Settings {
/*
* Override model roles (helper for modelRoles record).
*/
overrideModelRoles(roles: Record<string, string>): void {
overrideModelRoles(roles: ReadOnlyDict<string>): void {
const prev = this.get("modelRoles");
for (const [role, modelId] of Object.entries(roles)) {
if (modelId) {
@@ -51,7 +51,7 @@ export interface CustomToolContext {
/** Model registry - use for API key resolution and model retrieval */
modelRegistry: ModelRegistry;
/** Current model (may be undefined if no model is selected yet) */
model: Model<any> | undefined;
model: Model | undefined;
/** Whether the agent is idle (not streaming) */
isIdle(): boolean;
/** Whether there are queued messages waiting to be processed */
@@ -206,7 +206,7 @@ class ConcreteExtensionAPI implements ExtensionAPI, IExtensionRuntime {
return this.runtime.setActiveTools(toolNames);
}
setModel(model: Model<any>): Promise<boolean> {
setModel(model: Model): Promise<boolean> {
return this.runtime.setModel(model);
}
@@ -112,7 +112,7 @@ export class ExtensionRunner {
private sessionManager: SessionManager;
private modelRegistry: ModelRegistry;
private errorListeners: Set<ExtensionErrorListener> = new Set();
private getModel: () => Model<any> | undefined = () => undefined;
private getModel: () => Model | undefined = () => undefined;
private isIdleFn: () => boolean = () => true;
private waitForIdleFn: () => Promise<void> = async () => {};
private abortFn: () => void = () => {};
@@ -162,7 +162,7 @@ export interface ExtensionContext {
/** Model registry for API key resolution */
modelRegistry: ModelRegistry;
/** Current model (may be undefined) */
model: Model<any> | undefined;
model: Model | undefined;
/** Whether the agent is idle (not streaming) */
isIdle(): boolean;
/** Abort the current agent operation */
@@ -776,7 +776,7 @@ export interface ExtensionAPI {
setActiveTools(toolNames: string[]): Promise<void>;
/** Set the current model. Returns false if no API key available. */
setModel(model: Model<any>): Promise<boolean>;
setModel(model: Model): Promise<boolean>;
/** Get current thinking level. */
getThinkingLevel(): ThinkingLevel;
@@ -835,7 +835,7 @@ export type GetAllToolsHandler = () => string[];
export type SetActiveToolsHandler = (toolNames: string[]) => Promise<void>;
export type SetModelHandler = (model: Model<any>) => Promise<boolean>;
export type SetModelHandler = (model: Model) => Promise<boolean>;
export type GetThinkingLevelHandler = () => ThinkingLevel;
@@ -862,7 +862,7 @@ export interface ExtensionActions {
/** Actions for ExtensionContext (ctx.* in event handlers). */
export interface ExtensionContextActions {
getModel: () => Model<any> | undefined;
getModel: () => Model | undefined;
isIdle: () => boolean;
abort: () => void;
hasPendingMessages: () => boolean;
@@ -69,7 +69,7 @@ export class HookRunner {
private sessionManager: SessionManager;
private modelRegistry: ModelRegistry;
private errorListeners: Set<HookErrorListener> = new Set();
private getModel: () => Model<any> | undefined = () => undefined;
private getModel: () => Model | undefined = () => undefined;
private isIdleFn: () => boolean = () => true;
private waitForIdleFn: () => Promise<void> = async () => {};
private abortFn: () => void = () => {};
@@ -93,7 +93,7 @@ export class HookRunner {
*/
initialize(options: {
/** Function to get the current model */
getModel: () => Model<any> | undefined;
getModel: () => Model | undefined;
/** Handler for hooks to send messages */
sendMessageHandler: SendMessageHandler;
/** Handler for hooks to append entries */
@@ -147,7 +147,7 @@ export interface HookContext {
/** Model registry - use for API key resolution and model retrieval */
modelRegistry: ModelRegistry;
/** Current model (may be undefined if no model is selected yet) */
model: Model<any> | undefined;
model: Model | undefined;
/** Whether the agent is idle (not streaming) */
isIdle(): boolean;
/** Abort the current agent operation (fire-and-forget, does not wait) */
@@ -27,11 +27,11 @@ function makeInvertedBadge(label: string, color: ThemeColor): string {
interface ModelItem {
provider: string;
id: string;
model: Model<any>;
model: Model;
}
interface ScopedModelItem {
model: Model<any>;
model: Model;
thinkingLevel: string;
}
@@ -69,10 +69,10 @@ export class ModelSelectorComponent extends Container {
private allModels: ModelItem[] = [];
private filteredModels: ModelItem[] = [];
private selectedIndex: number = 0;
private roles: { [key in ModelRole]?: Model<any> } = {};
private roles: { [key in ModelRole]?: Model } = {};
private settings: Settings;
private modelRegistry: ModelRegistry;
private onSelectCallback: (model: Model<any>, role: string) => void;
private onSelectCallback: (model: Model, role: ModelRole | null) => void;
private onCancelCallback: () => void;
private errorMessage?: string;
private tui: TUI;
@@ -89,11 +89,11 @@ export class ModelSelectorComponent extends Container {
constructor(
tui: TUI,
_currentModel: Model<any> | undefined,
_currentModel: Model | undefined,
settings: Settings,
modelRegistry: ModelRegistry,
scopedModels: ReadonlyArray<ScopedModelItem>,
onSelect: (model: Model<any>, role: string) => void,
onSelect: (model: Model, role: ModelRole | null) => void,
onCancel: () => void,
options?: { temporaryOnly?: boolean; initialSearchInput?: string },
) {
@@ -246,7 +246,7 @@ export class ModelSelectorComponent extends Container {
// Load available models (built-in models still work even if models.json failed)
try {
const availableModels = this.modelRegistry.getAvailable();
models = availableModels.map((model: Model<any>) => ({
models = availableModels.map((model: Model) => ({
provider: model.provider,
id: model.id,
model,
@@ -542,10 +542,10 @@ export class ModelSelectorComponent extends Container {
}
}
private handleSelect(model: Model<any>, role: ModelRole | null): void {
private handleSelect(model: Model, role: ModelRole | null): void {
// For temporary role, don't save to settings - just notify caller
if (role === null) {
this.onSelectCallback(model, "temporary");
this.onSelectCallback(model, null);
return;
}
@@ -137,7 +137,7 @@ export class InteractiveMode implements InteractiveModeContext {
private readonly version: string;
private readonly changelogMarkdown: string | undefined;
private planModePreviousTools: string[] | undefined;
private planModePreviousModel: Model<any> | undefined;
private planModePreviousModel: Model | undefined;
private planModeHasEntered = false;
public readonly lspServers:
| Array<{ name: string; status: "ready" | "error"; fileTypes: string[]; error?: string }>
@@ -68,7 +68,7 @@ export type RpcCommand =
// ============================================================================
export interface RpcSessionState {
model?: Model<any>;
model?: Model;
thinkingLevel: ThinkingLevel;
isStreaming: boolean;
isCompacting: boolean;
@@ -105,21 +105,21 @@ export type RpcResponse =
type: "response";
command: "set_model";
success: true;
data: Model<any>;
data: Model;
}
| {
id?: string;
type: "response";
command: "cycle_model";
success: true;
data: { model: Model<any>; thinkingLevel: ThinkingLevel; isScoped: boolean } | null;
data: { model: Model; thinkingLevel: ThinkingLevel; isScoped: boolean } | null;
}
| {
id?: string;
type: "response";
command: "get_available_models";
success: true;
data: { models: Model<any>[] };
data: { models: Model[] };
}
// Thinking
+2 -2
View File
@@ -131,11 +131,11 @@ export interface CreateAgentSessionOptions {
modelRegistry?: ModelRegistry;
/** Model to use. Default: from settings, else first available */
model?: Model<any>;
model?: Model;
/** Thinking level. Default: from settings, else 'off' (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; thinkingLevel: ThinkingLevel }>;
/** System prompt. String replaces default, function receives default and returns final. */
systemPrompt?: string | ((defaultPrompt: string) => string);
@@ -127,7 +127,7 @@ export interface AgentSessionConfig {
sessionManager: SessionManager;
settings: Settings;
/** Models to cycle through with Ctrl+P (from --models flag) */
scopedModels?: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;
scopedModels?: Array<{ model: Model; thinkingLevel: ThinkingLevel }>;
/** Prompt templates for expansion */
promptTemplates?: PromptTemplate[];
/** File-based slash commands for expansion */
@@ -167,7 +167,7 @@ export interface PromptOptions {
/** Result from cycleModel() */
export interface ModelCycleResult {
model: Model<any>;
model: Model;
thinkingLevel: ThinkingLevel;
/** Whether cycling through scoped models (--models flag) or all available */
isScoped: boolean;
@@ -175,9 +175,9 @@ export interface ModelCycleResult {
/** Result from cycleRoleModels() */
export interface RoleModelCycleResult {
model: Model<any>;
model: Model;
thinkingLevel: ThinkingLevel;
role: string;
role: ModelRole;
}
/** Session statistics for /session command */
@@ -257,7 +257,7 @@ export class AgentSession {
readonly sessionManager: SessionManager;
readonly settings: Settings;
private _scopedModels: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;
private _scopedModels: Array<{ model: Model; thinkingLevel: ThinkingLevel }>;
private _promptTemplates: PromptTemplate[];
private _slashCommands: FileSlashCommand[];
@@ -887,7 +887,7 @@ export class AgentSession {
}
/** Current model (may be undefined if not yet selected) */
get model(): Model<any> | undefined {
get model(): Model | undefined {
return this.agent.state.model;
}
@@ -994,7 +994,7 @@ export class AgentSession {
}
/** Scoped models for cycling (from --models flag) */
get scopedModels(): ReadonlyArray<{ model: Model<any>; thinkingLevel: ThinkingLevel }> {
get scopedModels(): ReadonlyArray<{ model: Model; thinkingLevel: ThinkingLevel }> {
return this._scopedModels;
}
@@ -1014,7 +1014,7 @@ export class AgentSession {
this._planReferenceSent = true;
}
resolveRoleModel(role: ModelRole): Model<any> | undefined {
resolveRoleModel(role: ModelRole): Model | undefined {
return this._resolveRoleModel(role, this._modelRegistry.getAvailable(), this.model);
}
@@ -1800,7 +1800,7 @@ export class AgentSession {
* Validates API key, saves to session and settings.
* @throws Error if no API key available for the model
*/
async setModel(model: Model<any>, role: string = "default"): Promise<void> {
async setModel(model: Model, role: ModelRole = "default"): Promise<void> {
const apiKey = await this._modelRegistry.getApiKey(model, this.sessionId);
if (!apiKey) {
throw new Error(`No API key for ${model.provider}/${model.id}`);
@@ -1820,7 +1820,7 @@ export class AgentSession {
* Validates API key, saves to session log but NOT to settings.
* @throws Error if no API key available for the model
*/
async setModelTemporary(model: Model<any>): Promise<void> {
async setModelTemporary(model: Model): Promise<void> {
const apiKey = await this._modelRegistry.getApiKey(model, this.sessionId);
if (!apiKey) {
throw new Error(`No API key for ${model.provider}/${model.id}`);
@@ -1854,7 +1854,7 @@ export class AgentSession {
* @param options - Optional settings: `temporary` to not persist to settings
*/
async cycleRoleModels(
roleOrder: string[],
roleOrder: ModelRole[],
options?: { temporary?: boolean },
): Promise<RoleModelCycleResult | undefined> {
const availableModels = this._modelRegistry.getAvailable();
@@ -1862,7 +1862,7 @@ export class AgentSession {
const currentModel = this.model;
if (!currentModel) return undefined;
const roleModels: Array<{ role: string; model: Model<any> }> = [];
const roleModels: Array<{ role: ModelRole; model: Model }> = [];
for (const role of roleOrder) {
const roleModelStr =
@@ -1872,7 +1872,7 @@ export class AgentSession {
if (!roleModelStr) continue;
const parsed = parseModelString(roleModelStr);
let match: Model<any> | undefined;
let match: Model | undefined;
if (parsed) {
match = availableModels.find(m => m.provider === parsed.provider && m.id === parsed.id);
}
@@ -1964,7 +1964,7 @@ export class AgentSession {
/**
* Get all available models with valid API keys.
*/
getAvailableModels(): Model<any>[] {
getAvailableModels(): Model[] {
return this._modelRegistry.getAvailable();
}
@@ -2530,15 +2530,15 @@ Be thorough - include exact file paths, function names, error messages, and tech
this.agent.continue().catch(() => {});
}
private _getModelKey(model: Model<any>): string {
private _getModelKey(model: Model): string {
return `${model.provider}/${model.id}`;
}
private _resolveRoleModel(
role: ModelRole,
availableModels: Model<any>[],
currentModel: Model<any> | undefined,
): Model<any> | undefined {
availableModels: Model[],
currentModel: Model | undefined,
): Model | undefined {
const roleModelStr =
role === "default"
? (this.settings.getModelRole("default") ??
@@ -2555,11 +2555,11 @@ Be thorough - include exact file paths, function names, error messages, and tech
return availableModels.find(m => m.id.toLowerCase() === roleLower);
}
private _getCompactionModelCandidates(availableModels: Model<any>[]): Model<any>[] {
const candidates: Model<any>[] = [];
private _getCompactionModelCandidates(availableModels: Model[]): Model[] {
const candidates: Model[] = [];
const seen = new Set<string>();
const addCandidate = (model: Model<any> | undefined): void => {
const addCandidate = (model: Model | undefined): void => {
if (!model) return;
const key = this._getModelKey(model);
if (seen.has(key)) return;
@@ -66,7 +66,7 @@ export interface CollectEntriesResult {
export interface GenerateBranchSummaryOptions {
/** Model to use for summarization */
model: Model<any>;
model: Model;
/** API key for the model */
apiKey: string;
/** Abort signal for cancellation */
@@ -478,7 +478,7 @@ export interface SummaryOptions {
export async function generateSummary(
currentMessages: AgentMessage[],
model: Model<any>,
model: Model,
reserveTokens: number,
apiKey: string,
signal?: AbortSignal,
@@ -547,7 +547,7 @@ export async function generateSummary(
async function generateShortSummary(
recentMessages: AgentMessage[],
historySummary: string | undefined,
model: Model<any>,
model: Model,
reserveTokens: number,
apiKey: string,
signal?: AbortSignal,
@@ -724,7 +724,7 @@ const TURN_PREFIX_SUMMARIZATION_PROMPT = renderPromptTemplate(compactionTurnPref
*/
export async function compact(
preparation: CompactionPreparation,
model: Model<any>,
model: Model,
apiKey: string,
customInstructions?: string,
signal?: AbortSignal,
@@ -822,7 +822,7 @@ export async function compact(
*/
async function generateTurnPrefixSummary(
messages: AgentMessage[],
model: Model<any>,
model: Model,
reserveTokens: number,
apiKey: string,
signal?: AbortSignal,
+1 -2
View File
@@ -39,7 +39,6 @@ import {
TASK_SUBAGENT_PROGRESS_CHANNEL,
} from "./types";
const DEFAULT_MODEL_ALIASES = new Set(["default", "pi/default"]);
const MCP_CALL_TIMEOUT_MS = 60_000;
const ajv = new Ajv({ allErrors: true, strict: false });
@@ -138,7 +137,7 @@ function resolveModelOverride(
const matchPreferences = { usageOrder: settings?.getStorage()?.getModelUsageOrder() };
for (const pattern of modelPatterns) {
const normalized = pattern.trim().toLowerCase();
if (!normalized || DEFAULT_MODEL_ALIASES.has(normalized)) {
if (!normalized || normalized === "default" || normalized === "pi/default") {
continue;
}
let effectivePattern = pattern;
@@ -156,7 +156,7 @@ describe.skipIf(!HAS_ANTHROPIC_AUTH)("Compaction with thinking models (Anthropic
}
});
async function createSession(model: Model<any>, thinkingLevel: ThinkingLevel = "high") {
async function createSession(model: Model, thinkingLevel: ThinkingLevel = "high") {
const toolSession: ToolSession = {
cwd: tempDir,
hasUI: false,