@providerprotocol/ai 0.0.16 → 0.0.17

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.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { P as ProviderConfig, L as LLMProvider, a as LLMHandler$1, E as EmbeddingHandler, I as ImageHandler, b as Provider } from './provider-vTZ74u-w.js';
2
- export { B as BoundEmbeddingModel, g as BoundImageModel, e as EmbeddingProvider, c as ErrorCode, f as ImageProvider, K as KeyStrategy, M as Modality, d as ModelReference, R as RetryStrategy, U as UPPError } from './provider-vTZ74u-w.js';
3
- export { D as DynamicKey, E as ExponentialBackoff, L as LinearBackoff, N as NoRetry, a as RetryAfterStrategy, R as RoundRobinKeys, T as TokenBucket, W as WeightedKeys } from './retry-CMdT0kD8.js';
1
+ import { P as ProviderConfig, L as LLMProvider, E as EmbeddingInput, a as EmbeddingUsage, B as BoundEmbeddingModel, b as LLMHandler$1, c as EmbeddingHandler, I as ImageHandler, d as Provider } from './provider-D5MO3-pS.js';
2
+ export { i as BoundImageModel, g as EmbeddingProvider, j as EmbeddingRequest, k as EmbeddingResponse, l as EmbeddingVector, e as ErrorCode, h as ImageProvider, K as KeyStrategy, M as Modality, f as ModelReference, R as RetryStrategy, U as UPPError } from './provider-D5MO3-pS.js';
3
+ export { D as DynamicKey, E as ExponentialBackoff, L as LinearBackoff, N as NoRetry, a as RetryAfterStrategy, R as RoundRobinKeys, T as TokenBucket, W as WeightedKeys } from './retry-DZ4Sqmxp.js';
4
4
 
5
5
  /**
6
6
  * @fileoverview Content block types for multimodal messages.
@@ -1831,6 +1831,205 @@ interface LLMHandler<TParams = unknown> {
1831
1831
  */
1832
1832
  declare function llm<TParams = unknown>(options: LLMOptions<TParams>): LLMInstance<TParams>;
1833
1833
 
1834
+ /**
1835
+ * @fileoverview Embedding types for vector embedding generation.
1836
+ *
1837
+ * Defines the interfaces for configuring and executing embedding operations,
1838
+ * including options, instances, requests, responses, and streaming progress.
1839
+ *
1840
+ * @module types/embedding
1841
+ */
1842
+
1843
+ /**
1844
+ * Structural type for embedding model input.
1845
+ * Uses structural typing to avoid generic variance issues with Provider generics.
1846
+ */
1847
+ interface EmbeddingModelInput {
1848
+ readonly modelId: string;
1849
+ readonly provider: {
1850
+ readonly name: string;
1851
+ readonly version: string;
1852
+ readonly modalities: {
1853
+ embedding?: unknown;
1854
+ };
1855
+ };
1856
+ }
1857
+ /**
1858
+ * Options for creating an embedding instance with the embedding() function.
1859
+ *
1860
+ * @typeParam TParams - Provider-specific parameter type
1861
+ *
1862
+ * @example
1863
+ * ```typescript
1864
+ * const options: EmbeddingOptions<OpenAIEmbedParams> = {
1865
+ * model: openai('text-embedding-3-large'),
1866
+ * config: { apiKey: process.env.OPENAI_API_KEY },
1867
+ * params: { dimensions: 1536 }
1868
+ * };
1869
+ * ```
1870
+ */
1871
+ interface EmbeddingOptions<TParams = unknown> {
1872
+ /** A model reference from a provider factory */
1873
+ model: EmbeddingModelInput;
1874
+ /** Provider infrastructure configuration */
1875
+ config?: ProviderConfig;
1876
+ /** Provider-specific parameters (passed through unchanged) */
1877
+ params?: TParams;
1878
+ }
1879
+ /**
1880
+ * Options for embed() calls.
1881
+ */
1882
+ interface EmbedOptions {
1883
+ /**
1884
+ * Enable chunked processing with progress for large input sets.
1885
+ * When true, returns EmbeddingStream instead of Promise.
1886
+ */
1887
+ chunked?: boolean;
1888
+ /** Inputs per batch when chunked (default: provider max) */
1889
+ batchSize?: number;
1890
+ /** Concurrent batch limit when chunked (default: 1) */
1891
+ concurrency?: number;
1892
+ /** Abort signal for cancellation */
1893
+ signal?: AbortSignal;
1894
+ }
1895
+ /**
1896
+ * Single embedding vector result.
1897
+ */
1898
+ interface Embedding {
1899
+ /** The embedding vector */
1900
+ vector: number[];
1901
+ /** Vector dimensionality */
1902
+ dimensions: number;
1903
+ /** Index corresponding to input array position */
1904
+ index: number;
1905
+ /** Token count for this input (if provider reports) */
1906
+ tokens?: number;
1907
+ /** Provider-specific per-embedding metadata */
1908
+ metadata?: Record<string, unknown>;
1909
+ }
1910
+ /**
1911
+ * Result from embed() call.
1912
+ */
1913
+ interface EmbeddingResult {
1914
+ /** Embeddings in same order as inputs */
1915
+ embeddings: Embedding[];
1916
+ /** Usage statistics */
1917
+ usage: EmbeddingUsage;
1918
+ /** Provider-specific response metadata */
1919
+ metadata?: Record<string, unknown>;
1920
+ }
1921
+ /**
1922
+ * Progress update when using chunked mode.
1923
+ */
1924
+ interface EmbeddingProgress {
1925
+ /** Embeddings from the latest batch */
1926
+ embeddings: Embedding[];
1927
+ /** Total embeddings completed so far */
1928
+ completed: number;
1929
+ /** Total number of inputs */
1930
+ total: number;
1931
+ /** Percentage complete (0-100) */
1932
+ percent: number;
1933
+ }
1934
+ /**
1935
+ * Async iterable stream with final result accessor.
1936
+ * Returned when embed() is called with { chunked: true }.
1937
+ */
1938
+ interface EmbeddingStream extends AsyncIterable<EmbeddingProgress> {
1939
+ /** Promise resolving to complete result after iteration */
1940
+ readonly result: Promise<EmbeddingResult>;
1941
+ /** Abort the operation */
1942
+ abort(): void;
1943
+ }
1944
+ /**
1945
+ * Embedding instance returned by the embedding() function.
1946
+ *
1947
+ * @typeParam TParams - Provider-specific parameter type
1948
+ *
1949
+ * @example
1950
+ * ```typescript
1951
+ * const embedder = embedding({ model: openai('text-embedding-3-large') });
1952
+ *
1953
+ * // Single input
1954
+ * const result = await embedder.embed('Hello world');
1955
+ *
1956
+ * // Batch input
1957
+ * const batch = await embedder.embed(['doc1', 'doc2', 'doc3']);
1958
+ *
1959
+ * // Large-scale with progress
1960
+ * const stream = embedder.embed(documents, { chunked: true });
1961
+ * for await (const progress of stream) {
1962
+ * console.log(`${progress.percent}% complete`);
1963
+ * }
1964
+ * ```
1965
+ */
1966
+ interface EmbeddingInstance<TParams = unknown> {
1967
+ /**
1968
+ * Generate embeddings for one or more inputs.
1969
+ *
1970
+ * @param input - Single input or array of inputs
1971
+ * @param options - Optional embed options
1972
+ * @returns Promise<EmbeddingResult> or EmbeddingStream if chunked
1973
+ */
1974
+ embed(input: EmbeddingInput | EmbeddingInput[], options?: EmbedOptions & {
1975
+ chunked?: false;
1976
+ }): Promise<EmbeddingResult>;
1977
+ embed(input: EmbeddingInput[], options: EmbedOptions & {
1978
+ chunked: true;
1979
+ }): EmbeddingStream;
1980
+ embed(input: EmbeddingInput | EmbeddingInput[], options?: EmbedOptions): Promise<EmbeddingResult> | EmbeddingStream;
1981
+ /** The bound embedding model */
1982
+ readonly model: BoundEmbeddingModel<TParams>;
1983
+ /** Current parameters */
1984
+ readonly params: TParams | undefined;
1985
+ }
1986
+
1987
+ /**
1988
+ * @fileoverview Embedding instance factory for the Universal Provider Protocol.
1989
+ *
1990
+ * This module provides the core functionality for creating embedding instances
1991
+ * that generate vector embeddings from text or other content.
1992
+ *
1993
+ * @module core/embedding
1994
+ */
1995
+
1996
+ /**
1997
+ * Creates an embedding instance configured with the specified options.
1998
+ *
1999
+ * This is the primary factory function for creating embedding instances.
2000
+ * It validates provider capabilities, binds the model, and returns an
2001
+ * instance with an `embed` method for generating embeddings.
2002
+ *
2003
+ * @typeParam TParams - Provider-specific parameter type
2004
+ * @param options - Configuration options for the embedding instance
2005
+ * @returns A configured embedding instance ready for use
2006
+ * @throws {UPPError} When the provider does not support the embedding modality
2007
+ *
2008
+ * @example
2009
+ * ```typescript
2010
+ * import { embedding } from 'upp';
2011
+ * import { openai } from 'upp/openai';
2012
+ *
2013
+ * const embedder = embedding({
2014
+ * model: openai('text-embedding-3-large'),
2015
+ * params: { dimensions: 1536 }
2016
+ * });
2017
+ *
2018
+ * // Single input
2019
+ * const result = await embedder.embed('Hello world');
2020
+ *
2021
+ * // Batch input
2022
+ * const batch = await embedder.embed(['doc1', 'doc2', 'doc3']);
2023
+ *
2024
+ * // Large-scale with progress
2025
+ * const stream = embedder.embed(documents, { chunked: true });
2026
+ * for await (const progress of stream) {
2027
+ * console.log(`${progress.percent}% complete`);
2028
+ * }
2029
+ * ```
2030
+ */
2031
+ declare function embedding<TParams = unknown>(options: EmbeddingOptions<TParams>): EmbeddingInstance<TParams>;
2032
+
1834
2033
  /**
1835
2034
  * @fileoverview Base provider interface and factory for the Universal Provider Protocol.
1836
2035
  *
@@ -2108,6 +2307,8 @@ declare class Image {
2108
2307
  declare const ai: {
2109
2308
  /** LLM instance factory */
2110
2309
  llm: typeof llm;
2310
+ /** Embedding instance factory */
2311
+ embedding: typeof embedding;
2111
2312
  };
2112
2313
 
2113
- export { type AfterCallResult, type AssistantContent, AssistantMessage, type AudioBlock, type BeforeCallResult, type BinaryBlock, type BoundLLMModel, type ContentBlock, EmbeddingHandler, type EventDelta, Image, type ImageBlock, ImageHandler, type ImageSource, type InferenceInput, type JSONSchema, type JSONSchemaProperty, type JSONSchemaPropertyType, type LLMCapabilities, type LLMHandler, type LLMInstance, type LLMOptions, LLMProvider, type LLMRequest, type LLMResponse, type LLMStreamResult, Message, type MessageJSON, type MessageMetadata, type MessageOptions, type MessageType, Provider, ProviderConfig, type StreamEvent, type StreamEventType, type StreamResult, type TextBlock, Thread, type ThreadJSON, type TokenUsage, type Tool, type ToolCall, type ToolExecution, type ToolMetadata, type ToolResult, ToolResultMessage, type ToolUseStrategy, type Turn, type UserContent, UserMessage, type VideoBlock, aggregateUsage, ai, contentBlockStart, contentBlockStop, createProvider, createStreamResult, createTurn, emptyUsage, isAssistantMessage, isAudioBlock, isBinaryBlock, isImageBlock, isTextBlock, isToolResultMessage, isUserMessage, isVideoBlock, llm, messageStart, messageStop, text, textDelta, toolCallDelta };
2314
+ export { type AfterCallResult, type AssistantContent, AssistantMessage, type AudioBlock, type BeforeCallResult, type BinaryBlock, BoundEmbeddingModel, type BoundLLMModel, type ContentBlock, type EmbedOptions, type Embedding, EmbeddingHandler, EmbeddingInput, type EmbeddingInstance, type EmbeddingModelInput, type EmbeddingOptions, type EmbeddingProgress, type EmbeddingResult, type EmbeddingStream, EmbeddingUsage, type EventDelta, Image, type ImageBlock, ImageHandler, type ImageSource, type InferenceInput, type JSONSchema, type JSONSchemaProperty, type JSONSchemaPropertyType, type LLMCapabilities, type LLMHandler, type LLMInstance, type LLMOptions, LLMProvider, type LLMRequest, type LLMResponse, type LLMStreamResult, Message, type MessageJSON, type MessageMetadata, type MessageOptions, type MessageType, Provider, ProviderConfig, type StreamEvent, type StreamEventType, type StreamResult, type TextBlock, Thread, type ThreadJSON, type TokenUsage, type Tool, type ToolCall, type ToolExecution, type ToolMetadata, type ToolResult, ToolResultMessage, type ToolUseStrategy, type Turn, type UserContent, UserMessage, type VideoBlock, aggregateUsage, ai, contentBlockStart, contentBlockStop, createProvider, createStreamResult, createTurn, embedding, emptyUsage, isAssistantMessage, isAudioBlock, isBinaryBlock, isImageBlock, isTextBlock, isToolResultMessage, isUserMessage, isVideoBlock, llm, messageStart, messageStop, text, textDelta, toolCallDelta };
package/dist/index.js CHANGED
@@ -578,6 +578,152 @@ function validateMediaCapabilities(messages, capabilities, providerName) {
578
578
  }
579
579
  }
580
580
 
581
+ // src/core/embedding.ts
582
+ function embedding(options) {
583
+ const { model: modelRef, config = {}, params } = options;
584
+ const provider = modelRef.provider;
585
+ if (!provider.modalities.embedding) {
586
+ throw new UPPError(
587
+ `Provider '${provider.name}' does not support embedding modality`,
588
+ "INVALID_REQUEST",
589
+ provider.name,
590
+ "embedding"
591
+ );
592
+ }
593
+ const handler = provider.modalities.embedding;
594
+ const boundModel = handler.bind(modelRef.modelId);
595
+ const instance = {
596
+ model: boundModel,
597
+ params,
598
+ embed(input, embedOptions) {
599
+ const inputs = Array.isArray(input) ? input : [input];
600
+ if (embedOptions?.chunked) {
601
+ return createChunkedStream(boundModel, inputs, params, config, embedOptions);
602
+ }
603
+ return executeEmbed(boundModel, inputs, params, config, embedOptions?.signal);
604
+ }
605
+ };
606
+ return instance;
607
+ }
608
+ async function executeEmbed(model, inputs, params, config, signal) {
609
+ const response = await model.embed({
610
+ inputs,
611
+ params,
612
+ config: config ?? {},
613
+ signal
614
+ });
615
+ return normalizeResponse(response);
616
+ }
617
+ function normalizeResponse(response) {
618
+ return {
619
+ embeddings: response.embeddings.map((vec, i) => {
620
+ const vector = normalizeVector(vec.vector);
621
+ return {
622
+ vector,
623
+ dimensions: vector.length,
624
+ index: vec.index ?? i,
625
+ tokens: vec.tokens,
626
+ metadata: vec.metadata
627
+ };
628
+ }),
629
+ usage: response.usage,
630
+ metadata: response.metadata
631
+ };
632
+ }
633
+ function normalizeVector(vector) {
634
+ if (Array.isArray(vector)) {
635
+ return vector;
636
+ }
637
+ return decodeBase64(vector);
638
+ }
639
+ function decodeBase64(b64) {
640
+ const binary = atob(b64);
641
+ const bytes = new Uint8Array(binary.length);
642
+ for (let i = 0; i < binary.length; i++) {
643
+ bytes[i] = binary.charCodeAt(i);
644
+ }
645
+ const floats = new Float32Array(bytes.buffer);
646
+ return Array.from(floats);
647
+ }
648
+ function createChunkedStream(model, inputs, params, config, options) {
649
+ const abortController = new AbortController();
650
+ const batchSize = options.batchSize ?? model.maxBatchSize;
651
+ const concurrency = options.concurrency ?? 1;
652
+ let resolveResult;
653
+ let rejectResult;
654
+ const resultPromise = new Promise((resolve, reject) => {
655
+ resolveResult = resolve;
656
+ rejectResult = reject;
657
+ });
658
+ async function* generate() {
659
+ const total = inputs.length;
660
+ const allEmbeddings = [];
661
+ let totalTokens = 0;
662
+ const batches = [];
663
+ for (let i = 0; i < inputs.length; i += batchSize) {
664
+ batches.push(inputs.slice(i, i + batchSize));
665
+ }
666
+ try {
667
+ for (let i = 0; i < batches.length; i += concurrency) {
668
+ if (abortController.signal.aborted || options.signal?.aborted) {
669
+ throw new UPPError(
670
+ "Embedding cancelled",
671
+ "CANCELLED",
672
+ model.provider.name,
673
+ "embedding"
674
+ );
675
+ }
676
+ const chunk = batches.slice(i, i + concurrency);
677
+ const responses = await Promise.all(
678
+ chunk.map(
679
+ (batch) => model.embed({
680
+ inputs: batch,
681
+ params,
682
+ config: config ?? {},
683
+ signal: abortController.signal
684
+ })
685
+ )
686
+ );
687
+ const batchEmbeddings = [];
688
+ for (const response of responses) {
689
+ for (const vec of response.embeddings) {
690
+ const vector = normalizeVector(vec.vector);
691
+ const emb = {
692
+ vector,
693
+ dimensions: vector.length,
694
+ index: allEmbeddings.length + batchEmbeddings.length,
695
+ tokens: vec.tokens,
696
+ metadata: vec.metadata
697
+ };
698
+ batchEmbeddings.push(emb);
699
+ }
700
+ totalTokens += response.usage.totalTokens;
701
+ }
702
+ allEmbeddings.push(...batchEmbeddings);
703
+ yield {
704
+ embeddings: batchEmbeddings,
705
+ completed: allEmbeddings.length,
706
+ total,
707
+ percent: allEmbeddings.length / total * 100
708
+ };
709
+ }
710
+ resolveResult({
711
+ embeddings: allEmbeddings,
712
+ usage: { totalTokens }
713
+ });
714
+ } catch (error) {
715
+ rejectResult(error);
716
+ throw error;
717
+ }
718
+ }
719
+ const generator = generate();
720
+ return {
721
+ [Symbol.asyncIterator]: () => generator,
722
+ result: resultPromise,
723
+ abort: () => abortController.abort()
724
+ };
725
+ }
726
+
581
727
  // src/core/image.ts
582
728
  import { readFile } from "fs/promises";
583
729
  var Image = class _Image {
@@ -1074,7 +1220,9 @@ var Thread = class _Thread {
1074
1220
  // src/index.ts
1075
1221
  var ai = {
1076
1222
  /** LLM instance factory */
1077
- llm
1223
+ llm,
1224
+ /** Embedding instance factory */
1225
+ embedding
1078
1226
  };
1079
1227
  export {
1080
1228
  AssistantMessage,
@@ -1099,6 +1247,7 @@ export {
1099
1247
  createProvider,
1100
1248
  createStreamResult,
1101
1249
  createTurn,
1250
+ embedding,
1102
1251
  emptyUsage,
1103
1252
  isAssistantMessage,
1104
1253
  isAudioBlock,