Skip to content

Commit 6abf0be

Browse files
mark-bradshawmbradshawfrostbournesb
authored
Allow setting extra headers for openai compatible api (RooCodeInc#1136)
* Allow setting extra headers for openai compatible api * Fix to the extra headers form * Properly store header state * fix prettier * Cleanup styles --------- Co-authored-by: mbradshaw <[email protected]> Co-authored-by: frostbournesb <[email protected]>
1 parent c8b234a commit 6abf0be

File tree

5 files changed

+93
-3
lines changed

5 files changed

+93
-3
lines changed

src/api/providers/openai.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@ export class OpenAiHandler implements ApiHandler {
2121
baseURL: this.options.openAiBaseUrl,
2222
apiKey: this.options.openAiApiKey,
2323
apiVersion: this.options.azureApiVersion || azureOpenAiDefaultApiVersion,
24+
defaultHeaders: this.options.openAiHeaders,
2425
})
2526
} else {
2627
this.client = new OpenAI({
2728
baseURL: this.options.openAiBaseUrl,
2829
apiKey: this.options.openAiApiKey,
30+
defaultHeaders: this.options.openAiHeaders,
2931
})
3032
}
3133
}

src/core/storage/state-keys.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export type GlobalStateKey =
3737
| "openAiBaseUrl"
3838
| "openAiModelId"
3939
| "openAiModelInfo"
40+
| "openAiHeaders"
4041
| "ollamaModelId"
4142
| "ollamaBaseUrl"
4243
| "ollamaApiOptionsCtxNum"

src/core/storage/state.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
7373
openAiApiKey,
7474
openAiModelId,
7575
openAiModelInfo,
76+
openAiHeaders,
7677
ollamaModelId,
7778
ollamaBaseUrl,
7879
ollamaApiOptionsCtxNum,
@@ -144,6 +145,7 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
144145
getSecret(context, "openAiApiKey") as Promise<string | undefined>,
145146
getGlobalState(context, "openAiModelId") as Promise<string | undefined>,
146147
getGlobalState(context, "openAiModelInfo") as Promise<ModelInfo | undefined>,
148+
getGlobalState(context, "openAiHeaders") as Promise<Record<string, string> | undefined>,
147149
getGlobalState(context, "ollamaModelId") as Promise<string | undefined>,
148150
getGlobalState(context, "ollamaBaseUrl") as Promise<string | undefined>,
149151
getGlobalState(context, "ollamaApiOptionsCtxNum") as Promise<string | undefined>,
@@ -256,6 +258,7 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
256258
openAiApiKey,
257259
openAiModelId,
258260
openAiModelInfo,
261+
openAiHeaders: openAiHeaders || {},
259262
ollamaModelId,
260263
ollamaBaseUrl,
261264
ollamaApiOptionsCtxNum,
@@ -334,6 +337,7 @@ export async function updateApiConfiguration(context: vscode.ExtensionContext, a
334337
openAiApiKey,
335338
openAiModelId,
336339
openAiModelInfo,
340+
openAiHeaders,
337341
ollamaModelId,
338342
ollamaBaseUrl,
339343
ollamaApiOptionsCtxNum,
@@ -389,6 +393,7 @@ export async function updateApiConfiguration(context: vscode.ExtensionContext, a
389393
await storeSecret(context, "openAiApiKey", openAiApiKey)
390394
await updateGlobalState(context, "openAiModelId", openAiModelId)
391395
await updateGlobalState(context, "openAiModelInfo", openAiModelInfo)
396+
await updateGlobalState(context, "openAiHeaders", openAiHeaders || {})
392397
await updateGlobalState(context, "ollamaModelId", ollamaModelId)
393398
await updateGlobalState(context, "ollamaBaseUrl", ollamaBaseUrl)
394399
await updateGlobalState(context, "ollamaApiOptionsCtxNum", ollamaApiOptionsCtxNum)

src/shared/api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export interface ApiHandlerOptions {
3232
liteLlmModelId?: string
3333
liteLlmApiKey?: string
3434
liteLlmUsePromptCache?: boolean
35+
openAiHeaders?: Record<string, string> // Custom headers for OpenAI requests
3536
anthropicBaseUrl?: string
3637
openRouterApiKey?: string
3738
openRouterModelId?: string

webview-ui/src/components/settings/ApiOptions.tsx

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
VSCodeButton,
23
VSCodeCheckbox,
34
VSCodeDropdown,
45
VSCodeLink,
@@ -803,27 +804,107 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
803804
<div>
804805
<VSCodeTextField
805806
value={apiConfiguration?.openAiBaseUrl || ""}
806-
style={{ width: "100%" }}
807+
style={{ width: "100%", marginBottom: 10 }}
807808
type="url"
808809
onInput={handleInputChange("openAiBaseUrl")}
809810
placeholder={"Enter base URL..."}>
810811
<span style={{ fontWeight: 500 }}>Base URL</span>
811812
</VSCodeTextField>
812813
<VSCodeTextField
813814
value={apiConfiguration?.openAiApiKey || ""}
814-
style={{ width: "100%" }}
815+
style={{ width: "100%", marginBottom: 10 }}
815816
type="password"
816817
onInput={handleInputChange("openAiApiKey")}
817818
placeholder="Enter API Key...">
818819
<span style={{ fontWeight: 500 }}>API Key</span>
819820
</VSCodeTextField>
820821
<VSCodeTextField
821822
value={apiConfiguration?.openAiModelId || ""}
822-
style={{ width: "100%" }}
823+
style={{ width: "100%", marginBottom: 10 }}
823824
onInput={handleInputChange("openAiModelId")}
824825
placeholder={"Enter Model ID..."}>
825826
<span style={{ fontWeight: 500 }}>Model ID</span>
826827
</VSCodeTextField>
828+
829+
{/* OpenAI Compatible Custom Headers */}
830+
{(() => {
831+
const headerEntries = Object.entries(apiConfiguration?.openAiHeaders ?? {})
832+
return (
833+
<div style={{ marginBottom: 10 }}>
834+
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
835+
<span style={{ fontWeight: 500 }}>Custom Headers</span>
836+
<VSCodeButton
837+
onClick={() => {
838+
const currentHeaders = { ...(apiConfiguration?.openAiHeaders || {}) }
839+
const headerCount = Object.keys(currentHeaders).length
840+
const newKey = `header${headerCount + 1}`
841+
currentHeaders[newKey] = ""
842+
handleInputChange("openAiHeaders")({
843+
target: {
844+
value: currentHeaders,
845+
},
846+
})
847+
}}>
848+
Add Header
849+
</VSCodeButton>
850+
</div>
851+
<div>
852+
{headerEntries.map(([key, value], index) => (
853+
<div key={index} style={{ display: "flex", gap: 5, marginTop: 5 }}>
854+
<VSCodeTextField
855+
value={key}
856+
style={{ width: "40%" }}
857+
placeholder="Header name"
858+
onInput={(e: any) => {
859+
const currentHeaders = apiConfiguration?.openAiHeaders ?? {}
860+
const newValue = e.target.value
861+
if (newValue && newValue !== key) {
862+
const { [key]: _, ...rest } = currentHeaders
863+
handleInputChange("openAiHeaders")({
864+
target: {
865+
value: {
866+
...rest,
867+
[newValue]: value,
868+
},
869+
},
870+
})
871+
}
872+
}}
873+
/>
874+
<VSCodeTextField
875+
value={value}
876+
style={{ width: "40%" }}
877+
placeholder="Header value"
878+
onInput={(e: any) => {
879+
handleInputChange("openAiHeaders")({
880+
target: {
881+
value: {
882+
...(apiConfiguration?.openAiHeaders ?? {}),
883+
[key]: e.target.value,
884+
},
885+
},
886+
})
887+
}}
888+
/>
889+
<VSCodeButton
890+
appearance="secondary"
891+
onClick={() => {
892+
const { [key]: _, ...rest } = apiConfiguration?.openAiHeaders ?? {}
893+
handleInputChange("openAiHeaders")({
894+
target: {
895+
value: rest,
896+
},
897+
})
898+
}}>
899+
Remove
900+
</VSCodeButton>
901+
</div>
902+
))}
903+
</div>
904+
</div>
905+
)
906+
})()}
907+
827908
<VSCodeCheckbox
828909
checked={azureApiVersionSelected}
829910
onChange={(e: any) => {

0 commit comments

Comments
 (0)