principles-disciple 1.5.4 → 1.7.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/dist/commands/context.d.ts +5 -0
- package/dist/commands/context.js +312 -0
- package/dist/commands/evolution-status.d.ts +4 -0
- package/dist/commands/evolution-status.js +138 -0
- package/dist/commands/export.d.ts +2 -0
- package/dist/commands/export.js +45 -0
- package/dist/commands/focus.d.ts +14 -0
- package/dist/commands/focus.js +582 -0
- package/dist/commands/pain.js +143 -6
- package/dist/commands/principle-rollback.d.ts +4 -0
- package/dist/commands/principle-rollback.js +22 -0
- package/dist/commands/rollback.d.ts +19 -0
- package/dist/commands/rollback.js +119 -0
- package/dist/commands/samples.d.ts +2 -0
- package/dist/commands/samples.js +55 -0
- package/dist/core/config.d.ts +37 -0
- package/dist/core/config.js +47 -0
- package/dist/core/control-ui-db.d.ts +68 -0
- package/dist/core/control-ui-db.js +274 -0
- package/dist/core/detection-funnel.d.ts +1 -1
- package/dist/core/detection-funnel.js +4 -0
- package/dist/core/dictionary.d.ts +2 -0
- package/dist/core/dictionary.js +13 -0
- package/dist/core/event-log.d.ts +22 -1
- package/dist/core/event-log.js +319 -0
- package/dist/core/evolution-engine.d.ts +5 -5
- package/dist/core/evolution-engine.js +18 -18
- package/dist/core/evolution-migration.d.ts +5 -0
- package/dist/core/evolution-migration.js +65 -0
- package/dist/core/evolution-reducer.d.ts +69 -0
- package/dist/core/evolution-reducer.js +369 -0
- package/dist/core/evolution-types.d.ts +103 -0
- package/dist/core/focus-history.d.ts +65 -0
- package/dist/core/focus-history.js +266 -0
- package/dist/core/init.js +30 -7
- package/dist/core/migration.js +0 -2
- package/dist/core/path-resolver.d.ts +3 -0
- package/dist/core/path-resolver.js +90 -31
- package/dist/core/paths.d.ts +7 -8
- package/dist/core/paths.js +48 -40
- package/dist/core/profile.js +1 -1
- package/dist/core/session-tracker.d.ts +4 -0
- package/dist/core/session-tracker.js +15 -0
- package/dist/core/thinking-models.d.ts +38 -0
- package/dist/core/thinking-models.js +170 -0
- package/dist/core/trajectory.d.ts +184 -0
- package/dist/core/trajectory.js +817 -0
- package/dist/core/trust-engine.d.ts +2 -0
- package/dist/core/trust-engine.js +30 -4
- package/dist/core/workspace-context.d.ts +13 -0
- package/dist/core/workspace-context.js +50 -7
- package/dist/hooks/gate.js +301 -30
- package/dist/hooks/llm.d.ts +8 -0
- package/dist/hooks/llm.js +347 -69
- package/dist/hooks/message-sanitize.d.ts +3 -0
- package/dist/hooks/message-sanitize.js +37 -0
- package/dist/hooks/pain.js +105 -5
- package/dist/hooks/prompt.d.ts +20 -11
- package/dist/hooks/prompt.js +558 -158
- package/dist/hooks/subagent.d.ts +9 -2
- package/dist/hooks/subagent.js +40 -3
- package/dist/http/principles-console-route.d.ts +2 -0
- package/dist/http/principles-console-route.js +257 -0
- package/dist/i18n/commands.js +48 -20
- package/dist/index.js +264 -8
- package/dist/service/control-ui-query-service.d.ts +217 -0
- package/dist/service/control-ui-query-service.js +537 -0
- package/dist/service/empathy-observer-manager.d.ts +42 -0
- package/dist/service/empathy-observer-manager.js +147 -0
- package/dist/service/evolution-worker.d.ts +10 -0
- package/dist/service/evolution-worker.js +156 -24
- package/dist/service/trajectory-service.d.ts +2 -0
- package/dist/service/trajectory-service.js +15 -0
- package/dist/tools/agent-spawn.d.ts +27 -6
- package/dist/tools/agent-spawn.js +339 -87
- package/dist/tools/deep-reflect.d.ts +27 -7
- package/dist/tools/deep-reflect.js +282 -113
- package/dist/types/event-types.d.ts +84 -2
- package/dist/types/event-types.js +33 -0
- package/dist/types.d.ts +52 -0
- package/dist/types.js +24 -1
- package/openclaw.plugin.json +43 -11
- package/package.json +16 -6
- package/templates/langs/zh/core/HEARTBEAT.md +28 -4
- package/templates/langs/zh/skills/pd-daily/SKILL.md +97 -13
- package/templates/pain_settings.json +54 -2
- package/templates/workspace/.principles/PROFILE.json +2 -0
- package/templates/workspace/okr/CURRENT_FOCUS.md +57 -0
|
@@ -1,9 +1,81 @@
|
|
|
1
1
|
import { Type } from '@sinclair/typebox';
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import * as fs from 'fs';
|
|
4
|
+
import * as path from 'node:path';
|
|
4
5
|
import { EventLogService } from '../core/event-log.js';
|
|
5
6
|
import { buildCritiquePromptV2 } from './critique-prompt.js';
|
|
6
7
|
import { resolvePdPath } from '../core/paths.js';
|
|
8
|
+
import { reflectionLogRetentionDays } from '../types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Write reflection result to reflection-log.md
|
|
11
|
+
* Uses atomic write (temp file + rename) to prevent race conditions
|
|
12
|
+
*/
|
|
13
|
+
function writeToReflectionLog(workspaceDir, context, insights, modelId, depth) {
|
|
14
|
+
const reflectionLogPath = resolvePdPath(workspaceDir, 'REFLECTION_LOG');
|
|
15
|
+
const memoryDir = path.dirname(reflectionLogPath);
|
|
16
|
+
// Ensure memory directory exists
|
|
17
|
+
if (!fs.existsSync(memoryDir)) {
|
|
18
|
+
fs.mkdirSync(memoryDir, { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
const timestamp = new Date().toISOString();
|
|
21
|
+
const entry = `
|
|
22
|
+
---
|
|
23
|
+
## Reflection at ${timestamp}
|
|
24
|
+
**Model**: ${modelId || 'auto-select'}
|
|
25
|
+
**Depth**: ${depth || 2}
|
|
26
|
+
|
|
27
|
+
### Context
|
|
28
|
+
${context.substring(0, 500)}${context.length > 500 ? '...' : ''}
|
|
29
|
+
|
|
30
|
+
### Insights
|
|
31
|
+
${insights}
|
|
32
|
+
|
|
33
|
+
`;
|
|
34
|
+
const header = `# Reflection Log\n\n> Auto-generated by Deep Reflection Tool\n> Retention: ${reflectionLogRetentionDays} days\n`;
|
|
35
|
+
// Read existing content
|
|
36
|
+
let existingContent = '';
|
|
37
|
+
if (fs.existsSync(reflectionLogPath)) {
|
|
38
|
+
existingContent = fs.readFileSync(reflectionLogPath, 'utf8');
|
|
39
|
+
}
|
|
40
|
+
const newContent = header + entry + existingContent.replace(header, '');
|
|
41
|
+
// Atomic write: write to temp file first, then rename
|
|
42
|
+
const tempPath = `${reflectionLogPath}.tmp`;
|
|
43
|
+
fs.writeFileSync(tempPath, newContent, 'utf8');
|
|
44
|
+
fs.renameSync(tempPath, reflectionLogPath);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Clean up reflection log entries older than retention period
|
|
48
|
+
*/
|
|
49
|
+
function cleanupReflectionLog(workspaceDir) {
|
|
50
|
+
const reflectionLogPath = resolvePdPath(workspaceDir, 'REFLECTION_LOG');
|
|
51
|
+
if (!fs.existsSync(reflectionLogPath))
|
|
52
|
+
return;
|
|
53
|
+
const content = fs.readFileSync(reflectionLogPath, 'utf8');
|
|
54
|
+
const cutoffDate = new Date();
|
|
55
|
+
cutoffDate.setDate(cutoffDate.getDate() - reflectionLogRetentionDays);
|
|
56
|
+
// Use more precise regex to match ISO timestamp
|
|
57
|
+
// Pattern: ---\n## Reflection at 2024-01-15T10:30:00
|
|
58
|
+
const entryPattern = /---\n## Reflection at (\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})/g;
|
|
59
|
+
const parts = content.split(entryPattern);
|
|
60
|
+
// parts[0] = header, then alternates: timestamp, content, timestamp, content...
|
|
61
|
+
const header = parts[0];
|
|
62
|
+
const validEntries = [];
|
|
63
|
+
for (let i = 1; i < parts.length; i += 2) {
|
|
64
|
+
const timestamp = parts[i];
|
|
65
|
+
const entryContent = parts[i + 1] || '';
|
|
66
|
+
const entryDate = new Date(timestamp);
|
|
67
|
+
if (entryDate >= cutoffDate) {
|
|
68
|
+
validEntries.push(`---\n## Reflection at ${timestamp}${entryContent}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (validEntries.length < (parts.length - 1) / 2) {
|
|
72
|
+
const newContent = header + validEntries.join('');
|
|
73
|
+
// Atomic write
|
|
74
|
+
const tempPath = `${reflectionLogPath}.tmp`;
|
|
75
|
+
fs.writeFileSync(tempPath, newContent, 'utf8');
|
|
76
|
+
fs.renameSync(tempPath, reflectionLogPath);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
7
79
|
const DEFAULT_CONFIG = {
|
|
8
80
|
enabled: true,
|
|
9
81
|
mode: 'auto',
|
|
@@ -40,97 +112,176 @@ function loadConfig(workspaceDir, api) {
|
|
|
40
112
|
}
|
|
41
113
|
return DEFAULT_CONFIG;
|
|
42
114
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
115
|
+
/**
|
|
116
|
+
* Helper to read string parameter from rawParams
|
|
117
|
+
* Supports both camelCase and snake_case parameter names
|
|
118
|
+
*/
|
|
119
|
+
function readStringParam(rawParams, key) {
|
|
120
|
+
const value = rawParams[key];
|
|
121
|
+
if (typeof value === 'string')
|
|
122
|
+
return value.trim() || undefined;
|
|
123
|
+
// Try snake_case alias
|
|
124
|
+
const snakeKey = key.replace(/([A-Z])/g, '_$1').toLowerCase();
|
|
125
|
+
const snakeValue = rawParams[snakeKey];
|
|
126
|
+
if (typeof snakeValue === 'string')
|
|
127
|
+
return snakeValue.trim() || undefined;
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Helper to read number parameter from rawParams
|
|
132
|
+
* Supports both camelCase and snake_case parameter names
|
|
133
|
+
*/
|
|
134
|
+
function readNumberParam(rawParams, key) {
|
|
135
|
+
const value = rawParams[key];
|
|
136
|
+
if (typeof value === 'number')
|
|
137
|
+
return value;
|
|
138
|
+
// Try snake_case alias
|
|
139
|
+
const snakeKey = key.replace(/([A-Z])/g, '_$1').toLowerCase();
|
|
140
|
+
const snakeValue = rawParams[snakeKey];
|
|
141
|
+
if (typeof snakeValue === 'number')
|
|
142
|
+
return snakeValue;
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Create Deep Reflect Tool
|
|
147
|
+
*
|
|
148
|
+
* Uses factory pattern to capture `api` in closure, following OpenClaw plugin SDK conventions.
|
|
149
|
+
* The execute signature must be: async (_toolCallId: string, rawParams: Record<string, unknown>)
|
|
150
|
+
*/
|
|
151
|
+
export function createDeepReflectTool(api) {
|
|
152
|
+
return {
|
|
153
|
+
name: 'deep_reflect',
|
|
154
|
+
description: '执行深层次的元认知反思,分析当前任务的潜在风险、逻辑漏洞或架构改进点。',
|
|
155
|
+
parameters: Type.Object({
|
|
156
|
+
context: Type.String({ description: '需要反思的任务上下文、代码片段或当前遇到的困难。' }),
|
|
157
|
+
depth: Type.Optional(Type.Number({ description: '反思深度 (1-3)。1: 快速扫描, 2: 均衡分析, 3: 彻底解构。默认为 2。', minimum: 1, maximum: 3 })),
|
|
158
|
+
model_id: Type.Optional(Type.String({ description: '可选:强制指定使用的思维模型 ID。' }))
|
|
159
|
+
}),
|
|
160
|
+
/**
|
|
161
|
+
* Tool execution logic
|
|
162
|
+
*
|
|
163
|
+
* OpenClaw tool execute signature:
|
|
164
|
+
* - First parameter: _toolCallId (string) - the tool call ID
|
|
165
|
+
* - Second parameter: rawParams (Record<string, unknown>) - the actual parameters
|
|
166
|
+
* - Third parameter (optional): signal (AbortSignal) - for cancellation
|
|
167
|
+
*/
|
|
168
|
+
async execute(_toolCallId, rawParams) {
|
|
169
|
+
const context = readStringParam(rawParams, 'context') || '';
|
|
170
|
+
const depth = readNumberParam(rawParams, 'depth') ?? 2;
|
|
171
|
+
const model_id = readStringParam(rawParams, 'model_id');
|
|
172
|
+
if (!context) {
|
|
173
|
+
return {
|
|
174
|
+
content: [{
|
|
175
|
+
type: 'text',
|
|
176
|
+
text: '❌ 错误: 必须提供反思上下文 (context)。'
|
|
177
|
+
}]
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
// 路径解析优先级:api.config > api.workspaceDir > api.resolvePath
|
|
181
|
+
const effectiveWorkspaceDir = api.config?.workspaceDir
|
|
182
|
+
|| api.workspaceDir
|
|
183
|
+
|| api.resolvePath?.('.');
|
|
184
|
+
if (!effectiveWorkspaceDir) {
|
|
185
|
+
return {
|
|
186
|
+
content: [{
|
|
187
|
+
type: 'text',
|
|
188
|
+
text: '❌ 反思执行失败: Workspace directory is required for deep reflection.。请检查 API 配置或网络连接。'
|
|
189
|
+
}]
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
const config = loadConfig(effectiveWorkspaceDir, api);
|
|
193
|
+
if (config.mode === 'disabled' || !config.enabled) {
|
|
194
|
+
return {
|
|
195
|
+
content: [{
|
|
196
|
+
type: 'text',
|
|
197
|
+
text: '⏭️ Deep Reflection 已禁用。'
|
|
198
|
+
}]
|
|
199
|
+
};
|
|
101
200
|
}
|
|
102
|
-
if (
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
201
|
+
if (model_id) {
|
|
202
|
+
safeLog(api, 'warn', `[DeepReflect] The 'model_id' parameter is deprecated. The agent will now auto-select models based on the context index.`);
|
|
203
|
+
}
|
|
204
|
+
const agentId = 'main';
|
|
205
|
+
const sessionKey = `agent:${agentId}:reflection:${randomUUID()}`;
|
|
206
|
+
const sessionId = sessionKey.split(':').pop();
|
|
207
|
+
const stateDir = resolvePdPath(effectiveWorkspaceDir, 'STATE_DIR');
|
|
208
|
+
const eventLog = EventLogService.get(stateDir, api.logger);
|
|
209
|
+
try {
|
|
210
|
+
const extraSystemPrompt = buildCritiquePromptV2({
|
|
211
|
+
context,
|
|
212
|
+
depth,
|
|
213
|
+
model_id,
|
|
214
|
+
api,
|
|
215
|
+
workspaceDir: effectiveWorkspaceDir
|
|
216
|
+
});
|
|
217
|
+
const startTime = Date.now();
|
|
218
|
+
const subagentRuntime = api.runtime.subagent;
|
|
219
|
+
if (!subagentRuntime)
|
|
220
|
+
throw new Error('OpenClaw subagent runtime not found.');
|
|
221
|
+
await subagentRuntime.run({
|
|
222
|
+
sessionKey,
|
|
223
|
+
message: `请对我当前的任务进行深层次反思。\n\n上下文:${context}`,
|
|
224
|
+
extraSystemPrompt,
|
|
225
|
+
deliver: false
|
|
226
|
+
});
|
|
227
|
+
const finalStatus = await subagentRuntime.waitForRun({ runId: sessionKey });
|
|
228
|
+
const duration = Date.now() - startTime;
|
|
229
|
+
if (finalStatus.status === 'timeout') {
|
|
230
|
+
return {
|
|
231
|
+
content: [{
|
|
232
|
+
type: 'text',
|
|
233
|
+
text: '⚠️ 反思任务执行超时。你可以尝试减少上下文长度或增加深度。'
|
|
234
|
+
}]
|
|
235
|
+
};
|
|
107
236
|
}
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
if (
|
|
112
|
-
insights =
|
|
237
|
+
if (finalStatus.status === 'ok') {
|
|
238
|
+
const rawMessages = await subagentRuntime.getSessionMessages({ sessionKey });
|
|
239
|
+
let insights = '';
|
|
240
|
+
if (rawMessages.assistantTexts && Array.isArray(rawMessages.assistantTexts)) {
|
|
241
|
+
insights = rawMessages.assistantTexts.join('\n');
|
|
113
242
|
}
|
|
114
|
-
else
|
|
115
|
-
|
|
243
|
+
else {
|
|
244
|
+
const messages = rawMessages.messages || [];
|
|
245
|
+
const lastMessage = messages[messages.length - 1];
|
|
246
|
+
if (typeof lastMessage?.content === 'string') {
|
|
247
|
+
insights = lastMessage.content;
|
|
248
|
+
}
|
|
249
|
+
else if (Array.isArray(lastMessage?.content)) {
|
|
250
|
+
insights = lastMessage.content.filter((c) => c.type === 'text').map((c) => c.text).join('\n');
|
|
251
|
+
}
|
|
116
252
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
253
|
+
if (insights.includes('REFLECTION_OK')) {
|
|
254
|
+
return {
|
|
255
|
+
content: [{
|
|
256
|
+
type: 'text',
|
|
257
|
+
text: '✅ 反思完成:当前任务逻辑严密,未发现显著问题。'
|
|
258
|
+
}]
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
if (eventLog && sessionId) {
|
|
262
|
+
eventLog.recordDeepReflection(sessionId, {
|
|
263
|
+
modelId: model_id || 'auto-select',
|
|
264
|
+
modelSelectionMode: model_id ? 'manual' : 'auto',
|
|
265
|
+
depth,
|
|
266
|
+
contextPreview: context.substring(0, 200),
|
|
267
|
+
resultPreview: insights.substring(0, 300),
|
|
268
|
+
durationMs: duration,
|
|
269
|
+
passed: true,
|
|
270
|
+
timeout: false
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
// Write to reflection log and cleanup old entries
|
|
274
|
+
try {
|
|
275
|
+
writeToReflectionLog(effectiveWorkspaceDir, context, insights, model_id, depth);
|
|
276
|
+
cleanupReflectionLog(effectiveWorkspaceDir);
|
|
277
|
+
}
|
|
278
|
+
catch (logErr) {
|
|
279
|
+
safeLog(api, 'warn', `[DeepReflect] Failed to write reflection log: ${String(logErr)}`);
|
|
280
|
+
}
|
|
281
|
+
return {
|
|
282
|
+
content: [{
|
|
283
|
+
type: 'text',
|
|
284
|
+
text: `
|
|
134
285
|
# 💎 Deep Reflection Insights
|
|
135
286
|
---
|
|
136
287
|
**Selected Model(s)**: ${model_id || 'auto-select'}
|
|
@@ -141,34 +292,52 @@ ${insights}
|
|
|
141
292
|
|
|
142
293
|
---
|
|
143
294
|
*Generated by Principles Disciple Meta-Cognitive Engine*
|
|
144
|
-
`.trim()
|
|
295
|
+
`.trim()
|
|
296
|
+
}]
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
throw new Error(`Subagent status: ${finalStatus.status}`);
|
|
301
|
+
}
|
|
145
302
|
}
|
|
146
|
-
|
|
147
|
-
|
|
303
|
+
catch (err) {
|
|
304
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
305
|
+
safeLog(api, 'error', `[DeepReflect] Reflection failed: ${errorMsg}`);
|
|
306
|
+
if (eventLog && sessionId) {
|
|
307
|
+
eventLog.recordDeepReflection(sessionId, {
|
|
308
|
+
modelId: model_id || 'auto-select',
|
|
309
|
+
modelSelectionMode: model_id ? 'manual' : 'auto',
|
|
310
|
+
depth,
|
|
311
|
+
contextPreview: context.substring(0, 200),
|
|
312
|
+
durationMs: 0,
|
|
313
|
+
passed: false,
|
|
314
|
+
timeout: errorMsg.toLowerCase().includes('timeout'),
|
|
315
|
+
error: errorMsg
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
if (errorMsg === 'API throw')
|
|
319
|
+
throw err;
|
|
320
|
+
return {
|
|
321
|
+
content: [{
|
|
322
|
+
type: 'text',
|
|
323
|
+
text: `❌ 反思执行失败: ${errorMsg}。请检查 API 配置或网络连接。`
|
|
324
|
+
}]
|
|
325
|
+
};
|
|
148
326
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
safeLog(api, 'error', `[DeepReflect] Reflection failed: ${errorMsg}`);
|
|
153
|
-
if (eventLog && sessionId) {
|
|
154
|
-
eventLog.recordDeepReflection(sessionId, {
|
|
155
|
-
modelId: model_id || 'auto-select',
|
|
156
|
-
modelSelectionMode: model_id ? 'manual' : 'auto',
|
|
157
|
-
depth,
|
|
158
|
-
contextPreview: context.substring(0, 200),
|
|
159
|
-
durationMs: 0,
|
|
160
|
-
passed: false,
|
|
161
|
-
timeout: errorMsg.toLowerCase().includes('timeout'),
|
|
162
|
-
error: errorMsg
|
|
163
|
-
});
|
|
327
|
+
finally {
|
|
328
|
+
if (api.runtime.subagent)
|
|
329
|
+
await api.runtime.subagent.deleteSession({ sessionKey }).catch(() => { });
|
|
164
330
|
}
|
|
165
|
-
if (errorMsg === 'API throw')
|
|
166
|
-
throw err;
|
|
167
|
-
return `❌ 反思执行失败: ${errorMsg}。请检查 API 配置或网络连接。`;
|
|
168
|
-
}
|
|
169
|
-
finally {
|
|
170
|
-
if (api.runtime.subagent)
|
|
171
|
-
await api.runtime.subagent.deleteSession({ sessionKey }).catch(() => { });
|
|
172
331
|
}
|
|
173
|
-
}
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
// Legacy export for backward compatibility with tests that call execute directly
|
|
335
|
+
export const deepReflectTool = {
|
|
336
|
+
name: 'deep_reflect',
|
|
337
|
+
description: '执行深层次的元认知反思,分析当前任务的潜在风险、逻辑漏洞或架构改进点。',
|
|
338
|
+
parameters: Type.Object({
|
|
339
|
+
context: Type.String({ description: '需要反思的任务上下文、代码片段或当前遇到的困难。' }),
|
|
340
|
+
depth: Type.Optional(Type.Number({ description: '反思深度 (1-3)。1: 快速扫描, 2: 均衡分析, 3: 彻底解构。默认为 2。', minimum: 1, maximum: 3 })),
|
|
341
|
+
model_id: Type.Optional(Type.String({ description: '可选:强制指定使用的思维模型 ID。' }))
|
|
342
|
+
}),
|
|
174
343
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Event types for structured logging and daily statistics.
|
|
3
3
|
*/
|
|
4
|
-
export type EventType = 'tool_call' | 'pain_signal' | 'rule_match' | 'rule_promotion' | 'hook_execution' | 'gate_block' | 'plan_approval' | 'evolution_task' | 'deep_reflection' | 'trust_change' | 'error' | 'warn';
|
|
5
|
-
export type EventCategory = 'success' | 'failure' | 'detected' | 'blocked' | 'approved' | 'enqueued' | 'completed' | 'promoted' | 'passed' | 'changed';
|
|
4
|
+
export type EventType = 'tool_call' | 'pain_signal' | 'rule_match' | 'rule_promotion' | 'hook_execution' | 'gate_block' | 'gate_bypass' | 'plan_approval' | 'evolution_task' | 'deep_reflection' | 'trust_change' | 'empathy_rollback' | 'error' | 'warn';
|
|
5
|
+
export type EventCategory = 'success' | 'failure' | 'detected' | 'blocked' | 'bypassed' | 'approved' | 'enqueued' | 'completed' | 'promoted' | 'passed' | 'changed' | 'rolled_back';
|
|
6
6
|
/**
|
|
7
7
|
* Base event structure for JSONL logging.
|
|
8
8
|
*/
|
|
@@ -42,6 +42,14 @@ export interface PainSignalEventData {
|
|
|
42
42
|
source: string;
|
|
43
43
|
reason?: string;
|
|
44
44
|
isRisky?: boolean;
|
|
45
|
+
origin?: 'assistant_self_report' | 'user_manual' | 'system_infer';
|
|
46
|
+
severity?: 'mild' | 'moderate' | 'severe';
|
|
47
|
+
confidence?: number;
|
|
48
|
+
detection_mode?: 'structured' | 'legacy_tag';
|
|
49
|
+
deduped?: boolean;
|
|
50
|
+
trigger_text_excerpt?: string;
|
|
51
|
+
raw_score?: number;
|
|
52
|
+
calibrated_score?: number;
|
|
45
53
|
}
|
|
46
54
|
export interface RuleMatchEventData {
|
|
47
55
|
ruleId: string;
|
|
@@ -67,6 +75,13 @@ export interface GateBlockEventData {
|
|
|
67
75
|
reason: string;
|
|
68
76
|
planStatus?: string;
|
|
69
77
|
}
|
|
78
|
+
export interface GateBypassEventData {
|
|
79
|
+
toolName: string;
|
|
80
|
+
filePath: string;
|
|
81
|
+
bypassType: 'stage4_architect' | 'plan_approved' | 'whitelisted';
|
|
82
|
+
trustScore: number;
|
|
83
|
+
trustStage: number;
|
|
84
|
+
}
|
|
70
85
|
export interface PlanApprovalEventData {
|
|
71
86
|
toolName: string;
|
|
72
87
|
filePath: string;
|
|
@@ -106,6 +121,18 @@ export interface DeepReflectionEventData {
|
|
|
106
121
|
/** 发现的风险数量 */
|
|
107
122
|
risksCount?: number;
|
|
108
123
|
}
|
|
124
|
+
export interface EmpathyRollbackEventData {
|
|
125
|
+
/** Event ID being rolled back */
|
|
126
|
+
eventId: string;
|
|
127
|
+
/** Original penalty score that was applied */
|
|
128
|
+
originalScore: number;
|
|
129
|
+
/** Session ID where the original event occurred */
|
|
130
|
+
originalSessionId?: string;
|
|
131
|
+
/** Reason for rollback (manual, false_positive, etc.) */
|
|
132
|
+
reason: string;
|
|
133
|
+
/** Who initiated the rollback */
|
|
134
|
+
triggeredBy: 'user_command' | 'natural_language' | 'system';
|
|
135
|
+
}
|
|
109
136
|
export interface ToolCallStats {
|
|
110
137
|
total: number;
|
|
111
138
|
success: number;
|
|
@@ -128,6 +155,59 @@ export interface PainStats {
|
|
|
128
155
|
avgScore: number;
|
|
129
156
|
maxScore: number;
|
|
130
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Empathy Engine event statistics for tracking emotional signals.
|
|
160
|
+
* Used for /pd-status empathy card and effectiveness metrics.
|
|
161
|
+
*/
|
|
162
|
+
export interface EmpathyEventStats {
|
|
163
|
+
/** Total empathy events detected (excluding deduped) */
|
|
164
|
+
totalEvents: number;
|
|
165
|
+
/** Events that were deduped (not counted in totalEvents) */
|
|
166
|
+
dedupedCount: number;
|
|
167
|
+
/** Dedupe hit rate (dedupedCount / (totalEvents + dedupedCount)) */
|
|
168
|
+
dedupeHitRate: number;
|
|
169
|
+
/** Total penalty score applied */
|
|
170
|
+
totalPenaltyScore: number;
|
|
171
|
+
/** Score rolled back via manual rollback */
|
|
172
|
+
rolledBackScore: number;
|
|
173
|
+
/** Number of rollback operations */
|
|
174
|
+
rollbackCount: number;
|
|
175
|
+
/** Events by severity level */
|
|
176
|
+
bySeverity: {
|
|
177
|
+
mild: number;
|
|
178
|
+
moderate: number;
|
|
179
|
+
severe: number;
|
|
180
|
+
};
|
|
181
|
+
/** Score by severity level */
|
|
182
|
+
scoreBySeverity: {
|
|
183
|
+
mild: number;
|
|
184
|
+
moderate: number;
|
|
185
|
+
severe: number;
|
|
186
|
+
};
|
|
187
|
+
/** Events by detection mode */
|
|
188
|
+
byDetectionMode: {
|
|
189
|
+
structured: number;
|
|
190
|
+
legacy_tag: number;
|
|
191
|
+
};
|
|
192
|
+
/** Events by origin */
|
|
193
|
+
byOrigin: {
|
|
194
|
+
assistant_self_report: number;
|
|
195
|
+
user_manual: number;
|
|
196
|
+
system_infer: number;
|
|
197
|
+
};
|
|
198
|
+
/** Confidence distribution */
|
|
199
|
+
confidenceDistribution: {
|
|
200
|
+
high: number;
|
|
201
|
+
medium: number;
|
|
202
|
+
low: number;
|
|
203
|
+
};
|
|
204
|
+
/** Daily trend (last 7 days) */
|
|
205
|
+
dailyTrend: Array<{
|
|
206
|
+
date: string;
|
|
207
|
+
count: number;
|
|
208
|
+
score: number;
|
|
209
|
+
}>;
|
|
210
|
+
}
|
|
131
211
|
export interface GfiStats {
|
|
132
212
|
peak: number;
|
|
133
213
|
samples: number;
|
|
@@ -214,6 +294,8 @@ export interface DailyStats {
|
|
|
214
294
|
errors: ErrorStats;
|
|
215
295
|
/** Pain signal statistics */
|
|
216
296
|
pain: PainStats;
|
|
297
|
+
/** Empathy Engine event statistics */
|
|
298
|
+
empathy: EmpathyEventStats;
|
|
217
299
|
/** GFI statistics */
|
|
218
300
|
gfi: GfiStats;
|
|
219
301
|
/** Evolution statistics */
|
|
@@ -34,6 +34,39 @@ export function createEmptyDailyStats(date) {
|
|
|
34
34
|
avgScore: 0,
|
|
35
35
|
maxScore: 0,
|
|
36
36
|
},
|
|
37
|
+
empathy: {
|
|
38
|
+
totalEvents: 0,
|
|
39
|
+
dedupedCount: 0,
|
|
40
|
+
dedupeHitRate: 0,
|
|
41
|
+
totalPenaltyScore: 0,
|
|
42
|
+
rolledBackScore: 0,
|
|
43
|
+
rollbackCount: 0,
|
|
44
|
+
bySeverity: {
|
|
45
|
+
mild: 0,
|
|
46
|
+
moderate: 0,
|
|
47
|
+
severe: 0,
|
|
48
|
+
},
|
|
49
|
+
scoreBySeverity: {
|
|
50
|
+
mild: 0,
|
|
51
|
+
moderate: 0,
|
|
52
|
+
severe: 0,
|
|
53
|
+
},
|
|
54
|
+
byDetectionMode: {
|
|
55
|
+
structured: 0,
|
|
56
|
+
legacy_tag: 0,
|
|
57
|
+
},
|
|
58
|
+
byOrigin: {
|
|
59
|
+
assistant_self_report: 0,
|
|
60
|
+
user_manual: 0,
|
|
61
|
+
system_infer: 0,
|
|
62
|
+
},
|
|
63
|
+
confidenceDistribution: {
|
|
64
|
+
high: 0,
|
|
65
|
+
medium: 0,
|
|
66
|
+
low: 0,
|
|
67
|
+
},
|
|
68
|
+
dailyTrend: [],
|
|
69
|
+
},
|
|
37
70
|
gfi: {
|
|
38
71
|
peak: 0,
|
|
39
72
|
samples: 0,
|
package/dist/types.d.ts
CHANGED
|
@@ -1 +1,53 @@
|
|
|
1
1
|
export type { PluginCommandContext, PluginCommandResult } from './openclaw-sdk.js';
|
|
2
|
+
/**
|
|
3
|
+
* Context Injection Configuration
|
|
4
|
+
* Controls what content gets injected into the LLM prompt.
|
|
5
|
+
*
|
|
6
|
+
* NOTE: Core Principles (PRINCIPLES.md) are ALWAYS injected and cannot be disabled.
|
|
7
|
+
* This is by design - principles are the foundation of the agent's behavior.
|
|
8
|
+
*/
|
|
9
|
+
export type ProjectFocusMode = 'full' | 'summary' | 'off';
|
|
10
|
+
export interface EvolutionContextConfig {
|
|
11
|
+
/** Enable conversation context in evolution task (default: true) */
|
|
12
|
+
enabled: boolean;
|
|
13
|
+
/** Max recent messages included in evolution task (default: 4) */
|
|
14
|
+
maxMessages: number;
|
|
15
|
+
/** Max chars per message snippet (default: 200) */
|
|
16
|
+
maxCharsPerMessage: number;
|
|
17
|
+
}
|
|
18
|
+
export interface ContextInjectionConfig {
|
|
19
|
+
/** Thinking OS (mental models) - can be toggled */
|
|
20
|
+
thinkingOs: boolean;
|
|
21
|
+
/** Project context (CURRENT_FOCUS.md) mode */
|
|
22
|
+
projectFocus: ProjectFocusMode;
|
|
23
|
+
/** Reflection log - can be toggled */
|
|
24
|
+
reflectionLog: boolean;
|
|
25
|
+
/** Trust score awareness - can be toggled */
|
|
26
|
+
trustScore: boolean;
|
|
27
|
+
/** Evolution task context injection settings */
|
|
28
|
+
evolutionContext: EvolutionContextConfig;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Default context injection configuration
|
|
32
|
+
* Based on user requirements:
|
|
33
|
+
* - principles: always on (not configurable)
|
|
34
|
+
* - thinkingOs: true (can be turned off)
|
|
35
|
+
* - projectFocus: 'off' (default closed, user can enable)
|
|
36
|
+
* - reflectionLog: true (default on)
|
|
37
|
+
* - trustScore: true (can be turned off)
|
|
38
|
+
*/
|
|
39
|
+
export declare const defaultContextConfig: ContextInjectionConfig;
|
|
40
|
+
/**
|
|
41
|
+
* Reflection log entry structure
|
|
42
|
+
*/
|
|
43
|
+
export interface ReflectionLogEntry {
|
|
44
|
+
timestamp: string;
|
|
45
|
+
context: string;
|
|
46
|
+
insights: string;
|
|
47
|
+
modelId?: string;
|
|
48
|
+
depth?: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Reflection log retention configuration
|
|
52
|
+
*/
|
|
53
|
+
export declare const reflectionLogRetentionDays = 7;
|