principles-disciple 1.30.0 → 1.32.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/openclaw.plugin.json +4 -4
- package/package.json +1 -1
- package/src/service/evolution-worker.ts +6 -2
- package/src/service/nocturnal-runtime.ts +5 -3
- package/src/service/nocturnal-service.ts +15 -4
- package/src/service/nocturnal-target-selector.ts +2 -1
- package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +26 -6
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "principles-disciple",
|
|
3
3
|
"name": "Principles Disciple",
|
|
4
4
|
"description": "Evolutionary programming agent framework with strategic guardrails and reflection loops.",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.32.0",
|
|
6
6
|
"skills": [
|
|
7
7
|
"./skills"
|
|
8
8
|
],
|
|
@@ -76,8 +76,8 @@
|
|
|
76
76
|
}
|
|
77
77
|
},
|
|
78
78
|
"buildFingerprint": {
|
|
79
|
-
"gitSha": "
|
|
80
|
-
"bundleMd5": "
|
|
81
|
-
"builtAt": "2026-04-
|
|
79
|
+
"gitSha": "15c19a4dc3f2",
|
|
80
|
+
"bundleMd5": "684e47fd5c521d722150a93813fddd02",
|
|
81
|
+
"builtAt": "2026-04-14T03:01:11.396Z"
|
|
82
82
|
}
|
|
83
83
|
}
|
package/package.json
CHANGED
|
@@ -1722,6 +1722,9 @@ async function processEvolutionQueue(wctx: WorkspaceContext, logger: PluginLogge
|
|
|
1722
1722
|
taskId: sleepTask.id,
|
|
1723
1723
|
painContext: sleepTask.recentPainContext,
|
|
1724
1724
|
triggerSource: sleepTask.source,
|
|
1725
|
+
// #297: Configure which preflight gates to skip.
|
|
1726
|
+
// sleep_reflection uses periodic trigger which bypasses idle by design.
|
|
1727
|
+
skipPreflightGates: ['idle'],
|
|
1725
1728
|
},
|
|
1726
1729
|
});
|
|
1727
1730
|
sleepTask.resultRef = workflowHandle.workflowId;
|
|
@@ -2166,8 +2169,8 @@ export const EvolutionWorkerService: ExtendedEvolutionWorkerService = {
|
|
|
2166
2169
|
shouldTrySleepReflection = true;
|
|
2167
2170
|
}
|
|
2168
2171
|
|
|
2169
|
-
// Path 2: Periodic trigger (
|
|
2170
|
-
if (
|
|
2172
|
+
// Path 2: Periodic trigger (fires regardless of idle state)
|
|
2173
|
+
if (sleepConfig.trigger_mode === 'periodic') {
|
|
2171
2174
|
if (heartbeatCounter >= sleepConfig.period_heartbeats) {
|
|
2172
2175
|
logger?.info?.(`[PD:EvolutionWorker] Periodic trigger: heartbeatCounter=${heartbeatCounter} >= period_heartbeats=${sleepConfig.period_heartbeats}`);
|
|
2173
2176
|
shouldTrySleepReflection = true;
|
|
@@ -2179,6 +2182,7 @@ export const EvolutionWorkerService: ExtendedEvolutionWorkerService = {
|
|
|
2179
2182
|
|
|
2180
2183
|
if (shouldTrySleepReflection) {
|
|
2181
2184
|
const cooldown = checkCooldown(wctx.stateDir, undefined, {
|
|
2185
|
+
globalCooldownMs: sleepConfig.cooldown_ms,
|
|
2182
2186
|
maxRunsPerWindow: sleepConfig.max_runs_per_day,
|
|
2183
2187
|
quotaWindowMs: 24 * 60 * 60 * 1000,
|
|
2184
2188
|
});
|
|
@@ -436,10 +436,12 @@ export function checkCooldown(
|
|
|
436
436
|
*
|
|
437
437
|
* @param stateDir - State directory
|
|
438
438
|
* @param principleId - Target principle ID for this run
|
|
439
|
+
* @param cooldownMs - Global cooldown duration in ms (default: 1 hour)
|
|
439
440
|
*/
|
|
440
441
|
export async function recordRunStart(
|
|
441
442
|
stateDir: string,
|
|
442
|
-
principleId: string
|
|
443
|
+
principleId: string,
|
|
444
|
+
cooldownMs: number = DEFAULT_GLOBAL_COOLDOWN_MS
|
|
443
445
|
): Promise<void> {
|
|
444
446
|
const state = await readState(stateDir);
|
|
445
447
|
const now = new Date().toISOString();
|
|
@@ -450,8 +452,8 @@ export async function recordRunStart(
|
|
|
450
452
|
status: 'skipped', // Will be updated on completion
|
|
451
453
|
};
|
|
452
454
|
|
|
453
|
-
// Set global cooldown
|
|
454
|
-
const cooldownUntil = new Date(Date.now() +
|
|
455
|
+
// Set global cooldown (use configured value, not hardcoded default)
|
|
456
|
+
const cooldownUntil = new Date(Date.now() + cooldownMs).toISOString();
|
|
455
457
|
state.globalCooldownUntil = cooldownUntil;
|
|
456
458
|
|
|
457
459
|
// Add to recent runs for quota tracking
|
|
@@ -96,6 +96,7 @@ import {
|
|
|
96
96
|
type IdleCheckResult,
|
|
97
97
|
type PreflightCheckResult,
|
|
98
98
|
} from './nocturnal-runtime.js';
|
|
99
|
+
import { loadNocturnalConfig } from './nocturnal-config.js';
|
|
99
100
|
import { NocturnalPathResolver } from '../core/nocturnal-paths.js';
|
|
100
101
|
import { registerSample } from '../core/nocturnal-dataset.js';
|
|
101
102
|
import { getPrincipleState, setPrincipleState } from '../core/principle-training-state.js';
|
|
@@ -721,7 +722,8 @@ export function executeNocturnalReflection(
|
|
|
721
722
|
if (!preflight.canRun) {
|
|
722
723
|
return {
|
|
723
724
|
success: false,
|
|
724
|
-
noTargetSelected:
|
|
725
|
+
noTargetSelected: true,
|
|
726
|
+
skipReason: 'preflight_blocked',
|
|
725
727
|
validationFailed: false,
|
|
726
728
|
validationFailures: [],
|
|
727
729
|
diagnostics,
|
|
@@ -784,7 +786,8 @@ export function executeNocturnalReflection(
|
|
|
784
786
|
// -------------------------------------------------------------------------
|
|
785
787
|
// Note: We use a sync approximation here since this is called from sync context
|
|
786
788
|
// The async version would be used in real worker integration
|
|
787
|
-
|
|
789
|
+
const config = loadNocturnalConfig(stateDir);
|
|
790
|
+
void recordRunStart(stateDir, selectedPrincipleId, config.cooldown_ms).catch((err) => {
|
|
788
791
|
console.warn(`[nocturnal-service] Failed to record run start: ${String(err)}`);
|
|
789
792
|
});
|
|
790
793
|
|
|
@@ -1195,7 +1198,14 @@ async function executeNocturnalReflectionWithAdapter(
|
|
|
1195
1198
|
diagnostics.preflight = preflight;
|
|
1196
1199
|
|
|
1197
1200
|
if (!preflight.canRun) {
|
|
1198
|
-
return {
|
|
1201
|
+
return {
|
|
1202
|
+
success: false,
|
|
1203
|
+
noTargetSelected: true,
|
|
1204
|
+
skipReason: 'preflight_blocked',
|
|
1205
|
+
validationFailed: false,
|
|
1206
|
+
validationFailures: [],
|
|
1207
|
+
diagnostics
|
|
1208
|
+
};
|
|
1199
1209
|
}
|
|
1200
1210
|
|
|
1201
1211
|
// Step 2: Target selection (or use override to skip)
|
|
@@ -1317,7 +1327,8 @@ async function executeNocturnalReflectionWithAdapter(
|
|
|
1317
1327
|
}
|
|
1318
1328
|
|
|
1319
1329
|
// Step 3: Record run start
|
|
1320
|
-
|
|
1330
|
+
const config = loadNocturnalConfig(stateDir);
|
|
1331
|
+
void recordRunStart(stateDir, selectedPrincipleId, config.cooldown_ms).catch((err) => {
|
|
1321
1332
|
console.warn(`[nocturnal-service] Failed to record run start: ${String(err)}`);
|
|
1322
1333
|
});
|
|
1323
1334
|
|
|
@@ -63,7 +63,8 @@ export type SkipReason =
|
|
|
63
63
|
| 'workspace_not_idle' // Workspace is active, nocturnal not allowed
|
|
64
64
|
| 'quota_exhausted' // Max runs per quota window reached
|
|
65
65
|
| 'insufficient_snapshot_data' // Sessions exist but lack tool calls / events
|
|
66
|
-
| 'global_cooldown_active'
|
|
66
|
+
| 'global_cooldown_active' // Global cooldown is in effect
|
|
67
|
+
| 'preflight_blocked'; // Preflight check blocked (idle/cooldown/quota)
|
|
67
68
|
|
|
68
69
|
export interface SelectionDiagnostics {
|
|
69
70
|
/** Total evaluable principles found */
|
|
@@ -260,10 +260,9 @@ export class NocturnalWorkflowManager implements WorkflowManager {
|
|
|
260
260
|
},
|
|
261
261
|
// Pass painContext for Selector ranking bias
|
|
262
262
|
painContext,
|
|
263
|
-
// #244:
|
|
264
|
-
//
|
|
265
|
-
...(((options.metadata)?.
|
|
266
|
-
(options.metadata)?.triggerSource === 'test')
|
|
263
|
+
// #244: Skip preflight gates as configured by caller (e.g. manual/test/sleep_reflection).
|
|
264
|
+
// Gates not in skipPreflightGates go through normal checks.
|
|
265
|
+
...(((options.metadata)?.skipPreflightGates as string[] | undefined)?.includes('idle')
|
|
267
266
|
? {
|
|
268
267
|
idleCheckOverride: {
|
|
269
268
|
isIdle: true,
|
|
@@ -272,7 +271,7 @@ export class NocturnalWorkflowManager implements WorkflowManager {
|
|
|
272
271
|
userActiveSessions: 0,
|
|
273
272
|
abandonedSessionIds: [],
|
|
274
273
|
trajectoryGuardrailConfirmsIdle: true,
|
|
275
|
-
reason: '
|
|
274
|
+
reason: 'skipPreflightGates override',
|
|
276
275
|
},
|
|
277
276
|
}
|
|
278
277
|
: {}),
|
|
@@ -293,7 +292,28 @@ export class NocturnalWorkflowManager implements WorkflowManager {
|
|
|
293
292
|
this.completedWorkflows.set(workflowId, Date.now());
|
|
294
293
|
} else {
|
|
295
294
|
const reason = result.noTargetSelected ? 'no_target_selected' : 'validation_failed';
|
|
296
|
-
|
|
295
|
+
const failuresSummary = result.validationFailures?.length > 0
|
|
296
|
+
? result.validationFailures.join('; ')
|
|
297
|
+
: (result.skipReason ?? 'none');
|
|
298
|
+
this.logger.warn(`[PD:NocturnalWorkflow] [${workflowId}] Pipeline failed: reason=${reason}, noTargetSelected=${result.noTargetSelected}, skipReason=${result.skipReason ?? 'none'}, validationFailures=${result.validationFailures?.length ?? 0}, details=${failuresSummary}`);
|
|
299
|
+
|
|
300
|
+
// Log full result structure for debugging
|
|
301
|
+
this.logger.warn(`[PD:NocturnalWorkflow] [${workflowId}] Full result: success=${result.success}, validationFailed=${result.validationFailed}, noTargetSelected=${result.noTargetSelected}`);
|
|
302
|
+
|
|
303
|
+
// Log diagnostics for debugging
|
|
304
|
+
if (result.diagnostics?.trinityResult) {
|
|
305
|
+
this.logger.warn(`[PD:NocturnalWorkflow] [${workflowId}] Trinity result: success=${result.diagnostics.trinityResult.success}, chainMode=${result.diagnostics.chainModeUsed ?? 'unknown'}`);
|
|
306
|
+
if (!result.diagnostics.trinityResult.success) {
|
|
307
|
+
this.logger.warn(`[PD:NocturnalWorkflow] [${workflowId}] Trinity failures: ${result.diagnostics.trinityResult.failures.map(f => `${f.stage}: ${f.reason}`).join('; ')}`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
if (result.diagnostics?.arbiterResult) {
|
|
311
|
+
this.logger.warn(`[PD:NocturnalWorkflow] [${workflowId}] Arbiter result: passed=${result.diagnostics.arbiterResult.passed}, failures=${result.diagnostics.arbiterResult.failures.map(f => f.reason).join('; ')}`);
|
|
312
|
+
}
|
|
313
|
+
if (result.diagnostics?.selection) {
|
|
314
|
+
this.logger.warn(`[PD:NocturnalWorkflow] [${workflowId}] Selection: decision=${result.diagnostics.selection.decision}, principleId=${result.diagnostics.selection.selectedPrincipleId ?? 'none'}, sessionId=${result.diagnostics.selection.selectedSessionId ?? 'none'}`);
|
|
315
|
+
}
|
|
316
|
+
|
|
297
317
|
this.store.updateWorkflowState(workflowId, 'terminal_error');
|
|
298
318
|
this.store.recordEvent(workflowId, 'nocturnal_failed', null, 'terminal_error', reason, {
|
|
299
319
|
failures: result.validationFailures,
|