diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 70932712..a5e6a99a 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -12,6 +12,7 @@ env: WEAVIATE_135: 1.35.16 WEAVIATE_136: 1.36.10 WEAVIATE_137: 1.37.5 + WEAVIATE_138: 1.38.2 concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} @@ -44,8 +45,9 @@ jobs: { node: "24.x", weaviate: $WEAVIATE_134 }, { node: "24.x", weaviate: $WEAVIATE_135 }, { node: "24.x", weaviate: $WEAVIATE_136 }, - { node: "22.x", weaviate: $WEAVIATE_137 }, { node: "24.x", weaviate: $WEAVIATE_137 }, + { node: "22.x", weaviate: $WEAVIATE_138 }, + { node: "24.x", weaviate: $WEAVIATE_138 }, ] steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 @@ -75,7 +77,7 @@ jobs: strategy: fail-fast: false matrix: - versions: [{ node: "24.x", weaviate: $WEAVIATE_137 }] + versions: [{ node: "24.x", weaviate: $WEAVIATE_138 }] steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - uses: actions/setup-node@3235b876344d2a9aa001b8d1453c930bba69e610 # v3 diff --git a/src/collections/config/types/index.ts b/src/collections/config/types/index.ts index e82c4909..abe6e6ff 100644 --- a/src/collections/config/types/index.ts +++ b/src/collections/config/types/index.ts @@ -74,6 +74,8 @@ export type ReplicationDeletionStrategy = export type AsyncReplicationConfig = WeaviateAsyncReplicationConfig; export type ReplicationConfig = { + /** @deprecated From v1.38 onwards this setting is determined server-side + * and should be considered read-only.*/ asyncEnabled: boolean; asyncConfig?: AsyncReplicationConfig; deletionStrategy: ReplicationDeletionStrategy; diff --git a/src/collections/query/types.ts b/src/collections/query/types.ts index 62e5b95c..ff2e7683 100644 --- a/src/collections/query/types.ts +++ b/src/collections/query/types.ts @@ -1,5 +1,5 @@ import { FilterValue } from '../filters/index.js'; -import { CallOptions, MultiTargetVectorJoin, ReturnVectors } from '../index.js'; +import { BoostOptions, CallOptions, MultiTargetVectorJoin, ReturnVectors } from '../index.js'; import { Sorting } from '../sort/classes.js'; import { GroupByOptions, @@ -61,6 +61,8 @@ export type SearchOptions = { autoLimit?: number; /** The filters to be applied to the query. Use `weaviate.filter.*` to create filters */ filters?: FilterValue; + /** Promote search results based on a boosting function. */ + boost?: BoostOptions; /** How to rerank the query results. Requires a configured [reranking](https://weaviate.io/developers/weaviate/concepts/reranking) module. */ rerank?: RerankOptions; /** Whether to include the vector of the object in the response. If using named vectors, pass an array of strings to include only specific vectors. */ diff --git a/src/collections/query/utils.ts b/src/collections/query/utils.ts index a46334da..e6e6d215 100644 --- a/src/collections/query/utils.ts +++ b/src/collections/query/utils.ts @@ -1,4 +1,13 @@ -import { MultiTargetVectorJoin, Vectors } from '../index.js'; +import { WeaviateInvalidInputError } from '../../errors.js'; +import { + BoostOptions, + FilterValue, + MultiTargetVectorJoin, + NumericDecay, + PropertyValue, + TimeDecay, + Vectors, +} from '../index.js'; import { Bm25OperatorOptions, Bm25OperatorOr, @@ -67,6 +76,93 @@ export class TargetVectorInputGuards { } } +export class Boost { + static filter(filter: FilterValue, args?: Pick): BoostOptions { + return { + ...args, + conditions: [ + { + weight: args?.weight, + func: { + ...filter, + type: 'filter', + }, + }, + ], + }; + } + static timeDecay(args: Omit & Pick): BoostOptions { + const { weight, depth, ...func } = args; + return { + conditions: [ + { + weight, + func: { + ...func, + type: 'timeDecay', + }, + }, + ], + weight, + depth, + }; + } + static numericDecay( + args: Omit & Pick + ): BoostOptions { + const { weight, depth, ...func } = args; + return { + conditions: [ + { + weight, + func: { + ...func, + type: 'numericDecay', + }, + }, + ], + weight, + depth, + }; + } + static numericProperty( + args: Omit & Pick + ): BoostOptions { + const { weight, depth, ...func } = args; + return { + conditions: [ + { + weight, + func: { + ...func, + type: 'propertyValue', + }, + }, + ], + weight, + depth, + }; + } + static blend(boosts: BoostOptions[], options: Pick): BoostOptions { + const out: BoostOptions = { ...options, conditions: [] }; + for (const boost of boosts) { + if (boost.depth) { + throw new WeaviateInvalidInputError('A boost passed to Boost.blend() cannot set its own depth.'); + } + for (let cond of boost.conditions) { + if (!cond.weight && boost.weight) { + cond = { + ...cond, + weight: boost.weight, + }; + } + out.conditions.push({ ...cond }); + } + } + return out; + } +} + export class Bm25Operator { static and(): Bm25OperatorOptions { return { operator: 'And' }; diff --git a/src/collections/serialize/index.ts b/src/collections/serialize/index.ts index 04413230..67d59913 100644 --- a/src/collections/serialize/index.ts +++ b/src/collections/serialize/index.ts @@ -35,6 +35,13 @@ import { GenerativeSearch_Single, } from '../../proto/v1/generative.js'; import { + Boost as BoostGRPC, + Boost_Condition, + Boost_DecayCurve, + Boost_NumericDecayFunction, + Boost_PropertyValueFunction, + Boost_PropertyValueModifier, + Boost_TimeDecayFunction, GroupBy, MetadataRequest, ObjectPropertiesRequest, @@ -111,13 +118,19 @@ import { AggregateHybridOptions, AggregateNearOptions, BatchReference, + BoostOptions, + Curve, GenerativeConfigRuntime, GroupByAggregate, GroupedTask, + Modifier, MultiTargetVectorJoin, + NumericDecay, PrimitiveKeys, PropertiesMetrics, + PropertyValue, SinglePrompt, + TimeDecay, } from '../index.js'; import { BaseHybridOptions, @@ -649,6 +662,7 @@ class Search { limit: args?.limit, offset: args?.offset, filters: args?.filters ? Serialize.filtersGRPC(args.filters) : undefined, + boost: args?.boost ? Serialize.boostGRPC(args.boost) : undefined, properties: args?.returnProperties || args?.returnReferences ? Search.queryProperties(args.returnProperties, args.returnReferences) @@ -1544,6 +1558,84 @@ export class Serialize { }); }; + private static boostCurve(curve?: Curve): Boost_DecayCurve { + switch (curve) { + case 'exponential': + return Boost_DecayCurve.DECAY_CURVE_EXPONENTIAL; + case 'gaussian': + return Boost_DecayCurve.DECAY_CURVE_GAUSS; + case 'linear': + return Boost_DecayCurve.DECAY_CURVE_LINEAR; + default: + return Boost_DecayCurve.DECAY_CURVE_UNSPECIFIED; + } + } + + private static boostModifier(modifier?: Modifier): Boost_PropertyValueModifier { + switch (modifier) { + case 'log1p': + return Boost_PropertyValueModifier.PROPERTY_VALUE_MODIFIER_LOG1P; + case 'sqrt': + return Boost_PropertyValueModifier.PROPERTY_VALUE_MODIFIER_LOG1P; + default: + return Boost_PropertyValueModifier.PROPERTY_VALUE_MODIFIER_UNSPECIFIED; + } + } + + public static boostGRPC = (boost: BoostOptions): BoostGRPC => { + const out: BoostGRPC = { weight: boost.weight, depth: boost.depth, conditions: [] }; + for (const cond of boost.conditions) { + let condProto: Boost_Condition = { weight: cond.weight }; + const { type, ...func } = cond.func; + + switch (type) { + case 'filter': + condProto = { + ...condProto, + filter: this.filtersGRPC(func as FilterValue), + }; + break; + case 'timeDecay': { + const { curve, ...timeDecay } = func as TimeDecay; + condProto = { + ...condProto, + timeDecay: Boost_TimeDecayFunction.fromPartial({ + ...timeDecay, + curve: this.boostCurve(curve), + }), + }; + break; + } + case 'numericDecay': { + const { curve, ...numericDecay } = func as NumericDecay; + condProto = { + ...condProto, + numericDecay: Boost_NumericDecayFunction.fromPartial({ + ...numericDecay, + curve: this.boostCurve(curve), + }), + }; + break; + } + case 'propertyValue': { + const { modifier, ...propertyValue } = func as PropertyValue; + condProto = { + ...condProto, + propertyValue: Boost_PropertyValueFunction.fromPartial({ + ...propertyValue, + modifier: this.boostModifier(modifier), + }), + }; + break; + } + } + out.conditions.push(condProto); + } + + console.error(JSON.stringify(out)); + return out; + }; + public static filtersGRPC = (filters: FilterValue): FiltersGRPC => { const resolveFilters = (filters: FilterValue): FiltersGRPC[] => { const out: FiltersGRPC[] = []; diff --git a/src/collections/types/query.ts b/src/collections/types/query.ts index a257cc99..fa99b87b 100644 --- a/src/collections/types/query.ts +++ b/src/collections/types/query.ts @@ -1,4 +1,4 @@ -import { WeaviateField } from '../index.js'; +import { FilterValue, WeaviateField } from '../index.js'; import { PrimitiveVectorType } from '../query/types.js'; import { CrossReferenceDefault } from '../references/index.js'; import { @@ -189,3 +189,41 @@ export type SortBy = { property: string; ascending?: boolean; }; + +export type BoostOptions = { + conditions: { + func: TimeDecay | NumericDecay | PropertyValue | (FilterValue & { type: 'filter' }); + weight?: number; + }[]; + weight?: number; + depth?: number; +}; + +export type Curve = 'exponential' | 'gaussian' | 'linear'; +export type Modifier = 'log1p' | 'sqrt'; + +export type TimeDecay = { + property: string; + scale: string; + origin?: string; + offset?: string; + curve?: Curve; + decay?: number; + type: 'timeDecay'; +}; + +export type NumericDecay = { + property: string; + scale: number; + origin: number; + offset?: number; + curve?: Curve; + decay?: number; + type: 'numericDecay'; +}; + +export type PropertyValue = { + property: string; + modifier?: Modifier; + type: 'propertyValue'; +}; diff --git a/src/grpc/searcher.ts b/src/grpc/searcher.ts index 60f38cf4..e2172db3 100644 --- a/src/grpc/searcher.ts +++ b/src/grpc/searcher.ts @@ -16,6 +16,7 @@ import { NearVideoSearch, } from '../proto/v1/base_search.js'; import { + Boost, GroupBy, MetadataRequest, PropertiesRequest, @@ -50,6 +51,7 @@ export type BaseSearchArgs = { offset?: number; autocut?: number; filters?: Filters; + boost?: Boost; rerank?: Rerank; metadata?: MetadataRequest; properties?: PropertiesRequest; diff --git a/src/openapi/schema.ts b/src/openapi/schema.ts index 60144cb2..9d509b47 100644 --- a/src/openapi/schema.ts +++ b/src/openapi/schema.ts @@ -264,6 +264,14 @@ export interface paths { /** Adds a new property definition to an existing collection (`className`) definition. */ post: operations['schema.objects.properties.add']; }; + '/schema/{className}/indexes': { + /** Returns per-property index state including active reindex progress. This powers the UI to show live migration status. */ + get: operations['schema.objects.indexes.get']; + }; + '/schema/{className}/indexes/{propertyName}': { + /** Declaratively sets the desired index state for a property. The system computes the diff from the current state and triggers the appropriate reindex task. */ + put: operations['schema.objects.indexes.update']; + }; '/schema/{className}/properties/{propertyName}/index/{indexName}': { /** Deletes an inverted index of a specific property within a collection (`className`). The index to delete is identified by `indexName` and must be one of `filterable`, `searchable`, or `rangeFilters`. */ delete: operations['schema.objects.properties.delete']; @@ -314,6 +322,20 @@ export interface paths { /** Remove an existing alias from the system. This will delete the alias mapping but will not affect the underlying collection (class). */ delete: operations['aliases.delete']; }; + '/namespaces': { + /** Retrieve the list of all namespaces the caller has permission to see. Callers without any applicable `manage_namespaces` permission receive an empty list (never 403). */ + get: operations['listNamespaces']; + }; + '/namespaces/{namespace_id}': { + /** Retrieve details about a specific namespace by its name. */ + get: operations['getNamespace']; + /** Update a namespace's `home_node`. The new value applies to future placement decisions only (new collection create, new tenant create, tenant reactivation). Existing live shards are not moved. */ + put: operations['updateNamespace']; + /** Create a new cluster-level namespace with the given name. Names must contain only lowercase letters, digits, and hyphens, must start and end with a letter or digit, must be 3-36 characters long, and must not be a reserved name. */ + post: operations['createNamespace']; + /** Mark a namespace for deletion. The endpoint is asynchronous: the namespace is flipped to the "deleting" state and its dynamic users are removed synchronously; classes and aliases are torn down by the leader on a periodic cleanup tick. Repeated calls while the namespace is still in the "deleting" state are idempotent and return 202. */ + delete: operations['deleteNamespace']; + }; '/backups/{backend}': { /** List all created backups IDs, Status */ get: operations['backups.list']; @@ -424,6 +446,8 @@ export interface definitions { * @description Date and time in ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ. */ lastUsedAt?: unknown; + /** @description The namespace this user is bound to. Only populated for callers with global-operator privileges; omitted otherwise. */ + namespace?: string; }; UserApiKey: { /** @description The API key associated with the user. */ @@ -554,6 +578,14 @@ export interface definitions { */ alias?: string; }; + /** @description Resources applicable for namespace actions. */ + namespaces?: { + /** + * @description A string that specifies which namespaces this permission applies to. Can be an exact namespace name or a regex pattern. The default value `*` applies the permission to all namespaces. + * @default * + */ + namespace?: string; + }; /** * @description Allowed actions in weaviate. * @enum {string} @@ -595,7 +627,8 @@ export interface definitions { | 'read_groups' | 'create_mcp' | 'read_mcp' - | 'update_mcp'; + | 'update_mcp' + | 'manage_namespaces'; }; /** @description List of roles. */ RolesListResponse: definitions['Role'][]; @@ -614,6 +647,10 @@ export interface definitions { username?: string; groups?: string[]; userType?: definitions['UserTypeInput']; + /** @description The namespace this principal is bound to. Empty for global principals (e.g. static API keys). */ + namespace?: string; + /** @description True for principals that operate across all namespaces (e.g. static API keys). Authoritative marker for operator-level principals; do not infer from an empty namespace. */ + isGlobalOperator?: boolean; }; /** @description An array of available words and contexts. */ C11yWordsResponse: { @@ -697,6 +734,116 @@ export interface definitions { message?: string; }[]; }; + IndexStatusResponse: { + collection?: string; + properties?: definitions['PropertyIndexStatus'][]; + }; + PropertyIndexStatus: { + name?: string; + dataType?: string; + description?: string; + indexes?: definitions['IndexStatus'][]; + }; + IndexStatus: { + /** @enum {string} */ + type?: 'filterable' | 'searchable' | 'rangeable'; + /** @enum {string} */ + status?: 'ready' | 'indexing' | 'pending' | 'failed' | 'cancelled'; + /** Format: float */ + progress?: number; + tokenization?: string; + targetTokenization?: string; + /** + * @description BM25 algorithm currently backing this searchable index. 'wand' is the legacy map-based bucket strategy; 'blockmax' is the Block Max WAND inverted strategy. Only populated for `type=searchable` entries. Not populated for filterable or rangeable indexes. + * @enum {string} + */ + algorithm?: 'wand' | 'blockmax'; + /** + * @description BM25 algorithm this searchable index is being rebuilt onto. Populated only while an in-flight rebuild is changing the algorithm; mirrors `targetTokenization` for the change-tokenization verb. Today the only supported transition is wand -> blockmax. + * @enum {string} + */ + targetAlgorithm?: 'wand' | 'blockmax'; + }; + IndexUpdateRequest: { + searchable?: definitions['IndexUpdateSearchable']; + filterable?: definitions['IndexUpdateFilterable']; + rangeable?: definitions['IndexUpdateRangeable']; + }; + IndexUpdateSearchable: { + tokenization?: string; + /** @description When true, rebuilds the searchable index for this property from the stored objects. Preserves the current tokenization and BM25 algorithm. Only valid when the property's current algorithm is `blockmax`; on a WAND property the request is rejected with guidance to use `algorithm:"blockmax"` first. */ + rebuild?: boolean; + /** + * @description Switch the BM25 algorithm for this property's searchable index. Currently only `blockmax` is accepted. From WAND this triggers the Map → BlockMax migration; on an already-`blockmax` property the request is rejected. WAND is deprecated; downgrade is intentionally not supported. + * @enum {string} + */ + algorithm?: 'blockmax'; + enabled?: boolean; + /** @description When true, cancels the in-flight reindex task targeting this property's searchable index. The task transitions to CANCELLED; partial state is left on disk for the next-restart finalize. */ + cancel?: boolean; + }; + IndexUpdateFilterable: { + rebuild?: boolean; + enabled?: boolean; + /** @description Change the tokenization used by the filterable index on this text/text[] property. Only valid when the property already has a filterable index. Use this for filterable-only properties; for properties that ALSO have a searchable index, prefer searchable.tokenization since it retokenizes both buckets in a single coordinated migration. */ + tokenization?: string; + /** @description When true, cancels the in-flight reindex task targeting this property's filterable index. */ + cancel?: boolean; + }; + IndexUpdateRangeable: { + enabled?: boolean; + /** @description When true, rebuilds the rangeable index from the existing filterable bucket (same source-of-truth as enable-rangeable). */ + rebuild?: boolean; + /** @description When true, cancels the in-flight reindex task targeting this property's rangeable index. */ + cancel?: boolean; + }; + IndexUpdateResponse: { + taskId?: string; + status?: string; + }; + /** @description Returned with HTTP 429 when a configured Weaviate usage limit (objects/collections/tenants/shards) is exceeded. The structured fields (`errorCode`, `limit`, `value`) are stable contract; the `message` text is operator-overridable via the `USAGE_LIMITS_ERROR_MESSAGE` template. */ + UsageLimitExceededResponse: { + /** + * @description Machine-stable identifier. Always `USAGE_LIMIT_EXCEEDED` for this response. + * @enum {string} + */ + errorCode?: 'USAGE_LIMIT_EXCEEDED'; + /** + * @description Which limit was hit. + * @enum {string} + */ + limit?: 'objects' | 'collections' | 'tenants' | 'shards'; + /** + * Format: int64 + * @description The configured threshold value (the cap, not the current count). + */ + value?: number; + /** @description Human-readable message rendered from the `USAGE_LIMITS_ERROR_MESSAGE` template with `{limit}` and `{value}` placeholders substituted. */ + message?: string; + }; + /** @description Returned with HTTP 422 from class create/update endpoints. For restriction violations (operator-disallowed config via ALLOWED_VECTOR_INDEX_TYPES or ALLOWED_COMPRESSION_TYPES) the structured fields (`errorCode`, `restriction`, `value`, `allowed`, `message`) are populated; the `message` text is rendered from the operator-overridable `RESTRICTIONS_ERROR_MESSAGE` template. For unrelated 422 errors the `error` array is populated (matching the legacy ErrorResponse shape) and the structured fields are omitted. */ + RestrictionViolationResponse: { + /** @description Legacy ErrorResponse-style error list, populated for non-restriction 422 errors. */ + error?: { + message?: string; + }[]; + /** + * @description Machine-stable identifier. Set to `CONFIG_NOT_ALLOWED` for restriction violations; omitted otherwise. + * @enum {string} + */ + errorCode?: 'CONFIG_NOT_ALLOWED'; + /** + * @description Which restriction was violated. + * @enum {string} + */ + restriction?: 'vector_index_type' | 'compression'; + /** @description The disallowed value the client submitted. */ + value?: string; + /** @description The operator-configured allow-list. */ + allowed?: string[]; + /** @description Human-readable message rendered from the `RESTRICTIONS_ERROR_MESSAGE` template with `{restriction}`, `{value}`, `{allowed}` placeholders substituted. */ + message?: string; + }; /** @description Request to create a new export operation */ ExportCreateRequest: { /** @description Unique identifier for this export. Must be URL-safe. */ @@ -843,8 +990,6 @@ export interface definitions { ReplicationConfig: { /** @description Number of times a collection (class) is replicated (default: 1). */ factor?: number; - /** @description Enable asynchronous replication (default: `false`). */ - asyncEnabled?: boolean; /** @description Configuration parameters for asynchronous replication. */ asyncConfig?: definitions['ReplicationAsyncConfig']; /** @@ -1049,7 +1194,7 @@ export interface definitions { * @description The current operational state of the replica during the replication process. * @enum {string} */ - state?: 'REGISTERED' | 'HYDRATING' | 'FINALIZING' | 'DEHYDRATING' | 'READY' | 'CANCELLED'; + state?: 'REGISTERED' | 'HYDRATING' | 'FINALIZING' | 'INTEGRATING' | 'DEHYDRATING' | 'READY' | 'CANCELLED'; /** * Format: int64 * @description The UNIX timestamp in ms when this state was first entered. This is an approximate time and so should not be used for precise timing. @@ -1188,6 +1333,11 @@ export interface definitions { name?: string; /** @description (Deprecated). Whether to include this property in the inverted index. If `false`, this property cannot be used in `where` filters, `bm25` or `hybrid` search.

Unrelated to vectorization behavior (deprecated as of v1.19; use indexFilterable or/and indexSearchable instead) */ indexInverted?: boolean; + /** + * Format: int64 + * @description Internal RAFT-replicated counter bumped by semantic runtime-reindex migrations (e.g. change-tokenization, enable-filterable, enable-searchable). Used by the data path to resolve the property's inverted-index bucket name; a single RAFT commit flipping the schema flag AND bumping this counter atomically cuts the cluster from the old bucket to the new one. Defaults to 0. Internal use; clients should not set this. + */ + bucketGeneration?: number; /** @description Whether to include this property in the filterable, Roaring Bitmap index. If `false`, this property cannot be used in `where` filters.

Note: Unrelated to vectorization behavior. */ indexFilterable?: boolean; /** @description Optional. Should this property be indexed in the inverted index. Defaults to true. Applicable only to properties of data type text and text[]. If you choose false, you will not be able to use this property in bm25 or hybrid search. This property has no affect on vectorization decisions done by modules */ @@ -1217,11 +1367,11 @@ export interface definitions { disableDuplicatedReferences?: boolean; textAnalyzer?: definitions['TextAnalyzerConfig']; }; - /** @description Text analysis options for a property. The asciiFold setting is immutable after creation, while the asciiFoldIgnore list can be updated later; changes to asciiFoldIgnore only affect newly indexed data and do not retroactively re-index existing data. Applies only to text and text[] data types that use an inverted index (searchable or filterable). */ + /** @description Text analysis options for a property. These settings are immutable after the property is created. Applies only to text and text[] data types that use an inverted index (searchable or filterable). */ TextAnalyzerConfig: { /** @description If true, accent/diacritic marks are folded to their base characters during indexing and search. For example, 'école' matches 'ecole'. Defaults to false. */ asciiFold?: boolean; - /** @description If provided, specifies a list of characters that should be excluded from ascii folding. For example, if ['é'] is provided, then 'é' will not be folded to 'e' during indexing and search. This list can be updated after the property is created, but updates only affect documents indexed after the change. */ + /** @description If provided, specifies a list of characters that should be excluded from ascii folding. For example, if ['é'] is provided, then 'é' will not be folded to 'e' during indexing and search. This list is immutable after the property is created. */ asciiFoldIgnore?: string[]; /** @description Stopword preset name. Overrides the collection-level invertedIndexConfig.stopwords for this property. Only applies to properties using 'word' tokenization. Can be a built-in preset ('en', 'none') or a user-defined preset from invertedIndexConfig.stopwordPresets. */ stopwordPreset?: string; @@ -1311,6 +1461,8 @@ export interface definitions { * @description Size of the backup in Gibs */ size?: number; + /** @description The ID of the base backup this incremental backup was built on; empty if the backup is not incremental. */ + incremental_base_backup_id?: string; }; /** @description The definition of a backup restore metadata. */ BackupRestoreStatusResponse: { @@ -1471,6 +1623,8 @@ export interface definitions { * @description Size of the backup in Gibs */ size?: number; + /** @description The ID of the base backup this incremental backup was built on; empty if the backup is not incremental. */ + incremental_base_backup_id?: string; }[]; /** @description Request body for restoring a backup for a set of collections (classes). */ BackupRestoreRequest: { @@ -2306,6 +2460,30 @@ export interface definitions { /** @description Array of alias objects, each containing an alias-to-collection mapping. */ aliases?: definitions['Alias'][]; }; + /** @description A cluster-level namespace used to group resources under a common administrative unit. Namespace names must contain only lowercase letters, digits, and hyphens, must start and end with a letter or digit, must be 3-36 characters long, and must not be a reserved name. */ + Namespace: { + /** @description The unique name of the namespace. */ + name?: string; + /** @description The cluster node where this namespace's shards are placed. Set at create time and updatable later. Updating it only affects future placement decisions; existing live shards are not moved. */ + home_node?: string; + /** + * @description Lifecycle state. "active" namespaces accept all operations. "deleting" namespaces are being removed: new classes, aliases, and users can no longer be created in the namespace, and the namespace itself disappears once removal completes. + * @enum {string} + */ + state?: 'active' | 'deleting'; + }; + /** @description Optional body for namespace creation. When `home_node` is omitted, the cluster picks one automatically. */ + NamespaceCreateRequest: { + /** @description Optional. Cluster node to place this namespace's shards on. Must be a current storage candidate. When omitted, the cluster picks one. */ + home_node?: string; + }; + /** @description Update payload for an existing namespace. */ + NamespaceUpdateRequest: { + /** @description Cluster node to use for future placements in this namespace. Must be a current storage candidate. Existing live shards are not moved. */ + home_node: string; + }; + /** @description Response object containing a list of namespaces. */ + NamespaceListResponse: definitions['Namespace'][]; } export interface parameters { @@ -3273,6 +3451,10 @@ export interface operations { }; /** No role found. */ 404: unknown; + /** Endpoint not available in the current cluster configuration. */ + 410: { + schema: definitions['ErrorResponse']; + }; /** An error has occurred while trying to fulfill the request. Most likely the ErrorResponse will contain more information about the error. */ 500: { schema: definitions['ErrorResponse']; @@ -3376,6 +3558,10 @@ export interface operations { }; /** No roles found for specified user. */ 404: unknown; + /** Endpoint not available in the current cluster configuration. */ + 410: { + schema: definitions['ErrorResponse']; + }; /** The request syntax is correct, but the server couldn't process it due to semantic issues. Please check the values in your request. */ 422: { schema: definitions['ErrorResponse']; @@ -3688,6 +3874,10 @@ export interface operations { }; /** Successful query result but no matching objects were found. */ 404: unknown; + /** Endpoint not available in the current cluster configuration. */ + 410: { + schema: definitions['ErrorResponse']; + }; /** The request syntax is correct, but the server couldn't process it due to semantic issues. Please check the values in your request. Ensure the specified collection exists. */ 422: { schema: definitions['ErrorResponse']; @@ -3729,6 +3919,10 @@ export interface operations { 422: { schema: definitions['ErrorResponse']; }; + /** The configured object-count usage limit was exceeded. See `UsageLimitExceededResponse` for the limit value. */ + 429: { + schema: definitions['UsageLimitExceededResponse']; + }; /** An error occurred while trying to fulfill the request. Check the ErrorResponse for details. */ 500: { schema: definitions['ErrorResponse']; @@ -3764,6 +3958,10 @@ export interface operations { }; /** Object not found. */ 404: unknown; + /** Endpoint not available in the current cluster configuration. */ + 410: { + schema: definitions['ErrorResponse']; + }; /** An error occurred while trying to fulfill the request. Check the ErrorResponse for details. */ 500: { schema: definitions['ErrorResponse']; @@ -3799,6 +3997,10 @@ export interface operations { }; /** Object not found. */ 404: unknown; + /** Endpoint not available in the current cluster configuration. */ + 410: { + schema: definitions['ErrorResponse']; + }; /** The request syntax is correct, but the server couldn't process it due to semantic issues. Please check the values in your request. Ensure the collection exists and the object properties are valid. */ 422: { schema: definitions['ErrorResponse']; @@ -3834,6 +4036,10 @@ export interface operations { }; /** Object not found. */ 404: unknown; + /** Endpoint not available in the current cluster configuration. */ + 410: { + schema: definitions['ErrorResponse']; + }; /** An error occurred while trying to fulfill the request. Check the ErrorResponse for details. */ 500: { schema: definitions['ErrorResponse']; @@ -3859,6 +4065,10 @@ export interface operations { }; /** Object does not exist. */ 404: unknown; + /** Endpoint not available in the current cluster configuration. */ + 410: { + schema: definitions['ErrorResponse']; + }; /** An error occurred while trying to fulfill the request. Check the ErrorResponse for details. */ 500: { schema: definitions['ErrorResponse']; @@ -3894,6 +4104,10 @@ export interface operations { }; /** Object not found. */ 404: unknown; + /** Endpoint not available in the current cluster configuration. */ + 410: { + schema: definitions['ErrorResponse']; + }; /** The patch object is valid JSON but is unprocessable for other reasons (e.g., invalid schema). */ 422: { schema: definitions['ErrorResponse']; @@ -3986,6 +4200,10 @@ export interface operations { 422: { schema: definitions['ErrorResponse']; }; + /** The configured object-count usage limit was exceeded. See `UsageLimitExceededResponse` for the limit value. */ + 429: { + schema: definitions['UsageLimitExceededResponse']; + }; /** An error occurred while trying to fulfill the request. Check the ErrorResponse for details. */ 500: { schema: definitions['ErrorResponse']; @@ -4140,6 +4358,10 @@ export interface operations { 403: { schema: definitions['ErrorResponse']; }; + /** Endpoint not available in the current cluster configuration. */ + 410: { + schema: definitions['ErrorResponse']; + }; /** The request syntax is correct, but the server couldn't process it due to semantic issues. Please check the values in your request. Ensure the property exists and is a reference type. */ 422: { schema: definitions['ErrorResponse']; @@ -4177,6 +4399,10 @@ export interface operations { 403: { schema: definitions['ErrorResponse']; }; + /** Endpoint not available in the current cluster configuration. */ + 410: { + schema: definitions['ErrorResponse']; + }; /** The request syntax is correct, but the server couldn't process it due to semantic issues. Please check the values in your request. Ensure the property exists and is a reference type. */ 422: { schema: definitions['ErrorResponse']; @@ -4218,6 +4444,10 @@ export interface operations { 404: { schema: definitions['ErrorResponse']; }; + /** Endpoint not available in the current cluster configuration. */ + 410: { + schema: definitions['ErrorResponse']; + }; /** An error occurred while trying to fulfill the request. Check the ErrorResponse for details. */ 500: { schema: definitions['ErrorResponse']; @@ -4261,6 +4491,10 @@ export interface operations { }; /** Source object not found. */ 404: unknown; + /** Endpoint not available in the current cluster configuration. */ + 410: { + schema: definitions['ErrorResponse']; + }; /** The request syntax is correct, but the server couldn't process it due to semantic issues. Please check the values in your request. Ensure the property exists and is a reference type. */ 422: { schema: definitions['ErrorResponse']; @@ -4308,6 +4542,10 @@ export interface operations { }; /** Source object not found. */ 404: unknown; + /** Endpoint not available in the current cluster configuration. */ + 410: { + schema: definitions['ErrorResponse']; + }; /** The request syntax is correct, but the server couldn't process it due to semantic issues. Please check the values in your request. Ensure the property exists and is a reference type. */ 422: { schema: definitions['ErrorResponse']; @@ -4357,6 +4595,10 @@ export interface operations { 404: { schema: definitions['ErrorResponse']; }; + /** Endpoint not available in the current cluster configuration. */ + 410: { + schema: definitions['ErrorResponse']; + }; /** The request syntax is correct, but the server couldn't process it due to semantic issues. Please check the values in your request. Ensure the property exists and is a reference type. */ 422: { schema: definitions['ErrorResponse']; @@ -4430,6 +4672,10 @@ export interface operations { 422: { schema: definitions['ErrorResponse']; }; + /** The configured object-count usage limit was exceeded. The whole batch is rejected (no partial fill); the client decides what to retry. See `UsageLimitExceededResponse` for the limit value. */ + 429: { + schema: definitions['UsageLimitExceededResponse']; + }; /** An error occurred while trying to fulfill the request. Check the ErrorResponse for details. */ 500: { schema: definitions['ErrorResponse']; @@ -4531,6 +4777,10 @@ export interface operations { 403: { schema: definitions['ErrorResponse']; }; + /** Endpoint not available in the current cluster configuration. */ + 410: { + schema: definitions['ErrorResponse']; + }; /** The request syntax is correct, but the server couldn't process it due to semantic issues. Please check the values in your request. */ 422: { schema: definitions['ErrorResponse']; @@ -4560,6 +4810,10 @@ export interface operations { 403: { schema: definitions['ErrorResponse']; }; + /** Endpoint not available in the current cluster configuration. */ + 410: { + schema: definitions['ErrorResponse']; + }; /** The request syntax is correct, but the server couldn't process it due to semantic issues. Please check the values in your request. */ 422: { schema: definitions['ErrorResponse']; @@ -4665,7 +4919,11 @@ export interface operations { }; /** Invalid collection definition provided. Check the definition structure and properties. */ 422: { - schema: definitions['ErrorResponse']; + schema: definitions['RestrictionViolationResponse']; + }; + /** A configured usage limit (collections/shards) was exceeded. See the `UsageLimitExceededResponse` body for which limit and the configured value. */ + 429: { + schema: definitions['UsageLimitExceededResponse']; }; /** An error occurred during collection creation. Check the ErrorResponse for details. */ 500: { @@ -4698,6 +4956,10 @@ export interface operations { }; /** Collection not found. */ 404: unknown; + /** Invalid collection name provided (e.g. malformed namespace prefix). Check the ErrorResponse for details. */ + 422: { + schema: definitions['ErrorResponse']; + }; /** An error occurred while retrieving the collection definition. Check the ErrorResponse for details. */ 500: { schema: definitions['ErrorResponse']; @@ -4733,7 +4995,7 @@ export interface operations { }; /** Invalid update attempt. */ 422: { - schema: definitions['ErrorResponse']; + schema: definitions['RestrictionViolationResponse']; }; /** An error occurred while updating the collection. Check the ErrorResponse for details. */ 500: { @@ -4793,7 +5055,7 @@ export interface operations { }; /** Invalid property definition provided. */ 422: { - schema: definitions['ErrorResponse']; + schema: definitions['RestrictionViolationResponse']; }; /** An error occurred while adding the property. Check the ErrorResponse for details. */ 500: { @@ -4801,6 +5063,80 @@ export interface operations { }; }; }; + /** Returns per-property index state including active reindex progress. This powers the UI to show live migration status. */ + 'schema.objects.indexes.get': { + parameters: { + path: { + className: string; + }; + }; + responses: { + /** Index status for all properties. */ + 200: { + schema: definitions['IndexStatusResponse']; + }; + /** Unauthorized or invalid credentials. */ + 401: unknown; + /** Forbidden */ + 403: { + schema: definitions['ErrorResponse']; + }; + /** Collection not found. */ + 404: unknown; + /** An error occurred. */ + 500: { + schema: definitions['ErrorResponse']; + }; + }; + }; + /** Declaratively sets the desired index state for a property. The system computes the diff from the current state and triggers the appropriate reindex task. */ + 'schema.objects.indexes.update': { + parameters: { + path: { + className: string; + propertyName: string; + }; + query: { + /** Tenant names to target. Only for non-semantic operations on multi-tenant collections. Omit to target all tenants. */ + tenants?: string[]; + }; + body: { + body: definitions['IndexUpdateRequest']; + }; + }; + responses: { + /** Reindex task submitted. */ + 202: { + schema: definitions['IndexUpdateResponse']; + }; + /** Invalid request. */ + 400: { + schema: definitions['ErrorResponse']; + }; + /** Unauthorized or invalid credentials. */ + 401: unknown; + /** Forbidden */ + 403: { + schema: definitions['ErrorResponse']; + }; + /** Collection or property not found. cancel:true with nothing to cancel returns 202 with Status: NO_OP instead — 404 is reserved for missing collection/property. */ + 404: { + schema: definitions['ErrorResponse']; + }; + /** Conflicting reindex task already running. */ + 409: { + schema: definitions['ErrorResponse']; + }; + /** An error occurred. */ + 500: { + schema: definitions['ErrorResponse']; + }; + /** Distributed tasks not enabled. */ + 503: { + schema: definitions['ErrorResponse']; + }; + }; + }; /** Deletes an inverted index of a specific property within a collection (`className`). The index to delete is identified by `indexName` and must be one of `filterable`, `searchable`, or `rangeFilters`. */ 'schema.objects.properties.delete': { parameters: { @@ -5064,6 +5400,10 @@ export interface operations { 422: { schema: definitions['ErrorResponse']; }; + /** The configured tenant-per-collection usage limit was exceeded. See `UsageLimitExceededResponse` for the limit value. */ + 429: { + schema: definitions['UsageLimitExceededResponse']; + }; /** An error occurred while creating tenants. Check the ErrorResponse for details. */ 500: { schema: definitions['ErrorResponse']; @@ -5330,6 +5670,175 @@ export interface operations { }; }; }; + /** Retrieve the list of all namespaces the caller has permission to see. Callers without any applicable `manage_namespaces` permission receive an empty list (never 403). */ + listNamespaces: { + responses: { + /** Successfully retrieved the list of namespaces (possibly empty). */ + 200: { + schema: definitions['NamespaceListResponse']; + }; + /** Unauthorized or invalid credentials. */ + 401: unknown; + /** Not Found - The namespaces feature is not enabled on this cluster. */ + 404: { + schema: definitions['ErrorResponse']; + }; + /** The request syntax is correct, but the server couldn't process it. */ + 422: { + schema: definitions['ErrorResponse']; + }; + /** An error has occurred while trying to fulfill the request. Most likely the ErrorResponse will contain more information about the error. */ + 500: { + schema: definitions['ErrorResponse']; + }; + }; + }; + /** Retrieve details about a specific namespace by its name. */ + getNamespace: { + parameters: { + path: { + /** The name of the namespace. */ + namespace_id: string; + }; + }; + responses: { + /** Successfully retrieved the namespace. */ + 200: { + schema: definitions['Namespace']; + }; + /** Unauthorized or invalid credentials. */ + 401: unknown; + /** Forbidden */ + 403: { + schema: definitions['ErrorResponse']; + }; + /** Not Found - Namespace does not exist, or the namespaces feature is not enabled on this cluster. */ + 404: { + schema: definitions['ErrorResponse']; + }; + /** The request syntax is correct, but the server couldn't process it due to semantic issues (e.g. invalid name format or reserved name). */ + 422: { + schema: definitions['ErrorResponse']; + }; + /** An error has occurred while trying to fulfill the request. Most likely the ErrorResponse will contain more information about the error. */ + 500: { + schema: definitions['ErrorResponse']; + }; + }; + }; + /** Update a namespace's `home_node`. The new value applies to future placement decisions only (new collection create, new tenant create, tenant reactivation). Existing live shards are not moved. */ + updateNamespace: { + parameters: { + path: { + /** The name of the namespace. */ + namespace_id: string; + }; + body: { + /** Required body. `home_node` is the new placement target. */ + body: definitions['NamespaceUpdateRequest']; + }; + }; + responses: { + /** Namespace updated successfully. */ + 200: { + schema: definitions['Namespace']; + }; + /** Unauthorized or invalid credentials. */ + 401: unknown; + /** Forbidden */ + 403: { + schema: definitions['ErrorResponse']; + }; + /** Not Found - Namespace does not exist, or the namespaces feature is not enabled on this cluster. */ + 404: { + schema: definitions['ErrorResponse']; + }; + /** The namespace is being deleted; `home_node` cannot be updated while the namespace is in the `deleting` state. */ + 409: { + schema: definitions['ErrorResponse']; + }; + /** The request syntax is correct, but the server couldn't process it due to semantic issues (e.g. invalid name format, reserved name, or unknown home_node). */ + 422: { + schema: definitions['ErrorResponse']; + }; + /** An error has occurred while trying to fulfill the request. Most likely the ErrorResponse will contain more information about the error. */ + 500: { + schema: definitions['ErrorResponse']; + }; + }; + }; + /** Create a new cluster-level namespace with the given name. Names must contain only lowercase letters, digits, and hyphens, must start and end with a letter or digit, must be 3-36 characters long, and must not be a reserved name. */ + createNamespace: { + parameters: { + path: { + /** The name of the namespace. Must start with a lowercase letter, contain only lowercase letters and digits, length 3-36, and not be a reserved name. */ + namespace_id: string; + }; + body: { + /** Optional body. When omitted, `home_node` is picked automatically. */ + body?: definitions['NamespaceCreateRequest']; + }; + }; + responses: { + /** Namespace created successfully. */ + 201: { + schema: definitions['Namespace']; + }; + /** Unauthorized or invalid credentials. */ + 401: unknown; + /** Forbidden */ + 403: { + schema: definitions['ErrorResponse']; + }; + /** Not Found - The namespaces feature is not enabled on this cluster. */ + 404: { + schema: definitions['ErrorResponse']; + }; + /** A namespace with the specified name already exists, or a namespace with the same name is currently being deleted. Differentiate by reading the human-readable message in the error payload. */ + 409: { + schema: definitions['ErrorResponse']; + }; + /** The request syntax is correct, but the server couldn't process it due to semantic issues (e.g. invalid name format or reserved name). */ + 422: { + schema: definitions['ErrorResponse']; + }; + /** An error has occurred while trying to fulfill the request. Most likely the ErrorResponse will contain more information about the error. */ + 500: { + schema: definitions['ErrorResponse']; + }; + }; + }; + /** Mark a namespace for deletion. The endpoint is asynchronous: the namespace is flipped to the "deleting" state and its dynamic users are removed synchronously; classes and aliases are torn down by the leader on a periodic cleanup tick. Repeated calls while the namespace is still in the "deleting" state are idempotent and return 202. */ + deleteNamespace: { + parameters: { + path: { + /** The name of the namespace. */ + namespace_id: string; + }; + }; + responses: { + /** The namespace has been marked for deletion. Cleanup of its classes, aliases, and users completes asynchronously. */ + 202: unknown; + /** Unauthorized or invalid credentials. */ + 401: unknown; + /** Forbidden */ + 403: { + schema: definitions['ErrorResponse']; + }; + /** Not Found - Namespace does not exist, or the namespaces feature is not enabled on this cluster. */ + 404: { + schema: definitions['ErrorResponse']; + }; + /** The request syntax is correct, but the server couldn't process it due to semantic issues (e.g. invalid name format or reserved name). */ + 422: { + schema: definitions['ErrorResponse']; + }; + /** An error has occurred while trying to fulfill the request. Most likely the ErrorResponse will contain more information about the error. */ + 500: { + schema: definitions['ErrorResponse']; + }; + }; + }; /** List all created backups IDs, Status */ 'backups.list': { parameters: { @@ -5824,6 +6333,10 @@ export interface operations { 403: { schema: definitions['ErrorResponse']; }; + /** Endpoint not available in the current cluster configuration. */ + 410: { + schema: definitions['ErrorResponse']; + }; /** An internal server error occurred while starting the classification task. Check the ErrorResponse for details. */ 500: { schema: definitions['ErrorResponse']; @@ -5851,6 +6364,10 @@ export interface operations { }; /** Classification with the given ID not found. */ 404: unknown; + /** Endpoint not available in the current cluster configuration. */ + 410: { + schema: definitions['ErrorResponse']; + }; /** An internal server error occurred while retrieving the classification status. Check the ErrorResponse for details. */ 500: { schema: definitions['ErrorResponse']; diff --git a/src/openapi/types.ts b/src/openapi/types.ts index 010ed717..4cecdcfc 100644 --- a/src/openapi/types.ts +++ b/src/openapi/types.ts @@ -40,8 +40,14 @@ export type Classification = definitions['Classification']; // GraphQL export type WhereFilter = definitions['WhereFilter']; // Schema +// This PR upstream https://github.com/weaviate/weaviate/pull/11214 removes asyncEnabled parameter, +// but the server continues to emit it for backwards compatibility. +// We can't change the auto-generated schema.js file, so we'll just extend it here. export type WeaviateSchema = definitions['Schema']; -export type WeaviateClass = definitions['Class']; +export type WeaviateReplicationConfig = definitions['Class']['replicationConfig'] & { asyncEnabled: boolean }; +export type WeaviateClass = Omit & { + replicationConfig?: WeaviateReplicationConfig; +}; export type WeaviateProperty = definitions['Property']; export type WeaviateNestedProperty = definitions['NestedProperty']; export type ShardStatus = definitions['ShardStatus']; @@ -54,7 +60,6 @@ export type WeaviateBM25Config = definitions['BM25Config']; export type WeaviateStopwordConfig = definitions['StopwordConfig']; export type WeaviateMultiTenancyConfig = WeaviateClass['multiTenancyConfig']; export type WeaviateObjectTTLConfig = WeaviateClass['objectTtlConfig']; -export type WeaviateReplicationConfig = WeaviateClass['replicationConfig']; export type WeaviateShardingConfig = WeaviateClass['shardingConfig']; export type WeaviateShardStatus = definitions['ShardStatusGetResponse']; export type WeaviateVectorIndexConfig = WeaviateClass['vectorIndexConfig']; diff --git a/src/proto/v1/generative.ts b/src/proto/v1/generative.ts index 5214412b..bd228463 100644 --- a/src/proto/v1/generative.ts +++ b/src/proto/v1/generative.ts @@ -55,6 +55,7 @@ export interface GenerativeProvider { nvidia?: GenerativeNvidia | undefined; xai?: GenerativeXAI | undefined; contextualai?: GenerativeContextualAI | undefined; + deepseek?: GenerativeDeepseek | undefined; } export interface GenerativeAnthropic { @@ -253,6 +254,7 @@ export interface GenerativeGoogle { region?: string | undefined; images?: TextArray | undefined; imageProperties?: TextArray | undefined; + location?: string | undefined; } export interface GenerativeDatabricks { @@ -306,6 +308,17 @@ export interface GenerativeContextualAI { knowledge?: TextArray | undefined; } +export interface GenerativeDeepseek { + baseUrl?: string | undefined; + model?: string | undefined; + temperature?: number | undefined; + maxTokens?: number | undefined; + frequencyPenalty?: number | undefined; + presencePenalty?: number | undefined; + topP?: number | undefined; + stop?: TextArray | undefined; +} + export interface GenerativeAnthropicMetadata { usage: GenerativeAnthropicMetadata_Usage | undefined; } @@ -437,6 +450,16 @@ export interface GenerativeXAIMetadata_Usage { totalTokens?: number | undefined; } +export interface GenerativeDeepseekMetadata { + usage?: GenerativeDeepseekMetadata_Usage | undefined; +} + +export interface GenerativeDeepseekMetadata_Usage { + promptTokens?: number | undefined; + completionTokens?: number | undefined; + totalTokens?: number | undefined; +} + export interface GenerativeMetadata { anthropic?: GenerativeAnthropicMetadata | undefined; anyscale?: GenerativeAnyscaleMetadata | undefined; @@ -451,6 +474,7 @@ export interface GenerativeMetadata { friendliai?: GenerativeFriendliAIMetadata | undefined; nvidia?: GenerativeNvidiaMetadata | undefined; xai?: GenerativeXAIMetadata | undefined; + deepseek?: GenerativeDeepseekMetadata | undefined; } export interface GenerativeReply { @@ -814,6 +838,7 @@ function createBaseGenerativeProvider(): GenerativeProvider { nvidia: undefined, xai: undefined, contextualai: undefined, + deepseek: undefined, }; } @@ -864,6 +889,9 @@ export const GenerativeProvider = { if (message.contextualai !== undefined) { GenerativeContextualAI.encode(message.contextualai, writer.uint32(122).fork()).ldelim(); } + if (message.deepseek !== undefined) { + GenerativeDeepseek.encode(message.deepseek, writer.uint32(130).fork()).ldelim(); + } return writer; }, @@ -979,6 +1007,13 @@ export const GenerativeProvider = { message.contextualai = GenerativeContextualAI.decode(reader, reader.uint32()); continue; + case 16: + if (tag !== 130) { + break; + } + + message.deepseek = GenerativeDeepseek.decode(reader, reader.uint32()); + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -1005,6 +1040,7 @@ export const GenerativeProvider = { nvidia: isSet(object.nvidia) ? GenerativeNvidia.fromJSON(object.nvidia) : undefined, xai: isSet(object.xai) ? GenerativeXAI.fromJSON(object.xai) : undefined, contextualai: isSet(object.contextualai) ? GenerativeContextualAI.fromJSON(object.contextualai) : undefined, + deepseek: isSet(object.deepseek) ? GenerativeDeepseek.fromJSON(object.deepseek) : undefined, }; }, @@ -1055,6 +1091,9 @@ export const GenerativeProvider = { if (message.contextualai !== undefined) { obj.contextualai = GenerativeContextualAI.toJSON(message.contextualai); } + if (message.deepseek !== undefined) { + obj.deepseek = GenerativeDeepseek.toJSON(message.deepseek); + } return obj; }, @@ -1102,6 +1141,9 @@ export const GenerativeProvider = { message.contextualai = (object.contextualai !== undefined && object.contextualai !== null) ? GenerativeContextualAI.fromPartial(object.contextualai) : undefined; + message.deepseek = (object.deepseek !== undefined && object.deepseek !== null) + ? GenerativeDeepseek.fromPartial(object.deepseek) + : undefined; return message; }, }; @@ -2474,6 +2516,7 @@ function createBaseGenerativeGoogle(): GenerativeGoogle { region: undefined, images: undefined, imageProperties: undefined, + location: undefined, }; } @@ -2521,6 +2564,9 @@ export const GenerativeGoogle = { if (message.imageProperties !== undefined) { TextArray.encode(message.imageProperties, writer.uint32(114).fork()).ldelim(); } + if (message.location !== undefined) { + writer.uint32(122).string(message.location); + } return writer; }, @@ -2629,6 +2675,13 @@ export const GenerativeGoogle = { message.imageProperties = TextArray.decode(reader, reader.uint32()); continue; + case 15: + if (tag !== 122) { + break; + } + + message.location = reader.string(); + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -2654,6 +2707,7 @@ export const GenerativeGoogle = { region: isSet(object.region) ? globalThis.String(object.region) : undefined, images: isSet(object.images) ? TextArray.fromJSON(object.images) : undefined, imageProperties: isSet(object.imageProperties) ? TextArray.fromJSON(object.imageProperties) : undefined, + location: isSet(object.location) ? globalThis.String(object.location) : undefined, }; }, @@ -2701,6 +2755,9 @@ export const GenerativeGoogle = { if (message.imageProperties !== undefined) { obj.imageProperties = TextArray.toJSON(message.imageProperties); } + if (message.location !== undefined) { + obj.location = message.location; + } return obj; }, @@ -2729,6 +2786,7 @@ export const GenerativeGoogle = { message.imageProperties = (object.imageProperties !== undefined && object.imageProperties !== null) ? TextArray.fromPartial(object.imageProperties) : undefined; + message.location = object.location ?? undefined; return message; }, }; @@ -3534,6 +3592,179 @@ export const GenerativeContextualAI = { }, }; +function createBaseGenerativeDeepseek(): GenerativeDeepseek { + return { + baseUrl: undefined, + model: undefined, + temperature: undefined, + maxTokens: undefined, + frequencyPenalty: undefined, + presencePenalty: undefined, + topP: undefined, + stop: undefined, + }; +} + +export const GenerativeDeepseek = { + encode(message: GenerativeDeepseek, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.baseUrl !== undefined) { + writer.uint32(10).string(message.baseUrl); + } + if (message.model !== undefined) { + writer.uint32(18).string(message.model); + } + if (message.temperature !== undefined) { + writer.uint32(25).double(message.temperature); + } + if (message.maxTokens !== undefined) { + writer.uint32(32).int64(message.maxTokens); + } + if (message.frequencyPenalty !== undefined) { + writer.uint32(41).double(message.frequencyPenalty); + } + if (message.presencePenalty !== undefined) { + writer.uint32(49).double(message.presencePenalty); + } + if (message.topP !== undefined) { + writer.uint32(57).double(message.topP); + } + if (message.stop !== undefined) { + TextArray.encode(message.stop, writer.uint32(66).fork()).ldelim(); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): GenerativeDeepseek { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseGenerativeDeepseek(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.baseUrl = reader.string(); + continue; + case 2: + if (tag !== 18) { + break; + } + + message.model = reader.string(); + continue; + case 3: + if (tag !== 25) { + break; + } + + message.temperature = reader.double(); + continue; + case 4: + if (tag !== 32) { + break; + } + + message.maxTokens = longToNumber(reader.int64() as Long); + continue; + case 5: + if (tag !== 41) { + break; + } + + message.frequencyPenalty = reader.double(); + continue; + case 6: + if (tag !== 49) { + break; + } + + message.presencePenalty = reader.double(); + continue; + case 7: + if (tag !== 57) { + break; + } + + message.topP = reader.double(); + continue; + case 8: + if (tag !== 66) { + break; + } + + message.stop = TextArray.decode(reader, reader.uint32()); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): GenerativeDeepseek { + return { + baseUrl: isSet(object.baseUrl) ? globalThis.String(object.baseUrl) : undefined, + model: isSet(object.model) ? globalThis.String(object.model) : undefined, + temperature: isSet(object.temperature) ? globalThis.Number(object.temperature) : undefined, + maxTokens: isSet(object.maxTokens) ? globalThis.Number(object.maxTokens) : undefined, + frequencyPenalty: isSet(object.frequencyPenalty) ? globalThis.Number(object.frequencyPenalty) : undefined, + presencePenalty: isSet(object.presencePenalty) ? globalThis.Number(object.presencePenalty) : undefined, + topP: isSet(object.topP) ? globalThis.Number(object.topP) : undefined, + stop: isSet(object.stop) ? TextArray.fromJSON(object.stop) : undefined, + }; + }, + + toJSON(message: GenerativeDeepseek): unknown { + const obj: any = {}; + if (message.baseUrl !== undefined) { + obj.baseUrl = message.baseUrl; + } + if (message.model !== undefined) { + obj.model = message.model; + } + if (message.temperature !== undefined) { + obj.temperature = message.temperature; + } + if (message.maxTokens !== undefined) { + obj.maxTokens = Math.round(message.maxTokens); + } + if (message.frequencyPenalty !== undefined) { + obj.frequencyPenalty = message.frequencyPenalty; + } + if (message.presencePenalty !== undefined) { + obj.presencePenalty = message.presencePenalty; + } + if (message.topP !== undefined) { + obj.topP = message.topP; + } + if (message.stop !== undefined) { + obj.stop = TextArray.toJSON(message.stop); + } + return obj; + }, + + create(base?: DeepPartial): GenerativeDeepseek { + return GenerativeDeepseek.fromPartial(base ?? {}); + }, + fromPartial(object: DeepPartial): GenerativeDeepseek { + const message = createBaseGenerativeDeepseek(); + message.baseUrl = object.baseUrl ?? undefined; + message.model = object.model ?? undefined; + message.temperature = object.temperature ?? undefined; + message.maxTokens = object.maxTokens ?? undefined; + message.frequencyPenalty = object.frequencyPenalty ?? undefined; + message.presencePenalty = object.presencePenalty ?? undefined; + message.topP = object.topP ?? undefined; + message.stop = (object.stop !== undefined && object.stop !== null) ? TextArray.fromPartial(object.stop) : undefined; + return message; + }, +}; + function createBaseGenerativeAnthropicMetadata(): GenerativeAnthropicMetadata { return { usage: undefined }; } @@ -5502,6 +5733,154 @@ export const GenerativeXAIMetadata_Usage = { }, }; +function createBaseGenerativeDeepseekMetadata(): GenerativeDeepseekMetadata { + return { usage: undefined }; +} + +export const GenerativeDeepseekMetadata = { + encode(message: GenerativeDeepseekMetadata, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.usage !== undefined) { + GenerativeDeepseekMetadata_Usage.encode(message.usage, writer.uint32(10).fork()).ldelim(); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): GenerativeDeepseekMetadata { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseGenerativeDeepseekMetadata(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.usage = GenerativeDeepseekMetadata_Usage.decode(reader, reader.uint32()); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): GenerativeDeepseekMetadata { + return { usage: isSet(object.usage) ? GenerativeDeepseekMetadata_Usage.fromJSON(object.usage) : undefined }; + }, + + toJSON(message: GenerativeDeepseekMetadata): unknown { + const obj: any = {}; + if (message.usage !== undefined) { + obj.usage = GenerativeDeepseekMetadata_Usage.toJSON(message.usage); + } + return obj; + }, + + create(base?: DeepPartial): GenerativeDeepseekMetadata { + return GenerativeDeepseekMetadata.fromPartial(base ?? {}); + }, + fromPartial(object: DeepPartial): GenerativeDeepseekMetadata { + const message = createBaseGenerativeDeepseekMetadata(); + message.usage = (object.usage !== undefined && object.usage !== null) + ? GenerativeDeepseekMetadata_Usage.fromPartial(object.usage) + : undefined; + return message; + }, +}; + +function createBaseGenerativeDeepseekMetadata_Usage(): GenerativeDeepseekMetadata_Usage { + return { promptTokens: undefined, completionTokens: undefined, totalTokens: undefined }; +} + +export const GenerativeDeepseekMetadata_Usage = { + encode(message: GenerativeDeepseekMetadata_Usage, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.promptTokens !== undefined) { + writer.uint32(8).int64(message.promptTokens); + } + if (message.completionTokens !== undefined) { + writer.uint32(16).int64(message.completionTokens); + } + if (message.totalTokens !== undefined) { + writer.uint32(24).int64(message.totalTokens); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): GenerativeDeepseekMetadata_Usage { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseGenerativeDeepseekMetadata_Usage(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 8) { + break; + } + + message.promptTokens = longToNumber(reader.int64() as Long); + continue; + case 2: + if (tag !== 16) { + break; + } + + message.completionTokens = longToNumber(reader.int64() as Long); + continue; + case 3: + if (tag !== 24) { + break; + } + + message.totalTokens = longToNumber(reader.int64() as Long); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): GenerativeDeepseekMetadata_Usage { + return { + promptTokens: isSet(object.promptTokens) ? globalThis.Number(object.promptTokens) : undefined, + completionTokens: isSet(object.completionTokens) ? globalThis.Number(object.completionTokens) : undefined, + totalTokens: isSet(object.totalTokens) ? globalThis.Number(object.totalTokens) : undefined, + }; + }, + + toJSON(message: GenerativeDeepseekMetadata_Usage): unknown { + const obj: any = {}; + if (message.promptTokens !== undefined) { + obj.promptTokens = Math.round(message.promptTokens); + } + if (message.completionTokens !== undefined) { + obj.completionTokens = Math.round(message.completionTokens); + } + if (message.totalTokens !== undefined) { + obj.totalTokens = Math.round(message.totalTokens); + } + return obj; + }, + + create(base?: DeepPartial): GenerativeDeepseekMetadata_Usage { + return GenerativeDeepseekMetadata_Usage.fromPartial(base ?? {}); + }, + fromPartial(object: DeepPartial): GenerativeDeepseekMetadata_Usage { + const message = createBaseGenerativeDeepseekMetadata_Usage(); + message.promptTokens = object.promptTokens ?? undefined; + message.completionTokens = object.completionTokens ?? undefined; + message.totalTokens = object.totalTokens ?? undefined; + return message; + }, +}; + function createBaseGenerativeMetadata(): GenerativeMetadata { return { anthropic: undefined, @@ -5517,6 +5896,7 @@ function createBaseGenerativeMetadata(): GenerativeMetadata { friendliai: undefined, nvidia: undefined, xai: undefined, + deepseek: undefined, }; } @@ -5561,6 +5941,9 @@ export const GenerativeMetadata = { if (message.xai !== undefined) { GenerativeXAIMetadata.encode(message.xai, writer.uint32(106).fork()).ldelim(); } + if (message.deepseek !== undefined) { + GenerativeDeepseekMetadata.encode(message.deepseek, writer.uint32(114).fork()).ldelim(); + } return writer; }, @@ -5662,6 +6045,13 @@ export const GenerativeMetadata = { message.xai = GenerativeXAIMetadata.decode(reader, reader.uint32()); continue; + case 14: + if (tag !== 114) { + break; + } + + message.deepseek = GenerativeDeepseekMetadata.decode(reader, reader.uint32()); + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -5686,6 +6076,7 @@ export const GenerativeMetadata = { friendliai: isSet(object.friendliai) ? GenerativeFriendliAIMetadata.fromJSON(object.friendliai) : undefined, nvidia: isSet(object.nvidia) ? GenerativeNvidiaMetadata.fromJSON(object.nvidia) : undefined, xai: isSet(object.xai) ? GenerativeXAIMetadata.fromJSON(object.xai) : undefined, + deepseek: isSet(object.deepseek) ? GenerativeDeepseekMetadata.fromJSON(object.deepseek) : undefined, }; }, @@ -5730,6 +6121,9 @@ export const GenerativeMetadata = { if (message.xai !== undefined) { obj.xai = GenerativeXAIMetadata.toJSON(message.xai); } + if (message.deepseek !== undefined) { + obj.deepseek = GenerativeDeepseekMetadata.toJSON(message.deepseek); + } return obj; }, @@ -5777,6 +6171,9 @@ export const GenerativeMetadata = { message.xai = (object.xai !== undefined && object.xai !== null) ? GenerativeXAIMetadata.fromPartial(object.xai) : undefined; + message.deepseek = (object.deepseek !== undefined && object.deepseek !== null) + ? GenerativeDeepseekMetadata.fromPartial(object.deepseek) + : undefined; return message; }, }; diff --git a/src/proto/v1/search_get.ts b/src/proto/v1/search_get.ts index 721fad75..ede2069e 100644 --- a/src/proto/v1/search_get.ts +++ b/src/proto/v1/search_get.ts @@ -61,8 +61,9 @@ export interface SearchRequest { nearThermal?: NearThermalSearch | undefined; nearImu?: NearIMUSearch | undefined; generative?: GenerativeSearch | undefined; - rerank?: - | Rerank + rerank?: Rerank | undefined; + boost?: + | Boost | undefined; /** @deprecated */ uses123Api: boolean; @@ -252,6 +253,127 @@ export interface RefPropertiesResult { propName: string; } +export interface Boost { + conditions: Boost_Condition[]; + weight?: number | undefined; + depth?: number | undefined; +} + +export enum Boost_PropertyValueModifier { + PROPERTY_VALUE_MODIFIER_UNSPECIFIED = 0, + PROPERTY_VALUE_MODIFIER_LOG1P = 1, + PROPERTY_VALUE_MODIFIER_SQRT = 2, + UNRECOGNIZED = -1, +} + +export function boost_PropertyValueModifierFromJSON(object: any): Boost_PropertyValueModifier { + switch (object) { + case 0: + case "PROPERTY_VALUE_MODIFIER_UNSPECIFIED": + return Boost_PropertyValueModifier.PROPERTY_VALUE_MODIFIER_UNSPECIFIED; + case 1: + case "PROPERTY_VALUE_MODIFIER_LOG1P": + return Boost_PropertyValueModifier.PROPERTY_VALUE_MODIFIER_LOG1P; + case 2: + case "PROPERTY_VALUE_MODIFIER_SQRT": + return Boost_PropertyValueModifier.PROPERTY_VALUE_MODIFIER_SQRT; + case -1: + case "UNRECOGNIZED": + default: + return Boost_PropertyValueModifier.UNRECOGNIZED; + } +} + +export function boost_PropertyValueModifierToJSON(object: Boost_PropertyValueModifier): string { + switch (object) { + case Boost_PropertyValueModifier.PROPERTY_VALUE_MODIFIER_UNSPECIFIED: + return "PROPERTY_VALUE_MODIFIER_UNSPECIFIED"; + case Boost_PropertyValueModifier.PROPERTY_VALUE_MODIFIER_LOG1P: + return "PROPERTY_VALUE_MODIFIER_LOG1P"; + case Boost_PropertyValueModifier.PROPERTY_VALUE_MODIFIER_SQRT: + return "PROPERTY_VALUE_MODIFIER_SQRT"; + case Boost_PropertyValueModifier.UNRECOGNIZED: + default: + return "UNRECOGNIZED"; + } +} + +export enum Boost_DecayCurve { + DECAY_CURVE_UNSPECIFIED = 0, + DECAY_CURVE_GAUSS = 1, + DECAY_CURVE_LINEAR = 2, + DECAY_CURVE_EXPONENTIAL = 3, + UNRECOGNIZED = -1, +} + +export function boost_DecayCurveFromJSON(object: any): Boost_DecayCurve { + switch (object) { + case 0: + case "DECAY_CURVE_UNSPECIFIED": + return Boost_DecayCurve.DECAY_CURVE_UNSPECIFIED; + case 1: + case "DECAY_CURVE_GAUSS": + return Boost_DecayCurve.DECAY_CURVE_GAUSS; + case 2: + case "DECAY_CURVE_LINEAR": + return Boost_DecayCurve.DECAY_CURVE_LINEAR; + case 3: + case "DECAY_CURVE_EXPONENTIAL": + return Boost_DecayCurve.DECAY_CURVE_EXPONENTIAL; + case -1: + case "UNRECOGNIZED": + default: + return Boost_DecayCurve.UNRECOGNIZED; + } +} + +export function boost_DecayCurveToJSON(object: Boost_DecayCurve): string { + switch (object) { + case Boost_DecayCurve.DECAY_CURVE_UNSPECIFIED: + return "DECAY_CURVE_UNSPECIFIED"; + case Boost_DecayCurve.DECAY_CURVE_GAUSS: + return "DECAY_CURVE_GAUSS"; + case Boost_DecayCurve.DECAY_CURVE_LINEAR: + return "DECAY_CURVE_LINEAR"; + case Boost_DecayCurve.DECAY_CURVE_EXPONENTIAL: + return "DECAY_CURVE_EXPONENTIAL"; + case Boost_DecayCurve.UNRECOGNIZED: + default: + return "UNRECOGNIZED"; + } +} + +export interface Boost_PropertyValueFunction { + property: string; + modifier?: Boost_PropertyValueModifier | undefined; +} + +export interface Boost_TimeDecayFunction { + property: string; + origin: string; + scale: string; + offset?: string | undefined; + curve?: Boost_DecayCurve | undefined; + decayValue?: number | undefined; +} + +export interface Boost_NumericDecayFunction { + property: string; + origin: number; + scale: number; + offset?: number | undefined; + curve?: Boost_DecayCurve | undefined; + decayValue?: number | undefined; +} + +export interface Boost_Condition { + filter?: Filters | undefined; + timeDecay?: Boost_TimeDecayFunction | undefined; + propertyValue?: Boost_PropertyValueFunction | undefined; + numericDecay?: Boost_NumericDecayFunction | undefined; + weight?: number | undefined; +} + function createBaseSearchRequest(): SearchRequest { return { collection: "", @@ -279,6 +401,7 @@ function createBaseSearchRequest(): SearchRequest { nearImu: undefined, generative: undefined, rerank: undefined, + boost: undefined, uses123Api: false, uses125Api: false, uses127Api: false, @@ -362,6 +485,9 @@ export const SearchRequest = { if (message.rerank !== undefined) { Rerank.encode(message.rerank, writer.uint32(490).fork()).ldelim(); } + if (message.boost !== undefined) { + Boost.encode(message.boost, writer.uint32(498).fork()).ldelim(); + } if (message.uses123Api !== false) { writer.uint32(800).bool(message.uses123Api); } @@ -556,6 +682,13 @@ export const SearchRequest = { message.rerank = Rerank.decode(reader, reader.uint32()); continue; + case 62: + if (tag !== 498) { + break; + } + + message.boost = Boost.decode(reader, reader.uint32()); + continue; case 100: if (tag !== 800) { break; @@ -613,6 +746,7 @@ export const SearchRequest = { nearImu: isSet(object.nearImu) ? NearIMUSearch.fromJSON(object.nearImu) : undefined, generative: isSet(object.generative) ? GenerativeSearch.fromJSON(object.generative) : undefined, rerank: isSet(object.rerank) ? Rerank.fromJSON(object.rerank) : undefined, + boost: isSet(object.boost) ? Boost.fromJSON(object.boost) : undefined, uses123Api: isSet(object.uses123Api) ? globalThis.Boolean(object.uses123Api) : false, uses125Api: isSet(object.uses125Api) ? globalThis.Boolean(object.uses125Api) : false, uses127Api: isSet(object.uses127Api) ? globalThis.Boolean(object.uses127Api) : false, @@ -696,6 +830,9 @@ export const SearchRequest = { if (message.rerank !== undefined) { obj.rerank = Rerank.toJSON(message.rerank); } + if (message.boost !== undefined) { + obj.boost = Boost.toJSON(message.boost); + } if (message.uses123Api !== false) { obj.uses123Api = message.uses123Api; } @@ -772,6 +909,7 @@ export const SearchRequest = { message.rerank = (object.rerank !== undefined && object.rerank !== null) ? Rerank.fromPartial(object.rerank) : undefined; + message.boost = (object.boost !== undefined && object.boost !== null) ? Boost.fromPartial(object.boost) : undefined; message.uses123Api = object.uses123Api ?? false; message.uses125Api = object.uses125Api ?? false; message.uses127Api = object.uses127Api ?? false; @@ -3067,6 +3205,574 @@ export const RefPropertiesResult = { }, }; +function createBaseBoost(): Boost { + return { conditions: [], weight: undefined, depth: undefined }; +} + +export const Boost = { + encode(message: Boost, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + for (const v of message.conditions) { + Boost_Condition.encode(v!, writer.uint32(10).fork()).ldelim(); + } + if (message.weight !== undefined) { + writer.uint32(21).float(message.weight); + } + if (message.depth !== undefined) { + writer.uint32(24).uint32(message.depth); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): Boost { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseBoost(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.conditions.push(Boost_Condition.decode(reader, reader.uint32())); + continue; + case 2: + if (tag !== 21) { + break; + } + + message.weight = reader.float(); + continue; + case 3: + if (tag !== 24) { + break; + } + + message.depth = reader.uint32(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): Boost { + return { + conditions: globalThis.Array.isArray(object?.conditions) + ? object.conditions.map((e: any) => Boost_Condition.fromJSON(e)) + : [], + weight: isSet(object.weight) ? globalThis.Number(object.weight) : undefined, + depth: isSet(object.depth) ? globalThis.Number(object.depth) : undefined, + }; + }, + + toJSON(message: Boost): unknown { + const obj: any = {}; + if (message.conditions?.length) { + obj.conditions = message.conditions.map((e) => Boost_Condition.toJSON(e)); + } + if (message.weight !== undefined) { + obj.weight = message.weight; + } + if (message.depth !== undefined) { + obj.depth = Math.round(message.depth); + } + return obj; + }, + + create(base?: DeepPartial): Boost { + return Boost.fromPartial(base ?? {}); + }, + fromPartial(object: DeepPartial): Boost { + const message = createBaseBoost(); + message.conditions = object.conditions?.map((e) => Boost_Condition.fromPartial(e)) || []; + message.weight = object.weight ?? undefined; + message.depth = object.depth ?? undefined; + return message; + }, +}; + +function createBaseBoost_PropertyValueFunction(): Boost_PropertyValueFunction { + return { property: "", modifier: undefined }; +} + +export const Boost_PropertyValueFunction = { + encode(message: Boost_PropertyValueFunction, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.property !== "") { + writer.uint32(10).string(message.property); + } + if (message.modifier !== undefined) { + writer.uint32(16).int32(message.modifier); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): Boost_PropertyValueFunction { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseBoost_PropertyValueFunction(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.property = reader.string(); + continue; + case 2: + if (tag !== 16) { + break; + } + + message.modifier = reader.int32() as any; + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): Boost_PropertyValueFunction { + return { + property: isSet(object.property) ? globalThis.String(object.property) : "", + modifier: isSet(object.modifier) ? boost_PropertyValueModifierFromJSON(object.modifier) : undefined, + }; + }, + + toJSON(message: Boost_PropertyValueFunction): unknown { + const obj: any = {}; + if (message.property !== "") { + obj.property = message.property; + } + if (message.modifier !== undefined) { + obj.modifier = boost_PropertyValueModifierToJSON(message.modifier); + } + return obj; + }, + + create(base?: DeepPartial): Boost_PropertyValueFunction { + return Boost_PropertyValueFunction.fromPartial(base ?? {}); + }, + fromPartial(object: DeepPartial): Boost_PropertyValueFunction { + const message = createBaseBoost_PropertyValueFunction(); + message.property = object.property ?? ""; + message.modifier = object.modifier ?? undefined; + return message; + }, +}; + +function createBaseBoost_TimeDecayFunction(): Boost_TimeDecayFunction { + return { property: "", origin: "", scale: "", offset: undefined, curve: undefined, decayValue: undefined }; +} + +export const Boost_TimeDecayFunction = { + encode(message: Boost_TimeDecayFunction, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.property !== "") { + writer.uint32(10).string(message.property); + } + if (message.origin !== "") { + writer.uint32(18).string(message.origin); + } + if (message.scale !== "") { + writer.uint32(26).string(message.scale); + } + if (message.offset !== undefined) { + writer.uint32(34).string(message.offset); + } + if (message.curve !== undefined) { + writer.uint32(40).int32(message.curve); + } + if (message.decayValue !== undefined) { + writer.uint32(53).float(message.decayValue); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): Boost_TimeDecayFunction { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseBoost_TimeDecayFunction(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.property = reader.string(); + continue; + case 2: + if (tag !== 18) { + break; + } + + message.origin = reader.string(); + continue; + case 3: + if (tag !== 26) { + break; + } + + message.scale = reader.string(); + continue; + case 4: + if (tag !== 34) { + break; + } + + message.offset = reader.string(); + continue; + case 5: + if (tag !== 40) { + break; + } + + message.curve = reader.int32() as any; + continue; + case 6: + if (tag !== 53) { + break; + } + + message.decayValue = reader.float(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): Boost_TimeDecayFunction { + return { + property: isSet(object.property) ? globalThis.String(object.property) : "", + origin: isSet(object.origin) ? globalThis.String(object.origin) : "", + scale: isSet(object.scale) ? globalThis.String(object.scale) : "", + offset: isSet(object.offset) ? globalThis.String(object.offset) : undefined, + curve: isSet(object.curve) ? boost_DecayCurveFromJSON(object.curve) : undefined, + decayValue: isSet(object.decayValue) ? globalThis.Number(object.decayValue) : undefined, + }; + }, + + toJSON(message: Boost_TimeDecayFunction): unknown { + const obj: any = {}; + if (message.property !== "") { + obj.property = message.property; + } + if (message.origin !== "") { + obj.origin = message.origin; + } + if (message.scale !== "") { + obj.scale = message.scale; + } + if (message.offset !== undefined) { + obj.offset = message.offset; + } + if (message.curve !== undefined) { + obj.curve = boost_DecayCurveToJSON(message.curve); + } + if (message.decayValue !== undefined) { + obj.decayValue = message.decayValue; + } + return obj; + }, + + create(base?: DeepPartial): Boost_TimeDecayFunction { + return Boost_TimeDecayFunction.fromPartial(base ?? {}); + }, + fromPartial(object: DeepPartial): Boost_TimeDecayFunction { + const message = createBaseBoost_TimeDecayFunction(); + message.property = object.property ?? ""; + message.origin = object.origin ?? ""; + message.scale = object.scale ?? ""; + message.offset = object.offset ?? undefined; + message.curve = object.curve ?? undefined; + message.decayValue = object.decayValue ?? undefined; + return message; + }, +}; + +function createBaseBoost_NumericDecayFunction(): Boost_NumericDecayFunction { + return { property: "", origin: 0, scale: 0, offset: undefined, curve: undefined, decayValue: undefined }; +} + +export const Boost_NumericDecayFunction = { + encode(message: Boost_NumericDecayFunction, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.property !== "") { + writer.uint32(10).string(message.property); + } + if (message.origin !== 0) { + writer.uint32(17).double(message.origin); + } + if (message.scale !== 0) { + writer.uint32(25).double(message.scale); + } + if (message.offset !== undefined) { + writer.uint32(33).double(message.offset); + } + if (message.curve !== undefined) { + writer.uint32(40).int32(message.curve); + } + if (message.decayValue !== undefined) { + writer.uint32(53).float(message.decayValue); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): Boost_NumericDecayFunction { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseBoost_NumericDecayFunction(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.property = reader.string(); + continue; + case 2: + if (tag !== 17) { + break; + } + + message.origin = reader.double(); + continue; + case 3: + if (tag !== 25) { + break; + } + + message.scale = reader.double(); + continue; + case 4: + if (tag !== 33) { + break; + } + + message.offset = reader.double(); + continue; + case 5: + if (tag !== 40) { + break; + } + + message.curve = reader.int32() as any; + continue; + case 6: + if (tag !== 53) { + break; + } + + message.decayValue = reader.float(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): Boost_NumericDecayFunction { + return { + property: isSet(object.property) ? globalThis.String(object.property) : "", + origin: isSet(object.origin) ? globalThis.Number(object.origin) : 0, + scale: isSet(object.scale) ? globalThis.Number(object.scale) : 0, + offset: isSet(object.offset) ? globalThis.Number(object.offset) : undefined, + curve: isSet(object.curve) ? boost_DecayCurveFromJSON(object.curve) : undefined, + decayValue: isSet(object.decayValue) ? globalThis.Number(object.decayValue) : undefined, + }; + }, + + toJSON(message: Boost_NumericDecayFunction): unknown { + const obj: any = {}; + if (message.property !== "") { + obj.property = message.property; + } + if (message.origin !== 0) { + obj.origin = message.origin; + } + if (message.scale !== 0) { + obj.scale = message.scale; + } + if (message.offset !== undefined) { + obj.offset = message.offset; + } + if (message.curve !== undefined) { + obj.curve = boost_DecayCurveToJSON(message.curve); + } + if (message.decayValue !== undefined) { + obj.decayValue = message.decayValue; + } + return obj; + }, + + create(base?: DeepPartial): Boost_NumericDecayFunction { + return Boost_NumericDecayFunction.fromPartial(base ?? {}); + }, + fromPartial(object: DeepPartial): Boost_NumericDecayFunction { + const message = createBaseBoost_NumericDecayFunction(); + message.property = object.property ?? ""; + message.origin = object.origin ?? 0; + message.scale = object.scale ?? 0; + message.offset = object.offset ?? undefined; + message.curve = object.curve ?? undefined; + message.decayValue = object.decayValue ?? undefined; + return message; + }, +}; + +function createBaseBoost_Condition(): Boost_Condition { + return { + filter: undefined, + timeDecay: undefined, + propertyValue: undefined, + numericDecay: undefined, + weight: undefined, + }; +} + +export const Boost_Condition = { + encode(message: Boost_Condition, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.filter !== undefined) { + Filters.encode(message.filter, writer.uint32(10).fork()).ldelim(); + } + if (message.timeDecay !== undefined) { + Boost_TimeDecayFunction.encode(message.timeDecay, writer.uint32(18).fork()).ldelim(); + } + if (message.propertyValue !== undefined) { + Boost_PropertyValueFunction.encode(message.propertyValue, writer.uint32(26).fork()).ldelim(); + } + if (message.numericDecay !== undefined) { + Boost_NumericDecayFunction.encode(message.numericDecay, writer.uint32(34).fork()).ldelim(); + } + if (message.weight !== undefined) { + writer.uint32(45).float(message.weight); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): Boost_Condition { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseBoost_Condition(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.filter = Filters.decode(reader, reader.uint32()); + continue; + case 2: + if (tag !== 18) { + break; + } + + message.timeDecay = Boost_TimeDecayFunction.decode(reader, reader.uint32()); + continue; + case 3: + if (tag !== 26) { + break; + } + + message.propertyValue = Boost_PropertyValueFunction.decode(reader, reader.uint32()); + continue; + case 4: + if (tag !== 34) { + break; + } + + message.numericDecay = Boost_NumericDecayFunction.decode(reader, reader.uint32()); + continue; + case 5: + if (tag !== 45) { + break; + } + + message.weight = reader.float(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): Boost_Condition { + return { + filter: isSet(object.filter) ? Filters.fromJSON(object.filter) : undefined, + timeDecay: isSet(object.timeDecay) ? Boost_TimeDecayFunction.fromJSON(object.timeDecay) : undefined, + propertyValue: isSet(object.propertyValue) + ? Boost_PropertyValueFunction.fromJSON(object.propertyValue) + : undefined, + numericDecay: isSet(object.numericDecay) ? Boost_NumericDecayFunction.fromJSON(object.numericDecay) : undefined, + weight: isSet(object.weight) ? globalThis.Number(object.weight) : undefined, + }; + }, + + toJSON(message: Boost_Condition): unknown { + const obj: any = {}; + if (message.filter !== undefined) { + obj.filter = Filters.toJSON(message.filter); + } + if (message.timeDecay !== undefined) { + obj.timeDecay = Boost_TimeDecayFunction.toJSON(message.timeDecay); + } + if (message.propertyValue !== undefined) { + obj.propertyValue = Boost_PropertyValueFunction.toJSON(message.propertyValue); + } + if (message.numericDecay !== undefined) { + obj.numericDecay = Boost_NumericDecayFunction.toJSON(message.numericDecay); + } + if (message.weight !== undefined) { + obj.weight = message.weight; + } + return obj; + }, + + create(base?: DeepPartial): Boost_Condition { + return Boost_Condition.fromPartial(base ?? {}); + }, + fromPartial(object: DeepPartial): Boost_Condition { + const message = createBaseBoost_Condition(); + message.filter = (object.filter !== undefined && object.filter !== null) + ? Filters.fromPartial(object.filter) + : undefined; + message.timeDecay = (object.timeDecay !== undefined && object.timeDecay !== null) + ? Boost_TimeDecayFunction.fromPartial(object.timeDecay) + : undefined; + message.propertyValue = (object.propertyValue !== undefined && object.propertyValue !== null) + ? Boost_PropertyValueFunction.fromPartial(object.propertyValue) + : undefined; + message.numericDecay = (object.numericDecay !== undefined && object.numericDecay !== null) + ? Boost_NumericDecayFunction.fromPartial(object.numericDecay) + : undefined; + message.weight = object.weight ?? undefined; + return message; + }, +}; + function bytesFromBase64(b64: string): Uint8Array { if ((globalThis as any).Buffer) { return Uint8Array.from(globalThis.Buffer.from(b64, "base64")); diff --git a/test/collections/query/integration.test.ts b/test/collections/query/integration.test.ts index e2cb3520..5078273a 100644 --- a/test/collections/query/integration.test.ts +++ b/test/collections/query/integration.test.ts @@ -2,6 +2,7 @@ /* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */ import { AbortError } from 'abort-controller-x'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; +import { Boost } from '../../../src/collections/query/utils.js'; import { WeaviateUnsupportedFeatureError } from '../../../src/errors.js'; import weaviate, { Bm25Operator, @@ -10,6 +11,7 @@ import weaviate, { GroupByOptions, Reference, WeaviateClient, + WeaviateReturn, } from '../../../src/index.js'; import { requireAtLeast } from '../../../test/version.js'; @@ -309,6 +311,126 @@ describe('Testing of the collection.query methods with a simple collection', () }); }); +requireAtLeast(1, 38, 0).describe('Testing of collection.query methods with boost parameter', () => { + const collectionName = 'TestCollectionQueryBoost'; + let client: WeaviateClient; + let collection: Collection< + { category: string; createdAt: Date; position: number }, + 'TestCollectionQueryBoost' + >; + + afterAll(() => { + return client.collections.delete(collectionName).catch((err) => { + console.error(err); + throw err; + }); + }); + + beforeAll(async () => { + client = await weaviate.connectToLocal(); + collection = await client.collections.create({ + name: collectionName, + properties: [ + { + name: 'category', + dataType: 'text', + }, + { + name: 'createdAt', + dataType: 'date', + }, + { + name: 'position', + dataType: 'int', + }, + ], + vectorizers: weaviate.configure.vectors.selfProvided(), + }); + return collection.data + .insertMany([ + { + properties: { + category: 'red', + createdAt: new Date(Date.now()), + position: 1, + }, + vectors: [4, 5, 6], + }, + { + properties: { + category: 'blue', + createdAt: new Date(Date.now()), + position: 2, + }, + vectors: [1, 2, 3], + }, + { + properties: { + category: 'green', + createdAt: new Date(Date.now()), + position: 3, + }, + vectors: [1, 2, 3], + }, + ]) + .catch((err) => console.error(err)); + }); + + const ids = (ret: WeaviateReturn): string[] => { + const out: string[] = []; + for (const obj of ret.objects) { + out.push(obj.uuid); + } + return out; + }; + + it.each([ + { + name: 'filter', + boost: Boost.filter( + { target: { property: 'category' }, operator: 'Equal', value: 'red' }, + { weight: 1 } + ), + }, + { + name: 'timeDecay', + boost: Boost.timeDecay({ + property: 'createdAt', + origin: '2024-01-01T00:00:00Z', + scale: '365d', + curve: 'exponential', + decay: 0.3, + weight: 1, + }), + }, + { + name: 'numericDecay', + boost: Boost.numericDecay({ + property: 'position', + origin: 10, + scale: 3234, + curve: 'linear', + decay: 0.2, + weight: 1, + }), + }, + { + name: 'numericProperty', + boost: Boost.numericProperty({ + property: 'position', + modifier: 'log1p', + weight: 1, + }), + }, + ])('$name', async ({ boost }) => { + const baseline = ids(await collection.query.nearVector([1, 2, 3])); + expect(baseline).toHaveLength(3); + + const boosted = ids(await collection.query.nearVector([1, 2, 3], { boost })); + expect(boosted).not.toEqual(baseline); + }); +}); + describe('Testing of the collection.query methods with a collection with a reference property', () => { let client: WeaviateClient; let collection: Collection;