fix(proxy): 修复 Trae Authorization 头发成字面量 jwt + 补全 SOLO 头
Some checks are pending
Release / build (push) Waiting to run
Some checks are pending
Release / build (push) Waiting to run
- 上一版把 \ 写成了字符串 jwt,Trae 收到 Cloud-IDE-JWT jwt 必然被网关拒绝 - 完整 SOLO 头集合对齐 trae2api-cn:x-app-version/x-lscbd-*/x-ttnet-* 等 - 版本升至 1.7.0
This commit is contained in:
parent
8e692a0c6e
commit
fa796d57b5
@ -16,8 +16,8 @@ android {
|
||||
applicationId = "com.rainy.token"
|
||||
minSdk = 31
|
||||
targetSdk = 35
|
||||
versionCode = 19
|
||||
versionName = "1.6.9"
|
||||
versionCode = 20
|
||||
versionName = "1.7.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
|
||||
@ -15,6 +15,7 @@ import kotlinx.serialization.json.JsonPrimitive
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import kotlinx.serialization.json.contentOrNull
|
||||
import kotlinx.serialization.json.put
|
||||
import okhttp3.Headers.Companion.toHeaders
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
@ -23,9 +24,9 @@ import okhttp3.RequestBody.Companion.toRequestBody
|
||||
/**
|
||||
* Trae CN 上游 Chat 代理。
|
||||
*
|
||||
* 上游为私有协议 POST {base}/api/agent/v3/llm_utils_chat,
|
||||
* 请求头需要 Cloud-IDE-JWT / x-device-id / x-uid 等设备与身份指纹。
|
||||
* M1b 实现最小 body 转换:保留 messages/tools,注入 config_name/function/stream/session。
|
||||
* 上游为私有协议 POST {base}/api/agent/v3/llm_utils_chat。
|
||||
* CN 模型网关固定走 trae-api-cn.mchost.guru(api.trae.cn 只是账号/OAuth 主机,返回 404)。
|
||||
* 请求头/body 对齐 trae2api-cn 参考实现的 SOLO 协议。
|
||||
*/
|
||||
@Singleton
|
||||
class TraeChatProxy @Inject constructor(
|
||||
@ -57,30 +58,10 @@ class TraeChatProxy @Inject constructor(
|
||||
}
|
||||
val upstreamBody = buildUpstreamBody(requestBody, credential)
|
||||
val requestId = UUID.randomUUID().toString()
|
||||
val sessionId = UUID.randomUUID().toString().replace("-", "")
|
||||
|
||||
val builder = Request.Builder()
|
||||
.url(base + "/api/agent/v3/llm_utils_chat")
|
||||
.addHeader("Content-Type", "application/json")
|
||||
.addHeader("Accept", "text/event-stream")
|
||||
.addHeader("Authorization", "Cloud-IDE-JWT jwt")
|
||||
.addHeader("X-Cloudide-Token", jwt)
|
||||
.addHeader("x-uid", credential.userId ?: "")
|
||||
.addHeader("x-app-id", "6eefa01c-1036-4c7e-9ca5-d891f63bfcd8")
|
||||
.addHeader("x-device-id", credential.deviceId ?: credential.checkinDeviceId ?: "")
|
||||
.addHeader("x-machine-id", credential.deviceId ?: credential.checkinDeviceId ?: "")
|
||||
.addHeader("x-request-id", requestId)
|
||||
.addHeader("x-ide-version", "3.3.67")
|
||||
.addHeader("x-ide-version-code", "20260401")
|
||||
.addHeader("x-ide-version-type", "stable")
|
||||
.addHeader("x-device-cpu", "AMD")
|
||||
.addHeader("x-device-brand", "83DG")
|
||||
.addHeader("x-device-type", "windows")
|
||||
.addHeader("x-ide-token", jwt)
|
||||
.addHeader("x-os-version", "Windows 10")
|
||||
.addHeader("x-system-type", "Windows")
|
||||
.addHeader("Connection", "keep-alive")
|
||||
.addHeader("User-Agent", "")
|
||||
.headers(soloHeaders(jwt, credential, requestId).toHeaders())
|
||||
.post(upstreamBody.toRequestBody("application/json".toMediaType()))
|
||||
|
||||
val response = try {
|
||||
@ -110,36 +91,16 @@ class TraeChatProxy @Inject constructor(
|
||||
ProviderRegion.valueOf(credential.region.uppercase())
|
||||
}.getOrNull()
|
||||
val base = if (effectiveRegion == ProviderRegion.INTL) {
|
||||
"https://grow-normal.trae.ai"
|
||||
"https://a0ai-api-sg.byteintlapi.com"
|
||||
} else {
|
||||
"https://api.trae.cn"
|
||||
"https://trae-api-cn.mchost.guru"
|
||||
}
|
||||
val upstreamBody = buildUpstreamBody(requestBody, credential)
|
||||
val requestId = UUID.randomUUID().toString()
|
||||
val sessionId = UUID.randomUUID().toString().replace("-", "")
|
||||
|
||||
val builder = Request.Builder()
|
||||
.url(base + "/api/agent/v3/llm_utils_chat")
|
||||
.addHeader("Content-Type", "application/json")
|
||||
.addHeader("Accept", "text/event-stream")
|
||||
.addHeader("Authorization", "Cloud-IDE-JWT jwt")
|
||||
.addHeader("X-Cloudide-Token", jwt)
|
||||
.addHeader("x-uid", credential.userId ?: "")
|
||||
.addHeader("x-app-id", "6eefa01c-1036-4c7e-9ca5-d891f63bfcd8")
|
||||
.addHeader("x-device-id", credential.deviceId ?: credential.checkinDeviceId ?: "")
|
||||
.addHeader("x-machine-id", credential.deviceId ?: credential.checkinDeviceId ?: "")
|
||||
.addHeader("x-request-id", requestId)
|
||||
.addHeader("x-ide-version", "3.3.67")
|
||||
.addHeader("x-ide-version-code", "20260401")
|
||||
.addHeader("x-ide-version-type", "stable")
|
||||
.addHeader("x-device-cpu", "AMD")
|
||||
.addHeader("x-device-brand", "83DG")
|
||||
.addHeader("x-device-type", "windows")
|
||||
.addHeader("x-ide-token", jwt)
|
||||
.addHeader("x-os-version", "Windows 10")
|
||||
.addHeader("x-system-type", "Windows")
|
||||
.addHeader("Connection", "keep-alive")
|
||||
.addHeader("User-Agent", "")
|
||||
.headers(soloHeaders(jwt, credential, requestId).toHeaders())
|
||||
.post(upstreamBody.toRequestBody("application/json".toMediaType()))
|
||||
|
||||
val response = try {
|
||||
@ -159,6 +120,50 @@ class TraeChatProxy @Inject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
private fun soloHeaders(
|
||||
jwt: String,
|
||||
credential: Credential.TraeCredential,
|
||||
requestId: String,
|
||||
): Map<String, String> = linkedMapOf(
|
||||
"Content-Type" to "application/json",
|
||||
"Accept" to "text/event-stream",
|
||||
"Connection" to "keep-alive",
|
||||
"Authorization" to "Cloud-IDE-JWT $jwt",
|
||||
"X-Cloudide-Token" to jwt,
|
||||
"x-ide-token" to jwt,
|
||||
"x-uid" to (credential.userId ?: ""),
|
||||
"x-app-id" to "6eefa01c-1036-4c7e-9ca5-d891f63bfcd8",
|
||||
"x-device-id" to (credential.deviceId ?: credential.checkinDeviceId ?: ""),
|
||||
"x-machine-id" to (credential.deviceId ?: credential.checkinDeviceId ?: ""),
|
||||
"x-request-id" to requestId,
|
||||
"x-ide-version" to "0.1.52",
|
||||
"x-ide-version-code" to "20260811",
|
||||
"x-ide-version-type" to "stable",
|
||||
"x-app-version" to "default",
|
||||
"x-app-version-code" to "20260811",
|
||||
"x-version-code" to "20260811",
|
||||
"x-device-cpu" to "AMD",
|
||||
"x-device-brand" to "83DG",
|
||||
"x-device-type" to "windows",
|
||||
"x-device-platform" to "windows",
|
||||
"x-os-version" to "Windows 11 Pro",
|
||||
"x-system-type" to "Windows",
|
||||
"package-type" to "stable_cn",
|
||||
"x-lscbd-aid" to "787976",
|
||||
"x-lscbd-platform" to "windows",
|
||||
"x-ss-dp" to "787976",
|
||||
"x-plugin-channel" to "icube-ai",
|
||||
"app-version" to "0.1.52",
|
||||
"x-bridge-transport" to "aha",
|
||||
"x-ahanet-timeout" to "86400",
|
||||
"x-lgw-req-sdk-type" to "3",
|
||||
"x-net-sdk-domain-dispatch" to "1",
|
||||
"x-ttnet-bypass-decompression" to "1",
|
||||
"x-ttnet-bypass-cookie" to "0",
|
||||
"request-traffic-type" to "prod",
|
||||
"User-Agent" to "Trae/0.1.52",
|
||||
)
|
||||
|
||||
private fun buildUpstreamBody(raw: String, credential: Credential.TraeCredential): String {
|
||||
val src = try {
|
||||
json.parseToJsonElement(raw) as? JsonObject
|
||||
|
||||
Loading…
Reference in New Issue
Block a user