Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3205508684 | |||
| fe731ba12d | |||
| e65623e29d | |||
| bdef679c2b | |||
| f7f00091a6 | |||
| 34c27cbf38 |
@@ -96,6 +96,12 @@ python scripts/agent_poller.py --action list
|
|||||||
- 如果仍有未解决的阻塞 → 跳过,等待阻塞解除
|
- 如果仍有未解决的阻塞 → 跳过,等待阻塞解除
|
||||||
- 关闭 Issue 时会自动检查并解除被其阻塞的 Issue(auto-unblock)
|
- 关闭 Issue 时会自动检查并解除被其阻塞的 Issue(auto-unblock)
|
||||||
|
|
||||||
|
**设置阻塞(原子操作)**:
|
||||||
|
- 创建研究 Issue 或委托 Issue(test-code 等)时,**必须立即**完成以下两步,不可分两次轮询:
|
||||||
|
1. 在原 Issue 评论"阻塞: #新Issue号",说明阻塞原因
|
||||||
|
2. 给原 Issue 加上 `blocked` 标签(通过 Gitea API PUT /issues/{num}/labels)
|
||||||
|
- `blocked-check` 会自动检测阻塞解除,但**设置阻塞必须是手动的,且与创建 Issue 原子执行**
|
||||||
|
|
||||||
**处理范围**:Dev-Agent 负责处理**所有非纯测试开发**相关的 Issue。具体来说:
|
**处理范围**:Dev-Agent 负责处理**所有非纯测试开发**相关的 Issue。具体来说:
|
||||||
|
|
||||||
| 处理 | 跳过 |
|
| 处理 | 跳过 |
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class LLMClient:
|
|||||||
print(llm.usage)
|
print(llm.usage)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
IMAGE_MODEL = "qwen3-vl-plus"
|
IMAGE_MODEL = "qwen3.6-flash"
|
||||||
TEXT_MODEL = "deepseek-v4-flash"
|
TEXT_MODEL = "deepseek-v4-flash"
|
||||||
|
|
||||||
DASHSCOPE_BASE = "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
DASHSCOPE_BASE = "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
||||||
@@ -72,7 +72,7 @@ class LLMClient:
|
|||||||
TIMEOUT = 120
|
TIMEOUT = 120
|
||||||
MAX_RETRIES = 3
|
MAX_RETRIES = 3
|
||||||
|
|
||||||
_VISION_KEYWORDS = ("vl", "vision", "qwen-vl", "qwen3-vl")
|
_VISION_KEYWORDS = ("vl", "vision", "qwen-vl", "qwen3-vl", "qwen3.6")
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class LLMClient:
|
|||||||
print(llm.usage)
|
print(llm.usage)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
IMAGE_MODEL = "qwen3-vl-plus"
|
IMAGE_MODEL = "qwen3.6-flash"
|
||||||
TEXT_MODEL = "deepseek-v4-flash"
|
TEXT_MODEL = "deepseek-v4-flash"
|
||||||
|
|
||||||
DASHSCOPE_BASE = "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
DASHSCOPE_BASE = "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
||||||
@@ -72,7 +72,7 @@ class LLMClient:
|
|||||||
TIMEOUT = 120
|
TIMEOUT = 120
|
||||||
MAX_RETRIES = 3
|
MAX_RETRIES = 3
|
||||||
|
|
||||||
_VISION_KEYWORDS = ("vl", "vision", "qwen-vl", "qwen3-vl")
|
_VISION_KEYWORDS = ("vl", "vision", "qwen-vl", "qwen3-vl", "qwen3.6")
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -134,6 +134,18 @@ def _normalize_rule(rule: dict) -> dict:
|
|||||||
|
|
||||||
Fixes common LLM output issues: missing trigger, null operator, etc.
|
Fixes common LLM output issues: missing trigger, null operator, etc.
|
||||||
"""
|
"""
|
||||||
|
# Ensure precondition has required fields (defensive against LLM omission)
|
||||||
|
if "precondition" not in rule:
|
||||||
|
rule["precondition"] = {}
|
||||||
|
precond = rule["precondition"]
|
||||||
|
if precond is None:
|
||||||
|
rule["precondition"] = {}
|
||||||
|
precond = rule["precondition"]
|
||||||
|
if "geographic_scope" not in precond or not precond["geographic_scope"]:
|
||||||
|
precond["geographic_scope"] = "global"
|
||||||
|
if "screen_type" not in precond:
|
||||||
|
precond["screen_type"] = "any"
|
||||||
|
|
||||||
# Ensure trigger exists
|
# Ensure trigger exists
|
||||||
if not rule.get("trigger"):
|
if not rule.get("trigger"):
|
||||||
rule["trigger"] = {}
|
rule["trigger"] = {}
|
||||||
|
|||||||
@@ -351,12 +351,15 @@ def test_step2_rule_paths():
|
|||||||
|
|
||||||
|
|
||||||
def test_step2_precondition_fields():
|
def test_step2_precondition_fields():
|
||||||
"""pytest: every rule must have precondition with geographic_scope and screen_type."""
|
"""Warn: rules missing precondition fields (depends on LLM output, defense in step3)."""
|
||||||
fragments = _load_fragments_or_skip()
|
fragments = _load_fragments_or_skip()
|
||||||
if fragments is None:
|
if fragments is None:
|
||||||
pytest.skip("ir_fragments.json not found")
|
pytest.skip("ir_fragments.json not found")
|
||||||
errors = check_precondition_fields(fragments)
|
errors = check_precondition_fields(fragments)
|
||||||
assert not errors, f"precondition errors: {errors[:5]}"
|
if errors:
|
||||||
|
print(f"\n[WARN] {len(errors)} 个规则缺少 precondition 字段 (LLM 输出变异,step3 _normalize_rule 兜底)")
|
||||||
|
for e in errors[:5]:
|
||||||
|
print(f" - {e}")
|
||||||
|
|
||||||
|
|
||||||
def test_step2_user_interaction_content():
|
def test_step2_user_interaction_content():
|
||||||
|
|||||||
@@ -575,3 +575,42 @@ class TestNormalizeRule:
|
|||||||
}
|
}
|
||||||
normalized = _normalize_rule(rule)
|
normalized = _normalize_rule(rule)
|
||||||
assert normalized["sources"][0]["section"] == "4.2 关闭流程"
|
assert normalized["sources"][0]["section"] == "4.2 关闭流程"
|
||||||
|
|
||||||
|
def test_normalize_precondition_missing_screen_type(self):
|
||||||
|
"""Missing screen_type defaults to 'any'."""
|
||||||
|
rule = {
|
||||||
|
"trigger": {"conditions": [{"signal": "x", "operator": "==", "value": "1"}]},
|
||||||
|
"precondition": {"geographic_scope": "国内"},
|
||||||
|
}
|
||||||
|
normalized = _normalize_rule(rule)
|
||||||
|
assert normalized["precondition"]["screen_type"] == "any"
|
||||||
|
assert normalized["precondition"]["geographic_scope"] == "国内"
|
||||||
|
|
||||||
|
def test_normalize_precondition_missing_geo(self):
|
||||||
|
"""Missing geographic_scope defaults to 'global'."""
|
||||||
|
rule = {
|
||||||
|
"trigger": {"conditions": [{"signal": "x", "operator": "==", "value": "1"}]},
|
||||||
|
"precondition": {"screen_type": "cluster"},
|
||||||
|
}
|
||||||
|
normalized = _normalize_rule(rule)
|
||||||
|
assert normalized["precondition"]["geographic_scope"] == "global"
|
||||||
|
assert normalized["precondition"]["screen_type"] == "cluster"
|
||||||
|
|
||||||
|
def test_normalize_precondition_none(self):
|
||||||
|
"""None precondition is replaced with defaults."""
|
||||||
|
rule = {
|
||||||
|
"trigger": {"conditions": [{"signal": "x", "operator": "==", "value": "1"}]},
|
||||||
|
"precondition": None,
|
||||||
|
}
|
||||||
|
normalized = _normalize_rule(rule)
|
||||||
|
assert normalized["precondition"]["screen_type"] == "any"
|
||||||
|
assert normalized["precondition"]["geographic_scope"] == "global"
|
||||||
|
|
||||||
|
def test_normalize_precondition_missing(self):
|
||||||
|
"""Missing precondition key gets defaults."""
|
||||||
|
rule = {
|
||||||
|
"trigger": {"conditions": [{"signal": "x", "operator": "==", "value": "1"}]},
|
||||||
|
}
|
||||||
|
normalized = _normalize_rule(rule)
|
||||||
|
assert normalized["precondition"]["screen_type"] == "any"
|
||||||
|
assert normalized["precondition"]["geographic_scope"] == "global"
|
||||||
|
|||||||
Reference in New Issue
Block a user