@ariacompute/engine-rn 1.5.1 → 1.6.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 (3) hide show
  1. package/README.md +14 -0
  2. package/package.json +1 -1
  3. package/src/index.js +80 -2
package/README.md CHANGED
@@ -7,3 +7,17 @@ console.log(await eng.complete([{ role: 'user', content: 'hi' }]));
7
7
  ```
8
8
 
9
9
  npm publish name: `@ariacompute/engine-rn`. Device-farm CI: `.github/workflows/bindings-mobile.yml`.
10
+
11
+ ## Auto-download by model name
12
+
13
+ `AriaEngine.open(modelRef, { token, site })` accepts a local bundle path **or**
14
+ an Aria model name (e.g. `gemma-4-e2b-it_q4`). A value containing `/` or already
15
+ on disk is loaded directly; otherwise the SDK downloads it from the Dashboard
16
+ private source (requires `token`; `site` defaults to `https://ariacompute.com`)
17
+ into `~/.ariacompute/models/{model}` and then loads it. A valid cached bundle is
18
+ reused without re-downloading. The zip streaming + extraction is delegated to the
19
+ native `AriaEngineModule` bridge.
20
+
21
+ ```js
22
+ const eng = await AriaEngine.open("gemma-4-e2b-it_q4", { token: "API_TOKEN" });
23
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ariacompute/engine-rn",
3
- "version": "1.5.1",
3
+ "version": "1.6.1",
4
4
  "description": "React Native binding for Aria Engine",
5
5
  "main": "src/index.js",
6
6
  "license": "MIT",
package/src/index.js CHANGED
@@ -1,20 +1,98 @@
1
1
  /**
2
2
  * React Native surface — native module bridges to libaria_ffi (Turbo Module / JSI).
3
3
  * JS API mirrors @ariacompute/engine-ts for docs samples.
4
+ *
5
+ * Auto-download: `AriaEngine.open(modelRef, { token, site })` resolves a model
6
+ * name via the Dashboard private source (requires `token`), downloads the zip,
7
+ * extracts it through the native `AriaEngineModule` (which bridges unzip and
8
+ * writes to `~/.ariacompute/models/{model}`), then loads via the native init.
4
9
  */
10
+ import { NativeModules, Platform } from 'react-native';
11
+
12
+ const AriaEngineModule = NativeModules.AriaEngine;
13
+
14
+ const DEFAULT_SITE = 'https://ariacompute.com';
15
+
16
+ function parseBundleName(model) {
17
+ if (!model || model.includes('/') || model.includes('\\')) {
18
+ throw new Error(`invalid model name: ${model}`);
19
+ }
20
+ const idx = model.lastIndexOf('_q');
21
+ if (idx !== -1) {
22
+ const slug = model.slice(0, idx);
23
+ const suffix = model.slice(idx + 2);
24
+ const quant =
25
+ suffix === '4'
26
+ ? 'int4'
27
+ : suffix === '8'
28
+ ? 'int8'
29
+ : suffix === '326' || suffix === '3.26'
30
+ ? 'int326'
31
+ : (() => {
32
+ throw new Error(`unknown quant suffix _q${suffix}`);
33
+ })();
34
+ if (!slug) throw new Error(`invalid model name: ${model}`);
35
+ return { slug, quant };
36
+ }
37
+ return { slug: model, quant: 'int4' };
38
+ }
39
+
40
+ function ariaHome() {
41
+ if (process.env.ARIA_COMPUTE_HOME) return process.env.ARIA_COMPUTE_HOME;
42
+ return `${require('os').homedir()}/.ariacompute`;
43
+ }
44
+
45
+ function cacheDir(model) {
46
+ return `${ariaHome()}/models/${model}`;
47
+ }
48
+
49
+ function isLocalRef(ref) {
50
+ return ref.includes('/') || ref.includes('\\') || require('fs').existsSync(ref);
51
+ }
52
+
53
+ async function downloadModel(model, token, site = DEFAULT_SITE) {
54
+ if (!token) throw new Error('api token is required to download a model');
55
+ const { slug, quant } = parseBundleName(model);
56
+ const cache = cacheDir(model);
57
+ if (require('fs').existsSync(cache) && (await AriaEngineModule?.isValidBundle?.(cache))) {
58
+ return cache;
59
+ }
60
+ if (!AriaEngineModule?.downloadModel) {
61
+ throw new Error('native AriaEngineModule.downloadModel bridge is not linked');
62
+ }
63
+ const metaUrl = `${site.replace(/\/$/, '')}/api/dashboard/models/${encodeURIComponent(
64
+ slug,
65
+ )}/download?quant=${encodeURIComponent(quant)}&sdk=v1.0&format=json`;
66
+ const metaResp = await fetch(metaUrl, { headers: { Authorization: `Bearer ${token}` } });
67
+ if (!metaResp.ok) throw new Error(`dashboard request failed: ${metaResp.status}`);
68
+ const meta = await metaResp.json();
69
+ if (!meta.url) throw new Error('dashboard meta returned empty url');
70
+ // Delegates streaming + zip extraction (and bundle validation) to native.
71
+ return AriaEngineModule.downloadModel(model, meta.url, token, cache);
72
+ }
73
+
5
74
  export class AriaEngine {
6
75
  constructor(bundlePath) {
7
76
  this.bundlePath = bundlePath;
8
77
  // NativeModules.AriaEngine.init(bundlePath) when linked.
9
78
  }
10
79
 
80
+ static async open(modelRef, opts = {}) {
81
+ if (isLocalRef(modelRef)) return new AriaEngine(modelRef);
82
+ if (!opts.token) {
83
+ throw new Error(`model name '${modelRef}' requires an api token to download`);
84
+ }
85
+ const bundle = await downloadModel(modelRef, opts.token, opts.site ?? DEFAULT_SITE);
86
+ return new AriaEngine(bundle);
87
+ }
88
+
11
89
  async complete(messages, options = { max_tokens: 16 }, tools = []) {
12
90
  // return NativeModules.AriaEngine.complete(...)
13
91
  return {
14
92
  success: true,
15
- response: "",
93
+ response: '',
16
94
  function_calls: [],
17
- note: "Link native module to libaria_ffi",
95
+ note: 'Link native module to libaria_ffi',
18
96
  };
19
97
  }
20
98