aicodeswitch 5.2.2 → 5.2.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.
|
@@ -122,10 +122,14 @@ function extractMessageContent(content) {
|
|
|
122
122
|
/**
|
|
123
123
|
* 检测消息是否为 Claude Code 的 compact 命令请求。
|
|
124
124
|
*
|
|
125
|
+
* 采用两级检测策略:
|
|
126
|
+
* - 严格匹配:四个关键词全部命中(适配已知格式)
|
|
127
|
+
* - 宽松匹配:"TEXT ONLY" + "<summary>" 组合(覆盖 prompt 格式变化)
|
|
128
|
+
*
|
|
125
129
|
* Compact 命令触发时,Claude Code 会在 messages 末尾插入一条特殊指令:
|
|
126
130
|
* - role 为 "user"
|
|
127
131
|
* - content 为数组,包含一个 text 块
|
|
128
|
-
* - text
|
|
132
|
+
* - text 内容包含 "CRITICAL: Respond with TEXT ONLY" 等标识
|
|
129
133
|
* - 包含对话摘要生成指令,要求输出 <analysis> 和 <summary> 结构
|
|
130
134
|
*/
|
|
131
135
|
function isClaudeCompactRequest(message) {
|
|
@@ -139,10 +143,21 @@ function isClaudeCompactRequest(message) {
|
|
|
139
143
|
for (const block of content) {
|
|
140
144
|
if ((block === null || block === void 0 ? void 0 : block.type) === 'text' && typeof block.text === 'string') {
|
|
141
145
|
const text = block.text;
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
+
const hasTextOnly = text.includes('TEXT ONLY');
|
|
147
|
+
const hasSummary = text.includes('<summary>');
|
|
148
|
+
const hasCritical = text.includes('CRITICAL: Respond with TEXT ONLY');
|
|
149
|
+
const hasDetailedSummary = text.includes('create a detailed summary of the conversation');
|
|
150
|
+
const hasAnalysis = text.includes('<analysis>');
|
|
151
|
+
// 严格匹配:Claude Code 标准格式(四个关键词)
|
|
152
|
+
if (hasCritical && hasDetailedSummary && hasAnalysis && hasSummary) {
|
|
153
|
+
console.log('[COMPACT] Strict match: all 4 markers found');
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
// 宽松匹配:覆盖 Claude Code prompt 格式变化
|
|
157
|
+
// "TEXT ONLY" 是紧凑指令的核心标识,<summary> 是输出格式标签
|
|
158
|
+
// 两者组合在非 compact 请求中几乎不可能同时出现
|
|
159
|
+
if (hasTextOnly && hasSummary) {
|
|
160
|
+
console.log(`[COMPACT] Loose match: CRITICAL=${hasCritical}, detailed_summary=${hasDetailedSummary}, <analysis>=${hasAnalysis}`);
|
|
146
161
|
return true;
|
|
147
162
|
}
|
|
148
163
|
}
|
|
@@ -150,13 +165,22 @@ function isClaudeCompactRequest(message) {
|
|
|
150
165
|
return false;
|
|
151
166
|
}
|
|
152
167
|
/**
|
|
153
|
-
*
|
|
168
|
+
* 检测消息列表中是否包含 Claude Code compact 请求。
|
|
169
|
+
*
|
|
170
|
+
* 从最后一条消息开始往前搜索,最多检查 3 条,
|
|
171
|
+
* 处理 compact 指令后面可能跟了 assistant 占位消息的边缘情况。
|
|
154
172
|
*/
|
|
155
173
|
function isLastClaudeMessageCompact(messages) {
|
|
156
174
|
if (!Array.isArray(messages) || messages.length === 0) {
|
|
157
175
|
return false;
|
|
158
176
|
}
|
|
159
|
-
|
|
177
|
+
const checkCount = Math.min(messages.length, 3);
|
|
178
|
+
for (let i = messages.length - 1; i >= messages.length - checkCount; i--) {
|
|
179
|
+
if (isClaudeCompactRequest(messages[i])) {
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return false;
|
|
160
184
|
}
|
|
161
185
|
/**
|
|
162
186
|
* 检测请求是否为 Codex 的 compact(压缩)请求。
|
|
@@ -1779,6 +1779,28 @@ class ProxyServer {
|
|
|
1779
1779
|
return rule;
|
|
1780
1780
|
}
|
|
1781
1781
|
}
|
|
1782
|
+
// compact 规则同样拥有最高优先级,确保压缩请求不被其他规则覆盖
|
|
1783
|
+
if (contentType === 'compact') {
|
|
1784
|
+
const compactRules = enabledRules.filter(rule => rule.contentType === 'compact');
|
|
1785
|
+
for (const rule of compactRules) {
|
|
1786
|
+
const isBlacklisted = yield this.dbManager.isServiceBlacklisted(rule.targetServiceId, routeId, rule.contentType);
|
|
1787
|
+
if (isBlacklisted) {
|
|
1788
|
+
continue;
|
|
1789
|
+
}
|
|
1790
|
+
this.dbManager.checkAndResetRuleIfNeeded(rule.id);
|
|
1791
|
+
this.dbManager.checkAndResetRequestCountIfNeeded(rule.id);
|
|
1792
|
+
if (rule.tokenLimit && rule.totalTokensUsed !== undefined && rule.totalTokensUsed >= rule.tokenLimit * 1000) {
|
|
1793
|
+
continue;
|
|
1794
|
+
}
|
|
1795
|
+
if (rule.requestCountLimit && rule.totalRequestsUsed !== undefined && rule.totalRequestsUsed >= rule.requestCountLimit) {
|
|
1796
|
+
continue;
|
|
1797
|
+
}
|
|
1798
|
+
if (this.isFrequencyLimitExceeded(rule)) {
|
|
1799
|
+
continue;
|
|
1800
|
+
}
|
|
1801
|
+
return rule;
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1782
1804
|
// 1. 查找其他内容类型的规则
|
|
1783
1805
|
const contentTypeRules = enabledRules.filter(rule => rule.contentType === contentType);
|
|
1784
1806
|
// 过滤黑名单和token限制
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aicodeswitch",
|
|
3
|
-
"version": "5.2.
|
|
3
|
+
"version": "5.2.3",
|
|
4
4
|
"description": "A tool to help you manage AI programming tools to access large language models locally. It allows your Claude Code, Codex and other tools to no longer be limited to official models.",
|
|
5
5
|
"author": "tangshuang",
|
|
6
6
|
"license": "GPL-3.0",
|