principles-disciple 1.6.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.
Files changed (75) hide show
  1. package/dist/commands/context.js +7 -3
  2. package/dist/commands/evolution-status.d.ts +4 -0
  3. package/dist/commands/evolution-status.js +134 -0
  4. package/dist/commands/export.d.ts +2 -0
  5. package/dist/commands/export.js +45 -0
  6. package/dist/commands/focus.js +9 -6
  7. package/dist/commands/pain.js +8 -0
  8. package/dist/commands/principle-rollback.d.ts +4 -0
  9. package/dist/commands/principle-rollback.js +22 -0
  10. package/dist/commands/rollback.js +9 -3
  11. package/dist/commands/samples.d.ts +2 -0
  12. package/dist/commands/samples.js +55 -0
  13. package/dist/commands/trust.js +64 -81
  14. package/dist/core/config.d.ts +5 -0
  15. package/dist/core/control-ui-db.d.ts +68 -0
  16. package/dist/core/control-ui-db.js +274 -0
  17. package/dist/core/detection-funnel.d.ts +1 -1
  18. package/dist/core/detection-funnel.js +4 -0
  19. package/dist/core/dictionary.d.ts +2 -0
  20. package/dist/core/dictionary.js +13 -0
  21. package/dist/core/event-log.d.ts +7 -1
  22. package/dist/core/event-log.js +10 -0
  23. package/dist/core/evolution-engine.d.ts +5 -5
  24. package/dist/core/evolution-engine.js +18 -18
  25. package/dist/core/evolution-migration.d.ts +5 -0
  26. package/dist/core/evolution-migration.js +65 -0
  27. package/dist/core/evolution-reducer.d.ts +69 -0
  28. package/dist/core/evolution-reducer.js +369 -0
  29. package/dist/core/evolution-types.d.ts +103 -0
  30. package/dist/core/path-resolver.js +75 -36
  31. package/dist/core/paths.d.ts +7 -8
  32. package/dist/core/paths.js +48 -40
  33. package/dist/core/profile.js +1 -1
  34. package/dist/core/session-tracker.d.ts +14 -2
  35. package/dist/core/session-tracker.js +75 -9
  36. package/dist/core/thinking-models.d.ts +38 -0
  37. package/dist/core/thinking-models.js +170 -0
  38. package/dist/core/trajectory.d.ts +184 -0
  39. package/dist/core/trajectory.js +817 -0
  40. package/dist/core/trust-engine.d.ts +6 -0
  41. package/dist/core/trust-engine.js +50 -29
  42. package/dist/core/workspace-context.d.ts +13 -0
  43. package/dist/core/workspace-context.js +50 -7
  44. package/dist/hooks/gate.js +171 -87
  45. package/dist/hooks/llm.js +119 -71
  46. package/dist/hooks/pain.js +105 -5
  47. package/dist/hooks/prompt.d.ts +11 -14
  48. package/dist/hooks/prompt.js +283 -57
  49. package/dist/hooks/subagent.js +69 -28
  50. package/dist/hooks/trajectory-collector.d.ts +32 -0
  51. package/dist/hooks/trajectory-collector.js +256 -0
  52. package/dist/http/principles-console-route.d.ts +2 -0
  53. package/dist/http/principles-console-route.js +257 -0
  54. package/dist/i18n/commands.js +16 -0
  55. package/dist/index.js +105 -4
  56. package/dist/service/control-ui-query-service.d.ts +217 -0
  57. package/dist/service/control-ui-query-service.js +537 -0
  58. package/dist/service/empathy-observer-manager.d.ts +2 -0
  59. package/dist/service/empathy-observer-manager.js +43 -1
  60. package/dist/service/evolution-worker.d.ts +27 -0
  61. package/dist/service/evolution-worker.js +256 -41
  62. package/dist/service/runtime-summary-service.d.ts +79 -0
  63. package/dist/service/runtime-summary-service.js +319 -0
  64. package/dist/service/trajectory-service.d.ts +2 -0
  65. package/dist/service/trajectory-service.js +15 -0
  66. package/dist/tools/agent-spawn.d.ts +27 -6
  67. package/dist/tools/agent-spawn.js +339 -87
  68. package/dist/tools/deep-reflect.d.ts +27 -7
  69. package/dist/tools/deep-reflect.js +210 -121
  70. package/dist/types/event-types.d.ts +10 -2
  71. package/dist/types.d.ts +10 -0
  72. package/dist/types.js +5 -0
  73. package/openclaw.plugin.json +43 -11
  74. package/package.json +14 -4
  75. package/templates/langs/zh/skills/pd-daily/SKILL.md +97 -13
@@ -17,6 +17,8 @@ export interface TrustScorecard {
17
17
  reason: string;
18
18
  timestamp: string;
19
19
  }>;
20
+ frozen?: boolean;
21
+ reward_policy?: 'frozen_all_positive' | 'frozen_atomic_positive_keep_plan_ready';
20
22
  }
21
23
  export type TrustStage = 1 | 2 | 3 | 4;
22
24
  export declare const EXPLORATORY_TOOLS: string[];
@@ -29,6 +31,7 @@ export declare class TrustEngine {
29
31
  private get config();
30
32
  private get trustSettings();
31
33
  private loadScorecard;
34
+ private applyLegacyFreezeMetadata;
32
35
  private saveScorecard;
33
36
  getScore(): number;
34
37
  getScorecard(): TrustScorecard;
@@ -43,7 +46,9 @@ export declare class TrustEngine {
43
46
  sessionId?: string;
44
47
  api?: any;
45
48
  toolName?: string;
49
+ error?: string;
46
50
  }): void;
51
+ private touchScorecard;
47
52
  private updateScore;
48
53
  resetTrust(newScore?: number): void;
49
54
  getStatusSummary(): {
@@ -67,6 +72,7 @@ export declare function recordFailure(type: 'tool' | 'risky' | 'bypass', workspa
67
72
  sessionId?: string;
68
73
  api?: any;
69
74
  toolName?: string;
75
+ error?: string;
70
76
  }): void;
71
77
  export declare function getAgentScorecard(workspaceDir: string): TrustScorecard;
72
78
  export declare function getTrustStats(scorecard: TrustScorecard): {
@@ -7,6 +7,7 @@ import * as path from 'path';
7
7
  import { EventLogService } from './event-log.js';
8
8
  import { resolvePdPath } from './paths.js';
9
9
  import { ConfigService } from './config-service.js';
10
+ import { TrajectoryRegistry } from './trajectory.js';
10
11
  export const EXPLORATORY_TOOLS = [
11
12
  // 文件读取
12
13
  'read', 'read_file', 'read_many_files', 'image_read',
@@ -26,8 +27,9 @@ export const EXPLORATORY_TOOLS = [
26
27
  export const CONSTRUCTIVE_TOOLS = [
27
28
  'write', 'write_file', 'edit', 'edit_file', 'replace', 'apply_patch',
28
29
  'insert', 'patch', 'delete_file', 'move_file', 'run_shell_command',
29
- 'pd_spawn_agent', 'sessions_spawn', 'evolve-task', 'init-strategy'
30
+ 'pd_run_worker', 'sessions_spawn', 'evolve-task', 'init-strategy'
30
31
  ];
32
+ const LEGACY_TRUST_REWARD_POLICY = 'frozen_all_positive';
31
33
  export class TrustEngine {
32
34
  scorecard;
33
35
  workspaceDir;
@@ -49,7 +51,8 @@ export class TrustEngine {
49
51
  return settings || {
50
52
  stages: { stage_1_observer: 30, stage_2_editor: 60, stage_3_developer: 80 },
51
53
  cold_start: { initial_trust: 85, grace_failures: 5, cold_start_period_ms: 86400000 },
52
- penalties: { tool_failure_base: -2, risky_failure_base: -10, gate_bypass_attempt: -5, failure_streak_multiplier: -2, max_penalty: -20 },
54
+ // BUGFIX #84: Reduced penalties to prevent Trust collapse
55
+ penalties: { tool_failure_base: -1, risky_failure_base: -5, gate_bypass_attempt: -3, failure_streak_multiplier: -1, max_penalty: -10 },
53
56
  rewards: { success_base: 2, subagent_success: 5, tool_success_reward: 0.2, streak_bonus_threshold: 3, streak_bonus: 5, recovery_boost: 5, max_reward: 15 },
54
57
  limits: { stage_2_max_lines: 50, stage_3_max_lines: 300 }
55
58
  };
@@ -67,6 +70,7 @@ export class TrustEngine {
67
70
  data.history = [];
68
71
  if (data.exploratory_failure_streak === undefined)
69
72
  data.exploratory_failure_streak = 0;
73
+ this.applyLegacyFreezeMetadata(data);
70
74
  return data;
71
75
  }
72
76
  catch (e) {
@@ -75,7 +79,7 @@ export class TrustEngine {
75
79
  }
76
80
  const now = new Date();
77
81
  const coldStartEnd = new Date(now.getTime() + settings.cold_start.cold_start_period_ms);
78
- return {
82
+ const scorecard = {
79
83
  trust_score: settings.cold_start.initial_trust,
80
84
  success_streak: 0,
81
85
  failure_streak: 0,
@@ -86,6 +90,12 @@ export class TrustEngine {
86
90
  first_activity_at: now.toISOString(),
87
91
  history: []
88
92
  };
93
+ this.applyLegacyFreezeMetadata(scorecard);
94
+ return scorecard;
95
+ }
96
+ applyLegacyFreezeMetadata(scorecard) {
97
+ scorecard.frozen = true;
98
+ scorecard.reward_policy = LEGACY_TRUST_REWARD_POLICY;
89
99
  }
90
100
  saveScorecard() {
91
101
  const scorecardPath = resolvePdPath(this.workspaceDir, 'AGENT_SCORECARD');
@@ -118,39 +128,19 @@ export class TrustEngine {
118
128
  return new Date() < new Date(this.scorecard.cold_start_end);
119
129
  }
120
130
  recordSuccess(reason, context, isSubagent = false) {
121
- const settings = this.trustSettings;
122
- const rewards = settings.rewards;
123
131
  const toolName = context?.toolName;
124
132
  // 1. Check if this is an exploratory tool success
125
133
  const isExploratory = toolName && EXPLORATORY_TOOLS.includes(toolName);
126
134
  if (reason === 'tool_success' && isExploratory) {
127
- // Exploratory tools don't grant trust points, but they:
128
- // 1. Reset the exploratory failure streak
129
- // 2. Prove the agent isn't stuck (no delta, no success_streak increment)
130
135
  this.scorecard.exploratory_failure_streak = 0;
131
- this.updateScore(0, `Exploratory Success: ${toolName}`, 'info', context);
136
+ this.touchScorecard();
132
137
  return;
133
138
  }
134
- let delta = rewards.success_base;
135
- if (isSubagent) {
136
- delta = rewards.subagent_success;
137
- }
138
- else if (reason === 'tool_success') {
139
- delta = rewards.tool_success_reward ?? 0.2;
140
- }
141
- else if (reason === 'plan_ready') {
142
- delta = 5; // Strategic reward
143
- }
144
- this.scorecard.success_streak++;
139
+ // Phase 1 freeze: do not let atomic successes inflate legacy trust.
140
+ this.scorecard.success_streak = 0;
145
141
  this.scorecard.failure_streak = 0; // Reset failure streak on constructive success
146
142
  this.scorecard.exploratory_failure_streak = 0;
147
- if (this.scorecard.success_streak >= rewards.streak_bonus_threshold) {
148
- delta += rewards.streak_bonus;
149
- }
150
- if (this.scorecard.trust_score < settings.stages.stage_1_observer) {
151
- delta += rewards.recovery_boost;
152
- }
153
- this.updateScore(delta, reason, 'success', context);
143
+ this.touchScorecard();
154
144
  }
155
145
  recordFailure(type, context) {
156
146
  const settings = this.trustSettings;
@@ -170,6 +160,13 @@ export class TrustEngine {
170
160
  this.updateScore(-1, `Exploratory Failure: ${toolName}`, 'failure', context);
171
161
  return;
172
162
  }
163
+ // BUGFIX #84: sessions_send timeout should not be penalized
164
+ // Communication timeouts are not agent failures - the message may have been delivered
165
+ const errorStr = String(context?.error || '');
166
+ if (toolName === 'sessions_send' && (errorStr.includes('timeout') || errorStr === 'timeout')) {
167
+ this.updateScore(0, `Communication timeout (sessions_send): ignored`, 'info', context);
168
+ return;
169
+ }
173
170
  // 3. Constructive Failure (Risky or failed writes)
174
171
  let delta = 0;
175
172
  switch (type) {
@@ -195,11 +192,18 @@ export class TrustEngine {
195
192
  delta = penalties.max_penalty;
196
193
  this.updateScore(delta, `Failure: ${toolName || type}`, 'failure', context);
197
194
  }
195
+ touchScorecard() {
196
+ this.applyLegacyFreezeMetadata(this.scorecard);
197
+ this.scorecard.last_updated = new Date().toISOString();
198
+ this.saveScorecard();
199
+ }
198
200
  updateScore(delta, reason, type, context) {
199
201
  const oldScore = this.scorecard.trust_score;
202
+ this.applyLegacyFreezeMetadata(this.scorecard);
200
203
  this.scorecard.trust_score += delta;
201
- if (this.scorecard.trust_score < 0)
202
- this.scorecard.trust_score = 0;
204
+ // Floor score: never drop below 30 (prevents Trust collapse from cascades)
205
+ if (this.scorecard.trust_score < 30)
206
+ this.scorecard.trust_score = 30;
203
207
  if (this.scorecard.trust_score > 100)
204
208
  this.scorecard.trust_score = 100;
205
209
  this.scorecard.last_updated = new Date().toISOString();
@@ -210,6 +214,22 @@ export class TrustEngine {
210
214
  const eventLog = EventLogService.get(this.stateDir);
211
215
  eventLog.recordTrustChange(context.sessionId, { previousScore: oldScore, newScore: this.scorecard.trust_score, delta, reason });
212
216
  }
217
+ if (context?.sessionId) {
218
+ try {
219
+ TrajectoryRegistry.use(this.workspaceDir, (trajectory) => {
220
+ trajectory.recordTrustChange({
221
+ sessionId: context.sessionId,
222
+ previousScore: oldScore,
223
+ newScore: this.scorecard.trust_score,
224
+ delta,
225
+ reason,
226
+ });
227
+ });
228
+ }
229
+ catch {
230
+ // Do not block trust updates if trajectory storage is unavailable.
231
+ }
232
+ }
213
233
  const limit = this.trustSettings.history_limit || 50;
214
234
  if (this.scorecard.history.length > limit) {
215
235
  this.scorecard.history.shift();
@@ -229,6 +249,7 @@ export class TrustEngine {
229
249
  this.scorecard.first_activity_at = now.toISOString();
230
250
  this.scorecard.cold_start_end = coldStartEnd.toISOString();
231
251
  this.scorecard.history.push({ type: 'success', delta: 0, reason: 'Manual trust reset (Spiritual Cleanse)', timestamp: now.toISOString() });
252
+ this.applyLegacyFreezeMetadata(this.scorecard);
232
253
  this.saveScorecard();
233
254
  }
234
255
  getStatusSummary() {
@@ -4,6 +4,8 @@ import { EventLog } from './event-log.js';
4
4
  import { PainDictionary } from './dictionary.js';
5
5
  import { TrustEngine } from './trust-engine.js';
6
6
  import { HygieneTracker } from './hygiene/tracker.js';
7
+ import { EvolutionReducerImpl } from './evolution-reducer.js';
8
+ import { TrajectoryDatabase } from './trajectory.js';
7
9
  /**
8
10
  * WorkspaceContext - Centralized management of workspace-specific paths and services.
9
11
  * Implements a cached singleton pattern per workspace directory.
@@ -18,6 +20,8 @@ export declare class WorkspaceContext {
18
20
  private _dictionary?;
19
21
  private _trust?;
20
22
  private _hygiene?;
23
+ private _evolutionReducer?;
24
+ private _trajectory?;
21
25
  private constructor();
22
26
  /**
23
27
  * Governance configuration for this workspace.
@@ -39,6 +43,15 @@ export declare class WorkspaceContext {
39
43
  * Hygiene tracking service for this workspace.
40
44
  */
41
45
  get hygiene(): HygieneTracker;
46
+ /**
47
+ * Evolution reducer singleton for this workspace.
48
+ */
49
+ get evolutionReducer(): EvolutionReducerImpl;
50
+ /**
51
+ * Trajectory database for analytics and sample curation.
52
+ */
53
+ get trajectory(): TrajectoryDatabase;
54
+ private getTrajectoryOptions;
42
55
  /**
43
56
  * Creates or retrieves a WorkspaceContext instance from an OpenClaw hook context.
44
57
  * Uses PathResolver to handle path normalization and fallback logic.
@@ -5,6 +5,8 @@ import { EventLogService } from './event-log.js';
5
5
  import { DictionaryService } from './dictionary-service.js';
6
6
  import { TrustEngine } from './trust-engine.js';
7
7
  import { HygieneTracker } from './hygiene/tracker.js';
8
+ import { EvolutionReducerImpl } from './evolution-reducer.js';
9
+ import { TrajectoryRegistry } from './trajectory.js';
8
10
  /**
9
11
  * WorkspaceContext - Centralized management of workspace-specific paths and services.
10
12
  * Implements a cached singleton pattern per workspace directory.
@@ -19,6 +21,8 @@ export class WorkspaceContext {
19
21
  _dictionary;
20
22
  _trust;
21
23
  _hygiene;
24
+ _evolutionReducer;
25
+ _trajectory;
22
26
  constructor(workspaceDir, stateDir) {
23
27
  this.workspaceDir = workspaceDir;
24
28
  this.stateDir = stateDir;
@@ -68,22 +72,53 @@ export class WorkspaceContext {
68
72
  }
69
73
  return this._hygiene;
70
74
  }
75
+ /**
76
+ * Evolution reducer singleton for this workspace.
77
+ */
78
+ get evolutionReducer() {
79
+ if (!this._evolutionReducer) {
80
+ this._evolutionReducer = new EvolutionReducerImpl({ workspaceDir: this.workspaceDir });
81
+ }
82
+ return this._evolutionReducer;
83
+ }
84
+ /**
85
+ * Trajectory database for analytics and sample curation.
86
+ */
87
+ get trajectory() {
88
+ if (!this._trajectory) {
89
+ this._trajectory = TrajectoryRegistry.get(this.workspaceDir, this.getTrajectoryOptions());
90
+ }
91
+ return this._trajectory;
92
+ }
93
+ getTrajectoryOptions() {
94
+ const inlineThreshold = Number(this.config.get('trajectory.blob_inline_threshold_bytes'));
95
+ const busyTimeoutMs = Number(this.config.get('trajectory.busy_timeout_ms'));
96
+ const orphanBlobGraceDays = Number(this.config.get('trajectory.orphan_blob_grace_days'));
97
+ return {
98
+ blobInlineThresholdBytes: Number.isFinite(inlineThreshold) && inlineThreshold > 0 ? inlineThreshold : undefined,
99
+ busyTimeoutMs: Number.isFinite(busyTimeoutMs) && busyTimeoutMs >= 0 ? busyTimeoutMs : undefined,
100
+ orphanBlobGraceDays: Number.isFinite(orphanBlobGraceDays) && orphanBlobGraceDays >= 0 ? orphanBlobGraceDays : undefined,
101
+ };
102
+ }
71
103
  /**
72
104
  * Creates or retrieves a WorkspaceContext instance from an OpenClaw hook context.
73
105
  * Uses PathResolver to handle path normalization and fallback logic.
74
106
  * @throws Error if workspaceDir is missing and no fallback available.
75
107
  */
76
108
  static fromHookContext(ctx) {
109
+ const logger = ctx.logger;
110
+ const log = (msg) => logger?.info?.(msg) ?? console.log(msg);
111
+ const logWarn = (msg) => logger?.warn?.(msg) ?? console.warn(msg);
77
112
  let workspaceDir = ctx.workspaceDir;
78
113
  if (!workspaceDir) {
79
- console.warn('[PD:WorkspaceContext] workspaceDir not provided in context, using PathResolver fallback');
114
+ logWarn('[PD:WorkspaceContext] workspaceDir not provided in context, using PathResolver fallback');
80
115
  workspaceDir = this.pathResolver.getWorkspaceDir();
81
- console.log(`[PD:WorkspaceContext] Resolved workspaceDir to: ${workspaceDir}`);
116
+ log(`[PD:WorkspaceContext] Resolved workspaceDir to: ${workspaceDir}`);
82
117
  }
83
118
  else {
84
119
  const normalized = this.pathResolver.normalizeWorkspacePath(workspaceDir);
85
120
  if (normalized !== workspaceDir) {
86
- console.log(`[PD:WorkspaceContext] Normalized workspaceDir: ${workspaceDir} -> ${normalized}`);
121
+ log(`[PD:WorkspaceContext] Normalized workspaceDir: ${workspaceDir} -> ${normalized}`);
87
122
  workspaceDir = normalized;
88
123
  }
89
124
  }
@@ -93,11 +128,11 @@ export class WorkspaceContext {
93
128
  let stateDir = ctx.stateDir;
94
129
  if (!stateDir) {
95
130
  stateDir = resolvePdPath(workspaceDir, 'STATE_DIR');
96
- console.log(`[PD:WorkspaceContext] Computed stateDir: ${stateDir}`);
131
+ log(`[PD:WorkspaceContext] Computed stateDir: ${stateDir}`);
97
132
  }
98
133
  const instance = new WorkspaceContext(workspaceDir, stateDir);
99
134
  this.instances.set(workspaceDir, instance);
100
- console.log(`[PD:WorkspaceContext] Created new context for workspace: ${workspaceDir}`);
135
+ log(`[PD:WorkspaceContext] Created new context for workspace: ${workspaceDir}`);
101
136
  return instance;
102
137
  }
103
138
  /**
@@ -114,21 +149,29 @@ export class WorkspaceContext {
114
149
  this._eventLog = undefined;
115
150
  this._dictionary = undefined;
116
151
  this._trust = undefined;
152
+ this._evolutionReducer = undefined;
153
+ this._trajectory = undefined;
117
154
  }
118
155
  /**
119
156
  * Removes a workspace from the cache.
120
157
  */
121
158
  static dispose(workspaceDir) {
122
- const instance = this.instances.get(workspaceDir);
159
+ const normalized = this.pathResolver.normalizeWorkspacePath(workspaceDir);
160
+ const instance = this.instances.get(normalized);
123
161
  if (instance) {
124
162
  instance.invalidate();
125
- this.instances.delete(workspaceDir);
163
+ this.instances.delete(normalized);
126
164
  }
165
+ TrajectoryRegistry.dispose(normalized);
127
166
  }
128
167
  /**
129
168
  * Clears the instance cache (primarily for testing).
130
169
  */
131
170
  static clearCache() {
171
+ for (const instance of this.instances.values()) {
172
+ instance.invalidate();
173
+ }
132
174
  this.instances.clear();
175
+ TrajectoryRegistry.clear();
133
176
  }
134
177
  }