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
|
@@ -222,10 +222,12 @@ function writeRegistry(stateDir: string, registry: ShadowRegistry): void {
|
|
|
222
222
|
/**
|
|
223
223
|
* Execute a read-modify-write under an exclusive file lock.
|
|
224
224
|
*/
|
|
225
|
+
/* eslint-disable no-unused-vars -- Reason: registry param name in type signature intentionally unused - actual function uses different param name */
|
|
225
226
|
function withShadowRegistryLock<T>(
|
|
226
227
|
stateDir: string,
|
|
227
|
-
fn: (
|
|
228
|
+
fn: (_registry: ShadowRegistry) => T
|
|
228
229
|
): T {
|
|
230
|
+
/* eslint-enable no-unused-vars */
|
|
229
231
|
const registryPath = getRegistryPath(stateDir);
|
|
230
232
|
return withLock(registryPath, () => {
|
|
231
233
|
const registry = readRegistry(stateDir);
|
|
@@ -339,6 +341,7 @@ export function completeShadowObservation(
|
|
|
339
341
|
* @param failureSignals - Runtime failure signals
|
|
340
342
|
* @returns The updated ShadowObservation, or null if not found
|
|
341
343
|
*/
|
|
344
|
+
// eslint-disable-next-line @typescript-eslint/max-params -- Reason: shadow observation completion requires all 4 params - refactoring would break API
|
|
342
345
|
export function completeShadowObservationByTask(
|
|
343
346
|
stateDir: string,
|
|
344
347
|
taskFingerprint: string,
|
|
@@ -355,7 +358,7 @@ export function completeShadowObservationByTask(
|
|
|
355
358
|
return null;
|
|
356
359
|
}
|
|
357
360
|
|
|
358
|
-
const observation = pendingObs
|
|
361
|
+
const [observation] = pendingObs;
|
|
359
362
|
observation.completedAt = new Date().toISOString();
|
|
360
363
|
observation.outcome = outcome;
|
|
361
364
|
observation.failureSignals = failureSignals ?? {
|
|
@@ -477,7 +480,7 @@ export function computeShadowStats(
|
|
|
477
480
|
export function queryShadowObservations(
|
|
478
481
|
stateDir: string,
|
|
479
482
|
checkpointId: string,
|
|
480
|
-
limit
|
|
483
|
+
limit = 100
|
|
481
484
|
): ShadowObservation[] {
|
|
482
485
|
return withShadowRegistryLock(stateDir, (registry) => {
|
|
483
486
|
return registry.observations
|
|
@@ -25,10 +25,10 @@ export const SystemLogger = {
|
|
|
25
25
|
const logEntry = `[${timestamp}] [${eventType.padEnd(15)}] ${message}\n`;
|
|
26
26
|
|
|
27
27
|
// Use fire-and-forget async append to prevent blocking
|
|
28
|
-
fs.appendFile(logFile, logEntry, 'utf8', (
|
|
28
|
+
fs.appendFile(logFile, logEntry, 'utf8', (_err) => { // eslint-disable-line @typescript-eslint/no-unused-vars, no-unused-vars -- Reason: fire-and-forget, errors silently dropped
|
|
29
29
|
// Silently drop errors (e.g. disk full) to not crash the gateway
|
|
30
30
|
});
|
|
31
|
-
} catch (e) {
|
|
31
|
+
} catch (e) { // eslint-disable-line @typescript-eslint/no-unused-vars, no-unused-vars -- Reason: intentionally unused - silently fail if we can't setup the log
|
|
32
32
|
// Silently fail if we can't setup the log
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -1,7 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thinking Models — Detection Engine
|
|
3
|
+
*
|
|
4
|
+
* THINKING_OS.md is the single source of truth for model definitions (id, name, description).
|
|
5
|
+
* Detection patterns are carefully tuned regexes that match AI output text.
|
|
6
|
+
*
|
|
7
|
+
* Flow:
|
|
8
|
+
* THINKING_OS.md (authority) → id, name, description, antiPattern
|
|
9
|
+
* BUILTIN_PATTERNS (engine) → detection regexes per model id
|
|
10
|
+
* THINKING_MODELS (merged) → full definitions with patterns
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { loadThinkingOsFromWorkspace, generateDetectionPatterns } from './thinking-os-parser.js';
|
|
14
|
+
|
|
1
15
|
export interface ThinkingModelDefinition {
|
|
2
16
|
id: string;
|
|
3
17
|
name: string;
|
|
4
18
|
description: string;
|
|
19
|
+
antiPattern?: string;
|
|
5
20
|
patterns: RegExp[];
|
|
6
21
|
baselineScenarios: string[];
|
|
7
22
|
}
|
|
@@ -12,146 +27,250 @@ export interface ThinkingModelMatch {
|
|
|
12
27
|
}
|
|
13
28
|
|
|
14
29
|
export interface ThinkingScenarioContext {
|
|
15
|
-
recentToolCalls?:
|
|
30
|
+
recentToolCalls?: {
|
|
16
31
|
toolName: string;
|
|
17
32
|
outcome: 'success' | 'failure' | 'blocked';
|
|
18
33
|
errorType?: string | null;
|
|
19
|
-
}
|
|
20
|
-
recentPainEvents?:
|
|
34
|
+
}[];
|
|
35
|
+
recentPainEvents?: {
|
|
21
36
|
source: string;
|
|
22
37
|
score: number;
|
|
23
|
-
}
|
|
24
|
-
recentGateBlocks?:
|
|
38
|
+
}[];
|
|
39
|
+
recentGateBlocks?: {
|
|
25
40
|
toolName: string;
|
|
26
41
|
reason: string;
|
|
27
|
-
}
|
|
28
|
-
recentUserCorrections?:
|
|
42
|
+
}[];
|
|
43
|
+
recentUserCorrections?: {
|
|
29
44
|
correctionCue?: string | null;
|
|
30
|
-
}
|
|
31
|
-
recentPrincipleEvents?:
|
|
45
|
+
}[];
|
|
46
|
+
recentPrincipleEvents?: {
|
|
32
47
|
eventType: string;
|
|
33
48
|
principleId?: string | null;
|
|
34
|
-
}
|
|
49
|
+
}[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Detection patterns — carefully tuned for AI output text matching
|
|
54
|
+
// These must be manually updated when THINKING_OS.md adds new directives.
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
interface BuiltinPatternEntry {
|
|
58
|
+
id: string;
|
|
59
|
+
patterns: RegExp[];
|
|
60
|
+
baselineScenarios: string[];
|
|
35
61
|
}
|
|
36
62
|
|
|
37
|
-
const
|
|
63
|
+
const BUILTIN_PATTERNS: BuiltinPatternEntry[] = [
|
|
38
64
|
{
|
|
39
65
|
id: 'T-01',
|
|
40
|
-
name: 'Survey Before Acting',
|
|
41
|
-
description: 'Understand the structure first before making changes.',
|
|
42
|
-
baselineScenarios: ['exploration', 'discovery'],
|
|
43
66
|
patterns: [
|
|
44
67
|
/let me (first )?(understand|map|outline|survey|review the (structure|architecture|dependencies))/i,
|
|
45
68
|
/before (changing|editing|touching) anything/i,
|
|
46
69
|
/让我先(梳理|理解|看看|盘点).*(结构|架构|依赖|全貌)/i,
|
|
70
|
+
/在执行任何.*/i,
|
|
47
71
|
],
|
|
72
|
+
baselineScenarios: ['exploration', 'discovery'],
|
|
48
73
|
},
|
|
49
74
|
{
|
|
50
75
|
id: 'T-02',
|
|
51
|
-
name: 'Respect Constraints',
|
|
52
|
-
description: 'Explicitly reason about contracts, tests, schemas, and requirements.',
|
|
53
|
-
baselineScenarios: ['constraint-check', 'contract-verification'],
|
|
54
76
|
patterns: [
|
|
55
77
|
/(type|test|contract|schema|interface) (constraint|requirement|check|validation)/i,
|
|
56
|
-
/we (must|need to) (respect|follow|adhere to) the/i,
|
|
57
78
|
/(必须|需要).*(遵守|符合|满足).*(类型|测试|契约|接口|规范)/i,
|
|
58
79
|
],
|
|
80
|
+
baselineScenarios: ['constraint-check', 'contract-verification'],
|
|
59
81
|
},
|
|
60
82
|
{
|
|
61
83
|
id: 'T-03',
|
|
62
|
-
name: 'Evidence Over Assumption',
|
|
63
|
-
description: 'Use logs, code, and outputs before inferring causes.',
|
|
64
|
-
baselineScenarios: ['evidence-gathering', 'verification'],
|
|
65
84
|
patterns: [
|
|
66
85
|
/based on (the |this )?(evidence|logs?|output|error|stack trace|test result)/i,
|
|
67
86
|
/let me (check|verify|confirm|read|look at) (the |)(actual|source|code|file|log)/i,
|
|
68
87
|
/根据(日志|证据|输出|报错|堆栈|测试结果)/i,
|
|
69
88
|
],
|
|
89
|
+
baselineScenarios: ['evidence-gathering', 'verification'],
|
|
70
90
|
},
|
|
71
91
|
{
|
|
72
92
|
id: 'T-04',
|
|
73
|
-
name: 'Reversible First',
|
|
74
|
-
description: 'Prefer changes that are safe to roll back when risk is high.',
|
|
75
|
-
baselineScenarios: ['risk-management', 'reversibility'],
|
|
76
93
|
patterns: [
|
|
77
94
|
/this (is|would be) (irreversible|destructive|permanent|not easily undone)/i,
|
|
78
95
|
/(reversible|can be undone|safely roll back)/i,
|
|
79
96
|
/(不可逆|破坏性|无法回滚|可以回滚|安全撤销)/i,
|
|
80
97
|
],
|
|
98
|
+
baselineScenarios: ['risk-management', 'reversibility'],
|
|
81
99
|
},
|
|
82
100
|
{
|
|
83
101
|
id: 'T-05',
|
|
84
|
-
name: 'Safety Rails',
|
|
85
|
-
description: 'Call out guardrails, prohibitions, and failure-prevention constraints.',
|
|
86
|
-
baselineScenarios: ['guardrails', 'safety-rails'],
|
|
87
102
|
patterns: [
|
|
88
103
|
/we (must|should) (not|never|avoid|prevent|ensure we don't)/i,
|
|
89
104
|
/(critical|important) (not to|that we don't|to avoid)/i,
|
|
90
105
|
/(绝不能|必须避免|不可|禁止|确保不会)/i,
|
|
91
106
|
],
|
|
107
|
+
baselineScenarios: ['guardrails', 'safety-rails'],
|
|
92
108
|
},
|
|
93
109
|
{
|
|
94
110
|
id: 'T-06',
|
|
95
|
-
name: 'Simplicity First',
|
|
96
|
-
description: 'Prefer the smallest understandable solution over over-engineering.',
|
|
97
|
-
baselineScenarios: ['simplification', 'pragmatism'],
|
|
98
111
|
patterns: [
|
|
99
112
|
/(simpl(er|est|ify)|minimal|straightforward|lean) (approach|solution|fix|implementation)/i,
|
|
100
113
|
/(simple is better|keep it simple|no need to over)/i,
|
|
101
114
|
/(最简|更简单|精简|没必要过度设计)/i,
|
|
102
115
|
],
|
|
116
|
+
baselineScenarios: ['simplification', 'pragmatism'],
|
|
103
117
|
},
|
|
104
118
|
{
|
|
105
119
|
id: 'T-07',
|
|
106
|
-
name: 'Minimal Change Surface',
|
|
107
|
-
description: 'Limit the blast radius and touch only what is necessary.',
|
|
108
|
-
baselineScenarios: ['minimal-diff', 'blast-radius-control'],
|
|
109
120
|
patterns: [
|
|
110
121
|
/(minimal|smallest|narrowest|least) (change|diff|modification|impact)/i,
|
|
111
122
|
/only (change|modify|touch|edit) (the |what)/i,
|
|
112
123
|
/(最小改动|最小变更|只改|只动必要部分)/i,
|
|
113
124
|
],
|
|
125
|
+
baselineScenarios: ['minimal-diff', 'blast-radius-control'],
|
|
114
126
|
},
|
|
115
127
|
{
|
|
116
128
|
id: 'T-08',
|
|
117
|
-
name: 'Pain As Signal',
|
|
118
|
-
description: 'Treat failures and friction as clues to step back and rethink.',
|
|
119
|
-
baselineScenarios: ['reflection', 'pain-response'],
|
|
120
129
|
patterns: [
|
|
121
130
|
/this (error|failure|issue) (tells us|indicates|signals|suggests|means)/i,
|
|
122
131
|
/let me (stop|pause|step back|reconsider|rethink)/i,
|
|
123
132
|
/这个(错误|失败|问题).*(说明|意味着|提示)/i,
|
|
124
133
|
/让我(停下|暂停|退一步|重新考虑|重新审视)/i,
|
|
125
134
|
],
|
|
135
|
+
baselineScenarios: ['reflection', 'pain-response'],
|
|
126
136
|
},
|
|
127
137
|
{
|
|
128
138
|
id: 'T-09',
|
|
129
|
-
name: 'Divide And Conquer',
|
|
130
|
-
description: 'Split the task into smaller phases before execution.',
|
|
131
|
-
baselineScenarios: ['decomposition', 'phased-execution'],
|
|
132
139
|
patterns: [
|
|
133
140
|
/(break|split|decompose|divide) (this |the task |it )?(into|down)/i,
|
|
134
141
|
/(step 1|first,? (we|i|let's)|phase 1)/i,
|
|
135
142
|
/(拆分|分解|分步|分阶段|第一步)/i,
|
|
136
143
|
],
|
|
144
|
+
baselineScenarios: ['decomposition', 'phased-execution'],
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
id: 'T-10',
|
|
148
|
+
patterns: [
|
|
149
|
+
/let me (write|save|record|note down|document)/i,
|
|
150
|
+
/memory.*scratchpad|write.*plan\.md|write.*memory|memory.*persist/i,
|
|
151
|
+
/(让我.*写入|写入.*memory|记录.*scratchpad)/i,
|
|
152
|
+
],
|
|
153
|
+
baselineScenarios: ['memory-persistence', 'state-externalization'],
|
|
137
154
|
},
|
|
138
155
|
];
|
|
139
156
|
|
|
140
|
-
|
|
157
|
+
const BUILTIN_PATTERN_MAP = new Map(BUILTIN_PATTERNS.map((p) => [p.id, p]));
|
|
158
|
+
|
|
159
|
+
// Fallback name/description lookup tables (must be defined before listThinkingModels uses them)
|
|
160
|
+
function getFallbackName(id: string): string {
|
|
161
|
+
const names: Record<string, string> = {
|
|
162
|
+
'T-01': 'Survey Before Acting',
|
|
163
|
+
'T-02': 'Respect Constraints',
|
|
164
|
+
'T-03': 'Evidence Over Assumption',
|
|
165
|
+
'T-04': 'Reversible First',
|
|
166
|
+
'T-05': 'Safety Rails',
|
|
167
|
+
'T-06': 'Simplicity First',
|
|
168
|
+
'T-07': 'Minimal Change Surface',
|
|
169
|
+
'T-08': 'Pain As Signal',
|
|
170
|
+
'T-09': 'Divide And Conquer',
|
|
171
|
+
'T-10': 'Memory Externalization',
|
|
172
|
+
};
|
|
173
|
+
return names[id] ?? id;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function getFallbackDescription(id: string): string {
|
|
177
|
+
const descs: Record<string, string> = {
|
|
178
|
+
'T-01': 'Understand the structure first before making changes.',
|
|
179
|
+
'T-02': 'Trust files, not your context window. Write conclusions to files.',
|
|
180
|
+
'T-03': 'Use logs, code, and outputs before inferring causes.',
|
|
181
|
+
'T-04': 'Prefer changes that are safe to roll back when risk is high.',
|
|
182
|
+
'T-05': 'Call out guardrails, prohibitions, and failure-prevention constraints.',
|
|
183
|
+
'T-06': 'Prefer the smallest understandable solution over over-engineering.',
|
|
184
|
+
'T-07': 'Limit the blast radius and touch only what is necessary.',
|
|
185
|
+
'T-08': 'Treat failures and friction as clues to step back and rethink.',
|
|
186
|
+
'T-09': 'Split the task into smaller phases before execution.',
|
|
187
|
+
'T-10': 'Write intermediate conclusions to files for persistence.',
|
|
188
|
+
};
|
|
189
|
+
return descs[id] ?? '';
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// ---------------------------------------------------------------------------
|
|
193
|
+
// Runtime model definitions — merged from THINKING_OS.md + builtin patterns
|
|
194
|
+
// ---------------------------------------------------------------------------
|
|
195
|
+
|
|
196
|
+
let _cachedDefinitions: ThinkingModelDefinition[] | null = null;
|
|
197
|
+
let _cachedWorkspace: string | null = null;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Load thinking model definitions dynamically from THINKING_OS.md.
|
|
201
|
+
* Falls back to built-in definitions if parsing fails.
|
|
202
|
+
*
|
|
203
|
+
* @param workspaceDir Optional. If provided, loads from that workspace's THINKING_OS.md.
|
|
204
|
+
*/
|
|
205
|
+
export function listThinkingModels(workspaceDir?: string): ThinkingModelDefinition[] {
|
|
206
|
+
const cacheKey = workspaceDir ?? '__global__';
|
|
207
|
+
if (_cachedDefinitions && _cachedWorkspace === cacheKey) {
|
|
208
|
+
return _cachedDefinitions.slice();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const models: ThinkingModelDefinition[] = [];
|
|
212
|
+
|
|
213
|
+
if (workspaceDir) {
|
|
214
|
+
// Try to load from THINKING_OS.md
|
|
215
|
+
const directives = loadThinkingOsFromWorkspace(workspaceDir);
|
|
216
|
+
if (directives.length > 0) {
|
|
217
|
+
for (const dir of directives) {
|
|
218
|
+
const builtin = BUILTIN_PATTERN_MAP.get(dir.id);
|
|
219
|
+
const patterns = builtin?.patterns ?? generateDetectionPatterns(dir.trigger);
|
|
220
|
+
if (patterns.length === 0) {
|
|
221
|
+
console.warn(`[PD:thinking-models] No detection patterns for ${dir.id}: "${dir.trigger}"`);
|
|
222
|
+
}
|
|
223
|
+
models.push({
|
|
224
|
+
id: dir.id,
|
|
225
|
+
name: dir.name,
|
|
226
|
+
description: dir.must,
|
|
227
|
+
antiPattern: dir.forbidden || undefined,
|
|
228
|
+
patterns,
|
|
229
|
+
baselineScenarios: builtin?.baselineScenarios ?? [],
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
_cachedDefinitions = models;
|
|
233
|
+
_cachedWorkspace = cacheKey;
|
|
234
|
+
return models.slice();
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Fallback: built-in definitions
|
|
239
|
+
for (const bp of BUILTIN_PATTERNS) {
|
|
240
|
+
models.push({
|
|
241
|
+
id: bp.id,
|
|
242
|
+
name: getFallbackName(bp.id),
|
|
243
|
+
description: getFallbackDescription(bp.id),
|
|
244
|
+
patterns: bp.patterns,
|
|
245
|
+
baselineScenarios: bp.baselineScenarios,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
_cachedDefinitions = models;
|
|
249
|
+
_cachedWorkspace = cacheKey;
|
|
250
|
+
return models.slice();
|
|
251
|
+
}
|
|
141
252
|
|
|
142
|
-
|
|
143
|
-
|
|
253
|
+
/**
|
|
254
|
+
* Clear the cached model definitions.
|
|
255
|
+
* Call this when THINKING_OS.md changes.
|
|
256
|
+
*/
|
|
257
|
+
export function clearThinkingModelCache(): void {
|
|
258
|
+
_cachedDefinitions = null;
|
|
259
|
+
_cachedWorkspace = null;
|
|
144
260
|
}
|
|
145
261
|
|
|
146
|
-
export function getThinkingModel(modelId: string): ThinkingModelDefinition | undefined {
|
|
147
|
-
|
|
262
|
+
export function getThinkingModel(modelId: string, workspaceDir?: string): ThinkingModelDefinition | undefined {
|
|
263
|
+
const models = listThinkingModels(workspaceDir);
|
|
264
|
+
return models.find(m => m.id === modelId);
|
|
148
265
|
}
|
|
149
266
|
|
|
150
|
-
export function detectThinkingModelMatches(text: string): ThinkingModelMatch[] {
|
|
267
|
+
export function detectThinkingModelMatches(text: string, workspaceDir?: string): ThinkingModelMatch[] {
|
|
151
268
|
if (!text) return [];
|
|
152
269
|
|
|
270
|
+
const models = listThinkingModels(workspaceDir);
|
|
153
271
|
const matches: ThinkingModelMatch[] = [];
|
|
154
|
-
|
|
272
|
+
|
|
273
|
+
for (const model of models) {
|
|
155
274
|
for (const pattern of model.patterns) {
|
|
156
275
|
if (pattern.test(text)) {
|
|
157
276
|
matches.push({
|
|
@@ -165,6 +284,23 @@ export function detectThinkingModelMatches(text: string): ThinkingModelMatch[] {
|
|
|
165
284
|
return matches;
|
|
166
285
|
}
|
|
167
286
|
|
|
287
|
+
/**
|
|
288
|
+
* Get all model definitions for display purposes (no patterns).
|
|
289
|
+
*/
|
|
290
|
+
export function getThinkingModelDefinitions(workspaceDir?: string): {
|
|
291
|
+
modelId: string;
|
|
292
|
+
name: string;
|
|
293
|
+
description: string;
|
|
294
|
+
antiPattern?: string;
|
|
295
|
+
}[] {
|
|
296
|
+
return listThinkingModels(workspaceDir).map(m => ({
|
|
297
|
+
modelId: m.id,
|
|
298
|
+
name: m.id + ': ' + m.name,
|
|
299
|
+
description: m.description,
|
|
300
|
+
antiPattern: m.antiPattern,
|
|
301
|
+
}));
|
|
302
|
+
}
|
|
303
|
+
|
|
168
304
|
export function deriveThinkingScenarios(
|
|
169
305
|
modelId: string,
|
|
170
306
|
context: ThinkingScenarioContext,
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thinking OS XML Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses THINKING_OS.md to extract directive definitions.
|
|
5
|
+
* THINKING_OS.md is the single source of truth for thinking models.
|
|
6
|
+
*
|
|
7
|
+
* Required XML structure:
|
|
8
|
+
* <directive id="T-01" name="MAP_BEFORE_TERRITORY">
|
|
9
|
+
* <trigger>...</trigger>
|
|
10
|
+
* <must>...</must>
|
|
11
|
+
* <forbidden>...</forbidden>
|
|
12
|
+
* </directive>
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import * as fs from 'fs';
|
|
16
|
+
import * as path from 'path';
|
|
17
|
+
import { fileURLToPath } from 'url';
|
|
18
|
+
import { resolvePdPath } from './paths.js';
|
|
19
|
+
|
|
20
|
+
export interface ThinkingOsDirective {
|
|
21
|
+
id: string; // "T-01"
|
|
22
|
+
name: string; // "MAP_BEFORE_TERRITORY"
|
|
23
|
+
trigger: string; // <trigger> content — used for detection patterns
|
|
24
|
+
must: string; // <must> content — used as description
|
|
25
|
+
forbidden: string; // <forbidden> content — used as anti-pattern
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Extract a single XML tag's text content from a string.
|
|
30
|
+
*/
|
|
31
|
+
function extractTag(content: string, tagName: string): string {
|
|
32
|
+
const regex = new RegExp(`<${tagName}>([\\s\\S]*?)</${tagName}>`, 'i');
|
|
33
|
+
const match = content.match(regex);
|
|
34
|
+
if (!match) return '';
|
|
35
|
+
return match[1].trim().replace(/\s+/g, ' ');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Parse THINKING_OS.md content and extract all <directive> blocks.
|
|
40
|
+
* Returns empty array if no XML directives found.
|
|
41
|
+
*/
|
|
42
|
+
export function parseThinkingOsMd(content: string): ThinkingOsDirective[] {
|
|
43
|
+
const directives: ThinkingOsDirective[] = [];
|
|
44
|
+
const directiveRegex = /<directive\s+([^>]*)>([\s\S]*?)<\/directive>/gi;
|
|
45
|
+
|
|
46
|
+
let match: RegExpExecArray | null = null;
|
|
47
|
+
|
|
48
|
+
while ((match = directiveRegex.exec(content)) !== null) {
|
|
49
|
+
const attrs = match[1];
|
|
50
|
+
const body = match[2];
|
|
51
|
+
const idMatch = attrs.match(/id="([^"]+)"/i);
|
|
52
|
+
const nameMatch = attrs.match(/name="([^"]+)"/i);
|
|
53
|
+
if (!idMatch) continue;
|
|
54
|
+
|
|
55
|
+
directives.push({
|
|
56
|
+
id: idMatch[1],
|
|
57
|
+
name: nameMatch ? nameMatch[1] : '',
|
|
58
|
+
trigger: extractTag(body, 'trigger'),
|
|
59
|
+
must: extractTag(body, 'must'),
|
|
60
|
+
forbidden: extractTag(body, 'forbidden'),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return directives;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Load THINKING_OS.md from the workspace.
|
|
69
|
+
* Falls back to plugin templates if workspace file doesn't exist or has no XML directives.
|
|
70
|
+
*/
|
|
71
|
+
export function loadThinkingOsFromWorkspace(
|
|
72
|
+
workspaceDir: string,
|
|
73
|
+
language = 'zh',
|
|
74
|
+
): ThinkingOsDirective[] {
|
|
75
|
+
// Priority 1: workspace THINKING_OS.md
|
|
76
|
+
const workspacePath = resolvePdPath(workspaceDir, 'THINKING_OS');
|
|
77
|
+
if (fs.existsSync(workspacePath)) {
|
|
78
|
+
try {
|
|
79
|
+
const content = fs.readFileSync(workspacePath, 'utf-8');
|
|
80
|
+
const directives = parseThinkingOsMd(content);
|
|
81
|
+
if (directives.length > 0) return directives;
|
|
82
|
+
} catch {
|
|
83
|
+
// Fall through to template
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Priority 2: plugin template for the given language
|
|
88
|
+
const templatePath = resolveTemplatePath(language);
|
|
89
|
+
if (templatePath) {
|
|
90
|
+
try {
|
|
91
|
+
const content = fs.readFileSync(templatePath, 'utf-8');
|
|
92
|
+
const directives = parseThinkingOsMd(content);
|
|
93
|
+
if (directives.length > 0) return directives;
|
|
94
|
+
} catch {
|
|
95
|
+
// Fall through to zh template
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Priority 3: zh template as ultimate fallback
|
|
100
|
+
const zhPath = resolveTemplatePath('zh');
|
|
101
|
+
if (zhPath) {
|
|
102
|
+
try {
|
|
103
|
+
const content = fs.readFileSync(zhPath, 'utf-8');
|
|
104
|
+
return parseThinkingOsMd(content);
|
|
105
|
+
} catch {
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Resolve the THINKING_OS.md template path for a given language.
|
|
115
|
+
*/
|
|
116
|
+
function resolveTemplatePath(language: string): string | null {
|
|
117
|
+
const currentDir = path.dirname(fileURLToPath(import.meta.url));
|
|
118
|
+
const templatePath = path.join(
|
|
119
|
+
path.dirname(path.dirname(path.dirname(currentDir))),
|
|
120
|
+
'templates',
|
|
121
|
+
'langs',
|
|
122
|
+
language,
|
|
123
|
+
'principles',
|
|
124
|
+
'THINKING_OS.md',
|
|
125
|
+
);
|
|
126
|
+
return fs.existsSync(templatePath) ? templatePath : null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Extract meaningful detection keywords from a trigger string.
|
|
131
|
+
* Returns an array of regex patterns.
|
|
132
|
+
*/
|
|
133
|
+
export function generateDetectionPatterns(trigger: string): RegExp[] {
|
|
134
|
+
if (!trigger) return [];
|
|
135
|
+
|
|
136
|
+
const patterns: string[] = [];
|
|
137
|
+
|
|
138
|
+
// Extract Chinese phrases: 3-8 character sequences
|
|
139
|
+
const chinesePattern = /[\u4e00-\u9fff]{3,8}/g;
|
|
140
|
+
const chineseMatches = trigger.match(chinesePattern) ?? [];
|
|
141
|
+
for (const phrase of chineseMatches) {
|
|
142
|
+
patterns.push(phrase);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Extract English words/phrases
|
|
146
|
+
const englishPattern = /[a-zA-Z]{3,20}(?:\s+[a-zA-Z]{3,20}){0,3}/g;
|
|
147
|
+
const englishMatches = trigger.match(englishPattern) ?? [];
|
|
148
|
+
for (const phrase of englishMatches) {
|
|
149
|
+
const cleaned = phrase.trim();
|
|
150
|
+
if (cleaned.length >= 3) {
|
|
151
|
+
patterns.push(cleaned);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return patterns.map(p => new RegExp(p.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i'));
|
|
156
|
+
}
|
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
|
|
31
31
|
import * as fs from 'fs';
|
|
32
32
|
import * as path from 'path';
|
|
33
|
-
import * as crypto from 'crypto';
|
|
34
33
|
import { fileURLToPath } from 'url';
|
|
35
34
|
import {
|
|
36
35
|
type TrainingExperimentSpec,
|
|
@@ -42,7 +41,6 @@ import {
|
|
|
42
41
|
type TrainingBudget,
|
|
43
42
|
validateTrainerResult,
|
|
44
43
|
computeConfigFingerprint,
|
|
45
|
-
computeDatasetFingerprint,
|
|
46
44
|
computeCodeHash,
|
|
47
45
|
generateExperimentId,
|
|
48
46
|
validateHardwareTier,
|
|
@@ -279,7 +277,7 @@ export interface ExecuteTrainerParams {
|
|
|
279
277
|
export async function executeTrainer(
|
|
280
278
|
spec: TrainingExperimentSpec,
|
|
281
279
|
scriptsDir?: string
|
|
282
|
-
): Promise<
|
|
280
|
+
): Promise<TrainingExperimentResult> {
|
|
283
281
|
const baseDir = scriptsDir ?? path.join(REPO_ROOT, TRAINER_SCRIPTS_DIR);
|
|
284
282
|
|
|
285
283
|
// Map backend to script name
|
|
@@ -341,7 +339,7 @@ export async function executeTrainer(
|
|
|
341
339
|
const MAX_STDOUT_BUFFER = 1 * 1024 * 1024; // 1MB cap
|
|
342
340
|
|
|
343
341
|
const trainerResult = await new Promise<
|
|
344
|
-
|
|
342
|
+
TrainingExperimentResult
|
|
345
343
|
>((resolve, reject) => {
|
|
346
344
|
const proc = spawn(pythonExecutable, [scriptPath, '--spec', specPath, '--output-dir', spec.outputDir]);
|
|
347
345
|
|
|
@@ -372,7 +370,7 @@ export async function executeTrainer(
|
|
|
372
370
|
const trimmed = stdout.trim();
|
|
373
371
|
if (trimmed) {
|
|
374
372
|
try {
|
|
375
|
-
resolve(JSON.parse(trimmed) as
|
|
373
|
+
resolve(JSON.parse(trimmed) as TrainingExperimentResult);
|
|
376
374
|
return;
|
|
377
375
|
} catch {
|
|
378
376
|
// fall through to result file
|
|
@@ -382,7 +380,7 @@ export async function executeTrainer(
|
|
|
382
380
|
if (fs.existsSync(resultFilePath)) {
|
|
383
381
|
try {
|
|
384
382
|
const content = fs.readFileSync(resultFilePath, 'utf-8');
|
|
385
|
-
resolve(JSON.parse(content) as
|
|
383
|
+
resolve(JSON.parse(content) as TrainingExperimentResult);
|
|
386
384
|
return;
|
|
387
385
|
} catch {
|
|
388
386
|
// fall through to error
|
|
@@ -399,7 +397,7 @@ export async function executeTrainer(
|
|
|
399
397
|
if (fs.existsSync(resultFilePath)) {
|
|
400
398
|
try {
|
|
401
399
|
const content = fs.readFileSync(resultFilePath, 'utf-8');
|
|
402
|
-
resolve(JSON.parse(content) as
|
|
400
|
+
resolve(JSON.parse(content) as TrainingExperimentResult);
|
|
403
401
|
} catch {
|
|
404
402
|
reject(new Error(`Trainer exited with code ${code} and result file was invalid: ${resultFilePath}`));
|
|
405
403
|
}
|
|
@@ -567,7 +565,9 @@ export function processTrainerResult(
|
|
|
567
565
|
* ```
|
|
568
566
|
*/
|
|
569
567
|
export class TrainingProgram {
|
|
568
|
+
/* eslint-disable no-unused-vars -- Reason: stateDir is used via this.stateDir in createExperiment method */
|
|
570
569
|
constructor(private readonly stateDir: string) {}
|
|
570
|
+
/* eslint-enable no-unused-vars */
|
|
571
571
|
|
|
572
572
|
/**
|
|
573
573
|
* Create a new training experiment.
|