├── .eslintrc.json ├── .github └── workflows │ └── cla.yml ├── .gitignore ├── .gitmodules ├── .npmrc ├── .prettierrc.json ├── .vscode ├── extensions.json └── settings.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── jest.config.js ├── jestSnapshotResolver.js ├── lerna.json ├── package-lock.json ├── package.json ├── packages ├── lms-client │ ├── package.json │ ├── src │ │ ├── Chat.ts │ │ ├── ChatInput.ts │ │ ├── LMStudioClient.ts │ │ ├── PluginContext.ts │ │ ├── cacheQuantizationTypeToCheckbox.ts │ │ ├── createAuthenticatedClientPort.ts │ │ ├── customConfig.ts │ │ ├── diagnostics │ │ │ └── DiagnosticsNamespace.ts │ │ ├── embedding │ │ │ ├── .test-snapshots │ │ │ │ └── EmbeddingModel.heavy.test.ts.snap │ │ │ ├── EmbeddingDynamicHandle.ts │ │ │ ├── EmbeddingModel.heavy.test.ts │ │ │ ├── EmbeddingModel.ts │ │ │ └── EmbeddingNamespace.ts │ │ ├── files │ │ │ ├── FileHandle.ts │ │ │ ├── FilesNamespace.ts │ │ │ ├── ParseDocumentOpts.ts │ │ │ ├── ParseDocumentResult.ts │ │ │ ├── RetrievalOpts.ts │ │ │ └── RetrievalResult.ts │ │ ├── friendlyErrorDeserializer.ts │ │ ├── index.ts │ │ ├── llm │ │ │ ├── .test-snapshots │ │ │ │ ├── LLM.act.heavy.test.ts.snap │ │ │ │ ├── LLM.complete.heavy.test.ts.snap │ │ │ │ ├── LLM.heavy.test.ts.snap │ │ │ │ ├── LLM.respond.heavy.test.ts.snap │ │ │ │ ├── LLM.speculativeDecoding.heavy.test.ts.snap │ │ │ │ └── LLM.vision.heavy.test.ts.snap │ │ │ ├── ActResult.ts │ │ │ ├── LLM.act.heavy.test.ts │ │ │ ├── LLM.complete.heavy.test.ts │ │ │ ├── LLM.heavy.test.ts │ │ │ ├── LLM.respond.heavy.test.ts │ │ │ ├── LLM.speculativeDecoding.heavy.test.ts │ │ │ ├── LLM.ts │ │ │ ├── LLM.vision.heavy.test.ts │ │ │ ├── LLMDynamicHandle.ts │ │ │ ├── LLMNamespace.ts │ │ │ ├── OngoingPrediction.ts │ │ │ ├── PredictionResult.ts │ │ │ └── tool.ts │ │ ├── modelShared │ │ │ ├── DynamicHandle.ts │ │ │ ├── ModelNamespace.ts │ │ │ └── SpecificModel.ts │ │ ├── numberToCheckboxNumeric.ts │ │ ├── plugins │ │ │ ├── PluginsNamespace.ts │ │ │ └── processing │ │ │ │ ├── Generator.ts │ │ │ │ ├── Preprocessor.ts │ │ │ │ ├── ProcessingController.ts │ │ │ │ ├── SimpleGenerator.ts │ │ │ │ ├── ToolsProvider.ts │ │ │ │ └── ToolsProviderController.ts │ │ ├── repository │ │ │ ├── ArtifactDownloadPlanner.ts │ │ │ ├── ModelSearchResultDownloadOption.ts │ │ │ ├── ModelSearchResultEntry.ts │ │ │ └── RepositoryNamespace.ts │ │ ├── shared.heavy.test.ts │ │ └── system │ │ │ └── SystemNamespace.ts │ ├── tsconfig.cjs.json │ ├── tsconfig.esm.json │ ├── tsconfig.json │ └── tsconfig.types.json ├── lms-common-server │ ├── package.json │ ├── src │ │ ├── FileData.ts │ │ ├── PlainTextFileData.ts │ │ ├── SimpleFileData.ts │ │ ├── findLMStudioHome.ts │ │ └── index.ts │ ├── tsconfig.cjs.json │ ├── tsconfig.esm.json │ ├── tsconfig.json │ └── tsconfig.types.json ├── lms-common │ ├── package.json │ ├── src │ │ ├── .test-snapshots │ │ │ └── SlicedSignal.test.ts.snap │ │ ├── BufferedEvent.test.ts │ │ ├── BufferedEvent.ts │ │ ├── CancelEvent.ts │ │ ├── Cleaner.ts │ │ ├── DeepReplaceType.ts │ │ ├── Event.test.ts │ │ ├── Event.ts │ │ ├── HandledEvent.ts │ │ ├── LazySignal.test.ts │ │ ├── LazySignal.ts │ │ ├── MaybeMutable.ts │ │ ├── OWLSignal.ts │ │ ├── OmitStatics.ts │ │ ├── Signal.test.ts │ │ ├── Signal.ts │ │ ├── SimpleLogger.test.ts │ │ ├── SimpleLogger.ts │ │ ├── SlicedSignal.test.ts │ │ ├── SlicedSignal.ts │ │ ├── StreamablePromise.test.ts │ │ ├── StreamablePromise.ts │ │ ├── Subscribable.ts │ │ ├── SyncEvent.ts │ │ ├── TimeoutTracker.ts │ │ ├── Validator.ts │ │ ├── WaitQueue.ts │ │ ├── apiServerPorts.ts │ │ ├── casingConvert.test.ts │ │ ├── casingConvert.ts │ │ ├── deepFreeze.test.ts │ │ ├── deepFreeze.ts │ │ ├── errorStack.ts │ │ ├── fileName.ts │ │ ├── flattenSignal.test.ts │ │ ├── flattenSignal.ts │ │ ├── index.ts │ │ ├── makePrettyError.ts │ │ ├── makePromise.test.ts │ │ ├── makePromise.ts │ │ ├── makeSetter.test.ts │ │ ├── makeSetter.ts │ │ ├── parseFileIdentifier.ts │ │ ├── promisifyAbortSignal.ts │ │ ├── removeUndefinedValues.test.ts │ │ ├── removeUndefinedValues.ts │ │ ├── resultTypes.test.ts │ │ ├── resultTypes.ts │ │ ├── runOnDispose.ts │ │ ├── safeCallCallback.ts │ │ ├── text.test.ts │ │ ├── text.ts │ │ ├── toJSONSafeNumber.test.ts │ │ ├── toJSONSafeNumber.ts │ │ ├── zodHelpers.test.ts │ │ └── zodHelpers.ts │ ├── tsconfig.cjs.json │ ├── tsconfig.esm.json │ ├── tsconfig.json │ └── tsconfig.types.json ├── lms-communication-client │ ├── package.json │ ├── src │ │ ├── AuthenticatedWsClientTransport.ts │ │ ├── ClientPort.ts │ │ ├── GenericClientTransport.ts │ │ ├── LMStudioHostedEnv.ts │ │ ├── WsClientTransport.ts │ │ └── index.ts │ ├── tsconfig.cjs.json │ ├── tsconfig.esm.json │ ├── tsconfig.json │ └── tsconfig.types.json ├── lms-communication-mock │ ├── package.json │ ├── src │ │ ├── createMockedPorts.ts │ │ └── index.ts │ ├── tsconfig.cjs.json │ ├── tsconfig.esm.json │ ├── tsconfig.json │ └── tsconfig.types.json ├── lms-communication-server │ ├── package.json │ ├── src │ │ ├── AuthenticatedIpcServer.ts │ │ ├── AuthenticatedWsServer.ts │ │ ├── Authenticator.ts │ │ ├── GenericServerTransport.ts │ │ ├── IpcServer.ts │ │ ├── IpcServerTransport.ts │ │ ├── ServerPort.ts │ │ ├── WsServer.ts │ │ ├── WsServerTransport.ts │ │ ├── electronTypes.ts │ │ ├── fcfsAuthenticator.ts │ │ └── index.ts │ ├── tsconfig.cjs.json │ ├── tsconfig.esm.json │ ├── tsconfig.json │ └── tsconfig.types.json ├── lms-communication │ ├── package.json │ ├── src │ │ ├── BackendInterface.ts │ │ ├── Channel.ts │ │ ├── Transport.ts │ │ ├── WsAuthenticationResult.ts │ │ ├── authentication.ts │ │ ├── index.ts │ │ ├── serialization.ts │ │ ├── timeoutConstants.ts │ │ └── wsTypes.ts │ ├── tsconfig.cjs.json │ ├── tsconfig.esm.json │ ├── tsconfig.json │ └── tsconfig.types.json ├── lms-es-plugin-runner │ ├── package.json │ ├── src │ │ ├── EsPluginInstaller.ts │ │ ├── EsPluginRunnerWatcher.ts │ │ ├── UtilBinary.ts │ │ ├── esbuildArgs.ts │ │ ├── generateEntryFile.ts │ │ └── index.ts │ ├── tsconfig.cjs.json │ ├── tsconfig.esm.json │ ├── tsconfig.json │ └── tsconfig.types.json ├── lms-external-backend-interfaces │ ├── package.json │ ├── src │ │ ├── baseModelBackendInterface.ts │ │ ├── diagnosticsBackendInterface.ts │ │ ├── embeddingBackendInterface.ts │ │ ├── filesBackendInterface.ts │ │ ├── index.ts │ │ ├── llmBackendInterface.ts │ │ ├── pluginsBackendInterface.ts │ │ ├── repositoryBackendInterface.ts │ │ └── systemBackendInterface.ts │ ├── tsconfig.cjs.json │ ├── tsconfig.esm.json │ ├── tsconfig.json │ └── tsconfig.types.json ├── lms-isomorphic │ ├── .npmignore │ ├── package.json │ ├── src │ │ ├── browser.ts │ │ ├── browser │ │ │ ├── WebSocket.ts │ │ │ ├── generateRandomBase64.ts │ │ │ ├── readFileAsBase64.ts │ │ │ └── terminalSize.ts │ │ ├── index.ts │ │ └── index │ │ │ ├── WebSocket.ts │ │ │ ├── generateRandomBase64.ts │ │ │ ├── readFileAsBase64.ts │ │ │ └── terminalSize.ts │ ├── tsconfig.cjs.json │ ├── tsconfig.esm.json │ ├── tsconfig.json │ └── tsconfig.types.json ├── lms-json-schema │ ├── .gitignore │ ├── package.json │ ├── src │ │ └── index.ts │ └── tsconfig.json ├── lms-kv-config │ ├── package.json │ ├── src │ │ ├── KVConfig.ts │ │ ├── conversion │ │ │ ├── llmPredictionConfig.ts │ │ │ └── utils.ts │ │ ├── index.ts │ │ ├── schema.test.ts │ │ ├── schema.ts │ │ └── valueTypes.ts │ ├── tsconfig.cjs.json │ ├── tsconfig.esm.json │ ├── tsconfig.json │ └── tsconfig.types.json ├── lms-lmstudio │ ├── package.json │ ├── src │ │ ├── index.ts │ │ └── installCli │ │ │ ├── darwinOrLinux.ts │ │ │ ├── index.ts │ │ │ └── win32.ts │ ├── tsconfig.cjs.json │ ├── tsconfig.esm.json │ ├── tsconfig.json │ └── tsconfig.types.json ├── lms-shared-types │ ├── package.json │ ├── src │ │ ├── AllowableEnvVars.ts │ │ ├── ArtifactManifest.ts │ │ ├── ArtifactManifestBase.ts │ │ ├── BackendNotification.ts │ │ ├── ChatHistoryData.ts │ │ ├── CitationSource.ts │ │ ├── ColorPalette.ts │ │ ├── Error.ts │ │ ├── GPUSplitStrategy.ts │ │ ├── GenericErrorDisplayData.ts │ │ ├── JSONSerializable.ts │ │ ├── KVConfig.ts │ │ ├── ModelCompatibilityType.ts │ │ ├── ModelDomainType.ts │ │ ├── ModelDownloadSource.ts │ │ ├── ModelInfo.ts │ │ ├── ModelInfoBase.ts │ │ ├── ModelManifest.ts │ │ ├── ModelSpecifier.ts │ │ ├── PluginManifest.ts │ │ ├── PresetManifest.ts │ │ ├── Runtime.ts │ │ ├── SerializedKVConfigSchematics.ts │ │ ├── VirtualModelDefinition.ts │ │ ├── Zod.ts │ │ ├── diagnostics │ │ │ └── DiagnosticsLogEvent.ts │ │ ├── embedding │ │ │ ├── EmbeddingLoadModelConfig.ts │ │ │ └── EmbeddingModelInfo.ts │ │ ├── files │ │ │ ├── DocumentParsingOpts.ts │ │ │ ├── FileIdentifier.ts │ │ │ └── FileType.ts │ │ ├── index.ts │ │ ├── kebab.ts │ │ ├── llm │ │ │ ├── ContentBlockStyle.ts │ │ │ ├── LLMApplyPromptTemplateOpts.ts │ │ │ ├── LLMContextReference.ts │ │ │ ├── LLMErrorDisplayData.ts │ │ │ ├── LLMLoadModelConfig.ts │ │ │ ├── LLMModelInfo.ts │ │ │ ├── LLMPredictionConfig.ts │ │ │ ├── LLMPredictionFragment.ts │ │ │ ├── LLMPredictionStats.ts │ │ │ ├── LLMPromptTemplate.ts │ │ │ ├── LLMStructuredPredictionSetting.ts │ │ │ ├── LLMToolUseSetting.ts │ │ │ └── processing │ │ │ │ ├── GeneratorUpdate.ts │ │ │ │ ├── PreprocessorUpdate.ts │ │ │ │ ├── ProcessingRequest.ts │ │ │ │ ├── ProcessingUpdate.ts │ │ │ │ └── Processor.ts │ │ ├── path.ts │ │ ├── reasonable.test.ts │ │ ├── reasonable.ts │ │ ├── repository │ │ │ ├── ArtifactDownloadPlan.ts │ │ │ ├── ArtifactUpload.ts │ │ │ ├── DownloadProgressUpdate.ts │ │ │ └── ModelSearch.ts │ │ └── retrieval │ │ │ ├── InternalRetrievalResult.ts │ │ │ ├── RetrievalChunk.ts │ │ │ ├── RetrievalChunkingMethod.ts │ │ │ └── RetrievalFileProcessingStep.ts │ ├── tsconfig.cjs.json │ ├── tsconfig.esm.json │ ├── tsconfig.json │ └── tsconfig.types.json └── template │ ├── package.json │ ├── src │ └── index.ts │ └── tsconfig.json ├── patches ├── boxen+5.1.2.patch └── promise-inflight+1.0.1.patch ├── publish ├── cli │ ├── .gitignore │ ├── LICENSE │ ├── entitlements.plist │ ├── injectVariables.js │ ├── make-bin-darwin.sh │ ├── make-bin-linux.sh │ ├── make-bin-win32.ps1 │ ├── package.json │ ├── rollup.config.js │ └── sea-config.json ├── lms │ ├── .gitignore │ ├── README.md │ ├── index.js │ └── package.json ├── lmstudio │ ├── .gitignore │ ├── README.md │ ├── package.json │ └── rollup.config.js └── sdk │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── api-extractor.json │ ├── package.json │ ├── removeSourceMapComments.js │ ├── rollup.config.js │ ├── src │ ├── exportedTypes.ts │ └── index.ts │ └── tsconfig.json ├── release.sh ├── scaffolds ├── .gitignore ├── buildScaffoldsJSON.js ├── node-javascript-empty │ ├── .gitignore │ ├── README.md │ ├── gitignore_template │ ├── lms-scaffold.json │ ├── package.json │ └── src │ │ └── index.js ├── node-javascript │ ├── .gitignore │ ├── README.md │ ├── gitignore_template │ ├── lms-scaffold.json │ ├── package.json │ └── src │ │ └── index.js ├── node-typescript-empty │ ├── .gitignore │ ├── README.md │ ├── gitignore_template │ ├── lms-scaffold.json │ ├── package.json │ ├── src │ │ └── index.ts │ └── tsconfig.json ├── node-typescript-preprocessor │ ├── .gitignore │ ├── README.md │ ├── gitignore_template │ ├── lms-scaffold.json │ ├── package.json │ ├── src │ │ └── index.ts │ └── tsconfig.json ├── node-typescript │ ├── .gitignore │ ├── README.md │ ├── gitignore_template │ ├── lms-scaffold.json │ ├── package.json │ ├── src │ │ └── index.ts │ └── tsconfig.json ├── scaffold-json-schema-v1.json └── upload.js ├── scripts ├── generateEsmPackageJson.mjs └── starter.mjs ├── tsconfig.build.json ├── tsconfig.cjs.json ├── tsconfig.esm.json ├── tsconfig.json └── tsconfig.types.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "node": true 6 | }, 7 | "plugins": ["eslint-plugin-tsdoc"], 8 | "extends": [ 9 | "eslint:recommended", 10 | "plugin:@typescript-eslint/eslint-recommended", 11 | "plugin:@typescript-eslint/recommended", 12 | "plugin:import/recommended", 13 | "plugin:import/electron", 14 | "plugin:import/typescript", 15 | "plugin:react-hooks/recommended" 16 | ], 17 | "parser": "@typescript-eslint/parser", 18 | "rules": { 19 | "@typescript-eslint/no-unused-vars": [ 20 | "warn", 21 | { 22 | "varsIgnorePattern": "^_", 23 | "argsIgnorePattern": "^_" 24 | } 25 | ], 26 | "@typescript-eslint/no-explicit-any": "off", 27 | "@typescript-eslint/consistent-type-imports": [ 28 | "error", 29 | { 30 | "prefer": "type-imports", 31 | "fixStyle": "inline-type-imports" 32 | } 33 | ], 34 | "tsdoc/syntax": "warn", 35 | "@typescript-eslint/ban-types": "off" 36 | }, 37 | "settings": { 38 | "import/resolver": { 39 | "typescript": { 40 | "alwaysTryTypes": true 41 | } 42 | } 43 | }, 44 | "overrides": [ 45 | { 46 | "files": ["*.fixture.tsx"], 47 | "rules": { 48 | "react-hooks/rules-of-hooks": "off" 49 | } 50 | }, 51 | { 52 | "files": ["*.js"], 53 | "rules": { 54 | "@typescript-eslint/no-var-requires": "off" 55 | } 56 | } 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | *.tsbuildinfo 4 | .parcel-cache 5 | coverage 6 | .env 7 | .DS_Store 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "packages/lms-cli"] 2 | path = packages/lms-cli 3 | url = git@github.com:lmstudio-ai/lmstudio-cli.git 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | audit=false 2 | fund=false 3 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["prettier-plugin-tailwindcss"], 3 | "printWidth": 100, 4 | "quoteProps": "consistent", 5 | "arrowParens": "avoid", 6 | "trailingComma": "all", 7 | "tabs": false, 8 | "tabWidth": 2 9 | } 10 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "streetsidesoftware.code-spell-checker", 4 | "dbaeumer.vscode-eslint", 5 | "Orta.vscode-jest", 6 | "esbenp.prettier-vscode", 7 | "stkb.rewrap", 8 | "Gruntfuggly.todo-tree" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsserver.experimental.enableProjectDiagnostics": true, 3 | "editor.codeActionsOnSave": { 4 | "source.organizeImports": "always", 5 | "source.fixAll.eslint": "always" 6 | }, 7 | "editor.rulers": [100], 8 | "cSpell.words": [ 9 | "concatenator", 10 | "Deserializers", 11 | "Fcfs", 12 | "GGUF", 13 | "huggingface", 14 | "immer", 15 | "inferencing", 16 | "lmstudio", 17 | "Logit", 18 | "Mirostat", 19 | "Mmap", 20 | "Onnx", 21 | "outfile", 22 | "Probs", 23 | "proxying", 24 | "reindex", 25 | "Rpcs", 26 | "Streamable", 27 | "superjson", 28 | "uncategorized", 29 | "unsubscriber" 30 | ], 31 | "rewrap.wrappingColumn": 100, 32 | "jest.runMode": "on-demand", 33 | "typescript.tsdk": "node_modules\\typescript\\lib" 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Element Labs 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. 22 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | "^.+\\.(t|j)sx?$": "@swc/jest", 4 | }, 5 | testEnvironment: "node", 6 | snapshotResolver: "./jestSnapshotResolver.js", 7 | collectCoverage: true, 8 | watchPathIgnorePatterns: ["\\.git", "node_modules"], 9 | resolver: "jest-ts-webcompat-resolver", 10 | }; 11 | -------------------------------------------------------------------------------- /jestSnapshotResolver.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | resolveSnapshotPath: testPath => 5 | path.join( 6 | path.join(path.dirname(testPath), ".test-snapshots"), 7 | path.basename(testPath) + ".snap", 8 | ), 9 | 10 | resolveTestPath: snapshotPath => 11 | path.resolve(path.dirname(snapshotPath), "..", path.basename(snapshotPath, ".snap")), 12 | 13 | testPathForConsistencyCheck: path.resolve("consistency_check", "__tests__", "example.test.js"), 14 | }; 15 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["packages/*", "publish/*", "scaffolds/*"], 3 | "$schema": "node_modules/lerna/schemas/lerna-schema.json", 4 | "version": "independent" 5 | } 6 | -------------------------------------------------------------------------------- /packages/lms-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/lms-client", 3 | "version": "1.2.1", 4 | "description": "", 5 | "main": "./dist/cjs/index.js", 6 | "module": "./dist/esm/index.js", 7 | "types": "./dist/types/index.d.ts", 8 | "scripts": { 9 | "build": "tsc" 10 | }, 11 | "author": "", 12 | "license": "Apache-2.0", 13 | "dependencies": { 14 | "@lmstudio/lms-common": "^0.8.5", 15 | "@lmstudio/lms-external-backend-interfaces": "^0.3.6", 16 | "@lmstudio/lms-isomorphic": "^0.4.5", 17 | "@lmstudio/lms-kv-config": "^0.2.11", 18 | "@lmstudio/lms-shared-types": "^0.6.10", 19 | "boxen": "^5.1.2", 20 | "chalk": "^4.1.2", 21 | "jsonschema": "^1.5.0", 22 | "process": "^0.11.10", 23 | "zod": "^3.22.4", 24 | "zod-to-json-schema": "^3.22.5" 25 | }, 26 | "exports": { 27 | ".": { 28 | "types": "./dist/types/index.d.ts", 29 | "require": "./dist/cjs/index.js", 30 | "import": "./dist/esm/index.js", 31 | "default": "./dist/esm/index.js" 32 | } 33 | }, 34 | "files": [ 35 | "./dist/cjs/**/*.js", 36 | "./dist/esm/package.json", 37 | "./dist/esm/**/*.js", 38 | "./dist/types/**/*.d.ts" 39 | ], 40 | "gitHead": "abe566030fdea1ad86c21c3d5f32ded4782e8c0b" 41 | } 42 | -------------------------------------------------------------------------------- /packages/lms-client/src/PluginContext.ts: -------------------------------------------------------------------------------- 1 | import { type ConfigSchematics, type VirtualConfigSchematics } from "./customConfig.js"; 2 | import { type Generator } from "./plugins/processing/Generator.js"; 3 | import { type Preprocessor } from "./plugins/processing/Preprocessor.js"; 4 | import { type SimpleGenerator } from "./plugins/processing/SimpleGenerator.js"; 5 | import { type ToolsProvider } from "./plugins/processing/ToolsProvider.js"; 6 | 7 | /** 8 | * @public 9 | */ 10 | export interface PluginContext { 11 | /** 12 | * Sets the config schematics associated with this plugin context. Returns the same PluginContext 13 | * for chaining. 14 | */ 15 | withConfigSchematics: ( 16 | configSchematics: ConfigSchematics, 17 | ) => PluginContext; 18 | /** 19 | * Sets the generator associated with this plugin context. Returns the same PluginContext for 20 | * chaining. 21 | */ 22 | withGenerator(generate: Generator): PluginContext; 23 | /** 24 | * Sets the preprocessor associated with this plugin context. Returns the same PluginContext for 25 | * chaining. 26 | */ 27 | withPreprocessor(preprocess: Preprocessor): PluginContext; 28 | /** 29 | * Sets the tools provider associated with this plugin context. Returns the same PluginContext for 30 | * chaining. 31 | */ 32 | withToolsProvider(toolsProvider: ToolsProvider): PluginContext; 33 | /** 34 | * Returns the config schematics associated with this plugin context. 35 | */ 36 | withSimplerGenerator(simpleGenerator: SimpleGenerator): PluginContext; 37 | } 38 | -------------------------------------------------------------------------------- /packages/lms-client/src/cacheQuantizationTypeToCheckbox.ts: -------------------------------------------------------------------------------- 1 | import { type LLMLlamaCacheQuantizationType } from "@lmstudio/lms-shared-types"; 2 | 3 | export function cacheQuantizationTypeToCheckbox({ 4 | value, 5 | falseDefault, 6 | }: { 7 | value: LLMLlamaCacheQuantizationType | false | undefined; 8 | falseDefault: LLMLlamaCacheQuantizationType; 9 | }) { 10 | return value === undefined 11 | ? undefined 12 | : value === false 13 | ? { checked: false, value: falseDefault } 14 | : { checked: true, value: value }; 15 | } 16 | -------------------------------------------------------------------------------- /packages/lms-client/src/diagnostics/DiagnosticsNamespace.ts: -------------------------------------------------------------------------------- 1 | import { 2 | getCurrentStack, 3 | SimpleLogger, 4 | type LoggerInterface, 5 | type Validator, 6 | } from "@lmstudio/lms-common"; 7 | import { type DiagnosticsPort } from "@lmstudio/lms-external-backend-interfaces"; 8 | import { type DiagnosticsLogEvent } from "@lmstudio/lms-shared-types"; 9 | import { z } from "zod"; 10 | 11 | /** @public */ 12 | export class DiagnosticsNamespace { 13 | /** @internal */ 14 | private readonly logger: SimpleLogger; 15 | /** @internal */ 16 | public constructor( 17 | private readonly diagnosticsPort: DiagnosticsPort, 18 | private readonly validator: Validator, 19 | parentLogger: LoggerInterface, 20 | ) { 21 | this.logger = new SimpleLogger("Diagnostics", parentLogger); 22 | } 23 | 24 | /** 25 | * Register a callback to receive log events. Return a function to stop receiving log events. 26 | * 27 | * This method is in alpha. Do not use this method in production yet. 28 | * @alpha 29 | */ 30 | public unstable_streamLogs(listener: (logEvent: DiagnosticsLogEvent) => void): () => void { 31 | const stack = getCurrentStack(1); 32 | this.validator.validateMethodParamOrThrow( 33 | "client.diagnostics", 34 | "unstable_streamLogs", 35 | "listener", 36 | z.function(), 37 | listener, 38 | stack, 39 | ); 40 | const channel = this.diagnosticsPort.createChannel("streamLogs", undefined, undefined, { 41 | stack, 42 | }); 43 | const unsubscribe = channel.onMessage.subscribe(message => { 44 | if (message.type === "log") { 45 | listener(message.log); 46 | } 47 | }); 48 | return () => { 49 | unsubscribe(); 50 | channel.send({ 51 | type: "stop", 52 | }); 53 | }; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/lms-client/src/embedding/.test-snapshots/EmbeddingModel.heavy.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`EmbeddingModel Can tokenize correctly 1`] = ` 4 | [ 5 | 101, 6 | 8488, 7 | 2003, 8 | 1037, 9 | 10535, 10 | 1012, 11 | 102, 12 | ] 13 | `; 14 | 15 | exports[`EmbeddingModel Can tokenize multiple strings correctly 1`] = ` 16 | [ 17 | [ 18 | 101, 19 | 8292, 20 | 22573, 21 | 2072, 22 | 19821, 23 | 1996, 24 | 8465, 25 | 1997, 26 | 2014, 27 | 6438, 28 | 102, 29 | ], 30 | [ 31 | 101, 32 | 1998, 33 | 2016, 34 | 2003, 35 | 9962, 36 | 4312, 37 | 102, 38 | ], 39 | ] 40 | `; 41 | 42 | exports[`EmbeddingModel can get model info 1`] = ` 43 | { 44 | "architecture": "nomic-bert", 45 | "contextLength": 2048, 46 | "displayName": "Nomic Embed Text v1.5", 47 | "format": "gguf", 48 | "identifier": Any, 49 | "instanceReference": Any, 50 | "maxContextLength": 2048, 51 | "modelKey": Any, 52 | "path": "nomic-ai/nomic-embed-text-v1.5-GGUF/nomic-embed-text-v1.5.Q4_K_M.gguf", 53 | "sizeBytes": 84106624, 54 | "type": "embedding", 55 | } 56 | `; 57 | -------------------------------------------------------------------------------- /packages/lms-client/src/files/FileHandle.ts: -------------------------------------------------------------------------------- 1 | import { parseFileIdentifier } from "@lmstudio/lms-common"; 2 | import { type FileType, type ParsedFileIdentifier } from "@lmstudio/lms-shared-types"; 3 | import { type FilesNamespace } from "./FilesNamespace.js"; 4 | 5 | /** 6 | * Represents a file. Currently, the file can be either in the local file system or base64 encoded. 7 | * 8 | * @public 9 | */ 10 | export class FileHandle { 11 | /** 12 | * @deprecated Direct construction is not recommended. Please use the `prepareFile` API instead 13 | */ 14 | public constructor( 15 | public readonly filesNamespace: FilesNamespace, 16 | public readonly identifier: string, 17 | public readonly type: FileType, 18 | public readonly sizeBytes: number, 19 | /** 20 | * Original file name 21 | */ 22 | public readonly name: string, 23 | ) { 24 | this.parsedIdentifier = parseFileIdentifier(identifier); 25 | } 26 | private readonly parsedIdentifier: ParsedFileIdentifier; 27 | 28 | /** 29 | * Gets the absolute file path of this file. 30 | */ 31 | public async getFilePath() { 32 | switch (this.parsedIdentifier.type) { 33 | case "local": { 34 | return (await this.filesNamespace.getLocalFileAbsolutePath(this.parsedIdentifier.fileName)) 35 | .path; 36 | } 37 | case "base64": { 38 | throw new Error( 39 | "Not implemented. Please open an issue on GitHub if you encountered this error.", 40 | ); 41 | } 42 | default: { 43 | const _exhaustiveCheck: never = this.parsedIdentifier; 44 | throw new Error(`Unexpected file identifier type: ${JSON.stringify(_exhaustiveCheck)}`); 45 | } 46 | } 47 | } 48 | 49 | public isImage() { 50 | return this.type === "image"; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/lms-client/src/files/ParseDocumentOpts.ts: -------------------------------------------------------------------------------- 1 | import { type DocumentParsingOpts, documentParsingOptsSchema } from "@lmstudio/lms-shared-types"; 2 | import { z } from "zod"; 3 | 4 | export type ParseDocumentOpts = DocumentParsingOpts & { 5 | /** 6 | * A callback function that is called with the progress of the document parsing (0-1). 7 | */ 8 | onProgress?: (progress: number) => void; 9 | /** 10 | * An optional AbortSignal that can be used to abort the document parsing. 11 | */ 12 | signal?: AbortSignal; 13 | }; 14 | 15 | export const parseDocumentOptsSchema = documentParsingOptsSchema.extend({ 16 | onProgress: z.function().optional(), 17 | signal: z.instanceof(AbortSignal).optional(), 18 | }); 19 | -------------------------------------------------------------------------------- /packages/lms-client/src/files/ParseDocumentResult.ts: -------------------------------------------------------------------------------- 1 | import { type DocumentParsingLibraryIdentifier } from "@lmstudio/lms-shared-types"; 2 | 3 | export interface ParseDocumentResult { 4 | content: string; 5 | parser: DocumentParsingLibraryIdentifier; 6 | } 7 | -------------------------------------------------------------------------------- /packages/lms-client/src/files/RetrievalResult.ts: -------------------------------------------------------------------------------- 1 | import { type FileHandle } from "./FileHandle.js"; 2 | 3 | /** @public */ 4 | export interface RetrievalResult { 5 | entries: Array; 6 | } 7 | 8 | /** @public */ 9 | export interface RetrievalResultEntry { 10 | content: string; 11 | score: number; 12 | source: FileHandle; 13 | } 14 | -------------------------------------------------------------------------------- /packages/lms-client/src/llm/.test-snapshots/LLM.act.heavy.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`LLM.act should call the tool with the correct parameters 1`] = ` 4 | { 5 | "architecture": "qwen2", 6 | "contextLength": 4096, 7 | "displayName": "Qwen2.5 0.5B Instruct", 8 | "format": "gguf", 9 | "identifier": Any, 10 | "instanceReference": Any, 11 | "maxContextLength": 32768, 12 | "modelKey": Any, 13 | "paramsString": "0.5B", 14 | "path": "lmstudio-community/Qwen2.5-0.5B-Instruct-GGUF/Qwen2.5-0.5B-Instruct-Q4_K_M.gguf", 15 | "sizeBytes": 397807936, 16 | "trainedForToolUse": true, 17 | "type": "llm", 18 | "vision": false, 19 | } 20 | `; 21 | 22 | exports[`LLM.act should call the tool with the correct parameters 2`] = ` 23 | { 24 | "numGpuLayers": Any, 25 | "predictedTokensCount": 38, 26 | "promptTokensCount": 192, 27 | "stopReason": "eosFound", 28 | "timeToFirstTokenSec": Any, 29 | "tokensPerSecond": Any, 30 | "totalTokensCount": 230, 31 | } 32 | `; 33 | 34 | exports[`LLM.act should call the tool with the correct parameters 3`] = ` 35 | { 36 | "architecture": "qwen2", 37 | "contextLength": 4096, 38 | "displayName": "Qwen2.5 0.5B Instruct", 39 | "format": "gguf", 40 | "identifier": Any, 41 | "instanceReference": Any, 42 | "maxContextLength": 32768, 43 | "modelKey": Any, 44 | "paramsString": "0.5B", 45 | "path": "lmstudio-community/Qwen2.5-0.5B-Instruct-GGUF/Qwen2.5-0.5B-Instruct-Q4_K_M.gguf", 46 | "sizeBytes": 397807936, 47 | "trainedForToolUse": true, 48 | "type": "llm", 49 | "vision": false, 50 | } 51 | `; 52 | 53 | exports[`LLM.act should call the tool with the correct parameters 4`] = ` 54 | { 55 | "numGpuLayers": Any, 56 | "predictedTokensCount": 13, 57 | "promptTokensCount": 249, 58 | "stopReason": "eosFound", 59 | "timeToFirstTokenSec": Any, 60 | "tokensPerSecond": Any, 61 | "totalTokensCount": 262, 62 | } 63 | `; 64 | -------------------------------------------------------------------------------- /packages/lms-client/src/llm/.test-snapshots/LLM.heavy.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`LLM Can tokenize correctly 1`] = ` 4 | [ 5 | 1143, 6 | 64866, 7 | 374, 8 | 264, 9 | 35765, 10 | 13, 11 | ] 12 | `; 13 | 14 | exports[`LLM Can tokenize multiple strings correctly 1`] = ` 15 | [ 16 | [ 17 | 34, 18 | 261, 19 | 72768, 20 | 30769, 21 | 279, 22 | 15917, 23 | 315, 24 | 1059, 25 | 19265, 26 | ], 27 | [ 28 | 437, 29 | 1340, 30 | 374, 31 | 27211, 32 | 13657, 33 | ], 34 | ] 35 | `; 36 | 37 | exports[`LLM can apply prompt template to a regular chat 1`] = ` 38 | "<|im_start|>system 39 | This is the system prompt.<|im_end|> 40 | <|im_start|>user 41 | User message 1<|im_end|> 42 | <|im_start|>assistant 43 | Assistant message 1<|im_end|> 44 | <|im_start|>user 45 | User message 2<|im_end|> 46 | <|im_start|>assistant 47 | " 48 | `; 49 | 50 | exports[`LLM can get model info 1`] = ` 51 | { 52 | "architecture": "qwen2", 53 | "contextLength": 4096, 54 | "displayName": "Qwen2.5 0.5B Instruct", 55 | "format": "gguf", 56 | "identifier": Any, 57 | "instanceReference": Any, 58 | "maxContextLength": 32768, 59 | "modelKey": Any, 60 | "paramsString": "0.5B", 61 | "path": "lmstudio-community/Qwen2.5-0.5B-Instruct-GGUF/Qwen2.5-0.5B-Instruct-Q4_K_M.gguf", 62 | "sizeBytes": 397807936, 63 | "trainedForToolUse": true, 64 | "type": "llm", 65 | "vision": false, 66 | } 67 | `; 68 | -------------------------------------------------------------------------------- /packages/lms-client/src/llm/.test-snapshots/LLM.vision.heavy.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`LLM with vision should work with base64 upload 1`] = `"I see the W3C logo, which"`; 4 | 5 | exports[`LLM with vision should work with base64 upload 2`] = ` 6 | { 7 | "numGpuLayers": Any, 8 | "predictedTokensCount": 10, 9 | "promptTokensCount": 27, 10 | "stopReason": "maxPredictedTokensReached", 11 | "timeToFirstTokenSec": Any, 12 | "tokensPerSecond": Any, 13 | "totalTokensCount": 37, 14 | } 15 | `; 16 | 17 | exports[`LLM with vision should work with base64 upload 3`] = ` 18 | { 19 | "architecture": "qwen2vl", 20 | "contextLength": 4096, 21 | "displayName": "Qwen2 VL 2B Instruct", 22 | "format": "gguf", 23 | "identifier": Any, 24 | "instanceReference": Any, 25 | "maxContextLength": 32768, 26 | "modelKey": Any, 27 | "paramsString": "2B", 28 | "path": "lmstudio-community/Qwen2-VL-2B-Instruct-GGUF/Qwen2-VL-2B-Instruct-Q4_K_M.gguf", 29 | "sizeBytes": 3647162336, 30 | "trainedForToolUse": false, 31 | "type": "llm", 32 | "vision": true, 33 | } 34 | `; 35 | 36 | exports[`LLM with vision should work with file upload 1`] = `"I see the W3C logo, which"`; 37 | 38 | exports[`LLM with vision should work with file upload 2`] = ` 39 | { 40 | "numGpuLayers": Any, 41 | "predictedTokensCount": 10, 42 | "promptTokensCount": 27, 43 | "stopReason": "maxPredictedTokensReached", 44 | "timeToFirstTokenSec": Any, 45 | "tokensPerSecond": Any, 46 | "totalTokensCount": 37, 47 | } 48 | `; 49 | 50 | exports[`LLM with vision should work with file upload 3`] = ` 51 | { 52 | "architecture": "qwen2vl", 53 | "contextLength": 4096, 54 | "displayName": "Qwen2 VL 2B Instruct", 55 | "format": "gguf", 56 | "identifier": Any, 57 | "instanceReference": Any, 58 | "maxContextLength": 32768, 59 | "modelKey": Any, 60 | "paramsString": "2B", 61 | "path": "lmstudio-community/Qwen2-VL-2B-Instruct-GGUF/Qwen2-VL-2B-Instruct-Q4_K_M.gguf", 62 | "sizeBytes": 3647162336, 63 | "trainedForToolUse": false, 64 | "type": "llm", 65 | "vision": true, 66 | } 67 | `; 68 | -------------------------------------------------------------------------------- /packages/lms-client/src/llm/ActResult.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Represents the result of running `llm.act`. Currently only contains minimum amount of 3 | * information. 4 | * 5 | * If you think more information/fields should be added, please open an issue or a PR on GitHub. 6 | * 7 | * @public 8 | */ 9 | export class ActResult { 10 | public constructor( 11 | /** 12 | * Number of rounds performed. 13 | * 14 | * For example, in the following scenario: 15 | * 16 | * - User asks the model to add 1234 and 5678. 17 | * - The model requests to use a calculator tool. 18 | * - The calculator tool outputs 6912. 19 | * - The calculator's output is then fed back to the model for a second round of prediction. 20 | * - The model sees the output and generates a paragraph explaining the result. 21 | * 22 | * There are 2 rounds. On the beginning of a round, the callback `onRoundStart` is triggered. 23 | * On the end of a round, the callback `onRoundEnd` is triggered. 24 | */ 25 | public readonly rounds: number, 26 | /** 27 | * Total time taken to run `.act` in seconds. measured from beginning of the `.act` invocation 28 | * to when the entire operation is finished. 29 | */ 30 | public readonly totalExecutionTimeSeconds: number, 31 | ) {} 32 | } 33 | -------------------------------------------------------------------------------- /packages/lms-client/src/modelShared/SpecificModel.ts: -------------------------------------------------------------------------------- 1 | import { type BaseModelPort } from "@lmstudio/lms-external-backend-interfaces"; 2 | import { type ModelInfoBase, type ModelInstanceInfoBase } from "@lmstudio/lms-shared-types"; 3 | import { type DynamicHandle } from "./DynamicHandle.js"; 4 | 5 | /** 6 | * @public 7 | */ 8 | export interface SpecificModel< 9 | /** @internal */ 10 | TClientPort extends BaseModelPort, 11 | > extends DynamicHandle< 12 | // prettier-ignore 13 | /** @internal */ TClientPort, 14 | ModelInstanceInfoBase 15 | > { 16 | readonly identifier: string; 17 | readonly path: string; 18 | unload(): Promise; 19 | } 20 | -------------------------------------------------------------------------------- /packages/lms-client/src/numberToCheckboxNumeric.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Translate a number to a checkbox numeric value. 3 | * 4 | * @param value - The value to translate. 5 | * @param uncheckedValue - The value to use when the checkbox is unchecked. 6 | * @param valueWhenUnchecked - The value to use when the checkbox is unchecked. 7 | */ 8 | export function numberToCheckboxNumeric( 9 | value: number | undefined, 10 | uncheckedValue: number, 11 | valueWhenUnchecked: number, 12 | ): undefined | { checked: boolean; value: number } { 13 | if (value === undefined) { 14 | return undefined; 15 | } 16 | if (value === uncheckedValue) { 17 | return { checked: false, value: valueWhenUnchecked }; 18 | } 19 | return { checked: true, value }; 20 | } 21 | -------------------------------------------------------------------------------- /packages/lms-client/src/plugins/processing/Generator.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { type GeneratorController } from "./ProcessingController.js"; 3 | 4 | /** 5 | * TODO: Documentation 6 | * 7 | * @public 8 | */ 9 | export type Generator = (ctl: GeneratorController) => Promise; 10 | export const generatorSchema = z.function(); 11 | -------------------------------------------------------------------------------- /packages/lms-client/src/plugins/processing/Preprocessor.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { type ChatMessage } from "../../Chat.js"; 3 | import { type PreprocessorController } from "./ProcessingController.js"; 4 | 5 | /** 6 | * TODO: Documentation 7 | * 8 | * @public 9 | */ 10 | export type Preprocessor = ( 11 | ctl: PreprocessorController, 12 | userMessage: ChatMessage, 13 | ) => Promise; 14 | export const preprocessorSchema = z.function(); 15 | -------------------------------------------------------------------------------- /packages/lms-client/src/plugins/processing/SimpleGenerator.ts: -------------------------------------------------------------------------------- 1 | import { type Chat } from "../../Chat"; 2 | 3 | /** 4 | * WIP 5 | */ 6 | export type SimpleGenerator = (context: Chat, onFragment: () => void) => Promise; 7 | -------------------------------------------------------------------------------- /packages/lms-client/src/plugins/processing/ToolsProvider.ts: -------------------------------------------------------------------------------- 1 | import { type Tool } from "../../llm/tool"; 2 | import { type ToolsProviderController } from "./ToolsProviderController"; 3 | 4 | export type ToolsProvider = (ctl: ToolsProviderController) => Promise>; 5 | -------------------------------------------------------------------------------- /packages/lms-client/src/plugins/processing/ToolsProviderController.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type GlobalKVFieldValueTypeLibraryMap, 3 | type KVConfigSchematics, 4 | } from "@lmstudio/lms-kv-config"; 5 | import { type KVConfig } from "@lmstudio/lms-shared-types"; 6 | import { 7 | type ConfigSchematics, 8 | type ParsedConfig, 9 | type VirtualConfigSchematics, 10 | } from "../../customConfig"; 11 | import { type LMStudioClient } from "../../LMStudioClient"; 12 | 13 | export class ToolsProviderController { 14 | public constructor( 15 | public readonly client: LMStudioClient, 16 | private readonly pluginConfig: KVConfig, 17 | public readonly signal: AbortSignal, 18 | private readonly workingDirectoryPath: string | null, 19 | ) {} 20 | 21 | public getWorkingDirectory(): string { 22 | if (this.workingDirectoryPath === null) { 23 | throw new Error("This prediction process is not attached to a working directory."); 24 | } 25 | return this.workingDirectoryPath; 26 | } 27 | 28 | public getPluginConfig( 29 | configSchematics: ConfigSchematics, 30 | ): ParsedConfig { 31 | return ( 32 | configSchematics as KVConfigSchematics< 33 | GlobalKVFieldValueTypeLibraryMap, 34 | TVirtualConfigSchematics 35 | > 36 | ).parse(this.pluginConfig); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/lms-client/src/repository/ModelSearchResultEntry.ts: -------------------------------------------------------------------------------- 1 | import { type SimpleLogger, type Validator } from "@lmstudio/lms-common"; 2 | import { type RepositoryPort } from "@lmstudio/lms-external-backend-interfaces"; 3 | import { type ModelSearchResultEntryData } from "@lmstudio/lms-shared-types"; 4 | import { ModelSearchResultDownloadOption } from "./ModelSearchResultDownloadOption.js"; 5 | 6 | /** @public */ 7 | export class ModelSearchResultEntry { 8 | public readonly name: string; 9 | 10 | /** 11 | * @internal 12 | */ 13 | public constructor( 14 | /** @internal */ 15 | private readonly repositoryPort: RepositoryPort, 16 | /** @internal */ 17 | private readonly validator: Validator, 18 | private readonly logger: SimpleLogger, 19 | private readonly data: ModelSearchResultEntryData, 20 | ) { 21 | this.name = data.name; 22 | } 23 | 24 | public isExactMatch(): boolean { 25 | return this.data.exact ?? false; 26 | } 27 | 28 | public isStaffPick(): boolean { 29 | return this.data.staffPick ?? false; 30 | } 31 | 32 | public async getDownloadOptions(): Promise> { 33 | const { results } = await this.repositoryPort.callRpc("getModelDownloadOptions", { 34 | modelSearchResultIdentifier: this.data.identifier, 35 | }); 36 | return results.map( 37 | data => 38 | new ModelSearchResultDownloadOption(this.repositoryPort, this.validator, this.logger, data), 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/lms-client/tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.cjs.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/cjs" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-client/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.esm.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/esm" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": [ 3 | { "path": "./tsconfig.cjs.json" }, 4 | { "path": "./tsconfig.esm.json" }, 5 | { "path": "./tsconfig.types.json" } 6 | ], 7 | "include": [] 8 | } 9 | -------------------------------------------------------------------------------- /packages/lms-client/tsconfig.types.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.types.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/types" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-common-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/lms-common-server", 3 | "version": "0.2.14", 4 | "description": "", 5 | "main": "./dist/cjs/index.js", 6 | "module": "./dist/esm/index.js", 7 | "types": "./dist/types/index.d.ts", 8 | "scripts": { 9 | "build": "tsc" 10 | }, 11 | "author": "", 12 | "license": "Apache-2.0", 13 | "dependencies": { 14 | "@lmstudio/lms-common": "^0.8.5" 15 | }, 16 | "exports": { 17 | ".": { 18 | "types": "./dist/types/index.d.ts", 19 | "require": "./dist/cjs/index.js", 20 | "import": "./dist/esm/index.js", 21 | "default": "./dist/esm/index.js" 22 | } 23 | }, 24 | "files": [ 25 | "./dist/cjs/**/*.js", 26 | "./dist/esm/package.json", 27 | "./dist/esm/**/*.js", 28 | "./dist/types/**/*.d.ts" 29 | ], 30 | "sideEffects": false, 31 | "gitHead": "9a71db006654e012e2749a17ac10859c5d5a36b2" 32 | } 33 | -------------------------------------------------------------------------------- /packages/lms-common-server/src/PlainTextFileData.ts: -------------------------------------------------------------------------------- 1 | import { FileData, type FileDataOpts } from "./FileData.js"; 2 | 3 | /** 4 | * Capable of storing plain text 5 | */ 6 | export class PlainTextFileData extends FileData { 7 | public constructor( 8 | filePath: string, 9 | defaultData: string | (() => string | Promise) = "", 10 | opts?: FileDataOpts, 11 | ) { 12 | super( 13 | filePath, 14 | defaultData, 15 | data => Buffer.from(data, "utf-8"), 16 | buffer => buffer.toString("utf-8"), 17 | opts, 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/lms-common-server/src/SimpleFileData.ts: -------------------------------------------------------------------------------- 1 | import { isAvailable, type StripNotAvailable } from "@lmstudio/lms-common"; 2 | import { type ZodSchema } from "zod"; 3 | import { FileData, type FileDataOpts } from "./FileData.js"; 4 | 5 | /** 6 | * Capable of storing JSON serializable values. 7 | */ 8 | export class SimpleFileData extends FileData { 9 | public constructor( 10 | filePath: string, 11 | defaultData: StripNotAvailable, 12 | schema: ZodSchema>, 13 | opts?: FileDataOpts, 14 | ) { 15 | super( 16 | filePath, 17 | defaultData, 18 | data => { 19 | if (isAvailable(data)) { 20 | if (!schema.safeParse(data).success) { 21 | throw new Error("Data does not match schema"); 22 | } 23 | return Buffer.from(JSON.stringify(data), "utf-8"); 24 | } 25 | throw new Error("Data is not available"); 26 | }, 27 | buffer => schema.parse(JSON.parse(buffer.toString("utf-8"))), 28 | opts, 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/lms-common-server/src/findLMStudioHome.ts: -------------------------------------------------------------------------------- 1 | import { existsSync, readFileSync, realpathSync, writeFileSync } from "fs"; 2 | import { homedir } from "os"; 3 | import { join } from "path"; 4 | 5 | let lmstudioHome: string | null = null; 6 | 7 | export function findLMStudioHome() { 8 | if (lmstudioHome !== null) { 9 | return lmstudioHome; 10 | } 11 | 12 | // if applicable, convert relative path to absolute and follow the symlink 13 | const resolvedHomeDir = realpathSync(homedir()); 14 | 15 | const pointerFilePath = join(resolvedHomeDir, ".lmstudio-home-pointer"); 16 | if (existsSync(pointerFilePath)) { 17 | lmstudioHome = readFileSync(pointerFilePath, "utf-8").trim(); 18 | return lmstudioHome; 19 | } 20 | 21 | // See if ~/.cache/lm-studio exists. If it does, use it. 22 | const cacheHome = join(resolvedHomeDir, ".cache", "lm-studio"); 23 | if (existsSync(cacheHome)) { 24 | lmstudioHome = cacheHome; 25 | writeFileSync(pointerFilePath, lmstudioHome, "utf-8"); 26 | return lmstudioHome; 27 | } 28 | 29 | // Otherwise, fallback to ~/.lmstudio 30 | const home = join(resolvedHomeDir, ".lmstudio"); 31 | lmstudioHome = home; 32 | writeFileSync(pointerFilePath, lmstudioHome, "utf-8"); 33 | return lmstudioHome; 34 | } 35 | -------------------------------------------------------------------------------- /packages/lms-common-server/src/index.ts: -------------------------------------------------------------------------------- 1 | export { FileData } from "./FileData.js"; 2 | export { findLMStudioHome } from "./findLMStudioHome.js"; 3 | export { PlainTextFileData } from "./PlainTextFileData.js"; 4 | export { SimpleFileData } from "./SimpleFileData.js"; 5 | -------------------------------------------------------------------------------- /packages/lms-common-server/tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.cjs.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/cjs" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-common-server/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.esm.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/esm" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-common-server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": [ 3 | { "path": "./tsconfig.cjs.json" }, 4 | { "path": "./tsconfig.esm.json" }, 5 | { "path": "./tsconfig.types.json" } 6 | ], 7 | "include": [] 8 | } 9 | -------------------------------------------------------------------------------- /packages/lms-common-server/tsconfig.types.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.types.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/types" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-common/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/lms-common", 3 | "version": "0.8.5", 4 | "description": "", 5 | "main": "./dist/cjs/index.js", 6 | "module": "./dist/esm/index.js", 7 | "types": "./dist/types/index.d.ts", 8 | "scripts": { 9 | "build": "tsc" 10 | }, 11 | "author": "", 12 | "license": "Apache-2.0", 13 | "dependencies": { 14 | "@lmstudio/immer-with-plugins": "^10.1.1", 15 | "@lmstudio/lms-isomorphic": "^0.4.5", 16 | "@lmstudio/lms-shared-types": "^0.6.10", 17 | "boxen": "^5.1.2", 18 | "chalk": "^4.1.2", 19 | "process": "^0.11.10", 20 | "zod": "^3.22.4" 21 | }, 22 | "exports": { 23 | ".": { 24 | "types": "./dist/types/index.d.ts", 25 | "require": "./dist/cjs/index.js", 26 | "import": "./dist/esm/index.js", 27 | "default": "./dist/esm/index.js" 28 | } 29 | }, 30 | "files": [ 31 | "./dist/cjs/**/*.js", 32 | "./dist/esm/package.json", 33 | "./dist/esm/**/*.js", 34 | "./dist/types/**/*.d.ts" 35 | ], 36 | "sideEffects": false, 37 | "gitHead": "9a71db006654e012e2749a17ac10859c5d5a36b2" 38 | } 39 | -------------------------------------------------------------------------------- /packages/lms-common/src/.test-snapshots/SlicedSignal.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`SlicedSignal should be able to subscribe with regular signals containing maps 1`] = ` 4 | [ 5 | { 6 | "c": 2, 7 | }, 8 | [ 9 | { 10 | "op": "replace", 11 | "path": [ 12 | "c", 13 | ], 14 | "value": 2, 15 | }, 16 | ], 17 | [], 18 | ] 19 | `; 20 | 21 | exports[`SlicedSignal should be able to subscribe with regular signals containing maps 2`] = ` 22 | [ 23 | { 24 | "c": 3, 25 | }, 26 | [ 27 | { 28 | "op": "replace", 29 | "path": [], 30 | "value": { 31 | "c": 3, 32 | }, 33 | }, 34 | ], 35 | [], 36 | ] 37 | `; 38 | 39 | exports[`SlicedSignal should be able to subscribe with regular signals containing maps 3`] = ` 40 | [ 41 | { 42 | "c": 4, 43 | }, 44 | [ 45 | { 46 | "op": "replace", 47 | "path": [], 48 | "value": { 49 | "c": 4, 50 | }, 51 | }, 52 | ], 53 | [], 54 | ] 55 | `; 56 | -------------------------------------------------------------------------------- /packages/lms-common/src/CancelEvent.ts: -------------------------------------------------------------------------------- 1 | import { Subscribable } from "./Subscribable.js"; 2 | 3 | export class CancelEvent extends Subscribable { 4 | private canceled = false; 5 | private readonly listeners = new Set<() => void>(); 6 | public override subscribe(listener: () => void): () => void { 7 | if (this.canceled) { 8 | let callbackCanceled = false; 9 | Promise.resolve().then(() => { 10 | if (!callbackCanceled) { 11 | listener(); 12 | } 13 | }); 14 | return () => { 15 | callbackCanceled = true; 16 | }; 17 | } 18 | this.listeners.add(listener); 19 | return () => { 20 | this.listeners.delete(listener); 21 | }; 22 | } 23 | public cancel() { 24 | if (this.canceled) { 25 | throw new Error("Already canceled"); 26 | } 27 | this.canceled = true; 28 | for (const listener of this.listeners) { 29 | listener(); 30 | } 31 | } 32 | public isCanceled() { 33 | return this.canceled; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/lms-common/src/Cleaner.ts: -------------------------------------------------------------------------------- 1 | export class Cleaner { 2 | private eagerCleaned = false; 3 | private readonly disposed = false; 4 | private readonly cleanups: Array<() => void> = []; 5 | public register(fn: () => void) { 6 | if (this.eagerCleaned) { 7 | throw new Error("Cannot register a cleanup after eagerClean() was called."); 8 | } 9 | if (this.disposed) { 10 | throw new Error("Cannot register a cleanup after the Cleaner was disposed."); 11 | } 12 | this.cleanups.push(fn); 13 | } 14 | private runCleanersInternal() { 15 | for (const cleanup of this.cleanups) { 16 | cleanup(); 17 | } 18 | // Just to free some memory because why not 19 | this.cleanups.length = 0; 20 | } 21 | public [Symbol.dispose]() { 22 | if (this.eagerCleaned) { 23 | // Already eagerly cleaned. Nothing to do. 24 | return; 25 | } 26 | if (this.disposed) { 27 | throw new Error("Cannot dispose a Cleaner that was already disposed."); 28 | } 29 | this.runCleanersInternal(); 30 | } 31 | public eagerClean() { 32 | if (this.eagerCleaned) { 33 | throw new Error("Cannot call eagerClean() twice."); 34 | } 35 | if (this.disposed) { 36 | throw new Error("Cannot call eagerClean() after the Cleaner was disposed."); 37 | } 38 | this.eagerCleaned = true; 39 | this.runCleanersInternal(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/lms-common/src/DeepReplaceType.ts: -------------------------------------------------------------------------------- 1 | export type DeepReplaceType = TInput extends TSearch 2 | ? TReplace 3 | : TInput extends Array 4 | ? Array> 5 | : TInput extends object 6 | ? { 7 | [K in keyof TInput]: DeepReplaceType; 8 | } 9 | : TInput; 10 | 11 | export type DeepReplaceType2 = 12 | TInput extends TSearch1 13 | ? TReplace1 14 | : TInput extends TSearch2 15 | ? TReplace2 16 | : TInput extends Array 17 | ? Array> 18 | : TInput extends object 19 | ? { 20 | [K in keyof TInput]: DeepReplaceType2< 21 | TInput[K], 22 | TSearch1, 23 | TReplace1, 24 | TSearch2, 25 | TReplace2 26 | >; 27 | } 28 | : TInput; 29 | -------------------------------------------------------------------------------- /packages/lms-common/src/Event.test.ts: -------------------------------------------------------------------------------- 1 | import "."; // Import order 2 | import { Event } from "./Event.js"; 3 | 4 | test("should trigger in next microtask", async () => { 5 | const [event, emit] = Event.create(); 6 | const listener = jest.fn(); 7 | event.subscribe(listener); 8 | emit(1); 9 | expect(listener).not.toHaveBeenCalled(); 10 | await Promise.resolve(); 11 | expect(listener).toHaveBeenCalledWith(1); 12 | }); 13 | 14 | test("unsubscribe should work", async () => { 15 | const [event, emit] = Event.create(); 16 | const listener = jest.fn(); 17 | const unsubscribe = event.subscribe(listener); 18 | emit(1); 19 | unsubscribe(); 20 | await Promise.resolve(); 21 | expect(listener).not.toHaveBeenCalled(); 22 | }); 23 | 24 | test("multiple subscribers should be called in order", async () => { 25 | const [event, emit] = Event.create(); 26 | const arr: Array = []; 27 | const listener1 = () => arr.push(1); 28 | const listener2 = () => arr.push(2); 29 | event.subscribe(listener1); 30 | event.subscribe(listener2); 31 | emit(1); 32 | await Promise.resolve(); 33 | expect(arr).toEqual([1, 2]); 34 | }); 35 | 36 | test("events should not buffer", async () => { 37 | const [event, emit] = Event.create(); 38 | const listener = jest.fn(); 39 | emit(1); 40 | await Promise.resolve(); 41 | event.subscribe(listener); 42 | await Promise.resolve(); 43 | expect(listener).not.toHaveBeenCalled(); 44 | }); 45 | 46 | test("events emitted in subscribe should be emitted in next microtask", async () => { 47 | const [event, emit] = Event.create(); 48 | let first = true; 49 | const listener = jest.fn(() => { 50 | if (first) { 51 | emit(2); 52 | first = false; 53 | } 54 | }); 55 | event.subscribe(listener); 56 | emit(1); 57 | await Promise.resolve(); 58 | expect(listener).toHaveBeenCalledTimes(1); 59 | expect(listener).toHaveBeenCalledWith(1); 60 | await Promise.resolve(); 61 | expect(listener).toHaveBeenCalledTimes(2); 62 | expect(listener).toHaveBeenCalledWith(2); 63 | }); 64 | -------------------------------------------------------------------------------- /packages/lms-common/src/HandledEvent.ts: -------------------------------------------------------------------------------- 1 | import { Subscribable } from "./Subscribable.js"; 2 | 3 | /** 4 | * Emit events immediately and returns a promise when all handlers are done. 5 | * 6 | * May cause problems if listeners are added or removed during the event. 7 | */ 8 | export class HandledEvent extends Subscribable { 9 | public static create(): readonly [ 10 | event: HandledEvent, 11 | emit: (data: TData) => Promise, 12 | ] { 13 | const event = new HandledEvent(); 14 | return [event, event.emit.bind(event)]; 15 | } 16 | public listeners: Set<(data: TData) => void> = new Set(); 17 | public override subscribe(listener: (data: TData) => void | Promise): () => void { 18 | this.listeners.add(listener); 19 | return () => { 20 | this.listeners.delete(listener); 21 | }; 22 | } 23 | private async emit(data: TData): Promise { 24 | const promises: Promise[] = []; 25 | for (const listener of this.listeners) { 26 | promises.push(Promise.resolve(listener(data))); 27 | } 28 | await Promise.all(promises); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/lms-common/src/MaybeMutable.ts: -------------------------------------------------------------------------------- 1 | import { text } from "./text.js"; 2 | 3 | /** 4 | * Represents some underlying data that may or may not be mutable. 5 | * 6 | * @public 7 | */ 8 | export abstract class MaybeMutable { 9 | protected constructor( 10 | protected readonly data: Data, 11 | protected readonly mutable: boolean, 12 | ) {} 13 | 14 | /** 15 | * Gets the underlying data without any access control. Only used internally. 16 | * 17 | * @internal 18 | */ 19 | public _internalGetData(): Data { 20 | return this.data; 21 | } 22 | 23 | /** 24 | * If this instance is mutable, return as is. 25 | * 26 | * If this instance is immutable, return a mutable copy. 27 | * 28 | * Very easy to misuse, thus internal only for now. 29 | * 30 | * @internal 31 | */ 32 | public _internalToMutable(): this { 33 | if (this.mutable) { 34 | return this; 35 | } 36 | return this.asMutableCopy(); 37 | } 38 | 39 | /** 40 | * Gets the class name. This is used for printing errors. 41 | */ 42 | protected abstract getClassName(): string; 43 | /** 44 | * Creates a new instance of the class with the given data. 45 | */ 46 | protected abstract create(data: Data, mutable: boolean): this; 47 | /** 48 | * Clones the data. 49 | */ 50 | protected abstract cloneData(data: Data): Data; 51 | 52 | public asMutableCopy(): this { 53 | return this.create(this.cloneData(this.data), true); 54 | } 55 | 56 | public asImmutableCopy(): this { 57 | if (this.mutable) { 58 | return this.create(this.cloneData(this.data), false); 59 | } 60 | return this; 61 | } 62 | 63 | protected guardMutable(): void { 64 | if (!this.mutable) { 65 | throw new Error(text` 66 | Cannot modify immutable ${this.getClassName()} instance. Use asMutableCopy() to get a 67 | mutable copy. 68 | `); 69 | } 70 | } 71 | } 72 | 73 | export interface MaybeMutableInternal extends MaybeMutable { 74 | _internalGetData(): Data; 75 | _internalToMutable(): this; 76 | } 77 | 78 | export function accessMaybeMutableInternals(maybeMutable: MaybeMutable) { 79 | return maybeMutable as MaybeMutableInternal; 80 | } 81 | -------------------------------------------------------------------------------- /packages/lms-common/src/OmitStatics.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Removes static properties from a type. This allows defining static methods on a subclass that is 3 | * not compatible with the parent class. 4 | * 5 | * https://github.com/microsoft/TypeScript/issues/4628#issuecomment-1147905253 6 | */ 7 | export type OmitStatics = T extends { new (...args: infer A): infer R } 8 | ? { new (...args: A): R } & Omit 9 | : Omit; 10 | -------------------------------------------------------------------------------- /packages/lms-common/src/SimpleLogger.test.ts: -------------------------------------------------------------------------------- 1 | import { SimpleLogger, type LoggerInterface } from "./SimpleLogger.js"; 2 | 3 | describe.skip("SimpleLogger", () => { 4 | let mockLogger: LoggerInterface; 5 | let simpleLogger: SimpleLogger; 6 | 7 | beforeEach(() => { 8 | mockLogger = { 9 | info: jest.fn(), 10 | error: jest.fn(), 11 | warn: jest.fn(), 12 | debug: jest.fn(), 13 | }; 14 | simpleLogger = new SimpleLogger("test", mockLogger); 15 | }); 16 | 17 | it("should log info correctly", () => { 18 | simpleLogger.info("info message"); 19 | expect(mockLogger.info).toHaveBeenCalledWith("[test]", "info message"); 20 | }); 21 | 22 | it("should log error correctly", () => { 23 | simpleLogger.error("error message"); 24 | expect(mockLogger.error).toHaveBeenCalledWith("[test]", "error message"); 25 | }); 26 | 27 | it("should log warn correctly", () => { 28 | simpleLogger.warn("warn message"); 29 | expect(mockLogger.warn).toHaveBeenCalledWith("[test]", "warn message"); 30 | }); 31 | 32 | it("should log debug correctly", () => { 33 | simpleLogger.debug("debug message"); 34 | expect(mockLogger.debug).toHaveBeenCalledWith("[test]", "debug message"); 35 | }); 36 | 37 | it("should log at level correctly", () => { 38 | simpleLogger.logAtLevel("info", "info message"); 39 | expect(mockLogger.info).toHaveBeenCalledWith("[test]", "info message"); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /packages/lms-common/src/SyncEvent.ts: -------------------------------------------------------------------------------- 1 | import { Subscribable } from "./Subscribable.js"; 2 | 3 | type Listener = (data: TData) => void; 4 | 5 | export class SyncEvent extends Subscribable { 6 | private subscribers = new Set>(); 7 | protected constructor() { 8 | super(); 9 | } 10 | protected emit(data: TData) { 11 | for (const subscriber of this.subscribers) { 12 | subscriber(data); 13 | } 14 | } 15 | public static create() { 16 | const event = new SyncEvent(); 17 | const emitter: (data: TData) => void = data => { 18 | event.emit(data); 19 | }; 20 | return [event, emitter] as const; 21 | } 22 | public subscribe(listener: Listener) { 23 | this.subscribers.add(listener); 24 | return () => { 25 | this.subscribers.delete(listener) 26 | }; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/lms-common/src/TimeoutTracker.ts: -------------------------------------------------------------------------------- 1 | import { BufferedEvent } from "./BufferedEvent.js"; 2 | 3 | export class TimeoutTracker { 4 | public constructor(private readonly timeoutMs: number) { 5 | [this.triggeredEvent, this.emitTriggeredEvent] = BufferedEvent.create(); 6 | } 7 | 8 | public readonly triggeredEvent: BufferedEvent; 9 | private emitTriggeredEvent: () => void; 10 | 11 | public started = false; 12 | private timeout: NodeJS.Timeout | null = null; 13 | public reset() { 14 | if (!this.started) { 15 | return; 16 | } 17 | if (this.timeout !== null) { 18 | clearTimeout(this.timeout); 19 | } 20 | this.timeout = setTimeout(() => { 21 | this.emitTriggeredEvent(); 22 | if (this.timeout !== null) { 23 | clearTimeout(this.timeout); 24 | } 25 | }, this.timeoutMs); 26 | } 27 | public start() { 28 | this.started = true; 29 | this.reset(); 30 | } 31 | public stop() { 32 | if (this.timeout !== null) { 33 | clearTimeout(this.timeout); 34 | this.timeout = null; 35 | } 36 | this.started = false; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/lms-common/src/apiServerPorts.ts: -------------------------------------------------------------------------------- 1 | export const apiServerPorts = [41343, 52993, 16141, 39414, 22931]; 2 | -------------------------------------------------------------------------------- /packages/lms-common/src/casingConvert.test.ts: -------------------------------------------------------------------------------- 1 | import { kebabToCamelCase } from "./casingConvert"; 2 | 3 | describe("kebabToCamelCase", () => { 4 | it("should convert a simple kebab-case string to camelCase", () => { 5 | expect(kebabToCamelCase("hello-world")).toBe("helloWorld"); 6 | }); 7 | 8 | it("should handle single-word strings without hyphens", () => { 9 | expect(kebabToCamelCase("hello")).toBe("hello"); 10 | }); 11 | 12 | it("should convert strings with multiple hyphens to camelCase", () => { 13 | expect(kebabToCamelCase("this-is-a-test")).toBe("thisIsATest"); 14 | }); 15 | 16 | it("should return an empty string when input is empty", () => { 17 | expect(kebabToCamelCase("")).toBe(""); 18 | }); 19 | 20 | it("should handle strings with numbers and special characters", () => { 21 | expect(kebabToCamelCase("hello-world-123")).toBe("helloWorld123"); 22 | expect(kebabToCamelCase("foo-bar-baz!")).toBe("fooBarBaz!"); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /packages/lms-common/src/casingConvert.ts: -------------------------------------------------------------------------------- 1 | export function kebabToCamelCase(kebab: string): string { 2 | const parts = kebab.split("-"); 3 | return ( 4 | parts[0] + 5 | parts 6 | .slice(1) 7 | .map(part => part[0].toUpperCase() + part.slice(1)) 8 | .join("") 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /packages/lms-common/src/deepFreeze.test.ts: -------------------------------------------------------------------------------- 1 | import { deepFreeze } from "./deepFreeze.js"; 2 | 3 | describe("deepFreeze", () => { 4 | it("should return non-objects as is", () => { 5 | expect(deepFreeze(123)).toBe(123); 6 | expect(deepFreeze("abc")).toBe("abc"); 7 | expect(deepFreeze(undefined)).toBe(undefined); 8 | expect(deepFreeze(null)).toBe(null); 9 | }); 10 | 11 | it("should freeze an object", () => { 12 | const obj = { a: 1, b: 2 }; 13 | const result = deepFreeze(obj); 14 | expect(Object.isFrozen(result)).toBe(true); 15 | }); 16 | 17 | it("should not affect already frozen objects", () => { 18 | const obj = Object.freeze({ a: 1, b: 2 }); 19 | const result = deepFreeze(obj); 20 | expect(Object.isFrozen(result)).toBe(true); 21 | }); 22 | 23 | it("should freeze nested objects", () => { 24 | const obj = { a: 1, b: { c: 3 } }; 25 | const result = deepFreeze(obj); 26 | expect(Object.isFrozen(result.b)).toBe(true); 27 | }); 28 | 29 | it("should freeze arrays", () => { 30 | const array = [1, 2, 3]; 31 | const result = deepFreeze(array); 32 | expect(Object.isFrozen(result)).toBe(true); 33 | }); 34 | 35 | it("should freeze objects within arrays", () => { 36 | const array = [1, { a: 2 }, 3]; 37 | const result = deepFreeze(array); 38 | expect(Object.isFrozen(result[1])).toBe(true); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /packages/lms-common/src/deepFreeze.ts: -------------------------------------------------------------------------------- 1 | export function deepFreeze(obj: any) { 2 | if (typeof obj !== "object" || obj === null) { 3 | return obj; 4 | } 5 | if (Object.isFrozen(obj)) { 6 | return obj; 7 | } 8 | Object.freeze(obj); 9 | for (const key in obj) { 10 | if (Object.prototype.hasOwnProperty.call(obj, key)) { 11 | deepFreeze(obj[key]); 12 | } 13 | } 14 | return obj; 15 | } 16 | -------------------------------------------------------------------------------- /packages/lms-common/src/errorStack.ts: -------------------------------------------------------------------------------- 1 | import process from "process"; 2 | 3 | // Error stack manipulation related functions 4 | 5 | export function getCurrentStack(goAbove = 0) { 6 | const stack = new Error().stack; 7 | if (!stack) { 8 | return ""; 9 | } 10 | const lines = stack.split("\n"); 11 | return lines.slice(2 + goAbove).join("\n"); 12 | } 13 | 14 | export function changeErrorStackInPlace(error: Error, newStack: string) { 15 | if (process.env.LMS_KEEP_INTERNAL_STACK) { 16 | return; 17 | } 18 | const stackContent = error.stack ?? ""; 19 | error.stack = ( 20 | stackContent.substring(0, stackContent.indexOf("\n at ")).trimEnd() + 21 | "\n" + 22 | newStack 23 | ).trimEnd(); 24 | } 25 | -------------------------------------------------------------------------------- /packages/lms-common/src/fileName.ts: -------------------------------------------------------------------------------- 1 | export const modelExtensions = [".gguf"]; 2 | 3 | export const doesFileNameIndicateModel = (path: string) => { 4 | return modelExtensions.some(ext => path.toLowerCase().endsWith(ext)); 5 | }; 6 | -------------------------------------------------------------------------------- /packages/lms-common/src/makePrettyError.ts: -------------------------------------------------------------------------------- 1 | import { terminalSize } from "@lmstudio/lms-isomorphic"; 2 | import boxen from "boxen"; 3 | import chalk from "chalk"; 4 | import process from "process"; 5 | import { changeErrorStackInPlace } from "./errorStack.js"; 6 | 7 | export function makeTitledPrettyError(title: string, content: string, stack?: string) { 8 | return makePrettyError(chalk.redBright(title) + "\n\n" + content, stack); 9 | } 10 | export function makePrettyError(content: string, stack?: string): Error { 11 | if ((process as any).browser || process.env.LMS_NO_FANCY_ERRORS || terminalSize().columns < 80) { 12 | const error = new Error(content); 13 | if (stack === undefined) { 14 | changeErrorStackInPlace(error, ""); 15 | } else { 16 | changeErrorStackInPlace(error, stack); 17 | } 18 | return error; 19 | } else { 20 | if (stack !== undefined) { 21 | content += 22 | "\n\n\n " + chalk.bgWhite.black(" STACK TRACE ") + "\n\n" + chalk.gray(stack); 23 | } 24 | const error = new Error( 25 | "\n" + boxen(content, { padding: 1, margin: 1, borderColor: "redBright", title: "Error" }), 26 | ); 27 | Object.defineProperty(error, "lmstudioRawError", { value: content, enumerable: false }); 28 | changeErrorStackInPlace(error, ""); 29 | return error; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/lms-common/src/makePromise.test.ts: -------------------------------------------------------------------------------- 1 | import { makePromise } from "./makePromise.js"; 2 | 3 | describe("makePromise", () => { 4 | it("should resolve correctly", async () => { 5 | const { promise, resolve } = makePromise(); 6 | const testValue = 42; 7 | 8 | resolve(testValue); 9 | 10 | await expect(promise).resolves.toBe(testValue); 11 | }); 12 | 13 | it("should reject correctly", async () => { 14 | const { promise, reject } = makePromise(); 15 | const testError = new Error("test error"); 16 | 17 | reject(testError); 18 | 19 | await expect(promise).rejects.toThrow(testError); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/lms-common/src/makePromise.ts: -------------------------------------------------------------------------------- 1 | export interface DeferredPromise { 2 | promise: Promise; 3 | resolve(value: TData | PromiseLike): void; 4 | reject(error: any): void; 5 | } 6 | 7 | export function makePromise(): DeferredPromise { 8 | let resolve: (value: TData | PromiseLike) => void; 9 | let reject: (error: any) => void; 10 | const promise = new Promise((_resolve, _reject) => { 11 | resolve = _resolve; 12 | reject = _reject; 13 | }); 14 | return { promise, resolve: resolve!, reject: reject! }; 15 | } 16 | -------------------------------------------------------------------------------- /packages/lms-common/src/parseFileIdentifier.ts: -------------------------------------------------------------------------------- 1 | import { type ParsedFileIdentifier } from "@lmstudio/lms-shared-types"; 2 | 3 | export function parseFileIdentifier(fileIdentifier: string): ParsedFileIdentifier { 4 | if (!fileIdentifier.includes(":")) { 5 | fileIdentifier = `local:${fileIdentifier}`; 6 | } 7 | const colonIndex = fileIdentifier.indexOf(":"); 8 | const namespace = fileIdentifier.slice(0, colonIndex); 9 | const content = fileIdentifier.slice(colonIndex + 1); 10 | switch (namespace) { 11 | case "local": { 12 | if (content.includes("/") || content.includes("\\") || content.length === 0) { 13 | throw new Error(`Invalid local file name: ${content}.`); 14 | } 15 | return { 16 | type: "local", 17 | fileName: content, 18 | }; 19 | } 20 | case "base64": { 21 | return { 22 | type: "base64", 23 | base64Data: content, 24 | }; 25 | } 26 | default: { 27 | throw new Error(`Unknown file identifier namespace: ${namespace}.`); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/lms-common/src/promisifyAbortSignal.ts: -------------------------------------------------------------------------------- 1 | export function promisifyAbortSignal(abortSignal: AbortSignal): Promise { 2 | return new Promise((_resolve, reject) => { 3 | if (abortSignal.aborted) { 4 | reject(abortSignal.reason); 5 | return; 6 | } 7 | abortSignal.addEventListener( 8 | "abort", 9 | () => { 10 | reject(abortSignal.reason); 11 | }, 12 | { once: true }, 13 | ); 14 | }); 15 | } 16 | 17 | export function raceWithAbortSignal( 18 | promise: Promise, 19 | abortSignal: AbortSignal, 20 | ): Promise { 21 | return Promise.race([promise, promisifyAbortSignal(abortSignal)]); 22 | } 23 | -------------------------------------------------------------------------------- /packages/lms-common/src/removeUndefinedValues.test.ts: -------------------------------------------------------------------------------- 1 | import { removeUndefinedValues } from "./removeUndefinedValues.js"; 2 | 3 | describe("removeUndefinedValues function", () => { 4 | it("should remove properties with undefined values", () => { 5 | const obj = { a: 1, b: undefined, c: "test" }; 6 | const result = removeUndefinedValues(obj); 7 | expect(result).toEqual({ a: 1, c: "test" }); 8 | expect(Object.prototype.hasOwnProperty.call(result, "b")).toBe(false); 9 | }); 10 | 11 | it("should return an empty object if all properties are undefined", () => { 12 | const obj = { a: undefined, b: undefined, c: undefined }; 13 | const result = removeUndefinedValues(obj); 14 | expect(result).toEqual({}); 15 | expect(Object.keys(result).length).toBe(0); 16 | }); 17 | 18 | it("should return the same object if there are no undefined values", () => { 19 | const obj = { a: 1, b: 2, c: "test" }; 20 | const result = removeUndefinedValues(obj); 21 | expect(result).toEqual(obj); 22 | }); 23 | 24 | it("should not mutate the original object", () => { 25 | const obj = { a: 1, b: undefined, c: "test" }; 26 | const copy = { ...obj }; 27 | removeUndefinedValues(obj); 28 | expect(obj).toEqual(copy); 29 | }); 30 | 31 | it("should not be susceptible to prototype pollution", () => { 32 | const obj = { a: 1, b: undefined, c: "test", __proto__: { d: 4 } }; 33 | const result = removeUndefinedValues(obj); 34 | expect((result as any).d).toBeUndefined(); 35 | expect(Object.prototype.hasOwnProperty.call(result, "d")).toBe(false); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /packages/lms-common/src/removeUndefinedValues.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Removes properties with `undefined` values from an object. 3 | * 4 | * This function can be useful in scenarios where you want to ensure that an object does not contain 5 | * any `undefined` values. For example, when the resulting value is used to overwrite some default 6 | * values. 7 | * 8 | * Note: This function does not mutate the original object. It returns a new object that does not 9 | * include the `undefined` values. 10 | * 11 | * @param obj - The object from which to remove `undefined` values. 12 | * @returns A new object that does not include the `undefined` values. 13 | * @example 14 | * ```typescript 15 | * const obj = { a: 1, b: undefined, c: 'test' }; 16 | * const result = removeUndefinedValues(obj); 17 | * console.log(result); // { a: 1, c: 'test' } 18 | * ``` 19 | */ 20 | export function removeUndefinedValues(obj: T): T { 21 | return Object.fromEntries(Object.entries(obj).filter(([_, v]) => v !== undefined)) as T; 22 | } 23 | -------------------------------------------------------------------------------- /packages/lms-common/src/runOnDispose.ts: -------------------------------------------------------------------------------- 1 | export function runOnDispose(fn: () => void) { 2 | return { 3 | [Symbol.dispose]: fn, 4 | }; 5 | } 6 | -------------------------------------------------------------------------------- /packages/lms-common/src/safeCallCallback.ts: -------------------------------------------------------------------------------- 1 | import { type SimpleLogger } from "./SimpleLogger.js"; 2 | 3 | /** 4 | * Call a user provided callback and log any errors that occur. This prevents the error from 5 | * crashing the application. 6 | */ 7 | export function safeCallCallback>( 8 | logger: SimpleLogger, 9 | name: string, 10 | callback: ((...args: TArgs) => void) | undefined, 11 | args: TArgs, 12 | ) { 13 | if (callback === undefined) { 14 | return; 15 | } 16 | try { 17 | const maybePromise = callback(...args) as any; 18 | if (typeof maybePromise === "object" && typeof maybePromise.catch === "function") { 19 | maybePromise.catch((error: Error) => { 20 | logger.error(`Error in the ${name} callback (triggered asynchronously):`, error); 21 | }); 22 | } 23 | } catch (error) { 24 | logger.error(`Error in the ${name} callback:`, error); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/lms-common/src/toJSONSafeNumber.test.ts: -------------------------------------------------------------------------------- 1 | import { toJSONSafeNumber } from "./toJSONSafeNumber.js"; 2 | 3 | describe("toJSONSafeNumber", () => { 4 | it("should return undefined when the input is not a finite number", () => { 5 | expect(toJSONSafeNumber(Infinity)).toBeUndefined(); 6 | expect(toJSONSafeNumber(-Infinity)).toBeUndefined(); 7 | }); 8 | 9 | it("should return undefined when the input is NaN", () => { 10 | expect(toJSONSafeNumber(NaN)).toBeUndefined(); 11 | }); 12 | 13 | it("should return the input when it is a finite number and not NaN", () => { 14 | expect(toJSONSafeNumber(123)).toBe(123); 15 | expect(toJSONSafeNumber(-123)).toBe(-123); 16 | expect(toJSONSafeNumber(0)).toBe(0); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /packages/lms-common/src/toJSONSafeNumber.ts: -------------------------------------------------------------------------------- 1 | export function toJSONSafeNumber(value: number | undefined): number | undefined { 2 | if (value === undefined) { 3 | return undefined; 4 | } else if (!Number.isFinite(value)) { 5 | return undefined; 6 | } else if (Number.isNaN(value)) { 7 | return undefined; 8 | } else { 9 | return value; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/lms-common/src/zodHelpers.test.ts: -------------------------------------------------------------------------------- 1 | import { z, type ZodSchema } from "zod"; 2 | import { filteredArray } from "./zodHelpers.js"; // replace with your actual file path 3 | 4 | describe("filteredArray", () => { 5 | it("should return an array with elements that match the provided schema", () => { 6 | // Define a ZodSchema for number 7 | const numberSchema: ZodSchema = z.number(); 8 | 9 | // Create a filtered array schema 10 | const filteredNumberArray = filteredArray(numberSchema); 11 | 12 | // Test data 13 | const data = [1, "2", 3, "4", 5]; 14 | 15 | // Parse the data using the filtered array schema 16 | const result = filteredNumberArray.safeParse(data); 17 | 18 | // Expect the parse to be successful and only contains numbers 19 | expect(result.success).toBe(true); 20 | if (result.success) { 21 | expect(result.data).toEqual([1, 3, 5]); 22 | } 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /packages/lms-common/src/zodHelpers.ts: -------------------------------------------------------------------------------- 1 | import { z, type ZodSchema } from "zod"; 2 | 3 | /** 4 | * Makes a Zod schema that filters out elements that do not match the provided schema. 5 | */ 6 | export function filteredArray(schema: ZodSchema): ZodSchema> { 7 | return z.array(z.any()).transform(val => 8 | val 9 | .map(v => schema.safeParse(v)) 10 | .filter(parsed => parsed.success) 11 | .map(parsed => (parsed as any).data as T), 12 | ); 13 | } 14 | 15 | /** 16 | * Makes a Zod schema that turns a failed parse into an `undefined`. 17 | */ 18 | export function failOk(schema: ZodSchema): ZodSchema { 19 | return z.any().transform(val => { 20 | const parsed = schema.safeParse(val); 21 | if (parsed.success) { 22 | return parsed.data; 23 | } 24 | return undefined; 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /packages/lms-common/tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.cjs.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/cjs" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-common/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.esm.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/esm" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-common/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": [ 3 | { "path": "./tsconfig.cjs.json" }, 4 | { "path": "./tsconfig.esm.json" }, 5 | { "path": "./tsconfig.types.json" } 6 | ], 7 | "include": [] 8 | } 9 | -------------------------------------------------------------------------------- /packages/lms-common/tsconfig.types.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.types.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/types" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-communication-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/lms-communication-client", 3 | "version": "0.6.14", 4 | "description": "", 5 | "main": "./dist/cjs/index.js", 6 | "module": "./dist/esm/index.js", 7 | "types": "./dist/types/index.d.ts", 8 | "scripts": { 9 | "build": "tsc" 10 | }, 11 | "author": "", 12 | "license": "Apache-2.0", 13 | "dependencies": { 14 | "@lmstudio/immer-with-plugins": "^10.1.1", 15 | "@lmstudio/lms-common": "^0.8.5", 16 | "@lmstudio/lms-communication": "^0.6.14", 17 | "@lmstudio/lms-isomorphic": "^0.4.5" 18 | }, 19 | "exports": { 20 | ".": { 21 | "types": "./dist/types/index.d.ts", 22 | "require": "./dist/cjs/index.js", 23 | "import": "./dist/esm/index.js", 24 | "default": "./dist/esm/index.js" 25 | } 26 | }, 27 | "files": [ 28 | "./dist/cjs/**/*.js", 29 | "./dist/esm/package.json", 30 | "./dist/esm/**/*.js", 31 | "./dist/types/**/*.d.ts" 32 | ], 33 | "sideEffects": false, 34 | "gitHead": "9a71db006654e012e2749a17ac10859c5d5a36b2" 35 | } 36 | -------------------------------------------------------------------------------- /packages/lms-communication-client/src/GenericClientTransport.ts: -------------------------------------------------------------------------------- 1 | import { SimpleLogger, type BufferedEvent, type LoggerInterface } from "@lmstudio/lms-common"; 2 | import type { 3 | ClientToServerMessage, 4 | ClientTransportFactory, 5 | ServerToClientMessage, 6 | } from "@lmstudio/lms-communication"; 7 | import { ClientTransport } from "@lmstudio/lms-communication"; 8 | 9 | export class GenericClientTransport extends ClientTransport { 10 | protected readonly logger; 11 | private closed = false; 12 | public constructor( 13 | onMessage: BufferedEvent, 14 | onClose: BufferedEvent, 15 | private readonly sendMessage: (message: ClientToServerMessage) => void, 16 | private readonly receivedMessage: (message: ServerToClientMessage) => void, 17 | private readonly errored: (error: any) => void, 18 | parentLogger?: LoggerInterface, 19 | ) { 20 | super(); 21 | this.logger = new SimpleLogger("GenericClientTransport", parentLogger); 22 | onMessage.subscribe(message => { 23 | let parsed: ServerToClientMessage; 24 | try { 25 | parsed = this.parseIncomingMessage(message); 26 | } catch (error) { 27 | this.logger.warn("Received invalid message from server:", message); 28 | return; 29 | } 30 | this.receivedMessage(parsed); 31 | }); 32 | onClose.subscribeOnce(() => { 33 | if (this.closed) { 34 | return; 35 | } 36 | this.closed = true; 37 | this.errored(new Error("Server closed the connection")); 38 | }); 39 | } 40 | public static createFactory( 41 | onMessage: BufferedEvent, 42 | onClose: BufferedEvent, 43 | sendMessage: (message: ClientToServerMessage) => void, 44 | ): ClientTransportFactory { 45 | return (receivedMessage, errored, parentLogger) => 46 | new GenericClientTransport( 47 | onMessage, 48 | onClose, 49 | sendMessage, 50 | receivedMessage, 51 | errored, 52 | parentLogger, 53 | ); 54 | } 55 | public override sendViaTransport(message: ClientToServerMessage) { 56 | this.sendMessage(message); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /packages/lms-communication-client/src/LMStudioHostedEnv.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type ClientToServerMessage, 3 | type ServerToClientMessage, 4 | } from "@lmstudio/lms-communication"; 5 | 6 | export interface LMStudioHostedEnv { 7 | /** 8 | * @param apiNamespace - The ID of the API to get a tunnel for. 9 | * @param initMessage - The message to send to the server when the tunnel is created. 10 | * @param onMessage - A callback to be called when a message is received from the server. 11 | * @param onClose - A callback to be called when the tunnel is closed. 12 | * @returns A function that can be used to send messages to the server. 13 | */ 14 | getApiIpcTunnel: ( 15 | apiNamespace: string, 16 | initMessage: any, 17 | onMessage: (message: ServerToClientMessage) => void, 18 | onClose: () => void, 19 | ) => (message: ClientToServerMessage) => void; 20 | } 21 | 22 | export function getHostedEnv(): LMStudioHostedEnv | null { 23 | let anyWindow: any; 24 | try { 25 | anyWindow = window; 26 | } catch (error) { 27 | anyWindow = undefined; 28 | } 29 | if (anyWindow !== undefined && anyWindow.lmsHostedEnv !== undefined) { 30 | return anyWindow.lmsHostedEnv as LMStudioHostedEnv; 31 | } 32 | return null; 33 | } 34 | -------------------------------------------------------------------------------- /packages/lms-communication-client/src/index.ts: -------------------------------------------------------------------------------- 1 | export { AuthenticatedWsClientTransport } from "./AuthenticatedWsClientTransport.js"; 2 | export { ClientPort, InferClientPort } from "./ClientPort.js"; 3 | export { GenericClientTransport } from "./GenericClientTransport.js"; 4 | export { LMStudioHostedEnv, getHostedEnv } from "./LMStudioHostedEnv.js"; 5 | export { WsClientTransport } from "./WsClientTransport.js"; 6 | -------------------------------------------------------------------------------- /packages/lms-communication-client/tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.cjs.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/cjs" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-communication-client/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.esm.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/esm" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-communication-client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": [ 3 | { "path": "./tsconfig.cjs.json" }, 4 | { "path": "./tsconfig.esm.json" }, 5 | { "path": "./tsconfig.types.json" } 6 | ], 7 | "include": [] 8 | } 9 | -------------------------------------------------------------------------------- /packages/lms-communication-client/tsconfig.types.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.types.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/types" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-communication-mock/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/lms-communication-mock", 3 | "version": "0.4.14", 4 | "description": "", 5 | "main": "./dist/cjs/index.js", 6 | "module": "./dist/esm/index.js", 7 | "types": "./dist/types/index.d.ts", 8 | "scripts": { 9 | "build": "tsc" 10 | }, 11 | "dependencies": { 12 | "@lmstudio/lms-communication": "^0.6.14", 13 | "@lmstudio/lms-communication-client": "^0.6.14", 14 | "@lmstudio/lms-communication-server": "^0.6.14" 15 | }, 16 | "exports": { 17 | ".": { 18 | "types": "./dist/types/index.d.ts", 19 | "require": "./dist/cjs/index.js", 20 | "import": "./dist/esm/index.js", 21 | "default": "./dist/esm/index.js" 22 | } 23 | }, 24 | "files": [ 25 | "./dist/cjs/**/*.js", 26 | "./dist/esm/package.json", 27 | "./dist/esm/**/*.js", 28 | "./dist/types/**/*.d.ts" 29 | ], 30 | "author": "", 31 | "license": "Apache-2.0", 32 | "sideEffects": false, 33 | "gitHead": "9a71db006654e012e2749a17ac10859c5d5a36b2" 34 | } 35 | -------------------------------------------------------------------------------- /packages/lms-communication-mock/src/index.ts: -------------------------------------------------------------------------------- 1 | export { createMockedPorts } from "./createMockedPorts.js"; 2 | -------------------------------------------------------------------------------- /packages/lms-communication-mock/tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.cjs.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/cjs" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-communication-mock/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.esm.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/esm" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-communication-mock/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": [ 3 | { "path": "./tsconfig.cjs.json" }, 4 | { "path": "./tsconfig.esm.json" }, 5 | { "path": "./tsconfig.types.json" } 6 | ], 7 | "include": [] 8 | } 9 | -------------------------------------------------------------------------------- /packages/lms-communication-mock/tsconfig.types.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.types.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/types" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-communication-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/lms-communication-server", 3 | "version": "0.6.14", 4 | "description": "", 5 | "main": "./dist/cjs/index.js", 6 | "module": "./dist/esm/index.js", 7 | "types": "./dist/types/index.d.ts", 8 | "scripts": { 9 | "build": "tsc" 10 | }, 11 | "author": "", 12 | "license": "Apache-2.0", 13 | "dependencies": { 14 | "@lmstudio/lms-common": "^0.8.5", 15 | "@lmstudio/lms-communication": "^0.6.14", 16 | "ws": "^8.16.0" 17 | }, 18 | "devDependencies": { 19 | "@types/ws": "^8.5.10" 20 | }, 21 | "exports": { 22 | ".": { 23 | "types": "./dist/types/index.d.ts", 24 | "require": "./dist/cjs/index.js", 25 | "import": "./dist/esm/index.js", 26 | "default": "./dist/esm/index.js" 27 | } 28 | }, 29 | "files": [ 30 | "./dist/cjs/**/*.js", 31 | "./dist/esm/package.json", 32 | "./dist/esm/**/*.js", 33 | "./dist/types/**/*.d.ts" 34 | ], 35 | "sideEffects": false, 36 | "gitHead": "9a71db006654e012e2749a17ac10859c5d5a36b2" 37 | } 38 | -------------------------------------------------------------------------------- /packages/lms-communication-server/src/Authenticator.ts: -------------------------------------------------------------------------------- 1 | import { type BufferedEvent, type LoggerInterface } from "@lmstudio/lms-common"; 2 | import { type AuthPacket } from "@lmstudio/lms-communication"; 3 | import { type ClientHolder } from "./AuthenticatedWsServer.js"; 4 | 5 | export interface ContextCreatorParams { 6 | type: "rpc" | "channel" | "signal" | "writableSignal"; 7 | endpointName: string; 8 | } 9 | 10 | export interface Context { 11 | logger: LoggerInterface; 12 | } 13 | 14 | export type ContextCreator = (params: ContextCreatorParams) => TContext; 15 | 16 | export abstract class Authenticator { 17 | public abstract authenticate(authPacket: AuthPacket): Promise<{ 18 | holder: ClientHolder; 19 | contextCreator: ContextCreator; 20 | authenticationRevokedEvent: BufferedEvent; 21 | }>; 22 | } 23 | -------------------------------------------------------------------------------- /packages/lms-communication-server/src/GenericServerTransport.ts: -------------------------------------------------------------------------------- 1 | import { SimpleLogger, type BufferedEvent, type LoggerInterface } from "@lmstudio/lms-common"; 2 | import type { 3 | ClientToServerMessage, 4 | ServerToClientMessage, 5 | ServerTransportFactory, 6 | } from "@lmstudio/lms-communication"; 7 | import { ServerTransport } from "@lmstudio/lms-communication"; 8 | 9 | export class GenericServerTransport extends ServerTransport { 10 | protected readonly logger; 11 | private closed = false; 12 | public constructor( 13 | onMessage: BufferedEvent, 14 | onClose: BufferedEvent, 15 | private readonly sendMessage: (message: ServerToClientMessage) => void, 16 | private readonly receivedMessage: (message: ClientToServerMessage) => void, 17 | private readonly errored: (error: any) => void, 18 | parentLogger?: LoggerInterface, 19 | ) { 20 | super(); 21 | this.logger = new SimpleLogger("GenericServerTransport", parentLogger); 22 | onMessage.subscribe(message => { 23 | let parsed: ClientToServerMessage; 24 | try { 25 | parsed = this.parseIncomingMessage(message); 26 | } catch (error) { 27 | this.logger.warn("Received invalid message from client:", message); 28 | return; 29 | } 30 | this.receivedMessage(parsed); 31 | }); 32 | onClose.subscribeOnce(() => { 33 | if (this.closed) { 34 | return; 35 | } 36 | this.closed = true; 37 | this.errored(new Error("Server closed the connection")); 38 | }); 39 | } 40 | public static createFactory( 41 | onMessage: BufferedEvent, 42 | onClose: BufferedEvent, 43 | sendMessage: (message: ServerToClientMessage) => void, 44 | ): ServerTransportFactory { 45 | return (receivedMessage, errored, parentLogger) => 46 | new GenericServerTransport( 47 | onMessage, 48 | onClose, 49 | sendMessage, 50 | receivedMessage, 51 | errored, 52 | parentLogger, 53 | ); 54 | } 55 | public override sendViaTransport(message: ServerToClientMessage) { 56 | this.sendMessage(message); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /packages/lms-communication-server/src/IpcServer.ts: -------------------------------------------------------------------------------- 1 | import { SimpleLogger } from "@lmstudio/lms-common"; 2 | import type { BackendInterface } from "@lmstudio/lms-communication"; 3 | import { type Context, type ContextCreator } from "./Authenticator.js"; 4 | import { IpcServerTransport } from "./IpcServerTransport.js"; 5 | import { ServerPort } from "./ServerPort.js"; 6 | import { type IpcMainEvent, type MessagePortMain } from "./electronTypes.js"; 7 | 8 | export type RegisterIpcListener = ( 9 | channel: string, 10 | listener: (event: IpcMainEvent, ...args: any[]) => void, 11 | ) => void; 12 | 13 | export abstract class IpcServer { 14 | protected readonly logger: SimpleLogger; 15 | public constructor( 16 | protected readonly backendInterface: BackendInterface, 17 | registerIpcListener: RegisterIpcListener, 18 | channel: string, 19 | parentLogger?: SimpleLogger, 20 | ) { 21 | this.logger = new SimpleLogger("IpcServer", parentLogger); 22 | registerIpcListener(channel, (event, ...args) => this.onConnection(event, ...args)); 23 | } 24 | protected createServerPort(contextCreator: ContextCreator, port: MessagePortMain) { 25 | return new ServerPort( 26 | this.backendInterface, 27 | contextCreator, 28 | IpcServerTransport.createFactory(port), 29 | ); 30 | } 31 | protected abstract onConnection(event: IpcMainEvent, ...args: Array): Promise; 32 | } 33 | -------------------------------------------------------------------------------- /packages/lms-communication-server/src/IpcServerTransport.ts: -------------------------------------------------------------------------------- 1 | import { SimpleLogger, type LoggerInterface } from "@lmstudio/lms-common"; 2 | import type { 3 | ClientToServerMessage, 4 | ServerToClientMessage, 5 | ServerTransportFactory, 6 | } from "@lmstudio/lms-communication"; 7 | import { ServerTransport } from "@lmstudio/lms-communication"; 8 | import { type MessagePortMain } from "./electronTypes"; 9 | 10 | export class IpcServerTransport extends ServerTransport { 11 | protected readonly logger: SimpleLogger; 12 | private closed = false; 13 | public constructor( 14 | private readonly electronPort: MessagePortMain, 15 | private readonly receivedMessage: (message: ClientToServerMessage) => void, 16 | private readonly errored: (error: any) => void, 17 | parentLogger?: LoggerInterface, 18 | ) { 19 | super(); 20 | this.logger = new SimpleLogger("IpcServerTransport", parentLogger); 21 | this.electronPort.on("message", event => { 22 | let parsed: ClientToServerMessage; 23 | try { 24 | parsed = this.parseIncomingMessage(event.data); 25 | } catch (error) { 26 | this.logger.warn("Received invalid message from client:", event.data); 27 | return; 28 | } 29 | this.receivedMessage(parsed); 30 | }); 31 | this.electronPort.start(); 32 | this.electronPort.on("close", () => { 33 | if (this.closed) { 34 | return; 35 | } 36 | this.closed = true; 37 | this.errored(new Error("MessagePort closed by the client")); 38 | }); 39 | } 40 | public static createFactory(electronPort: MessagePortMain): ServerTransportFactory { 41 | return (receivedMessage, errored) => 42 | new IpcServerTransport(electronPort, receivedMessage, errored); 43 | } 44 | public override sendViaTransport(message: ServerToClientMessage) { 45 | this.electronPort!.postMessage(message); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/lms-communication-server/src/WsServer.ts: -------------------------------------------------------------------------------- 1 | import { SimpleLogger } from "@lmstudio/lms-common"; 2 | import type { BackendInterface } from "@lmstudio/lms-communication"; 3 | import type { Server } from "http"; 4 | import { parse } from "url"; 5 | import type { WebSocket } from "ws"; 6 | import { WebSocketServer } from "ws"; 7 | 8 | export abstract class WsServer { 9 | protected readonly logger: SimpleLogger; 10 | private readonly wss: WebSocketServer; 11 | public constructor( 12 | protected readonly backendInterface: BackendInterface, 13 | server: Server, 14 | pathName: string, 15 | parentLogger?: SimpleLogger, 16 | ) { 17 | this.logger = new SimpleLogger("WsServer", parentLogger); 18 | this.wss = new WebSocketServer({ noServer: true }); 19 | this.wss.on("connection", ws => this.onConnection(ws)); 20 | server.on("upgrade", (request, socket, head) => { 21 | const { pathname } = parse(request.url ?? ""); 22 | if (pathname === `/${pathName}`) { 23 | socket.on("error", error => { 24 | this.logger.warn("Socket error:", error); 25 | }); 26 | this.wss.handleUpgrade(request, socket, head, ws => { 27 | this.wss.emit("connection", ws, request); 28 | }); 29 | } 30 | }); 31 | } 32 | protected abstract onConnection(ws: WebSocket): void; 33 | } 34 | -------------------------------------------------------------------------------- /packages/lms-communication-server/src/index.ts: -------------------------------------------------------------------------------- 1 | export { AuthenticatedIpcServer } from "./AuthenticatedIpcServer.js"; 2 | export { AuthenticatedWsServer, ClientHolder } from "./AuthenticatedWsServer.js"; 3 | export { Context, ContextCreator } from "./Authenticator.js"; 4 | export { 5 | FcfsAuthenticatedContext, 6 | FcfsAuthenticator, 7 | FcfsAuthenticatorBase, 8 | FcfsClient, 9 | } from "./fcfsAuthenticator.js"; 10 | export { GenericServerTransport } from "./GenericServerTransport.js"; 11 | export { IpcServer, RegisterIpcListener } from "./IpcServer.js"; 12 | export { ServerPort } from "./ServerPort.js"; 13 | export { WsServer } from "./WsServer.js"; 14 | -------------------------------------------------------------------------------- /packages/lms-communication-server/tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.cjs.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/cjs" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-communication-server/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.esm.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/esm" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-communication-server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": [ 3 | { "path": "./tsconfig.cjs.json" }, 4 | { "path": "./tsconfig.esm.json" }, 5 | { "path": "./tsconfig.types.json" } 6 | ], 7 | "include": [] 8 | } 9 | -------------------------------------------------------------------------------- /packages/lms-communication-server/tsconfig.types.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.types.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/types" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-communication/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/lms-communication", 3 | "version": "0.6.14", 4 | "description": "", 5 | "main": "./dist/cjs/index.js", 6 | "module": "./dist/esm/index.js", 7 | "types": "./dist/types/index.d.ts", 8 | "scripts": { 9 | "build": "tsc" 10 | }, 11 | "author": "", 12 | "license": "Apache-2.0", 13 | "dependencies": { 14 | "@lmstudio/lms-common": "^0.8.5", 15 | "superjson": "^1.13.3", 16 | "zod": "^3.22.4" 17 | }, 18 | "devDependencies": { 19 | "@types/ws": "^8.5.10" 20 | }, 21 | "exports": { 22 | ".": { 23 | "types": "./dist/types/index.d.ts", 24 | "require": "./dist/cjs/index.js", 25 | "import": "./dist/esm/index.js", 26 | "default": "./dist/esm/index.js" 27 | } 28 | }, 29 | "files": [ 30 | "./dist/cjs/**/*.js", 31 | "./dist/esm/package.json", 32 | "./dist/esm/**/*.js", 33 | "./dist/types/**/*.d.ts" 34 | ], 35 | "sideEffects": false, 36 | "gitHead": "9a71db006654e012e2749a17ac10859c5d5a36b2" 37 | } 38 | -------------------------------------------------------------------------------- /packages/lms-communication/src/WsAuthenticationResult.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export const wsAuthenticationResultSchema = z.discriminatedUnion("success", [ 4 | z.object({ 5 | success: z.literal(true), 6 | }), 7 | z.object({ 8 | success: z.literal(false), 9 | error: z.string(), 10 | }), 11 | ]); 12 | 13 | export type WsAuthenticationResult = z.infer; 14 | -------------------------------------------------------------------------------- /packages/lms-communication/src/authentication.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export const authPacketSchema = z.object({ 4 | authVersion: z.literal(1), 5 | clientIdentifier: z.string().max(256), 6 | clientPasskey: z.string().max(256), 7 | }); 8 | 9 | export type AuthPacket = z.infer; 10 | -------------------------------------------------------------------------------- /packages/lms-communication/src/index.ts: -------------------------------------------------------------------------------- 1 | export { AuthPacket, authPacketSchema } from "./authentication.js"; 2 | export { 3 | BackendInterface, 4 | BackendInterfaceWithContext, 5 | ChannelEndpoint, 6 | ChannelEndpointsSpecBase, 7 | ExtractBackendInterfaceChannelEndpoints, 8 | ExtractBackendInterfaceRpcEndpoints, 9 | ExtractBackendInterfaceSignalEndpoints, 10 | ExtractBackendInterfaceWritableSignalEndpoints, 11 | RpcEndpoint, 12 | RpcEndpointsSpecBase, 13 | SignalEndpoint, 14 | SignalEndpointsSpecBase, 15 | WritableSignalEndpoint, 16 | WritableSignalEndpointsSpecBase, 17 | } from "./BackendInterface.js"; 18 | export { Channel, InferClientChannelType, InferServerChannelType } from "./Channel.js"; 19 | export { 20 | deserialize, 21 | SerializationType, 22 | serialize, 23 | SerializedOpaque, 24 | serializedOpaqueSchema, 25 | } from "./serialization.js"; 26 | export { KEEP_ALIVE_INTERVAL, KEEP_ALIVE_TIMEOUT } from "./timeoutConstants.js"; 27 | export { 28 | ClientToServerMessage, 29 | ClientTransport, 30 | ClientTransportFactory, 31 | ServerToClientMessage, 32 | ServerTransport, 33 | ServerTransportFactory, 34 | } from "./Transport.js"; 35 | export { WsAuthenticationResult, wsAuthenticationResultSchema } from "./WsAuthenticationResult.js"; 36 | export { WsMessageEvent } from "./wsTypes.js"; 37 | -------------------------------------------------------------------------------- /packages/lms-communication/src/serialization.ts: -------------------------------------------------------------------------------- 1 | import { deserialize as superJsonDeserialize, serialize as superJsonSerialize } from "superjson"; 2 | import { z, type ZodSchema } from "zod"; 3 | 4 | /** 5 | * Type of serialization: 6 | * 7 | * Raw: JSON.stringify and JSON.parse 8 | * Superjson: SuperJSON.serialize and SuperJSON.deserialize 9 | */ 10 | export type SerializationType = "raw" | "superjson"; 11 | 12 | const serializedOpaqueSymbol = Symbol("SerializedOpaque"); 13 | 14 | /** 15 | * Opaque type that represents a serialized value. The representation here is not accurate and is 16 | * only used to prevent accidental reading/writing of the opaque value. 17 | */ 18 | export type SerializedOpaque = { 19 | [serializedOpaqueSymbol]: T; 20 | }; 21 | 22 | /** 23 | * Serialize a value to another value using the specified serialization type. 24 | */ 25 | export function serialize(type: SerializationType, value: TData): SerializedOpaque { 26 | switch (type) { 27 | case "raw": 28 | return value as SerializedOpaque; 29 | case "superjson": 30 | return superJsonSerialize(value) as unknown as SerializedOpaque; 31 | } 32 | } 33 | 34 | export function deserialize(type: SerializationType, value: SerializedOpaque): TData { 35 | switch (type) { 36 | case "raw": 37 | return value as TData; 38 | case "superjson": 39 | return superJsonDeserialize(value as unknown as any) as TData; 40 | } 41 | } 42 | 43 | export const serializedOpaqueSchema = z.any() as ZodSchema>; 44 | -------------------------------------------------------------------------------- /packages/lms-communication/src/timeoutConstants.ts: -------------------------------------------------------------------------------- 1 | export const KEEP_ALIVE_INTERVAL = 5_000; 2 | export const KEEP_ALIVE_TIMEOUT = 15_000; 3 | -------------------------------------------------------------------------------- /packages/lms-communication/src/wsTypes.ts: -------------------------------------------------------------------------------- 1 | import { type WebSocket } from "ws"; 2 | 3 | type Data = string | Buffer | ArrayBuffer | Buffer[]; 4 | export interface WsMessageEvent { 5 | data: Data; 6 | type: string; 7 | target: WebSocket; 8 | } 9 | -------------------------------------------------------------------------------- /packages/lms-communication/tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.cjs.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/cjs" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-communication/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.esm.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/esm" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-communication/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": [ 3 | { "path": "./tsconfig.cjs.json" }, 4 | { "path": "./tsconfig.esm.json" }, 5 | { "path": "./tsconfig.types.json" } 6 | ], 7 | "include": [] 8 | } 9 | -------------------------------------------------------------------------------- /packages/lms-communication/tsconfig.types.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.types.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/types" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-es-plugin-runner/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/lms-es-plugin-runner", 3 | "version": "0.0.16", 4 | "description": "", 5 | "main": "./dist/cjs/index.js", 6 | "module": "./dist/esm/index.js", 7 | "types": "./dist/types/index.d.ts", 8 | "scripts": { 9 | "build": "tsc" 10 | }, 11 | "author": "", 12 | "license": "Apache-2.0", 13 | "dependencies": { 14 | "@lmstudio/lms-common": "^0.8.5", 15 | "@lmstudio/lms-common-server": "^0.2.14", 16 | "@npmcli/arborist": "^8.0.0" 17 | }, 18 | "devDependencies": { 19 | "@types/node": "^22.7.7", 20 | "@types/npmcli__arborist": "^5.6.11" 21 | }, 22 | "exports": { 23 | ".": { 24 | "types": "./dist/types/index.d.ts", 25 | "require": "./dist/cjs/index.js", 26 | "import": "./dist/esm/index.js", 27 | "default": "./dist/esm/index.js" 28 | }, 29 | "./installer": { 30 | "types": "./dist/types/EsPluginInstaller.d.ts", 31 | "require": "./dist/cjs/EsPluginInstaller.js", 32 | "import": "./dist/esm/EsPluginInstaller.js", 33 | "default": "./dist/esm/EsPluginInstaller.js" 34 | }, 35 | "./runner-watcher": { 36 | "types": "./dist/types/EsPluginRunnerWatcher.d.ts", 37 | "require": "./dist/cjs/EsPluginRunnerWatcher.js", 38 | "import": "./dist/esm/EsPluginRunnerWatcher.js", 39 | "default": "./dist/esm/EsPluginRunnerWatcher.js" 40 | }, 41 | "./util-binary": { 42 | "types": "./dist/types/UtilBinary.d.ts", 43 | "require": "./dist/cjs/UtilBinary.js", 44 | "import": "./dist/esm/UtilBinary.js", 45 | "default": "./dist/esm/UtilBinary.js" 46 | } 47 | }, 48 | "sideEffects": false, 49 | "files": [ 50 | "./dist/cjs/**/*.js", 51 | "./dist/esm/package.json", 52 | "./dist/esm/**/*.js", 53 | "./dist/types/**/*.d.ts" 54 | ], 55 | "gitHead": "9a71db006654e012e2749a17ac10859c5d5a36b2" 56 | } 57 | -------------------------------------------------------------------------------- /packages/lms-es-plugin-runner/src/UtilBinary.ts: -------------------------------------------------------------------------------- 1 | import { text } from "@lmstudio/lms-common"; 2 | import { findLMStudioHome } from "@lmstudio/lms-common-server"; 3 | import { spawn, type SpawnOptionsWithoutStdio } from "child_process"; 4 | import { access } from "fs/promises"; 5 | import { join } from "path"; 6 | 7 | export interface UtilBinaryOpts { 8 | /** 9 | * If provided, uses the util binary from this folder instead. 10 | */ 11 | utilsFolderPathOverride?: string; 12 | } 13 | 14 | export class UtilBinary { 15 | private readonly path: string; 16 | public constructor( 17 | private readonly name: string, 18 | { utilsFolderPathOverride }: UtilBinaryOpts = {}, 19 | ) { 20 | const utilsFolder = utilsFolderPathOverride ?? join(findLMStudioHome(), ".internal", "utils"); 21 | this.path = join(utilsFolder, process.platform === "win32" ? `${name}.exe` : name); 22 | } 23 | public async check() { 24 | try { 25 | access(this.path); 26 | } catch { 27 | throw new Error(text` 28 | Cannot locate required dependencies (${this.name}). Please make sure you have the latest version 29 | of LM Studio installed. 30 | `); 31 | } 32 | } 33 | public spawn(args: Array, opts?: SpawnOptionsWithoutStdio) { 34 | return spawn(this.path, args, opts); 35 | } 36 | public exec(args: Array) { 37 | const childProcess = this.spawn(args); 38 | childProcess.stdout.pipe(process.stdout as any); 39 | childProcess.stderr.pipe(process.stderr as any); 40 | return new Promise((resolve, reject) => { 41 | childProcess.on("exit", code => { 42 | if (code === 0) { 43 | resolve(); 44 | } else { 45 | reject(new Error(text`${this.name} failed with code ${code ?? "unknown"}`)); 46 | } 47 | }); 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/lms-es-plugin-runner/src/esbuildArgs.ts: -------------------------------------------------------------------------------- 1 | interface EsBuildArgsOpts { 2 | entryPath: string; 3 | outPath: string; 4 | watch?: boolean; 5 | production?: boolean; 6 | } 7 | const alwaysArgs = [ 8 | "--platform=node", 9 | "--target=node18.16.0", 10 | "--sourcemap=inline", 11 | "--tree-shaking=true", 12 | "--bundle", 13 | // Don't bundle node_modules as they are not necessarily designed to be bundled. 14 | "--packages=external", 15 | ]; 16 | export function createEsBuildArgs({ entryPath, outPath, watch, production }: EsBuildArgsOpts) { 17 | // We don't need to worry about shell injections here because we never pass the args to a shell, 18 | // but rather to spawn directly. 19 | const args = [entryPath, ...alwaysArgs]; 20 | args.push("--outfile=" + outPath); 21 | if (watch) { 22 | args.push("--watch"); 23 | } 24 | if (production) { 25 | args.push('--define:process.env.NODE_ENV="production"'); 26 | } else { 27 | args.push('--define:process.env.NODE_ENV="development"'); 28 | } 29 | return args; 30 | } 31 | -------------------------------------------------------------------------------- /packages/lms-es-plugin-runner/src/index.ts: -------------------------------------------------------------------------------- 1 | export { EsPluginInstaller } from "./EsPluginInstaller.js"; 2 | export { EsPluginRunnerWatcher } from "./EsPluginRunnerWatcher.js"; 3 | export { UtilBinary } from "./UtilBinary.js"; 4 | -------------------------------------------------------------------------------- /packages/lms-es-plugin-runner/tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.cjs.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/cjs" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-es-plugin-runner/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.esm.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/esm" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-es-plugin-runner/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": [ 3 | { "path": "./tsconfig.cjs.json" }, 4 | { "path": "./tsconfig.esm.json" }, 5 | { "path": "./tsconfig.types.json" } 6 | ], 7 | "include": [] 8 | } 9 | -------------------------------------------------------------------------------- /packages/lms-es-plugin-runner/tsconfig.types.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.types.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/types" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-external-backend-interfaces/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/lms-external-backend-interfaces", 3 | "version": "0.3.6", 4 | "description": "", 5 | "main": "./dist/cjs/index.js", 6 | "module": "./dist/esm/index.js", 7 | "types": "./dist/types/index.d.ts", 8 | "scripts": { 9 | "build": "tsc" 10 | }, 11 | "author": "", 12 | "dependencies": { 13 | "@lmstudio/lms-common": "^0.8.5", 14 | "@lmstudio/lms-communication": "^0.6.14", 15 | "@lmstudio/lms-shared-types": "^0.6.10", 16 | "zod": "^3.22.4" 17 | }, 18 | "devDependencies": { 19 | "@lmstudio/lms-communication-client": "^0.6.14" 20 | }, 21 | "exports": { 22 | ".": { 23 | "types": "./dist/types/index.d.ts", 24 | "require": "./dist/cjs/index.js", 25 | "import": "./dist/esm/index.js", 26 | "default": "./dist/esm/index.js" 27 | } 28 | }, 29 | "files": [ 30 | "./dist/cjs/**/*.js", 31 | "./dist/esm/package.json", 32 | "./dist/esm/**/*.js", 33 | "./dist/types/**/*.d.ts" 34 | ], 35 | "license": "Apache-2.0", 36 | "sideEffects": false, 37 | "gitHead": "abe566030fdea1ad86c21c3d5f32ded4782e8c0b" 38 | } 39 | -------------------------------------------------------------------------------- /packages/lms-external-backend-interfaces/src/diagnosticsBackendInterface.ts: -------------------------------------------------------------------------------- 1 | import { BackendInterface } from "@lmstudio/lms-communication"; 2 | import { type InferClientPort } from "@lmstudio/lms-communication-client"; 3 | import { diagnosticsLogEventSchema } from "@lmstudio/lms-shared-types"; 4 | import { z } from "zod"; 5 | 6 | export function createDiagnosticsBackendInterface() { 7 | return new BackendInterface().addChannelEndpoint("streamLogs", { 8 | creationParameter: z.void(), 9 | toServerPacket: z.discriminatedUnion("type", [ 10 | z.object({ 11 | type: z.literal("stop"), 12 | }), 13 | ]), 14 | toClientPacket: z.discriminatedUnion("type", [ 15 | z.object({ 16 | type: z.literal("log"), 17 | log: diagnosticsLogEventSchema, 18 | }), 19 | ]), 20 | }); 21 | } 22 | 23 | export type DiagnosticsPort = InferClientPort; 24 | export type DiagnosticsBackendInterface = ReturnType; 25 | -------------------------------------------------------------------------------- /packages/lms-external-backend-interfaces/src/embeddingBackendInterface.ts: -------------------------------------------------------------------------------- 1 | import { type InferClientPort } from "@lmstudio/lms-communication-client"; 2 | import { 3 | type EmbeddingModelInfo, 4 | embeddingModelInfoSchema, 5 | type EmbeddingModelInstanceInfo, 6 | embeddingModelInstanceInfoSchema, 7 | modelSpecifierSchema, 8 | } from "@lmstudio/lms-shared-types"; 9 | import { z } from "zod"; 10 | import { 11 | type BaseModelBackendInterface, 12 | createBaseModelBackendInterface, 13 | } from "./baseModelBackendInterface.js"; 14 | 15 | export function createEmbeddingBackendInterface() { 16 | const baseModelBackendInterface = createBaseModelBackendInterface( 17 | embeddingModelInstanceInfoSchema, 18 | embeddingModelInfoSchema, 19 | ) as any as BaseModelBackendInterface; 20 | return baseModelBackendInterface 21 | .addRpcEndpoint("embedString", { 22 | parameter: z.object({ 23 | modelSpecifier: modelSpecifierSchema, 24 | inputString: z.string(), 25 | }), 26 | returns: z.object({ 27 | embedding: z.array(z.number()), 28 | }), 29 | }) 30 | .addRpcEndpoint("tokenize", { 31 | parameter: z.object({ 32 | specifier: modelSpecifierSchema, 33 | inputString: z.string(), 34 | }), 35 | returns: z.object({ 36 | tokens: z.array(z.number()), 37 | }), 38 | }) 39 | .addRpcEndpoint("countTokens", { 40 | parameter: z.object({ 41 | specifier: modelSpecifierSchema, 42 | inputString: z.string(), 43 | }), 44 | returns: z.object({ 45 | tokenCount: z.number().int(), 46 | }), 47 | }); 48 | } 49 | 50 | export type EmbeddingPort = InferClientPort; 51 | export type EmbeddingBackendInterface = ReturnType; 52 | -------------------------------------------------------------------------------- /packages/lms-external-backend-interfaces/src/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | BaseModelBackendInterface, 3 | BaseModelPort, 4 | createBaseModelBackendInterface, 5 | } from "./baseModelBackendInterface.js"; 6 | export { 7 | createDiagnosticsBackendInterface, 8 | DiagnosticsBackendInterface, 9 | DiagnosticsPort, 10 | } from "./diagnosticsBackendInterface.js"; 11 | export { 12 | createEmbeddingBackendInterface, 13 | EmbeddingBackendInterface, 14 | EmbeddingPort, 15 | } from "./embeddingBackendInterface.js"; 16 | export { 17 | createFilesBackendInterface, 18 | FilesBackendInterface, 19 | FilesPort, 20 | } from "./filesBackendInterface.js"; 21 | export { createLlmBackendInterface, LLMBackendInterface, LLMPort } from "./llmBackendInterface.js"; 22 | export { 23 | createPluginsBackendInterface, 24 | PluginsBackendInterface, 25 | PluginsPort, 26 | } from "./pluginsBackendInterface.js"; 27 | export { 28 | createRepositoryBackendInterface, 29 | RepositoryBackendInterface, 30 | RepositoryPort, 31 | } from "./repositoryBackendInterface.js"; 32 | export { 33 | createSystemBackendInterface, 34 | SystemBackendInterface, 35 | SystemPort, 36 | } from "./systemBackendInterface.js"; 37 | -------------------------------------------------------------------------------- /packages/lms-external-backend-interfaces/src/systemBackendInterface.ts: -------------------------------------------------------------------------------- 1 | import { BackendInterface } from "@lmstudio/lms-communication"; 2 | import { type InferClientPort } from "@lmstudio/lms-communication-client"; 3 | import { backendNotificationSchema, modelInfoSchema } from "@lmstudio/lms-shared-types"; 4 | import { z } from "zod"; 5 | 6 | export function createSystemBackendInterface() { 7 | return ( 8 | new BackendInterface() 9 | .addRpcEndpoint("listDownloadedModels", { 10 | parameter: z.void(), 11 | returns: z.array(modelInfoSchema), 12 | }) 13 | .addChannelEndpoint("alive", { 14 | creationParameter: z.void(), 15 | toServerPacket: z.void(), 16 | toClientPacket: z.void(), 17 | }) 18 | .addRpcEndpoint("notify", { 19 | parameter: backendNotificationSchema, 20 | returns: z.void(), 21 | }) 22 | /** 23 | * Get the LM Studio version 24 | */ 25 | .addRpcEndpoint("version", { 26 | parameter: z.void(), 27 | returns: z.object({ 28 | /** 29 | * `major.minor.patch` 30 | */ 31 | version: z.string(), 32 | /** 33 | * LM Studio build number 34 | */ 35 | build: z.number(), 36 | }), 37 | }) 38 | .addRpcEndpoint("setExperimentFlag", { 39 | parameter: z.object({ 40 | code: z.string(), 41 | value: z.boolean(), 42 | }), 43 | returns: z.void(), 44 | }) 45 | .addRpcEndpoint("getExperimentFlags", { 46 | parameter: z.void(), 47 | returns: z.array(z.string()), 48 | }) 49 | ); 50 | } 51 | 52 | export type SystemPort = InferClientPort; 53 | export type SystemBackendInterface = ReturnType; 54 | -------------------------------------------------------------------------------- /packages/lms-external-backend-interfaces/tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.cjs.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/cjs" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-external-backend-interfaces/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.esm.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/esm" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-external-backend-interfaces/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": [ 3 | { "path": "./tsconfig.cjs.json" }, 4 | { "path": "./tsconfig.esm.json" }, 5 | { "path": "./tsconfig.types.json" } 6 | ], 7 | "include": [] 8 | } 9 | -------------------------------------------------------------------------------- /packages/lms-external-backend-interfaces/tsconfig.types.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.types.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/types" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-isomorphic/.npmignore: -------------------------------------------------------------------------------- 1 | *.tsbuildinfo 2 | -------------------------------------------------------------------------------- /packages/lms-isomorphic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/lms-isomorphic", 3 | "version": "0.4.5", 4 | "description": "", 5 | "main": "dist/cjs/index.js", 6 | "browser": "dist/cjs/browser.js", 7 | "types": "dist/types/index.d.ts", 8 | "scripts": { 9 | "build": "tsc" 10 | }, 11 | "author": "", 12 | "license": "Apache-2.0", 13 | "devDependencies": { 14 | "@types/ws": "^8.5.10" 15 | }, 16 | "dependencies": { 17 | "ws": "^8.16.0" 18 | }, 19 | "sideEffects": false, 20 | "gitHead": "9a71db006654e012e2749a17ac10859c5d5a36b2" 21 | } 22 | -------------------------------------------------------------------------------- /packages/lms-isomorphic/src/browser.ts: -------------------------------------------------------------------------------- 1 | export { generateRandomBase64 } from "./browser/generateRandomBase64.js"; 2 | export { readFileAsBase64 } from "./browser/readFileAsBase64.js"; 3 | export { terminalSize } from "./browser/terminalSize.js"; 4 | export { WebSocket } from "./browser/WebSocket.js"; 5 | -------------------------------------------------------------------------------- /packages/lms-isomorphic/src/browser/WebSocket.ts: -------------------------------------------------------------------------------- 1 | export const WebSocket = globalThis.WebSocket; 2 | -------------------------------------------------------------------------------- /packages/lms-isomorphic/src/browser/generateRandomBase64.ts: -------------------------------------------------------------------------------- 1 | export function generateRandomBase64(bytesOfRandomness = 18) { 2 | const randomBytes = new Uint8Array(bytesOfRandomness); 3 | globalThis.crypto.getRandomValues(randomBytes); 4 | // Using btoa here is safe because the input is not string anyways. 5 | return btoa(String.fromCharCode(...randomBytes)); 6 | } 7 | -------------------------------------------------------------------------------- /packages/lms-isomorphic/src/browser/readFileAsBase64.ts: -------------------------------------------------------------------------------- 1 | export async function readFileAsBase64(_path: string): Promise< 2 | | { 3 | success: true; 4 | base64: string; 5 | } 6 | | { 7 | success: false; 8 | } 9 | > { 10 | return { success: false }; 11 | } 12 | -------------------------------------------------------------------------------- /packages/lms-isomorphic/src/browser/terminalSize.ts: -------------------------------------------------------------------------------- 1 | export function terminalSize() { 2 | return { columns: 80, rows: 24 }; 3 | } 4 | -------------------------------------------------------------------------------- /packages/lms-isomorphic/src/index.ts: -------------------------------------------------------------------------------- 1 | export { generateRandomBase64 } from "./index/generateRandomBase64.js"; 2 | export { readFileAsBase64 } from "./index/readFileAsBase64.js"; 3 | export { terminalSize } from "./index/terminalSize.js"; 4 | export { WebSocket } from "./index/WebSocket.js"; 5 | -------------------------------------------------------------------------------- /packages/lms-isomorphic/src/index/WebSocket.ts: -------------------------------------------------------------------------------- 1 | import WebSocket from "ws"; 2 | 3 | export { WebSocket }; 4 | -------------------------------------------------------------------------------- /packages/lms-isomorphic/src/index/generateRandomBase64.ts: -------------------------------------------------------------------------------- 1 | import { randomBytes } from "crypto"; 2 | 3 | export function generateRandomBase64(bytesOfRandomness = 18) { 4 | const randomBytesBuffer = randomBytes(bytesOfRandomness); 5 | return randomBytesBuffer.toString("base64"); 6 | } 7 | -------------------------------------------------------------------------------- /packages/lms-isomorphic/src/index/readFileAsBase64.ts: -------------------------------------------------------------------------------- 1 | import { readFile } from "fs/promises"; 2 | 3 | export async function readFileAsBase64(path: string): Promise< 4 | | { 5 | success: true; 6 | base64: string; 7 | } 8 | | { 9 | success: false; 10 | } 11 | > { 12 | return { success: true, base64: await readFile(path, "base64") }; 13 | } 14 | -------------------------------------------------------------------------------- /packages/lms-isomorphic/tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.cjs.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/cjs" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-isomorphic/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.esm.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/esm" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-isomorphic/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": [ 3 | { "path": "./tsconfig.cjs.json" }, 4 | { "path": "./tsconfig.esm.json" }, 5 | { "path": "./tsconfig.types.json" } 6 | ], 7 | "include": [] 8 | } 9 | -------------------------------------------------------------------------------- /packages/lms-isomorphic/tsconfig.types.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.types.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/types" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-json-schema/.gitignore: -------------------------------------------------------------------------------- 1 | schemas 2 | -------------------------------------------------------------------------------- /packages/lms-json-schema/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/lms-json-schema", 3 | "version": "0.0.17", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "scripts": { 8 | "build": "tsc", 9 | "make-schemas": "node ./dist/index.js" 10 | }, 11 | "dependencies": { 12 | "@lmstudio/lms-communication": "^0.6.14", 13 | "@lmstudio/lms-external-backend-interfaces": "^0.3.6", 14 | "@lmstudio/lms-shared-types": "^0.6.10", 15 | "zod": "^3.22.4", 16 | "zod-to-json-schema": "3.22.4" 17 | }, 18 | "devDependencies": { 19 | "@types/node": "20.12.7" 20 | }, 21 | "author": "", 22 | "license": "Apache-2.0", 23 | "gitHead": "abe566030fdea1ad86c21c3d5f32ded4782e8c0b" 24 | } 25 | -------------------------------------------------------------------------------- /packages/lms-json-schema/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist", 6 | "module": "nodenext", 7 | "moduleResolution": "nodenext" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/lms-kv-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/lms-kv-config", 3 | "version": "0.2.11", 4 | "description": "", 5 | "main": "./dist/cjs/index.js", 6 | "module": "./dist/esm/index.js", 7 | "types": "./dist/types/index.d.ts", 8 | "scripts": { 9 | "build": "tsc" 10 | }, 11 | "author": "", 12 | "license": "Apache-2.0", 13 | "dependencies": { 14 | "@lmstudio/lms-shared-types": "^0.6.10", 15 | "zod": "^3.22.4" 16 | }, 17 | "devDependencies": { 18 | "ts-toolbelt": "^9.6.0" 19 | }, 20 | "exports": { 21 | ".": { 22 | "types": "./dist/types/index.d.ts", 23 | "require": "./dist/cjs/index.js", 24 | "import": "./dist/esm/index.js", 25 | "default": "./dist/esm/index.js" 26 | } 27 | }, 28 | "files": [ 29 | "./dist/cjs/**/*.js", 30 | "./dist/esm/package.json", 31 | "./dist/esm/**/*.js", 32 | "./dist/types/**/*.d.ts" 33 | ], 34 | "sideEffects": false, 35 | "gitHead": "9a71db006654e012e2749a17ac10859c5d5a36b2" 36 | } 37 | -------------------------------------------------------------------------------- /packages/lms-kv-config/src/conversion/utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Convert a number that can be false to checkbox numeric value. 3 | * 4 | * @param maybeFalseNumber - The value to translate. 5 | * @param valueWhenUnchecked - The value to use when the checkbox is unchecked. 6 | */ 7 | export function maybeFalseNumberToCheckboxNumeric( 8 | maybeFalseNumber: undefined | number | false, 9 | valueWhenUnchecked: number, 10 | ): undefined | { checked: boolean; value: number } { 11 | if (maybeFalseNumber === undefined) { 12 | return undefined; 13 | } 14 | if (maybeFalseNumber === false) { 15 | return { checked: false, value: valueWhenUnchecked }; 16 | } 17 | return { checked: true, value: maybeFalseNumber }; 18 | } 19 | -------------------------------------------------------------------------------- /packages/lms-kv-config/tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.cjs.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/cjs" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-kv-config/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.esm.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/esm" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-kv-config/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": [ 3 | { "path": "./tsconfig.cjs.json" }, 4 | { "path": "./tsconfig.esm.json" }, 5 | { "path": "./tsconfig.types.json" } 6 | ], 7 | "include": [] 8 | } 9 | -------------------------------------------------------------------------------- /packages/lms-kv-config/tsconfig.types.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.types.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/types" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-lmstudio/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/lms-lmstudio", 3 | "version": "0.0.28", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "scripts": { 8 | "build": "tsc" 9 | }, 10 | "author": "", 11 | "license": "Apache-2.0", 12 | "dependencies": { 13 | "@lmstudio/lms-common": "^0.8.5", 14 | "@lmstudio/lms-common-server": "^0.2.14", 15 | "boxen": "^5.1.2", 16 | "chalk": "^4.1.2", 17 | "inquirer": "^8.2.6" 18 | }, 19 | "devDependencies": { 20 | "@types/inquirer": "^9.0.7", 21 | "@types/node": "^20.12.7" 22 | }, 23 | "exports": { 24 | ".": { 25 | "types": "./dist/types/index.d.ts", 26 | "require": "./dist/cjs/index.js", 27 | "import": "./dist/esm/index.js", 28 | "default": "./dist/esm/index.js" 29 | }, 30 | "./install-cli": { 31 | "types": "./dist/types/installCli/index.d.ts", 32 | "require": "./dist/cjs/installCli/index.js", 33 | "import": "./dist/esm/installCli/index.js", 34 | "default": "./dist/esm/installCli/index.js" 35 | } 36 | }, 37 | "files": [ 38 | "./dist/cjs/**/*.js", 39 | "./dist/esm/package.json", 40 | "./dist/esm/**/*.js", 41 | "./dist/types/**/*.d.ts" 42 | ], 43 | "gitHead": "9a71db006654e012e2749a17ac10859c5d5a36b2" 44 | } 45 | -------------------------------------------------------------------------------- /packages/lms-lmstudio/src/index.ts: -------------------------------------------------------------------------------- 1 | import { makeTitledPrettyError } from "@lmstudio/lms-common"; 2 | import chalk from "chalk"; 3 | import { installCli } from "./installCli/index.js"; 4 | 5 | async function main() { 6 | if (process.argv.length !== 3 && process.argv[2] !== "install-cli") { 7 | throw makeTitledPrettyError( 8 | "Invalid usage, only the following is supported:", 9 | ` ${chalk.yellowBright("npx lmstudio install-cli")}`, 10 | ); 11 | } 12 | await installCli(); 13 | } 14 | 15 | main().catch(e => { 16 | if (typeof e.message === "string") { 17 | console.error(e.message); 18 | return; 19 | } 20 | throw e; 21 | }); 22 | -------------------------------------------------------------------------------- /packages/lms-lmstudio/src/installCli/index.ts: -------------------------------------------------------------------------------- 1 | import { makeTitledPrettyError, text } from "@lmstudio/lms-common"; 2 | import { findLMStudioHome } from "@lmstudio/lms-common-server"; 3 | import chalk from "chalk"; 4 | import { stat } from "node:fs/promises"; 5 | import { join } from "node:path"; 6 | import { platform } from "node:process"; 7 | import { installCliDarwinOrLinux } from "./darwinOrLinux.js"; 8 | import { installCliWin32 } from "./win32.js"; 9 | 10 | export interface InstallCliOpts { 11 | skipConfirmation?: boolean; 12 | } 13 | 14 | export async function installCli(opts: InstallCliOpts = {}) { 15 | const targetPath = join(`${findLMStudioHome()}`, `bin`); 16 | const pathStat = await stat(targetPath).catch(() => null); 17 | if (pathStat === null || pathStat.isDirectory() === false) { 18 | throw makeTitledPrettyError( 19 | "Cannot find LM Studio installation", 20 | text` 21 | LM Studio CLI (lms) is shipped with the latest version of LM Studio. Please install LM 22 | Studio first. You can download it from: 23 | 24 | ${chalk.cyanBright("https://lmstudio.ai/")} 25 | 26 | If you have just installed LM Studio, please run it at least once before running this tool 27 | again. 28 | `, 29 | ); 30 | } 31 | if (platform === "win32") { 32 | await installCliWin32(targetPath, opts); 33 | // await installCliWin32(targetPath); 34 | } else if (platform === "linux" || platform === "darwin") { 35 | await installCliDarwinOrLinux(targetPath, opts); 36 | } else { 37 | throw makeTitledPrettyError( 38 | `Your platform (${chalk.yellowBright(platform)}) is not support by this tool`, 39 | text` 40 | To complete the setup manually, please try to add the following directory to the PATH 41 | environment variable: 42 | 43 | ${chalk.yellowBright(targetPath)} 44 | `, 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/lms-lmstudio/tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.cjs.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/cjs" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-lmstudio/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.esm.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/esm" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-lmstudio/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": [ 3 | { "path": "./tsconfig.cjs.json" }, 4 | { "path": "./tsconfig.esm.json" }, 5 | { "path": "./tsconfig.types.json" } 6 | ], 7 | "include": [] 8 | } 9 | -------------------------------------------------------------------------------- /packages/lms-lmstudio/tsconfig.types.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.types.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/types" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-shared-types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/lms-shared-types", 3 | "version": "0.6.10", 4 | "description": "", 5 | "main": "./dist/cjs/index.js", 6 | "module": "./dist/esm/index.js", 7 | "types": "./dist/types/index.d.ts", 8 | "scripts": { 9 | "build": "tsc" 10 | }, 11 | "author": "", 12 | "license": "Apache-2.0", 13 | "dependencies": { 14 | "zod": "^3.22.4" 15 | }, 16 | "exports": { 17 | ".": { 18 | "types": "./dist/types/index.d.ts", 19 | "require": "./dist/cjs/index.js", 20 | "import": "./dist/esm/index.js", 21 | "default": "./dist/esm/index.js" 22 | } 23 | }, 24 | "files": [ 25 | "./dist/cjs/**/*.js", 26 | "./dist/esm/package.json", 27 | "./dist/esm/**/*.js", 28 | "./dist/types/**/*.d.ts" 29 | ], 30 | "gitHead": "9a71db006654e012e2749a17ac10859c5d5a36b2", 31 | "devDependencies": { 32 | "@swc/core": "^1.9.3", 33 | "@types/node": "^22.9.3" 34 | }, 35 | "sideEffects": false 36 | } 37 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/AllowableEnvVars.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export const allowableEnvVarKeys = ["HSA_OVERRIDE_GFX_VERSION"] as const; 4 | /** 5 | * Type representing the environment variables that can be set by the user. 6 | * 7 | * @public 8 | */ 9 | export type AllowableEnvVarKeys = "HSA_OVERRIDE_GFX_VERSION"; 10 | export const allowableEnvVarKeysSchema = z.enum(allowableEnvVarKeys); 11 | 12 | /** 13 | * Allow-list only record of environment variables and their values. 14 | * 15 | * @public 16 | */ 17 | export type AllowableEnvVars = Partial>; 18 | export const allowableEnvVarsSchema = z.record( 19 | allowableEnvVarKeysSchema, 20 | z.string(), 21 | ) as z.ZodSchema; 22 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/ArtifactManifest.ts: -------------------------------------------------------------------------------- 1 | import { z, type ZodSchema } from "zod"; 2 | import { modelManifestSchema, type ModelManifest } from "./ModelManifest.js"; 3 | import { pluginManifestSchema, type PluginManifest } from "./PluginManifest.js"; 4 | import { presetManifestSchema, type PresetManifest } from "./PresetManifest.js"; 5 | 6 | export type ArtifactManifest = PluginManifest | PresetManifest | ModelManifest; 7 | export const artifactManifestSchema = z.discriminatedUnion("type", [ 8 | pluginManifestSchema, 9 | presetManifestSchema, 10 | modelManifestSchema, 11 | ]) as ZodSchema; 12 | 13 | export type ArtifactType = "plugin" | "preset" | "model"; 14 | export const artifactTypeSchema = z.enum(["plugin", "preset", "model"]); 15 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/BackendNotification.ts: -------------------------------------------------------------------------------- 1 | import { z, type ZodSchema } from "zod"; 2 | 3 | /** 4 | * @public 5 | */ 6 | export interface BackendNotification { 7 | title: string; 8 | description?: string; 9 | noAutoDismiss?: boolean; 10 | } 11 | export const backendNotificationSchema = z.object({ 12 | title: z.string(), 13 | description: z.string().optional(), 14 | noAutoDismiss: z.boolean().optional(), 15 | }) as ZodSchema; 16 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/CitationSource.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | /** 4 | * Represents a source of a citation. 5 | * 6 | * @public 7 | */ 8 | export interface CitationSource { 9 | fileName: string; 10 | absoluteFilePath?: string; 11 | pageNumber?: number | [start: number, end: number]; 12 | lineNumber?: number | [start: number, end: number]; 13 | } 14 | export const citationSourceSchema = z.object({ 15 | fileName: z.string(), 16 | absoluteFilePath: z.string().optional(), 17 | pageNumber: z.union([z.number().int(), z.tuple([z.number().int(), z.number().int()])]).optional(), 18 | lineNumber: z.union([z.number().int(), z.tuple([z.number().int(), z.number().int()])]).optional(), 19 | }) as z.Schema; 20 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/ColorPalette.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | /** 4 | * Theme color options. 5 | * 6 | * @public 7 | */ 8 | export type ColorPalette = "red" | "green" | "blue" | "yellow" | "orange" | "purple" | "default"; 9 | /** 10 | * @deprecated Use colorPaletteSchema instead. 11 | */ 12 | export const colorPalette = z.enum([ 13 | "red", 14 | "green", 15 | "blue", 16 | "yellow", 17 | "orange", 18 | "purple", 19 | "default", 20 | ]); 21 | export const colorPaletteSchema = colorPalette; 22 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/JSONSerializable.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export const jsonSerializableSchema = z.any().transform((val, ctx) => { 4 | try { 5 | // Needs a more performant way to do this. 6 | return JSON.parse(JSON.stringify(val)); 7 | } catch (e: any) { 8 | ctx.addIssue({ 9 | code: z.ZodIssueCode.custom, 10 | message: "Not JSON serializable: " + e.message, 11 | }); 12 | return val; 13 | } 14 | }); 15 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/ModelCompatibilityType.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | /** 4 | * @public 5 | */ 6 | export type ModelCompatibilityType = 7 | | "gguf" 8 | | "safetensors" 9 | | "onnx" 10 | | "ggml" 11 | | "mlx_placeholder" 12 | | "torch_safetensors"; 13 | export const modelCompatibilityTypeSchema = z.enum([ 14 | "gguf", 15 | "safetensors", 16 | "onnx", 17 | "ggml", 18 | "mlx_placeholder", 19 | "torch_safetensors", 20 | ]); 21 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/ModelDomainType.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | /** 4 | * @public 5 | */ 6 | export type ModelDomainType = "llm" | "embedding" | "imageGen" | "transcription" | "tts"; 7 | export const modelDomainTypeSchema = z.enum([ 8 | "llm", 9 | "embedding", 10 | "imageGen", 11 | "transcription", 12 | "tts", 13 | ]); 14 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/ModelDownloadSource.ts: -------------------------------------------------------------------------------- 1 | import { z, type ZodSchema } from "zod"; 2 | import { fileNameSchema } from "./path.js"; 3 | 4 | export type HuggingFaceModelDownloadSource = { 5 | type: "huggingface"; 6 | user: string; 7 | repo: string; 8 | }; 9 | export const huggingFaceModelDownloadSourceSchema = z.object({ 10 | type: z.literal("huggingface"), 11 | user: fileNameSchema, 12 | repo: fileNameSchema, 13 | }); 14 | 15 | export type ModelDownloadSource = HuggingFaceModelDownloadSource; 16 | export const modelDownloadSourceSchema: ZodSchema = z.discriminatedUnion( 17 | "type", 18 | [huggingFaceModelDownloadSourceSchema], 19 | ); 20 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/ModelInfo.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { 3 | type EmbeddingModelInfo, 4 | embeddingModelInfoSchema, 5 | type EmbeddingModelInstanceInfo, 6 | embeddingModelInstanceInfoSchema, 7 | } from "./embedding/EmbeddingModelInfo.js"; 8 | import { 9 | type LLMInfo, 10 | llmInfoSchema, 11 | type LLMInstanceInfo, 12 | llmInstanceInfoSchema, 13 | } from "./llm/LLMModelInfo.js"; 14 | 15 | /** 16 | * Information about a model. 17 | * 18 | * @public 19 | */ 20 | export type ModelInfo = LLMInfo | EmbeddingModelInfo; 21 | export const modelInfoSchema = z.discriminatedUnion("type", [ 22 | llmInfoSchema as any, 23 | embeddingModelInfoSchema as any, 24 | ]) as z.ZodSchema; 25 | 26 | /** 27 | * Information about a model that is loaded. 28 | * 29 | * @public 30 | */ 31 | export type ModelInstanceInfo = LLMInstanceInfo | EmbeddingModelInstanceInfo; 32 | export const modelInstanceInfoSchema = z.discriminatedUnion("type", [ 33 | llmInstanceInfoSchema as any, 34 | embeddingModelInstanceInfoSchema as any, 35 | ]) as z.ZodSchema; 36 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/ModelInfoBase.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { 3 | modelCompatibilityTypeSchema, 4 | type ModelCompatibilityType, 5 | } from "./ModelCompatibilityType.js"; 6 | 7 | /** 8 | * Represents info of a model that is downloaded and sits on the disk. This is the base type shared 9 | * by all models of different domains. 10 | * 11 | * @public 12 | */ 13 | export interface ModelInfoBase { 14 | /** 15 | * The key of the model. Use to load the model. 16 | */ 17 | modelKey: string; 18 | /** 19 | * The format of the model. 20 | */ 21 | format: ModelCompatibilityType; 22 | /** 23 | * Machine generated name of the model. 24 | */ 25 | displayName: string; 26 | /** 27 | * The relative path of the model. 28 | */ 29 | path: string; 30 | /** 31 | * The size of the model in bytes. 32 | */ 33 | sizeBytes: number; 34 | /** 35 | * A string that represents the number of params in the model. May not always be available. 36 | */ 37 | paramsString?: string; 38 | /** 39 | * The architecture of the model. 40 | */ 41 | architecture?: string; 42 | } 43 | export const modelInfoBaseSchema = z.object({ 44 | modelKey: z.string(), 45 | format: modelCompatibilityTypeSchema, 46 | displayName: z.string(), 47 | path: z.string(), 48 | sizeBytes: z.number().int(), 49 | paramsString: z.string().optional(), 50 | architecture: z.string().optional(), 51 | }); 52 | 53 | /** 54 | * Represents info of a model that is already loaded. Contains all fields from 55 | * {@link ModelInfoBase}. This is the base typed share by all model instances of different domains. 56 | * 57 | * @public 58 | */ 59 | export interface ModelInstanceInfoBase extends ModelInfoBase { 60 | /** 61 | * The identifier of the instance. 62 | */ 63 | identifier: string; 64 | /** 65 | * The internal immutable reference of the instance. 66 | */ 67 | instanceReference: string; 68 | } 69 | export const modelInstanceInfoBaseSchema = modelInfoBaseSchema.extend({ 70 | identifier: z.string(), 71 | instanceReference: z.string(), 72 | }); 73 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/ModelManifest.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { artifactManifestBaseSchema, type ArtifactManifestBase } from "./ArtifactManifestBase.js"; 3 | 4 | /** 5 | * @public 6 | */ 7 | export interface ModelManifest extends ArtifactManifestBase { 8 | type: "model"; 9 | } 10 | export const modelManifestSchema = z.object({ 11 | type: z.literal("model"), 12 | ...artifactManifestBaseSchema.shape, 13 | }); 14 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/PluginManifest.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { artifactManifestBaseSchema, type ArtifactManifestBase } from "./ArtifactManifestBase.js"; 3 | 4 | /** 5 | * @public 6 | */ 7 | export type PluginRunnerType = "ecmascript" | "node" | "mcpBridge"; 8 | export const pluginRunnerTypeSchema = z.enum(["ecmascript", "node", "mcpBridge"]); 9 | 10 | /** 11 | * @public 12 | */ 13 | export interface PluginManifest extends ArtifactManifestBase { 14 | type: "plugin"; 15 | runner: PluginRunnerType; 16 | } 17 | export const pluginManifestSchema = z.object({ 18 | type: z.literal("plugin"), 19 | runner: pluginRunnerTypeSchema, 20 | ...artifactManifestBaseSchema.shape, 21 | }); 22 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/PresetManifest.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { artifactManifestBaseSchema, type ArtifactManifestBase } from "./ArtifactManifestBase.js"; 3 | 4 | /** 5 | * @public 6 | */ 7 | export interface PresetManifest extends ArtifactManifestBase { 8 | type: "preset"; 9 | } 10 | export const presetManifestSchema = z.object({ 11 | type: z.literal("preset"), 12 | ...artifactManifestBaseSchema.shape, 13 | }); 14 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/Runtime.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export type AcceleratorType = "unknown" | "integratedGpu" | "dedicatedGpu"; 4 | export const acceleratorTypeSchema = z.enum(["unknown", "integratedGpu", "dedicatedGpu"]); 5 | 6 | export interface Accelerator { 7 | name: string; 8 | deviceId: number; 9 | totalMemoryBytes: number; 10 | type: AcceleratorType; 11 | } 12 | export const acceleratorSchema = z.object({ 13 | name: z.string(), 14 | deviceId: z.number().int(), 15 | totalMemoryBytes: z.number().int(), 16 | type: acceleratorTypeSchema, 17 | }); 18 | 19 | export interface Runtime { 20 | key: string; 21 | name: string; 22 | accelerators: Array; 23 | supports: Array; 24 | } 25 | export const runtimeSchema = z.object({ 26 | key: z.string(), 27 | name: z.string(), 28 | accelerators: z.array(acceleratorSchema), 29 | }); 30 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/SerializedKVConfigSchematics.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { type SerializedLMSExtendedError } from "./Error.js"; 3 | import { jsonSerializableSchema } from "./JSONSerializable.js"; 4 | 5 | /** 6 | * @public 7 | */ 8 | export interface SerializedKVConfigSchematicsField { 9 | shortKey: string; 10 | fullKey: string; 11 | typeKey: string; 12 | typeParams: any; 13 | defaultValue: any; 14 | } 15 | export const serializedKVConfigSchematicsFieldSchema = z.object({ 16 | shortKey: z.string(), 17 | fullKey: z.string(), 18 | typeKey: z.string(), 19 | typeParams: jsonSerializableSchema, 20 | defaultValue: jsonSerializableSchema, 21 | }) as z.ZodSchema; 22 | 23 | /** 24 | * @public 25 | */ 26 | export interface SerializedKVConfigSchematics { 27 | fields: Array; 28 | extensionPrefixes?: Array; 29 | } 30 | export const serializedKVConfigSchematicsSchema = z.object({ 31 | fields: z.array(serializedKVConfigSchematicsFieldSchema), 32 | extensionPrefixes: z.array(z.string()).optional(), 33 | }) as z.ZodSchema; 34 | 35 | export interface KVConfigSchematicsDeserializationError { 36 | fullKey: string; 37 | error: SerializedLMSExtendedError; 38 | } 39 | export const kvConfigSchematicsDeserializationErrorSchema = z.object({ 40 | fullKey: z.string(), 41 | error: jsonSerializableSchema, 42 | }) as z.ZodSchema; 43 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/Zod.ts: -------------------------------------------------------------------------------- 1 | import { z, type ZodSchema } from "zod"; 2 | 3 | /** 4 | * Check if has a parse method. If not, output error message asking for it to be a zod schema. 5 | */ 6 | export const zodSchemaSchema = z.custom(value => { 7 | if (typeof (value as any)?.parse !== "function") { 8 | return false; 9 | } 10 | return true; 11 | }, "Expected a zod schema"); 12 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/diagnostics/DiagnosticsLogEvent.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export const diagnosticsLogEventDataSchema = z.discriminatedUnion("type", [ 4 | z.object({ 5 | type: z.literal("llm.prediction.input"), 6 | modelPath: z.string(), 7 | modelIdentifier: z.string(), 8 | input: z.string(), 9 | }), 10 | ]); 11 | /** 12 | * @public 13 | */ 14 | export type DiagnosticsLogEventData = { 15 | type: "llm.prediction.input"; 16 | modelPath: string; 17 | modelIdentifier: string; 18 | input: string; 19 | }; 20 | 21 | export const diagnosticsLogEventSchema = z.object({ 22 | timestamp: z.number(), 23 | data: diagnosticsLogEventDataSchema, 24 | }); 25 | /** 26 | * @public 27 | */ 28 | export type DiagnosticsLogEvent = { 29 | timestamp: number; 30 | data: DiagnosticsLogEventData; 31 | }; 32 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/embedding/EmbeddingLoadModelConfig.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { gpuSettingSchema, type GPUSetting } from "../llm/LLMLoadModelConfig.js"; 3 | 4 | /** 5 | * @public 6 | */ 7 | export interface EmbeddingLoadModelConfig { 8 | // TODO: Fix type 9 | gpu?: GPUSetting; 10 | contextLength?: number; 11 | ropeFrequencyBase?: number; 12 | ropeFrequencyScale?: number; 13 | keepModelInMemory?: boolean; 14 | tryMmap?: boolean; 15 | } 16 | export const embeddingLoadModelConfigSchema = z.object({ 17 | gpu: gpuSettingSchema.optional(), 18 | contextLength: z.number().int().min(1).optional(), 19 | ropeFrequencyBase: z.number().optional(), 20 | ropeFrequencyScale: z.number().optional(), 21 | keepModelInMemory: z.boolean().optional(), 22 | tryMmap: z.boolean().optional(), 23 | }); 24 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/files/DocumentParsingOpts.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export type DocumentParsingLibraryIdentifier = { 4 | /** 5 | * The identifier of the document parsing library. 6 | */ 7 | library: string; 8 | /** 9 | * The version of the document parsing library. 10 | */ 11 | version: string; 12 | }; 13 | 14 | export const documentParsingLibraryIdentifierSchema = z.object({ 15 | library: z.string(), 16 | version: z.string(), 17 | }); 18 | 19 | /** 20 | * @deprecated 21 | */ 22 | export type DocumentParsingOpts = { 23 | /** 24 | * The parser backend to use for parsing the document. If not specified, the best available parser will be used. 25 | */ 26 | parserId?: DocumentParsingLibraryIdentifier; 27 | }; 28 | export const documentParsingOptsSchema = z.object({ 29 | parserId: documentParsingLibraryIdentifierSchema.optional(), 30 | }); 31 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/files/FileIdentifier.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export type FileNamespace = "local" | "base64"; 4 | export const fileNamespaceSchema = z.enum(["local", "base64"]); 5 | 6 | export type ParsedFileIdentifier = 7 | | { 8 | type: "local"; 9 | fileName: string; 10 | } 11 | | { 12 | type: "base64"; 13 | base64Data: string; 14 | }; 15 | export const parsedFileIdentifierSchema = z.discriminatedUnion("type", [ 16 | z.object({ 17 | type: z.literal("local"), 18 | fileName: z.string(), 19 | }), 20 | z.object({ 21 | type: z.literal("base64"), 22 | base64Data: z.string(), 23 | }), 24 | ]); 25 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/files/FileType.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | /** 4 | * @public 5 | * 6 | * TODO: Documentation 7 | */ 8 | export type FileType = 9 | | "image" 10 | | "text/plain" 11 | | "application/pdf" 12 | | "application/word" 13 | | "text/other" 14 | | "unknown"; 15 | export const fileTypeSchema = z.enum([ 16 | "image", 17 | "text/plain", 18 | "application/pdf", 19 | "application/word", 20 | "text/other", 21 | "unknown", 22 | ]); 23 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/kebab.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export const kebabCaseRegex = /^[a-z0-9]+(?:-[a-z0-9]+)*$/; 4 | export const kebabCaseSchema = z.string().regex(kebabCaseRegex); 5 | 6 | export const kebabCaseWithDotsRegex = /^[a-z0-9]+(?:[-.][a-z0-9]+)*$/; 7 | export const kebabCaseWithDotsSchema = z.string().regex(kebabCaseWithDotsRegex); 8 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/llm/ContentBlockStyle.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { colorPaletteSchema, type ColorPalette } from "../ColorPalette.js"; 3 | 4 | /** 5 | * The style of a content block. 6 | * 7 | * @public 8 | */ 9 | export type ContentBlockStyle = 10 | | { 11 | type: "default"; 12 | } 13 | | { 14 | type: "customLabel"; 15 | label: string; 16 | color?: ColorPalette; 17 | } 18 | | { 19 | type: "thinking"; 20 | ended?: boolean; 21 | title?: string; 22 | }; 23 | export const contentBlockStyleSchema = z.discriminatedUnion("type", [ 24 | z.object({ 25 | type: z.literal("default"), 26 | }), 27 | z.object({ 28 | type: z.literal("customLabel"), 29 | label: z.string(), 30 | color: z.optional(colorPaletteSchema), 31 | }), 32 | z.object({ 33 | type: z.literal("thinking"), 34 | ended: z.boolean().optional(), 35 | title: z.string().optional(), 36 | }), 37 | ]) as z.Schema; 38 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/llm/LLMApplyPromptTemplateOpts.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | /** 4 | * Options for applying a prompt template. 5 | * @public 6 | */ 7 | export interface LLMApplyPromptTemplateOpts { 8 | /** 9 | * Whether to omit the BOS token when formatting. 10 | * 11 | * Default: false 12 | */ 13 | omitBosToken?: boolean; 14 | /** 15 | * Whether to omit the EOS token when formatting. 16 | * 17 | * Default: false 18 | */ 19 | omitEosToken?: boolean; 20 | } 21 | export const llmApplyPromptTemplateOptsSchema = z.object({ 22 | omitBosToken: z.boolean().optional(), 23 | omitEosToken: z.boolean().optional(), 24 | }); 25 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/llm/LLMContextReference.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | /** 4 | * Represents a reference to a LLM context that can be loaded into a context. 5 | */ 6 | export type LLMContextReference = 7 | | { 8 | type: "jsonFile"; 9 | absPath: string; 10 | } 11 | | { 12 | type: "yamlFile"; 13 | absPath: string; 14 | }; 15 | export const llmContextReferenceSchema = z.discriminatedUnion("type", [ 16 | z.object({ 17 | type: z.literal("jsonFile"), 18 | absPath: z.string(), 19 | }), 20 | z.object({ 21 | type: z.literal("yamlFile"), 22 | absPath: z.string(), 23 | }), 24 | ]); 25 | 26 | export type LLMContextReferenceJsonFile = Array<{ 27 | role: "user" | "assistant" | "system"; 28 | content: string; 29 | }>; 30 | export const llmContextReferenceJsonFileSchema = z.array( 31 | z.object({ 32 | role: z.enum(["user", "assistant", "system"]), 33 | content: z.string(), 34 | }), 35 | ); 36 | 37 | export type LLMContextReferenceYamlFile = Array< 38 | | { 39 | system: string; 40 | } 41 | | { 42 | user: string; 43 | } 44 | | { 45 | assistant: string; 46 | } 47 | >; 48 | export const llmContextReferenceYamlFileSchema = z.array( 49 | z.union([ 50 | z.object({ 51 | system: z.string(), 52 | }), 53 | z.object({ 54 | user: z.string(), 55 | }), 56 | z.object({ 57 | assistant: z.string(), 58 | }), 59 | ]), 60 | ); 61 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/llm/LLMErrorDisplayData.ts: -------------------------------------------------------------------------------- 1 | export type LLMErrorDisplayData = never; 2 | export const llmErrorDisplayDataSchema = [] as const; 3 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/llm/LLMModelInfo.ts: -------------------------------------------------------------------------------- 1 | import { z, type ZodSchema } from "zod"; 2 | import { 3 | modelInfoBaseSchema, 4 | modelInstanceInfoBaseSchema, 5 | type ModelInfoBase, 6 | type ModelInstanceInfoBase, 7 | } from "../ModelInfoBase.js"; 8 | 9 | /** 10 | * LLM specific information. 11 | * 12 | * @public 13 | */ 14 | export interface LLMAdditionalInfo { 15 | /** 16 | * Whether this model is vision-enabled (i.e. supports image input). 17 | */ 18 | vision: boolean; 19 | /** 20 | * Whether this model is trained natively for tool use. 21 | */ 22 | trainedForToolUse: boolean; 23 | /** 24 | * Maximum context length of the model. 25 | */ 26 | maxContextLength: number; 27 | } 28 | export const llmAdditionalInfoSchema = z.object({ 29 | vision: z.boolean(), 30 | trainedForToolUse: z.boolean(), 31 | maxContextLength: z.number().int(), 32 | }); 33 | 34 | /** 35 | * Additional information of an LLM instance. 36 | * 37 | * @public 38 | */ 39 | export interface LLMInstanceAdditionalInfo { 40 | contextLength: number; 41 | } 42 | export const llmInstanceAdditionalInfoSchema = z.object({ 43 | contextLength: z.number().int(), 44 | }); 45 | 46 | /** 47 | * Info of an LLM. It is a combination of {@link ModelInfoBase} and {@link LLMAdditionalInfo}. 48 | * 49 | * @public 50 | */ 51 | export type LLMInfo = { type: "llm" } & ModelInfoBase & LLMAdditionalInfo; 52 | export const llmInfoSchema = z 53 | .object({ 54 | type: z.literal("llm"), 55 | }) 56 | .extend(modelInfoBaseSchema.shape) 57 | .extend(llmAdditionalInfoSchema.shape) as ZodSchema; 58 | 59 | /** 60 | * Info of a loaded LLM instance. It is a combination of {@link ModelInstanceInfoBase}, 61 | * {@link LLMAdditionalInfo} and {@link LLMInstanceAdditionalInfo}. 62 | * 63 | * @public 64 | */ 65 | export type LLMInstanceInfo = { type: "llm" } & ModelInstanceInfoBase & 66 | LLMAdditionalInfo & 67 | LLMInstanceAdditionalInfo; 68 | export const llmInstanceInfoSchema = z 69 | .object({ 70 | type: z.literal("llm"), 71 | }) 72 | .extend(modelInstanceInfoBaseSchema.shape) 73 | .extend(llmAdditionalInfoSchema.shape) 74 | .extend(llmInstanceAdditionalInfoSchema.shape) as ZodSchema; 75 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/llm/LLMPredictionFragment.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | /** 4 | * Represents the type of this fragment in terms of reasoning. 5 | * 6 | * - `none`: Content outside of a reasoning block. 7 | * - `reasoning`: Content inside a reasoning block. 8 | * - `reasoningStartTag`: Start tag of a reasoning block. 9 | * - `reasoningEndTag`: End tag of a reasoning block. 10 | * 11 | * @public 12 | */ 13 | export type LLMPredictionFragmentReasoningType = 14 | | "none" 15 | | "reasoning" 16 | | "reasoningStartTag" 17 | | "reasoningEndTag"; 18 | export const llmPredictionFragmentReasoningTypeSchema = z.enum([ 19 | "none", 20 | "reasoning", 21 | "reasoningStartTag", 22 | "reasoningEndTag", 23 | ]); 24 | 25 | /** 26 | * Represents a fragment of a prediction from an LLM. Note that a fragment may contain multiple 27 | * tokens. 28 | * 29 | * @public 30 | */ 31 | export interface LLMPredictionFragment { 32 | /** 33 | * String content of the fragment. 34 | */ 35 | content: string; 36 | /** 37 | * Number of tokens contains in this fragment. Note this value is not always accurate as tokens 38 | * may be split across fragments. However, over a period of time, the sum of token counts of 39 | * multiple fragments will be close to the actual token count. As such, this value can be 40 | * accumulated to provide a "live tokens count". 41 | */ 42 | tokensCount: number; 43 | /** 44 | * Whether this fragment contains tokens from the draft model. 45 | */ 46 | containsDrafted: boolean; 47 | /** 48 | * Type of reasoning for this fragment. See {@link LLMPredictionFragmentReasoningType} for more 49 | * info. 50 | */ 51 | reasoningType: LLMPredictionFragmentReasoningType; 52 | } 53 | export const llmPredictionFragmentSchema = z.object({ 54 | content: z.string(), 55 | tokensCount: z.number().int(), 56 | containsDrafted: z.boolean(), 57 | reasoningType: llmPredictionFragmentReasoningTypeSchema, 58 | }); 59 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/llm/LLMToolUseSetting.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { jsonSerializableSchema } from "../JSONSerializable.js"; 3 | 4 | /** 5 | * TODO: Documentation 6 | * 7 | * @public 8 | */ 9 | export type LLMToolParameters = { 10 | type: "object"; 11 | properties: Record; 12 | required?: string[]; 13 | additionalProperties?: boolean; 14 | }; 15 | 16 | export const llmToolParametersSchema = z.discriminatedUnion("type", [ 17 | z.object({ 18 | type: z.literal("object"), 19 | properties: z.record(jsonSerializableSchema), 20 | required: z.array(z.string()).optional(), 21 | additionalProperties: z.boolean().optional(), 22 | }), 23 | // add more parameter types here 24 | // ... 25 | ]); 26 | 27 | /** 28 | * TODO: Documentation 29 | * 30 | * @public 31 | */ 32 | export type LLMTool = { 33 | type: "function"; 34 | function: { 35 | name: string; 36 | description?: string; 37 | parameters?: LLMToolParameters; 38 | }; 39 | // add more tool types here 40 | // ... 41 | }; 42 | 43 | export const llmToolSchema = z.discriminatedUnion("type", [ 44 | z.object({ 45 | type: z.literal("function"), 46 | function: z.object({ 47 | name: z.string(), 48 | description: z.string().optional(), 49 | parameters: llmToolParametersSchema.optional(), 50 | }), 51 | }), 52 | // add more tool types here 53 | // ... 54 | ]); 55 | 56 | /** 57 | * For convenience 58 | */ 59 | export const llmToolArraySchema = z.array(llmToolSchema); 60 | 61 | /** 62 | * TODO: Documentation 63 | * 64 | * @public 65 | */ 66 | export type LLMToolUseSetting = 67 | | { 68 | type: "none"; 69 | } 70 | | { 71 | type: "toolArray"; 72 | tools?: LLMTool[]; 73 | force?: boolean; 74 | }; 75 | 76 | export const llmToolUseSettingSchema = z.discriminatedUnion("type", [ 77 | z.object({ 78 | type: z.literal("none"), 79 | }), 80 | z.object({ 81 | type: z.literal("toolArray"), 82 | tools: z.array(llmToolSchema).optional(), 83 | force: z.boolean().optional(), 84 | }), 85 | ]); 86 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/llm/processing/PreprocessorUpdate.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { 3 | processingUpdateCitationBlockCreateSchema, 4 | processingUpdateDebugInfoBlockCreateSchema, 5 | processingUpdateStatusCreateSchema, 6 | processingUpdateStatusRemoveSchema, 7 | processingUpdateStatusUpdateSchema, 8 | type ProcessingUpdateCitationBlockCreate, 9 | type ProcessingUpdateDebugInfoBlockCreate, 10 | type ProcessingUpdateStatusCreate, 11 | type ProcessingUpdateStatusRemove, 12 | type ProcessingUpdateStatusUpdate, 13 | } from "./ProcessingUpdate.js"; 14 | 15 | export type PreprocessorUpdate = 16 | | ProcessingUpdateStatusCreate 17 | | ProcessingUpdateStatusUpdate 18 | | ProcessingUpdateStatusRemove 19 | | ProcessingUpdateCitationBlockCreate 20 | | ProcessingUpdateDebugInfoBlockCreate; 21 | 22 | export const preprocessorUpdateSchema = z.discriminatedUnion("type", [ 23 | processingUpdateStatusCreateSchema, 24 | processingUpdateStatusUpdateSchema, 25 | processingUpdateStatusRemoveSchema, 26 | processingUpdateCitationBlockCreateSchema, 27 | processingUpdateDebugInfoBlockCreateSchema, 28 | ]) as z.Schema; 29 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/llm/processing/Processor.ts: -------------------------------------------------------------------------------- 1 | import { z, type ZodSchema } from "zod"; 2 | import { type ModelDomainType } from "../../ModelDomainType.js"; 3 | 4 | export interface GetModelOpts { 5 | /** 6 | * The domain type of the model. By default, the domain type is "LLM". 7 | */ 8 | domain?: ModelDomainType; 9 | /** 10 | * Model tag usually denotes the purpose of the tag. For example, "judge" can be used to tag the 11 | * model that is for judging the result. By default, the model tag is "default". 12 | */ 13 | modelTag?: string; 14 | } 15 | export const getModelOptsSchema = z.object({ 16 | modelTag: z.string().optional(), 17 | ignoreUserConfig: z.boolean().optional(), 18 | }) as ZodSchema; 19 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/path.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | /** 4 | * Matches valid file names 5 | */ 6 | export const fileNameRegex = 7 | /^[\p{L}\p{N}!@#$%^&()\-_+=,.;'[\]{}~`][\p{L}\p{N}!@#$%^&()\-_+=,.;'[\]{}~` ]*(? { 4 | it("should allow strings between 1 and 1024 characters", () => { 5 | expect(reasonableKeyStringSchema.safeParse("a").success).toBe(true); 6 | expect(reasonableKeyStringSchema.safeParse("a".repeat(1024)).success).toBe(true); 7 | }); 8 | 9 | it("should not allow empty strings", () => { 10 | expect(reasonableKeyStringSchema.safeParse("").success).toBe(false); 11 | }); 12 | 13 | it("should not allow strings longer than 1024 characters", () => { 14 | expect(reasonableKeyStringSchema.safeParse("a".repeat(1025)).success).toBe(false); 15 | }); 16 | 17 | it('should not allow string "__proto__"', () => { 18 | expect(reasonableKeyStringSchema.safeParse("__proto__").success).toBe(false); 19 | }); 20 | 21 | it("should not allow strings with control characters", () => { 22 | expect(reasonableKeyStringSchema.safeParse("\u0000").success).toBe(false); 23 | expect(reasonableKeyStringSchema.safeParse("\n").success).toBe(false); 24 | expect(reasonableKeyStringSchema.safeParse("\t").success).toBe(false); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/reasonable.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | /** 4 | * A string that is reasonable to use as a key. For example, as preset name, model path, or model 5 | * identifier. 6 | */ 7 | export const reasonableKeyStringSchema = z 8 | .string() 9 | .min(1) 10 | .max(1024) 11 | .refine(value => value !== "__proto__", { 12 | message: 'For security reasons, "__proto__" is not allowed', 13 | }) 14 | .refine(value => /\p{C}/u.test(value) === false, { 15 | message: "Control characters are not allowed", 16 | }); 17 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/repository/ArtifactUpload.ts: -------------------------------------------------------------------------------- 1 | import { z, type ZodSchema } from "zod"; 2 | 3 | export interface LocalArtifactFileEntry { 4 | relativePath: string; 5 | sizeBytes: number; 6 | } 7 | export const localArtifactFileEntrySchema = z.object({ 8 | relativePath: z.string(), 9 | sizeBytes: z.number().int(), 10 | }) as ZodSchema; 11 | 12 | export interface LocalArtifactFileList { 13 | files: Array; 14 | usedIgnoreFile: string | null; 15 | } 16 | export const localArtifactFileListSchema = z.object({ 17 | files: z.array(localArtifactFileEntrySchema), 18 | usedIgnoreFile: z.string().nullable(), 19 | }) as ZodSchema; 20 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/repository/DownloadProgressUpdate.ts: -------------------------------------------------------------------------------- 1 | import { z, type ZodSchema } from "zod"; 2 | 3 | /** 4 | * @public 5 | */ 6 | export interface DownloadProgressUpdate { 7 | downloadedBytes: number; 8 | totalBytes: number; 9 | speedBytesPerSecond: number; 10 | } 11 | export const downloadProgressUpdateSchema = z.object({ 12 | downloadedBytes: z.number().int(), 13 | totalBytes: z.number().int(), 14 | speedBytesPerSecond: z.number(), 15 | }) as ZodSchema; 16 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/retrieval/InternalRetrievalResult.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export interface InternalRetrievalResultEntry { 4 | content: string; 5 | score: number; 6 | sourceIndex: number; 7 | pageNumber?: number | [start: number, end: number]; 8 | lineNumber?: number | [start: number, end: number]; 9 | } 10 | export const internalRetrievalResultEntrySchema = z.object({ 11 | content: z.string(), 12 | score: z.number(), 13 | sourceIndex: z.number().int(), 14 | pageNumber: z.union([z.number().int(), z.tuple([z.number().int(), z.number().int()])]).optional(), 15 | lineNumber: z.union([z.number().int(), z.tuple([z.number().int(), z.number().int()])]).optional(), 16 | }); 17 | 18 | /** 19 | * Retrieval result used internally in transport. Most notably, only the index of the file is being 20 | * passed back. 21 | */ 22 | export interface InternalRetrievalResult { 23 | entries: Array; 24 | } 25 | export const internalRetrievalResultSchema = z.object({ 26 | entries: z.array(internalRetrievalResultEntrySchema), 27 | }); 28 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/retrieval/RetrievalChunk.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { citationSourceSchema, type CitationSource } from "../CitationSource.js"; 3 | 4 | /** 5 | * @public 6 | */ 7 | export interface RetrievalChunk { 8 | content: string; 9 | score: number; 10 | citation: CitationSource; 11 | } 12 | export const retrievalChunkSchema = z.object({ 13 | content: z.string(), 14 | score: z.number(), 15 | citation: citationSourceSchema, 16 | }); 17 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/retrieval/RetrievalChunkingMethod.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | /** 4 | * @public 5 | */ 6 | export type RetrievalChunkingMethod = { 7 | type: "recursive-v1"; 8 | chunkSize: number; 9 | chunkOverlap: number; 10 | }; 11 | export const retrievalChunkingMethodSchema = z.discriminatedUnion("type", [ 12 | z.object({ 13 | type: z.literal("recursive-v1"), 14 | chunkSize: z.number().int(), 15 | chunkOverlap: z.number().int(), 16 | }), 17 | ]); 18 | 19 | export type RetrievalChunkingMethodIdentifier = `recursive-v1(${number},${number})`; 20 | 21 | export function serializeRetrievalChunkingMethod( 22 | chunkingMethod: RetrievalChunkingMethod, 23 | ): RetrievalChunkingMethodIdentifier { 24 | switch (chunkingMethod.type) { 25 | case "recursive-v1": 26 | return `recursive-v1(${chunkingMethod.chunkSize},${chunkingMethod.chunkOverlap})`; 27 | default: { 28 | const exhaustiveCheck: never = chunkingMethod.type; 29 | throw new Error(`Unknown chunking method type: ${exhaustiveCheck}.`); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/lms-shared-types/src/retrieval/RetrievalFileProcessingStep.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | /** 4 | * @public 5 | */ 6 | export type RetrievalFileProcessingStep = "loading" | "chunking" | "embedding"; 7 | export const retrievalFileProcessingStepSchema = z.enum(["loading", "chunking", "embedding"]); 8 | -------------------------------------------------------------------------------- /packages/lms-shared-types/tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.cjs.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/cjs" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-shared-types/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.esm.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/esm" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lms-shared-types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": [ 3 | { "path": "./tsconfig.cjs.json" }, 4 | { "path": "./tsconfig.esm.json" }, 5 | { "path": "./tsconfig.types.json" } 6 | ], 7 | "include": [] 8 | } 9 | -------------------------------------------------------------------------------- /packages/lms-shared-types/tsconfig.types.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.types.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist/types" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/template/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/template", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "scripts": { 8 | "build": "tsc" 9 | }, 10 | "author": "", 11 | "license": "Apache-2.0" 12 | } 13 | -------------------------------------------------------------------------------- /packages/template/src/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmstudio-ai/lmstudio-js/b5800cda9e79238fb5b43f762ea619fe2bcaa7ce/packages/template/src/index.ts -------------------------------------------------------------------------------- /packages/template/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /patches/boxen+5.1.2.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/boxen/index.js b/node_modules/boxen/index.js 2 | index d6bc693..da5e32f 100644 3 | --- a/node_modules/boxen/index.js 4 | +++ b/node_modules/boxen/index.js 5 | @@ -218,7 +218,7 @@ module.exports = (text, options) => { 6 | 7 | const colorizeContent = content => options.backgroundColor ? getBGColorFn(options.backgroundColor)(content) : content; 8 | 9 | - const columns = terminalColumns(); 10 | + const columns = terminalColumns() - 1; 11 | 12 | let contentWidth = widestLine(wrapAnsi(text, columns - BORDERS_WIDTH, {hard: true, trim: false})) + padding.left + padding.right; 13 | 14 | @@ -265,7 +265,7 @@ module.exports = (text, options) => { 15 | const bottom = colorizeBorder(marginLeft + chars.bottomLeft + horizontal + chars.bottomRight + NL.repeat(margin.bottom)); 16 | const side = colorizeBorder(chars.vertical); 17 | 18 | - const LINE_SEPARATOR = (contentWidth + BORDERS_WIDTH + margin.left >= columns) ? '' : NL; 19 | + const LINE_SEPARATOR = NL; 20 | 21 | const lines = text.split(NL); 22 | 23 | -------------------------------------------------------------------------------- /patches/promise-inflight+1.0.1.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/promise-inflight/inflight.js b/node_modules/promise-inflight/inflight.js 2 | index ce054d3..3e2dcff 100644 3 | --- a/node_modules/promise-inflight/inflight.js 4 | +++ b/node_modules/promise-inflight/inflight.js 5 | @@ -1,12 +1,7 @@ 6 | 'use strict' 7 | module.exports = inflight 8 | 9 | -let Bluebird 10 | -try { 11 | - Bluebird = require('bluebird') 12 | -} catch (_) { 13 | - Bluebird = Promise 14 | -} 15 | +let Bluebird = Promise; 16 | 17 | const active = {} 18 | inflight.active = active 19 | -------------------------------------------------------------------------------- /publish/cli/.gitignore: -------------------------------------------------------------------------------- 1 | ts-out 2 | temp 3 | 4 | # lms-key file is generated by LM Studio build system. It will be placed in this directory to allow 5 | # lms to use the same passKey as LM Studio. This is not secure, but prevents trivial attempts at 6 | # disguising as lms. 7 | lms-key 8 | -------------------------------------------------------------------------------- /publish/cli/entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.cs.allow-jit 6 | 7 | com.apple.security.cs.allow-unsigned-executable-memory 8 | 9 | 10 | -------------------------------------------------------------------------------- /publish/cli/injectVariables.js: -------------------------------------------------------------------------------- 1 | // Inject the current version by replacing the magic string 2 | // This is much faster than rollup-plugin-replace 3 | 4 | const { readFileSync, writeFileSync } = require("fs"); 5 | const { join } = require("path"); 6 | 7 | const content = readFileSync(join(__dirname, "dist", "index.js"), "utf-8"); 8 | const packageJson = readFileSync(join(__dirname, "package.json"), "utf-8"); 9 | let lmsKey = null; 10 | try { 11 | lmsKey = readFileSync(join(__dirname, "lms-key"), "utf-8").trim(); 12 | } catch (e) { 13 | console.error("Failed to read lms-key. Build in development mode."); 14 | } 15 | 16 | let replaced = content.replaceAll("", JSON.parse(packageJson).version); 17 | if (lmsKey !== null) { 18 | replaced = replaced.replaceAll("", lmsKey); 19 | } 20 | 21 | writeFileSync(join(__dirname, "dist", "index.js"), replaced, "utf-8"); 22 | -------------------------------------------------------------------------------- /publish/cli/make-bin-linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NODE_VERSION="v20.12.2" 4 | NODE_DOWNLOAD_URL="https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-linux-x64.tar.xz" 5 | TEMP_DIR="./temp" 6 | DIST_DIR="./dist" 7 | NODE_TAR="${TEMP_DIR}/node.tar.xz" 8 | NODE_DIR="${TEMP_DIR}/node" 9 | EXE_NAME="lms" 10 | 11 | load_env_from_ancestors() { 12 | local current_dir=$(pwd) 13 | while [ "$current_dir" != "/" ]; do 14 | if [ -f "$current_dir/.env" ]; then 15 | echo "Loading .env from $current_dir" 16 | set -a 17 | . "$current_dir/.env" 18 | set +a 19 | fi 20 | current_dir=$(dirname "$current_dir") 21 | done 22 | } 23 | 24 | load_env_from_ancestors 25 | 26 | mkdir -p $TEMP_DIR 27 | mkdir -p $DIST_DIR 28 | 29 | if [ ! -f "${NODE_DIR}/bin/node" ]; then 30 | echo "Node.js not found. Downloading..." 31 | curl $NODE_DOWNLOAD_URL --output $NODE_TAR 32 | tar -xf $NODE_TAR -C $TEMP_DIR 33 | mv "${TEMP_DIR}/node-${NODE_VERSION}-linux-x64" $NODE_DIR 34 | rm $NODE_TAR 35 | else 36 | echo "Node.js already downloaded." 37 | fi 38 | 39 | "${NODE_DIR}/bin/node" --experimental-sea-config ./sea-config.json 40 | 41 | cp "${NODE_DIR}/bin/node" "${DIST_DIR}/${EXE_NAME}" 42 | 43 | postject "${DIST_DIR}/${EXE_NAME}" NODE_SEA_BLOB ./temp/sea-prep.blob --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 44 | -------------------------------------------------------------------------------- /publish/cli/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/cli", 3 | "version": "0.0.43", 4 | "description": "LM Studio CLI", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "build-rollup": "rollup -c", 8 | "build-inject-variables": "node ./injectVariables.js", 9 | "build": "npm run build-rollup && npm run build-inject-variables", 10 | "make-bin:win32": "powershell -File make-bin-win32.ps1", 11 | "make-bin:linux": "bash make-bin-linux.sh", 12 | "make-bin:darwin": "bash make-bin-darwin.sh", 13 | "make-bin": "run-script-os", 14 | "make": "npm run build && npm run make-bin", 15 | "watch": "rollup -wc" 16 | }, 17 | "files": [ 18 | "dist/index.js" 19 | ], 20 | "author": "", 21 | "license": "Apache-2.0", 22 | "dependencies": { 23 | "@lmstudio/lms-cli": "^0.3.39" 24 | }, 25 | "devDependencies": { 26 | "postject": "^1.0.0-alpha.6", 27 | "run-script-os": "^1.1.6" 28 | }, 29 | "gitHead": "abe566030fdea1ad86c21c3d5f32ded4782e8c0b" 30 | } 31 | -------------------------------------------------------------------------------- /publish/cli/rollup.config.js: -------------------------------------------------------------------------------- 1 | const { nodeResolve } = require("@rollup/plugin-node-resolve"); 2 | const { join, resolve } = require("path"); 3 | const commonjs = require("@rollup/plugin-commonjs"); 4 | const json = require("@rollup/plugin-json"); 5 | const banner = require("rollup-plugin-banner2"); 6 | 7 | module.exports = { 8 | input: resolve(require.resolve("@lmstudio/lms-cli")), 9 | output: [ 10 | { 11 | file: join(__dirname, "dist", "index.js"), 12 | format: "cjs", 13 | }, 14 | ], 15 | context: "globalThis", 16 | plugins: [ 17 | nodeResolve({ 18 | extensions: [".ts", ".tsx", ".js", ".jsx"], 19 | }), 20 | commonjs(), 21 | json(), 22 | banner(() => "#!/usr/bin/env node\n"), 23 | ], 24 | }; 25 | -------------------------------------------------------------------------------- /publish/cli/sea-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./dist/index.js", 3 | "output": "./temp/sea-prep.blob", 4 | "disableExperimentalSEAWarning": true, 5 | "useCodeCache": true 6 | } 7 | -------------------------------------------------------------------------------- /publish/lms/.gitignore: -------------------------------------------------------------------------------- 1 | ts-out 2 | -------------------------------------------------------------------------------- /publish/lms/README.md: -------------------------------------------------------------------------------- 1 | # LM Studio CLI - lms 2 | 3 | See https://github.com/lmstudio-ai/lms for more information 4 | -------------------------------------------------------------------------------- /publish/lms/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require("@lmstudio/cli"); 3 | -------------------------------------------------------------------------------- /publish/lms/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lms", 3 | "version": "0.0.17", 4 | "description": "", 5 | "main": "index.js", 6 | "files": [ 7 | "index.js" 8 | ], 9 | "bin": "index.js", 10 | "author": "", 11 | "license": "Apache-2.0", 12 | "devDependencies": { 13 | "@lmstudio/cli": "^0.0.43" 14 | }, 15 | "gitHead": "abe566030fdea1ad86c21c3d5f32ded4782e8c0b" 16 | } 17 | -------------------------------------------------------------------------------- /publish/lmstudio/.gitignore: -------------------------------------------------------------------------------- 1 | ts-out 2 | -------------------------------------------------------------------------------- /publish/lmstudio/README.md: -------------------------------------------------------------------------------- 1 | # LM Studio Setup Tool 2 | 3 | This tool is currently used to setup LM Studio CLI (lms). 4 | 5 | To run the tool, run the following command: 6 | 7 | ```bash 8 | npx lmstudio install-cli 9 | ``` 10 | -------------------------------------------------------------------------------- /publish/lmstudio/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lmstudio", 3 | "version": "0.0.28", 4 | "description": "LM Studio Setup Tool", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "build-rollup": "rollup -c", 8 | "build": "npm run build-rollup", 9 | "watch": "rollup -wc" 10 | }, 11 | "files": [ 12 | "dist/index.js" 13 | ], 14 | "bin": "dist/index.js", 15 | "author": "", 16 | "license": "Apache-2.0", 17 | "devDependencies": { 18 | "@lmstudio/lms-lmstudio": "^0.0.28", 19 | "postject": "^1.0.0-alpha.6", 20 | "run-script-os": "^1.1.6" 21 | }, 22 | "gitHead": "9a71db006654e012e2749a17ac10859c5d5a36b2" 23 | } 24 | -------------------------------------------------------------------------------- /publish/lmstudio/rollup.config.js: -------------------------------------------------------------------------------- 1 | const { nodeResolve } = require("@rollup/plugin-node-resolve"); 2 | const { join, resolve } = require("path"); 3 | const commonjs = require("@rollup/plugin-commonjs"); 4 | const json = require("@rollup/plugin-json"); 5 | const banner = require("rollup-plugin-banner2"); 6 | 7 | module.exports = { 8 | input: resolve(require.resolve("@lmstudio/lms-lmstudio")), 9 | output: [ 10 | { 11 | file: join(__dirname, "dist", "index.js"), 12 | format: "cjs", 13 | }, 14 | ], 15 | context: "globalThis", 16 | plugins: [ 17 | nodeResolve({ 18 | extensions: [".ts", ".tsx", ".js", ".jsx"], 19 | }), 20 | commonjs(), 21 | json(), 22 | banner(() => "#!/usr/bin/env node\n"), 23 | ], 24 | }; 25 | -------------------------------------------------------------------------------- /publish/sdk/.gitignore: -------------------------------------------------------------------------------- 1 | ts-out 2 | -------------------------------------------------------------------------------- /publish/sdk/api-extractor.json: -------------------------------------------------------------------------------- 1 | { 2 | "mainEntryPointFilePath": "./ts-out/index.d.ts", 3 | "apiReport": { 4 | "enabled": false 5 | }, 6 | "docModel": { 7 | "enabled": false 8 | }, 9 | "dtsRollup": { 10 | "enabled": true, 11 | "untrimmedFilePath": "./dist/index.d.ts" 12 | }, 13 | "bundledPackages": [ 14 | "@lmstudio/lms-client", 15 | "@lmstudio/lms-common", 16 | "@lmstudio/lms-communication", 17 | "@lmstudio/lms-communication-client", 18 | "@lmstudio/lms-external-backend-interfaces", 19 | "@lmstudio/lms-llm-sdk", 20 | "@lmstudio/lms-platform-sdk", 21 | "@lmstudio/lms-sdk-common", 22 | "@lmstudio/lms-shared-types", 23 | "@lmstudio/lms-kv-config" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /publish/sdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/sdk", 3 | "version": "1.2.1", 4 | "description": "LM Studio SDK", 5 | "main": "dist/index.js", 6 | "module": "dist/index.mjs", 7 | "types": "dist/index.d.ts", 8 | "scripts": { 9 | "build-rollup": "rollup -c", 10 | "build-ae": "api-extractor run --local", 11 | "build": "npm run build-rollup && npm run build-ae", 12 | "watch-rollup": "rollup -wc", 13 | "watch-ae": "nodemon --exec \"npm run build-ae\" --watch dist/index.cjs" 14 | }, 15 | "files": [ 16 | "dist/index.cjs", 17 | "dist/index.d.ts", 18 | "dist/index.mjs", 19 | "README.md" 20 | ], 21 | "author": "", 22 | "license": "Apache-2.0", 23 | "dependencies": { 24 | "@lmstudio/lms-isomorphic": "^0.4.5", 25 | "chalk": "^4.1.2", 26 | "jsonschema": "^1.5.0", 27 | "zod": "^3.22.4", 28 | "zod-to-json-schema": "^3.22.5" 29 | }, 30 | "devDependencies": { 31 | "@lmstudio/lms-client": "^1.2.1", 32 | "nodemon": "^3.1.0" 33 | }, 34 | "repository": { 35 | "type": "git", 36 | "url": "git+https://github.com/lmstudio-ai/lmstudio.js.git" 37 | }, 38 | "exports": { 39 | ".": { 40 | "types": "./dist/index.d.ts", 41 | "require": "./dist/index.cjs", 42 | "import": "./dist/index.mjs", 43 | "default": "./dist/index.mjs" 44 | } 45 | }, 46 | "sideEffects": false, 47 | "gitHead": "abe566030fdea1ad86c21c3d5f32ded4782e8c0b" 48 | } 49 | -------------------------------------------------------------------------------- /publish/sdk/removeSourceMapComments.js: -------------------------------------------------------------------------------- 1 | // We don't ship sourcemaps, so we will remove those comments to prevent error messages 2 | 3 | const fs = require("fs"); 4 | const path = require("path"); 5 | 6 | const filePath = path.join(__dirname, "dist/index.js"); 7 | const content = fs.readFileSync(filePath, "utf8"); 8 | const newContent = content.replace(/\/\/# sourceMappingURL=.*\.js\.map/g, "//"); 9 | fs.writeFileSync(filePath, newContent, "utf8"); 10 | -------------------------------------------------------------------------------- /publish/sdk/rollup.config.js: -------------------------------------------------------------------------------- 1 | const { nodeResolve } = require("@rollup/plugin-node-resolve"); 2 | const path = require("path"); 3 | const commonjs = require("@rollup/plugin-commonjs"); 4 | const json = require("@rollup/plugin-json"); 5 | 6 | module.exports = { 7 | input: path.join(__dirname, "ts-out", "index.js"), 8 | output: [ 9 | { 10 | file: path.join(__dirname, "dist", "index.mjs"), 11 | format: "esm", 12 | }, 13 | { 14 | file: path.join(__dirname, "dist", "index.cjs"), 15 | format: "cjs", 16 | }, 17 | ], 18 | context: "globalThis", 19 | plugins: [ 20 | nodeResolve({ 21 | extensions: [".ts", ".tsx", ".js", ".jsx"], 22 | }), 23 | commonjs(), 24 | json(), 25 | ], 26 | external: ["process", "chalk", "zod", "zod-to-json-schema", "@lmstudio/lms-isomorphic"], 27 | }; 28 | -------------------------------------------------------------------------------- /publish/sdk/src/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | Chat, 3 | ChatMessage, 4 | createConfigSchematics, 5 | FileHandle, 6 | LMStudioClient, 7 | rawFunctionTool, 8 | tool, 9 | } from "@lmstudio/lms-client"; 10 | export { MaybeMutable, text } from "@lmstudio/lms-common"; 11 | export { kvValueTypesLibrary } from "@lmstudio/lms-kv-config"; 12 | export type * from "./exportedTypes.js"; 13 | -------------------------------------------------------------------------------- /publish/sdk/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src/index.ts"], 3 | "compilerOptions": { 4 | "strict": true, 5 | "module": "esnext", 6 | "moduleResolution": "node", 7 | "target": "ES2021", 8 | "declaration": true, 9 | "noImplicitOverride": true, 10 | "skipLibCheck": true, 11 | "outDir": "ts-out", 12 | "esModuleInterop": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /scaffolds/.gitignore: -------------------------------------------------------------------------------- 1 | scaffolds.json 2 | -------------------------------------------------------------------------------- /scaffolds/buildScaffoldsJSON.js: -------------------------------------------------------------------------------- 1 | const { readdirSync, statSync, writeFileSync } = require("fs"); 2 | 3 | const names = readdirSync(__dirname); 4 | const output = []; 5 | for (const name of names) { 6 | const stat = statSync(name); 7 | if (stat.isDirectory() && !name.startsWith(".")) { 8 | const metadata = require(`./${name}/lms-scaffold.json`); 9 | output.push(metadata); 10 | } 11 | } 12 | writeFileSync("scaffolds.json", JSON.stringify(output, null, 2)); 13 | -------------------------------------------------------------------------------- /scaffolds/node-javascript-empty/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /scaffolds/node-javascript-empty/README.md: -------------------------------------------------------------------------------- 1 | # 2 | 3 | #### Created with LM Studio scaffold: node-javascript-empty 4 | 5 | Welcome to your new project! This scaffold is a starting point for building an AI-enabled Node.js project with [LM Studio](https://lmstudio.ai/) SDK. To interact with LM Studio, you should start the LM Studio local server with the command: 6 | 7 | ```bash 8 | lms server start 9 | ``` 10 | 11 | ## Getting Started 12 | 13 | ### Development 14 | 15 | The source code resides in the `src/` directory. For development purposes, you can run the project using: 16 | 17 | ```start 18 | npm start 19 | ``` 20 | 21 | ### Community & Help 22 | 23 | - [lmstudio.js GitHub](https://github.com/lmstudio-ai/lmstudio.js) 24 | - [Documentation](https://lmstudio.ai/docs/welcome) 25 | - [Discord](https://discord.gg/6Q7Xn6MRVS) 26 | - [Twitter](https://twitter.com/LMStudioAI) 27 | -------------------------------------------------------------------------------- /scaffolds/node-javascript-empty/gitignore_template: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /scaffolds/node-javascript-empty/lms-scaffold.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./../scaffold-json-schema-v1.json", 3 | "scaffoldVersion": 1, 4 | "name": "node-javascript-empty", 5 | "displayName": "Node.js with JavaScript (Empty)", 6 | "description": "Minimalistic Node.js JavaScript empty project with lmstudio.js", 7 | "args": [ 8 | { 9 | "name": "Project Name", 10 | "default": "node-javascript-empty", 11 | "replaceFrom": ["@lmstudio/scaffold-node-javascript-empty", ""], 12 | "isProjectName": true 13 | } 14 | ], 15 | "renames": [{ "from": "gitignore_template", "to": ".gitignore" }], 16 | "motd": [ 17 | { "type": "title", "text": "✓ Project Creation Successful" }, 18 | { 19 | "type": "regular", 20 | "text": "An empty Node.js JavaScript project with lmstudio.js has been created in the folder. You can enter it with:" 21 | }, 22 | { "type": "command", "text": "cd " }, 23 | { "type": "regular", "text": "Then you can run the project with:" }, 24 | { "type": "command", "text": "npm start" } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /scaffolds/node-javascript-empty/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/scaffold-node-javascript-empty", 3 | "version": "1.2.1", 4 | "description": "", 5 | "main": "src/index.js", 6 | "type": "module", 7 | "scripts": { 8 | "start": "node src/index.js" 9 | }, 10 | "author": "Your Name", 11 | "license": "UNLICENSED", 12 | "dependencies": { 13 | "@lmstudio/sdk": "^1.2.1" 14 | }, 15 | "gitHead": "abe566030fdea1ad86c21c3d5f32ded4782e8c0b" 16 | } 17 | -------------------------------------------------------------------------------- /scaffolds/node-javascript-empty/src/index.js: -------------------------------------------------------------------------------- 1 | import { LMStudioClient } from "@lmstudio/sdk"; 2 | 3 | const client = new LMStudioClient(); 4 | 5 | console.log("👾👾 Welcome to my new project! 👾👾"); 6 | console.log("\nDownloaded models:\n"); 7 | console.log(await client.system.listDownloadedModels()); 8 | console.log("\n👉 For more, visit our documentation website at https://lmstudio.ai/docs/welcome\n"); 9 | -------------------------------------------------------------------------------- /scaffolds/node-javascript/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /scaffolds/node-javascript/README.md: -------------------------------------------------------------------------------- 1 | # 2 | 3 | #### Created with LM Studio scaffold: node-javascript 4 | 5 | Welcome to your new project! This scaffold is a starting point for building an AI-enabled Node.js project with [LM Studio](https://lmstudio.ai/) SDK. To interact with LM Studio, you should start the LM Studio local server with the command: 6 | 7 | ```bash 8 | lms server start 9 | ``` 10 | 11 | ## Getting Started 12 | 13 | ### Development 14 | 15 | The source code resides in the `src/` directory. For development purposes, you can run the project using: 16 | 17 | ```start 18 | npm start 19 | ``` 20 | 21 | ### Community & Help 22 | 23 | - [lmstudio.js GitHub](https://github.com/lmstudio-ai/lmstudio.js) 24 | - [Documentation](https://lmstudio.ai/docs/welcome) 25 | - [Discord](https://discord.gg/6Q7Xn6MRVS) 26 | - [Twitter](https://twitter.com/LMStudioAI) 27 | -------------------------------------------------------------------------------- /scaffolds/node-javascript/gitignore_template: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /scaffolds/node-javascript/lms-scaffold.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./../scaffold-json-schema-v1.json", 3 | "scaffoldVersion": 1, 4 | "name": "node-javascript", 5 | "displayName": "Node.js with JavaScript", 6 | "description": "Example Node.js JavaScript project with lmstudio.js", 7 | "args": [ 8 | { 9 | "name": "Project Name", 10 | "default": "node-javascript", 11 | "replaceFrom": ["@lmstudio/scaffold-node-javascript", ""], 12 | "isProjectName": true 13 | } 14 | ], 15 | "renames": [{ "from": "gitignore_template", "to": ".gitignore" }], 16 | "motd": [ 17 | { "type": "title", "text": "✓ Project Creation Successful" }, 18 | { 19 | "type": "regular", 20 | "text": "An example Node.js JavaScript project with lmstudio.js has been created in the folder. You can enter it with:" 21 | }, 22 | { "type": "command", "text": "cd " }, 23 | { "type": "regular", "text": "Then you can run the project with:" }, 24 | { "type": "command", "text": "npm start" } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /scaffolds/node-javascript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/scaffold-node-javascript", 3 | "version": "1.2.1", 4 | "description": "", 5 | "main": "src/index.js", 6 | "type": "module", 7 | "scripts": { 8 | "start": "node src/index.js" 9 | }, 10 | "author": "Your Name", 11 | "license": "UNLICENSED", 12 | "dependencies": { 13 | "@lmstudio/sdk": "^1.2.1" 14 | }, 15 | "gitHead": "abe566030fdea1ad86c21c3d5f32ded4782e8c0b" 16 | } 17 | -------------------------------------------------------------------------------- /scaffolds/node-javascript/src/index.js: -------------------------------------------------------------------------------- 1 | import { LMStudioClient } from "@lmstudio/sdk"; 2 | 3 | const client = new LMStudioClient(); 4 | 5 | await printDownloadedModels(); 6 | await printLoadedModels(); 7 | await predictWithAnyModel(); 8 | 9 | // ---------- Functions ---------- 10 | 11 | async function printDownloadedModels() { 12 | const downloadedModels = await client.system.listDownloadedModels(); 13 | console.log("Downloaded Models:"); 14 | if (downloadedModels.length === 0) { 15 | console.log(" No models downloaded. Get some in LM Studio."); 16 | process.exit(0); 17 | } 18 | 19 | // Limit to printing 5 models 20 | for (const model of downloadedModels.slice(0, 5)) { 21 | console.log(` - ${model.modelKey} (${model.displayName})`); 22 | } 23 | if (downloadedModels.length > 5) { 24 | console.log(` (... and ${downloadedModels.length - 5} more)`); 25 | } 26 | console.log(); // Create an empty line 27 | } 28 | 29 | async function printLoadedModels() { 30 | const loadedLLMs = await client.llm.listLoaded(); 31 | console.log("Loaded Models:"); 32 | if (loadedLLMs.length === 0) { 33 | console.log(" You don't have any models loaded. (Run `lms load` to load a model)"); 34 | process.exit(0); 35 | } 36 | for (const model of loadedLLMs) { 37 | console.log(` - ${model.identifier} (${model.displayName})`); 38 | } 39 | console.log(); // Create an empty line 40 | } 41 | 42 | async function predictWithAnyModel() { 43 | const model = await client.llm.model(); 44 | const prompt = "The meaning of life is"; 45 | const prediction = model.complete(prompt, { 46 | maxTokens: 100, 47 | temperature: 0.7, 48 | }); 49 | process.stdout.write(prompt); // Print the prompt 50 | // Stream the prediction text to console 51 | for await (const { content } of prediction) { 52 | process.stdout.write(content); 53 | } 54 | const { stats } = await prediction.result(); 55 | console.log("\n\nPrediction Stats:", stats); 56 | } 57 | -------------------------------------------------------------------------------- /scaffolds/node-typescript-empty/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /scaffolds/node-typescript-empty/README.md: -------------------------------------------------------------------------------- 1 | # 2 | 3 | #### Created with LM Studio scaffold: node-typescript 4 | 5 | Welcome to your new project! This scaffold is a starting point for building an AI-enabled Node.js project with [LM Studio](https://lmstudio.ai/) SDK. To interact with LM Studio, you should start the LM Studio local server with the command: 6 | 7 | ```bash 8 | lms server start 9 | ``` 10 | 11 | ## Getting Started 12 | 13 | ### Development 14 | 15 | The source code resides in the `src/` directory. For development purposes, you can run the project using: 16 | 17 | ```start 18 | npm start 19 | ``` 20 | 21 | ### Building for Production 22 | 23 | To prepare your project for production, compile the TypeScript code to JavaScript using: 24 | 25 | ```bash 26 | npm run build 27 | ``` 28 | 29 | This will compile the TypeScript code in the `src/` directory to JavaScript in the `dist/` directory. 30 | 31 | ### Community & Help 32 | 33 | - [lmstudio.js GitHub](https://github.com/lmstudio-ai/lmstudio.js) 34 | - [Documentation](https://lmstudio.ai/docs/welcome) 35 | - [Discord](https://discord.gg/6Q7Xn6MRVS) 36 | - [Twitter](https://twitter.com/LMStudioAI) 37 | -------------------------------------------------------------------------------- /scaffolds/node-typescript-empty/gitignore_template: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /scaffolds/node-typescript-empty/lms-scaffold.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./../scaffold-json-schema-v1.json", 3 | "scaffoldVersion": 1, 4 | "name": "node-typescript-empty", 5 | "displayName": "Node.js with TypeScript (Empty)", 6 | "description": "Minimalistic Node.js TypeScript empty project with lmstudio.js", 7 | "args": [ 8 | { 9 | "name": "Project Name", 10 | "default": "node-typescript-empty", 11 | "replaceFrom": ["@lmstudio/scaffold-node-typescript-empty", ""], 12 | "isProjectName": true 13 | } 14 | ], 15 | "renames": [{ "from": "gitignore_template", "to": ".gitignore" }], 16 | "motd": [ 17 | { "type": "title", "text": "✓ Project Creation Successful" }, 18 | { 19 | "type": "regular", 20 | "text": "An empty Node.js TypeScript project with lmstudio.js has been created in the folder. You can enter it with:" 21 | }, 22 | { "type": "command", "text": "cd " }, 23 | { "type": "regular", "text": "Then you can run the project with:" }, 24 | { "type": "command", "text": "npm start" } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /scaffolds/node-typescript-empty/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/scaffold-node-typescript-empty", 3 | "version": "1.2.1", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "type": "module", 8 | "scripts": { 9 | "start": "tsc && node --enable-source-maps dist/index.js", 10 | "build": "tsc" 11 | }, 12 | "author": "Your Name", 13 | "license": "UNLICENSED", 14 | "dependencies": { 15 | "@lmstudio/sdk": "^1.2.1" 16 | }, 17 | "gitHead": "abe566030fdea1ad86c21c3d5f32ded4782e8c0b", 18 | "devDependencies": { 19 | "@types/node": "^22.13.1", 20 | "typescript": "^5.7.2" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scaffolds/node-typescript-empty/src/index.ts: -------------------------------------------------------------------------------- 1 | import { LMStudioClient } from "@lmstudio/sdk"; 2 | 3 | const client = new LMStudioClient(); 4 | 5 | console.log("👾👾 Welcome to my new project! 👾👾"); 6 | console.log("\nDownloaded models:\n"); 7 | console.log(await client.system.listDownloadedModels()); 8 | console.log("\n👉 For more, visit our documentation website at https://lmstudio.ai/docs/welcome\n"); 9 | -------------------------------------------------------------------------------- /scaffolds/node-typescript-empty/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "module": "nodenext", 5 | "moduleResolution": "nodenext", 6 | "target": "ES2021", 7 | "declaration": true, 8 | "noImplicitOverride": true, 9 | "sourceMap": true, 10 | "declarationMap": true, 11 | "esModuleInterop": true, 12 | "skipLibCheck": true, 13 | "rootDir": "src", 14 | "outDir": "dist" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /scaffolds/node-typescript-preprocessor/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /scaffolds/node-typescript-preprocessor/README.md: -------------------------------------------------------------------------------- 1 | # 2 | 3 | #### Created with LM Studio scaffold: node-typescript-preprocessor 4 | 5 | Welcome to your new project! This scaffold is a starting point for building an prompt preprocessor with [LM Studio](https://lmstudio.ai/) SDK. To interact with LM Studio, you should start the LM Studio local server with the command: 6 | 7 | ```bash 8 | lms server start 9 | ``` 10 | 11 | ## Getting Started 12 | 13 | ### Development 14 | 15 | The source code resides in the `src/` directory. For development purposes, you can run the project using: 16 | 17 | ```start 18 | npm start 19 | ``` 20 | 21 | ### Building for Production 22 | 23 | To prepare your project for production, compile the TypeScript code to JavaScript using: 24 | 25 | ```bash 26 | npm run build 27 | ``` 28 | 29 | This will compile the TypeScript code in the `src/` directory to JavaScript in the `dist/` directory. 30 | 31 | ### Community & Help 32 | 33 | - [lmstudio.js GitHub](https://github.com/lmstudio-ai/lmstudio.js) 34 | - [Documentation](https://lmstudio.ai/docs/welcome) 35 | - [Discord](https://discord.gg/6Q7Xn6MRVS) 36 | - [Twitter](https://twitter.com/LMStudioAI) 37 | -------------------------------------------------------------------------------- /scaffolds/node-typescript-preprocessor/gitignore_template: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /scaffolds/node-typescript-preprocessor/lms-scaffold.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./../scaffold-json-schema-v1.json", 3 | "scaffoldVersion": 1, 4 | "name": "node-typescript-preprocessor", 5 | "displayName": "Prompt Preprocessor with TypeScript", 6 | "description": "Example prompt preprocessor implemented TypeScript.", 7 | "args": [ 8 | { 9 | "name": "Project Name", 10 | "default": "node-typescript-preprocessor", 11 | "replaceFrom": ["@lmstudio/scaffold-node-typescript-preprocessor", ""], 12 | "isProjectName": true 13 | } 14 | ], 15 | "renames": [{ "from": "gitignore_template", "to": ".gitignore" }], 16 | "motd": [ 17 | { "type": "title", "text": "✓ Project Creation Successful" }, 18 | { 19 | "type": "regular", 20 | "text": "An example Prompt Preprocessor TypeScript project with lmstudio.js has been created in the folder. You can enter it with:" 21 | }, 22 | { "type": "command", "text": "cd " }, 23 | { "type": "regular", "text": "Then you can run the project with:" }, 24 | { "type": "command", "text": "npm start" } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /scaffolds/node-typescript-preprocessor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/scaffold-node-typescript-preprocessor", 3 | "version": "0.2.1", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "scripts": { 8 | "start": "ts-node src/index.ts", 9 | "build": "tsc" 10 | }, 11 | "author": "Your Name", 12 | "license": "UNLICENSED", 13 | "dependencies": { 14 | "@lmstudio/sdk": "^1.2.1" 15 | }, 16 | "devDependencies": { 17 | "ts-node": "^10.9.2", 18 | "typescript": "^5.4.5" 19 | }, 20 | "gitHead": "abe566030fdea1ad86c21c3d5f32ded4782e8c0b" 21 | } 22 | -------------------------------------------------------------------------------- /scaffolds/node-typescript-preprocessor/src/index.ts: -------------------------------------------------------------------------------- 1 | import { LMStudioClient } from "@lmstudio/lms-client"; 2 | 3 | (async () => { 4 | const client = new LMStudioClient(); 5 | client.llm.registerPreprocessor({ 6 | identifier: "example - prepend date", 7 | preprocess: async (ctl, userMessage) => { 8 | const dateTime = new Date().toLocaleString(); 9 | const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone; 10 | return `(Current time: ${dateTime} ${timeZone})\n${userMessage.getText()}`; 11 | }, 12 | }); 13 | client.llm.registerPreprocessor({ 14 | identifier: "example - think step-by-step", 15 | preprocess: async (ctl, userMessage) => { 16 | return `${userMessage.getText()}\n\nPlease think step-by-step.`; 17 | }, 18 | }); 19 | })(); 20 | -------------------------------------------------------------------------------- /scaffolds/node-typescript-preprocessor/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "module": "CommonJS", 5 | "target": "ES2021", 6 | "declaration": true, 7 | "noImplicitOverride": true, 8 | "sourceMap": true, 9 | "declarationMap": true, 10 | "esModuleInterop": true, 11 | "skipLibCheck": true, 12 | "rootDir": "src", 13 | "outDir": "dist" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /scaffolds/node-typescript/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /scaffolds/node-typescript/README.md: -------------------------------------------------------------------------------- 1 | # 2 | 3 | #### Created with LM Studio scaffold: node-typescript-empty 4 | 5 | Welcome to your new project! This scaffold is a starting point for building an AI-enabled Node.js project with [LM Studio](https://lmstudio.ai/) SDK. To interact with LM Studio, you should start the LM Studio local server with the command: 6 | 7 | ```bash 8 | lms server start 9 | ``` 10 | 11 | ## Getting Started 12 | 13 | ### Development 14 | 15 | The source code resides in the `src/` directory. For development purposes, you can run the project using: 16 | 17 | ```start 18 | npm start 19 | ``` 20 | 21 | ### Building for Production 22 | 23 | To prepare your project for production, compile the TypeScript code to JavaScript using: 24 | 25 | ```bash 26 | npm run build 27 | ``` 28 | 29 | This will compile the TypeScript code in the `src/` directory to JavaScript in the `dist/` directory. 30 | 31 | ### Community & Help 32 | 33 | - [lmstudio.js GitHub](https://github.com/lmstudio-ai/lmstudio.js) 34 | - [Documentation](https://lmstudio.ai/docs/welcome) 35 | - [Discord](https://discord.gg/6Q7Xn6MRVS) 36 | - [Twitter](https://twitter.com/LMStudioAI) 37 | -------------------------------------------------------------------------------- /scaffolds/node-typescript/gitignore_template: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /scaffolds/node-typescript/lms-scaffold.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./../scaffold-json-schema-v1.json", 3 | "scaffoldVersion": 1, 4 | "name": "node-typescript", 5 | "displayName": "Node.js with TypeScript", 6 | "description": "Example Node.js TypeScript project with lmstudio.js", 7 | "args": [ 8 | { 9 | "name": "Project Name", 10 | "default": "node-typescript", 11 | "replaceFrom": ["@lmstudio/scaffold-node-typescript", ""], 12 | "isProjectName": true 13 | } 14 | ], 15 | "renames": [{ "from": "gitignore_template", "to": ".gitignore" }], 16 | "motd": [ 17 | { "type": "title", "text": "✓ Project Creation Successful" }, 18 | { 19 | "type": "regular", 20 | "text": "An example Node.js TypeScript project with lmstudio.js has been created in the folder. You can enter it with:" 21 | }, 22 | { "type": "command", "text": "cd " }, 23 | { "type": "regular", "text": "Then you can run the project with:" }, 24 | { "type": "command", "text": "npm start" } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /scaffolds/node-typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lmstudio/scaffold-node-typescript", 3 | "version": "1.2.1", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "type": "module", 8 | "scripts": { 9 | "start": "tsc && node --enable-source-maps dist/index.js", 10 | "build": "tsc" 11 | }, 12 | "author": "Your Name", 13 | "license": "UNLICENSED", 14 | "dependencies": { 15 | "@lmstudio/sdk": "^1.2.1" 16 | }, 17 | "gitHead": "abe566030fdea1ad86c21c3d5f32ded4782e8c0b", 18 | "devDependencies": { 19 | "@types/node": "^22.13.1", 20 | "typescript": "^5.7.2" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scaffolds/node-typescript/src/index.ts: -------------------------------------------------------------------------------- 1 | import { LMStudioClient } from "@lmstudio/sdk"; 2 | 3 | const client = new LMStudioClient(); 4 | 5 | await printDownloadedModels(); 6 | await printLoadedModels(); 7 | await predictWithAnyModel(); 8 | 9 | // ---------- Functions ---------- 10 | 11 | async function printDownloadedModels() { 12 | const downloadedModels = await client.system.listDownloadedModels(); 13 | console.log("Downloaded Models:"); 14 | if (downloadedModels.length === 0) { 15 | console.log(" No models downloaded. Get some in LM Studio."); 16 | process.exit(0); 17 | } 18 | 19 | // Limit to printing 5 models 20 | for (const model of downloadedModels.slice(0, 5)) { 21 | console.log(` - ${model.modelKey} (${model.displayName})`); 22 | } 23 | if (downloadedModels.length > 5) { 24 | console.log(` (... and ${downloadedModels.length - 5} more)`); 25 | } 26 | console.log(); // Create an empty line 27 | } 28 | 29 | async function printLoadedModels() { 30 | const loadedLLMs = await client.llm.listLoaded(); 31 | console.log("Loaded Models:"); 32 | if (loadedLLMs.length === 0) { 33 | console.log(" You don't have any models loaded. (Run `lms load` to load a model)"); 34 | process.exit(0); 35 | } 36 | for (const model of loadedLLMs) { 37 | console.log(` - ${model.identifier} (${model.displayName})`); 38 | } 39 | console.log(); // Create an empty line 40 | } 41 | 42 | async function predictWithAnyModel() { 43 | const model = await client.llm.model(); 44 | const prompt = "The meaning of life is"; 45 | const prediction = model.complete(prompt, { 46 | maxTokens: 100, 47 | temperature: 0.7, 48 | }); 49 | process.stdout.write(prompt); // Print the prompt 50 | // Stream the prediction text to console 51 | for await (const { content } of prediction) { 52 | process.stdout.write(content); 53 | } 54 | const { stats } = await prediction.result(); 55 | console.log("\n\nPrediction Stats:", stats); 56 | } 57 | -------------------------------------------------------------------------------- /scaffolds/node-typescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "module": "nodenext", 5 | "moduleResolution": "nodenext", 6 | "target": "ES2021", 7 | "declaration": true, 8 | "noImplicitOverride": true, 9 | "sourceMap": true, 10 | "declarationMap": true, 11 | "esModuleInterop": true, 12 | "skipLibCheck": true, 13 | "rootDir": "src", 14 | "outDir": "dist" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /scaffolds/scaffold-json-schema-v1.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft-07/schema", 3 | "type": "object", 4 | "required": ["scaffoldVersion", "name", "displayName", "description", "args", "motd"], 5 | "properties": { 6 | "scaffoldVersion": { 7 | "type": "number" 8 | }, 9 | "name": { 10 | "type": "string" 11 | }, 12 | "displayName": { 13 | "type": "string" 14 | }, 15 | "description": { 16 | "type": "string" 17 | }, 18 | "args": { 19 | "type": "array", 20 | "items": { 21 | "type": "object", 22 | "required": ["name", "default"], 23 | "properties": { 24 | "name": { 25 | "type": "string" 26 | }, 27 | "replaceFrom": { 28 | "type": "array", 29 | "items": { 30 | "type": "string" 31 | } 32 | }, 33 | "default": { 34 | "type": "string" 35 | }, 36 | "isProjectName": { 37 | "type": "boolean" 38 | } 39 | } 40 | } 41 | }, 42 | "renames": { 43 | "type": "array", 44 | "items": { 45 | "type": "object", 46 | "required": ["from", "to"], 47 | "properties": { 48 | "from": { 49 | "type": "string" 50 | }, 51 | "to": { 52 | "type": "string" 53 | } 54 | } 55 | } 56 | }, 57 | "motd": { 58 | "type": "array", 59 | "items": { 60 | "type": "object", 61 | "required": ["type", "text"], 62 | "properties": { 63 | "type": { 64 | "type": "string", 65 | "enum": ["regular", "title", "command", "hint"] 66 | }, 67 | "text": { 68 | "type": "string" 69 | } 70 | } 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /scaffolds/upload.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | const { S3Client, PutObjectCommand } = require("@aws-sdk/client-s3"); 3 | const { readFileSync } = require("fs"); 4 | const { join } = require("path"); 5 | 6 | // Create an S3 client 7 | const s3Client = new S3Client({ 8 | region: "auto", // or your specific region 9 | credentials: { 10 | accessKeyId: process.env.CF_ACCESS_KEY_ID, 11 | secretAccessKey: process.env.CF_SECRET_ACCESS_KEY, 12 | }, 13 | endpoint: process.env.CF_ENDPOINT, 14 | forcePathStyle: true, // Needed for Cloudflare R2 15 | signatureVersion: "v4", 16 | }); 17 | 18 | const bucketName = "scaffolds-manifest"; 19 | const filePath = join(__dirname, "scaffolds.json"); 20 | const keyName = "scaffolds.json"; 21 | 22 | const uploadFile = async () => { 23 | try { 24 | const data = await s3Client.send( 25 | new PutObjectCommand({ 26 | Bucket: bucketName, 27 | Key: keyName, 28 | Body: readFileSync(filePath), 29 | ContentType: "application/json", 30 | }), 31 | ); 32 | console.log("Success", data); 33 | } catch (err) { 34 | console.log("Error", err); 35 | } 36 | }; 37 | 38 | uploadFile(); 39 | -------------------------------------------------------------------------------- /scripts/generateEsmPackageJson.mjs: -------------------------------------------------------------------------------- 1 | // In order for node.js to correctly recognize the esm folder in dist is an ES module, we need to 2 | // generate and place a "package.json" with { "type": "module" } in each of the packages that have 3 | // esm support 4 | 5 | import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "fs"; 6 | import { resolve } from "path"; 7 | 8 | const packagesFolder = resolve("../packages"); 9 | 10 | for (const dirent of readdirSync(packagesFolder, { withFileTypes: true })) { 11 | if (!dirent.isDirectory()) { 12 | continue; 13 | } 14 | if (!dirent.name.startsWith("lms-")) { 15 | continue; 16 | } 17 | const packageFolder = resolve(packagesFolder, dirent.name); 18 | const packageJson = JSON.parse(readFileSync(resolve(packageFolder, "package.json"), "utf-8")); 19 | const exports = packageJson.exports; 20 | if (typeof exports !== "object") { 21 | continue; 22 | } 23 | // If none of the exports have specified the "import" field, we don't need to generate a 24 | // package.json file 25 | if (Object.values(exports).every(value => !value || !value.import)) { 26 | continue; 27 | } 28 | const targetFolder = resolve(packageFolder, "dist", "esm"); 29 | const targetPath = resolve(targetFolder, "package.json"); 30 | if (existsSync(targetPath)) { 31 | continue; 32 | } 33 | mkdirSync(targetFolder, { recursive: true }); 34 | writeFileSync(targetPath, JSON.stringify({ type: "module" })); 35 | } 36 | -------------------------------------------------------------------------------- /scripts/starter.mjs: -------------------------------------------------------------------------------- 1 | import { spawn } from "child_process"; 2 | import inquirer from "inquirer"; 3 | 4 | const { commands } = await inquirer.createPromptModule({ 5 | output: process.stderr, 6 | })({ 7 | type: "checkbox", 8 | name: "commands", 9 | message: "Which services would you like to use?", 10 | choices: [ 11 | { 12 | checked: true, 13 | value: '"npm run watch-tsc"', 14 | name: "TypeScript Compilation (for regular packages)", 15 | }, 16 | { 17 | checked: true, 18 | value: '"npm run watch-jest"', 19 | name: "Jest (unit tests)", 20 | }, 21 | { 22 | checked: true, 23 | value: '[ "npm run watch-sdk-ae" : "npm run watch-sdk-rollup" ]', 24 | name: "SDK (in /publish/lmstudio)", 25 | }, 26 | { 27 | checked: false, 28 | value: '[ "npm run watch-cli-package" : "npm run watch-cli-rollup" ]', 29 | name: "CLI (in /packages/lms-cli and in /publish/cli)", 30 | }, 31 | { 32 | checked: false, 33 | value: '"npm run watch-lmstudio"', 34 | name: "LM Studio Installer (in /publish/lmstudio)", 35 | }, 36 | ], 37 | }); 38 | 39 | // Yes, it is dangerous to do command concatenation without proper escaping. But in this case, we 40 | // have full control over the commands. We are not using any user input to build the command. 41 | const command = `npx stmux -e "(?:error TS| failed\\, )" -- [ ${commands.join(" .. ")} ]`; 42 | const sp = spawn(command, { shell: true, stdio: "inherit" }); 43 | 44 | sp.on("exit", () => { 45 | console.info("Processes terminated. The command ran was:"); 46 | console.info(command); 47 | }); 48 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "packages/lms-shared-types" }, 5 | { "path": "packages/lms-kv-config" }, 6 | { "path": "packages/lms-isomorphic" }, 7 | { "path": "packages/lms-common" }, 8 | { "path": "packages/lms-common-server" }, 9 | { "path": "packages/lms-communication" }, 10 | { "path": "packages/lms-communication-client" }, 11 | { "path": "packages/lms-communication-server" }, 12 | { "path": "packages/lms-communication-mock" }, 13 | { "path": "packages/lms-external-backend-interfaces" }, 14 | { "path": "packages/lms-client" }, 15 | { "path": "packages/lms-lmstudio" }, 16 | { "path": "packages/lms-es-plugin-runner" }, 17 | { "path": "packages/lms-json-schema" }, 18 | { "path": "packages/template" }, 19 | { "path": "publish/sdk" } 20 | ], 21 | "exclude": ["*.test.ts"] 22 | } 23 | -------------------------------------------------------------------------------- /tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "esnext" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "ES2022", 5 | "useDefineForClassFields": false, 6 | "moduleResolution": "node", 7 | "incremental": true, 8 | "noImplicitOverride": true, 9 | "sourceMap": true, 10 | "skipLibCheck": true, 11 | "stripInternal": true, 12 | "composite": true, 13 | "esModuleInterop": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.types.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": true, 5 | "declarationMap": true, 6 | "emitDeclarationOnly": true 7 | } 8 | } 9 | --------------------------------------------------------------------------------