Skip to content

Commit c589db2

Browse files
committed
refactor: Refactor error handling and copilot API calls
1 parent 1654e64 commit c589db2

File tree

16 files changed

+97
-173
lines changed

16 files changed

+97
-173
lines changed

bun.lock

Lines changed: 1 addition & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,7 @@
4343
"consola": "^3.4.0",
4444
"fetch-event-stream": "^0.1.5",
4545
"hono": "^4.7.4",
46-
"ofetch": "^1.4.1",
47-
"srvx": "^0.2.5",
48-
"zod": "^3.24.2"
46+
"srvx": "^0.2.5"
4947
},
5048
"devDependencies": {
5149
"@echristian/eslint-config": "^0.0.32",

src/lib/api-config.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,14 @@ export const COPILOT_API_CONFIG = {
1212
export const COPILOT_API_BASE_URL = "https://api.individual.githubcopilot.com"
1313
export const copilotHeaders = (state: State) => ({
1414
Authorization: `Bearer ${state.copilotToken}`,
15+
"content-type": "application/json",
1516
"copilot-integration-id": "vscode-chat",
17+
"editor-version": `vscode/${state.vsCodeVersion}`,
18+
"editor-plugin-version": "copilot-chat/0.24.1",
19+
"openai-intent": "conversation-panel",
20+
"x-github-api-version": "2024-12-15",
21+
"x-request-id": globalThis.crypto.randomUUID(),
22+
"x-vscode-user-agent-library-version": "electron-fetch",
1623
})
1724

1825
export const GITHUB_API_BASE_URL = "https://api.github.com"

src/lib/forward-error.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import type { Context } from "hono"
2+
import type { ContentfulStatusCode } from "hono/utils/http-status"
3+
4+
import consola from "consola"
5+
6+
import { HTTPError } from "./http-error"
7+
8+
export async function forwardError(c: Context, error: unknown) {
9+
consola.error("Error occurred:", error)
10+
11+
if (error instanceof HTTPError) {
12+
return c.json(
13+
{
14+
error: {
15+
message: await error.response.text(),
16+
type: "error",
17+
},
18+
},
19+
error.response.status as ContentfulStatusCode,
20+
)
21+
}
22+
23+
return c.json(
24+
{
25+
error: {
26+
message: (error as Error).message,
27+
type: "error",
28+
},
29+
},
30+
500,
31+
)
32+
}

src/lib/http-error.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export class HTTPError extends Error {
2+
response: Response
3+
4+
constructor(message: string, response: Response) {
5+
super(message)
6+
this.response = response
7+
}
8+
}

src/routes/chat-completions/handler.ts

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,14 @@ import type { Context } from "hono"
22

33
import { streamSSE, type SSEMessage } from "hono/streaming"
44

5-
import type { ChatCompletionsPayload } from "~/services/copilot/chat-completions/types"
5+
import type {
6+
ChatCompletionResponse,
7+
ChatCompletionsPayload,
8+
} from "~/services/copilot/chat-completions/types"
69

710
import { isNullish } from "~/lib/is-nullish"
811
import { state } from "~/lib/state"
9-
import { createChatCompletions } from "~/services/copilot/chat-completions/service"
10-
import { chatCompletionsStream } from "~/services/copilot/chat-completions/service-streaming"
11-
12-
function handleStreaming(c: Context, payload: ChatCompletionsPayload) {
13-
return streamSSE(c, async (stream) => {
14-
const response = await chatCompletionsStream(payload)
15-
16-
for await (const chunk of response) {
17-
await stream.writeSSE(chunk as SSEMessage)
18-
}
19-
})
20-
}
21-
22-
async function handleNonStreaming(c: Context, payload: ChatCompletionsPayload) {
23-
const response = await createChatCompletions(payload)
24-
return c.json(response)
25-
}
12+
import { createChatCompletions } from "~/services/copilot/create-chat-completions"
2613

2714
export async function handleCompletion(c: Context) {
2815
let payload = await c.req.json<ChatCompletionsPayload>()
@@ -38,9 +25,19 @@ export async function handleCompletion(c: Context) {
3825
}
3926
}
4027

41-
if (payload.stream) {
42-
return handleStreaming(c, payload)
28+
const response = await createChatCompletions(payload)
29+
30+
if (isNonStreaming(response)) {
31+
return c.json(response)
4332
}
4433

45-
return handleNonStreaming(c, payload)
34+
return streamSSE(c, async (stream) => {
35+
for await (const chunk of response) {
36+
await stream.writeSSE(chunk as SSEMessage)
37+
}
38+
})
4639
}
40+
41+
const isNonStreaming = (
42+
response: Awaited<ReturnType<typeof createChatCompletions>>,
43+
): response is ChatCompletionResponse => Object.hasOwn(response, "choices")
Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import consola from "consola"
21
import { Hono } from "hono"
32

3+
import { forwardError } from "~/lib/forward-error"
4+
45
import { handleCompletion } from "./handler"
56

67
export const completionRoutes = new Hono()
@@ -9,28 +10,6 @@ completionRoutes.post("/", async (c) => {
910
try {
1011
return await handleCompletion(c)
1112
} catch (error) {
12-
consola.error("Error occurred:", error)
13-
14-
if (error instanceof Response) {
15-
return c.json(
16-
{
17-
error: {
18-
message: error.message,
19-
type: "error",
20-
},
21-
},
22-
500,
23-
)
24-
}
25-
26-
return c.json(
27-
{
28-
error: {
29-
message: error.message,
30-
type: "error",
31-
},
32-
},
33-
500,
34-
)
13+
return forwardError(c, error)
3514
}
3615
})

src/routes/chat-completions/types.ts

Lines changed: 0 additions & 53 deletions
This file was deleted.

src/routes/embeddings/route.ts

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
1-
import consola from "consola"
21
import { Hono } from "hono"
3-
import { FetchError } from "ofetch"
42

5-
import type { EmbeddingRequest } from "~/services/copilot/embedding/types"
6-
7-
import { createEmbeddings } from "~/services/copilot/create-embeddings"
3+
import { forwardError } from "~/lib/forward-error"
4+
import {
5+
createEmbeddings,
6+
type EmbeddingRequest,
7+
} from "~/services/copilot/create-embeddings"
88

99
export const embeddingRoutes = new Hono()
1010

1111
embeddingRoutes.post("/", async (c) => {
1212
try {
13-
const embeddings = await createEmbeddings(
14-
await c.req.json<EmbeddingRequest>(),
15-
)
16-
return c.json(embeddings)
13+
const paylod = await c.req.json<EmbeddingRequest>()
14+
const response = await createEmbeddings(paylod)
15+
16+
return c.json(response)
1717
} catch (error) {
18-
if (error instanceof FetchError) {
19-
consola.error(`Request failed: ${error.message}`, error.response?._data)
20-
}
21-
throw error
18+
return forwardError(c, error)
2219
}
2320
})

src/services/copilot/chat-completions/service-streaming.ts

Lines changed: 0 additions & 21 deletions
This file was deleted.

0 commit comments

Comments
 (0)