principles-disciple 1.65.0 → 1.67.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/ADVANCED_CONFIG_ZH.md +0 -4
- package/README.md +0 -11
- package/openclaw.plugin.json +1 -25
- package/package.json +1 -1
- package/src/commands/context.ts +6 -14
- package/src/commands/evolution-status.ts +29 -3
- package/src/commands/pain.ts +3 -4
- package/src/config/defaults/runtime.ts +0 -2
- package/src/constants/tools.ts +0 -1
- package/src/core/config.ts +0 -30
- package/src/core/event-log.ts +4 -12
- package/src/hooks/prompt.ts +3 -35
- package/src/hooks/subagent.ts +0 -7
- package/src/index.ts +0 -2
- package/src/service/evolution-worker.ts +0 -13
- package/src/service/runtime-summary-service.ts +94 -15
- package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +1 -204
- package/src/service/subagent-workflow/index.ts +0 -8
- package/src/service/subagent-workflow/types.ts +0 -11
- package/src/service/subagent-workflow/workflow-manager-base.ts +1 -1
- package/src/tools/critique-prompt.ts +1 -97
- package/src/tools/deep-reflect.ts +1 -337
- package/src/tools/model-index.ts +1 -100
- package/src/types/event-payload.ts +0 -6
- package/src/types/event-types.ts +0 -86
- package/src/types.ts +0 -21
- package/templates/langs/en/core/TOOLS.md +0 -43
- package/templates/langs/zh/core/TOOLS.md +0 -43
- package/templates/pain_settings.json +0 -21
- package/tests/commands/evolution-status.test.ts +288 -0
- package/tests/core/event-log.test.ts +1 -29
- package/tests/service/runtime-summary-service.test.ts +1 -1
|
@@ -6,49 +6,6 @@
|
|
|
6
6
|
- **工具偏好**:优先使用 `rg` (ripgrep) 进行高性能检索,严禁盲目遍历。
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
## 3. 深度反思工具 (Deep Reflection)
|
|
10
|
-
`deep_reflect` 是**认知分析工具**——在执行复杂任务前,进行批判性分析,识别盲点、风险和替代方案。
|
|
11
|
-
|
|
12
|
-
### 何时应该调用
|
|
13
|
-
- **复杂任务**:规划、设计、决策、分析等需要深思熟虑的场景
|
|
14
|
-
- **信息不足**:需求模糊、约束不明确、缺少关键信息
|
|
15
|
-
- **高风险决策**:重要决策、不可逆操作、影响范围大
|
|
16
|
-
- **不确定时**:对最佳方案存疑,需要多角度思考
|
|
17
|
-
|
|
18
|
-
### 使用场景示例
|
|
19
|
-
- 营销方案设计:分析目标受众、渠道选择、风险预案
|
|
20
|
-
- 产品功能规划:评估用户需求、技术可行性、资源投入
|
|
21
|
-
- 架构设计决策:权衡方案优劣、识别潜在风险
|
|
22
|
-
- 问题分析诊断:多角度分析根因、避免遗漏关键因素
|
|
23
|
-
|
|
24
|
-
### 带来的好处
|
|
25
|
-
- 识别可能遗漏的盲点
|
|
26
|
-
- 发现潜在风险和失败模式
|
|
27
|
-
- 提供替代方案及权衡分析
|
|
28
|
-
- 应用结构化思维模型深化洞察
|
|
29
|
-
|
|
30
|
-
### 如何调用
|
|
31
|
-
```
|
|
32
|
-
deep_reflect(
|
|
33
|
-
model_id: "T-01" | "T-02" | ... | "T-09", // 推荐 T-01 或 T-05
|
|
34
|
-
context: "描述你的计划和担忧...",
|
|
35
|
-
depth: 1 | 2 | 3 // 1=快速, 2=平衡, 3=详尽
|
|
36
|
-
)
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### 思维模型选择
|
|
40
|
-
| 模型 | 名称 | 适用场景 |
|
|
41
|
-
|------|------|----------|
|
|
42
|
-
| T-01 | 地图先于领土 | 规划、设计、理解系统 |
|
|
43
|
-
| T-05 | 否定优于肯定 | 风险分析、找漏洞 |
|
|
44
|
-
| T-07 | 系统优于组件 | 架构决策、集成问题 |
|
|
45
|
-
|
|
46
|
-
### 输出结构
|
|
47
|
-
工具返回:盲点分析 → 风险警告 → 替代方案 → 建议 → 置信度
|
|
48
|
-
|
|
49
|
-
**注意**:这是批判性反馈,最终决策权在你。认真考虑建议,但不必盲目遵循。
|
|
50
|
-
|
|
51
|
-
---
|
|
52
9
|
|
|
53
10
|
## 4. 智能体路由澄清
|
|
54
11
|
|
|
@@ -60,27 +60,6 @@
|
|
|
60
60
|
"stage_3_max_lines": 300
|
|
61
61
|
}
|
|
62
62
|
},
|
|
63
|
-
"deep_reflection": {
|
|
64
|
-
"enabled": true,
|
|
65
|
-
"mode": "auto",
|
|
66
|
-
"force_checkpoint": true,
|
|
67
|
-
"checkpoint_message": "Before responding, quick self-check: 1. Task complexity (simple/medium/complex) 2. Information sufficiency (sufficient/need more) 3. If complex or insufficient info, call deep_reflect tool",
|
|
68
|
-
"auto_trigger_conditions": {
|
|
69
|
-
"min_tool_calls": 5,
|
|
70
|
-
"error_rate_threshold": 0.3,
|
|
71
|
-
"complexity_keywords": [
|
|
72
|
-
"refactor",
|
|
73
|
-
"architecture",
|
|
74
|
-
"design",
|
|
75
|
-
"optimize",
|
|
76
|
-
"security",
|
|
77
|
-
"critical"
|
|
78
|
-
]
|
|
79
|
-
},
|
|
80
|
-
"default_model": "T-01",
|
|
81
|
-
"default_depth": 2,
|
|
82
|
-
"timeout_ms": 60000
|
|
83
|
-
},
|
|
84
63
|
"empathy_engine": {
|
|
85
64
|
"enabled": true,
|
|
86
65
|
"dedupe_window_ms": 60000,
|
|
@@ -8,6 +8,8 @@ import { appendCandidateArtifactLineageRecord } from '../../src/core/nocturnal-a
|
|
|
8
8
|
import { getImplementationAssetRoot } from '../../src/core/code-implementation-storage.js';
|
|
9
9
|
import { EvolutionReducerImpl } from '../../src/core/evolution-reducer.js';
|
|
10
10
|
import { saveLedger } from '../../src/core/principle-tree-ledger.js';
|
|
11
|
+
import { WorkflowFunnelLoader } from '../../src/core/workflow-funnel-loader.js';
|
|
12
|
+
import { RuntimeSummaryService } from '../../src/service/runtime-summary-service.js';
|
|
11
13
|
|
|
12
14
|
const tempDirs: string[] = [];
|
|
13
15
|
|
|
@@ -338,4 +340,290 @@ describe('evolution commands', () => {
|
|
|
338
340
|
|
|
339
341
|
expect(result.text).toContain('internalization routes: P-001:skill@');
|
|
340
342
|
});
|
|
343
|
+
|
|
344
|
+
it('renders workflowFunnel blocks when YAML-driven funnels are present', () => {
|
|
345
|
+
const workspace = makeTempDir();
|
|
346
|
+
const stateDir = path.join(workspace, '.state');
|
|
347
|
+
|
|
348
|
+
// Write workflows.yaml with two funnels matching actual schema
|
|
349
|
+
const workflowsYaml = `
|
|
350
|
+
version: "1.0"
|
|
351
|
+
funnels:
|
|
352
|
+
- workflowId: nocturnal
|
|
353
|
+
stages:
|
|
354
|
+
- name: dreamer_completed
|
|
355
|
+
eventType: nocturnal_dreamer_completed
|
|
356
|
+
eventCategory: completed
|
|
357
|
+
statsField: evolution.nocturnalDreamerCompleted
|
|
358
|
+
- name: artifact_persisted
|
|
359
|
+
eventType: nocturnal_artifact_persisted
|
|
360
|
+
eventCategory: completed
|
|
361
|
+
statsField: evolution.nocturnalArtifactPersisted
|
|
362
|
+
- workflowId: rulehost
|
|
363
|
+
stages:
|
|
364
|
+
- name: evaluated
|
|
365
|
+
eventType: rulehost_evaluated
|
|
366
|
+
eventCategory: evaluated
|
|
367
|
+
statsField: evolution.rulehostEvaluated
|
|
368
|
+
`;
|
|
369
|
+
fs.writeFileSync(path.join(stateDir, 'workflows.yaml'), workflowsYaml, 'utf8');
|
|
370
|
+
|
|
371
|
+
// Write daily stats with matching event counts (must be in logs/ subdirectory)
|
|
372
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
373
|
+
writeJson(path.join(stateDir, 'logs', 'daily-stats.json'), {
|
|
374
|
+
[today]: {
|
|
375
|
+
evolution: {
|
|
376
|
+
nocturnalDreamerCompleted: 3,
|
|
377
|
+
nocturnalArtifactPersisted: 2,
|
|
378
|
+
rulehostEvaluated: 15,
|
|
379
|
+
},
|
|
380
|
+
},
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
const result = handleEvolutionStatusCommand({
|
|
384
|
+
config: { workspaceDir: workspace, language: 'en' },
|
|
385
|
+
} as any);
|
|
386
|
+
|
|
387
|
+
expect(result.text).toContain('Workflow Funnel: nocturnal');
|
|
388
|
+
expect(result.text).toMatch(/dreamer_completed: 3/);
|
|
389
|
+
expect(result.text).toMatch(/artifact_persisted: 2/);
|
|
390
|
+
expect(result.text).toContain('Workflow Funnel: rulehost');
|
|
391
|
+
expect(result.text).toMatch(/evaluated: 15/);
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
it('skips funnel block when workflowFunnels is empty array', () => {
|
|
395
|
+
const workspace = makeTempDir();
|
|
396
|
+
|
|
397
|
+
// Write empty funnels array — valid YAML but no funnels defined
|
|
398
|
+
const workflowsYaml = `version: "1.0"\nfunnels: []`;
|
|
399
|
+
fs.writeFileSync(path.join(workspace, '.state', 'workflows.yaml'), workflowsYaml, 'utf8');
|
|
400
|
+
|
|
401
|
+
const result = handleEvolutionStatusCommand({
|
|
402
|
+
config: { workspaceDir: workspace, language: 'en' },
|
|
403
|
+
} as any);
|
|
404
|
+
|
|
405
|
+
expect(result.text).not.toContain('Workflow Funnel:');
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it('shows degraded status and warning when YAML load has warnings', () => {
|
|
409
|
+
const workspace = makeTempDir();
|
|
410
|
+
const stateDir = path.join(workspace, '.state');
|
|
411
|
+
|
|
412
|
+
// Write malformed YAML — loader emits a parse warning
|
|
413
|
+
const badYaml = `
|
|
414
|
+
version: "1.0"
|
|
415
|
+
funnels:
|
|
416
|
+
- workflowId: nocturnal
|
|
417
|
+
stages:
|
|
418
|
+
- name: "unclosed string
|
|
419
|
+
`;
|
|
420
|
+
fs.writeFileSync(path.join(stateDir, 'workflows.yaml'), badYaml, 'utf8');
|
|
421
|
+
|
|
422
|
+
const result = handleEvolutionStatusCommand({
|
|
423
|
+
config: { workspaceDir: workspace, language: 'en' },
|
|
424
|
+
} as any);
|
|
425
|
+
|
|
426
|
+
// Should still render — degraded but not crashed
|
|
427
|
+
expect(result.text).toContain('Evolution Status');
|
|
428
|
+
// Loader warning should appear in output
|
|
429
|
+
expect(result.text).toMatch(/YAML load warning|YAML parse error|workflows\.yaml/);
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
it('renders Chinese workflow funnel labels from YAML', () => {
|
|
433
|
+
const workspace = makeTempDir();
|
|
434
|
+
const stateDir = path.join(workspace, '.state');
|
|
435
|
+
|
|
436
|
+
const workflowsYaml = `
|
|
437
|
+
version: "1.0"
|
|
438
|
+
funnels:
|
|
439
|
+
- workflowId: nocturnal
|
|
440
|
+
stages:
|
|
441
|
+
- name: 做梦完成
|
|
442
|
+
eventType: nocturnal_dreamer_completed
|
|
443
|
+
eventCategory: completed
|
|
444
|
+
statsField: evolution.nocturnalDreamerCompleted
|
|
445
|
+
`;
|
|
446
|
+
fs.writeFileSync(path.join(stateDir, 'workflows.yaml'), workflowsYaml, 'utf8');
|
|
447
|
+
|
|
448
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
449
|
+
writeJson(path.join(stateDir, 'logs', 'daily-stats.json'), {
|
|
450
|
+
[today]: {
|
|
451
|
+
evolution: { nocturnalDreamerCompleted: 7 },
|
|
452
|
+
},
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
const result = handleEvolutionStatusCommand({
|
|
456
|
+
config: { workspaceDir: workspace, language: 'zh' },
|
|
457
|
+
} as any);
|
|
458
|
+
|
|
459
|
+
expect(result.text).toContain('Workflow 漏斗: nocturnal');
|
|
460
|
+
expect(result.text).toMatch(/做梦完成: 7/);
|
|
461
|
+
});
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
describe('YAML funnel E2E integration tests', () => {
|
|
465
|
+
// TEST-01: Full YAML-driven flow with real WorkflowFunnelLoader
|
|
466
|
+
it('e2e_test_full_yaml_driven_flow', () => {
|
|
467
|
+
const workspace = makeTempDir();
|
|
468
|
+
const stateDir = path.join(workspace, '.state');
|
|
469
|
+
|
|
470
|
+
// Create real WorkflowFunnelLoader (not mocked)
|
|
471
|
+
const loader = new WorkflowFunnelLoader(stateDir);
|
|
472
|
+
loader.watch();
|
|
473
|
+
|
|
474
|
+
// Write valid workflows.yaml
|
|
475
|
+
const workflowsYaml = `
|
|
476
|
+
version: "1.0"
|
|
477
|
+
funnels:
|
|
478
|
+
- workflowId: nocturnal
|
|
479
|
+
stages:
|
|
480
|
+
- name: dreamer_completed
|
|
481
|
+
eventType: nocturnal_dreamer_completed
|
|
482
|
+
eventCategory: completed
|
|
483
|
+
statsField: evolution.nocturnalDreamerCompleted
|
|
484
|
+
- name: artifact_persisted
|
|
485
|
+
eventType: nocturnal_artifact_persisted
|
|
486
|
+
eventCategory: completed
|
|
487
|
+
statsField: evolution.nocturnalArtifactPersisted
|
|
488
|
+
- workflowId: rulehost
|
|
489
|
+
stages:
|
|
490
|
+
- name: evaluated
|
|
491
|
+
eventType: rulehost_evaluated
|
|
492
|
+
eventCategory: evaluated
|
|
493
|
+
statsField: evolution.rulehostEvaluated
|
|
494
|
+
`;
|
|
495
|
+
fs.writeFileSync(path.join(stateDir, 'workflows.yaml'), workflowsYaml, 'utf8');
|
|
496
|
+
loader.load(); // reload after writing file
|
|
497
|
+
|
|
498
|
+
// Write daily-stats.json
|
|
499
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
500
|
+
writeJson(path.join(stateDir, 'logs', 'daily-stats.json'), {
|
|
501
|
+
[today]: {
|
|
502
|
+
evolution: {
|
|
503
|
+
nocturnalDreamerCompleted: 3,
|
|
504
|
+
nocturnalArtifactPersisted: 2,
|
|
505
|
+
rulehostEvaluated: 15,
|
|
506
|
+
},
|
|
507
|
+
},
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
// Call getSummary directly with real loader data
|
|
511
|
+
const summary = RuntimeSummaryService.getSummary(workspace, {
|
|
512
|
+
funnels: loader.getAllFunnels(),
|
|
513
|
+
loaderWarnings: loader.getWarnings(),
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
// Assert workflowFunnels structure
|
|
517
|
+
expect(summary.workflowFunnels).toBeDefined();
|
|
518
|
+
expect(summary.workflowFunnels!.length).toBe(2);
|
|
519
|
+
expect(summary.workflowFunnels![0].funnelKey).toBe('nocturnal');
|
|
520
|
+
expect(summary.workflowFunnels![0].stages[0].label).toBe('dreamer_completed');
|
|
521
|
+
expect(summary.workflowFunnels![0].stages[0].count).toBe(3);
|
|
522
|
+
expect(summary.workflowFunnels![0].stages[1].label).toBe('artifact_persisted');
|
|
523
|
+
expect(summary.workflowFunnels![0].stages[1].count).toBe(2);
|
|
524
|
+
expect(summary.workflowFunnels![1].funnelKey).toBe('rulehost');
|
|
525
|
+
expect(summary.workflowFunnels![1].stages[0].label).toBe('evaluated');
|
|
526
|
+
expect(summary.workflowFunnels![1].stages[0].count).toBe(15);
|
|
527
|
+
expect(summary.workflowFunnels![0].funnelLabel).toBe('nocturnal');
|
|
528
|
+
|
|
529
|
+
// DEGRADED-01: valid YAML + valid stats → status ok, no funnel-related warnings
|
|
530
|
+
expect(summary.metadata.status).toBe('ok');
|
|
531
|
+
// Note: warnings array may contain non-funnel warnings (GFI/Daily stats defaults); funnel warnings are checked separately
|
|
532
|
+
const funnelWarnings = summary.metadata.warnings.filter(w => w.includes('statsField') || w.includes('YAML load'));
|
|
533
|
+
expect(funnelWarnings).toHaveLength(0);
|
|
534
|
+
|
|
535
|
+
loader.dispose();
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
// TEST-02: Degraded fallback when YAML is missing
|
|
539
|
+
it('e2e_test_degraded_fallback_on_missing_yaml', () => {
|
|
540
|
+
const workspace = makeTempDir();
|
|
541
|
+
const stateDir = path.join(workspace, '.state');
|
|
542
|
+
|
|
543
|
+
// Create real loader pointing at stateDir with NO workflows.yaml
|
|
544
|
+
const loader = new WorkflowFunnelLoader(stateDir);
|
|
545
|
+
loader.watch();
|
|
546
|
+
|
|
547
|
+
// Write daily-stats.json (so the file exists, but no YAML)
|
|
548
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
549
|
+
writeJson(path.join(stateDir, 'logs', 'daily-stats.json'), {
|
|
550
|
+
[today]: { evolution: {} },
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
// Call getSummary — should not crash
|
|
554
|
+
const summary = RuntimeSummaryService.getSummary(workspace, {
|
|
555
|
+
funnels: loader.getAllFunnels(),
|
|
556
|
+
loaderWarnings: loader.getWarnings(),
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
// Assert degraded status
|
|
560
|
+
expect(summary.metadata.status).toBe('degraded');
|
|
561
|
+
// loaderWarnings are prefixed with "YAML load warning: " when propagated to metadata.warnings
|
|
562
|
+
expect(summary.metadata.warnings).toContain('YAML load warning: workflows.yaml file not found.');
|
|
563
|
+
// DEGRADED-02: funnels absent/empty when YAML missing — empty array is acceptable, just not rendered
|
|
564
|
+
expect(summary.workflowFunnels == null || summary.workflowFunnels.length === 0).toBe(true);
|
|
565
|
+
|
|
566
|
+
loader.dispose();
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
// TEST-03: Hot-reload — YAML changes reflected after loader.load()
|
|
570
|
+
it('e2e_test_hot_reload_reflects_yaml_changes', () => {
|
|
571
|
+
const workspace = makeTempDir();
|
|
572
|
+
const stateDir = path.join(workspace, '.state');
|
|
573
|
+
|
|
574
|
+
const loader = new WorkflowFunnelLoader(stateDir);
|
|
575
|
+
loader.watch();
|
|
576
|
+
|
|
577
|
+
// Write initial workflows.yaml with original_label
|
|
578
|
+
const workflowsYamlV1 = `
|
|
579
|
+
version: "1.0"
|
|
580
|
+
funnels:
|
|
581
|
+
- workflowId: nocturnal
|
|
582
|
+
stages:
|
|
583
|
+
- name: original_label
|
|
584
|
+
eventType: nocturnal_dreamer_completed
|
|
585
|
+
eventCategory: completed
|
|
586
|
+
statsField: evolution.nocturnalDreamerCompleted
|
|
587
|
+
`;
|
|
588
|
+
const yamlPath = path.join(stateDir, 'workflows.yaml');
|
|
589
|
+
fs.writeFileSync(yamlPath, workflowsYamlV1, 'utf8');
|
|
590
|
+
loader.load();
|
|
591
|
+
|
|
592
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
593
|
+
writeJson(path.join(stateDir, 'logs', 'daily-stats.json'), {
|
|
594
|
+
[today]: { evolution: { nocturnalDreamerCompleted: 5 } },
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
// First call — should show original_label
|
|
598
|
+
const summary1 = RuntimeSummaryService.getSummary(workspace, {
|
|
599
|
+
funnels: loader.getAllFunnels(),
|
|
600
|
+
loaderWarnings: loader.getWarnings(),
|
|
601
|
+
});
|
|
602
|
+
expect(summary1.workflowFunnels![0].stages[0].label).toBe('original_label');
|
|
603
|
+
expect(summary1.workflowFunnels![0].stages[0].count).toBe(5);
|
|
604
|
+
|
|
605
|
+
// Modify workflows.yaml to use modified_label
|
|
606
|
+
const workflowsYamlV2 = `
|
|
607
|
+
version: "1.0"
|
|
608
|
+
funnels:
|
|
609
|
+
- workflowId: nocturnal
|
|
610
|
+
stages:
|
|
611
|
+
- name: modified_label
|
|
612
|
+
eventType: nocturnal_dreamer_completed
|
|
613
|
+
eventCategory: completed
|
|
614
|
+
statsField: evolution.nocturnalDreamerCompleted
|
|
615
|
+
`;
|
|
616
|
+
fs.writeFileSync(yamlPath, workflowsYamlV2, 'utf8');
|
|
617
|
+
loader.load(); // trigger hot-reload manually
|
|
618
|
+
|
|
619
|
+
// Second call — should show modified_label
|
|
620
|
+
const summary2 = RuntimeSummaryService.getSummary(workspace, {
|
|
621
|
+
funnels: loader.getAllFunnels(),
|
|
622
|
+
loaderWarnings: loader.getWarnings(),
|
|
623
|
+
});
|
|
624
|
+
expect(summary2.workflowFunnels![0].stages[0].label).toBe('modified_label');
|
|
625
|
+
expect(summary2.workflowFunnels![0].stages[0].count).toBe(5);
|
|
626
|
+
|
|
627
|
+
loader.dispose();
|
|
628
|
+
});
|
|
341
629
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
2
|
import { EventLogService, EventLog } from '../../src/core/event-log.js';
|
|
3
|
-
import type { DailyStats,
|
|
3
|
+
import type { DailyStats, DiagnosticianReportEventData } from '../../src/types/event-types.js';
|
|
4
4
|
import * as fs from 'fs';
|
|
5
5
|
import * as path from 'path';
|
|
6
6
|
import * as os from 'os';
|
|
@@ -19,32 +19,6 @@ describe('EventLog', () => {
|
|
|
19
19
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
-
describe('recordDeepReflection', () => {
|
|
23
|
-
it('should record deep reflection event', () => {
|
|
24
|
-
const data: DeepReflectionEventData = {
|
|
25
|
-
modelId: 'claude-sonnet-4',
|
|
26
|
-
modelSelectionMode: 'auto',
|
|
27
|
-
confidenceScore: 0.85,
|
|
28
|
-
insightsGenerated: 3,
|
|
29
|
-
durationMs: 1500,
|
|
30
|
-
passed: true
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
eventLog.recordDeepReflection('session-1', data);
|
|
34
|
-
eventLog.flush();
|
|
35
|
-
|
|
36
|
-
const today = new Date().toISOString().slice(0, 10);
|
|
37
|
-
const eventsFile = path.join(tempDir, 'logs', `events_${today}.jsonl`);
|
|
38
|
-
const content = fs.readFileSync(eventsFile, 'utf-8');
|
|
39
|
-
const event = JSON.parse(content.trim());
|
|
40
|
-
|
|
41
|
-
expect(event.type).toBe('deep_reflection');
|
|
42
|
-
expect(event.category).toBe('passed');
|
|
43
|
-
expect(event.data.modelId).toBe('claude-sonnet-4');
|
|
44
|
-
expect(event.data.modelSelectionMode).toBe('auto');
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
|
|
48
22
|
describe('DailyStats', () => {
|
|
49
23
|
it('should aggregate tool call statistics correctly', () => {
|
|
50
24
|
// Record multiple tool calls
|
|
@@ -97,8 +71,6 @@ describe('EventLog', () => {
|
|
|
97
71
|
// Hooks field
|
|
98
72
|
expect(stats.hooks).toBeDefined();
|
|
99
73
|
|
|
100
|
-
// Deep Reflection field
|
|
101
|
-
expect(stats.deepReflection).toBeDefined();
|
|
102
74
|
});
|
|
103
75
|
|
|
104
76
|
it('should increment tools.failure on error', () => {
|
|
@@ -678,7 +678,7 @@ describe('RuntimeSummaryService', () => {
|
|
|
678
678
|
last_updated: '2026-03-20T10:00:00Z',
|
|
679
679
|
});
|
|
680
680
|
writeJson(path.join(workspace, '.state', 'logs', 'daily-stats.json'), {
|
|
681
|
-
|
|
681
|
+
[new Date().toISOString().slice(0, 10)]: {
|
|
682
682
|
toolCalls: 120,
|
|
683
683
|
painSignals: 15,
|
|
684
684
|
evolutionTasks: 5,
|