fix(copilot): use gpt-4.1 as default model and 127.0.0.1 for local connections

Key changes:
- Changed default model from claude-sonnet-4.5 to gpt-4.1 (free tier compatible)
- Updated all Claude models to minPlan: 'pro' (requires paid Copilot subscription)
- Replaced 'localhost' with '127.0.0.1' for more reliable local connections
  (bypasses DNS resolution and potential IPv6 issues)
- Updated UI presets: replaced Claude Haiku with Raptor Mini in free tier
- Fixed FREE_PRESETS to only include actually free models

This fixes the "model_not_supported" error when using free tier GitHub Copilot
subscription, which doesn't have access to Claude models.
This commit is contained in:
kaitranntt
2025-12-18 04:58:49 -05:00
parent 2c6dfe746b
commit ec6face8db
6 changed files with 31 additions and 17 deletions
+2 -1
View File
@@ -253,6 +253,7 @@ export interface SecretsConfig {
/** /**
* Default Copilot configuration. * Default Copilot configuration.
* Strictly opt-in - disabled by default. * Strictly opt-in - disabled by default.
* Uses gpt-4.1 as default model (free tier compatible).
*/ */
export const DEFAULT_COPILOT_CONFIG: CopilotConfig = { export const DEFAULT_COPILOT_CONFIG: CopilotConfig = {
enabled: false, enabled: false,
@@ -261,7 +262,7 @@ export const DEFAULT_COPILOT_CONFIG: CopilotConfig = {
account_type: 'individual', account_type: 'individual',
rate_limit: null, rate_limit: null,
wait_on_limit: true, wait_on_limit: true,
model: 'claude-sonnet-4.5', model: 'gpt-4.1', // Free tier compatible
}; };
/** /**
+2 -1
View File
@@ -17,12 +17,13 @@ const PID_FILE = path.join(getCopilotDir(), 'daemon.pid');
/** /**
* Check if copilot-api daemon is running on the specified port. * Check if copilot-api daemon is running on the specified port.
* Uses 127.0.0.1 instead of localhost for more reliable local connections.
*/ */
export async function isDaemonRunning(port: number): Promise<boolean> { export async function isDaemonRunning(port: number): Promise<boolean> {
return new Promise((resolve) => { return new Promise((resolve) => {
const req = http.request( const req = http.request(
{ {
hostname: 'localhost', hostname: '127.0.0.1',
port, port,
path: '/usage', path: '/usage',
method: 'GET', method: 'GET',
+3 -1
View File
@@ -40,8 +40,10 @@ export function generateCopilotEnv(config: CopilotConfig): Record<string, string
const sonnetModel = config.sonnet_model || config.model; const sonnetModel = config.sonnet_model || config.model;
const haikuModel = config.haiku_model || config.model; const haikuModel = config.haiku_model || config.model;
// Use 127.0.0.1 instead of localhost for more reliable local connections
// (bypasses DNS resolution and potential IPv6 issues)
return { return {
ANTHROPIC_BASE_URL: `http://localhost:${config.port}`, ANTHROPIC_BASE_URL: `http://127.0.0.1:${config.port}`,
ANTHROPIC_AUTH_TOKEN: 'dummy', // copilot-api handles auth internally ANTHROPIC_AUTH_TOKEN: 'dummy', // copilot-api handles auth internally
ANTHROPIC_MODEL: config.model, ANTHROPIC_MODEL: config.model,
// Model tier mapping - allows different models for opus/sonnet/haiku // Model tier mapping - allows different models for opus/sonnet/haiku
+15 -7
View File
@@ -18,12 +18,11 @@ import { CopilotModel } from './types';
* Multipliers: 0 = free tier, 0.25-0.33 = cheap, 1 = standard, 3-10 = premium * Multipliers: 0 = free tier, 0.25-0.33 = cheap, 1 = standard, 3-10 = premium
*/ */
export const DEFAULT_COPILOT_MODELS: CopilotModel[] = [ export const DEFAULT_COPILOT_MODELS: CopilotModel[] = [
// Anthropic Models // Anthropic Models - All require paid Copilot subscription
{ {
id: 'claude-sonnet-4.5', id: 'claude-sonnet-4.5',
name: 'Claude Sonnet 4.5', name: 'Claude Sonnet 4.5',
provider: 'anthropic', provider: 'anthropic',
isDefault: true,
minPlan: 'pro', minPlan: 'pro',
multiplier: 1, multiplier: 1,
}, },
@@ -53,7 +52,7 @@ export const DEFAULT_COPILOT_MODELS: CopilotModel[] = [
id: 'claude-haiku-4.5', id: 'claude-haiku-4.5',
name: 'Claude Haiku 4.5', name: 'Claude Haiku 4.5',
provider: 'anthropic', provider: 'anthropic',
minPlan: 'free', minPlan: 'pro', // Requires paid Copilot subscription
multiplier: 0.33, multiplier: 0.33,
}, },
@@ -93,7 +92,14 @@ export const DEFAULT_COPILOT_MODELS: CopilotModel[] = [
}, },
{ id: 'gpt-5', name: 'GPT-5', provider: 'openai', minPlan: 'pro', multiplier: 1 }, { id: 'gpt-5', name: 'GPT-5', provider: 'openai', minPlan: 'pro', multiplier: 1 },
{ id: 'gpt-5-mini', name: 'GPT-5 Mini', provider: 'openai', minPlan: 'free', multiplier: 0 }, { id: 'gpt-5-mini', name: 'GPT-5 Mini', provider: 'openai', minPlan: 'free', multiplier: 0 },
{ id: 'gpt-4.1', name: 'GPT-4.1', provider: 'openai', minPlan: 'free', multiplier: 0 }, {
id: 'gpt-4.1',
name: 'GPT-4.1',
provider: 'openai',
isDefault: true,
minPlan: 'free',
multiplier: 0,
},
// Google Models // Google Models
{ {
@@ -150,7 +156,8 @@ export async function fetchModelsFromDaemon(port: number): Promise<CopilotModel[
return new Promise((resolve) => { return new Promise((resolve) => {
const req = http.request( const req = http.request(
{ {
hostname: 'localhost', // Use 127.0.0.1 instead of localhost for more reliable local connections
hostname: '127.0.0.1',
port, port,
path: '/v1/models', path: '/v1/models',
method: 'GET', method: 'GET',
@@ -171,7 +178,7 @@ export async function fetchModelsFromDaemon(port: number): Promise<CopilotModel[
id: m.id, id: m.id,
name: formatModelName(m.id), name: formatModelName(m.id),
provider: detectProvider(m.id), provider: detectProvider(m.id),
isDefault: m.id === 'claude-sonnet-4.5', isDefault: m.id === 'gpt-4.1', // Free tier default
})); }));
resolve(models.length > 0 ? models : DEFAULT_COPILOT_MODELS); resolve(models.length > 0 ? models : DEFAULT_COPILOT_MODELS);
} else { } else {
@@ -206,9 +213,10 @@ export async function getAvailableModels(port: number): Promise<CopilotModel[]>
/** /**
* Get the default model. * Get the default model.
* Uses gpt-4.1 as it's available on free tier.
*/ */
export function getDefaultModel(): string { export function getDefaultModel(): string {
return 'claude-sonnet-4.5'; return 'gpt-4.1';
} }
/** /**
+2 -1
View File
@@ -1826,9 +1826,10 @@ apiRoutes.get('/copilot/settings/raw', (_req: Request, res: Response): void => {
// If file doesn't exist, return default structure with all model mappings // If file doesn't exist, return default structure with all model mappings
if (!fs.existsSync(settingsPath)) { if (!fs.existsSync(settingsPath)) {
// Create settings structure matching CLIProxy pattern - always include all model mappings // Create settings structure matching CLIProxy pattern - always include all model mappings
// Use 127.0.0.1 instead of localhost for more reliable local connections
const defaultSettings = { const defaultSettings = {
env: { env: {
ANTHROPIC_BASE_URL: `http://localhost:${copilotConfig.port}`, ANTHROPIC_BASE_URL: `http://127.0.0.1:${copilotConfig.port}`,
ANTHROPIC_AUTH_TOKEN: 'copilot-managed', ANTHROPIC_AUTH_TOKEN: 'copilot-managed',
ANTHROPIC_MODEL: defaultModel, ANTHROPIC_MODEL: defaultModel,
ANTHROPIC_DEFAULT_OPUS_MODEL: copilotConfig.opus_model || defaultModel, ANTHROPIC_DEFAULT_OPUS_MODEL: copilotConfig.opus_model || defaultModel,
@@ -39,6 +39,7 @@ const CodeEditor = lazy(() =>
// Model presets for quick configuration // Model presets for quick configuration
// Grouped by tier: Free (available to all) and Paid (requires Pro+) // Grouped by tier: Free (available to all) and Paid (requires Pro+)
// Note: ALL Claude models require paid Copilot subscription
const FREE_PRESETS = [ const FREE_PRESETS = [
{ {
name: 'GPT-4.1 (Free)', name: 'GPT-4.1 (Free)',
@@ -57,12 +58,12 @@ const FREE_PRESETS = [
haiku: 'gpt-5-mini', haiku: 'gpt-5-mini',
}, },
{ {
name: 'Claude Haiku 4.5 (Free)', name: 'Raptor Mini (Free)',
description: 'Free tier - fast Anthropic model', description: 'Free tier - fine-tuned for coding',
default: 'claude-haiku-4.5', default: 'raptor-mini',
opus: 'claude-haiku-4.5', opus: 'raptor-mini',
sonnet: 'claude-haiku-4.5', sonnet: 'raptor-mini',
haiku: 'claude-haiku-4.5', haiku: 'raptor-mini',
}, },
]; ];