mirror of
https://github.com/carlrobertoh/ProxyAI.git
synced 2026-07-10 01:39:13 +00:00
fix: respect advanced settings (http/socks proxy) for agent mode
This commit is contained in:
parent
e939d9dc00
commit
e55778d668
4 changed files with 126 additions and 10 deletions
|
|
@ -33,6 +33,7 @@ import com.intellij.openapi.components.service
|
|||
import com.intellij.openapi.project.Project
|
||||
import ee.carlrobert.codegpt.EncodingManager
|
||||
import ee.carlrobert.codegpt.agent.clients.CustomOpenAILLMClient
|
||||
import ee.carlrobert.codegpt.agent.clients.HttpClientProvider
|
||||
import ee.carlrobert.codegpt.agent.clients.InceptionAILLMClient
|
||||
import ee.carlrobert.codegpt.agent.clients.ProxyAILLMClient
|
||||
import ee.carlrobert.codegpt.agent.clients.RetryingPromptExecutor
|
||||
|
|
@ -165,26 +166,28 @@ object AgentFactory {
|
|||
}
|
||||
|
||||
fun createExecutor(provider: ServiceType, events: AgentEvents? = null): PromptExecutor {
|
||||
val httpClient = HttpClientProvider.createHttpClient()
|
||||
return when (provider) {
|
||||
ServiceType.OPENAI -> {
|
||||
val apiKey = getCredential(CredentialKey.OpenaiApiKey) ?: ""
|
||||
createRetryingExecutor(OpenAILLMClient(apiKey), events)
|
||||
createRetryingExecutor(OpenAILLMClient(apiKey, baseClient = httpClient), events)
|
||||
}
|
||||
|
||||
ServiceType.ANTHROPIC -> {
|
||||
val apiKey = getCredential(CredentialKey.AnthropicApiKey) ?: ""
|
||||
createRetryingExecutor(AnthropicLLMClient(apiKey), events)
|
||||
createRetryingExecutor(AnthropicLLMClient(apiKey, baseClient = httpClient), events)
|
||||
}
|
||||
|
||||
ServiceType.GOOGLE -> {
|
||||
val apiKey = getCredential(CredentialKey.GoogleApiKey) ?: ""
|
||||
createRetryingExecutor(GoogleLLMClient(apiKey), events)
|
||||
createRetryingExecutor(GoogleLLMClient(apiKey, baseClient = httpClient), events)
|
||||
}
|
||||
|
||||
ServiceType.OLLAMA -> {
|
||||
createRetryingExecutor(
|
||||
OllamaClient(
|
||||
baseUrl = service<OllamaSettings>().state.host ?: "http://localhost:11434"
|
||||
baseUrl = service<OllamaSettings>().state.host ?: "http://localhost:11434",
|
||||
baseClient = httpClient
|
||||
),
|
||||
events
|
||||
)
|
||||
|
|
@ -192,7 +195,7 @@ object AgentFactory {
|
|||
|
||||
ServiceType.MISTRAL -> {
|
||||
val apiKey = getCredential(CredentialKey.MistralApiKey) ?: ""
|
||||
createRetryingExecutor(MistralAILLMClient(apiKey), events)
|
||||
createRetryingExecutor(MistralAILLMClient(apiKey, baseClient = httpClient), events)
|
||||
}
|
||||
|
||||
ServiceType.CUSTOM_OPENAI -> {
|
||||
|
|
@ -207,6 +210,7 @@ object AgentFactory {
|
|||
CustomOpenAILLMClient.fromSettingsState(
|
||||
apiKey,
|
||||
state.chatCompletionSettings,
|
||||
httpClient
|
||||
),
|
||||
events
|
||||
)
|
||||
|
|
@ -214,12 +218,12 @@ object AgentFactory {
|
|||
|
||||
ServiceType.PROXYAI -> {
|
||||
val apiKey = getCredential(CredentialKey.CodeGptApiKey) ?: ""
|
||||
createRetryingExecutor(ProxyAILLMClient(apiKey), events)
|
||||
createRetryingExecutor(ProxyAILLMClient(apiKey, baseClient = httpClient), events)
|
||||
}
|
||||
|
||||
ServiceType.INCEPTION -> {
|
||||
val apiKey = getCredential(CredentialKey.InceptionApiKey) ?: ""
|
||||
createRetryingExecutor(InceptionAILLMClient(apiKey), events)
|
||||
createRetryingExecutor(InceptionAILLMClient(apiKey, baseClient = httpClient), events)
|
||||
}
|
||||
|
||||
else -> throw UnsupportedOperationException("Provider not supported: $provider")
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ public class CustomOpenAILLMClient(
|
|||
fun fromSettingsState(
|
||||
apiKey: String,
|
||||
state: CustomServiceChatCompletionSettingsState,
|
||||
baseClient: HttpClient = HttpClient(),
|
||||
timeoutConfig: ConnectionTimeoutConfig = ConnectionTimeoutConfig()
|
||||
): CustomOpenAILLMClient {
|
||||
val stateUrl = state.url ?: throw IllegalStateException("Url not set")
|
||||
|
|
@ -80,7 +81,7 @@ public class CustomOpenAILLMClient(
|
|||
chatCompletionsPath = uri.path,
|
||||
timeoutConfig = timeoutConfig
|
||||
)
|
||||
return CustomOpenAILLMClient(apiKey, settings, state)
|
||||
return CustomOpenAILLMClient(apiKey, settings, state, baseClient)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
package ee.carlrobert.codegpt.agent.clients
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.util.net.ssl.CertificateManager
|
||||
import ee.carlrobert.codegpt.settings.advanced.AdvancedSettings
|
||||
import ee.carlrobert.codegpt.settings.advanced.AdvancedSettingsState
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.engine.apache5.*
|
||||
import io.ktor.client.plugins.*
|
||||
import org.apache.hc.client5.http.auth.AuthScope
|
||||
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials
|
||||
import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder
|
||||
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider
|
||||
import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner
|
||||
import org.apache.hc.core5.http.HttpHost
|
||||
import java.net.Proxy
|
||||
|
||||
/**
|
||||
* Provides configured Ktor HttpClient instances with proxy support for Agent mode.
|
||||
*/
|
||||
object HttpClientProvider {
|
||||
|
||||
private val logger = Logger.getInstance(HttpClientProvider::class.java)
|
||||
|
||||
/**
|
||||
* Creates a Ktor HttpClient configured with proxy settings from AdvancedSettings.
|
||||
* Supports both HTTP and SOCKS proxies with optional authentication.
|
||||
*/
|
||||
fun createHttpClient(): HttpClient {
|
||||
val advancedSettings = AdvancedSettings.getCurrentState()
|
||||
return HttpClient(Apache5) {
|
||||
engine {
|
||||
configureProxy(advancedSettings)
|
||||
}
|
||||
|
||||
install(HttpTimeout) {
|
||||
connectTimeoutMillis = advancedSettings.connectTimeout.toLong() * 1000
|
||||
requestTimeoutMillis = advancedSettings.readTimeout.toLong() * 1000
|
||||
socketTimeoutMillis = advancedSettings.readTimeout.toLong() * 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Apache5EngineConfig.configureProxy(settings: AdvancedSettingsState) {
|
||||
val proxyHost = settings.proxyHost
|
||||
val proxyPort = settings.proxyPort
|
||||
|
||||
if (proxyHost.isBlank() || proxyPort == 0) {
|
||||
logger.info("No proxy configured for Agent mode")
|
||||
customizeClient {
|
||||
sslContext = CertificateManager.getInstance().sslContext
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
logger.info("Configuring Agent mode with ${settings.proxyType} proxy: $proxyHost:$proxyPort")
|
||||
|
||||
val proxy = createProxy(settings) ?: run {
|
||||
logger.warn("Invalid proxy type configured: ${settings.proxyType}")
|
||||
customizeClient {
|
||||
sslContext = CertificateManager.getInstance().sslContext
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
customizeClient {
|
||||
sslContext = CertificateManager.getInstance().sslContext
|
||||
|
||||
setRoutePlanner(DefaultProxyRoutePlanner(proxy))
|
||||
|
||||
if (settings.isProxyAuthSelected) {
|
||||
configureProxyAuthentication(settings, proxy, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createProxy(settings: AdvancedSettingsState): HttpHost? {
|
||||
return when (settings.proxyType) {
|
||||
Proxy.Type.HTTP -> HttpHost("http", settings.proxyHost, settings.proxyPort)
|
||||
Proxy.Type.SOCKS -> HttpHost("socks", settings.proxyHost, settings.proxyPort)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun configureProxyAuthentication(
|
||||
settings: AdvancedSettingsState,
|
||||
proxy: HttpHost,
|
||||
clientBuilder: HttpAsyncClientBuilder
|
||||
) {
|
||||
val username = settings.proxyUsername ?: ""
|
||||
if (username.isNotBlank()) {
|
||||
logger.info("Configuring proxy authentication for user: $username")
|
||||
|
||||
val credentialsProvider = BasicCredentialsProvider()
|
||||
credentialsProvider.setCredentials(
|
||||
AuthScope(proxy),
|
||||
UsernamePasswordCredentials(
|
||||
username,
|
||||
settings.proxyPassword?.toCharArray() ?: charArrayOf()
|
||||
)
|
||||
)
|
||||
|
||||
clientBuilder.setDefaultCredentialsProvider(credentialsProvider)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,13 +6,18 @@ import ai.koog.prompt.executor.clients.openai.OpenAIClientSettings
|
|||
import ai.koog.prompt.executor.clients.openai.OpenAILLMClient
|
||||
import ai.koog.prompt.llm.LLMProvider
|
||||
import ai.koog.prompt.llm.LLModel
|
||||
import io.ktor.client.*
|
||||
|
||||
class InceptionAILLMClient(apiKey: String) : OpenAILLMClient(
|
||||
class InceptionAILLMClient(
|
||||
apiKey: String,
|
||||
baseClient: HttpClient = HttpClient()
|
||||
) : OpenAILLMClient(
|
||||
apiKey = apiKey,
|
||||
settings = OpenAIClientSettings(
|
||||
baseUrl = "https://api.inceptionlabs.ai",
|
||||
chatCompletionsPath = "v1/chat/completions"
|
||||
)
|
||||
),
|
||||
baseClient = baseClient
|
||||
) {
|
||||
data object Inception : LLMProvider("inception", "Inception")
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue