@xano-sdk/vector 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md ADDED
@@ -0,0 +1,68 @@
1
+ # AGENTS.md
2
+
3
+ > For agents **consuming** the published package, see [llms.txt](llms.txt) instead.
4
+ > This file is for agents **working on and maintaining** the `@xano-sdk/vector` package itself.
5
+
6
+ ## What This Is
7
+
8
+ `@xano-sdk/vector` is a Xano SDK module providing an end-to-end vector embedding & similarity search pipeline using Google Gemini Embeddings (768 dimensions) and pgvector.
9
+
10
+ There is **no runtime execution** inside this package: every export is a plain, typed Xano SDK def object (`table()`, `defineFunction()`, `tool()`, `apiGroup()`, `query()`) or a def factory. All registration and compilation happens in the consumer's `@xano/sdk` workspace compiler at `export()`.
11
+
12
+ ## Commands
13
+
14
+ ```bash
15
+ # Typecheck
16
+ npm run typecheck
17
+
18
+ # Run test suite
19
+ npm test
20
+
21
+ # Regenerate golden fixture (deliberate act only — see below)
22
+ npm run fixture:regen
23
+
24
+ # Build distribution bundle
25
+ npm run build
26
+
27
+ # Lint
28
+ npm run lint
29
+ ```
30
+
31
+ ## Directory Layout
32
+
33
+ - `src/options.ts`: Option types, defaults, and the single `resolveOptions` validation gate.
34
+ - `src/tables/`: `documentTable` and `chunkTable` (with `f.vector(768)` and HNSW cosine index).
35
+ - `src/functions/`: `generateEmbeddingFn`, `chunkTextFn`, `ingestDocumentFn`, and `searchVectorsFn`.
36
+ - `src/tool/`: `vectorSearchTool` for AI Agent knowledge retrieval.
37
+ - `src/api/`: Endpoint definitions (`group.ts`, `documents.ts`, `search.ts`, `types.ts`, `client-types.ts`).
38
+ - `src/register.ts`: `createVector` and `registerVector`.
39
+ - `src/index.ts`: The unified public package surface.
40
+ - `test/`: Unit tests, options tests, golden bundle tests, published docs contract.
41
+ - `scripts/regen-golden.ts`: Regenerates `test/fixtures/golden-bundle.json`.
42
+
43
+ ## Rules That Bite
44
+
45
+ - **Defs are factories:** `f.tableRef` resolves its target guid eagerly at column-construction time, and the document table is referenced by chunks and queries. Minting defs per `createVector` / `registerVector` call eliminates cross-call identity contamination.
46
+ - **Idempotency WeakSet:** The SDK's duplicate-def guard compares def identity. Two `createVector` calls produce distinct objects sharing names, so `registerVector` keeps a `WeakSet<Xano>` to flag duplicate calls early with a clear diagnostic.
47
+ - **Literal Stack Tuples:** Function and query stacks must remain literal tuples (`readonly Statement[]`) or `statements(...)` helpers. Spreading an untyped `Statement[]` collapses the stack tuple and widens `InferResponse` to `StackTupleWidened`. `test/types.test.ts` guards this.
48
+ - **pgvector Cosine Search:** The HNSW index on `vector_chunk` uses `vector_cosine_ops`, and search evaluates `vector_cos_distance` sorted `asc`.
49
+ - **Module manifest:** `package.json` carries a `"xanosdk"` field (`register: "registerVector"`, `returns: "handle"`, `options: {}`) so `xanosdk marketplace install` / `xanosdk init --marketplace` wire the module into `xano/index.ts` and bind the returned handle. Keep `register` in sync with the export name, and keep `options: {}` only while every option stays optional.
50
+ - **Search is not owner-scoped:** with `authenticated`, document endpoints filter by `user_id`, but `searchVectorsFn` (and so `/search` and the agent tool) searches every chunk. The docs say so; change both together.
51
+ - **Peer Range:** `@xano/sdk` is a peer dependency (`>=1.0.0 <2.0.0`). Dev dependency is pinned exactly to `1.0.0`. The window is `>=<floor> <2.0.0`: the floor is the lowest SDK the module is tested against, the ceiling is the next major.
52
+
53
+ ## The Golden-Bundle Contract
54
+
55
+ `test/fixtures/golden-bundle.json` is a byte-exact peer-drift tripwire. Any change to statement encoding or schema in `@xano/sdk` breaks `test/bundle.test.ts`.
56
+
57
+ Regenerating the fixture is a deliberate, reviewed action (`npm run fixture:regen && git diff test/fixtures/golden-bundle.json`).
58
+
59
+ ## Docs
60
+
61
+ `README.md` and `llms.txt` ship in the tarball. When options, endpoints, or the SDK floor change, update both, and type-check any code snippet you change against the pinned SDK (the SDK's `agent()` / `workspaceConfig()` shapes have changed before). `test/published-docs.test.ts` checks the shipped file list and relative links, not content.
62
+
63
+ ## Release
64
+
65
+ 1. Bump `version` in `package.json` according to SemVer (versions start at 1.0.0 and only the patch number (1.0.x) increments for now, whatever the change; do not bump unless told) and merge it to `main`.
66
+ 2. Run `npm test && npm run lint && npm run build`.
67
+ 3. Verify `npm pack --dry-run` contains exactly the expected files.
68
+ 4. Publish: `npm publish --access public`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Xano, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,210 @@
1
+ # @xano-sdk/vector
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@xano-sdk/vector.svg)](https://www.npmjs.com/package/@xano-sdk/vector)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ A vector embedding, document ingestion, chunking, and semantic search module for [Xano SDK](https://github.com/xanots/sdk). It uses Google Gemini Embeddings 2 (`gemini-embedding-2`) at **768 dimensions**, stores vectors in PostgreSQL `pgvector` with a cosine index, and ships an AI agent search tool.
7
+
8
+ Everything it exports is a typed Xano SDK def. Nothing runs inside this package; your workspace compiles the defs at `export()`.
9
+
10
+ ---
11
+
12
+ ## Features
13
+
14
+ - **Gemini Embeddings 2**: text, images (PNG, JPEG, WebP), audio (WAV, MP3), and video (MP4), reduced to **768 dimensions** with Matryoshka Representation Learning (MRL).
15
+ - **Asymmetric retrieval**: documents are embedded as `RETRIEVAL_DOCUMENT` and queries as `RETRIEVAL_QUERY` by default.
16
+ - **Cross-modal search**: text-to-text, text-to-image, and image-to-image search by cosine similarity (`vector_cosine_ops`).
17
+ - **Chunking strategies**: `paragraph`, `sentence`, `markdown`, `fixed`, and `custom`, with configurable chunk size and overlap.
18
+ - **Document lifecycle**: `pending`, `indexing`, `indexed`, `failed`, with chunk storage and reindexing.
19
+ - **Agent tool**: a `vector_search` tool for Xano agents and MCP servers, with configurable citation style.
20
+ - **Typed client**: request and response types for every endpoint.
21
+
22
+ ---
23
+
24
+ ## Installation
25
+
26
+ With the Xano SDK CLI, which installs the package and wires it into `xano/index.ts`:
27
+
28
+ ```bash
29
+ xanosdk marketplace install @xano-sdk/vector
30
+ # or, for a new project:
31
+ xanosdk init my-app --marketplace @xano-sdk/vector
32
+ ```
33
+
34
+ Or manually:
35
+
36
+ ```bash
37
+ npm install @xano-sdk/vector @xano/sdk
38
+ ```
39
+
40
+ Requires `@xano/sdk` `>=1.0.0 <2.0.0`.
41
+
42
+ ---
43
+
44
+ ## Quickstart
45
+
46
+ ```ts
47
+ // xano/index.ts
48
+ import { workspace, workspaceConfig } from "@xano/sdk";
49
+ import { registerVector } from "@xano-sdk/vector";
50
+
51
+ const ws = workspace("my-app").registerWorkspace(
52
+ workspaceConfig({ name: "my-app", env: { GEMINI_API_KEY: "" } }),
53
+ );
54
+
55
+ export const vector = registerVector(ws, { defaultStrategy: "markdown" });
56
+
57
+ export default vector.xano;
58
+ ```
59
+
60
+ Declare the env var name in source and put its value in `xano/.env`, which is gitignored:
61
+
62
+ ```bash
63
+ # xano/.env
64
+ GEMINI_API_KEY=your-google-ai-studio-key
65
+ ```
66
+
67
+ Do not write `process.env.GEMINI_API_KEY` into `workspaceConfig`. It is read at export time, so the key's value ends up in the bundle.
68
+
69
+ ---
70
+
71
+ ## Configuration Options
72
+
73
+ | Option | Type | Default | Description |
74
+ | :--- | :--- | :--- | :--- |
75
+ | `apiKeyEnv` | `string` | `"GEMINI_API_KEY"` | Name of the workspace env var that holds the Gemini API key. |
76
+ | `model` | `string` | `"gemini-embedding-2"` | Gemini embedding model id. |
77
+ | `taskTypeDocument` | `string` | `"RETRIEVAL_DOCUMENT"` | Gemini `taskType` used when embedding documents. |
78
+ | `taskTypeQuery` | `string` | `"RETRIEVAL_QUERY"` | Gemini `taskType` used when embedding search queries. |
79
+ | `defaultStrategy` | `ChunkStrategy` | `"paragraph"` | `fixed`, `paragraph`, `sentence`, `markdown`, or `custom`. |
80
+ | `defaultChunkSize` | `number` | `500` | Target characters per chunk (integer, 20 to 10000). |
81
+ | `defaultChunkOverlap` | `number` | `50` | Characters shared by consecutive chunks (integer, `>= 0` and `< defaultChunkSize`). |
82
+ | `searchLimit` | `number` | `10` | Default top-k for search (integer, 1 to 100). |
83
+ | `searchThreshold` | `number` | `0.0` | Default minimum cosine similarity (0.0 to 1.0). |
84
+ | `citationFormat` | `"markdown" \| "numeric" \| "none"` | `"markdown"` | How the agent tool tells the model to cite sources. |
85
+ | `authTable` | `TableDef \| string` | `undefined` | Auth table that owns documents. Required when `authenticated` is `true`. |
86
+ | `authenticated` | `boolean` | `true` if `authTable` is set, else `false` | Require a signed-in user on every endpoint and scope documents to their owner. |
87
+ | `userIdType` | `"int" \| "uuid"` | inferred from `authTable` | Type of the `user_id` column. |
88
+ | `routePrefix` | `string` | `"vector"` | Path prefix for the endpoints. |
89
+ | `canonical` | `string` | `undefined` | API group canonical (`/api:<canonical>`). Also replaces `routePrefix` and prefixes def names (`<canonical>_document`, `<canonical>/search_vectors`, …). |
90
+ | `names` | `VectorNames` | see `DEFAULT_NAMES` | Override individual table, function, tool, and API group names. |
91
+ | `tags` | `string[]` | `["vector", "ai", "search"]` | Tags on the API group. |
92
+
93
+ ### Authentication
94
+
95
+ ```ts
96
+ export const vector = registerVector(ws, { authTable: users, canonical: "kb" });
97
+ ```
98
+
99
+ When `authenticated` is on, every endpoint requires a signed-in user. Documents get a `user_id` column, and the list, get, delete, and reindex endpoints only return the caller's own documents.
100
+
101
+ `/search`, `/embed`, and the `vector_search` tool also require sign-in, but search runs across **all** indexed chunks, not only the caller's. Do not rely on it to keep one user's content away from another user.
102
+
103
+ ---
104
+
105
+ ## API Endpoints
106
+
107
+ The endpoints live in one API group, at `https://<your-instance>/api:<canonical>/<routePrefix>/...`. Without a `canonical` option, Xano assigns the group's canonical on deploy. With `canonical: "kb"`, the base is `/api:kb/kb/`.
108
+
109
+ | Verb | Path | Inputs | Returns |
110
+ | :--- | :--- | :--- | :--- |
111
+ | `POST` | `/documents/create` | `title`, `content?`, `media_data?`, `mime_type?`, `metadata?`, `strategy?`, `chunk_size?`, `chunk_overlap?` | `{ document, chunk_count, status }` |
112
+ | `GET` | `/documents` | `page?` (1), `per_page?` (20) | Paged `{ items, curPage, perPage, itemsReceived, itemsTotal, pageTotal }` |
113
+ | `GET` | `/documents/{id}` | `id` | `{ document, chunks }` |
114
+ | `DELETE` | `/documents/{id}/delete` | `id` | `{ deleted, id }`. Deletes the document's chunks too. |
115
+ | `POST` | `/documents/{id}/reindex` | `id`, `strategy?`, `chunk_size?`, `chunk_overlap?` | `{ document_id, status, chunk_count }` |
116
+ | `POST` | `/search` | `query?`, `query_media_data?`, `query_mime_type?`, `query_embedding?`, `limit?`, `threshold?` | `{ results, count }` |
117
+ | `POST` | `/embed` | `text?`, `media_data?`, `mime_type?`, `model?` | `{ embedding, dimensions }` |
118
+
119
+ `media_data` is base64. `mime_type` defaults to `text/plain`. Send the user's auth token as `Authorization: Bearer <token>` when `authenticated` is on.
120
+
121
+ The examples below use `const API = "https://<your-instance>/api:<canonical>/<routePrefix>";`.
122
+
123
+ ---
124
+
125
+ ## Examples
126
+
127
+ ### Ingest a text document
128
+
129
+ ```ts
130
+ await fetch(`${API}/documents/create`, {
131
+ method: "POST",
132
+ headers: { "Content-Type": "application/json" },
133
+ body: JSON.stringify({
134
+ title: "System Architecture Guide",
135
+ content: "# System Architecture\nOur service runs on Kubernetes with PostgreSQL...",
136
+ mime_type: "text/markdown",
137
+ strategy: "markdown",
138
+ chunk_size: 400,
139
+ chunk_overlap: 40,
140
+ }),
141
+ });
142
+ ```
143
+
144
+ ### Ingest an image, audio, or video file
145
+
146
+ ```ts
147
+ await fetch(`${API}/documents/create`, {
148
+ method: "POST",
149
+ headers: { "Content-Type": "application/json" },
150
+ body: JSON.stringify({
151
+ title: "Product Diagram",
152
+ content: "Diagram illustrating cloud sync architecture.",
153
+ media_data: "<base64_image_data>",
154
+ mime_type: "image/png",
155
+ metadata: { category: "diagrams", width: 1024, height: 768 },
156
+ }),
157
+ });
158
+ ```
159
+
160
+ ### Search
161
+
162
+ ```ts
163
+ const res = await fetch(`${API}/search`, {
164
+ method: "POST",
165
+ headers: { "Content-Type": "application/json" },
166
+ body: JSON.stringify({ query: "architecture diagrams explaining cloud sync", limit: 5 }),
167
+ });
168
+ const { results, count } = await res.json();
169
+ ```
170
+
171
+ Send `query_media_data` + `query_mime_type` to search with an image or audio clip, or `query_embedding` to search with a 768-dim vector you already have.
172
+
173
+ ---
174
+
175
+ ## AI Agent Search Tool
176
+
177
+ Pass `vector.searchTool` in an agent's or MCP server's `tools`:
178
+
179
+ ```ts
180
+ import { agent } from "@xano/sdk";
181
+
182
+ export const supportAgent = agent({
183
+ name: "support_agent",
184
+ llm: {
185
+ type: "google-genai",
186
+ model: "gemini-2.5-flash",
187
+ apiKey: "{{ $env.GEMINI_API_KEY }}",
188
+ systemPrompt: "Answer questions using the vector_search tool. Cite your sources.",
189
+ },
190
+ tools: [vector.searchTool],
191
+ });
192
+
193
+ ws.registerAgents([supportAgent]);
194
+ ```
195
+
196
+ The tool takes `query`, optional `media_data` / `mime_type`, and `limit` (default 5).
197
+
198
+ ---
199
+
200
+ ## Building defs without registering
201
+
202
+ `createVector(options)` returns the same defs as `registerVector` without touching a workspace: `document`, `chunk`, `embedFn`, `chunkFn`, `ingestFn`, `searchFn`, `searchTool`, `group`, and `queries`. The individual factories (`documentTable`, `chunkTable`, `generateEmbeddingFn`, …) are exported too.
203
+
204
+ Call `registerVector` once per workspace; a second call throws. To run two pipelines in one workspace, register the second set yourself from `createVector` with a different `canonical` and `names.searchTool` (the tool name is not derived from `canonical`).
205
+
206
+ ---
207
+
208
+ ## License
209
+
210
+ MIT