-
Notifications
You must be signed in to change notification settings - Fork 4
feat: add model mapping configuration #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| { | ||
| "mock-gpt-thinking": "custom-gpt-mini", | ||
| "gpt-4-mock": "custom-gpt-pro", | ||
| "mock-gpt-markdown": "custom-gpt-markdown", | ||
| "gpt-4o-image": "custom-dalle", | ||
| "mock-claude-markdown": "custom-claude-pro", | ||
| "gemini-1.5-pro": "custom-gemini-pro", | ||
| "gemini-1.5-flash": "custom-gemini-flash", | ||
| "gemini-pro": "custom-gemini-basic", | ||
| "gemini-pro-vision": "custom-gemini-vision" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| { | ||
| "mock-gpt-thinking": "gpt-4o-mini", | ||
| "mock-gpt-thinking-tag": "gpt-4o-mini", | ||
| "gpt-4-mock": "gpt-4-turbo", | ||
| "mock-gpt-markdown": "gpt-4o", | ||
| "gpt-4o-image": "dall-e-3", | ||
| "mock-claude-markdown": "claude-3-opus-20240229", | ||
| "gemini-1.5-pro": "gemini-2.0-pro-exp-2025-01-15", | ||
| "gemini-1.5-flash": "gemini-2.0-flash-exp-2025-01-15", | ||
| "gemini-pro": "gemini-pro-1.0", | ||
| "gemini-pro-vision": "gemini-pro-vision-1.0" | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,60 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import fs from 'fs'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import path from 'path'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| interface ModelMappingConfig { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [originalModel: string]: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let modelMapping: ModelMappingConfig = {}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let configLoaded = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const CONFIG_FILE_PATH = process.env.MODEL_MAPPING_CONFIG || path.join(process.cwd(), 'model-mapping.json'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function loadModelMapping(configPath?: string): void { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (configLoaded) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const configFilePath = configPath || CONFIG_FILE_PATH; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (fs.existsSync(configFilePath)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const configContent = fs.readFileSync(configFilePath, 'utf-8'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const config = JSON.parse(configContent); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof config === 'object' && config !== null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| modelMapping = config; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(`✅ Loaded model mapping configuration from ${configFilePath}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(`📋 Model mappings: ${Object.keys(modelMapping).length} mappings configured`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (Object.keys(modelMapping).length > 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Object.entries(modelMapping).forEach(([original, mapped]) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(` • ${original} → ${mapped}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+20
to
+36
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Validate mapping shape; reject/skip non-string values to avoid runtime surprises. Currently any JSON object is accepted. Guard against arrays and non-string values; log warnings for skipped entries. - if (typeof config === 'object' && config !== null) {
- modelMapping = config;
+ if (typeof config === 'object' && config !== null && !Array.isArray(config)) {
+ const next: ModelMappingConfig = {};
+ for (const [k, v] of Object.entries(config as Record<string, unknown>)) {
+ if (typeof k === 'string' && typeof v === 'string') {
+ next[k] = v;
+ } else {
+ console.warn(`⚠️ Skipping invalid mapping entry: ${String(k)} → ${String(v)}`);
+ }
+ }
+ modelMapping = next;🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(`ℹ️ No model mapping configuration found at ${configFilePath}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error(`❌ Failed to load model mapping configuration: ${error}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| configLoaded = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+13
to
+44
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don’t set configLoaded=true on failure; allows second attempt with another path. If the first call points to a non-existent or invalid file, export function loadModelMapping(configPath?: string): void {
if (configLoaded) {
return;
}
const configFilePath = configPath || CONFIG_FILE_PATH;
try {
if (fs.existsSync(configFilePath)) {
const configContent = fs.readFileSync(configFilePath, 'utf-8');
const config = JSON.parse(configContent);
- if (typeof config === 'object' && config !== null) {
- modelMapping = config;
+ if (typeof config === 'object' && config !== null) {
+ modelMapping = config;
console.log(`✅ Loaded model mapping configuration from ${configFilePath}`);
console.log(`📋 Model mappings: ${Object.keys(modelMapping).length} mappings configured`);
if (Object.keys(modelMapping).length > 0) {
Object.entries(modelMapping).forEach(([original, mapped]) => {
console.log(` • ${original} → ${mapped}`);
});
}
+ configLoaded = true;
}
} else {
console.log(`ℹ️ No model mapping configuration found at ${configFilePath}`);
}
} catch (error) {
console.error(`❌ Failed to load model mapping configuration: ${error}`);
}
-
- configLoaded = true;
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function getMappedModelName(originalModel: string): string { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return modelMapping[originalModel] || originalModel; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function getOriginalModelName(mappedModel: string): string | undefined { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Object.keys(modelMapping).find(key => modelMapping[key] === mappedModel); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function getAllMappings(): ModelMappingConfig { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { ...modelMapping }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function hasMappings(): boolean { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Object.keys(modelMapping).length > 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| import { MockModel } from "../types/index"; | ||
| import { anthropicMockModels } from "../data/anthropicMockData"; | ||
| import { ErrorResponse, StreamingEvent } from "../types/anthropic"; | ||
| import { getMappedModelName } from "../config/modelMapping"; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Anthropic model lookup also uses the wrong mapping direction Same issue as Gemini: external IDs won’t resolve. Switch to reverse lookup first, keep direct and forward as fallbacks. -import { getMappedModelName } from "../config/modelMapping";
+import { getMappedModelName, getOriginalModelName } from "../config/modelMapping";
@@
export function findModelById(modelId: string): MockModel | undefined {
- const mappedModelId = getMappedModelName(modelId);
- return anthropicMockModels.find(model => model.id === mappedModelId);
+ // 1) direct
+ const direct = anthropicMockModels.find(model => model.id === modelId);
+ if (direct) return direct;
+ // 2) external -> internal
+ const originalId = getOriginalModelName(modelId);
+ if (originalId) return anthropicMockModels.find(model => model.id === originalId);
+ // 3) internal -> external (unlikely to hit)
+ const mappedId = getMappedModelName(modelId);
+ return anthropicMockModels.find(model => model.id === mappedId);
}Also applies to: 31-33 🤖 Prompt for AI Agents |
||
|
|
||
| /** | ||
| * Get current timestamp | ||
|
|
@@ -27,7 +28,8 @@ export function calculateTokens(text: string): number { | |
| * Find model by ID | ||
| */ | ||
| export function findModelById(modelId: string): MockModel | undefined { | ||
| return anthropicMockModels.find(model => model.id === modelId); | ||
| const mappedModelId = getMappedModelName(modelId); | ||
| return anthropicMockModels.find(model => model.id === mappedModelId); | ||
| } | ||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| import { geminiMockModels } from '../data/geminiMockData'; | ||
| import { getMappedModelName } from '../config/modelMapping'; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wrong mapping direction causes lookups to fail for external names getMappedModelName maps internal->external. For requests that send external (mapped) IDs, this returns the external again, so the lookup misses. Use getOriginalModelName first, with sensible fallbacks. -import { getMappedModelName } from '../config/modelMapping';
+import { getMappedModelName, getOriginalModelName } from '../config/modelMapping';
@@
export function findGeminiModelById(modelId: string) {
// Remove 'models/' prefix if present
const cleanModelId = modelId.replace('models/', '');
- const mappedModelId = getMappedModelName(cleanModelId);
- return geminiMockModels.find(model => model.id === mappedModelId);
+ // 1) direct hit
+ const direct = geminiMockModels.find(model => model.id === cleanModelId);
+ if (direct) return direct;
+ // 2) external -> internal
+ const originalId = getOriginalModelName(cleanModelId);
+ if (originalId) return geminiMockModels.find(model => model.id === originalId);
+ // 3) last resort: internal -> external (unlikely to match, but harmless)
+ const mappedId = getMappedModelName(cleanModelId);
+ return geminiMockModels.find(model => model.id === mappedId);
}Also applies to: 33-35 🤖 Prompt for AI Agents |
||
|
|
||
| /** | ||
| * Get current timestamp | ||
|
|
@@ -29,7 +30,8 @@ export function generateModelName(): string { | |
| export function findGeminiModelById(modelId: string) { | ||
| // Remove 'models/' prefix if present | ||
| const cleanModelId = modelId.replace('models/', ''); | ||
| return geminiMockModels.find(model => model.id === cleanModelId); | ||
| const mappedModelId = getMappedModelName(cleanModelId); | ||
| return geminiMockModels.find(model => model.id === mappedModelId); | ||
| } | ||
|
|
||
| /** | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update the CLI options table to include --config.
The new option exists in src/cli.ts but is missing from the README table; users will miss it.
📝 Committable suggestion
🧰 Tools
🪛 LanguageTool
[grammar] ~491-~491: There might be a mistake here.
Context: ... internal model names to external names for better user experience. **Example mode...
(QB_NEW_EN)
🤖 Prompt for AI Agents