UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

127 lines • 6.09 kB
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= import { z } from 'zod'; import { timeoutShape } from "../../core/api/config.js"; import { DEFAULT_TIMEOUT } from "../../core/api/constants.js"; import { REDACTED_SECRET, secretSchema, secretStr } from "../secrets.js"; export const QdrantConfig = z.object({ ...timeoutShape, url: z .string() .optional() .describe('Full URL of the Qdrant server, such as a Qdrant Cloud cluster URL; when set, `host`, `port` and `https` are ignored.'), host: z.string().optional().meta({ description: 'Host name of the Qdrant server when `url` is unset.', default: 'localhost', }), port: z .number() .optional() .meta({ description: 'Port of the Qdrant server when `url` is unset.', default: 6333 }), https: z .boolean() .optional() .meta({ description: 'Connect to `host` over HTTPS when `url` is unset.', default: false }), apiKey: secretStr().optional().describe('Qdrant API key, required by Qdrant Cloud.'), collection: z .string() .optional() .describe('Collection the mount root shows; unset lists every collection as a top-level folder.'), groupBy: z.array(z.string()).optional().meta({ description: "Payload fields that become folder levels, one per field in order; dotted paths reach nested keys. Unset puts every point's files directly under the collection.", default: [], }), basenameFields: z.array(z.string()).optional().meta({ description: '`groupBy` fields whose folder names keep only the last path or URL segment of the value; two values with one basename under the same parent are refused as a collision.', default: [], }), idField: z.string().optional().meta({ description: "Key the point id is written under in a point's `.json`; it replaces a payload field of that name.", default: 'id', }), nameField: z .string() .optional() .describe("Payload field whose value prefixes each point's file stem as `<name>__<id>`; unset names files by point id alone."), textField: z .string() .optional() .describe("Payload field served as the point's `.txt` file and printed by `search`; unset leaves no `.txt`, and `search` returns the `.json`."), blobField: z .string() .optional() .describe('Payload field of raw or base64 bytes served as `<id>.<blobExt>` and left out of the `.json`; unset adds no blob file.'), blobExt: z .string() .optional() .meta({ description: 'File extension of the blob file, without the dot.', default: 'bin' }), vectorField: z .string() .optional() .describe('Payload field holding a copy of the vector, left out of the `.json`.'), searchLimit: z .number() .optional() .meta({ description: 'Results `search` returns when `--top-k` is not given.', default: 10 }), maxRows: z.number().optional().meta({ description: 'Most points one folder listing scrolls; points past it are left out, and a group folder lists only the values those points carry.', default: 1000, }), embeddingModel: z.string().optional().meta({ description: 'Model the server embeds a `search` query with under `cloudInference`; it must match the model the stored vectors came from.', default: 'sentence-transformers/all-MiniLM-L6-v2', }), cloudInference: z.boolean().optional().meta({ description: 'Send the `search` query text to the server to embed, which needs a cluster with inference enabled (Qdrant Cloud). `embed` takes precedence; with neither, `search` refuses the query.', default: false, }), // Declared so parse keeps it, and marked secret so no snapshot carries // it: a restored mount asks for a fresh VFS rather than searching // with a hook it cannot have. embed: secretSchema(z.custom((value) => typeof value === 'function')) .optional() .describe('Async function that turns a `search` query into a vector in-process, `(text: string) => Promise<number[]>`.'), }); export function resolveQdrantConfig(config) { return { timeout: config.timeout ?? DEFAULT_TIMEOUT, url: config.url ?? null, host: config.host ?? 'localhost', port: config.port ?? 6333, https: config.https ?? false, apiKey: config.apiKey ?? null, collection: config.collection ?? null, groupBy: config.groupBy ?? [], basenameFields: config.basenameFields ?? [], idField: config.idField ?? 'id', nameField: config.nameField ?? null, textField: config.textField ?? null, blobField: config.blobField ?? null, blobExt: config.blobExt ?? 'bin', vectorField: config.vectorField ?? null, searchLimit: config.searchLimit ?? 10, maxRows: config.maxRows ?? 1000, embeddingModel: config.embeddingModel ?? 'sentence-transformers/all-MiniLM-L6-v2', cloudInference: config.cloudInference ?? false, embed: config.embed ?? null, }; } export function redactQdrantConfig(config) { return { ...config, apiKey: config.apiKey === null ? null : REDACTED_SECRET, embed: config.embed === null ? null : REDACTED_SECRET, }; } //# sourceMappingURL=config.js.map