react-native-nobodywho 4.0.0 → 5.0.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": "react-native-nobodywho",
3
- "version": "4.0.0",
3
+ "version": "5.0.0",
4
4
  "description": "Run LLMs locally and offline with React Native & Expo - Tool calling, RAG, Speech-to-Text, Text-to-Speech, and VAD",
5
5
  "main": "src/wrapper.ts",
6
6
  "types": "src/wrapper.ts",
package/src/chat.ts CHANGED
@@ -2,6 +2,7 @@ import {
2
2
  RustChat,
3
3
  SamplerConfig,
4
4
  MtpConfig,
5
+ ContextShiftOptions,
5
6
  type ChatStats,
6
7
  } from "../generated/ts/nobodywho";
7
8
  import { Model } from "./model";
@@ -49,6 +50,9 @@ export class Chat {
49
50
  * device's physical core count (performance cores only, on Apple silicon) — hyperthreads
50
51
  * and efficiency cores make inference slower, not faster. Lower it to leave CPU headroom
51
52
  * for the rest of the app.
53
+ *
54
+ * `contextShift` sets how old turns are forgotten when the context is full; omit it for
55
+ * the defaults, or pass `{ enabled: false }` to disable shifting.
52
56
  */
53
57
  constructor(opts: {
54
58
  model: Model;
@@ -59,6 +63,7 @@ export class Chat {
59
63
  sampler?: SamplerConfig;
60
64
  mtp?: Partial<MtpConfig>;
61
65
  threadCount?: number;
66
+ contextShift?: Partial<ContextShiftOptions>;
62
67
  }) {
63
68
  this._inner = new RustChat(
64
69
  opts.model._inner,
@@ -69,6 +74,7 @@ export class Chat {
69
74
  opts.sampler ?? undefined,
70
75
  opts.mtp !== undefined ? MtpConfig.create(opts.mtp) : undefined,
71
76
  opts.threadCount ?? undefined,
77
+ opts.contextShift !== undefined ? ContextShiftOptions.create(opts.contextShift) : undefined,
72
78
  );
73
79
  }
74
80
 
@@ -96,6 +102,7 @@ export class Chat {
96
102
  sampler?: SamplerConfig;
97
103
  mtp?: Partial<MtpConfig>;
98
104
  threadCount?: number;
105
+ contextShift?: Partial<ContextShiftOptions>;
99
106
  onDownloadProgress?: (downloaded: number, total: number) => void;
100
107
  }): Promise<Chat> {
101
108
  const model = await Model.load({
@@ -122,11 +129,11 @@ export class Chat {
122
129
  /**
123
130
  * Answer a full list of messages, replacing the chat history.
124
131
  *
125
- * The list is the whole conversation, used as given: it must be non-empty, end
126
- * in a user or tool message, and carry a system message only first. That system
127
- * message sets the chat's system prompt; leave it out and the prompt already on
128
- * the chat is kept. The response is appended, and the next `ask` continues from
129
- * there.
132
+ * The list is the whole conversation, used as given: it must be non-empty and
133
+ * end in a user or tool message. A leading system message sets the chat's system
134
+ * prompt; leave it out and the prompt already on the chat is kept. A later one
135
+ * stays in the history, for the chat template to render in place. The response
136
+ * is appended, and the next `ask` continues from there.
130
137
  *
131
138
  * `options` follows the same rule for the chat's other settings.
132
139
  */
@@ -180,12 +187,12 @@ export class Chat {
180
187
  }
181
188
 
182
189
  /** Tokenize a text message or multimodal prompt and return the token IDs.
183
- * Each element is a token ID (number) for text, or null for image/audio embedding slots. */
184
- async tokenize(message: string | Prompt): Promise<(number | null)[]> {
190
+ * Each element is a token ID (number) for text, or undefined for image/audio embedding slots. */
191
+ async tokenize(message: string | Prompt): Promise<(number | undefined)[]> {
185
192
  if (typeof message === "string") {
186
193
  return this._inner.tokenize(message);
187
194
  }
188
- return this._inner.tokenizeWithPrompt(message._parts);
195
+ return this._inner.tokenizeWithPrompt(message._parts!);
189
196
  }
190
197
 
191
198
  /** Set the system prompt. */
@@ -193,6 +200,11 @@ export class Chat {
193
200
  return this._inner.setSystemPrompt(systemPrompt);
194
201
  }
195
202
 
203
+ /** Set how old turns are forgotten when the context is full. */
204
+ async setContextShift(options: Partial<ContextShiftOptions>): Promise<void> {
205
+ return this._inner.setContextShift(ContextShiftOptions.create(options));
206
+ }
207
+
196
208
  /** Set the tools available to the model. */
197
209
  async setTools(tools: Tool[]): Promise<void> {
198
210
  return this._inner.setTools(tools.map((t) => t._inner));
package/src/model.ts CHANGED
@@ -65,6 +65,11 @@ export class Model {
65
65
  return new Model(inner);
66
66
  }
67
67
 
68
+ /** The identifier used to load this model. */
69
+ get source(): string {
70
+ return this._inner.source();
71
+ }
72
+
68
73
  /**
69
74
  * The maximum context size this model was trained with.
70
75
  * Use this to avoid setting `contextSize` above what the model supports.
@@ -5,7 +5,6 @@ import {
5
5
  samplerPresetConstrainWithRegex,
6
6
  samplerPresetDefault,
7
7
  samplerPresetDry,
8
- samplerPresetGrammar,
9
8
  samplerPresetGreedy,
10
9
  samplerPresetJson,
11
10
  samplerPresetTemperature,
@@ -16,6 +15,10 @@ import {
16
15
  /**
17
16
  * Static factory methods for common sampler configurations.
18
17
  *
18
+ * Every preset builds on the default configuration and adds its own step on top,
19
+ * replacing the default step of the same kind if there is one. `greedy()` is the
20
+ * exception: it always picks the most probable token, so it needs no steps.
21
+ *
19
22
  * @example
20
23
  * ```typescript
21
24
  * const sampler = SamplerPresets.temperature(0.7);
@@ -30,12 +33,12 @@ export class SamplerPresets {
30
33
  return samplerPresetDefault() as SamplerConfig;
31
34
  }
32
35
 
33
- /** Create a sampler with top-k filtering only. */
36
+ /** Create a sampler with the default steps, but top-k overridden. */
34
37
  static topK(topK: number): SamplerConfig {
35
38
  return samplerPresetTopK(topK) as SamplerConfig;
36
39
  }
37
40
 
38
- /** Create a sampler with nucleus (top-p) sampling. */
41
+ /** Create a sampler with the default steps, but nucleus (top-p) overridden. */
39
42
  static topP(topP: number): SamplerConfig {
40
43
  return samplerPresetTopP(topP) as SamplerConfig;
41
44
  }
@@ -55,7 +58,7 @@ export class SamplerPresets {
55
58
  return samplerPresetDry() as SamplerConfig;
56
59
  }
57
60
 
58
- /** Create a sampler configured for JSON output generation (any valid JSON, GBNF-based). */
61
+ /** Constrain output to a JSON object of any shape. */
59
62
  static json(): SamplerConfig {
60
63
  return samplerPresetJson() as SamplerConfig;
61
64
  }
@@ -80,11 +83,4 @@ export class SamplerPresets {
80
83
  static constrainWithGrammar(grammar: string): SamplerConfig {
81
84
  return samplerPresetConstrainWithGrammar(grammar) as SamplerConfig;
82
85
  }
83
-
84
- /**
85
- * @deprecated Use {@link constrainWithGrammar} instead. It accepts both Lark and GBNF strings.
86
- */
87
- static grammar(grammar: string): SamplerConfig {
88
- return samplerPresetGrammar(grammar) as SamplerConfig;
89
- }
90
86
  }
package/src/wrapper.ts CHANGED
@@ -77,6 +77,7 @@ export type { Message, Content, ContentPart } from "./message";
77
77
  export {
78
78
  SamplerBuilder,
79
79
  SamplerConfig,
80
+ ShiftTarget,
80
81
  cosineSimilarity,
81
82
  getCachedModels,
82
83
  } from "../generated/ts/nobodywho";
@@ -85,6 +86,7 @@ export type {
85
86
  ToolCall,
86
87
  CachedModel,
87
88
  ChatStats,
89
+ ContextShiftOptions,
88
90
  } from "../generated/ts/nobodywho";
89
91
  export type { TextToSpeechArchitecture, TextToSpeechDevice, TextToSpeechOptions } from "./text_to_speech";
90
92
  export type { SpeechToTextOptions } from "./speech_to_text";