tjs-lang 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CLAUDE.md +6 -2
  2. package/CONTEXT.md +4 -0
  3. package/demo/docs.json +12 -690
  4. package/dist/eslint.config.d.ts +2 -0
  5. package/dist/index.js +137 -135
  6. package/dist/index.js.map +4 -4
  7. package/dist/src/lang/emitters/js-wasm.d.ts +5 -1
  8. package/dist/src/lang/emitters/js.d.ts +9 -0
  9. package/dist/src/lang/index.d.ts +1 -0
  10. package/dist/src/lang/module-loader.d.ts +125 -0
  11. package/dist/src/lang/parser-transforms.d.ts +79 -0
  12. package/dist/src/lang/parser-types.d.ts +33 -0
  13. package/dist/src/lang/wasm.d.ts +67 -1
  14. package/dist/tjs-batteries.js +2 -2
  15. package/dist/tjs-batteries.js.map +2 -2
  16. package/dist/tjs-eval.js +39 -37
  17. package/dist/tjs-eval.js.map +3 -3
  18. package/dist/tjs-from-ts.js +2 -2
  19. package/dist/tjs-from-ts.js.map +2 -2
  20. package/dist/tjs-lang.js +102 -102
  21. package/dist/tjs-lang.js.map +3 -3
  22. package/dist/tjs-vm.js +50 -48
  23. package/dist/tjs-vm.js.map +3 -3
  24. package/docs/README.md +2 -0
  25. package/docs/lm-studio-setup.md +143 -0
  26. package/docs/universal-endpoint.md +122 -0
  27. package/llms.txt +8 -2
  28. package/package.json +5 -4
  29. package/src/batteries/audit.ts +3 -3
  30. package/src/batteries/llm.ts +8 -3
  31. package/src/builder.ts +0 -3
  32. package/src/cli/commands/test.ts +1 -1
  33. package/src/lang/docs.test.ts +0 -1
  34. package/src/lang/emitters/from-ts.ts +1 -1
  35. package/src/lang/emitters/js.ts +0 -1
  36. package/src/lang/linter.ts +1 -1
  37. package/src/lang/module-loader.test.ts +9 -5
  38. package/src/lang/module-loader.ts +4 -5
  39. package/src/lang/parser-params.ts +1 -1
  40. package/src/lang/parser-transforms.ts +12 -18
  41. package/src/lang/perf.test.ts +10 -4
  42. package/src/lang/runtime.ts +0 -1
  43. package/src/lang/wasm.test.ts +14 -14
  44. package/src/linalg/linalg.test.ts +8 -2
  45. package/src/linalg/vector-search.bench.test.ts +31 -10
  46. package/src/types/Type.ts +6 -6
  47. package/src/use-cases/asymmetric-client-server.test.ts +0 -2
  48. package/src/use-cases/client-server.test.ts +1 -1
  49. package/src/use-cases/unbundled-imports.test.ts +0 -1
  50. package/src/vm/runtime.ts +3 -3
  51. package/src/vm/vm.ts +3 -1
  52. package/dist/examples/modules/dist/main.d.ts +0 -34
  53. package/dist/examples/modules/dist/math.d.ts +0 -120
@@ -1,7 +1,11 @@
1
1
  /**
2
2
  * TJS WASM Bootstrap Generation
3
3
  *
4
- * Compiles inline WASM blocks and generates JavaScript bootstrap code.
4
+ * Compiles the file's WASM blocks into a single WebAssembly.Module with
5
+ * one exported function per block, then emits JavaScript that compiles
6
+ * and instantiates the module once at startup. This is the foundation
7
+ * for cross-file wasm composition (see wasm-library-plan.md, Phase 3) —
8
+ * once everything's in one module, intra-module calls cost nothing.
5
9
  */
6
10
  import type { WasmBlock } from '../parser';
7
11
  export declare function generateWasmBootstrap(blocks: WasmBlock[]): {
@@ -74,6 +74,15 @@ export interface TJSTranspileOptions {
74
74
  * Used when tests depend on imported modules.
75
75
  */
76
76
  resolvedImports?: Record<string, string>;
77
+ /**
78
+ * Optional ModuleLoader for cross-file `wasm function` composition (Phase 3
79
+ * of the wasm-library plan). When provided, `import { dot } from
80
+ * 'tjs-lang/linalg'`-style imports are resolved at transpile time and any
81
+ * matching `wasm function` declarations are composed into this file's
82
+ * consolidated WebAssembly.Module. When omitted, imports are preserved
83
+ * verbatim (default behavior — runtime resolves them).
84
+ */
85
+ moduleLoader?: any;
77
86
  }
78
87
  /** Result of running tests at transpile time */
79
88
  export type { TestResult } from './js-tests';
@@ -34,6 +34,7 @@ export { typeDescriptorToJSONSchema, exampleToJSONSchema, functionMetaToJSONSche
34
34
  export { MetadataCache, getGlobalCache, setGlobalCache } from './metadata-cache';
35
35
  export { lint, type LintResult, type LintDiagnostic, type LintOptions, } from './linter';
36
36
  export { generateDocs, generateDocsMarkdown, type DocResult, type DocItem, type FunctionTypeInfo, type ParamTypeInfo, } from './docs';
37
+ export { ModuleLoader, inMemoryFileSystem, type ModuleLoaderOptions, type FileSystem, type LoadedModule, type ImportEntry, type ExportEntry, } from './module-loader';
37
38
  export { extractTests, assertFunction, expectFunction, testUtils, type ExtractedTest, type ExtractedMock, type TestExtractionResult, } from './tests';
38
39
  export { runtime, installRuntime, isError, error, typeOf, checkType, validateArgs, wrap, emitRuntimeWrapper, TJS_VERSION, type TJSError, } from './runtime';
39
40
  export { compileToWasm, instantiateWasm, registerWasmBlock, compileWasmBlocks, type WasmCompileResult, } from './wasm';
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Transpile-time module loader.
3
+ *
4
+ * Until now the transpiler has preserved import statements verbatim — runtime
5
+ * resolvers (the bun plugin, the playground service worker, the browser ESM
6
+ * loader) handle them on demand. That's the right default for regular JS
7
+ * interop, but Phase 3 of the wasm-library plan needs *static* visibility into
8
+ * imported sources: given `import { dot } from 'tjs-lang/linalg'`, we have to
9
+ * read linalg's source at transpile time so cross-file `wasm function`
10
+ * declarations can be composed into the consumer's wasm module.
11
+ *
12
+ * This loader is the foundation for that work. It's also useful as a building
13
+ * block for any future cross-file static analysis (type flow, dead code, etc.)
14
+ * — hence the name "module loader" rather than "wasm import resolver."
15
+ *
16
+ * Usage:
17
+ * const loader = new ModuleLoader({ baseDir: '/path/to/project' })
18
+ * const mod = loader.load('./math.tjs', '/path/to/project/app.tjs')
19
+ * if (mod) { console.log(mod.exports) }
20
+ *
21
+ * Resolution rules (in order):
22
+ * - URL specifiers (http://, https://, data:): not loadable, returns null
23
+ * - Relative paths (./foo, ../bar): resolved against importer's dir
24
+ * - Absolute paths (/foo/bar): used as-is
25
+ * - Bare specifiers (foo, foo/bar): walk up importer looking for
26
+ * node_modules/<spec>; also
27
+ * try bareSpecifierRoots
28
+ *
29
+ * For each candidate, we try extensions in order: `.tjs`, `.ts`, `.js`.
30
+ * (Index files: `<dir>/index.<ext>`.)
31
+ *
32
+ * The loader does NOT mutate transpiler behavior. It's an additive capability;
33
+ * Phase 3 (cross-file wasm composition) is the first caller.
34
+ */
35
+ import { parse as parseTjs } from './parser';
36
+ /** Pluggable filesystem hook. Default uses node:fs. */
37
+ export interface FileSystem {
38
+ /** Return source text for an absolute path, or null if it doesn't exist. */
39
+ readFile(path: string): string | null;
40
+ /** Return true if the path exists and is a file. */
41
+ exists(path: string): boolean;
42
+ }
43
+ export interface ModuleLoaderOptions {
44
+ /** Filesystem hook (default: node:fs based) */
45
+ fs?: FileSystem;
46
+ /** Where to resolve bare specifiers from when no importer is given. */
47
+ baseDir?: string;
48
+ /**
49
+ * Extra roots tried for bare specifiers BEFORE the standard node_modules
50
+ * walk. Useful for monorepos or tests that want to point at a virtual
51
+ * package directory. Each root is treated as if it were a `node_modules/`.
52
+ */
53
+ bareSpecifierRoots?: string[];
54
+ /** Cache size cap. 0 disables caching. (default 256) */
55
+ cacheLimit?: number;
56
+ }
57
+ /** A single import / re-export specifier extracted from the AST */
58
+ export interface ImportEntry {
59
+ /** Original module specifier (e.g. './math.tjs', 'tjs-lang/linalg') */
60
+ specifier: string;
61
+ /** Local name in the importing module */
62
+ local: string;
63
+ /** Imported name in the source module ('default' for default imports) */
64
+ imported: string;
65
+ /** True if this came from `import * as X` */
66
+ namespace: boolean;
67
+ }
68
+ /** A top-level export from a module */
69
+ export interface ExportEntry {
70
+ /** Exported name (or 'default' for default exports) */
71
+ name: string;
72
+ /** Kind of declaration being exported */
73
+ kind: 'function' | 'class' | 'variable' | 're-export' | 'unknown';
74
+ /** For re-exports, the source specifier */
75
+ fromSpecifier?: string;
76
+ }
77
+ export interface LoadedModule {
78
+ /** Resolved absolute path */
79
+ path: string;
80
+ /** Original source text */
81
+ source: string;
82
+ /** AST + tjs preprocessing output (lazy — only computed once per module) */
83
+ parseResult: ReturnType<typeof parseTjs>;
84
+ /** Imports declared by this module */
85
+ imports: ImportEntry[];
86
+ /** Top-level exports */
87
+ exports: ExportEntry[];
88
+ }
89
+ export declare class ModuleLoader {
90
+ private cache;
91
+ private fs;
92
+ private baseDir;
93
+ private bareSpecifierRoots;
94
+ private cacheLimit;
95
+ constructor(options?: ModuleLoaderOptions);
96
+ /**
97
+ * Resolve a specifier to an absolute path. Returns null when the specifier
98
+ * is not loadable as a local TJS/TS/JS file (URLs, missing files, unknown
99
+ * bare specifiers all return null — the caller falls back to verbatim
100
+ * import preservation).
101
+ */
102
+ resolve(specifier: string, importerPath?: string): string | null;
103
+ /**
104
+ * Load a module by specifier. Returns null if not resolvable (caller treats
105
+ * this as "leave the import statement alone").
106
+ *
107
+ * Repeated calls with the same specifier+importer combination hit the cache.
108
+ */
109
+ load(specifier: string, importerPath?: string): LoadedModule | null;
110
+ /** Drop all cached modules. */
111
+ clearCache(): void;
112
+ /** Try each supported extension; return the first existing path or null. */
113
+ private tryExtensions;
114
+ /**
115
+ * Resolve a bare specifier (e.g. `tjs-lang/linalg`, `lodash`) by walking
116
+ * up the importer's directory tree looking for `node_modules/<spec>`.
117
+ * Also checks each configured `bareSpecifierRoots` entry first.
118
+ */
119
+ private resolveBare;
120
+ }
121
+ /**
122
+ * Helper for tests / advanced use: build a FileSystem from a plain
123
+ * `Map<string, string>`. Keys must be absolute paths.
124
+ */
125
+ export declare function inMemoryFileSystem(files: Map<string, string> | Record<string, string>): FileSystem;
@@ -32,6 +32,85 @@ export declare function extractWasmBlocks(source: string): {
32
32
  source: string;
33
33
  blocks: WasmBlock[];
34
34
  };
35
+ /**
36
+ * Extract top-level `wasm function NAME(params): RetType { body }` declarations.
37
+ *
38
+ * Unlike `extractWasmBlocks` (which finds `wasm { ... }` blocks nested inside
39
+ * regular tjs functions with auto-captured variables), this extractor finds
40
+ * top-level wasm function declarations with explicit parameters and an
41
+ * optional return type. The body is the wasm-subset source.
42
+ *
43
+ * Each declaration becomes a `WasmBlock` whose `captures` array holds the
44
+ * function's parameters with their type annotations (e.g. `['a: Float32Array',
45
+ * 'b: Float32Array', 'n: i32']`). The block ID is derived from the function
46
+ * name (`__tjs_wasm_<name>`), so the JS-side wrapper can reference it.
47
+ *
48
+ * The declaration is replaced in source with a regular JS function that
49
+ * forwards its args to the wasm export, preserving the `export` modifier
50
+ * if present:
51
+ *
52
+ * (export)? wasm function dot(a: Float32Array, b: Float32Array, n: f64): f64 {
53
+ * <wasm-source>
54
+ * }
55
+ *
56
+ * becomes:
57
+ *
58
+ * (export)? function dot(a, b, n) { return globalThis.__tjs_wasm_dot(a, b, n) }
59
+ *
60
+ * This runs BEFORE `extractWasmBlocks` so its output (a regular JS function
61
+ * wrapper) isn't disturbed by the inline-block scanner.
62
+ *
63
+ * Return-type note: the underlying wasm bytecode builder currently emits f64
64
+ * or void return types only. The declared `: RetType` annotation is parsed
65
+ * and preserved on the block, but not yet validated against the backend's
66
+ * capabilities — `: f64` and omitted-return work today; other types (`: i32`,
67
+ * `: f32`, `: v128`) will be supported when the bytecode builder grows
68
+ * per-function return-type encoding.
69
+ */
70
+ export declare function extractWasmFunctions(source: string): {
71
+ source: string;
72
+ blocks: WasmBlock[];
73
+ };
74
+ /**
75
+ * Phase 3: cross-file wasm-function composition.
76
+ *
77
+ * Scans the consumer's source for `import { name1, name2, ... } from 'spec'`
78
+ * statements. For each, resolves the spec via the supplied ModuleLoader; if
79
+ * the imported file is tjs/ts and one of the imported names corresponds to a
80
+ * `wasm function` declared there, the function's WasmBlock is pulled into the
81
+ * consumer's compilation and replaced in source by a local JS wrapper. The
82
+ * import statement is rewritten to remove the satisfied names (or removed
83
+ * entirely if every imported name was wasm-composed).
84
+ *
85
+ * This is the heart of the cross-file composition story: imported wasm
86
+ * functions become local functions in the consumer's single WebAssembly.Module
87
+ * (via the Phase 0.5 consolidated-module path). The library's transpiled .js
88
+ * is NOT involved — the source is consumed at transpile time.
89
+ *
90
+ * Caller is responsible for providing a configured ModuleLoader. When no
91
+ * loader is supplied (the common case before Phase 3 is fully wired up), this
92
+ * function returns the source unchanged with an empty blocks array.
93
+ *
94
+ * @param source the consumer's source (after extractWasmFunctions on its own
95
+ * wasm functions, before transformParenExpressions)
96
+ * @param options.loader the ModuleLoader to resolve imports through
97
+ * @param options.importerPath the path of the file being transpiled (used as
98
+ * the resolver's importer context); optional
99
+ * @returns updated source + the list of imported wasm function blocks
100
+ */
101
+ export declare function composeImportedWasmFunctions(source: string, options: {
102
+ loader?: {
103
+ load(specifier: string, importerPath?: string): {
104
+ parseResult: {
105
+ wasmBlocks: WasmBlock[];
106
+ };
107
+ } | null;
108
+ };
109
+ importerPath?: string;
110
+ }): {
111
+ source: string;
112
+ blocks: WasmBlock[];
113
+ };
35
114
  /**
36
115
  * Transform Is/IsNot infix operators to function calls
37
116
  *
@@ -14,6 +14,17 @@ export interface ParseOptions {
14
14
  * When true, skips == to Is() transformation since the VM handles == correctly.
15
15
  */
16
16
  vmTarget?: boolean;
17
+ /**
18
+ * Optional ModuleLoader for cross-file `wasm function` composition (Phase 3).
19
+ * When provided, imports are resolved at transpile time and matching wasm
20
+ * functions are composed into the consumer's WebAssembly.Module. When
21
+ * omitted, imports are preserved verbatim (the default — runtime resolves
22
+ * them as before).
23
+ *
24
+ * Type is left as `any` here to avoid a circular import with module-loader.ts;
25
+ * callers should pass a `ModuleLoader` instance.
26
+ */
27
+ moduleLoader?: any;
17
28
  }
18
29
  /**
19
30
  * A WASM block extracted from source
@@ -35,6 +46,21 @@ export interface ParseOptions {
35
46
  export interface WasmBlock {
36
47
  /** Unique ID for this block */
37
48
  id: string;
49
+ /**
50
+ * Declared function name (only set for top-level `wasm function NAME(...)`
51
+ * declarations — Phase 1+). Used by Phase 3 cross-file composition to
52
+ * match an imported symbol against a wasm function declaration. Inline
53
+ * `wasm {}` blocks have no name and don't participate in composition.
54
+ */
55
+ name?: string;
56
+ /**
57
+ * Declared return-type annotation, e.g. `'f64'`. Only set for top-level
58
+ * `wasm function NAME(...): RetType` declarations; presence/absence is
59
+ * used to determine `hasReturn` BEFORE the body is compiled, so the
60
+ * function index map can be built up-front for wasm-to-wasm calls.
61
+ * Inline blocks have no declared return type.
62
+ */
63
+ returnType?: string;
38
64
  /** The body (JS subset that compiles to WASM, also used as fallback) */
39
65
  body: string;
40
66
  /** Explicit fallback body (only if different from body) */
@@ -79,6 +105,13 @@ export interface PreprocessOptions {
79
105
  * Default: false (transform == to Is() for TJS code running in regular JS)
80
106
  */
81
107
  vmTarget?: boolean;
108
+ /**
109
+ * Optional ModuleLoader for cross-file `wasm function` composition (Phase 3).
110
+ * See ParseOptions.moduleLoader for details.
111
+ */
112
+ moduleLoader?: any;
113
+ /** Path of the file being preprocessed (used as importer context). */
114
+ filename?: string;
82
115
  }
83
116
  /**
84
117
  * Tokenizer state for tracking context during source transformation
@@ -15,6 +15,29 @@
15
15
  * audio processing, image manipulation, and physics simulations.
16
16
  */
17
17
  import type { WasmBlock } from './parser';
18
+ /** TJS type that maps to WASM */
19
+ type WasmValueType = 'i32' | 'i64' | 'f32' | 'f64' | 'v128';
20
+ /** Parameter with type annotation */
21
+ interface TypedParam {
22
+ name: string;
23
+ type: WasmValueType;
24
+ isArray?: boolean;
25
+ arrayType?: string;
26
+ }
27
+ /**
28
+ * Signature of a wasm function in the current module. Used to resolve
29
+ * cross-function calls (wasm-to-wasm `call <index>` instructions) without
30
+ * routing through JS. Populated by compileBlocksToModule before compiling
31
+ * any individual body, so forward references and mutual recursion work.
32
+ */
33
+ export interface ModuleFunctionSig {
34
+ /** Function index in the composed module */
35
+ index: number;
36
+ /** Parameter types (used for arg-type checking + auto-conversion) */
37
+ params: TypedParam[];
38
+ /** Whether this function returns a value (f64) or is void */
39
+ hasReturn: boolean;
40
+ }
18
41
  /** Compile result */
19
42
  export interface WasmCompileResult {
20
43
  /** The compiled WebAssembly module bytes */
@@ -31,9 +54,51 @@ export interface WasmCompileResult {
31
54
  wat?: string;
32
55
  }
33
56
  /**
34
- * Compile a WASM block to WebAssembly
57
+ * Compile a single WASM block to a complete WebAssembly module.
58
+ * The module exports a single function named `compute`.
35
59
  */
36
60
  export declare function compileToWasm(block: WasmBlock): WasmCompileResult;
61
+ /** Per-export metadata produced by compileBlocksToModule */
62
+ export interface BlockExport {
63
+ /** Original block ID (assigned by the parser) */
64
+ id: string;
65
+ /** Export name in the composed module (e.g. 'compute_0') */
66
+ exportName: string;
67
+ /** Capture annotations (preserved for runtime wrapper) */
68
+ captures: string[];
69
+ /** Whether this function reads/writes memory */
70
+ needsMemory: boolean;
71
+ /** WAT disassembly */
72
+ wat: string;
73
+ }
74
+ /** Result of composing multiple blocks into one module */
75
+ export interface MultiBlockCompileResult {
76
+ /** The composed module bytes, or empty if all blocks failed */
77
+ bytes: Uint8Array;
78
+ /** Per-block compile status (preserves input order) */
79
+ results: {
80
+ id: string;
81
+ success: boolean;
82
+ error?: string;
83
+ /** Index into `exports` (only when success === true) */
84
+ exportIndex?: number;
85
+ }[];
86
+ /** Successfully-compiled exports (in module-index order) */
87
+ exports: BlockExport[];
88
+ /** True if any included function needs memory */
89
+ needsMemory: boolean;
90
+ /** Aggregated warnings from all blocks */
91
+ warnings: string[];
92
+ }
93
+ /**
94
+ * Compile N WASM blocks into a single WebAssembly module with N exports.
95
+ * Failed blocks are skipped (their slot in `results` records the error)
96
+ * but do not abort compilation of the rest.
97
+ *
98
+ * Exports are named `compute_0`, `compute_1`, ... in input order, skipping
99
+ * indices that correspond to failed blocks.
100
+ */
101
+ export declare function compileBlocksToModule(blocks: WasmBlock[]): MultiBlockCompileResult;
37
102
  /**
38
103
  * Instantiate a compiled WASM module
39
104
  */
@@ -81,3 +146,4 @@ export declare function compileWasmBlocksForIframe(blocks: WasmBlock[]): Promise
81
146
  * This code should be injected into the iframe's script
82
147
  */
83
148
  export declare function generateWasmInstantiationCode(compiledBlocks: CompiledWasmData[]): string;
149
+ export {};
@@ -1,3 +1,3 @@
1
- var S=new Map,p=new Map;function k(e,t){if(e.length!==t.length)throw new Error("Vectors must have the same length for cosine similarity.");let o=0,n=0,s=0;for(let r=0;r<e.length;r++)o+=e[r]*t[r],n+=e[r]*e[r],s+=t[r]*t[r];return n=Math.sqrt(n),s=Math.sqrt(s),n===0||s===0?0:o/(n*s)}function w(){return{async get(e){return S.get(e)},async set(e,t){S.set(e,t)},async createCollection(e,t,o){p.has(e)&&console.warn(`Collection '${e}' already exists. Overwriting.`),p.set(e,[])},async vectorAdd(e,t){let o=p.get(e);if(!o)throw new Error(`Collection '${e}' not found. Create it first.`);if(!t.embedding||!Array.isArray(t.embedding))throw new Error("Document must have an 'embedding' property that is an array of numbers.");o.push(t)},async vectorSearch(e,t,o=5){let n=p.get(e);if(!n)throw new Error(`Collection '${e}' not found. Create it first.`);let s=n.map(r=>({doc:r,score:k(t,r.embedding)}));return s.sort((r,i)=>i.score-r.score),s.slice(0,o).map(r=>r.doc)}}}function O(e){if(typeof e=="string")return{role:"user",content:e};let t=[{type:"text",text:e.text}];for(let o of e.images||[])t.push({type:"image_url",image_url:{url:o}});return{role:"user",content:t}}var P="http://localhost:1234/v1";function E(e,t=P){return{async predict(o,n,s,r){try{let i=r?e.getStructuredLLM():e.getLLM(),l=[{role:"system",content:o},O(n)],a=await fetch(`${t}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:i.id,messages:l,temperature:.7,tools:s,response_format:r})});if(!a.ok)throw new Error(`LLM Error: ${a.status} ${a.statusText}`);return(await a.json()).choices[0]?.message??{content:""}}catch(i){throw i.cause?.code==="ECONNREFUSED"?new Error("No LLM provider configured. Please start LM Studio or provide an API key."):i}},async embed(o){try{let n=e.getEmbedding(),s=await fetch(`${t}/embeddings`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:n.id,input:o})});if(!s.ok)throw new Error(`Embedding Error: ${s.status}`);return(await s.json()).data[0]?.embedding??[]}catch(n){throw n.cause?.code==="ECONNREFUSED"?new Error("No LLM provider configured. Please start LM Studio or provide an API key."):n}}}}var h=".models.cache.json";var c=typeof window<"u"&&typeof window.localStorage<"u";async function _(e){try{if(c){let t=window.localStorage.getItem(h);if(!t)return null;let o=JSON.parse(t);return o.baseUrl!==e||Date.now()-o.timestamp>864e5?null:o.models}else{let t=await import("node:fs/promises"),n=(await import("node:path")).join(process.cwd(),h);try{let s=await t.readFile(n,"utf-8"),r=JSON.parse(s);return r.baseUrl!==e||Date.now()-r.timestamp>864e5?null:r.models}catch{return null}}}catch(t){return console.warn("\u26A0\uFE0F Error reading model cache:",t),null}}async function N(e,t){let o={timestamp:Date.now(),baseUrl:e,models:t};try{if(c)window.localStorage.setItem(h,JSON.stringify(o));else{let n=await import("node:fs/promises"),r=(await import("node:path")).join(process.cwd(),h);await n.writeFile(r,JSON.stringify(o,null,2))}}catch(n){console.error("\u274C Error writing model cache:",n)}}var u=async(e,t)=>{let o=new AbortController,n=setTimeout(()=>o.abort(),6e4);try{let s=await fetch(e,{...t,signal:o.signal});return clearTimeout(n),s}catch(s){throw clearTimeout(n),s}};async function v(e,t){try{let o={type:"json_schema",json_schema:{name:"test",strict:!1,schema:{type:"object",properties:{status:{type:"string"}}}}},n=await u(`${e}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:t,messages:[{role:"system",content:"You respond in JSON."},{role:"user",content:'Return JSON: {"status": "ok"}'}],response_format:o,max_tokens:20})});if(!n.ok)return n.status===400?x(e,t):{ok:!1,msg:`HTTP ${n.status}`};let s=await n.json();return JSON.parse(s.choices[0].message.content),{ok:!0,msg:"OK (Schema)"}}catch(o){return{ok:!1,msg:o.message||"Error"}}}async function x(e,t){try{return(await u(`${e}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:t,messages:[{role:"user",content:'JSON: {"a":1}'}],response_format:{type:"json_object"},max_tokens:10})})).ok?{ok:!0,msg:"OK (Legacy Mode)"}:{ok:!1,msg:"Not Supported"}}catch{return{ok:!1,msg:"Legacy Fail"}}}async function D(e,t){try{return(await u(`${e}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:t,messages:[{role:"user",content:"hi"}],max_tokens:1})})).ok}catch{return!1}}async function j(e,t){try{let o=await u(`${e}/embeddings`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:t,input:"test"})});return o.ok?(await o.json()).data[0]?.embedding?.length??null:null}catch{return null}}var J="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg==";async function $(e,t){try{return(await u(`${e}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:t,messages:[{role:"user",content:[{type:"text",text:"What color is this?"},{type:"image_url",image_url:{url:J}}]}],max_tokens:10})})).ok}catch{return!1}}async function A(e){let t=await _(e),o=[];try{let i=await fetch(`${e}/models`);if(!i.ok)throw new Error("Could not connect");o=(await i.json()).data.map(a=>a.id).sort()}catch{return t?(console.log("\u26A0\uFE0F LM Studio unavailable, using cached model audit."),t):(console.error("\u274C Failed to connect to LM Studio."),[])}if(t){let i=t.map(l=>l.id).sort();if(JSON.stringify(o)===JSON.stringify(i))return console.log("\u2705 Using cached model audit."),t;console.log("\u{1F50D} Model list changed. Re-running audit...")}console.log("\u{1F50D} Scanning models (this may take a moment)...");let n=[],s=o.map(i=>({id:i})),r;c||(r=await import("node:readline"));for(let i of s){!c&&r&&(r.cursorTo(process.stdout,0),process.stdout.write(`\u{1F449} Testing: ${i.id}...`),r.clearLine(process.stdout,1));let l="Unknown",a=!1,g=!1,d="",b,T=await D(e,i.id),f=await j(e,i.id);if(f&&(b=f),T){l="LLM";let L=await v(e,i.id);a=L.ok,g=await $(e,i.id),d=a?L.msg:`Fail: ${L.msg}`,g&&(d+=" +Vision")}else f?(l="Embedding",d=`OK (Dim: ${f})`):d="LLM Fail";n.push({id:i.id,type:l,structuredOutput:a,vision:g,dimension:b,status:d})}return!c&&r&&(r.cursorTo(process.stdout,0),r.clearLine(process.stdout,0)),console.log(`
2
- `),console.table(n),await N(e,n),console.log("\u{1F4DD} Audit results saved to cache."),n}var U="http://localhost:1234/v1",y=class{constructor(t=U){this.baseUrl=t}baseUrl;models=[];defaultLLM=null;defaultEmbedding=null;defaultStructuredLLM=null;async audit(){this.models=await A(this.baseUrl),this.selectDefaults()}selectDefaults(){this.defaultEmbedding=this.models.find(t=>t.type==="Embedding")||null,this.defaultLLM=this.models.find(t=>t.type==="LLM")||null,this.defaultStructuredLLM=this.models.find(t=>t.type==="LLM"&&t.structuredOutput)||null,this.defaultEmbedding||console.warn("\u26A0\uFE0F No embedding model found."),this.defaultLLM||console.warn("\u26A0\uFE0F No LLM found."),this.defaultStructuredLLM||console.warn("\u26A0\uFE0F No LLM with structured output support found.")}getModels(){return this.models}_setDefaultModel(t,o,n,s){let r=this.models.find(i=>i.id===t&&n(i));if(!r)throw new Error(`Model '${t}' not found or is not ${s}.`);this[o]=r}setDefaultLLM(t){this._setDefaultModel(t,"defaultLLM",o=>o.type==="LLM","an LLM")}setDefaultEmbedding(t){this._setDefaultModel(t,"defaultEmbedding",o=>o.dimension!==void 0,"an embedding model")}setDefaultStructuredLLM(t){this._setDefaultModel(t,"defaultStructuredLLM",o=>o.type==="LLM"&&o.structuredOutput,"a structured-output LLM")}getLLM(){if(!this.defaultLLM)throw new Error("No LLM available.");return this.defaultLLM}getEmbedding(){if(!this.defaultEmbedding)throw new Error("No embedding model available.");return this.defaultEmbedding}getStructuredLLM(){if(!this.defaultStructuredLLM)throw new Error("No structured-output LLM available.");return this.defaultStructuredLLM}};var F=typeof window<"u",R=F&&window.location.protocol==="https:",m=null,M=null,C=!1;async function I(){if(C)return{localModels:m,llm:M};if(C=!0,R)return console.log("\u{1F4E1} HTTPS detected - local LLM endpoints disabled. Use HTTP for local LLM support."),{localModels:null,llm:null};try{m=new y,await m.audit(),M=E(m)}catch(e){console.warn("\u26A0\uFE0F Could not connect to local LLM:",e)}return{localModels:m,llm:M}}async function B(){let{localModels:e,llm:t}=await I();return{vector:t?{embed:t.embed}:void 0,store:w(),llmBattery:t,models:e}}async function W(){return B()}var X={store:w(),llmBattery:null,vector:void 0,models:null};export{y as LocalModels,X as batteries,B as getBatteries,E as getLLMCapability,W as getStandardCapabilities,w as getStoreCapabilityDefault};
1
+ var S=new Map,p=new Map;function k(e,t){if(e.length!==t.length)throw new Error("Vectors must have the same length for cosine similarity.");let n=0,o=0,s=0;for(let r=0;r<e.length;r++)n+=e[r]*t[r],o+=e[r]*e[r],s+=t[r]*t[r];return o=Math.sqrt(o),s=Math.sqrt(s),o===0||s===0?0:n/(o*s)}function w(){return{async get(e){return S.get(e)},async set(e,t){S.set(e,t)},async createCollection(e,t,n){p.has(e)&&console.warn(`Collection '${e}' already exists. Overwriting.`),p.set(e,[])},async vectorAdd(e,t){let n=p.get(e);if(!n)throw new Error(`Collection '${e}' not found. Create it first.`);if(!t.embedding||!Array.isArray(t.embedding))throw new Error("Document must have an 'embedding' property that is an array of numbers.");n.push(t)},async vectorSearch(e,t,n=5){let o=p.get(e);if(!o)throw new Error(`Collection '${e}' not found. Create it first.`);let s=o.map(r=>({doc:r,score:k(t,r.embedding)}));return s.sort((r,i)=>i.score-r.score),s.slice(0,n).map(r=>r.doc)}}}function O(e){if(typeof e=="string")return{role:"user",content:e};let t=[{type:"text",text:e.text}];for(let n of e.images||[])t.push({type:"image_url",image_url:{url:n}});return{role:"user",content:t}}var P="http://localhost:1234/v1";function E(e,t=P){return{async predict(n,o,s,r){try{let i=r?e.getStructuredLLM():e.getLLM(),l=[{role:"system",content:n},O(o)],a=await fetch(`${t}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:i.id,messages:l,temperature:.7,...s&&s.length>0?{tools:s}:{},response_format:r})});if(!a.ok)throw new Error(`LLM Error: ${a.status} ${a.statusText}`);return(await a.json()).choices[0]?.message??{content:""}}catch(i){throw i.cause?.code==="ECONNREFUSED"?new Error("No LLM provider configured. Please start LM Studio or provide an API key.",{cause:i}):i}},async embed(n){try{let o=e.getEmbedding(),s=await fetch(`${t}/embeddings`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:o.id,input:n})});if(!s.ok)throw new Error(`Embedding Error: ${s.status}`);return(await s.json()).data[0]?.embedding??[]}catch(o){throw o.cause?.code==="ECONNREFUSED"?new Error("No LLM provider configured. Please start LM Studio or provide an API key.",{cause:o}):o}}}}var h=".models.cache.json";var c=typeof window<"u"&&typeof window.localStorage<"u";async function _(e){try{if(c){let t=window.localStorage.getItem(h);if(!t)return null;let n=JSON.parse(t);return n.baseUrl!==e||Date.now()-n.timestamp>864e5?null:n.models}else{let t=await import("node:fs/promises"),o=(await import("node:path")).join(process.cwd(),h);try{let s=await t.readFile(o,"utf-8"),r=JSON.parse(s);return r.baseUrl!==e||Date.now()-r.timestamp>864e5?null:r.models}catch{return null}}}catch(t){return console.warn("\u26A0\uFE0F Error reading model cache:",t),null}}async function N(e,t){let n={timestamp:Date.now(),baseUrl:e,models:t};try{if(c)window.localStorage.setItem(h,JSON.stringify(n));else{let o=await import("node:fs/promises"),r=(await import("node:path")).join(process.cwd(),h);await o.writeFile(r,JSON.stringify(n,null,2))}}catch(o){console.error("\u274C Error writing model cache:",o)}}var u=async(e,t)=>{let n=new AbortController,o=setTimeout(()=>n.abort(),6e4);try{let s=await fetch(e,{...t,signal:n.signal});return clearTimeout(o),s}catch(s){throw clearTimeout(o),s}};async function v(e,t){try{let n={type:"json_schema",json_schema:{name:"test",strict:!1,schema:{type:"object",properties:{status:{type:"string"}}}}},o=await u(`${e}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:t,messages:[{role:"system",content:"You respond in JSON."},{role:"user",content:'Return JSON: {"status": "ok"}'}],response_format:n,max_tokens:20})});if(!o.ok)return o.status===400?x(e,t):{ok:!1,msg:`HTTP ${o.status}`};let s=await o.json();return JSON.parse(s.choices[0].message.content),{ok:!0,msg:"OK (Schema)"}}catch(n){return{ok:!1,msg:n.message||"Error"}}}async function x(e,t){try{return(await u(`${e}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:t,messages:[{role:"user",content:'JSON: {"a":1}'}],response_format:{type:"json_object"},max_tokens:10})})).ok?{ok:!0,msg:"OK (Legacy Mode)"}:{ok:!1,msg:"Not Supported"}}catch{return{ok:!1,msg:"Legacy Fail"}}}async function D(e,t){try{return(await u(`${e}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:t,messages:[{role:"user",content:"hi"}],max_tokens:1})})).ok}catch{return!1}}async function j(e,t){try{let n=await u(`${e}/embeddings`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:t,input:"test"})});return n.ok?(await n.json()).data[0]?.embedding?.length??null:null}catch{return null}}var J="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg==";async function $(e,t){try{return(await u(`${e}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:t,messages:[{role:"user",content:[{type:"text",text:"What color is this?"},{type:"image_url",image_url:{url:J}}]}],max_tokens:10})})).ok}catch{return!1}}async function A(e){let t=await _(e),n;try{let i=await fetch(`${e}/models`);if(!i.ok)throw new Error("Could not connect");n=(await i.json()).data.map(a=>a.id).sort()}catch{return t?(console.log("\u26A0\uFE0F LM Studio unavailable, using cached model audit."),t):(console.error("\u274C Failed to connect to LM Studio."),[])}if(t){let i=t.map(l=>l.id).sort();if(JSON.stringify(n)===JSON.stringify(i))return console.log("\u2705 Using cached model audit."),t;console.log("\u{1F50D} Model list changed. Re-running audit...")}console.log("\u{1F50D} Scanning models (this may take a moment)...");let o=[],s=n.map(i=>({id:i})),r;c||(r=await import("node:readline"));for(let i of s){!c&&r&&(r.cursorTo(process.stdout,0),process.stdout.write(`\u{1F449} Testing: ${i.id}...`),r.clearLine(process.stdout,1));let l="Unknown",a=!1,g=!1,d,b,T=await D(e,i.id),f=await j(e,i.id);if(f&&(b=f),T){l="LLM";let L=await v(e,i.id);a=L.ok,g=await $(e,i.id),d=a?L.msg:`Fail: ${L.msg}`,g&&(d+=" +Vision")}else f?(l="Embedding",d=`OK (Dim: ${f})`):d="LLM Fail";o.push({id:i.id,type:l,structuredOutput:a,vision:g,dimension:b,status:d})}return!c&&r&&(r.cursorTo(process.stdout,0),r.clearLine(process.stdout,0)),console.log(`
2
+ `),console.table(o),await N(e,o),console.log("\u{1F4DD} Audit results saved to cache."),o}var U="http://localhost:1234/v1",y=class{constructor(t=U){this.baseUrl=t}baseUrl;models=[];defaultLLM=null;defaultEmbedding=null;defaultStructuredLLM=null;async audit(){this.models=await A(this.baseUrl),this.selectDefaults()}selectDefaults(){this.defaultEmbedding=this.models.find(t=>t.type==="Embedding")||null,this.defaultLLM=this.models.find(t=>t.type==="LLM")||null,this.defaultStructuredLLM=this.models.find(t=>t.type==="LLM"&&t.structuredOutput)||null,this.defaultEmbedding||console.warn("\u26A0\uFE0F No embedding model found."),this.defaultLLM||console.warn("\u26A0\uFE0F No LLM found."),this.defaultStructuredLLM||console.warn("\u26A0\uFE0F No LLM with structured output support found.")}getModels(){return this.models}_setDefaultModel(t,n,o,s){let r=this.models.find(i=>i.id===t&&o(i));if(!r)throw new Error(`Model '${t}' not found or is not ${s}.`);this[n]=r}setDefaultLLM(t){this._setDefaultModel(t,"defaultLLM",n=>n.type==="LLM","an LLM")}setDefaultEmbedding(t){this._setDefaultModel(t,"defaultEmbedding",n=>n.dimension!==void 0,"an embedding model")}setDefaultStructuredLLM(t){this._setDefaultModel(t,"defaultStructuredLLM",n=>n.type==="LLM"&&n.structuredOutput,"a structured-output LLM")}getLLM(){if(!this.defaultLLM)throw new Error("No LLM available.");return this.defaultLLM}getEmbedding(){if(!this.defaultEmbedding)throw new Error("No embedding model available.");return this.defaultEmbedding}getStructuredLLM(){if(!this.defaultStructuredLLM)throw new Error("No structured-output LLM available.");return this.defaultStructuredLLM}};var F=typeof window<"u",R=F&&window.location.protocol==="https:",m=null,M=null,C=!1;async function I(){if(C)return{localModels:m,llm:M};if(C=!0,R)return console.log("\u{1F4E1} HTTPS detected - local LLM endpoints disabled. Use HTTP for local LLM support."),{localModels:null,llm:null};try{m=new y,await m.audit(),M=E(m)}catch(e){console.warn("\u26A0\uFE0F Could not connect to local LLM:",e)}return{localModels:m,llm:M}}async function B(){let{localModels:e,llm:t}=await I();return{vector:t?{embed:t.embed}:void 0,store:w(),llmBattery:t,models:e}}async function W(){return B()}var X={store:w(),llmBattery:null,vector:void 0,models:null};export{y as LocalModels,X as batteries,B as getBatteries,E as getLLMCapability,W as getStandardCapabilities,w as getStoreCapabilityDefault};
3
3
  //# sourceMappingURL=tjs-batteries.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/batteries/store.ts", "../src/batteries/llm.ts", "../src/batteries/audit.ts", "../src/batteries/models.ts", "../src/batteries/index.ts"],
4
- "sourcesContent": ["/**\n * Store Capability Battery\n * Provides Key-Value storage and lightweight in-memory Vector Search.\n */\n\nexport interface StoreCapability {\n get(key: string): Promise<any>\n set(key: string, val: any): Promise<void>\n createCollection(\n name: string,\n schema?: any,\n dimension?: number\n ): Promise<void>\n vectorAdd(collection: string, doc: any): Promise<void>\n vectorSearch(collection: string, vector: number[], k?: number): Promise<any[]>\n}\n\n// In-memory KV store fallback\nconst kvStore = new Map<string, any>()\n// In-memory Vector store fallback\nconst collections = new Map<string, any[]>()\n\nexport function cosineSimilarity(vecA: number[], vecB: number[]): number {\n if (vecA.length !== vecB.length) {\n throw new Error('Vectors must have the same length for cosine similarity.')\n }\n let dotProduct = 0\n let magA = 0\n let magB = 0\n for (let i = 0; i < vecA.length; i++) {\n dotProduct += vecA[i] * vecB[i]\n magA += vecA[i] * vecA[i]\n magB += vecB[i] * vecB[i]\n }\n magA = Math.sqrt(magA)\n magB = Math.sqrt(magB)\n if (magA === 0 || magB === 0) {\n return 0\n }\n return dotProduct / (magA * magB)\n}\n\nexport function getStoreCapability(): StoreCapability {\n return {\n async get(key: string) {\n return kvStore.get(key)\n },\n\n async set(key: string, val: any) {\n kvStore.set(key, val)\n },\n\n async createCollection(name: string, _schema?: any, _dimension?: number) {\n if (collections.has(name)) {\n console.warn(`Collection '${name}' already exists. Overwriting.`)\n }\n collections.set(name, [])\n },\n\n async vectorAdd(collection: string, doc: any) {\n const db = collections.get(collection)\n if (!db)\n throw new Error(\n `Collection '${collection}' not found. Create it first.`\n )\n if (!doc.embedding || !Array.isArray(doc.embedding)) {\n throw new Error(\n \"Document must have an 'embedding' property that is an array of numbers.\"\n )\n }\n db.push(doc)\n },\n\n async vectorSearch(collection: string, vector: number[], k = 5) {\n const db = collections.get(collection)\n if (!db)\n throw new Error(\n `Collection '${collection}' not found. Create it first.`\n )\n\n const scoredDocs = db.map((doc) => ({\n doc,\n score: cosineSimilarity(vector, doc.embedding),\n }))\n\n scoredDocs.sort((a, b) => b.score - a.score)\n\n return scoredDocs.slice(0, k).map((item) => item.doc)\n },\n }\n}\n", "import { LocalModels } from './models'\n\n/**\n * LLM Capability Battery\n * Bridges to local LM Studio instance via HTTP.\n */\n\n/**\n * User content can be a simple string or multimodal with images.\n * Images should be URLs or data URIs (data:image/...;base64,...)\n */\nexport type UserContent = string | { text: string; images?: string[] }\n\nexport interface LLMCapability {\n predict(\n system: string,\n user: UserContent,\n tools?: any[],\n responseFormat?: any\n ): Promise<any>\n embed(text: string): Promise<number[]>\n}\n\n/**\n * Build user message content - supports text-only or multimodal (text + images)\n */\nfunction buildUserMessage(user: UserContent): { role: string; content: any } {\n if (typeof user === 'string') {\n return { role: 'user', content: user }\n }\n\n // Multimodal: array of content blocks (OpenAI vision format)\n const content: any[] = [{ type: 'text', text: user.text }]\n\n for (const img of user.images || []) {\n content.push({\n type: 'image_url',\n image_url: {\n url: img, // Can be URL or data:image/...;base64,...\n },\n })\n }\n\n return { role: 'user', content }\n}\n\nconst DEFAULT_BASE_URL = 'http://localhost:1234/v1'\n\nexport function getLLMCapability(\n models: LocalModels,\n baseUrl = DEFAULT_BASE_URL\n): LLMCapability {\n return {\n async predict(\n system: string,\n user: UserContent,\n tools?: any[],\n responseFormat?: any\n ): Promise<any> {\n try {\n const model = responseFormat\n ? models.getStructuredLLM()\n : models.getLLM()\n const messages = [\n { role: 'system', content: system },\n buildUserMessage(user),\n ]\n\n const response = await fetch(`${baseUrl}/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: model.id,\n messages,\n temperature: 0.7,\n tools,\n response_format: responseFormat,\n }),\n })\n\n if (!response.ok) {\n throw new Error(\n `LLM Error: ${response.status} ${response.statusText}`\n )\n }\n\n const data = await response.json()\n return data.choices[0]?.message ?? { content: '' }\n } catch (e: any) {\n if (e.cause?.code === 'ECONNREFUSED') {\n throw new Error(\n 'No LLM provider configured. Please start LM Studio or provide an API key.'\n )\n }\n throw e\n }\n },\n\n async embed(text: string): Promise<number[]> {\n try {\n const model = models.getEmbedding()\n const response = await fetch(`${baseUrl}/embeddings`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: model.id,\n input: text,\n }),\n })\n\n if (!response.ok) {\n throw new Error(`Embedding Error: ${response.status}`)\n }\n\n const data = await response.json()\n return data.data[0]?.embedding ?? []\n } catch (e: any) {\n if (e.cause?.code === 'ECONNREFUSED') {\n throw new Error(\n 'No LLM provider configured. Please start LM Studio or provide an API key.'\n )\n }\n throw e\n }\n },\n }\n}\n", "const TIMEOUT_MS = 60000\nconst CACHE_FILE = '.models.cache.json'\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000 // 24 hours\n\nexport interface ModelAudit {\n id: string\n type: 'LLM' | 'Embedding' | 'Unknown'\n structuredOutput: boolean\n vision: boolean\n dimension?: number\n status: string\n}\n\ninterface CacheData {\n timestamp: number\n baseUrl: string\n models: ModelAudit[]\n}\n\nconst isBrowser =\n typeof window !== 'undefined' && typeof window.localStorage !== 'undefined'\n\nasync function readCache(baseUrl: string): Promise<ModelAudit[] | null> {\n try {\n if (isBrowser) {\n const cached = window.localStorage.getItem(CACHE_FILE)\n if (!cached) return null\n const data: CacheData = JSON.parse(cached)\n // Check TTL and baseUrl match\n if (data.baseUrl !== baseUrl) return null\n if (Date.now() - data.timestamp > CACHE_TTL_MS) return null\n return data.models\n } else {\n // Node.js: read from file\n const fs = await import('node:fs/promises')\n const path = await import('node:path')\n const cacheFile = path.join(process.cwd(), CACHE_FILE)\n try {\n const content = await fs.readFile(cacheFile, 'utf-8')\n const data: CacheData = JSON.parse(content)\n // Check TTL and baseUrl match\n if (data.baseUrl !== baseUrl) return null\n if (Date.now() - data.timestamp > CACHE_TTL_MS) return null\n return data.models\n } catch {\n return null // File doesn't exist or can't be read\n }\n }\n } catch (e) {\n console.warn('\u26A0\uFE0F Error reading model cache:', e)\n return null\n }\n}\n\nasync function writeCache(\n baseUrl: string,\n models: ModelAudit[]\n): Promise<void> {\n const data: CacheData = {\n timestamp: Date.now(),\n baseUrl,\n models,\n }\n try {\n if (isBrowser) {\n window.localStorage.setItem(CACHE_FILE, JSON.stringify(data))\n } else {\n // Node.js: write to file\n const fs = await import('node:fs/promises')\n const path = await import('node:path')\n const cacheFile = path.join(process.cwd(), CACHE_FILE)\n await fs.writeFile(cacheFile, JSON.stringify(data, null, 2))\n }\n } catch (e) {\n console.error('\u274C Error writing model cache:', e)\n }\n}\n\n// ... (fetchWithTimeout, checkStructured, etc. remain the same)\nconst fetchWithTimeout = async (url: string, options: RequestInit) => {\n const controller = new AbortController()\n const id = setTimeout(() => controller.abort(), TIMEOUT_MS)\n try {\n const res = await fetch(url, { ...options, signal: controller.signal })\n clearTimeout(id)\n return res\n } catch (error) {\n clearTimeout(id)\n throw error\n }\n}\n\nasync function checkStructured(\n baseUrl: string,\n modelId: string\n): Promise<{ ok: boolean; msg?: string }> {\n try {\n const schemaPayload = {\n type: 'json_schema',\n json_schema: {\n name: 'test',\n strict: false,\n schema: {\n type: 'object',\n properties: { status: { type: 'string' } },\n },\n },\n }\n const res = await fetchWithTimeout(`${baseUrl}/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: modelId,\n messages: [\n { role: 'system', content: 'You respond in JSON.' },\n { role: 'user', content: 'Return JSON: {\"status\": \"ok\"}' },\n ],\n response_format: schemaPayload,\n max_tokens: 20,\n }),\n })\n if (!res.ok) {\n if (res.status === 400) {\n return checkStructuredLegacy(baseUrl, modelId)\n }\n return { ok: false, msg: `HTTP ${res.status}` }\n }\n const data = await res.json()\n JSON.parse(data.choices[0].message.content)\n return { ok: true, msg: 'OK (Schema)' }\n } catch (e: any) {\n return { ok: false, msg: e.message || 'Error' }\n }\n}\n\nasync function checkStructuredLegacy(\n baseUrl: string,\n modelId: string\n): Promise<{ ok: boolean; msg?: string }> {\n try {\n const res = await fetchWithTimeout(`${baseUrl}/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: modelId,\n messages: [{ role: 'user', content: 'JSON: {\"a\":1}' }],\n response_format: { type: 'json_object' },\n max_tokens: 10,\n }),\n })\n if (res.ok) return { ok: true, msg: 'OK (Legacy Mode)' }\n return { ok: false, msg: 'Not Supported' }\n } catch {\n return { ok: false, msg: 'Legacy Fail' }\n }\n}\n\nasync function checkLLM(baseUrl: string, modelId: string): Promise<boolean> {\n try {\n const res = await fetchWithTimeout(`${baseUrl}/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: modelId,\n messages: [{ role: 'user', content: 'hi' }],\n max_tokens: 1,\n }),\n })\n return res.ok\n } catch {\n return false\n }\n}\n\nasync function checkEmbedding(\n baseUrl: string,\n modelId: string\n): Promise<number | null> {\n try {\n const res = await fetchWithTimeout(`${baseUrl}/embeddings`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ model: modelId, input: 'test' }),\n })\n if (!res.ok) return null\n const data = await res.json()\n return data.data[0]?.embedding?.length ?? null\n } catch {\n return null\n }\n}\n\n// Tiny 1x1 red PNG as base64 for vision testing\nconst TINY_TEST_IMAGE =\n 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg=='\n\nasync function checkVision(baseUrl: string, modelId: string): Promise<boolean> {\n try {\n const res = await fetchWithTimeout(`${baseUrl}/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: modelId,\n messages: [\n {\n role: 'user',\n content: [\n { type: 'text', text: 'What color is this?' },\n { type: 'image_url', image_url: { url: TINY_TEST_IMAGE } },\n ],\n },\n ],\n max_tokens: 10,\n }),\n })\n // If the model accepts the multimodal format without error, it supports vision\n return res.ok\n } catch {\n return false\n }\n}\n\nexport async function auditModels(baseUrl: string): Promise<ModelAudit[]> {\n // 1. Try to load from cache first (file-based with 24h TTL)\n const cachedData = await readCache(baseUrl)\n\n // 2. Get current model list from server\n let serverModelIds: string[] = []\n try {\n const res = await fetch(`${baseUrl}/models`)\n if (!res.ok) throw new Error('Could not connect')\n const data = (await res.json()) as { data: { id: string }[] }\n serverModelIds = data.data.map((m) => m.id).sort()\n } catch (e) {\n // If we have cache and server is unavailable, use cache\n if (cachedData) {\n console.log('\u26A0\uFE0F LM Studio unavailable, using cached model audit.')\n return cachedData\n }\n console.error('\u274C Failed to connect to LM Studio.')\n return []\n }\n\n // 3. Check if cache is still valid (same models)\n if (cachedData) {\n const cachedModelIds = cachedData.map((m) => m.id).sort()\n if (JSON.stringify(serverModelIds) === JSON.stringify(cachedModelIds)) {\n console.log('\u2705 Using cached model audit.')\n return cachedData\n }\n console.log('\uD83D\uDD0D Model list changed. Re-running audit...')\n }\n\n // 4. Run full audit\n console.log('\uD83D\uDD0D Scanning models (this may take a moment)...')\n const results: ModelAudit[] = []\n const modelList = serverModelIds.map((id) => ({ id }))\n\n let readline: typeof import('node:readline') | undefined\n if (!isBrowser) {\n readline = await import('node:readline')\n }\n\n for (const model of modelList) {\n if (!isBrowser && readline) {\n readline.cursorTo(process.stdout, 0)\n process.stdout.write(`\uD83D\uDC49 Testing: ${model.id}...`)\n readline.clearLine(process.stdout, 1)\n }\n let type: ModelAudit['type'] = 'Unknown'\n let structured = false\n let vision = false\n let statusMsg = ''\n let dimension: number | undefined = undefined\n\n const isLLM = await checkLLM(baseUrl, model.id)\n const dim = await checkEmbedding(baseUrl, model.id)\n\n if (dim) {\n dimension = dim\n }\n\n if (isLLM) {\n type = 'LLM'\n const structRes = await checkStructured(baseUrl, model.id)\n structured = structRes.ok\n vision = await checkVision(baseUrl, model.id)\n statusMsg = structured ? structRes.msg! : `Fail: ${structRes.msg}`\n if (vision) statusMsg += ' +Vision'\n } else if (dim) {\n type = 'Embedding'\n statusMsg = `OK (Dim: ${dim})`\n } else {\n statusMsg = 'LLM Fail'\n }\n\n results.push({\n id: model.id,\n type,\n structuredOutput: structured,\n vision,\n dimension,\n status: statusMsg,\n })\n }\n if (!isBrowser && readline) {\n readline.cursorTo(process.stdout, 0)\n readline.clearLine(process.stdout, 0)\n }\n\n console.log('\\n')\n console.table(results)\n\n // 5. Save to cache\n await writeCache(baseUrl, results)\n console.log(`\uD83D\uDCDD Audit results saved to cache.`)\n\n return results\n}\n", "import { auditModels, type ModelAudit } from './audit'\n\nconst DEFAULT_BASE_URL = 'http://localhost:1234/v1'\n\nexport class LocalModels {\n private models: ModelAudit[] = []\n private defaultLLM: ModelAudit | null = null\n private defaultEmbedding: ModelAudit | null = null\n private defaultStructuredLLM: ModelAudit | null = null\n\n constructor(private baseUrl = DEFAULT_BASE_URL) {}\n\n async audit() {\n this.models = await auditModels(this.baseUrl)\n this.selectDefaults()\n }\n\n private selectDefaults() {\n this.defaultEmbedding =\n this.models.find((m) => m.type === 'Embedding') || null\n this.defaultLLM = this.models.find((m) => m.type === 'LLM') || null\n this.defaultStructuredLLM =\n this.models.find((m) => m.type === 'LLM' && m.structuredOutput) || null\n\n if (!this.defaultEmbedding) {\n console.warn('\u26A0\uFE0F No embedding model found.')\n }\n if (!this.defaultLLM) {\n console.warn('\u26A0\uFE0F No LLM found.')\n }\n if (!this.defaultStructuredLLM) {\n console.warn('\u26A0\uFE0F No LLM with structured output support found.')\n }\n }\n\n getModels() {\n return this.models\n }\n\n private _setDefaultModel(\n modelId: string,\n property: 'defaultLLM' | 'defaultEmbedding' | 'defaultStructuredLLM',\n predicate: (model: ModelAudit) => boolean,\n errorType: string\n ) {\n const model = this.models.find((m) => m.id === modelId && predicate(m))\n if (!model) {\n throw new Error(`Model '${modelId}' not found or is not ${errorType}.`)\n }\n this[property] = model\n }\n\n setDefaultLLM(modelId: string) {\n this._setDefaultModel(\n modelId,\n 'defaultLLM',\n (m) => m.type === 'LLM',\n 'an LLM'\n )\n }\n\n setDefaultEmbedding(modelId: string) {\n this._setDefaultModel(\n modelId,\n 'defaultEmbedding',\n (m) => m.dimension !== undefined,\n 'an embedding model'\n )\n }\n\n setDefaultStructuredLLM(modelId: string) {\n this._setDefaultModel(\n modelId,\n 'defaultStructuredLLM',\n (m) => m.type === 'LLM' && m.structuredOutput,\n 'a structured-output LLM'\n )\n }\n\n getLLM() {\n if (!this.defaultLLM) {\n throw new Error('No LLM available.')\n }\n return this.defaultLLM\n }\n\n getEmbedding() {\n if (!this.defaultEmbedding) {\n throw new Error('No embedding model available.')\n }\n return this.defaultEmbedding\n }\n\n getStructuredLLM() {\n if (!this.defaultStructuredLLM) {\n throw new Error('No structured-output LLM available.')\n }\n return this.defaultStructuredLLM\n }\n}\n", "import { getStoreCapability as getStoreCapabilityDefault } from './store'\nimport { getLLMCapability } from './llm'\nimport { LocalModels } from './models'\n\n// Check if we're in a browser on HTTPS (can't connect to local HTTP endpoints)\nconst isBrowser = typeof window !== 'undefined'\nconst isHttps = isBrowser && window.location.protocol === 'https:'\n\n// Lazy initialization - don't audit on import\nlet localModels: LocalModels | null = null\nlet llm: ReturnType<typeof getLLMCapability> | null = null\nlet initializationAttempted = false\n\nasync function ensureInitialized() {\n if (initializationAttempted) {\n return { localModels, llm }\n }\n initializationAttempted = true\n\n // Skip local LLM initialization on HTTPS (mixed content would block it anyway)\n if (isHttps) {\n console.log(\n '\uD83D\uDCE1 HTTPS detected - local LLM endpoints disabled. Use HTTP for local LLM support.'\n )\n return { localModels: null, llm: null }\n }\n\n try {\n localModels = new LocalModels()\n await localModels.audit()\n llm = getLLMCapability(localModels)\n } catch (e) {\n console.warn('\u26A0\uFE0F Could not connect to local LLM:', e)\n }\n return { localModels, llm }\n}\n\nexport async function getBatteries() {\n const { localModels, llm } = await ensureInitialized()\n return {\n vector: llm ? { embed: llm.embed } : undefined,\n store: getStoreCapabilityDefault(),\n llmBattery: llm,\n models: localModels,\n }\n}\n\nexport async function getStandardCapabilities() {\n return getBatteries()\n}\n\n// For non-async access (after initialization)\nexport { LocalModels, getLLMCapability, getStoreCapabilityDefault }\n\n// Synchronous batteries object for tests and simple use cases\nexport const batteries = {\n store: getStoreCapabilityDefault(),\n llmBattery: null as ReturnType<typeof getLLMCapability> | null,\n vector: undefined as\n | { embed: (text: string) => Promise<number[]> }\n | undefined,\n models: null as LocalModels | null,\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Store Capability Battery\n * Provides Key-Value storage and lightweight in-memory Vector Search.\n */\n\nexport interface StoreCapability {\n get(key: string): Promise<any>\n set(key: string, val: any): Promise<void>\n createCollection(\n name: string,\n schema?: any,\n dimension?: number\n ): Promise<void>\n vectorAdd(collection: string, doc: any): Promise<void>\n vectorSearch(collection: string, vector: number[], k?: number): Promise<any[]>\n}\n\n// In-memory KV store fallback\nconst kvStore = new Map<string, any>()\n// In-memory Vector store fallback\nconst collections = new Map<string, any[]>()\n\nexport function cosineSimilarity(vecA: number[], vecB: number[]): number {\n if (vecA.length !== vecB.length) {\n throw new Error('Vectors must have the same length for cosine similarity.')\n }\n let dotProduct = 0\n let magA = 0\n let magB = 0\n for (let i = 0; i < vecA.length; i++) {\n dotProduct += vecA[i] * vecB[i]\n magA += vecA[i] * vecA[i]\n magB += vecB[i] * vecB[i]\n }\n magA = Math.sqrt(magA)\n magB = Math.sqrt(magB)\n if (magA === 0 || magB === 0) {\n return 0\n }\n return dotProduct / (magA * magB)\n}\n\nexport function getStoreCapability(): StoreCapability {\n return {\n async get(key: string) {\n return kvStore.get(key)\n },\n\n async set(key: string, val: any) {\n kvStore.set(key, val)\n },\n\n async createCollection(name: string, _schema?: any, _dimension?: number) {\n if (collections.has(name)) {\n console.warn(`Collection '${name}' already exists. Overwriting.`)\n }\n collections.set(name, [])\n },\n\n async vectorAdd(collection: string, doc: any) {\n const db = collections.get(collection)\n if (!db)\n throw new Error(\n `Collection '${collection}' not found. Create it first.`\n )\n if (!doc.embedding || !Array.isArray(doc.embedding)) {\n throw new Error(\n \"Document must have an 'embedding' property that is an array of numbers.\"\n )\n }\n db.push(doc)\n },\n\n async vectorSearch(collection: string, vector: number[], k = 5) {\n const db = collections.get(collection)\n if (!db)\n throw new Error(\n `Collection '${collection}' not found. Create it first.`\n )\n\n const scoredDocs = db.map((doc) => ({\n doc,\n score: cosineSimilarity(vector, doc.embedding),\n }))\n\n scoredDocs.sort((a, b) => b.score - a.score)\n\n return scoredDocs.slice(0, k).map((item) => item.doc)\n },\n }\n}\n", "import { LocalModels } from './models'\n\n/**\n * LLM Capability Battery\n * Bridges to local LM Studio instance via HTTP.\n */\n\n/**\n * User content can be a simple string or multimodal with images.\n * Images should be URLs or data URIs (data:image/...;base64,...)\n */\nexport type UserContent = string | { text: string; images?: string[] }\n\nexport interface LLMCapability {\n predict(\n system: string,\n user: UserContent,\n tools?: any[],\n responseFormat?: any\n ): Promise<any>\n embed(text: string): Promise<number[]>\n}\n\n/**\n * Build user message content - supports text-only or multimodal (text + images)\n */\nfunction buildUserMessage(user: UserContent): { role: string; content: any } {\n if (typeof user === 'string') {\n return { role: 'user', content: user }\n }\n\n // Multimodal: array of content blocks (OpenAI vision format)\n const content: any[] = [{ type: 'text', text: user.text }]\n\n for (const img of user.images || []) {\n content.push({\n type: 'image_url',\n image_url: {\n url: img, // Can be URL or data:image/...;base64,...\n },\n })\n }\n\n return { role: 'user', content }\n}\n\nconst DEFAULT_BASE_URL = 'http://localhost:1234/v1'\n\nexport function getLLMCapability(\n models: LocalModels,\n baseUrl = DEFAULT_BASE_URL\n): LLMCapability {\n return {\n async predict(\n system: string,\n user: UserContent,\n tools?: any[],\n responseFormat?: any\n ): Promise<any> {\n try {\n const model = responseFormat\n ? models.getStructuredLLM()\n : models.getLLM()\n const messages = [\n { role: 'system', content: system },\n buildUserMessage(user),\n ]\n\n const response = await fetch(`${baseUrl}/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: model.id,\n messages,\n temperature: 0.7,\n // Only include tools when non-empty: an empty tools array makes\n // LM Studio apply a tool-call grammar that can't be combined with\n // a structured-output response_format (\"lazy grammar\" 400).\n ...(tools && tools.length > 0 ? { tools } : {}),\n response_format: responseFormat,\n }),\n })\n\n if (!response.ok) {\n throw new Error(\n `LLM Error: ${response.status} ${response.statusText}`\n )\n }\n\n const data = await response.json()\n return data.choices[0]?.message ?? { content: '' }\n } catch (e: any) {\n if (e.cause?.code === 'ECONNREFUSED') {\n throw new Error(\n 'No LLM provider configured. Please start LM Studio or provide an API key.',\n { cause: e }\n )\n }\n throw e\n }\n },\n\n async embed(text: string): Promise<number[]> {\n try {\n const model = models.getEmbedding()\n const response = await fetch(`${baseUrl}/embeddings`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: model.id,\n input: text,\n }),\n })\n\n if (!response.ok) {\n throw new Error(`Embedding Error: ${response.status}`)\n }\n\n const data = await response.json()\n return data.data[0]?.embedding ?? []\n } catch (e: any) {\n if (e.cause?.code === 'ECONNREFUSED') {\n throw new Error(\n 'No LLM provider configured. Please start LM Studio or provide an API key.',\n { cause: e }\n )\n }\n throw e\n }\n },\n }\n}\n", "const TIMEOUT_MS = 60000\nconst CACHE_FILE = '.models.cache.json'\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000 // 24 hours\n\nexport interface ModelAudit {\n id: string\n type: 'LLM' | 'Embedding' | 'Unknown'\n structuredOutput: boolean\n vision: boolean\n dimension?: number\n status: string\n}\n\ninterface CacheData {\n timestamp: number\n baseUrl: string\n models: ModelAudit[]\n}\n\nconst isBrowser =\n typeof window !== 'undefined' && typeof window.localStorage !== 'undefined'\n\nasync function readCache(baseUrl: string): Promise<ModelAudit[] | null> {\n try {\n if (isBrowser) {\n const cached = window.localStorage.getItem(CACHE_FILE)\n if (!cached) return null\n const data: CacheData = JSON.parse(cached)\n // Check TTL and baseUrl match\n if (data.baseUrl !== baseUrl) return null\n if (Date.now() - data.timestamp > CACHE_TTL_MS) return null\n return data.models\n } else {\n // Node.js: read from file\n const fs = await import('node:fs/promises')\n const path = await import('node:path')\n const cacheFile = path.join(process.cwd(), CACHE_FILE)\n try {\n const content = await fs.readFile(cacheFile, 'utf-8')\n const data: CacheData = JSON.parse(content)\n // Check TTL and baseUrl match\n if (data.baseUrl !== baseUrl) return null\n if (Date.now() - data.timestamp > CACHE_TTL_MS) return null\n return data.models\n } catch {\n return null // File doesn't exist or can't be read\n }\n }\n } catch (e) {\n console.warn('\u26A0\uFE0F Error reading model cache:', e)\n return null\n }\n}\n\nasync function writeCache(\n baseUrl: string,\n models: ModelAudit[]\n): Promise<void> {\n const data: CacheData = {\n timestamp: Date.now(),\n baseUrl,\n models,\n }\n try {\n if (isBrowser) {\n window.localStorage.setItem(CACHE_FILE, JSON.stringify(data))\n } else {\n // Node.js: write to file\n const fs = await import('node:fs/promises')\n const path = await import('node:path')\n const cacheFile = path.join(process.cwd(), CACHE_FILE)\n await fs.writeFile(cacheFile, JSON.stringify(data, null, 2))\n }\n } catch (e) {\n console.error('\u274C Error writing model cache:', e)\n }\n}\n\n// ... (fetchWithTimeout, checkStructured, etc. remain the same)\nconst fetchWithTimeout = async (url: string, options: RequestInit) => {\n const controller = new AbortController()\n const id = setTimeout(() => controller.abort(), TIMEOUT_MS)\n try {\n const res = await fetch(url, { ...options, signal: controller.signal })\n clearTimeout(id)\n return res\n } catch (error) {\n clearTimeout(id)\n throw error\n }\n}\n\nasync function checkStructured(\n baseUrl: string,\n modelId: string\n): Promise<{ ok: boolean; msg?: string }> {\n try {\n const schemaPayload = {\n type: 'json_schema',\n json_schema: {\n name: 'test',\n strict: false,\n schema: {\n type: 'object',\n properties: { status: { type: 'string' } },\n },\n },\n }\n const res = await fetchWithTimeout(`${baseUrl}/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: modelId,\n messages: [\n { role: 'system', content: 'You respond in JSON.' },\n { role: 'user', content: 'Return JSON: {\"status\": \"ok\"}' },\n ],\n response_format: schemaPayload,\n max_tokens: 20,\n }),\n })\n if (!res.ok) {\n if (res.status === 400) {\n return checkStructuredLegacy(baseUrl, modelId)\n }\n return { ok: false, msg: `HTTP ${res.status}` }\n }\n const data = await res.json()\n JSON.parse(data.choices[0].message.content)\n return { ok: true, msg: 'OK (Schema)' }\n } catch (e: any) {\n return { ok: false, msg: e.message || 'Error' }\n }\n}\n\nasync function checkStructuredLegacy(\n baseUrl: string,\n modelId: string\n): Promise<{ ok: boolean; msg?: string }> {\n try {\n const res = await fetchWithTimeout(`${baseUrl}/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: modelId,\n messages: [{ role: 'user', content: 'JSON: {\"a\":1}' }],\n response_format: { type: 'json_object' },\n max_tokens: 10,\n }),\n })\n if (res.ok) return { ok: true, msg: 'OK (Legacy Mode)' }\n return { ok: false, msg: 'Not Supported' }\n } catch {\n return { ok: false, msg: 'Legacy Fail' }\n }\n}\n\nasync function checkLLM(baseUrl: string, modelId: string): Promise<boolean> {\n try {\n const res = await fetchWithTimeout(`${baseUrl}/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: modelId,\n messages: [{ role: 'user', content: 'hi' }],\n max_tokens: 1,\n }),\n })\n return res.ok\n } catch {\n return false\n }\n}\n\nasync function checkEmbedding(\n baseUrl: string,\n modelId: string\n): Promise<number | null> {\n try {\n const res = await fetchWithTimeout(`${baseUrl}/embeddings`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ model: modelId, input: 'test' }),\n })\n if (!res.ok) return null\n const data = await res.json()\n return data.data[0]?.embedding?.length ?? null\n } catch {\n return null\n }\n}\n\n// Tiny 1x1 red PNG as base64 for vision testing\nconst TINY_TEST_IMAGE =\n 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg=='\n\nasync function checkVision(baseUrl: string, modelId: string): Promise<boolean> {\n try {\n const res = await fetchWithTimeout(`${baseUrl}/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: modelId,\n messages: [\n {\n role: 'user',\n content: [\n { type: 'text', text: 'What color is this?' },\n { type: 'image_url', image_url: { url: TINY_TEST_IMAGE } },\n ],\n },\n ],\n max_tokens: 10,\n }),\n })\n // If the model accepts the multimodal format without error, it supports vision\n return res.ok\n } catch {\n return false\n }\n}\n\nexport async function auditModels(baseUrl: string): Promise<ModelAudit[]> {\n // 1. Try to load from cache first (file-based with 24h TTL)\n const cachedData = await readCache(baseUrl)\n\n // 2. Get current model list from server\n let serverModelIds: string[]\n try {\n const res = await fetch(`${baseUrl}/models`)\n if (!res.ok) throw new Error('Could not connect')\n const data = (await res.json()) as { data: { id: string }[] }\n serverModelIds = data.data.map((m) => m.id).sort()\n } catch {\n // If we have cache and server is unavailable, use cache\n if (cachedData) {\n console.log('\u26A0\uFE0F LM Studio unavailable, using cached model audit.')\n return cachedData\n }\n console.error('\u274C Failed to connect to LM Studio.')\n return []\n }\n\n // 3. Check if cache is still valid (same models)\n if (cachedData) {\n const cachedModelIds = cachedData.map((m) => m.id).sort()\n if (JSON.stringify(serverModelIds) === JSON.stringify(cachedModelIds)) {\n console.log('\u2705 Using cached model audit.')\n return cachedData\n }\n console.log('\uD83D\uDD0D Model list changed. Re-running audit...')\n }\n\n // 4. Run full audit\n console.log('\uD83D\uDD0D Scanning models (this may take a moment)...')\n const results: ModelAudit[] = []\n const modelList = serverModelIds.map((id) => ({ id }))\n\n let readline: typeof import('node:readline') | undefined\n if (!isBrowser) {\n readline = await import('node:readline')\n }\n\n for (const model of modelList) {\n if (!isBrowser && readline) {\n readline.cursorTo(process.stdout, 0)\n process.stdout.write(`\uD83D\uDC49 Testing: ${model.id}...`)\n readline.clearLine(process.stdout, 1)\n }\n let type: ModelAudit['type'] = 'Unknown'\n let structured = false\n let vision = false\n let statusMsg: string\n let dimension: number | undefined = undefined\n\n const isLLM = await checkLLM(baseUrl, model.id)\n const dim = await checkEmbedding(baseUrl, model.id)\n\n if (dim) {\n dimension = dim\n }\n\n if (isLLM) {\n type = 'LLM'\n const structRes = await checkStructured(baseUrl, model.id)\n structured = structRes.ok\n vision = await checkVision(baseUrl, model.id)\n statusMsg = structured ? structRes.msg! : `Fail: ${structRes.msg}`\n if (vision) statusMsg += ' +Vision'\n } else if (dim) {\n type = 'Embedding'\n statusMsg = `OK (Dim: ${dim})`\n } else {\n statusMsg = 'LLM Fail'\n }\n\n results.push({\n id: model.id,\n type,\n structuredOutput: structured,\n vision,\n dimension,\n status: statusMsg,\n })\n }\n if (!isBrowser && readline) {\n readline.cursorTo(process.stdout, 0)\n readline.clearLine(process.stdout, 0)\n }\n\n console.log('\\n')\n console.table(results)\n\n // 5. Save to cache\n await writeCache(baseUrl, results)\n console.log(`\uD83D\uDCDD Audit results saved to cache.`)\n\n return results\n}\n", "import { auditModels, type ModelAudit } from './audit'\n\nconst DEFAULT_BASE_URL = 'http://localhost:1234/v1'\n\nexport class LocalModels {\n private models: ModelAudit[] = []\n private defaultLLM: ModelAudit | null = null\n private defaultEmbedding: ModelAudit | null = null\n private defaultStructuredLLM: ModelAudit | null = null\n\n constructor(private baseUrl = DEFAULT_BASE_URL) {}\n\n async audit() {\n this.models = await auditModels(this.baseUrl)\n this.selectDefaults()\n }\n\n private selectDefaults() {\n this.defaultEmbedding =\n this.models.find((m) => m.type === 'Embedding') || null\n this.defaultLLM = this.models.find((m) => m.type === 'LLM') || null\n this.defaultStructuredLLM =\n this.models.find((m) => m.type === 'LLM' && m.structuredOutput) || null\n\n if (!this.defaultEmbedding) {\n console.warn('\u26A0\uFE0F No embedding model found.')\n }\n if (!this.defaultLLM) {\n console.warn('\u26A0\uFE0F No LLM found.')\n }\n if (!this.defaultStructuredLLM) {\n console.warn('\u26A0\uFE0F No LLM with structured output support found.')\n }\n }\n\n getModels() {\n return this.models\n }\n\n private _setDefaultModel(\n modelId: string,\n property: 'defaultLLM' | 'defaultEmbedding' | 'defaultStructuredLLM',\n predicate: (model: ModelAudit) => boolean,\n errorType: string\n ) {\n const model = this.models.find((m) => m.id === modelId && predicate(m))\n if (!model) {\n throw new Error(`Model '${modelId}' not found or is not ${errorType}.`)\n }\n this[property] = model\n }\n\n setDefaultLLM(modelId: string) {\n this._setDefaultModel(\n modelId,\n 'defaultLLM',\n (m) => m.type === 'LLM',\n 'an LLM'\n )\n }\n\n setDefaultEmbedding(modelId: string) {\n this._setDefaultModel(\n modelId,\n 'defaultEmbedding',\n (m) => m.dimension !== undefined,\n 'an embedding model'\n )\n }\n\n setDefaultStructuredLLM(modelId: string) {\n this._setDefaultModel(\n modelId,\n 'defaultStructuredLLM',\n (m) => m.type === 'LLM' && m.structuredOutput,\n 'a structured-output LLM'\n )\n }\n\n getLLM() {\n if (!this.defaultLLM) {\n throw new Error('No LLM available.')\n }\n return this.defaultLLM\n }\n\n getEmbedding() {\n if (!this.defaultEmbedding) {\n throw new Error('No embedding model available.')\n }\n return this.defaultEmbedding\n }\n\n getStructuredLLM() {\n if (!this.defaultStructuredLLM) {\n throw new Error('No structured-output LLM available.')\n }\n return this.defaultStructuredLLM\n }\n}\n", "import { getStoreCapability as getStoreCapabilityDefault } from './store'\nimport { getLLMCapability } from './llm'\nimport { LocalModels } from './models'\n\n// Check if we're in a browser on HTTPS (can't connect to local HTTP endpoints)\nconst isBrowser = typeof window !== 'undefined'\nconst isHttps = isBrowser && window.location.protocol === 'https:'\n\n// Lazy initialization - don't audit on import\nlet localModels: LocalModels | null = null\nlet llm: ReturnType<typeof getLLMCapability> | null = null\nlet initializationAttempted = false\n\nasync function ensureInitialized() {\n if (initializationAttempted) {\n return { localModels, llm }\n }\n initializationAttempted = true\n\n // Skip local LLM initialization on HTTPS (mixed content would block it anyway)\n if (isHttps) {\n console.log(\n '\uD83D\uDCE1 HTTPS detected - local LLM endpoints disabled. Use HTTP for local LLM support.'\n )\n return { localModels: null, llm: null }\n }\n\n try {\n localModels = new LocalModels()\n await localModels.audit()\n llm = getLLMCapability(localModels)\n } catch (e) {\n console.warn('\u26A0\uFE0F Could not connect to local LLM:', e)\n }\n return { localModels, llm }\n}\n\nexport async function getBatteries() {\n const { localModels, llm } = await ensureInitialized()\n return {\n vector: llm ? { embed: llm.embed } : undefined,\n store: getStoreCapabilityDefault(),\n llmBattery: llm,\n models: localModels,\n }\n}\n\nexport async function getStandardCapabilities() {\n return getBatteries()\n}\n\n// For non-async access (after initialization)\nexport { LocalModels, getLLMCapability, getStoreCapabilityDefault }\n\n// Synchronous batteries object for tests and simple use cases\nexport const batteries = {\n store: getStoreCapabilityDefault(),\n llmBattery: null as ReturnType<typeof getLLMCapability> | null,\n vector: undefined as\n | { embed: (text: string) => Promise<number[]> }\n | undefined,\n models: null as LocalModels | null,\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["kvStore", "collections", "cosineSimilarity", "vecA", "vecB", "dotProduct", "magA", "magB", "i", "getStoreCapability", "key", "val", "name", "_schema", "_dimension", "collection", "doc", "db", "vector", "k", "scoredDocs", "a", "b", "item", "buildUserMessage", "user", "content", "img", "DEFAULT_BASE_URL", "getLLMCapability", "models", "baseUrl", "system", "tools", "responseFormat", "model", "messages", "response", "e", "text", "CACHE_FILE", "isBrowser", "readCache", "baseUrl", "cached", "CACHE_FILE", "data", "fs", "cacheFile", "content", "e", "writeCache", "models", "fetchWithTimeout", "url", "options", "controller", "id", "res", "error", "checkStructured", "modelId", "schemaPayload", "checkStructuredLegacy", "checkLLM", "checkEmbedding", "TINY_TEST_IMAGE", "checkVision", "auditModels", "cachedData", "serverModelIds", "m", "cachedModelIds", "results", "modelList", "readline", "model", "type", "structured", "vision", "statusMsg", "dimension", "isLLM", "dim", "structRes", "DEFAULT_BASE_URL", "LocalModels", "baseUrl", "auditModels", "m", "modelId", "property", "predicate", "errorType", "model", "isBrowser", "isHttps", "localModels", "llm", "initializationAttempted", "ensureInitialized", "LocalModels", "getLLMCapability", "getBatteries", "getStoreCapability", "getStandardCapabilities", "batteries", "getStoreCapability"]
7
7
  }