principles-disciple 1.7.0 → 1.7.1
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/evolution-status.js +114 -118
- package/dist/commands/rollback.js +9 -3
- package/dist/commands/trust.js +64 -81
- package/dist/core/event-log.d.ts +6 -1
- package/dist/core/event-log.js +7 -0
- package/dist/core/session-tracker.d.ts +10 -2
- package/dist/core/session-tracker.js +60 -9
- package/dist/core/trust-engine.d.ts +4 -0
- package/dist/core/trust-engine.js +20 -25
- package/dist/hooks/gate.js +68 -53
- package/dist/hooks/llm.js +5 -2
- package/dist/hooks/subagent.js +42 -27
- package/dist/hooks/trajectory-collector.d.ts +32 -0
- package/dist/hooks/trajectory-collector.js +256 -0
- package/dist/index.js +22 -0
- package/dist/service/empathy-observer-manager.d.ts +2 -0
- package/dist/service/empathy-observer-manager.js +43 -1
- package/dist/service/evolution-worker.d.ts +19 -1
- package/dist/service/evolution-worker.js +116 -31
- package/dist/service/runtime-summary-service.d.ts +79 -0
- package/dist/service/runtime-summary-service.js +319 -0
- package/dist/types/event-types.d.ts +1 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
|
@@ -1,138 +1,134 @@
|
|
|
1
1
|
import { EvolutionReducerImpl } from '../core/evolution-reducer.js';
|
|
2
2
|
import { normalizeLanguage } from '../i18n/commands.js';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
function getQueueStats(workspaceDir) {
|
|
8
|
-
const stateDir = path.join(workspaceDir, '.state', 'principles');
|
|
9
|
-
const queuePath = path.join(stateDir, 'evolution_queue.json');
|
|
10
|
-
let pending = 0;
|
|
11
|
-
let completed = 0;
|
|
12
|
-
let inProgress = 0;
|
|
13
|
-
try {
|
|
14
|
-
if (fs.existsSync(queuePath)) {
|
|
15
|
-
const queue = JSON.parse(fs.readFileSync(queuePath, 'utf-8'));
|
|
16
|
-
for (const item of queue) {
|
|
17
|
-
if (item.status === 'completed') {
|
|
18
|
-
completed++;
|
|
19
|
-
}
|
|
20
|
-
else if (item.status === 'in_progress') {
|
|
21
|
-
inProgress++;
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
pending++;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
3
|
+
import { RuntimeSummaryService } from '../service/runtime-summary-service.js';
|
|
4
|
+
function formatAge(ageSeconds, lang) {
|
|
5
|
+
if (ageSeconds === null) {
|
|
6
|
+
return '--';
|
|
28
7
|
}
|
|
29
|
-
|
|
30
|
-
|
|
8
|
+
if (ageSeconds < 60) {
|
|
9
|
+
return lang === 'zh' ? `${ageSeconds} \u79d2` : `${ageSeconds}s`;
|
|
31
10
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const stateDir = path.join(workspaceDir, '.state', 'principles');
|
|
36
|
-
const painFlagPath = path.join(stateDir, '.pain_flag');
|
|
37
|
-
try {
|
|
38
|
-
if (fs.existsSync(painFlagPath)) {
|
|
39
|
-
const data = JSON.parse(fs.readFileSync(painFlagPath, 'utf-8'));
|
|
40
|
-
return {
|
|
41
|
-
painScore: data.score || 0,
|
|
42
|
-
painSource: data.source || 'none'
|
|
43
|
-
};
|
|
44
|
-
}
|
|
11
|
+
const minutes = Math.floor(ageSeconds / 60);
|
|
12
|
+
if (minutes < 60) {
|
|
13
|
+
return lang === 'zh' ? `${minutes} \u5206\u949f` : `${minutes}m`;
|
|
45
14
|
}
|
|
46
|
-
|
|
47
|
-
|
|
15
|
+
const hours = Math.floor(minutes / 60);
|
|
16
|
+
if (hours < 24) {
|
|
17
|
+
return lang === 'zh' ? `${hours} \u5c0f\u65f6` : `${hours}h`;
|
|
48
18
|
}
|
|
49
|
-
|
|
19
|
+
const days = Math.floor(hours / 24);
|
|
20
|
+
return lang === 'zh' ? `${days} \u5929` : `${days}d`;
|
|
50
21
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const stats = reducer.getStats();
|
|
55
|
-
// Get Trust Score
|
|
56
|
-
let trustScore = 0;
|
|
57
|
-
let trustStage = 1;
|
|
58
|
-
try {
|
|
59
|
-
const scorecard = getAgentScorecard(workspaceDir);
|
|
60
|
-
trustScore = scorecard.trust_score ?? 0;
|
|
61
|
-
trustStage = trustScore >= 80 ? 4 : trustScore >= 60 ? 3 : trustScore >= 30 ? 2 : 1;
|
|
62
|
-
}
|
|
63
|
-
catch {
|
|
64
|
-
// Ignore errors, use defaults
|
|
65
|
-
}
|
|
66
|
-
// Get EventLog for GFI and Pain stats
|
|
67
|
-
let gfiPeak = 0;
|
|
68
|
-
let painSignals = 0;
|
|
69
|
-
try {
|
|
70
|
-
const stateDir = path.join(workspaceDir, '.state', 'principles');
|
|
71
|
-
const eventLog = EventLogService.get(stateDir);
|
|
72
|
-
const today = new Date().toISOString().split('T')[0];
|
|
73
|
-
const dailyStats = eventLog.getDailyStats(today);
|
|
74
|
-
gfiPeak = dailyStats.gfi?.peak ?? 0;
|
|
75
|
-
painSignals = dailyStats.pain?.signalsDetected ?? 0;
|
|
76
|
-
}
|
|
77
|
-
catch {
|
|
78
|
-
// Ignore errors, use defaults
|
|
22
|
+
function formatNumber(value) {
|
|
23
|
+
if (value === null || Number.isNaN(value)) {
|
|
24
|
+
return '--';
|
|
79
25
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const lines = [
|
|
89
|
-
'📈 Evolution 状态',
|
|
90
|
-
'━━━━━━━━━━━━━━━━━━━━━━━━━━━━',
|
|
91
|
-
'',
|
|
92
|
-
`🛡️ Trust Score: ${trustScore}/100 (Stage ${trustStage})`,
|
|
93
|
-
`😴 GFI Peak: ${gfiPeak.toFixed(1)}`,
|
|
94
|
-
`⚡ Current Pain: ${currentPain.painScore} pts (${currentPain.painSource})`,
|
|
95
|
-
`📈 Pain Signals Today: ${painSignals}`,
|
|
96
|
-
'',
|
|
97
|
-
'📊 Evolution Rules',
|
|
98
|
-
'━━━━━━━━━━━━━━━━━━━━━━━━━━━━',
|
|
99
|
-
`- 候选原则: ${stats.candidateCount}`,
|
|
100
|
-
`- 观察期原则: ${stats.probationCount}`,
|
|
101
|
-
`- 生效原则: ${stats.activeCount}`,
|
|
102
|
-
`- 已废弃原则: ${stats.deprecatedCount}`,
|
|
103
|
-
`- 最近晋升时间: ${stats.lastPromotedAt ?? '无'}`,
|
|
104
|
-
'',
|
|
105
|
-
'📋 Evolution Queue',
|
|
106
|
-
'━━━━━━━━━━━━━━━━━━━━━━━━━━━━',
|
|
107
|
-
`- 待处理: ${queueStats.pending} 项`,
|
|
108
|
-
`- 进行中: ${queueStats.inProgress} 项`,
|
|
109
|
-
`- 已完成: ${queueStats.completed} 项`,
|
|
110
|
-
];
|
|
111
|
-
return { text: lines.join('\n') };
|
|
26
|
+
return Number.isInteger(value) ? String(value) : value.toFixed(1);
|
|
27
|
+
}
|
|
28
|
+
function formatStage(value) {
|
|
29
|
+
return value === null ? '--' : String(value);
|
|
30
|
+
}
|
|
31
|
+
function formatSources(sources) {
|
|
32
|
+
if (sources.length === 0) {
|
|
33
|
+
return '--';
|
|
112
34
|
}
|
|
113
|
-
|
|
35
|
+
return sources
|
|
36
|
+
.map((source) => source.score === undefined
|
|
37
|
+
? source.source
|
|
38
|
+
: `${source.source}(${formatNumber(source.score)})`)
|
|
39
|
+
.join(', ');
|
|
40
|
+
}
|
|
41
|
+
function buildEnglishOutput(workspaceDir, sessionId, warnings, stats, summary) {
|
|
114
42
|
const lines = [
|
|
115
|
-
'
|
|
116
|
-
'
|
|
43
|
+
'Evolution Status',
|
|
44
|
+
'================',
|
|
45
|
+
'',
|
|
46
|
+
'Control Plane',
|
|
47
|
+
`- Legacy Trust: ${formatNumber(summary.legacyTrust.score)}/100 (stage ${formatStage(summary.legacyTrust.stage)}, legacy/frozen, ${summary.legacyTrust.rewardPolicy})`,
|
|
48
|
+
`- Session GFI: current ${formatNumber(summary.gfi.current)}, peak ${formatNumber(summary.gfi.peak)} (${summary.gfi.dataQuality})`,
|
|
49
|
+
`- GFI Sources: ${formatSources(summary.gfi.sources)}`,
|
|
50
|
+
`- Pain Flag: ${summary.pain.activeFlag ? 'active' : 'inactive'}${summary.pain.activeFlagSource ? ` (${summary.pain.activeFlagSource})` : ''}`,
|
|
51
|
+
`- Last Pain Signal: ${summary.pain.lastSignal ? `${summary.pain.lastSignal.source}${summary.pain.lastSignal.reason ? ` - ${summary.pain.lastSignal.reason}` : ''}` : '--'}`,
|
|
52
|
+
`- Gate Events: blocks ${formatNumber(summary.gate.recentBlocks)}, bypasses ${formatNumber(summary.gate.recentBypasses)} (${summary.gate.dataQuality})`,
|
|
117
53
|
'',
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
54
|
+
'Evolution',
|
|
55
|
+
`- Queue: pending ${summary.evolution.queue.pending}, in_progress ${summary.evolution.queue.inProgress}, completed ${summary.evolution.queue.completed} (${summary.evolution.dataQuality})`,
|
|
56
|
+
`- Directive: ${summary.evolution.directive.exists ? 'present' : 'missing'}, active ${summary.evolution.directive.active === null ? '--' : summary.evolution.directive.active ? 'yes' : 'no'}, age ${formatAge(summary.evolution.directive.ageSeconds, 'en')}`,
|
|
57
|
+
`- Directive Task: ${summary.evolution.directive.taskPreview ?? '--'}`,
|
|
122
58
|
'',
|
|
123
|
-
'
|
|
124
|
-
'━━━━━━━━━━━━━━━━━━━━━━━━━━━━',
|
|
59
|
+
'Principles',
|
|
125
60
|
`- candidate principles: ${stats.candidateCount}`,
|
|
126
61
|
`- probation principles: ${stats.probationCount}`,
|
|
127
62
|
`- active principles: ${stats.activeCount}`,
|
|
128
63
|
`- deprecated principles: ${stats.deprecatedCount}`,
|
|
129
64
|
`- last promoted: ${stats.lastPromotedAt ?? 'none'}`,
|
|
130
65
|
'',
|
|
131
|
-
'
|
|
132
|
-
|
|
133
|
-
`-
|
|
134
|
-
`-
|
|
135
|
-
`- Completed: ${queueStats.completed}`,
|
|
66
|
+
'Metadata',
|
|
67
|
+
`- workspace: ${workspaceDir}`,
|
|
68
|
+
`- session: ${sessionId ?? '--'} (${summary.metadata.selectedSessionReason})`,
|
|
69
|
+
`- generatedAt: ${summary.metadata.generatedAt}`,
|
|
136
70
|
];
|
|
137
|
-
|
|
71
|
+
if (warnings.length > 0) {
|
|
72
|
+
lines.push('', 'Warnings');
|
|
73
|
+
for (const warning of warnings) {
|
|
74
|
+
lines.push(`- ${warning}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return lines.join('\n');
|
|
78
|
+
}
|
|
79
|
+
function buildChineseOutput(workspaceDir, sessionId, warnings, stats, summary) {
|
|
80
|
+
const lines = [
|
|
81
|
+
'\u8fdb\u5316\u72b6\u6001',
|
|
82
|
+
'================',
|
|
83
|
+
'',
|
|
84
|
+
'\u63a7\u5236\u9762',
|
|
85
|
+
`- Legacy Trust: ${formatNumber(summary.legacyTrust.score)}/100\uff08\u9636\u6bb5 ${formatStage(summary.legacyTrust.stage)}\uff0clegacy/frozen\uff0c${summary.legacyTrust.rewardPolicy}\uff09`,
|
|
86
|
+
`- \u4f1a\u8bdd GFI: \u5f53\u524d ${formatNumber(summary.gfi.current)}\uff0c\u5cf0\u503c ${formatNumber(summary.gfi.peak)}\uff08${summary.gfi.dataQuality}\uff09`,
|
|
87
|
+
`- GFI \u6765\u6e90: ${formatSources(summary.gfi.sources)}`,
|
|
88
|
+
`- Pain Flag: ${summary.pain.activeFlag ? 'active' : 'inactive'}${summary.pain.activeFlagSource ? `\uff08${summary.pain.activeFlagSource}\uff09` : ''}`,
|
|
89
|
+
`- \u6700\u8fd1 Pain \u4fe1\u53f7: ${summary.pain.lastSignal ? `${summary.pain.lastSignal.source}${summary.pain.lastSignal.reason ? ` - ${summary.pain.lastSignal.reason}` : ''}` : '--'}`,
|
|
90
|
+
`- Gate \u4e8b\u4ef6: block ${formatNumber(summary.gate.recentBlocks)}\uff0cbypass ${formatNumber(summary.gate.recentBypasses)}\uff08${summary.gate.dataQuality}\uff09`,
|
|
91
|
+
'',
|
|
92
|
+
'\u8fdb\u5316',
|
|
93
|
+
`- \u961f\u5217: pending ${summary.evolution.queue.pending}\uff0cin_progress ${summary.evolution.queue.inProgress}\uff0ccompleted ${summary.evolution.queue.completed}\uff08${summary.evolution.dataQuality}\uff09`,
|
|
94
|
+
`- Directive: ${summary.evolution.directive.exists ? 'present' : 'missing'}\uff0cactive ${summary.evolution.directive.active === null ? '--' : summary.evolution.directive.active ? 'yes' : 'no'}\uff0cage ${formatAge(summary.evolution.directive.ageSeconds, 'zh')}`,
|
|
95
|
+
`- Directive \u4efb\u52a1: ${summary.evolution.directive.taskPreview ?? '--'}`,
|
|
96
|
+
'',
|
|
97
|
+
'\u539f\u5219\u7edf\u8ba1',
|
|
98
|
+
`- \u5019\u9009\u539f\u5219: ${stats.candidateCount}`,
|
|
99
|
+
`- \u89c2\u5bdf\u671f\u539f\u5219: ${stats.probationCount}`,
|
|
100
|
+
`- \u751f\u6548\u539f\u5219: ${stats.activeCount}`,
|
|
101
|
+
`- \u5df2\u5e9f\u5f03\u539f\u5219: ${stats.deprecatedCount}`,
|
|
102
|
+
`- \u6700\u8fd1\u664b\u5347: ${stats.lastPromotedAt ?? '\u65e0'}`,
|
|
103
|
+
'',
|
|
104
|
+
'\u5143\u6570\u636e',
|
|
105
|
+
`- \u5de5\u4f5c\u533a: ${workspaceDir}`,
|
|
106
|
+
`- Session: ${sessionId ?? '--'}\uff08${summary.metadata.selectedSessionReason}\uff09`,
|
|
107
|
+
`- \u751f\u6210\u65f6\u95f4: ${summary.metadata.generatedAt}`,
|
|
108
|
+
];
|
|
109
|
+
if (warnings.length > 0) {
|
|
110
|
+
lines.push('', '警告');
|
|
111
|
+
for (const warning of warnings) {
|
|
112
|
+
lines.push(`- ${warning}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return lines.join('\n');
|
|
116
|
+
}
|
|
117
|
+
export function handleEvolutionStatusCommand(ctx) {
|
|
118
|
+
const workspaceDir = ctx.config?.workspaceDir || process.cwd();
|
|
119
|
+
const sessionId = ctx.sessionId ?? null;
|
|
120
|
+
const reducer = new EvolutionReducerImpl({ workspaceDir });
|
|
121
|
+
const stats = reducer.getStats();
|
|
122
|
+
const summary = RuntimeSummaryService.getSummary(workspaceDir, { sessionId });
|
|
123
|
+
const rawLang = ctx.config?.language || 'en';
|
|
124
|
+
const lang = normalizeLanguage(rawLang);
|
|
125
|
+
const warnings = summary.metadata.warnings.slice(0, 12);
|
|
126
|
+
if (lang === 'zh') {
|
|
127
|
+
return {
|
|
128
|
+
text: buildChineseOutput(workspaceDir, summary.metadata.sessionId, warnings, stats, summary),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
text: buildEnglishOutput(workspaceDir, summary.metadata.sessionId, warnings, stats, summary),
|
|
133
|
+
};
|
|
138
134
|
}
|
|
@@ -63,7 +63,10 @@ Usage:
|
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
65
|
// Reduce the GFI by the rolled back score
|
|
66
|
-
resetFriction(sessionId
|
|
66
|
+
resetFriction(sessionId, workspaceDir, {
|
|
67
|
+
source: 'user_empathy',
|
|
68
|
+
amount: rolledBackScore,
|
|
69
|
+
});
|
|
67
70
|
return {
|
|
68
71
|
text: isZh
|
|
69
72
|
? `✅ 已回滚情绪事件
|
|
@@ -107,8 +110,11 @@ export function handleNaturalLanguageRollback(wctx, sessionId, reason) {
|
|
|
107
110
|
message: isZh ? '回滚失败,事件可能不存在' : 'Rollback failed, event may not exist'
|
|
108
111
|
};
|
|
109
112
|
}
|
|
110
|
-
// Reduce the GFI
|
|
111
|
-
resetFriction(sessionId
|
|
113
|
+
// Reduce only the empathy slice instead of wiping the whole session GFI.
|
|
114
|
+
resetFriction(sessionId, wctx.workspaceDir, {
|
|
115
|
+
source: 'user_empathy',
|
|
116
|
+
amount: rolledBackScore,
|
|
117
|
+
});
|
|
112
118
|
return {
|
|
113
119
|
success: true,
|
|
114
120
|
score: rolledBackScore,
|
package/dist/commands/trust.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { WorkspaceContext } from '../core/workspace-context.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
function createProgressBar(value, max, length = 12) {
|
|
3
|
+
const safeValue = Math.max(0, Math.min(max, value));
|
|
4
|
+
const filledLength = Math.round((safeValue / max) * length);
|
|
5
|
+
const emptyLength = Math.max(0, length - filledLength);
|
|
6
|
+
return `[${'#'.repeat(filledLength)}${'-'.repeat(emptyLength)}]`;
|
|
7
|
+
}
|
|
8
|
+
function formatStageTitle(stage, isZh) {
|
|
9
|
+
const titles = isZh
|
|
10
|
+
? ['Observer', 'Editor', 'Developer', 'Architect']
|
|
11
|
+
: ['Observer', 'Editor', 'Developer', 'Architect'];
|
|
12
|
+
return titles[Math.max(0, Math.min(3, stage - 1))] ?? 'Unknown';
|
|
9
13
|
}
|
|
10
14
|
export function handleTrustCommand(ctx) {
|
|
11
15
|
const { workspaceDir } = ctx;
|
|
@@ -14,82 +18,61 @@ export function handleTrustCommand(ctx) {
|
|
|
14
18
|
const wctx = WorkspaceContext.fromHookContext(ctx);
|
|
15
19
|
const trustEngine = wctx.trust;
|
|
16
20
|
const trustScore = trustEngine.getScore();
|
|
17
|
-
const
|
|
21
|
+
const stage = trustEngine.getStage();
|
|
18
22
|
const isZh = wctx.config.get('language') === 'zh';
|
|
19
|
-
|
|
20
|
-
let title = isZh ? '编辑者' : 'Editor';
|
|
21
|
-
let permissions = isZh
|
|
22
|
-
? `- 允许小范围修改 (< ${trustSettings.limits.stage_2_max_lines} 行)\n- 禁止修改风险目录`
|
|
23
|
-
: `- Small modifications (< ${trustSettings.limits.stage_2_max_lines} lines)\n- Non-risk paths only`;
|
|
24
|
-
let nextLevel = `Trust Score >= ${trustSettings.stages.stage_3_developer}`;
|
|
25
|
-
if (trustScore < trustSettings.stages.stage_1_observer) {
|
|
26
|
-
stage = 1;
|
|
27
|
-
title = isZh ? '观察者 (只读模式)' : 'Observer (Read-only)';
|
|
28
|
-
permissions = isZh ? '- 仅限只读访问\n- 仅限诊断工具' : '- Read-only access\n- Diagnosis tools only';
|
|
29
|
-
nextLevel = `Trust Score >= ${trustSettings.stages.stage_1_observer}`;
|
|
30
|
-
}
|
|
31
|
-
else if (trustScore < trustSettings.stages.stage_2_editor) {
|
|
32
|
-
// Default stage 2
|
|
33
|
-
nextLevel = `Trust Score >= ${trustSettings.stages.stage_2_editor}`;
|
|
34
|
-
}
|
|
35
|
-
else if (trustScore < trustSettings.stages.stage_3_developer) {
|
|
36
|
-
stage = 3;
|
|
37
|
-
title = isZh ? '开发者' : 'Developer';
|
|
38
|
-
permissions = isZh
|
|
39
|
-
? `- 允许中等范围修改 (< ${trustSettings.limits.stage_3_max_lines} 行)\n- 风险目录修改需要有 PLAN (计划)`
|
|
40
|
-
: `- Medium modifications (< ${trustSettings.limits.stage_3_max_lines} lines)\n- Risk paths require READY plan`;
|
|
41
|
-
nextLevel = `Trust Score >= ${trustSettings.stages.stage_3_developer}`;
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
stage = 4;
|
|
45
|
-
title = isZh ? '架构师' : 'Architect';
|
|
46
|
-
permissions = isZh ? '- 🚨 **无限制访问**\n- 计划和审计非强制要求' : '- 🚨 **UNRESTRICTED access**\n- Plan and Audit are optional';
|
|
47
|
-
nextLevel = isZh ? '已达最高级' : 'MAX LEVEL REACHED';
|
|
48
|
-
}
|
|
49
|
-
const progressBar = createProgressBar(trustScore, 100, 15);
|
|
23
|
+
const scorecard = trustEngine.getScorecard();
|
|
50
24
|
const hygiene = wctx.hygiene.getStats();
|
|
51
|
-
const
|
|
52
|
-
const
|
|
25
|
+
const trustBar = createProgressBar(trustScore, 100);
|
|
26
|
+
const hygieneScore = Math.min(100, hygiene.persistenceCount * 10);
|
|
27
|
+
const hygieneBar = createProgressBar(hygieneScore, 100);
|
|
28
|
+
const rewardPolicy = scorecard.reward_policy ?? 'frozen_all_positive';
|
|
29
|
+
const lastUpdated = scorecard.last_updated ?? '--';
|
|
53
30
|
if (isZh) {
|
|
54
|
-
return
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
${
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
-
|
|
66
|
-
-
|
|
67
|
-
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
78
|
-
🛡️ **Security Stage**: Stage ${stage} (${title})
|
|
79
|
-
💰 **Trust Score**: ${progressBar} ${trustScore}/100
|
|
80
|
-
🧠 **Cognitive Hygiene**: ${hygieneBar} ${hygiene.persistenceCount} actions (Today)
|
|
81
|
-
|
|
82
|
-
**Current Permissions**:
|
|
83
|
-
${permissions}
|
|
84
|
-
|
|
85
|
-
**Knowledge Assets Today**:
|
|
86
|
-
- Physical Persists: ${hygiene.persistenceCount} actions
|
|
87
|
-
- Total Chars: ${hygiene.totalCharsPersisted} chars
|
|
88
|
-
- Workspace Grooming: ${hygiene.groomingExecutedCount > 0 ? '🟢 Good' : '🟡 Pending'}
|
|
89
|
-
|
|
90
|
-
**Next Promotion Requirement**: ${nextLevel}
|
|
91
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
92
|
-
*💡 Hint: Frequent notes (PLAN.md/memory) prevent amnesia and ensure task continuity.*
|
|
93
|
-
`.trim();
|
|
31
|
+
return [
|
|
32
|
+
'Principles Disciple - Legacy Trust',
|
|
33
|
+
'=================================',
|
|
34
|
+
'',
|
|
35
|
+
`- Legacy Trust: ${trustBar} ${trustScore}/100`,
|
|
36
|
+
`- Stage: ${stage} (${formatStageTitle(stage, true)})`,
|
|
37
|
+
`- Status: legacy/frozen`,
|
|
38
|
+
`- Reward Policy: ${rewardPolicy}`,
|
|
39
|
+
`- Last Updated: ${lastUpdated}`,
|
|
40
|
+
'',
|
|
41
|
+
'说明',
|
|
42
|
+
'- 这是兼容旧控制面的 legacy trust 视图,不再代表新的长期能力模型。',
|
|
43
|
+
'- `tool_success` 与 `subagent_success` 不再自动提升 trust。',
|
|
44
|
+
'- 当前观察窗口内,trust 主要保留为兼容读数与 gate 兼容输入。',
|
|
45
|
+
'',
|
|
46
|
+
'认知卫生',
|
|
47
|
+
`- Persistence: ${hygieneBar} ${hygiene.persistenceCount} actions today`,
|
|
48
|
+
`- Total Chars Persisted: ${hygiene.totalCharsPersisted}`,
|
|
49
|
+
`- Workspace Grooming: ${hygiene.groomingExecutedCount > 0 ? 'done' : 'pending'}`,
|
|
50
|
+
'',
|
|
51
|
+
'下一步',
|
|
52
|
+
'- 在进入 Phase 3 capability shadow 之前,先看 production observation 数据是否稳定。',
|
|
53
|
+
].join('\n');
|
|
94
54
|
}
|
|
55
|
+
return [
|
|
56
|
+
'Principles Disciple - Legacy Trust',
|
|
57
|
+
'=================================',
|
|
58
|
+
'',
|
|
59
|
+
`- Legacy Trust: ${trustBar} ${trustScore}/100`,
|
|
60
|
+
`- Stage: ${stage} (${formatStageTitle(stage, false)})`,
|
|
61
|
+
'- Status: legacy/frozen',
|
|
62
|
+
`- Reward Policy: ${rewardPolicy}`,
|
|
63
|
+
`- Last Updated: ${lastUpdated}`,
|
|
64
|
+
'',
|
|
65
|
+
'Notes',
|
|
66
|
+
'- This is a compatibility view of legacy trust, not the future long-term capability model.',
|
|
67
|
+
'- `tool_success` and `subagent_success` no longer raise trust automatically.',
|
|
68
|
+
'- During the current observation window, trust remains mainly for compatibility reads and gate compatibility.',
|
|
69
|
+
'',
|
|
70
|
+
'Cognitive Hygiene',
|
|
71
|
+
`- Persistence: ${hygieneBar} ${hygiene.persistenceCount} actions today`,
|
|
72
|
+
`- Total Chars Persisted: ${hygiene.totalCharsPersisted}`,
|
|
73
|
+
`- Workspace Grooming: ${hygiene.groomingExecutedCount > 0 ? 'done' : 'pending'}`,
|
|
74
|
+
'',
|
|
75
|
+
'Next',
|
|
76
|
+
'- Do not move into Phase 3 capability shadow until production observation data is stable.',
|
|
77
|
+
].join('\n');
|
|
95
78
|
}
|
package/dist/core/event-log.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DailyStats, EmpathyEventStats, ToolCallEventData, PainSignalEventData, RuleMatchEventData, RulePromotionEventData, HookExecutionEventData, GateBlockEventData, GateBypassEventData, PlanApprovalEventData, EvolutionTaskEventData, DeepReflectionEventData, TrustChangeEventData, EmpathyRollbackEventData } from '../types/event-types.js';
|
|
1
|
+
import type { EventLogEntry, DailyStats, EmpathyEventStats, ToolCallEventData, PainSignalEventData, RuleMatchEventData, RulePromotionEventData, HookExecutionEventData, GateBlockEventData, GateBypassEventData, PlanApprovalEventData, EvolutionTaskEventData, DeepReflectionEventData, TrustChangeEventData, EmpathyRollbackEventData } from '../types/event-types.js';
|
|
2
2
|
import type { PluginLogger } from '../openclaw-sdk.js';
|
|
3
3
|
/**
|
|
4
4
|
* EventLog - Structured event logging with daily statistics aggregation.
|
|
@@ -33,6 +33,11 @@ export declare class EventLog {
|
|
|
33
33
|
private updateStats;
|
|
34
34
|
private startFlushTimer;
|
|
35
35
|
flush(): void;
|
|
36
|
+
/**
|
|
37
|
+
* Return in-memory buffered events that have not been flushed yet.
|
|
38
|
+
* Intended for live runtime summaries that should not lag behind disk snapshots.
|
|
39
|
+
*/
|
|
40
|
+
getBufferedEvents(): EventLogEntry[];
|
|
36
41
|
private flushEvents;
|
|
37
42
|
private flushStats;
|
|
38
43
|
/**
|
package/dist/core/event-log.js
CHANGED
|
@@ -169,6 +169,13 @@ export class EventLog {
|
|
|
169
169
|
this.flushEvents();
|
|
170
170
|
this.flushStats();
|
|
171
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* Return in-memory buffered events that have not been flushed yet.
|
|
174
|
+
* Intended for live runtime summaries that should not lag behind disk snapshots.
|
|
175
|
+
*/
|
|
176
|
+
getBufferedEvents() {
|
|
177
|
+
return this.eventBuffer.map((entry) => ({ ...entry, data: { ...entry.data } }));
|
|
178
|
+
}
|
|
172
179
|
flushEvents() {
|
|
173
180
|
if (this.eventBuffer.length === 0)
|
|
174
181
|
return;
|
|
@@ -18,6 +18,8 @@ export interface SessionState {
|
|
|
18
18
|
cacheHits: number;
|
|
19
19
|
stuckLoops: number;
|
|
20
20
|
currentGfi: number;
|
|
21
|
+
gfiBySource?: Record<string, number>;
|
|
22
|
+
lastErrorSource?: string;
|
|
21
23
|
lastErrorHash: string;
|
|
22
24
|
consecutiveErrors: number;
|
|
23
25
|
dailyToolCalls: number;
|
|
@@ -41,11 +43,16 @@ export declare function trackLlmOutput(sessionId: string, usage: TokenUsage | un
|
|
|
41
43
|
/**
|
|
42
44
|
* Tracks physical friction based on tool execution failures.
|
|
43
45
|
*/
|
|
44
|
-
export declare function trackFriction(sessionId: string, deltaF: number, hash: string, workspaceDir?: string
|
|
46
|
+
export declare function trackFriction(sessionId: string, deltaF: number, hash: string, workspaceDir?: string, options?: {
|
|
47
|
+
source?: string;
|
|
48
|
+
}): SessionState;
|
|
45
49
|
/**
|
|
46
50
|
* Resets the friction index upon successful action.
|
|
47
51
|
*/
|
|
48
|
-
export declare function resetFriction(sessionId: string, workspaceDir?: string
|
|
52
|
+
export declare function resetFriction(sessionId: string, workspaceDir?: string, options?: {
|
|
53
|
+
source?: string;
|
|
54
|
+
amount?: number;
|
|
55
|
+
}): SessionState;
|
|
49
56
|
/**
|
|
50
57
|
* Records that deep thinking (Thinking OS) was performed in this session.
|
|
51
58
|
* Used by the Thinking OS checkpoint to allow high-risk operations.
|
|
@@ -63,6 +70,7 @@ export declare function setInjectedProbationIds(sessionId: string, ids: string[]
|
|
|
63
70
|
export declare function getInjectedProbationIds(sessionId: string, workspaceDir?: string): string[];
|
|
64
71
|
export declare function clearInjectedProbationIds(sessionId: string, workspaceDir?: string): SessionState;
|
|
65
72
|
export declare function getSession(sessionId: string): SessionState | undefined;
|
|
73
|
+
export declare function listSessions(workspaceDir?: string): SessionState[];
|
|
66
74
|
export declare function clearSession(sessionId: string): void;
|
|
67
75
|
export declare function garbageCollectSessions(): void;
|
|
68
76
|
/**
|