@yeaft/webchat-agent 1.0.514 → 1.0.516
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/local-runtime/version.json +1 -1
- package/local-runtime/web/app.bundle.js +19 -0
- package/local-runtime/web/app.bundle.js.gz +0 -0
- package/local-runtime/web/index.html +2 -2
- package/local-runtime/web/style.bundle.css +1 -1
- package/local-runtime/web/style.bundle.css.gz +0 -0
- package/package.json +1 -1
- package/yeaft/engine.js +12 -91
- package/yeaft/prompts.js +27 -341
- package/yeaft/tasks/manager.js +0 -56
- package/yeaft/templates/common-rules.md +2 -2
- package/yeaft/tools/activation.js +0 -6
- package/yeaft/tools/file-read.js +4 -5
- package/yeaft/tools/index.js +4 -9
- package/yeaft/vp/vp-store.js +4 -7
- package/yeaft/web-bridge.js +3 -30
- package/yeaft/templates/plan-instruction.md +0 -45
- package/yeaft/templates/tool-guidance.md +0 -11
- package/yeaft/tools/start-plan.js +0 -182
- package/yeaft/tools/todo-write.js +0 -174
package/yeaft/prompts.js
CHANGED
|
@@ -9,12 +9,10 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Concept layering (DESIGN-PROMPT §3):
|
|
11
11
|
* ① Identity — VP persona body (or Yeaft fallback)
|
|
12
|
-
* ② Rules —
|
|
13
|
-
* tool-guidance, skills, common rules
|
|
12
|
+
* ② Rules — Session/Project instructions, date, runtime, and skills
|
|
14
13
|
* ③ Memory — single block produced upstream by the AMS render
|
|
15
14
|
* outlet and threaded through here as `memoryInjection`
|
|
16
|
-
* ④
|
|
17
|
-
* (session / vp / members / envelope IDs)
|
|
15
|
+
* ④ Routing — multi-VP identity and handoff metadata when applicable
|
|
18
16
|
*
|
|
19
17
|
* Long-term semantic context comes only from the AMS Memory outlet. The
|
|
20
18
|
* conversation transcript stays in the messages timeline and is bounded by
|
|
@@ -142,7 +140,6 @@ const RAW_TEMPLATES = {
|
|
|
142
140
|
commonRules: readTemplate('common-rules.md', { required: false }),
|
|
143
141
|
modeUnified: readTemplate('mode-unified.md'),
|
|
144
142
|
modeDream: readTemplate('mode-dream.md'),
|
|
145
|
-
toolGuidance: readTemplate('tool-guidance.md'),
|
|
146
143
|
// Phase 1 — DESIGN.md "Migration Plan" harness fragments. Optional so
|
|
147
144
|
// older deployments without the templates still boot; buildWorkerPrompt /
|
|
148
145
|
// buildRouterPrompt callers will simply omit the section.
|
|
@@ -150,10 +147,6 @@ const RAW_TEMPLATES = {
|
|
|
150
147
|
harnessRouterShape: readTemplate('harness/router-shape.md', { required: false }),
|
|
151
148
|
// Phase 3b — coordinator harness rule for inter-VP forwarding.
|
|
152
149
|
harnessRouterHandoff: readTemplate('harness/router-handoff.md', { required: false }),
|
|
153
|
-
// task — StartPlan tool fallback. The `StartPlan` tool reads this when
|
|
154
|
-
// a VP has no `planInstruction` of its own. Required so a misconfigured
|
|
155
|
-
// install fails fast instead of injecting an empty plan instruction.
|
|
156
|
-
planInstruction: readTemplate('plan-instruction.md'),
|
|
157
150
|
};
|
|
158
151
|
|
|
159
152
|
/**
|
|
@@ -168,23 +161,6 @@ function getTemplate(key, language) {
|
|
|
168
161
|
return extractLangSection(raw, language);
|
|
169
162
|
}
|
|
170
163
|
|
|
171
|
-
/**
|
|
172
|
-
* Default planning-instruction text returned by the `StartPlan` tool when
|
|
173
|
-
* the active VP has no `planInstruction` override on its role.md frontmatter.
|
|
174
|
-
*
|
|
175
|
-
* Pulled from `templates/plan-instruction.md`. Marked required at load time
|
|
176
|
-
* so a missing template fails fast on agent boot — preferable to silently
|
|
177
|
-
* shipping an empty plan instruction to the LLM.
|
|
178
|
-
*
|
|
179
|
-
* @param {string} [language='en'] — 'en' / 'zh' (uses lang-section markers
|
|
180
|
-
* if the template carries them; falls
|
|
181
|
-
* back to the whole body otherwise).
|
|
182
|
-
* @returns {string}
|
|
183
|
-
*/
|
|
184
|
-
export function getDefaultPlanInstruction(language = 'en') {
|
|
185
|
-
return getTemplate('planInstruction', normalizePromptLanguage(language));
|
|
186
|
-
}
|
|
187
|
-
|
|
188
164
|
// ─── Prompt Templates (hardcoded fallbacks) ──────────────────────
|
|
189
165
|
|
|
190
166
|
const PROMPTS = {
|
|
@@ -192,12 +168,6 @@ const PROMPTS = {
|
|
|
192
168
|
identity: 'No VP soul is active for this turn. Participate in the current session with grounded, evidence-based answers and preserve the user\'s context.',
|
|
193
169
|
date: (d) => `Date: ${d}`,
|
|
194
170
|
dream: 'You are in dream mode. Reflect on past conversations and consolidate memories.',
|
|
195
|
-
// DESIGN-PROMPT §3 ④ — current session context block.
|
|
196
|
-
activeScopeHeader: '## Current session context',
|
|
197
|
-
activeScopeSessionIdLabel: 'Session ID',
|
|
198
|
-
activeScopeMembersLabel: 'Session members',
|
|
199
|
-
activeScopeTopicsLabel: 'Current focus',
|
|
200
|
-
activeScopeEnvelopeLabel: 'Handoff',
|
|
201
171
|
multiVpRoutingHeader: '## multi_vp_routing',
|
|
202
172
|
sessionAnnouncementHeader: '[Session Announcement]',
|
|
203
173
|
projectInstructionHeader: '[Project Instruction]',
|
|
@@ -218,12 +188,6 @@ const PROMPTS = {
|
|
|
218
188
|
identity: '你正在当前会话中参与协作。保持用户上下文,回答要基于证据;需要工具时使用工具,但不要把自己没有实际执行过的事说成已经执行。',
|
|
219
189
|
date: (d) => `日期:${d}`,
|
|
220
190
|
dream: '你处于梦境模式。回顾过去的对话,整理和巩固记忆。',
|
|
221
|
-
// DESIGN-PROMPT §3 ④ — 当前会话上下文。
|
|
222
|
-
activeScopeHeader: '## 当前会话上下文',
|
|
223
|
-
activeScopeSessionIdLabel: '会话 ID',
|
|
224
|
-
activeScopeMembersLabel: '会话成员',
|
|
225
|
-
activeScopeTopicsLabel: '当前讨论',
|
|
226
|
-
activeScopeEnvelopeLabel: '转交消息',
|
|
227
191
|
multiVpRoutingHeader: '## multi_vp_routing',
|
|
228
192
|
sessionAnnouncementHeader: '[会话公告]',
|
|
229
193
|
projectInstructionHeader: '[Project 指令]',
|
|
@@ -275,28 +239,22 @@ export function normalizePromptLanguage(language) {
|
|
|
275
239
|
*
|
|
276
240
|
* Prompt structure (DESIGN-PROMPT §3):
|
|
277
241
|
* ① Identity — Core identity (persona or Yeaft fallback)
|
|
278
|
-
* ② Rules — Session
|
|
242
|
+
* ② Rules — Session/Project instructions, date, runtime, and skills
|
|
279
243
|
* ③ Memory — Single block produced by the AMS render outlet
|
|
280
244
|
* (callers pass it as `memoryInjection`).
|
|
281
|
-
* ④
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
* context (`taskCtx`) was wired into Active Scope by task-334e
|
|
286
|
-
* but never actually populated by the engine; removed 2026-05-13.)
|
|
245
|
+
* ④ Routing — Multi-VP identity and handoff metadata when applicable
|
|
246
|
+
*
|
|
247
|
+
* Generic Session IDs, inferred topics, active-task labels, and repeated tool
|
|
248
|
+
* guidance are intentionally omitted from the system prompt.
|
|
287
249
|
*
|
|
288
|
-
*
|
|
289
|
-
* @param {object} [activeScope] —
|
|
290
|
-
* @param {string} [activeScope.
|
|
291
|
-
* @param {string} [activeScope.
|
|
292
|
-
* @param {string[]} [activeScope.sessionMembers] current session roster
|
|
293
|
-
* @param {string[]} [activeScope.sessionTopics] bounded topic labels for this session
|
|
294
|
-
* @param {object} [activeScope.envelope] inbound routing info (sender, intent)
|
|
250
|
+
* Multi-VP routing params:
|
|
251
|
+
* @param {object} [activeScope] — routing scope for this turn
|
|
252
|
+
* @param {string} [activeScope.vpId] current VP identity
|
|
253
|
+
* @param {string[]} [activeScope.sessionMembers] current Session roster
|
|
295
254
|
*
|
|
296
255
|
* @param {{
|
|
297
256
|
* language?: string,
|
|
298
257
|
* mode?: string,
|
|
299
|
-
* toolNames?: string[],
|
|
300
258
|
* memoryInjection?: string,
|
|
301
259
|
* skillContent?: string,
|
|
302
260
|
* activeScope?: object,
|
|
@@ -313,7 +271,6 @@ export function normalizePromptLanguage(language) {
|
|
|
313
271
|
export function buildSystemPrompt({
|
|
314
272
|
language = 'en',
|
|
315
273
|
mode,
|
|
316
|
-
toolNames = [],
|
|
317
274
|
memoryInjection,
|
|
318
275
|
skillContent,
|
|
319
276
|
activeScope,
|
|
@@ -324,7 +281,6 @@ export function buildSystemPrompt({
|
|
|
324
281
|
workCenterInstructions = '',
|
|
325
282
|
projectDoc = '',
|
|
326
283
|
runtimePlatform,
|
|
327
|
-
activeTasks = '',
|
|
328
284
|
promptNotices = [],
|
|
329
285
|
} = {}) {
|
|
330
286
|
// Normalize app locales like `zh-CN` to prompt dictionary/template keys.
|
|
@@ -405,20 +361,15 @@ export function buildSystemPrompt({
|
|
|
405
361
|
parts.push(dreamTemplate || lang.dream);
|
|
406
362
|
}
|
|
407
363
|
|
|
408
|
-
// ─── 4. Runtime Platform
|
|
364
|
+
// ─── 4. Runtime Platform ─────────────────────────────
|
|
365
|
+
// Tool schemas already carry their operational guidance. Repeating selected
|
|
366
|
+
// tool instructions in the system prompt wastes tokens and can drift from
|
|
367
|
+
// the executable schema, so only platform facts are rendered here.
|
|
409
368
|
const runtimePlatformBlock = renderRuntimePlatformPrompt(runtimePlatform || getRuntimePlatformInfo(), effectiveLang);
|
|
410
369
|
if (runtimePlatformBlock) {
|
|
411
370
|
parts.push(runtimePlatformBlock);
|
|
412
371
|
}
|
|
413
372
|
|
|
414
|
-
if (toolNames.length > 0) {
|
|
415
|
-
const guidance = renderActiveToolGuidance(toolNames, effectiveLang);
|
|
416
|
-
const toolGuidanceTemplate = getTemplate('toolGuidance', effectiveLang);
|
|
417
|
-
if (guidance && toolGuidanceTemplate) {
|
|
418
|
-
parts.push(toolGuidanceTemplate.replace('{{guidance}}', guidance));
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
|
|
422
373
|
// ─── 5. Skills Section ─────────────────────────────────
|
|
423
374
|
if (skillContent) {
|
|
424
375
|
parts.push(skillContent);
|
|
@@ -436,16 +387,10 @@ export function buildSystemPrompt({
|
|
|
436
387
|
parts.push(memoryInjection.trim());
|
|
437
388
|
}
|
|
438
389
|
|
|
439
|
-
// ─── 7.
|
|
440
|
-
//
|
|
441
|
-
//
|
|
442
|
-
//
|
|
443
|
-
const activeScopeBlock = renderActiveScope(activeScope, lang);
|
|
444
|
-
if (activeScopeBlock) parts.push(activeScopeBlock);
|
|
445
|
-
|
|
446
|
-
const activeTaskText = typeof activeTasks === 'string' ? activeTasks.trim() : '';
|
|
447
|
-
if (activeTaskText) parts.push(activeTaskText);
|
|
448
|
-
|
|
390
|
+
// ─── 7. Multi-VP routing ────────────────────────────────
|
|
391
|
+
// Generic Session IDs, inferred topics, and live task labels are runtime
|
|
392
|
+
// bookkeeping rather than model instructions. Keep only the routing block
|
|
393
|
+
// whose peer identities and RouteForward contract affect model behaviour.
|
|
449
394
|
const multiVpRoutingBlock = renderMultiVpRouting(activeScope, lang);
|
|
450
395
|
if (multiVpRoutingBlock) parts.push(multiVpRoutingBlock);
|
|
451
396
|
|
|
@@ -454,64 +399,6 @@ export function buildSystemPrompt({
|
|
|
454
399
|
|
|
455
400
|
// ─── helpers ─────────────────────────────────────────────────────
|
|
456
401
|
|
|
457
|
-
const TOOL_GUIDANCE_GROUPS = Object.freeze([
|
|
458
|
-
{
|
|
459
|
-
tools: ['DiscoverTools'],
|
|
460
|
-
en: 'If the visible tools do not clearly cover the request, use `DiscoverTools` with the user goal before concluding that a capability is unavailable. If the target is absent from a page, follow `next_cursor` until found or the hidden directory is exhausted. If `restart_required` is true, restart without a cursor because the registered directory changed.',
|
|
461
|
-
zh: '如果可见工具不能明确覆盖请求,应先按用户目标调用 `DiscoverTools`。若当前页没有目标,应按 `next_cursor` 继续翻页,直到找到或隐藏目录耗尽后,才能判断某项能力不可用。如果 `restart_required` 为 true,说明注册目录已变化,应丢弃游标重新开始。',
|
|
462
|
-
},
|
|
463
|
-
{
|
|
464
|
-
tools: ['FileRead', 'FileWrite', 'FileEdit', 'Glob', 'Grep', 'ListDir', 'ApplyPatch', 'NotebookEdit'],
|
|
465
|
-
en: 'Read existing files before editing. Use dedicated file/search tools instead of shell search or `sed -i`; make small, reviewable edits. Parallelize only proven-independent reads under the accuracy-first rule above.',
|
|
466
|
-
zh: '编辑前先读现有文件。文件搜索和修改优先使用专用工具,不用 shell 搜索或 `sed -i`;改动保持小而可审查。只有明确满足上述准确性优先判据的读取才可并行。',
|
|
467
|
-
},
|
|
468
|
-
{
|
|
469
|
-
tools: ['Bash'],
|
|
470
|
-
en: 'Use non-interactive, deterministic shell commands, set reasonable timeouts, quote paths with spaces, and do not run destructive operations without authorization.',
|
|
471
|
-
zh: 'Shell 命令保持非交互、确定性并设置合理 timeout;包含空格的路径要引用,未经授权不要执行破坏性操作。',
|
|
472
|
-
},
|
|
473
|
-
{
|
|
474
|
-
tools: ['TodoWrite'],
|
|
475
|
-
en: 'For non-trivial multi-step work, write a brief visible plan and call `TodoWrite` in the same assistant response as the first necessary work-tool call only when its arguments and safety do not depend on another result. Start with the smallest such call; do not speculative-batch the investigation or stop after planning unless user input genuinely blocks the first step.',
|
|
476
|
-
zh: '非平凡多步骤任务先写简短可见计划。只有第一个工作工具调用已经确定有必要,且其参数和安全性都不依赖其他结果时,才在同一个 assistant response 中把它与 `TodoWrite` 一起发出;先执行满足条件的最小调用,不要推测性批量展开调查。只有用户信息确实阻塞第一步时才在规划后停下。',
|
|
477
|
-
},
|
|
478
|
-
{
|
|
479
|
-
tools: ['SpawnAgent', 'PromptAgent', 'WaitAgent', 'CloseAgent', 'ListAgents'],
|
|
480
|
-
en: 'Delegate only independent, bounded work. Keep ownership in the parent. After PromptAgent queues follow-up work, call WaitAgent in the same parent turn and collect the reply before ending. If a bounded wait times out, wait again with a larger bound unless the agent is stale/stalled. Relay the reply or continue the dependent work, then close the sub-agent when it is no longer needed.',
|
|
481
|
-
zh: '只委派边界清晰且独立的工作。父级保留任务所有权。PromptAgent 排队后续工作后,必须在同一个父级 turn 调用 WaitAgent 并拿到回复再结束;有界等待超时后,除非 Agent 已 stale/stalled,否则使用更大上限继续等待;随后转述结果或继续依赖该结果的工作,不再需要时关闭子 Agent。',
|
|
482
|
-
},
|
|
483
|
-
{
|
|
484
|
-
tools: ['ListTasks', 'ReadTaskLog', 'CancelTask'],
|
|
485
|
-
en: 'Treat background tasks as live execution state, not memory facts. Inspect status or logs before retrying or cancelling work.',
|
|
486
|
-
zh: '后台任务是实时执行状态,不是记忆事实。重试或取消前先检查状态或日志。',
|
|
487
|
-
},
|
|
488
|
-
{
|
|
489
|
-
tools: ['RouteForward'],
|
|
490
|
-
en: 'Use `RouteForward` for explicit VP-to-VP handoff; writing an @mention in ordinary text does not dispatch another VP.',
|
|
491
|
-
zh: '显式 VP 转交必须使用 `RouteForward`;普通文本中的 @mention 不会调度另一个 VP。',
|
|
492
|
-
},
|
|
493
|
-
{
|
|
494
|
-
tools: ['CreateWorkItem'],
|
|
495
|
-
en: 'Use `CreateWorkItem` only for goals that need durable cross-turn coordination, recovery, review, waiting, or retry.',
|
|
496
|
-
zh: '只有目标需要跨 turn 持久协调、恢复、评审、等待或重试时才使用 `CreateWorkItem`。',
|
|
497
|
-
},
|
|
498
|
-
]);
|
|
499
|
-
|
|
500
|
-
function renderActiveToolGuidance(toolNames, language) {
|
|
501
|
-
const active = new Set(Array.isArray(toolNames) ? toolNames : []);
|
|
502
|
-
const lines = [];
|
|
503
|
-
if (active.size > 0) {
|
|
504
|
-
lines.push(language === 'zh'
|
|
505
|
-
? '- 准确性优先:先用能解决当前未知的最小定向调用。只有每个调用都已经确定有必要,且其参数和安全性都不依赖同批其他结果时,才在一个响应中发出多个工具调用;否则串行执行。不要推测性扇出、重复成功的读取/搜索,也不要默认抓取多个来源;先检查证据,再决定是否扩展。'
|
|
506
|
-
: '- Accuracy first: start with the smallest targeted call that can resolve the current uncertainty. Issue multiple tool calls in one response only when every call is already necessary and its arguments and safety do not depend on another call\'s result. Otherwise run them sequentially. Do not fan out speculatively, repeat a successful read/search, or fetch multiple sources by default; inspect evidence before expanding.');
|
|
507
|
-
}
|
|
508
|
-
for (const group of TOOL_GUIDANCE_GROUPS) {
|
|
509
|
-
if (!group.tools.some(name => active.has(name))) continue;
|
|
510
|
-
lines.push(`- ${language === 'zh' ? group.zh : group.en}`);
|
|
511
|
-
}
|
|
512
|
-
return lines.join('\n');
|
|
513
|
-
}
|
|
514
|
-
|
|
515
402
|
/**
|
|
516
403
|
* Render the VP identity block when the engine is running on behalf of an
|
|
517
404
|
* addressed VP. The `persona` body from role.md is the only soul source;
|
|
@@ -570,32 +457,6 @@ function selectVpPersonaBody(vpPersona, effectiveLang) {
|
|
|
570
457
|
|
|
571
458
|
|
|
572
459
|
|
|
573
|
-
function renderActiveScope(activeScope, lang) {
|
|
574
|
-
if (!activeScope || typeof activeScope !== 'object') return '';
|
|
575
|
-
|
|
576
|
-
const isZh = lang === PROMPTS.zh;
|
|
577
|
-
const separator = isZh ? ':' : ': ';
|
|
578
|
-
const lines = [];
|
|
579
|
-
const session = typeof activeScope.sessionId === 'string' && activeScope.sessionId.trim()
|
|
580
|
-
? activeScope.sessionId.trim()
|
|
581
|
-
: '';
|
|
582
|
-
if (session) lines.push(`${lang.activeScopeSessionIdLabel}${separator}${session}`);
|
|
583
|
-
|
|
584
|
-
const membersLine = renderSessionMembersLine(activeScope.sessionMembers || activeScope.members, isZh);
|
|
585
|
-
if (membersLine) lines.push(`${lang.activeScopeMembersLabel}${separator}${membersLine}`);
|
|
586
|
-
|
|
587
|
-
const topicsLine = renderSessionTopicsLine(activeScope.sessionTopics, isZh);
|
|
588
|
-
if (topicsLine) lines.push(`${lang.activeScopeTopicsLabel}${separator}${topicsLine}`);
|
|
589
|
-
|
|
590
|
-
const envLine = renderEnvelopeLine(activeScope.envelope, isZh);
|
|
591
|
-
if (envLine) lines.push(`${lang.activeScopeEnvelopeLabel}${separator}${envLine}`);
|
|
592
|
-
|
|
593
|
-
if (lines.length === 0) return '';
|
|
594
|
-
|
|
595
|
-
return `${lang.activeScopeHeader}\n${lines.join('\n')}`;
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
|
|
599
460
|
function firstNonEmptyString(...values) {
|
|
600
461
|
for (const value of values) {
|
|
601
462
|
if (typeof value === 'string' && value.trim()) return value.trim();
|
|
@@ -603,151 +464,6 @@ function firstNonEmptyString(...values) {
|
|
|
603
464
|
return '';
|
|
604
465
|
}
|
|
605
466
|
|
|
606
|
-
function renderSessionMembersLine(members, useChineseSeparator = false) {
|
|
607
|
-
return normalizeSessionMemberIds(members).join(useChineseSeparator ? '、' : ', ');
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
function renderSessionTopicsLine(topics, isZh = false) {
|
|
611
|
-
const descriptions = [];
|
|
612
|
-
const seen = new Set();
|
|
613
|
-
for (const topic of normalizeSessionTopicIds(topics)) {
|
|
614
|
-
const description = describeSessionTopic(topic, isZh);
|
|
615
|
-
if (!description || seen.has(description)) continue;
|
|
616
|
-
seen.add(description);
|
|
617
|
-
descriptions.push(description);
|
|
618
|
-
}
|
|
619
|
-
return descriptions.join(isZh ? ';' : '; ');
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
function normalizeSessionTopicIds(topics) {
|
|
623
|
-
if (!Array.isArray(topics)) return [];
|
|
624
|
-
const clean = [];
|
|
625
|
-
const seen = new Set();
|
|
626
|
-
for (const topic of topics) {
|
|
627
|
-
if (typeof topic !== 'string') continue;
|
|
628
|
-
const id = topic.trim();
|
|
629
|
-
if (!id || seen.has(id)) continue;
|
|
630
|
-
seen.add(id);
|
|
631
|
-
clean.push(id);
|
|
632
|
-
}
|
|
633
|
-
return clean;
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
function describeSessionTopic(topic, isZh = false) {
|
|
637
|
-
const normalized = topic.toLowerCase().replace(/[_\s]+/g, '-');
|
|
638
|
-
|
|
639
|
-
if (normalized.includes('dream') && normalized.includes('segments')) {
|
|
640
|
-
return isZh
|
|
641
|
-
? '梦境记忆片段的抽取与整理'
|
|
642
|
-
: 'Dream memory segment extraction and organization';
|
|
643
|
-
}
|
|
644
|
-
if (normalized.includes('dream') && normalized.includes('session') && normalized.includes('extraction')) {
|
|
645
|
-
return isZh
|
|
646
|
-
? '梦境会话记忆的抽取质量'
|
|
647
|
-
: 'Dream session-memory extraction quality';
|
|
648
|
-
}
|
|
649
|
-
if (normalized.includes('system-prompt') && normalized.includes('localization')) {
|
|
650
|
-
return isZh
|
|
651
|
-
? '系统提示词的中英文一致性'
|
|
652
|
-
: 'system prompt language localization';
|
|
653
|
-
}
|
|
654
|
-
if (normalized.includes('default-character') && normalized.includes('prompt-soul')) {
|
|
655
|
-
return isZh
|
|
656
|
-
? '默认角色灵魂提示词的表达方式'
|
|
657
|
-
: 'default persona soul prompt wording';
|
|
658
|
-
}
|
|
659
|
-
if (normalized.includes('prompt') && normalized.includes('soul')) {
|
|
660
|
-
return isZh
|
|
661
|
-
? '角色灵魂提示词的表达方式'
|
|
662
|
-
: 'persona soul prompt wording';
|
|
663
|
-
}
|
|
664
|
-
if (normalized.includes('openai-responses')) {
|
|
665
|
-
return isZh
|
|
666
|
-
? 'Yeaft 的 OpenAI Responses 适配与模型配置'
|
|
667
|
-
: 'Yeaft OpenAI Responses adapter and model configuration';
|
|
668
|
-
}
|
|
669
|
-
if (normalized.includes('model-config-isolation')) {
|
|
670
|
-
return isZh
|
|
671
|
-
? 'Yeaft 的模型配置隔离'
|
|
672
|
-
: 'Yeaft model configuration isolation';
|
|
673
|
-
}
|
|
674
|
-
if (normalized.includes('route-forward') || normalized.includes('handoff')) {
|
|
675
|
-
return isZh
|
|
676
|
-
? 'Yeaft 的会话路由交接与可见性'
|
|
677
|
-
: 'Yeaft session routing handoff and visibility';
|
|
678
|
-
}
|
|
679
|
-
if (normalized.includes('copilot-cli') || normalized.includes('chat-session')) {
|
|
680
|
-
return isZh
|
|
681
|
-
? 'Copilot CLI 的聊天会话行为'
|
|
682
|
-
: 'Copilot CLI chat session behavior';
|
|
683
|
-
}
|
|
684
|
-
if (normalized.includes('claude-opus')) {
|
|
685
|
-
return isZh
|
|
686
|
-
? 'Yeaft 的 Claude Opus 模型接入'
|
|
687
|
-
: 'Yeaft Claude Opus model integration';
|
|
688
|
-
}
|
|
689
|
-
if (normalized.includes('pr-workflow')) {
|
|
690
|
-
return isZh
|
|
691
|
-
? '项目的 PR review、merge 和 tag 发布流程'
|
|
692
|
-
: 'project PR review, merge, and tag release workflow';
|
|
693
|
-
}
|
|
694
|
-
if (/\bpr[-/]?\d+\b/.test(normalized) || normalized.includes('release') || /v\d+\.\d+\.\d+/.test(normalized)) {
|
|
695
|
-
return isZh
|
|
696
|
-
? '最近的 PR 修复、review、merge 和 tag 发布流程'
|
|
697
|
-
: 'recent PR fixes, review, merge, and tag release work';
|
|
698
|
-
}
|
|
699
|
-
if (normalized.includes('active-scope')) {
|
|
700
|
-
return isZh
|
|
701
|
-
? '当前会话上下文的提示词呈现'
|
|
702
|
-
: 'current session context prompt rendering';
|
|
703
|
-
}
|
|
704
|
-
if (normalized.includes('prompt') || normalized.includes('system')) {
|
|
705
|
-
return isZh
|
|
706
|
-
? '近期的系统提示词调整'
|
|
707
|
-
: humanizeTopicSlug(topic, false) || 'recent system prompt work';
|
|
708
|
-
}
|
|
709
|
-
if (normalized.includes('dream')) {
|
|
710
|
-
return isZh
|
|
711
|
-
? '近期的 Dream 记忆维护工作'
|
|
712
|
-
: humanizeTopicSlug(topic, false) || 'recent Dream memory work';
|
|
713
|
-
}
|
|
714
|
-
if (normalized.includes('session')) {
|
|
715
|
-
return isZh
|
|
716
|
-
? '近期的会话上下文调整'
|
|
717
|
-
: humanizeTopicSlug(topic, false) || 'recent session context work';
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
if (isZh) return '近期的项目协作事项';
|
|
721
|
-
return humanizeTopicSlug(topic, false) || 'recent session collaboration topics';
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
function humanizeTopicSlug(topic, isZh = false) {
|
|
725
|
-
if (isZh) return '';
|
|
726
|
-
const words = topic
|
|
727
|
-
.replace(/[\/_-]+/g, ' ')
|
|
728
|
-
.replace(/\bv\d+(?:\.\d+)+\b/gi, '')
|
|
729
|
-
.replace(/\bpr\s*\d+\b/gi, '')
|
|
730
|
-
.trim()
|
|
731
|
-
.split(/\s+/)
|
|
732
|
-
.filter(Boolean);
|
|
733
|
-
if (words.length === 0) return '';
|
|
734
|
-
|
|
735
|
-
const normalizedWords = words.map(word => {
|
|
736
|
-
const lower = word.toLowerCase();
|
|
737
|
-
if (lower === 'yeaft') return 'Yeaft';
|
|
738
|
-
if (lower === 'project') return 'project';
|
|
739
|
-
if (lower === 'config') return 'configuration';
|
|
740
|
-
if (lower === 'isolation') return 'isolation';
|
|
741
|
-
if (lower === 'rendering') return 'rendering';
|
|
742
|
-
if (lower === 'workflow') return 'workflow';
|
|
743
|
-
if (lower === 'session') return 'session';
|
|
744
|
-
if (lower === 'context') return 'context';
|
|
745
|
-
return word;
|
|
746
|
-
});
|
|
747
|
-
|
|
748
|
-
return normalizedWords.join(' ');
|
|
749
|
-
}
|
|
750
|
-
|
|
751
467
|
function normalizeSessionMemberIds(members) {
|
|
752
468
|
if (!Array.isArray(members)) return [];
|
|
753
469
|
const clean = [];
|
|
@@ -764,7 +480,7 @@ function normalizeSessionMemberIds(members) {
|
|
|
764
480
|
|
|
765
481
|
function renderMultiVpRouting(activeScope, lang) {
|
|
766
482
|
if (!activeScope || typeof activeScope !== 'object') return '';
|
|
767
|
-
const ownId = firstNonEmptyString(activeScope.
|
|
483
|
+
const ownId = firstNonEmptyString(activeScope.vpId);
|
|
768
484
|
const members = normalizeSessionMemberIds(activeScope.sessionMembers || activeScope.members);
|
|
769
485
|
const peers = ownId ? members.filter((member) => member !== ownId) : members;
|
|
770
486
|
if (peers.length === 0) return '';
|
|
@@ -793,33 +509,6 @@ function renderMultiVpRouting(activeScope, lang) {
|
|
|
793
509
|
].join('\n');
|
|
794
510
|
}
|
|
795
511
|
|
|
796
|
-
/**
|
|
797
|
-
* Render a one-line envelope summary. Pulls the small set of routing
|
|
798
|
-
* fields we surface to the LLM (sender, intent, originating user) and
|
|
799
|
-
* leaves the rest in AMS. Returns '' when the envelope carries no
|
|
800
|
-
* useful signal.
|
|
801
|
-
*
|
|
802
|
-
* @param {object|null|undefined} envelope
|
|
803
|
-
* @returns {string}
|
|
804
|
-
*/
|
|
805
|
-
function renderEnvelopeLine(envelope, isZh = false) {
|
|
806
|
-
if (!envelope || typeof envelope !== 'object') return '';
|
|
807
|
-
const segments = [];
|
|
808
|
-
const fromVp = typeof envelope.fromVpId === 'string' && envelope.fromVpId.trim()
|
|
809
|
-
? envelope.fromVpId.trim()
|
|
810
|
-
: (typeof envelope.senderVpId === 'string' ? envelope.senderVpId.trim() : '');
|
|
811
|
-
if (fromVp) segments.push(`${isZh ? '来自' : 'from'}=${fromVp}`);
|
|
812
|
-
const fromUser = typeof envelope.fromUserId === 'string' && envelope.fromUserId.trim()
|
|
813
|
-
? envelope.fromUserId.trim()
|
|
814
|
-
: '';
|
|
815
|
-
if (fromUser) segments.push(`${isZh ? '用户' : 'user'}=${fromUser}`);
|
|
816
|
-
const intent = typeof envelope.intent === 'string' && envelope.intent.trim()
|
|
817
|
-
? envelope.intent.trim()
|
|
818
|
-
: '';
|
|
819
|
-
if (intent) segments.push(`${isZh ? '意图' : 'intent'}=${intent}`);
|
|
820
|
-
return segments.join(' ');
|
|
821
|
-
}
|
|
822
|
-
|
|
823
512
|
// ─── Phase 1: Worker / Router prompt splits ──────────────────────
|
|
824
513
|
//
|
|
825
514
|
// DESIGN.md (multi-VP redesign) describes two distinct prompt shapes:
|
|
@@ -830,7 +519,7 @@ function renderEnvelopeLine(envelope, isZh = false) {
|
|
|
830
519
|
// carries Layer-A summaries + UserProfile + CoreMemory, AMS OnDemand
|
|
831
520
|
// carries the per-turn FTS hits. The worker shape that survives is:
|
|
832
521
|
// harness/worker-shape — optional descriptive metadata
|
|
833
|
-
// buildSystemPrompt(...) — ① Identity ② Rules ③ Memory ④
|
|
522
|
+
// buildSystemPrompt(...) — ① Identity ② Rules ③ Memory ④ Routing
|
|
834
523
|
// optional taskScope/turnScope — caller-provided pass-through strings
|
|
835
524
|
// `renderLayerASummaries` is no longer called inside the worker prompt
|
|
836
525
|
// because AMS already renders the same summaries — calling both was
|
|
@@ -891,15 +580,12 @@ export function renderLayerASummaries(summaries, language = 'en') {
|
|
|
891
580
|
*
|
|
892
581
|
* Output sections (DESIGN-PROMPT §3 layered concepts):
|
|
893
582
|
* harness/worker-shape (optional) — descriptive metadata
|
|
894
|
-
* buildSystemPrompt(...) — ① Identity ② Rules ③ Memory ④
|
|
583
|
+
* buildSystemPrompt(...) — ① Identity ② Rules ③ Memory ④ Routing
|
|
895
584
|
*
|
|
896
|
-
* Earlier
|
|
897
|
-
*
|
|
898
|
-
*
|
|
899
|
-
*
|
|
900
|
-
* rendered by `buildSystemPrompt` itself. Both pass-through params
|
|
901
|
-
* had zero remaining callers when v1 landed; removing them prevents the
|
|
902
|
-
* "two ways to describe scope" drift §1 set out to eliminate.
|
|
585
|
+
* Earlier variants accepted `taskScope` and `turnScope` pass-through
|
|
586
|
+
* strings so callers could append their own scope blocks. That surface is
|
|
587
|
+
* retired. `activeScope` now carries only the VP identity and Session roster
|
|
588
|
+
* needed to render the deterministic multi-VP routing contract.
|
|
903
589
|
*
|
|
904
590
|
* @param {{
|
|
905
591
|
* language?: 'en'|'zh',
|
|
@@ -924,7 +610,7 @@ export function buildWorkerPrompt(params = {}) {
|
|
|
924
610
|
if (shape) parts.push(shape);
|
|
925
611
|
}
|
|
926
612
|
|
|
927
|
-
// Identity + Rules + Memory +
|
|
613
|
+
// Identity + Rules + Memory + Routing (DESIGN-PROMPT §3).
|
|
928
614
|
const baseBlock = buildSystemPrompt({ ...rest, language: effectiveLang });
|
|
929
615
|
if (baseBlock) parts.push(baseBlock);
|
|
930
616
|
|
package/yeaft/tasks/manager.js
CHANGED
|
@@ -20,7 +20,6 @@ import { getRuntimePlatformInfo } from '../runtime-platform.js';
|
|
|
20
20
|
const LOG_PREVIEW_BYTES = 4096;
|
|
21
21
|
const SUB_AGENT_LOG_PREVIEW_BYTES = 1024 * 1024;
|
|
22
22
|
const DEFAULT_CANCEL_ESCALATION_MS = 2000;
|
|
23
|
-
const PROMPT_TASK_LIMIT = 5;
|
|
24
23
|
|
|
25
24
|
function logPreviewBytesFor(task) {
|
|
26
25
|
return task?.kind === 'sub_agent' ? SUB_AGENT_LOG_PREVIEW_BYTES : LOG_PREVIEW_BYTES;
|
|
@@ -55,37 +54,6 @@ function publicSnapshot(task) {
|
|
|
55
54
|
};
|
|
56
55
|
}
|
|
57
56
|
|
|
58
|
-
function taskKindLabel(kind, language) {
|
|
59
|
-
const zh = String(language || '').toLowerCase().startsWith('zh');
|
|
60
|
-
if (kind === 'sub_agent') return zh ? '子 Agent' : 'sub-agent';
|
|
61
|
-
if (kind === 'shell') return zh ? '后台命令' : 'background command';
|
|
62
|
-
return zh ? '后台任务' : 'background task';
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function safeTaskName(task) {
|
|
66
|
-
const name = typeof task?.runtime?.name === 'string' ? task.runtime.name.trim() : '';
|
|
67
|
-
return /^[\p{L}\p{N}][\p{L}\p{N}._-]{0,63}$/u.test(name) ? name : '';
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function promptTaskLabel(task, language) {
|
|
71
|
-
const name = task?.kind === 'sub_agent' ? safeTaskName(task) : '';
|
|
72
|
-
if (!name) return taskKindLabel(task?.kind, language);
|
|
73
|
-
return String(language || '').toLowerCase().startsWith('zh')
|
|
74
|
-
? `子 Agent ${name}`
|
|
75
|
-
: `sub-agent ${name}`;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function taskStatusLabel(status, language) {
|
|
79
|
-
const zh = String(language || '').toLowerCase().startsWith('zh');
|
|
80
|
-
if (!zh) return String(status || 'running').replace(/_/g, ' ');
|
|
81
|
-
const labels = {
|
|
82
|
-
running: '运行中',
|
|
83
|
-
queued: '等待中',
|
|
84
|
-
cancelling: '正在取消',
|
|
85
|
-
};
|
|
86
|
-
return labels[status] || String(status || '运行中').replace(/_/g, ' ');
|
|
87
|
-
}
|
|
88
|
-
|
|
89
57
|
export class TaskManager {
|
|
90
58
|
constructor({ yeaftDir, onEvent = null, runtimePlatform = null, cancelEscalationMs = DEFAULT_CANCEL_ESCALATION_MS } = {}) {
|
|
91
59
|
if (!yeaftDir) throw new Error('TaskManager requires yeaftDir');
|
|
@@ -384,28 +352,4 @@ export class TaskManager {
|
|
|
384
352
|
this.#emit('updated', task);
|
|
385
353
|
return publicSnapshot(task);
|
|
386
354
|
}
|
|
387
|
-
|
|
388
|
-
renderActiveTasksForPrompt(sessionId = null, { language = 'en', limit = PROMPT_TASK_LIMIT } = {}) {
|
|
389
|
-
const tasks = this.listActiveTasks(sessionId);
|
|
390
|
-
if (tasks.length === 0) return '';
|
|
391
|
-
const zh = String(language || '').toLowerCase().startsWith('zh');
|
|
392
|
-
const maxTasks = Number.isFinite(limit) && limit > 0 ? Math.floor(limit) : PROMPT_TASK_LIMIT;
|
|
393
|
-
const visible = tasks.slice(0, maxTasks);
|
|
394
|
-
const lines = [zh ? '## 可能相关的任务' : '## Possibly Relevant Tasks'];
|
|
395
|
-
lines.push(zh
|
|
396
|
-
? '以下任务仍在后台运行。需要进度或完整输出时使用任务工具查询;不要把它们当成记忆事实。'
|
|
397
|
-
: 'These tasks are still running in the background. Use the task tools for progress or full output; do not treat them as memory facts.');
|
|
398
|
-
for (const task of visible) {
|
|
399
|
-
const title = promptTaskLabel(task, language);
|
|
400
|
-
const detail = zh
|
|
401
|
-
? `${taskKindLabel(task.kind, language)},${taskStatusLabel(task.status, language)}`
|
|
402
|
-
: `${taskKindLabel(task.kind, language)}, ${taskStatusLabel(task.status, language)}`;
|
|
403
|
-
lines.push(`- ${title} (${detail})`);
|
|
404
|
-
}
|
|
405
|
-
if (tasks.length > visible.length) {
|
|
406
|
-
const remaining = tasks.length - visible.length;
|
|
407
|
-
lines.push(zh ? `- 另有 ${remaining} 个运行中任务,可用任务列表查看。` : `- ${remaining} more running task${remaining === 1 ? '' : 's'}; use the task list to inspect them.`);
|
|
408
|
-
}
|
|
409
|
-
return lines.join('\n');
|
|
410
|
-
}
|
|
411
355
|
}
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
## Compatibility Note
|
|
4
4
|
|
|
5
|
-
Runtime prompt assembly now uses `core.md
|
|
5
|
+
Runtime prompt assembly now uses `core.md`; tool behavior is carried by provider tool schemas. This file remains packaged for deployments or integrations that still read the historical fragment directly.
|
|
6
6
|
|
|
7
7
|
<!-- lang:zh -->
|
|
8
8
|
|
|
9
9
|
## 兼容说明
|
|
10
10
|
|
|
11
|
-
运行时 Prompt
|
|
11
|
+
运行时 Prompt 现在使用 `core.md`;工具行为由 provider tool schema 承载。此文件继续随包发布,只用于仍直接读取旧 fragment 的部署或集成兼容。
|
|
@@ -20,7 +20,6 @@ export const ALWAYS_VISIBLE_TOOL_NAMES = Object.freeze([
|
|
|
20
20
|
'Glob',
|
|
21
21
|
'Grep',
|
|
22
22
|
'ListDir',
|
|
23
|
-
'TodoWrite',
|
|
24
23
|
'ViewImage',
|
|
25
24
|
]);
|
|
26
25
|
|
|
@@ -53,11 +52,6 @@ export const CONDITIONAL_BUILTIN_TOOL_NAMES = new Set([
|
|
|
53
52
|
'ListAgents',
|
|
54
53
|
'RouteForward',
|
|
55
54
|
'CreateWorkItem',
|
|
56
|
-
// Legacy compatibility only. New planning is a single provider response:
|
|
57
|
-
// visible prose + TodoWrite + the first justified work-tool call. Keeping the
|
|
58
|
-
// definition registered lets old direct callers resolve it without paying a
|
|
59
|
-
// dedicated StartPlan -> provider -> TodoWrite round trip on every new task.
|
|
60
|
-
'StartPlan',
|
|
61
55
|
'JsRepl',
|
|
62
56
|
'NotebookEdit',
|
|
63
57
|
'ImageGeneration',
|
package/yeaft/tools/file-read.js
CHANGED
|
@@ -27,11 +27,10 @@ const BINARY_EXTS = new Set([
|
|
|
27
27
|
/** Max file size to read (10 MB). */
|
|
28
28
|
const MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
29
29
|
|
|
30
|
-
/** Default number of lines to read. Aligned with the
|
|
31
|
-
* lines" rule
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* round-trip this tool's prompt guidance promises to avoid). */
|
|
30
|
+
/** Default number of lines to read. Aligned with the FileRead tool schema's
|
|
31
|
+
* "large file = >3000 lines" rule so a ≤3000-line file is returned in one
|
|
32
|
+
* call (no silent truncation that would trigger a follow-up `offset:3000`
|
|
33
|
+
* call — exactly the round-trip the tool guidance avoids). */
|
|
35
34
|
const DEFAULT_LIMIT = 3000;
|
|
36
35
|
|
|
37
36
|
/** Keep raw output close to the model-facing 32 KiB budget while leaving
|