@zhushanwen/pi-evolve-daily 0.1.2 → 0.1.4
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/package.json +1 -1
- package/skills/evolve/SKILL.md +31 -0
- package/skills/evolve-report/SKILL.md +52 -0
- package/src/detectors/compact.ts +43 -0
- package/src/detectors/goal-quality.ts +59 -0
- package/src/detectors/param-error.ts +90 -0
- package/src/detectors/subagent-result.ts +65 -0
- package/src/index.ts +98 -4
- package/src/problems.ts +232 -0
- package/src/trackers/core.ts +459 -0
- package/src/trackers/run_tests.mjs +202 -0
- package/src/trackers/skill-execution.ts +126 -0
- package/src/trackers/types.ts +176 -0
package/package.json
CHANGED
package/skills/evolve/SKILL.md
CHANGED
|
@@ -120,6 +120,37 @@ Use these to identify:
|
|
|
120
120
|
- **Mixed-trigger skills** — both paths used; healthy signal
|
|
121
121
|
- **Never-triggered skills** — candidates for removal or description improvement
|
|
122
122
|
|
|
123
|
+
#### 3e. New Dimension Analysis
|
|
124
|
+
|
|
125
|
+
读取 daily-reports 中的新增字段,按优先级分析:
|
|
126
|
+
|
|
127
|
+
1. **Tool Parameter Errors**(tool_error_stats)
|
|
128
|
+
- `param_error_rate > 25%` → 高优先级建议
|
|
129
|
+
- 某工具参数错误集中 → 针对性建议
|
|
130
|
+
|
|
131
|
+
2. **Goal Task Quality**(goal_quality_stats)
|
|
132
|
+
- `task_completion_rate < 50%` → 任务拆分优化建议
|
|
133
|
+
- evidence 质量低 → Evidence 要求强化建议
|
|
134
|
+
|
|
135
|
+
3. **Subagent Efficiency**(subagent_stats)
|
|
136
|
+
- `failure_rate > 20%` → task prompt 优化建议
|
|
137
|
+
- `retry_rate > 15%` → 任务拆分优化建议
|
|
138
|
+
|
|
139
|
+
4. **Compact Efficiency**(compact_stats + context_stats)
|
|
140
|
+
- `compacts_per_session ≥ 3` → 上下文管理优化建议
|
|
141
|
+
- 上下文利用率持续偏高 → 工具输出优化建议
|
|
142
|
+
|
|
143
|
+
5. **Workflow Efficiency**(workflow_stats)
|
|
144
|
+
- 某阶段耗时占比 > 50% → 流程优化建议
|
|
145
|
+
- gate 重试频繁 → gate 检查项优化建议
|
|
146
|
+
|
|
147
|
+
6. **Todo Usage**(todo_stats)
|
|
148
|
+
- `abandon_rate > 25%` → Todo 使用模式优化建议
|
|
149
|
+
|
|
150
|
+
每个维度的分析结果应作为 actionable issues 写入 feedback-records。
|
|
151
|
+
对于高优先级发现(超过阈值的指标),生成 EvolutionSuggestion 对象并加入
|
|
152
|
+
第 4 步的 suggestions 列表中。
|
|
153
|
+
|
|
123
154
|
### 4. Generate Suggestions
|
|
124
155
|
|
|
125
156
|
For each actionable finding, create an EvolutionSuggestion object:
|
|
@@ -44,6 +44,58 @@ User says "/evolve-report", "evolve-report", "查看报告", "进化报告",
|
|
|
44
44
|
- Token consumption (input/output)
|
|
45
45
|
- Anomalies and signals
|
|
46
46
|
- Improvement suggestions (if any in the report)
|
|
47
|
+
4. **New Dimensions** — if present in the report, display additional sections:
|
|
48
|
+
|
|
49
|
+
#### Tool Parameter Errors (`tool_error_stats`)
|
|
50
|
+
|
|
51
|
+
Display when `tool_error_stats` field exists:
|
|
52
|
+
- Param error rate per tool (highlight tools with rate > 25%)
|
|
53
|
+
- Top parameter error patterns with occurrence counts
|
|
54
|
+
- Actionable issues from feedback-records (if any)
|
|
55
|
+
|
|
56
|
+
#### Goal Task Quality (`goal_quality_stats`)
|
|
57
|
+
|
|
58
|
+
Display when `goal_quality_stats` field exists:
|
|
59
|
+
- Task completion rate (highlight if < 50%)
|
|
60
|
+
- Average tasks per goal
|
|
61
|
+
- Evidence quality distribution (high/medium/low)
|
|
62
|
+
- Actionable issues: task splitting, evidence requirements
|
|
63
|
+
|
|
64
|
+
#### Subagent Efficiency (`subagent_stats`)
|
|
65
|
+
|
|
66
|
+
Display when `subagent_stats` field exists:
|
|
67
|
+
- Success / failure / retry counts
|
|
68
|
+
- Failure rate (highlight if > 20%)
|
|
69
|
+
- Retry rate (highlight if > 15%)
|
|
70
|
+
- Actionable issues: task prompt optimization, task splitting
|
|
71
|
+
|
|
72
|
+
#### Compact & Context Efficiency (`compact_stats` + `context_stats`)
|
|
73
|
+
|
|
74
|
+
Display when either field exists:
|
|
75
|
+
- Average compacts per session (highlight if ≥ 3)
|
|
76
|
+
- Context utilization trend (rising / stable / falling)
|
|
77
|
+
- Actionable issues: context management, tool output optimization
|
|
78
|
+
|
|
79
|
+
#### Workflow Efficiency (`workflow_stats`)
|
|
80
|
+
|
|
81
|
+
Display when `workflow_stats` field exists:
|
|
82
|
+
- Per-phase duration breakdown (highlight phase > 50% of total)
|
|
83
|
+
- Gate retry frequency per phase
|
|
84
|
+
- Actionable issues: workflow optimization, gate criteria tuning
|
|
85
|
+
|
|
86
|
+
#### Todo Usage (`todo_stats`)
|
|
87
|
+
|
|
88
|
+
Display when `todo_stats` field exists:
|
|
89
|
+
- Completion / abandon / in-progress counts
|
|
90
|
+
- Abandon rate (highlight if > 25%)
|
|
91
|
+
- Actionable issues: todo usage pattern optimization
|
|
92
|
+
|
|
93
|
+
**Formatting guidelines for new dimensions:**
|
|
94
|
+
- Use a consistent section header format: `### Dimension Name`
|
|
95
|
+
- Show metrics as key-value pairs or simple tables
|
|
96
|
+
- Prefix actionable issues with `⚠` marker
|
|
97
|
+
- If a dimension field is missing from the report, skip that section entirely
|
|
98
|
+
- Group all new dimension sections under a `## Extended Metrics` heading
|
|
47
99
|
|
|
48
100
|
### List Reports
|
|
49
101
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// packages/evolve-daily/src/detectors/compact.ts
|
|
2
|
+
|
|
3
|
+
import type { ProblemDefinition } from "../problems";
|
|
4
|
+
|
|
5
|
+
export interface CompactTrackedItem {
|
|
6
|
+
id: string;
|
|
7
|
+
problemId: "compact-frequency";
|
|
8
|
+
sessionId: string;
|
|
9
|
+
tokensBefore: number;
|
|
10
|
+
detected: boolean;
|
|
11
|
+
status: "pending" | "completed" | "error" | "dismissed";
|
|
12
|
+
detail?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function createCompactDetector(problem: ProblemDefinition) {
|
|
16
|
+
return {
|
|
17
|
+
problemId: problem.id,
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 从 session_compact 事件创建 tracked item。
|
|
21
|
+
* compact 不通过通用的 tool_execution_end handler,
|
|
22
|
+
* 而是独立监听 pi.on("session_compact") 事件。
|
|
23
|
+
*/
|
|
24
|
+
createItem(event: {
|
|
25
|
+
compactionEntry?: { tokensBefore?: number };
|
|
26
|
+
}): CompactTrackedItem {
|
|
27
|
+
return {
|
|
28
|
+
id: `compact-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
|
|
29
|
+
problemId: problem.id as "compact-frequency",
|
|
30
|
+
sessionId: "",
|
|
31
|
+
tokensBefore: event.compactionEntry?.tokensBefore ?? 0,
|
|
32
|
+
detected: true,
|
|
33
|
+
status: "pending",
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
steering(item: CompactTrackedItem): string {
|
|
38
|
+
return problem.detector.steering
|
|
39
|
+
.replace("{{id}}", item.id)
|
|
40
|
+
.replace("{{tokensBefore}}", String(item.tokensBefore));
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// packages/evolve-daily/src/detectors/goal-quality.ts
|
|
2
|
+
|
|
3
|
+
import type { ProblemDefinition } from "../problems";
|
|
4
|
+
|
|
5
|
+
export interface GoalQualityTrackedItem {
|
|
6
|
+
id: string;
|
|
7
|
+
problemId: "goal-task-quality";
|
|
8
|
+
sessionId: string;
|
|
9
|
+
goalId: string;
|
|
10
|
+
taskCount: number;
|
|
11
|
+
completedCount: number;
|
|
12
|
+
cancelledCount: number;
|
|
13
|
+
taskCompletionRate: number;
|
|
14
|
+
taskCancelRate: number;
|
|
15
|
+
status: "pending" | "completed" | "error" | "dismissed";
|
|
16
|
+
detail?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function createGoalQualityDetector(problem: ProblemDefinition) {
|
|
20
|
+
return {
|
|
21
|
+
problemId: problem.id,
|
|
22
|
+
events: problem.detector.events,
|
|
23
|
+
|
|
24
|
+
match(event: { type: string; toolName?: string }): boolean {
|
|
25
|
+
if (event.type !== "tool_result") return false;
|
|
26
|
+
return event.toolName === "goal_manager";
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
createItem(event: {
|
|
30
|
+
type: string;
|
|
31
|
+
toolName?: string;
|
|
32
|
+
details?: { tasks?: Array<{ status: string }> };
|
|
33
|
+
}): GoalQualityTrackedItem {
|
|
34
|
+
const tasks = event.details?.tasks ?? [];
|
|
35
|
+
const completed = tasks.filter((t) => t.status === "completed").length;
|
|
36
|
+
const cancelled = tasks.filter((t) => t.status === "cancelled").length;
|
|
37
|
+
const total = tasks.length;
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
id: `goal-quality-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
|
|
41
|
+
problemId: problem.id as "goal-task-quality",
|
|
42
|
+
sessionId: "",
|
|
43
|
+
goalId: "",
|
|
44
|
+
taskCount: total,
|
|
45
|
+
completedCount: completed,
|
|
46
|
+
cancelledCount: cancelled,
|
|
47
|
+
taskCompletionRate: total > 0 ? completed / total : 0,
|
|
48
|
+
taskCancelRate: total > 0 ? cancelled / total : 0,
|
|
49
|
+
status: "pending",
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
steering(item: GoalQualityTrackedItem): string {
|
|
54
|
+
return problem.detector.steering
|
|
55
|
+
.replace("{{id}}", item.id)
|
|
56
|
+
.replace("{{completionRate}}", String(item.taskCompletionRate));
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// packages/evolve-daily/src/detectors/param-error.ts
|
|
2
|
+
|
|
3
|
+
import type { ProblemDefinition } from "../problems";
|
|
4
|
+
|
|
5
|
+
export interface ParamErrorTrackedItem {
|
|
6
|
+
id: string;
|
|
7
|
+
problemId: "tool-param-validation";
|
|
8
|
+
sessionId: string;
|
|
9
|
+
toolName: string;
|
|
10
|
+
errorType: "param" | "runtime" | "unclassified";
|
|
11
|
+
errorPreview: string;
|
|
12
|
+
status: "pending" | "completed" | "error" | "dismissed";
|
|
13
|
+
detail?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const PARAM_ERROR_PATTERNS = [
|
|
17
|
+
/required.*parameter/i,
|
|
18
|
+
/missing.*argument/i,
|
|
19
|
+
/invalid.*type/i,
|
|
20
|
+
/schema.*validation/i,
|
|
21
|
+
/unexpected.*token/i,
|
|
22
|
+
/parameter.*missing/i,
|
|
23
|
+
/argument.*required/i,
|
|
24
|
+
/invalid.*argument/i,
|
|
25
|
+
/unknown.*parameter/i,
|
|
26
|
+
/missing.*required/i,
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const RUNTIME_ERROR_PATTERNS = [
|
|
30
|
+
/enoent/i,
|
|
31
|
+
/permission denied/i,
|
|
32
|
+
/non-zero exit/i,
|
|
33
|
+
/timeout/i,
|
|
34
|
+
/syntaxerror/i,
|
|
35
|
+
/typeerror/i,
|
|
36
|
+
/connection refused/i,
|
|
37
|
+
/out of memory/i,
|
|
38
|
+
/could not find the exact text/i,
|
|
39
|
+
/no such file/i,
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
function classifyError(errorMessage: string): "param" | "runtime" | "unclassified" {
|
|
43
|
+
for (const pattern of PARAM_ERROR_PATTERNS) {
|
|
44
|
+
if (pattern.test(errorMessage)) return "param";
|
|
45
|
+
}
|
|
46
|
+
for (const pattern of RUNTIME_ERROR_PATTERNS) {
|
|
47
|
+
if (pattern.test(errorMessage)) return "runtime";
|
|
48
|
+
}
|
|
49
|
+
return "unclassified";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const TRACKED_TOOLS = new Set(["edit", "bash", "read", "write"]);
|
|
53
|
+
|
|
54
|
+
export function createParamErrorDetector(problem: ProblemDefinition) {
|
|
55
|
+
return {
|
|
56
|
+
problemId: problem.id,
|
|
57
|
+
events: problem.detector.events,
|
|
58
|
+
|
|
59
|
+
match(event: { type: string; toolName?: string; isError?: boolean }): boolean {
|
|
60
|
+
if (event.type !== "tool_result") return false;
|
|
61
|
+
if (event.isError !== true) return false;
|
|
62
|
+
return TRACKED_TOOLS.has(event.toolName ?? "");
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
createItem(event: {
|
|
66
|
+
type: string;
|
|
67
|
+
toolName?: string;
|
|
68
|
+
isError?: boolean;
|
|
69
|
+
content?: string;
|
|
70
|
+
}): ParamErrorTrackedItem {
|
|
71
|
+
const errorMessage = event.content ?? "";
|
|
72
|
+
return {
|
|
73
|
+
id: `param-error-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
|
|
74
|
+
problemId: problem.id as "tool-param-validation",
|
|
75
|
+
sessionId: "",
|
|
76
|
+
toolName: event.toolName ?? "unknown",
|
|
77
|
+
errorType: classifyError(errorMessage),
|
|
78
|
+
errorPreview: errorMessage.slice(0, 200),
|
|
79
|
+
status: "pending",
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
steering(item: ParamErrorTrackedItem): string {
|
|
84
|
+
return problem.detector.steering
|
|
85
|
+
.replace("{{id}}", item.id)
|
|
86
|
+
.replace("{{toolName}}", item.toolName)
|
|
87
|
+
.replace("{{errorPreview}}", item.errorPreview);
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// packages/evolve-daily/src/detectors/subagent-result.ts
|
|
2
|
+
|
|
3
|
+
import type { ProblemDefinition } from "../problems";
|
|
4
|
+
|
|
5
|
+
export interface SubagentTrackedItem {
|
|
6
|
+
id: string;
|
|
7
|
+
problemId: "subagent-efficiency";
|
|
8
|
+
sessionId: string;
|
|
9
|
+
taskType: string;
|
|
10
|
+
isError: boolean;
|
|
11
|
+
resultLength: number;
|
|
12
|
+
status: "pending" | "completed" | "error" | "dismissed";
|
|
13
|
+
detail?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const TASK_TYPE_PATTERNS: Record<string, RegExp> = {
|
|
17
|
+
code_review: /review|审查|检查/i,
|
|
18
|
+
implementation: /implement|实现|编写|创建/i,
|
|
19
|
+
testing: /test|测试|验证/i,
|
|
20
|
+
analysis: /analyze|分析|研究/i,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function classifyTaskType(taskPrompt: string): string {
|
|
24
|
+
for (const [type, pattern] of Object.entries(TASK_TYPE_PATTERNS)) {
|
|
25
|
+
if (pattern.test(taskPrompt)) return type;
|
|
26
|
+
}
|
|
27
|
+
return "unknown";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function createSubagentDetector(problem: ProblemDefinition) {
|
|
31
|
+
return {
|
|
32
|
+
problemId: problem.id,
|
|
33
|
+
events: problem.detector.events,
|
|
34
|
+
|
|
35
|
+
match(event: { type: string; toolName?: string; isError?: boolean }): boolean {
|
|
36
|
+
if (event.type !== "tool_result") return false;
|
|
37
|
+
return event.toolName === "subagent";
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
createItem(event: {
|
|
41
|
+
type: string;
|
|
42
|
+
toolName?: string;
|
|
43
|
+
isError?: boolean;
|
|
44
|
+
content?: string;
|
|
45
|
+
taskPrompt?: string;
|
|
46
|
+
}): SubagentTrackedItem {
|
|
47
|
+
return {
|
|
48
|
+
id: `subagent-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
|
|
49
|
+
problemId: problem.id as "subagent-efficiency",
|
|
50
|
+
sessionId: "",
|
|
51
|
+
taskType: classifyTaskType(event.taskPrompt ?? ""),
|
|
52
|
+
isError: event.isError ?? false,
|
|
53
|
+
resultLength: event.content?.length ?? 0,
|
|
54
|
+
status: "pending",
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
steering(item: SubagentTrackedItem): string {
|
|
59
|
+
return problem.detector.steering
|
|
60
|
+
.replace("{{id}}", item.id)
|
|
61
|
+
.replace("{{exitCode}}", item.isError ? "error" : "0")
|
|
62
|
+
.replace("{{duration}}", "unknown");
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,18 +1,35 @@
|
|
|
1
|
+
// packages/evolve-daily/src/index.ts
|
|
2
|
+
|
|
1
3
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
2
4
|
import { existsSync, unlinkSync } from "node:fs";
|
|
3
5
|
import { homedir } from "node:os";
|
|
4
6
|
import { dirname, join } from "node:path";
|
|
5
7
|
import { fileURLToPath } from "node:url";
|
|
6
8
|
|
|
9
|
+
import { PROBLEM_REGISTRY } from "./problems";
|
|
10
|
+
import { createCompactDetector } from "./detectors/compact";
|
|
11
|
+
import { createSubagentDetector } from "./detectors/subagent-result";
|
|
12
|
+
import { createParamErrorDetector } from "./detectors/param-error";
|
|
13
|
+
import { createGoalQualityDetector } from "./detectors/goal-quality";
|
|
14
|
+
import { createTracker } from "./trackers/core";
|
|
15
|
+
import { skillExecutionConfig } from "./trackers/skill-execution";
|
|
16
|
+
|
|
7
17
|
// 资源文件(Python 脚本)相对于扩展目录自身定位,不依赖外部绝对路径
|
|
8
18
|
const EXT_DIR = dirname(fileURLToPath(import.meta.url)); // src/
|
|
9
|
-
const ANALYZER_PATH = join(EXT_DIR, "..", "
|
|
19
|
+
const ANALYZER_PATH = join(EXT_DIR, "..", "analyzer", "analyze.py");
|
|
10
20
|
|
|
11
21
|
// 运行时数据目录使用 Pi 平台约定路径(homedir + .pi/agent/)
|
|
12
|
-
// 这是运行时产出数据,不是扩展自带的资源,用平台约定路径是合理的
|
|
13
22
|
const REPORTS_DIR = join(homedir(), ".pi", "agent", "evolution-data", "daily-reports");
|
|
14
23
|
|
|
24
|
+
/** tool_result 事件中匹配的工具结果 detector */
|
|
25
|
+
interface ToolResultDetector {
|
|
26
|
+
problemId: string;
|
|
27
|
+
match(event: Record<string, unknown>): boolean;
|
|
28
|
+
createItem(event: Record<string, unknown>): { id: string; problemId: string; status: string; detail?: string };
|
|
29
|
+
}
|
|
30
|
+
|
|
15
31
|
export default function evolveDailyExtension(pi: ExtensionAPI) {
|
|
32
|
+
// ── L1: session_start 时调用 Python analyzer ──
|
|
16
33
|
pi.on("session_start", async () => {
|
|
17
34
|
const today = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
|
|
18
35
|
const reportPath = join(REPORTS_DIR, `${today}.json`);
|
|
@@ -22,13 +39,90 @@ export default function evolveDailyExtension(pi: ExtensionAPI) {
|
|
|
22
39
|
try {
|
|
23
40
|
await pi.exec(
|
|
24
41
|
"python3",
|
|
25
|
-
[
|
|
42
|
+
[
|
|
43
|
+
ANALYZER_PATH,
|
|
44
|
+
"--since",
|
|
45
|
+
"1d",
|
|
46
|
+
"--format",
|
|
47
|
+
"json",
|
|
48
|
+
"--output",
|
|
49
|
+
reportPath,
|
|
50
|
+
],
|
|
26
51
|
{ timeout: 30_000 }
|
|
27
52
|
);
|
|
28
53
|
} catch (e) {
|
|
29
54
|
// Clean up partial output if analyzer failed mid-write
|
|
30
|
-
try {
|
|
55
|
+
try {
|
|
56
|
+
unlinkSync(reportPath);
|
|
57
|
+
} catch {
|
|
58
|
+
/* already gone */
|
|
59
|
+
}
|
|
31
60
|
console.error("[evolve-daily] analyzer failed:", e);
|
|
32
61
|
}
|
|
33
62
|
});
|
|
63
|
+
|
|
64
|
+
// ── L2c: Tracker 主动追踪(createTracker 在闭包内调用) ──
|
|
65
|
+
createTracker(pi, skillExecutionConfig);
|
|
66
|
+
|
|
67
|
+
// ── L2a: Compact 实时追踪 — 监听 session_compact 事件 ──
|
|
68
|
+
const compactDetector = createCompactDetector(
|
|
69
|
+
PROBLEM_REGISTRY.find((p) => p.id === "compact-frequency")!
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
pi.on("session_compact", async (event: Record<string, unknown>) => {
|
|
73
|
+
try {
|
|
74
|
+
const item = compactDetector.createItem(event);
|
|
75
|
+
pi.appendEntry("evolve-feedback", {
|
|
76
|
+
problemId: item.problemId,
|
|
77
|
+
itemId: item.id,
|
|
78
|
+
status: item.status,
|
|
79
|
+
detail: item.detail ?? null,
|
|
80
|
+
timestamp: new Date().toISOString(),
|
|
81
|
+
});
|
|
82
|
+
} catch (e) {
|
|
83
|
+
console.error(
|
|
84
|
+
`[evolve-daily] compact detector error:`,
|
|
85
|
+
e
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// ── L2b: 工具结果实时追踪 — 监听 tool_result 事件 ──
|
|
91
|
+
// subagent/param-error/goal-quality detectors 检查 event.type === "tool_result"
|
|
92
|
+
const toolDetectors: ToolResultDetector[] = [
|
|
93
|
+
createSubagentDetector(
|
|
94
|
+
PROBLEM_REGISTRY.find((p) => p.id === "subagent-efficiency")!
|
|
95
|
+
),
|
|
96
|
+
createParamErrorDetector(
|
|
97
|
+
PROBLEM_REGISTRY.find((p) => p.id === "tool-param-validation")!
|
|
98
|
+
),
|
|
99
|
+
createGoalQualityDetector(
|
|
100
|
+
PROBLEM_REGISTRY.find((p) => p.id === "goal-task-quality")!
|
|
101
|
+
),
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
pi.on(
|
|
105
|
+
"tool_result",
|
|
106
|
+
async (event: Record<string, unknown>, _ctx?: unknown) => {
|
|
107
|
+
for (const detector of toolDetectors) {
|
|
108
|
+
try {
|
|
109
|
+
if (detector.match(event)) {
|
|
110
|
+
const item = detector.createItem(event);
|
|
111
|
+
pi.appendEntry("evolve-feedback", {
|
|
112
|
+
problemId: item.problemId,
|
|
113
|
+
itemId: item.id,
|
|
114
|
+
status: item.status,
|
|
115
|
+
detail: item.detail ?? null,
|
|
116
|
+
timestamp: new Date().toISOString(),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
} catch (e) {
|
|
120
|
+
console.error(
|
|
121
|
+
`[evolve-daily] detector ${detector.problemId} error:`,
|
|
122
|
+
e
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
);
|
|
34
128
|
}
|