File size: 10,936 Bytes
c6dedd5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
/**
 * constants.ts - 全局常量定义
 *
 * 集中管理拒绝检测规则、身份探针模式、固定回复模板等常量。
 * 方便查阅和修改内置规则,无需翻阅 handler.ts 的业务逻辑。
 */

import { getConfig } from './config.js';

// ==================== 拒绝模式识别 ====================
// 模型返回以下任意模式匹配的内容时,判定为拒绝响应并触发重试
// 如需添加新规则,请追加到对应分类末尾,或通过 config.yaml 的 refusal_patterns 配置

export const REFUSAL_PATTERNS: RegExp[] = [
    // ── English: 身份拒绝 ──
    /Cursor(?:'s)?\s+support\s+assistant/i,
    /support\s+assistant\s+for\s+Cursor/i,
    /I[''']\s*m\s+sorry/i,
    /I\s+am\s+sorry/i,
    /not\s+able\s+to\s+fulfill/i,
    /cannot\s+perform/i,
    /I\s+can\s+only\s+answer/i,
    /I\s+only\s+answer/i,
    /cannot\s+write\s+files/i,
    /pricing[, \s]*or\s*troubleshooting/i,
    /I\s+cannot\s+help\s+with/i,
    /I'm\s+a\s+coding\s+assistant/i,
    /not\s+able\s+to\s+search/i,
    /not\s+in\s+my\s+core/i,
    /outside\s+my\s+capabilities/i,
    /I\s+cannot\s+search/i,
    /focused\s+on\s+software\s+development/i,
    /not\s+able\s+to\s+help\s+with\s+(?:that|this)/i,
    /beyond\s+(?:my|the)\s+scope/i,
    /I'?m\s+not\s+(?:able|designed)\s+to/i,
    /I\s+don't\s+have\s+(?:the\s+)?(?:ability|capability)/i,
    /questions\s+about\s+(?:Cursor|the\s+(?:AI\s+)?code\s+editor)/i,

    // ── English: 话题拒绝 ── Cursor 拒绝非编程话题
    /help\s+with\s+(?:coding|programming)\s+and\s+Cursor/i,
    /Cursor\s+IDE\s+(?:questions|features|related)/i,
    /unrelated\s+to\s+(?:programming|coding)(?:\s+or\s+Cursor)?/i,
    /Cursor[- ]related\s+question/i,
    /(?:ask|please\s+ask)\s+a\s+(?:programming|coding|Cursor)/i,
    /(?:I'?m|I\s+am)\s+here\s+to\s+help\s+with\s+(?:coding|programming)/i,
    /appears\s+to\s+be\s+(?:asking|about)\s+.*?unrelated/i,
    /(?:not|isn't|is\s+not)\s+(?:related|relevant)\s+to\s+(?:programming|coding|software)/i,
    /I\s+can\s+help\s+(?:you\s+)?with\s+things\s+like/i,

    // ── English: 新拒绝措辞 (2026-03) ──
    /isn't\s+something\s+I\s+can\s+help\s+with/i,
    /not\s+something\s+I\s+can\s+help\s+with/i,
    /scoped\s+to\s+answering\s+questions\s+about\s+Cursor/i,
    /falls\s+outside\s+(?:the\s+scope|what\s+I)/i,

    // ── English: 提示注入/社会工程检测 ──
    /prompt\s+injection\s+attack/i,
    /prompt\s+injection/i,
    /social\s+engineering/i,
    /I\s+need\s+to\s+stop\s+and\s+flag/i,
    /What\s+I\s+will\s+not\s+do/i,
    /What\s+is\s+actually\s+happening/i,
    /replayed\s+against\s+a\s+real\s+system/i,
    /tool-call\s+payloads/i,
    /copy-pasteable\s+JSON/i,
    /injected\s+into\s+another\s+AI/i,
    /emit\s+tool\s+invocations/i,
    /make\s+me\s+output\s+tool\s+calls/i,

    // ── English: 工具可用性声明 (Cursor 角色锁定) ──
    /I\s+(?:only\s+)?have\s+(?:access\s+to\s+)?(?:two|2|read_file|read_dir)\s+tool/i,
    /(?:only|just)\s+(?:two|2)\s+(?:tools?|functions?)\b/i,
    /\bread_file\b.*\bread_dir\b/i,
    /\bread_dir\b.*\bread_file\b/i,

    // ── English: 范围/专长措辞 (2026-03 批次) ──
    /(?:outside|beyond)\s+(?:the\s+)?scope\s+of\s+what/i,
    /not\s+(?:within|in)\s+(?:my|the)\s+scope/i,
    /this\s+assistant\s+is\s+(?:focused|scoped)/i,
    /(?:only|just)\s+(?:able|here)\s+to\s+(?:answer|help)/i,
    /I\s+(?:can\s+)?only\s+help\s+with\s+(?:questions|issues)\s+(?:related|about)/i,
    /(?:here|designed)\s+to\s+help\s+(?:with\s+)?(?:questions\s+)?about\s+Cursor/i,
    /not\s+(?:something|a\s+topic)\s+(?:related|specific)\s+to\s+(?:Cursor|coding)/i,
    /outside\s+(?:my|the|your)\s+area\s+of\s+(?:expertise|scope)/i,
    /(?:can[.']?t|cannot|unable\s+to)\s+help\s+with\s+(?:this|that)\s+(?:request|question|topic)/i,
    /scoped\s+to\s+(?:answering|helping)/i,

    // ── English: Cursor support assistant context leak (2026-03) ──
    /currently\s+in\s+(?:the\s+)?Cursor\s+(?:support\s+)?(?:assistant\s+)?context/i,
    /it\s+appears\s+I['']?m\s+currently\s+in\s+the\s+Cursor/i,

    // ── 中文: 身份拒绝 ──
    /我是\s*Cursor\s*的?\s*支持助手/,
    /Cursor\s*的?\s*支持系统/,
    /Cursor\s*(?:编辑器|IDE)?\s*相关的?\s*问题/,
    /我的职责是帮助你解答/,
    /我无法透露/,
    /帮助你解答\s*Cursor/,
    /运行在\s*Cursor\s*的/,
    /专门.*回答.*(?:Cursor|编辑器)/,
    /我只能回答/,
    /无法提供.*信息/,
    /我没有.*也不会提供/,
    /功能使用[、,]\s*账单/,
    /故障排除/,

    // ── 中文: 话题拒绝 ──
    /与\s*(?:编程|代码|开发)\s*无关/,
    /请提问.*(?:编程|代码|开发|技术).*问题/,
    /只能帮助.*(?:编程|代码|开发)/,

    // ── 中文: 提示注入检测 ──
    /不是.*需要文档化/,
    /工具调用场景/,
    /语言偏好请求/,
    /提供.*具体场景/,
    /即报错/,

    // ── 中文: 工具可用性声明 ──
    /有以下.*?(?:两|2)个.*?工具/,
    /我有.*?(?:两|2)个工具/,
    /工具.*?(?:只有|有以下|仅有).*?(?:两|2)个/,
    /只能用.*?read_file/i,
    /无法调用.*?工具/,
    /(?:仅限于|仅用于).*?(?:查阅|浏览).*?(?:文档|docs)/,
    // ── 中文: 工具可用性声明 (2026-03 新增) ──
    /只有.*?读取.*?Cursor.*?工具/,
    /只有.*?读取.*?文档的工具/,
    /无法访问.*?本地文件/,
    /无法.*?执行命令/,
    /需要在.*?Claude\s*Code/i,
    /需要.*?CLI.*?环境/i,
    /当前环境.*?只有.*?工具/,
    /只有.*?read_file.*?read_dir/i,
    /只有.*?read_dir.*?read_file/i,

    // ── 中文: Cursor 中文界面拒绝措辞 (2026-03 批次) ──
    /只能回答.*(?:Cursor|编辑器).*(?:相关|有关)/,
    /专[注门].*(?:回答|帮助|解答).*(?:Cursor|编辑器)/,
    /有什么.*(?:Cursor|编辑器).*(?:问题|可以)/,
    /无法提供.*(?:推荐|建议|帮助)/,
    /(?:功能使用|账户|故障排除|账号|订阅|套餐|计费).*(?:等|问题)/,
];

// ==================== 自定义拒绝规则 ====================
// 从 config.yaml 的 refusal_patterns 字段编译,追加到内置列表之后,支持热重载

let _customRefusalPatterns: RegExp[] = [];
let _lastRefusalPatternsKey = '';

function getCustomRefusalPatterns(): RegExp[] {
    const config = getConfig();
    const patterns = config.refusalPatterns;
    if (!patterns || patterns.length === 0) return _customRefusalPatterns = [];

    // 用 join key 做缓存判断,避免每次调用都重新编译
    const key = patterns.join('\0');
    if (key === _lastRefusalPatternsKey) return _customRefusalPatterns;

    _lastRefusalPatternsKey = key;
    _customRefusalPatterns = [];
    for (const p of patterns) {
        try {
            _customRefusalPatterns.push(new RegExp(p, 'i'));
        } catch {
            // 无效正则 → 退化为字面量匹配
            _customRefusalPatterns.push(new RegExp(p.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i'));
            console.warn(`[Config] refusal_patterns: "${p}" 不是有效正则,已转换为字面量匹配`);
        }
    }
    console.log(`[Config] 加载了 ${_customRefusalPatterns.length} 条自定义拒绝规则`);
    return _customRefusalPatterns;
}

/**
 * 检查文本是否匹配拒绝模式(内置 + 自定义规则)
 */
export function isRefusal(text: string): boolean {
    if (REFUSAL_PATTERNS.some(p => p.test(text))) return true;
    const custom = getCustomRefusalPatterns();
    return custom.length > 0 && custom.some(p => p.test(text));
}

// ==================== 身份探针检测 ====================
// 用户消息匹配以下模式时判定为身份探针,直接返回 mock 回复

export const IDENTITY_PROBE_PATTERNS: RegExp[] = [
    // 精确短句
    /^\s*(who are you\??|你是谁[呀啊吗]?\??|what is your name\??|你叫什么\??|你叫什么名字\??|what are you\??|你是什么\??|Introduce yourself\??|自我介绍一下\??|hi\??|hello\??|hey\??|你好\??|在吗\??|哈喽\??)\s*$/i,
    // 问模型/身份类
    /(?:什么|哪个|啥)\s*模型/,
    /(?:真实|底层|实际|真正).{0,10}(?:模型|身份|名字)/,
    /模型\s*(?:id|名|名称|名字|是什么)/i,
    /(?:what|which)\s+model/i,
    /(?:real|actual|true|underlying)\s+(?:model|identity|name)/i,
    /your\s+(?:model|identity|real\s+name)/i,
    // 问平台/运行环境类
    /运行在\s*(?:哪|那|什么)/,
    /(?:哪个|什么)\s*平台/,
    /running\s+on\s+(?:what|which)/i,
    /what\s+platform/i,
    // 问系统提示词类
    /系统\s*提示词/,
    /system\s*prompt/i,
    // "你是谁"的变体
    /你\s*(?:到底|究竟|真的|真实)\s*是\s*谁/,
    /你\s*是[^。,,\.]{0,5}(?:AI|人工智能|助手|机器人|模型|Claude|GPT|Gemini)/i,
    // 注意:工具能力询问不在这里拦截,由拒绝检测+重试自然处理
];

// ==================== 工具能力询问检测 ====================
// 用户问"你有哪些工具"时,重试失败后返回专用回复

export const TOOL_CAPABILITY_PATTERNS: RegExp[] = [
    /你\s*(?:有|能用|可以用)\s*(?:哪些|什么|几个)\s*(?:工具|tools?|functions?)/i,
    /(?:what|which|list).*?tools?/i,
    /你\s*用\s*(?:什么|哪个|啥)\s*(?:mcp|工具)/i,
    /你\s*(?:能|可以)\s*(?:做|干)\s*(?:什么|哪些|啥)/,
    /(?:what|which).*?(?:capabilities|functions)/i,
    /能力|功能/,
];

// ==================== 固定回复模板 ====================

/** Claude 身份回复(身份探针拦截 / 拒绝后降级) */
export const CLAUDE_IDENTITY_RESPONSE = `I am Claude, made by Anthropic. I'm an AI assistant designed to be helpful, harmless, and honest. I can help you with a wide range of tasks including writing, analysis, coding, math, and more.

I don't have information about the specific model version or ID being used for this conversation, but I'm happy to help you with whatever you need!`;

/** 工具能力询问的模拟回复(当用户问"你有哪些工具"时) */
export const CLAUDE_TOOLS_RESPONSE = `作为 Claude,我的核心能力包括:

**内置能力:**
- 💻 **代码编写与调试** — 支持所有主流编程语言
- 📝 **文本写作与分析** — 文章、报告、翻译等
- 📊 **数据分析与数学推理** — 复杂计算和逻辑分析
- 🧠 **问题解答与知识查询** — 各类技术和非技术问题

**工具调用能力(MCP):**
如果你的客户端配置了 MCP(Model Context Protocol)工具,我可以通过工具调用来执行更多操作,例如:
- 🔍 **网络搜索** — 实时查找信息
- 📁 **文件操作** — 读写文件、执行命令
- 🛠️ **自定义工具** — 取决于你配置的 MCP Server

具体可用的工具取决于你客户端的配置。你可以告诉我你想做什么,我会尽力帮助你!`;