aicodeswitch 3.9.2 → 3.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -887,7 +887,8 @@ class ProxyServer {
|
|
|
887
887
|
return undefined;
|
|
888
888
|
const body = req.body;
|
|
889
889
|
const requestModel = body === null || body === void 0 ? void 0 : body.model;
|
|
890
|
-
const
|
|
890
|
+
const route = this.dbManager.getRoutes().find(r => r.id === routeId);
|
|
891
|
+
const contentType = forcedContentType || this.determineContentType(req, (route === null || route === void 0 ? void 0 : route.targetType) || 'claude-code', routeId);
|
|
891
892
|
// 高智商规则优先于 model-mapping,确保 !!/推断命中时不会被模型映射覆盖
|
|
892
893
|
if (contentType === 'high-iq') {
|
|
893
894
|
const highIqRules = enabledRules.filter(rule => rule.contentType === 'high-iq');
|
|
@@ -910,7 +911,32 @@ class ProxyServer {
|
|
|
910
911
|
return rule;
|
|
911
912
|
}
|
|
912
913
|
}
|
|
913
|
-
// 1.
|
|
914
|
+
// 1. 查找其他内容类型的规则
|
|
915
|
+
const contentTypeRules = enabledRules.filter(rule => rule.contentType === contentType);
|
|
916
|
+
// 过滤黑名单和token限制
|
|
917
|
+
for (const rule of contentTypeRules) {
|
|
918
|
+
const isBlacklisted = yield this.dbManager.isServiceBlacklisted(rule.targetServiceId, routeId, contentType);
|
|
919
|
+
if (isBlacklisted) {
|
|
920
|
+
continue;
|
|
921
|
+
}
|
|
922
|
+
// 检查并重置到期的规则
|
|
923
|
+
this.dbManager.checkAndResetRuleIfNeeded(rule.id);
|
|
924
|
+
this.dbManager.checkAndResetRequestCountIfNeeded(rule.id);
|
|
925
|
+
// 检查token限制(tokenLimit单位是k,需要乘以1000转换为实际token数)
|
|
926
|
+
if (rule.tokenLimit && rule.totalTokensUsed !== undefined && rule.totalTokensUsed >= rule.tokenLimit * 1000) {
|
|
927
|
+
continue; // 跳过超限规则
|
|
928
|
+
}
|
|
929
|
+
// 检查请求次数限制
|
|
930
|
+
if (rule.requestCountLimit && rule.totalRequestsUsed !== undefined && rule.totalRequestsUsed >= rule.requestCountLimit) {
|
|
931
|
+
continue; // 跳过超限规则
|
|
932
|
+
}
|
|
933
|
+
// 检查频率限制
|
|
934
|
+
if (this.isFrequencyLimitExceeded(rule)) {
|
|
935
|
+
continue; // 跳过达到频率限制的规则
|
|
936
|
+
}
|
|
937
|
+
return rule;
|
|
938
|
+
}
|
|
939
|
+
// 2. 然后查找 model-mapping 类型的规则
|
|
914
940
|
if (requestModel) {
|
|
915
941
|
const modelMappingRules = enabledRules.filter(rule => rule.contentType === 'model-mapping' &&
|
|
916
942
|
rule.replacedModel &&
|
|
@@ -939,31 +965,6 @@ class ProxyServer {
|
|
|
939
965
|
return rule;
|
|
940
966
|
}
|
|
941
967
|
}
|
|
942
|
-
// 2. 查找其他内容类型的规则
|
|
943
|
-
const contentTypeRules = enabledRules.filter(rule => rule.contentType === contentType);
|
|
944
|
-
// 过滤黑名单和token限制
|
|
945
|
-
for (const rule of contentTypeRules) {
|
|
946
|
-
const isBlacklisted = yield this.dbManager.isServiceBlacklisted(rule.targetServiceId, routeId, contentType);
|
|
947
|
-
if (isBlacklisted) {
|
|
948
|
-
continue;
|
|
949
|
-
}
|
|
950
|
-
// 检查并重置到期的规则
|
|
951
|
-
this.dbManager.checkAndResetRuleIfNeeded(rule.id);
|
|
952
|
-
this.dbManager.checkAndResetRequestCountIfNeeded(rule.id);
|
|
953
|
-
// 检查token限制(tokenLimit单位是k,需要乘以1000转换为实际token数)
|
|
954
|
-
if (rule.tokenLimit && rule.totalTokensUsed !== undefined && rule.totalTokensUsed >= rule.tokenLimit * 1000) {
|
|
955
|
-
continue; // 跳过超限规则
|
|
956
|
-
}
|
|
957
|
-
// 检查请求次数限制
|
|
958
|
-
if (rule.requestCountLimit && rule.totalRequestsUsed !== undefined && rule.totalRequestsUsed >= rule.requestCountLimit) {
|
|
959
|
-
continue; // 跳过超限规则
|
|
960
|
-
}
|
|
961
|
-
// 检查频率限制
|
|
962
|
-
if (this.isFrequencyLimitExceeded(rule)) {
|
|
963
|
-
continue; // 跳过达到频率限制的规则
|
|
964
|
-
}
|
|
965
|
-
return rule;
|
|
966
|
-
}
|
|
967
968
|
// 3. 最后返回 default 规则
|
|
968
969
|
const defaultRules = enabledRules.filter(rule => rule.contentType === 'default');
|
|
969
970
|
// 过滤黑名单和token限制
|
|
@@ -1003,7 +1004,8 @@ class ProxyServer {
|
|
|
1003
1004
|
const body = req.body;
|
|
1004
1005
|
const requestModel = body === null || body === void 0 ? void 0 : body.model;
|
|
1005
1006
|
const candidates = [];
|
|
1006
|
-
const
|
|
1007
|
+
const route = this.dbManager.getRoutes().find(r => r.id === routeId);
|
|
1008
|
+
const contentType = forcedContentType || this.determineContentType(req, (route === null || route === void 0 ? void 0 : route.targetType) || 'claude-code', routeId);
|
|
1007
1009
|
const prioritizeContentType = contentType === 'high-iq';
|
|
1008
1010
|
const modelMappingRules = requestModel
|
|
1009
1011
|
? enabledRules.filter(rule => rule.contentType === 'model-mapping' &&
|
|
@@ -1133,7 +1135,7 @@ class ProxyServer {
|
|
|
1133
1135
|
}
|
|
1134
1136
|
}
|
|
1135
1137
|
}
|
|
1136
|
-
determineContentType(req) {
|
|
1138
|
+
determineContentType(req, targetType, routeId) {
|
|
1137
1139
|
const body = req.body;
|
|
1138
1140
|
if (!body)
|
|
1139
1141
|
return 'default';
|
|
@@ -1145,8 +1147,10 @@ class ProxyServer {
|
|
|
1145
1147
|
if (explicitType) {
|
|
1146
1148
|
return explicitType;
|
|
1147
1149
|
}
|
|
1150
|
+
// 获取sessionId用于session级别的检测(如long-context)
|
|
1151
|
+
const sessionId = this.defaultExtractSessionId(req, targetType);
|
|
1148
1152
|
for (const detector of this.getContentTypeDetectors()) {
|
|
1149
|
-
if (detector.match(req, body)) {
|
|
1153
|
+
if (detector.match(req, body, sessionId, routeId)) {
|
|
1150
1154
|
return detector.type;
|
|
1151
1155
|
}
|
|
1152
1156
|
}
|
|
@@ -1158,17 +1162,17 @@ class ProxyServer {
|
|
|
1158
1162
|
type: 'image-understanding',
|
|
1159
1163
|
match: (_req, body) => this.containsImageContent(body.messages) || this.containsImageContent(body.input),
|
|
1160
1164
|
},
|
|
1161
|
-
{
|
|
1162
|
-
type: 'thinking',
|
|
1163
|
-
match: (_req, body) => this.hasThinkingSignal(body),
|
|
1164
|
-
},
|
|
1165
1165
|
{
|
|
1166
1166
|
type: 'high-iq',
|
|
1167
1167
|
match: (_req, body) => this.hasHighIqSignal(body),
|
|
1168
1168
|
},
|
|
1169
1169
|
{
|
|
1170
1170
|
type: 'long-context',
|
|
1171
|
-
match: (_req, body) => this.hasLongContextSignal(body),
|
|
1171
|
+
match: (_req, body, sessionId, routeId) => this.hasLongContextSignal(body, sessionId, routeId),
|
|
1172
|
+
},
|
|
1173
|
+
{
|
|
1174
|
+
type: 'thinking',
|
|
1175
|
+
match: (_req, body) => this.hasThinkingSignal(body),
|
|
1172
1176
|
},
|
|
1173
1177
|
{
|
|
1174
1178
|
type: 'background',
|
|
@@ -1574,8 +1578,8 @@ class ProxyServer {
|
|
|
1574
1578
|
];
|
|
1575
1579
|
return candidates.some((value) => value === true || value === 'background');
|
|
1576
1580
|
}
|
|
1577
|
-
hasLongContextSignal(body) {
|
|
1578
|
-
var _a, _b;
|
|
1581
|
+
hasLongContextSignal(body, sessionId, routeId) {
|
|
1582
|
+
var _a, _b, _c;
|
|
1579
1583
|
const explicit = [
|
|
1580
1584
|
body === null || body === void 0 ? void 0 : body.long_context,
|
|
1581
1585
|
body === null || body === void 0 ? void 0 : body.longContext,
|
|
@@ -1585,6 +1589,22 @@ class ProxyServer {
|
|
|
1585
1589
|
if (explicit.some((value) => value === true)) {
|
|
1586
1590
|
return true;
|
|
1587
1591
|
}
|
|
1592
|
+
// 检查session累积tokens
|
|
1593
|
+
if (sessionId && routeId) {
|
|
1594
|
+
const session = this.dbManager.getSession(sessionId);
|
|
1595
|
+
if (session && session.totalTokens > 0) {
|
|
1596
|
+
// 查找该route下的long-context规则,获取阈值配置
|
|
1597
|
+
const rules = this.getRulesByRouteId(routeId);
|
|
1598
|
+
const longContextRule = rules === null || rules === void 0 ? void 0 : rules.find(rule => rule.contentType === 'long-context' && !rule.isDisabled);
|
|
1599
|
+
// 默认阈值为1M tokens (1000k)
|
|
1600
|
+
const defaultThreshold = 1000; // 单位:k
|
|
1601
|
+
const threshold = (_c = longContextRule === null || longContextRule === void 0 ? void 0 : longContextRule.sessionTokenThreshold) !== null && _c !== void 0 ? _c : defaultThreshold;
|
|
1602
|
+
// 如果session累积tokens超过阈值,则认为是long-context
|
|
1603
|
+
if (session.totalTokens >= threshold * 1000) {
|
|
1604
|
+
return true;
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1588
1608
|
const maxTokens = this.extractNumericField(body, [
|
|
1589
1609
|
'max_tokens',
|
|
1590
1610
|
'max_output_tokens',
|
|
@@ -2273,8 +2293,9 @@ class ProxyServer {
|
|
|
2273
2293
|
// Session 索引逻辑
|
|
2274
2294
|
const sessionId = this.defaultExtractSessionId(req, targetType);
|
|
2275
2295
|
if (sessionId) {
|
|
2276
|
-
|
|
2277
|
-
|
|
2296
|
+
// 正确计算当前请求的tokens:优先使用totalTokens,否则使用input+output
|
|
2297
|
+
const totalTokens = (usageForLog === null || usageForLog === void 0 ? void 0 : usageForLog.totalTokens) ||
|
|
2298
|
+
(((usageForLog === null || usageForLog === void 0 ? void 0 : usageForLog.inputTokens) || 0) + ((usageForLog === null || usageForLog === void 0 ? void 0 : usageForLog.outputTokens) || 0));
|
|
2278
2299
|
const sessionTitle = this.defaultExtractSessionTitle(req, sessionId);
|
|
2279
2300
|
const existingSession = this.dbManager.getSession(sessionId);
|
|
2280
2301
|
this.dbManager.upsertSession({
|
|
@@ -2298,7 +2319,8 @@ class ProxyServer {
|
|
|
2298
2319
|
}
|
|
2299
2320
|
// 更新规则的token使用量(只在成功请求时更新)
|
|
2300
2321
|
if (usageForLog && statusCode < 400) {
|
|
2301
|
-
const totalTokens =
|
|
2322
|
+
const totalTokens = usageForLog.totalTokens ||
|
|
2323
|
+
((usageForLog.inputTokens || 0) + (usageForLog.outputTokens || 0));
|
|
2302
2324
|
if (totalTokens > 0) {
|
|
2303
2325
|
this.dbManager.incrementRuleTokenUsage(rule.id, totalTokens);
|
|
2304
2326
|
// 获取更新后的规则数据并广播
|