chattercatcher 0.1.22 → 0.1.24
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/dist/cli.js +25 -19
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +11 -4
- package/dist/index.js +24 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import fs14 from "fs/promises";
|
|
|
8
8
|
// package.json
|
|
9
9
|
var package_default = {
|
|
10
10
|
name: "chattercatcher",
|
|
11
|
-
version: "0.1.
|
|
11
|
+
version: "0.1.24",
|
|
12
12
|
description: "\u672C\u5730\u4F18\u5148\u7684\u98DE\u4E66/Lark \u5BB6\u5EAD\u7FA4\u77E5\u8BC6\u5E93\u673A\u5668\u4EBA",
|
|
13
13
|
type: "module",
|
|
14
14
|
main: "dist/index.js",
|
|
@@ -1623,7 +1623,7 @@ var EpisodeRepository = class {
|
|
|
1623
1623
|
endedAt: last.sentAt,
|
|
1624
1624
|
messages: windowMessages
|
|
1625
1625
|
};
|
|
1626
|
-
const summary = await input2.summarize(window);
|
|
1626
|
+
const summary = await input2.summarize(window, input2.now);
|
|
1627
1627
|
created.push(this.insertEpisode(window, summary));
|
|
1628
1628
|
}
|
|
1629
1629
|
}
|
|
@@ -2613,16 +2613,17 @@ async function restoreLocalData(input2) {
|
|
|
2613
2613
|
}
|
|
2614
2614
|
|
|
2615
2615
|
// src/episodes/summarizer.ts
|
|
2616
|
-
async function summarizeEpisodeWindow(window, model) {
|
|
2616
|
+
async function summarizeEpisodeWindow(window, model, now) {
|
|
2617
2617
|
const transcript = window.messages.map((message) => `[${message.sentAt}] ${message.senderName}\uFF1A${message.text}`).join("\n");
|
|
2618
2618
|
const summary = await model.complete([
|
|
2619
2619
|
{
|
|
2620
2620
|
role: "system",
|
|
2621
|
-
content: "\u4F60\u662F ChatterCatcher \u7684\u4F1A\u8BDD\u8BB0\u5FC6\u6574\u7406\u6A21\u5757\u3002\u4F60\u7684\u4EFB\u52A1\u662F\u628A\u788E\u7247\u5316\u95F2\u804A\u6574\u7406\u6210\u53EF\u68C0\u7D22\u4E8B\u5B9E\uFF0C\u8865\u5168\u77ED\u6D88\u606F\u3001\u4EE3\u8BCD\u3001\u7F29\u5199\u4E0E\u4E0A\u4E0B\u6587\u4E4B\u95F4\u7684\u5173\u7CFB\u3002\u53EA\u603B\u7ED3\u660E\u786E\u4E8B\u5B9E\uFF0C\u4E0D\u8981\u7F16\u9020\u3002\u4FDD\u7559\u91CD\u8981\u6570\u5B57\u3001\u65E5\u671F\u3001\u94FE\u63A5\u548C\u4EE3\u7801\uFF1B\u5982\u679C\u5185\u5BB9\u50CF\u5BC6\u7801\u3001API key\u3001token \u6216\u5BC6\u94A5\uFF0C\u53EA\u63CF\u8FF0\u5176\u4E0A\u4E0B\u6587\u5173\u7CFB\uFF0C\u4E0D\u8981\u5728\u6458\u8981\u4E2D\u590D\u5199\u539F\u6587\u3002"
|
|
2621
|
+
content: "\u4F60\u662F ChatterCatcher \u7684\u4F1A\u8BDD\u8BB0\u5FC6\u6574\u7406\u6A21\u5757\u3002\u4F60\u7684\u4EFB\u52A1\u662F\u628A\u788E\u7247\u5316\u95F2\u804A\u6574\u7406\u6210\u53EF\u68C0\u7D22\u4E8B\u5B9E\uFF0C\u8865\u5168\u77ED\u6D88\u606F\u3001\u4EE3\u8BCD\u3001\u7F29\u5199\u4E0E\u4E0A\u4E0B\u6587\u4E4B\u95F4\u7684\u5173\u7CFB\u3002\u53EA\u603B\u7ED3\u660E\u786E\u4E8B\u5B9E\uFF0C\u4E0D\u8981\u7F16\u9020\u3002\u4FDD\u7559\u91CD\u8981\u6570\u5B57\u3001\u65E5\u671F\u3001\u94FE\u63A5\u548C\u4EE3\u7801\uFF1B\u5982\u679C\u5185\u5BB9\u50CF\u5BC6\u7801\u3001API key\u3001token \u6216\u5BC6\u94A5\uFF0C\u53EA\u63CF\u8FF0\u5176\u4E0A\u4E0B\u6587\u5173\u7CFB\uFF0C\u4E0D\u8981\u5728\u6458\u8981\u4E2D\u590D\u5199\u539F\u6587\u3002\u6D88\u606F\u91CC\u7684\u201C\u4ECA\u5929\u201D\u201C\u660E\u5929\u201D\u201C\u6628\u665A\u201D\u201C\u4E0B\u5468\u4E09\u201D\u7B49\u76F8\u5BF9\u65F6\u95F4\u8868\u8FF0\uFF0C\u8BF7\u57FA\u4E8E\u6BCF\u6761\u6D88\u606F\u524D\u7684\u53D1\u9001\u65F6\u95F4\u6233\u63A8\u5BFC\u4E3A\u5177\u4F53\u65E5\u671F\u5199\u5165\u6458\u8981\u3002\u4F8B\u5982 [2026-05-05T20:00:00.000Z] \u5988\u5988\u8BF4\u201C\u660E\u5929\u8981\u7528\u4E1D\u4E1D\u9732\u201D\uFF0C\u6458\u8981\u5E94\u5199\u4E3A\u201C2026-05-06 \u8981\u7528\u4E1D\u4E1D\u9732\u201D\u3002"
|
|
2622
2622
|
},
|
|
2623
2623
|
{
|
|
2624
2624
|
role: "user",
|
|
2625
|
-
content: `\
|
|
2625
|
+
content: `\u5F53\u524D\u65F6\u95F4\uFF1A${now.toISOString()}
|
|
2626
|
+
\u7FA4\u804A\uFF1A${window.chatName}
|
|
2626
2627
|
\u65F6\u95F4\uFF1A${window.startedAt} - ${window.endedAt}
|
|
2627
2628
|
|
|
2628
2629
|
\u804A\u5929\u8BB0\u5F55\uFF1A
|
|
@@ -2641,7 +2642,7 @@ async function processEpisodesNow(input2) {
|
|
|
2641
2642
|
now: input2.now ?? /* @__PURE__ */ new Date(),
|
|
2642
2643
|
quietMs: input2.config.episodes.quietMinutes * 60 * 1e3,
|
|
2643
2644
|
windowMs: input2.config.episodes.windowMinutes * 60 * 1e3,
|
|
2644
|
-
summarize: (window) => summarizeEpisodeWindow(window, input2.model)
|
|
2645
|
+
summarize: (window, now) => summarizeEpisodeWindow(window, input2.model, now)
|
|
2645
2646
|
});
|
|
2646
2647
|
return { created: created.length };
|
|
2647
2648
|
}
|
|
@@ -3772,7 +3773,7 @@ function stripMentions(text, mentions) {
|
|
|
3772
3773
|
}
|
|
3773
3774
|
return result.replace(/@/g, " ").replace(/\s+/g, " ").trim();
|
|
3774
3775
|
}
|
|
3775
|
-
var FEISHU_TOOL_SYSTEM_PROMPT = "\u4F60\u662F\u98DE\u4E66\u7FA4\u804A\u52A9\u624B\u3002\u4F60\u53EF\u4EE5\u5148\u641C\u7D22\u672C\u5730\u77E5\u8BC6\u6765\u56DE\u7B54\u95EE\u9898\uFF1B\u5F53\u7528\u6237\u660E\u786E\u8981\u6C42\u521B\u5EFA\u3001\u67E5\u770B\u6216\u5220\u9664\u7FA4\u6D88\u606F\u5B9A\u65F6\u4EFB\u52A1\u65F6\uFF0C\u4E5F\u53EF\u4EE5\u8C03\u7528\u5B9A\u65F6\u4EFB\u52A1\u5DE5\u5177\u3002\u5B9A\u65F6\u4EFB\u52A1\u5DE5\u5177\u53EA\u7BA1\u7406\u5F53\u524D\u7FA4\u804A\uFF0C\u4E0D\u80FD\u8DE8\u7FA4\u64CD\u4F5C\u3002\u82E5\u7528\u6237\u7528\u81EA\u7136\u8BED\u8A00\u63CF\u8FF0\u65F6\u95F4\uFF0C\u4F60\u9700\u8981\u5148\u5C06\u5176\u8F6C\u6362\u4E3A\u4E94\u5B57\u6BB5 cron \u8868\u8FBE\u5F0F\uFF08\u5206 \u65F6 \u65E5 \u6708 \u5468\uFF09\uFF0C\u518D\u8C03\u7528\u5DE5\u5177\u3002\u5BF9\u4E8E\u4E00\u822C\u95EE\u7B54\uFF0C\u5148\u6309\u9700\u8C03\u7528\u641C\u7D22\u5DE5\u5177\uFF0C\u518D\u57FA\u4E8E\u5DE5\u5177\u8FD4\u56DE\u7684\u8BC1\u636E\u76F4\u63A5\u7ED9\u51FA\u6700\u7EC8\u7B54\u6848\uFF1B\u82E5\u5F15\u7528\u4E86\u68C0\u7D22\u7ED3\u679C\uFF0C\u8981\u5728\u7B54\u6848\u91CC\u76F4\u63A5\u5199\u51FA\u5F15\u7528\u5185\u5BB9\u3002\u4E0D\u8981\u58F0\u79F0\u5B8C\u6210\u4E86\u672A\u5B9E\u9645\u8C03\u7528\u7684\u64CD\u4F5C\u3002";
|
|
3776
|
+
var FEISHU_TOOL_SYSTEM_PROMPT = "\u4F60\u662F\u98DE\u4E66\u7FA4\u804A\u52A9\u624B\u3002\u4F60\u53EF\u4EE5\u5148\u641C\u7D22\u672C\u5730\u77E5\u8BC6\u6765\u56DE\u7B54\u95EE\u9898\uFF1B\u5F53\u7528\u6237\u660E\u786E\u8981\u6C42\u521B\u5EFA\u3001\u67E5\u770B\u6216\u5220\u9664\u7FA4\u6D88\u606F\u5B9A\u65F6\u4EFB\u52A1\u65F6\uFF0C\u4E5F\u53EF\u4EE5\u8C03\u7528\u5B9A\u65F6\u4EFB\u52A1\u5DE5\u5177\u3002\u5B9A\u65F6\u4EFB\u52A1\u5DE5\u5177\u53EA\u7BA1\u7406\u5F53\u524D\u7FA4\u804A\uFF0C\u4E0D\u80FD\u8DE8\u7FA4\u64CD\u4F5C\u3002\u82E5\u7528\u6237\u7528\u81EA\u7136\u8BED\u8A00\u63CF\u8FF0\u65F6\u95F4\uFF0C\u4F60\u9700\u8981\u5148\u5C06\u5176\u8F6C\u6362\u4E3A\u4E94\u5B57\u6BB5 cron \u8868\u8FBE\u5F0F\uFF08\u5206 \u65F6 \u65E5 \u6708 \u5468\uFF09\uFF0C\u518D\u8C03\u7528\u5DE5\u5177\u3002\u5F53\u524D\u65F6\u95F4\u4F1A\u63D0\u4F9B\u7ED9\u4F60\u3002\u68C0\u7D22\u8BC1\u636E\u4E2D\u7684\u65F6\u95F4\u6233\u662F\u6D88\u606F\u88AB\u53D1\u9001\u65F6\u7684\u771F\u5B9E\u65F6\u95F4\u3002\u56DE\u7B54\u65F6\u82E5\u6D89\u53CA\u76F8\u5BF9\u65F6\u95F4\u8868\u8FF0\uFF08\u5982\u6D88\u606F\u4E2D\u8BF4\u201C\u660E\u5929\u201D\u201C\u4ECA\u665A\u201D\uFF09\uFF0C\u5FC5\u987B\u57FA\u4E8E\u8BC1\u636E\u4E2D\u6BCF\u6761\u6D88\u606F\u7684\u65F6\u95F4\u6233\u63A8\u5BFC\u4E3A\u5177\u4F53\u65E5\u671F\uFF0C\u4E0D\u8981\u7167\u642C\u539F\u6587\u7684\u76F8\u5BF9\u8868\u8FF0\u3002\u5BF9\u4E8E\u4E00\u822C\u95EE\u7B54\uFF0C\u5148\u6309\u9700\u8C03\u7528\u641C\u7D22\u5DE5\u5177\uFF0C\u518D\u57FA\u4E8E\u5DE5\u5177\u8FD4\u56DE\u7684\u8BC1\u636E\u76F4\u63A5\u7ED9\u51FA\u6700\u7EC8\u7B54\u6848\uFF1B\u82E5\u5F15\u7528\u4E86\u68C0\u7D22\u7ED3\u679C\uFF0C\u8981\u5728\u7B54\u6848\u91CC\u76F4\u63A5\u5199\u51FA\u5F15\u7528\u5185\u5BB9\u3002\u4E0D\u8981\u58F0\u79F0\u5B8C\u6210\u4E86\u672A\u5B9E\u9645\u8C03\u7528\u7684\u64CD\u4F5C\u3002";
|
|
3776
3777
|
var DEFAULT_MAX_MODEL_TURNS = 4;
|
|
3777
3778
|
var DEFAULT_MAX_TOOL_CALLS = 8;
|
|
3778
3779
|
var FEISHU_TOOL_LOOP_FALLBACK = "\u5B9A\u65F6\u4EFB\u52A1\u64CD\u4F5C\u5DF2\u63D0\u4EA4\uFF0C\u4F46\u6A21\u578B\u6CA1\u6709\u751F\u6210\u6700\u7EC8\u56DE\u590D\u3002";
|
|
@@ -3795,7 +3796,8 @@ async function runFeishuToolLoop(input2) {
|
|
|
3795
3796
|
const maxToolCalls = input2.maxToolCalls ?? DEFAULT_MAX_TOOL_CALLS;
|
|
3796
3797
|
const messages = [
|
|
3797
3798
|
{ role: "system", content: FEISHU_TOOL_SYSTEM_PROMPT },
|
|
3798
|
-
{ role: "user", content: input2.
|
|
3799
|
+
{ role: "user", content: `\u5F53\u524D\u65F6\u95F4\uFF1A${input2.now.toISOString()}
|
|
3800
|
+
\u95EE\u9898\uFF1A${input2.question}` }
|
|
3799
3801
|
];
|
|
3800
3802
|
const toolsByName = new Map(input2.tools.map((tool) => [tool.name, tool]));
|
|
3801
3803
|
let toolCallsUsed = 0;
|
|
@@ -3926,6 +3928,7 @@ var FeishuQuestionHandler = class {
|
|
|
3926
3928
|
return decision;
|
|
3927
3929
|
}
|
|
3928
3930
|
const questionMessageId = payload.event?.message?.message_id;
|
|
3931
|
+
const now = /* @__PURE__ */ new Date();
|
|
3929
3932
|
const qaLogs = new QaLogRepository(this.options.database);
|
|
3930
3933
|
await this.acknowledgeQuestion(decision.chatId, questionMessageId);
|
|
3931
3934
|
const { tools, close } = await createAgenticRagSearchTools({
|
|
@@ -3945,6 +3948,7 @@ var FeishuQuestionHandler = class {
|
|
|
3945
3948
|
const allTools = [...tools, ...cronTools];
|
|
3946
3949
|
const answer = await runFeishuToolLoop({
|
|
3947
3950
|
question: decision.question,
|
|
3951
|
+
now,
|
|
3948
3952
|
tools: allTools,
|
|
3949
3953
|
model: this.options.model
|
|
3950
3954
|
});
|
|
@@ -4918,7 +4922,8 @@ function rankEvidenceForPrompt(evidence) {
|
|
|
4918
4922
|
return scoreDiff;
|
|
4919
4923
|
});
|
|
4920
4924
|
}
|
|
4921
|
-
function buildEvidencePrompt(
|
|
4925
|
+
function buildEvidencePrompt(input2, options = {}) {
|
|
4926
|
+
const { question, evidence, now } = input2;
|
|
4922
4927
|
if (evidence.length === 0) {
|
|
4923
4928
|
throw new Error("RAG evidence is required before answer generation.");
|
|
4924
4929
|
}
|
|
@@ -4949,11 +4954,12 @@ function buildEvidencePrompt(question, evidence, options = {}) {
|
|
|
4949
4954
|
messages: [
|
|
4950
4955
|
{
|
|
4951
4956
|
role: "system",
|
|
4952
|
-
content: "\u4F60\u662F ChatterCatcher \u7684\u95EE\u7B54\u6A21\u5757\u3002\u53EA\u80FD\u6839\u636E\u63D0\u4F9B\u7684\u68C0\u7D22\u8BC1\u636E\u56DE\u7B54\uFF0C\u5FC5\u987B\u7B80\u77ED\u76F4\u63A5\u3002\u4E8B\u5B9E\u6027\u7ED3\u8BBA\u5FC5\u987B\u5F15\u7528 [S1] \u8FD9\u6837\u7684\u6765\u6E90\u6807\u8BB0\u3002\u8BC1\u636E\u4E0D\u8DB3\u65F6\u8BF4\u4E0D\u77E5\u9053\uFF0C\u4E0D\u8981\u731C\u3002\u82E5\u8BC1\u636E\u4E92\u76F8\u77DB\u76FE\uFF0C\u4F18\u5148\u91C7\u7528\u65F6\u95F4\u66F4\u65B0\u4E14\u8868\u8FF0\u660E\u786E\u7684\u8BC1\u636E\uFF1B\u5982\u679C\u8F83\u65B0\u7684\u8BC1\u636E\u53EA\u662F\u8BA8\u8BBA\u3001\u731C\u6D4B\u6216\u4E0D\u786E\u5B9A\u8868\u8FBE\uFF0C\u4E0D\u8981\u628A\u5B83\u5F53\u4F5C\u786E\u5B9A\u66F4\u65B0\u3002"
|
|
4957
|
+
content: "\u4F60\u662F ChatterCatcher \u7684\u95EE\u7B54\u6A21\u5757\u3002\u53EA\u80FD\u6839\u636E\u63D0\u4F9B\u7684\u68C0\u7D22\u8BC1\u636E\u56DE\u7B54\uFF0C\u5FC5\u987B\u7B80\u77ED\u76F4\u63A5\u3002\u4E8B\u5B9E\u6027\u7ED3\u8BBA\u5FC5\u987B\u5F15\u7528 [S1] \u8FD9\u6837\u7684\u6765\u6E90\u6807\u8BB0\u3002\u8BC1\u636E\u4E0D\u8DB3\u65F6\u8BF4\u4E0D\u77E5\u9053\uFF0C\u4E0D\u8981\u731C\u3002\u82E5\u8BC1\u636E\u4E92\u76F8\u77DB\u76FE\uFF0C\u4F18\u5148\u91C7\u7528\u65F6\u95F4\u66F4\u65B0\u4E14\u8868\u8FF0\u660E\u786E\u7684\u8BC1\u636E\uFF1B\u5982\u679C\u8F83\u65B0\u7684\u8BC1\u636E\u53EA\u662F\u8BA8\u8BBA\u3001\u731C\u6D4B\u6216\u4E0D\u786E\u5B9A\u8868\u8FBE\uFF0C\u4E0D\u8981\u628A\u5B83\u5F53\u4F5C\u786E\u5B9A\u66F4\u65B0\u3002\u68C0\u7D22\u8BC1\u636E\u4E2D\u7684\u65F6\u95F4\u6233\u662F\u6D88\u606F\u88AB\u53D1\u9001\u65F6\u7684\u771F\u5B9E\u65F6\u95F4\u3002\u56DE\u7B54\u65F6\u82E5\u6D89\u53CA\u76F8\u5BF9\u65F6\u95F4\u8868\u8FF0\uFF08\u5982\u6D88\u606F\u4E2D\u8BF4\u201C\u660E\u5929\u201D\u201C\u4ECA\u665A\u201D\uFF09\uFF0C\u5FC5\u987B\u57FA\u4E8E\u8BC1\u636E\u4E2D\u6BCF\u6761\u6D88\u606F\u7684\u65F6\u95F4\u6233\u63A8\u5BFC\u4E3A\u5177\u4F53\u65E5\u671F\uFF08\u5982\u201C2026-05-06\u201D\uFF09\uFF0C\u4E0D\u8981\u7167\u642C\u539F\u6587\u7684\u76F8\u5BF9\u8868\u8FF0\u3002\u8BC1\u636E\u4E2D\u6BCF\u6761\u6D88\u606F\u6807\u6CE8\u4E86\u53D1\u9001\u65F6\u95F4\u3002\u56DE\u7B54\u65F6\u4F18\u5148\u8F93\u51FA\u7EDD\u5BF9\u65E5\u671F\uFF0C\u4E0D\u786E\u5B9A\u65F6\u5F15\u7528\u539F\u6587\u65F6\u95F4\u6233\uFF0C\u4E0D\u8981\u4F7F\u7528\u201C\u4ECA\u5929\u201D\u201C\u660E\u5929\u201D\u7B49\u4F9D\u8D56\u5F53\u524D\u4E0A\u4E0B\u6587\u7684\u6A21\u7CCA\u8868\u8FF0\u3002"
|
|
4953
4958
|
},
|
|
4954
4959
|
{
|
|
4955
4960
|
role: "user",
|
|
4956
|
-
content: `\
|
|
4961
|
+
content: `\u5F53\u524D\u65F6\u95F4\uFF1A${now.toISOString()}
|
|
4962
|
+
\u95EE\u9898\uFF1A${question}
|
|
4957
4963
|
|
|
4958
4964
|
\u8BC1\u636E\u5904\u7406\u89C4\u5219\uFF1A
|
|
4959
4965
|
1. \u5148\u5224\u65AD\u8BC1\u636E\u662F\u5426\u8DB3\u4EE5\u56DE\u7B54\u95EE\u9898\u3002
|
|
@@ -4967,7 +4973,7 @@ ${evidenceText}`
|
|
|
4967
4973
|
};
|
|
4968
4974
|
}
|
|
4969
4975
|
async function generateGroundedAnswer(input2) {
|
|
4970
|
-
const prompt = buildEvidencePrompt(input2.question, input2.evidence);
|
|
4976
|
+
const prompt = buildEvidencePrompt({ question: input2.question, evidence: input2.evidence, now: input2.now });
|
|
4971
4977
|
const answer = await input2.model.complete(prompt.messages);
|
|
4972
4978
|
return {
|
|
4973
4979
|
answer,
|
|
@@ -4977,6 +4983,7 @@ async function generateGroundedAnswer(input2) {
|
|
|
4977
4983
|
|
|
4978
4984
|
// src/rag/qa-service.ts
|
|
4979
4985
|
async function askWithRag(input2) {
|
|
4986
|
+
const now = input2.now ?? /* @__PURE__ */ new Date();
|
|
4980
4987
|
const evidence = await input2.retriever.retrieve(input2.question);
|
|
4981
4988
|
if (evidence.length === 0) {
|
|
4982
4989
|
return {
|
|
@@ -4987,7 +4994,8 @@ async function askWithRag(input2) {
|
|
|
4987
4994
|
return generateGroundedAnswer({
|
|
4988
4995
|
question: input2.question,
|
|
4989
4996
|
evidence,
|
|
4990
|
-
model: input2.model
|
|
4997
|
+
model: input2.model,
|
|
4998
|
+
now
|
|
4991
4999
|
});
|
|
4992
5000
|
}
|
|
4993
5001
|
|
|
@@ -5540,18 +5548,16 @@ function buildHtml() {
|
|
|
5540
5548
|
" <span>" + escapeHtml(item.status) + "</span>",
|
|
5541
5549
|
" <span>" + escapeHtml(citationCount) + " \u6761\u5F15\u7528</span>",
|
|
5542
5550
|
" </div>",
|
|
5543
|
-
" <div class
|
|
5544
|
-
" <div class
|
|
5551
|
+
" <div class=\\"message-body\\"><strong>\u95EE\uFF1A</strong>" + escapeHtml(item.question) + "</div>",
|
|
5552
|
+
" <div class=\\"message-body\\"><strong>\u7B54\uFF1A</strong>" + escapeHtml(item.answer) + "</div>",
|
|
5545
5553
|
"</article>",
|
|
5546
|
-
].join("
|
|
5547
|
-
");
|
|
5554
|
+
].join("\\n");
|
|
5548
5555
|
});
|
|
5549
5556
|
qaLogs.innerHTML = [
|
|
5550
5557
|
'<div class="message-list">',
|
|
5551
5558
|
rows.join(""),
|
|
5552
5559
|
"</div>",
|
|
5553
|
-
].join("
|
|
5554
|
-
");
|
|
5560
|
+
].join("\\n");
|
|
5555
5561
|
}
|
|
5556
5562
|
|
|
5557
5563
|
async function fetchJson(path) {
|