@yeaft/webchat-agent 1.0.514 → 1.0.515
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 +9 -44
- package/yeaft/prompts.js +27 -320
- package/yeaft/tasks/manager.js +0 -56
- package/yeaft/templates/common-rules.md +2 -2
- package/yeaft/tools/file-read.js +4 -5
- package/yeaft/web-bridge.js +3 -30
- package/yeaft/templates/tool-guidance.md +0 -11
|
Binary file
|
package/package.json
CHANGED
package/yeaft/engine.js
CHANGED
|
@@ -1250,8 +1250,8 @@ export class Engine {
|
|
|
1250
1250
|
}
|
|
1251
1251
|
|
|
1252
1252
|
/**
|
|
1253
|
-
* Build the system prompt with the AMS-rendered Memory block,
|
|
1254
|
-
*
|
|
1253
|
+
* Build the system prompt with the AMS-rendered Memory block, routing
|
|
1254
|
+
* metadata, and skill content. The legacy multi-path
|
|
1255
1255
|
* Memory injection (FTS-formatted + AMS snapshot + Layer-A summaries +
|
|
1256
1256
|
* userProfile + coreMemory) was retired in DESIGN-PROMPT v1; callers
|
|
1257
1257
|
* now thread a single `memoryInjection` string composed upstream from
|
|
@@ -1260,8 +1260,7 @@ export class Engine {
|
|
|
1260
1260
|
* Routes through `buildWorkerPrompt`, which:
|
|
1261
1261
|
* - Lays in the persona-as-identity block (or Yeaft identity fallback)
|
|
1262
1262
|
* - Adds the Memory section (passed in as `memoryInjection`)
|
|
1263
|
-
* - Adds
|
|
1264
|
-
* - Forwards optional `taskCtx` for the legacy task-context sub-block
|
|
1263
|
+
* - Adds multi-VP routing metadata from `activeScope` when applicable
|
|
1265
1264
|
*
|
|
1266
1265
|
* @param {object} args
|
|
1267
1266
|
* @param {string} args.prompt — user prompt (for skill relevance matching)
|
|
@@ -1273,11 +1272,10 @@ export class Engine {
|
|
|
1273
1272
|
* @param {string} [args.projectLabel] — current Project name and id for prompt attribution
|
|
1274
1273
|
* @param {string} [args.workCenterInstructions] — frozen Agent-level Work Center policy
|
|
1275
1274
|
* @param {string} [args.projectDoc] — resolved CLAUDE.md / AGENTS.md text (already truncated)
|
|
1276
|
-
* @param {object} [args.taskCtx] — legacy task-context sub-block (optional)
|
|
1277
1275
|
* @param {string} [args.explicitSkillName] — leading /skill:<name> command, if present
|
|
1278
1276
|
* @returns {string}
|
|
1279
1277
|
*/
|
|
1280
|
-
#buildSystemPrompt({ prompt, memoryInjection, vpPersona, activeScope, sessionAnnouncement, projectInstruction, projectLabel, workCenterInstructions, projectDoc,
|
|
1278
|
+
#buildSystemPrompt({ prompt, memoryInjection, vpPersona, activeScope, sessionAnnouncement, projectInstruction, projectLabel, workCenterInstructions, projectDoc, promptNotices = [], explicitSkillName, resolvedSkillContent = null } = {}) {
|
|
1281
1279
|
// #runQuery resolves Skill selection at each provider-request boundary so
|
|
1282
1280
|
// a live Plugin policy change cannot leave stale content in the next prompt.
|
|
1283
1281
|
// Keep the local fallback for internal callers that do not need selection
|
|
@@ -1292,21 +1290,8 @@ export class Engine {
|
|
|
1292
1290
|
}
|
|
1293
1291
|
}
|
|
1294
1292
|
|
|
1295
|
-
// Prompt guidance must describe the same canonical capability
|
|
1296
|
-
// intersection that reaches provider schemas and execution.
|
|
1297
|
-
const registeredToolNames = this.#toolRegistry
|
|
1298
|
-
? this.#toolRegistry.getToolNames({
|
|
1299
|
-
plugins: this.#config?.plugins,
|
|
1300
|
-
collabToolPolicy,
|
|
1301
|
-
})
|
|
1302
|
-
: Array.from(this.#tools.keys());
|
|
1303
|
-
const toolNames = activeToolNames instanceof Set
|
|
1304
|
-
? registeredToolNames.filter(name => activeToolNames.has(name))
|
|
1305
|
-
: registeredToolNames;
|
|
1306
|
-
|
|
1307
1293
|
return buildWorkerPrompt({
|
|
1308
1294
|
language: this.#config.language || 'en',
|
|
1309
|
-
toolNames,
|
|
1310
1295
|
memoryInjection,
|
|
1311
1296
|
skillContent,
|
|
1312
1297
|
vpPersona,
|
|
@@ -1317,8 +1302,6 @@ export class Engine {
|
|
|
1317
1302
|
workCenterInstructions,
|
|
1318
1303
|
projectDoc,
|
|
1319
1304
|
runtimePlatform: getRuntimePlatformInfo(),
|
|
1320
|
-
taskCtx,
|
|
1321
|
-
activeTasks,
|
|
1322
1305
|
promptNotices,
|
|
1323
1306
|
// Worker-shape harness is descriptive metadata for human inspection;
|
|
1324
1307
|
// production prompts skip it to save tokens. Re-enable via env when
|
|
@@ -2306,18 +2289,13 @@ export class Engine {
|
|
|
2306
2289
|
}))
|
|
2307
2290
|
: [];
|
|
2308
2291
|
|
|
2309
|
-
// ───
|
|
2310
|
-
//
|
|
2311
|
-
//
|
|
2312
|
-
//
|
|
2313
|
-
const activeSessionTopics = topicScopesForResident
|
|
2314
|
-
.map(scope => scope.replace(/^sessions\/[^/]+\/topic\//, ''));
|
|
2292
|
+
// ─── Multi-VP routing scope ──────────────────────────────────
|
|
2293
|
+
// Only identity and peer membership affect the routing contract rendered in
|
|
2294
|
+
// the system prompt. Session bookkeeping and inferred topics remain in their
|
|
2295
|
+
// owning runtime/memory paths instead of being mirrored into prompt metadata.
|
|
2315
2296
|
const activeScope = {
|
|
2316
|
-
|
|
2317
|
-
sessionMember: ownVpIdForAms || '',
|
|
2297
|
+
vpId: ownVpIdForAms || '',
|
|
2318
2298
|
sessionMembers: Array.isArray(sessionMembers) ? sessionMembers : [],
|
|
2319
|
-
sessionTopics: activeSessionTopics,
|
|
2320
|
-
envelope: inboundEnvelope || null,
|
|
2321
2299
|
};
|
|
2322
2300
|
|
|
2323
2301
|
let projectDocSource = this.#getProjectDocBlock(workDir);
|
|
@@ -2332,11 +2310,6 @@ export class Engine {
|
|
|
2332
2310
|
&& typeof this.#taskManager.listActiveTasks === 'function'
|
|
2333
2311
|
? this.#taskManager.listActiveTasks(runtimeSessionId)
|
|
2334
2312
|
: [];
|
|
2335
|
-
let activeTasks = this.#taskManager
|
|
2336
|
-
? this.#taskManager.renderActiveTasksForPrompt(runtimeSessionId, {
|
|
2337
|
-
language: this.#config.language || 'en',
|
|
2338
|
-
})
|
|
2339
|
-
: '';
|
|
2340
2313
|
const registeredToolNames = this.#toolRegistry
|
|
2341
2314
|
? this.#toolRegistry.getToolNames({
|
|
2342
2315
|
collabToolPolicy: effectiveCollabToolPolicy,
|
|
@@ -2407,9 +2380,6 @@ export class Engine {
|
|
|
2407
2380
|
projectLabel,
|
|
2408
2381
|
workCenterInstructions,
|
|
2409
2382
|
projectDoc: projectDocContext.text,
|
|
2410
|
-
activeTasks,
|
|
2411
|
-
collabToolPolicy: effectiveCollabToolPolicy,
|
|
2412
|
-
activeToolNames,
|
|
2413
2383
|
promptNotices,
|
|
2414
2384
|
explicitSkillName,
|
|
2415
2385
|
resolvedSkillContent,
|
|
@@ -2825,11 +2795,6 @@ export class Engine {
|
|
|
2825
2795
|
&& typeof this.#taskManager.listActiveTasks === 'function'
|
|
2826
2796
|
? this.#taskManager.listActiveTasks(runtimeSessionId)
|
|
2827
2797
|
: [];
|
|
2828
|
-
activeTasks = this.#taskManager
|
|
2829
|
-
? this.#taskManager.renderActiveTasksForPrompt(runtimeSessionId, {
|
|
2830
|
-
language: this.#config.language || 'en',
|
|
2831
|
-
})
|
|
2832
|
-
: '';
|
|
2833
2798
|
activeToolNames = resolveCurrentActiveToolNames();
|
|
2834
2799
|
for (const name of [...discoveredToolNames]) {
|
|
2835
2800
|
if (this.#toolRegistry?.has(name)) activeToolNames?.add(name);
|
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.
|
|
@@ -192,12 +189,6 @@ const PROMPTS = {
|
|
|
192
189
|
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
190
|
date: (d) => `Date: ${d}`,
|
|
194
191
|
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
192
|
multiVpRoutingHeader: '## multi_vp_routing',
|
|
202
193
|
sessionAnnouncementHeader: '[Session Announcement]',
|
|
203
194
|
projectInstructionHeader: '[Project Instruction]',
|
|
@@ -218,12 +209,6 @@ const PROMPTS = {
|
|
|
218
209
|
identity: '你正在当前会话中参与协作。保持用户上下文,回答要基于证据;需要工具时使用工具,但不要把自己没有实际执行过的事说成已经执行。',
|
|
219
210
|
date: (d) => `日期:${d}`,
|
|
220
211
|
dream: '你处于梦境模式。回顾过去的对话,整理和巩固记忆。',
|
|
221
|
-
// DESIGN-PROMPT §3 ④ — 当前会话上下文。
|
|
222
|
-
activeScopeHeader: '## 当前会话上下文',
|
|
223
|
-
activeScopeSessionIdLabel: '会话 ID',
|
|
224
|
-
activeScopeMembersLabel: '会话成员',
|
|
225
|
-
activeScopeTopicsLabel: '当前讨论',
|
|
226
|
-
activeScopeEnvelopeLabel: '转交消息',
|
|
227
212
|
multiVpRoutingHeader: '## multi_vp_routing',
|
|
228
213
|
sessionAnnouncementHeader: '[会话公告]',
|
|
229
214
|
projectInstructionHeader: '[Project 指令]',
|
|
@@ -275,28 +260,22 @@ export function normalizePromptLanguage(language) {
|
|
|
275
260
|
*
|
|
276
261
|
* Prompt structure (DESIGN-PROMPT §3):
|
|
277
262
|
* ① Identity — Core identity (persona or Yeaft fallback)
|
|
278
|
-
* ② Rules — Session
|
|
263
|
+
* ② Rules — Session/Project instructions, date, runtime, and skills
|
|
279
264
|
* ③ Memory — Single block produced by the AMS render outlet
|
|
280
265
|
* (callers pass it as `memoryInjection`).
|
|
281
|
-
* ④
|
|
282
|
-
* (session / vp / members / envelope IDs).
|
|
283
|
-
* (The previous standalone user_profile / core_memory blocks are
|
|
284
|
-
* gone — those signals now arrive through AMS Resident. Task
|
|
285
|
-
* context (`taskCtx`) was wired into Active Scope by task-334e
|
|
286
|
-
* but never actually populated by the engine; removed 2026-05-13.)
|
|
266
|
+
* ④ Routing — Multi-VP identity and handoff metadata when applicable
|
|
287
267
|
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
*
|
|
292
|
-
* @param {
|
|
293
|
-
* @param {string
|
|
294
|
-
* @param {
|
|
268
|
+
* Generic Session IDs, inferred topics, active-task labels, and repeated tool
|
|
269
|
+
* guidance are intentionally omitted from the system prompt.
|
|
270
|
+
*
|
|
271
|
+
* Multi-VP routing params:
|
|
272
|
+
* @param {object} [activeScope] — routing scope for this turn
|
|
273
|
+
* @param {string} [activeScope.vpId] current VP identity
|
|
274
|
+
* @param {string[]} [activeScope.sessionMembers] current Session roster
|
|
295
275
|
*
|
|
296
276
|
* @param {{
|
|
297
277
|
* language?: string,
|
|
298
278
|
* mode?: string,
|
|
299
|
-
* toolNames?: string[],
|
|
300
279
|
* memoryInjection?: string,
|
|
301
280
|
* skillContent?: string,
|
|
302
281
|
* activeScope?: object,
|
|
@@ -313,7 +292,6 @@ export function normalizePromptLanguage(language) {
|
|
|
313
292
|
export function buildSystemPrompt({
|
|
314
293
|
language = 'en',
|
|
315
294
|
mode,
|
|
316
|
-
toolNames = [],
|
|
317
295
|
memoryInjection,
|
|
318
296
|
skillContent,
|
|
319
297
|
activeScope,
|
|
@@ -324,7 +302,6 @@ export function buildSystemPrompt({
|
|
|
324
302
|
workCenterInstructions = '',
|
|
325
303
|
projectDoc = '',
|
|
326
304
|
runtimePlatform,
|
|
327
|
-
activeTasks = '',
|
|
328
305
|
promptNotices = [],
|
|
329
306
|
} = {}) {
|
|
330
307
|
// Normalize app locales like `zh-CN` to prompt dictionary/template keys.
|
|
@@ -405,20 +382,15 @@ export function buildSystemPrompt({
|
|
|
405
382
|
parts.push(dreamTemplate || lang.dream);
|
|
406
383
|
}
|
|
407
384
|
|
|
408
|
-
// ─── 4. Runtime Platform
|
|
385
|
+
// ─── 4. Runtime Platform ─────────────────────────────
|
|
386
|
+
// Tool schemas already carry their operational guidance. Repeating selected
|
|
387
|
+
// tool instructions in the system prompt wastes tokens and can drift from
|
|
388
|
+
// the executable schema, so only platform facts are rendered here.
|
|
409
389
|
const runtimePlatformBlock = renderRuntimePlatformPrompt(runtimePlatform || getRuntimePlatformInfo(), effectiveLang);
|
|
410
390
|
if (runtimePlatformBlock) {
|
|
411
391
|
parts.push(runtimePlatformBlock);
|
|
412
392
|
}
|
|
413
393
|
|
|
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
394
|
// ─── 5. Skills Section ─────────────────────────────────
|
|
423
395
|
if (skillContent) {
|
|
424
396
|
parts.push(skillContent);
|
|
@@ -436,16 +408,10 @@ export function buildSystemPrompt({
|
|
|
436
408
|
parts.push(memoryInjection.trim());
|
|
437
409
|
}
|
|
438
410
|
|
|
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
|
-
|
|
411
|
+
// ─── 7. Multi-VP routing ────────────────────────────────
|
|
412
|
+
// Generic Session IDs, inferred topics, and live task labels are runtime
|
|
413
|
+
// bookkeeping rather than model instructions. Keep only the routing block
|
|
414
|
+
// whose peer identities and RouteForward contract affect model behaviour.
|
|
449
415
|
const multiVpRoutingBlock = renderMultiVpRouting(activeScope, lang);
|
|
450
416
|
if (multiVpRoutingBlock) parts.push(multiVpRoutingBlock);
|
|
451
417
|
|
|
@@ -454,64 +420,6 @@ export function buildSystemPrompt({
|
|
|
454
420
|
|
|
455
421
|
// ─── helpers ─────────────────────────────────────────────────────
|
|
456
422
|
|
|
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
423
|
/**
|
|
516
424
|
* Render the VP identity block when the engine is running on behalf of an
|
|
517
425
|
* addressed VP. The `persona` body from role.md is the only soul source;
|
|
@@ -570,32 +478,6 @@ function selectVpPersonaBody(vpPersona, effectiveLang) {
|
|
|
570
478
|
|
|
571
479
|
|
|
572
480
|
|
|
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
481
|
function firstNonEmptyString(...values) {
|
|
600
482
|
for (const value of values) {
|
|
601
483
|
if (typeof value === 'string' && value.trim()) return value.trim();
|
|
@@ -603,151 +485,6 @@ function firstNonEmptyString(...values) {
|
|
|
603
485
|
return '';
|
|
604
486
|
}
|
|
605
487
|
|
|
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
488
|
function normalizeSessionMemberIds(members) {
|
|
752
489
|
if (!Array.isArray(members)) return [];
|
|
753
490
|
const clean = [];
|
|
@@ -764,7 +501,7 @@ function normalizeSessionMemberIds(members) {
|
|
|
764
501
|
|
|
765
502
|
function renderMultiVpRouting(activeScope, lang) {
|
|
766
503
|
if (!activeScope || typeof activeScope !== 'object') return '';
|
|
767
|
-
const ownId = firstNonEmptyString(activeScope.
|
|
504
|
+
const ownId = firstNonEmptyString(activeScope.vpId);
|
|
768
505
|
const members = normalizeSessionMemberIds(activeScope.sessionMembers || activeScope.members);
|
|
769
506
|
const peers = ownId ? members.filter((member) => member !== ownId) : members;
|
|
770
507
|
if (peers.length === 0) return '';
|
|
@@ -793,33 +530,6 @@ function renderMultiVpRouting(activeScope, lang) {
|
|
|
793
530
|
].join('\n');
|
|
794
531
|
}
|
|
795
532
|
|
|
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
533
|
// ─── Phase 1: Worker / Router prompt splits ──────────────────────
|
|
824
534
|
//
|
|
825
535
|
// DESIGN.md (multi-VP redesign) describes two distinct prompt shapes:
|
|
@@ -830,7 +540,7 @@ function renderEnvelopeLine(envelope, isZh = false) {
|
|
|
830
540
|
// carries Layer-A summaries + UserProfile + CoreMemory, AMS OnDemand
|
|
831
541
|
// carries the per-turn FTS hits. The worker shape that survives is:
|
|
832
542
|
// harness/worker-shape — optional descriptive metadata
|
|
833
|
-
// buildSystemPrompt(...) — ① Identity ② Rules ③ Memory ④
|
|
543
|
+
// buildSystemPrompt(...) — ① Identity ② Rules ③ Memory ④ Routing
|
|
834
544
|
// optional taskScope/turnScope — caller-provided pass-through strings
|
|
835
545
|
// `renderLayerASummaries` is no longer called inside the worker prompt
|
|
836
546
|
// because AMS already renders the same summaries — calling both was
|
|
@@ -891,15 +601,12 @@ export function renderLayerASummaries(summaries, language = 'en') {
|
|
|
891
601
|
*
|
|
892
602
|
* Output sections (DESIGN-PROMPT §3 layered concepts):
|
|
893
603
|
* harness/worker-shape (optional) — descriptive metadata
|
|
894
|
-
* buildSystemPrompt(...) — ① Identity ② Rules ③ Memory ④
|
|
604
|
+
* buildSystemPrompt(...) — ① Identity ② Rules ③ Memory ④ Routing
|
|
895
605
|
*
|
|
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.
|
|
606
|
+
* Earlier variants accepted `taskScope` and `turnScope` pass-through
|
|
607
|
+
* strings so callers could append their own scope blocks. That surface is
|
|
608
|
+
* retired. `activeScope` now carries only the VP identity and Session roster
|
|
609
|
+
* needed to render the deterministic multi-VP routing contract.
|
|
903
610
|
*
|
|
904
611
|
* @param {{
|
|
905
612
|
* language?: 'en'|'zh',
|
|
@@ -924,7 +631,7 @@ export function buildWorkerPrompt(params = {}) {
|
|
|
924
631
|
if (shape) parts.push(shape);
|
|
925
632
|
}
|
|
926
633
|
|
|
927
|
-
// Identity + Rules + Memory +
|
|
634
|
+
// Identity + Rules + Memory + Routing (DESIGN-PROMPT §3).
|
|
928
635
|
const baseBlock = buildSystemPrompt({ ...rest, language: effectiveLang });
|
|
929
636
|
if (baseBlock) parts.push(baseBlock);
|
|
930
637
|
|