@yeaft/webchat-agent 0.1.84 → 0.1.86
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/conversation.js +47 -0
- package/package.json +1 -1
- package/roleplay-dir.js +11 -7
- package/roleplay-i18n.js +86 -0
- package/roleplay.js +75 -4
package/conversation.js
CHANGED
|
@@ -607,6 +607,53 @@ export async function handleUserInput(msg) {
|
|
|
607
607
|
console.log(`[RolePlay] Human responded, resuming from ${fromRole}'s request`);
|
|
608
608
|
}
|
|
609
609
|
|
|
610
|
+
// ★ RolePlay: handle @mention targetRole routing
|
|
611
|
+
const targetRole = msg.targetRole;
|
|
612
|
+
if (targetRole && rpSession && rpSession._routeInitialized) {
|
|
613
|
+
const roleNames = new Set(rpSession.roles.map(r => r.name));
|
|
614
|
+
if (roleNames.has(targetRole)) {
|
|
615
|
+
const targetRoleConfig = rpSession.roles.find(r => r.name === targetRole);
|
|
616
|
+
const targetLabel = targetRoleConfig
|
|
617
|
+
? (targetRoleConfig.icon ? `${targetRoleConfig.icon} ${targetRoleConfig.displayName}` : targetRoleConfig.displayName)
|
|
618
|
+
: targetRole;
|
|
619
|
+
const targetClaudeMd = targetRoleConfig?.claudeMd || '';
|
|
620
|
+
|
|
621
|
+
// Prepend ROLE signal so Claude responds as the target role
|
|
622
|
+
let rolePrefix = `---ROLE: ${targetRole}---\n\n`;
|
|
623
|
+
rolePrefix += `用户指定由 ${targetLabel} 来回复。\n`;
|
|
624
|
+
if (targetClaudeMd) {
|
|
625
|
+
rolePrefix += `<role-context>\n${targetClaudeMd}\n</role-context>\n\n`;
|
|
626
|
+
}
|
|
627
|
+
rolePrefix += `请以 ${targetLabel} 的身份回复以下消息:\n\n`;
|
|
628
|
+
effectivePrompt = rolePrefix + effectivePrompt;
|
|
629
|
+
|
|
630
|
+
// Update rpSession state
|
|
631
|
+
const prevRole = rpSession.currentRole;
|
|
632
|
+
rpSession.currentRole = targetRole;
|
|
633
|
+
if (rpSession.roleStates[targetRole]) {
|
|
634
|
+
rpSession.roleStates[targetRole].status = 'active';
|
|
635
|
+
}
|
|
636
|
+
if (prevRole && prevRole !== targetRole && rpSession.roleStates[prevRole]) {
|
|
637
|
+
rpSession.roleStates[prevRole].status = 'idle';
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// Send roleplay_status update to frontend
|
|
641
|
+
ctx.sendToServer({
|
|
642
|
+
type: 'roleplay_status',
|
|
643
|
+
conversationId,
|
|
644
|
+
currentRole: rpSession.currentRole,
|
|
645
|
+
round: rpSession.round,
|
|
646
|
+
features: rpSession.features ? Array.from(rpSession.features.values()) : [],
|
|
647
|
+
roleStates: rpSession.roleStates || {},
|
|
648
|
+
waitingHuman: false
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
console.log(`[RolePlay] @mention routing: ${prevRole || 'none'} -> ${targetRole}`);
|
|
652
|
+
} else {
|
|
653
|
+
console.warn(`[RolePlay] @mention target role not found: ${targetRole}`);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
610
657
|
const userMessage = {
|
|
611
658
|
type: 'user',
|
|
612
659
|
message: { role: 'user', content: effectivePrompt }
|
package/package.json
CHANGED
package/roleplay-dir.js
CHANGED
|
@@ -24,9 +24,9 @@ import { getRolePlayMessages } from './roleplay-i18n.js';
|
|
|
24
24
|
// Each entry is a list of role names (keys into roleTemplates in i18n).
|
|
25
25
|
const TEAM_ROLES = {
|
|
26
26
|
dev: ['pm', 'dev', 'reviewer', 'tester'],
|
|
27
|
-
writing: ['
|
|
28
|
-
trading: ['
|
|
29
|
-
video: ['director', '
|
|
27
|
+
writing: ['editor', 'writer', 'proofreader'],
|
|
28
|
+
trading: ['analyst', 'strategist', 'risk-manager'],
|
|
29
|
+
video: ['director', 'writer', 'producer'],
|
|
30
30
|
custom: ['pm', 'dev', 'reviewer', 'tester'], // default same as dev
|
|
31
31
|
};
|
|
32
32
|
|
|
@@ -193,9 +193,13 @@ export async function writeSessionClaudeMd(projectDir, sessionName, config) {
|
|
|
193
193
|
const roleSection = buildRoleSection(teamType, language, customRoles);
|
|
194
194
|
|
|
195
195
|
// Build workflow section
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
: m.
|
|
196
|
+
const workflowMap = {
|
|
197
|
+
dev: m.devWorkflow,
|
|
198
|
+
writing: m.writingWorkflow,
|
|
199
|
+
trading: m.tradingWorkflow,
|
|
200
|
+
video: m.videoWorkflow,
|
|
201
|
+
};
|
|
202
|
+
const workflow = workflowMap[teamType] || m.genericWorkflow;
|
|
199
203
|
|
|
200
204
|
const content = `${m.sessionTitle(sessionName)}
|
|
201
205
|
|
|
@@ -278,7 +282,7 @@ export function getDefaultRoles(teamType, language = 'zh-CN') {
|
|
|
278
282
|
if (!tmpl) return { name, displayName: name, icon: '' };
|
|
279
283
|
|
|
280
284
|
// Extract icon and displayName from heading: "## 📋 PM-乔布斯 (pm)"
|
|
281
|
-
const headingMatch = tmpl.heading.match(/^##\s*(\S+)\s+(.+?)\s*\((\w+)\)\s*$/);
|
|
285
|
+
const headingMatch = tmpl.heading.match(/^##\s*(\S+)\s+(.+?)\s*\(([\w-]+)\)\s*$/);
|
|
282
286
|
if (headingMatch) {
|
|
283
287
|
return {
|
|
284
288
|
name: headingMatch[3],
|
package/roleplay-i18n.js
CHANGED
|
@@ -189,6 +189,37 @@ const messages = {
|
|
|
189
189
|
|
|
190
190
|
风格:视觉思维,善于用画面讲故事。`,
|
|
191
191
|
},
|
|
192
|
+
// RolePlay-specific roles (not in Crew templates)
|
|
193
|
+
proofreader: {
|
|
194
|
+
heading: '## 🔎 审校-马伯庸 (proofreader)',
|
|
195
|
+
content: `你是审校-马伯庸。你的职责:
|
|
196
|
+
- 检查内容的逻辑一致性和事实准确性
|
|
197
|
+
- 审核文字质量、错别字和表达规范
|
|
198
|
+
- 核实引用和数据的准确性
|
|
199
|
+
- 提出具体的修改建议
|
|
200
|
+
|
|
201
|
+
风格:考据成瘾,逻辑洁癖,毒舌但建设性,指出问题必给修改方案。`,
|
|
202
|
+
},
|
|
203
|
+
'risk-manager': {
|
|
204
|
+
heading: '## 🛡️ 风控官-塔勒布 (risk-manager)',
|
|
205
|
+
content: `你是风控官-塔勒布。你的职责:
|
|
206
|
+
- 对策略进行压力测试和尾部风险评估
|
|
207
|
+
- 检查仓位是否符合风控原则
|
|
208
|
+
- 审核止损设置和对冲方案
|
|
209
|
+
- 如果策略风险不可接受,直接打回并说明原因
|
|
210
|
+
|
|
211
|
+
风格:尾部风险偏执狂,反脆弱思维,杠铃策略信徒。`,
|
|
212
|
+
},
|
|
213
|
+
producer: {
|
|
214
|
+
heading: '## 🎬 制片-徐克 (producer)',
|
|
215
|
+
content: `你是制片-徐克。你的职责:
|
|
216
|
+
- 审核脚本和分镜的可执行性
|
|
217
|
+
- 评估制作资源需求和技术可行性
|
|
218
|
+
- 把控制作进度和质量标准
|
|
219
|
+
- 生成最终的 AI 视频 prompt 序列
|
|
220
|
+
|
|
221
|
+
风格:视觉想象力爆棚,技术与艺术兼备。`,
|
|
222
|
+
},
|
|
192
223
|
},
|
|
193
224
|
|
|
194
225
|
routeProtocol: `# ROUTE 协议
|
|
@@ -214,6 +245,18 @@ taskTitle: {任务标题}(可选)
|
|
|
214
245
|
3. **审查者** Code Review(不通过 → 返回开发者修复)
|
|
215
246
|
4. **测试者** 运行测试 & 验证(有 bug → 返回开发者修复)
|
|
216
247
|
5. **PM** 验收总结`,
|
|
248
|
+
writingWorkflow: `1. **编辑** 分析需求,确定内容方向和框架
|
|
249
|
+
2. **作者** 根据大纲撰写内容
|
|
250
|
+
3. **审校** 检查逻辑一致性、事实准确性和文字质量(不通过 → 返回作者修改)
|
|
251
|
+
4. **编辑** 验收最终成果`,
|
|
252
|
+
tradingWorkflow: `1. **分析师** 研究市场,输出技术分析和关键价位
|
|
253
|
+
2. **策略师** 综合分析,制定投资策略和仓位方案
|
|
254
|
+
3. **风控官** 压力测试策略,评估尾部风险(不通过 → 返回策略师调整)
|
|
255
|
+
4. **策略师** 确认最终方案并总结`,
|
|
256
|
+
videoWorkflow: `1. **导演** 确定主题、情绪基调和视觉风格
|
|
257
|
+
2. **编剧** 构思故事线,撰写分段脚本
|
|
258
|
+
3. **制片** 审核可行性,生成最终 prompt 序列(不通过 → 返回编剧调整)
|
|
259
|
+
4. **导演** 最终审核并验收`,
|
|
217
260
|
genericWorkflow: '按角色顺序依次完成任务。',
|
|
218
261
|
|
|
219
262
|
projectPathTitle: '# 项目路径',
|
|
@@ -399,6 +442,37 @@ Style: Good storytelling, focused on emotional resonance.`,
|
|
|
399
442
|
|
|
400
443
|
Style: Visual thinking, good at telling stories with images.`,
|
|
401
444
|
},
|
|
445
|
+
// RolePlay-specific roles (not in Crew templates)
|
|
446
|
+
proofreader: {
|
|
447
|
+
heading: '## 🔎 Proofreader-Tolkien (proofreader)',
|
|
448
|
+
content: `You are Proofreader-Tolkien. Your responsibilities:
|
|
449
|
+
- Check content for logical consistency and factual accuracy
|
|
450
|
+
- Review writing quality, typos, and expression standards
|
|
451
|
+
- Verify accuracy of citations and data
|
|
452
|
+
- Provide specific revision suggestions
|
|
453
|
+
|
|
454
|
+
Style: Research addict, logic purist, sharp but constructive — every critique comes with a fix.`,
|
|
455
|
+
},
|
|
456
|
+
'risk-manager': {
|
|
457
|
+
heading: '## 🛡️ Risk-Officer-Taleb (risk-manager)',
|
|
458
|
+
content: `You are Risk-Officer-Taleb. Your responsibilities:
|
|
459
|
+
- Stress-test strategies and assess tail risks
|
|
460
|
+
- Verify positions comply with risk principles
|
|
461
|
+
- Review stop-loss settings and hedging plans
|
|
462
|
+
- Reject strategies with unacceptable risk — explain which principle is violated
|
|
463
|
+
|
|
464
|
+
Style: Tail risk obsessive, antifragile thinking, barbell strategy devotee.`,
|
|
465
|
+
},
|
|
466
|
+
producer: {
|
|
467
|
+
heading: '## 🎬 Producer-Spielberg (producer)',
|
|
468
|
+
content: `You are Producer-Spielberg. Your responsibilities:
|
|
469
|
+
- Review script and storyboard feasibility
|
|
470
|
+
- Assess production resource needs and technical viability
|
|
471
|
+
- Control production schedule and quality standards
|
|
472
|
+
- Generate final AI video prompt sequences
|
|
473
|
+
|
|
474
|
+
Style: Visual imagination overflows, art and craft in equal measure.`,
|
|
475
|
+
},
|
|
402
476
|
},
|
|
403
477
|
|
|
404
478
|
routeProtocol: `# ROUTE Protocol
|
|
@@ -424,6 +498,18 @@ Rules:
|
|
|
424
498
|
3. **Reviewer** code review (if fails → back to Dev)
|
|
425
499
|
4. **Tester** runs tests & verifies (if bugs → back to Dev)
|
|
426
500
|
5. **PM** acceptance & summary`,
|
|
501
|
+
writingWorkflow: `1. **Editor** analyzes requirements, determines content direction and framework
|
|
502
|
+
2. **Writer** writes content based on outline
|
|
503
|
+
3. **Proofreader** checks logical consistency, factual accuracy, and writing quality (if fails → back to Writer)
|
|
504
|
+
4. **Editor** final acceptance of deliverables`,
|
|
505
|
+
tradingWorkflow: `1. **Analyst** researches market, outputs technical analysis and key levels
|
|
506
|
+
2. **Strategist** synthesizes analysis, formulates investment strategy and position plan
|
|
507
|
+
3. **Risk Manager** stress-tests strategy, assesses tail risks (if fails → back to Strategist)
|
|
508
|
+
4. **Strategist** confirms final plan and summarizes`,
|
|
509
|
+
videoWorkflow: `1. **Director** establishes theme, emotional tone, and visual style
|
|
510
|
+
2. **Screenwriter** conceives storyline, writes segmented script
|
|
511
|
+
3. **Producer** reviews feasibility, generates final prompt sequence (if fails → back to Screenwriter)
|
|
512
|
+
4. **Director** final review and acceptance`,
|
|
427
513
|
genericWorkflow: 'Complete tasks by following the role sequence.',
|
|
428
514
|
|
|
429
515
|
projectPathTitle: '# Project Path',
|
package/roleplay.js
CHANGED
|
@@ -483,8 +483,17 @@ function getWorkflow(teamType, roles, isZh) {
|
|
|
483
483
|
if (teamType === 'dev') {
|
|
484
484
|
return buildDevWorkflow(roleNames, isZh);
|
|
485
485
|
}
|
|
486
|
+
if (teamType === 'writing') {
|
|
487
|
+
return buildWritingWorkflow(roleNames, isZh);
|
|
488
|
+
}
|
|
489
|
+
if (teamType === 'trading') {
|
|
490
|
+
return buildTradingWorkflow(roleNames, isZh);
|
|
491
|
+
}
|
|
492
|
+
if (teamType === 'video') {
|
|
493
|
+
return buildVideoWorkflow(roleNames, isZh);
|
|
494
|
+
}
|
|
486
495
|
|
|
487
|
-
// Generic fallback for
|
|
496
|
+
// Generic fallback for custom / unknown team types
|
|
488
497
|
return isZh ? '按角色顺序依次完成任务。' : 'Complete tasks by following the role sequence.';
|
|
489
498
|
}
|
|
490
499
|
|
|
@@ -516,9 +525,71 @@ function buildDevWorkflow(roleNames, isZh) {
|
|
|
516
525
|
return steps.join('\n');
|
|
517
526
|
}
|
|
518
527
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
528
|
+
function buildWritingWorkflow(roleNames, isZh) {
|
|
529
|
+
const hasEditor = roleNames.includes('editor');
|
|
530
|
+
const hasWriter = roleNames.includes('writer');
|
|
531
|
+
const hasProofreader = roleNames.includes('proofreader');
|
|
532
|
+
|
|
533
|
+
const steps = [];
|
|
534
|
+
|
|
535
|
+
if (isZh) {
|
|
536
|
+
if (hasEditor) steps.push(`${steps.length + 1}. **编辑** 分析需求,确定内容方向和框架`);
|
|
537
|
+
if (hasWriter) steps.push(`${steps.length + 1}. **作者** 根据大纲撰写内容`);
|
|
538
|
+
if (hasProofreader) steps.push(`${steps.length + 1}. **审校** 检查逻辑一致性、事实准确性和文字质量(不通过 → 返回作者修改)`);
|
|
539
|
+
if (hasEditor) steps.push(`${steps.length + 1}. **编辑** 验收最终成果`);
|
|
540
|
+
} else {
|
|
541
|
+
if (hasEditor) steps.push(`${steps.length + 1}. **Editor** analyzes requirements, determines content direction and framework`);
|
|
542
|
+
if (hasWriter) steps.push(`${steps.length + 1}. **Writer** writes content based on outline`);
|
|
543
|
+
if (hasProofreader) steps.push(`${steps.length + 1}. **Proofreader** checks logical consistency, factual accuracy, and writing quality (if fails → back to Writer)`);
|
|
544
|
+
if (hasEditor) steps.push(`${steps.length + 1}. **Editor** final acceptance of deliverables`);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
return steps.join('\n');
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function buildTradingWorkflow(roleNames, isZh) {
|
|
551
|
+
const hasAnalyst = roleNames.includes('analyst');
|
|
552
|
+
const hasStrategist = roleNames.includes('strategist');
|
|
553
|
+
const hasRiskManager = roleNames.includes('risk-manager');
|
|
554
|
+
|
|
555
|
+
const steps = [];
|
|
556
|
+
|
|
557
|
+
if (isZh) {
|
|
558
|
+
if (hasAnalyst) steps.push(`${steps.length + 1}. **分析师** 研究市场,输出技术分析和关键价位`);
|
|
559
|
+
if (hasStrategist) steps.push(`${steps.length + 1}. **策略师** 综合分析,制定投资策略和仓位方案`);
|
|
560
|
+
if (hasRiskManager) steps.push(`${steps.length + 1}. **风控官** 压力测试策略,评估尾部风险(不通过 → 返回策略师调整)`);
|
|
561
|
+
if (hasStrategist) steps.push(`${steps.length + 1}. **策略师** 确认最终方案并总结`);
|
|
562
|
+
} else {
|
|
563
|
+
if (hasAnalyst) steps.push(`${steps.length + 1}. **Analyst** researches market, outputs technical analysis and key levels`);
|
|
564
|
+
if (hasStrategist) steps.push(`${steps.length + 1}. **Strategist** synthesizes analysis, formulates investment strategy and position plan`);
|
|
565
|
+
if (hasRiskManager) steps.push(`${steps.length + 1}. **Risk Manager** stress-tests strategy, assesses tail risks (if fails → back to Strategist)`);
|
|
566
|
+
if (hasStrategist) steps.push(`${steps.length + 1}. **Strategist** confirms final plan and summarizes`);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
return steps.join('\n');
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
function buildVideoWorkflow(roleNames, isZh) {
|
|
573
|
+
const hasDirector = roleNames.includes('director');
|
|
574
|
+
const hasWriter = roleNames.includes('writer');
|
|
575
|
+
const hasProducer = roleNames.includes('producer');
|
|
576
|
+
|
|
577
|
+
const steps = [];
|
|
578
|
+
|
|
579
|
+
if (isZh) {
|
|
580
|
+
if (hasDirector) steps.push(`${steps.length + 1}. **导演** 确定主题、情绪基调和视觉风格`);
|
|
581
|
+
if (hasWriter) steps.push(`${steps.length + 1}. **编剧** 构思故事线,撰写分段脚本`);
|
|
582
|
+
if (hasProducer) steps.push(`${steps.length + 1}. **制片** 审核可行性,生成最终 prompt 序列(不通过 → 返回编剧调整)`);
|
|
583
|
+
if (hasDirector) steps.push(`${steps.length + 1}. **导演** 最终审核并验收`);
|
|
584
|
+
} else {
|
|
585
|
+
if (hasDirector) steps.push(`${steps.length + 1}. **Director** establishes theme, emotional tone, and visual style`);
|
|
586
|
+
if (hasWriter) steps.push(`${steps.length + 1}. **Screenwriter** conceives storyline, writes segmented script`);
|
|
587
|
+
if (hasProducer) steps.push(`${steps.length + 1}. **Producer** reviews feasibility, generates final prompt sequence (if fails → back to Screenwriter)`);
|
|
588
|
+
if (hasDirector) steps.push(`${steps.length + 1}. **Director** final review and acceptance`);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
return steps.join('\n');
|
|
592
|
+
}
|
|
522
593
|
|
|
523
594
|
// Re-export parseRoutes for use by claude.js and tests
|
|
524
595
|
export { parseRoutes } from './crew/routing.js';
|