@yeaft/webchat-agent 0.1.974 → 0.1.975

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yeaft/webchat-agent",
3
- "version": "0.1.974",
3
+ "version": "0.1.975",
4
4
  "description": "Remote agent for Yeaft WebChat — connects worker machines to the central server",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -1312,15 +1312,125 @@ const DEFAULT_VP_PERSONA_ZH = Object.freeze({
1312
1312
  }
1313
1313
  });
1314
1314
 
1315
+
1316
+ function cleanDefaultPersonaFragment(value) {
1317
+ let text = String(value || '').trim();
1318
+ text = text.replace(/cross-VP/g, 'cross-member').replace(/Cross-VP/g, 'Cross-member');
1319
+ text = text.replace(/\bdevelopment VP\b/g, 'developer');
1320
+ text = text.replace(/\bVP\b/g, '');
1321
+ text = text.replace(/generic assistant/gi, 'generic helper');
1322
+ text = text.replace(/generic helper/g, 'generic coordinator');
1323
+ text = text.replace(/\s+,/g, ',').replace(/\s+\./g, '.').replace(/ {2,}/g, ' ');
1324
+ return text.trim();
1325
+ }
1326
+
1327
+ function sentenceFromFragment(value) {
1328
+ const text = cleanDefaultPersonaFragment(value);
1329
+ if (!text) return '';
1330
+ const first = text[0].toUpperCase() + text.slice(1);
1331
+ return /[.!?"”]$/.test(first) ? first : `${first}.`;
1332
+ }
1333
+
1334
+ function firstSection(value) {
1335
+ return String(value || '').split(/\n\n(?:Core capabilities|Traits|Strengths|Problem-solving style|Decision style|Catchphrases|Good for|Bad for|Expected from you|Answer style):/)[0].trim();
1336
+ }
1337
+
1338
+ function extractLabel(value, label) {
1339
+ const text = String(value || '');
1340
+ const escaped = label.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
1341
+ const match = text.match(new RegExp(`\\n\\n${escaped}: ([\\s\\S]*?)(?=\\n\\n[A-Z][A-Za-z -]+:|\\nBad for:|$)`));
1342
+ return match ? match[1].trim() : '';
1343
+ }
1344
+
1345
+ function extractBulletDetails(value) {
1346
+ const details = [];
1347
+ for (const match of String(value || '').matchAll(/^- [^:\n]+: ([^\n]+)$/gm)) {
1348
+ details.push(sentenceFromFragment(match[1]));
1349
+ }
1350
+ return details;
1351
+ }
1352
+
1353
+ function cleanDefaultPersonaIdentityEn(value) {
1354
+ let text = String(value || '').trim();
1355
+ text = text.replace(/cross-VP/g, 'cross-member').replace(/Cross-VP/g, 'Cross-member');
1356
+ text = text.replace(/\bdevelopment VP\b/g, 'developer');
1357
+ text = text.replace(/You are Omni, a VP responsible for ([^\.]+)\./g, 'You are Omni. You are responsible for $1.');
1358
+ text = text.replace(/You are ([^\.\n]+?), a ([^\.\n]*?) VP\. /g, 'You are $1. You bring $2 judgment. ');
1359
+ text = text.replace(/\bVP\b/g, '');
1360
+ text = text.replace(/generic assistant/gi, 'generic helper');
1361
+ text = text.replace(/generic helper/g, 'generic coordinator');
1362
+ text = text.replace(/\s+,/g, ',').replace(/\s+\./g, '.').replace(/ {2,}/g, ' ');
1363
+ return text.trim();
1364
+ }
1365
+
1366
+ function naturalizeDefaultPersonaEn(value) {
1367
+ const raw = String(value || '').trim();
1368
+ const identity = cleanDefaultPersonaIdentityEn(firstSection(raw));
1369
+ const core = extractBulletDetails(raw);
1370
+ const traits = extractLabel(raw, 'Traits');
1371
+ const strengths = extractLabel(raw, 'Strengths');
1372
+ const problemSolving = extractLabel(raw, 'Problem-solving style');
1373
+ const decision = extractLabel(raw, 'Decision style');
1374
+ const catchphrases = extractLabel(raw, 'Catchphrases');
1375
+ const goodFor = extractLabel(raw, 'Good for');
1376
+ const badFor = extractLabel(raw, 'Bad for');
1377
+ const expected = extractLabel(raw, 'Expected from you');
1378
+ const answerStyle = extractLabel(raw, 'Answer style');
1379
+
1380
+ const craft = [];
1381
+ if (core.length) craft.push(`You look for the work that matters first: ${core.join(' ')}`);
1382
+ if (traits) craft.push(sentenceFromFragment(`You are ${traits}`));
1383
+ if (strengths) craft.push(sentenceFromFragment(`You are at your best in ${strengths}`));
1384
+
1385
+ const conduct = [];
1386
+ if (decision) conduct.push(sentenceFromFragment(decision));
1387
+ if (problemSolving) conduct.push(sentenceFromFragment(`You work by ${problemSolving}`));
1388
+ if (catchphrases) conduct.push(sentenceFromFragment(`Your familiar lines still matter: ${catchphrases}`));
1389
+ if (goodFor) conduct.push(sentenceFromFragment(`People come to you for ${goodFor}`));
1390
+ if (expected) conduct.push(sentenceFromFragment(`People come to you when they need ${expected}`));
1391
+ if (badFor) conduct.push(sentenceFromFragment(`You are the wrong voice for ${badFor}`));
1392
+ if (answerStyle) conduct.push(sentenceFromFragment(`You answer ${answerStyle}`));
1393
+
1394
+ return [identity, craft.join(' '), conduct.join(' ')].filter(Boolean).join('\n\n').trim();
1395
+ }
1396
+
1397
+ function naturalizeDefaultPersonaZh(value) {
1398
+ let text = String(value || '').trim();
1399
+ text = text.replace(/跨\s*VP\s*协作/g, '跨成员协作');
1400
+ text = text.replace(/开发\s*VP/g, '开发者');
1401
+ text = text.replace(/直接替开发者写代码/g, '直接替开发者写代码');
1402
+ text = text.replace(/安全 VP/g, '安全判断');
1403
+ text = text.replace(/AI 伙伴/g, '伙伴');
1404
+ text = text.replace(/泛用助手/g, '泛泛的协调者');
1405
+ text = text.replace(/你是([^,。]+),一个负责(.+?)的\s*VP。/g, '你是$1。你负责$2。');
1406
+ text = text.replace(/你是([^,。]+),一个以(.+?)为核心的设计\s*VP。/g, '你是$1。你以$2看设计问题。');
1407
+ text = text.replace(/你是([^,。]+),一个以(.+?)为核心的安全\s*VP。/g, '你是$1。你以$2做安全判断。');
1408
+ text = text.replace(/你是([^,。]+),一个以(.+?)为核心的\s*VP。/g, '你是$1。你以$2看问题。');
1409
+ text = text.replace(/\n\n人物特点:([^\n]+)/g, '\n\n你$1');
1410
+ text = text.replace(/\n\n擅长的事情:([^\n]+)/g, '\n\n你最擅长$1');
1411
+ text = text.replace(/\n\n解决问题的方式:([^\n]+)/g, '\n\n处理问题时,$1');
1412
+ text = text.replace(/\n\n用户通常期待你完成:([^\n]+)/g, '\n\n用户来找你,通常是为了$1');
1413
+ text = text.replace(/\n\n回答风格:([^\n]+)/g, '\n\n回答时,$1');
1414
+ text = text.replace(/\bVP\b/g, '');
1415
+ text = text.replace(/\s+,/g, ',').replace(/\s+。/g, '。');
1416
+ return text.trim();
1417
+ }
1418
+
1315
1419
  function localizeDefaultVpPersona(vp) {
1316
1420
  const zh = DEFAULT_VP_PERSONA_ZH[vp.vpId];
1317
1421
  if (!zh) return vp;
1422
+ const legacyPersonaEn = String(vp.persona || '').trim();
1423
+ const legacyPersonaZh = String(zh.persona || '').trim();
1424
+ const personaEn = naturalizeDefaultPersonaEn(legacyPersonaEn);
1425
+ const personaZh = naturalizeDefaultPersonaZh(legacyPersonaZh);
1318
1426
  return {
1319
1427
  ...vp,
1320
1428
  roleZh: zh.roleZh,
1321
- persona: localizedPersonaSections(vp.persona, zh.persona),
1322
- personaEn: vp.persona,
1323
- personaZh: zh.persona,
1429
+ persona: localizedPersonaSections(personaEn, personaZh),
1430
+ personaEn,
1431
+ personaZh,
1432
+ legacyPersonaEn,
1433
+ legacyPersona: localizedPersonaSections(legacyPersonaEn, legacyPersonaZh),
1324
1434
  };
1325
1435
  }
1326
1436
 
@@ -234,9 +234,17 @@ function replaceRoleBody(source, body) {
234
234
  function backfillLocalizedPersonaBody(source, vp) {
235
235
  const body = roleBodyOf(source).trim();
236
236
  const nextBody = typeof vp.persona === 'string' ? vp.persona.trim() : '';
237
- const oldBody = typeof vp.personaEn === 'string' ? vp.personaEn.trim() : '';
238
- if (!body || !nextBody || body.includes('<!-- lang:')) return null;
239
- if (!oldBody || body !== oldBody) return null;
237
+ if (!body || !nextBody || body === nextBody) return null;
238
+
239
+ const acceptedOldBodies = [
240
+ vp.legacyPersonaEn,
241
+ vp.legacyPersona,
242
+ vp.personaEn,
243
+ ]
244
+ .filter(value => typeof value === 'string' && value.trim())
245
+ .map(value => value.trim());
246
+
247
+ if (!acceptedOldBodies.includes(body)) return null;
240
248
  return replaceRoleBody(source, nextBody);
241
249
  }
242
250