mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-03-30 00:51:04 +00:00
fix: 移除1m模型限制和配套的apikey功能
This commit is contained in:
@@ -1313,7 +1313,6 @@ const authenticateApiKey = async (req, res, next) => {
|
|||||||
restrictedModels: validation.keyData.restrictedModels,
|
restrictedModels: validation.keyData.restrictedModels,
|
||||||
enableClientRestriction: validation.keyData.enableClientRestriction,
|
enableClientRestriction: validation.keyData.enableClientRestriction,
|
||||||
allowedClients: validation.keyData.allowedClients,
|
allowedClients: validation.keyData.allowedClients,
|
||||||
allow1mContext: validation.keyData.allow1mContext,
|
|
||||||
dailyCostLimit: validation.keyData.dailyCostLimit,
|
dailyCostLimit: validation.keyData.dailyCostLimit,
|
||||||
dailyCost: validation.keyData.dailyCost,
|
dailyCost: validation.keyData.dailyCost,
|
||||||
totalCostLimit: validation.keyData.totalCostLimit,
|
totalCostLimit: validation.keyData.totalCostLimit,
|
||||||
|
|||||||
@@ -773,7 +773,7 @@ class RedisClient {
|
|||||||
const parsed = { ...data }
|
const parsed = { ...data }
|
||||||
|
|
||||||
// 布尔字段
|
// 布尔字段
|
||||||
const boolFields = ['isActive', 'enableModelRestriction', 'isDeleted', 'allow1mContext']
|
const boolFields = ['isActive', 'enableModelRestriction', 'isDeleted']
|
||||||
for (const field of boolFields) {
|
for (const field of boolFields) {
|
||||||
if (parsed[field] !== undefined) {
|
if (parsed[field] !== undefined) {
|
||||||
parsed[field] = parsed[field] === 'true'
|
parsed[field] = parsed[field] === 'true'
|
||||||
|
|||||||
@@ -1483,7 +1483,6 @@ router.post('/api-keys', authenticateAdmin, async (req, res) => {
|
|||||||
restrictedModels,
|
restrictedModels,
|
||||||
enableClientRestriction,
|
enableClientRestriction,
|
||||||
allowedClients,
|
allowedClients,
|
||||||
allow1mContext,
|
|
||||||
dailyCostLimit,
|
dailyCostLimit,
|
||||||
totalCostLimit,
|
totalCostLimit,
|
||||||
weeklyOpusCostLimit,
|
weeklyOpusCostLimit,
|
||||||
@@ -1563,10 +1562,6 @@ router.post('/api-keys', authenticateAdmin, async (req, res) => {
|
|||||||
return res.status(400).json({ error: 'Allowed clients must be an array' })
|
return res.status(400).json({ error: 'Allowed clients must be an array' })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allow1mContext !== undefined && typeof allow1mContext !== 'boolean') {
|
|
||||||
return res.status(400).json({ error: 'allow1mContext must be a boolean' })
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证标签字段
|
// 验证标签字段
|
||||||
if (tags !== undefined && !Array.isArray(tags)) {
|
if (tags !== undefined && !Array.isArray(tags)) {
|
||||||
return res.status(400).json({ error: 'Tags must be an array' })
|
return res.status(400).json({ error: 'Tags must be an array' })
|
||||||
@@ -1667,7 +1662,6 @@ router.post('/api-keys', authenticateAdmin, async (req, res) => {
|
|||||||
restrictedModels,
|
restrictedModels,
|
||||||
enableClientRestriction,
|
enableClientRestriction,
|
||||||
allowedClients,
|
allowedClients,
|
||||||
allow1mContext,
|
|
||||||
dailyCostLimit,
|
dailyCostLimit,
|
||||||
totalCostLimit,
|
totalCostLimit,
|
||||||
weeklyOpusCostLimit,
|
weeklyOpusCostLimit,
|
||||||
@@ -1719,7 +1713,6 @@ router.post('/api-keys/batch', authenticateAdmin, async (req, res) => {
|
|||||||
restrictedModels,
|
restrictedModels,
|
||||||
enableClientRestriction,
|
enableClientRestriction,
|
||||||
allowedClients,
|
allowedClients,
|
||||||
allow1mContext,
|
|
||||||
dailyCostLimit,
|
dailyCostLimit,
|
||||||
totalCostLimit,
|
totalCostLimit,
|
||||||
weeklyOpusCostLimit,
|
weeklyOpusCostLimit,
|
||||||
@@ -1785,7 +1778,6 @@ router.post('/api-keys/batch', authenticateAdmin, async (req, res) => {
|
|||||||
restrictedModels,
|
restrictedModels,
|
||||||
enableClientRestriction,
|
enableClientRestriction,
|
||||||
allowedClients,
|
allowedClients,
|
||||||
allow1mContext,
|
|
||||||
dailyCostLimit,
|
dailyCostLimit,
|
||||||
totalCostLimit,
|
totalCostLimit,
|
||||||
weeklyOpusCostLimit,
|
weeklyOpusCostLimit,
|
||||||
@@ -1947,9 +1939,6 @@ router.put('/api-keys/batch', authenticateAdmin, async (req, res) => {
|
|||||||
if (updates.serviceRates !== undefined) {
|
if (updates.serviceRates !== undefined) {
|
||||||
finalUpdates.serviceRates = updates.serviceRates
|
finalUpdates.serviceRates = updates.serviceRates
|
||||||
}
|
}
|
||||||
if (updates.allow1mContext !== undefined) {
|
|
||||||
finalUpdates.allow1mContext = updates.allow1mContext
|
|
||||||
}
|
|
||||||
if (updates.weeklyResetDay !== undefined) {
|
if (updates.weeklyResetDay !== undefined) {
|
||||||
const day = Number(updates.weeklyResetDay)
|
const day = Number(updates.weeklyResetDay)
|
||||||
if (Number.isInteger(day) && day >= 1 && day <= 7) {
|
if (Number.isInteger(day) && day >= 1 && day <= 7) {
|
||||||
@@ -2090,7 +2079,6 @@ router.put('/api-keys/:keyId', authenticateAdmin, async (req, res) => {
|
|||||||
restrictedModels,
|
restrictedModels,
|
||||||
enableClientRestriction,
|
enableClientRestriction,
|
||||||
allowedClients,
|
allowedClients,
|
||||||
allow1mContext,
|
|
||||||
expiresAt,
|
expiresAt,
|
||||||
dailyCostLimit,
|
dailyCostLimit,
|
||||||
totalCostLimit,
|
totalCostLimit,
|
||||||
@@ -2224,13 +2212,6 @@ router.put('/api-keys/:keyId', authenticateAdmin, async (req, res) => {
|
|||||||
updates.allowedClients = allowedClients
|
updates.allowedClients = allowedClients
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allow1mContext !== undefined) {
|
|
||||||
if (typeof allow1mContext !== 'boolean') {
|
|
||||||
return res.status(400).json({ error: 'allow1mContext must be a boolean' })
|
|
||||||
}
|
|
||||||
updates.allow1mContext = allow1mContext
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理过期时间字段
|
// 处理过期时间字段
|
||||||
if (expiresAt !== undefined) {
|
if (expiresAt !== undefined) {
|
||||||
if (expiresAt === null) {
|
if (expiresAt === null) {
|
||||||
|
|||||||
@@ -197,18 +197,6 @@ async function handleMessagesRequest(req, res) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测 1M 上下文窗口请求(anthropic-beta 包含 context-1m)
|
|
||||||
const betaHeader = (req.headers['anthropic-beta'] || '').toLowerCase()
|
|
||||||
const is1mContextRequest = betaHeader.includes('context-1m')
|
|
||||||
if (is1mContextRequest && !req.apiKey.allow1mContext) {
|
|
||||||
return res.status(403).json({
|
|
||||||
error: {
|
|
||||||
type: 'forbidden',
|
|
||||||
message: '该 API Key 未启用 1M 上下文窗口,请联系管理员开启或切换为非 [1m] 模型'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.api('📥 /v1/messages request received', {
|
logger.api('📥 /v1/messages request received', {
|
||||||
model: req.body.model || null,
|
model: req.body.model || null,
|
||||||
forcedVendor,
|
forcedVendor,
|
||||||
@@ -389,13 +377,6 @@ async function handleMessagesRequest(req, res) {
|
|||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1M 上下文窗口:记录日志(admin 已通过 allow1mContext 授权,信任其决定)
|
|
||||||
if (is1mContextRequest) {
|
|
||||||
logger.api(
|
|
||||||
`📐 1M context request allowed for key: ${req.apiKey.name}, accountType: ${accountType}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 🔗 在成功调度后建立会话绑定(仅 claude-official 类型)
|
// 🔗 在成功调度后建立会话绑定(仅 claude-official 类型)
|
||||||
// claude-official 只接受:1) 新会话 2) 已绑定的会话
|
// claude-official 只接受:1) 新会话 2) 已绑定的会话
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -153,7 +153,6 @@ class ApiKeyService {
|
|||||||
restrictedModels = [],
|
restrictedModels = [],
|
||||||
enableClientRestriction = false,
|
enableClientRestriction = false,
|
||||||
allowedClients = [],
|
allowedClients = [],
|
||||||
allow1mContext = false,
|
|
||||||
dailyCostLimit = 0,
|
dailyCostLimit = 0,
|
||||||
totalCostLimit = 0,
|
totalCostLimit = 0,
|
||||||
weeklyOpusCostLimit = 0,
|
weeklyOpusCostLimit = 0,
|
||||||
@@ -198,7 +197,6 @@ class ApiKeyService {
|
|||||||
restrictedModels: JSON.stringify(restrictedModels || []),
|
restrictedModels: JSON.stringify(restrictedModels || []),
|
||||||
enableClientRestriction: String(enableClientRestriction || false),
|
enableClientRestriction: String(enableClientRestriction || false),
|
||||||
allowedClients: JSON.stringify(allowedClients || []),
|
allowedClients: JSON.stringify(allowedClients || []),
|
||||||
allow1mContext: String(allow1mContext || false),
|
|
||||||
dailyCostLimit: String(dailyCostLimit || 0),
|
dailyCostLimit: String(dailyCostLimit || 0),
|
||||||
totalCostLimit: String(totalCostLimit || 0),
|
totalCostLimit: String(totalCostLimit || 0),
|
||||||
weeklyOpusCostLimit: String(weeklyOpusCostLimit || 0),
|
weeklyOpusCostLimit: String(weeklyOpusCostLimit || 0),
|
||||||
@@ -453,7 +451,6 @@ class ApiKeyService {
|
|||||||
restrictedModels,
|
restrictedModels,
|
||||||
enableClientRestriction: keyData.enableClientRestriction === 'true',
|
enableClientRestriction: keyData.enableClientRestriction === 'true',
|
||||||
allowedClients,
|
allowedClients,
|
||||||
allow1mContext: keyData.allow1mContext === 'true',
|
|
||||||
dailyCostLimit,
|
dailyCostLimit,
|
||||||
totalCostLimit,
|
totalCostLimit,
|
||||||
weeklyOpusCostLimit,
|
weeklyOpusCostLimit,
|
||||||
@@ -1231,7 +1228,6 @@ class ApiKeyService {
|
|||||||
'restrictedModels',
|
'restrictedModels',
|
||||||
'enableClientRestriction',
|
'enableClientRestriction',
|
||||||
'allowedClients',
|
'allowedClients',
|
||||||
'allow1mContext',
|
|
||||||
'dailyCostLimit',
|
'dailyCostLimit',
|
||||||
'totalCostLimit',
|
'totalCostLimit',
|
||||||
'weeklyOpusCostLimit',
|
'weeklyOpusCostLimit',
|
||||||
|
|||||||
@@ -322,32 +322,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 允许 1M 上下文 -->
|
|
||||||
<div>
|
|
||||||
<div class="mb-3 flex items-center gap-4">
|
|
||||||
<label class="text-sm font-semibold text-gray-700 dark:text-gray-300"
|
|
||||||
>允许 1M 上下文</label
|
|
||||||
>
|
|
||||||
<div class="flex gap-4">
|
|
||||||
<label class="flex cursor-pointer items-center">
|
|
||||||
<input v-model="form.allow1mContext" class="mr-2" type="radio" :value="true" />
|
|
||||||
<span class="text-sm text-gray-700 dark:text-gray-300">启用</span>
|
|
||||||
</label>
|
|
||||||
<label class="flex cursor-pointer items-center">
|
|
||||||
<input v-model="form.allow1mContext" class="mr-2" type="radio" :value="false" />
|
|
||||||
<span class="text-sm text-gray-700 dark:text-gray-300">禁用</span>
|
|
||||||
</label>
|
|
||||||
<label class="flex cursor-pointer items-center">
|
|
||||||
<input v-model="form.allow1mContext" class="mr-2" type="radio" :value="null" />
|
|
||||||
<span class="text-sm text-gray-700 dark:text-gray-300">不修改</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p class="ml-0 text-xs text-gray-500 dark:text-gray-400">
|
|
||||||
启用后允许使用 [1m] 模型(需要 Bedrock 账户支持)
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 服务权限 -->
|
<!-- 服务权限 -->
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
|
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
|
||||||
@@ -583,8 +557,7 @@ const form = reactive({
|
|||||||
bedrockAccountId: '',
|
bedrockAccountId: '',
|
||||||
droidAccountId: '',
|
droidAccountId: '',
|
||||||
tags: [],
|
tags: [],
|
||||||
isActive: null, // null表示不修改
|
isActive: null // null表示不修改
|
||||||
allow1mContext: null // null表示不修改
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const UNCHANGED_OPTION_VALUE = '__KEEP_ORIGINAL__'
|
const UNCHANGED_OPTION_VALUE = '__KEEP_ORIGINAL__'
|
||||||
@@ -869,11 +842,6 @@ const batchUpdateApiKeys = async () => {
|
|||||||
updates.isActive = form.isActive
|
updates.isActive = form.isActive
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1M 上下文
|
|
||||||
if (form.allow1mContext !== null) {
|
|
||||||
updates.allow1mContext = form.allow1mContext
|
|
||||||
}
|
|
||||||
|
|
||||||
// 标签处理
|
// 标签处理
|
||||||
if (tagOperation.value !== 'none') {
|
if (tagOperation.value !== 'none') {
|
||||||
updates.tags = form.tags
|
updates.tags = form.tags
|
||||||
|
|||||||
@@ -938,27 +938,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 允许 1M 上下文 -->
|
|
||||||
<div>
|
|
||||||
<div class="mb-2 flex items-center">
|
|
||||||
<input
|
|
||||||
id="allow1mContext"
|
|
||||||
v-model="form.allow1mContext"
|
|
||||||
class="h-4 w-4 rounded border-gray-300 bg-gray-100 text-blue-600 focus:ring-blue-500"
|
|
||||||
type="checkbox"
|
|
||||||
/>
|
|
||||||
<label
|
|
||||||
class="ml-2 cursor-pointer text-sm font-semibold text-gray-700 dark:text-gray-300"
|
|
||||||
for="allow1mContext"
|
|
||||||
>
|
|
||||||
允许 1M 上下文
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<p class="ml-6 text-xs text-gray-500 dark:text-gray-400">
|
|
||||||
启用后允许使用 [1m] 模型(需要 Bedrock 账户支持)
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex gap-3 pt-2">
|
<div class="flex gap-3 pt-2">
|
||||||
<button
|
<button
|
||||||
class="flex-1 rounded-lg bg-gray-100 px-4 py-2.5 text-sm font-semibold text-gray-700 transition-colors hover:bg-gray-200 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600"
|
class="flex-1 rounded-lg bg-gray-100 px-4 py-2.5 text-sm font-semibold text-gray-700 transition-colors hover:bg-gray-200 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600"
|
||||||
@@ -1135,7 +1114,6 @@ const form = reactive({
|
|||||||
modelInput: '',
|
modelInput: '',
|
||||||
enableClientRestriction: false,
|
enableClientRestriction: false,
|
||||||
allowedClients: [],
|
allowedClients: [],
|
||||||
allow1mContext: false,
|
|
||||||
tags: []
|
tags: []
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1564,8 +1542,7 @@ const createApiKey = async () => {
|
|||||||
enableModelRestriction: form.enableModelRestriction,
|
enableModelRestriction: form.enableModelRestriction,
|
||||||
restrictedModels: form.restrictedModels,
|
restrictedModels: form.restrictedModels,
|
||||||
enableClientRestriction: form.enableClientRestriction,
|
enableClientRestriction: form.enableClientRestriction,
|
||||||
allowedClients: form.allowedClients,
|
allowedClients: form.allowedClients
|
||||||
allow1mContext: form.allow1mContext
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理Claude账户绑定(区分OAuth和Console)
|
// 处理Claude账户绑定(区分OAuth和Console)
|
||||||
|
|||||||
@@ -776,27 +776,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 允许 1M 上下文 -->
|
|
||||||
<div>
|
|
||||||
<div class="mb-2 flex items-center">
|
|
||||||
<input
|
|
||||||
id="editAllow1mContext"
|
|
||||||
v-model="form.allow1mContext"
|
|
||||||
class="h-4 w-4 rounded border-gray-300 bg-gray-100 text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700"
|
|
||||||
type="checkbox"
|
|
||||||
/>
|
|
||||||
<label
|
|
||||||
class="ml-2 cursor-pointer text-sm font-semibold text-gray-700 dark:text-gray-300"
|
|
||||||
for="editAllow1mContext"
|
|
||||||
>
|
|
||||||
允许 1M 上下文
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<p class="ml-6 text-xs text-gray-500 dark:text-gray-400">
|
|
||||||
启用后允许使用 [1m] 模型(需要 Bedrock 账户支持)
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex gap-3 pt-4">
|
<div class="flex gap-3 pt-4">
|
||||||
<button
|
<button
|
||||||
class="flex-1 rounded-xl bg-gray-100 px-6 py-3 font-semibold text-gray-700 transition-colors hover:bg-gray-200 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600"
|
class="flex-1 rounded-xl bg-gray-100 px-6 py-3 font-semibold text-gray-700 transition-colors hover:bg-gray-200 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600"
|
||||||
@@ -969,7 +948,6 @@ const form = reactive({
|
|||||||
modelInput: '',
|
modelInput: '',
|
||||||
enableClientRestriction: false,
|
enableClientRestriction: false,
|
||||||
allowedClients: [],
|
allowedClients: [],
|
||||||
allow1mContext: false,
|
|
||||||
tags: [],
|
tags: [],
|
||||||
isActive: true,
|
isActive: true,
|
||||||
ownerId: '' // 新增:所有者ID
|
ownerId: '' // 新增:所有者ID
|
||||||
@@ -1153,9 +1131,6 @@ const updateApiKey = async () => {
|
|||||||
data.enableClientRestriction = form.enableClientRestriction
|
data.enableClientRestriction = form.enableClientRestriction
|
||||||
data.allowedClients = form.allowedClients
|
data.allowedClients = form.allowedClients
|
||||||
|
|
||||||
// 1M 上下文
|
|
||||||
data.allow1mContext = form.allow1mContext
|
|
||||||
|
|
||||||
// 活跃状态
|
// 活跃状态
|
||||||
data.isActive = form.isActive
|
data.isActive = form.isActive
|
||||||
|
|
||||||
@@ -1473,8 +1448,6 @@ onMounted(async () => {
|
|||||||
props.apiKey.enableModelRestriction === true || props.apiKey.enableModelRestriction === 'true'
|
props.apiKey.enableModelRestriction === true || props.apiKey.enableModelRestriction === 'true'
|
||||||
form.enableClientRestriction =
|
form.enableClientRestriction =
|
||||||
props.apiKey.enableClientRestriction === true || props.apiKey.enableClientRestriction === 'true'
|
props.apiKey.enableClientRestriction === true || props.apiKey.enableClientRestriction === 'true'
|
||||||
form.allow1mContext =
|
|
||||||
props.apiKey.allow1mContext === true || props.apiKey.allow1mContext === 'true'
|
|
||||||
// 初始化活跃状态,默认为 true(强制转换为布尔值,因为Redis返回字符串)
|
// 初始化活跃状态,默认为 true(强制转换为布尔值,因为Redis返回字符串)
|
||||||
form.isActive =
|
form.isActive =
|
||||||
props.apiKey.isActive === undefined ||
|
props.apiKey.isActive === undefined ||
|
||||||
|
|||||||
Reference in New Issue
Block a user