@code-yeongyu/senpi-agent-core 2026.10.16-4 → 2026.10.18

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.
Files changed (2) hide show
  1. package/dist/agent-loop.js +24 -2
  2. package/package.json +3 -3
@@ -609,7 +609,13 @@ async function streamAssistantResponse(context, config, signal, emit, streamFunc
609
609
  await emit({ type: "message_end", message: finalMessage });
610
610
  return { message: finalMessage, providerToolResults };
611
611
  }
612
- const finalMessage = createTerminalFailureAssistantMessage(config.model, signal?.aborted ? "aborted" : "error", error, partialMessage);
612
+ // A caller abort is the reason a turn ended even when the bound fired first on a step that never finished:
613
+ // the user gets the abort's own message, not a timeout and advice to raise it (#3481).
614
+ // A step that rethrows the caller's own reason (`throwIfAborted()`, a fetch rejected with it) shows that reason
615
+ // through the same shaping and cap (#3510).
616
+ const callerAbortedPastBound = signal?.aborted === true &&
617
+ (error instanceof StreamStartTimeoutError || isStreamIdleTimeoutError(error) || error === signal.reason);
618
+ const finalMessage = createTerminalFailureAssistantMessage(config.model, signal?.aborted ? "aborted" : "error", callerAbortedPastBound ? abortError(signal.reason) : error, partialMessage);
613
619
  propagateThinkingTiming(finalMessage);
614
620
  if (addedPartial) {
615
621
  context.messages[context.messages.length - 1] = finalMessage;
@@ -627,8 +633,24 @@ async function streamAssistantResponse(context, config, signal, emit, streamFunc
627
633
  }
628
634
  }
629
635
  const ABORTED = Symbol("aborted");
636
+ const MAX_ABORT_REASON_CHARS = 500;
630
637
  function abortError(reason) {
631
- return reason instanceof Error ? reason : new Error("Request was aborted");
638
+ if (reason instanceof Error)
639
+ return reason;
640
+ // A caller's own words are its abort reason: a plain string, or an object carrying a `message` (#3510).
641
+ const text = abortReasonText(reason);
642
+ if (text === undefined)
643
+ return new Error("Request was aborted");
644
+ const characters = Array.from(text);
645
+ return new Error(characters.length > MAX_ABORT_REASON_CHARS ? `${characters.slice(0, MAX_ABORT_REASON_CHARS).join("")}…` : text);
646
+ }
647
+ function abortReasonText(reason) {
648
+ const text = typeof reason === "string"
649
+ ? reason
650
+ : typeof reason === "object" && reason !== null && "message" in reason && typeof reason.message === "string"
651
+ ? reason.message
652
+ : undefined;
653
+ return text !== undefined && text.trim() !== "" ? text : undefined;
632
654
  }
633
655
  function closeAssistantIterator(iterator) {
634
656
  void Promise.resolve(iterator.return?.()).catch(() => undefined);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/senpi-agent-core",
3
- "version": "2026.10.16-4",
3
+ "version": "2026.10.18",
4
4
  "description": "General-purpose agent with transport abstraction, state management, and attachment support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -62,8 +62,8 @@
62
62
  },
63
63
  "dependencies": {
64
64
  "@earendil-works/chord": "0.99.1",
65
- "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.10.16-4",
66
- "@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.10.16-4",
65
+ "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.10.18",
66
+ "@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.10.18",
67
67
  "diff": "9.0.0",
68
68
  "ignore": "7.0.9",
69
69
  "typebox": "1.3.34",