- Fix delete agent 500: clean up FK records (agent_llm_logs, permissions, schedules, executions, team_members) and unbind goals/tasks before delete - Remove hardcoded personality templates in Android, replace with dynamic system prompt generation from name + description - Set promptSectionsEnabled=false to bypass PromptComposer for personality - Add Tencent Cloud Linux deployment guide (Docker Compose) - Accumulated backend service updates, frontend UI fixes, Android app changes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
178 lines
7.6 KiB
Python
178 lines
7.6 KiB
Python
"""
|
||
Round 12: Commander-monitored Android client testing
|
||
Monitor phase transitions, detect failures, report to commander.
|
||
Commander: Claude Code (you) monitors this output.
|
||
"""
|
||
import urllib.request
|
||
import json
|
||
import sys
|
||
import time
|
||
|
||
BASE = "http://127.0.0.1:8037/api/v1"
|
||
TEAM_ID = "5b032316-9e31-4ecb-a2b1-b46c7beff2eb"
|
||
|
||
def login():
|
||
req = urllib.request.Request(
|
||
f"{BASE}/auth/login",
|
||
data=b"username=admin&password=123456",
|
||
headers={"Content-Type": "application/x-www-form-urlencoded"}
|
||
)
|
||
return json.loads(urllib.request.urlopen(req).read())["access_token"]
|
||
|
||
TOKEN = login()
|
||
print(f"[CMD] Logged in. Token: {TOKEN[:30]}...")
|
||
|
||
TASK = """## 任务: Android客户端全面质量审计
|
||
|
||
### 目标
|
||
D:\\aaa\\aiagent\\android - Kotlin/Jetpack Compose Android 客户端
|
||
|
||
### 要求
|
||
1. 每个Agent必须扫描真实源代码文件(.kt/.xml/.gradle.kts),不得基于设计文档分析
|
||
2. 对标ChatGPT Android和豆包(Doubao)进行UX体验对比
|
||
3. 所有发现必须标注具体文件路径和行号
|
||
4. 使用 list_files → project_scan → file_read → grep_search 标准流程
|
||
|
||
### 各阶段产出
|
||
- 架构师: 技术栈分析、模块结构、数据流路径、已知架构风险
|
||
- 测试规划师: 15+测试场景、风险矩阵、用户画像
|
||
- 功能测试员: 12+真实bug(含文件路径+行号+修复代码)
|
||
- UX审查员: vs ChatGPT/豆包的差距分析、优先级、修复建议
|
||
- 边界探索员: 30+边界场景(网络/并发/数据/输入/资源)
|
||
- 性能评估员: 线程模型/内存/Compose/网络/数据库反模式
|
||
|
||
### 成功标准
|
||
- 所有发现引用真实源文件路径和行号
|
||
- 跨阶段重复率<10%
|
||
- 50%以上发现可独立验证
|
||
"""
|
||
|
||
body = json.dumps({"project_description": TASK}).encode("utf-8")
|
||
|
||
req = urllib.request.Request(
|
||
f"{BASE}/teams/{TEAM_ID}/execute/stream",
|
||
data=body,
|
||
headers={
|
||
"Authorization": f"Bearer {TOKEN}",
|
||
"Content-Type": "application/json"
|
||
},
|
||
method="POST"
|
||
)
|
||
|
||
print("[CMD] 任务已下达,等待虚拟团队执行...")
|
||
print("[CMD] 监控中 — 发现问题会立即报告\n")
|
||
|
||
phases_seen = set()
|
||
errors = []
|
||
start_time = time.time()
|
||
|
||
try:
|
||
response = urllib.request.urlopen(req, timeout=900) # 15 min timeout
|
||
buffer = ""
|
||
while True:
|
||
chunk = response.read(4096)
|
||
if not chunk:
|
||
break
|
||
try:
|
||
text = chunk.decode("utf-8")
|
||
except:
|
||
text = chunk.decode("gbk", errors="replace")
|
||
buffer += text
|
||
while "\n\n" in buffer:
|
||
event_str, buffer = buffer.split("\n\n", 1)
|
||
lines = event_str.strip().split("\n")
|
||
for line in lines:
|
||
if not line.startswith("data: "):
|
||
continue
|
||
try:
|
||
data = json.loads(line[6:])
|
||
event_type = data.get("type", "?")
|
||
|
||
if event_type == "plan_start":
|
||
print(f"[{time.time()-start_time:.0f}s] PLAN_START | 团队: {data.get('team_name','?')} | 成员: {data.get('member_count','?')}")
|
||
print(f"[{time.time()-start_time:.0f}s] 项目路径: {data.get('project_path','?')}")
|
||
|
||
elif event_type == "phase_start":
|
||
pid = f"{data.get('phase','?')}-{data.get('name','?')}"
|
||
print(f"\n[{time.time()-start_time:.0f}s] PHASE_START | 阶段{data.get('phase','?')}: {data.get('name','?')} | 角色: {data.get('role','?')} | Agent: {data.get('agent','?')}")
|
||
|
||
elif event_type == "phase_done":
|
||
success = data.get("success", False)
|
||
iters = data.get("iterations", "?")
|
||
tool_calls = data.get("tool_calls", "?")
|
||
output_len = len(data.get("output", ""))
|
||
files = data.get("files", [])
|
||
status_icon = "OK" if success else "FAIL"
|
||
print(f"[{time.time()-start_time:.0f}s] PHASE_DONE {status_icon} | 阶段{data.get('phase','?')}: {data.get('name','?')}")
|
||
print(f" success={success} iterations={iters} tool_calls={tool_calls} output={output_len}chars files={len(files)}")
|
||
if not success:
|
||
error_msg = data.get("error", "")
|
||
print(f" ERROR: {error_msg[:300]}")
|
||
errors.append({
|
||
"phase": data.get("name", "?"),
|
||
"role": data.get("role", "?"),
|
||
"error": error_msg
|
||
})
|
||
if files:
|
||
for f in files[:5]:
|
||
print(f" file: {f}")
|
||
|
||
elif event_type == "plan_done":
|
||
plan = data.get("plan", {})
|
||
phases = plan.get("phases", [])
|
||
success = data.get("success", False)
|
||
print(f"\n[{time.time()-start_time:.0f}s] PLAN_DONE | success={success} | phases={len(phases)}")
|
||
if not success:
|
||
raw = data.get("raw_output", "")[:200]
|
||
print(f" raw: {raw}")
|
||
if phases:
|
||
for p in phases:
|
||
deps = p.get("depends_on", [])
|
||
dep_str = f" depends_on={deps}" if deps else ""
|
||
print(f" Phase{p.get('phase')}: {p.get('name','?')} [{p.get('role','?')}]{dep_str}")
|
||
|
||
elif event_type == "plan_fallback":
|
||
print(f"\n[{time.time()-start_time:.0f}s] PLAN_FALLBACK | {data.get('content','?')[:200]}")
|
||
|
||
elif event_type == "qa_done":
|
||
review = data.get("review", {})
|
||
print(f"\n[{time.time()-start_time:.0f}s] QA_DONE | pass={review.get('pass','?')} score={review.get('score','?')}")
|
||
|
||
elif event_type == "final":
|
||
print(f"\n[{'='*50}]")
|
||
print(f"[{time.time()-start_time:.0f}s] FINAL | 执行完成!")
|
||
print(f" 项目路径: {data.get('project_path','?')}")
|
||
files = data.get("files", [])
|
||
print(f" 产出文件: {len(files)} 个")
|
||
for f in files[:15]:
|
||
print(f" {f}")
|
||
if len(files) > 15:
|
||
print(f" ...还有 {len(files)-15} 个文件")
|
||
deliv = data.get("deliverable", "")[:500]
|
||
if deliv:
|
||
print(f" 交付物摘要: {deliv}")
|
||
|
||
elif event_type == "error":
|
||
msg = data.get("content", "")[:400]
|
||
print(f"\n[{time.time()-start_time:.0f}s] *** ERROR *** {msg}")
|
||
errors.append({"phase": "global", "error": msg})
|
||
|
||
else:
|
||
# brief for other events
|
||
short = str(data.get("content", str(data)))[:80]
|
||
print(f"[{time.time()-start_time:.0f}s] {event_type}: {short}")
|
||
|
||
except json.JSONDecodeError:
|
||
pass
|
||
|
||
print(f"\n[CMD] 流结束 | 总耗时: {time.time()-start_time:.0f}s | 错误数: {len(errors)}")
|
||
|
||
except Exception as e:
|
||
print(f"\n[CMD] 连接异常: {e}")
|
||
|
||
finally:
|
||
if errors:
|
||
print(f"\n[CMD] === 需要处理的错误 ({len(errors)}) ===")
|
||
for i, err in enumerate(errors):
|
||
print(f" [{i+1}] {err['phase']}({err.get('role','?')}): {err['error'][:200]}")
|