feat: 更新版本至2.12.3并修复多个问题
更新项目版本至2.12.3,新增赞助商LingtrueAPI信息至README文档。修复Qwen提供商缺少系统提示词时自动添加默认提示词的问题。优化Gemini和Antigravity提供商的OAuth2Client代理配置逻辑,根据baseURL自动选择HTTP/HTTPS agent。修复Antigravity提供商中thinking budget逻辑及历史记录中思考签名缺失的问题。将Windows安装脚本翻译为英文。
This commit is contained in:
parent
0c9d52f537
commit
1570fbb096
9 changed files with 162 additions and 69 deletions
10
README-JA.md
10
README-JA.md
|
|
@ -47,6 +47,16 @@
|
|||
AICodeMirror の本プロジェクトへのスポンサーシップに感謝します!AICodeMirror は、Claude Code / Codex / Gemini CLI 向けに公式の高安定性リレーサービスを提供しており、企業レベルの同時実行性、迅速な請求書発行、24時間365日の専用技術サポートを備えています。Claude Code / Codex / Gemini の公式チャンネルを、元の価格の 38% / 2% / 9% で利用でき、チャージ時にはさらなる割引もあります!AICodeMirror は AIClient-2-API ユーザーに特別な特典を提供しています:<a href="https://www.aicodemirror.com/register?invitecode=5BUE62">このリンクから登録</a>すると、初回チャージが <strong>20% オフ</strong>になり、法人のお客様は最大 25% オフになります!
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="25%" align="center" valign="middle">
|
||||
<a href="https://www.lingtrue.com/register?aff=MP34">
|
||||
<img src="static/lingtrueapi.png" alt="LingtrueAPI Sponsor" width="180">
|
||||
</a>
|
||||
</td>
|
||||
<td width="75%" align="left" valign="middle">
|
||||
LingtrueAPIによる本プロジェクトへのスポンサーに感謝します!LingtrueAPIは世界的な大規模言語モデルAPI中継プラットフォームであり、Claude opus 4.6、GPT 5.4、Gemini 3.1 proなど各種モデルのAPI呼び出しサービスを提供しています。低コスト、高安定性で世界中のAI機能に接続し、生産性を最大化することを目指しています。LingtrueAPIは本ソフトウェアユーザー向けに特別優遇を提供しています。<a href="https://www.lingtrue.com/register?aff=MP34">このリンクから登録</a>し、初回チャージ時に「<strong>LingtrueAPI</strong>」のクーポンコードを入力すると、<strong>10%オフ</strong>で利用できます。
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="25%" align="center" valign="middle">
|
||||
<img src="static/wechat.png" alt="Sponsor Contact" width="150">
|
||||
|
|
|
|||
10
README-ZH.md
10
README-ZH.md
|
|
@ -46,6 +46,16 @@
|
|||
感谢 AICodeMirror 赞助本项目!AICodeMirror 为 Claude Code / Codex / Gemini CLI 提供官方高稳定性中转服务,具备企业级并发能力、快速开票和 7/24 专属技术支持。Claude Code / Codex / Gemini 官方渠道价格仅为原价的 38% / 2% / 9%,充值还有额外优惠!AICodeMirror 为 AIClient-2-API 用户提供专属福利:<a href="https://www.aicodemirror.com/register?invitecode=5BUE62">通过此链接注册</a>即可享受首充 <strong>8折(20% off)</strong> 优惠,企业客户最高可享 75折(25% off)!
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="25%" align="center" valign="middle">
|
||||
<a href="https://www.lingtrue.com/register?aff=MP34">
|
||||
<img src="static/lingtrueapi.png" alt="LingtrueAPI Sponsor" width="180">
|
||||
</a>
|
||||
</td>
|
||||
<td width="75%" align="left" valign="middle">
|
||||
感谢 LingtrueAPI 对本项目的赞助!LingtrueAPI 是一家全球大模型API中转服务平台,提供Claude opus 4.6、GPT 5.4、Gemini 3.1 pro等多种模型API调用服务,致力于让用户以低成本、高稳定性链接全球AI能力,最大化生产效率。LingtrueAPI为本软件用户提供了特别优惠:<a href="https://www.lingtrue.com/register?aff=MP34">通过此链接注册</a>并在首次充值时输入 <strong>LingtrueAPI</strong> 优惠码即可享受 <strong>9折优惠</strong>。
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="25%" align="center" valign="middle">
|
||||
<img src="static/wechat.png" alt="Sponsor Contact" width="150">
|
||||
|
|
|
|||
10
README.md
10
README.md
|
|
@ -47,6 +47,16 @@
|
|||
Thanks to AICodeMirror for sponsoring this project! AICodeMirror provides official high-stability relay services for Claude Code / Codex / Gemini CLI, with enterprise-grade concurrency, fast invoicing, and 24/7 dedicated technical support. Claude Code / Codex / Gemini official channels at 38% / 2% / 9% of original price, with extra discounts on top-ups! AICodeMirror offers special benefits for AIClient-2-API users: <a href="https://www.aicodemirror.com/register?invitecode=5BUE62">register via this link</a> to enjoy <strong>20% off</strong> your first top-up, and enterprise customers can get up to 25% off!
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="25%" align="center" valign="middle">
|
||||
<a href="https://www.lingtrue.com/register?aff=MP34">
|
||||
<img src="static/lingtrueapi.png" alt="LingtrueAPI Sponsor" width="180">
|
||||
</a>
|
||||
</td>
|
||||
<td width="75%" align="left" valign="middle">
|
||||
Thanks to LingtrueAPI for its sponsorship of this project! LingtrueAPI is a global large-model API intermediary service platform that offers API calling services for various models such as Claude opus 4.6, GPT 5.4, and Gemini 3.1 pro. It is committed to enabling users to connect to global AI capabilities at low cost and with high stability, maximizing production efficiency. LingtrueAPI provides special discounts for users of this software: <a href="https://www.lingtrue.com/register?aff=MP34">register using this link</a> and enter the <strong>LingtrueAPI</strong> promo code when making the first recharge to enjoy a <strong>10% discount</strong>.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="25%" align="center" valign="middle">
|
||||
<img src="static/wechat.png" alt="Sponsor Contact" width="150">
|
||||
|
|
|
|||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
2.12.2.2
|
||||
2.12.3
|
||||
|
|
|
|||
|
|
@ -2,70 +2,70 @@
|
|||
$OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host " AI Client 2 API 快速安装启动脚本" -ForegroundColor Cyan
|
||||
Write-Host " AI Client 2 API Quick Setup Script" -ForegroundColor Cyan
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# 处理参数
|
||||
# Handle parameters
|
||||
$forcePull = $args -contains "--pull"
|
||||
|
||||
# 检查 Git 并拉取
|
||||
# Check Git and Pull
|
||||
if ($forcePull) {
|
||||
Write-Host "[更新] 正在从远程仓库拉取最新代码..."
|
||||
Write-Host "[UPDATE] Pulling latest code from remote repository..."
|
||||
if (Get-Command git -ErrorAction SilentlyContinue) {
|
||||
git pull
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Warning "Git pull 失败,请检查网络或手动处理冲突。"
|
||||
Write-Warning "Git pull failed. Please check your network or handle conflicts manually."
|
||||
} else {
|
||||
Write-Host "[成功] 代码已更新。" -ForegroundColor Green
|
||||
Write-Host "[SUCCESS] Code updated." -ForegroundColor Green
|
||||
}
|
||||
} else {
|
||||
Write-Warning "未检测到 Git,跳过代码拉取。"
|
||||
Write-Warning "Git not detected. Skipping code pull."
|
||||
}
|
||||
}
|
||||
|
||||
# 检查 Node.js
|
||||
Write-Host "[检查] 正在检查Node.js是否已安装..."
|
||||
# Check Node.js
|
||||
Write-Host "[CHECK] Checking if Node.js is installed..."
|
||||
if (-not (Get-Command node -ErrorAction SilentlyContinue)) {
|
||||
Write-Host "[错误] 未检测到Node.js,请先安装Node.js (https://nodejs.org/)" -ForegroundColor Red
|
||||
Write-Host "[ERROR] Node.js not detected. Please install Node.js (https://nodejs.org/)" -ForegroundColor Red
|
||||
Pause
|
||||
exit 1
|
||||
}
|
||||
|
||||
$nodeVersion = node --version
|
||||
Write-Host "[成功] Node.js已安装,版本: $nodeVersion" -ForegroundColor Green
|
||||
Write-Host "[SUCCESS] Node.js installed, version: $nodeVersion" -ForegroundColor Green
|
||||
|
||||
# 检查 package.json
|
||||
# Check package.json
|
||||
if (-not (Test-Path "package.json")) {
|
||||
Write-Host "[错误] 未找到package.json文件,请确保在项目根目录下运行此脚本" -ForegroundColor Red
|
||||
Write-Host "[ERROR] package.json not found. Please ensure you are running this script from the project root." -ForegroundColor Red
|
||||
Pause
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 确定包管理器
|
||||
# Determine package manager
|
||||
$pkgManager = if (Get-Command pnpm -ErrorAction SilentlyContinue) { "pnpm" } else { "npm" }
|
||||
Write-Host "[安装] 正在使用 $pkgManager 安装/更新依赖..." -ForegroundColor Cyan
|
||||
Write-Host "[INSTALL] Installing/updating dependencies using $pkgManager..." -ForegroundColor Cyan
|
||||
|
||||
& $pkgManager install
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "[错误] 依赖安装失败,请检查网络连接。" -ForegroundColor Red
|
||||
Write-Host "[ERROR] Dependency installation failed. Please check your network connection." -ForegroundColor Red
|
||||
Pause
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 检查主文件
|
||||
# Check master file
|
||||
if (-not (Test-Path "src\core\master.js")) {
|
||||
Write-Host "[错误] 未找到 src\core\master.js 文件" -ForegroundColor Red
|
||||
Write-Host "[ERROR] src\core\master.js not found." -ForegroundColor Red
|
||||
Pause
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "========================================" -ForegroundColor Green
|
||||
Write-Host " 启动 AIClient2API 服务器..." -ForegroundColor Green
|
||||
Write-Host " Starting AIClient2API Server..." -ForegroundColor Green
|
||||
Write-Host "========================================" -ForegroundColor Green
|
||||
Write-Host "服务器将在 http://localhost:3000 启动"
|
||||
Write-Host "按 Ctrl+C 停止服务器"
|
||||
Write-Host "Server will start at http://localhost:3000"
|
||||
Write-Host "Press Ctrl+C to stop the server"
|
||||
Write-Host ""
|
||||
|
||||
node src\core\master.js
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ const ANTIGRAVITY_SYSTEM_PROMPT = `You are Antigravity, a powerful agentic AI co
|
|||
// Thinking 配置相关常量
|
||||
const DEFAULT_THINKING_MIN = 1024;
|
||||
const DEFAULT_THINKING_MAX = 100000;
|
||||
const FALLBACK_THINKING_SIGNATURE = "skip_thought_signature_validator_fallback";
|
||||
|
||||
// 获取 Antigravity 模型列表
|
||||
const ANTIGRAVITY_MODELS = getProviderModels(MODEL_PROVIDER.ANTIGRAVITY);
|
||||
|
|
@ -199,16 +200,16 @@ function normalizeAntigravityThinking(modelName, payload, isClaudeModel) {
|
|||
|
||||
let normalizedBudget = normalizeThinkingBudget(modelName, budget);
|
||||
|
||||
// 对于 Claude 模型,确保 thinking budget < max_tokens
|
||||
// 确保 thinking budget < max_tokens (对所有模型生效,不仅是 Claude)
|
||||
const maxTokens = payload?.request?.generationConfig?.maxOutputTokens || payload?.request?.generationConfig?.max_output_tokens;
|
||||
if (maxTokens && maxTokens > 0 && normalizedBudget >= maxTokens) {
|
||||
normalizedBudget = Math.max(0, maxTokens - 1);
|
||||
}
|
||||
|
||||
// 如果是 Claude 模型,检查最小 budget
|
||||
if (isClaudeModel) {
|
||||
const maxTokens = payload?.request?.generationConfig?.maxOutputTokens;
|
||||
if (maxTokens && maxTokens > 0 && normalizedBudget >= maxTokens) {
|
||||
normalizedBudget = maxTokens - 1;
|
||||
}
|
||||
|
||||
// 检查最小 budget
|
||||
const minBudget = DEFAULT_THINKING_MIN;
|
||||
if (normalizedBudget >= 0 && normalizedBudget < minBudget) {
|
||||
if (normalizedBudget >= 0 && normalizedBudget < minBudget && normalizedBudget !== -1) {
|
||||
// Budget 低于最小值,移除 thinking 配置
|
||||
delete payload.request.generationConfig.thinkingConfig;
|
||||
return payload;
|
||||
|
|
@ -599,7 +600,7 @@ function toGeminiApiResponse(antigravityResponse) {
|
|||
}
|
||||
|
||||
/**
|
||||
* 确保请求体中的内容部分都有角色属性
|
||||
* 确保请求体中的内容部分都有角色属性,并修复历史记录中的思考签名
|
||||
* @param {Object} requestBody - 请求体
|
||||
* @returns {Object} 处理后的请求体
|
||||
*/
|
||||
|
|
@ -674,6 +675,24 @@ function ensureRolesInContents(requestBody, modelName) {
|
|||
if (!content.role) {
|
||||
content.role = 'user';
|
||||
}
|
||||
|
||||
// [FIX] 修复历史记录中的思考块,确保有签名 (messages.1.content.0.thinking.signature 报错修复)
|
||||
if (content.parts && Array.isArray(content.parts)) {
|
||||
content.parts.forEach(part => {
|
||||
if (part && part.thought === true) {
|
||||
if (!part.thoughtSignature && !part.thought_signature) {
|
||||
part.thoughtSignature = FALLBACK_THINKING_SIGNATURE;
|
||||
}
|
||||
|
||||
// [FIX] 额外增加一个 'thinking' 对象以适配某些 Antigravity 内部验证逻辑
|
||||
if (!part.thinking) {
|
||||
part.thinking = {
|
||||
signature: part.thoughtSignature || part.thought_signature || FALLBACK_THINKING_SIGNATURE
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -696,25 +715,6 @@ export class AntigravityApiService {
|
|||
timeout: 120000,
|
||||
});
|
||||
|
||||
// 检查是否需要使用代理
|
||||
const proxyConfig = getGoogleAuthProxyConfig(config, config.MODEL_PROVIDER || MODEL_PROVIDER.ANTIGRAVITY);
|
||||
|
||||
// 配置 OAuth2Client 使用自定义的 HTTP agent
|
||||
const oauth2Options = {
|
||||
clientId: OAUTH_CLIENT_ID,
|
||||
clientSecret: OAUTH_CLIENT_SECRET,
|
||||
};
|
||||
|
||||
if (proxyConfig) {
|
||||
oauth2Options.transporterOptions = proxyConfig;
|
||||
logger.info('[Antigravity] Using proxy for OAuth2Client');
|
||||
} else {
|
||||
oauth2Options.transporterOptions = {
|
||||
agent: this.httpsAgent,
|
||||
};
|
||||
}
|
||||
|
||||
this.authClient = new OAuth2Client(oauth2Options);
|
||||
this.availableModels = [];
|
||||
this.isInitialized = false;
|
||||
|
||||
|
|
@ -730,6 +730,32 @@ export class AntigravityApiService {
|
|||
|
||||
// 保存代理配置供后续使用
|
||||
this.proxyConfig = getProxyConfigForProvider(config, config.MODEL_PROVIDER || MODEL_PROVIDER.ANTIGRAVITY);
|
||||
|
||||
// 检查是否需要使用代理
|
||||
const proxyConfig = getGoogleAuthProxyConfig(config, config.MODEL_PROVIDER || MODEL_PROVIDER.ANTIGRAVITY);
|
||||
|
||||
// 配置 OAuth2Client 使用自定义的 HTTP agent
|
||||
const oauth2Options = {
|
||||
clientId: OAUTH_CLIENT_ID,
|
||||
clientSecret: OAUTH_CLIENT_SECRET,
|
||||
};
|
||||
|
||||
if (proxyConfig) {
|
||||
oauth2Options.transporterOptions = proxyConfig;
|
||||
logger.info('[Antigravity] Using proxy for OAuth2Client');
|
||||
} else {
|
||||
// 根据 base URL 判断使用 http 还是 https agent
|
||||
const firstBaseURL = this.baseURLs && this.baseURLs.length > 0 ? this.baseURLs[0] : '';
|
||||
const useHttp = firstBaseURL.startsWith('http://');
|
||||
oauth2Options.transporterOptions = {
|
||||
agent: useHttp ? this.httpAgent : this.httpsAgent,
|
||||
};
|
||||
if (useHttp) {
|
||||
logger.info('[Antigravity] Using HTTP agent for OAuth2Client');
|
||||
}
|
||||
}
|
||||
|
||||
this.authClient = new OAuth2Client(oauth2Options);
|
||||
}
|
||||
|
||||
_applySidecar(requestOptions) {
|
||||
|
|
|
|||
|
|
@ -287,24 +287,6 @@ export class GeminiApiService {
|
|||
maxFreeSockets: 5,
|
||||
timeout: 120000,
|
||||
});
|
||||
|
||||
// 检查是否需要使用代理
|
||||
const proxyConfig = getGoogleAuthProxyConfig(config, config.MODEL_PROVIDER || MODEL_PROVIDER.GEMINI_CLI);
|
||||
|
||||
// 配置 OAuth2Client 使用自定义的 HTTP agent
|
||||
const oauth2Options = {
|
||||
clientId: OAUTH_CLIENT_ID,
|
||||
clientSecret: OAUTH_CLIENT_SECRET,
|
||||
};
|
||||
|
||||
if (proxyConfig) {
|
||||
oauth2Options.transporterOptions = proxyConfig;
|
||||
logger.info('[Gemini] Using proxy for OAuth2Client');
|
||||
} else {
|
||||
oauth2Options.transporterOptions = {
|
||||
agent: this.httpsAgent,
|
||||
};
|
||||
}
|
||||
|
||||
this.authClient = new OAuth2Client(oauth2Options);
|
||||
this.availableModels = [];
|
||||
|
|
@ -322,6 +304,29 @@ export class GeminiApiService {
|
|||
|
||||
// 保存代理配置供后续使用
|
||||
this.proxyConfig = getProxyConfigForProvider(config, config.MODEL_PROVIDER || MODEL_PROVIDER.GEMINI_CLI);
|
||||
|
||||
// 检查是否需要使用代理
|
||||
const proxyConfig = getGoogleAuthProxyConfig(config, config.MODEL_PROVIDER || MODEL_PROVIDER.GEMINI_CLI);
|
||||
|
||||
// 配置 OAuth2Client 使用自定义的 HTTP agent
|
||||
const oauth2Options = {
|
||||
clientId: OAUTH_CLIENT_ID,
|
||||
clientSecret: OAUTH_CLIENT_SECRET,
|
||||
};
|
||||
|
||||
if (proxyConfig) {
|
||||
oauth2Options.transporterOptions = proxyConfig;
|
||||
logger.info('[Gemini] Using proxy for OAuth2Client');
|
||||
} else {
|
||||
// 根据 base URL 判断使用 http 还是 https agent
|
||||
const useHttp = this.codeAssistEndpoint && this.codeAssistEndpoint.startsWith('http://');
|
||||
oauth2Options.transporterOptions = {
|
||||
agent: useHttp ? this.httpAgent : this.httpsAgent,
|
||||
};
|
||||
if (useHttp) {
|
||||
logger.info('[Gemini] Using HTTP agent for OAuth2Client');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async initialize() {
|
||||
|
|
|
|||
|
|
@ -50,6 +50,38 @@ export const qwenOAuth2Events = new EventEmitter();
|
|||
|
||||
// --- Helper Functions ---
|
||||
|
||||
/**
|
||||
* Qwen 默认系统提示词
|
||||
*/
|
||||
const QWEN_DEFAULT_SYSTEM_PROMPT = "You are a helpful assistant. You are Qwen, a large language model trained by Alibaba.";
|
||||
|
||||
/**
|
||||
* 应用 Qwen 默认系统提示词逻辑
|
||||
* @param {Object} requestBody - OpenAI 格式的请求体
|
||||
* @returns {Object} 处理后的请求体
|
||||
*/
|
||||
function applyQwenDefaultSystemPrompt(requestBody) {
|
||||
if (!requestBody || !requestBody.messages || !Array.isArray(requestBody.messages)) {
|
||||
return requestBody;
|
||||
}
|
||||
|
||||
// 检查是否已有系统提示词 (role 为 system 或 developer)
|
||||
const hasSystemPrompt = requestBody.messages.some(msg =>
|
||||
msg.role === 'system' || msg.role === 'developer'
|
||||
);
|
||||
|
||||
// 如果没有系统提示词,则在消息列表最前面插入默认提示词
|
||||
if (!hasSystemPrompt) {
|
||||
requestBody.messages.unshift({
|
||||
role: 'system',
|
||||
content: QWEN_DEFAULT_SYSTEM_PROMPT
|
||||
});
|
||||
logger.info('[Qwen Auth] 已应用默认系统提示词');
|
||||
}
|
||||
|
||||
return requestBody;
|
||||
}
|
||||
|
||||
// 封装公共的 await fetch 方法
|
||||
async function commonFetch(url, options = {}, useSystemProxy = false) {
|
||||
const defaultOptions = {
|
||||
|
|
@ -580,7 +612,7 @@ export class QwenApiService {
|
|||
this.currentAxiosInstance = axios.create(axiosConfig);
|
||||
|
||||
// Process message content before sending the request
|
||||
const processedBody = body;//this.processMessageContent(body);
|
||||
const processedBody = applyQwenDefaultSystemPrompt(body);
|
||||
|
||||
// Check if model in body is in QWEN_MODEL_LIST, if not, use the first model's id
|
||||
if (processedBody.model && !QWEN_MODEL_LIST.some(model => model.id === processedBody.model)) {
|
||||
|
|
|
|||
BIN
static/lingtrueapi.png
Normal file
BIN
static/lingtrueapi.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 196 KiB |
Loading…
Reference in a new issue