mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-27 21:01:32 +08:00
feat: add patch for Google Vertex AI and enhance private key handling
- Introduced a patch for the @ai-sdk/google-vertex package to improve URL handling based on region. - Added a new utility function to format private keys, ensuring correct PEM structure and validation. - Updated the ProviderConfigBuilder to utilize the new private key formatting function for Google credentials. - Created a pnpm workspace configuration to manage patched dependencies effectively.
This commit is contained in:
parent
2f58b3360e
commit
e421b81fca
26
packages/aiCore/patches/@ai-sdk__google-vertex.patch
Normal file
26
packages/aiCore/patches/@ai-sdk__google-vertex.patch
Normal file
@ -0,0 +1,26 @@
|
||||
diff --git a/edge/dist/index.js b/edge/dist/index.js
|
||||
index 87cb4e77c6e02c9cc16082f47d9a80878bea1006..8061d52940bfef4f4815051fd09bb700cf0034c7 100644
|
||||
--- a/edge/dist/index.js
|
||||
+++ b/edge/dist/index.js
|
||||
@@ -248,7 +248,7 @@ function createVertex(options = {}) {
|
||||
var _a;
|
||||
const region = loadVertexLocation();
|
||||
const project = loadVertexProject();
|
||||
- return (_a = (0, import_provider_utils4.withoutTrailingSlash)(options.baseURL)) != null ? _a : `https://${region}-aiplatform.googleapis.com/v1/projects/${project}/locations/${region}/publishers/google`;
|
||||
+ return (_a = (0, import_provider_utils4.withoutTrailingSlash)(options.baseURL)) != null ? _a : region === "global" ? `https://aiplatform.googleapis.com/v1/projects/${project}/locations/global/publishers/google` : `https://${region}-aiplatform.googleapis.com/v1/projects/${project}/locations/${region}/publishers/google`;
|
||||
};
|
||||
const createConfig = (name) => {
|
||||
var _a;
|
||||
diff --git a/edge/dist/index.mjs b/edge/dist/index.mjs
|
||||
index bd4ed39abe78fae60673607ab46241cc29dfa0a2..2e6f36d3668635d93b17660eda18f89972b4ccfd 100644
|
||||
--- a/edge/dist/index.mjs
|
||||
+++ b/edge/dist/index.mjs
|
||||
@@ -238,7 +238,7 @@ function createVertex(options = {}) {
|
||||
var _a;
|
||||
const region = loadVertexLocation();
|
||||
const project = loadVertexProject();
|
||||
- return (_a = withoutTrailingSlash(options.baseURL)) != null ? _a : `https://${region}-aiplatform.googleapis.com/v1/projects/${project}/locations/${region}/publishers/google`;
|
||||
+ return (_a = withoutTrailingSlash(options.baseURL)) != null ? _a : region === "global" ? `https://aiplatform.googleapis.com/v1/projects/${project}/locations/global/publishers/google` : `https://${region}-aiplatform.googleapis.com/v1/projects/${project}/locations/${region}/publishers/google`;
|
||||
};
|
||||
const createConfig = (name) => {
|
||||
var _a;
|
||||
@ -4,6 +4,11 @@ settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
patchedDependencies:
|
||||
'@ai-sdk/google-vertex':
|
||||
hash: b7c4a8a2274e90367ea6efb1e3056a9c6c83cb14329086354e8d20db1139e2f1
|
||||
path: patches/@ai-sdk__google-vertex.patch
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
@ -40,7 +45,7 @@ importers:
|
||||
version: 1.2.19(zod@3.25.67)
|
||||
'@ai-sdk/google-vertex':
|
||||
specifier: ^2.2.24
|
||||
version: 2.2.24(zod@3.25.67)
|
||||
version: 2.2.24(patch_hash=b7c4a8a2274e90367ea6efb1e3056a9c6c83cb14329086354e8d20db1139e2f1)(zod@3.25.67)
|
||||
'@ai-sdk/groq':
|
||||
specifier: ^1.2.9
|
||||
version: 1.2.9(zod@3.25.67)
|
||||
@ -612,7 +617,7 @@ snapshots:
|
||||
'@ai-sdk/provider-utils': 2.2.8(zod@3.25.67)
|
||||
zod: 3.25.67
|
||||
|
||||
'@ai-sdk/google-vertex@2.2.24(zod@3.25.67)':
|
||||
'@ai-sdk/google-vertex@2.2.24(patch_hash=b7c4a8a2274e90367ea6efb1e3056a9c6c83cb14329086354e8d20db1139e2f1)(zod@3.25.67)':
|
||||
dependencies:
|
||||
'@ai-sdk/anthropic': 1.2.12(zod@3.25.67)
|
||||
'@ai-sdk/google': 1.2.19(zod@3.25.67)
|
||||
|
||||
2
packages/aiCore/pnpm-workspace.yaml
Normal file
2
packages/aiCore/pnpm-workspace.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
patchedDependencies:
|
||||
'@ai-sdk/google-vertex': patches/@ai-sdk__google-vertex.patch
|
||||
@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import type { ProviderId, ProviderSettingsMap } from './registry'
|
||||
import { formatPrivateKey } from './utils'
|
||||
|
||||
/**
|
||||
* 通用配置基础类型,包含所有 Provider 共有的属性
|
||||
@ -141,7 +142,10 @@ export class ProviderConfigBuilder<T extends ProviderId = ProviderId> {
|
||||
withGoogleCredentials(credentials: any): any {
|
||||
if (this.providerId === 'google-vertex') {
|
||||
const vertexConfig = this.config as CompleteProviderConfig<'google-vertex'>
|
||||
vertexConfig.googleCredentials = credentials
|
||||
vertexConfig.googleCredentials = {
|
||||
clientEmail: credentials.clientEmail,
|
||||
privateKey: formatPrivateKey(credentials.privateKey)
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
86
packages/aiCore/src/providers/utils.ts
Normal file
86
packages/aiCore/src/providers/utils.ts
Normal file
@ -0,0 +1,86 @@
|
||||
/**
|
||||
* 格式化私钥,确保它包含正确的PEM头部和尾部
|
||||
*/
|
||||
export function formatPrivateKey(privateKey: string): string {
|
||||
if (!privateKey || typeof privateKey !== 'string') {
|
||||
throw new Error('Private key must be a non-empty string')
|
||||
}
|
||||
|
||||
// 先处理 JSON 字符串中的转义换行符
|
||||
const key = privateKey.replace(/\\n/g, '\n')
|
||||
|
||||
// 检查是否已经是正确格式的 PEM 私钥
|
||||
const hasBeginMarker = key.includes('-----BEGIN PRIVATE KEY-----')
|
||||
const hasEndMarker = key.includes('-----END PRIVATE KEY-----')
|
||||
|
||||
if (hasBeginMarker && hasEndMarker) {
|
||||
// 已经是 PEM 格式,但可能格式不规范,重新格式化
|
||||
return normalizePemFormat(key)
|
||||
}
|
||||
|
||||
// 如果没有完整的 PEM 头尾,尝试重新构建
|
||||
return reconstructPemKey(key)
|
||||
}
|
||||
|
||||
/**
|
||||
* 标准化 PEM 格式
|
||||
*/
|
||||
function normalizePemFormat(pemKey: string): string {
|
||||
// 分离头部、内容和尾部
|
||||
const lines = pemKey
|
||||
.split('\n')
|
||||
.map((line) => line.trim())
|
||||
.filter((line) => line.length > 0)
|
||||
|
||||
let keyContent = ''
|
||||
let foundBegin = false
|
||||
let foundEnd = false
|
||||
|
||||
for (const line of lines) {
|
||||
if (line === '-----BEGIN PRIVATE KEY-----') {
|
||||
foundBegin = true
|
||||
continue
|
||||
}
|
||||
if (line === '-----END PRIVATE KEY-----') {
|
||||
foundEnd = true
|
||||
break
|
||||
}
|
||||
if (foundBegin && !foundEnd) {
|
||||
keyContent += line
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundBegin || !foundEnd || !keyContent) {
|
||||
throw new Error('Invalid PEM format: missing BEGIN/END markers or key content')
|
||||
}
|
||||
|
||||
// 重新格式化为 64 字符一行
|
||||
const formattedContent = keyContent.match(/.{1,64}/g)?.join('\n') || keyContent
|
||||
|
||||
return `-----BEGIN PRIVATE KEY-----\n${formattedContent}\n-----END PRIVATE KEY-----`
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新构建 PEM 私钥
|
||||
*/
|
||||
function reconstructPemKey(key: string): string {
|
||||
// 移除所有空白字符和可能存在的不完整头尾
|
||||
let cleanKey = key.replace(/\s+/g, '')
|
||||
cleanKey = cleanKey.replace(/-----BEGIN[^-]*-----/g, '')
|
||||
cleanKey = cleanKey.replace(/-----END[^-]*-----/g, '')
|
||||
|
||||
// 确保私钥内容不为空
|
||||
if (!cleanKey) {
|
||||
throw new Error('Private key content is empty after cleaning')
|
||||
}
|
||||
|
||||
// 验证是否是有效的 Base64 字符
|
||||
if (!/^[A-Za-z0-9+/=]+$/.test(cleanKey)) {
|
||||
throw new Error('Private key contains invalid characters (not valid Base64)')
|
||||
}
|
||||
|
||||
// 格式化为 64 字符一行
|
||||
const formattedKey = cleanKey.match(/.{1,64}/g)?.join('\n') || cleanKey
|
||||
|
||||
return `-----BEGIN PRIVATE KEY-----\n${formattedKey}\n-----END PRIVATE KEY-----`
|
||||
}
|
||||
@ -241,7 +241,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@ai-sdk/openai-compatible@npm:0.2.14":
|
||||
"@ai-sdk/openai-compatible@npm:0.2.14, @ai-sdk/openai-compatible@npm:^0.2.14":
|
||||
version: 0.2.14
|
||||
resolution: "@ai-sdk/openai-compatible@npm:0.2.14"
|
||||
dependencies:
|
||||
@ -944,6 +944,7 @@ __metadata:
|
||||
"@ai-sdk/groq": "npm:^1.2.9"
|
||||
"@ai-sdk/mistral": "npm:^1.2.8"
|
||||
"@ai-sdk/openai": "npm:^1.3.22"
|
||||
"@ai-sdk/openai-compatible": "npm:^0.2.14"
|
||||
"@ai-sdk/perplexity": "npm:^1.1.9"
|
||||
"@ai-sdk/replicate": "npm:^0.2.8"
|
||||
"@ai-sdk/togetherai": "npm:^0.2.14"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user