@bunny-agent/runner-cli 0.9.53 → 0.9.56

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/bundle.mjs +100 -7
  2. package/package.json +4 -4
package/dist/bundle.mjs CHANGED
@@ -2483,6 +2483,92 @@ function isRateLimitError(err) {
2483
2483
  const msg = err.message;
2484
2484
  return msg.includes("429") || msg.includes("rate") || msg.includes("quota") || msg.includes("limit");
2485
2485
  }
2486
+ var RETRYABLE_NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
2487
+ "EAI_AGAIN",
2488
+ "ECONNREFUSED",
2489
+ "ECONNRESET",
2490
+ "EHOSTUNREACH",
2491
+ "ENETUNREACH",
2492
+ "ENOTFOUND",
2493
+ "ETIMEDOUT",
2494
+ "UND_ERR_BODY_TIMEOUT",
2495
+ "UND_ERR_CONNECT_TIMEOUT",
2496
+ "UND_ERR_HEADERS_TIMEOUT",
2497
+ "UND_ERR_SOCKET"
2498
+ ]);
2499
+ function hasRetryableNetworkCode(error, seen = /* @__PURE__ */ new Set()) {
2500
+ if (error === null || typeof error !== "object" || seen.has(error))
2501
+ return false;
2502
+ seen.add(error);
2503
+ const code = getErrorField(error, "code");
2504
+ if (code && RETRYABLE_NETWORK_ERROR_CODES.has(code))
2505
+ return true;
2506
+ const nestedErrors = [];
2507
+ if ("cause" in error)
2508
+ nestedErrors.push(error.cause);
2509
+ if ("errors" in error && Array.isArray(error.errors)) {
2510
+ nestedErrors.push(...error.errors);
2511
+ }
2512
+ return nestedErrors.some((nested) => hasRetryableNetworkCode(nested, seen));
2513
+ }
2514
+ function isRetryableNetworkError(err) {
2515
+ if (hasRetryableNetworkCode(err))
2516
+ return true;
2517
+ return err instanceof TypeError && err.message === "fetch failed";
2518
+ }
2519
+ function getFallbackReason(err) {
2520
+ if (isRateLimitError(err))
2521
+ return "rate limit";
2522
+ if (isRetryableNetworkError(err))
2523
+ return "network error";
2524
+ return null;
2525
+ }
2526
+ function getErrorField(error, key) {
2527
+ if (!(key in error))
2528
+ return void 0;
2529
+ const value = error[key];
2530
+ if (typeof value === "string" || typeof value === "number") {
2531
+ return String(value);
2532
+ }
2533
+ return void 0;
2534
+ }
2535
+ function formatErrorCause(cause) {
2536
+ if (cause === null || cause === void 0)
2537
+ return "unknown";
2538
+ if (typeof cause !== "object")
2539
+ return String(cause);
2540
+ const details = [
2541
+ ["code", getErrorField(cause, "code")],
2542
+ [
2543
+ "message",
2544
+ cause instanceof Error ? cause.message : getErrorField(cause, "message")
2545
+ ],
2546
+ ["errno", getErrorField(cause, "errno")],
2547
+ ["syscall", getErrorField(cause, "syscall")],
2548
+ ["hostname", getErrorField(cause, "hostname")],
2549
+ ["address", getErrorField(cause, "address")],
2550
+ ["port", getErrorField(cause, "port")]
2551
+ ].filter((entry) => Boolean(entry[1])).map(([key, value]) => `${key}=${value}`);
2552
+ const nestedErrors = "errors" in cause && Array.isArray(cause.errors) ? cause.errors : [];
2553
+ if (nestedErrors.length > 0) {
2554
+ const nested = nestedErrors.slice(0, 3).map(formatErrorCause).join("; ");
2555
+ details.push(`errors=[${nested}]`);
2556
+ }
2557
+ return details.length > 0 ? details.join(", ") : String(cause);
2558
+ }
2559
+ function formatWebToolError(error) {
2560
+ if (!(error instanceof Error))
2561
+ return String(error);
2562
+ const cause = "cause" in error ? error.cause : void 0;
2563
+ return cause === void 0 ? error.message : `${error.name}: ${error.message} (cause: ${formatErrorCause(cause)})`;
2564
+ }
2565
+ function getSafeTarget(url) {
2566
+ try {
2567
+ return new URL(url).origin;
2568
+ } catch {
2569
+ return "invalid-url";
2570
+ }
2571
+ }
2486
2572
  var BROWSER_UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
2487
2573
  function stripNullBytes(s) {
2488
2574
  return s.replace(/\0/g, "");
@@ -2513,7 +2599,8 @@ async function fetchPageContent(url, externalSignal) {
2513
2599
 
2514
2600
  [Truncated]` : text;
2515
2601
  } catch (e) {
2516
- const msg = e instanceof Error ? e.message : String(e);
2602
+ const msg = formatWebToolError(e);
2603
+ console.error(`[bunny-agent:pi] web_fetch failed target=${getSafeTarget(url)}: ${msg}`);
2517
2604
  return `(Error fetching ${url}: ${msg})`;
2518
2605
  } finally {
2519
2606
  clearTimeout(timeout);
@@ -2600,7 +2687,9 @@ function buildWebSearchTool(env) {
2600
2687
  const freshness = p.freshness;
2601
2688
  const shouldFetchContent = p.fetch_content ?? false;
2602
2689
  let lastError;
2603
- for (const { provider, apiKey } of providers) {
2690
+ let lastProviderLabel = "unknown provider";
2691
+ for (const [providerIndex, { provider, apiKey }] of providers.entries()) {
2692
+ lastProviderLabel = provider.label;
2604
2693
  try {
2605
2694
  const { results } = await provider.search({
2606
2695
  apiKey,
@@ -2638,19 +2727,23 @@ function buildWebSearchTool(env) {
2638
2727
  };
2639
2728
  } catch (e) {
2640
2729
  lastError = e;
2641
- if (isRateLimitError(e) && providers.length > 1) {
2642
- console.error(`[bunny-agent:pi] ${provider.label} rate-limited, trying next provider...`);
2730
+ const diagnostic = formatWebToolError(e);
2731
+ console.error(`[bunny-agent:pi] ${provider.label} web_search failed: ${diagnostic}`);
2732
+ const fallbackReason = getFallbackReason(e);
2733
+ const nextProvider = providers[providerIndex + 1];
2734
+ if (fallbackReason && nextProvider) {
2735
+ console.error(`[bunny-agent:pi] ${provider.label} ${fallbackReason}, trying ${nextProvider.provider.label}...`);
2643
2736
  continue;
2644
2737
  }
2645
2738
  break;
2646
2739
  }
2647
2740
  }
2648
- const msg = lastError instanceof Error ? lastError.message : String(lastError);
2741
+ const msg = formatWebToolError(lastError);
2649
2742
  return {
2650
2743
  content: [
2651
2744
  {
2652
2745
  type: "text",
2653
- text: `Web search error: ${msg}`
2746
+ text: `Web search error (${lastProviderLabel}): ${msg}`
2654
2747
  }
2655
2748
  ],
2656
2749
  details: void 0
@@ -2680,7 +2773,7 @@ function buildWebFetchTool() {
2680
2773
  details: void 0
2681
2774
  };
2682
2775
  } catch (e) {
2683
- const msg = e instanceof Error ? e.message : String(e);
2776
+ const msg = formatWebToolError(e);
2684
2777
  return {
2685
2778
  content: [
2686
2779
  { type: "text", text: `Error fetching URL: ${msg}` }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bunny-agent/runner-cli",
3
- "version": "0.9.53",
3
+ "version": "0.9.56",
4
4
  "description": "BunnyAgent Runner CLI - Like gemini-cli or claude-code, runs in your local terminal with AI SDK UI streaming",
5
5
  "type": "module",
6
6
  "bin": {
@@ -55,10 +55,10 @@
55
55
  "typescript": "^5.3.0",
56
56
  "vitest": "^1.6.1",
57
57
  "@bunny-agent/runner-claude": "0.6.2",
58
- "@bunny-agent/runner-harness": "0.1.1-beta.0",
59
- "@bunny-agent/runner-pi": "0.6.4-beta.0",
60
- "@bunny-agent/runner-opencode": "0.6.2",
61
58
  "@bunny-agent/runner-codex": "0.6.2",
59
+ "@bunny-agent/runner-opencode": "0.6.2",
60
+ "@bunny-agent/runner-pi": "0.6.4-beta.0",
61
+ "@bunny-agent/runner-harness": "0.1.1-beta.0",
62
62
  "@bunny-agent/runner-gemini": "0.6.2"
63
63
  },
64
64
  "scripts": {