Skip to content

Commit fd84ee2

Browse files
author
202226442
committed
feat(server): 添加对Lingma提供商的支持并重构聊天完成服务
- 添加新的Provider类型定义,支持copilot和lingma两种提供商 - 实现Lingma提供商的连接、初始化和聊天完成功能 - 重构createChatCompletions服务以支持多提供商架构 - 在start命令中添加provider参数和相关配置选项 - 为Lingma提供商实现模型缓存和配置解析功能 - 添加APIError类用于更精确的错误处理 - 在各个路由中添加提供商特定的功能限制检查 - 实现Lingma聊天完成的验证和渲染逻辑 - 更新状态管理以支持新的提供商模式
1 parent 0ea08fe commit fd84ee2

18 files changed

Lines changed: 1511 additions & 22 deletions

File tree

src/lib/error.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,36 @@ export class HTTPError extends Error {
1212
}
1313
}
1414

15+
export class APIError extends Error {
16+
status: ContentfulStatusCode
17+
type: string
18+
19+
constructor(
20+
message: string,
21+
status: ContentfulStatusCode = 500,
22+
type = "error",
23+
) {
24+
super(message)
25+
this.status = status
26+
this.type = type
27+
}
28+
}
29+
1530
export async function forwardError(c: Context, error: unknown) {
1631
consola.error("Error occurred:", error)
1732

33+
if (error instanceof APIError) {
34+
return c.json(
35+
{
36+
error: {
37+
message: error.message,
38+
type: error.type,
39+
},
40+
},
41+
error.status,
42+
)
43+
}
44+
1845
if (error instanceof HTTPError) {
1946
const errorText = await error.response.text()
2047
let errorJson: unknown

src/lib/state.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
import type { ModelsResponse } from "~/services/copilot/get-models"
2+
import type { LingmaRpcClient } from "~/services/lingma/json-rpc"
3+
4+
export type Provider = "copilot" | "lingma"
25

36
export interface State {
7+
provider: Provider
48
githubToken?: string
59
copilotToken?: string
10+
lingmaClient?: LingmaRpcClient
611

712
accountType: string
813
models?: ModelsResponse
@@ -18,6 +23,7 @@ export interface State {
1823
}
1924

2025
export const state: State = {
26+
provider: "copilot",
2127
accountType: "individual",
2228
manualApprove: false,
2329
rateLimitWait: false,

src/lib/utils.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ import consola from "consola"
22

33
import { getModels } from "~/services/copilot/get-models"
44
import { getVSCodeVersion } from "~/services/get-vscode-version"
5+
import {
6+
createLingmaModels,
7+
parseLingmaModelIds,
8+
} from "~/services/lingma/models"
59

610
import { state } from "./state"
711

@@ -18,6 +22,15 @@ export async function cacheModels(): Promise<void> {
1822
state.models = models
1923
}
2024

25+
export async function cacheProviderModels(): Promise<void> {
26+
if (state.provider === "lingma") {
27+
state.models = createLingmaModels(parseLingmaModelIds())
28+
return
29+
}
30+
31+
await cacheModels()
32+
}
33+
2134
export const cacheVSCodeVersion = async () => {
2235
const response = await getVSCodeVersion()
2336
state.vsCodeVersion = response

src/routes/chat-completions/handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
createChatCompletions,
1313
type ChatCompletionResponse,
1414
type ChatCompletionsPayload,
15-
} from "~/services/copilot/create-chat-completions"
15+
} from "~/services/create-chat-completions"
1616

1717
export async function handleCompletion(c: Context) {
1818
await checkRateLimit(state)

src/routes/embeddings/route.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Hono } from "hono"
22

3-
import { forwardError } from "~/lib/error"
3+
import { APIError, forwardError } from "~/lib/error"
4+
import { state } from "~/lib/state"
45
import {
56
createEmbeddings,
67
type EmbeddingRequest,
@@ -10,6 +11,14 @@ export const embeddingRoutes = new Hono()
1011

1112
embeddingRoutes.post("/", async (c) => {
1213
try {
14+
if (state.provider === "lingma") {
15+
throw new APIError(
16+
"Embeddings are not supported by the Lingma provider in V1",
17+
501,
18+
"unsupported_feature",
19+
)
20+
}
21+
1322
const paylod = await c.req.json<EmbeddingRequest>()
1423
const response = await createEmbeddings(paylod)
1524

src/routes/messages/route.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Hono } from "hono"
22

3-
import { forwardError } from "~/lib/error"
3+
import { APIError, forwardError } from "~/lib/error"
4+
import { state } from "~/lib/state"
45

56
import { handleCountTokens } from "./count-tokens-handler"
67
import { handleCompletion } from "./handler"
@@ -9,6 +10,14 @@ export const messageRoutes = new Hono()
910

1011
messageRoutes.post("/", async (c) => {
1112
try {
13+
if (state.provider === "lingma") {
14+
throw new APIError(
15+
"Anthropic messages are not supported by the Lingma provider in V1",
16+
501,
17+
"unsupported_feature",
18+
)
19+
}
20+
1221
return await handleCompletion(c)
1322
} catch (error) {
1423
return await forwardError(c, error)
@@ -17,6 +26,14 @@ messageRoutes.post("/", async (c) => {
1726

1827
messageRoutes.post("/count_tokens", async (c) => {
1928
try {
29+
if (state.provider === "lingma") {
30+
throw new APIError(
31+
"Token counting is not supported by the Lingma provider in V1",
32+
501,
33+
"unsupported_feature",
34+
)
35+
}
36+
2037
return await handleCountTokens(c)
2138
} catch (error) {
2239
return await forwardError(c, error)

src/routes/models/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ import { Hono } from "hono"
22

33
import { forwardError } from "~/lib/error"
44
import { state } from "~/lib/state"
5-
import { cacheModels } from "~/lib/utils"
5+
import { cacheProviderModels } from "~/lib/utils"
66

77
export const modelRoutes = new Hono()
88

99
modelRoutes.get("/", async (c) => {
1010
try {
1111
if (!state.models) {
1212
// This should be handled by startup logic, but as a fallback.
13-
await cacheModels()
13+
await cacheProviderModels()
1414
}
1515

1616
const models = state.models?.data.map((model) => ({

src/routes/token/route.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
import { Hono } from "hono"
22

3+
import { APIError, forwardError } from "~/lib/error"
34
import { state } from "~/lib/state"
45

56
export const tokenRoute = new Hono()
67

78
tokenRoute.get("/", (c) => {
89
try {
10+
if (state.provider === "lingma") {
11+
throw new APIError(
12+
"Token inspection is not supported by the Lingma provider in V1",
13+
501,
14+
"unsupported_feature",
15+
)
16+
}
17+
918
return c.json({
1019
token: state.copilotToken,
1120
})
1221
} catch (error) {
13-
console.error("Error fetching token:", error)
14-
return c.json({ error: "Failed to fetch token", token: null }, 500)
22+
return forwardError(c, error)
1523
}
1624
})

src/routes/usage/route.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
import { Hono } from "hono"
22

3+
import { APIError, forwardError } from "~/lib/error"
4+
import { state } from "~/lib/state"
35
import { getCopilotUsage } from "~/services/github/get-copilot-usage"
46

57
export const usageRoute = new Hono()
68

79
usageRoute.get("/", async (c) => {
810
try {
11+
if (state.provider === "lingma") {
12+
throw new APIError(
13+
"Usage is not supported by the Lingma provider in V1",
14+
501,
15+
"unsupported_feature",
16+
)
17+
}
18+
919
const usage = await getCopilotUsage()
1020
return c.json(usage)
1121
} catch (error) {
12-
console.error("Error fetching Copilot usage:", error)
13-
return c.json({ error: "Failed to fetch Copilot usage" }, 500)
22+
return await forwardError(c, error)
1423
}
1524
})
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { state } from "~/lib/state"
2+
3+
import type { ChatCompletionsPayload } from "./copilot/create-chat-completions"
4+
5+
import { createChatCompletions as createCopilotChatCompletions } from "./copilot/create-chat-completions"
6+
import { createLingmaChatCompletions } from "./lingma/create-chat-completions"
7+
8+
export type {
9+
ChatCompletionChunk,
10+
ChatCompletionResponse,
11+
ChatCompletionsPayload,
12+
ContentPart,
13+
ImagePart,
14+
Message,
15+
TextPart,
16+
Tool,
17+
ToolCall,
18+
} from "./copilot/create-chat-completions"
19+
20+
export const createChatCompletions = async (
21+
payload: ChatCompletionsPayload,
22+
) => {
23+
if (state.provider === "lingma") {
24+
return await createLingmaChatCompletions(payload)
25+
}
26+
27+
return await createCopilotChatCompletions(payload)
28+
}

0 commit comments

Comments
 (0)