principles-disciple 1.66.0 → 1.68.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 +3 -26
- package/package.json +1 -1
- package/scripts/sync-plugin.mjs +113 -28
- 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 +6 -38
- 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,9 +2,10 @@
|
|
|
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.68.0",
|
|
6
6
|
"skills": [
|
|
7
|
-
"
|
|
7
|
+
"templates/langs/en/skills",
|
|
8
|
+
"templates/langs/zh/skills"
|
|
8
9
|
],
|
|
9
10
|
"configSchema": {
|
|
10
11
|
"type": "object",
|
|
@@ -37,27 +38,6 @@
|
|
|
37
38
|
"default": [],
|
|
38
39
|
"description": "自定义高危目录(例如 .git/, prod_db/)。AI 试图修改这些目录前,将被强制拦截并要求出具安全计划。"
|
|
39
40
|
},
|
|
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
41
|
}
|
|
62
42
|
},
|
|
63
43
|
"uiHints": {
|
|
@@ -70,9 +50,6 @@
|
|
|
70
50
|
},
|
|
71
51
|
"riskPaths": {
|
|
72
52
|
"label": "⚠️ 绝对高危目录 (空表示不设限)"
|
|
73
|
-
},
|
|
74
|
-
"deep_reflection": {
|
|
75
|
-
"label": "💡 AI 深度反思功能"
|
|
76
53
|
}
|
|
77
54
|
},
|
|
78
55
|
"buildFingerprint": {
|
package/package.json
CHANGED
package/scripts/sync-plugin.mjs
CHANGED
|
@@ -400,6 +400,7 @@ function verifyBundleContents() {
|
|
|
400
400
|
{ name: 'checkPainFlag', reason: 'pain flag detection' },
|
|
401
401
|
{ name: 'processEvolutionQueue', reason: 'queue processing' },
|
|
402
402
|
{ name: 'acquireQueueLock', reason: 'queue lock for pd-reflect and worker' },
|
|
403
|
+
{ name: 'write_pain_flag', reason: 'pain signal recording tool' },
|
|
403
404
|
];
|
|
404
405
|
|
|
405
406
|
const missing = [];
|
|
@@ -523,6 +524,26 @@ function verifyInstalledFingerprint() {
|
|
|
523
524
|
console.log('✅ Installed fingerprint verified');
|
|
524
525
|
}
|
|
525
526
|
|
|
527
|
+
/**
|
|
528
|
+
* Update the plugin version in openclaw.json after successful sync.
|
|
529
|
+
* This ensures the recorded version always matches the installed version.
|
|
530
|
+
*/
|
|
531
|
+
function updateInstalledPluginVersion(version) {
|
|
532
|
+
const configPath = join(OPENCLAW_DIR, 'openclaw.json');
|
|
533
|
+
try {
|
|
534
|
+
const raw = readFileSync(configPath, 'utf-8');
|
|
535
|
+
const config = JSON.parse(raw);
|
|
536
|
+
if (config?.plugins?.installs?.['principles-disciple']) {
|
|
537
|
+
config.plugins.installs['principles-disciple'].version = version;
|
|
538
|
+
config.plugins.installs['principles-disciple'].installedAt = new Date().toISOString();
|
|
539
|
+
writeFileAtomic(configPath, JSON.stringify(config, null, 2) + '\n');
|
|
540
|
+
console.log(`✅ openclaw.json updated: version=${version}`);
|
|
541
|
+
}
|
|
542
|
+
} catch (err) {
|
|
543
|
+
console.warn(`⚠️ Could not update openclaw.json: ${err.message}`);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
526
547
|
/**
|
|
527
548
|
* Remove existing installation directory with Windows-friendly retry logic.
|
|
528
549
|
*/
|
|
@@ -583,16 +604,37 @@ function ensureInstallDir() {
|
|
|
583
604
|
}
|
|
584
605
|
|
|
585
606
|
/**
|
|
586
|
-
* Sync skills.
|
|
607
|
+
* Sync skills directories based on the skills field in openclaw.plugin.json.
|
|
608
|
+
* Reads the manifest to find declared skill paths, resolves them relative to
|
|
609
|
+
* source root, then copies each to the install target.
|
|
587
610
|
*/
|
|
588
|
-
function
|
|
589
|
-
const
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
611
|
+
function syncSkillDirs() {
|
|
612
|
+
const manifestPath = join(SOURCE_DIR, 'openclaw.plugin.json');
|
|
613
|
+
if (!existsSync(manifestPath)) return;
|
|
614
|
+
|
|
615
|
+
let skillsPaths;
|
|
616
|
+
try {
|
|
617
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
|
|
618
|
+
skillsPaths = manifest.skills;
|
|
619
|
+
} catch {
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
if (!skillsPaths || !Array.isArray(skillsPaths)) return;
|
|
624
|
+
|
|
625
|
+
for (const sp of skillsPaths) {
|
|
626
|
+
if (typeof sp !== 'string') continue;
|
|
627
|
+
const source = join(SOURCE_DIR, sp);
|
|
628
|
+
const name = sp.split('/').pop();
|
|
629
|
+
const target = join(INSTALL_DIR, 'skills', name);
|
|
630
|
+
if (!existsSync(source)) {
|
|
631
|
+
console.warn(` ⚠️ skills path not found: ${sp}`);
|
|
632
|
+
continue;
|
|
633
|
+
}
|
|
634
|
+
if (existsSync(target)) rmSync(target, { recursive: true, force: true });
|
|
635
|
+
cpSync(source, target, { recursive: true });
|
|
636
|
+
console.log(` 📄 skills/${name} (from ${sp})`);
|
|
637
|
+
}
|
|
596
638
|
}
|
|
597
639
|
|
|
598
640
|
/**
|
|
@@ -701,6 +743,23 @@ function isWindows() {
|
|
|
701
743
|
return process.platform === 'win32';
|
|
702
744
|
}
|
|
703
745
|
|
|
746
|
+
/**
|
|
747
|
+
* Check if a process is running by PID.
|
|
748
|
+
*/
|
|
749
|
+
function isProcessRunning(pid) {
|
|
750
|
+
try {
|
|
751
|
+
if (isWindows()) {
|
|
752
|
+
execSync(`tasklist /FI "PID eq ${pid}" /FO CSV /NH`, { stdio: 'ignore' });
|
|
753
|
+
return true;
|
|
754
|
+
} else {
|
|
755
|
+
process.kill(pid, 0);
|
|
756
|
+
return true;
|
|
757
|
+
}
|
|
758
|
+
} catch {
|
|
759
|
+
return false;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
704
763
|
/**
|
|
705
764
|
* Get temporary directory path (cross-platform).
|
|
706
765
|
*/
|
|
@@ -751,32 +810,57 @@ function restartGatewayWindows() {
|
|
|
751
810
|
}
|
|
752
811
|
} catch { /* no existing processes */ }
|
|
753
812
|
|
|
813
|
+
// Clean stale lock files — prevents ghost gateway false positives
|
|
814
|
+
try {
|
|
815
|
+
const lockDir = join(getTempDir(), 'openclaw');
|
|
816
|
+
if (existsSync(lockDir)) {
|
|
817
|
+
const files = readdirSync(lockDir).filter(f => f.startsWith('gateway.') && f.endsWith('.lock'));
|
|
818
|
+
for (const file of files) {
|
|
819
|
+
const lockPath = join(lockDir, file);
|
|
820
|
+
try {
|
|
821
|
+
const content = readFileSync(lockPath, 'utf-8');
|
|
822
|
+
const pid = parseInt(content.trim());
|
|
823
|
+
// Only remove if PID is not running
|
|
824
|
+
if (!pid || !isProcessRunning(pid)) {
|
|
825
|
+
rmSync(lockPath, { force: true });
|
|
826
|
+
console.log(` Removed stale lock: ${file}`);
|
|
827
|
+
}
|
|
828
|
+
} catch { /* ignore */ }
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
} catch { /* ignore lock cleanup failures */ }
|
|
832
|
+
|
|
754
833
|
// Trigger via schtasks — reliable, avoids CLI busy-port misdetection
|
|
755
834
|
console.log(' Starting gateway via scheduled task...');
|
|
756
835
|
execSync('schtasks /Run /TN "OpenClaw Gateway"', { stdio: 'inherit' });
|
|
757
836
|
|
|
758
|
-
// Wait for gateway to
|
|
759
|
-
const
|
|
837
|
+
// Wait for gateway to be listening on port (同步等待,不异步)
|
|
838
|
+
const port = 18789;
|
|
839
|
+
const deadline = Date.now() + 30000;
|
|
760
840
|
const pollInterval = 1000;
|
|
841
|
+
let gatewayListening = false;
|
|
761
842
|
|
|
762
|
-
|
|
763
|
-
if (Date.now() > deadline) {
|
|
764
|
-
console.warn('⚠️ Gateway started but PD registration not confirmed after 20s.');
|
|
765
|
-
console.log(' Check logs at: ' + logPath);
|
|
766
|
-
return;
|
|
767
|
-
}
|
|
843
|
+
while (Date.now() < deadline) {
|
|
768
844
|
try {
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
845
|
+
const result = execSync(
|
|
846
|
+
`powershell -NoProfile -Command "Get-NetTCPConnection -LocalPort ${port} -State Listen -ErrorAction SilentlyContinue | Measure-Object -Line).Count"`,
|
|
847
|
+
{ encoding: 'utf-8', timeout: 5000 }
|
|
848
|
+
).trim();
|
|
849
|
+
if (parseInt(result) > 0) {
|
|
850
|
+
gatewayListening = true;
|
|
851
|
+
break;
|
|
775
852
|
}
|
|
776
|
-
} catch { /*
|
|
777
|
-
|
|
778
|
-
}
|
|
779
|
-
|
|
853
|
+
} catch { /* port not listening yet */ }
|
|
854
|
+
execSync('timeout /t 1 /nobreak > nul', { shell: true, stdio: 'ignore' });
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
if (!gatewayListening) {
|
|
858
|
+
console.error('\n❌ Gateway did not start on port 18789 within 30s.');
|
|
859
|
+
console.error(' Please restart manually: openclaw gateway start');
|
|
860
|
+
process.exit(1);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
console.log(' ✅ Gateway is listening on port 18789');
|
|
780
864
|
|
|
781
865
|
} catch (error) {
|
|
782
866
|
console.error(`\n❌ Gateway restart failed: ${error.message}`);
|
|
@@ -890,7 +974,7 @@ function main() {
|
|
|
890
974
|
|
|
891
975
|
console.log('\n📦 Syncing files to OpenClaw...');
|
|
892
976
|
for (const item of SYNC_ITEMS) syncItem(item);
|
|
893
|
-
|
|
977
|
+
syncSkillDirs();
|
|
894
978
|
|
|
895
979
|
injectLocalWorkspacePackages();
|
|
896
980
|
installTargetDependencies();
|
|
@@ -948,6 +1032,7 @@ function main() {
|
|
|
948
1032
|
}
|
|
949
1033
|
|
|
950
1034
|
verifyInstalledFingerprint();
|
|
1035
|
+
updateInstalledPluginVersion(sourceVersion);
|
|
951
1036
|
if (args.dev || args.restart) cleanStaleBackups();
|
|
952
1037
|
|
|
953
1038
|
console.log('\n╔════════════════════════════════════════════════════════════╗');
|
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
|
@@ -435,7 +435,7 @@ export async function handleBeforePromptBuild(
|
|
|
435
435
|
const contextConfig = loadContextInjectionConfig(workspaceDir);
|
|
436
436
|
|
|
437
437
|
// Minimal mode: heartbeat and subagents skip most context to reduce tokens
|
|
438
|
-
const isMinimalMode = trigger === "heartbeat" || sessionId?.includes(":subagent:") === true;
|
|
438
|
+
const isMinimalMode = trigger === "heartbeat" || trigger === "cron" || sessionId?.includes(":subagent:") === true;
|
|
439
439
|
|
|
440
440
|
const session = sessionId ? getSession(sessionId) : undefined;
|
|
441
441
|
|
|
@@ -700,8 +700,8 @@ The empathy observer subagent handles pain detection independently.
|
|
|
700
700
|
// }
|
|
701
701
|
}
|
|
702
702
|
|
|
703
|
-
// ──── 4. Heartbeat-specific checklist ────
|
|
704
|
-
if (trigger === 'heartbeat') {
|
|
703
|
+
// ──── 4. Heartbeat-specific checklist (also fires for cron-triggered sessions) ────
|
|
704
|
+
if (trigger === 'heartbeat' || trigger === 'cron') {
|
|
705
705
|
// ──── 4a. GFI Time-based Decay ────
|
|
706
706
|
// Apply segmented exponential decay to GFI on each heartbeat
|
|
707
707
|
if (sessionId) {
|
|
@@ -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
|
}
|