pi-distill 1.0.1 → 1.0.2

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/README.md CHANGED
@@ -33,7 +33,7 @@ The distillation prompt strictly follows the current locale selected by `/pi-lan
33
33
  - Treats a prompt containing only `RAW` as an explicit request for the original output.
34
34
  - Uses the current session model by default, or a configured `provider/model` override.
35
35
  - Keeps diagnostic metadata such as status, character counts, compression ratio, duration, and anomalies in the tool result details.
36
- - Writes oversized distilled output or final output to a temporary file and returns its path instead of overflowing the tool result.
36
+ - Oversized output is no longer written to a file or truncated by pi-distill; it is left to Pi's own output-limiting mechanism.
37
37
  - Adds a compact audit card when the active Pi display middleware is available, with a fallback renderer otherwise. The shared display protocol is provided by `pi-extensions-tool-display`.
38
38
 
39
39
  It does not register a second `bash`, `read`, `grep`, or `find` tool.
@@ -117,7 +117,7 @@ Agent consumes a result suited to the current decision, with auditable diagnosti
117
117
  | `outputRequest` | Behavior | Use it when |
118
118
  | --- | --- | --- |
119
119
  | Omitted | Invalid tool call; Pi rejects the call before the underlying tool runs | Never omit it; use `RAW` when no compression is explicitly requested |
120
- | Exactly `RAW` (case-insensitive) | Skip the distillation model and keep the complete original text; oversized text is returned through a file path | You need to inspect, copy, or verify exact output |
120
+ | Exactly `RAW` (case-insensitive) | Skip the distillation model and keep the complete original text; oversized text is handled by Pi's own output-limiting mechanism | You need to inspect, copy, or verify exact output |
121
121
  | Any non-empty value other than `RAW` | Call the model once the output reaches the threshold; the prompt defines what to retain | “Keep errors, warnings, and final status” workflows |
122
122
  | Any non-text content such as images or audio | Preserve the result as-is; do not send it to the distillation model or apply text truncation | Image reads, binary results, and mixed text/media results |
123
123
 
@@ -138,7 +138,7 @@ The distillation prompt strictly follows the locale selected by `/pi-language`:
138
138
  - Registers no replacement tools, does not change tool execution semantics, and does not require a separately installed `pi-tool-display` host package.
139
139
  - Text distillation is lossy; use `RAW` when completeness matters.
140
140
  - Non-text results are a completeness boundary: images, audio, binary data, and mixed content bypass text distillation.
141
- - Oversized distilled or final text is written to a temporary file and represented by its path, preventing unbounded context growth.
141
+ - Oversized distilled or final text is no longer written to a file or truncated by pi-distill; it is left to Pi's own output-limiting mechanism, preventing unbounded context growth.
142
142
  - If no model is available, distillation fails open: the original result is retained and Pi can continue running.
143
143
 
144
144
  ## Configuration
@@ -157,7 +157,6 @@ Start from [`config.example.json`](./config.example.json):
157
157
  "model": "",
158
158
  "minChars": 200,
159
159
  "maxChars": 100000,
160
- "maxOutputChars": 10000,
161
160
  "timeoutSeconds": 10,
162
161
  "missedCompressionRatio": 10,
163
162
  "summarizeErrors": true,
@@ -175,14 +174,13 @@ Configuration-file fields take precedence over environment variables. Unspecifie
175
174
  | --- | --- |
176
175
  | `model` | Optional `provider/model`; empty uses the current Pi session model. |
177
176
  | `minChars` | Minimum output size before a summary is requested. |
178
- | `maxChars` | Maximum size of the model's distilled result before it is written to a file. |
179
- | `maxOutputChars` | Maximum text size returned to the agent; larger results are written to a file. |
177
+ | `maxChars` | Maximum output budget for the distillation model (about `maxChars / 2` tokens) and a diagnostic reference; no longer used to write files. |
180
178
  | `timeoutSeconds` | Maximum time allowed for the distillation model call. |
181
179
  | `missedCompressionRatio` | Long-output threshold for a diagnostic when no summary prompt was supplied. |
182
180
  | `summarizeErrors` | Whether error results should still be sent to the distillation model. |
183
181
  | `render.*` | Controls the audit card, prompt preview, and result preview. |
184
182
 
185
- The main environment variables are `PI_DISTILL_MODEL`, `PI_DISTILL_MIN_CHARS`, `PI_DISTILL_MAX_CHARS`, `PI_DISTILL_MAX_OUTPUT_CHARS`, `PI_DISTILL_TIMEOUT_SECONDS`, `PI_DISTILL_MISSED_COMPRESSION_RATIO`, and `PI_DISTILL_SUMMARIZE_ERRORS`.
183
+ The main environment variables are `PI_DISTILL_MODEL`, `PI_DISTILL_MIN_CHARS`, `PI_DISTILL_MAX_CHARS`, `PI_DISTILL_TIMEOUT_SECONDS`, `PI_DISTILL_MISSED_COMPRESSION_RATIO`, and `PI_DISTILL_SUMMARIZE_ERRORS`. The legacy `maxOutputChars` / `PI_DISTILL_MAX_OUTPUT_CHARS` option is still parsed for backward compatibility but no longer has any effect.
186
184
 
187
185
  ## Requirements
188
186
 
package/README.zh-CN.md CHANGED
@@ -33,7 +33,7 @@
33
33
  - 当提示词严格只有 `RAW` 时,视为明确要求返回原始输出。
34
34
  - 默认使用当前会话模型,也可以配置独立的 `provider/model`。
35
35
  - 在工具结果 details 中保留状态、字符数、压缩比、耗时和异常等诊断信息。
36
- - 提炼结果或最终返回结果过大时写入临时文件,只把文件路径返回给 Agent,避免工具结果失控膨胀。
36
+ - 超长输出不再由 pi-distill 写文件或截断,统一交由 Pi 自身的输出限制机制处理。
37
37
  - 当前 Pi 展示中间件可用时显示紧凑审计卡片,否则使用自己的 fallback renderer。展示协议由公共运行库 `pi-extensions-tool-display` 提供。
38
38
 
39
39
  它不会注册第二个 `bash`、`read`、`grep` 或 `find` 工具。
@@ -103,7 +103,7 @@ Agent 提出处理目标
103
103
  ↓ 通过 outputRequest 传给工具
104
104
  工具执行真实操作,返回 stdout / stderr / 文件内容 / 多媒体结果
105
105
 
106
- pi-distill 根据真实结果和配置决定:原样返回、调用模型提炼,或写入文件
106
+ pi-distill 根据真实结果和配置决定:原样返回,或调用模型提炼
107
107
 
108
108
  Agent 消费更适合当前决策的结果,并获得可审计的处理诊断
109
109
  ```
@@ -119,7 +119,7 @@ Agent 消费更适合当前决策的结果,并获得可审计的处理诊断
119
119
  | `outputRequest` | 行为 | 适用场景 |
120
120
  | --- | --- | --- |
121
121
  | 未提供 | 工具调用无效;Pi 会在底层工具执行前拒绝该调用 | 不要省略;未明确要求压缩时使用 `RAW` |
122
- | 严格为 `RAW`(大小写不敏感) | 不调用提炼模型,保留完整原始文本;如超出返回上限则返回原文文件路径 | 逐字核对、复制内容、需要完整日志时 |
122
+ | 严格为 `RAW`(大小写不敏感) | 不调用提炼模型,保留完整原始文本;超长时由 Pi 自身的输出限制机制处理 | 逐字核对、复制内容、需要完整日志时 |
123
123
  | 任意非空且非 `RAW` | 输出达到阈值后调用模型,具体保留内容由 prompt 决定 | “只保留错误、警告和最终状态”等场景 |
124
124
  | 包含图片、音频或其他非文本内容 | 原样保留,不发送给提炼模型,不做文本长度截断 | 图片读取、二进制结果、混合文本与图片结果 |
125
125
 
@@ -140,7 +140,7 @@ Agent 消费更适合当前决策的结果,并获得可审计的处理诊断
140
140
  - 不注册替代工具,不改变原工具的执行语义,也不要求额外安装独立的 `pi-tool-display` 宿主包。
141
141
  - 文本提炼是有损操作;完整性要求应使用 `RAW`。
142
142
  - 非文本结果是完整性边界:图片、音频、二进制和混合 content 不进入文本提炼链路。
143
- - 提炼结果或最终文本过大时写入临时文件并返回路径,避免上下文无限膨胀。
143
+ - 超长输出不再由 pi-distill 写临时文件或截断,统一交由 Pi 自身的输出限制机制处理,避免上下文无限膨胀。
144
144
  - 当前会话没有模型时,提炼会失败并保留原始结果,不阻止 Pi 启动。
145
145
 
146
146
  ## 配置
@@ -159,7 +159,6 @@ Agent 消费更适合当前决策的结果,并获得可审计的处理诊断
159
159
  "model": "",
160
160
  "minChars": 200,
161
161
  "maxChars": 100000,
162
- "maxOutputChars": 10000,
163
162
  "timeoutSeconds": 10,
164
163
  "missedCompressionRatio": 10,
165
164
  "summarizeErrors": true,
@@ -177,14 +176,13 @@ Agent 消费更适合当前决策的结果,并获得可审计的处理诊断
177
176
  | --- | --- |
178
177
  | `model` | 可选的 `provider/model`;为空时使用当前 Pi 会话模型。 |
179
178
  | `minChars` | 达到此输出长度后才请求提炼。 |
180
- | `maxChars` | 模型提炼结果超过此长度时写入文件。 |
181
- | `maxOutputChars` | 返回给 Agent 的最大文本长度,超出后写入文件。 |
179
+ | `maxChars` | 提炼模型的最大输出预算(约 `maxChars / 2` tokens),同时作为诊断参考;不再用于写文件。 |
182
180
  | `timeoutSeconds` | 提炼模型调用的最长等待时间。 |
183
181
  | `missedCompressionRatio` | 没有提供摘要 prompt 时,用于长输出诊断的倍数阈值。 |
184
182
  | `summarizeErrors` | 工具返回错误时是否仍发送给提炼模型。 |
185
183
  | `render.*` | 控制审计卡片、prompt 预览和结果预览。 |
186
184
 
187
- 主要环境变量包括 `PI_DISTILL_MODEL`、`PI_DISTILL_MIN_CHARS`、`PI_DISTILL_MAX_CHARS`、`PI_DISTILL_MAX_OUTPUT_CHARS`、`PI_DISTILL_TIMEOUT_SECONDS`、`PI_DISTILL_MISSED_COMPRESSION_RATIO` 和 `PI_DISTILL_SUMMARIZE_ERRORS`。
185
+ 主要环境变量包括 `PI_DISTILL_MODEL`、`PI_DISTILL_MIN_CHARS`、`PI_DISTILL_MAX_CHARS`、`PI_DISTILL_TIMEOUT_SECONDS`、`PI_DISTILL_MISSED_COMPRESSION_RATIO` 和 `PI_DISTILL_SUMMARIZE_ERRORS`。旧配置中的 `maxOutputChars` / `PI_DISTILL_MAX_OUTPUT_CHARS` 仍会被解析以兼容旧文件,但不再生效。
188
186
 
189
187
  ## 要求
190
188
 
@@ -3,7 +3,6 @@
3
3
  "model": "",
4
4
  "minChars": 200,
5
5
  "maxChars": 100000,
6
- "maxOutputChars": 10000,
7
6
  "timeoutSeconds": 10,
8
7
  "missedCompressionRatio": 10,
9
8
  "summarizeErrors": true,
@@ -52,8 +52,8 @@
52
52
  "en-US": " • Ctrl+O to expand"
53
53
  },
54
54
  "header": {
55
- "zh-CN": " Distill {status}",
56
- "en-US": " Distill {status}"
55
+ "zh-CN": " Distill {status}",
56
+ "en-US": " Distill {status}"
57
57
  },
58
58
  "summary": {
59
59
  "zh-CN": "摘要",
@@ -75,4 +75,4 @@
75
75
  "zh-CN": "outputRequest",
76
76
  "en-US": "outputRequest"
77
77
  }
78
- }
78
+ }
@@ -63,10 +63,6 @@
63
63
  "zh-CN": "摘要上限:{value} 字符",
64
64
  "en-US": "Summary limit: {value} chars"
65
65
  },
66
- "finalLimit": {
67
- "zh-CN": "最终输出上限:{value} 字符",
68
- "en-US": "Final output limit: {value} chars"
69
- },
70
66
  "timeout": {
71
67
  "zh-CN": "超时:{value}s",
72
68
  "en-US": "Timeout: {value}s"
@@ -99,10 +95,6 @@
99
95
  "zh-CN": "摘要字符上限",
100
96
  "en-US": "Summary character limit"
101
97
  },
102
- "finalLimitTitle": {
103
- "zh-CN": "最终输出字符上限",
104
- "en-US": "Final output character limit"
105
- },
106
98
  "timeoutTitle": {
107
99
  "zh-CN": "提炼模型超时(秒)",
108
100
  "en-US": "Summarizer timeout (seconds)"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-distill",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Pi tool-output distillation with file-first configuration",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
@@ -58,8 +58,8 @@ function formatCount(value: number): string {
58
58
 
59
59
  function renderDistillAuditLine(audit: DistillAuditView, line: string, index: number, theme: RenderTheme): string {
60
60
  if (index === 0) {
61
- const title = theme.fg("accent", theme.bold(" Distill"));
62
- const afterTitle = line.slice(" Distill".length);
61
+ const title = theme.fg("accent", theme.bold(" Distill"));
62
+ const afterTitle = line.slice(" Distill".length);
63
63
  const statusIndex = afterTitle.indexOf(audit.statusLabel);
64
64
  if (statusIndex < 0) return `${title}${theme.fg("muted", afterTitle)}`;
65
65
  const beforeStatus = afterTitle.slice(0, statusIndex);
package/src/index.ts CHANGED
@@ -6,14 +6,13 @@
6
6
  *
7
7
  * 所有工具统一使用 outputRequest:严格传入 RAW 时返回原始输出;其他非空
8
8
  * outputRequest 表示调用提炼模型,具体保留内容由 outputRequest 决定。
9
- * 提炼结果超过 maxChars 时写入临时文件,只返回文件路径。
9
+ * 超长输出由 Pi 自身的 output-limit 机制处理,pi-distill 不再做文件转储或截断。
10
10
  *
11
11
  * 配置文件优先;旧环境变量继续兼容:
12
12
  * - ~/.pi/agent/extensions/pi-distill/config.json
13
13
  * - PI_DISTILL_MODEL=provider/model
14
14
  * - PI_DISTILL_MIN_CHARS=触发提炼的最小输出字符数,默认 200
15
- * - PI_DISTILL_MAX_CHARS=提炼结果超过此字符数时写入文件,默认 100000
16
- * - PI_DISTILL_MAX_OUTPUT_CHARS=最终返回内容超过此字符数时写入文件,默认 10000
15
+ * - PI_DISTILL_MAX_CHARS=提炼模型最大输出字符数,默认 100000
17
16
  * - PI_DISTILL_TIMEOUT_SECONDS=模型调用最长等待秒数,默认 10
18
17
  * - PI_DISTILL_MISSED_COMPRESSION_RATIO=长输出提醒倍数,默认 10
19
18
  * - 旧 PI_BASH_SUMMARY_* 变量作为兼容回退
@@ -36,10 +35,9 @@ import {
36
35
  isDistillToolDisplayMiddlewareActive,
37
36
  registerDistillToolDisplayMiddleware,
38
37
  } from "./tool-display-bridge.ts";
39
- import { getTextContent, hasNonTextContent, limitReturnedToolResult } from "./output-limit.ts";
38
+ import { getTextContent, hasNonTextContent } from "./output-limit.ts";
40
39
  import { mkdir, readFile, writeFile } from "node:fs/promises";
41
- import { tmpdir } from "node:os";
42
- import { dirname, join } from "node:path";
40
+ import { dirname } from "node:path";
43
41
  import { createTranslator, loadCatalog } from "pi-extensions-i18n";
44
42
  import {
45
43
  buildSummaryPrompt,
@@ -91,7 +89,6 @@ const OUTPUT_REQUEST_SYSTEM_GUIDELINE = i18n.t("outputRequestSystemGuideline");
91
89
  type SummaryResult = {
92
90
  text: string;
93
91
  summaryChars: number;
94
- summaryFilePath?: string;
95
92
  summaryModel: string;
96
93
  };
97
94
 
@@ -229,17 +226,6 @@ async function getCompleteOutput(result: ToolResult): Promise<string> {
229
226
  return getTextContent(result);
230
227
  }
231
228
 
232
- async function writeSummaryFile(summary: string): Promise<string> {
233
- const directory = join(tmpdir(), "pi-distill");
234
- await mkdir(directory, { recursive: true });
235
- const filePath = join(
236
- directory,
237
- `summary-${Date.now()}-${Math.random().toString(16).slice(2)}.txt`,
238
- );
239
- await writeFile(filePath, summary, "utf8");
240
- return filePath;
241
- }
242
-
243
229
  async function summarizeOutput(
244
230
  prompt: string,
245
231
  output: string,
@@ -293,19 +279,9 @@ async function summarizeOutput(
293
279
  .trim();
294
280
 
295
281
  if (!summary) throw new Error("Summarizer returned no text");
296
- if (summary.length <= config.maxChars) {
297
- return {
298
- text: summary,
299
- summaryChars: summary.length,
300
- summaryModel: `${model.provider}/${model.id}`,
301
- };
302
- }
303
-
304
- const summaryFilePath = await writeSummaryFile(summary);
305
282
  return {
306
- text: `Summary exceeded ${config.maxChars} chars and was written to: ${summaryFilePath}`,
283
+ text: summary,
307
284
  summaryChars: summary.length,
308
- summaryFilePath,
309
285
  summaryModel: `${model.provider}/${model.id}`,
310
286
  };
311
287
  }
@@ -325,9 +301,6 @@ async function processToolResult(
325
301
  const loaded = loadDistillConfig();
326
302
  const config = loaded.config;
327
303
  const outputSummaryRender = { ...loaded.render };
328
- const maxReturnedChars = config?.maxOutputChars ?? 10_000;
329
- const finish = (candidate: ToolResult) =>
330
- limitReturnedToolResult(candidate, maxReturnedChars);
331
304
  if (loaded.warnings.length > 0) {
332
305
  console.warn(`[pi-distill] ${loaded.warnings.join(" | ")}`);
333
306
  }
@@ -354,12 +327,12 @@ async function processToolResult(
354
327
  : "Distill is disabled by configuration.",
355
328
  };
356
329
  const agentDiagnostic = buildAgentDiagnosticText(diagnostics);
357
- return finish({
330
+ return {
358
331
  ...attachDiagnostics(result, diagnostics),
359
332
  content: agentDiagnostic
360
333
  ? [...result.content, { type: "text", text: agentDiagnostic }]
361
334
  : result.content,
362
- });
335
+ };
363
336
  }
364
337
 
365
338
  let output: string;
@@ -369,7 +342,7 @@ async function processToolResult(
369
342
  console.warn(
370
343
  `[tool-output-summary] ${context.toolName} could not read the full output; returning the original result: ${error instanceof Error ? error.message : String(error)}`,
371
344
  );
372
- return finish(attachDiagnostics(result, {
345
+ return attachDiagnostics(result, {
373
346
  toolExecutionMs,
374
347
  outputSummaryPrompt: prompt || undefined,
375
348
  outputSummaryRender,
@@ -378,7 +351,7 @@ async function processToolResult(
378
351
  summaryTriggerMaxChars: null,
379
352
  summaryResultMaxChars: config.maxChars,
380
353
  missedCompressionRatio: config.missedCompressionRatio,
381
- }));
354
+ });
382
355
  }
383
356
 
384
357
  const decision = decideOutputSummary(prompt, output, config, result.isError === true);
@@ -404,7 +377,7 @@ async function processToolResult(
404
377
  ? [...result.content, { type: "text", text: agentDiagnostic }]
405
378
  : result.content,
406
379
  };
407
- return finish(candidate);
380
+ return candidate;
408
381
  }
409
382
 
410
383
  const summaryStartedAt = performance.now();
@@ -451,7 +424,7 @@ async function processToolResult(
451
424
  ...(agentDiagnostic ? [{ type: "text", text: agentDiagnostic }] : []),
452
425
  ],
453
426
  };
454
- return finish(candidate);
427
+ return candidate;
455
428
  }
456
429
  const compressionDiagnostics = getCompressionDiagnostics(
457
430
  decision.intent,
@@ -465,7 +438,7 @@ async function processToolResult(
465
438
  };
466
439
  const agentDiagnostic = buildAgentDiagnosticText(diagnostics);
467
440
 
468
- return finish({
441
+ return {
469
442
  // 输出处理参数只影响结果上下文,不改变原工具的业务执行。
470
443
  // 异常诊断额外作为文本传给 Agent;普通成功总结不增加噪音。
471
444
  content: [
@@ -486,10 +459,9 @@ async function processToolResult(
486
459
  missedCompressionRatio: config.missedCompressionRatio,
487
460
  summaryModel: summarized.summaryModel,
488
461
  summaryText: summarized.text,
489
- summaryFilePath: summarized.summaryFilePath,
490
462
  ...diagnostics,
491
463
  },
492
- });
464
+ };
493
465
  } catch (error) {
494
466
  const summaryDurationMs = Math.round(performance.now() - summaryStartedAt);
495
467
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -520,7 +492,7 @@ async function processToolResult(
520
492
  ? [...result.content, { type: "text", text: agentDiagnostic }]
521
493
  : result.content,
522
494
  };
523
- return finish(candidate);
495
+ return candidate;
524
496
  } finally {
525
497
  clearTimeout(timeout);
526
498
  context.signal?.removeEventListener("abort", abortFromParent);
@@ -575,7 +547,7 @@ function toToolResultEventResult(result: ToolResult): ToolResultEventPatch {
575
547
  };
576
548
  }
577
549
 
578
- type DistillUiConfig = Required<Pick<DistillConfigFile, "enabled" | "model" | "minChars" | "maxChars" | "maxOutputChars" | "timeoutSeconds" | "missedCompressionRatio" | "summarizeErrors">> & {
550
+ type DistillUiConfig = Required<Pick<DistillConfigFile, "enabled" | "model" | "minChars" | "maxChars" | "timeoutSeconds" | "missedCompressionRatio" | "summarizeErrors">> & {
579
551
  render: DistillRenderConfig;
580
552
  };
581
553
 
@@ -589,7 +561,6 @@ function getDistillUiConfig(): DistillUiConfig {
589
561
  : "",
590
562
  minChars: config?.minChars ?? 200,
591
563
  maxChars: config?.maxChars ?? 100_000,
592
- maxOutputChars: config?.maxOutputChars ?? 10_000,
593
564
  timeoutSeconds: config?.timeoutSeconds ?? 10,
594
565
  missedCompressionRatio: config?.missedCompressionRatio ?? 10,
595
566
  summarizeErrors: config?.summarizeErrors ?? true,
@@ -654,7 +625,6 @@ async function runDistillConfigUi(ctx: ExtensionCommandContext, configPath: stri
654
625
  i18n.t("model", { value: config.model || i18n.t("currentModel") }),
655
626
  i18n.t("minOutput", { value: config.minChars }),
656
627
  i18n.t("summaryLimit", { value: config.maxChars }),
657
- i18n.t("finalLimit", { value: config.maxOutputChars }),
658
628
  i18n.t("timeout", { value: config.timeoutSeconds }),
659
629
  i18n.t("threshold", { value: config.missedCompressionRatio }),
660
630
  i18n.t("summarizeErrors", { value: config.summarizeErrors ? i18n.t("on") : i18n.t("off") }),
@@ -687,33 +657,27 @@ async function runDistillConfigUi(ctx: ExtensionCommandContext, configPath: stri
687
657
  await saveDistillConfigFile(ctx, config, configPath);
688
658
  }
689
659
  } else if (choice === choices[4]) {
690
- const value = await editDistillNumber(ctx, i18n.t("finalLimitTitle"), config.maxOutputChars);
691
- if (value !== undefined) {
692
- config.maxOutputChars = value;
693
- await saveDistillConfigFile(ctx, config, configPath);
694
- }
695
- } else if (choice === choices[5]) {
696
660
  const value = await editDistillNumber(ctx, i18n.t("timeoutTitle"), config.timeoutSeconds);
697
661
  if (value !== undefined) {
698
662
  config.timeoutSeconds = value;
699
663
  await saveDistillConfigFile(ctx, config, configPath);
700
664
  }
701
- } else if (choice === choices[6]) {
665
+ } else if (choice === choices[5]) {
702
666
  const value = await editDistillNumber(ctx, i18n.t("thresholdTitle"), config.missedCompressionRatio);
703
667
  if (value !== undefined) {
704
668
  config.missedCompressionRatio = value;
705
669
  await saveDistillConfigFile(ctx, config, configPath);
706
670
  }
707
- } else if (choice === choices[7]) {
671
+ } else if (choice === choices[6]) {
708
672
  config.summarizeErrors = !config.summarizeErrors;
709
673
  await saveDistillConfigFile(ctx, config, configPath);
710
- } else if (choice === choices[8]) {
674
+ } else if (choice === choices[7]) {
711
675
  config.render.enabled = !config.render.enabled;
712
676
  await saveDistillConfigFile(ctx, config, configPath);
713
- } else if (choice === choices[9]) {
677
+ } else if (choice === choices[8]) {
714
678
  config.render.showPrompt = !config.render.showPrompt;
715
679
  await saveDistillConfigFile(ctx, config, configPath);
716
- } else if (choice === choices[10]) {
680
+ } else if (choice === choices[9]) {
717
681
  config.render.showResult = !config.render.showResult;
718
682
  await saveDistillConfigFile(ctx, config, configPath);
719
683
  }
@@ -1,7 +1,3 @@
1
- import { mkdir, writeFile } from "node:fs/promises";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
-
5
1
  export type OutputLimitToolResult = {
6
2
  content: Array<{ type?: string; text?: string }>;
7
3
  details?: {
@@ -19,52 +15,3 @@ export function getTextContent(result: OutputLimitToolResult): string {
19
15
  export function hasNonTextContent(result: OutputLimitToolResult): boolean {
20
16
  return result.content.some((content) => content.type !== "text" || typeof content.text !== "string");
21
17
  }
22
-
23
- async function writeSummaryFile(summary: string): Promise<string> {
24
- const directory = join(tmpdir(), "pi-distill");
25
- await mkdir(directory, { recursive: true });
26
- const filePath = join(
27
- directory,
28
- `summary-${Date.now()}-${Math.random().toString(16).slice(2)}.txt`,
29
- );
30
- await writeFile(filePath, summary, "utf8");
31
- return filePath;
32
- }
33
-
34
- export async function limitReturnedToolResult(
35
- result: OutputLimitToolResult,
36
- maxChars: number,
37
- ): Promise<OutputLimitToolResult> {
38
- if (hasNonTextContent(result)) return result;
39
-
40
- const text = getTextContent(result);
41
- if (text.length <= maxChars) return result;
42
-
43
- try {
44
- const filePath = await writeSummaryFile(text);
45
- const pointer = `Output exceeded ${maxChars} chars and was written to: ${filePath}`;
46
- return {
47
- ...result,
48
- content: [{ type: "text", text: pointer.slice(0, maxChars) }],
49
- details: {
50
- ...(result.details ?? {}),
51
- fullOutputPath: filePath,
52
- outputTruncated: true,
53
- outputLimitChars: maxChars,
54
- },
55
- };
56
- } catch (error) {
57
- const message = error instanceof Error ? error.message : String(error);
58
- console.warn(`[pi-distill] Failed to write oversized output to a temp file; returning a truncated result: ${message}`);
59
- return {
60
- ...result,
61
- content: [{ type: "text", text: text.slice(0, maxChars) }],
62
- details: {
63
- ...(result.details ?? {}),
64
- outputTruncated: true,
65
- outputLimitChars: maxChars,
66
- outputFileError: message,
67
- },
68
- };
69
- }
70
- }