Skip to content

Commit 47eb502

Browse files
committed
feat: implement findEndpointModel function to enhance claude model mapping
1 parent ca2c7f9 commit 47eb502

3 files changed

Lines changed: 81 additions & 7 deletions

File tree

src/lib/models.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import type { Model } from "~/services/copilot/get-models"
2+
3+
import { state } from "~/lib/state"
4+
5+
export const findEndpointModel = (sdkModelId: string): Model | undefined => {
6+
const models = state.models?.data ?? []
7+
const exactMatch = models.find((m) => m.id === sdkModelId)
8+
if (exactMatch) {
9+
return exactMatch
10+
}
11+
12+
const normalized = _normalizeSdkModelId(sdkModelId)
13+
if (!normalized) {
14+
return undefined
15+
}
16+
17+
const modelName = `claude-${normalized.family}-${normalized.version}`
18+
const model = models.find((m) => m.id === modelName)
19+
if (model) {
20+
return model
21+
}
22+
23+
return undefined
24+
}
25+
26+
/**
27+
* Normalizes an SDK model ID to extract the model family and version.
28+
* this method from github copilot extension
29+
* Examples:
30+
* - "claude-opus-4-5-20251101" -> { family: "opus", version: "4.5" }
31+
* - "claude-3-5-sonnet-20241022" -> { family: "sonnet", version: "3.5" }
32+
* - "claude-sonnet-4-20250514" -> { family: "sonnet", version: "4" }
33+
* - "claude-haiku-3-5-20250514" -> { family: "haiku", version: "3.5" }
34+
* - "claude-haiku-4.5" -> { family: "haiku", version: "4.5" }
35+
*/
36+
const _normalizeSdkModelId = (
37+
sdkModelId: string,
38+
): { family: string; version: string } | undefined => {
39+
const lower = sdkModelId.toLowerCase()
40+
41+
// Strip date suffix (8 digits at the end)
42+
const withoutDate = lower.replace(/-\d{8}$/, "")
43+
44+
// Pattern 1: claude-{family}-{major}-{minor} (e.g., claude-opus-4-5, claude-haiku-3-5)
45+
const pattern1 = withoutDate.match(/^claude-(\w+)-(\d+)-(\d+)$/)
46+
if (pattern1) {
47+
return { family: pattern1[1], version: `${pattern1[2]}.${pattern1[3]}` }
48+
}
49+
50+
// Pattern 2: claude-{major}-{minor}-{family} (e.g., claude-3-5-sonnet)
51+
const pattern2 = withoutDate.match(/^claude-(\d+)-(\d+)-(\w+)$/)
52+
if (pattern2) {
53+
return { family: pattern2[3], version: `${pattern2[1]}.${pattern2[2]}` }
54+
}
55+
56+
// Pattern 3: claude-{family}-{major}.{minor} (e.g., claude-haiku-4.5)
57+
const pattern3 = withoutDate.match(/^claude-(\w+)-(\d+)\.(\d+)$/)
58+
if (pattern3) {
59+
return { family: pattern3[1], version: `${pattern3[2]}.${pattern3[3]}` }
60+
}
61+
62+
// Pattern 4: claude-{family}-{major} (e.g., claude-sonnet-4)
63+
const pattern4 = withoutDate.match(/^claude-(\w+)-(\d+)$/)
64+
if (pattern4) {
65+
return { family: pattern4[1], version: pattern4[2] }
66+
}
67+
68+
// Pattern 5: claude-{major}-{family} (e.g., claude-3-opus)
69+
const pattern5 = withoutDate.match(/^claude-(\d+)-(\w+)$/)
70+
if (pattern5) {
71+
return { family: pattern5[2], version: pattern5[1] }
72+
}
73+
74+
return undefined
75+
}

src/routes/messages/count-tokens-handler.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import type { Context } from "hono"
22

33
import consola from "consola"
44

5-
import { state } from "~/lib/state"
65
import { getTokenCount } from "~/lib/tokenizer"
76

7+
import { findEndpointModel } from "../../lib/models"
88
import { type AnthropicMessagesPayload } from "./anthropic-types"
99
import { translateToOpenAI } from "./non-stream-translation"
1010

@@ -19,9 +19,8 @@ export async function handleCountTokens(c: Context) {
1919

2020
const openAIPayload = translateToOpenAI(anthropicPayload)
2121

22-
const selectedModel = state.models?.data.find(
23-
(model) => model.id === anthropicPayload.model,
24-
)
22+
const selectedModel = findEndpointModel(anthropicPayload.model)
23+
anthropicPayload.model = selectedModel?.id ?? anthropicPayload.model
2524

2625
if (!selectedModel) {
2726
consola.warn("Model not found, returning default token count")

src/routes/messages/handler.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
getReasoningEffortForModel,
1212
} from "~/lib/config"
1313
import { createHandlerLogger } from "~/lib/logger"
14+
import { findEndpointModel } from "~/lib/models"
1415
import { checkRateLimit } from "~/lib/rate-limit"
1516
import { state } from "~/lib/state"
1617
import { generateRequestIdFromPayload, getRootSessionId } from "~/lib/utils"
@@ -107,9 +108,8 @@ export async function handleCompletion(c: Context) {
107108
await awaitApproval()
108109
}
109110

110-
const selectedModel = state.models?.data.find(
111-
(m) => m.id === anthropicPayload.model,
112-
)
111+
const selectedModel = findEndpointModel(anthropicPayload.model)
112+
anthropicPayload.model = selectedModel?.id ?? anthropicPayload.model
113113

114114
if (shouldUseMessagesApi(selectedModel)) {
115115
return await handleWithMessagesApi(c, anthropicPayload, {

0 commit comments

Comments
 (0)