@prestyj/agent 5.9.0 → 5.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/dist/index.cjs CHANGED
@@ -26,6 +26,7 @@ __export(index_exports, {
26
26
  isAbortError: () => isAbortError,
27
27
  isBillingError: () => isBillingError,
28
28
  isContextOverflow: () => isContextOverflow,
29
+ isLocalBackendUrl: () => isLocalBackendUrl,
29
30
  isUsageLimitError: () => isUsageLimitError,
30
31
  setStreamDiagnostic: () => setStreamDiagnostic
31
32
  });
@@ -37,6 +38,30 @@ var import_ai2 = require("@prestyj/ai");
37
38
  // src/agent-loop.ts
38
39
  var import_zod = require("zod");
39
40
  var import_ai = require("@prestyj/ai");
41
+
42
+ // src/local-backend.ts
43
+ function isLocalBackendUrl(baseUrl) {
44
+ if (!baseUrl) return false;
45
+ let host;
46
+ try {
47
+ host = new URL(baseUrl).hostname.toLowerCase();
48
+ } catch {
49
+ return false;
50
+ }
51
+ if (host === "[::1]" || host === "::1") return true;
52
+ if (host === "localhost" || host.endsWith(".localhost")) return true;
53
+ if (host === "0.0.0.0") return true;
54
+ if (host.endsWith(".local")) return true;
55
+ const ipv4 = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
56
+ if (ipv4) {
57
+ const octets = ipv4.slice(1).map(Number);
58
+ if (octets.some((n) => n > 255)) return false;
59
+ return octets[0] === 127;
60
+ }
61
+ return false;
62
+ }
63
+
64
+ // src/agent-loop.ts
40
65
  var DEFAULT_MAX_TURNS = 300;
41
66
  var _diagFn = null;
42
67
  function setStreamDiagnostic(fn) {
@@ -303,9 +328,10 @@ async function* agentLoop(messages, options) {
303
328
  const STREAM_THINKING_IDLE_TIMEOUT_MS = 3e5;
304
329
  const STREAM_THINKING_HARD_TIMEOUT_MS = 6e5;
305
330
  const NON_STREAMING_HARD_TIMEOUT_MS = 3e5;
306
- const isSakana = options.provider === "sakana";
307
- const firstEventTimeoutMs = isSakana ? STREAM_THINKING_IDLE_TIMEOUT_MS : STREAM_FIRST_EVENT_TIMEOUT_MS;
308
- const initialHardTimeoutMs = isSakana ? STREAM_THINKING_HARD_TIMEOUT_MS : STREAM_HARD_TIMEOUT_MS;
331
+ const usesSilentReasoningBudget = options.provider === "sakana" || options.provider === "openai" && options.thinking != null;
332
+ const localBackend = isLocalBackendUrl(options.baseUrl);
333
+ const firstEventTimeoutMs = localBackend ? Number.POSITIVE_INFINITY : usesSilentReasoningBudget ? STREAM_THINKING_IDLE_TIMEOUT_MS : STREAM_FIRST_EVENT_TIMEOUT_MS;
334
+ const initialHardTimeoutMs = localBackend || usesSilentReasoningBudget ? STREAM_THINKING_HARD_TIMEOUT_MS : STREAM_HARD_TIMEOUT_MS;
309
335
  const MAX_TOOLCALL_DELTA_CHARS = 1e6;
310
336
  const MAX_TOOLCALL_DELTA_EVENTS = 2e4;
311
337
  let logicalTurnStartedAt = 0;
@@ -333,7 +359,11 @@ async function* agentLoop(messages, options) {
333
359
  messages: messages.length,
334
360
  chars: msgChars,
335
361
  provider: options.provider,
336
- model: options.model
362
+ model: options.model,
363
+ thinking: options.thinking ?? "off",
364
+ firstEventTimeoutMs,
365
+ initialHardTimeoutMs,
366
+ localBackend
337
367
  });
338
368
  }
339
369
  if (firstTurn && options.getSteeringMessages) {
@@ -391,6 +421,7 @@ async function* agentLoop(messages, options) {
391
421
  if (useNonStreamingFallback) return;
392
422
  if (idleTimer) clearTimeout(idleTimer);
393
423
  const timeoutMs = hasReceivedEvent ? STREAM_IDLE_TIMEOUT_MS : hasReceivedThinking ? STREAM_THINKING_IDLE_TIMEOUT_MS : firstEventTimeoutMs;
424
+ if (!Number.isFinite(timeoutMs)) return;
394
425
  idleTimer = setTimeout(() => {
395
426
  diag("idle_timeout_fired", {
396
427
  events: streamEventCount,
@@ -775,15 +806,29 @@ async function* agentLoop(messages, options) {
775
806
  continue;
776
807
  }
777
808
  if (transportFailure) {
809
+ const cause = malformed ? "malformed_stream" : socketDrop ? "socket_drop" : "stream_stall";
778
810
  diag("stall_exhausted", {
779
811
  stallRetries: MAX_STALL_RETRIES,
780
812
  provider: options.provider,
781
- model: options.model
813
+ model: options.model,
814
+ cause,
815
+ nonStreaming: useNonStreamingFallback,
816
+ events: streamEventCount,
817
+ eventTypes: eventTypeCounts,
818
+ lastEventType,
819
+ sinceLastEventMs: Date.now() - lastEventTime,
820
+ attemptDurationMs: Date.now() - streamCallStart,
821
+ maxConsumerLagMs
782
822
  });
783
823
  yield {
784
824
  type: "error",
785
- error: new Error(
786
- `The API provider's stream stalled ${MAX_STALL_RETRIES} times \u2014 the provider may be experiencing capacity issues. Your conversation is preserved. Send another message to retry.`
825
+ error: new import_ai.EZCoderAIError(
826
+ `The connection to the API provider stopped responding after ${MAX_STALL_RETRIES} automatic retries. Your conversation is preserved.`,
827
+ {
828
+ source: "network",
829
+ hint: "Retry once. If it keeps happening on this device, disable any VPN or proxy and allow EZ Coder through firewall or antivirus web protection.",
830
+ cause: err
831
+ }
787
832
  )
788
833
  };
789
834
  break;
@@ -1603,6 +1648,7 @@ var Agent = class {
1603
1648
  isAbortError,
1604
1649
  isBillingError,
1605
1650
  isContextOverflow,
1651
+ isLocalBackendUrl,
1606
1652
  isUsageLimitError,
1607
1653
  setStreamDiagnostic
1608
1654
  });