@riconext/hermes-repo 1.2.2 → 1.2.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2.4
4
+
5
+ ### Patch Changes
6
+
7
+ - 089eb55: 兼容 LLM 返回 path 和 YAML frontmatter 的知识文件格式,避免有效知识文件在 flush 时被过滤丢弃。
8
+
9
+ ## 1.2.3
10
+
11
+ ### Patch Changes
12
+
13
+ - 17d33f3: 增加 flush 调用 LLM 时的详细 debug 日志,便于检查请求输入、原始响应和标准化后的知识文件结果。
14
+
3
15
  ## 1.2.2
4
16
 
5
17
  ### Patch Changes
package/dist/cli.js CHANGED
@@ -62,6 +62,16 @@ function debugLog(enabled, phase, message) {
62
62
  console.error(line);
63
63
  writeToLogFile(line);
64
64
  }
65
+ function debugLogBlock(enabled, phase, label, content) {
66
+ if (!enabled) {
67
+ return;
68
+ }
69
+ debugLog(true, phase, `${label} BEGIN`);
70
+ for (const line of content.split(/\r?\n/)) {
71
+ debugLog(true, phase, `| ${line}`);
72
+ }
73
+ debugLog(true, phase, `${label} END`);
74
+ }
65
75
  function debugFromContext(ctx, phase, message) {
66
76
  debugLog(ctx?.config.debug === true, phase, message);
67
77
  }
@@ -1339,7 +1349,11 @@ var CONSOLIDATE_SYSTEM_PROMPT = `\u4F60\u662F\u4E00\u4E2A\u9879\u76EE\u77E5\u8BC
1339
1349
  ## \u8F93\u51FA\u8981\u6C42
1340
1350
  - \u8F93\u51FA\u4E25\u683C JSON \u683C\u5F0F
1341
1351
  - knowledgeFiles \u6570\u7EC4\u5305\u542B\u6240\u6709\u9700\u8981\u521B\u5EFA/\u66F4\u65B0\u7684\u6587\u4EF6
1342
- - \u6BCF\u9879\u5FC5\u987B\u5305\u542B\u5B8C\u6574\u7684 frontmatter \u548C body markdown
1352
+ - \u6BCF\u9879\u5FC5\u987B\u5305\u542B targetPath\u3001action\u3001frontmatter\u3001body
1353
+ - targetPath \u662F\u76F8\u5BF9 .memory/ \u7684\u8DEF\u5F84\uFF0C\u4F8B\u5982 "domains/canvas/canvas-interaction.md"
1354
+ - \u4E0D\u8981\u4F7F\u7528 path\u3001filePath\u3001filename \u7B49\u5B57\u6BB5\u4EE3\u66FF targetPath
1355
+ - frontmatter \u5FC5\u987B\u662F JSON \u5BF9\u8C61\uFF0C\u4E0D\u8981\u8F93\u51FA YAML \u5B57\u7B26\u4E32
1356
+ - body \u662F\u4E0D\u5305\u542B frontmatter \u7684 markdown \u6B63\u6587
1343
1357
  - memoryMd \u662F\u5B8C\u6574 MEMORY.md \u5185\u5BB9
1344
1358
  - \u65E0\u4EF7\u503C\u7684 session \u5728 skippedSessions \u4E2D\u8BF4\u660E\u539F\u56E0\uFF08\u800C\u975E\u751F\u6210\u7A7A\u5185\u5BB9\uFF09`;
1345
1359
  function scanExistingKnowledge(repoRoot) {
@@ -1423,7 +1437,7 @@ function buildLlmConsolidateInput(repoRoot, sessions) {
1423
1437
  currentMemoryMd
1424
1438
  };
1425
1439
  }
1426
- async function callLlmConsolidate(input2, llmConfig) {
1440
+ async function callLlmConsolidate(input2, llmConfig, debug = false) {
1427
1441
  if (!llmConfig.enabled) {
1428
1442
  throw new Error(
1429
1443
  "LLM \u672A\u542F\u7528\uFF1A\u8BF7\u5728 config.json \u4E2D\u8BBE\u7F6E llm.enabled = true"
@@ -1436,6 +1450,23 @@ async function callLlmConsolidate(input2, llmConfig) {
1436
1450
  }
1437
1451
  const url = `${llmConfig.baseUrl.replace(/\/$/, "")}/chat/completions`;
1438
1452
  const userContent = formatUserMessage(input2);
1453
+ debugLog(
1454
+ debug,
1455
+ "llm",
1456
+ `request: provider=${llmConfig.provider}, model=${llmConfig.model}, baseUrl=${llmConfig.baseUrl}, pendingSessions=${input2.pendingSessions.length}, existingKnowledge=${input2.existingKnowledge.length}, currentMemoryChars=${input2.currentMemoryMd?.length ?? 0}`
1457
+ );
1458
+ debugLogBlock(debug, "llm", "system prompt", CONSOLIDATE_SYSTEM_PROMPT);
1459
+ debugLogBlock(debug, "llm", "user input", userContent);
1460
+ const requestBody = {
1461
+ model: llmConfig.model,
1462
+ response_format: { type: "json_object" },
1463
+ messages: [
1464
+ { role: "system", content: CONSOLIDATE_SYSTEM_PROMPT },
1465
+ { role: "user", content: userContent }
1466
+ ],
1467
+ temperature: 0.2
1468
+ };
1469
+ debugLogBlock(debug, "llm", "request body", JSON.stringify(requestBody, null, 2));
1439
1470
  const controller = new AbortController();
1440
1471
  const timeout = setTimeout(() => controller.abort(), 12e4);
1441
1472
  try {
@@ -1445,35 +1476,58 @@ async function callLlmConsolidate(input2, llmConfig) {
1445
1476
  "Content-Type": "application/json",
1446
1477
  Authorization: `Bearer ${llmConfig.apiKey}`
1447
1478
  },
1448
- body: JSON.stringify({
1449
- model: llmConfig.model,
1450
- response_format: { type: "json_object" },
1451
- messages: [
1452
- { role: "system", content: CONSOLIDATE_SYSTEM_PROMPT },
1453
- { role: "user", content: userContent }
1454
- ],
1455
- temperature: 0.2
1456
- }),
1479
+ body: JSON.stringify(requestBody),
1457
1480
  signal: controller.signal
1458
1481
  });
1482
+ debugLog(debug, "llm", `response status: ${res.status} ${res.statusText}`);
1459
1483
  if (!res.ok) {
1460
1484
  const errBody = await res.text().catch(() => "");
1485
+ debugLogBlock(debug, "llm", "error response body", errBody);
1461
1486
  throw new Error(
1462
1487
  `LLM API \u9519\u8BEF (${res.status}): ${errBody.slice(0, 300)}`
1463
1488
  );
1464
1489
  }
1465
1490
  const data = await res.json();
1491
+ debugLogBlock(debug, "llm", "response json", JSON.stringify(data, null, 2));
1466
1492
  const rawContent = data.choices?.[0]?.message?.content;
1467
1493
  if (!rawContent) {
1468
1494
  throw new Error("LLM \u8FD4\u56DE\u5185\u5BB9\u4E3A\u7A7A");
1469
1495
  }
1496
+ debugLogBlock(debug, "llm", "raw message content", rawContent);
1470
1497
  let parsed;
1471
1498
  try {
1472
1499
  parsed = JSON.parse(rawContent);
1473
1500
  } catch {
1474
1501
  throw new Error("LLM \u8FD4\u56DE\u5185\u5BB9\u4E0D\u662F\u5408\u6CD5 JSON");
1475
1502
  }
1476
- return validateAndNormalizeLlmResult(parsed);
1503
+ debugLogBlock(debug, "llm", "parsed content", JSON.stringify(parsed, null, 2));
1504
+ const normalized = validateAndNormalizeLlmResult(parsed);
1505
+ debugLog(
1506
+ debug,
1507
+ "llm",
1508
+ `normalized: knowledgeFiles=${normalized.knowledgeFiles.length}, memoryChars=${normalized.memoryMd.length}, skippedSessions=${normalized.skippedSessions.length}`
1509
+ );
1510
+ debugLogBlock(
1511
+ debug,
1512
+ "llm",
1513
+ "normalized knowledgeFiles",
1514
+ JSON.stringify(normalized.knowledgeFiles, null, 2)
1515
+ );
1516
+ debugLogBlock(debug, "llm", "normalized memoryMd", normalized.memoryMd);
1517
+ debugLogBlock(
1518
+ debug,
1519
+ "llm",
1520
+ "normalized skippedSessions",
1521
+ JSON.stringify(normalized.skippedSessions, null, 2)
1522
+ );
1523
+ return normalized;
1524
+ } catch (err) {
1525
+ debugLog(
1526
+ debug,
1527
+ "llm",
1528
+ `error: ${err instanceof Error ? err.message : String(err)}`
1529
+ );
1530
+ throw err;
1477
1531
  } finally {
1478
1532
  clearTimeout(timeout);
1479
1533
  }
@@ -1518,16 +1572,51 @@ function validateAndNormalizeLlmResult(raw) {
1518
1572
  function normalizeKnowledgeFile(raw) {
1519
1573
  if (!raw || typeof raw !== "object") return null;
1520
1574
  const obj = raw;
1521
- if (typeof obj.targetPath !== "string" || !["create", "update"].includes(obj.action) || typeof obj.body !== "string") {
1575
+ const targetPath = typeof obj.targetPath === "string" ? obj.targetPath : typeof obj.path === "string" ? obj.path : null;
1576
+ if (!targetPath || !["create", "update"].includes(obj.action) || typeof obj.body !== "string") {
1522
1577
  return null;
1523
1578
  }
1524
1579
  return {
1525
- targetPath: obj.targetPath,
1580
+ targetPath,
1526
1581
  action: obj.action,
1527
- frontmatter: typeof obj.frontmatter === "object" && obj.frontmatter !== null ? obj.frontmatter : {},
1582
+ frontmatter: normalizeFrontmatter(obj.frontmatter),
1528
1583
  body: obj.body
1529
1584
  };
1530
1585
  }
1586
+ function normalizeFrontmatter(raw) {
1587
+ if (raw && typeof raw === "object" && !Array.isArray(raw)) {
1588
+ return raw;
1589
+ }
1590
+ if (typeof raw !== "string") {
1591
+ return {};
1592
+ }
1593
+ const text = raw.trim();
1594
+ const yaml = text.startsWith("---") ? text.replace(/^---\r?\n?/, "").replace(/\r?\n?---$/, "") : text;
1595
+ const frontmatter = {};
1596
+ for (const line of yaml.split(/\r?\n/)) {
1597
+ const trimmed = line.trim();
1598
+ if (!trimmed || trimmed.startsWith("#")) {
1599
+ continue;
1600
+ }
1601
+ const separator = trimmed.indexOf(":");
1602
+ if (separator <= 0) {
1603
+ continue;
1604
+ }
1605
+ const key = trimmed.slice(0, separator).trim();
1606
+ const value = trimmed.slice(separator + 1).trim();
1607
+ frontmatter[key] = parseFrontmatterValue(value);
1608
+ }
1609
+ return frontmatter;
1610
+ }
1611
+ function parseFrontmatterValue(value) {
1612
+ const unquoted = value.replace(/^["']|["']$/g, "");
1613
+ if (unquoted.startsWith("[") && unquoted.endsWith("]")) {
1614
+ return unquoted.slice(1, -1).split(",").map((item) => item.trim().replace(/^["']|["']$/g, "")).filter(Boolean);
1615
+ }
1616
+ if (unquoted === "true") return true;
1617
+ if (unquoted === "false") return false;
1618
+ return unquoted;
1619
+ }
1531
1620
  function isSkippedEntry(raw) {
1532
1621
  if (!raw || typeof raw !== "object") return false;
1533
1622
  const obj = raw;
@@ -1769,7 +1858,7 @@ async function runConsolidate(opts) {
1769
1858
  );
1770
1859
  let llmResult;
1771
1860
  try {
1772
- llmResult = await callLlmConsolidate(llmInput, llmConfig);
1861
+ llmResult = await callLlmConsolidate(llmInput, llmConfig, debug === true);
1773
1862
  } catch (err) {
1774
1863
  console.error(`[consolidate] LLM \u8C03\u7528\u5931\u8D25: ${err.message}`);
1775
1864
  throw err;