Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/tame-wasps-carry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@mixedbread/cli": patch
---

- Fixed `--base-url` global option not working
- Migrated to zod v4
10 changes: 5 additions & 5 deletions packages/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@

### Minor Changes

- 37cf096: - Change max parallel upload/deletion to 200
- Change default parallel and `parallel` in config to 100
- 37cf096: - Changed max parallel upload/deletion to 200
- Changed default parallel and `parallel` in config to 100

## 1.1.0

### Minor Changes

- 384880d: Add intelligent shell completion for vector store names
- 384880d: Added intelligent shell completion for vector store names

- **Dynamic completions**: Tab completion now suggests vector store names in commands like `mxbai vs sync [TAB]`, `mxbai vs upload [TAB]`, etc.
- **Multi-key support**: Completions work seamlessly with multiple API keys, showing stores for the current default key
Expand All @@ -25,13 +25,13 @@

### Patch Changes

- d60b52d: Fix metadata types before uploading
- d60b52d: Fixed metadata types before uploading

## 1.0.0

### Major Changes

- 617f988: Add force upload option and standardize CLI flags (breaking changes)
- 617f988: Added force upload option and standardize CLI flags (breaking changes)

## Breaking Changes

Expand Down
9 changes: 5 additions & 4 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,11 @@ files:
When using the CLI, configuration values are resolved in the following order (highest to lowest priority):

1. **Command-line flags** - Direct CLI options (e.g., `--strategy high_quality`)
2. **Manifest entry** - File-specific settings in manifest files
3. **Manifest defaults** - Default settings in manifest files
4. **Config file** - User configuration file settings
5. **Built-in defaults** - CLI default values
2. **Environment variables** - System environment settings (e.g., `MXBAI_API_KEY`, `MXBAI_BASE_URL`, `MXBAI_CONFIG_PATH`, `MXBAI_DEBUG`)
3. **Manifest entry** - File-specific settings in manifest files
4. **Manifest defaults** - Default settings in manifest files
5. **Config file** - User configuration file settings
6. **Built-in defaults** - CLI default values

This allows flexible configuration while maintaining predictable behavior.

Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"ora": "^8.0.1",
"p-limit": "^6.2.0",
"yaml": "^2.4.5",
"zod": "^3.25.56"
"zod": "^4.1.5"
},
"devDependencies": {
"@jest/globals": "^30.0.2",
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/src/commands/config/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
} from "../../utils/global-options";

const RemoveKeySchema = z.object({
name: z.string().min(1, { message: '"name" is required' }),
name: z.string().min(1, { error: '"name" is required' }),
yes: z.boolean().optional(),
});

Expand Down Expand Up @@ -98,7 +98,7 @@ export function createKeysCommand(): Command {
// Populate completion cache for the new key
const client = createClient({
apiKey: key,
baseURL: parsedOptions.baseURL,
baseUrl: parsedOptions.baseUrl,
});
refreshCacheForKey(name, client);
});
Expand Down Expand Up @@ -232,7 +232,7 @@ export function createKeysCommand(): Command {
// Refresh cache for the newly set default key
const client = createClient({
apiKey: config.api_keys[name],
baseURL: parsedOptions.baseURL,
baseUrl: parsedOptions.baseUrl,
});
refreshCacheForKey(name, client);
});
Expand Down
8 changes: 4 additions & 4 deletions packages/cli/src/commands/vector-store/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ import { validateMetadata } from "../../utils/metadata";
import { formatOutput } from "../../utils/output";

const CreateVectorStoreSchema = extendGlobalOptions({
name: z.string().min(1, { message: '"name" is required' }),
name: z.string().min(1, { error: '"name" is required' }),
description: z.string().optional(),
expiresAfter: z.coerce
.number({ message: '"expires-after" must be a number' })
.int({ message: '"expires-after" must be an integer' })
.positive({ message: '"expires-after" must be positive' })
.number({ error: '"expires-after" must be a number' })
.int({ error: '"expires-after" must be an integer' })
.positive({ error: '"expires-after" must be positive' })
.optional(),
metadata: z.string().optional(),
});
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/commands/vector-store/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
import { resolveVectorStore } from "../../utils/vector-store";

const DeleteVectorStoreSchema = extendGlobalOptions({
nameOrId: z.string().min(1, { message: '"name-or-id" is required' }),
nameOrId: z.string().min(1, { error: '"name-or-id" is required' }),
yes: z.boolean().optional(),
});

Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/commands/vector-store/files/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import {
import { resolveVectorStore } from "../../../utils/vector-store";

const DeleteFileSchema = extendGlobalOptions({
nameOrId: z.string().min(1, { message: '"name-or-id" is required' }),
fileId: z.string().min(1, { message: '"file-id" is required' }),
nameOrId: z.string().min(1, { error: '"name-or-id" is required' }),
fileId: z.string().min(1, { error: '"file-id" is required' }),
yes: z.boolean().optional(),
});

Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/commands/vector-store/files/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import { formatBytes, formatOutput } from "../../../utils/output";
import { resolveVectorStore } from "../../../utils/vector-store";

const GetFileSchema = extendGlobalOptions({
nameOrId: z.string().min(1, { message: '"name-or-id" is required' }),
fileId: z.string().min(1, { message: '"file-id" is required' }),
nameOrId: z.string().min(1, { error: '"name-or-id" is required' }),
fileId: z.string().min(1, { error: '"file-id" is required' }),
});

export function createGetCommand(): Command {
Expand Down
12 changes: 6 additions & 6 deletions packages/cli/src/commands/vector-store/files/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ import { resolveVectorStore } from "../../../utils/vector-store";
import type { FilesOptions } from ".";

const ListFilesSchema = extendGlobalOptions({
nameOrId: z.string().min(1, { message: '"name-or-id" is required' }),
nameOrId: z.string().min(1, { error: '"name-or-id" is required' }),
status: z
.enum(["all", "completed", "in_progress", "failed"], {
message: '"status" must be one of: all, completed, in_progress, failed',
error: '"status" must be one of: all, completed, in_progress, failed',
})
.optional(),
limit: z.coerce
.number({ message: '"limit" must be a number' })
.int({ message: '"limit" must be an integer' })
.positive({ message: '"limit" must be positive' })
.max(100, { message: '"limit" must be less than or equal to 100' })
.number({ error: '"limit" must be a number' })
.int({ error: '"limit" must be an integer' })
.positive({ error: '"limit" must be positive' })
.max(100, { error: '"limit" must be less than or equal to 100' })
.optional(),
});

Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/commands/vector-store/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { formatBytes, formatOutput } from "../../utils/output";
import { resolveVectorStore } from "../../utils/vector-store";

const GetVectorStoreSchema = extendGlobalOptions({
nameOrId: z.string().min(1, { message: '"name-or-id" is required' }),
nameOrId: z.string().min(1, { error: '"name-or-id" is required' }),
});

interface GetOptions extends GlobalOptions {}
Expand Down
8 changes: 4 additions & 4 deletions packages/cli/src/commands/vector-store/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ import {
const ListVectorStoreSchema = extendGlobalOptions({
filter: z.string().optional(),
limit: z.coerce
.number({ message: '"limit" must be a number' })
.int({ message: '"limit" must be an integer' })
.positive({ message: '"limit" must be positive' })
.max(100, { message: '"limit" must be less than or equal to 100' })
.number({ error: '"limit" must be a number' })
.int({ error: '"limit" must be an integer' })
.positive({ error: '"limit" must be positive' })
.max(100, { error: '"limit" must be less than or equal to 100' })
.optional(),
});

Expand Down
18 changes: 9 additions & 9 deletions packages/cli/src/commands/vector-store/qa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ import { formatOutput } from "../../utils/output";
import { resolveVectorStore } from "../../utils/vector-store";

const QAVectorStoreSchema = extendGlobalOptions({
nameOrId: z.string().min(1, { message: '"name-or-id" is required' }),
question: z.string().min(1, { message: '"question" is required' }),
nameOrId: z.string().min(1, { error: '"name-or-id" is required' }),
question: z.string().min(1, { error: '"question" is required' }),
topK: z.coerce
.number({ message: '"top-k" must be a number' })
.int({ message: '"top-k" must be an integer' })
.positive({ message: '"top-k" must be positive' })
.max(100, { message: '"top-k" must be less than or equal to 100' })
.number({ error: '"top-k" must be a number' })
.int({ error: '"top-k" must be an integer' })
.positive({ error: '"top-k" must be positive' })
.max(100, { error: '"top-k" must be less than or equal to 100' })
.optional(),
threshold: z.coerce
.number({ message: '"threshold" must be a number' })
.min(0, { message: '"threshold" must be greater than or equal to 0' })
.max(1, { message: '"threshold" must be less than or equal to 1' })
.number({ error: '"threshold" must be a number' })
.min(0, { error: '"threshold" must be greater than or equal to 0' })
.max(1, { error: '"threshold" must be less than or equal to 1' })
.optional(),
cite: z.boolean().optional(),
multimodal: z.boolean().optional(),
Expand Down
18 changes: 9 additions & 9 deletions packages/cli/src/commands/vector-store/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,18 @@ import { formatCountWithSuffix, formatOutput } from "../../utils/output";
import { resolveVectorStore } from "../../utils/vector-store";

const SearchVectorStoreSchema = extendGlobalOptions({
nameOrId: z.string().min(1, { message: '"name-or-id" is required' }),
query: z.string().min(1, { message: '"query" is required' }),
nameOrId: z.string().min(1, { error: '"name-or-id" is required' }),
query: z.string().min(1, { error: '"query" is required' }),
topK: z.coerce
.number({ message: '"top-k" must be a number' })
.int({ message: '"top-k" must be an integer' })
.positive({ message: '"top-k" must be positive' })
.max(100, { message: '"top-k" must be less than or equal to 100' })
.number({ error: '"top-k" must be a number' })
.int({ error: '"top-k" must be an integer' })
.positive({ error: '"top-k" must be positive' })
.max(100, { error: '"top-k" must be less than or equal to 100' })
.optional(),
threshold: z.coerce
.number({ message: '"threshold" must be a number' })
.min(0, { message: '"threshold" must be greater than or equal to 0' })
.max(1, { message: '"threshold" must be less than or equal to 1' })
.number({ error: '"threshold" must be a number' })
.min(0, { error: '"threshold" must be greater than or equal to 0' })
.max(1, { error: '"threshold" must be less than or equal to 1' })
.optional(),
returnMetadata: z.boolean().optional(),
rerank: z.boolean().optional(),
Expand Down
14 changes: 7 additions & 7 deletions packages/cli/src/commands/vector-store/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,24 @@ import { getSyncedFiles } from "../../utils/sync-state";
import { resolveVectorStore } from "../../utils/vector-store";

const SyncVectorStoreSchema = extendGlobalOptions({
nameOrId: z.string().min(1, { message: '"name-or-id" is required' }),
nameOrId: z.string().min(1, { error: '"name-or-id" is required' }),
patterns: z
.array(z.string())
.min(1, { message: "At least one pattern is required" }),
.min(1, { error: "At least one pattern is required" }),
strategy: z.enum(["fast", "high_quality"]).optional(),
contextualization: z
.boolean({ message: '"contextualization" must be a boolean' })
.boolean({ error: '"contextualization" must be a boolean' })
.optional(),
fromGit: z.string().optional(),
dryRun: z.boolean().optional(),
yes: z.boolean().optional(),
force: z.boolean().optional(),
metadata: z.string().optional(),
parallel: z.coerce
.number({ message: '"parallel" must be a number' })
.int({ message: '"parallel" must be an integer' })
.min(1, { message: '"parallel" must be at least 1' })
.max(200, { message: '"parallel" must be less than or equal to 200' })
.number({ error: '"parallel" must be a number' })
.int({ error: '"parallel" must be an integer' })
.min(1, { error: '"parallel" must be at least 1' })
.max(200, { error: '"parallel" must be less than or equal to 200' })
.optional()
.default(100),
});
Expand Down
8 changes: 4 additions & 4 deletions packages/cli/src/commands/vector-store/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ import { formatOutput } from "../../utils/output";
import { resolveVectorStore } from "../../utils/vector-store";

const UpdateVectorStoreSchema = extendGlobalOptions({
nameOrId: z.string().min(1, { message: '"name-or-id" is required' }),
nameOrId: z.string().min(1, { error: '"name-or-id" is required' }),
name: z.string().optional(),
description: z.string().optional(),
expiresAfter: z.coerce
.number({ message: '"expires-after" must be a number' })
.int({ message: '"expires-after" must be an integer' })
.positive({ message: '"expires-after" must be positive' })
.number({ error: '"expires-after" must be a number' })
.int({ error: '"expires-after" must be an integer' })
.positive({ error: '"expires-after" must be positive' })
.optional(),
metadata: z.string().optional(),
});
Expand Down
14 changes: 7 additions & 7 deletions packages/cli/src/commands/vector-store/upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,23 @@ import {
} from "../../utils/vector-store";

const UploadVectorStoreSchema = extendGlobalOptions({
nameOrId: z.string().min(1, { message: '"name-or-id" is required' }),
nameOrId: z.string().min(1, { error: '"name-or-id" is required' }),
patterns: z.array(z.string()).optional(),
strategy: z
.enum(["fast", "high_quality"], {
message: '"strategy" must be either "fast" or "high_quality"',
error: '"strategy" must be either "fast" or "high_quality"',
})
.optional(),
contextualization: z
.boolean({ message: '"contextualization" must be a boolean' })
.boolean({ error: '"contextualization" must be a boolean' })
.optional(),
metadata: z.string().optional(),
dryRun: z.boolean().optional(),
parallel: z.coerce
.number({ message: '"parallel" must be a number' })
.int({ message: '"parallel" must be an integer' })
.min(1, { message: '"parallel" must be at least 1' })
.max(200, { message: '"parallel" must be less than or equal to 200' })
.number({ error: '"parallel" must be a number' })
.int({ error: '"parallel" must be an integer' })
.min(1, { error: '"parallel" must be at least 1' })
.max(200, { error: '"parallel" must be less than or equal to 200' })
.optional(),
unique: z.boolean().optional(),
manifest: z.string().optional(),
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/utils/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { getApiKey, getBaseURL } from "./config";

export function createClient(options?: {
apiKey?: string;
baseURL?: string;
baseUrl?: string;
}): Mixedbread {
const apiKey = getApiKey(options);
const baseURL = getBaseURL(options);
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/utils/completion-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export async function refreshCacheForKey(
}

export async function refreshAllCaches(options: {
baseURL?: string;
baseUrl?: string;
}): Promise<void> {
const config = loadConfig();

Expand All @@ -120,7 +120,7 @@ export async function refreshAllCaches(options: {
for (const keyName of Object.keys(config.api_keys)) {
const client = createClient({
apiKey: config.api_keys[keyName],
baseURL: options.baseURL,
baseUrl: options.baseUrl,
});

await refreshCacheForKey(keyName, client);
Expand Down
Loading