voyageai-cli 1.3.0 → 1.4.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/CHANGELOG.md CHANGED
@@ -7,6 +7,8 @@ Format based on [Keep a Changelog](https://keepachangelog.com/).
7
7
  ## [Unreleased]
8
8
 
9
9
  ### Added
10
+ - `vai ingest` — Bulk import from JSONL/JSON/CSV/text with batching, progress bar, and dry-run
11
+ - `vai similarity` — Compute cosine similarity between texts without MongoDB
10
12
  - `vai demo` — Interactive guided walkthrough of all features
11
13
  - ASCII banner when running `vai` with no arguments
12
14
  - CONTRIBUTING.md for open-source contributors
package/NOTICE ADDED
@@ -0,0 +1,23 @@
1
+ voyageai-cli — Community CLI for Voyage AI and MongoDB Atlas Vector Search
2
+
3
+ Copyright (c) 2026 Michael Lynn
4
+
5
+ DISCLAIMER:
6
+ This software is an independent, community-built tool. It is NOT an official
7
+ product of MongoDB, Inc. or Voyage AI (a MongoDB company). It is not supported,
8
+ endorsed, or maintained by either organization.
9
+
10
+ This tool interacts with:
11
+ - The MongoDB Atlas Embedding and Reranking API (https://ai.mongodb.com/v1/)
12
+ - MongoDB Atlas Vector Search (https://www.mongodb.com/docs/atlas/atlas-vector-search/)
13
+
14
+ For official documentation, support, and products:
15
+ - MongoDB: https://www.mongodb.com
16
+ - Voyage AI: https://www.mongodb.com/docs/voyageai/
17
+ - MongoDB Support: https://support.mongodb.com
18
+
19
+ "MongoDB", "MongoDB Atlas", and "Voyage AI" are trademarks of MongoDB, Inc.
20
+ All trademarks belong to their respective owners.
21
+
22
+ This software is provided "as is" without warranty of any kind. See LICENSE
23
+ for the full MIT License terms.
package/README.md CHANGED
@@ -6,6 +6,12 @@ CLI for [Voyage AI](https://www.mongodb.com/docs/voyageai/) embeddings, rerankin
6
6
 
7
7
  Generate embeddings, rerank search results, store vectors in Atlas, and run semantic search — all from the command line.
8
8
 
9
+ > **⚠️ Disclaimer:** This is an independent, community-built tool. It is **not** an official product of MongoDB, Inc. or Voyage AI. It is not supported, endorsed, or maintained by either company. For official documentation, support, and products, visit:
10
+ > - **MongoDB:** [mongodb.com](https://www.mongodb.com) | [MongoDB Atlas](https://www.mongodb.com/atlas) | [Support](https://support.mongodb.com)
11
+ > - **Voyage AI:** [MongoDB Voyage AI Docs](https://www.mongodb.com/docs/voyageai/)
12
+ >
13
+ > Use at your own risk. No warranty is provided. See [LICENSE](LICENSE) for details.
14
+
9
15
  ## Install
10
16
 
11
17
  ```bash
@@ -60,6 +66,19 @@ vai rerank --query "best database" --documents-file candidates.json --top-k 3
60
66
  vai rerank --query "query" --documents "doc1" "doc2" --model rerank-2.5-lite
61
67
  ```
62
68
 
69
+ ### `vai similarity` — Compare text similarity
70
+
71
+ ```bash
72
+ # Compare two texts
73
+ vai similarity "MongoDB is a document database" "MongoDB Atlas is a cloud database"
74
+
75
+ # Compare one text against many
76
+ vai similarity "database performance" --against "MongoDB is fast" "PostgreSQL is relational"
77
+
78
+ # From files
79
+ vai similarity --file1 doc1.txt --file2 doc2.txt
80
+ ```
81
+
63
82
  ### `vai store` — Embed and insert into MongoDB Atlas
64
83
 
65
84
  Requires `MONGODB_URI` environment variable.
@@ -79,6 +98,29 @@ vai store --db myapp --collection docs --field embedding \
79
98
  --file documents.jsonl
80
99
  ```
81
100
 
101
+ ### `vai ingest` — Bulk import with progress
102
+
103
+ ```bash
104
+ # JSONL (one JSON object per line with a "text" field)
105
+ vai ingest --file corpus.jsonl --db myapp --collection docs --field embedding
106
+
107
+ # JSON array
108
+ vai ingest --file documents.json --db myapp --collection docs --field embedding
109
+
110
+ # CSV (specify text column)
111
+ vai ingest --file data.csv --db myapp --collection docs --field embedding --text-column content
112
+
113
+ # Plain text (one document per line)
114
+ vai ingest --file lines.txt --db myapp --collection docs --field embedding
115
+
116
+ # Options
117
+ vai ingest --file corpus.jsonl --db myapp --collection docs --field embedding \
118
+ --model voyage-4 --batch-size 100 --input-type document
119
+
120
+ # Preview without embedding
121
+ vai ingest --file corpus.jsonl --db myapp --collection docs --field embedding --dry-run
122
+ ```
123
+
82
124
  ### `vai search` — Vector similarity search
83
125
 
84
126
  Requires `MONGODB_URI` environment variable.
@@ -237,6 +279,10 @@ Free tier: 200M tokens for most models. All Voyage 4 series models share the sam
237
279
  - A [MongoDB Atlas](https://www.mongodb.com/atlas) account (free tier works)
238
280
  - A [Voyage AI model API key](https://www.mongodb.com/docs/voyageai/management/api-keys/) (created in Atlas)
239
281
 
282
+ ## Disclaimer
283
+
284
+ This is a community tool and is not affiliated with, endorsed by, or supported by MongoDB, Inc. or Voyage AI. All trademarks belong to their respective owners. For official support, visit [mongodb.com](https://www.mongodb.com).
285
+
240
286
  ## License
241
287
 
242
288
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "voyageai-cli",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "CLI for Voyage AI embeddings, reranking, and MongoDB Atlas Vector Search",
5
5
  "bin": {
6
6
  "vai": "./src/cli.js"
package/src/cli.js CHANGED
@@ -4,6 +4,7 @@
4
4
  require('dotenv').config({ quiet: true });
5
5
 
6
6
  const { program } = require('commander');
7
+ const pc = require('picocolors');
7
8
  const { registerEmbed } = require('./commands/embed');
8
9
  const { registerRerank } = require('./commands/rerank');
9
10
  const { registerStore } = require('./commands/store');
@@ -13,12 +14,17 @@ const { registerModels } = require('./commands/models');
13
14
  const { registerPing } = require('./commands/ping');
14
15
  const { registerConfig } = require('./commands/config');
15
16
  const { registerDemo } = require('./commands/demo');
16
- const { showBanner, showQuickStart } = require('./lib/banner');
17
+ const { registerExplain } = require('./commands/explain');
18
+ const { registerSimilarity } = require('./commands/similarity');
19
+ const { registerIngest } = require('./commands/ingest');
20
+ const { showBanner, showQuickStart, getVersion } = require('./lib/banner');
21
+
22
+ const version = getVersion();
17
23
 
18
24
  program
19
25
  .name('vai')
20
26
  .description('Voyage AI embeddings, reranking, and Atlas Vector Search CLI')
21
- .version('1.1.0');
27
+ .version(`vai/${version} (community tool — not an official MongoDB or Voyage AI product)`, '-V, --version', 'output the version number');
22
28
 
23
29
  registerEmbed(program);
24
30
  registerRerank(program);
@@ -29,6 +35,15 @@ registerModels(program);
29
35
  registerPing(program);
30
36
  registerConfig(program);
31
37
  registerDemo(program);
38
+ registerExplain(program);
39
+ registerSimilarity(program);
40
+ registerIngest(program);
41
+
42
+ // Append disclaimer to all help output
43
+ program.addHelpText('after', `
44
+ ${pc.dim('Community tool — not an official MongoDB or Voyage AI product.')}
45
+ ${pc.dim('Docs: https://www.mongodb.com/docs/voyageai/')}
46
+ `);
32
47
 
33
48
  // If no args (just `vai`), show banner + quick start + help
34
49
  if (process.argv.length <= 2) {
@@ -130,6 +130,9 @@ function registerDemo(program) {
130
130
  console.log(pc.bold(' 🧭 Voyage AI Interactive Demo'));
131
131
  console.log(pc.dim(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
132
132
  console.log('');
133
+ console.log(pc.dim(' Note: This is a community tool, not an official MongoDB or Voyage AI product.'));
134
+ console.log(pc.dim(' For official docs and support: https://www.mongodb.com/docs/voyageai/'));
135
+ console.log('');
133
136
  console.log(' This walkthrough demonstrates embeddings, semantic search, and reranking');
134
137
  console.log(' using Voyage AI models via MongoDB Atlas.');
135
138
  console.log('');
@@ -0,0 +1,170 @@
1
+ 'use strict';
2
+
3
+ const pc = require('picocolors');
4
+ const { resolveConcept, listConcepts, getConcept } = require('../lib/explanations');
5
+
6
+ const DISCLAIMER = pc.dim(' This tool is not affiliated with MongoDB, Inc. or Voyage AI.');
7
+
8
+ /**
9
+ * Show the list of available topics.
10
+ */
11
+ function showTopicList() {
12
+ console.log('');
13
+ console.log(` 🧭 ${pc.bold('Voyage AI Concepts')}`);
14
+ console.log('');
15
+ console.log(' Available topics:');
16
+
17
+ const concepts = listConcepts();
18
+ const maxKeyLen = Math.max(...concepts.map(k => k.length));
19
+
20
+ for (const key of concepts) {
21
+ const concept = getConcept(key);
22
+ const padding = ' '.repeat(maxKeyLen - key.length + 4);
23
+ console.log(` ${pc.cyan(key)}${padding}${pc.dim(concept.summary)}`);
24
+ }
25
+
26
+ console.log('');
27
+ console.log(` Usage: ${pc.cyan('vai explain <topic>')}`);
28
+ console.log('');
29
+ }
30
+
31
+ /**
32
+ * Show a formatted explanation of a concept.
33
+ * @param {string} key - canonical concept key
34
+ */
35
+ function showExplanation(key) {
36
+ const concept = getConcept(key);
37
+ if (!concept) return;
38
+
39
+ console.log('');
40
+ console.log(` 🧭 ${pc.bold(concept.title)}`);
41
+ console.log(` ${pc.dim('━'.repeat(concept.title.length + 2))}`);
42
+ console.log('');
43
+
44
+ // Indent the content
45
+ const lines = concept.content.split('\n');
46
+ for (const line of lines) {
47
+ console.log(` ${line}`);
48
+ }
49
+
50
+ console.log('');
51
+ console.log(` ${pc.bold('Key points:')}`);
52
+
53
+ // Extract key points from content — use a curated approach
54
+ // Actually, the content itself is the explanation. Let's show tryIt and links.
55
+
56
+ if (concept.tryIt && concept.tryIt.length > 0) {
57
+ console.log('');
58
+ console.log(` ${pc.bold('Try it:')}`);
59
+ for (const cmd of concept.tryIt) {
60
+ console.log(` ${pc.dim('$')} ${pc.cyan(cmd)}`);
61
+ }
62
+ }
63
+
64
+ if (concept.links && concept.links.length > 0) {
65
+ console.log('');
66
+ console.log(` ${pc.bold('Learn more:')}`);
67
+ for (const link of concept.links) {
68
+ console.log(` ${link}`);
69
+ }
70
+ }
71
+
72
+ console.log('');
73
+ console.log(DISCLAIMER);
74
+ console.log('');
75
+ }
76
+
77
+ /**
78
+ * Show a JSON explanation of a concept.
79
+ * @param {string} key - canonical concept key
80
+ */
81
+ function showJsonExplanation(key) {
82
+ const concept = getConcept(key);
83
+ if (!concept) return;
84
+
85
+ // Strip ANSI codes for JSON
86
+ const stripAnsi = (str) => str.replace(/\x1b\[[0-9;]*m/g, '');
87
+
88
+ const output = {
89
+ concept: key,
90
+ title: concept.title,
91
+ summary: concept.summary,
92
+ content: stripAnsi(concept.content),
93
+ links: concept.links,
94
+ tryIt: concept.tryIt,
95
+ };
96
+
97
+ console.log(JSON.stringify(output, null, 2));
98
+ }
99
+
100
+ /**
101
+ * Find close matches for an unknown concept.
102
+ * @param {string} input
103
+ * @returns {string[]} up to 3 suggestions
104
+ */
105
+ function findSuggestions(input) {
106
+ const normalized = input.toLowerCase().trim();
107
+ const allKeys = listConcepts();
108
+
109
+ // Simple substring matching
110
+ const matches = allKeys.filter(k =>
111
+ k.includes(normalized) || normalized.includes(k)
112
+ );
113
+
114
+ if (matches.length > 0) return matches.slice(0, 3);
115
+
116
+ // Levenshtein-ish: just return first 3 concepts as fallback
117
+ return allKeys.slice(0, 3);
118
+ }
119
+
120
+ /**
121
+ * Register the explain command on a Commander program.
122
+ * @param {import('commander').Command} program
123
+ */
124
+ function registerExplain(program) {
125
+ program
126
+ .command('explain [concept]')
127
+ .description('Learn about embeddings, reranking, vector search, and more')
128
+ .option('--json', 'Output in JSON format')
129
+ .action((concept, opts) => {
130
+ if (!concept) {
131
+ // Show topic list
132
+ if (opts.json) {
133
+ const topics = listConcepts().map(key => {
134
+ const c = getConcept(key);
135
+ return { key, title: c.title, summary: c.summary };
136
+ });
137
+ console.log(JSON.stringify({ topics }, null, 2));
138
+ } else {
139
+ showTopicList();
140
+ }
141
+ return;
142
+ }
143
+
144
+ const resolved = resolveConcept(concept);
145
+ if (!resolved) {
146
+ const suggestions = findSuggestions(concept);
147
+ console.error('');
148
+ console.error(` ${pc.red('✗')} Unknown topic: ${pc.bold(concept)}`);
149
+ console.error('');
150
+ if (suggestions.length > 0) {
151
+ console.error(' Did you mean?');
152
+ for (const s of suggestions) {
153
+ console.error(` ${pc.cyan('vai explain ' + s)}`);
154
+ }
155
+ console.error('');
156
+ }
157
+ console.error(` Run ${pc.cyan('vai explain')} to see all available topics.`);
158
+ console.error('');
159
+ process.exit(1);
160
+ }
161
+
162
+ if (opts.json) {
163
+ showJsonExplanation(resolved);
164
+ } else {
165
+ showExplanation(resolved);
166
+ }
167
+ });
168
+ }
169
+
170
+ module.exports = { registerExplain };