principles-disciple 1.66.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 +0 -6
- 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
|
@@ -1,204 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import type {
|
|
3
|
-
SubagentWorkflowSpec,
|
|
4
|
-
DeepReflectResult,
|
|
5
|
-
WorkflowResultContext,
|
|
6
|
-
WorkflowPersistContext,
|
|
7
|
-
WorkflowHandle,
|
|
8
|
-
} from './types.js';
|
|
9
|
-
|
|
10
|
-
// Re-export DeepReflectResult so index.ts can re-export it
|
|
11
|
-
export type { DeepReflectResult } from './types.js';
|
|
12
|
-
import type { RuntimeDirectDriver } from './runtime-direct-driver.js';
|
|
13
|
-
import { isSubagentRuntimeAvailable } from '../../utils/subagent-probe.js';
|
|
14
|
-
import { buildCritiquePromptV2 } from '../../tools/critique-prompt.js';
|
|
15
|
-
import { WorkflowManagerBase } from './workflow-manager-base.js';
|
|
16
|
-
import { DEEP_REFLECT_TTL_MS } from '../../config/defaults/runtime.js';
|
|
17
|
-
|
|
18
|
-
const WORKFLOW_SESSION_PREFIX = 'agent:main:subagent:workflow-';
|
|
19
|
-
|
|
20
|
-
const DEFAULT_TIMEOUT_MS = 60_000; // Deep-reflect needs more time than empathy
|
|
21
|
-
|
|
22
|
-
export interface DeepReflectWorkflowOptions {
|
|
23
|
-
workspaceDir: string;
|
|
24
|
-
logger: PluginLogger;
|
|
25
|
-
subagent: RuntimeDirectDriver['subagent'];
|
|
26
|
-
/** Pass api.runtime.agent.session to enable heartbeat-safe cleanup (#188) */
|
|
27
|
-
agentSession?: RuntimeDirectDriver['agentSession'];
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export class DeepReflectWorkflowManager extends WorkflowManagerBase {
|
|
31
|
-
constructor(opts: DeepReflectWorkflowOptions) {
|
|
32
|
-
super({
|
|
33
|
-
workspaceDir: opts.workspaceDir,
|
|
34
|
-
logger: opts.logger,
|
|
35
|
-
subagent: opts.subagent,
|
|
36
|
-
agentSession: opts.agentSession,
|
|
37
|
-
workflowType: 'deep-reflect',
|
|
38
|
-
sessionPrefix: WORKFLOW_SESSION_PREFIX,
|
|
39
|
-
defaultTimeoutMs: DEFAULT_TIMEOUT_MS,
|
|
40
|
-
defaultTtlMs: DEEP_REFLECT_TTL_MS,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async startWorkflow<TResult>(
|
|
45
|
-
spec: SubagentWorkflowSpec<TResult>,
|
|
46
|
-
options: {
|
|
47
|
-
parentSessionId: string;
|
|
48
|
-
workspaceDir?: string;
|
|
49
|
-
taskInput: unknown;
|
|
50
|
-
metadata?: Record<string, unknown>;
|
|
51
|
-
}
|
|
52
|
-
): Promise<WorkflowHandle> {
|
|
53
|
-
// Surface degrade: skip boot sessions
|
|
54
|
-
if (options.parentSessionId.startsWith('boot-')) {
|
|
55
|
-
this.logger.info(`[PD:DeepReflectWorkflow] Skipping workflow: boot session`);
|
|
56
|
-
throw new Error(`DeepReflectWorkflowManager: cannot start workflow for boot session`);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Surface degrade: check subagent runtime availability
|
|
60
|
-
if (!isSubagentRuntimeAvailable(this.driver.getSubagent())) {
|
|
61
|
-
this.logger.info(`[PD:DeepReflectWorkflow] Skipping workflow: subagent runtime unavailable`);
|
|
62
|
-
throw new Error(`DeepReflectWorkflowManager: subagent runtime unavailable`);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (spec.transport !== 'runtime_direct') {
|
|
66
|
-
throw new Error(`DeepReflectWorkflowManager only supports runtime_direct transport`);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return super.startWorkflow(spec, options);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
protected override generateWorkflowId(): string {
|
|
75
|
-
return `wf_dr_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// ─── Interfaces ───────────────────────────────────────────────────────────────
|
|
80
|
-
|
|
81
|
-
export interface DeepReflectTaskInput {
|
|
82
|
-
context: string;
|
|
83
|
-
depth: number;
|
|
84
|
-
model_id?: string;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export interface DeepReflectBuildPromptContext {
|
|
88
|
-
parentSessionId: string;
|
|
89
|
-
workspaceDir?: string;
|
|
90
|
-
taskInput: unknown;
|
|
91
|
-
startedAt: number;
|
|
92
|
-
workflowType: string;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// ─── Workflow Spec ─────────────────────────────────────────────────────────────
|
|
96
|
-
|
|
97
|
-
export const deepReflectWorkflowSpec: SubagentWorkflowSpec<DeepReflectResult> = {
|
|
98
|
-
workflowType: 'deep-reflect',
|
|
99
|
-
transport: 'runtime_direct',
|
|
100
|
-
timeoutMs: 60_000,
|
|
101
|
-
ttlMs: DEEP_REFLECT_TTL_MS,
|
|
102
|
-
shouldDeleteSessionAfterFinalize: true,
|
|
103
|
-
|
|
104
|
-
buildPrompt(taskInput: unknown, ctx: DeepReflectBuildPromptContext): string {
|
|
105
|
-
const input = taskInput as DeepReflectTaskInput;
|
|
106
|
-
// Use the existing critique prompt builder
|
|
107
|
-
return buildCritiquePromptV2({
|
|
108
|
-
context: input.context,
|
|
109
|
-
depth: input.depth,
|
|
110
|
-
model_id: input.model_id,
|
|
111
|
-
api: undefined, // Not available in workflow context
|
|
112
|
-
workspaceDir: ctx.workspaceDir,
|
|
113
|
-
});
|
|
114
|
-
},
|
|
115
|
-
|
|
116
|
-
shouldFinalizeOnWaitStatus(status: 'ok' | 'error' | 'timeout'): boolean {
|
|
117
|
-
return status === 'ok';
|
|
118
|
-
},
|
|
119
|
-
|
|
120
|
-
async parseResult(ctx: WorkflowResultContext): Promise<DeepReflectResult | null> {
|
|
121
|
-
const { assistantTexts, messages } = ctx;
|
|
122
|
-
|
|
123
|
-
let insights = '';
|
|
124
|
-
if (assistantTexts && assistantTexts.length > 0) {
|
|
125
|
-
insights = assistantTexts[assistantTexts.length - 1] || '';
|
|
126
|
-
} else if (messages && messages.length > 0) {
|
|
127
|
-
const lastMessage = messages[messages.length - 1] as { role?: string; content?: unknown };
|
|
128
|
-
if (typeof lastMessage?.content === 'string') {
|
|
129
|
-
insights = lastMessage.content;
|
|
130
|
-
} else if (Array.isArray(lastMessage?.content)) {
|
|
131
|
-
insights = (lastMessage.content as { type?: string; text?: string }[])
|
|
132
|
-
.filter((c) => c?.type === 'text' && typeof c.text === 'string')
|
|
133
|
-
|
|
134
|
-
.map((c) => c.text!)
|
|
135
|
-
.join('\n');
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (!insights?.trim()) {
|
|
140
|
-
return null;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const taskInput = ctx.metadata.taskInput as DeepReflectTaskInput | undefined;
|
|
144
|
-
|
|
145
|
-
return {
|
|
146
|
-
insights,
|
|
147
|
-
context: taskInput?.context ?? '',
|
|
148
|
-
depth: taskInput?.depth ?? 2,
|
|
149
|
-
modelId: taskInput?.model_id ?? 'auto-select',
|
|
150
|
-
passed: !insights.includes('REFLECTION_FAIL'),
|
|
151
|
-
};
|
|
152
|
-
},
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
async persistResult(ctx: WorkflowPersistContext<DeepReflectResult>): Promise<void> {
|
|
156
|
-
const { result, metadata, workspaceDir } = ctx;
|
|
157
|
-
|
|
158
|
-
if (!result || !result.insights) return;
|
|
159
|
-
|
|
160
|
-
try {
|
|
161
|
-
const fs = await import('fs');
|
|
162
|
-
const pathMod = await import('path');
|
|
163
|
-
const { resolvePdPath } = await import('../../core/paths.js');
|
|
164
|
-
|
|
165
|
-
const reflectionLogPath = resolvePdPath(workspaceDir, 'REFLECTION_LOG');
|
|
166
|
-
const memoryDir = pathMod.default.dirname(reflectionLogPath);
|
|
167
|
-
if (!fs.default.existsSync(memoryDir)) {
|
|
168
|
-
fs.default.mkdirSync(memoryDir, { recursive: true });
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const timestamp = new Date().toISOString();
|
|
172
|
-
const taskInput = metadata.taskInput as DeepReflectTaskInput | undefined;
|
|
173
|
-
const entry = `
|
|
174
|
-
---
|
|
175
|
-
## Reflection at ${timestamp}
|
|
176
|
-
**Model**: ${result.modelId || 'auto-select'}
|
|
177
|
-
**Depth**: ${result.depth || 2}
|
|
178
|
-
|
|
179
|
-
### Context
|
|
180
|
-
${(taskInput?.context ?? '').substring(0, 500)}${(taskInput?.context ?? '').length > 500 ? '...' : ''}
|
|
181
|
-
|
|
182
|
-
### Insights
|
|
183
|
-
${result.insights}
|
|
184
|
-
|
|
185
|
-
`;
|
|
186
|
-
|
|
187
|
-
const header = `# Reflection Log\n\n> Auto-generated by Deep Reflection Tool\n> Retention: 30 days\n`;
|
|
188
|
-
|
|
189
|
-
let existingContent = '';
|
|
190
|
-
if (fs.default.existsSync(reflectionLogPath)) {
|
|
191
|
-
existingContent = fs.default.readFileSync(reflectionLogPath, 'utf8');
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const newContent = header + entry + existingContent.replace(header, '');
|
|
195
|
-
|
|
196
|
-
const tempPath = `${reflectionLogPath}.tmp`;
|
|
197
|
-
fs.default.writeFileSync(tempPath, newContent, 'utf8');
|
|
198
|
-
fs.default.renameSync(tempPath, reflectionLogPath);
|
|
199
|
-
} catch (err) {
|
|
200
|
-
// Let the error propagate to finalizeOnce for proper event logging
|
|
201
|
-
throw new Error(`DeepReflectWorkflow persistResult failed: ${String(err)}`, { cause: err });
|
|
202
|
-
}
|
|
203
|
-
},
|
|
204
|
-
};
|
|
1
|
+
export {};
|
|
@@ -21,14 +21,6 @@ export {
|
|
|
21
21
|
type EmpathyObserverWorkflowOptions,
|
|
22
22
|
} from './empathy-observer-workflow-manager.js';
|
|
23
23
|
|
|
24
|
-
export {
|
|
25
|
-
DeepReflectWorkflowManager,
|
|
26
|
-
deepReflectWorkflowSpec,
|
|
27
|
-
type DeepReflectWorkflowOptions,
|
|
28
|
-
type DeepReflectTaskInput,
|
|
29
|
-
type DeepReflectResult,
|
|
30
|
-
} from './deep-reflect-workflow-manager.js';
|
|
31
|
-
|
|
32
24
|
export {
|
|
33
25
|
NocturnalWorkflowManager,
|
|
34
26
|
nocturnalWorkflowSpec,
|
|
@@ -204,17 +204,6 @@ export interface EmpathyResult {
|
|
|
204
204
|
painScore: number;
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
/**
|
|
208
|
-
* Deep-reflect workflow result.
|
|
209
|
-
*/
|
|
210
|
-
export interface DeepReflectResult {
|
|
211
|
-
insights: string;
|
|
212
|
-
context: string;
|
|
213
|
-
depth: number;
|
|
214
|
-
modelId: string;
|
|
215
|
-
passed: boolean;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
207
|
/**
|
|
219
208
|
* Empathy observer workflow specification.
|
|
220
209
|
* This is the concrete spec for PR2 migration.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* WorkflowManagerBase - Shared base class for polling-based workflow managers
|
|
3
3
|
*
|
|
4
4
|
* Extracts common lifecycle, state transitions, and store operations from
|
|
5
|
-
* EmpathyObserverWorkflowManager
|
|
5
|
+
* EmpathyObserverWorkflowManager.
|
|
6
6
|
*
|
|
7
7
|
* Both managers implement the same polling-based workflow lifecycle:
|
|
8
8
|
* startWorkflow → driver.run() → store.createWorkflow → scheduleWaitPollWithRetry
|
|
@@ -1,97 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { loadModelIndex } from './model-index.js';
|
|
3
|
-
import { resolveWorkspaceDirFromApi } from '../core/path-resolver.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* 深度指令模板 (必须与测试用例中的 quick/balanced/thorough 关键字对齐)
|
|
7
|
-
*/
|
|
8
|
-
const DEPTH_INSTRUCTIONS = {
|
|
9
|
-
1: 'Provide a quick surface-level analysis.',
|
|
10
|
-
2: 'Provide a balanced analysis with moderate depth.',
|
|
11
|
-
3: 'Provide an extremely thorough and exhaustive analysis.',
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* 构建反思提示词 (Critique Prompt) V2
|
|
16
|
-
*
|
|
17
|
-
* 严格按照测试用例的调用习惯和断言要求进行重写。
|
|
18
|
-
* 增加 OpenClaw 兼容性路径解析。
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
export function buildCritiquePromptV2(
|
|
22
|
-
params: {
|
|
23
|
-
context: string;
|
|
24
|
-
depth?: number;
|
|
25
|
-
model_id?: string;
|
|
26
|
-
workspaceDir?: string;
|
|
27
|
-
api?: OpenClawPluginApi;
|
|
28
|
-
}
|
|
29
|
-
): string {
|
|
30
|
-
const { context, depth = 2, workspaceDir, api } = params;
|
|
31
|
-
|
|
32
|
-
// FIX (B): Priority: explicitly passed workspaceDir > official API resolution
|
|
33
|
-
// Do NOT chain through api.config?.workspaceDir which may be stale.
|
|
34
|
-
const effectiveWorkspaceDir = workspaceDir || resolveWorkspaceDirFromApi(api);
|
|
35
|
-
|
|
36
|
-
if (!effectiveWorkspaceDir) {
|
|
37
|
-
throw new Error('Workspace directory is required for deep reflection.');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// 2. 深度校验与警告日志
|
|
41
|
-
let validatedDepth = 2;
|
|
42
|
-
if (typeof depth === 'number') {
|
|
43
|
-
if (depth >= 1 && depth <= 3) {
|
|
44
|
-
validatedDepth = depth;
|
|
45
|
-
} else {
|
|
46
|
-
if (api?.logger) {
|
|
47
|
-
api.logger.warn(`[DeepReflect] Invalid depth value ${depth}. Falling back to 2.`);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const depthMsg = DEPTH_INSTRUCTIONS[validatedDepth as keyof typeof DEPTH_INSTRUCTIONS];
|
|
53
|
-
|
|
54
|
-
// 3. 加载模型索引
|
|
55
|
-
const modelIndexMessage = loadModelIndex(effectiveWorkspaceDir, api);
|
|
56
|
-
|
|
57
|
-
// 4. 构造最终提示词
|
|
58
|
-
return `
|
|
59
|
-
# Role: Principal Critical Thinker & Strategist
|
|
60
|
-
---
|
|
61
|
-
[SYSTEM_ID: Critical Analysis Engine]
|
|
62
|
-
|
|
63
|
-
## Objective
|
|
64
|
-
Provide a high-intensity critical analysis and actionable feedback for the provided task context.
|
|
65
|
-
|
|
66
|
-
## Depth Requirement
|
|
67
|
-
${depthMsg}
|
|
68
|
-
|
|
69
|
-
## Meta-Cognitive Models
|
|
70
|
-
The agent has inherited meta-cognitive models (T-01 to T-09) from the **thinking_os** framework. Use these as your foundational logic.
|
|
71
|
-
|
|
72
|
-
## Model Selection Guidelines
|
|
73
|
-
Step 1: Determine if the task context is a **general planning** task or **domain-specific**.
|
|
74
|
-
Step 2: Select 1-2 relevant models.
|
|
75
|
-
Step 3: If no match is found, use **Fallback** to **Meta-Cognitive Models**.
|
|
76
|
-
|
|
77
|
-
## Domain-Specific Models Index
|
|
78
|
-
${modelIndexMessage}
|
|
79
|
-
|
|
80
|
-
## Task Context to Analyze
|
|
81
|
-
---
|
|
82
|
-
${context}
|
|
83
|
-
---
|
|
84
|
-
|
|
85
|
-
## Instructions
|
|
86
|
-
1. Apply the selected models rigorously.
|
|
87
|
-
2. Identify blind spots and logic gaps.
|
|
88
|
-
3. Provide high-impact recommendations.
|
|
89
|
-
|
|
90
|
-
## Output Structure
|
|
91
|
-
- **Blind Spots**: ...
|
|
92
|
-
- **Risk Warnings**: ...
|
|
93
|
-
- **Alternative Approaches**: ...
|
|
94
|
-
- **Recommendations**: ...
|
|
95
|
-
- **Confidence Level**: [LOW/MEDIUM/HIGH]
|
|
96
|
-
`.trim();
|
|
97
|
-
}
|
|
1
|
+
export {};
|
|
@@ -1,337 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import type { PluginRuntimeSubagent } from '../service/subagent-workflow/runtime-direct-driver.js';
|
|
3
|
-
import { Type } from '@sinclair/typebox';
|
|
4
|
-
import * as fs from 'fs';
|
|
5
|
-
import { EventLogService } from '../core/event-log.js';
|
|
6
|
-
import { resolvePdPath } from '../core/paths.js';
|
|
7
|
-
import { resolveWorkspaceDirFromApi } from '../core/path-resolver.js';
|
|
8
|
-
import { WorkspaceNotFoundError } from '../config/index.js';
|
|
9
|
-
import {
|
|
10
|
-
DeepReflectWorkflowManager,
|
|
11
|
-
deepReflectWorkflowSpec,
|
|
12
|
-
type DeepReflectTaskInput,
|
|
13
|
-
} from '../service/subagent-workflow/index.js';
|
|
14
|
-
|
|
15
|
-
interface DeepReflectionConfig {
|
|
16
|
-
enabled: boolean;
|
|
17
|
-
mode: 'auto' | 'forced' | 'disabled';
|
|
18
|
-
auto_trigger_conditions: {
|
|
19
|
-
min_tool_calls: number;
|
|
20
|
-
error_rate_threshold: number;
|
|
21
|
-
high_gfi_threshold: number;
|
|
22
|
-
};
|
|
23
|
-
modelsDir?: string;
|
|
24
|
-
timeout_ms?: number;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Type assertion: OpenClaw SDK subagent -> workflow manager subagent type.
|
|
29
|
-
* Both types are structurally identical but come from different import paths.
|
|
30
|
-
*/
|
|
31
|
-
function toWorkflowSubagent(
|
|
32
|
-
subagent: NonNullable<OpenClawPluginApi['runtime']>['subagent']
|
|
33
|
-
): PluginRuntimeSubagent {
|
|
34
|
-
return subagent as unknown as PluginRuntimeSubagent;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const DEFAULT_CONFIG: DeepReflectionConfig = {
|
|
38
|
-
enabled: true,
|
|
39
|
-
mode: 'auto',
|
|
40
|
-
auto_trigger_conditions: {
|
|
41
|
-
min_tool_calls: 5,
|
|
42
|
-
error_rate_threshold: 0.3,
|
|
43
|
-
high_gfi_threshold: 70
|
|
44
|
-
},
|
|
45
|
-
timeout_ms: 60000
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
function safeLog(
|
|
49
|
-
api: OpenClawPluginApi | undefined,
|
|
50
|
-
level: 'info' | 'debug' | 'warn' | 'error',
|
|
51
|
-
message: string
|
|
52
|
-
): void {
|
|
53
|
-
try {
|
|
54
|
-
if (api?.logger && typeof api.logger[level] === 'function') {
|
|
55
|
-
api.logger[level](message);
|
|
56
|
-
}
|
|
57
|
-
} catch {
|
|
58
|
-
// Never recurse on logger failures
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function loadConfig(workspaceDir: string | undefined, api: OpenClawPluginApi): DeepReflectionConfig {
|
|
63
|
-
if (!workspaceDir) return DEFAULT_CONFIG;
|
|
64
|
-
const configPath = resolvePdPath(workspaceDir, 'PAIN_SETTINGS');
|
|
65
|
-
try {
|
|
66
|
-
if (fs.existsSync(configPath)) {
|
|
67
|
-
const raw = fs.readFileSync(configPath, 'utf-8');
|
|
68
|
-
const settings = JSON.parse(raw);
|
|
69
|
-
return { ...DEFAULT_CONFIG, ...settings.deep_reflection };
|
|
70
|
-
}
|
|
71
|
-
} catch (err) {
|
|
72
|
-
safeLog(api, 'warn', `[DeepReflect] Failed to load config: ${String(err)}`);
|
|
73
|
-
}
|
|
74
|
-
return DEFAULT_CONFIG;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function readStringParam(rawParams: Record<string, unknown>, key: string): string | undefined {
|
|
78
|
-
const value = rawParams[key];
|
|
79
|
-
if (typeof value === 'string') return value.trim() || undefined;
|
|
80
|
-
|
|
81
|
-
const snakeKey = key.replace(/([A-Z])/g, '_$1').toLowerCase();
|
|
82
|
-
const snakeValue = rawParams[snakeKey];
|
|
83
|
-
if (typeof snakeValue === 'string') return snakeValue.trim() || undefined;
|
|
84
|
-
|
|
85
|
-
return undefined;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function readNumberParam(rawParams: Record<string, unknown>, key: string): number | undefined {
|
|
89
|
-
const value = rawParams[key];
|
|
90
|
-
if (typeof value === 'number') return value;
|
|
91
|
-
|
|
92
|
-
const snakeKey = key.replace(/([A-Z])/g, '_$1').toLowerCase();
|
|
93
|
-
const snakeValue = rawParams[snakeKey];
|
|
94
|
-
if (typeof snakeValue === 'number') return snakeValue;
|
|
95
|
-
|
|
96
|
-
return undefined;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function createDeepReflectTool(api: OpenClawPluginApi) {
|
|
100
|
-
return {
|
|
101
|
-
name: 'deep_reflect',
|
|
102
|
-
description: '执行深层次的元认知反思,分析当前任务的潜在风险、逻辑漏洞或架构改进点。',
|
|
103
|
-
parameters: Type.Object({
|
|
104
|
-
context: Type.String({ description: '需要反思的任务上下文、代码片段或当前遇到的困难。' }),
|
|
105
|
-
depth: Type.Optional(Type.Number({ description: '反思深度 (1-3)。1: 快速扫描, 2: 均衡分析, 3: 彻底解构。默认为 2。', minimum: 1, maximum: 3 })),
|
|
106
|
-
model_id: Type.Optional(Type.String({ description: '可选:强制指定使用的思维模型 ID。' }))
|
|
107
|
-
}),
|
|
108
|
-
|
|
109
|
-
async execute(
|
|
110
|
-
_toolCallId: string,
|
|
111
|
-
rawParams: Record<string, unknown>
|
|
112
|
-
): Promise<{ content: { type: string; text: string }[] }> {
|
|
113
|
-
const context = readStringParam(rawParams, 'context') || '';
|
|
114
|
-
const depth = readNumberParam(rawParams, 'depth') ?? 2;
|
|
115
|
-
const model_id = readStringParam(rawParams, 'model_id');
|
|
116
|
-
|
|
117
|
-
if (!context) {
|
|
118
|
-
return { content: [{ type: 'text', text: '❌ 错误: 必须提供反思上下文 (context)。' }] };
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const effectiveWorkspaceDir = resolveReflectionWorkspace(api);
|
|
124
|
-
|
|
125
|
-
const config = loadConfig(effectiveWorkspaceDir, api);
|
|
126
|
-
if (config.mode === 'disabled' || !config.enabled) {
|
|
127
|
-
return { content: [{ type: 'text', text: '⏭️ Deep Reflection 已禁用。' }] };
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (model_id) {
|
|
131
|
-
safeLog(api, 'warn', `[DeepReflect] The 'model_id' parameter is deprecated. The agent will now auto-select models based on the context index.`);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
try {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
return await executeReflectionWorkflow(effectiveWorkspaceDir, config, context, depth, model_id, api);
|
|
138
|
-
} catch (err) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
return handleReflectionError(err, context, depth, model_id, effectiveWorkspaceDir, api);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Resolve workspace directory for deep reflection tool.
|
|
149
|
-
*/
|
|
150
|
-
function resolveReflectionWorkspace(api: OpenClawPluginApi): string {
|
|
151
|
-
// FIX (B): Only use resolveWorkspaceDirFromApi — do not chain through api.config?.workspaceDir
|
|
152
|
-
// which may be stale. Fail-fast if workspace cannot be resolved.
|
|
153
|
-
const dir = resolveWorkspaceDirFromApi(api);
|
|
154
|
-
if (!dir) {
|
|
155
|
-
throw new WorkspaceNotFoundError('deep-reflect: workspace directory could not be resolved via API');
|
|
156
|
-
}
|
|
157
|
-
return dir;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Execute the deep reflection workflow: start, poll, collect results.
|
|
162
|
-
*/
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
async function executeReflectionWorkflow(
|
|
166
|
-
effectiveWorkspaceDir: string,
|
|
167
|
-
config: DeepReflectionConfig,
|
|
168
|
-
context: string,
|
|
169
|
-
depth: number,
|
|
170
|
-
model_id: string | undefined,
|
|
171
|
-
api: OpenClawPluginApi,
|
|
172
|
-
): Promise<{ content: { type: string; text: string }[] }> {
|
|
173
|
-
const stateDir = resolvePdPath(effectiveWorkspaceDir, 'STATE_DIR');
|
|
174
|
-
const eventLog = EventLogService.get(stateDir, api.logger);
|
|
175
|
-
const parentSessionId = effectiveWorkspaceDir.replace(/[^a-zA-Z0-9_-]/g, '_').substring(0, 64);
|
|
176
|
-
|
|
177
|
-
const manager = new DeepReflectWorkflowManager({
|
|
178
|
-
workspaceDir: effectiveWorkspaceDir,
|
|
179
|
-
logger: api.logger,
|
|
180
|
-
|
|
181
|
-
subagent: toWorkflowSubagent(api.runtime.subagent),
|
|
182
|
-
agentSession: api.runtime.agent?.session,
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
try {
|
|
186
|
-
const taskInput: DeepReflectTaskInput = { context, depth, model_id };
|
|
187
|
-
const handle = await manager.startWorkflow(deepReflectWorkflowSpec, {
|
|
188
|
-
parentSessionId,
|
|
189
|
-
workspaceDir: effectiveWorkspaceDir,
|
|
190
|
-
taskInput,
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
const startTime = Date.now();
|
|
194
|
-
const timeoutMs = config.timeout_ms ?? 60000;
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
return await pollReflectionCompletion(manager, handle, timeoutMs, startTime, eventLog, effectiveWorkspaceDir, context, model_id, depth);
|
|
198
|
-
} finally {
|
|
199
|
-
manager.dispose();
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Poll the reflection workflow until completion, timeout, or error.
|
|
205
|
-
*/
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
async function pollReflectionCompletion(
|
|
209
|
-
manager: DeepReflectWorkflowManager,
|
|
210
|
-
handle: { workflowId: string; childSessionKey: string },
|
|
211
|
-
timeoutMs: number,
|
|
212
|
-
startTime: number,
|
|
213
|
-
eventLog: ReturnType<typeof EventLogService.get>,
|
|
214
|
-
workspaceDir: string,
|
|
215
|
-
context: string,
|
|
216
|
-
model_id: string | undefined,
|
|
217
|
-
depth: number,
|
|
218
|
-
): Promise<{ content: { type: string; text: string }[] }> {
|
|
219
|
-
const pollInterval = 500;
|
|
220
|
-
|
|
221
|
-
while (Date.now() - startTime < timeoutMs) {
|
|
222
|
-
await new Promise(resolve => setTimeout(resolve, pollInterval));
|
|
223
|
-
const workflowState = manager.getWorkflowState(handle.workflowId);
|
|
224
|
-
if (!workflowState) break;
|
|
225
|
-
|
|
226
|
-
if (workflowState === 'completed') {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
return formatReflectionSuccess(handle, context, depth, model_id, startTime, eventLog, workspaceDir);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (workflowState === 'terminal_error' || workflowState === 'expired') {
|
|
233
|
-
throw new Error(`Deep-reflect workflow failed: ${workflowState}`);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return { content: [{ type: 'text', text: '⚠️ 反思任务执行超时。你可以尝试减少上下文长度或增加深度。' }] };
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Format the success response from a completed reflection.
|
|
242
|
-
*/
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
function formatReflectionSuccess(
|
|
246
|
-
handle: { childSessionKey: string },
|
|
247
|
-
context: string,
|
|
248
|
-
depth: number,
|
|
249
|
-
model_id: string | undefined,
|
|
250
|
-
startTime: number,
|
|
251
|
-
eventLog: ReturnType<typeof EventLogService.get>,
|
|
252
|
-
workspaceDir: string,
|
|
253
|
-
): { content: { type: string; text: string }[] } {
|
|
254
|
-
const reflectionLogPath = resolvePdPath(workspaceDir, 'REFLECTION_LOG');
|
|
255
|
-
let insights = '';
|
|
256
|
-
if (fs.existsSync(reflectionLogPath)) {
|
|
257
|
-
const content = fs.readFileSync(reflectionLogPath, 'utf8');
|
|
258
|
-
const match = /### Insights\n([\s\S]*?)(?=---|$)/.exec(content);
|
|
259
|
-
if (match) insights = match[1].trim();
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
if (eventLog) {
|
|
263
|
-
eventLog.recordDeepReflection(handle.childSessionKey, {
|
|
264
|
-
modelId: model_id || 'auto-select',
|
|
265
|
-
modelSelectionMode: model_id ? 'manual' : 'auto',
|
|
266
|
-
depth,
|
|
267
|
-
contextPreview: context.substring(0, 200),
|
|
268
|
-
resultPreview: insights.substring(0, 300),
|
|
269
|
-
durationMs: Date.now() - startTime,
|
|
270
|
-
passed: true,
|
|
271
|
-
timeout: false,
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
return {
|
|
276
|
-
content: [{
|
|
277
|
-
type: 'text',
|
|
278
|
-
text: `
|
|
279
|
-
# 💎 Deep Reflection Insights
|
|
280
|
-
---
|
|
281
|
-
**Selected Model(s)**: ${model_id || 'auto-select'}
|
|
282
|
-
**Reflection Depth**: ${depth}
|
|
283
|
-
**Analysis Duration**: ${((Date.now() - startTime) / 1000).toFixed(1)}s
|
|
284
|
-
|
|
285
|
-
${insights || '反思完成,详见 REFLECTION_LOG。'}
|
|
286
|
-
|
|
287
|
-
---
|
|
288
|
-
*Generated by Principles Disciple Meta-Cognitive Engine*
|
|
289
|
-
`.trim(),
|
|
290
|
-
}],
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Handle reflection errors and format error response.
|
|
296
|
-
*/
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
function handleReflectionError(
|
|
300
|
-
err: unknown,
|
|
301
|
-
context: string,
|
|
302
|
-
depth: number,
|
|
303
|
-
model_id: string | undefined,
|
|
304
|
-
workspaceDir: string,
|
|
305
|
-
api: OpenClawPluginApi,
|
|
306
|
-
): { content: { type: string; text: string }[] } {
|
|
307
|
-
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
308
|
-
safeLog(api, 'error', `[DeepReflect] Reflection failed: ${errorMsg}`);
|
|
309
|
-
|
|
310
|
-
const stateDir = resolvePdPath(workspaceDir, 'STATE_DIR');
|
|
311
|
-
const eventLog = EventLogService.get(stateDir, api.logger);
|
|
312
|
-
|
|
313
|
-
if (eventLog) {
|
|
314
|
-
eventLog.recordDeepReflection('deep-reflect-error', {
|
|
315
|
-
modelId: model_id || 'auto-select',
|
|
316
|
-
modelSelectionMode: model_id ? 'manual' : 'auto',
|
|
317
|
-
depth,
|
|
318
|
-
contextPreview: context.substring(0, 200),
|
|
319
|
-
durationMs: 0,
|
|
320
|
-
passed: false,
|
|
321
|
-
timeout: errorMsg.toLowerCase().includes('timeout'),
|
|
322
|
-
error: errorMsg,
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
return { content: [{ type: 'text', text: `❌ 反思执行失败: ${errorMsg}。请检查 API 配置或网络连接。` }] };
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
export const deepReflectTool = {
|
|
330
|
-
name: 'deep_reflect',
|
|
331
|
-
description: '执行深层次的元认知反思,分析当前任务的潜在风险、逻辑漏洞或架构改进点。',
|
|
332
|
-
parameters: Type.Object({
|
|
333
|
-
context: Type.String({ description: '需要反思的任务上下文、代码片段或当前遇到的困难。' }),
|
|
334
|
-
depth: Type.Optional(Type.Number({ description: '反思深度 (1-3)。1: 快速扫描, 2: 均衡分析, 3: 彻底解构。默认为 2。', minimum: 1, maximum: 3 })),
|
|
335
|
-
model_id: Type.Optional(Type.String({ description: '可选:强制指定使用的思维模型 ID。' }))
|
|
336
|
-
}),
|
|
337
|
-
};
|
|
1
|
+
export {};
|