@zaclinley/dsh-mailharbor 0.9.0 → 0.10.0
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 +27 -0
- package/lib/client.js +42 -31
- package/lib/client.js.map +2 -2
- package/lib/index.js +76 -15
- package/lib/index.js.map +2 -2
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -1716,21 +1716,28 @@ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as rea
|
|
|
1716
1716
|
import { dirname, join as join4 } from "node:path";
|
|
1717
1717
|
var TIMEOUT_MS = 9e4;
|
|
1718
1718
|
var MAX_PROMPT_CHARS = 4e4;
|
|
1719
|
-
var SUMMARY_SYSTEM = `\u4F60\u662F\u90AE\u4EF6\u52A9\u7406\uFF0C\u670D\u52A1\u4E8E\u4E2D\u6587\u7528\u6237\u3002\
|
|
1719
|
+
var SUMMARY_SYSTEM = `\u4F60\u662F\u90AE\u4EF6\u52A9\u7406\uFF0C\u670D\u52A1\u4E8E\u4E2D\u6587\u7528\u6237\u3002\u7528\u7B80\u4F53\u4E2D\u6587\uFF0C\u7B80\u6D01\u4F18\u5148\uFF0C\u603B\u957F\u4E0D\u8D85\u8FC7 180 \u5B57\u3002
|
|
1720
|
+
|
|
1721
|
+
\u4E25\u683C\u6309\u4E0B\u9762\u56DB\u4E2A\u5C0F\u6807\u9898\u8F93\u51FA\uFF0C\u4E0D\u8981\u8F93\u51FA\u5176\u4ED6\u5185\u5BB9\uFF1A
|
|
1720
1722
|
|
|
1721
1723
|
\u7ED3\u8BBA
|
|
1722
|
-
\
|
|
1724
|
+
\u4E00\u53E5\u8BDD\uFF08\u4E0D\u8D85\u8FC7 40 \u5B57\uFF09\u8BF4\u660E\u8FD9\u662F\u4EC0\u4E48\u90AE\u4EF6\u3001\u8C01\u8981\u505A\u4EC0\u4E48\u3002
|
|
1723
1725
|
|
|
1724
1726
|
\u9700\u8981\u4F60\u505A\u4EC0\u4E48
|
|
1725
|
-
\
|
|
1727
|
+
- \u6700\u591A 3 \u6761\uFF0C\u6BCF\u6761\u4E0D\u8D85\u8FC7 20 \u5B57\uFF1B\u6CA1\u6709\u5C31\u53EA\u5199\u300C\u65E0\u9700\u64CD\u4F5C\u300D\u3002
|
|
1728
|
+
- \u5982\u679C\u8EAB\u4EFD\u662F\u300C\u4EC5\u6284\u9001\u300D\uFF0C\u53EA\u5199\u300C\u4F60\u53EA\u662F\u88AB\u6284\u9001\uFF0C\u901A\u5E38\u65E0\u9700\u64CD\u4F5C\u300D\u3002
|
|
1729
|
+
- \u5982\u679C\u8EAB\u4EFD\u662F\u300C\u53D1\u4EF6\u4EBA\u300D\uFF0C\u53EA\u5199\u300C\u8FD9\u662F\u4F60\u53D1\u51FA\u7684\u90AE\u4EF6\uFF0C\u65E0\u9700\u64CD\u4F5C\u300D\u3002
|
|
1730
|
+
- \u5982\u679C\u8EAB\u4EFD\u662F\u300C\u4E0D\u5728\u6536\u4EF6\u4EBA/\u6284\u9001\u5217\u8868\u300D\uFF0C\u53EA\u5199\u300C\u4F60\u4E0D\u5728\u6536\u4EF6\u4EBA\u5217\u8868\uFF0C\u901A\u5E38\u65E0\u9700\u64CD\u4F5C\u300D\u3002
|
|
1726
1731
|
|
|
1727
1732
|
\u5173\u952E\u4FE1\u606F
|
|
1728
|
-
\
|
|
1733
|
+
- \u6700\u591A 5 \u6761\uFF0C\u6BCF\u6761\u4E0D\u8D85\u8FC7 30 \u5B57\uFF1B\u53EA\u5217\u771F\u6B63\u6709\u7528\u7684\u65F6\u95F4\u3001\u91D1\u989D\u3001\u4EBA\u540D\u3001\u5355\u53F7\u3001\u94FE\u63A5\u3002
|
|
1734
|
+
- \u6CA1\u6709\u5C31\u5199\u300C\u65E0\u300D\u3002
|
|
1729
1735
|
|
|
1730
1736
|
\u5EFA\u8BAE\u56DE\u590D\u8981\u70B9
|
|
1731
|
-
|
|
1737
|
+
- \u53EA\u6709\u5F53\u8EAB\u4EFD\u662F\u300C\u76F4\u63A5\u6536\u4EF6\u4EBA\u300D\u4E14\u90AE\u4EF6\u660E\u786E\u8981\u6C42\u4F60\u884C\u52A8\u65F6\u624D\u8F93\u51FA\uFF1B\u6700\u591A 2 \u6761\uFF0C\u6BCF\u6761\u4E0D\u8D85\u8FC7 25 \u5B57\u3002
|
|
1738
|
+
- \u5176\u4ED6\u8EAB\u4EFD\u4E0D\u8981\u8F93\u51FA\u8FD9\u4E2A\u5C0F\u6807\u9898\u3002
|
|
1732
1739
|
|
|
1733
|
-
\
|
|
1740
|
+
\u4E0D\u8981\u590D\u8FF0\u539F\u6587\uFF0C\u4E0D\u8981\u89E3\u91CA\uFF0C\u4E0D\u8981\u8F93\u51FA\u601D\u8003\u8FC7\u7A0B\u3002`;
|
|
1734
1741
|
var REPLY_SYSTEM = (language, style) => `\u4F60\u662F\u90AE\u4EF6\u5199\u4F5C\u52A9\u7406\u3002\u6839\u636E\u539F\u59CB\u90AE\u4EF6\u548C\u7528\u6237\u7684\u8981\u6C42\uFF0C\u5199\u4E00\u5C01\u53EF\u4EE5\u76F4\u63A5\u53D1\u9001\u7684\u56DE\u590D\u6B63\u6587\u3002
|
|
1735
1742
|
|
|
1736
1743
|
\u8981\u6C42\uFF1A
|
|
@@ -1837,12 +1844,30 @@ function bodyText(message) {
|
|
|
1837
1844
|
if (message.text.trim() !== "") return message.text;
|
|
1838
1845
|
return (message.html ?? "").replace(/<style[\s\S]*?<\/style>/gi, "").replace(/<script[\s\S]*?<\/script>/gi, "").replace(/<br\s*\/?>/gi, "\n").replace(/<\/(p|div|li|tr|h[1-6])>/gi, "\n").replace(/<[^>]+>/g, "").replace(/ /g, " ").replace(/&/g, "&").trim();
|
|
1839
1846
|
}
|
|
1840
|
-
function
|
|
1847
|
+
function roleOf(message, email) {
|
|
1848
|
+
const target = String(email ?? "").trim().toLowerCase();
|
|
1849
|
+
if (target === "") return "unknown";
|
|
1850
|
+
const has = (list) => list.some((item) => item.address.trim().toLowerCase() === target);
|
|
1851
|
+
if (has(message.to)) return "to";
|
|
1852
|
+
if (has(message.cc)) return "cc";
|
|
1853
|
+
if (message.from.address.trim().toLowerCase() === target) return "sender";
|
|
1854
|
+
return "other";
|
|
1855
|
+
}
|
|
1856
|
+
var ROLE_TEXT = {
|
|
1857
|
+
to: "\u76F4\u63A5\u6536\u4EF6\u4EBA",
|
|
1858
|
+
cc: "\u4EC5\u6284\u9001\uFF08\u4E0D\u5728\u6536\u4EF6\u4EBA\u91CC\uFF09",
|
|
1859
|
+
sender: "\u53D1\u4EF6\u4EBA\uFF08\u4F60\u53D1\u51FA\u7684\u90AE\u4EF6\uFF09",
|
|
1860
|
+
other: "\u4E0D\u5728\u6536\u4EF6\u4EBA/\u6284\u9001\u5217\u8868\uFF08\u53EF\u80FD\u662F\u90AE\u4EF6\u5217\u8868\u6216\u5BC6\u9001\uFF09",
|
|
1861
|
+
unknown: "\u672A\u77E5"
|
|
1862
|
+
};
|
|
1863
|
+
function contextOf(message, email) {
|
|
1864
|
+
const role = roleOf(message, email);
|
|
1841
1865
|
const lines = [
|
|
1842
1866
|
`\u4E3B\u9898: ${message.subject}`,
|
|
1843
1867
|
`\u53D1\u4EF6\u4EBA: ${message.from.name !== "" ? `${message.from.name} <${message.from.address}>` : message.from.address}`,
|
|
1844
1868
|
`\u6536\u4EF6\u4EBA: ${message.to.map((item) => item.name !== "" ? `${item.name} <${item.address}>` : item.address).join(", ")}`,
|
|
1845
1869
|
...message.cc.length === 0 ? [] : [`\u6284\u9001: ${message.cc.map((item) => item.address).join(", ")}`],
|
|
1870
|
+
...role === "unknown" ? [] : [`\u4F60\u7684\u8EAB\u4EFD: ${ROLE_TEXT[role]}`],
|
|
1846
1871
|
`\u65F6\u95F4: ${message.date}`,
|
|
1847
1872
|
"",
|
|
1848
1873
|
clip(bodyText(message))
|
|
@@ -1941,8 +1966,11 @@ var AiService = class {
|
|
|
1941
1966
|
if (trimmed === "") throw new Error("\u6A21\u578B\u6CA1\u6709\u8FD4\u56DE\u5185\u5BB9");
|
|
1942
1967
|
return trimmed;
|
|
1943
1968
|
}
|
|
1944
|
-
async summarize(message, signal) {
|
|
1945
|
-
|
|
1969
|
+
async summarize(message, email, signal) {
|
|
1970
|
+
const output = await this.complete(SUMMARY_SYSTEM, contextOf(message, email), signal);
|
|
1971
|
+
const compact = compactSummary(output);
|
|
1972
|
+
const role = roleOf(message, email);
|
|
1973
|
+
return role === "to" || role === "unknown" ? compact : stripReplySuggestions(compact);
|
|
1946
1974
|
}
|
|
1947
1975
|
async reply(account, message, options = {}, signal) {
|
|
1948
1976
|
const style = this.style(account)?.profile ?? "";
|
|
@@ -1961,14 +1989,14 @@ var AiService = class {
|
|
|
1961
1989
|
return this.complete(TRANSLATE_SYSTEM(target), clip(text2, 2e4), signal);
|
|
1962
1990
|
}
|
|
1963
1991
|
/** Free-form question about a mail, with up to three earlier AI outputs as context. */
|
|
1964
|
-
async ask(message, question, history, signal) {
|
|
1992
|
+
async ask(message, question, history, email, signal) {
|
|
1965
1993
|
const prompt = (question ?? "").trim();
|
|
1966
1994
|
if (prompt === "") throw new Error("\u95EE\u9898\u4E0D\u80FD\u4E3A\u7A7A");
|
|
1967
1995
|
const earlier = history.filter((item) => item.trim() !== "").slice(-3).map((item, index) => `\u3010\u5DF2\u6709\u8BB0\u5F55 ${String(index + 1)}\u3011
|
|
1968
1996
|
${clip(item, 4e3)}`).join("\n\n");
|
|
1969
1997
|
const user = [
|
|
1970
1998
|
"\u90AE\u4EF6\uFF1A",
|
|
1971
|
-
contextOf(message),
|
|
1999
|
+
contextOf(message, email),
|
|
1972
2000
|
...earlier === "" ? [] : ["", "\u5DF2\u6709 AI \u8BB0\u5F55\uFF1A", earlier],
|
|
1973
2001
|
"",
|
|
1974
2002
|
`\u7528\u6237\u7684\u95EE\u9898\uFF1A${prompt}`
|
|
@@ -2103,6 +2131,39 @@ function parseTaskJson(text2) {
|
|
|
2103
2131
|
}
|
|
2104
2132
|
return result.slice(0, 30);
|
|
2105
2133
|
}
|
|
2134
|
+
function compactSummary(text2) {
|
|
2135
|
+
const sections = [];
|
|
2136
|
+
let current = { title: "", lines: [] };
|
|
2137
|
+
for (const raw of text2.split(/\r?\n/)) {
|
|
2138
|
+
const line2 = raw.trim();
|
|
2139
|
+
const heading = /^#{0,4}\s*(结论|需要你做什么|关键信息|建议回复要点)\s*[::]?\s*$/.exec(line2);
|
|
2140
|
+
if (heading !== null) {
|
|
2141
|
+
if (current.title !== "" || current.lines.length > 0) sections.push(current);
|
|
2142
|
+
current = { title: heading[1] ?? "", lines: [] };
|
|
2143
|
+
} else if (line2 !== "") {
|
|
2144
|
+
current.lines.push(line2.replace(/^[-*•]\s*/, "").trim());
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
if (current.title !== "" || current.lines.length > 0) sections.push(current);
|
|
2148
|
+
if (sections.length === 0) return text2.trim();
|
|
2149
|
+
const limits = { \u7ED3\u8BBA: 2, \u9700\u8981\u4F60\u505A\u4EC0\u4E48: 3, \u5173\u952E\u4FE1\u606F: 5, \u5EFA\u8BAE\u56DE\u590D\u8981\u70B9: 2 };
|
|
2150
|
+
const output = [];
|
|
2151
|
+
for (const section of sections) {
|
|
2152
|
+
if (section.title === "") continue;
|
|
2153
|
+
const limit = limits[section.title] ?? 3;
|
|
2154
|
+
const lines = section.lines.filter((line2) => line2 !== "").slice(0, limit);
|
|
2155
|
+
if (lines.length === 0) continue;
|
|
2156
|
+
output.push(`${section.title}
|
|
2157
|
+
${lines.join("\n")}`);
|
|
2158
|
+
}
|
|
2159
|
+
return output.join("\n\n");
|
|
2160
|
+
}
|
|
2161
|
+
function stripReplySuggestions(text2) {
|
|
2162
|
+
const lines = text2.split(/\r?\n/);
|
|
2163
|
+
const index = lines.findIndex((line2) => /^#{0,4}\s*建议回复要点\s*[::]?\s*$/.test(line2.trim()));
|
|
2164
|
+
if (index < 0) return text2.trimEnd();
|
|
2165
|
+
return lines.slice(0, index).join("\n").trimEnd();
|
|
2166
|
+
}
|
|
2106
2167
|
function summaryBlocks(text2) {
|
|
2107
2168
|
const blocks = [];
|
|
2108
2169
|
let current = { title: "", lines: [] };
|
|
@@ -2349,7 +2410,7 @@ ${conversation.trim()}
|
|
|
2349
2410
|
}
|
|
2350
2411
|
|
|
2351
2412
|
// src/host/version.ts
|
|
2352
|
-
var VERSION = "0.
|
|
2413
|
+
var VERSION = "0.10.0";
|
|
2353
2414
|
|
|
2354
2415
|
// src/host/api.ts
|
|
2355
2416
|
init_smtp();
|
|
@@ -2708,7 +2769,7 @@ function buildRouter(runtime) {
|
|
|
2708
2769
|
let html;
|
|
2709
2770
|
let meta;
|
|
2710
2771
|
if (kind === "summary") {
|
|
2711
|
-
output = await ai.summarize(detail);
|
|
2772
|
+
output = await ai.summarize(detail, account.email);
|
|
2712
2773
|
} else if (kind === "reply") {
|
|
2713
2774
|
output = await ai.reply(account, detail, { instruction, language });
|
|
2714
2775
|
html = textToHtml(output);
|
|
@@ -2727,7 +2788,7 @@ function buildRouter(runtime) {
|
|
|
2727
2788
|
meta = { target };
|
|
2728
2789
|
} else {
|
|
2729
2790
|
const earlier = runtime.aiThreads(account).get(key)?.cards.filter((card2) => card2.kind === "answer").map((card2) => card2.output) ?? [];
|
|
2730
|
-
output = await ai.ask(detail, instruction, earlier);
|
|
2791
|
+
output = await ai.ask(detail, instruction, earlier, account.email);
|
|
2731
2792
|
}
|
|
2732
2793
|
const card = {
|
|
2733
2794
|
id: randomUUID3(),
|
|
@@ -2830,7 +2891,7 @@ function buildRouter(runtime) {
|
|
|
2830
2891
|
mailboxOfPayload(payload)
|
|
2831
2892
|
);
|
|
2832
2893
|
try {
|
|
2833
|
-
const summary = await runtime.ai().summarize(detail);
|
|
2894
|
+
const summary = await runtime.ai().summarize(detail, account.email);
|
|
2834
2895
|
return { summary, blocks: summaryBlocks(summary) };
|
|
2835
2896
|
} catch (error) {
|
|
2836
2897
|
throw aiHttpError(error);
|