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:
@@ -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[];
|
||||
|
||||
@@ -246,7 +246,7 @@ export class Agent {
|
||||
this._state.systemPrompt = v;
|
||||
}
|
||||
|
||||
setModel(m: Model<any>) {
|
||||
setModel(m: Model) {
|
||||
this._state.model = m;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 () => {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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] = {};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user