wllama-service 2.0.4 → 2.0.6

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.
package/dist/index.d.mts CHANGED
@@ -13,6 +13,8 @@ interface GenerateRequest {
13
13
  temperature?: number;
14
14
  topK?: number;
15
15
  topP?: number;
16
+ stop?: string | string[];
17
+ abortSignal?: AbortSignal;
16
18
  }
17
19
  interface GenerateResult {
18
20
  success: boolean;
@@ -35,22 +37,38 @@ interface ConnectionResult {
35
37
  declare class WllamaService {
36
38
  private wllama;
37
39
  private modelName;
38
- private config;
40
+ private readonly config;
39
41
  constructor(config?: WllamaServiceConfig);
40
- /** Check browser compatibility and capabilities */
42
+ /**
43
+ * Check WebGPU without directly accessing navigator.gpu.
44
+ *
45
+ * This avoids requiring @webgpu/types merely for feature detection.
46
+ */
47
+ private hasWebGPU;
48
+ /** Check browser compatibility and capabilities. */
41
49
  checkEnvironment(): ConnectionResult;
42
- /** Load a GGUF model file from the user's filesystem */
50
+ /** Load a GGUF model file from the user's filesystem. */
43
51
  loadModel(file: File, onProgress?: (progress: number) => void): Promise<LoadModelResult>;
44
- /** Generate a response from the loaded model */
52
+ /**
53
+ * Generate a chat response using the model's embedded chat template.
54
+ *
55
+ * Suitable for instruction-tuned models such as Phi-3 Instruct,
56
+ * Llama Instruct, ChatML models, and similar chat models.
57
+ */
45
58
  generate(req: GenerateRequest): Promise<GenerateResult>;
46
- /** Unload the current model and free memory */
59
+ /**
60
+ * Generate a raw completion without applying a chat template.
61
+ *
62
+ * Suitable for base completion models, manually formatted prompts,
63
+ * few-shot completion, fill-in-the-middle, and custom templates.
64
+ */
65
+ generateCompletion(req: GenerateRequest): Promise<GenerateResult>;
66
+ /** Unload the current model and release its resources. */
47
67
  unload(): Promise<void>;
48
- /** Whether a model is currently loaded */
68
+ /** Whether a model is currently loaded. */
49
69
  get isLoaded(): boolean;
50
- /** Name of the currently loaded model */
70
+ /** Name of the currently loaded model. */
51
71
  get currentModel(): string;
52
- private storeInCache;
53
- private deleteFromCache;
54
72
  }
55
73
 
56
74
  export { type ConnectionResult, type GenerateRequest, type GenerateResult, type LoadModelResult, WllamaService, type WllamaServiceConfig };
package/dist/index.d.ts CHANGED
@@ -13,6 +13,8 @@ interface GenerateRequest {
13
13
  temperature?: number;
14
14
  topK?: number;
15
15
  topP?: number;
16
+ stop?: string | string[];
17
+ abortSignal?: AbortSignal;
16
18
  }
17
19
  interface GenerateResult {
18
20
  success: boolean;
@@ -35,22 +37,38 @@ interface ConnectionResult {
35
37
  declare class WllamaService {
36
38
  private wllama;
37
39
  private modelName;
38
- private config;
40
+ private readonly config;
39
41
  constructor(config?: WllamaServiceConfig);
40
- /** Check browser compatibility and capabilities */
42
+ /**
43
+ * Check WebGPU without directly accessing navigator.gpu.
44
+ *
45
+ * This avoids requiring @webgpu/types merely for feature detection.
46
+ */
47
+ private hasWebGPU;
48
+ /** Check browser compatibility and capabilities. */
41
49
  checkEnvironment(): ConnectionResult;
42
- /** Load a GGUF model file from the user's filesystem */
50
+ /** Load a GGUF model file from the user's filesystem. */
43
51
  loadModel(file: File, onProgress?: (progress: number) => void): Promise<LoadModelResult>;
44
- /** Generate a response from the loaded model */
52
+ /**
53
+ * Generate a chat response using the model's embedded chat template.
54
+ *
55
+ * Suitable for instruction-tuned models such as Phi-3 Instruct,
56
+ * Llama Instruct, ChatML models, and similar chat models.
57
+ */
45
58
  generate(req: GenerateRequest): Promise<GenerateResult>;
46
- /** Unload the current model and free memory */
59
+ /**
60
+ * Generate a raw completion without applying a chat template.
61
+ *
62
+ * Suitable for base completion models, manually formatted prompts,
63
+ * few-shot completion, fill-in-the-middle, and custom templates.
64
+ */
65
+ generateCompletion(req: GenerateRequest): Promise<GenerateResult>;
66
+ /** Unload the current model and release its resources. */
47
67
  unload(): Promise<void>;
48
- /** Whether a model is currently loaded */
68
+ /** Whether a model is currently loaded. */
49
69
  get isLoaded(): boolean;
50
- /** Name of the currently loaded model */
70
+ /** Name of the currently loaded model. */
51
71
  get currentModel(): string;
52
- private storeInCache;
53
- private deleteFromCache;
54
72
  }
55
73
 
56
74
  export { type ConnectionResult, type GenerateRequest, type GenerateResult, type LoadModelResult, WllamaService, type WllamaServiceConfig };
package/dist/index.js CHANGED
@@ -36,116 +36,189 @@ var WllamaService = class {
36
36
  nCtx: config.nCtx ?? 2048
37
37
  };
38
38
  }
39
- /** Check browser compatibility and capabilities */
39
+ /**
40
+ * Check WebGPU without directly accessing navigator.gpu.
41
+ *
42
+ * This avoids requiring @webgpu/types merely for feature detection.
43
+ */
44
+ hasWebGPU() {
45
+ return typeof navigator !== "undefined" && "gpu" in navigator;
46
+ }
47
+ /** Check browser compatibility and capabilities. */
40
48
  checkEnvironment() {
41
- if (typeof WebAssembly === "undefined") {
42
- return { success: false, error: "WebAssembly is not supported in this browser." };
49
+ if (typeof window === "undefined" || typeof navigator === "undefined") {
50
+ return {
51
+ success: false,
52
+ error: "WllamaService can only run in a browser environment."
53
+ };
43
54
  }
44
- if (!("caches" in window)) {
45
- return { success: false, error: "Cache API is not supported in this browser." };
55
+ if (typeof WebAssembly === "undefined") {
56
+ return {
57
+ success: false,
58
+ error: "WebAssembly is not supported in this browser."
59
+ };
46
60
  }
47
- const hasWebGPU = !!navigator.gpu;
48
- const isolated = window.crossOriginIsolated;
49
61
  return {
50
62
  success: true,
51
- hasWebGPU,
52
- crossOriginIsolated: isolated
63
+ hasWebGPU: this.hasWebGPU(),
64
+ crossOriginIsolated: window.crossOriginIsolated
53
65
  };
54
66
  }
55
- /** Load a GGUF model file from the user's filesystem */
67
+ /** Load a GGUF model file from the user's filesystem. */
56
68
  async loadModel(file, onProgress) {
57
- const env = this.checkEnvironment();
58
- if (!env.success) return { success: false, error: env.error };
69
+ const environment = this.checkEnvironment();
70
+ if (!environment.success) {
71
+ return {
72
+ success: false,
73
+ error: environment.error
74
+ };
75
+ }
59
76
  await this.unload();
60
77
  try {
61
78
  onProgress?.(10);
62
- const configPaths = { default: this.config.wasmPath };
63
- this.wllama = new import_esm.Wllama(configPaths);
79
+ this.wllama = new import_esm.Wllama({
80
+ default: this.config.wasmPath
81
+ });
64
82
  onProgress?.(30);
65
- await this.storeInCache(file);
66
- onProgress?.(50);
67
- const hasWebGPU = !!navigator.gpu;
83
+ const useWebGPU = this.hasWebGPU() && this.config.nGpuLayers > 0;
68
84
  await this.wllama.loadModel([file], {
69
85
  n_ctx: this.config.nCtx,
70
- ...hasWebGPU && this.config.nGpuLayers > 0 ? { n_gpu_layers: this.config.nGpuLayers } : {}
86
+ n_gpu_layers: useWebGPU ? this.config.nGpuLayers : 0,
87
+ jinja: true
71
88
  });
72
89
  this.modelName = file.name;
73
90
  onProgress?.(100);
74
- return { success: true, usedWebGPU: hasWebGPU };
75
- } catch (e) {
91
+ return {
92
+ success: true,
93
+ usedWebGPU: useWebGPU
94
+ };
95
+ } catch (error) {
76
96
  await this.unload();
77
- const message = e instanceof Error ? e.message : "Failed to load model";
78
- return { success: false, error: message };
97
+ return {
98
+ success: false,
99
+ error: error instanceof Error ? error.message : "Failed to load model"
100
+ };
79
101
  }
80
102
  }
81
- /** Generate a response from the loaded model */
103
+ /**
104
+ * Generate a chat response using the model's embedded chat template.
105
+ *
106
+ * Suitable for instruction-tuned models such as Phi-3 Instruct,
107
+ * Llama Instruct, ChatML models, and similar chat models.
108
+ */
82
109
  async generate(req) {
83
110
  if (!this.wllama) {
84
- return { success: false, error: "No model loaded. Call loadModel() first." };
111
+ return {
112
+ success: false,
113
+ error: "No model loaded. Call loadModel() first."
114
+ };
85
115
  }
86
116
  try {
87
- const t0 = performance.now();
117
+ const startedAt = performance.now();
88
118
  const messages = [];
89
- if (req.system) messages.push({ role: "system", content: req.system });
90
- messages.push({ role: "user", content: req.prompt });
119
+ if (req.system) {
120
+ messages.push({
121
+ role: "system",
122
+ content: req.system
123
+ });
124
+ }
125
+ messages.push({
126
+ role: "user",
127
+ content: req.prompt
128
+ });
91
129
  const response = await this.wllama.createChatCompletion({
92
130
  messages,
131
+ stream: false,
93
132
  max_tokens: req.maxTokens ?? 512,
94
133
  temperature: req.temperature ?? 0.7,
95
134
  top_k: req.topK ?? 40,
96
- top_p: req.topP ?? 0.95
135
+ top_p: req.topP ?? 0.95,
136
+ stop: req.stop,
137
+ abortSignal: req.abortSignal
97
138
  });
98
- const text = response?.choices?.[0]?.message?.content ?? "";
139
+ const text = response.choices?.[0]?.message?.content ?? "";
99
140
  return {
100
141
  success: true,
101
142
  text,
102
- timeMs: Math.round(performance.now() - t0)
143
+ timeMs: Math.round(
144
+ performance.now() - startedAt
145
+ )
146
+ };
147
+ } catch (error) {
148
+ return {
149
+ success: false,
150
+ error: error instanceof Error ? error.message : "Generation failed"
151
+ };
152
+ }
153
+ }
154
+ /**
155
+ * Generate a raw completion without applying a chat template.
156
+ *
157
+ * Suitable for base completion models, manually formatted prompts,
158
+ * few-shot completion, fill-in-the-middle, and custom templates.
159
+ */
160
+ async generateCompletion(req) {
161
+ if (!this.wllama) {
162
+ return {
163
+ success: false,
164
+ error: "No model loaded. Call loadModel() first."
165
+ };
166
+ }
167
+ try {
168
+ const startedAt = performance.now();
169
+ const prompt = req.system ? `${req.system}
170
+
171
+ ${req.prompt}` : req.prompt;
172
+ const response = await this.wllama.createCompletion({
173
+ prompt,
174
+ stream: false,
175
+ max_tokens: req.maxTokens ?? 512,
176
+ temperature: req.temperature ?? 0.7,
177
+ top_k: req.topK ?? 40,
178
+ top_p: req.topP ?? 0.95,
179
+ stop: req.stop,
180
+ abortSignal: req.abortSignal
181
+ });
182
+ const choice = response.choices?.[0];
183
+ console.debug("[wllama] raw completion", {
184
+ text: choice?.text,
185
+ finishReason: choice?.finish_reason,
186
+ usage: response.usage,
187
+ timings: response.timings
188
+ });
189
+ return {
190
+ success: true,
191
+ text: choice?.text ?? "",
192
+ timeMs: Math.round(
193
+ performance.now() - startedAt
194
+ )
195
+ };
196
+ } catch (error) {
197
+ return {
198
+ success: false,
199
+ error: error instanceof Error ? error.message : "Generation failed"
103
200
  };
104
- } catch (e) {
105
- const message = e instanceof Error ? e.message : "Generation failed";
106
- return { success: false, error: message };
107
201
  }
108
202
  }
109
- /** Unload the current model and free memory */
203
+ /** Unload the current model and release its resources. */
110
204
  async unload() {
111
205
  if (this.wllama) {
112
206
  try {
113
207
  await this.wllama.exit();
114
- } catch (_) {
208
+ } catch {
115
209
  }
116
210
  this.wllama = null;
117
211
  }
118
- if (this.modelName) {
119
- try {
120
- await this.deleteFromCache(this.modelName);
121
- } catch (_) {
122
- }
123
- this.modelName = "";
124
- }
212
+ this.modelName = "";
125
213
  }
126
- /** Whether a model is currently loaded */
214
+ /** Whether a model is currently loaded. */
127
215
  get isLoaded() {
128
216
  return this.wllama !== null;
129
217
  }
130
- /** Name of the currently loaded model */
218
+ /** Name of the currently loaded model. */
131
219
  get currentModel() {
132
220
  return this.modelName;
133
221
  }
134
- async storeInCache(file) {
135
- const url = `${window.location.origin}/wllama-local-models/${file.name}`;
136
- const cache = await caches.open("wllama-local-models");
137
- await cache.put(
138
- url,
139
- new Response(file, {
140
- headers: { "Content-Type": "application/octet-stream" }
141
- })
142
- );
143
- }
144
- async deleteFromCache(fileName) {
145
- const url = `${window.location.origin}/wllama-local-models/${fileName}`;
146
- const cache = await caches.open("wllama-local-models");
147
- await cache.delete(url);
148
- }
149
222
  };
150
223
  // Annotate the CommonJS export names for ESM import in node:
151
224
  0 && (module.exports = {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/WllamaService.ts"],"sourcesContent":["export { WllamaService } from './WllamaService';\nexport type {\n WllamaServiceConfig,\n GenerateRequest,\n GenerateResult,\n LoadModelResult,\n ConnectionResult,\n} from './types';","import { Wllama } from '@wllama/wllama/esm/index.js';\nimport type {\n WllamaServiceConfig,\n GenerateRequest,\n GenerateResult,\n LoadModelResult,\n ConnectionResult,\n} from './types';\n\nexport class WllamaService {\n private wllama: Wllama | null = null;\n private modelName: string = '';\n private config: Required<WllamaServiceConfig>;\n\n constructor(config: WllamaServiceConfig = {}) {\n this.config = {\n wasmPath: config.wasmPath ?? '/wllama/wllama.wasm',\n nGpuLayers: config.nGpuLayers ?? 999,\n nCtx: config.nCtx ?? 2048,\n };\n }\n\n /** Check browser compatibility and capabilities */\n checkEnvironment(): ConnectionResult {\n if (typeof WebAssembly === 'undefined') {\n return { success: false, error: 'WebAssembly is not supported in this browser.' };\n }\n if (!('caches' in window)) {\n return { success: false, error: 'Cache API is not supported in this browser.' };\n }\n const hasWebGPU = !!(navigator as any).gpu;\n const isolated = window.crossOriginIsolated;\n return {\n success: true,\n hasWebGPU,\n crossOriginIsolated: isolated,\n };\n }\n\n /** Load a GGUF model file from the user's filesystem */\n async loadModel(\n file: File,\n onProgress?: (progress: number) => void,\n ): Promise<LoadModelResult> {\n const env = this.checkEnvironment();\n if (!env.success) return { success: false, error: env.error };\n\n await this.unload();\n\n try {\n onProgress?.(10);\n\n // AssetsPathConfig requires `default` — this is the key the\n // Wllama runtime actually reads (confirmed against the real\n // @wllama/wllama@3.5.1 implementation, not just its docs).\n // No `as any` needed: this shape is type-correct as written.\n const configPaths = { default: this.config.wasmPath };\n this.wllama = new Wllama(configPaths);\n onProgress?.(30);\n\n await this.storeInCache(file);\n onProgress?.(50);\n\n const hasWebGPU = !!(navigator as any).gpu;\n await (this.wllama as any).loadModel([file], {\n n_ctx: this.config.nCtx,\n ...(hasWebGPU && this.config.nGpuLayers > 0\n ? { n_gpu_layers: this.config.nGpuLayers }\n : {}),\n });\n\n this.modelName = file.name;\n onProgress?.(100);\n\n return { success: true, usedWebGPU: hasWebGPU };\n } catch (e: unknown) {\n await this.unload();\n const message = e instanceof Error ? e.message : 'Failed to load model';\n return { success: false, error: message };\n }\n }\n\n /** Generate a response from the loaded model */\n async generate(req: GenerateRequest): Promise<GenerateResult> {\n if (!this.wllama) {\n return { success: false, error: 'No model loaded. Call loadModel() first.' };\n }\n\n try {\n const t0 = performance.now();\n\n const messages: { role: string; content: string }[] = [];\n if (req.system) messages.push({ role: 'system', content: req.system });\n messages.push({ role: 'user', content: req.prompt });\n\n const response = await (this.wllama as any).createChatCompletion({\n messages,\n max_tokens: req.maxTokens ?? 512,\n temperature: req.temperature ?? 0.7,\n top_k: req.topK ?? 40,\n top_p: req.topP ?? 0.95,\n });\n\n const text: string = response?.choices?.[0]?.message?.content ?? '';\n return {\n success: true,\n text,\n timeMs: Math.round(performance.now() - t0),\n };\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : 'Generation failed';\n return { success: false, error: message };\n }\n }\n\n /** Unload the current model and free memory */\n async unload(): Promise<void> {\n if (this.wllama) {\n try {\n await (this.wllama as any).exit();\n } catch (_) {\n /* ignore */\n }\n this.wllama = null;\n }\n if (this.modelName) {\n try {\n await this.deleteFromCache(this.modelName);\n } catch (_) {\n /* ignore */\n }\n this.modelName = '';\n }\n }\n\n /** Whether a model is currently loaded */\n get isLoaded(): boolean {\n return this.wllama !== null;\n }\n\n /** Name of the currently loaded model */\n get currentModel(): string {\n return this.modelName;\n }\n\n private async storeInCache(file: File): Promise<void> {\n const url = `${window.location.origin}/wllama-local-models/${file.name}`;\n const cache = await caches.open('wllama-local-models');\n await cache.put(\n url,\n new Response(file, {\n headers: { 'Content-Type': 'application/octet-stream' },\n }),\n );\n }\n\n private async deleteFromCache(fileName: string): Promise<void> {\n const url = `${window.location.origin}/wllama-local-models/${fileName}`;\n const cache = await caches.open('wllama-local-models');\n await cache.delete(url);\n }\n}"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/WllamaService.ts"],"sourcesContent":["export { WllamaService } from './WllamaService';\nexport type {\n WllamaServiceConfig,\n GenerateRequest,\n GenerateResult,\n LoadModelResult,\n ConnectionResult,\n} from './types';","// src/WllamaService.ts\n\nimport { Wllama } from \"@wllama/wllama/esm/index.js\";\n\nimport type {\n WllamaServiceConfig,\n GenerateRequest,\n GenerateResult,\n LoadModelResult,\n ConnectionResult,\n} from \"./types\";\n\nexport class WllamaService {\n private wllama: Wllama | null = null;\n private modelName = \"\";\n private readonly config: Required<WllamaServiceConfig>;\n\n constructor(config: WllamaServiceConfig = {}) {\n this.config = {\n wasmPath: config.wasmPath ?? \"/wllama/wllama.wasm\",\n nGpuLayers: config.nGpuLayers ?? 999,\n nCtx: config.nCtx ?? 2048,\n };\n }\n\n /**\n * Check WebGPU without directly accessing navigator.gpu.\n *\n * This avoids requiring @webgpu/types merely for feature detection.\n */\n private hasWebGPU(): boolean {\n return typeof navigator !== \"undefined\" && \"gpu\" in navigator;\n }\n\n /** Check browser compatibility and capabilities. */\n checkEnvironment(): ConnectionResult {\n if (\n typeof window === \"undefined\" ||\n typeof navigator === \"undefined\"\n ) {\n return {\n success: false,\n error: \"WllamaService can only run in a browser environment.\",\n };\n }\n\n if (typeof WebAssembly === \"undefined\") {\n return {\n success: false,\n error: \"WebAssembly is not supported in this browser.\",\n };\n }\n\n return {\n success: true,\n hasWebGPU: this.hasWebGPU(),\n crossOriginIsolated: window.crossOriginIsolated,\n };\n }\n\n /** Load a GGUF model file from the user's filesystem. */\n async loadModel(\n file: File,\n onProgress?: (progress: number) => void,\n ): Promise<LoadModelResult> {\n const environment = this.checkEnvironment();\n\n if (!environment.success) {\n return {\n success: false,\n error: environment.error,\n };\n }\n\n await this.unload();\n\n try {\n onProgress?.(10);\n\n this.wllama = new Wllama({\n default: this.config.wasmPath,\n });\n\n onProgress?.(30);\n\n const useWebGPU =\n this.hasWebGPU() && this.config.nGpuLayers > 0;\n\n await this.wllama.loadModel([file], {\n n_ctx: this.config.nCtx,\n n_gpu_layers: useWebGPU\n ? this.config.nGpuLayers\n : 0,\n jinja: true,\n });\n\n this.modelName = file.name;\n\n onProgress?.(100);\n\n return {\n success: true,\n usedWebGPU: useWebGPU,\n };\n } catch (error: unknown) {\n await this.unload();\n\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Failed to load model\",\n };\n }\n }\n\n /**\n * Generate a chat response using the model's embedded chat template.\n *\n * Suitable for instruction-tuned models such as Phi-3 Instruct,\n * Llama Instruct, ChatML models, and similar chat models.\n */\n async generate(\n req: GenerateRequest,\n ): Promise<GenerateResult> {\n if (!this.wllama) {\n return {\n success: false,\n error: \"No model loaded. Call loadModel() first.\",\n };\n }\n\n try {\n const startedAt = performance.now();\n\n const messages: Array<{\n role: \"system\" | \"user\";\n content: string;\n }> = [];\n\n if (req.system) {\n messages.push({\n role: \"system\",\n content: req.system,\n });\n }\n\n messages.push({\n role: \"user\",\n content: req.prompt,\n });\n\n /*\n * Keep the cast here if the installed @wllama/wllama declaration\n * does not expose the exact createChatCompletion signature.\n */\n const response = await (\n this.wllama as unknown as {\n createChatCompletion(options: {\n messages: Array<{\n role: \"system\" | \"user\";\n content: string;\n }>;\n stream: false;\n max_tokens: number;\n temperature: number;\n top_k: number;\n top_p: number;\n stop?: string | string[];\n abortSignal?: AbortSignal;\n }): Promise<{\n choices?: Array<{\n message?: {\n content?: string;\n };\n }>;\n }>;\n }\n ).createChatCompletion({\n messages,\n stream: false,\n max_tokens: req.maxTokens ?? 512,\n temperature: req.temperature ?? 0.7,\n top_k: req.topK ?? 40,\n top_p: req.topP ?? 0.95,\n stop: req.stop,\n abortSignal: req.abortSignal,\n });\n\n const text =\n response.choices?.[0]?.message?.content ?? \"\";\n\n return {\n success: true,\n text,\n timeMs: Math.round(\n performance.now() - startedAt,\n ),\n };\n } catch (error: unknown) {\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Generation failed\",\n };\n }\n }\n\n /**\n * Generate a raw completion without applying a chat template.\n *\n * Suitable for base completion models, manually formatted prompts,\n * few-shot completion, fill-in-the-middle, and custom templates.\n */\n async generateCompletion(\n req: GenerateRequest,\n ): Promise<GenerateResult> {\n if (!this.wllama) {\n return {\n success: false,\n error: \"No model loaded. Call loadModel() first.\",\n };\n }\n\n try {\n const startedAt = performance.now();\n\n const prompt = req.system\n ? `${req.system}\\n\\n${req.prompt}`\n : req.prompt;\n\n const response =\n await this.wllama.createCompletion({\n prompt,\n stream: false,\n max_tokens: req.maxTokens ?? 512,\n temperature: req.temperature ?? 0.7,\n top_k: req.topK ?? 40,\n top_p: req.topP ?? 0.95,\n stop: req.stop,\n abortSignal: req.abortSignal,\n });\n\n const choice = response.choices?.[0];\n\n console.debug(\"[wllama] raw completion\", {\n text: choice?.text,\n finishReason: choice?.finish_reason,\n usage: response.usage,\n timings: response.timings,\n });\n\n return {\n success: true,\n text: choice?.text ?? \"\",\n timeMs: Math.round(\n performance.now() - startedAt,\n ),\n };\n } catch (error: unknown) {\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Generation failed\",\n };\n }\n }\n\n /** Unload the current model and release its resources. */\n async unload(): Promise<void> {\n if (this.wllama) {\n try {\n await this.wllama.exit();\n } catch {\n // Ignore shutdown errors.\n }\n\n this.wllama = null;\n }\n\n this.modelName = \"\";\n }\n\n /** Whether a model is currently loaded. */\n get isLoaded(): boolean {\n return this.wllama !== null;\n }\n\n /** Name of the currently loaded model. */\n get currentModel(): string {\n return this.modelName;\n }\n}"],"mappings":"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","names":[]}
package/dist/index.mjs CHANGED
@@ -10,116 +10,189 @@ var WllamaService = class {
10
10
  nCtx: config.nCtx ?? 2048
11
11
  };
12
12
  }
13
- /** Check browser compatibility and capabilities */
13
+ /**
14
+ * Check WebGPU without directly accessing navigator.gpu.
15
+ *
16
+ * This avoids requiring @webgpu/types merely for feature detection.
17
+ */
18
+ hasWebGPU() {
19
+ return typeof navigator !== "undefined" && "gpu" in navigator;
20
+ }
21
+ /** Check browser compatibility and capabilities. */
14
22
  checkEnvironment() {
15
- if (typeof WebAssembly === "undefined") {
16
- return { success: false, error: "WebAssembly is not supported in this browser." };
23
+ if (typeof window === "undefined" || typeof navigator === "undefined") {
24
+ return {
25
+ success: false,
26
+ error: "WllamaService can only run in a browser environment."
27
+ };
17
28
  }
18
- if (!("caches" in window)) {
19
- return { success: false, error: "Cache API is not supported in this browser." };
29
+ if (typeof WebAssembly === "undefined") {
30
+ return {
31
+ success: false,
32
+ error: "WebAssembly is not supported in this browser."
33
+ };
20
34
  }
21
- const hasWebGPU = !!navigator.gpu;
22
- const isolated = window.crossOriginIsolated;
23
35
  return {
24
36
  success: true,
25
- hasWebGPU,
26
- crossOriginIsolated: isolated
37
+ hasWebGPU: this.hasWebGPU(),
38
+ crossOriginIsolated: window.crossOriginIsolated
27
39
  };
28
40
  }
29
- /** Load a GGUF model file from the user's filesystem */
41
+ /** Load a GGUF model file from the user's filesystem. */
30
42
  async loadModel(file, onProgress) {
31
- const env = this.checkEnvironment();
32
- if (!env.success) return { success: false, error: env.error };
43
+ const environment = this.checkEnvironment();
44
+ if (!environment.success) {
45
+ return {
46
+ success: false,
47
+ error: environment.error
48
+ };
49
+ }
33
50
  await this.unload();
34
51
  try {
35
52
  onProgress?.(10);
36
- const configPaths = { default: this.config.wasmPath };
37
- this.wllama = new Wllama(configPaths);
53
+ this.wllama = new Wllama({
54
+ default: this.config.wasmPath
55
+ });
38
56
  onProgress?.(30);
39
- await this.storeInCache(file);
40
- onProgress?.(50);
41
- const hasWebGPU = !!navigator.gpu;
57
+ const useWebGPU = this.hasWebGPU() && this.config.nGpuLayers > 0;
42
58
  await this.wllama.loadModel([file], {
43
59
  n_ctx: this.config.nCtx,
44
- ...hasWebGPU && this.config.nGpuLayers > 0 ? { n_gpu_layers: this.config.nGpuLayers } : {}
60
+ n_gpu_layers: useWebGPU ? this.config.nGpuLayers : 0,
61
+ jinja: true
45
62
  });
46
63
  this.modelName = file.name;
47
64
  onProgress?.(100);
48
- return { success: true, usedWebGPU: hasWebGPU };
49
- } catch (e) {
65
+ return {
66
+ success: true,
67
+ usedWebGPU: useWebGPU
68
+ };
69
+ } catch (error) {
50
70
  await this.unload();
51
- const message = e instanceof Error ? e.message : "Failed to load model";
52
- return { success: false, error: message };
71
+ return {
72
+ success: false,
73
+ error: error instanceof Error ? error.message : "Failed to load model"
74
+ };
53
75
  }
54
76
  }
55
- /** Generate a response from the loaded model */
77
+ /**
78
+ * Generate a chat response using the model's embedded chat template.
79
+ *
80
+ * Suitable for instruction-tuned models such as Phi-3 Instruct,
81
+ * Llama Instruct, ChatML models, and similar chat models.
82
+ */
56
83
  async generate(req) {
57
84
  if (!this.wllama) {
58
- return { success: false, error: "No model loaded. Call loadModel() first." };
85
+ return {
86
+ success: false,
87
+ error: "No model loaded. Call loadModel() first."
88
+ };
59
89
  }
60
90
  try {
61
- const t0 = performance.now();
91
+ const startedAt = performance.now();
62
92
  const messages = [];
63
- if (req.system) messages.push({ role: "system", content: req.system });
64
- messages.push({ role: "user", content: req.prompt });
93
+ if (req.system) {
94
+ messages.push({
95
+ role: "system",
96
+ content: req.system
97
+ });
98
+ }
99
+ messages.push({
100
+ role: "user",
101
+ content: req.prompt
102
+ });
65
103
  const response = await this.wllama.createChatCompletion({
66
104
  messages,
105
+ stream: false,
67
106
  max_tokens: req.maxTokens ?? 512,
68
107
  temperature: req.temperature ?? 0.7,
69
108
  top_k: req.topK ?? 40,
70
- top_p: req.topP ?? 0.95
109
+ top_p: req.topP ?? 0.95,
110
+ stop: req.stop,
111
+ abortSignal: req.abortSignal
71
112
  });
72
- const text = response?.choices?.[0]?.message?.content ?? "";
113
+ const text = response.choices?.[0]?.message?.content ?? "";
73
114
  return {
74
115
  success: true,
75
116
  text,
76
- timeMs: Math.round(performance.now() - t0)
117
+ timeMs: Math.round(
118
+ performance.now() - startedAt
119
+ )
120
+ };
121
+ } catch (error) {
122
+ return {
123
+ success: false,
124
+ error: error instanceof Error ? error.message : "Generation failed"
77
125
  };
78
- } catch (e) {
79
- const message = e instanceof Error ? e.message : "Generation failed";
80
- return { success: false, error: message };
81
126
  }
82
127
  }
83
- /** Unload the current model and free memory */
128
+ /**
129
+ * Generate a raw completion without applying a chat template.
130
+ *
131
+ * Suitable for base completion models, manually formatted prompts,
132
+ * few-shot completion, fill-in-the-middle, and custom templates.
133
+ */
134
+ async generateCompletion(req) {
135
+ if (!this.wllama) {
136
+ return {
137
+ success: false,
138
+ error: "No model loaded. Call loadModel() first."
139
+ };
140
+ }
141
+ try {
142
+ const startedAt = performance.now();
143
+ const prompt = req.system ? `${req.system}
144
+
145
+ ${req.prompt}` : req.prompt;
146
+ const response = await this.wllama.createCompletion({
147
+ prompt,
148
+ stream: false,
149
+ max_tokens: req.maxTokens ?? 512,
150
+ temperature: req.temperature ?? 0.7,
151
+ top_k: req.topK ?? 40,
152
+ top_p: req.topP ?? 0.95,
153
+ stop: req.stop,
154
+ abortSignal: req.abortSignal
155
+ });
156
+ const choice = response.choices?.[0];
157
+ console.debug("[wllama] raw completion", {
158
+ text: choice?.text,
159
+ finishReason: choice?.finish_reason,
160
+ usage: response.usage,
161
+ timings: response.timings
162
+ });
163
+ return {
164
+ success: true,
165
+ text: choice?.text ?? "",
166
+ timeMs: Math.round(
167
+ performance.now() - startedAt
168
+ )
169
+ };
170
+ } catch (error) {
171
+ return {
172
+ success: false,
173
+ error: error instanceof Error ? error.message : "Generation failed"
174
+ };
175
+ }
176
+ }
177
+ /** Unload the current model and release its resources. */
84
178
  async unload() {
85
179
  if (this.wllama) {
86
180
  try {
87
181
  await this.wllama.exit();
88
- } catch (_) {
182
+ } catch {
89
183
  }
90
184
  this.wllama = null;
91
185
  }
92
- if (this.modelName) {
93
- try {
94
- await this.deleteFromCache(this.modelName);
95
- } catch (_) {
96
- }
97
- this.modelName = "";
98
- }
186
+ this.modelName = "";
99
187
  }
100
- /** Whether a model is currently loaded */
188
+ /** Whether a model is currently loaded. */
101
189
  get isLoaded() {
102
190
  return this.wllama !== null;
103
191
  }
104
- /** Name of the currently loaded model */
192
+ /** Name of the currently loaded model. */
105
193
  get currentModel() {
106
194
  return this.modelName;
107
195
  }
108
- async storeInCache(file) {
109
- const url = `${window.location.origin}/wllama-local-models/${file.name}`;
110
- const cache = await caches.open("wllama-local-models");
111
- await cache.put(
112
- url,
113
- new Response(file, {
114
- headers: { "Content-Type": "application/octet-stream" }
115
- })
116
- );
117
- }
118
- async deleteFromCache(fileName) {
119
- const url = `${window.location.origin}/wllama-local-models/${fileName}`;
120
- const cache = await caches.open("wllama-local-models");
121
- await cache.delete(url);
122
- }
123
196
  };
124
197
  export {
125
198
  WllamaService
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/WllamaService.ts"],"sourcesContent":["import { Wllama } from '@wllama/wllama/esm/index.js';\nimport type {\n WllamaServiceConfig,\n GenerateRequest,\n GenerateResult,\n LoadModelResult,\n ConnectionResult,\n} from './types';\n\nexport class WllamaService {\n private wllama: Wllama | null = null;\n private modelName: string = '';\n private config: Required<WllamaServiceConfig>;\n\n constructor(config: WllamaServiceConfig = {}) {\n this.config = {\n wasmPath: config.wasmPath ?? '/wllama/wllama.wasm',\n nGpuLayers: config.nGpuLayers ?? 999,\n nCtx: config.nCtx ?? 2048,\n };\n }\n\n /** Check browser compatibility and capabilities */\n checkEnvironment(): ConnectionResult {\n if (typeof WebAssembly === 'undefined') {\n return { success: false, error: 'WebAssembly is not supported in this browser.' };\n }\n if (!('caches' in window)) {\n return { success: false, error: 'Cache API is not supported in this browser.' };\n }\n const hasWebGPU = !!(navigator as any).gpu;\n const isolated = window.crossOriginIsolated;\n return {\n success: true,\n hasWebGPU,\n crossOriginIsolated: isolated,\n };\n }\n\n /** Load a GGUF model file from the user's filesystem */\n async loadModel(\n file: File,\n onProgress?: (progress: number) => void,\n ): Promise<LoadModelResult> {\n const env = this.checkEnvironment();\n if (!env.success) return { success: false, error: env.error };\n\n await this.unload();\n\n try {\n onProgress?.(10);\n\n // AssetsPathConfig requires `default` — this is the key the\n // Wllama runtime actually reads (confirmed against the real\n // @wllama/wllama@3.5.1 implementation, not just its docs).\n // No `as any` needed: this shape is type-correct as written.\n const configPaths = { default: this.config.wasmPath };\n this.wllama = new Wllama(configPaths);\n onProgress?.(30);\n\n await this.storeInCache(file);\n onProgress?.(50);\n\n const hasWebGPU = !!(navigator as any).gpu;\n await (this.wllama as any).loadModel([file], {\n n_ctx: this.config.nCtx,\n ...(hasWebGPU && this.config.nGpuLayers > 0\n ? { n_gpu_layers: this.config.nGpuLayers }\n : {}),\n });\n\n this.modelName = file.name;\n onProgress?.(100);\n\n return { success: true, usedWebGPU: hasWebGPU };\n } catch (e: unknown) {\n await this.unload();\n const message = e instanceof Error ? e.message : 'Failed to load model';\n return { success: false, error: message };\n }\n }\n\n /** Generate a response from the loaded model */\n async generate(req: GenerateRequest): Promise<GenerateResult> {\n if (!this.wllama) {\n return { success: false, error: 'No model loaded. Call loadModel() first.' };\n }\n\n try {\n const t0 = performance.now();\n\n const messages: { role: string; content: string }[] = [];\n if (req.system) messages.push({ role: 'system', content: req.system });\n messages.push({ role: 'user', content: req.prompt });\n\n const response = await (this.wllama as any).createChatCompletion({\n messages,\n max_tokens: req.maxTokens ?? 512,\n temperature: req.temperature ?? 0.7,\n top_k: req.topK ?? 40,\n top_p: req.topP ?? 0.95,\n });\n\n const text: string = response?.choices?.[0]?.message?.content ?? '';\n return {\n success: true,\n text,\n timeMs: Math.round(performance.now() - t0),\n };\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : 'Generation failed';\n return { success: false, error: message };\n }\n }\n\n /** Unload the current model and free memory */\n async unload(): Promise<void> {\n if (this.wllama) {\n try {\n await (this.wllama as any).exit();\n } catch (_) {\n /* ignore */\n }\n this.wllama = null;\n }\n if (this.modelName) {\n try {\n await this.deleteFromCache(this.modelName);\n } catch (_) {\n /* ignore */\n }\n this.modelName = '';\n }\n }\n\n /** Whether a model is currently loaded */\n get isLoaded(): boolean {\n return this.wllama !== null;\n }\n\n /** Name of the currently loaded model */\n get currentModel(): string {\n return this.modelName;\n }\n\n private async storeInCache(file: File): Promise<void> {\n const url = `${window.location.origin}/wllama-local-models/${file.name}`;\n const cache = await caches.open('wllama-local-models');\n await cache.put(\n url,\n new Response(file, {\n headers: { 'Content-Type': 'application/octet-stream' },\n }),\n );\n }\n\n private async deleteFromCache(fileName: string): Promise<void> {\n const url = `${window.location.origin}/wllama-local-models/${fileName}`;\n const cache = await caches.open('wllama-local-models');\n await cache.delete(url);\n }\n}"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/WllamaService.ts"],"sourcesContent":["// src/WllamaService.ts\n\nimport { Wllama } from \"@wllama/wllama/esm/index.js\";\n\nimport type {\n WllamaServiceConfig,\n GenerateRequest,\n GenerateResult,\n LoadModelResult,\n ConnectionResult,\n} from \"./types\";\n\nexport class WllamaService {\n private wllama: Wllama | null = null;\n private modelName = \"\";\n private readonly config: Required<WllamaServiceConfig>;\n\n constructor(config: WllamaServiceConfig = {}) {\n this.config = {\n wasmPath: config.wasmPath ?? \"/wllama/wllama.wasm\",\n nGpuLayers: config.nGpuLayers ?? 999,\n nCtx: config.nCtx ?? 2048,\n };\n }\n\n /**\n * Check WebGPU without directly accessing navigator.gpu.\n *\n * This avoids requiring @webgpu/types merely for feature detection.\n */\n private hasWebGPU(): boolean {\n return typeof navigator !== \"undefined\" && \"gpu\" in navigator;\n }\n\n /** Check browser compatibility and capabilities. */\n checkEnvironment(): ConnectionResult {\n if (\n typeof window === \"undefined\" ||\n typeof navigator === \"undefined\"\n ) {\n return {\n success: false,\n error: \"WllamaService can only run in a browser environment.\",\n };\n }\n\n if (typeof WebAssembly === \"undefined\") {\n return {\n success: false,\n error: \"WebAssembly is not supported in this browser.\",\n };\n }\n\n return {\n success: true,\n hasWebGPU: this.hasWebGPU(),\n crossOriginIsolated: window.crossOriginIsolated,\n };\n }\n\n /** Load a GGUF model file from the user's filesystem. */\n async loadModel(\n file: File,\n onProgress?: (progress: number) => void,\n ): Promise<LoadModelResult> {\n const environment = this.checkEnvironment();\n\n if (!environment.success) {\n return {\n success: false,\n error: environment.error,\n };\n }\n\n await this.unload();\n\n try {\n onProgress?.(10);\n\n this.wllama = new Wllama({\n default: this.config.wasmPath,\n });\n\n onProgress?.(30);\n\n const useWebGPU =\n this.hasWebGPU() && this.config.nGpuLayers > 0;\n\n await this.wllama.loadModel([file], {\n n_ctx: this.config.nCtx,\n n_gpu_layers: useWebGPU\n ? this.config.nGpuLayers\n : 0,\n jinja: true,\n });\n\n this.modelName = file.name;\n\n onProgress?.(100);\n\n return {\n success: true,\n usedWebGPU: useWebGPU,\n };\n } catch (error: unknown) {\n await this.unload();\n\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Failed to load model\",\n };\n }\n }\n\n /**\n * Generate a chat response using the model's embedded chat template.\n *\n * Suitable for instruction-tuned models such as Phi-3 Instruct,\n * Llama Instruct, ChatML models, and similar chat models.\n */\n async generate(\n req: GenerateRequest,\n ): Promise<GenerateResult> {\n if (!this.wllama) {\n return {\n success: false,\n error: \"No model loaded. Call loadModel() first.\",\n };\n }\n\n try {\n const startedAt = performance.now();\n\n const messages: Array<{\n role: \"system\" | \"user\";\n content: string;\n }> = [];\n\n if (req.system) {\n messages.push({\n role: \"system\",\n content: req.system,\n });\n }\n\n messages.push({\n role: \"user\",\n content: req.prompt,\n });\n\n /*\n * Keep the cast here if the installed @wllama/wllama declaration\n * does not expose the exact createChatCompletion signature.\n */\n const response = await (\n this.wllama as unknown as {\n createChatCompletion(options: {\n messages: Array<{\n role: \"system\" | \"user\";\n content: string;\n }>;\n stream: false;\n max_tokens: number;\n temperature: number;\n top_k: number;\n top_p: number;\n stop?: string | string[];\n abortSignal?: AbortSignal;\n }): Promise<{\n choices?: Array<{\n message?: {\n content?: string;\n };\n }>;\n }>;\n }\n ).createChatCompletion({\n messages,\n stream: false,\n max_tokens: req.maxTokens ?? 512,\n temperature: req.temperature ?? 0.7,\n top_k: req.topK ?? 40,\n top_p: req.topP ?? 0.95,\n stop: req.stop,\n abortSignal: req.abortSignal,\n });\n\n const text =\n response.choices?.[0]?.message?.content ?? \"\";\n\n return {\n success: true,\n text,\n timeMs: Math.round(\n performance.now() - startedAt,\n ),\n };\n } catch (error: unknown) {\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Generation failed\",\n };\n }\n }\n\n /**\n * Generate a raw completion without applying a chat template.\n *\n * Suitable for base completion models, manually formatted prompts,\n * few-shot completion, fill-in-the-middle, and custom templates.\n */\n async generateCompletion(\n req: GenerateRequest,\n ): Promise<GenerateResult> {\n if (!this.wllama) {\n return {\n success: false,\n error: \"No model loaded. Call loadModel() first.\",\n };\n }\n\n try {\n const startedAt = performance.now();\n\n const prompt = req.system\n ? `${req.system}\\n\\n${req.prompt}`\n : req.prompt;\n\n const response =\n await this.wllama.createCompletion({\n prompt,\n stream: false,\n max_tokens: req.maxTokens ?? 512,\n temperature: req.temperature ?? 0.7,\n top_k: req.topK ?? 40,\n top_p: req.topP ?? 0.95,\n stop: req.stop,\n abortSignal: req.abortSignal,\n });\n\n const choice = response.choices?.[0];\n\n console.debug(\"[wllama] raw completion\", {\n text: choice?.text,\n finishReason: choice?.finish_reason,\n usage: response.usage,\n timings: response.timings,\n });\n\n return {\n success: true,\n text: choice?.text ?? \"\",\n timeMs: Math.round(\n performance.now() - startedAt,\n ),\n };\n } catch (error: unknown) {\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Generation failed\",\n };\n }\n }\n\n /** Unload the current model and release its resources. */\n async unload(): Promise<void> {\n if (this.wllama) {\n try {\n await this.wllama.exit();\n } catch {\n // Ignore shutdown errors.\n }\n\n this.wllama = null;\n }\n\n this.modelName = \"\";\n }\n\n /** Whether a model is currently loaded. */\n get isLoaded(): boolean {\n return this.wllama !== null;\n }\n\n /** Name of the currently loaded model. */\n get currentModel(): string {\n return this.modelName;\n }\n}"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wllama-service",
3
- "version": "2.0.4",
3
+ "version": "2.0.6",
4
4
  "description": "Framework-agnostic browser LLM service wrapper with WebGPU and WebAssembly support",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",