1- import { useCallback , useState } from "react"
1+ import { useCallback , useState , useEffect } from "react"
22import { Checkbox } from "vscrui"
3- import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
3+ import { VSCodeButton , VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
44
55import type { ProviderSettings } from "@roo-code/types"
66
77import { useAppTranslation } from "@src/i18n/TranslationContext"
88import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
99import { useSelectedModel } from "@src/components/ui/hooks/useSelectedModel"
10+ import { StandardTooltip } from "@src/components/ui"
1011
12+ import { convertHeadersToObject } from "../utils/headers"
1113import { inputEventTransform , noTransform } from "../transforms"
1214
1315type AnthropicProps = {
@@ -22,6 +24,11 @@ export const Anthropic = ({ apiConfiguration, setApiConfigurationField }: Anthro
2224
2325 const [ anthropicBaseUrlSelected , setAnthropicBaseUrlSelected ] = useState ( ! ! apiConfiguration ?. anthropicBaseUrl )
2426
27+ const [ customHeaders , setCustomHeaders ] = useState < [ string , string ] [ ] > ( ( ) => {
28+ const headers = apiConfiguration ?. anthropicHeaders || { }
29+ return Object . entries ( headers )
30+ } )
31+
2532 // Check if the current model supports 1M context beta
2633 const supports1MContextBeta =
2734 selectedModel ?. id === "claude-sonnet-4-20250514" || selectedModel ?. id === "claude-sonnet-4-5"
@@ -37,6 +44,50 @@ export const Anthropic = ({ apiConfiguration, setApiConfigurationField }: Anthro
3744 [ setApiConfigurationField ] ,
3845 )
3946
47+ const handleAddCustomHeader = useCallback ( ( ) => {
48+ // Only update the local state to show the new row in the UI.
49+ setCustomHeaders ( ( prev ) => [ ...prev , [ "" , "" ] ] )
50+ // Do not update the main configuration yet, wait for user input.
51+ } , [ ] )
52+
53+ const handleUpdateHeaderKey = useCallback ( ( index : number , newKey : string ) => {
54+ setCustomHeaders ( ( prev ) => {
55+ const updated = [ ...prev ]
56+
57+ if ( updated [ index ] ) {
58+ updated [ index ] = [ newKey , updated [ index ] [ 1 ] ]
59+ }
60+
61+ return updated
62+ } )
63+ } , [ ] )
64+
65+ const handleUpdateHeaderValue = useCallback ( ( index : number , newValue : string ) => {
66+ setCustomHeaders ( ( prev ) => {
67+ const updated = [ ...prev ]
68+
69+ if ( updated [ index ] ) {
70+ updated [ index ] = [ updated [ index ] [ 0 ] , newValue ]
71+ }
72+
73+ return updated
74+ } )
75+ } , [ ] )
76+
77+ const handleRemoveCustomHeader = useCallback ( ( index : number ) => {
78+ setCustomHeaders ( ( prev ) => prev . filter ( ( _ , i ) => i !== index ) )
79+ } , [ ] )
80+
81+ // Add effect to update the parent component's state when local headers change
82+ useEffect ( ( ) => {
83+ const timer = setTimeout ( ( ) => {
84+ const headerObject = convertHeadersToObject ( customHeaders )
85+ setApiConfigurationField ( "anthropicHeaders" , headerObject )
86+ } , 300 )
87+
88+ return ( ) => clearTimeout ( timer )
89+ } , [ customHeaders , setApiConfigurationField ] )
90+
4091 return (
4192 < >
4293 < VSCodeTextField
@@ -86,6 +137,46 @@ export const Anthropic = ({ apiConfiguration, setApiConfigurationField }: Anthro
86137 </ >
87138 ) }
88139 </ div >
140+
141+ { /* Custom Headers UI */ }
142+ < div className = "mb-4" >
143+ < div className = "flex justify-between items-center mb-2" >
144+ < label className = "block font-medium" > { t ( "settings:providers.customHeaders" ) } </ label >
145+ < StandardTooltip content = { t ( "settings:common.add" ) } >
146+ < VSCodeButton appearance = "icon" onClick = { handleAddCustomHeader } >
147+ < span className = "codicon codicon-add" > </ span >
148+ </ VSCodeButton >
149+ </ StandardTooltip >
150+ </ div >
151+ { ! customHeaders . length ? (
152+ < div className = "text-sm text-vscode-descriptionForeground" >
153+ { t ( "settings:providers.noCustomHeaders" ) }
154+ </ div >
155+ ) : (
156+ customHeaders . map ( ( [ key , value ] , index ) => (
157+ < div key = { index } className = "flex items-center mb-2" >
158+ < VSCodeTextField
159+ value = { key }
160+ className = "flex-1 mr-2"
161+ placeholder = { t ( "settings:providers.headerName" ) }
162+ onInput = { ( e : any ) => handleUpdateHeaderKey ( index , e . target . value ) }
163+ />
164+ < VSCodeTextField
165+ value = { value }
166+ className = "flex-1 mr-2"
167+ placeholder = { t ( "settings:providers.headerValue" ) }
168+ onInput = { ( e : any ) => handleUpdateHeaderValue ( index , e . target . value ) }
169+ />
170+ < StandardTooltip content = { t ( "settings:common.remove" ) } >
171+ < VSCodeButton appearance = "icon" onClick = { ( ) => handleRemoveCustomHeader ( index ) } >
172+ < span className = "codicon codicon-trash" > </ span >
173+ </ VSCodeButton >
174+ </ StandardTooltip >
175+ </ div >
176+ ) )
177+ ) }
178+ </ div >
179+
89180 { supports1MContextBeta && (
90181 < div >
91182 < Checkbox
0 commit comments