@nemesis-oss/ollama-sdk 1.15.0 → 1.16.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
@@ -393,6 +393,36 @@ var OllamaGenericClientError = class extends OllamaClientError {
393
393
  function isDomAbortError(error) {
394
394
  return typeof DOMException !== "undefined" && error instanceof DOMException && error.name === "AbortError";
395
395
  }
396
+ var NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
397
+ "ECONNRESET",
398
+ "ECONNREFUSED",
399
+ "EPIPE",
400
+ "ETIMEDOUT",
401
+ "ECONNABORTED",
402
+ "EHOSTUNREACH",
403
+ "ENETUNREACH",
404
+ "ENOTFOUND",
405
+ "EAI_AGAIN",
406
+ "UND_ERR_SOCKET",
407
+ "UND_ERR_CONNECT_TIMEOUT",
408
+ "UND_ERR_HEADERS_TIMEOUT",
409
+ "UND_ERR_BODY_TIMEOUT",
410
+ "UND_ERR_CLOSED"
411
+ ]);
412
+ var MAX_CAUSE_DEPTH = 4;
413
+ function isNetworkLevelError(error) {
414
+ let current = error;
415
+ for (let depth = 0; depth < MAX_CAUSE_DEPTH && current !== void 0 && current !== null; depth += 1) {
416
+ if (typeof current === "object" && "code" in current) {
417
+ const code = current.code;
418
+ if (typeof code === "string" && NETWORK_ERROR_CODES.has(code)) {
419
+ return true;
420
+ }
421
+ }
422
+ current = current.cause;
423
+ }
424
+ return false;
425
+ }
396
426
  function statusToError(status, message, options) {
397
427
  if (status === 401 || status === 403) {
398
428
  return new OllamaAuthError(message, { ...options, status });
@@ -424,6 +454,13 @@ function mapError(error, context = {}) {
424
454
  request: context.request
425
455
  });
426
456
  }
457
+ if (isNetworkLevelError(error)) {
458
+ const message2 = error instanceof Error && error.message ? error.message : "Network request failed";
459
+ return new OllamaNetworkError(message2, {
460
+ cause: error,
461
+ request: context.request
462
+ });
463
+ }
427
464
  if (error instanceof TypeError) {
428
465
  return new OllamaNetworkError(error.message || "Network request failed", {
429
466
  cause: error,
@@ -1649,6 +1686,13 @@ function estimateGenerateRequestTokens(req) {
1649
1686
  if (req.images !== void 0) total += req.images.length * IMAGE_TOKEN_ESTIMATE;
1650
1687
  return total;
1651
1688
  }
1689
+ function recommendContextWindow(estimatedTokens) {
1690
+ if (!Number.isFinite(estimatedTokens) || estimatedTokens <= 0) return 4096;
1691
+ const target = estimatedTokens * 1.3;
1692
+ let window = 4096;
1693
+ while (window < target) window *= 2;
1694
+ return window;
1695
+ }
1652
1696
  function checkChatContext(req, options = {}) {
1653
1697
  return check(estimateChatRequestTokens(req), req.options?.num_ctx, options);
1654
1698
  }
@@ -1658,39 +1702,46 @@ function checkGenerateContext(req, options = {}) {
1658
1702
  function check(estimatedPromptTokens, requestNumCtx, options) {
1659
1703
  const threshold = options.threshold ?? DEFAULT_CONTEXT_WARNING_THRESHOLD;
1660
1704
  if (requestNumCtx !== void 0) {
1705
+ const exceeds2 = estimatedPromptTokens > requestNumCtx * threshold;
1661
1706
  return {
1662
1707
  estimatedPromptTokens,
1663
1708
  effectiveContextLength: requestNumCtx,
1664
1709
  windowSource: "request",
1665
- exceedsThreshold: estimatedPromptTokens > requestNumCtx * threshold
1710
+ exceedsThreshold: exceeds2,
1711
+ ...exceeds2 ? { recommendedNumCtx: recommendContextWindow(estimatedPromptTokens) } : {}
1666
1712
  };
1667
1713
  }
1668
1714
  if (options.defaultContextLength !== void 0) {
1715
+ const exceeds2 = estimatedPromptTokens > options.defaultContextLength * threshold;
1669
1716
  return {
1670
1717
  estimatedPromptTokens,
1671
1718
  effectiveContextLength: options.defaultContextLength,
1672
1719
  windowSource: "client-default",
1673
- exceedsThreshold: estimatedPromptTokens > options.defaultContextLength * threshold
1720
+ exceedsThreshold: exceeds2,
1721
+ ...exceeds2 ? { recommendedNumCtx: recommendContextWindow(estimatedPromptTokens) } : {}
1674
1722
  };
1675
1723
  }
1724
+ const exceeds = estimatedPromptTokens > OLLAMA_FALLBACK_CONTEXT_LENGTH;
1676
1725
  return {
1677
1726
  estimatedPromptTokens,
1678
1727
  effectiveContextLength: OLLAMA_FALLBACK_CONTEXT_LENGTH,
1679
1728
  windowSource: "server-fallback",
1680
- exceedsThreshold: estimatedPromptTokens > OLLAMA_FALLBACK_CONTEXT_LENGTH
1729
+ exceedsThreshold: exceeds,
1730
+ ...exceeds ? { recommendedNumCtx: recommendContextWindow(estimatedPromptTokens) } : {}
1681
1731
  };
1682
1732
  }
1683
1733
  var OLLAMA_FALLBACK_CONTEXT_LENGTH = 2048;
1684
1734
  function contextWarningMessage(check2, kind) {
1685
1735
  const where = `OllamaClient.${kind}()`;
1686
1736
  const estimate = `~${check2.estimatedPromptTokens} tokens`;
1737
+ const suggestion = check2.recommendedNumCtx !== void 0 ? ` A window of at least ${check2.recommendedNumCtx} tokens would fit this prompt with ~30% headroom (see \`recommendContextWindow\`) \u2014 verify the model's native maximum via \`client.models.getContextLength()\` before adopting it.` : "";
1687
1738
  if (check2.windowSource === "request") {
1688
- return `${where}: estimated prompt size ${estimate} is close to or beyond the request's context window (num_ctx=${check2.effectiveContextLength}). The server will likely silently truncate the top of the conversation \u2014 the model loses earlier turns with no error. Raise \`options.num_ctx\` or shorten the conversation. Estimates are heuristic (\xB120\u201330%); see \`estimateTokens\`.`;
1739
+ return `${where}: estimated prompt size ${estimate} is close to or beyond the request's context window (num_ctx=${check2.effectiveContextLength}). The server will likely silently truncate the top of the conversation \u2014 the model loses earlier turns with no error. Raise \`options.num_ctx\` or shorten the conversation.${suggestion} Estimates are heuristic (\xB120\u201330%); see \`estimateTokens\`.`;
1689
1740
  }
1690
1741
  if (check2.windowSource === "client-default") {
1691
- return `${where}: estimated prompt size ${estimate} is close to or beyond the client's \`defaultContextLength\` (${check2.effectiveContextLength}, injected as \`num_ctx\`). The server will likely silently truncate the top of the conversation \u2014 the model loses earlier turns with no error. Raise \`defaultContextLength\`, set \`options.num_ctx\` per request, or shorten the conversation. Estimates are heuristic (\xB120\u201330%); see \`estimateTokens\`.`;
1742
+ return `${where}: estimated prompt size ${estimate} is close to or beyond the client's \`defaultContextLength\` (${check2.effectiveContextLength}, injected as \`num_ctx\`). The server will likely silently truncate the top of the conversation \u2014 the model loses earlier turns with no error. Raise \`defaultContextLength\`, set \`options.num_ctx\` per request, or shorten the conversation.${suggestion} Estimates are heuristic (\xB120\u201330%); see \`estimateTokens\`.`;
1692
1743
  }
1693
- return `${where}: estimated prompt size ${estimate} outright exceeds Ollama's conservative server-default context window (${OLLAMA_FALLBACK_CONTEXT_LENGTH}\u20134096 tokens when \`num_ctx\` is unset \u2014 model-dependent). Unless the model's default is larger, the server will silently truncate the top of the conversation \u2014 the model loses earlier turns with no error. Set \`options.num_ctx\` (or the client's \`defaultContextLength\`) to an explicit window to make truncation visible and controllable. Estimates are heuristic (\xB120\u201330%); see \`estimateTokens\`.`;
1744
+ return `${where}: estimated prompt size ${estimate} outright exceeds Ollama's conservative server-default context window (${OLLAMA_FALLBACK_CONTEXT_LENGTH}\u20134096 tokens when \`num_ctx\` is unset \u2014 model-dependent). Unless the model's default is larger, the server will silently truncate the top of the conversation \u2014 the model loses earlier turns with no error. Set \`options.num_ctx\` (or the client's \`defaultContextLength\`) to an explicit window to make truncation visible and controllable.${suggestion} Estimates are heuristic (\xB120\u201330%); see \`estimateTokens\`.`;
1694
1745
  }
1695
1746
 
1696
1747
  // src/context-discovery.ts
@@ -6666,6 +6717,56 @@ function toResponse(stream, init = {}) {
6666
6717
  return new Response(body, { ...init, headers });
6667
6718
  }
6668
6719
 
6720
+ // src/streaming/observe.ts
6721
+ async function* observeStream(source, callbacks = {}) {
6722
+ const { onChunk, onError, onDone, onAbandon, onListenerError } = callbacks;
6723
+ const reportListenerFailure = (error, phase) => {
6724
+ try {
6725
+ onListenerError?.(error, phase);
6726
+ } catch {
6727
+ }
6728
+ };
6729
+ let observerChain = Promise.resolve();
6730
+ const dispatch2 = (phase, task) => {
6731
+ observerChain = observerChain.then(task).then(
6732
+ () => void 0,
6733
+ (error) => {
6734
+ reportListenerFailure(error, phase);
6735
+ }
6736
+ );
6737
+ };
6738
+ let state = "running";
6739
+ try {
6740
+ for await (const chunk of source) {
6741
+ if (onChunk !== void 0) {
6742
+ dispatch2("chunk", () => onChunk(chunk));
6743
+ }
6744
+ yield chunk;
6745
+ }
6746
+ state = "done";
6747
+ if (onDone !== void 0) {
6748
+ dispatch2("done", () => onDone());
6749
+ }
6750
+ } catch (error) {
6751
+ state = "error";
6752
+ try {
6753
+ onError?.(error);
6754
+ } catch (listenerError) {
6755
+ reportListenerFailure(listenerError, "error");
6756
+ }
6757
+ throw error;
6758
+ } finally {
6759
+ if (state === "running") {
6760
+ state = "abandoned";
6761
+ try {
6762
+ onAbandon?.();
6763
+ } catch (listenerError) {
6764
+ reportListenerFailure(listenerError, "abandoned");
6765
+ }
6766
+ }
6767
+ }
6768
+ }
6769
+
6669
6770
  // src/quota.ts
6670
6771
  var QuotaManager = class {
6671
6772
  now;
@@ -8062,6 +8163,7 @@ exports.ModelAffinityScheduler = ModelAffinityScheduler;
8062
8163
  exports.ModelsClient = ModelsClient;
8063
8164
  exports.NANOS_PER_MS = NANOS_PER_MS;
8064
8165
  exports.NANOS_PER_SECOND = NANOS_PER_SECOND;
8166
+ exports.NETWORK_ERROR_CODES = NETWORK_ERROR_CODES;
8065
8167
  exports.NOOP_LOGGER = NOOP_LOGGER;
8066
8168
  exports.OLLAMA_CLOUD_BASE_URL = OLLAMA_CLOUD_BASE_URL;
8067
8169
  exports.OLLAMA_FALLBACK_CONTEXT_LENGTH = OLLAMA_FALLBACK_CONTEXT_LENGTH;
@@ -8150,6 +8252,7 @@ exports.inferRuntimeMode = inferRuntimeMode;
8150
8252
  exports.isKeepAliveSugar = isKeepAliveSugar;
8151
8253
  exports.isKnownDoneReason = isKnownDoneReason;
8152
8254
  exports.isModelResident = isModelResident;
8255
+ exports.isNetworkLevelError = isNetworkLevelError;
8153
8256
  exports.isSameToolCall = isSameToolCall;
8154
8257
  exports.listAllMcpTools = listAllMcpTools;
8155
8258
  exports.listAvailableModels = listAvailableModels;
@@ -8162,10 +8265,12 @@ exports.normalizeChatStream = normalizeChatStream;
8162
8265
  exports.normalizeGenerateStream = normalizeGenerateStream;
8163
8266
  exports.normalizeKeepAlive = normalizeKeepAlive;
8164
8267
  exports.normalizeProgressStream = normalizeProgressStream;
8268
+ exports.observeStream = observeStream;
8165
8269
  exports.parseFrontmatter = parseFrontmatter;
8166
8270
  exports.parseNdjsonStream = parseNdjsonStream;
8167
8271
  exports.parseSseStream = parseSseStream;
8168
8272
  exports.parseStructuredOutput = parseStructuredOutput;
8273
+ exports.recommendContextWindow = recommendContextWindow;
8169
8274
  exports.registerMcpTools = registerMcpTools;
8170
8275
  exports.resolveContextLength = resolveContextLength;
8171
8276
  exports.resolveCredentialEndpoints = resolveCredentialEndpoints;