Compare commits

...

70 Commits

Author SHA1 Message Date
cfdaily b3707f1e62 revert: remove CI yml changes from lint PR
CI / lint (pull_request) Failing after 14m23s
CI / test (pull_request) Has been skipped
CI / notify-on-failure (pull_request) Failing after 14m58s
CI yml concurrency changes caused lint step to be skipped.
Lint PR should only contain source code formatting fixes.
2026-06-11 09:58:58 +08:00
cfdaily 2f1cb5c277 fix(lint): resolve all 37 flake8 issues
CI / lint (pull_request) Failing after 14m13s
CI / test (pull_request) Has been skipped
CI / notify-on-failure (pull_request) Failing after 12m7s
- Remove 7 unused imports (F401)
- Fix 4 f-strings without placeholders (F541)
- Fix indentation and blank line issues (E127/E302/E402)
- Remove trailing whitespace on 22 blank lines (W293)

Pure formatting changes, no logic modifications.
2026-06-11 08:55:05 +08:00
cfdaily 7b788809d8 Merge branch 'main' of http://192.168.2.154:3000/sanguo/sanguo_moziplus_v2 2026-06-11 08:52:04 +08:00
cfdaily 846fcbda5d docs: §21 handler 注册后 E2E 验证报告
Mail/Toolchain 核心流程全部通过:
- Mail: inform auto-working → auto-done 
- Toolchain Issue 指派: webhook → Mail 
- Toolchain PR Review: webhook → Review 请求 → Review 结果 
- CI 失败重复 Mail 问题确认(org+repo webhook 双触发,已知)

Task review 路径待明天验证。
2026-06-11 00:09:28 +08:00
cfdaily 83694adfea fix: task_handler SKILL_BASE_PATH 硬编码改为环境变量
与 bootstrap.py 保持一致,支持 MOZI_SKILL_PATH 环境变量覆盖。
默认值不变。
2026-06-10 23:46:32 +08:00
cfdaily 603af2a857 fix: dispatcher _legacy_on_complete 闭包内删除错误的重复 import
get_connection 已在文件顶部 L22 import(from src.blackboard.db),
闭包内 L258 错误地 from src.daemon.db import(模块不存在),
会触发 ImportError 被 try/except 吞掉导致 review verdict 逻辑不生效。

司马懿 review 发现。
2026-06-10 23:41:33 +08:00
cfdaily 36cee16679 fix: v3.0→HEAD review 修复 — handler 注册 + review verdict + skill 全文注入
基于庞统+司马懿背靠背 review,修复 6 个问题:

P0 致命:
- A1: _legacy_on_complete 补回 review verdict 处理(approved→done,非 approved→@mention assignee)
- A2: 添加 TaskTypeRegistry.register() 启动初始化(注册 Task/Mail/Toolchain handler)

P1 中等:
- B11-1: RoleSkillSection 从索引提示改为全文注入(对齐设计 §2.3 + BootstrapBuilder 行为)
- A8: retry prompt is_mail 硬编码改走 TaskTypeRegistry handler 判断

P2 低:
- _mail_* 4 个方法添加 DEPRECATED 注释
- ticker.py handler check_completion 代码块缩进对齐(28→24 空格)

测试:394 passed, 0 failed
Review reports: docs/design/review-v3-vs-head-{pangtong,simayi}.md
2026-06-10 23:37:46 +08:00
cfdaily fb31ce3752 fix: S1 handler display_name + S2 import 移顶部 + W1 注释
- S1: vp_name 硬编码字典 → handler.display_name 属性
- S2: ticker/spawner 中 TaskTypeRegistry 局部 import → 移文件顶部
- W1: TaskHandler executor verify 失败不调 on_failure 加注释说明
2026-06-10 23:37:46 +08:00
cfdaily 15fbc933ca feat: Step 5 引擎接入 + H1-H3/S3 修复 + 审计 D1/D2/D5 修复
引擎接入(dispatcher/spawner/ticker → handler 统一路由):
- dispatcher: guardrail/on_checks_passed/on_complete → handler 查询
- spawner: _build_prompt/_build_api_section → handler.build_prompt
- ticker: 虚拟项目扫描/assignee/claimed/review/幻觉门控 → handler 判断

Handler 缺陷修复:
- H1: _mark_task_status 加 3 次重试(防 DB 锁)
- H2: review @mention 加 comment_type='review'
- H3: review 非 approved 保持 review 状态(不标 working)
- S3: 通知链接改 Gitea(PR/Issue/Commit)

审计修复:
- D1: pre_spawn 返回值未检查 → 加 if not 抛 RuntimeError
- D2: PromptContext 缺 from_agent/mail_type → 从 must_haves 解析
- D5: _check_reply 查错表 → 恢复查 tasks 表找 in_reply_to

旧方法保留未删(deprecated),确认稳定后再清理。
2026-06-10 23:37:46 +08:00
cfdaily 5121b04d8c fix: S1-S3 review suggestions — type annotations unified, urllib replaces curl, rich notification content 2026-06-10 23:37:46 +08:00
cfdaily 65e8c4d461 feat: Step 2-4 Task/Mail/Toolchain handlers + PromptSections + BaseTaskHandler
- base_task_handler.py: 基类统一4步流程(crash→verify→mark→notify)
- task_handler.py: 5 PromptSections + 三信号验证 + review流程
- mail_handler.py: 3 PromptSections + inform/request区分 + 基类统一流程
- toolchain_handler.py: 3 PromptSections + 模板引擎渲染 + Mail API通知
- 背靠背设计-编码一致性检查通过(4严重已修/6轻微保留)
2026-06-10 23:37:46 +08:00
cfdaily b7136f4bf6 fix: S1-S4 建议项修复 — 类型标注精确化+BaseTaskHandler标注后续PR+token预算说明 2026-06-10 23:37:46 +08:00
cfdaily 02cb1610f1 fix: M1-M4 修复 Protocol 签名与设计文档对齐 + §14 去重 2026-06-10 23:37:46 +08:00
cfdaily f6a64e305b docs: 20-task-type-architecture.md v3.0 - §14-§18 五层架构+BaseTaskHandler+执行流程+决策记录 2026-06-10 23:37:46 +08:00
cfdaily 4bd109f09b feat: Step 1 — TaskTypeRegistry + PromptComposer 基础设施
- task_type_registry.py: TaskTypeHandler Protocol (10方法+2属性) + TaskTypeRegistry 注册表
- prompt_composer.py: PromptSection Protocol + PromptContext dataclass + PromptComposer 拼装器
- 零依赖,纯新增文件,不影响现有功能
2026-06-10 23:37:46 +08:00
cfdaily 9ef52049d1 docs: 20-task-type-architecture.md v2.1 - 修复 review M1-M3 必修项 2026-06-10 23:37:46 +08:00
cfdaily ad02cb8fef docs: 20-task-type-architecture.md v2.0 - 新增 §11-§13 PromptSection 模式 2026-06-10 23:37:46 +08:00
cfdaily 1e16f63be5 docs: add 20-task-type-architecture.md - TaskTypeRegistry + Handler 架构重构设计 2026-06-10 23:37:46 +08:00
cfdaily 3071c95629 docs(#13): merge #19 context layers into #13, delete standalone #19
§19 上下文四层改造方案(原独立文档 #19)合并到 #13 工具链设计文档末尾。
v3.1 → v3.3。两个专题本就是一个整体,分开维护增加认知负担。
2026-06-10 23:37:46 +08:00
cfdaily 29fb333c77 fix(frontend): resumed_from null→undefined 类型兼容
TypeScript: resumed_from 是 string|null,StatusButtons 期望 string|undefined。
用 ?? undefined 转换。
2026-06-10 23:37:46 +08:00
cfdaily 234c560522 fix(test): e2e test 在 collection 阶段跳过(不 import 安装目录)
根因: test_e2e_v27.py 的 skipif 只标记了函数级别,pytest collection 阶段
仍会 import 该文件,触发 sys.path.insert 指向安装目录的 spawner.py。
如果安装目录有 merge conflict 残留,整个 test job crash。

修复: 将 skipif 加入 pytestmark 级别,collection 阶段即跳过。
2026-06-10 23:37:46 +08:00
cfdaily 16a9783416 fix(frontend): V2Task 添加 resumed_from 字段
deploy 时 TypeScript 编译报 TS2339: Property 'resumed_from' does not exist on type 'V2Task'。
DB 表有此字段但 TS interface 遗漏。
2026-06-10 23:37:46 +08:00
cfdaily 52073fb955 fix(ci): deploy.yml 用 /tmp/ci-venv + 直接 pip install 替代 requirements.txt
仓库没有 requirements.txt,deploy workflow 每次 push 到 main 都报错。
改为与 ci.yml 一致的方式:/tmp/ci-venv + 直接 pip install 依赖。
2026-06-10 23:37:46 +08:00
cfdaily eaaf42b37d fix(lint): 修复 PR #14 引入的 lint 回退 (119→0)
PR #14 从旧分支复制文件导致回退了 PR #10 的 lint 修复。
修复内容:
- autoflake 移除未使用导入/变量
- autopep8 修复缩进/空格
- 手动修复 F821(pathlib→Path), F541(f-string), F841(未使用变量)
- 所有修复均通过 flake8 --max-line-length=120 --extend-ignore=E501 检查 (0 errors)
2026-06-10 23:37:46 +08:00
cfdaily c4b219892c docs(#08): update A13 revised - exit=0 always completed
Merge old A12/A13 into single A13 revised: trust exit_code=0
regardless of stdout/JSON output. Old logic caused inform Mail
infinite retry loop.
2026-06-10 23:37:46 +08:00
cfdaily 2478c425b0 fix(spawner): A13 exit=0 always completed, not agent_error
exit=0 means process exited normally. Trust the exit code regardless
of stdout/JSON output or task_status. Old logic misclassified inform
Mail completions as agent_error, causing infinite retry loops.

Includes test update: test_task_status_pending expects completed.
2026-06-10 23:37:46 +08:00
cfdaily e504e56ecc chore: simayi-approved changes - lint fixes, toolchain improvements, healthz
All changes reviewed and APPROVED in PR #12 (Review ID: 40):
- toolchain_routes: webhook repo/org format compat, content dedup (sha256), closed issue filter
- dispatcher: inform mail crash 误标 done 修复
- ticker: cleanup and improvements
- healthz endpoint
- conftest: integration/e2e deselect markers
- docs: design docs, test-guide updates
- various lint/whitespace fixes across 30 files
2026-06-10 23:37:46 +08:00
cfdaily d45ebe87e1 docs: #19 adopt simayi review suggestions (v1.1) 2026-06-10 23:37:46 +08:00
cfdaily 8fe0233d94 fix(spawner): crash cooldown分级 + inform mail crash误标done修复
- crashed outcome cooldown 60s(vs 其他 300s)
- import init_db
- whitespace/lint fixes
2026-06-10 23:37:46 +08:00
cfdaily 45c48c1ccf fix(ci): 修复notify竞态条件 - 用needs.result替代commit status查询
根因:notify-on-failure job 通过 commit status API 查询结果时,
自身的 pending status 会污染查询结果(竞态条件):
1. lint/test 都 success
2. notify 开始运行,自身状态 pending 写入 commit status
3. notify 查询 commit status → 看到 pending(自己的)≠ success
4. 误发 [CI] 失败 评论 + webhook 触发 Mail 通知

修复方案:
- 不再查询 commit status API
- 直接用 needs.lint.result 和 needs.test.result 判断
- 只有明确的 failure 才发通知
- 同时去掉 push 触发避免双倍运行
2026-06-10 23:37:46 +08:00
cfdaily d93ad989ab fix(ci): 去掉push触发避免双倍触发 + 修复notify误报
1. 触发器:去掉 push,只保留 pull_request(opened, synchronize)
   - 每次 push 到 PR 分支不再跑 2 次 CI
2. notify-on-failure:只有明确的 failure 状态才发通知
   - 之前:空状态/unknown/pending 都触发通知(误报根因)
   - 现在:只有 STATUS=failure 才发通知
3. venv 路径:统一用 /tmp/ci-venv-lint 和 /tmp/ci-venv-test
   - 避免 host 模式下与开发目录 .venv 冲突
2026-06-10 23:37:46 +08:00
cfdaily 1f4634feb9 fix: remove dead code config.get experience 2026-06-10 23:37:46 +08:00
cfdaily 33e8c68458 fix: resolve all flake8 lint errors (118 → 0) 2026-06-10 23:37:46 +08:00
jiangwei-infra 308c5a63bd fix(ci): install all test dependencies (fastapi, pydantic, pyyaml, etc.) 2026-06-10 23:37:07 +08:00
jiangwei-infra 3323bc76bd fix(ci): install pytest directly instead of editable mode 2026-06-10 23:37:07 +08:00
jiangwei-infra 9dd9e44a83 fix(ci): use pyproject.toml instead of missing requirements.txt 2026-06-10 23:37:07 +08:00
jiangwei-infra e7b6d4af45 fix(ci): use /tmp/ci-venv-* to avoid host .venv conflict 2026-06-10 23:37:07 +08:00
cfdaily 8085a71d9f auto-sync: 2026-06-09 11:57:58
CI / lint (push) Failing after 8s
CI / test (push) Has been skipped
CI / lint (pull_request) Failing after 6s
CI / notify-on-failure (push) Successful in 0s
CI / test (pull_request) Has been skipped
CI / notify-on-failure (pull_request) Successful in 3s
2026-06-09 11:57:58 +08:00
cfdaily 4840b68901 auto-sync: 2026-06-09 11:17:56 2026-06-09 11:17:56 +08:00
cfdaily 0111273811 auto-sync: 2026-06-09 11:16:05 2026-06-09 11:16:05 +08:00
cfdaily dd2572b8b8 auto-sync: 2026-06-09 11:15:09 2026-06-09 11:15:09 +08:00
cfdaily ce7c1e7108 auto-sync: 2026-06-09 11:13:34 2026-06-09 11:13:34 +08:00
cfdaily 68932f9be5 auto-sync: 2026-06-09 08:47:09 (catch-all) 2026-06-09 08:47:09 +08:00
cfdaily 6963faac83 auto-sync: 2026-06-09 08:46:58 2026-06-09 08:46:58 +08:00
cfdaily 5010ff7db1 auto-sync: 2026-06-09 08:30:45 2026-06-09 08:30:45 +08:00
cfdaily cf7e136330 auto-sync: 2026-06-09 08:06:43 2026-06-09 08:06:43 +08:00
cfdaily 795cfa81d1 auto-sync: 2026-06-09 07:46:23 2026-06-09 07:46:23 +08:00
cfdaily 3f1daa9f8d auto-sync: 2026-06-09 07:46:02 2026-06-09 07:46:02 +08:00
cfdaily 67a187aa0f auto-sync: 2026-06-09 00:45:50 2026-06-09 00:45:50 +08:00
cfdaily 4492a75e7e auto-sync: 2026-06-09 00:45:24 2026-06-09 00:45:24 +08:00
cfdaily 639fb3ecea auto-sync: 2026-06-09 00:44:21 2026-06-09 00:44:21 +08:00
cfdaily 60195f6250 auto-sync: 2026-06-09 00:38:45 2026-06-09 00:38:45 +08:00
cfdaily f00aeb96e9 auto-sync: 2026-06-09 00:24:51 2026-06-09 00:24:51 +08:00
cfdaily 96c8378a91 auto-sync: 2026-06-09 00:14:25 (catch-all) 2026-06-09 00:14:25 +08:00
cfdaily 632ca35681 auto-sync: 2026-06-09 00:14:14 2026-06-09 00:14:14 +08:00
cfdaily 041f54e699 auto-sync: 2026-06-08 23:39:15 2026-06-08 23:39:15 +08:00
cfdaily 81cca26adb auto-sync: 2026-06-08 23:38:59 (catch-all) 2026-06-08 23:38:59 +08:00
cfdaily 29438a5789 auto-sync: 2026-06-08 23:38:34 (catch-all) 2026-06-08 23:38:34 +08:00
cfdaily 5d83747e99 auto-sync: 2026-06-08 23:37:35 (catch-all) 2026-06-08 23:37:35 +08:00
cfdaily 339519a062 auto-sync: 2026-06-08 23:37:25 2026-06-08 23:37:25 +08:00
cfdaily 12f03e48a4 auto-sync: 2026-06-08 23:23:43 2026-06-08 23:23:43 +08:00
cfdaily 473ae73230 auto-sync: 2026-06-08 23:22:36 2026-06-08 23:22:36 +08:00
cfdaily 34335a6487 auto-sync: 2026-06-08 23:21:31 2026-06-08 23:21:31 +08:00
cfdaily b2ace1b6a7 auto-sync: 2026-06-08 23:20:47 2026-06-08 23:20:47 +08:00
cfdaily 55fc25d9a6 auto-sync: 2026-06-08 23:19:23 2026-06-08 23:19:23 +08:00
cfdaily 0b7bb288f9 auto-sync: 2026-06-08 22:58:35 2026-06-08 22:58:35 +08:00
cfdaily b5d26da914 auto-sync: 2026-06-08 22:26:47 2026-06-08 22:26:47 +08:00
cfdaily f32991ddee auto-sync: 2026-06-08 22:11:11 2026-06-08 22:11:11 +08:00
cfdaily 0546825642 auto-sync: 2026-06-08 22:04:07 2026-06-08 22:04:07 +08:00
cfdaily f0a673ff20 auto-sync: 2026-06-08 21:59:26 2026-06-08 21:59:26 +08:00
7 changed files with 33 additions and 34 deletions
+21 -21
View File
@@ -10,7 +10,7 @@ from dataclasses import dataclass
from pathlib import Path
from typing import Optional
from src.daemon.prompt_composer import PromptContext, PromptComposer, PromptSection
from src.daemon.prompt_composer import PromptContext, PromptSection
from src.blackboard.db import get_connection
logger = logging.getLogger("moziplus-v2.handler")
@@ -28,46 +28,46 @@ class VerifyResult:
class BaseTaskHandler:
"""所有 task type handler 的基类。
职责:L2 引擎注入层的业务逻辑——prompt 构建、完成验证、状态标记。
不管:进程生命周期、exit 分类、重试决策(这些归 spawner)。
"""
# crash 类 outcome(进程级异常,需要 rollback)
CRASH_OUTCOMES = frozenset({
"crashed", "compact_failed", "process_crash",
"session_stuck", "compact_hanging",
})
task_type: str = ""
virtual_project: Optional[str] = None
display_name: str = "" # 中文展示名(ticker 扫描日志用)
# === 子类必须实现 ===
def build_prompt(self, context: PromptContext) -> str:
"""构建 L2 prompt(通过 PromptComposer 拼 section)。子类实现。"""
raise NotImplementedError
def verify_completion(self, task_id: str, db_path: Path) -> VerifyResult:
"""验证任务完成质量。每个 handler 自己的验证逻辑。子类实现。"""
raise NotImplementedError
def target_success_status(self) -> str:
"""验证通过后的目标状态。task='review', mail/toolchain='done'"""
return "review"
def get_sections(self) -> list[PromptSection]:
"""返回此 handler 的 prompt section 列表。子类实现。"""
return []
# === 基类提供统一流程 ===
def pre_spawn(self, task_id: str, db_path: Path) -> bool:
"""spawn 前业务准备。默认 True。
mail/toolchain override 为 auto_working。"""
return True
def post_complete(self, task_id: str, agent_id: str,
outcome: str, db_path: Path) -> None:
"""spawn 完成后的业务处理。统一 4 步流程:
@@ -80,10 +80,10 @@ class BaseTaskHandler:
if outcome in self.CRASH_OUTCOMES:
self._rollback_current_agent(db_path, task_id, agent_id)
return
# 2. verify
result = self.verify_completion(task_id, db_path)
# 3. mark
if result.passed:
self._mark_task_status(db_path, task_id, self.target_success_status())
@@ -92,20 +92,20 @@ class BaseTaskHandler:
else:
# 4. notify
self.on_failure(task_id, agent_id, db_path, result)
def on_failure(self, task_id: str, agent_id: str,
db_path: Path, verify: VerifyResult) -> None:
"""验证失败处理。默认:标 failed。子类可 override。"""
self._mark_task_status(db_path, task_id, "failed")
logger.info("Task %s: verify failed (%s), marked failed",
task_id, verify.reason)
task_id, verify.reason)
def check_completion(self, task_id: str, db_path: Path) -> bool:
"""ticker 级别的完成检查。默认:False。"""
return False
# === 内部工具方法 ===
def _rollback_current_agent(self, db_path: Path, task_id: str, agent_id: str) -> None:
"""crash 后回退 current_agent → assignee,避免 exclude_current 卡死。
从 dispatcher._rollback_current_agent 迁移。"""
@@ -126,7 +126,7 @@ class BaseTaskHandler:
except Exception as e:
logger.warning("Task %s: failed to rollback current_agent: %s",
task_id, e)
def _mark_task_status(self, db_path: Path, task_id: str, status: str) -> None:
"""更新任务状态 + 写审计事件(带 3 次重试,防 SQLite DB 锁)。"""
for attempt in range(3):
@@ -157,7 +157,7 @@ class BaseTaskHandler:
logger.warning("Handler: mark %s%s attempt %d failed: %s",
task_id, status, attempt + 1, e)
logger.error("Handler: mark %s%s all 3 attempts failed", task_id, status)
def _auto_mark_working(self, task_id: str, db_path: Path) -> bool:
"""pending → workingmail/toolchain 通用)。"""
try:
+3 -3
View File
@@ -7,7 +7,6 @@ from __future__ import annotations
import json
import logging
from pathlib import Path
from typing import Dict, Optional
from src.daemon.base_task_handler import BaseTaskHandler, VerifyResult
from src.daemon.prompt_composer import PromptComposer, PromptContext
@@ -15,6 +14,7 @@ from src.blackboard.db import get_connection
logger = logging.getLogger("moziplus-v2.handler.mail")
class MailHandler(BaseTaskHandler):
"""Mail 任务 handler。"""
@@ -65,7 +65,7 @@ class MailHandler(BaseTaskHandler):
"""request 验证失败 → 标 failed + 通知发件人"""
self._mark_task_status(db_path, task_id, "failed")
logger.info("Mail %s: request verify failed (%s), marked failed",
task_id, verify.reason)
task_id, verify.reason)
# 通知发件人
try:
@@ -95,7 +95,7 @@ class MailHandler(BaseTaskHandler):
def _check_reply(self, task_id: str, db_path: Path) -> bool:
"""检查是否已回复(查 tasks 表找 in_reply_to 回复邮件)
从 dispatcher._mail_check_reply 迁移。
Mail 回复机制:创建新 taskmust_haves JSON 中包含 in_reply_to = original_task_id。
不能查 comments 表——回复邮件是独立的 task,不是 comment。
+1 -1
View File
@@ -6,7 +6,7 @@ prompt_composer.py — PromptSection Protocol + PromptContext + PromptComposer
import logging
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional, Protocol, runtime_checkable
from typing import Dict, List, Optional, Protocol, runtime_checkable
logger = logging.getLogger("moziplus-v2.prompt_composer")
+1 -2
View File
@@ -16,11 +16,10 @@ from pathlib import Path
from typing import Any, Dict, List, Optional
from src.blackboard.db import get_connection
from src.daemon.task_type_registry import TaskTypeRegistry
logger = logging.getLogger("moziplus-v2.spawner")
from src.daemon.task_type_registry import TaskTypeRegistry
# ── Prompt 模板 ──
+3 -3
View File
@@ -7,7 +7,7 @@ from __future__ import annotations
import logging
import os
from pathlib import Path
from typing import Dict, List, Optional
from typing import Dict, Optional
from src.daemon.base_task_handler import BaseTaskHandler, VerifyResult
from src.daemon.prompt_composer import PromptComposer, PromptContext
@@ -182,7 +182,7 @@ class TaskConstraintsSection:
class TaskHandler(BaseTaskHandler):
"""黑板标准任务 handler。
- verify: 三信号检查(output / comment / terminal status
- 成功 → review
- 失败 → 保持 working,让 ticker 重试
@@ -198,7 +198,7 @@ class TaskHandler(BaseTaskHandler):
def post_complete(self, task_id: str, agent_id: str,
outcome: str, db_path: Path) -> None:
"""Task on_complete:区分 executor 和 review。
executor: 基类统一流程(crash → verify → mark review
review: handle_review_complete(读 verdict → done/keep review
"""
+1 -1
View File
@@ -9,7 +9,7 @@ from __future__ import annotations
import logging
from pathlib import Path
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Protocol, runtime_checkable
from typing import TYPE_CHECKING, Dict, Optional, Protocol, runtime_checkable
if TYPE_CHECKING:
from src.daemon.prompt_composer import PromptContext
+3 -3
View File
@@ -38,13 +38,13 @@ class ToolchainContextSection:
return render_template(event_type, variables)
# fallback:通用事件描述
lines = [f"## 工具链事件", f""]
lines = ["## 工具链事件", ""]
lines.append(f"- **事件类型**: {event_type or '未知'}")
if event_data:
lines.append(f"- **事件详情**:")
lines.append("- **事件详情**:")
for key, value in event_data.items():
lines.append(f" - {key}: {value}")
lines.append(f"")
lines.append("")
return "\n".join(lines)
def should_include(self, context: PromptContext) -> bool: