@zaclinley/dsh-mailharbor 0.10.1 → 0.11.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/lib/index.js CHANGED
@@ -606,7 +606,8 @@ var DEFAULTS = {
606
606
  provider: "deepseek-account",
607
607
  model: "deepseek-flash",
608
608
  styleSampleCount: 100,
609
- maxChars: 4e4
609
+ maxChars: 4e4,
610
+ summaryLength: "brief"
610
611
  },
611
612
  read: { markOnOpen: true, pollSeconds: 60 },
612
613
  render: { listLimit: 40 },
@@ -739,7 +740,8 @@ function loadConfig() {
739
740
  provider: stringOr(aiRaw.provider, DEFAULTS.ai.provider),
740
741
  model: stringOr(aiRaw.model, DEFAULTS.ai.model),
741
742
  styleSampleCount: intOr(aiRaw.styleSampleCount, DEFAULTS.ai.styleSampleCount, 10, 200),
742
- maxChars: intOr(aiRaw.maxChars, DEFAULTS.ai.maxChars, 1e3, 2e5)
743
+ maxChars: intOr(aiRaw.maxChars, DEFAULTS.ai.maxChars, 1e3, 2e5),
744
+ summaryLength: aiRaw.summaryLength === "normal" || aiRaw.summaryLength === "detailed" ? aiRaw.summaryLength : "brief"
743
745
  },
744
746
  read: {
745
747
  markOnOpen: readRaw.markOnOpen !== false,
@@ -1716,28 +1718,54 @@ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as rea
1716
1718
  import { dirname, join as join4 } from "node:path";
1717
1719
  var TIMEOUT_MS = 9e4;
1718
1720
  var MAX_PROMPT_CHARS = 4e4;
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
1721
+ var SUMMARY_RULES = {
1722
+ brief: {
1723
+ total: "\u603B\u957F\u4E0D\u8D85\u8FC7 180 \u5B57",
1724
+ conclusion: "\u4E00\u53E5\u8BDD\uFF08\u4E0D\u8D85\u8FC7 40 \u5B57\uFF09",
1725
+ actions: "\u6700\u591A 3 \u6761\uFF0C\u6BCF\u6761\u4E0D\u8D85\u8FC7 20 \u5B57",
1726
+ facts: "\u6700\u591A 5 \u6761\uFF0C\u6BCF\u6761\u4E0D\u8D85\u8FC7 30 \u5B57",
1727
+ replies: "\u6700\u591A 2 \u6761\uFF0C\u6BCF\u6761\u4E0D\u8D85\u8FC7 25 \u5B57"
1728
+ },
1729
+ normal: {
1730
+ total: "\u603B\u957F\u4E0D\u8D85\u8FC7 400 \u5B57",
1731
+ conclusion: "\u4E00\u5230\u4E24\u53E5\u8BDD\uFF08\u4E0D\u8D85\u8FC7 60 \u5B57\uFF09",
1732
+ actions: "\u6700\u591A 5 \u6761\uFF0C\u6BCF\u6761\u4E0D\u8D85\u8FC7 25 \u5B57",
1733
+ facts: "\u6700\u591A 8 \u6761\uFF0C\u6BCF\u6761\u4E0D\u8D85\u8FC7 40 \u5B57",
1734
+ replies: "\u6700\u591A 3 \u6761\uFF0C\u6BCF\u6761\u4E0D\u8D85\u8FC7 30 \u5B57"
1735
+ },
1736
+ detailed: {
1737
+ total: "\u4E0D\u8981\u5199\u6210\u62A5\u544A\uFF0C\u4F46\u4ECD\u4EE5\u4E8B\u5B9E\u4E3A\u4E3B",
1738
+ conclusion: "\u4E00\u53E5\u8BDD\uFF08\u4E0D\u8D85\u8FC7 100 \u5B57\uFF09\uFF0C\u53EF\u4EE5\u8865\u5145\u80CC\u666F",
1739
+ actions: "\u6700\u591A 6 \u6761\uFF0C\u6BCF\u6761\u4E0D\u8D85\u8FC7 35 \u5B57",
1740
+ facts: "\u6700\u591A 10 \u6761\uFF0C\u6BCF\u6761\u4E0D\u8D85\u8FC7 50 \u5B57",
1741
+ replies: "\u6700\u591A 4 \u6761\uFF0C\u6BCF\u6761\u4E0D\u8D85\u8FC7 40 \u5B57"
1742
+ }
1743
+ };
1744
+ function summarySystem(length) {
1745
+ const rules = SUMMARY_RULES[length];
1746
+ return `\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${rules.total}\u3002
1720
1747
 
1721
1748
  \u4E25\u683C\u6309\u4E0B\u9762\u56DB\u4E2A\u5C0F\u6807\u9898\u8F93\u51FA\uFF0C\u4E0D\u8981\u8F93\u51FA\u5176\u4ED6\u5185\u5BB9\uFF1A
1722
1749
 
1723
1750
  \u7ED3\u8BBA
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
1751
+ ${rules.conclusion}\u8BF4\u660E\u8FD9\u662F\u4EC0\u4E48\u90AE\u4EF6\u3001\u8C01\u8981\u505A\u4EC0\u4E48\u3002
1725
1752
 
1726
1753
  \u9700\u8981\u4F60\u505A\u4EC0\u4E48
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
1754
+ - ${rules.actions}\uFF1B\u6CA1\u6709\u5C31\u53EA\u5199\u300C\u65E0\u9700\u64CD\u4F5C\u300D\u3002
1728
1755
  - \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
1756
  - \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
1757
  - \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
1731
1758
 
1732
1759
  \u5173\u952E\u4FE1\u606F
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
1760
+ - ${rules.facts}\uFF1B\u53EA\u5217\u771F\u6B63\u6709\u7528\u7684\u65F6\u95F4\u3001\u91D1\u989D\u3001\u4EBA\u540D\u3001\u5355\u53F7\u3001\u94FE\u63A5\u3002
1734
1761
  - \u6CA1\u6709\u5C31\u5199\u300C\u65E0\u300D\u3002
1735
1762
 
1736
1763
  \u5EFA\u8BAE\u56DE\u590D\u8981\u70B9
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
1764
+ - \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${rules.replies}\u3002
1738
1765
  - \u5176\u4ED6\u8EAB\u4EFD\u4E0D\u8981\u8F93\u51FA\u8FD9\u4E2A\u5C0F\u6807\u9898\u3002
1739
1766
 
1740
1767
  \u4E0D\u8981\u590D\u8FF0\u539F\u6587\uFF0C\u4E0D\u8981\u89E3\u91CA\uFF0C\u4E0D\u8981\u8F93\u51FA\u601D\u8003\u8FC7\u7A0B\u3002`;
1768
+ }
1741
1769
  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
1742
1770
 
1743
1771
  \u8981\u6C42\uFF1A
@@ -1966,9 +1994,10 @@ var AiService = class {
1966
1994
  if (trimmed === "") throw new Error("\u6A21\u578B\u6CA1\u6709\u8FD4\u56DE\u5185\u5BB9");
1967
1995
  return trimmed;
1968
1996
  }
1969
- async summarize(message, email, signal) {
1970
- const output = await this.complete(SUMMARY_SYSTEM, contextOf(message, email), signal);
1971
- const compact = compactSummary(output);
1997
+ async summarize(message, email, length, signal) {
1998
+ const depth = length ?? this.deps.config().ai.summaryLength;
1999
+ const output = await this.complete(summarySystem(depth), contextOf(message, email), signal);
2000
+ const compact = compactSummary(output, depth);
1972
2001
  const role = roleOf(message, email);
1973
2002
  return role === "to" || role === "unknown" ? compact : stripReplySuggestions(compact);
1974
2003
  }
@@ -2131,7 +2160,7 @@ function parseTaskJson(text2) {
2131
2160
  }
2132
2161
  return result.slice(0, 30);
2133
2162
  }
2134
- function compactSummary(text2) {
2163
+ function compactSummary(text2, length = "brief") {
2135
2164
  const sections = [];
2136
2165
  let current = { title: "", lines: [] };
2137
2166
  for (const raw of text2.split(/\r?\n/)) {
@@ -2146,7 +2175,12 @@ function compactSummary(text2) {
2146
2175
  }
2147
2176
  if (current.title !== "" || current.lines.length > 0) sections.push(current);
2148
2177
  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 };
2178
+ const profiles = {
2179
+ brief: { \u7ED3\u8BBA: 2, \u9700\u8981\u4F60\u505A\u4EC0\u4E48: 3, \u5173\u952E\u4FE1\u606F: 5, \u5EFA\u8BAE\u56DE\u590D\u8981\u70B9: 2 },
2180
+ normal: { \u7ED3\u8BBA: 3, \u9700\u8981\u4F60\u505A\u4EC0\u4E48: 5, \u5173\u952E\u4FE1\u606F: 8, \u5EFA\u8BAE\u56DE\u590D\u8981\u70B9: 3 },
2181
+ detailed: { \u7ED3\u8BBA: 4, \u9700\u8981\u4F60\u505A\u4EC0\u4E48: 6, \u5173\u952E\u4FE1\u606F: 10, \u5EFA\u8BAE\u56DE\u590D\u8981\u70B9: 4 }
2182
+ };
2183
+ const limits = profiles[length] ?? profiles.brief;
2150
2184
  const output = [];
2151
2185
  for (const section of sections) {
2152
2186
  if (section.title === "") continue;
@@ -2410,7 +2444,7 @@ ${conversation.trim()}
2410
2444
  }
2411
2445
 
2412
2446
  // src/host/version.ts
2413
- var VERSION = "0.10.1";
2447
+ var VERSION = "0.11.0";
2414
2448
 
2415
2449
  // src/host/api.ts
2416
2450
  init_smtp();
@@ -2760,6 +2794,7 @@ function buildRouter(runtime) {
2760
2794
  mailboxOfPayload(payload)
2761
2795
  );
2762
2796
  const config = runtime.current;
2797
+ const summaryLength = payload.length === "normal" || payload.length === "detailed" || payload.length === "brief" ? payload.length : config.ai.summaryLength;
2763
2798
  const instruction = typeof payload.instruction === "string" ? payload.instruction : "";
2764
2799
  const language = payload.language === "en" ? "en" : "zh";
2765
2800
  const target = payload.target === "en" ? "en" : "zh";
@@ -2769,7 +2804,8 @@ function buildRouter(runtime) {
2769
2804
  let html;
2770
2805
  let meta;
2771
2806
  if (kind === "summary") {
2772
- output = await ai.summarize(detail, account.email);
2807
+ output = await ai.summarize(detail, account.email, summaryLength);
2808
+ meta = { length: summaryLength };
2773
2809
  } else if (kind === "reply") {
2774
2810
  output = await ai.reply(account, detail, { instruction, language });
2775
2811
  html = textToHtml(output);
@@ -2891,8 +2927,9 @@ function buildRouter(runtime) {
2891
2927
  mailboxOfPayload(payload)
2892
2928
  );
2893
2929
  try {
2894
- const summary = await runtime.ai().summarize(detail, account.email);
2895
- return { summary, blocks: summaryBlocks(summary) };
2930
+ const length = payload.length === "normal" || payload.length === "detailed" || payload.length === "brief" ? payload.length : runtime.current.ai.summaryLength;
2931
+ const summary = await runtime.ai().summarize(detail, account.email, length);
2932
+ return { summary, blocks: summaryBlocks(summary), length };
2896
2933
  } catch (error) {
2897
2934
  throw aiHttpError(error);
2898
2935
  }
@@ -3272,7 +3309,8 @@ function settingsView(config) {
3272
3309
  enabled: config.ai.enabled,
3273
3310
  provider: config.ai.provider,
3274
3311
  model: config.ai.model,
3275
- styleSampleCount: config.ai.styleSampleCount
3312
+ styleSampleCount: config.ai.styleSampleCount,
3313
+ summaryLength: config.ai.summaryLength
3276
3314
  },
3277
3315
  read: { markOnOpen: config.read.markOnOpen, pollSeconds: config.read.pollSeconds },
3278
3316
  render: { listLimit: config.render.listLimit },