hermes-connect-services 1.2.0 → 1.3.0
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.
- package/lib/stall_detector.py +61 -16
- package/package.json +1 -1
package/lib/stall_detector.py
CHANGED
|
@@ -32,15 +32,19 @@ MIN_WEIGHTED_CHARS = 14.0
|
|
|
32
32
|
# 请求用户裁决 / 提供输入的措辞。命中即否决。
|
|
33
33
|
REQUEST_PATTERNS = [
|
|
34
34
|
# 中文:把决定权交回用户
|
|
35
|
-
r"请你?(
|
|
35
|
+
r"请你?(?:确认|批准|授权|选择|决定|提供|粘贴|发送|告知|告诉|现在|立刻|马上|配合|扫码|扫|在)",
|
|
36
36
|
r"你(?:可以|需要|来)(?:确认|决定|选择|提供|先)",
|
|
37
37
|
r"需要你(?:确认|决定|操作|提供|回复|选择)",
|
|
38
38
|
r"(?:是否|要不要|需不需要|要不要我|需要我)(?:继续|执行|我|帮|先|再)?",
|
|
39
|
-
r"等你(
|
|
40
|
-
r"告诉我(
|
|
39
|
+
r"等你(?:确认|回复|决定|操作|安排)",
|
|
40
|
+
r"告诉我(?:你|是否|要|结果|选择|一声|什么时候)",
|
|
41
|
+
r"(?:说|吱|喊)一声",
|
|
42
|
+
r"你(?:点个?头|说[「“\"']?开[」”\"']?)(?:我就|我立刻|我马上)?",
|
|
43
|
+
r"要我[^。!?\n]{0,24}(?:就|的话|吗)",
|
|
44
|
+
r"扫完(?:不用回复|告诉我|说一声)",
|
|
41
45
|
r"让我知道",
|
|
42
|
-
r"由你(
|
|
43
|
-
r"你(?:先|来)(
|
|
46
|
+
r"由你(?:决定|来|选|定)",
|
|
47
|
+
r"你(?:先|来)(?:确认|决定|操作|选|说)",
|
|
44
48
|
r"确认后(?:我)?再",
|
|
45
49
|
r"(?:你|您)看(?:看|一下)?(?:是否|要不要|行不行)",
|
|
46
50
|
# English: handing the decision back
|
|
@@ -55,11 +59,18 @@ REQUEST_PATTERNS = [
|
|
|
55
59
|
r"\bwaiting (?:for|on) your\b",
|
|
56
60
|
]
|
|
57
61
|
|
|
62
|
+
# 确认/复述长期规则或未来条件约定(「以后遇到…我会先…」「可以,主人。以后…」)。
|
|
63
|
+
# 这是回答用户的规则设定,不是当前回合宣布下一步动作后漏调工具。
|
|
64
|
+
STANDING_RULE_PATTERNS = [
|
|
65
|
+
r"(?:以后|今后|之后|下次|后续|往后|接下来每次|每当|每次)[^。!?\n]{0,40}(?:提到|遇到|收到|让我|你让我|要求|需要|开始|做|时|的时候)[^。!?\n]{0,30}我(?:会|将|都会|先|就)",
|
|
66
|
+
r"^(?:可以|好的?|明白|没问题|收到|记下了|知道了)[,,。!!\s]*(?:主人|小主|老板)?[,,。!!\s]*(?:以后|今后|之后|下次|后续|往后|每当|每次)",
|
|
67
|
+
]
|
|
68
|
+
|
|
58
69
|
# 「已经做完」的收尾。命中且无未来标记时否决。
|
|
59
70
|
DONE_PATTERNS = [
|
|
60
71
|
r"(?:已|已经)(?:经)?(?:完成|修好|改好|搞定|处理完|就绪|生效|上线|发布|通过)",
|
|
61
|
-
r"(?:全部|都)(
|
|
62
|
-
r"(
|
|
72
|
+
r"(?:全部|都)(?:完成|通过|搞定|就绪|闭合)",
|
|
73
|
+
r"(?:搞定|收工|完事|可以收尾)(?:了)?[。.!!]?$",
|
|
63
74
|
r"(?:到|就)这里(?:为止|结束)?",
|
|
64
75
|
r"(?:没有|无需)(?:其他|更多|别的)(?:改动|问题|需要)",
|
|
65
76
|
r"\b(?:all )?done\b",
|
|
@@ -77,6 +88,8 @@ FUTURE_STRONG = [
|
|
|
77
88
|
r"让(?:我们|我)先",
|
|
78
89
|
r"(?:接下来|下面|现在)我(?:来|将|会|要)",
|
|
79
90
|
r"开始(?:执行|处理|修改|实现|写|改|跑|检查)",
|
|
91
|
+
r"(?:^|[。!?\n]\s*)(?:开始[。,,\s]*)?先(?:把|将|从|去|给|对|用|跑|看|查|改|写|读|登记|核对|整理|创建|执行|检查)[^。!?\n]{1,60}再",
|
|
92
|
+
r"(?:^|[。!?\n]\s*)现在(?:重新|开始|把|将|先|去|来|给|对|跑|开|改|写|整理|执行|检查)",
|
|
80
93
|
r"\blet me\b",
|
|
81
94
|
r"\bi'?ll\b",
|
|
82
95
|
r"\bi will\b",
|
|
@@ -98,11 +111,11 @@ FUTURE_WEAK = [
|
|
|
98
111
|
|
|
99
112
|
# 动作动词:把「未来时」落到「要做一件具体的事」上。
|
|
100
113
|
ACTION_VERB = [
|
|
101
|
-
r"(
|
|
102
|
-
r"(
|
|
103
|
-
r"(
|
|
114
|
+
r"(?:检查|查看|看看|查一下|读取|打开|搜索|定位|核对|登记|整理)",
|
|
115
|
+
r"(?:修改|改成|改掉|编辑|写入|创建|新建|删除|移除|重写|写进)",
|
|
116
|
+
r"(?:执行|运行|跑一下|跑起|启动|重启|安装|部署|发布|提交|开窗口|重新开)",
|
|
104
117
|
r"(?:修复|实现|添加|增加|补充|更新|替换|迁移|重构)",
|
|
105
|
-
r"(
|
|
118
|
+
r"(?:验证|测试|校验|确认一下|跑通|编译|上机)",
|
|
106
119
|
r"\b(?:check|read|open|inspect|look at|search|grep)\b",
|
|
107
120
|
r"\b(?:edit|write|create|add|remove|delete|rewrite|patch|update)\b",
|
|
108
121
|
r"\b(?:run|execute|install|deploy|build|start|restart|publish)\b",
|
|
@@ -114,6 +127,11 @@ COLON_TAIL = re.compile(r"[::]\s*\Z")
|
|
|
114
127
|
ELLIPSIS_TAIL = re.compile(r"(?:\.{3,}|…)\s*\Z")
|
|
115
128
|
QUESTION_TAIL = re.compile(r"[??]\s*\Z")
|
|
116
129
|
|
|
130
|
+
# action-colon 判定用:末行收尾的冒号、分句切分、列表项前缀。
|
|
131
|
+
_COLON_AT_END = re.compile(r"[::]\s*\Z")
|
|
132
|
+
_CLAUSE_SPLIT = re.compile(r"[,,。;;!!??]")
|
|
133
|
+
_LIST_ITEM = re.compile(r"^[-*•\d|]")
|
|
134
|
+
|
|
117
135
|
# 阈值。只有弱未来标记时必须靠额外信号才能过线。
|
|
118
136
|
THRESHOLD_STRONG = 3.0
|
|
119
137
|
THRESHOLD_WEAK_ONLY = 4.5
|
|
@@ -140,6 +158,7 @@ def _any_match(group: str, text: str) -> bool:
|
|
|
140
158
|
|
|
141
159
|
_PATTERN_GROUPS = {
|
|
142
160
|
"request": REQUEST_PATTERNS,
|
|
161
|
+
"standing_rule": STANDING_RULE_PATTERNS,
|
|
143
162
|
"done": DONE_PATTERNS,
|
|
144
163
|
"future_strong": FUTURE_STRONG,
|
|
145
164
|
"future_weak": FUTURE_WEAK,
|
|
@@ -207,10 +226,14 @@ def detect_stall(raw_text: Any, tool_call_count: int = 0) -> Dict[str, Any]:
|
|
|
207
226
|
if _any_match("request", tail):
|
|
208
227
|
return _result("asked-user")
|
|
209
228
|
|
|
229
|
+
# ── 否决 ③:确认/复述长期规则约定(「以后遇到…我会先…」)──────────────
|
|
230
|
+
if _any_match("standing_rule", tail):
|
|
231
|
+
return _result("standing-rule")
|
|
232
|
+
|
|
210
233
|
has_strong = _any_match("future_strong", tail)
|
|
211
234
|
has_weak = _any_match("future_weak", tail)
|
|
212
235
|
|
|
213
|
-
# ── 否决
|
|
236
|
+
# ── 否决 ④:明确宣告完成且没有未来时 ──────────────────────────────────
|
|
214
237
|
if not has_strong and not has_weak and _any_match("done", tail):
|
|
215
238
|
return _result("already-done")
|
|
216
239
|
|
|
@@ -224,20 +247,42 @@ def detect_stall(raw_text: Any, tool_call_count: int = 0) -> Dict[str, Any]:
|
|
|
224
247
|
if has_weak:
|
|
225
248
|
score += 1.5
|
|
226
249
|
signals.append("future-weak")
|
|
227
|
-
|
|
250
|
+
has_verb = _any_match("action_verb", tail)
|
|
251
|
+
if has_verb:
|
|
228
252
|
score += 1.0
|
|
229
253
|
signals.append("action-verb")
|
|
230
|
-
|
|
254
|
+
has_colon = bool(COLON_TAIL.search(raw))
|
|
255
|
+
if has_colon:
|
|
231
256
|
score += 1.5
|
|
232
257
|
signals.append("colon-tail")
|
|
233
258
|
if ELLIPSIS_TAIL.search(raw):
|
|
234
259
|
score += 0.5
|
|
235
260
|
signals.append("ellipsis-tail")
|
|
236
261
|
|
|
237
|
-
|
|
262
|
+
# 末行非列表项以「动作动词 + 冒号」收尾(例如「……整份重写干净:」):
|
|
263
|
+
# 即使省略了显式「我先/接下来」代词,也是典型的即将发起工具调用。
|
|
264
|
+
#
|
|
265
|
+
# 动词必须落在冒号前的**最后一个分句**里,否则「已定位问题并修好,根因有
|
|
266
|
+
# 三层:」这类说明性收尾会被误判 —— 它的动词讲的是已完成的事,冒号引出的
|
|
267
|
+
# 是名词性解释。宁可漏掉一次续跑,也不要把说明性收尾当成漏执行。
|
|
268
|
+
lines = [line.strip() for line in raw.split("\n") if line.strip()]
|
|
269
|
+
last_line = lines[-1] if lines else ""
|
|
270
|
+
tail_clause = _CLAUSE_SPLIT.split(_COLON_AT_END.sub("", last_line))[-1] if last_line else ""
|
|
271
|
+
is_action_colon = (
|
|
272
|
+
has_colon
|
|
273
|
+
and has_verb
|
|
274
|
+
and _any_match("action_verb", tail_clause)
|
|
275
|
+
and not _LIST_ITEM.match(last_line)
|
|
276
|
+
and len(last_line) <= 160
|
|
277
|
+
)
|
|
278
|
+
if not has_strong and not has_weak and is_action_colon:
|
|
279
|
+
score += 1.0
|
|
280
|
+
signals.append("action-colon")
|
|
281
|
+
|
|
282
|
+
if not has_strong and not has_weak and not is_action_colon:
|
|
238
283
|
return _result("no-future-cue", score, signals)
|
|
239
284
|
|
|
240
|
-
threshold = THRESHOLD_STRONG if has_strong else THRESHOLD_WEAK_ONLY
|
|
285
|
+
threshold = THRESHOLD_STRONG if (has_strong or is_action_colon) else THRESHOLD_WEAK_ONLY
|
|
241
286
|
if score < threshold:
|
|
242
287
|
return _result("weak-only", score, signals)
|
|
243
288
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hermes-connect-services",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Bring zcode-ai-connect's four loopback endpoints to hermes, and add the missing turn-end gate that re-runs a turn when the model announces a next step but calls no tool.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|