parent
02fdc39571
commit
8531343c2b
4 changed files with 131 additions and 68 deletions
|
|
@ -2,70 +2,70 @@
|
||||||
$OutputEncoding = [System.Text.Encoding]::UTF8
|
$OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
|
|
||||||
Write-Host "========================================" -ForegroundColor Cyan
|
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 "========================================" -ForegroundColor Cyan
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
|
|
||||||
# 处理参数
|
# Handle parameters
|
||||||
$forcePull = $args -contains "--pull"
|
$forcePull = $args -contains "--pull"
|
||||||
|
|
||||||
# 检查 Git 并拉取
|
# Check Git and Pull
|
||||||
if ($forcePull) {
|
if ($forcePull) {
|
||||||
Write-Host "[更新] 正在从远程仓库拉取最新代码..."
|
Write-Host "[UPDATE] Pulling latest code from remote repository..."
|
||||||
if (Get-Command git -ErrorAction SilentlyContinue) {
|
if (Get-Command git -ErrorAction SilentlyContinue) {
|
||||||
git pull
|
git pull
|
||||||
if ($LASTEXITCODE -ne 0) {
|
if ($LASTEXITCODE -ne 0) {
|
||||||
Write-Warning "Git pull 失败,请检查网络或手动处理冲突。"
|
Write-Warning "Git pull failed. Please check your network or handle conflicts manually."
|
||||||
} else {
|
} else {
|
||||||
Write-Host "[成功] 代码已更新。" -ForegroundColor Green
|
Write-Host "[SUCCESS] Code updated." -ForegroundColor Green
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Write-Warning "未检测到 Git,跳过代码拉取。"
|
Write-Warning "Git not detected. Skipping code pull."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# 检查 Node.js
|
# Check Node.js
|
||||||
Write-Host "[检查] 正在检查Node.js是否已安装..."
|
Write-Host "[CHECK] Checking if Node.js is installed..."
|
||||||
if (-not (Get-Command node -ErrorAction SilentlyContinue)) {
|
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
|
Pause
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
$nodeVersion = node --version
|
$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")) {
|
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
|
Pause
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# 确定包管理器
|
# Determine package manager
|
||||||
$pkgManager = if (Get-Command pnpm -ErrorAction SilentlyContinue) { "pnpm" } else { "npm" }
|
$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
|
& $pkgManager install
|
||||||
if ($LASTEXITCODE -ne 0) {
|
if ($LASTEXITCODE -ne 0) {
|
||||||
Write-Host "[错误] 依赖安装失败,请检查网络连接。" -ForegroundColor Red
|
Write-Host "[ERROR] Dependency installation failed. Please check your network connection." -ForegroundColor Red
|
||||||
Pause
|
Pause
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# 检查主文件
|
# Check master file
|
||||||
if (-not (Test-Path "src\core\master.js")) {
|
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
|
Pause
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "========================================" -ForegroundColor Green
|
Write-Host "========================================" -ForegroundColor Green
|
||||||
Write-Host " 启动 AIClient2API 服务器..." -ForegroundColor Green
|
Write-Host " Starting AIClient2API Server..." -ForegroundColor Green
|
||||||
Write-Host "========================================" -ForegroundColor Green
|
Write-Host "========================================" -ForegroundColor Green
|
||||||
Write-Host "服务器将在 http://localhost:3000 启动"
|
Write-Host "Server will start at http://localhost:3000"
|
||||||
Write-Host "按 Ctrl+C 停止服务器"
|
Write-Host "Press Ctrl+C to stop the server"
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
|
|
||||||
node src\core\master.js
|
node src\core\master.js
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ const ANTIGRAVITY_SYSTEM_PROMPT = `You are Antigravity, a powerful agentic AI co
|
||||||
// Thinking 配置相关常量
|
// Thinking 配置相关常量
|
||||||
const DEFAULT_THINKING_MIN = 1024;
|
const DEFAULT_THINKING_MIN = 1024;
|
||||||
const DEFAULT_THINKING_MAX = 100000;
|
const DEFAULT_THINKING_MAX = 100000;
|
||||||
|
const FALLBACK_THINKING_SIGNATURE = "skip_thought_signature_validator_fallback";
|
||||||
|
|
||||||
// 获取 Antigravity 模型列表
|
// 获取 Antigravity 模型列表
|
||||||
const ANTIGRAVITY_MODELS = getProviderModels(MODEL_PROVIDER.ANTIGRAVITY);
|
const ANTIGRAVITY_MODELS = getProviderModels(MODEL_PROVIDER.ANTIGRAVITY);
|
||||||
|
|
@ -199,16 +200,16 @@ function normalizeAntigravityThinking(modelName, payload, isClaudeModel) {
|
||||||
|
|
||||||
let normalizedBudget = normalizeThinkingBudget(modelName, budget);
|
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) {
|
if (isClaudeModel) {
|
||||||
const maxTokens = payload?.request?.generationConfig?.maxOutputTokens;
|
|
||||||
if (maxTokens && maxTokens > 0 && normalizedBudget >= maxTokens) {
|
|
||||||
normalizedBudget = maxTokens - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查最小 budget
|
|
||||||
const minBudget = DEFAULT_THINKING_MIN;
|
const minBudget = DEFAULT_THINKING_MIN;
|
||||||
if (normalizedBudget >= 0 && normalizedBudget < minBudget) {
|
if (normalizedBudget >= 0 && normalizedBudget < minBudget && normalizedBudget !== -1) {
|
||||||
// Budget 低于最小值,移除 thinking 配置
|
// Budget 低于最小值,移除 thinking 配置
|
||||||
delete payload.request.generationConfig.thinkingConfig;
|
delete payload.request.generationConfig.thinkingConfig;
|
||||||
return payload;
|
return payload;
|
||||||
|
|
@ -599,7 +600,7 @@ function toGeminiApiResponse(antigravityResponse) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 确保请求体中的内容部分都有角色属性
|
* 确保请求体中的内容部分都有角色属性,并修复历史记录中的思考签名
|
||||||
* @param {Object} requestBody - 请求体
|
* @param {Object} requestBody - 请求体
|
||||||
* @returns {Object} 处理后的请求体
|
* @returns {Object} 处理后的请求体
|
||||||
*/
|
*/
|
||||||
|
|
@ -674,6 +675,24 @@ function ensureRolesInContents(requestBody, modelName) {
|
||||||
if (!content.role) {
|
if (!content.role) {
|
||||||
content.role = 'user';
|
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,
|
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.availableModels = [];
|
||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
|
|
||||||
|
|
@ -730,6 +730,32 @@ export class AntigravityApiService {
|
||||||
|
|
||||||
// 保存代理配置供后续使用
|
// 保存代理配置供后续使用
|
||||||
this.proxyConfig = getProxyConfigForProvider(config, config.MODEL_PROVIDER || MODEL_PROVIDER.ANTIGRAVITY);
|
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) {
|
_applySidecar(requestOptions) {
|
||||||
|
|
|
||||||
|
|
@ -287,24 +287,6 @@ export class GeminiApiService {
|
||||||
maxFreeSockets: 5,
|
maxFreeSockets: 5,
|
||||||
timeout: 120000,
|
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.authClient = new OAuth2Client(oauth2Options);
|
||||||
this.availableModels = [];
|
this.availableModels = [];
|
||||||
|
|
@ -322,6 +304,29 @@ export class GeminiApiService {
|
||||||
|
|
||||||
// 保存代理配置供后续使用
|
// 保存代理配置供后续使用
|
||||||
this.proxyConfig = getProxyConfigForProvider(config, config.MODEL_PROVIDER || MODEL_PROVIDER.GEMINI_CLI);
|
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() {
|
async initialize() {
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,38 @@ export const qwenOAuth2Events = new EventEmitter();
|
||||||
|
|
||||||
// --- Helper Functions ---
|
// --- 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 方法
|
// 封装公共的 await fetch 方法
|
||||||
async function commonFetch(url, options = {}, useSystemProxy = false) {
|
async function commonFetch(url, options = {}, useSystemProxy = false) {
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
|
|
@ -580,7 +612,7 @@ export class QwenApiService {
|
||||||
this.currentAxiosInstance = axios.create(axiosConfig);
|
this.currentAxiosInstance = axios.create(axiosConfig);
|
||||||
|
|
||||||
// Process message content before sending the request
|
// 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
|
// 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)) {
|
if (processedBody.model && !QWEN_MODEL_LIST.some(model => model.id === processedBody.model)) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue