principles-disciple 1.11.0 → 1.13.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/CHANGELOG.md +26 -0
- package/README.md +66 -0
- package/esbuild.config.js +1 -1
- package/openclaw.plugin.json +4 -4
- package/package.json +2 -3
- package/run-nocturnal.mjs +30 -0
- package/scripts/db-migrate.mjs +170 -0
- package/scripts/sync-plugin.mjs +250 -6
- package/src/commands/archive-impl.ts +136 -0
- package/src/commands/capabilities.ts +4 -2
- package/src/commands/context.ts +5 -1
- package/src/commands/disable-impl.ts +151 -0
- package/src/commands/evolution-status.ts +64 -19
- package/src/commands/export.ts +8 -6
- package/src/commands/focus.ts +8 -20
- package/src/commands/nocturnal-review.ts +5 -7
- package/src/commands/nocturnal-rollout.ts +1 -12
- package/src/commands/nocturnal-train.ts +21 -47
- package/src/commands/pain.ts +10 -5
- package/src/commands/principle-rollback.ts +4 -2
- package/src/commands/promote-impl.ts +274 -0
- package/src/commands/rollback-impl.ts +234 -0
- package/src/commands/rollback.ts +6 -3
- package/src/commands/samples.ts +2 -0
- package/src/commands/thinking-os.ts +3 -4
- package/src/commands/workflow-debug.ts +2 -1
- package/src/config/errors.ts +1 -0
- package/src/core/AGENTS.md +34 -0
- package/src/core/adaptive-thresholds.ts +4 -3
- package/src/core/code-implementation-storage.ts +241 -0
- package/src/core/config.ts +5 -2
- package/src/core/control-ui-db.ts +29 -10
- package/src/core/detection-funnel.ts +12 -7
- package/src/core/diagnostician-task-store.ts +156 -0
- package/src/core/dictionary.ts +4 -4
- package/src/core/empathy-keyword-matcher.ts +7 -3
- package/src/core/empathy-types.ts +13 -2
- package/src/core/event-log.ts +14 -6
- package/src/core/evolution-engine.ts +27 -31
- package/src/core/evolution-logger.ts +3 -2
- package/src/core/evolution-reducer.ts +110 -31
- package/src/core/evolution-types.ts +10 -0
- package/src/core/external-training-contract.ts +1 -0
- package/src/core/focus-history.ts +38 -24
- package/src/core/hygiene/tracker.ts +10 -6
- package/src/core/init.ts +5 -2
- package/src/core/migration.ts +3 -3
- package/src/core/model-deployment-registry.ts +6 -4
- package/src/core/model-training-registry.ts +5 -3
- package/src/core/nocturnal-arbiter.ts +13 -14
- package/src/core/nocturnal-artifact-lineage.ts +117 -0
- package/src/core/nocturnal-artificer.ts +257 -0
- package/src/core/nocturnal-candidate-scoring.ts +4 -2
- package/src/core/nocturnal-compliance.ts +67 -19
- package/src/core/nocturnal-dataset.ts +95 -2
- package/src/core/nocturnal-executability.ts +2 -3
- package/src/core/nocturnal-export.ts +6 -3
- package/src/core/nocturnal-rule-implementation-validator.ts +245 -0
- package/src/core/nocturnal-trajectory-extractor.ts +10 -3
- package/src/core/nocturnal-trinity.ts +319 -61
- package/src/core/pain-context-extractor.ts +29 -15
- package/src/core/pain.ts +7 -5
- package/src/core/path-resolver.ts +16 -15
- package/src/core/paths.ts +2 -1
- package/src/core/pd-task-reconciler.ts +463 -0
- package/src/core/pd-task-service.ts +42 -0
- package/src/core/pd-task-store.ts +77 -0
- package/src/core/pd-task-types.ts +128 -0
- package/src/core/principle-internalization/deprecated-readiness.ts +91 -0
- package/src/core/principle-internalization/internalization-routing-policy.ts +208 -0
- package/src/core/principle-internalization/lifecycle-metrics.ts +149 -0
- package/src/core/principle-internalization/lifecycle-read-model.ts +243 -0
- package/src/core/principle-internalization/lifecycle-refresh.ts +11 -0
- package/src/core/principle-internalization/principle-lifecycle-service.ts +167 -0
- package/src/core/principle-training-state.ts +95 -370
- package/src/core/principle-tree-ledger.ts +733 -0
- package/src/core/principle-tree-migration.ts +195 -0
- package/src/core/profile.ts +3 -1
- package/src/core/promotion-gate.ts +14 -18
- package/src/core/replay-engine.ts +562 -0
- package/src/core/risk-calculator.ts +6 -4
- package/src/core/rule-host-helpers.ts +39 -0
- package/src/core/rule-host-types.ts +82 -0
- package/src/core/rule-host.ts +245 -0
- package/src/core/rule-implementation-runtime.ts +38 -0
- package/src/core/schema/db-types.ts +16 -0
- package/src/core/schema/index.ts +26 -0
- package/src/core/schema/migration-runner.ts +207 -0
- package/src/core/schema/migrations/001-init-trajectory.ts +211 -0
- package/src/core/schema/migrations/002-init-central.ts +122 -0
- package/src/core/schema/migrations/003-init-workflow.ts +55 -0
- package/src/core/schema/migrations/004-add-thinking-and-gfi.ts +74 -0
- package/src/core/schema/migrations/index.ts +31 -0
- package/src/core/schema/schema-definitions.ts +650 -0
- package/src/core/session-tracker.ts +6 -4
- package/src/core/shadow-observation-registry.ts +6 -3
- package/src/core/system-logger.ts +2 -2
- package/src/core/thinking-models.ts +182 -46
- package/src/core/thinking-os-parser.ts +156 -0
- package/src/core/training-program.ts +7 -7
- package/src/core/trajectory.ts +42 -36
- package/src/core/workspace-context.ts +77 -11
- package/src/core/workspace-dir-validation.ts +152 -0
- package/src/hooks/AGENTS.md +31 -0
- package/src/hooks/bash-risk.ts +3 -1
- package/src/hooks/edit-verification.ts +9 -5
- package/src/hooks/gate-block-helper.ts +5 -1
- package/src/hooks/gate.ts +152 -5
- package/src/hooks/gfi-gate.ts +9 -2
- package/src/hooks/lifecycle-routing.ts +124 -0
- package/src/hooks/lifecycle.ts +12 -12
- package/src/hooks/llm.ts +17 -109
- package/src/hooks/message-sanitize.ts +5 -3
- package/src/hooks/pain.ts +19 -15
- package/src/hooks/progressive-trust-gate.ts +7 -1
- package/src/hooks/prompt.ts +169 -60
- package/src/hooks/subagent.ts +5 -4
- package/src/hooks/thinking-checkpoint.ts +2 -0
- package/src/hooks/trajectory-collector.ts +15 -12
- package/src/http/principles-console-route.ts +31 -68
- package/src/i18n/commands.ts +2 -2
- package/src/index.ts +130 -40
- package/src/service/central-database.ts +131 -43
- package/src/service/central-health-service.ts +47 -0
- package/src/service/central-overview-service.ts +135 -0
- package/src/service/central-sync-service.ts +87 -0
- package/src/service/control-ui-query-service.ts +46 -36
- package/src/service/event-log-auditor.ts +261 -0
- package/src/service/evolution-query-service.ts +23 -22
- package/src/service/evolution-worker.ts +565 -261
- package/src/service/health-query-service.ts +213 -36
- package/src/service/nocturnal-runtime.ts +8 -4
- package/src/service/nocturnal-service.ts +503 -59
- package/src/service/nocturnal-target-selector.ts +5 -7
- package/src/service/runtime-summary-service.ts +2 -1
- package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +25 -336
- package/src/service/subagent-workflow/dynamic-timeout.ts +30 -0
- package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +48 -386
- package/src/service/subagent-workflow/index.ts +2 -0
- package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +169 -284
- package/src/service/subagent-workflow/runtime-direct-driver.ts +114 -16
- package/src/service/subagent-workflow/subagent-error-utils.ts +25 -0
- package/src/service/subagent-workflow/types.ts +9 -4
- package/src/service/subagent-workflow/workflow-manager-base.ts +573 -0
- package/src/service/subagent-workflow/workflow-store.ts +71 -11
- package/src/service/trajectory-service.ts +2 -1
- package/src/tools/critique-prompt.ts +1 -1
- package/src/tools/deep-reflect.ts +175 -209
- package/src/tools/model-index.ts +2 -1
- package/src/types/event-types.ts +2 -2
- package/src/types/principle-tree-schema.ts +29 -23
- package/src/utils/file-lock.ts +5 -3
- package/src/utils/io.ts +5 -2
- package/src/utils/nlp.ts +5 -46
- package/src/utils/node-vm-polyfill.ts +11 -0
- package/src/utils/plugin-logger.ts +2 -0
- package/src/utils/retry.ts +572 -0
- package/src/utils/subagent-probe.ts +1 -1
- package/templates/langs/en/core/AGENTS.md +0 -13
- package/templates/langs/en/core/SOUL.md +1 -31
- package/templates/langs/en/core/TOOLS.md +0 -4
- package/templates/langs/en/principles/THINKING_OS.md +77 -0
- package/templates/langs/en/skills/admin/SKILL.md +0 -1
- package/templates/langs/en/skills/evolution-framework-update/SKILL.md +1 -1
- package/templates/langs/en/skills/pd-diagnostician/SKILL.md +18 -5
- package/templates/langs/zh/core/AGENTS.md +0 -22
- package/templates/langs/zh/core/SOUL.md +1 -31
- package/templates/langs/zh/core/TOOLS.md +0 -4
- package/templates/langs/zh/principles/THINKING_OS.md +77 -0
- package/templates/langs/zh/skills/admin/SKILL.md +0 -1
- package/templates/langs/zh/skills/evolution-framework-update/SKILL.md +1 -1
- package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +25 -4
- package/tests/commands/evolution-status.test.ts +119 -0
- package/tests/commands/implementation-lifecycle.test.ts +362 -0
- package/tests/core/code-implementation-storage.test.ts +398 -0
- package/tests/core/evolution-reducer.detector-metadata.test.ts +28 -28
- package/tests/core/nocturnal-artifact-lineage.test.ts +53 -0
- package/tests/core/nocturnal-artificer.test.ts +241 -0
- package/tests/core/nocturnal-compliance-p-principles.test.ts +133 -0
- package/tests/core/nocturnal-rule-implementation-validator.test.ts +127 -0
- package/tests/core/pd-task-store.test.ts +126 -0
- package/tests/core/principle-internalization/deprecated-readiness.test.ts +193 -0
- package/tests/core/principle-internalization/internalization-routing-policy.test.ts +212 -0
- package/tests/core/principle-internalization/lifecycle-metrics.test.ts +350 -0
- package/tests/core/principle-internalization/principle-lifecycle-service.test.ts +211 -0
- package/tests/core/principle-training-state.test.ts +228 -1
- package/tests/core/principle-tree-ledger.test.ts +423 -0
- package/tests/core/regression-v1-9-1.test.ts +265 -0
- package/tests/core/replay-engine.test.ts +234 -0
- package/tests/core/rule-host-helpers.test.ts +120 -0
- package/tests/core/rule-host.test.ts +389 -0
- package/tests/core/rule-implementation-runtime.test.ts +64 -0
- package/tests/core/workspace-context.test.ts +53 -0
- package/tests/core/workspace-dir-validation.test.ts +272 -0
- package/tests/hooks/gate-rule-host-pipeline.test.ts +385 -0
- package/tests/hooks/pain.test.ts +74 -10
- package/tests/hooks/prompt.test.ts +63 -1
- package/tests/integration/principle-lifecycle.e2e.test.ts +197 -0
- package/tests/integration/tool-hooks-workspace-dir.e2e.test.ts +211 -0
- package/tests/service/data-endpoints-regression.test.ts +834 -0
- package/tests/service/evolution-worker.test.ts +0 -123
- package/tests/service/nocturnal-service-code-candidate.test.ts +330 -0
- package/tests/utils/nlp.test.ts +1 -19
- package/tests/utils/retry.test.ts +327 -0
- package/ui/src/App.tsx +1 -1
- package/ui/src/api.ts +4 -0
- package/ui/src/charts.tsx +366 -0
- package/ui/src/components/WorkspaceConfig.tsx +107 -75
- package/ui/src/i18n/ui.ts +89 -31
- package/ui/src/pages/EvolutionPage.tsx +1 -1
- package/ui/src/pages/OverviewPage.tsx +441 -81
- package/ui/src/pages/ThinkingModelsPage.tsx +287 -69
- package/ui/src/styles.css +43 -0
- package/ui/src/types.ts +17 -1
- package/src/agents/nocturnal-dreamer.md +0 -152
- package/src/agents/nocturnal-philosopher.md +0 -138
- package/src/agents/nocturnal-reflector.md +0 -126
- package/src/agents/nocturnal-scribe.md +0 -164
- package/templates/workspace/.principles/00-kernel.md +0 -51
- package/templates/workspace/.principles/DECISION_POLICY.json +0 -44
- package/templates/workspace/.principles/PRINCIPLES.md +0 -20
- package/templates/workspace/.principles/PROFILE.json +0 -54
- package/templates/workspace/.principles/PROFILE.schema.json +0 -56
- package/templates/workspace/.principles/THINKING_OS.md +0 -64
- package/templates/workspace/.principles/THINKING_OS_ARCHIVE.md +0 -7
- package/templates/workspace/.principles/THINKING_OS_CANDIDATES.md +0 -9
- package/templates/workspace/.principles/models/_INDEX.md +0 -27
- package/templates/workspace/.principles/models/first_principles.md +0 -62
- package/templates/workspace/.principles/models/marketing_4p.md +0 -52
- package/templates/workspace/.principles/models/porter_five.md +0 -63
- package/templates/workspace/.principles/models/swot.md +0 -60
- package/templates/workspace/.principles/models/user_story_map.md +0 -63
- package/templates/workspace/.state/WORKBOARD.json +0 -4
package/src/hooks/llm.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
-
import { PluginHookLlmOutputEvent, PluginHookAgentContext } from '../openclaw-sdk.js';
|
|
4
|
-
import {
|
|
3
|
+
import type { PluginHookLlmOutputEvent, PluginHookAgentContext } from '../openclaw-sdk.js';
|
|
4
|
+
import { trackLlmOutput, recordThinkingCheckpoint, resetFriction } from '../core/session-tracker.js';
|
|
5
5
|
import { buildPainFlag, writePainFlag } from '../core/pain.js';
|
|
6
|
+
import { normalizeSeverity } from '../core/empathy-types.js';
|
|
6
7
|
import { ControlUiDatabase } from '../core/control-ui-db.js';
|
|
7
8
|
import { DetectionService } from '../core/detection-service.js';
|
|
8
9
|
import { detectThinkingModelMatches, deriveThinkingScenarios } from '../core/thinking-models.js';
|
|
@@ -17,27 +18,10 @@ export interface EmpathySignal {
|
|
|
17
18
|
mode?: 'structured' | 'legacy_tag';
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
type EmpathyRateState = {
|
|
21
|
-
turnScore: number;
|
|
22
|
-
hourScore: number;
|
|
23
|
-
hourWindowStart: number;
|
|
24
|
-
lastRunId?: string;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const empathyDedupState = new Map<string, number>();
|
|
28
|
-
const empathyRateState = new Map<string, EmpathyRateState>();
|
|
29
|
-
|
|
30
21
|
function clamp(value: number, min: number, max: number): number {
|
|
31
22
|
return Math.max(min, Math.min(max, value));
|
|
32
23
|
}
|
|
33
24
|
|
|
34
|
-
function normalizeSeverity(input?: string): 'mild' | 'moderate' | 'severe' {
|
|
35
|
-
const normalized = (input || '').toLowerCase();
|
|
36
|
-
if (normalized === 'severe' || normalized === 'high') return 'severe';
|
|
37
|
-
if (normalized === 'moderate' || normalized === 'medium') return 'moderate';
|
|
38
|
-
return 'mild';
|
|
39
|
-
}
|
|
40
|
-
|
|
41
25
|
function parseConfidence(raw?: string): number {
|
|
42
26
|
const parsed = Number(raw);
|
|
43
27
|
if (!Number.isFinite(parsed)) return 1;
|
|
@@ -45,7 +29,7 @@ function parseConfidence(raw?: string): number {
|
|
|
45
29
|
}
|
|
46
30
|
|
|
47
31
|
function parseTrustedLegacyTag(text: string): RegExpMatchArray | null {
|
|
48
|
-
return
|
|
32
|
+
return /^\s*\[EMOTIONAL_DAMAGE_DETECTED(?::(mild|moderate|severe))?\]\s*$/i.exec(text);
|
|
49
33
|
}
|
|
50
34
|
|
|
51
35
|
/**
|
|
@@ -94,19 +78,19 @@ export function extractEmpathySignal(text: string): EmpathySignal {
|
|
|
94
78
|
return { detected: false, severity: 'mild', confidence: 1 };
|
|
95
79
|
}
|
|
96
80
|
|
|
97
|
-
const xmlMatch =
|
|
81
|
+
const xmlMatch = /<empathy\s+([^>]*)\/?>(?:<\/empathy>)?/i.exec(text);
|
|
98
82
|
if (xmlMatch?.[1]) {
|
|
99
|
-
const attrs = xmlMatch
|
|
100
|
-
const signal =
|
|
83
|
+
const [, attrs] = xmlMatch;
|
|
84
|
+
const signal = (/signal\s*=\s*"([^"]+)"/i.exec(attrs))?.[1]?.toLowerCase();
|
|
101
85
|
if (signal === 'damage' || signal === 'pain' || signal === 'frustration') {
|
|
102
|
-
const severity = normalizeSeverity(
|
|
103
|
-
const confidence = parseConfidence(
|
|
104
|
-
const reason =
|
|
86
|
+
const severity = normalizeSeverity((/severity\s*=\s*"([^"]+)"/i.exec(attrs))?.[1]);
|
|
87
|
+
const confidence = parseConfidence((/confidence\s*=\s*"([^"]+)"/i.exec(attrs))?.[1]);
|
|
88
|
+
const reason = (/reason\s*=\s*"([^"]+)"/i.exec(attrs))?.[1];
|
|
105
89
|
return { detected: true, severity, confidence, reason, mode: 'structured' };
|
|
106
90
|
}
|
|
107
91
|
}
|
|
108
92
|
|
|
109
|
-
const jsonMatch =
|
|
93
|
+
const jsonMatch = /"empathy"\s*:\s*\{[\s\S]*?\}/i.exec(text);
|
|
110
94
|
if (jsonMatch) {
|
|
111
95
|
const jsonText = `{${jsonMatch[0]}}`;
|
|
112
96
|
try {
|
|
@@ -143,83 +127,6 @@ export function extractEmpathySignal(text: string): EmpathySignal {
|
|
|
143
127
|
return { detected: false, severity: 'mild', confidence: 1 };
|
|
144
128
|
}
|
|
145
129
|
|
|
146
|
-
function mapSeverityToPenalty(severity: 'mild' | 'moderate' | 'severe', config: ReturnType<typeof WorkspaceContext.fromHookContext>['config']): number {
|
|
147
|
-
const mild = Number(config.get('empathy_engine.penalties.mild') ?? 10);
|
|
148
|
-
const moderate = Number(config.get('empathy_engine.penalties.moderate') ?? 25);
|
|
149
|
-
const severe = Number(config.get('empathy_engine.penalties.severe') ?? 40);
|
|
150
|
-
|
|
151
|
-
if (severity === 'severe') return severe;
|
|
152
|
-
if (severity === 'moderate') return moderate;
|
|
153
|
-
return mild;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function dedupeKey(sessionId: string, runId: string, signal: EmpathySignal): string {
|
|
157
|
-
return `${sessionId}:${runId}:${signal.severity}:${(signal.reason || '').slice(0, 80)}`;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function shouldDedupe(sessionId: string, runId: string, signal: EmpathySignal, windowMs: number): boolean {
|
|
161
|
-
const key = dedupeKey(sessionId, runId, signal);
|
|
162
|
-
const now = Date.now();
|
|
163
|
-
const last = empathyDedupState.get(key);
|
|
164
|
-
if (typeof last === 'number' && now - last <= windowMs) {
|
|
165
|
-
return true;
|
|
166
|
-
}
|
|
167
|
-
empathyDedupState.set(key, now);
|
|
168
|
-
return false;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function resolveCalibrationFactor(
|
|
172
|
-
event: PluginHookLlmOutputEvent,
|
|
173
|
-
config: ReturnType<typeof WorkspaceContext.fromHookContext>['config']
|
|
174
|
-
): number {
|
|
175
|
-
const table = config.get('empathy_engine.model_calibration') as Record<string, number> | undefined;
|
|
176
|
-
if (!table || typeof table !== 'object') return 1;
|
|
177
|
-
|
|
178
|
-
const modelKey = `${event.provider}/${event.model}`;
|
|
179
|
-
const factor = Number(table[modelKey] ?? 1);
|
|
180
|
-
if (!Number.isFinite(factor)) return 1;
|
|
181
|
-
return clamp(factor, 0.1, 3);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
function applyRateLimit(
|
|
185
|
-
sessionId: string,
|
|
186
|
-
runId: string,
|
|
187
|
-
score: number,
|
|
188
|
-
config: ReturnType<typeof WorkspaceContext.fromHookContext>['config']
|
|
189
|
-
): number {
|
|
190
|
-
const maxPerTurn = Number(config.get('empathy_engine.rate_limit.max_per_turn') ?? 40);
|
|
191
|
-
const maxPerHour = Number(config.get('empathy_engine.rate_limit.max_per_hour') ?? 120);
|
|
192
|
-
const now = Date.now();
|
|
193
|
-
|
|
194
|
-
const prev = empathyRateState.get(sessionId) ?? {
|
|
195
|
-
turnScore: 0,
|
|
196
|
-
hourScore: 0,
|
|
197
|
-
hourWindowStart: now,
|
|
198
|
-
lastRunId: runId,
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
if (prev.lastRunId !== runId) {
|
|
202
|
-
prev.turnScore = 0;
|
|
203
|
-
prev.lastRunId = runId;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (now - prev.hourWindowStart >= 60 * 60 * 1000) {
|
|
207
|
-
prev.hourScore = 0;
|
|
208
|
-
prev.hourWindowStart = now;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const byTurn = Math.max(0, maxPerTurn - prev.turnScore);
|
|
212
|
-
const byHour = Math.max(0, maxPerHour - prev.hourScore);
|
|
213
|
-
const allowed = Math.max(0, Math.min(score, byTurn, byHour));
|
|
214
|
-
|
|
215
|
-
prev.turnScore += allowed;
|
|
216
|
-
prev.hourScore += allowed;
|
|
217
|
-
empathyRateState.set(sessionId, prev);
|
|
218
|
-
|
|
219
|
-
return allowed;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
|
|
223
130
|
export function isEmpathyAuditPayload(text: string): boolean {
|
|
224
131
|
if (!text || typeof text !== 'string') return false;
|
|
225
132
|
const trimmed = text.trim();
|
|
@@ -236,8 +143,8 @@ export function handleLlmOutput(
|
|
|
236
143
|
if (!ctx.workspaceDir || !ctx.sessionId) return;
|
|
237
144
|
|
|
238
145
|
const wctx = WorkspaceContext.fromHookContext(ctx);
|
|
239
|
-
const config = wctx
|
|
240
|
-
const eventLog = wctx
|
|
146
|
+
const {config} = wctx;
|
|
147
|
+
const {eventLog} = wctx;
|
|
241
148
|
|
|
242
149
|
// Track this turn in the core session memory
|
|
243
150
|
const state = trackLlmOutput(ctx.sessionId, event.usage, config, ctx.workspaceDir, ctx.sessionKey, ctx.trigger);
|
|
@@ -288,7 +195,7 @@ export function handleLlmOutput(
|
|
|
288
195
|
: '';
|
|
289
196
|
|
|
290
197
|
// ═══ Natural Language Rollback Detection ═══
|
|
291
|
-
const rollbackMatch =
|
|
198
|
+
const rollbackMatch = /^\s*\[EMPATHY_ROLLBACK_REQUEST\]\s*$/m.exec(text);
|
|
292
199
|
if (rollbackMatch) {
|
|
293
200
|
const eventId = eventLog.getLastEmpathyEventId(ctx.sessionId);
|
|
294
201
|
if (eventId) {
|
|
@@ -348,6 +255,7 @@ export function handleLlmOutput(
|
|
|
348
255
|
}
|
|
349
256
|
|
|
350
257
|
// ═══ Thinking OS: Mental Model Usage Tracking ═══
|
|
258
|
+
/* eslint-disable @typescript-eslint/no-use-before-define -- Reason: trackThinkingModelUsage is defined later in this file */
|
|
351
259
|
trackThinkingModelUsage({
|
|
352
260
|
text,
|
|
353
261
|
wctx,
|
|
@@ -383,12 +291,12 @@ function trackThinkingModelUsage(args: {
|
|
|
383
291
|
}
|
|
384
292
|
}
|
|
385
293
|
|
|
386
|
-
const matches = detectThinkingModelMatches(text);
|
|
294
|
+
const matches = detectThinkingModelMatches(text, wctx.workspaceDir);
|
|
387
295
|
for (const match of matches) {
|
|
388
296
|
usageLog[match.modelId] = (usageLog[match.modelId] || 0) + 1;
|
|
389
297
|
}
|
|
390
298
|
|
|
391
|
-
usageLog
|
|
299
|
+
usageLog._total_turns = (usageLog._total_turns || 0) + 1;
|
|
392
300
|
|
|
393
301
|
try {
|
|
394
302
|
fs.writeFileSync(logPath, JSON.stringify(usageLog, null, 2), 'utf8');
|
|
@@ -26,18 +26,20 @@ export function handleBeforeMessageWrite(
|
|
|
26
26
|
if (typeof msg.content === 'string') {
|
|
27
27
|
const sanitized = sanitizeAssistantText(msg.content);
|
|
28
28
|
if (sanitized !== msg.content) {
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Reason: message content is dynamically modified, type preserved from event.message union
|
|
29
30
|
return { message: { ...msg, content: sanitized } as any };
|
|
30
31
|
}
|
|
31
32
|
return;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
if (Array.isArray(msg.content)) {
|
|
35
|
-
const next = msg.content.map((part:
|
|
36
|
-
if (part && typeof part === 'object' && part.type === 'text' && typeof part.text === 'string') {
|
|
37
|
-
return { ...part, text: sanitizeAssistantText(part.text) };
|
|
36
|
+
const next = msg.content.map((part: unknown) => {
|
|
37
|
+
if (part && typeof part === 'object' && (part as { type?: string }).type === 'text' && typeof (part as { text?: unknown }).text === 'string') {
|
|
38
|
+
return { ...part, text: sanitizeAssistantText((part as { text: string }).text) };
|
|
38
39
|
}
|
|
39
40
|
return part;
|
|
40
41
|
});
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Reason: message content is dynamically modified, type preserved from event.message union
|
|
41
43
|
return { message: { ...msg, content: next } as any };
|
|
42
44
|
}
|
|
43
45
|
|
package/src/hooks/pain.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
2
|
import { isRisky, normalizePath } from '../utils/io.js';
|
|
4
3
|
import { normalizeProfile } from '../core/profile.js';
|
|
5
4
|
import { computePainScore, buildPainFlag, writePainFlag, trackPrincipleValue } from '../core/pain.js';
|
|
@@ -50,14 +49,14 @@ export function handleAfterToolCall(
|
|
|
50
49
|
ctx: PluginHookToolContext & { workspaceDir?: string; pluginConfig?: Record<string, unknown> },
|
|
51
50
|
api?: OpenClawPluginApi
|
|
52
51
|
): void {
|
|
53
|
-
const effectiveWorkspaceDir = ctx.workspaceDir || (api as
|
|
52
|
+
const effectiveWorkspaceDir = ctx.workspaceDir || (api as unknown as { workspaceDir?: string })?.workspaceDir || api?.resolvePath?.('.');
|
|
54
53
|
if (!effectiveWorkspaceDir) {
|
|
55
54
|
return;
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
const wctx = WorkspaceContext.fromHookContext({ ...ctx, workspaceDir: effectiveWorkspaceDir });
|
|
59
|
-
const config = wctx
|
|
60
|
-
const eventLog = wctx
|
|
58
|
+
const {config} = wctx;
|
|
59
|
+
const {eventLog} = wctx;
|
|
61
60
|
const sessionId = ctx.sessionId || 'unknown';
|
|
62
61
|
const sessionState = ctx.sessionId ? getSession(ctx.sessionId) : undefined;
|
|
63
62
|
const gfiBefore = sessionState?.currentGfi ?? 0;
|
|
@@ -115,7 +114,7 @@ export function handleAfterToolCall(
|
|
|
115
114
|
}
|
|
116
115
|
|
|
117
116
|
// 1. Determine if this was a failure
|
|
118
|
-
const exitCode = (event.result && typeof event.result === 'object') ? (event.result as
|
|
117
|
+
const exitCode = (event.result && typeof event.result === 'object') ? (event.result as Record<string, unknown>).exitCode : 0;
|
|
119
118
|
const isFailure = !!event.error || (exitCode !== 0 && exitCode !== undefined);
|
|
120
119
|
|
|
121
120
|
if (isFailure) {
|
|
@@ -127,6 +126,7 @@ export function handleAfterToolCall(
|
|
|
127
126
|
const updatedState = trackFriction(sessionId, deltaF, hash, effectiveWorkspaceDir);
|
|
128
127
|
|
|
129
128
|
// ── Trust Engine: Record failure ──
|
|
129
|
+
/* eslint-disable @typescript-eslint/no-use-before-define -- Reason: extractErrorType is defined later in this file */
|
|
130
130
|
const errorType = extractErrorType(event.error || errorText);
|
|
131
131
|
const filePath = params.file_path || params.path || params.file;
|
|
132
132
|
const relPath = typeof filePath === 'string' ? normalizePath(filePath, effectiveWorkspaceDir) : 'unknown';
|
|
@@ -158,14 +158,14 @@ export function handleAfterToolCall(
|
|
|
158
158
|
errorType,
|
|
159
159
|
gfi: updatedState.currentGfi,
|
|
160
160
|
consecutiveErrors: updatedState.consecutiveErrors,
|
|
161
|
-
exitCode,
|
|
161
|
+
exitCode: exitCode as number | undefined,
|
|
162
162
|
});
|
|
163
163
|
wctx.trajectory?.recordToolCall?.({
|
|
164
164
|
sessionId,
|
|
165
165
|
toolName: event.toolName,
|
|
166
166
|
outcome: 'failure',
|
|
167
167
|
durationMs: event.durationMs,
|
|
168
|
-
exitCode,
|
|
168
|
+
exitCode: exitCode as number | undefined,
|
|
169
169
|
errorType,
|
|
170
170
|
errorMessage: event.error ? String(event.error) : undefined,
|
|
171
171
|
gfiBefore,
|
|
@@ -305,14 +305,18 @@ export function handleAfterToolCall(
|
|
|
305
305
|
principle.valueMetrics = metrics;
|
|
306
306
|
// Persist to training state (best-effort, non-critical)
|
|
307
307
|
try {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
308
|
+
wctx.principleTreeLedger.updatePrincipleValueMetrics(id, {
|
|
309
|
+
principleId: id,
|
|
310
|
+
painPreventedCount: metrics.painPreventedCount,
|
|
311
|
+
lastPainPreventedAt: metrics.lastPainPreventedAt,
|
|
312
|
+
calculatedAt: metrics.calculatedAt,
|
|
313
|
+
avgPainSeverityPrevented: 0,
|
|
314
|
+
totalOpportunities: 0,
|
|
315
|
+
adheredCount: 0,
|
|
316
|
+
violatedCount: 0,
|
|
317
|
+
implementationCost: 0,
|
|
318
|
+
benefitScore: 0,
|
|
319
|
+
});
|
|
316
320
|
} catch {
|
|
317
321
|
// Non-critical — metrics tracked in memory
|
|
318
322
|
}
|
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
|
|
24
24
|
import type { PluginHookBeforeToolCallEvent, PluginHookBeforeToolCallResult } from '../openclaw-sdk.js';
|
|
25
25
|
import type { WorkspaceContext } from '../core/workspace-context.js';
|
|
26
|
-
import { normalizePath } from '../utils/io.js';
|
|
27
26
|
import { checkEvolutionGate } from '../core/evolution-engine.js';
|
|
28
27
|
import { recordGateBlockAndReturn } from './gate-block-helper.js';
|
|
29
28
|
|
|
@@ -87,12 +86,15 @@ export function buildEvolutionGateReason(
|
|
|
87
86
|
/**
|
|
88
87
|
* Internal helper to call the shared block helper with progressive-trust-gate source tag.
|
|
89
88
|
*/
|
|
89
|
+
/* eslint-disable @typescript-eslint/max-params -- Reason: Helper function requires all parameters for block recording */
|
|
90
90
|
function block(
|
|
91
91
|
filePath: string,
|
|
92
92
|
reason: string,
|
|
93
93
|
wctx: WorkspaceContext,
|
|
94
94
|
toolName: string,
|
|
95
|
+
/* eslint-disable no-unused-vars -- Reason: type-only callback params in logger type */
|
|
95
96
|
logger: { warn?: (message: string) => void; error?: (message: string) => void },
|
|
97
|
+
/* eslint-enable no-unused-vars */
|
|
96
98
|
sessionId?: string
|
|
97
99
|
): PluginHookBeforeToolCallResult {
|
|
98
100
|
return recordGateBlockAndReturn(wctx, {
|
|
@@ -117,13 +119,16 @@ function block(
|
|
|
117
119
|
* @param profile - Gate profile containing risk_paths config
|
|
118
120
|
* @returns PluginHookBeforeToolCallResult to block, or undefined to allow
|
|
119
121
|
*/
|
|
122
|
+
/* eslint-disable @typescript-eslint/max-params -- Reason: Gate function requires all parameters for comprehensive checks */
|
|
120
123
|
export function checkProgressiveTrustGate(
|
|
121
124
|
event: PluginHookBeforeToolCallEvent,
|
|
122
125
|
wctx: WorkspaceContext,
|
|
123
126
|
relPath: string,
|
|
124
127
|
risky: boolean,
|
|
125
128
|
lineChanges: number,
|
|
129
|
+
/* eslint-disable no-unused-vars -- Reason: type-only callback params in logger type */
|
|
126
130
|
logger: { warn?: (message: string) => void; error?: (message: string) => void; info?: (message: string) => void },
|
|
131
|
+
/* eslint-enable no-unused-vars */
|
|
127
132
|
ctx: { workspaceDir?: string; sessionId?: string },
|
|
128
133
|
profile?: { risk_paths: string[]; core_governance_files?: string[] }
|
|
129
134
|
): PluginHookBeforeToolCallResult | void {
|
|
@@ -146,6 +151,7 @@ export function checkProgressiveTrustGate(
|
|
|
146
151
|
});
|
|
147
152
|
|
|
148
153
|
const currentTier = epDecision.currentTier ?? 1;
|
|
154
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define -- Reason: mutual recursion between helper functions - reordering would break logical grouping
|
|
149
155
|
const tierName = getTierName(currentTier);
|
|
150
156
|
|
|
151
157
|
logger.info?.(`[PD_GATE] EP Gate: Tier ${currentTier} (${tierName}), Tool: ${event.toolName}, Risk: ${risky}, Allowed: ${epDecision.allowed}`);
|