principles-disciple 1.66.0 → 1.67.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/ADVANCED_CONFIG_ZH.md +0 -4
- package/README.md +0 -11
- package/openclaw.plugin.json +1 -25
- package/package.json +1 -1
- package/src/commands/context.ts +6 -14
- package/src/commands/evolution-status.ts +29 -3
- package/src/commands/pain.ts +3 -4
- package/src/config/defaults/runtime.ts +0 -2
- package/src/constants/tools.ts +0 -1
- package/src/core/config.ts +0 -30
- package/src/core/event-log.ts +0 -6
- package/src/hooks/prompt.ts +3 -35
- package/src/hooks/subagent.ts +0 -7
- package/src/index.ts +0 -2
- package/src/service/evolution-worker.ts +0 -13
- package/src/service/runtime-summary-service.ts +94 -15
- package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +1 -204
- package/src/service/subagent-workflow/index.ts +0 -8
- package/src/service/subagent-workflow/types.ts +0 -11
- package/src/service/subagent-workflow/workflow-manager-base.ts +1 -1
- package/src/tools/critique-prompt.ts +1 -97
- package/src/tools/deep-reflect.ts +1 -337
- package/src/tools/model-index.ts +1 -100
- package/src/types/event-payload.ts +0 -6
- package/src/types/event-types.ts +0 -86
- package/src/types.ts +0 -21
- package/templates/langs/en/core/TOOLS.md +0 -43
- package/templates/langs/zh/core/TOOLS.md +0 -43
- package/templates/pain_settings.json +0 -21
- package/tests/commands/evolution-status.test.ts +288 -0
- package/tests/core/event-log.test.ts +1 -29
- package/tests/service/runtime-summary-service.test.ts +1 -1
package/ADVANCED_CONFIG_ZH.md
CHANGED
|
@@ -44,10 +44,6 @@
|
|
|
44
44
|
* `success_base` (默认: 1): 成功干完一个小任务,加 1 分。
|
|
45
45
|
* `streak_bonus` (默认: 5): 连续 5 次成功(连杀奖励),额外加 5 分。
|
|
46
46
|
|
|
47
|
-
### 5. 元认知深度反思 (`deep_reflection`)
|
|
48
|
-
* `enabled`: 是否允许 AI 停下来深思熟虑。
|
|
49
|
-
* `auto_trigger_conditions.error_rate_threshold` (默认: 0.3): 当近期操作的错误率超过 30% 时,强制让 AI 停下手头的活,调用 `deep_reflect` 工具分析自己是不是大方向搞错了。
|
|
50
|
-
|
|
51
47
|
---
|
|
52
48
|
|
|
53
49
|
### ⚠️ 高风险操作警告!
|
package/README.md
CHANGED
|
@@ -44,15 +44,6 @@ All commands support **short aliases** for easier input:
|
|
|
44
44
|
| `/nocturnal-rollout` | Nocturnal rollout and promotion |
|
|
45
45
|
| `/pd-workflow-debug` | Debug workflow state |
|
|
46
46
|
|
|
47
|
-
### Tools
|
|
48
|
-
|
|
49
|
-
**`deep_reflect`** - Executes deep meta-cognitive reflection to analyze potential risks, logical gaps, or architectural improvements in the current task.
|
|
50
|
-
|
|
51
|
-
Parameters:
|
|
52
|
-
- `context` (required): Task context, code snippet, or current difficulty
|
|
53
|
-
- `depth` (optional): Reflection depth 1-3 (default: 2)
|
|
54
|
-
- `model_id` (optional): Force specific thinking model
|
|
55
|
-
|
|
56
47
|
### Configuration
|
|
57
48
|
|
|
58
49
|
The plugin accepts the following configuration options:
|
|
@@ -62,8 +53,6 @@ The plugin accepts the following configuration options:
|
|
|
62
53
|
| `language` | `zh` | Interaction language (`en` or `zh`) |
|
|
63
54
|
| `auditLevel` | `medium` | Security guardrail level (`low`, `medium`, `high`) |
|
|
64
55
|
| `riskPaths` | `[]` | High-risk directories requiring explicit authorization |
|
|
65
|
-
| `deep_reflection.enabled` | `true` | Enable AI deep reflection |
|
|
66
|
-
| `deep_reflection.mode` | `auto` | Reflection trigger mode (`auto` or `forced`) |
|
|
67
56
|
|
|
68
57
|
## Part of the principles monorepo
|
|
69
58
|
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "principles-disciple",
|
|
3
3
|
"name": "Principles Disciple",
|
|
4
4
|
"description": "Evolutionary programming agent framework with strategic guardrails and reflection loops.",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.67.0",
|
|
6
6
|
"skills": [
|
|
7
7
|
"./skills"
|
|
8
8
|
],
|
|
@@ -37,27 +37,6 @@
|
|
|
37
37
|
"default": [],
|
|
38
38
|
"description": "自定义高危目录(例如 .git/, prod_db/)。AI 试图修改这些目录前,将被强制拦截并要求出具安全计划。"
|
|
39
39
|
},
|
|
40
|
-
"deep_reflection": {
|
|
41
|
-
"type": "object",
|
|
42
|
-
"additionalProperties": false,
|
|
43
|
-
"description": "当 AI 遇到复杂问题或连续报错时,是否允许它停下来进行深度自我反思?",
|
|
44
|
-
"properties": {
|
|
45
|
-
"enabled": {
|
|
46
|
-
"type": "boolean",
|
|
47
|
-
"default": true,
|
|
48
|
-
"description": "开启 AI 深度反思功能"
|
|
49
|
-
},
|
|
50
|
-
"mode": {
|
|
51
|
-
"type": "string",
|
|
52
|
-
"enum": [
|
|
53
|
-
"auto",
|
|
54
|
-
"forced"
|
|
55
|
-
],
|
|
56
|
-
"default": "auto",
|
|
57
|
-
"description": "auto: 遇到困难自动触发; forced: 每次回答前都强制反思 (极耗时间,不推荐)"
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
40
|
}
|
|
62
41
|
},
|
|
63
42
|
"uiHints": {
|
|
@@ -70,9 +49,6 @@
|
|
|
70
49
|
},
|
|
71
50
|
"riskPaths": {
|
|
72
51
|
"label": "⚠️ 绝对高危目录 (空表示不设限)"
|
|
73
|
-
},
|
|
74
|
-
"deep_reflection": {
|
|
75
|
-
"label": "💡 AI 深度反思功能"
|
|
76
52
|
}
|
|
77
53
|
},
|
|
78
54
|
"buildFingerprint": {
|
package/package.json
CHANGED
package/src/commands/context.ts
CHANGED
|
@@ -74,7 +74,6 @@ function showStatus(workspaceDir: string, isZh: boolean): string {
|
|
|
74
74
|
|------|------|------|
|
|
75
75
|
| 核心原则 | ✅ 始终开启 | 不可关闭 |
|
|
76
76
|
| 思维模型 | ${config.thinkingOs ? '✅ 开启' : '❌ 关闭'} | /pd-context thinking on/off |
|
|
77
|
-
| 反思日志 | ${config.reflectionLog ? '✅ 开启' : '❌ 关闭'} | /pd-context reflection on/off |
|
|
78
77
|
| 项目上下文 | ${formatProjectFocus(config.projectFocus, isZh)} | /pd-context focus full/summary/off |
|
|
79
78
|
|
|
80
79
|
💡 输入 \`/pd-context help\` 查看更多选项
|
|
@@ -87,7 +86,6 @@ function showStatus(workspaceDir: string, isZh: boolean): string {
|
|
|
87
86
|
|---------|--------|---------|
|
|
88
87
|
| Core Principles | ✅ Always ON | Not configurable |
|
|
89
88
|
| Thinking OS | ${config.thinkingOs ? '✅ ON' : '❌ OFF'} | /pd-context thinking on/off |
|
|
90
|
-
| Reflection Log | ${config.reflectionLog ? '✅ ON' : '❌ OFF'} | /pd-context reflection on/off |
|
|
91
89
|
| Project Context | ${formatProjectFocus(config.projectFocus, isZh)} | /pd-context focus full/summary/off |
|
|
92
90
|
|
|
93
91
|
💡 Type \`/pd-context help\` for more options
|
|
@@ -102,26 +100,26 @@ function showStatus(workspaceDir: string, isZh: boolean): string {
|
|
|
102
100
|
|
|
103
101
|
function toggleSetting(
|
|
104
102
|
workspaceDir: string,
|
|
105
|
-
key: 'thinkingOs'
|
|
103
|
+
key: 'thinkingOs',
|
|
106
104
|
value: string,
|
|
107
105
|
isZh: boolean
|
|
108
106
|
): string {
|
|
109
107
|
const config = loadContextInjectionConfig(workspaceDir);
|
|
110
108
|
const oldValue = config[key];
|
|
111
|
-
|
|
109
|
+
|
|
112
110
|
if (value === 'on') {
|
|
113
111
|
config[key] = true;
|
|
114
112
|
} else if (value === 'off') {
|
|
115
113
|
config[key] = false;
|
|
116
114
|
} else {
|
|
117
|
-
return isZh
|
|
115
|
+
return isZh
|
|
118
116
|
? `❌ 无效值: "${value}"。使用 "on" 或 "off"。`
|
|
119
117
|
: `❌ Invalid value: "${value}". Use "on" or "off".`;
|
|
120
118
|
}
|
|
121
|
-
|
|
119
|
+
|
|
122
120
|
const newValue = config[key];
|
|
123
|
-
const keyName = isZh
|
|
124
|
-
? { thinkingOs: '思维模型'
|
|
121
|
+
const keyName = isZh
|
|
122
|
+
? { thinkingOs: '思维模型' }[key]
|
|
125
123
|
: key;
|
|
126
124
|
|
|
127
125
|
// No change needed
|
|
@@ -222,7 +220,6 @@ function applyPreset(
|
|
|
222
220
|
case 'minimal':
|
|
223
221
|
config = {
|
|
224
222
|
thinkingOs: false,
|
|
225
|
-
reflectionLog: false,
|
|
226
223
|
projectFocus: 'off',
|
|
227
224
|
evolutionContext: { ...defaultContextConfig.evolutionContext }
|
|
228
225
|
};
|
|
@@ -230,7 +227,6 @@ function applyPreset(
|
|
|
230
227
|
case 'standard':
|
|
231
228
|
config = {
|
|
232
229
|
thinkingOs: true,
|
|
233
|
-
reflectionLog: false,
|
|
234
230
|
projectFocus: 'off',
|
|
235
231
|
evolutionContext: { ...defaultContextConfig.evolutionContext }
|
|
236
232
|
};
|
|
@@ -238,7 +234,6 @@ function applyPreset(
|
|
|
238
234
|
case 'full':
|
|
239
235
|
config = {
|
|
240
236
|
thinkingOs: true,
|
|
241
|
-
reflectionLog: true,
|
|
242
237
|
projectFocus: 'summary',
|
|
243
238
|
evolutionContext: { ...defaultContextConfig.evolutionContext }
|
|
244
239
|
};
|
|
@@ -328,9 +323,6 @@ export function handleContextCommand(ctx: PluginCommandContext): PluginCommandRe
|
|
|
328
323
|
case 'thinking':
|
|
329
324
|
result = toggleSetting(workspaceDir, 'thinkingOs', value, isZh);
|
|
330
325
|
break;
|
|
331
|
-
case 'reflection':
|
|
332
|
-
result = toggleSetting(workspaceDir, 'reflectionLog', value, isZh);
|
|
333
|
-
break;
|
|
334
326
|
case 'focus':
|
|
335
327
|
result = setProjectFocus(workspaceDir, value, isZh);
|
|
336
328
|
break;
|
|
@@ -100,6 +100,17 @@ function buildEnglishOutput(
|
|
|
100
100
|
`- generatedAt: ${summary.metadata.generatedAt}`,
|
|
101
101
|
];
|
|
102
102
|
|
|
103
|
+
// E: YAML-driven Workflow Funnels (Phase 6)
|
|
104
|
+
if (summary.workflowFunnels && summary.workflowFunnels.length > 0) {
|
|
105
|
+
lines.push('');
|
|
106
|
+
for (const funnel of summary.workflowFunnels) {
|
|
107
|
+
lines.push(`Workflow Funnel: ${funnel.funnelLabel}`);
|
|
108
|
+
for (const stage of funnel.stages) {
|
|
109
|
+
lines.push(` - ${stage.label}: ${stage.count}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
103
114
|
if (warnings.length > 0) {
|
|
104
115
|
lines.push('', 'Warnings');
|
|
105
116
|
for (const warning of warnings) {
|
|
@@ -110,8 +121,8 @@ function buildEnglishOutput(
|
|
|
110
121
|
return lines.join('\n');
|
|
111
122
|
}
|
|
112
123
|
|
|
113
|
-
|
|
114
|
-
|
|
124
|
+
|
|
125
|
+
|
|
115
126
|
function buildChineseOutput(
|
|
116
127
|
workspaceDir: string,
|
|
117
128
|
sessionId: string | null,
|
|
@@ -161,6 +172,17 @@ function buildChineseOutput(
|
|
|
161
172
|
`- 生成时间: ${summary.metadata.generatedAt}`,
|
|
162
173
|
];
|
|
163
174
|
|
|
175
|
+
// E: YAML驱动的Workflow Funnels (Phase 6)
|
|
176
|
+
if (summary.workflowFunnels && summary.workflowFunnels.length > 0) {
|
|
177
|
+
lines.push('');
|
|
178
|
+
for (const funnel of summary.workflowFunnels) {
|
|
179
|
+
lines.push(`Workflow 漏斗: ${funnel.funnelLabel}`);
|
|
180
|
+
for (const stage of funnel.stages) {
|
|
181
|
+
lines.push(` - ${stage.label}: ${stage.count}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
164
186
|
if (warnings.length > 0) {
|
|
165
187
|
lines.push('', '警告');
|
|
166
188
|
for (const warning of warnings) {
|
|
@@ -183,7 +205,11 @@ export function handleEvolutionStatusCommand(ctx: PluginCommandContext): { text:
|
|
|
183
205
|
const loader = new WorkflowFunnelLoader(stateDir);
|
|
184
206
|
loader.watch();
|
|
185
207
|
try {
|
|
186
|
-
const summary = RuntimeSummaryService.getSummary(workspaceDir, {
|
|
208
|
+
const summary = RuntimeSummaryService.getSummary(workspaceDir, {
|
|
209
|
+
sessionId,
|
|
210
|
+
loaderWarnings: loader.getWarnings(),
|
|
211
|
+
funnels: loader.getAllFunnels(),
|
|
212
|
+
});
|
|
187
213
|
const recommendations = WorkspaceContext.fromHookContext({ workspaceDir })
|
|
188
214
|
.principleLifecycle
|
|
189
215
|
.recomputeAll()
|
package/src/commands/pain.ts
CHANGED
|
@@ -156,8 +156,7 @@ export function handlePainCommand(ctx: PluginCommandContext): PluginCommandResul
|
|
|
156
156
|
suggestionText = `
|
|
157
157
|
💡 **建议 (系统检测到您当前遇到较大阻力)**:
|
|
158
158
|
1. 执行 \`/pd-status reset\` 清零疲劳值。
|
|
159
|
-
2.
|
|
160
|
-
3. 如果当前上下文太乱,考虑使用 \`/clear\` 开启新会话。`;
|
|
159
|
+
2. 如果当前上下文太乱,考虑使用 \`/clear\` 开启新会话。`;
|
|
161
160
|
}
|
|
162
161
|
else if (gfi > 50) healthLabel = '遇到阻力 🟡';
|
|
163
162
|
else if (gfi > 20) healthLabel = '轻微受挫 🟢';
|
|
@@ -168,8 +167,8 @@ export function handlePainCommand(ctx: PluginCommandContext): PluginCommandResul
|
|
|
168
167
|
suggestionText = `
|
|
169
168
|
💡 **Suggestion (High friction detected)**:
|
|
170
169
|
1. Run \`/pd-status reset\` to clear friction.
|
|
171
|
-
2. Ask the AI to
|
|
172
|
-
|
|
170
|
+
2. Ask the AI to reflect deeply before continuing.
|
|
171
|
+
3. Consider starting a new session with \`/clear\`.`;
|
|
173
172
|
}
|
|
174
173
|
else if (gfi > 50) healthLabel = 'High Friction 🟡';
|
|
175
174
|
else if (gfi > 20) healthLabel = 'Minor Issues 🟢';
|
|
@@ -115,8 +115,6 @@ export const MAX_FILE_SIZE_BYTES = 10 * 1024 * 1024;
|
|
|
115
115
|
|
|
116
116
|
// ── Workflow TTL Settings ───────────────────────────────────────────────────────
|
|
117
117
|
|
|
118
|
-
/** Deep-reflect workflow TTL (10 minutes) */
|
|
119
|
-
export const DEEP_REFLECT_TTL_MS = 10 * ONE_MINUTE_MS;
|
|
120
118
|
|
|
121
119
|
// ── Time Window Constants ───────────────────────────────────────────────────────
|
|
122
120
|
|
package/src/constants/tools.ts
CHANGED
package/src/core/config.ts
CHANGED
|
@@ -3,21 +3,6 @@ import * as fs from 'fs';
|
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import { atomicWriteFileSync } from '../utils/io.js';
|
|
5
5
|
|
|
6
|
-
export interface DeepReflectionSettings {
|
|
7
|
-
enabled: boolean;
|
|
8
|
-
mode: 'auto' | 'forced' | 'disabled';
|
|
9
|
-
force_checkpoint?: boolean;
|
|
10
|
-
checkpoint_message?: string;
|
|
11
|
-
auto_trigger_conditions?: {
|
|
12
|
-
min_tool_calls?: number;
|
|
13
|
-
error_rate_threshold?: number;
|
|
14
|
-
complexity_keywords?: string[];
|
|
15
|
-
};
|
|
16
|
-
default_model?: string;
|
|
17
|
-
default_depth?: number;
|
|
18
|
-
timeout_ms?: number;
|
|
19
|
-
modelsDir?: string;
|
|
20
|
-
}
|
|
21
6
|
|
|
22
7
|
export interface GfiGateSettings {
|
|
23
8
|
enabled: boolean;
|
|
@@ -83,7 +68,6 @@ export interface PainSettings {
|
|
|
83
68
|
initial_delay_ms: number;
|
|
84
69
|
task_timeout_ms: number;
|
|
85
70
|
};
|
|
86
|
-
deep_reflection?: DeepReflectionSettings;
|
|
87
71
|
empathy_engine?: {
|
|
88
72
|
enabled?: boolean;
|
|
89
73
|
dedupe_window_ms?: number;
|
|
@@ -159,20 +143,6 @@ export const DEFAULT_SETTINGS: PainSettings = {
|
|
|
159
143
|
initial_delay_ms: 5000,
|
|
160
144
|
task_timeout_ms: 60 * 60 * 1000 // 1 hour, matching evolution-worker.ts default
|
|
161
145
|
},
|
|
162
|
-
deep_reflection: {
|
|
163
|
-
enabled: true,
|
|
164
|
-
mode: 'auto',
|
|
165
|
-
force_checkpoint: true,
|
|
166
|
-
checkpoint_message: 'Before responding, quick self-check: 1. Task complexity (simple/medium/complex) 2. Information sufficiency (sufficient/need more) 3. If complex or insufficient info, call deep_reflect tool',
|
|
167
|
-
auto_trigger_conditions: {
|
|
168
|
-
min_tool_calls: 5,
|
|
169
|
-
error_rate_threshold: 0.3,
|
|
170
|
-
complexity_keywords: ['refactor', 'architecture', 'design', 'optimize', 'security', 'critical']
|
|
171
|
-
},
|
|
172
|
-
default_model: 'T-01',
|
|
173
|
-
default_depth: 2,
|
|
174
|
-
timeout_ms: 60000
|
|
175
|
-
},
|
|
176
146
|
empathy_engine: {
|
|
177
147
|
enabled: true,
|
|
178
148
|
dedupe_window_ms: 60000,
|
package/src/core/event-log.ts
CHANGED
|
@@ -16,7 +16,6 @@ import type {
|
|
|
16
16
|
GateBypassEventData,
|
|
17
17
|
PlanApprovalEventData,
|
|
18
18
|
EvolutionTaskEventData,
|
|
19
|
-
DeepReflectionEventData,
|
|
20
19
|
EmpathyRollbackEventData,
|
|
21
20
|
// C: New event data types
|
|
22
21
|
DiagnosisTaskEventData,
|
|
@@ -178,11 +177,6 @@ export class EventLog {
|
|
|
178
177
|
this.record('evolution_task', 'completed', undefined, data);
|
|
179
178
|
}
|
|
180
179
|
|
|
181
|
-
recordDeepReflection(sessionId: string | undefined, data: DeepReflectionEventData): void {
|
|
182
|
-
const category = data.passed ? 'passed' : data.timeout ? 'failure' : 'completed';
|
|
183
|
-
this.record('deep_reflection', category, sessionId, data);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
180
|
recordEmpathyRollback(sessionId: string | undefined, data: EmpathyRollbackEventData): void {
|
|
187
181
|
this.record('empathy_rollback', 'rolled_back', sessionId, data);
|
|
188
182
|
}
|
package/src/hooks/prompt.ts
CHANGED
|
@@ -789,7 +789,6 @@ ${taskBlocks}${processingNote}
|
|
|
789
789
|
- **STOP** aggressive file modifications.
|
|
790
790
|
- **START** every response with a sincere, non-defensive apology.
|
|
791
791
|
- **ACTION**: Explain why you failed, and propose a highly cautious recovery plan.
|
|
792
|
-
- Use 'deep_reflect' to analyze the root cause before proceeding with code changes.
|
|
793
792
|
`;
|
|
794
793
|
} else if (currentGfi >= 40) {
|
|
795
794
|
attitudeDirective = `
|
|
@@ -839,18 +838,6 @@ ${taskBlocks}${processingNote}
|
|
|
839
838
|
}
|
|
840
839
|
}
|
|
841
840
|
|
|
842
|
-
// Reflection Log (configurable) - moved to appendSystemContext for WebUI UX
|
|
843
|
-
let reflectionLogContent = '';
|
|
844
|
-
if (contextConfig.reflectionLog) {
|
|
845
|
-
const reflectionLogPath = wctx.resolve('REFLECTION_LOG');
|
|
846
|
-
try {
|
|
847
|
-
const cached = cachedReadFile(reflectionLogPath);
|
|
848
|
-
if (cached) reflectionLogContent = cached.trim();
|
|
849
|
-
} catch (e) {
|
|
850
|
-
logger?.error(`[PD:Prompt] Failed to read REFLECTION_LOG: ${String(e)}`);
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
|
|
854
841
|
// Project Context (configurable: full/summary/off) - moved to appendSystemContext for WebUI UX
|
|
855
842
|
let projectContextContent = '';
|
|
856
843
|
let workingMemoryContent = '';
|
|
@@ -988,17 +975,12 @@ ${empathySilenceConstraint}
|
|
|
988
975
|
appendParts.push(workingMemoryContent);
|
|
989
976
|
}
|
|
990
977
|
|
|
991
|
-
// 2.
|
|
992
|
-
if (reflectionLogContent) {
|
|
993
|
-
appendParts.push(`<reflection_log>\n${reflectionLogContent}\n</reflection_log>`);
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
// 3. Thinking OS (configurable)
|
|
978
|
+
// 2. Thinking OS (configurable)
|
|
997
979
|
if (thinkingOsContent) {
|
|
998
980
|
appendParts.push(`<thinking_os>\n${thinkingOsContent}\n</thinking_os>`);
|
|
999
981
|
}
|
|
1000
982
|
|
|
1001
|
-
//
|
|
983
|
+
// 3. Evolution Loop principles (active/probation)
|
|
1002
984
|
if (evolutionPrinciplesContent) {
|
|
1003
985
|
appendParts.push(`<evolution_principles>\n${evolutionPrinciplesContent}\n</evolution_principles>`);
|
|
1004
986
|
}
|
|
@@ -1163,22 +1145,8 @@ ${attitudeDirective}
|
|
|
1163
1145
|
}
|
|
1164
1146
|
}
|
|
1165
1147
|
|
|
1166
|
-
// 2.
|
|
1148
|
+
// 2. Final check
|
|
1167
1149
|
let newSize = prependSystemContext.length + prependContext.length + appendSystemContext.length;
|
|
1168
|
-
if (newSize > MAX_SIZE && reflectionLogContent && appendSystemContext.includes('<reflection_log>')) {
|
|
1169
|
-
const lines = reflectionLogContent.split('\n');
|
|
1170
|
-
if (lines.length > 30) {
|
|
1171
|
-
const truncated = lines.slice(0, 30).join('\n') + '\n...[truncated]';
|
|
1172
|
-
appendSystemContext = appendSystemContext.replace(
|
|
1173
|
-
`<reflection_log>\n${reflectionLogContent}\n</reflection_log>`,
|
|
1174
|
-
`<reflection_log>\n${truncated}\n</reflection_log>`
|
|
1175
|
-
);
|
|
1176
|
-
truncationLog.push('reflection_log');
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
// 3. Final check
|
|
1181
|
-
newSize = prependSystemContext.length + prependContext.length + appendSystemContext.length;
|
|
1182
1150
|
if (newSize > MAX_SIZE) {
|
|
1183
1151
|
// NOTE: We still return the content even if over limit, as truncating more
|
|
1184
1152
|
// could lose critical context like principles or evolution directives.
|
package/src/hooks/subagent.ts
CHANGED
|
@@ -6,7 +6,6 @@ import { extractAgentIdFromSessionKey } from '../utils/session-key.js';
|
|
|
6
6
|
import { recordEvolutionSuccess } from '../core/evolution-engine.js';
|
|
7
7
|
import { WorkflowStore } from '../service/subagent-workflow/workflow-store.js';
|
|
8
8
|
import { EmpathyObserverWorkflowManager } from '../service/subagent-workflow/empathy-observer-workflow-manager.js';
|
|
9
|
-
import { DeepReflectWorkflowManager } from '../service/subagent-workflow/deep-reflect-workflow-manager.js';
|
|
10
9
|
import type { WorkflowManager } from '../service/subagent-workflow/types.js';
|
|
11
10
|
|
|
12
11
|
/**
|
|
@@ -35,12 +34,6 @@ function createWorkflowManagerForType(
|
|
|
35
34
|
logger: loggerAdapter,
|
|
36
35
|
subagent,
|
|
37
36
|
});
|
|
38
|
-
case 'deep-reflect':
|
|
39
|
-
return new DeepReflectWorkflowManager({
|
|
40
|
-
workspaceDir,
|
|
41
|
-
logger: loggerAdapter,
|
|
42
|
-
subagent,
|
|
43
|
-
});
|
|
44
37
|
default:
|
|
45
38
|
return null;
|
|
46
39
|
}
|
package/src/index.ts
CHANGED
|
@@ -55,7 +55,6 @@ import { CentralSyncService } from './service/central-sync-service.js';
|
|
|
55
55
|
import { ensureWorkspaceTemplates } from './core/init.js';
|
|
56
56
|
import { migrateDirectoryStructure } from './core/migration.js';
|
|
57
57
|
import { SystemLogger } from './core/system-logger.js';
|
|
58
|
-
import { createDeepReflectTool } from './tools/deep-reflect.js';
|
|
59
58
|
import { createWritePainFlagTool } from './tools/write-pain-flag.js';
|
|
60
59
|
import { PathResolver } from './core/path-resolver.js';
|
|
61
60
|
import { createPrinciplesConsoleRoute } from './http/principles-console-route.js';
|
|
@@ -750,7 +749,6 @@ const plugin = {
|
|
|
750
749
|
}
|
|
751
750
|
});
|
|
752
751
|
|
|
753
|
-
api.registerTool(createDeepReflectTool(api));
|
|
754
752
|
api.registerTool(createWritePainFlagTool(api));
|
|
755
753
|
}
|
|
756
754
|
};
|
|
@@ -31,7 +31,6 @@ import { checkWorkspaceIdle, checkCooldown, recordCooldown } from './nocturnal-r
|
|
|
31
31
|
import { loadCooldownEscalationConfig, loadNocturnalConfigMerged } from './nocturnal-config.js';
|
|
32
32
|
import { WorkflowStore } from './subagent-workflow/workflow-store.js';
|
|
33
33
|
import { EmpathyObserverWorkflowManager } from './subagent-workflow/empathy-observer-workflow-manager.js';
|
|
34
|
-
import { DeepReflectWorkflowManager } from './subagent-workflow/deep-reflect-workflow-manager.js';
|
|
35
34
|
import { NocturnalWorkflowManager, nocturnalWorkflowSpec } from './subagent-workflow/nocturnal-workflow-manager.js';
|
|
36
35
|
import {
|
|
37
36
|
createNocturnalTrajectoryExtractor,
|
|
@@ -2443,18 +2442,6 @@ export const EvolutionWorkerService: ExtendedEvolutionWorkerService = {
|
|
|
2443
2442
|
empathyMgr.dispose();
|
|
2444
2443
|
}
|
|
2445
2444
|
|
|
2446
|
-
const deepReflectMgr = new DeepReflectWorkflowManager({
|
|
2447
|
-
workspaceDir: wctx.workspaceDir,
|
|
2448
|
-
logger: api.logger,
|
|
2449
|
-
subagent: subagentRuntime,
|
|
2450
|
-
agentSession,
|
|
2451
|
-
});
|
|
2452
|
-
try {
|
|
2453
|
-
swept += await deepReflectMgr.sweepExpiredWorkflows(WORKFLOW_TTL_MS);
|
|
2454
|
-
} finally {
|
|
2455
|
-
deepReflectMgr.dispose();
|
|
2456
|
-
}
|
|
2457
|
-
|
|
2458
2445
|
// #183 + #188: Sweep Nocturnal workflows too (with gateway-safe fallback)
|
|
2459
2446
|
try {
|
|
2460
2447
|
const nocturnalMgr = new NocturnalWorkflowManager({
|
|
@@ -6,6 +6,7 @@ import { WorkspaceContext } from '../core/workspace-context.js';
|
|
|
6
6
|
import { evaluatePhase3Inputs } from './phase3-input-filter.js';
|
|
7
7
|
import { TrajectoryRegistry } from '../core/trajectory.js';
|
|
8
8
|
import { getPendingDiagnosticianTasks } from '../core/diagnostician-task-store.js';
|
|
9
|
+
import type { WorkflowStage } from '../core/workflow-funnel-loader.js';
|
|
9
10
|
import type { RuntimeTruth, AnalyticsTruth } from '../types/runtime-summary.js';
|
|
10
11
|
|
|
11
12
|
export type RuntimeDataQuality = 'authoritative' | 'partial';
|
|
@@ -106,11 +107,15 @@ export interface RuntimeSummary {
|
|
|
106
107
|
recentBypasses: number | null;
|
|
107
108
|
dataQuality: RuntimeDataQuality;
|
|
108
109
|
};
|
|
110
|
+
/** YAML-driven funnel counts — only present when funnels param is provided (YAML-SSOT-01) */
|
|
111
|
+
workflowFunnels?: WorkflowFunnelOutput[];
|
|
109
112
|
metadata: {
|
|
110
113
|
generatedAt: string;
|
|
111
114
|
workspaceDir: string;
|
|
112
115
|
sessionId: string | null;
|
|
113
116
|
selectedSessionReason: 'explicit' | 'latest_active' | 'none';
|
|
117
|
+
/** 'degraded' when YAML load errors or unresolved statsField paths exist; 'ok' otherwise */
|
|
118
|
+
status: 'ok' | 'degraded';
|
|
114
119
|
warnings: string[];
|
|
115
120
|
};
|
|
116
121
|
}
|
|
@@ -153,6 +158,23 @@ interface EventLogEntry {
|
|
|
153
158
|
data?: Record<string, unknown>;
|
|
154
159
|
}
|
|
155
160
|
|
|
161
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
162
|
+
// Workflow Funnel Types (YAML-SSOT-01 / YAML-SSOT-02)
|
|
163
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
164
|
+
|
|
165
|
+
export interface WorkflowFunnelStageOutput {
|
|
166
|
+
key: string;
|
|
167
|
+
label: string;
|
|
168
|
+
statsField: string;
|
|
169
|
+
count: number;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export interface WorkflowFunnelOutput {
|
|
173
|
+
funnelKey: string;
|
|
174
|
+
funnelLabel: string;
|
|
175
|
+
stages: WorkflowFunnelStageOutput[];
|
|
176
|
+
}
|
|
177
|
+
|
|
156
178
|
const MAX_SOURCE_EVENTS = 5;
|
|
157
179
|
const GFI_PARTIAL_WARNING =
|
|
158
180
|
'GFI source attribution remains partial in Phase 2b because only the empathy slice is source-attributed; most non-empathy friction still lacks full per-source attribution.';
|
|
@@ -167,17 +189,30 @@ function pushWarning(warnings: string[], message: string): void {
|
|
|
167
189
|
}
|
|
168
190
|
}
|
|
169
191
|
|
|
192
|
+
/**
|
|
193
|
+
* YAML-SSOT-03: resolve a dot-path (e.g. 'evolution.nocturnalDreamerCompleted') from dailyStats.
|
|
194
|
+
* Returns { count, resolvable } to distinguish "field not found / non-numeric" from "legitimate zero".
|
|
195
|
+
*/
|
|
196
|
+
function resolveStatsField(stats: unknown, dotPath: string): { count: number; resolvable: boolean } {
|
|
197
|
+
const parts = dotPath.split('.');
|
|
198
|
+
let current: unknown = stats;
|
|
199
|
+
for (const part of parts) {
|
|
200
|
+
if (current == null || typeof current !== 'object') return { count: 0, resolvable: false };
|
|
201
|
+
current = (current as Record<string, unknown>)[part];
|
|
202
|
+
}
|
|
203
|
+
if (typeof current === 'number') {
|
|
204
|
+
return { count: current, resolvable: true };
|
|
205
|
+
}
|
|
206
|
+
return { count: 0, resolvable: false };
|
|
207
|
+
}
|
|
208
|
+
|
|
170
209
|
export class RuntimeSummaryService {
|
|
171
210
|
static getSummary(
|
|
172
211
|
workspaceDir: string,
|
|
173
|
-
options?: { sessionId?: string | null; loaderWarnings?: string[] }
|
|
212
|
+
options?: { sessionId?: string | null; loaderWarnings?: string[]; funnels?: Map<string, WorkflowStage[]> }
|
|
174
213
|
): RuntimeSummary {
|
|
175
214
|
const generatedAt = new Date().toISOString();
|
|
176
215
|
const warnings: string[] = [];
|
|
177
|
-
// ERR-01: surface loader warnings (YAML parse failures) into metadata.warnings
|
|
178
|
-
if (options?.loaderWarnings) {
|
|
179
|
-
warnings.push(...options.loaderWarnings);
|
|
180
|
-
}
|
|
181
216
|
const wctx = WorkspaceContext.fromHookContext({ workspaceDir });
|
|
182
217
|
|
|
183
218
|
const sessions = this.mergeSessionSnapshots(
|
|
@@ -215,11 +250,54 @@ export class RuntimeSummaryService {
|
|
|
215
250
|
false
|
|
216
251
|
);
|
|
217
252
|
|
|
218
|
-
//
|
|
219
|
-
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
253
|
+
// Unified date for all "today"-scope reads in this summary — ensures funnel counts,
|
|
254
|
+
// heartbeat stats, and dailyStats all agree on the same date and never contradict.
|
|
255
|
+
const todayStr = generatedAt.slice(0, 10);
|
|
256
|
+
|
|
257
|
+
// YAML-SSOT-02/03: build workflowFunnels from funnels Map if provided
|
|
258
|
+
let workflowFunnelsOutput: WorkflowFunnelOutput[] | undefined;
|
|
259
|
+
if (options?.funnels) {
|
|
260
|
+
workflowFunnelsOutput = [];
|
|
261
|
+
for (const [funnelKey, stages] of options.funnels) {
|
|
262
|
+
const stageOutputs: WorkflowFunnelStageOutput[] = stages.map(stage => {
|
|
263
|
+
const { count, resolvable } = resolveStatsField(dailyStats?.[todayStr], stage.statsField);
|
|
264
|
+
return {
|
|
265
|
+
key: stage.name,
|
|
266
|
+
label: stage.name,
|
|
267
|
+
statsField: stage.statsField,
|
|
268
|
+
count,
|
|
269
|
+
_resolvable: resolvable, // internal tag for degraded detection
|
|
270
|
+
};
|
|
271
|
+
});
|
|
272
|
+
workflowFunnelsOutput.push({ funnelKey, funnelLabel: funnelKey, stages: stageOutputs });
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// YAML-SSOT-04: warn for any unresolvable statsField paths
|
|
277
|
+
let hasUnresolvableStage = false;
|
|
278
|
+
if (workflowFunnelsOutput) {
|
|
279
|
+
for (const funnel of workflowFunnelsOutput) {
|
|
280
|
+
for (const stage of funnel.stages) {
|
|
281
|
+
if (!(stage as { _resolvable?: boolean })._resolvable) {
|
|
282
|
+
hasUnresolvableStage = true;
|
|
283
|
+
pushWarning(warnings, `statsField not resolvable: ${stage.statsField}`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// DEGRADED-01/02: status is degraded when YAML load errors or unresolvable statsField paths exist
|
|
290
|
+
const loaderWarnings = options?.loaderWarnings ?? [];
|
|
291
|
+
if (loaderWarnings.length > 0) {
|
|
292
|
+
for (const w of loaderWarnings) {
|
|
293
|
+
pushWarning(warnings, `YAML load warning: ${w}`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
const status: 'ok' | 'degraded' =
|
|
297
|
+
(loaderWarnings.length > 0 || hasUnresolvableStage) ? 'degraded' : 'ok';
|
|
298
|
+
|
|
299
|
+
// GFI peak — use today's data (consistent with funnel/heartbeat)
|
|
300
|
+
const dailyGfiPeak = dailyStats?.[todayStr]?.gfi?.peak;
|
|
223
301
|
|
|
224
302
|
const gfiCurrent =
|
|
225
303
|
selectedSession.session && Number.isFinite(selectedSession.session.currentGfi)
|
|
@@ -269,7 +347,6 @@ export class RuntimeSummaryService {
|
|
|
269
347
|
// Read pending tasks from the diagnostician task store
|
|
270
348
|
const pendingDiagTasks = getPendingDiagnosticianTasks(wctx.stateDir);
|
|
271
349
|
// Read heartbeat diagnosis stats from daily event log
|
|
272
|
-
const todayStr = generatedAt.slice(0, 10);
|
|
273
350
|
const diagDailyStats = dailyStats?.[todayStr]?.evolution;
|
|
274
351
|
const heartbeatDiagnosis = {
|
|
275
352
|
pendingTasks: pendingDiagTasks.length,
|
|
@@ -310,10 +387,10 @@ export class RuntimeSummaryService {
|
|
|
310
387
|
lastUpdated: trajectoryStats.lastIngestAt ?? generatedAt,
|
|
311
388
|
},
|
|
312
389
|
dailyStats: {
|
|
313
|
-
toolCalls: dailyStats?.[
|
|
314
|
-
painSignals: dailyStats?.[
|
|
315
|
-
evolutionTasks: dailyStats?.[
|
|
316
|
-
lastUpdated:
|
|
390
|
+
toolCalls: dailyStats?.[todayStr]?.toolCalls ?? 0,
|
|
391
|
+
painSignals: dailyStats?.[todayStr]?.painSignals ?? 0,
|
|
392
|
+
evolutionTasks: dailyStats?.[todayStr]?.evolutionTasks ?? 0,
|
|
393
|
+
lastUpdated: todayStr,
|
|
317
394
|
},
|
|
318
395
|
trends: {
|
|
319
396
|
sevenDay: { successRateChange: 0, toolCallVolumeChange: 0, painSignalRateChange: 0 },
|
|
@@ -360,11 +437,13 @@ export class RuntimeSummaryService {
|
|
|
360
437
|
gate: gateStats,
|
|
361
438
|
// D: Heartbeat Diagnostician chain — separate from evolution/nocturnal
|
|
362
439
|
heartbeatDiagnosis,
|
|
440
|
+
...(workflowFunnelsOutput && { workflowFunnels: workflowFunnelsOutput }),
|
|
363
441
|
metadata: {
|
|
364
442
|
generatedAt,
|
|
365
443
|
workspaceDir,
|
|
366
444
|
sessionId: selectedSessionId,
|
|
367
445
|
selectedSessionReason: selectedSession.reason,
|
|
446
|
+
status,
|
|
368
447
|
warnings,
|
|
369
448
|
},
|
|
370
449
|
};
|