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
@@ -2,11 +2,25 @@ import * as fs from 'fs';
2
2
  import { isRisky, normalizePath } from '../utils/io.js';
3
3
  import { normalizeProfile } from '../core/profile.js';
4
4
  import { computePainScore, writePainFlag } from '../core/pain.js';
5
- import { trackFriction, resetFriction } from '../core/session-tracker.js';
5
+ import { getSession, trackFriction, resetFriction, getInjectedProbationIds, clearInjectedProbationIds } from '../core/session-tracker.js';
6
6
  import { denoiseError, computeHash } from '../utils/hashing.js';
7
7
  import { SystemLogger } from '../core/system-logger.js';
8
8
  import { WorkspaceContext } from '../core/workspace-context.js';
9
9
  const WRITE_TOOLS = ['write', 'edit', 'apply_patch', 'write_file', 'edit_file', 'replace'];
10
+ function shouldAttributePrincipleToTool(principle, toolName) {
11
+ return principle.contextTags.includes(toolName) || principle.trigger.includes(toolName);
12
+ }
13
+ function emitPainDetectedEvent(wctx, event) {
14
+ try {
15
+ wctx.evolutionReducer.emitSync(event);
16
+ }
17
+ catch (e) {
18
+ SystemLogger.log(wctx.workspaceDir, 'EVOLUTION_EMIT_WARN', `Failed to emit evolution event: ${String(e)}`);
19
+ }
20
+ }
21
+ function createPainId(sessionId) {
22
+ return `pain_${Date.now()}_${computeHash(sessionId).slice(0, 8)}`;
23
+ }
10
24
  export function handleAfterToolCall(event, ctx, api) {
11
25
  const effectiveWorkspaceDir = ctx.workspaceDir || api?.workspaceDir || api?.resolvePath?.('.');
12
26
  if (!effectiveWorkspaceDir) {
@@ -17,6 +31,8 @@ export function handleAfterToolCall(event, ctx, api) {
17
31
  const eventLog = wctx.eventLog;
18
32
  const trust = wctx.trust;
19
33
  const sessionId = ctx.sessionId || 'unknown';
34
+ const sessionState = ctx.sessionId ? getSession(ctx.sessionId) : undefined;
35
+ const gfiBefore = sessionState?.currentGfi ?? 0;
20
36
  const params = event.params;
21
37
  // ── Track A: Empirical Friction (GFI) ──
22
38
  // 0. Special Case: Manual Pain Intervention
@@ -30,6 +46,25 @@ export function handleAfterToolCall(event, ctx, api) {
30
46
  reason: `User intervention: ${reason}`,
31
47
  isRisky: true
32
48
  });
49
+ wctx.trajectory?.recordPainEvent?.({
50
+ sessionId,
51
+ source: 'manual',
52
+ score: 100,
53
+ reason: `User intervention: ${reason}`,
54
+ origin: 'user_manual',
55
+ });
56
+ emitPainDetectedEvent(wctx, {
57
+ ts: new Date().toISOString(),
58
+ type: 'pain_detected',
59
+ data: {
60
+ painId: createPainId(sessionId),
61
+ painType: 'user_frustration',
62
+ source: event.toolName,
63
+ reason: `User intervention: ${reason}`,
64
+ score: 100,
65
+ sessionId,
66
+ },
67
+ });
33
68
  return;
34
69
  }
35
70
  // 1. Determine if this was a failure
@@ -52,13 +87,16 @@ export function handleAfterToolCall(event, ctx, api) {
52
87
  try {
53
88
  profile = normalizeProfile(JSON.parse(fs.readFileSync(profilePath, 'utf8')));
54
89
  }
55
- catch (_e) { }
90
+ catch (e) {
91
+ SystemLogger.log(effectiveWorkspaceDir, 'PROFILE_PARSE_WARN', `Failed to parse PROFILE.json: ${String(e)}`);
92
+ }
56
93
  }
57
94
  const isRisk = isRisky(relPath, profile.risk_paths);
58
95
  trust.recordFailure(isRisk ? 'risky' : 'tool', {
59
96
  sessionId,
60
97
  api,
61
- toolName: event.toolName // 👈 NEW: Pass toolName for classification
98
+ toolName: event.toolName,
99
+ error: event.error // Pass error for timeout detection
62
100
  });
63
101
  // Record tool call failure event
64
102
  eventLog.recordToolCall(sessionId, {
@@ -70,16 +108,56 @@ export function handleAfterToolCall(event, ctx, api) {
70
108
  consecutiveErrors: updatedState.consecutiveErrors,
71
109
  exitCode,
72
110
  });
111
+ wctx.trajectory?.recordToolCall?.({
112
+ sessionId,
113
+ toolName: event.toolName,
114
+ outcome: 'failure',
115
+ durationMs: event.durationMs,
116
+ exitCode,
117
+ errorType,
118
+ errorMessage: event.error ? String(event.error) : undefined,
119
+ gfiBefore,
120
+ gfiAfter: updatedState.currentGfi,
121
+ paramsJson: event.params,
122
+ });
123
+ const injectedProbationIds = getInjectedProbationIds(sessionId, effectiveWorkspaceDir);
124
+ for (const id of injectedProbationIds) {
125
+ const principle = wctx.evolutionReducer.getPrincipleById(id);
126
+ const shouldAttribute = !!principle && shouldAttributePrincipleToTool(principle, event.toolName);
127
+ if (shouldAttribute) {
128
+ wctx.evolutionReducer.recordProbationFeedback(id, false);
129
+ }
130
+ }
131
+ clearInjectedProbationIds(sessionId, effectiveWorkspaceDir);
73
132
  }
74
133
  else {
75
134
  // ── SUCCESS BRANCH ──
76
- resetFriction(sessionId, effectiveWorkspaceDir);
135
+ const resetState = resetFriction(sessionId, effectiveWorkspaceDir);
77
136
  // 👈 Record success to reset failure streak and earn minor trust (if constructive)
78
137
  trust.recordSuccess('tool_success', {
79
138
  sessionId,
80
139
  api,
81
140
  toolName: event.toolName // 👈 NEW: Pass toolName for classification
82
141
  });
142
+ const injectedProbationIds = getInjectedProbationIds(sessionId, effectiveWorkspaceDir);
143
+ for (const id of injectedProbationIds) {
144
+ const principle = wctx.evolutionReducer.getPrincipleById(id);
145
+ const shouldAttribute = !!principle && shouldAttributePrincipleToTool(principle, event.toolName);
146
+ if (shouldAttribute) {
147
+ wctx.evolutionReducer.recordProbationFeedback(id, true);
148
+ }
149
+ }
150
+ clearInjectedProbationIds(sessionId, effectiveWorkspaceDir);
151
+ wctx.trajectory?.recordToolCall?.({
152
+ sessionId,
153
+ toolName: event.toolName,
154
+ outcome: 'success',
155
+ durationMs: event.durationMs,
156
+ exitCode,
157
+ gfiBefore,
158
+ gfiAfter: resetState.currentGfi,
159
+ paramsJson: event.params,
160
+ });
83
161
  if (WRITE_TOOLS.includes(event.toolName)) {
84
162
  const filePath = params.file_path || params.path || params.file;
85
163
  eventLog.recordToolCall(sessionId, {
@@ -128,7 +206,9 @@ export function handleAfterToolCall(event, ctx, api) {
128
206
  try {
129
207
  profile = normalizeProfile(JSON.parse(fs.readFileSync(profilePath, 'utf8')));
130
208
  }
131
- catch (_e) { }
209
+ catch (e) {
210
+ SystemLogger.log(effectiveWorkspaceDir, 'PROFILE_PARSE_WARN', `Failed to parse PROFILE.json: ${String(e)}`);
211
+ }
132
212
  }
133
213
  const isRisk = isRisky(relPath, profile.risk_paths);
134
214
  const painScore = computePainScore(1, false, false, isRisk ? 20 : 0, effectiveWorkspaceDir);
@@ -146,6 +226,26 @@ export function handleAfterToolCall(event, ctx, api) {
146
226
  reason: `Tool ${event.toolName} failed on ${relPath}`,
147
227
  isRisky: isRisk,
148
228
  });
229
+ wctx.trajectory?.recordPainEvent?.({
230
+ sessionId,
231
+ source: 'tool_failure',
232
+ score: painScore,
233
+ reason: `Tool ${event.toolName} failed on ${relPath}`,
234
+ severity: painScore >= 70 ? 'severe' : painScore >= 40 ? 'moderate' : 'mild',
235
+ origin: 'system_infer',
236
+ });
237
+ emitPainDetectedEvent(wctx, {
238
+ ts: new Date().toISOString(),
239
+ type: 'pain_detected',
240
+ data: {
241
+ painId: createPainId(sessionId),
242
+ painType: 'tool_failure',
243
+ source: event.toolName,
244
+ reason: `Tool ${event.toolName} failed on ${relPath}`,
245
+ score: painScore,
246
+ sessionId,
247
+ },
248
+ });
149
249
  }
150
250
  function extractErrorType(error) {
151
251
  if (!error)
@@ -2,7 +2,7 @@ import type { PluginHookBeforePromptBuildEvent, PluginHookAgentContext, PluginHo
2
2
  import { ContextInjectionConfig } from '../types.js';
3
3
  import { type EmpathyObserverApi } from '../service/empathy-observer-manager.js';
4
4
  /**
5
- * 代理默认配置
5
+ * 濞寸媴绲块幃濠冾渶濡鍚囬梺鏉跨Ф閻?
6
6
  */
7
7
  interface AgentsDefaultsConfig {
8
8
  model?: unknown;
@@ -10,9 +10,6 @@ interface AgentsDefaultsConfig {
10
10
  model?: unknown;
11
11
  };
12
12
  }
13
- /**
14
- * OpenClaw API 接口定义(Prompt Hook 所需部分)
15
- */
16
13
  interface PromptHookApi {
17
14
  config?: {
18
15
  agents?: {
@@ -26,22 +23,22 @@ interface PromptHookApi {
26
23
  logger: PluginLogger;
27
24
  }
28
25
  /**
29
- * OpenClaw 配置中解析模型选择
30
- * 支持 string { primary, fallbacks } 格式
31
- * @internal 导出仅供测试使用
26
+ * 濞?OpenClaw 闂佹澘绉堕悿鍡樼▔椤撯寬鎺楀几閹邦劷渚€宕圭€n喒鍋撴径瀣仴
27
+ * 闁衡偓椤栨稑鐦?string 闁?{ primary, fallbacks } 闁哄秶鍘х槐?
28
+ * @internal 閻庣數鍘ч崵顓熺閸涱剛杩旀繛鏉戭儓閻︻垱鎷呯捄銊︽殢
32
29
  */
33
30
  export declare function resolveModelFromConfig(modelConfig: unknown, logger?: PluginLogger): string | null;
34
31
  /**
35
- * 加载上下文注入配置
36
- * PROFILE.json 读取 contextInjection 配置,如果不存在则返回默认配置
37
- * @internal 导出供其他模块使用
32
+ * 闁告梻濮惧ù鍥ㄧ▔婵犱胶鐟撻柡鍌氭处閺佺偤宕楅妷鈺佸赋缂?
33
+ * 濞?PROFILE.json 閻犲洩顕цぐ?contextInjection 闂佹澘绉堕悿鍡涙晬鐏炵瓔娲ら柡瀣矆缁楀鈧稒锚濠€顏堝礆濞嗘帞绠查柛銉у仱缁垳鎷嬮妶澶婂赋缂?
34
+ * @internal 閻庣數鍘ч崵顓熺瑹濞戞ê寰撳ù鐘崇墬鑶╅柛褎銇炴繛鍥偨?
38
35
  */
39
36
  export declare function loadContextInjectionConfig(workspaceDir: string): ContextInjectionConfig;
40
37
  /**
41
- * 获取诊断子智能体应使用的模型
42
- * 优先级:subagents.model > 主模型
43
- * 如果都没有配置,抛出错误
44
- * @internal 导出仅供测试使用
38
+ * 闁兼儳鍢茶ぐ鍥╂嫚婵犲啯鐒介悗娑欏姈濞呫倝鎳楅幋鎺旂Ъ閹煎瓨鏌ф繛鍥偨閵娧勭暠婵☆垪鈧磭鈧?
39
+ * 濞村吋锚閸樻稓鐥缁辩殜ubagents.model > 濞戞挾绮啯闁?
40
+ * 濠碘€冲€归悘澶愭焾閼恒儳姊鹃柡鍫濐樀閸樸倗绱旈鍡欑闁硅埖绋戦崵顓㈡煥濞嗘帩鍤?
41
+ * @internal 閻庣數鍘ч崵顓熺閸涱剛杩旀繛鏉戭儓閻︻垱鎷呯捄銊︽殢
45
42
  */
46
43
  export declare function getDiagnosticianModel(api: PromptHookApi | null, logger?: PluginLogger): string;
47
44
  export declare function handleBeforePromptBuild(event: PluginHookBeforePromptBuildEvent, ctx: PluginHookAgentContext & {