src / configSchematics.ts
src / configSchematics.ts
import * as path from "node:path";
import * as os from "node:os";
import { createConfigSchematics } from "@lmstudio/sdk";
const DEFAULT_BASE = path.join(os.homedir(), "Documents", "kwikines");
export const configSchematics = createConfigSchematics()
.field(
"wikiBaseDir",
"string",
{
displayName: "Wiki base directory",
hint: `Absolute path (~ allowed) to the folder that holds AGENTS.md, raw/ (immutable sources) and wiki/ (generated pages). This is the only root the plugin can read or write. Example: ${DEFAULT_BASE}`,
},
"",
)
.field(
"chatModelOverride",
"string",
{
displayName: "Chat model identifier (override)",
hint: "Identifier of the chat LLM used internally for ingest / query / lint. Leave empty to auto-pick the first non-vision LLM currently loaded in LM Studio.",
},
"",
)
.field(
"embeddingModelOverride",
"string",
{
displayName: "Embedding model identifier (override)",
hint: "Identifier of the embedding model used for the RAG layer (e.g. nomic-embed-text, bge-*). Leave empty to auto-pick the first embedding model currently loaded in LM Studio.",
},
"",
)
.field(
"vlModelOverride",
"string",
{
displayName: "Vision model identifier (override, for PDF)",
hint: "Identifier of the vision-language model used to transcribe .docx-incompatible .pdf sources on ingest. Leave empty to auto-pick the first vision-capable LLM currently loaded in LM Studio. A VL model must be loaded to ingest a .pdf.",
},
"",
)
.field(
"pdfRenderScale",
"numeric",
{
displayName: "PDF render scale",
hint: "Rasterisation scale for PDF pages before transcription. 1.0 ≈ 72 DPI, 2.0 ≈ 144 DPI. Higher = cleaner transcription but slower.",
slider: { min: 0.5, max: 4, step: 0.25 },
int: false,
},
2.0,
)
.field(
"pdfMaxPages",
"numeric",
{
displayName: "PDF max pages per ingest",
hint: "Optional hard cap on the number of PDF pages transcribed per ingest (safety guard). 0 (default) means unlimited — a .pdf is then ingested whole, like a .md/.docx. Use the ingest 'pages' parameter to transcribe a specific range instead.",
slider: { min: 0, max: 500, step: 1 },
int: true,
},
0,
)
.field(
"pdfLanguage",
"string",
{
displayName: "PDF document language",
hint: "Main expected language of PDF sources: 'fr', 'en', 'auto'… Influences the per-page transcription prompt.",
},
"auto",
)
.field(
"pdfTranscriptionStyle",
"select",
{
displayName: "PDF transcription style",
hint: "faithful = reproduce exactly what's visible. clean = strip repeated headers/footers across pages. structured = bias toward inferring titles and tables.",
options: [
{ value: "faithful", displayName: "faithful" },
{ value: "clean", displayName: "clean" },
{ value: "structured", displayName: "structured" },
],
},
"faithful",
)
.field(
"chunkSizeChars",
"numeric",
{
displayName: "Chunk size (characters)",
hint: "Target size of each wiki chunk fed to the embedding model. Larger = fewer, broader chunks; smaller = more, sharper chunks.",
slider: { min: 300, max: 4000, step: 100 },
int: true,
},
1200,
)
.field(
"chunkOverlapChars",
"numeric",
{
displayName: "Chunk overlap (characters)",
hint: "How many characters consecutive chunks share, so a fact split across a boundary is still retrievable.",
slider: { min: 0, max: 800, step: 25 },
int: true,
},
150,
)
.field(
"defaultTopK",
"numeric",
{
displayName: "Default passages returned (top-k)",
hint: "How many wiki passages kwikines_search / kwikines_query retrieve by default.",
slider: { min: 1, max: 30, step: 1 },
int: true,
},
6,
)
.field(
"hybridSearch",
"boolean",
{
displayName: "Hybrid search (semantic + keyword)",
hint: "Combine cosine similarity with a lightweight BM25 keyword score. Helps for exact names/terms the embedding model blurs.",
},
true,
)
.field(
"autoReindexOnSearch",
"boolean",
{
displayName: "Auto-reindex stale pages on search",
hint: "Before searching, re-embed wiki pages whose file changed since the last index build. Turn off for maximum search speed.",
},
true,
)
.field(
"supervisedIngest",
"boolean",
{
displayName: "Supervised ingest (preview before writing)",
hint: "When ON, kwikines_ingest returns a preview of the pages it intends to create/update and waits for a confirmed call before writing. When OFF, it writes immediately (batch ingest).",
},
true,
)
.field(
"maxFileSizeMb",
"numeric",
{
displayName: "Max source file size (MB)",
hint: "Raw sources larger than this are refused on ingest/read.",
slider: { min: 1, max: 200, step: 1 },
int: true,
},
25,
)
.field(
"verboseLogging",
"boolean",
{
displayName: "Verbose logging",
hint: "Log each ingest / index / search operation to the plugin console.",
},
false,
)
.build();
import * as path from "node:path";
import * as os from "node:os";
import { createConfigSchematics } from "@lmstudio/sdk";
const DEFAULT_BASE = path.join(os.homedir(), "Documents", "kwikines");
export const configSchematics = createConfigSchematics()
.field(
"wikiBaseDir",
"string",
{
displayName: "Wiki base directory",
hint: `Absolute path (~ allowed) to the folder that holds AGENTS.md, raw/ (immutable sources) and wiki/ (generated pages). This is the only root the plugin can read or write. Example: ${DEFAULT_BASE}`,
},
"",
)
.field(
"chatModelOverride",
"string",
{
displayName: "Chat model identifier (override)",
hint: "Identifier of the chat LLM used internally for ingest / query / lint. Leave empty to auto-pick the first non-vision LLM currently loaded in LM Studio.",
},
"",
)
.field(
"embeddingModelOverride",
"string",
{
displayName: "Embedding model identifier (override)",
hint: "Identifier of the embedding model used for the RAG layer (e.g. nomic-embed-text, bge-*). Leave empty to auto-pick the first embedding model currently loaded in LM Studio.",
},
"",
)
.field(
"vlModelOverride",
"string",
{
displayName: "Vision model identifier (override, for PDF)",
hint: "Identifier of the vision-language model used to transcribe .docx-incompatible .pdf sources on ingest. Leave empty to auto-pick the first vision-capable LLM currently loaded in LM Studio. A VL model must be loaded to ingest a .pdf.",
},
"",
)
.field(
"pdfRenderScale",
"numeric",
{
displayName: "PDF render scale",
hint: "Rasterisation scale for PDF pages before transcription. 1.0 ≈ 72 DPI, 2.0 ≈ 144 DPI. Higher = cleaner transcription but slower.",
slider: { min: 0.5, max: 4, step: 0.25 },
int: false,
},
2.0,
)
.field(
"pdfMaxPages",
"numeric",
{
displayName: "PDF max pages per ingest",
hint: "Optional hard cap on the number of PDF pages transcribed per ingest (safety guard). 0 (default) means unlimited — a .pdf is then ingested whole, like a .md/.docx. Use the ingest 'pages' parameter to transcribe a specific range instead.",
slider: { min: 0, max: 500, step: 1 },
int: true,
},
0,
)
.field(
"pdfLanguage",
"string",
{
displayName: "PDF document language",
hint: "Main expected language of PDF sources: 'fr', 'en', 'auto'… Influences the per-page transcription prompt.",
},
"auto",
)
.field(
"pdfTranscriptionStyle",
"select",
{
displayName: "PDF transcription style",
hint: "faithful = reproduce exactly what's visible. clean = strip repeated headers/footers across pages. structured = bias toward inferring titles and tables.",
options: [
{ value: "faithful", displayName: "faithful" },
{ value: "clean", displayName: "clean" },
{ value: "structured", displayName: "structured" },
],
},
"faithful",
)
.field(
"chunkSizeChars",
"numeric",
{
displayName: "Chunk size (characters)",
hint: "Target size of each wiki chunk fed to the embedding model. Larger = fewer, broader chunks; smaller = more, sharper chunks.",
slider: { min: 300, max: 4000, step: 100 },
int: true,
},
1200,
)
.field(
"chunkOverlapChars",
"numeric",
{
displayName: "Chunk overlap (characters)",
hint: "How many characters consecutive chunks share, so a fact split across a boundary is still retrievable.",
slider: { min: 0, max: 800, step: 25 },
int: true,
},
150,
)
.field(
"defaultTopK",
"numeric",
{
displayName: "Default passages returned (top-k)",
hint: "How many wiki passages kwikines_search / kwikines_query retrieve by default.",
slider: { min: 1, max: 30, step: 1 },
int: true,
},
6,
)
.field(
"hybridSearch",
"boolean",
{
displayName: "Hybrid search (semantic + keyword)",
hint: "Combine cosine similarity with a lightweight BM25 keyword score. Helps for exact names/terms the embedding model blurs.",
},
true,
)
.field(
"autoReindexOnSearch",
"boolean",
{
displayName: "Auto-reindex stale pages on search",
hint: "Before searching, re-embed wiki pages whose file changed since the last index build. Turn off for maximum search speed.",
},
true,
)
.field(
"supervisedIngest",
"boolean",
{
displayName: "Supervised ingest (preview before writing)",
hint: "When ON, kwikines_ingest returns a preview of the pages it intends to create/update and waits for a confirmed call before writing. When OFF, it writes immediately (batch ingest).",
},
true,
)
.field(
"maxFileSizeMb",
"numeric",
{
displayName: "Max source file size (MB)",
hint: "Raw sources larger than this are refused on ingest/read.",
slider: { min: 1, max: 200, step: 1 },
int: true,
},
25,
)
.field(
"verboseLogging",
"boolean",
{
displayName: "Verbose logging",
hint: "Log each ingest / index / search operation to the plugin console.",
},
false,
)
.build();