@snack-kit/porygon 0.6.0 → 0.8.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/README.md CHANGED
@@ -630,6 +630,33 @@ npm run playground # 启动 Playground
630
630
 
631
631
  ## Changelog
632
632
 
633
+ ### v0.8.0
634
+
635
+ #### 改进
636
+
637
+ - **`timeoutMs` 语义变更为空闲超时** — `timeoutMs` 不再表示进程的绝对超时时间,而是"空闲超时":进程无任何输出(stdout/stderr)超过此时间才触发终止。每次收到输出会重置计时器,更适合 LLM 调用耗时不可预测的场景
638
+ - **默认空闲超时调整** — 默认值从 `300_000`(5 分钟)调整为 `120_000`(2 分钟)
639
+
640
+ #### 破坏性变更
641
+
642
+ - **`timeoutMs` 语义变更** — 从绝对超时改为空闲超时(idle timeout)。如果依赖旧的绝对超时行为,需要调整使用方式。对于模型思考时间可能较长的场景,建议适当调大此值
643
+ - **默认超时时间缩短** — 从 5 分钟缩短至 2 分钟。如需更长超时,请在 `defaults.timeoutMs` 或请求参数中显式设置
644
+
645
+ ---
646
+
647
+ ### v0.7.0
648
+
649
+ #### 新特性
650
+
651
+ - **`InteractiveSession` 多轮对话封装** — 新增 `InteractiveSession` 类,封装 per-turn spawn + `--resume` 模式,提供透明的多轮对话体验。通过 `porygon.session()` 创建,调用 `session.send(prompt)` 自动管理 sessionId 续接
652
+ - **`EphemeralProcess` 超时错误明确化** — 进程超时终止后抛出明确的 `Process timed out after ${timeoutMs}ms` 错误,替代之前模糊的退出码错误信息
653
+
654
+ #### 改进
655
+
656
+ - `EphemeralProcess` 内部新增 `timedOut` 状态标记,区分正常退出与超时终止场景
657
+
658
+ ---
659
+
633
660
  ### v0.6.0
634
661
 
635
662
  #### 改进
package/dist/index.cjs CHANGED
@@ -58,8 +58,8 @@ var DEFAULT_CONFIG = {
58
58
  defaultBackend: "claude",
59
59
  backends: {},
60
60
  defaults: {
61
- timeoutMs: 3e5,
62
- // 5 minutes
61
+ timeoutMs: 12e4,
62
+ // 空闲超时:进程无任何输出超过此时间则终止
63
63
  maxTurns: 50
64
64
  },
65
65
  proxy: void 0
@@ -295,6 +295,7 @@ var GRACE_PERIOD_MS = 5e3;
295
295
  var EphemeralProcess = class {
296
296
  childProcess = null;
297
297
  aborted = false;
298
+ timedOut = false;
298
299
  /**
299
300
  * 执行命令并收集输出。支持 AbortController 进行取消操作。
300
301
  * @param options 进程启动选项
@@ -316,19 +317,25 @@ var EphemeralProcess = class {
316
317
  this.childProcess = child;
317
318
  const stdoutChunks = [];
318
319
  const stderrChunks = [];
320
+ let timeoutTimer;
321
+ const resetTimeout = () => {
322
+ if (options.timeoutMs !== void 0 && options.timeoutMs > 0) {
323
+ if (timeoutTimer) clearTimeout(timeoutTimer);
324
+ timeoutTimer = setTimeout(() => {
325
+ this.terminate();
326
+ reject(new Error(`Process idle timed out after ${options.timeoutMs}ms`));
327
+ }, options.timeoutMs);
328
+ }
329
+ };
330
+ resetTimeout();
319
331
  child.stdout?.on("data", (chunk) => {
320
332
  stdoutChunks.push(chunk);
333
+ resetTimeout();
321
334
  });
322
335
  child.stderr?.on("data", (chunk) => {
323
336
  stderrChunks.push(chunk);
337
+ resetTimeout();
324
338
  });
325
- let timeoutTimer;
326
- if (options.timeoutMs !== void 0 && options.timeoutMs > 0) {
327
- timeoutTimer = setTimeout(() => {
328
- this.terminate();
329
- reject(new Error(`Process timed out after ${options.timeoutMs}ms`));
330
- }, options.timeoutMs);
331
- }
332
339
  const onAbort = () => {
333
340
  this.terminate();
334
341
  reject(new Error("Process aborted"));
@@ -363,6 +370,7 @@ var EphemeralProcess = class {
363
370
  throw new Error("Process aborted before start");
364
371
  }
365
372
  this.aborted = false;
373
+ this.timedOut = false;
366
374
  const useStdin = options.stdinData !== void 0;
367
375
  const child = (0, import_cross_spawn.default)(options.command, options.args, {
368
376
  cwd: options.cwd,
@@ -376,11 +384,16 @@ var EphemeralProcess = class {
376
384
  });
377
385
  }
378
386
  let timeoutTimer;
379
- if (options.timeoutMs !== void 0 && options.timeoutMs > 0) {
380
- timeoutTimer = setTimeout(() => {
381
- this.terminate();
382
- }, options.timeoutMs);
383
- }
387
+ const resetTimeout = () => {
388
+ if (options.timeoutMs !== void 0 && options.timeoutMs > 0) {
389
+ if (timeoutTimer) clearTimeout(timeoutTimer);
390
+ timeoutTimer = setTimeout(() => {
391
+ this.timedOut = true;
392
+ this.terminate();
393
+ }, options.timeoutMs);
394
+ }
395
+ };
396
+ resetTimeout();
384
397
  const onAbort = () => {
385
398
  this.terminate();
386
399
  };
@@ -388,6 +401,7 @@ var EphemeralProcess = class {
388
401
  const stderrChunks = [];
389
402
  child.stderr?.on("data", (chunk) => {
390
403
  stderrChunks.push(chunk);
404
+ resetTimeout();
391
405
  });
392
406
  let exitCode = null;
393
407
  const exitPromise = new Promise((resolve) => {
@@ -396,6 +410,9 @@ var EphemeralProcess = class {
396
410
  resolve();
397
411
  });
398
412
  });
413
+ child.stdout?.on("data", () => {
414
+ resetTimeout();
415
+ });
399
416
  const rl = (0, import_node_readline.createInterface)({ input: child.stdout });
400
417
  let yieldedLines = 0;
401
418
  try {
@@ -410,6 +427,9 @@ var EphemeralProcess = class {
410
427
  stderr || `Process exited with code ${exitCode}`
411
428
  );
412
429
  }
430
+ if (this.timedOut) {
431
+ throw new Error(`Process idle timed out after ${options.timeoutMs}ms`);
432
+ }
413
433
  } finally {
414
434
  if (timeoutTimer) clearTimeout(timeoutTimer);
415
435
  abortSignal?.removeEventListener("abort", onAbort);