Skip to content

Commit 67d2fed

Browse files
committed
Implement dynamic vision capability enablement ericc-ch#36
1 parent 86fba08 commit 67d2fed

2 files changed

Lines changed: 30 additions & 6 deletions

File tree

src/lib/api-config.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const API_VERSION = "2025-04-01"
1515

1616
export const copilotBaseUrl = (state: State) =>
1717
`https://api.${state.accountType}.githubcopilot.com`
18-
export const copilotHeaders = (state: State) => {
18+
export const copilotHeaders = (state: State, vision: boolean = false) => {
1919
const headers: Record<string, string> = {
2020
Authorization: `Bearer ${state.copilotToken}`,
2121
"content-type": standardHeaders()["content-type"],
@@ -29,9 +29,7 @@ export const copilotHeaders = (state: State) => {
2929
"x-vscode-user-agent-library-version": "electron-fetch",
3030
}
3131

32-
if (state.visionEnabled) {
33-
headers["copilot-vision-request"] = "true"
34-
}
32+
if (vision) headers["copilot-vision-request"] = "true"
3533

3634
return headers
3735
}

src/services/copilot/create-chat-completions.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,19 @@ export const createChatCompletions = async (
99
) => {
1010
if (!state.copilotToken) throw new Error("Copilot token not found")
1111

12+
for (const message of payload.messages) {
13+
intoCopilotMessage(message)
14+
}
15+
16+
const visionEnable = payload.messages.some(
17+
(x) =>
18+
typeof x.content !== "string"
19+
&& x.content.some((x) => x.type === "image_url"),
20+
)
21+
1222
const response = await fetch(`${copilotBaseUrl(state)}/chat/completions`, {
1323
method: "POST",
14-
headers: copilotHeaders(state),
24+
headers: copilotHeaders(state, visionEnable),
1525
body: JSON.stringify(payload),
1626
})
1727

@@ -25,6 +35,14 @@ export const createChatCompletions = async (
2535
return (await response.json()) as ChatCompletionResponse
2636
}
2737

38+
const intoCopilotMessage = (message: Message) => {
39+
if (typeof message.content === "string") return false
40+
41+
for (const part of message.content) {
42+
if (part.type === "input_image") part.type = "image_url"
43+
}
44+
}
45+
2846
// Streaming types
2947

3048
export interface ChatCompletionChunk {
@@ -79,7 +97,15 @@ export interface ChatCompletionsPayload {
7997

8098
export interface Message {
8199
role: "user" | "assistant" | "system"
82-
content: string
100+
content: string | Array<ContentPart>
83101
}
84102

85103
// https://platform.openai.com/docs/api-reference
104+
105+
export interface ContentPart {
106+
type: "input_image" | "input_text" | "image_url"
107+
text?: string
108+
image_url?: string
109+
}
110+
// https://platform.openai.com/docs/guides/images-vision#giving-a-model-images-as-input
111+
// Note: copilot use "image_url", but openai use "input_image"

0 commit comments

Comments
 (0)