@nemesis-oss/ollama-sdk 1.13.0 → 1.15.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.js CHANGED
@@ -2815,12 +2815,29 @@ var ModelsClient = class {
2815
2815
  * await client.models.createModelFromGguf('my-model', '/path/to/model.gguf', {
2816
2816
  * template: '{{ .Prompt }}',
2817
2817
  * });
2818
+ *
2819
+ * // Speculative decoding: primary + draft shards + tuning:
2820
+ * await client.models.createModelFromGguf('my-model', '/path/to/model.gguf', {
2821
+ * draftGguf: '/path/to/draft.gguf',
2822
+ * draftQuantize: 'q8_0',
2823
+ * parameters: { draft_num_predict: 8 },
2824
+ * });
2818
2825
  * ```
2819
2826
  *
2827
+ * Speculative-decoding models assemble the same way: pass the draft
2828
+ * network's GGUF(s) as `draftGguf` (uploaded into `draft_files`), optionally
2829
+ * set `draft_quantize` to compress the draft weights independently of the
2830
+ * primary model, and set `parameters.draft_num_predict` to tune how many
2831
+ * tokens the draft network predicts per step (Ollama defaults separate
2832
+ * draft models to 4; `0` disables drafting; models with embedded MTP
2833
+ * tensors require setting it explicitly).
2834
+ *
2820
2835
  * @param model Name for the new model (e.g. `'my-model:latest'`).
2821
2836
  * @param gguf Path(s) to GGUF file(s) on the local filesystem.
2822
2837
  * @param opts Everything else `/api/create` accepts (`template`, `system`,
2823
- * `parameters`, `license`, `quantize`, …) except `files` and `from`.
2838
+ * `parameters`, `license`, `quantize`, `draftGguf`, …) except `files`,
2839
+ * `draft_files` (use `draftGguf` for path-based drafts; an explicit digest
2840
+ * map is still accepted and merged), `from`, and `stream`.
2824
2841
  */
2825
2842
  async createModelFromGguf(model, gguf, opts) {
2826
2843
  const paths = typeof gguf === "string" ? [gguf] : gguf;
@@ -2834,14 +2851,29 @@ var ModelsClient = class {
2834
2851
  const uploaded = await this.createBlobFromFile(path, { signal: opts?.signal });
2835
2852
  files[uploaded.fileName] = uploaded.digest;
2836
2853
  }
2854
+ const draftOpt = opts?.draftGguf;
2855
+ const draftPaths = typeof draftOpt === "string" ? [draftOpt] : draftOpt ?? [];
2837
2856
  const {
2838
2857
  model: _model,
2839
2858
  files: _files,
2840
2859
  from: _from,
2841
2860
  stream: _stream,
2861
+ draftGguf: _draftGguf,
2862
+ draft_files: _draftFiles,
2842
2863
  ...rest
2843
2864
  } = opts ?? {};
2844
- return this.create({ ...rest, model, files, stream: false });
2865
+ const draftFiles = { ..._draftFiles ?? {} };
2866
+ for (const path of draftPaths) {
2867
+ const uploaded = await this.createBlobFromFile(path, { signal: opts?.signal });
2868
+ draftFiles[uploaded.fileName] = uploaded.digest;
2869
+ }
2870
+ return this.create({
2871
+ ...rest,
2872
+ model,
2873
+ files,
2874
+ ...Object.keys(draftFiles).length > 0 ? { draft_files: draftFiles } : {},
2875
+ stream: false
2876
+ });
2845
2877
  }
2846
2878
  };
2847
2879
 
@@ -7716,6 +7748,111 @@ var Agent = class {
7716
7748
  }
7717
7749
  };
7718
7750
 
7751
+ // src/draft-benchmark.ts
7752
+ var DEFAULT_DRAFT_TOKENS = 4;
7753
+ var DEFAULT_SAMPLES = 5;
7754
+ var DEFAULT_NUM_PREDICT = 256;
7755
+ var DEFAULT_SEED = 42;
7756
+ var DEFAULT_GAIN_THRESHOLD = 1.05;
7757
+ function median(values) {
7758
+ const sorted = [...values].sort((a, b) => a - b);
7759
+ const mid = Math.floor(sorted.length / 2);
7760
+ return sorted.length % 2 === 1 ? sorted[mid] ?? 0 : ((sorted[mid - 1] ?? 0) + (sorted[mid] ?? 0)) / 2;
7761
+ }
7762
+ function roundTo(value, decimals) {
7763
+ const factor = 10 ** decimals;
7764
+ return Math.round(value * factor) / factor;
7765
+ }
7766
+ function requirePositiveInteger(name, value) {
7767
+ if (!Number.isInteger(value) || value < 1) {
7768
+ throw new RangeError(
7769
+ `compareDraftPerformance: ${name} must be an integer >= 1 (got ${value}).`
7770
+ );
7771
+ }
7772
+ }
7773
+ async function runSide(client, options, draftNumPredict, samples, numPredict, seed) {
7774
+ const samplingOptions = {
7775
+ num_predict: numPredict,
7776
+ temperature: 0,
7777
+ seed,
7778
+ draft_num_predict: draftNumPredict
7779
+ };
7780
+ if (options.warmup ?? true) {
7781
+ await client.generate({
7782
+ model: options.model,
7783
+ prompt: options.prompt,
7784
+ options: { ...samplingOptions, num_predict: 1 },
7785
+ stream: false,
7786
+ signal: options.signal
7787
+ });
7788
+ }
7789
+ const tokensPerSecond = [];
7790
+ const generationMs = [];
7791
+ for (let i = 0; i < samples; i++) {
7792
+ options.signal?.throwIfAborted();
7793
+ const response = await client.generate({
7794
+ model: options.model,
7795
+ prompt: options.prompt,
7796
+ options: samplingOptions,
7797
+ stream: false,
7798
+ signal: options.signal
7799
+ });
7800
+ const telemetry = formatTelemetry(response);
7801
+ if (Number.isFinite(telemetry.tokensPerSecond) && telemetry.tokensPerSecond > 0) {
7802
+ tokensPerSecond.push(telemetry.tokensPerSecond);
7803
+ generationMs.push(telemetry.generationMs);
7804
+ }
7805
+ }
7806
+ if (tokensPerSecond.length === 0) {
7807
+ throw new OllamaClientError(
7808
+ `compareDraftPerformance: every draft_num_predict=${draftNumPredict} sample returned a non-positive tokens/second. The model name is likely wrong, or the server returned empty generations.`,
7809
+ { code: "draft_benchmark_no_valid_samples" }
7810
+ );
7811
+ }
7812
+ return {
7813
+ draftNumPredict,
7814
+ medianTokensPerSecond: median(tokensPerSecond),
7815
+ sampleTokensPerSecond: tokensPerSecond,
7816
+ medianEvalDurationMs: median(generationMs)
7817
+ };
7818
+ }
7819
+ async function compareDraftPerformance(client, options) {
7820
+ const draftNumPredict = options.draftNumPredict ?? DEFAULT_DRAFT_TOKENS;
7821
+ requirePositiveInteger("draftNumPredict", draftNumPredict);
7822
+ const samples = options.samples ?? DEFAULT_SAMPLES;
7823
+ requirePositiveInteger("samples", samples);
7824
+ const numPredict = options.numPredict ?? DEFAULT_NUM_PREDICT;
7825
+ requirePositiveInteger("numPredict", numPredict);
7826
+ const seed = options.seed ?? DEFAULT_SEED;
7827
+ if (!Number.isInteger(seed)) {
7828
+ throw new RangeError(`compareDraftPerformance: seed must be an integer (got ${seed}).`);
7829
+ }
7830
+ const gainThreshold = options.gainThreshold ?? DEFAULT_GAIN_THRESHOLD;
7831
+ if (!Number.isFinite(gainThreshold) || gainThreshold <= 0) {
7832
+ throw new RangeError(
7833
+ `compareDraftPerformance: gainThreshold must be a positive finite number (got ${gainThreshold}).`
7834
+ );
7835
+ }
7836
+ options.signal?.throwIfAborted();
7837
+ const baseline = await runSide(client, options, 0, samples, numPredict, seed);
7838
+ const speculative = await runSide(client, options, draftNumPredict, samples, numPredict, seed);
7839
+ const baselineTokensPerSec = roundTo(baseline.medianTokensPerSecond, 1);
7840
+ const speculativeTokensPerSec = roundTo(speculative.medianTokensPerSecond, 1);
7841
+ const speedupMultiplier = baselineTokensPerSec > 0 ? roundTo(speculativeTokensPerSec / baselineTokensPerSec, 2) : 0;
7842
+ return {
7843
+ model: options.model,
7844
+ prompt: options.prompt,
7845
+ draftNumPredict,
7846
+ baselineTokensPerSec,
7847
+ speculativeTokensPerSec,
7848
+ speedupMultiplier,
7849
+ effectiveGain: speedupMultiplier > gainThreshold,
7850
+ gainThreshold,
7851
+ baseline,
7852
+ speculative
7853
+ };
7854
+ }
7855
+
7719
7856
  // src/affinity.ts
7720
7857
  var DEFAULT_CONCURRENT_MODELS = 1;
7721
7858
  var DEFAULT_PER_MODEL_CONCURRENCY = 1;
@@ -7877,6 +8014,6 @@ function estimateSystemOneRequestBytes(request) {
7877
8014
  return new TextEncoder().encode(JSON.stringify(request)).byteLength;
7878
8015
  }
7879
8016
 
7880
- export { ATTR_GEN_AI_OPERATION_NAME, ATTR_GEN_AI_REQUEST_MODEL, ATTR_GEN_AI_RESPONSE_MODEL, ATTR_GEN_AI_SYSTEM, ATTR_GEN_AI_TOOL_CALL_ID, ATTR_GEN_AI_TOOL_NAME, ATTR_GEN_AI_USAGE_INPUT_TOKENS, ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, ATTR_HTTP_REQUEST_METHOD, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_OLLAMA_AGENT_ITERATION, ATTR_OLLAMA_AGENT_MAX_ITERATIONS, ATTR_OLLAMA_ENDPOINT_ATTEMPT, ATTR_OLLAMA_ENDPOINT_NAME, ATTR_SERVER_ADDRESS, ATTR_SERVER_PORT, ATTR_URL_FULL, Agent, AnthropicCompatClient, AnthropicMessagesStream, ConversationSession, DEFAULT_BACKOFF, DEFAULT_BASE_URL, DEFAULT_CONTEXT_WARNING_THRESHOLD, DEFAULT_EMBED_BATCH_SIZE, DEFAULT_EMBED_CONCURRENCY, DEFAULT_FAILOVER_CODES, DEFAULT_FETCH_BACKOFF_CONFIG, DEFAULT_RETRY_CONFIG, DEFAULT_TIMEOUT_MS, EndpointRegistry, GEN_AI_SYSTEM_OLLAMA, HttpClient, IMAGE_TOKEN_ESTIMATE, KEEP_ALIVE_INDEFINITE, KEEP_ALIVE_UNLOAD, KNOWN_DONE_REASONS, MAX_SYSTEM_ONE_IMAGES_BYTES, MAX_SYSTEM_ONE_REQUEST_BYTES, MESSAGE_OVERHEAD_TOKENS, McpBridge, ModelAffinityRouter, ModelAffinityScheduler, ModelsClient, NANOS_PER_MS, NANOS_PER_SECOND, NOOP_LOGGER, OLLAMA_CLOUD_BASE_URL, OLLAMA_FALLBACK_CONTEXT_LENGTH, OllamaAbortError, OllamaAgentMaxIterationsError, OllamaAgentMaxToolCallsError, OllamaAgentToolLoopError, OllamaAuthError, OllamaBadGatewayError, OllamaClient, OllamaClientError, OllamaGenericClientError, OllamaIncompatibleModelError, OllamaMcpError, OllamaModelRoutingError, OllamaNetworkError, OllamaNotFoundError, OllamaOverloadedError, OllamaQuotaExceededError, OllamaRateLimitError, OllamaRequestTooLargeError, OllamaRequestValidationError, OllamaResponseValidationError, OllamaServerError, OllamaServerVersionUnknownError, OllamaSkillInvalidError, OllamaSkillNotFoundError, OllamaStream, OllamaStreamError, OllamaTimeoutError, OllamaToolTimeoutError, OllamaToolValidationError, OllamaUnsupportedCapabilityError, OpenAIChatCompletionStream, OpenAICompatClient, OpenAICompletionStream, OpenAIResponsesStream, OpenAIResponsesStreamError, QuotaManager, RETRYABLE_STATUS_CODES, ResponsesModule, ToolCallAccumulator, ToolRegistry, WEB_FETCH_TOOL_NAME, WEB_SEARCH_TOOL_NAME, addSpanEvent, applySkill, batchEmbed, calculateBackoff, canonicalToolCallSignature, checkChatContext, checkEndpointHealth, checkGenerateContext, compactConversationHistory, composeMiddleware, contextWarningMessage, createConsoleLogger, createDecision, createModelAffinityScheduler, createOllamaCloudFreeTierQuota, createTimeoutSignal, createWebFetchTool, createWebSearchTool, createWebTools, defineTool, detectModelCapabilities, embedBatchOverflowMessage, encodeImage, estimateChatRequestTokens, estimateGenerateRequestTokens, estimateMessageTokens, estimateSystemOneRequestBytes, estimateTokens, extractContextLength as extractNativeContextLength, extractParameterNumCtx, extractUsage, fetchWithBackoff, findOversizedEmbedInputs, findRunningModelContextLength, formatTelemetry, formatWebFetchResult, formatWebSearchResult, imageStringNeedsResolution, inferRuntimeMode, isKeepAliveSugar, isKnownDoneReason, isModelResident, isSameToolCall, listAllMcpTools, listAvailableModels, loadMcpTools, mapError, mergeToolCall, mergeToolCallArgumentsString, mergeToolCallArrays, normalizeChatStream, normalizeGenerateStream, normalizeKeepAlive, normalizeProgressStream, parseFrontmatter, parseNdjsonStream, parseSseStream, parseStructuredOutput, registerMcpTools, resolveContextLength, resolveCredentialEndpoints, resolveImageInput, sanitizeHistoryForNextTurn, setSpanError, toDataStream, toResponse, toTextStream, withRetry, withSpan, zodToJsonSchema };
8017
+ export { ATTR_GEN_AI_OPERATION_NAME, ATTR_GEN_AI_REQUEST_MODEL, ATTR_GEN_AI_RESPONSE_MODEL, ATTR_GEN_AI_SYSTEM, ATTR_GEN_AI_TOOL_CALL_ID, ATTR_GEN_AI_TOOL_NAME, ATTR_GEN_AI_USAGE_INPUT_TOKENS, ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, ATTR_HTTP_REQUEST_METHOD, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_OLLAMA_AGENT_ITERATION, ATTR_OLLAMA_AGENT_MAX_ITERATIONS, ATTR_OLLAMA_ENDPOINT_ATTEMPT, ATTR_OLLAMA_ENDPOINT_NAME, ATTR_SERVER_ADDRESS, ATTR_SERVER_PORT, ATTR_URL_FULL, Agent, AnthropicCompatClient, AnthropicMessagesStream, ConversationSession, DEFAULT_BACKOFF, DEFAULT_BASE_URL, DEFAULT_CONTEXT_WARNING_THRESHOLD, DEFAULT_EMBED_BATCH_SIZE, DEFAULT_EMBED_CONCURRENCY, DEFAULT_FAILOVER_CODES, DEFAULT_FETCH_BACKOFF_CONFIG, DEFAULT_RETRY_CONFIG, DEFAULT_TIMEOUT_MS, EndpointRegistry, GEN_AI_SYSTEM_OLLAMA, HttpClient, IMAGE_TOKEN_ESTIMATE, KEEP_ALIVE_INDEFINITE, KEEP_ALIVE_UNLOAD, KNOWN_DONE_REASONS, MAX_SYSTEM_ONE_IMAGES_BYTES, MAX_SYSTEM_ONE_REQUEST_BYTES, MESSAGE_OVERHEAD_TOKENS, McpBridge, ModelAffinityRouter, ModelAffinityScheduler, ModelsClient, NANOS_PER_MS, NANOS_PER_SECOND, NOOP_LOGGER, OLLAMA_CLOUD_BASE_URL, OLLAMA_FALLBACK_CONTEXT_LENGTH, OllamaAbortError, OllamaAgentMaxIterationsError, OllamaAgentMaxToolCallsError, OllamaAgentToolLoopError, OllamaAuthError, OllamaBadGatewayError, OllamaClient, OllamaClientError, OllamaGenericClientError, OllamaIncompatibleModelError, OllamaMcpError, OllamaModelRoutingError, OllamaNetworkError, OllamaNotFoundError, OllamaOverloadedError, OllamaQuotaExceededError, OllamaRateLimitError, OllamaRequestTooLargeError, OllamaRequestValidationError, OllamaResponseValidationError, OllamaServerError, OllamaServerVersionUnknownError, OllamaSkillInvalidError, OllamaSkillNotFoundError, OllamaStream, OllamaStreamError, OllamaTimeoutError, OllamaToolTimeoutError, OllamaToolValidationError, OllamaUnsupportedCapabilityError, OpenAIChatCompletionStream, OpenAICompatClient, OpenAICompletionStream, OpenAIResponsesStream, OpenAIResponsesStreamError, QuotaManager, RETRYABLE_STATUS_CODES, ResponsesModule, ToolCallAccumulator, ToolRegistry, WEB_FETCH_TOOL_NAME, WEB_SEARCH_TOOL_NAME, addSpanEvent, applySkill, batchEmbed, calculateBackoff, canonicalToolCallSignature, checkChatContext, checkEndpointHealth, checkGenerateContext, compactConversationHistory, compareDraftPerformance, composeMiddleware, contextWarningMessage, createConsoleLogger, createDecision, createModelAffinityScheduler, createOllamaCloudFreeTierQuota, createTimeoutSignal, createWebFetchTool, createWebSearchTool, createWebTools, defineTool, detectModelCapabilities, embedBatchOverflowMessage, encodeImage, estimateChatRequestTokens, estimateGenerateRequestTokens, estimateMessageTokens, estimateSystemOneRequestBytes, estimateTokens, extractContextLength as extractNativeContextLength, extractParameterNumCtx, extractUsage, fetchWithBackoff, findOversizedEmbedInputs, findRunningModelContextLength, formatTelemetry, formatWebFetchResult, formatWebSearchResult, imageStringNeedsResolution, inferRuntimeMode, isKeepAliveSugar, isKnownDoneReason, isModelResident, isSameToolCall, listAllMcpTools, listAvailableModels, loadMcpTools, mapError, mergeToolCall, mergeToolCallArgumentsString, mergeToolCallArrays, normalizeChatStream, normalizeGenerateStream, normalizeKeepAlive, normalizeProgressStream, parseFrontmatter, parseNdjsonStream, parseSseStream, parseStructuredOutput, registerMcpTools, resolveContextLength, resolveCredentialEndpoints, resolveImageInput, sanitizeHistoryForNextTurn, setSpanError, toDataStream, toResponse, toTextStream, withRetry, withSpan, zodToJsonSchema };
7881
8018
  //# sourceMappingURL=index.js.map
7882
8019
  //# sourceMappingURL=index.js.map