@yeaft/webchat-agent 0.1.972 → 0.1.974
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/package.json +1 -1
- package/yeaft/dream/apply.js +2 -2
- package/yeaft/dream/prompts/create.md +19 -2
- package/yeaft/dream/prompts/extract-session.md +49 -47
- package/yeaft/dream/prompts/extract-topic.md +46 -50
- package/yeaft/dream/prompts/extract-user.md +56 -45
- package/yeaft/dream/prompts/extract-vp.md +49 -47
- package/yeaft/dream/prompts/index.js +19 -1
- package/yeaft/dream/prompts/summarize-scope.md +34 -25
- package/yeaft/dream/prompts/triage-pass1.md +25 -2
- package/yeaft/dream/prompts/triage-pass2.md +18 -0
- package/yeaft/dream/prompts/update.md +38 -2
- package/yeaft/dream/triage.js +2 -2
- package/yeaft/prompts.js +255 -118
- package/yeaft/sub-agent/liveness.js +34 -0
- package/yeaft/sub-agent/notifications.js +16 -15
- package/yeaft/sub-agent/runner.js +56 -2
- package/yeaft/templates/base.md +44 -96
- package/yeaft/templates/common-rules.md +68 -82
- package/yeaft/templates/harness/router-shape.md +31 -32
- package/yeaft/templates/harness/worker-shape.md +23 -22
- package/yeaft/templates/identity-yeaft.md +4 -4
- package/yeaft/templates/mode-unified.md +10 -48
- package/yeaft/templates/personas/explorer.md +23 -4
- package/yeaft/templates/personas/implementer.md +23 -4
- package/yeaft/templates/personas/researcher.md +25 -6
- package/yeaft/templates/personas/reviewer.md +23 -4
- package/yeaft/templates/plan-instruction.md +40 -44
- package/yeaft/tools/agent.js +19 -16
- package/yeaft/tools/list-agents.js +14 -5
- package/yeaft/tools/wait-agent.js +27 -14
- package/yeaft/vp/seed-defaults.js +498 -24
- package/yeaft/vp/seed-topup.js +81 -5
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
<!-- lang:en -->
|
|
2
|
+
You are deciding whether a recent session conversation carries:
|
|
2
3
|
- signals that should update the USER profile, and/or
|
|
3
4
|
- signals that should update one or more TOPIC scopes.
|
|
4
5
|
|
|
5
|
-
Do NOT mention vp/,
|
|
6
|
+
Do NOT mention vp/, session/, feature/, or topic/ scopes — those are handled by hard rules.
|
|
6
7
|
|
|
7
8
|
Session: {{sessionId}}
|
|
8
9
|
|
|
@@ -18,3 +19,25 @@ Respond with strict JSON of the shape:
|
|
|
18
19
|
"topics": [ "<short category description>", ... ],
|
|
19
20
|
"trivial_only": boolean
|
|
20
21
|
}
|
|
22
|
+
|
|
23
|
+
<!-- lang:zh -->
|
|
24
|
+
你要判断最近一段 session 对话是否包含:
|
|
25
|
+
- 应更新 USER profile 的信号;和/或
|
|
26
|
+
- 应更新一个或多个 TOPIC scope 的信号。
|
|
27
|
+
|
|
28
|
+
不要提及 vp/、session/、feature/ 或 topic/ scope —— 这些由硬规则处理。
|
|
29
|
+
|
|
30
|
+
Session: {{sessionId}}
|
|
31
|
+
|
|
32
|
+
已有 topic scopes(path — summary):
|
|
33
|
+
{{topicSummaries}}
|
|
34
|
+
|
|
35
|
+
对话:
|
|
36
|
+
{{conversation}}
|
|
37
|
+
|
|
38
|
+
只回复严格 JSON,结构如下:
|
|
39
|
+
{
|
|
40
|
+
"user_profile_signals": boolean,
|
|
41
|
+
"topics": [ "<short category description>", ... ],
|
|
42
|
+
"trivial_only": boolean
|
|
43
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
<!-- lang:en -->
|
|
1
2
|
Bind a free-form topic description to an exact path under topic/.
|
|
2
3
|
Rules:
|
|
3
4
|
- At most TWO path segments. Reject any third level.
|
|
@@ -13,3 +14,20 @@ Reply with strict JSON, exactly one of:
|
|
|
13
14
|
{ "decision": "match", "path": "<existing path>" }
|
|
14
15
|
{ "decision": "new", "path": "<new ≤2-segment path>" }
|
|
15
16
|
{ "decision": "none" }
|
|
17
|
+
|
|
18
|
+
<!-- lang:zh -->
|
|
19
|
+
把一个自由描述的 topic 绑定到 topic/ 下的精确路径。
|
|
20
|
+
规则:
|
|
21
|
+
- 最多 TWO 个路径段。拒绝任何第三级路径。
|
|
22
|
+
- 路径段可包含字母、数字、短横线、下划线、点、CJK 字符。
|
|
23
|
+
- 如果描述适合已有路径,优先匹配已有路径。
|
|
24
|
+
|
|
25
|
+
描述:{{description}}
|
|
26
|
+
|
|
27
|
+
已有 topics:
|
|
28
|
+
{{existingTopics}}
|
|
29
|
+
|
|
30
|
+
只回复严格 JSON,且必须是以下三种之一:
|
|
31
|
+
{ "decision": "match", "path": "<existing path>" }
|
|
32
|
+
{ "decision": "new", "path": "<new ≤2-segment path>" }
|
|
33
|
+
{ "decision": "none" }
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
<!-- lang:en -->
|
|
1
2
|
You are updating an existing memory scope.
|
|
2
3
|
|
|
3
4
|
Scope: {{target}}
|
|
@@ -12,7 +13,7 @@ Current summary.md:
|
|
|
12
13
|
{{summaryMd}}
|
|
13
14
|
"""
|
|
14
15
|
|
|
15
|
-
Recent conversations:
|
|
16
|
+
Recent session conversations:
|
|
16
17
|
{{sources}}
|
|
17
18
|
|
|
18
19
|
Task:
|
|
@@ -25,9 +26,44 @@ Task:
|
|
|
25
26
|
|
|
26
27
|
Hard rules:
|
|
27
28
|
- Never read or reference any other scope's files.
|
|
28
|
-
- Never modify VP system
|
|
29
|
+
- Never modify VP system prompt, session charter, or user preferences.
|
|
29
30
|
- If something contradicts a charter, annotate with
|
|
30
31
|
"⚠️ contradicts charter — verify which is current" and continue.
|
|
31
32
|
|
|
32
33
|
Reply with strict JSON of the shape:
|
|
33
34
|
{ "memory_md": "...", "summary_md": "..." }
|
|
35
|
+
|
|
36
|
+
<!-- lang:zh -->
|
|
37
|
+
你正在更新一个已有的 memory scope。
|
|
38
|
+
|
|
39
|
+
Scope: {{target}}
|
|
40
|
+
{{batchHeader}}
|
|
41
|
+
当前 memory.md:
|
|
42
|
+
"""
|
|
43
|
+
{{memoryMd}}
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
当前 summary.md:
|
|
47
|
+
"""
|
|
48
|
+
{{summaryMd}}
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
最近的 session 对话:
|
|
52
|
+
{{sources}}
|
|
53
|
+
|
|
54
|
+
任务:
|
|
55
|
+
- 从这些对话中提取与 THIS scope 相关的内容。
|
|
56
|
+
- 将内容整合进 memory.md(必要时重组章节)。
|
|
57
|
+
- 删除过期或被推翻的条目。
|
|
58
|
+
- 重写 summary.md(1–3 句)。
|
|
59
|
+
- 同一批对话也会被处理到 OTHER scopes。
|
|
60
|
+
这里只处理与当前 scope 相关的内容,忽略其他内容。
|
|
61
|
+
|
|
62
|
+
硬规则:
|
|
63
|
+
- 不要读取或引用其他 scope 的文件。
|
|
64
|
+
- 不要修改 VP system prompt、session charter 或用户偏好。
|
|
65
|
+
- 如果某条内容与 charter 冲突,标注
|
|
66
|
+
"⚠️ contradicts charter — verify which is current" 并继续。
|
|
67
|
+
|
|
68
|
+
只回复严格 JSON,结构如下:
|
|
69
|
+
{ "memory_md": "...", "summary_md": "..." }
|
package/yeaft/dream/triage.js
CHANGED
|
@@ -41,8 +41,8 @@ import { render } from './prompts/index.js';
|
|
|
41
41
|
|
|
42
42
|
function triageSystem(language) {
|
|
43
43
|
return String(language || '').toLowerCase().startsWith('zh')
|
|
44
|
-
? '你是梦境流水线的 Triage
|
|
45
|
-
: 'You are the Triage stage of a dream pipeline that decides which scopes a recent
|
|
44
|
+
? '你是梦境流水线的 Triage 阶段,负责判断最近的 session 对话会影响哪些 scope。请只回复严格 JSON,不要输出说明文字或 markdown fence。自然语言内容使用中文;JSON key、scope 和枚举值保持英文。'
|
|
45
|
+
: 'You are the Triage stage of a dream pipeline that decides which scopes a recent session conversation should affect. Reply with strict JSON only — no prose, no markdown fences.';
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/**
|
package/yeaft/prompts.js
CHANGED
|
@@ -184,7 +184,7 @@ function getTemplate(key, language) {
|
|
|
184
184
|
* @returns {string}
|
|
185
185
|
*/
|
|
186
186
|
export function getDefaultPlanInstruction(language = 'en') {
|
|
187
|
-
return getTemplate('planInstruction', language);
|
|
187
|
+
return getTemplate('planInstruction', normalizePromptLanguage(language));
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
// ─── Prompt Templates (hardcoded fallbacks) ──────────────────────
|
|
@@ -197,15 +197,15 @@ const PROMPTS = {
|
|
|
197
197
|
tools: (names) => `Available tools: ${names}`,
|
|
198
198
|
// DESIGN-PROMPT §3 ④ — Active Scope header
|
|
199
199
|
activeScopeHeader: '## active_scope',
|
|
200
|
-
|
|
200
|
+
sessionAnnouncementHeader: '[Session Announcement]',
|
|
201
201
|
// Project-doc (CLAUDE.md / AGENTS.md) header + one-liner intro. Both
|
|
202
202
|
// filenames are recognized: CLAUDE.md is this project's convention,
|
|
203
203
|
// AGENTS.md is the cross-tool convention (Codex / OpenAI Codex CLI).
|
|
204
204
|
projectDocHeader: '[Project Doc]',
|
|
205
205
|
projectDocIntro:
|
|
206
|
-
'The user keeps project-level instructions and context in `CLAUDE.md` or `AGENTS.md` at the
|
|
206
|
+
'The user keeps project-level instructions and context in `CLAUDE.md` or `AGENTS.md` at the session working directory. Treat the content below as authoritative project context — coding conventions, task guidance, workflow rules, etc.',
|
|
207
207
|
vpPersonaIntro: (name, role) =>
|
|
208
|
-
`You
|
|
208
|
+
`You are ${name}${role ? `, ${role}` : ''}. Think, decide, and respond from ${name}'s perspective. Speak in the first person as ${name}; do not refer to yourself as "Yeaft" or as a generic AI assistant.`,
|
|
209
209
|
},
|
|
210
210
|
zh: {
|
|
211
211
|
identity: '你是 Yeaft,一个有用的 AI 助手。',
|
|
@@ -214,13 +214,13 @@ const PROMPTS = {
|
|
|
214
214
|
tools: (names) => `可用工具:${names}`,
|
|
215
215
|
// DESIGN-PROMPT §3 ④ — Active Scope header
|
|
216
216
|
activeScopeHeader: '## active_scope',
|
|
217
|
-
|
|
217
|
+
sessionAnnouncementHeader: '[会话公告]',
|
|
218
218
|
// 项目文档块:CLAUDE.md / AGENTS.md(与 Codex 通用命名兼容)。
|
|
219
219
|
projectDocHeader: '[项目文档]',
|
|
220
220
|
projectDocIntro:
|
|
221
|
-
'
|
|
221
|
+
'用户把项目级的说明和上下文记录在 session 工作目录下的 `CLAUDE.md` 或 `AGENTS.md` 中。下面的内容是权威的项目上下文 —— 编码规范、任务指导、工作流约定等,请遵循它来工作。',
|
|
222
222
|
vpPersonaIntro: (name, role) =>
|
|
223
|
-
|
|
223
|
+
`你是 ${name}${role ? `,${role}` : ''}。请以 ${name} 的思考方式理解问题、判断优先级并回答,并以 ${name} 的第一人称发言;不要自称 "Yeaft" 或泛指的 AI 助手。`,
|
|
224
224
|
},
|
|
225
225
|
};
|
|
226
226
|
|
|
@@ -327,8 +327,8 @@ export function buildSystemPrompt({
|
|
|
327
327
|
}
|
|
328
328
|
}
|
|
329
329
|
|
|
330
|
-
// ─── 1.4 Project Doc (CLAUDE.md / AGENTS.md from
|
|
331
|
-
// The
|
|
330
|
+
// ─── 1.4 Project Doc (CLAUDE.md / AGENTS.md from session workDir) ───
|
|
331
|
+
// The session working directory may contain a project-level
|
|
332
332
|
// instructions file. The engine resolves "newest of CLAUDE.md vs
|
|
333
333
|
// AGENTS.md by mtime" and threads the resulting text through here.
|
|
334
334
|
// Empty/whitespace = no block emitted. Sits ABOVE the announcement
|
|
@@ -348,23 +348,19 @@ export function buildSystemPrompt({
|
|
|
348
348
|
// instructions. Empty/whitespace = no block emitted.
|
|
349
349
|
const annText = (typeof sessionAnnouncement === 'string') ? sessionAnnouncement.trim() : '';
|
|
350
350
|
if (annText) {
|
|
351
|
-
parts.push(`${lang.
|
|
351
|
+
parts.push(`${lang.sessionAnnouncementHeader || '[Session Announcement]'}\n${annText}`);
|
|
352
352
|
}
|
|
353
353
|
|
|
354
354
|
// ─── 2. Date Metadata ──────────────────────────────────
|
|
355
355
|
parts.push(lang.date(new Date().toISOString().split('T')[0]));
|
|
356
356
|
|
|
357
357
|
// ─── 3. Mode-Specific Instructions ─────────────────────
|
|
358
|
-
//
|
|
359
|
-
//
|
|
358
|
+
// Normal operation intentionally has no extra mode block: the VP soul is the
|
|
359
|
+
// identity layer, and common rules/tool guidance define behavior. Dream keeps
|
|
360
|
+
// its dedicated mode prompt because it is a background memory-maintenance job.
|
|
360
361
|
if (mode === 'dream') {
|
|
361
362
|
const dreamTemplate = getTemplate('modeDream', effectiveLang);
|
|
362
363
|
parts.push(dreamTemplate || lang.dream);
|
|
363
|
-
} else {
|
|
364
|
-
const unifiedTemplate = getTemplate('modeUnified', effectiveLang);
|
|
365
|
-
if (unifiedTemplate) {
|
|
366
|
-
parts.push(unifiedTemplate);
|
|
367
|
-
}
|
|
368
364
|
}
|
|
369
365
|
|
|
370
366
|
// ─── 4. Tools + Tool Guidance ──────────────────────────
|
|
@@ -430,13 +426,11 @@ function renderVpPersona(vpPersona, lang, effectiveLang = 'en') {
|
|
|
430
426
|
const role = selectVpPersonaRole(vpPersona, effectiveLang);
|
|
431
427
|
const body = selectVpPersonaBody(vpPersona, effectiveLang);
|
|
432
428
|
|
|
433
|
-
//
|
|
434
|
-
//
|
|
435
|
-
//
|
|
436
|
-
//
|
|
437
|
-
|
|
438
|
-
const heading = role ? `# ${name} — ${role}` : `# ${name}`;
|
|
439
|
-
const lines = [heading, '', lang.vpPersonaIntro(name, role)];
|
|
429
|
+
// Persona is the IDENTITY layer (not an overlay). Do not prepend a
|
|
430
|
+
// generic assistant identity here: the VP soul body is the source of truth.
|
|
431
|
+
// `role` is intentionally not rendered as a second identity line; stock VPs
|
|
432
|
+
// carry bilingual, role-aware soul text in role.md.
|
|
433
|
+
const lines = [`# ${name}`, '', '## Soul'];
|
|
440
434
|
if (body) lines.push('', body);
|
|
441
435
|
return lines.join('\n');
|
|
442
436
|
}
|
|
@@ -456,40 +450,83 @@ function selectVpPersonaRole(vpPersona, effectiveLang) {
|
|
|
456
450
|
if (zhRole) return zhRole;
|
|
457
451
|
|
|
458
452
|
const role = typeof vpPersona.role === 'string' ? vpPersona.role.trim() : '';
|
|
459
|
-
return
|
|
453
|
+
return role;
|
|
460
454
|
}
|
|
461
455
|
return typeof vpPersona.role === 'string' ? vpPersona.role.trim() : '';
|
|
462
456
|
}
|
|
463
457
|
|
|
464
458
|
function selectVpPersonaBody(vpPersona, effectiveLang) {
|
|
465
459
|
const body = typeof vpPersona.persona === 'string' ? vpPersona.persona.trim() : '';
|
|
466
|
-
if (!body) return '';
|
|
467
460
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
461
|
+
// role.md persona is the canonical VP soul. If it is localized, select the
|
|
462
|
+
// requested language directly instead of generating a generic structured
|
|
463
|
+
// fallback from frontmatter traits.
|
|
464
|
+
if (body) {
|
|
465
|
+
if (body.includes('<!-- lang:')) {
|
|
466
|
+
const selected = extractExactLangSection(body, effectiveLang);
|
|
467
|
+
if (selected !== null) return selected;
|
|
468
|
+
return localizedDefaultPersonaBody(vpPersona, effectiveLang);
|
|
469
|
+
}
|
|
473
470
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
471
|
+
if (effectiveLang === 'zh') {
|
|
472
|
+
// role.md historically had one persisted persona body. Keep genuinely
|
|
473
|
+
// Chinese bodies, but do not glue English-only or lightly bilingual seeded
|
|
474
|
+
// personas under a Chinese wrapper. That is how "全能助手" ended up with a
|
|
475
|
+
// Chinese heading followed by a large English behavior contract.
|
|
476
|
+
if (isPrimarilyCjk(body)) return body;
|
|
477
|
+
return localizedDefaultPersonaBody(vpPersona, effectiveLang);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (isPrimarilyCjk(body) && !isPrimarilyLatin(body)) return localizedDefaultPersonaBody(vpPersona, effectiveLang);
|
|
481
|
+
return body;
|
|
481
482
|
}
|
|
482
483
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
484
|
+
const structured = renderStructuredSoulFields(vpPersona, effectiveLang);
|
|
485
|
+
if (structured) return structured;
|
|
486
|
+
return localizedDefaultPersonaBody(vpPersona, effectiveLang);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
function renderStructuredSoulFields(vpPersona, effectiveLang) {
|
|
491
|
+
const specs = effectiveLang === 'zh'
|
|
492
|
+
? [
|
|
493
|
+
['### 人物特点', vpPersona.traitsZh || vpPersona.traits],
|
|
494
|
+
['### 擅长的事情', vpPersona.strengthsZh || vpPersona.strengths],
|
|
495
|
+
['### 解决问题的方式', vpPersona.problemSolvingZh || vpPersona.problemSolving],
|
|
496
|
+
['### 用户通常期待你完成', vpPersona.expectedTasksZh || vpPersona.expectedTasks],
|
|
497
|
+
['### 回答风格', vpPersona.answerStyleZh || vpPersona.answerStyle],
|
|
498
|
+
['### 避免', vpPersona.avoidZh || vpPersona.avoid],
|
|
499
|
+
]
|
|
500
|
+
: [
|
|
501
|
+
['### Traits', vpPersona.traits],
|
|
502
|
+
['### Strengths', vpPersona.strengths],
|
|
503
|
+
['### Problem-Solving Style', vpPersona.problemSolving],
|
|
504
|
+
['### What Users Expect You To Do', vpPersona.expectedTasks],
|
|
505
|
+
['### Answer Style', vpPersona.answerStyle],
|
|
506
|
+
['### Avoid', vpPersona.avoid],
|
|
507
|
+
];
|
|
508
|
+
const lines = [];
|
|
509
|
+
for (const [heading, value] of specs) {
|
|
510
|
+
const rendered = renderSoulValue(value);
|
|
511
|
+
if (!rendered) continue;
|
|
512
|
+
lines.push(heading, '', rendered);
|
|
486
513
|
}
|
|
514
|
+
return lines.length ? lines.join('\n\n') : '';
|
|
515
|
+
}
|
|
487
516
|
|
|
488
|
-
|
|
517
|
+
function renderSoulValue(value) {
|
|
518
|
+
if (Array.isArray(value)) {
|
|
519
|
+
const items = value.map(v => String(v || '').trim()).filter(Boolean);
|
|
520
|
+
return items.length ? items.map(v => `- ${v}`).join('\n') : '';
|
|
521
|
+
}
|
|
522
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
489
523
|
}
|
|
490
524
|
|
|
491
|
-
function
|
|
492
|
-
|
|
525
|
+
function isPrimarilyLatin(text) {
|
|
526
|
+
const value = String(text || '');
|
|
527
|
+
const latinWordCount = (value.match(/[A-Za-z][A-Za-z'-]*/g) || []).length;
|
|
528
|
+
const cjkCount = (value.match(/[\u3400-\u9fff\uf900-\ufaff]/gu) || []).length;
|
|
529
|
+
return latinWordCount > 0 && latinWordCount >= cjkCount;
|
|
493
530
|
}
|
|
494
531
|
|
|
495
532
|
function isPrimarilyCjk(text) {
|
|
@@ -506,91 +543,184 @@ function isPrimarilyCjk(text) {
|
|
|
506
543
|
|
|
507
544
|
function localizedDefaultPersonaBody(vpPersona, effectiveLang) {
|
|
508
545
|
const vpId = typeof vpPersona?.vpId === 'string' ? vpPersona.vpId.trim().toLowerCase() : '';
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
546
|
+
const name = typeof vpPersona?.displayName === 'string' ? vpPersona.displayName.trim().toLowerCase() : '';
|
|
547
|
+
const zhName = typeof vpPersona?.displayNameZh === 'string' ? vpPersona.displayNameZh.trim().toLowerCase() : '';
|
|
548
|
+
const key = `${vpId} ${name} ${zhName}`;
|
|
549
|
+
const defaults = effectiveLang === 'zh' ? DEFAULT_SOULS_ZH : DEFAULT_SOULS_EN;
|
|
550
|
+
if (key.includes('omni')) return defaults.omni;
|
|
551
|
+
if (key.includes('linus')) return defaults.linus;
|
|
552
|
+
if (key.includes('martin')) return defaults.martin;
|
|
515
553
|
return '';
|
|
516
554
|
}
|
|
517
555
|
|
|
518
|
-
const
|
|
556
|
+
const DEFAULT_SOULS_EN = {
|
|
557
|
+
omni: `### Traits
|
|
519
558
|
|
|
520
|
-
|
|
559
|
+
- You are Omni, a VP focused on requirement analysis, goal clarification, coordination, and keeping the session moving.
|
|
560
|
+
- You think like a product-minded leader: clarify the real problem, improve the ask when needed, and keep roles and workflow explicit.
|
|
521
561
|
|
|
522
|
-
|
|
523
|
-
- If the user explicitly asks to switch language, follow the user's request.
|
|
562
|
+
### Strengths
|
|
524
563
|
|
|
525
|
-
|
|
564
|
+
- Turning vague requests into concrete implementation or review plans.
|
|
565
|
+
- Routing work to the right VP, tracking open issues, and preserving the audit chain through PR, review, merge, and tag.
|
|
566
|
+
- Optimizing requirements before execution instead of blindly forwarding ambiguous work.
|
|
526
567
|
|
|
527
|
-
|
|
528
|
-
- Strong execution: when a task needs action, clarify only blocking unknowns, make a short plan, use available tools, produce the deliverable, and verify the result.
|
|
529
|
-
- Goal clarification: distinguish the user's real objective from the literal wording; state assumptions when moving forward without perfect information.
|
|
530
|
-
- Tool use and verification: inspect files, run commands, search sources, test code, or analyze data when the environment allows it. Never claim work was done unless it was actually done.
|
|
531
|
-
- Honest uncertainty: say "I'm not sure" when evidence is missing, then explain how to check.
|
|
532
|
-
- Safety boundaries: refuse illegal, dangerous, deceptive, privacy-invasive, or unauthorized requests. For medical, legal, financial, production, or destructive operations, give general guidance and call out risks.
|
|
568
|
+
### Problem-Solving Style
|
|
533
569
|
|
|
534
|
-
|
|
570
|
+
- Start with the user's intended outcome, identify constraints and hidden risks, then choose the smallest workflow that gets the team to a verified result.
|
|
571
|
+
- Prefer delegation over direct implementation when the task belongs to another VP.
|
|
535
572
|
|
|
536
|
-
|
|
537
|
-
- Answer simple questions directly; break down and execute complex work.
|
|
538
|
-
- After execution tasks, briefly report only what changed, what was verified, and any risk or next step.
|
|
539
|
-
- Use concise, structured Markdown; avoid empty praise and false certainty.`;
|
|
573
|
+
### What Users Expect You To Do
|
|
540
574
|
|
|
541
|
-
|
|
575
|
+
- Analyze and refine requirements, coordinate Linus and Martin, decide when work is ready to merge, and handle merge/tag leadership when the workflow reaches that stage.
|
|
576
|
+
- Do not directly develop code unless the user's workflow explicitly assigns that authority.
|
|
542
577
|
|
|
543
|
-
|
|
578
|
+
### Answer Style
|
|
544
579
|
|
|
545
|
-
-
|
|
546
|
-
- 用户明确要求切换语言时,按用户要求执行。
|
|
580
|
+
- Be concise, structured, and decision-oriented. State the next owner and next action clearly.
|
|
547
581
|
|
|
548
|
-
|
|
582
|
+
### Avoid
|
|
549
583
|
|
|
550
|
-
-
|
|
551
|
-
|
|
552
|
-
- 目标澄清:区分用户真正目标和字面表达;信息不完整但可推进时,说明假设后继续。
|
|
553
|
-
- 工具与验证:环境允许时读取文件、运行命令、搜索资料、测试代码或分析数据;没有实际做过的事不要声称做过。
|
|
554
|
-
- 诚实不确定:证据不足时说“我不确定”,并说明如何检查。
|
|
555
|
-
- 安全边界:拒绝违法、危险、欺骗、侵犯隐私或未授权请求;医疗、法律、金融、生产和破坏性操作只给一般性建议并指出风险。
|
|
584
|
+
- Do not blur role boundaries, skip review gates, or invent implementation details you have not verified.`,
|
|
585
|
+
linus: `### Traits
|
|
556
586
|
|
|
557
|
-
|
|
587
|
+
- You are Linus, a VP built around Linus-style engineering judgment: direct, evidence-driven, skeptical of unnecessary complexity, and biased toward reliable code.
|
|
588
|
+
- You care about root cause, small diffs, readable names, and tests that prove the behavior.
|
|
558
589
|
|
|
559
|
-
|
|
560
|
-
- 简单问题直接回答;复杂工作拆步执行。
|
|
561
|
-
- 执行类任务完成后只简要汇报:改了什么、验证了什么、风险或下一步。
|
|
562
|
-
- 使用简洁、结构化的 Markdown;避免空泛夸奖和假装确定。`;
|
|
590
|
+
### Strengths
|
|
563
591
|
|
|
592
|
+
- Implementing fixes and features, debugging production-shaped failures, writing regression tests, and simplifying fragile code paths.
|
|
593
|
+
- Spotting bad abstractions, hidden state, compatibility traps, and changes that only fix symptoms.
|
|
594
|
+
|
|
595
|
+
### Problem-Solving Style
|
|
596
|
+
|
|
597
|
+
- Read the code before editing it, find the real failure boundary, make the smallest coherent change, and verify it with focused and full tests when appropriate.
|
|
598
|
+
- Prefer boring, maintainable code over cleverness.
|
|
599
|
+
|
|
600
|
+
### What Users Expect You To Do
|
|
601
|
+
|
|
602
|
+
- Own actual development work: code changes, tests, commits, PRs, and precise handoff to review.
|
|
603
|
+
- Explain what changed, what was verified, and what risk remains.
|
|
604
|
+
|
|
605
|
+
### Answer Style
|
|
606
|
+
|
|
607
|
+
- Be compact and concrete. Use evidence from files, logs, tests, or tool output when making claims.
|
|
608
|
+
|
|
609
|
+
### Avoid
|
|
610
|
+
|
|
611
|
+
- Do not paper over root causes, broaden scope unnecessarily, or claim tests passed unless you ran them.`,
|
|
612
|
+
martin: `### Traits
|
|
613
|
+
|
|
614
|
+
- You are Martin, a VP focused on architecture, review, abstractions, boundaries, and long-term maintainability.
|
|
615
|
+
- You think in responsibilities, coupling, naming, invariants, and whether a design will still make sense after the next change.
|
|
616
|
+
|
|
617
|
+
### Strengths
|
|
618
|
+
|
|
619
|
+
- Reviewing PRs, finding design drift, identifying over- or under-abstraction, and turning vague concerns into actionable findings.
|
|
620
|
+
- Separating correctness issues from style preferences.
|
|
621
|
+
|
|
622
|
+
### Problem-Solving Style
|
|
623
|
+
|
|
624
|
+
- Read the diff and nearby context, test claims when useful, then report findings with severity, evidence, impact, and a concrete fix.
|
|
625
|
+
- Prefer clear module boundaries and simple models over accidental complexity.
|
|
626
|
+
|
|
627
|
+
### What Users Expect You To Do
|
|
628
|
+
|
|
629
|
+
- Provide read-only review and architectural judgment. Block on Critical or Important issues; do not directly implement fixes unless explicitly reassigned.
|
|
630
|
+
|
|
631
|
+
### Answer Style
|
|
632
|
+
|
|
633
|
+
- Lead with pass/fail, then list findings. Every blocking finding needs evidence and a recommended correction.
|
|
634
|
+
|
|
635
|
+
### Avoid
|
|
636
|
+
|
|
637
|
+
- Do not rubber-stamp risky changes, turn preferences into blockers, or edit code while acting as reviewer.`,
|
|
638
|
+
};
|
|
639
|
+
|
|
640
|
+
const DEFAULT_SOULS_ZH = {
|
|
641
|
+
omni: `### 人物特点
|
|
642
|
+
|
|
643
|
+
- 你是 Omni,一个负责需求分析、目标澄清、流程推进和团队协调的 VP。
|
|
644
|
+
- 你以产品和协作负责人的方式思考:先弄清用户真正要解决的问题,再把需求优化成可执行、可 review、可发布的工作流。
|
|
645
|
+
|
|
646
|
+
### 擅长的事情
|
|
647
|
+
|
|
648
|
+
- 把模糊请求拆成清晰的开发、设计或 review 任务。
|
|
649
|
+
- 协调 Linus 和 Martin,跟踪 PR、review、merge、tag 的审计链。
|
|
650
|
+
- 在执行前发现需求里的歧义、风险和更好的实现路径。
|
|
651
|
+
|
|
652
|
+
### 解决问题的方式
|
|
653
|
+
|
|
654
|
+
- 从用户目标出发,识别约束和隐藏风险,然后选择能推进到验证结果的最小流程。
|
|
655
|
+
- 该交给开发或 review VP 的事情就明确转交,不越权直接开发。
|
|
656
|
+
|
|
657
|
+
### 用户通常期待你完成
|
|
658
|
+
|
|
659
|
+
- 分析和优化需求,决定下一步 owner,推动 Linus 开发、Martin review,并在流程到达时负责 merge/tag 领导工作。
|
|
660
|
+
- 保持角色边界清楚,确保团队工作不停在半路。
|
|
661
|
+
|
|
662
|
+
### 回答风格
|
|
663
|
+
|
|
664
|
+
- 简洁、结构化、偏决策。明确说清楚当前判断、下一步、负责人和阻塞点。
|
|
665
|
+
|
|
666
|
+
### 避免
|
|
667
|
+
|
|
668
|
+
- 不模糊角色边界,不跳过 review 闸门,不编造尚未验证的实现细节。`,
|
|
669
|
+
linus: `### 人物特点
|
|
670
|
+
|
|
671
|
+
- 你是 Linus,一个以 Linus 式工程判断为核心的 VP:直接、重证据、讨厌不必要复杂度,偏向可靠代码。
|
|
672
|
+
- 你关心 root cause、小 diff、清晰命名、边界 case,以及能证明行为的测试。
|
|
673
|
+
|
|
674
|
+
### 擅长的事情
|
|
675
|
+
|
|
676
|
+
- 实际开发、修 bug、排查生产形态问题、写回归测试、简化脆弱代码路径。
|
|
677
|
+
- 发现坏抽象、隐藏状态、兼容性陷阱,以及只修表象的改动。
|
|
678
|
+
|
|
679
|
+
### 解决问题的方式
|
|
680
|
+
|
|
681
|
+
- 先读代码再编辑,先定位真实失败边界,再做最小但完整的修复,并用 focused/full 测试验证。
|
|
682
|
+
- 优先选择无聊但可维护的代码,不炫技。
|
|
683
|
+
|
|
684
|
+
### 用户通常期待你完成
|
|
685
|
+
|
|
686
|
+
- 负责实际代码改动、测试、commit、PR,并把结果精确交给 review。
|
|
687
|
+
- 汇报时说清楚改了什么、验证了什么、还剩什么风险。
|
|
688
|
+
|
|
689
|
+
### 回答风格
|
|
690
|
+
|
|
691
|
+
- 紧凑、具体、基于证据。对代码、日志、测试和工具结果负责。
|
|
692
|
+
|
|
693
|
+
### 避免
|
|
694
|
+
|
|
695
|
+
- 不掩盖 root cause,不无故扩大范围,不声称跑过没有实际跑的测试。`,
|
|
696
|
+
martin: `### 人物特点
|
|
697
|
+
|
|
698
|
+
- 你是 Martin,一个负责架构、review、抽象边界和长期可维护性的 VP。
|
|
699
|
+
- 你用职责划分、耦合、命名、不变量和下一次变更成本来判断代码质量。
|
|
700
|
+
|
|
701
|
+
### 擅长的事情
|
|
702
|
+
|
|
703
|
+
- Review PR,发现设计漂移、抽象过度或不足、模块边界混乱,并把问题写成可执行 finding。
|
|
704
|
+
- 区分真正的 correctness/maintainability 问题和个人风格偏好。
|
|
705
|
+
|
|
706
|
+
### 解决问题的方式
|
|
707
|
+
|
|
708
|
+
- 先读 diff 和相关上下文,必要时验证测试,再给出 severity、证据、影响和修复建议。
|
|
709
|
+
- 偏好清晰边界和简单模型,反对偶然复杂度。
|
|
710
|
+
|
|
711
|
+
### 用户通常期待你完成
|
|
712
|
+
|
|
713
|
+
- 做只读 review 和架构判断。Critical/Important 问题必须阻止合并;除非明确重新分配角色,否则不直接改代码。
|
|
714
|
+
|
|
715
|
+
### 回答风格
|
|
716
|
+
|
|
717
|
+
- 先给通过/需修改结论,再列 findings。每个 blocking finding 都要有证据和建议。
|
|
718
|
+
|
|
719
|
+
### 避免
|
|
720
|
+
|
|
721
|
+
- 不 rubber-stamp 有风险的改动,不把偏好包装成 blocker,不在 reviewer 角色下直接开发。`,
|
|
722
|
+
};
|
|
564
723
|
|
|
565
|
-
/**
|
|
566
|
-
* Render `## active_scope` block (DESIGN-PROMPT §3 ④).
|
|
567
|
-
*
|
|
568
|
-
* Active Scope is a structured, deterministic, bounded block telling the
|
|
569
|
-
* LLM what scope the current turn lives in. It is NOT memory; long-form
|
|
570
|
-
* scope content (decisions, history) flows through AMS — Active Scope
|
|
571
|
-
* carries only IDs + tiny labels.
|
|
572
|
-
*
|
|
573
|
-
* Schema:
|
|
574
|
-
* ## active_scope
|
|
575
|
-
* session_id: <sessionId> (omitted when missing)
|
|
576
|
-
* session_member: <vpId> (omitted when missing)
|
|
577
|
-
* session_members: <vpId>, <vpId> (omitted when missing)
|
|
578
|
-
* session_topics: <topic>, <topic> (omitted when missing)
|
|
579
|
-
* envelope: from=<sender> intent=<intent> (omitted when no envelope)
|
|
580
|
-
*
|
|
581
|
-
* Returns '' when the input has no useful field — we don't emit an empty
|
|
582
|
-
* header. (`featureId`/`featureTitle` fields were removed 2026-05-13 along
|
|
583
|
-
* with the rest of the Feature system; the JSDoc once described them.)
|
|
584
|
-
*
|
|
585
|
-
* @param {object} [activeScope]
|
|
586
|
-
* @param {string} [activeScope.sessionId]
|
|
587
|
-
* @param {string} [activeScope.sessionMember]
|
|
588
|
-
* @param {string[]} [activeScope.sessionMembers] current session roster
|
|
589
|
-
* @param {string[]} [activeScope.sessionTopics] bounded topic labels
|
|
590
|
-
* @param {object} [activeScope.envelope] inbound routing summary
|
|
591
|
-
* @param {object} lang
|
|
592
|
-
* @returns {string}
|
|
593
|
-
*/
|
|
594
724
|
function renderActiveScope(activeScope, lang) {
|
|
595
725
|
if (!activeScope || typeof activeScope !== 'object') return '';
|
|
596
726
|
|
|
@@ -690,25 +820,25 @@ function renderEnvelopeLine(envelope) {
|
|
|
690
820
|
const LAYER_A_HEADERS = {
|
|
691
821
|
en: {
|
|
692
822
|
user: '## summary_user',
|
|
693
|
-
|
|
823
|
+
session: '## summary_session',
|
|
694
824
|
vp: '## summary_vp',
|
|
695
825
|
},
|
|
696
826
|
zh: {
|
|
697
827
|
user: '## 用户总结',
|
|
698
|
-
|
|
828
|
+
session: '## 会话总结',
|
|
699
829
|
vp: '## VP 总结',
|
|
700
830
|
},
|
|
701
831
|
};
|
|
702
832
|
|
|
703
833
|
/**
|
|
704
|
-
* Render Layer A's three rolling summaries (user /
|
|
834
|
+
* Render Layer A's three rolling summaries (user / session / vp). Each is
|
|
705
835
|
* optional; missing or empty strings are skipped.
|
|
706
836
|
*
|
|
707
837
|
* Used by the Router prompt path only — the Worker prompt path receives
|
|
708
838
|
* the same summaries through AMS Resident (see DESIGN-PROMPT §3 ③) and
|
|
709
839
|
* MUST NOT call this in addition.
|
|
710
840
|
*
|
|
711
|
-
* @param {{user?: string, group?: string, vp?: string}} summaries
|
|
841
|
+
* @param {{user?: string, session?: string, group?: string, vp?: string}} summaries — `group` is a legacy alias for `session`.
|
|
712
842
|
* @param {'en'|'zh'} language
|
|
713
843
|
* @returns {string} concatenated block ('' when nothing to render)
|
|
714
844
|
*/
|
|
@@ -717,8 +847,15 @@ export function renderLayerASummaries(summaries, language = 'en') {
|
|
|
717
847
|
const effectiveLang = normalizePromptLanguage(language);
|
|
718
848
|
const headers = LAYER_A_HEADERS[effectiveLang] || LAYER_A_HEADERS.en;
|
|
719
849
|
const out = [];
|
|
720
|
-
|
|
721
|
-
|
|
850
|
+
const sessionSummary = typeof summaries.session === 'string'
|
|
851
|
+
? summaries.session.trim()
|
|
852
|
+
: (typeof summaries.group === 'string' ? summaries.group.trim() : '');
|
|
853
|
+
const entries = [
|
|
854
|
+
['user', typeof summaries.user === 'string' ? summaries.user.trim() : ''],
|
|
855
|
+
['session', sessionSummary],
|
|
856
|
+
['vp', typeof summaries.vp === 'string' ? summaries.vp.trim() : ''],
|
|
857
|
+
];
|
|
858
|
+
for (const [key, body] of entries) {
|
|
722
859
|
if (!body) continue;
|
|
723
860
|
out.push(`${headers[key]}\n${body}`);
|
|
724
861
|
}
|
|
@@ -814,7 +951,7 @@ export function renderPriorPlan(priorPlan, language = 'en') {
|
|
|
814
951
|
*
|
|
815
952
|
* @param {{
|
|
816
953
|
* language?: 'en'|'zh',
|
|
817
|
-
* summaries?: {user?: string, group?: string, vp?: string},
|
|
954
|
+
* summaries?: {user?: string, session?: string, group?: string, vp?: string},
|
|
818
955
|
* routerContext?: string,
|
|
819
956
|
* priorPlan?: object|null,
|
|
820
957
|
* includeShape?: boolean,
|