'use strict';

// src/types/errors.ts
var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
  ErrorCode2["AUTH_EXPIRED"] = "AUTH_EXPIRED";
  ErrorCode2["AUTH_INVALID"] = "AUTH_INVALID";
  ErrorCode2["RATE_LIMIT"] = "RATE_LIMIT";
  ErrorCode2["NETWORK"] = "NETWORK";
  ErrorCode2["TIMEOUT"] = "TIMEOUT";
  ErrorCode2["PROVIDER_ERROR"] = "PROVIDER_ERROR";
  ErrorCode2["MODEL_NOT_FOUND"] = "MODEL_NOT_FOUND";
  ErrorCode2["MODEL_OVERLOADED"] = "MODEL_OVERLOADED";
  ErrorCode2["CONTEXT_OVERFLOW"] = "CONTEXT_OVERFLOW";
  ErrorCode2["INVALID_INPUT"] = "INVALID_INPUT";
  ErrorCode2["INVALID_RESPONSE"] = "INVALID_RESPONSE";
  ErrorCode2["REENTRANCY"] = "REENTRANCY";
  ErrorCode2["DISPOSED"] = "DISPOSED";
  ErrorCode2["ABORTED"] = "ABORTED";
  ErrorCode2["INVALID_TRANSITION"] = "INVALID_TRANSITION";
  ErrorCode2["DEPENDENCY_MISSING"] = "DEPENDENCY_MISSING";
  ErrorCode2["BACKEND_NOT_INSTALLED"] = "BACKEND_NOT_INSTALLED";
  ErrorCode2["TOOL_EXECUTION"] = "TOOL_EXECUTION";
  ErrorCode2["PERMISSION_DENIED"] = "PERMISSION_DENIED";
  ErrorCode2["SESSION_NOT_FOUND"] = "SESSION_NOT_FOUND";
  ErrorCode2["SESSION_EXPIRED"] = "SESSION_EXPIRED";
  ErrorCode2["PROVIDER_NOT_FOUND"] = "PROVIDER_NOT_FOUND";
  ErrorCode2["AUTH_REQUIRED"] = "AUTH_REQUIRED";
  ErrorCode2["STORAGE_ERROR"] = "STORAGE_ERROR";
  ErrorCode2["STORAGE_NOT_FOUND"] = "STORAGE_NOT_FOUND";
  ErrorCode2["STORAGE_DUPLICATE_KEY"] = "STORAGE_DUPLICATE_KEY";
  ErrorCode2["STORAGE_IO_ERROR"] = "STORAGE_IO_ERROR";
  ErrorCode2["STORAGE_SERIALIZATION_ERROR"] = "STORAGE_SERIALIZATION_ERROR";
  return ErrorCode2;
})(ErrorCode || {});

// src/errors.ts
var AgentSDKError = class extends Error {
  /** @internal Marker for cross-bundle identity checks */
  _agentSDKError = true;
  /** Machine-readable error code. Prefer values from the ErrorCode enum. */
  code;
  /** Whether this error is safe to retry */
  retryable;
  /** HTTP status code hint for error classification */
  httpStatus;
  constructor(message, options) {
    super(message, options);
    this.name = "AgentSDKError";
    this.code = options?.code;
    this.retryable = options?.retryable ?? false;
    this.httpStatus = options?.httpStatus;
  }
  /** Check if an error is an AgentSDKError (works across bundled copies) */
  static is(error) {
    return error instanceof Error && "_agentSDKError" in error && error._agentSDKError === true;
  }
};

// src/chat/errors.ts
var ChatError = class extends AgentSDKError {
  code;
  retryable;
  retryAfter;
  timestamp;
  constructor(message, options) {
    super(message, {
      cause: options.cause,
      code: options.code,
      retryable: options.retryable
    });
    this.name = "ChatError";
    this.code = options.code;
    this.retryable = options.retryable ?? false;
    this.retryAfter = options.retryAfter;
    this.timestamp = (/* @__PURE__ */ new Date()).toISOString();
  }
};
function classifyError(error) {
  if (error instanceof ChatError) {
    return error;
  }
  if (error instanceof Error) {
    const msg = error.message.toLowerCase();
    if (isNetworkError(msg)) {
      return new ChatError(error.message, {
        code: "NETWORK" /* NETWORK */,
        retryable: true,
        cause: error
      });
    }
    if (isTimeoutPattern(msg)) {
      return new ChatError(error.message, {
        code: "TIMEOUT" /* TIMEOUT */,
        retryable: true,
        cause: error
      });
    }
    if (isZodError(error)) {
      return new ChatError(error.message, {
        code: "INVALID_INPUT" /* INVALID_INPUT */,
        retryable: false,
        cause: error
      });
    }
    const statusCode = extractStatusCode(error);
    if (statusCode !== null) {
      return classifyByStatusCode(statusCode, error);
    }
    if (isContextOverflow(msg)) {
      return new ChatError(error.message, {
        code: "CONTEXT_OVERFLOW" /* CONTEXT_OVERFLOW */,
        retryable: false,
        cause: error
      });
    }
  }
  const message = error instanceof Error ? error.message : String(error);
  return new ChatError(message, {
    code: "PROVIDER_ERROR" /* PROVIDER_ERROR */,
    retryable: false,
    cause: error
  });
}
var NETWORK_PATTERNS = [
  "econnrefused",
  "econnreset",
  "enotfound",
  "etimedout",
  "enetunreach",
  "epipe",
  "fetch failed",
  "network error",
  "network request failed",
  "failed to fetch",
  "dns lookup failed"
];
function isNetworkError(msg) {
  return NETWORK_PATTERNS.some((p) => msg.includes(p));
}
function isTimeoutPattern(msg) {
  return msg.includes("timeout") || msg.includes("timed out") || msg.includes("deadline exceeded") || msg.includes("aborted due to timeout");
}
function isZodError(error) {
  return error.name === "ZodError" || "issues" in error && Array.isArray(error.issues);
}
function extractStatusCode(error) {
  const errRecord = error;
  if (typeof errRecord.status === "number") return errRecord.status;
  if (typeof errRecord.statusCode === "number") return errRecord.statusCode;
  const match = error.message.match(/\b(4\d{2}|5\d{2})\b/);
  return match ? parseInt(match[1], 10) : null;
}
function classifyByStatusCode(status, error) {
  if (status === 401 || status === 403) {
    return new ChatError(error.message, {
      code: "AUTH_INVALID" /* AUTH_INVALID */,
      retryable: false,
      cause: error
    });
  }
  if (status === 429) {
    const retryAfterSeconds = extractRetryAfter(error);
    return new ChatError(error.message, {
      code: "RATE_LIMIT" /* RATE_LIMIT */,
      retryable: true,
      retryAfter: retryAfterSeconds != null ? retryAfterSeconds * 1e3 : void 0,
      cause: error
    });
  }
  if (status >= 500) {
    return new ChatError(error.message, {
      code: "PROVIDER_ERROR" /* PROVIDER_ERROR */,
      retryable: true,
      cause: error
    });
  }
  if (status >= 400 && status < 500) {
    return new ChatError(error.message, {
      code: "INVALID_INPUT" /* INVALID_INPUT */,
      retryable: false,
      cause: error
    });
  }
  return new ChatError(error.message, {
    code: "NETWORK" /* NETWORK */,
    retryable: true,
    cause: error
  });
}
function extractRetryAfter(error) {
  const errRecord = error;
  if (typeof errRecord.retryAfter === "number") return errRecord.retryAfter;
  const match = error.message.match(/retry.after[:\s]*(\d+)/i);
  return match ? parseInt(match[1], 10) : void 0;
}
function isContextOverflow(msg) {
  return msg.includes("context length exceeded") || msg.includes("maximum context length") || msg.includes("context window") || msg.includes("token limit") || msg.includes("too many tokens");
}
var ExponentialBackoffStrategy = class {
  baseMs;
  maxMs;
  maxAttempts;
  jitter;
  constructor(options) {
    this.baseMs = options?.baseMs ?? 1e3;
    this.maxMs = options?.maxMs ?? 3e4;
    this.maxAttempts = options?.maxAttempts ?? 3;
    this.jitter = Math.max(0, Math.min(1, options?.jitter ?? 0.1));
  }
  nextDelay(attempt, error) {
    if (attempt >= this.maxAttempts) return null;
    if (!error.retryable) return null;
    if (error.code === "RATE_LIMIT" /* RATE_LIMIT */ && error.retryAfter) {
      return error.retryAfter;
    }
    const delay = Math.min(this.baseMs * Math.pow(2, attempt), this.maxMs);
    const jitterAmount = delay * this.jitter * (Math.random() * 2 - 1);
    return Math.max(0, Math.round(delay + jitterAmount));
  }
};
async function withRetry(fn, strategy, options) {
  let attempt = 0;
  for (; ; ) {
    try {
      return await fn();
    } catch (raw) {
      const error = classifyError(raw);
      const delay = strategy.nextDelay(attempt, error);
      if (delay === null) {
        throw error;
      }
      if (options?.signal?.aborted) {
        throw error;
      }
      options?.onRetry?.(error, attempt, delay);
      await sleep(delay, options?.signal);
      attempt++;
    }
  }
}
function isRetryable(error) {
  if (error instanceof ChatError) {
    return error.retryable;
  }
  const classified = classifyError(error);
  return classified.retryable;
}
function sleep(ms, signal) {
  return new Promise((resolve, reject) => {
    if (signal?.aborted) {
      reject(new ChatError("Retry aborted", { code: "ABORTED" /* ABORTED */ }));
      return;
    }
    const timer = setTimeout(resolve, ms);
    signal?.addEventListener(
      "abort",
      () => {
        clearTimeout(timer);
        reject(new ChatError("Retry aborted", { code: "ABORTED" /* ABORTED */ }));
      },
      { once: true }
    );
  });
}

exports.ChatError = ChatError;
exports.ErrorCode = ErrorCode;
exports.ExponentialBackoffStrategy = ExponentialBackoffStrategy;
exports.classifyError = classifyError;
exports.isRetryable = isRetryable;
exports.withRetry = withRetry;
//# sourceMappingURL=errors.cjs.map
//# sourceMappingURL=errors.cjs.map