minimal-agent 0.8.2 → 0.9.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/README.md +4 -5
- package/package.json +1 -1
- package/plugins/workflow-runner/plugin.js +1 -0
- package/plugins/workflow-runner/src/agentCommon.js +82 -47
- package/plugins/workflow-runner/src/expressions.js +48 -2
- package/plugins/workflow-runner/src/index.js +1 -0
- package/plugins/workflow-runner/src/jsonPayload.js +1 -1
- package/plugins/workflow-runner/src/loader.js +70 -8
- package/plugins/workflow-runner/src/recovery.js +43 -35
- package/plugins/workflow-runner/src/runner.js +143 -34
- package/plugins/workflow-runner/src/stepExecutors/agent.js +64 -35
- package/plugins/workflow-runner/src/stepExecutors/assert.js +14 -2
- package/plugins/workflow-runner/src/stepExecutors/llm.js +48 -107
- package/plugins/workflow-runner/src/stepExecutors/skill.js +50 -39
- package/plugins/workflow-runner/src/stepExecutors/tool.js +20 -7
- package/plugins/workflow-runner/src/stepExecutors/verify.js +11 -3
- package/plugins/workflow-runner/src/taskIdentity.js +141 -0
- package/plugins/workflow-runner/src/types.js +1 -2
- package/plugins/workflow-runner/src/workflowState.js +211 -28
- package/skills/adversarial-review/SKILL.md +0 -1
- package/skills/pptx/scripts/office/__pycache__/soffice.cpython-314.pyc +0 -0
- package/src/askBridge.js +10 -0
- package/src/context/archive.js +4 -0
- package/src/infra/verification.js +25 -13
- package/src/llm/client.js +160 -12
- package/src/loop.js +15 -12
- package/src/plugins/pluginLoader.js +2 -1
- package/src/plugins/pluginRunner.js +9 -21
- package/src/prompts/pluginList.js +5 -5
- package/src/prompts/promptAssembly.js +3 -38
- package/src/prompts/skillList.js +1 -1
- package/src/prompts/system.js +0 -1
- package/src/ui/AskQuestion.js +20 -3
- package/src/ui/InputBox.js +70 -3
- package/src/ui/hooks/useChat.js +13 -0
- package/workflows/adaptive-research.yaml +4 -3
- package/workflows/book-review-short.yaml +5 -3
- package/workflows/e2e-write-greet.yaml +3 -2
- package/workflows/plan.yaml +219 -168
- package/workflows/ralph-loop.yaml +169 -0
- package/workflows/youtube-shorts.yaml +8 -5
- package/plugins/HOW-TO-WRITE-A-PLUGIN.md +0 -186
- package/plugins/ralph-wiggum/.claude-plugin/plugin.json +0 -9
- package/plugins/ralph-wiggum/README.md +0 -197
- package/plugins/ralph-wiggum/commands/cancel-ralph.md +0 -18
- package/plugins/ralph-wiggum/commands/help.md +0 -137
- package/plugins/ralph-wiggum/commands/ralph-loop.md +0 -85
- package/plugins/ralph-wiggum/hooks/hooks.json +0 -15
- package/plugins/ralph-wiggum/hooks/stop-hook.sh +0 -191
- package/plugins/ralph-wiggum/plugin.js +0 -280
- package/plugins/ralph-wiggum/src/goalState.js +0 -258
- package/plugins/ralph-wiggum/src/sentinels.js +0 -76
- package/plugins/ralph-wiggum/src/stopHookRunner.js +0 -104
- package/plugins/ralph-wiggum/src/verificationGate.js +0 -202
- package/plugins/workflow-runner/src/miniReAct.js +0 -223
package/src/ui/InputBox.js
CHANGED
|
@@ -21,6 +21,26 @@ import { Box, Text, useApp, useInput } from 'ink';
|
|
|
21
21
|
import { useTextBuffer } from './hooks/useTextBuffer.js';
|
|
22
22
|
import { usePasteHandler } from './hooks/usePasteHandler.js';
|
|
23
23
|
import { useInputHistory } from './hooks/useInputHistory.js';
|
|
24
|
+
// ============================================================
|
|
25
|
+
// IME 启发式(中文输入法防护)
|
|
26
|
+
// ------------------------------------------------------------
|
|
27
|
+
// Ink 5.0.1 的 useInput(基于 readline)不暴露 composition event,
|
|
28
|
+
// 无法原生支持 IME 状态机。本启发式做"最小可行"的兜底:
|
|
29
|
+
// 1. 跟踪"短时间内连续插入"——IME 拼音→候选→提交过程中会产生
|
|
30
|
+
// 一连串短间隔字符(pinyin 字母 + 单字 commit)
|
|
31
|
+
// 2. 检测到 burst 后,**短时间窗口内**把 Enter 视为"IME 确认"
|
|
32
|
+
// 而非"提交"(避免候选窗按 Enter 时把半截拼音+候选字提交)
|
|
33
|
+
// 3. 不试图拦截或过滤 IME 字符——那是终端的活,拦了反而破坏
|
|
34
|
+
//
|
|
35
|
+
// 调参依据:微软拼音/搜狗拼音的 commit 节奏典型 < 100ms/char,
|
|
36
|
+
// 而人手打英文 ≥ 200ms/char。500ms idle 视作 IME 结束。
|
|
37
|
+
//
|
|
38
|
+
// 注意:这是 best-effort,**不能 100% 解决 IME 问题**。
|
|
39
|
+
// 终态方案是换掉 Ink 底层走 use-stdin 的 raw mode。
|
|
40
|
+
// ============================================================
|
|
41
|
+
const IME_BURST_GAP_MS = 200; // 字符间隔 < 此值视作 IME 连续输入
|
|
42
|
+
const IME_BURST_MIN_COUNT = 3; // 连续 N 个字符才触发 IME 锁定
|
|
43
|
+
const IME_LOCKOUT_MS = 500; // 触发后禁 Enter 提交的窗口
|
|
24
44
|
function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
|
|
25
45
|
const buf = useTextBuffer();
|
|
26
46
|
const hist = useInputHistory();
|
|
@@ -34,6 +54,30 @@ function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
|
|
|
34
54
|
// ✅ Delete 专用去重:只防止 Windows 双事件,不影响其他键
|
|
35
55
|
const lastDeleteTime = useRef(0);
|
|
36
56
|
const DELETE_DEBOUNCE_MS = 20; // 仅 Delete 键用极短防抖
|
|
57
|
+
// ✅ IME 启发式:跟踪字符插入节奏,检测 IME 草稿期间
|
|
58
|
+
// imeBurstRef: { lastAt: 上次插入 ms, count: 当前 burst 内插入数, lastInsertEnd: 上次 IME 锁定结束 ms }
|
|
59
|
+
const imeBurstRef = useRef({
|
|
60
|
+
lastAt: 0,
|
|
61
|
+
count: 0,
|
|
62
|
+
lockoutUntil: 0,
|
|
63
|
+
});
|
|
64
|
+
/** 把"刚插入了非空非控制字符"事件喂给 IME 检测器 */
|
|
65
|
+
const noteTextInsert = useCallback((textLen) => {
|
|
66
|
+
if (textLen <= 0)
|
|
67
|
+
return;
|
|
68
|
+
const now = Date.now();
|
|
69
|
+
const s = imeBurstRef.current;
|
|
70
|
+
if (now - s.lastAt < IME_BURST_GAP_MS) {
|
|
71
|
+
s.count++;
|
|
72
|
+
if (s.count >= IME_BURST_MIN_COUNT) {
|
|
73
|
+
s.lockoutUntil = now + IME_LOCKOUT_MS;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
s.count = 1;
|
|
78
|
+
}
|
|
79
|
+
s.lastAt = now;
|
|
80
|
+
}, []);
|
|
37
81
|
const forceRefresh = useCallback(() => {
|
|
38
82
|
setRefreshCounter((c) => c + 1);
|
|
39
83
|
}, []);
|
|
@@ -116,8 +160,16 @@ function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
|
|
|
116
160
|
}
|
|
117
161
|
// ---- ESC ----
|
|
118
162
|
if (key.escape) {
|
|
119
|
-
if (disabled)
|
|
120
|
-
onAbort
|
|
163
|
+
if (disabled) {
|
|
164
|
+
// try/catch 防 onAbort 异常冒泡到 Ink 渲染层(abort handler 多在 useChat 里,
|
|
165
|
+
// 内部若 throw 会黑屏;吞掉仅 stderr 注记)
|
|
166
|
+
try {
|
|
167
|
+
onAbort();
|
|
168
|
+
}
|
|
169
|
+
catch (e) {
|
|
170
|
+
console.error('[InputBox] onAbort threw:', e);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
121
173
|
return;
|
|
122
174
|
}
|
|
123
175
|
// ---- ✅ Ctrl+R 进入反向搜索(仅在空 buf + 非 disabled)----
|
|
@@ -135,7 +187,13 @@ function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
|
|
|
135
187
|
return;
|
|
136
188
|
}
|
|
137
189
|
if (disabled) {
|
|
138
|
-
onAbort
|
|
190
|
+
// 同 ESC 路径,try/catch 防 onAbort 异常冒泡到 Ink 渲染层
|
|
191
|
+
try {
|
|
192
|
+
onAbort();
|
|
193
|
+
}
|
|
194
|
+
catch (e) {
|
|
195
|
+
console.error('[InputBox] onAbort threw:', e);
|
|
196
|
+
}
|
|
139
197
|
return;
|
|
140
198
|
}
|
|
141
199
|
ctrlCCountRef.current++;
|
|
@@ -152,7 +210,15 @@ function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
|
|
|
152
210
|
// - Alt+Enter(Mac: Option+Enter):返回 'enter-newline' → 上面已处理为**插入换行**
|
|
153
211
|
// - Ctrl+Enter:返回 'continue' → 这里也执行**强制发送**
|
|
154
212
|
// - 粘贴期间 + Enter:返回 'enter-in-paste' → **忽略**(防误发)
|
|
213
|
+
// - IME 草稿期间 + Enter:视为 IME 确认而非提交(启发式,见 IME_BURST_* 常量)
|
|
155
214
|
if (key.return) {
|
|
215
|
+
const now = Date.now();
|
|
216
|
+
if (now < imeBurstRef.current.lockoutUntil) {
|
|
217
|
+
// IME 候选窗按 Enter → 走换行而非提交(pinyin 候选确认不打断草稿)
|
|
218
|
+
buf.insert('\n');
|
|
219
|
+
forceRefresh();
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
156
222
|
const text = buf.state.text.trim();
|
|
157
223
|
if (text.length === 0)
|
|
158
224
|
return;
|
|
@@ -290,6 +356,7 @@ function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
|
|
|
290
356
|
// (否则 layout 永远 1 行 → ↑/↓ 失效、输入框不长高,光标只能左右)。
|
|
291
357
|
if (input && !key.meta) {
|
|
292
358
|
const normalized = input.replace(/\r\n?/g, '\n');
|
|
359
|
+
noteTextInsert(normalized.length);
|
|
293
360
|
buf.insert(normalized);
|
|
294
361
|
forceRefresh();
|
|
295
362
|
}
|
package/src/ui/hooks/useChat.js
CHANGED
|
@@ -274,6 +274,12 @@ export function useChat(args) {
|
|
|
274
274
|
const ac = new AbortController();
|
|
275
275
|
abortRef.current = ac;
|
|
276
276
|
dlog('ui', 'turn START', { input: trimmed.slice(0, 80) });
|
|
277
|
+
// 长时间运行时(如工作流 agent 步骤)的定时 token 刷新:
|
|
278
|
+
// runQuery 的 text/reasoning 事件不触发 bump,导致 StatusLine token 数
|
|
279
|
+
// 可能冻结数十秒。此定时器每 10s 强制刷新一次,确保用户看到上下文增长。
|
|
280
|
+
const tokenRefreshTimer = setInterval(() => {
|
|
281
|
+
bump();
|
|
282
|
+
}, 10_000);
|
|
277
283
|
try {
|
|
278
284
|
for await (const ev of runWithPlugins(trimmed, {
|
|
279
285
|
provider: args.provider,
|
|
@@ -311,6 +317,7 @@ export function useChat(args) {
|
|
|
311
317
|
}
|
|
312
318
|
finally {
|
|
313
319
|
dlog('ui', 'turn END (finally)');
|
|
320
|
+
clearInterval(tokenRefreshTimer);
|
|
314
321
|
setIsLoading(false);
|
|
315
322
|
cancelAllThrottles();
|
|
316
323
|
resetTurnState();
|
|
@@ -532,18 +539,24 @@ export function handleEvent(ev, setters) {
|
|
|
532
539
|
switch (wf.type) {
|
|
533
540
|
case 'workflow_start':
|
|
534
541
|
setters.emitProgressLine?.(`▶ 工作流 ${wf.name} 开始(共 ${wf.totalSteps} 步)`);
|
|
542
|
+
// 工作流开始:立即刷新 token(可能已积累大量前置对话上下文)
|
|
543
|
+
setters.bump();
|
|
535
544
|
return;
|
|
536
545
|
case 'workflow_step_start':
|
|
537
546
|
setters.emitProgressLine?.(` ▶ ${(wf.index ?? 0) + 1}/${wf.total ?? '?'} ${wf.id} (${wf.kind})`);
|
|
538
547
|
return;
|
|
539
548
|
case 'workflow_step_end':
|
|
540
549
|
setters.emitProgressLine?.(` ${wf.ok ? '✓' : '✗'} ${wf.id}${wf.error ? `:${wf.error}` : ''}`);
|
|
550
|
+
// 步骤完成:强制刷新 token(agent/llm 步骤可能写入大量上下文)
|
|
551
|
+
setters.bump();
|
|
541
552
|
return;
|
|
542
553
|
case 'workflow_step_skipped':
|
|
543
554
|
setters.emitProgressLine?.(` ⊘ ${wf.id}:${wf.reason ?? ''}`);
|
|
544
555
|
return;
|
|
545
556
|
case 'workflow_done':
|
|
546
557
|
setters.emitProgressLine?.(`✓ 工作流 ${wf.name} 完成`);
|
|
558
|
+
// 工作流结束:最终刷新(反映完整执行后的上下文量)
|
|
559
|
+
setters.bump();
|
|
547
560
|
return;
|
|
548
561
|
}
|
|
549
562
|
// 收口到 LoopEvent:未识别的 PluginEvent type 走 default no-op
|
|
@@ -35,8 +35,9 @@ steps:
|
|
|
35
35
|
capture:
|
|
36
36
|
content: line_report
|
|
37
37
|
|
|
38
|
-
# 3. 守门 assert
|
|
38
|
+
# 3. 守门 verify(升级自 assert,享受 verify 的 file_exists 检查器)
|
|
39
39
|
- id: verify
|
|
40
|
-
type:
|
|
41
|
-
|
|
40
|
+
type: verify
|
|
41
|
+
checks:
|
|
42
|
+
- 'file_exists:./out/notes.md'
|
|
42
43
|
onFail: "调研笔记 ./out/notes.md 未生成,检查 research 步"
|
|
@@ -92,8 +92,10 @@ steps:
|
|
|
92
92
|
"thumbnail_prompt": "${thumb_prompt}"
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
# 7. 守门 assert
|
|
95
|
+
# 7. 守门 verify(升级自 assert;多条 file_exists 拆成 checks 数组)
|
|
96
96
|
- id: verify
|
|
97
|
-
type:
|
|
98
|
-
|
|
97
|
+
type: verify
|
|
98
|
+
checks:
|
|
99
|
+
- 'file_exists:videos/${inputs.book}/script.txt'
|
|
100
|
+
- 'file_exists:videos/${inputs.book}/meta.json'
|
|
99
101
|
onFail: "脚本或 meta 未写盘,请检查 Write 工具"
|
|
@@ -17,8 +17,9 @@ steps:
|
|
|
17
17
|
args.content: note_body
|
|
18
18
|
|
|
19
19
|
- id: verify_file
|
|
20
|
-
type:
|
|
21
|
-
|
|
20
|
+
type: verify
|
|
21
|
+
checks:
|
|
22
|
+
- 'file_exists:out/${inputs.topic}/note.txt'
|
|
22
23
|
onFail: "note.txt 未落盘"
|
|
23
24
|
|
|
24
25
|
- id: verify_capture
|
package/workflows/plan.yaml
CHANGED
|
@@ -1,189 +1,240 @@
|
|
|
1
|
-
#
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
|
|
13
|
-
# Summary : exit_summary(llm 退出摘要)
|
|
14
|
-
# ------------------------------------------------------------
|
|
15
|
-
# 提问策略:本工作流**零交互**。计划深度从用户 goal 自动推断:
|
|
16
|
-
# - 目标含"概览/快速/简单/简短" → 快速概览
|
|
17
|
-
# - 目标含"详细/完整/分步/彻底/带风险" → 带风险回滚评估
|
|
18
|
-
# - 其他 → 详细分步(默认推荐)
|
|
19
|
-
# 不询问用户选择深度——自行判断。
|
|
20
|
-
# ------------------------------------------------------------
|
|
21
|
-
# 注:critic 用 skill: 节点 dogfood 仓库自带的 adversarial-review skill。
|
|
22
|
-
# skill 双源查找(cwd 优先、packageRoot fallback);异地 cwd 缺该 skill 时
|
|
23
|
-
# critic 的 onError:continue 兜底——审稿出岔不应推翻已写好的计划。
|
|
24
|
-
# ============================================================
|
|
1
|
+
# workflows/plan.yaml —— Plan 模式工作流
|
|
2
|
+
#
|
|
3
|
+
# 架构参考: Claude Code Plan Mode (commands/plan/plan.tsx)
|
|
4
|
+
# 适配差异:
|
|
5
|
+
# - Claude Code 用多 sub-agent(Explore/Plan/Verification) 并行
|
|
6
|
+
# - 我们用单 TAOR 引擎 + 不同 prompt 角色扮演(共享 history 更自然)
|
|
7
|
+
# - Claude Code 有权限系统只读约束(EnterPlanMode/ExitPlanMode)
|
|
8
|
+
# - 我们通过 agent prompt 约束 + artifacts 声明达到类似效果
|
|
9
|
+
#
|
|
10
|
+
# 断点续执行: 由 runner 层自动处理(taskIdentity + checkpoint + capture 回放)
|
|
11
|
+
# 自愈: 由 runner 的 self_heal.backoff + 内部 retry 循环控制
|
|
12
|
+
|
|
25
13
|
name: plan
|
|
26
|
-
description:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
→ Critic(反向提问审稿追加) → Gate(assert 守门) → Execute(按计划执行) → Summary(退出摘要)。
|
|
30
|
-
version: "0.4"
|
|
14
|
+
description: >
|
|
15
|
+
Plan 模式:探索→设计→审查→写计划→等审批→执行。
|
|
16
|
+
5 阶段流水线,参考 Claude Code plan mode 的 Phase 1-5。
|
|
31
17
|
|
|
32
18
|
inputs:
|
|
33
19
|
- name: goal
|
|
34
20
|
type: string
|
|
35
21
|
required: true
|
|
36
|
-
description:
|
|
22
|
+
description: 用户想要实现的目标
|
|
23
|
+
|
|
24
|
+
self_heal:
|
|
25
|
+
backoff: 1 # step N 失败 → 回退 N 步重跑(覆盖可能有问题的产出)
|
|
26
|
+
max_retries: 2 # 每个步骤内部 retry 上限
|
|
27
|
+
|
|
28
|
+
artifacts:
|
|
29
|
+
- PLAN.md # 核心产出:实现计划文档
|
|
37
30
|
|
|
38
31
|
steps:
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
|
|
32
|
+
# ================================================================
|
|
33
|
+
# Phase 1: Initial Understanding —— 理解需求
|
|
34
|
+
# ================================================================
|
|
35
|
+
- id: gathering
|
|
42
36
|
agent: |
|
|
43
|
-
|
|
44
|
-
(不要写文件、不要执行副作用命令)摸清现状,整理出 3-6 条候选关键事实
|
|
45
|
-
以及 1-3 个仍未决 / 需用户拍板的点,用简洁中文 markdown 列点返回。
|
|
46
|
-
allowed_tools: [Read, Grep, Glob]
|
|
47
|
-
capture:
|
|
48
|
-
content: analysis
|
|
49
|
-
|
|
50
|
-
# [Analyze-2] 固化成可验证 claims:llm 单轮 + output_schema(provider 不支持时由 client.ts 自动退化)
|
|
51
|
-
- id: extract_findings
|
|
52
|
-
llm: |
|
|
53
|
-
从下面的调研笔记中抽取「候选关键事实」与「未决问题」,原样保留信息、不要新增臆测。
|
|
54
|
-
调研笔记:
|
|
55
|
-
${analysis}
|
|
56
|
-
output_schema:
|
|
57
|
-
type: object
|
|
58
|
-
additionalProperties: false
|
|
59
|
-
required: [findings, open_questions]
|
|
60
|
-
properties:
|
|
61
|
-
findings:
|
|
62
|
-
type: array
|
|
63
|
-
items: { type: string }
|
|
64
|
-
description: "每条独立成句的候选关键事实(便于逐条对抗验证)"
|
|
65
|
-
open_questions:
|
|
66
|
-
type: array
|
|
67
|
-
items: { type: string }
|
|
68
|
-
description: "仍需进一步验证 / 用户拍板的点"
|
|
69
|
-
capture:
|
|
70
|
-
findings: findings
|
|
71
|
-
open_questions: open_questions
|
|
72
|
-
|
|
73
|
-
# ===================== Verify =====================
|
|
74
|
-
# [Verify] 红队对抗:vote 对每条 finding 反向提问证伪(voter 默认倾向 refuted=true);
|
|
75
|
-
# 存活集可能偏少甚至为空,draft 对此 graceful degrade(见其提示)。
|
|
76
|
-
- id: verify_findings
|
|
77
|
-
type: vote
|
|
78
|
-
input: "findings"
|
|
79
|
-
voters_count: 3
|
|
80
|
-
threshold: 2
|
|
81
|
-
rules: |
|
|
82
|
-
判断这条「调研结论」是否站得住脚。不要问"它对不对",要问"它哪里是错的":
|
|
83
|
-
是否证据不足、把假设当事实、想当然、会被反例或现有代码/资料推翻。
|
|
84
|
-
只有当你找不到任何合理反驳、且它确有依据时,才认定成立(refuted=false)。
|
|
85
|
-
capture:
|
|
86
|
-
survived: verified_findings
|
|
87
|
-
kept: kept_count
|
|
88
|
-
total: total_count
|
|
89
|
-
|
|
90
|
-
# ===================== Synthesize =====================
|
|
91
|
-
# [Synthesize-1] 生成计划正文:llm 纯文本(不开工具、不提问)——确定性、跨模型稳,
|
|
92
|
-
# 彻底避开"agent 反复调 Write"的弱模型死循环。
|
|
93
|
-
- id: draft_plan
|
|
94
|
-
llm: |
|
|
95
|
-
综合下列输入,为目标「${inputs.goal}」写一份**中文实现计划的完整 markdown 正文**
|
|
96
|
-
(直接输出正文本身:不要寒暄、不要复述要求、不要用代码围栏包裹整篇)。
|
|
37
|
+
你是一名资深的需求分析师。用户的目标是:「${inputs.goal}」
|
|
97
38
|
|
|
98
|
-
|
|
99
|
-
|
|
39
|
+
请收集实现这个目标所需的关键信息:
|
|
40
|
+
1. 目标的具体范围和边界条件
|
|
41
|
+
2. 技术约束(语言、框架、兼容性要求)
|
|
42
|
+
3. 质量要求(性能、安全、可维护性)
|
|
43
|
+
4. 优先级排序(如果涉及多个子目标)
|
|
100
44
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
## 计划详细程度(自动推断,不询问用户)
|
|
105
|
-
根据用户目标「${inputs.goal}」中的关键词自动判断:
|
|
106
|
-
- 如果目标包含"概览"、"快速"、"简单"、"简短"、"简要"、"大致"等词 → 输出快速概览(高层方向与关键决策,不展开到每一步)
|
|
107
|
-
- 如果目标包含"详细"、"完整"、"分步"、"彻底"、"风险"、"回滚"、"全面"等词 → 输出带风险/回滚评估的详细计划
|
|
108
|
-
- 其他情况 → 默认输出**详细分步**计划(可执行的有序步骤,每步说清动作、涉及文件与验收点)
|
|
45
|
+
如果信息不足,使用 AskUserQuestion 工具向用户提问。
|
|
46
|
+
如果已有足够信息(从上下文或目标描述中能推断),直接输出分析结果。
|
|
109
47
|
|
|
110
48
|
要求:
|
|
111
|
-
-
|
|
112
|
-
-
|
|
113
|
-
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
#
|
|
119
|
-
#
|
|
120
|
-
- id:
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
49
|
+
- 不要过度提问,对不确定的点做合理默认假设并继续
|
|
50
|
+
- 在正文开头用「## 假设」一节列出假设
|
|
51
|
+
- 最终输出结构化的需求分析(3-8 条要点)
|
|
52
|
+
capture: requirements
|
|
53
|
+
max_retries: 1
|
|
54
|
+
|
|
55
|
+
# ================================================================
|
|
56
|
+
# Phase 2: Research —— 探索代码库
|
|
57
|
+
# ================================================================
|
|
58
|
+
- id: research
|
|
59
|
+
agent: |
|
|
60
|
+
你是一名资深工程师,负责研究现有代码库以支撑「${inputs.goal}」的实现。
|
|
61
|
+
|
|
62
|
+
已知需求分析:
|
|
63
|
+
${requirements}
|
|
64
|
+
|
|
65
|
+
请执行以下探索(并行使用 Read/Grep/Glob/RunCommand):
|
|
66
|
+
1. 定位所有相关的源代码文件(列出路径和关键行号)
|
|
67
|
+
2. 理解现有架构和数据流(文字描述)
|
|
68
|
+
3. 找到可复用的模式和函数(格式:函数名 @ file:line — 用途)
|
|
69
|
+
4. 识别潜在的技术风险和外部依赖
|
|
70
|
+
|
|
71
|
+
输出格式:
|
|
72
|
+
## 代码探索报告
|
|
73
|
+
### 相关文件
|
|
74
|
+
### 现有架构概要
|
|
75
|
+
### 可复用资源
|
|
76
|
+
### 风险与依赖
|
|
77
|
+
capture: research_report
|
|
78
|
+
max_retries: 1
|
|
79
|
+
|
|
80
|
+
# ================================================================
|
|
81
|
+
# Phase 3: Design —— 设计方案
|
|
82
|
+
# ================================================================
|
|
83
|
+
- id: design
|
|
84
|
+
agent: |
|
|
85
|
+
你是一名软件架构师。基于以下输入设计实现方案:
|
|
86
|
+
|
|
87
|
+
## 用户目标
|
|
88
|
+
${inputs.goal}
|
|
89
|
+
|
|
90
|
+
## 需求分析
|
|
91
|
+
${requirements}
|
|
92
|
+
|
|
93
|
+
## 代码探索报告
|
|
94
|
+
${research_report}
|
|
95
|
+
|
|
96
|
+
请输出完整设计方案:
|
|
97
|
+
|
|
98
|
+
### 1. 整体架构
|
|
99
|
+
(文字描述 + 关键决策及理由)
|
|
100
|
+
|
|
101
|
+
### 2. 文件变更清单
|
|
102
|
+
每个要修改/新建的文件一行:
|
|
103
|
+
- `path/to/file.ts` — 操作类型(new/edit/delete) — 具体改什么
|
|
104
|
+
|
|
105
|
+
### 3. 详细变更
|
|
106
|
+
对每个文件的变更给出具体内容概要(函数签名、数据结构、逻辑流)
|
|
107
|
+
|
|
108
|
+
### 4. 数据流和接口
|
|
109
|
+
(模块间调用关系、新增/变更的接口)
|
|
110
|
+
|
|
111
|
+
### 5. 验证方式
|
|
112
|
+
编译命令 + 测试命令 + 手动检查项
|
|
113
|
+
capture: design_doc
|
|
114
|
+
max_retries: 1
|
|
115
|
+
|
|
116
|
+
# ================================================================
|
|
117
|
+
# Phase 4: Review —— 对抗性审查
|
|
118
|
+
# ================================================================
|
|
119
|
+
- id: review
|
|
136
120
|
skill: adversarial-review
|
|
137
|
-
maxTurns: 25
|
|
138
121
|
input: |
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
#
|
|
146
|
-
#
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
122
|
+
待审查的设计方案:
|
|
123
|
+
${design_doc}
|
|
124
|
+
用户原始目标:${inputs.goal}
|
|
125
|
+
capture: review_notes
|
|
126
|
+
max_retries: 1
|
|
127
|
+
|
|
128
|
+
# ================================================================
|
|
129
|
+
# Phase 4.5: Revise —— 根据审查修订
|
|
130
|
+
# ================================================================
|
|
131
|
+
- id: revise
|
|
132
|
+
agent: |
|
|
133
|
+
你是一名资深工程师。设计方案刚经过对抗性审查,审稿意见如下:
|
|
134
|
+
|
|
135
|
+
${review_notes}
|
|
136
|
+
|
|
137
|
+
原始设计方案:
|
|
138
|
+
${design_doc}
|
|
139
|
+
|
|
140
|
+
请根据审稿意见修订方案:
|
|
141
|
+
- 对每个真实问题给出具体修复方案
|
|
142
|
+
- 对误报(审稿意见不合理的地方)说明为什么不改
|
|
143
|
+
- 输出最终版设计方案(完整文档,不是 patch)
|
|
144
|
+
- 保持与原设计方案相同的结构
|
|
145
|
+
capture: revised_design
|
|
146
|
+
max_retries: 1
|
|
147
|
+
|
|
148
|
+
# ================================================================
|
|
149
|
+
# Phase 5: Draft Plan —— 生成计划文档(核心产出)
|
|
150
|
+
# ================================================================
|
|
151
|
+
- id: draft_plan
|
|
152
|
+
agent: |
|
|
153
|
+
你是一名资深工程师,负责把最终设计方案写成可执行的实现计划。
|
|
154
|
+
|
|
155
|
+
## 用户目标
|
|
156
|
+
${inputs.goal}
|
|
157
|
+
|
|
158
|
+
## 最终设计方案
|
|
159
|
+
${revised_design}
|
|
160
|
+
|
|
161
|
+
请将计划写入 ./PLAN.md,内容必须包含:
|
|
162
|
+
|
|
163
|
+
# 实现计划:{goal 的简短摘要}
|
|
164
|
+
|
|
165
|
+
## 假设(如需调整请告知)
|
|
166
|
+
(列出所有默认假设,每条一行)
|
|
167
|
+
|
|
168
|
+
## 实现步骤
|
|
169
|
+
### Step 1: {标题}
|
|
170
|
+
- **文件**: path/to/file.ts
|
|
171
|
+
- **操作**: 具体改什么(精确到函数/行级别)
|
|
172
|
+
- **理由**: 为什么这么改
|
|
173
|
+
|
|
174
|
+
(每个要修改的文件一个 Step,按依赖顺序排列)
|
|
175
|
+
|
|
176
|
+
## 验证命令
|
|
177
|
+
\`\`\`bash
|
|
178
|
+
# 编译检查命令
|
|
179
|
+
# 测试运行命令
|
|
180
|
+
\`\`\`
|
|
181
|
+
|
|
182
|
+
## 产出物清单
|
|
183
|
+
- [ ] 文件 A
|
|
184
|
+
- [ ] 文件 B
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
**硬约束**:
|
|
188
|
+
① 绝对不要输出思考过程标签
|
|
189
|
+
② 绝对不要输出 JSON tool_call 原文
|
|
190
|
+
③ 必须是可直接执行的实现计划(不是审查意见、不是问题列表)
|
|
191
|
+
④ "存活结论"为空时按常识给出合理的计划骨架
|
|
192
|
+
⑤ 凡需拍板但未询问的点自行假设并继续,不中断
|
|
193
|
+
artifacts:
|
|
194
|
+
- PLAN.md
|
|
195
|
+
max_retries: 1
|
|
196
|
+
|
|
197
|
+
# ================================================================
|
|
198
|
+
# Phase 5.5: User Review —— 用户审批(交互模式)/ 自动通过(非交互)
|
|
199
|
+
# ================================================================
|
|
200
|
+
- id: user_review
|
|
201
|
+
type: pause
|
|
202
|
+
pause:
|
|
203
|
+
message: |
|
|
204
|
+
📋 计划已生成:./PLAN.md
|
|
205
|
+
请review后回复"继续"开始执行,或提出修改意见。
|
|
206
|
+
(非交互模式将自动跳过此步骤)
|
|
207
|
+
max_retries: 1
|
|
208
|
+
|
|
209
|
+
# ================================================================
|
|
210
|
+
# Phase 6: Execute Plan —— 执行实现
|
|
211
|
+
# ================================================================
|
|
156
212
|
- id: execute_plan
|
|
157
213
|
agent: |
|
|
158
|
-
|
|
214
|
+
你是一名资深工程师,负责执行一份已经过工作流验证的实现计划。
|
|
159
215
|
请先 Read ./PLAN.md 了解完整计划内容和步骤。
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
216
|
+
|
|
217
|
+
重要说明:
|
|
218
|
+
- PLAN.md 可能包含审稿意见章节(以"## 审稿意见"或"## 对抗审查结果"开头),
|
|
219
|
+
那是反向提问审查的输出,不是计划本身。请聚焦于计划正文部分提取实际任务步骤。
|
|
220
|
+
- 如果计划正文质量不佳或格式异常,请根据目标「${inputs.goal}」
|
|
221
|
+
自行推断合理的执行方案并继续推进。
|
|
222
|
+
|
|
223
|
+
执行要求:
|
|
224
|
+
1. 如果计划中提到使用某个 skill(如 pptx/pdf/docx),先用 Read 读取对应 SKILL.md 了解用法
|
|
163
225
|
2. 每完成一个主要步骤后简要汇报进度
|
|
164
226
|
3. 如果遇到计划中未预见的情况,自行判断合理方案并继续(不要中断等待)
|
|
165
227
|
4. 全部完成后用一两句话总结产出物位置和内容
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
执行结果:${execution_result}
|
|
180
|
-
|
|
181
|
-
请用简洁中文写一段最终摘要(3-5句话),包含:
|
|
182
|
-
1. 完成了什么
|
|
183
|
-
2. 最终产物路径(文件名和目录)
|
|
184
|
-
3. 如有后续建议也简短提及
|
|
185
|
-
|
|
186
|
-
直接输出摘要正文,不要寒暄。
|
|
187
|
-
${execution_result ? `执行结果:${execution_result}` : '(执行步骤未产出详细结果)'}
|
|
188
|
-
capture:
|
|
189
|
-
text: summary_text
|
|
228
|
+
5. 绝不要输出 __AGENT_GIVEUP__ —— 即使计划不完美也要尽力达成目标
|
|
229
|
+
max_retries: 2
|
|
230
|
+
|
|
231
|
+
# ================================================================
|
|
232
|
+
# Phase 7: Summary —— 总结
|
|
233
|
+
# ================================================================
|
|
234
|
+
- id: summary
|
|
235
|
+
agent: |
|
|
236
|
+
工作流已全部完成。请简要总结:
|
|
237
|
+
1. 产出物位置和内容(文件路径 + 一句话描述)
|
|
238
|
+
2. 是否有遗留问题需要用户关注
|
|
239
|
+
3. 验证结果(测试是否通过、编译是否成功)
|
|
240
|
+
max_retries: 1
|