kjarni-wasm 0.1.9 → 0.2.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kjarni-wasm",
3
- "version": "0.1.9",
3
+ "version": "0.2.0",
4
4
  "description": "Local AI inference in the browser: embeddings, classification, reranking, semantic search and chat, running in a Web Worker.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,19 +1,6 @@
1
1
  /* tslint:disable */
2
2
  /* eslint-disable */
3
3
 
4
- /**
5
- * A local language model running in the browser.
6
- *
7
- * Text generation is synchronous here, and deliberately so. The engine's streaming
8
- * path builds a background task with `tokio::task::spawn_blocking`, and wasm has no
9
- * blocking pool for that to run on — it compiles but would fail at runtime. Calling
10
- * the generation loop directly and draining the channel afterwards avoids the
11
- * problem entirely.
12
- *
13
- * The cost is that a call blocks until the whole response is ready, which for a few
14
- * hundred tokens is seconds, not milliseconds. Run it in a Web Worker; on the main
15
- * thread it will freeze the tab.
16
- */
17
4
  export class WasmChat {
18
5
  private constructor();
19
6
  free(): void;
@@ -26,6 +13,20 @@ export class WasmChat {
26
13
  * The model's context window, in tokens.
27
14
  */
28
15
  context_size(): number;
16
+ /**
17
+ * Reuse the KV cache across turns, so a conversation prefills only its newest
18
+ * message instead of replaying the whole transcript.
19
+ *
20
+ * Measured natively on Qwen2.5-0.5B with a long system prompt: turn one is
21
+ * unchanged, turns two and three go from about 2.2s to roughly 0.2s, for
22
+ * identical answers. A browser tab is one conversation, so there is no sharing
23
+ * hazard here.
24
+ *
25
+ * `tokens` is the longest transcript that can be reused, and what the memory
26
+ * cost scales with; pass 0 for [`DEFAULT_WASM_PREFIX_CACHE_TOKENS`]. Longer
27
+ * conversations keep working, they simply stop reusing once they outgrow it.
28
+ */
29
+ enablePrefixCache(tokens: number): void;
29
30
  /**
30
31
  * Generate a completion for `prompt`.
31
32
  */
@@ -45,6 +46,10 @@ export class WasmChat {
45
46
  * itself is in `generate_stream_core`, which builds and is tested natively.
46
47
  */
47
48
  generate_stream(prompt: string, max_new_tokens: number, temperature: number, on_token: Function): string;
49
+ /**
50
+ * Whether prefix reuse is on.
51
+ */
52
+ hasPrefixCache(): boolean;
48
53
  /**
49
54
  * Number of messages held, system prompt included.
50
55
  */
@@ -215,8 +220,10 @@ export interface InitOutput {
215
220
  readonly set_debug_logging: (a: number) => void;
216
221
  readonly wasmchat_clear_history: (a: number) => void;
217
222
  readonly wasmchat_context_size: (a: number) => number;
223
+ readonly wasmchat_enablePrefixCache: (a: number, b: number, c: number) => void;
218
224
  readonly wasmchat_generate: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
219
225
  readonly wasmchat_generate_stream: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
226
+ readonly wasmchat_hasPrefixCache: (a: number) => number;
220
227
  readonly wasmchat_history_len: (a: number) => number;
221
228
  readonly wasmchat_load: (a: number, b: number, c: number, d: number, e: number) => void;
222
229
  readonly wasmchat_send_stream: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
@@ -248,8 +255,8 @@ export interface InitOutput {
248
255
  readonly wasmsearch_search_keywords: (a: number, b: number, c: number, d: number, e: number) => void;
249
256
  readonly wasmsearch_search_semantic: (a: number, b: number, c: number, d: number, e: number) => void;
250
257
  readonly wasmsearch_update_file: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
251
- readonly __wasm_bindgen_func_elem_5516: (a: number, b: number, c: number, d: number) => void;
252
- readonly __wasm_bindgen_func_elem_5525: (a: number, b: number, c: number, d: number) => void;
258
+ readonly __wasm_bindgen_func_elem_5674: (a: number, b: number, c: number, d: number) => void;
259
+ readonly __wasm_bindgen_func_elem_5694: (a: number, b: number, c: number, d: number) => void;
253
260
  readonly __wbindgen_export: (a: number, b: number) => number;
254
261
  readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
255
262
  readonly __wbindgen_export3: (a: number) => void;
@@ -1,18 +1,5 @@
1
1
  /* @ts-self-types="./kjarni_wasm.d.ts" */
2
2
 
3
- /**
4
- * A local language model running in the browser.
5
- *
6
- * Text generation is synchronous here, and deliberately so. The engine's streaming
7
- * path builds a background task with `tokio::task::spawn_blocking`, and wasm has no
8
- * blocking pool for that to run on — it compiles but would fail at runtime. Calling
9
- * the generation loop directly and draining the channel afterwards avoids the
10
- * problem entirely.
11
- *
12
- * The cost is that a call blocks until the whole response is ready, which for a few
13
- * hundred tokens is seconds, not milliseconds. Run it in a Web Worker; on the main
14
- * thread it will freeze the tab.
15
- */
16
3
  export class WasmChat {
17
4
  static __wrap(ptr) {
18
5
  const obj = Object.create(WasmChat.prototype);
@@ -44,6 +31,33 @@ export class WasmChat {
44
31
  const ret = wasm.wasmchat_context_size(this.__wbg_ptr);
45
32
  return ret >>> 0;
46
33
  }
34
+ /**
35
+ * Reuse the KV cache across turns, so a conversation prefills only its newest
36
+ * message instead of replaying the whole transcript.
37
+ *
38
+ * Measured natively on Qwen2.5-0.5B with a long system prompt: turn one is
39
+ * unchanged, turns two and three go from about 2.2s to roughly 0.2s, for
40
+ * identical answers. A browser tab is one conversation, so there is no sharing
41
+ * hazard here.
42
+ *
43
+ * `tokens` is the longest transcript that can be reused, and what the memory
44
+ * cost scales with; pass 0 for [`DEFAULT_WASM_PREFIX_CACHE_TOKENS`]. Longer
45
+ * conversations keep working, they simply stop reusing once they outgrow it.
46
+ * @param {number} tokens
47
+ */
48
+ enablePrefixCache(tokens) {
49
+ try {
50
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
51
+ wasm.wasmchat_enablePrefixCache(retptr, this.__wbg_ptr, tokens);
52
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
53
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
54
+ if (r1) {
55
+ throw takeObject(r0);
56
+ }
57
+ } finally {
58
+ wasm.__wbindgen_add_to_stack_pointer(16);
59
+ }
60
+ }
47
61
  /**
48
62
  * Generate a completion for `prompt`.
49
63
  * @param {string} prompt
@@ -123,6 +137,14 @@ export class WasmChat {
123
137
  wasm.__wbindgen_export4(deferred3_0, deferred3_1, 1);
124
138
  }
125
139
  }
140
+ /**
141
+ * Whether prefix reuse is on.
142
+ * @returns {boolean}
143
+ */
144
+ hasPrefixCache() {
145
+ const ret = wasm.wasmchat_hasPrefixCache(this.__wbg_ptr);
146
+ return ret !== 0;
147
+ }
126
148
  /**
127
149
  * Number of messages held, system prompt included.
128
150
  * @returns {number}
@@ -1092,7 +1114,7 @@ function __wbg_get_imports() {
1092
1114
  const a = state0.a;
1093
1115
  state0.a = 0;
1094
1116
  try {
1095
- return __wasm_bindgen_func_elem_5525(a, state0.b, arg0, arg1);
1117
+ return __wasm_bindgen_func_elem_5694(a, state0.b, arg0, arg1);
1096
1118
  } finally {
1097
1119
  state0.a = a;
1098
1120
  }
@@ -1206,8 +1228,8 @@ function __wbg_get_imports() {
1206
1228
  return addHeapObject(ret);
1207
1229
  },
1208
1230
  __wbindgen_generic_0000000000000001: function(arg0, arg1) {
1209
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 2060, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
1210
- const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_5516);
1231
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 2082, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
1232
+ const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_5674);
1211
1233
  return addHeapObject(ret);
1212
1234
  },
1213
1235
  __wbindgen_generic_0000000000000002: function(arg0) {
@@ -1244,14 +1266,14 @@ function __wbg_get_imports() {
1244
1266
  };
1245
1267
  }
1246
1268
 
1247
- function __wasm_bindgen_func_elem_5525(arg0, arg1, arg2, arg3) {
1248
- wasm.__wasm_bindgen_func_elem_5525(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
1269
+ function __wasm_bindgen_func_elem_5694(arg0, arg1, arg2, arg3) {
1270
+ wasm.__wasm_bindgen_func_elem_5694(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
1249
1271
  }
1250
1272
 
1251
- function __wasm_bindgen_func_elem_5516(arg0, arg1, arg2) {
1273
+ function __wasm_bindgen_func_elem_5674(arg0, arg1, arg2) {
1252
1274
  try {
1253
1275
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1254
- wasm.__wasm_bindgen_func_elem_5516(retptr, arg0, arg1, addHeapObject(arg2));
1276
+ wasm.__wasm_bindgen_func_elem_5674(retptr, arg0, arg1, addHeapObject(arg2));
1255
1277
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1256
1278
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1257
1279
  if (r1) {
Binary file
@@ -12,8 +12,10 @@ export const init: () => void;
12
12
  export const set_debug_logging: (a: number) => void;
13
13
  export const wasmchat_clear_history: (a: number) => void;
14
14
  export const wasmchat_context_size: (a: number) => number;
15
+ export const wasmchat_enablePrefixCache: (a: number, b: number, c: number) => void;
15
16
  export const wasmchat_generate: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
16
17
  export const wasmchat_generate_stream: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
18
+ export const wasmchat_hasPrefixCache: (a: number) => number;
17
19
  export const wasmchat_history_len: (a: number) => number;
18
20
  export const wasmchat_load: (a: number, b: number, c: number, d: number, e: number) => void;
19
21
  export const wasmchat_send_stream: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
@@ -45,8 +47,8 @@ export const wasmsearch_search: (a: number, b: number, c: number, d: number, e:
45
47
  export const wasmsearch_search_keywords: (a: number, b: number, c: number, d: number, e: number) => void;
46
48
  export const wasmsearch_search_semantic: (a: number, b: number, c: number, d: number, e: number) => void;
47
49
  export const wasmsearch_update_file: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
48
- export const __wasm_bindgen_func_elem_5516: (a: number, b: number, c: number, d: number) => void;
49
- export const __wasm_bindgen_func_elem_5525: (a: number, b: number, c: number, d: number) => void;
50
+ export const __wasm_bindgen_func_elem_5674: (a: number, b: number, c: number, d: number) => void;
51
+ export const __wasm_bindgen_func_elem_5694: (a: number, b: number, c: number, d: number) => void;
50
52
  export const __wbindgen_export: (a: number, b: number) => number;
51
53
  export const __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
52
54
  export const __wbindgen_export3: (a: number) => void;
package/pkg/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "Ólafur Aron Jóhannsson <olafurjohannss@gmail.com>"
6
6
  ],
7
7
  "description": "Local AI inference in the browser: embeddings, classification, reranking, semantic search and chat, compiled to WebAssembly.",
8
- "version": "0.1.9",
8
+ "version": "0.2.0",
9
9
  "license": "MIT",
10
10
  "repository": {
11
11
  "type": "git",