Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
f311d92
docs: enrich model registry JSDoc comments and document rnexecutorchJsi
barhanc Aug 21, 2026
23d08ea
refactor(hooks): unify JSDoc documentation, link imperative APIs and …
barhanc Aug 21, 2026
249bb84
docs(hooks): format JSDoc type links onto dedicated lines to prevent …
barhanc Aug 21, 2026
11f25ea
docs: add top-level module documentation to index, models, constants,…
barhanc Aug 21, 2026
c370798
refactor(hooks): use switch statement for TTS factory resolution in u…
barhanc Aug 21, 2026
dd2700c
docs(core): improve error documentation and linking
barhanc Aug 21, 2026
e6824aa
docs(core): improve model and tensor documentation and error codes
barhanc Aug 21, 2026
e43597e
docs(core): improve runtime documentation and examples
barhanc Aug 21, 2026
80337d2
docs(core): add module doc to schema
barhanc Aug 21, 2026
37c7791
fix(core): return raw ConcreteDim for untyped dim accessors and mark …
barhanc Aug 21, 2026
be19426
docs(cv): standardize TSDoc comments, extract task options, and docum…
barhanc Aug 21, 2026
65e9adf
docs(speech): standardize TSDoc annotations, tensor specs, and error …
barhanc Aug 21, 2026
179df3d
docs(math): standardize TSDoc annotations, tensor specs, and use rand…
barhanc Aug 21, 2026
4a85ef6
docs(nlp): standardize TSDoc annotations, error throws, and simplify …
barhanc Aug 21, 2026
051b30e
docs(llm): standardize TSDoc annotations, module headers, and error t…
barhanc Aug 21, 2026
801ecb2
fix: improve JSDoc/TSDoc across src/ (25 files)
barhanc Aug 21, 2026
c780d65
fix: add missing @link for RnExecuTorchError in wrapAsync @returns
barhanc Aug 21, 2026
e3c4c8b
docs(ocr): standardize TSDoc annotations, extract task options, and d…
barhanc Aug 25, 2026
737071c
docs: refine category taxonomy and add explicit task return types
barhanc Aug 25, 2026
ed5d7b3
refactor: improve JSDoc documentation, task types, and module exports
barhanc Aug 25, 2026
449f1f5
docs: link create<Task> return types and expose flat CV operations
barhanc Aug 25, 2026
3cdd04a
refactor: flatten cv exports, add package subpaths, and eliminate re-…
barhanc Aug 25, 2026
b8b3ef8
chore: move preprocessing to cv/utils/imagePreprocessor, remove workl…
barhanc Aug 25, 2026
7d21bf8
style
barhanc Aug 25, 2026
33d3949
chore: rename ops/boxes -> box, ops/points -> point (singular consist…
barhanc Aug 25, 2026
daddb4e
fix: add subpath tsconfig path aliases for all app tsconfigs
barhanc Aug 25, 2026
40be915
docs: add @category tags to all CV ops and missing NLP utils functions
barhanc Aug 25, 2026
9733a07
docs: move LLM above NLP in category order, add namespace links to mo…
barhanc Aug 25, 2026
cad2b73
style
barhanc Aug 25, 2026
0a50750
docs: add @category tags to imagePreprocessor and paddleOcrUtils cv/u…
barhanc Aug 25, 2026
805e6ca
style
barhanc Aug 25, 2026
794065e
style
barhanc Aug 25, 2026
3826726
refactor(schema): rename constr -> constraint, eq -> equality
barhanc Aug 25, 2026
736ffd6
fix: update JSDoc references to use proper {/@link} syntax
barhanc Aug 25, 2026
c19d339
Add missing readonly
barhanc Aug 25, 2026
7232553
fix: add Core / Constants category and fix missing readonly and links
barhanc Aug 25, 2026
79483e0
fix: update agent skills, typedoc categories, model defaults, and doc…
barhanc Aug 26, 2026
150a4b5
docs(runtime): format WorkletRuntime as code in JSDoc to avoid extern…
barhanc Aug 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 6 additions & 13 deletions .agents/skills/add-task-pipeline/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ import { loadModel } from '../../../core/model';
import { validateSpec, method, f32 } from '../../../core/schema';
import { wrapAsync } from '../../../core/runtime';
import { type ImageBuffer } from '../image';
import { createImagePreprocessor, type ImagePreprocessorOptions } from './preprocessing';
import { createImagePreprocessor, type ImagePreprocessorOptions } from '../utils/imagePreprocessor';

export type MyTaskOptions = ImagePreprocessorOptions & {
readonly defaultThreshold: number;
Expand Down Expand Up @@ -190,28 +190,21 @@ Wrap the task pipeline in a custom React Hook using the core hooks `useResourceD

```typescript
import { useModel } from './useModel';
import { useResourceDownload } from './useResourceDownload';
import { useResourceDownload, type ResourceOptions } from './useResourceDownload';
import { createMyTask, type MyTaskModel } from '../extensions/<domain>/tasks/<task>';

export function useMyTask(config: MyTaskModel, options?: { preventLoad?: boolean }) {
export function useMyTask(config: MyTaskModel, options?: ResourceOptions) {
// 1. Resolve remote or local asset model path and download progress
const { localPath, downloadProgress, downloadError } = useResourceDownload(
config.modelPath,
options?.preventLoad
);
const { resource, downloadProgress, downloadError } = useResourceDownload(config, options);

// 2. Instantiate and compile the task pipeline (with automatic lifecycle cleanup)
const { model, error } = useModel(
createMyTask,
localPath ? { ...config, modelPath: localPath } : null,
[localPath]
);
const { model, error } = useModel(createMyTask, resource);

return {
isReady: !!model,
error: downloadError || error,
downloadProgress,
localPath,
resource,
runTask: model?.runTask,
runTaskWorklet: model?.runTaskWorklet,
};
Expand Down
20 changes: 10 additions & 10 deletions .agents/skills/model-schema-validation/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
i64,
i32,
DynamicDim as Dyn,
constr,
constraint,
} from '../../../core/schema';

const { variant, dims } = validateSpec(model.schema, {
Expand All @@ -39,7 +39,7 @@ const { variant, dims } = validateSpec(model.schema, {
[i64(1, Dyn('L')), i64(1, Dyn('L'))],
[f32(1, 'D')],
[
constr.eq(
constraint.equality(
{ paramSide: 'input', tensorIdx: 0, dimIdx: 1 },
{ paramSide: 'input', tensorIdx: 1, dimIdx: 1 }
),
Expand All @@ -50,7 +50,7 @@ const { variant, dims } = validateSpec(model.schema, {
[i64(Dyn('L')), i64(Dyn('L'))],
[f32('D')],
[
constr.eq(
constraint.equality(
{ paramSide: 'input', tensorIdx: 0, dimIdx: 0 },
{ paramSide: 'input', tensorIdx: 1, dimIdx: 0 }
),
Expand All @@ -68,10 +68,10 @@ const L = dims.range('L');
- **`f32(...)` / `i64(...)` / `i32(...)` / `ui8(...)`**: Shorthand helpers for tensor parameter specs.
- **`StaticDim('symbol')` / String Literals**: Strings passed to shape helpers (e.g. `'H'`, `'W'`) automatically map to `StaticDim`, acting as **static dimension wildcards**. They bind strictly to `constant` positive integer dimensions in the exported spec.
- **`DynamicDim('symbol')` (or `Dyn('symbol')`)**: Creates a dynamic dimension symbol. Must be used when a dimension genuinely varies at runtime and binds to a `range` or `enum` domain in the exported spec.
- **Constraint Helpers (`constr`)**:
- **Constraint Helpers (`constraint`)**:
- **`DimRef` Object Literal (`{ paramSide: 'input' | 'output', tensorIdx, dimIdx }`)**: Explicit reference to a tensor's dimension.
- **`constr.eq(...dims)`**: Creates an equality constraint requiring the referenced dimensions to take the exact same value at runtime.
- **`constr.linear(lhs, rhs, a, b)`**: Creates a linear constraint `lhs = a * rhs + b`.
- **`constraint.equality(...dims)`**: Creates an equality constraint requiring the referenced dimensions to take the exact same value at runtime.
- **`constraint.linear(lhs, rhs, a, b?)`**: Creates a linear constraint `lhs = a * rhs + b`.
- **`validateSpec(exportedSchema, allowedVariants)`**: Compares the model's exported schema against named variants and returns `{ variant, dim, dims }`.
- **Symbol Accessors (`dims` & `dim`)**:
- `dims.constant('N', 'H')`: Extracts constant values for symbols as numbers.
Expand Down Expand Up @@ -118,24 +118,24 @@ Understanding the distinction between a dimension's **domain** and its **runtime
- Dynamic symbols (`DynamicDim('S')`) bind to exported dimension domains. Reusing a symbol (`'S'`) across tensor inputs or outputs requires every occurrence to bind to the **exact same domain**.
- ⚠️ **Key Rule**: Binding to the same domain does **NOT** mean runtime values coincide! Two dimensions bound to the same domain (e.g., both having range `1..512`) may take _different_ runtime values in a single execution (e.g. length 10 and length 25).

### 2. Runtime Constraints (`constr.eq` & `constr.linear`)
### 2. Runtime Constraints (`constraint.equality` & `constraint.linear`)

- **Runtime Constraints**: Declarations about the **runtime values** of tensor dimensions during execution:
- **Equality Constraint (`constr.eq(...)`)**: Requires all referenced dimensions to take the exact same runtime value in any execution call.
- **Equality Constraint (`constraint.equality(...)`)**: Requires all referenced dimensions to take the exact same runtime value in any execution call.
```typescript
method(
'forward',
[f32('B', Dyn('S1')), f32('B', Dyn('S2'))],
[f32('B', Dyn('S1'))],
[
constr.eq(
constraint.equality(
{ paramSide: 'input', tensorIdx: 0, dimIdx: 0 },
{ paramSide: 'input', tensorIdx: 1, dimIdx: 0 }
),
]
);
```
- **Linear Constraint (`constr.linear(...)`)**: Requires two dimensions to satisfy `dimLhs = a * dimRhs + b` at runtime.
- **Linear Constraint (`constraint.linear(...)`)**: Requires two dimensions to satisfy `dimLhs = a * dimRhs + b` at runtime.
- **Validation & Enforcement**:
- `validateSpec` verifies that the exported model spec declares the exact same runtime constraints (1-to-1 declaration match).
- Native C++ validates input runtime constraints before invoking `model.execute()`.
Expand Down
11 changes: 2 additions & 9 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
const path = require('path');
const typedocConfig = require('./docs/typedoc.json');

const VALID_CATEGORIES = [
'Constants',
'Errors',
'Hooks',
'Types',
'Typescript API',
'Utils',
'Utilities - General',
];
const VALID_CATEGORIES = typedocConfig.categoryOrder.filter((cat) => cat !== '*');

const CATEGORY_TAG_MATCH = `^(${VALID_CATEGORIES.join('|')})$`;

Expand Down
4 changes: 2 additions & 2 deletions apps/computer-vision/app/detection/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ import { BoundingBox } from '../../components/BoundingBox';
const MODEL_OPTIONS: ModelOption[] = [
{
label: 'SSDLite 320 MobileNet V3 Large (XNNPACK FP32)',
value: models.objectDetection.SSDLITE320_MOBILENET_V3_LARGE,
value: models.objectDetection.SSDLITE320_MOBILENET_V3_LARGE.DEFAULT,
},
{
label: 'RF-DETR Nano (XNNPACK FP32)',
value: models.objectDetection.RFDETR_NANO,
value: models.objectDetection.RFDETR_NANO.DEFAULT,
},
{
label: 'RF-DETR Nano (CoreML FP16)',
Expand Down
2 changes: 1 addition & 1 deletion apps/computer-vision/app/imageEmbeddings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ function ImageEmbeddingsContent() {
// Zero-shot classification pairs a CLIP image encoder with the CLIP text
// encoder and scores the image against each text label by embedding similarity.
const imageModel = useImageEmbedder(selectedImageModel);
const textModel = useTextEmbedder(models.textEmbeddings.CLIP_VIT_BASE_PATCH32_TEXT);
const textModel = useTextEmbedder(models.textEmbeddings.CLIP_VIT_BASE_PATCH32_TEXT.DEFAULT);

const ready = imageModel.isReady && textModel.isReady;

Expand Down
6 changes: 3 additions & 3 deletions apps/computer-vision/app/inspect/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import {
Alert,
} from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { inspectModel, type ConcreteDim, type ParamSpec } from 'react-native-executorch';
import { inspectModel, type schema } from 'react-native-executorch';
import ScreenWrapper from '../../components/ScreenWrapper';
import { ColorPalette } from '../../theme';

type InspectionResult = Awaited<ReturnType<typeof inspectModel>>;

const formatDim = (dim: ConcreteDim): string => {
const formatDim = (dim: schema.ConcreteDim): string => {
switch (dim.kind) {
case 'constant':
return `${dim.value}`;
Expand Down Expand Up @@ -55,7 +55,7 @@ function InspectContent() {
};

const renderParamList = (
params: readonly ParamSpec<ConcreteDim>[] | undefined,
params: readonly schema.ParamSpec<schema.ConcreteDim>[] | undefined,
title: string
) => {
if (!params || params.length === 0) return null;
Expand Down
2 changes: 1 addition & 1 deletion apps/computer-vision/app/keypoint/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { BoundingBox } from '../../components/BoundingBox';
const MODEL_OPTIONS: ModelOption[] = [
{
label: 'BlazeFace (XNNPACK FP32)',
value: models.keypointDetection.BLAZEFACE,
value: models.keypointDetection.BLAZEFACE.DEFAULT,
},
{
label: 'YOLO26 Pose (XNNPACK FP32)',
Expand Down
12 changes: 11 additions & 1 deletion apps/computer-vision/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,17 @@
"customConditions": ["react-native"],
"noEmit": true,
"paths": {
"react-native-executorch": ["../../packages/react-native-executorch/src"]
"react-native-executorch": ["../../packages/react-native-executorch/src"],
"react-native-executorch/cv": ["../../packages/react-native-executorch/src/extensions/cv"],
"react-native-executorch/llm": ["../../packages/react-native-executorch/src/extensions/llm"],
"react-native-executorch/nlp": ["../../packages/react-native-executorch/src/extensions/nlp"],
"react-native-executorch/speech": [
"../../packages/react-native-executorch/src/extensions/speech"
],
"react-native-executorch/math": [
"../../packages/react-native-executorch/src/extensions/math"
],
"react-native-executorch/schema": ["../../packages/react-native-executorch/src/core/schema"]
}
}
}
19 changes: 6 additions & 13 deletions apps/nlp/app/llm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,7 @@ import {
import { Skia } from '@shopify/react-native-skia';
import RNBlobUtil from 'react-native-blob-util';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import {
useLLMChatSession,
type LLMGenerationStats,
type LLMKVCacheState,
type ToolCall,
type ChatMessage,
type cv,
} from 'react-native-executorch';
import { useLLMChatSession, type llm, type cv } from 'react-native-executorch';
import ScreenWrapper from '../../components/ScreenWrapper';
import { ModelPicker, type ModelOption } from '../../components/ModelPicker';
import { Button } from '../../components/Button';
Expand All @@ -33,11 +26,11 @@ type Turn = {
role: 'user' | 'assistant' | 'tool';
content: string;
imageUri?: string;
stats?: LLMGenerationStats;
toolCalls?: readonly ToolCall[];
stats?: llm.LLMGenerationStats;
toolCalls?: readonly llm.ToolCall[];
};

function formatStats(stats: LLMGenerationStats): string {
function formatStats(stats: llm.LLMGenerationStats): string {
const decodeMs = stats.inferenceEndMs - stats.firstTokenMs;
const tokensPerSec = decodeMs > 0 ? (stats.numGeneratedTokens / decodeMs) * 1000 : 0;
const decodeTtftMs = stats.firstTokenMs - stats.inferenceStartMs;
Expand Down Expand Up @@ -70,7 +63,7 @@ function LLMContent() {
[]
);

const initialMessages: ChatMessage[] = useMemo(
const initialMessages: llm.ChatMessage[] = useMemo(
() => (activeModel.systemPrompt ? [{ role: 'system', content: activeModel.systemPrompt }] : []),
[activeModel]
);
Expand All @@ -88,7 +81,7 @@ function LLMContent() {
const [turns, setTurns] = useState<Turn[]>([]);
const [streamingResponse, setStreamingResponse] = useState<string | null>(null);

let kvCacheState: LLMKVCacheState | null = null;
let kvCacheState: llm.LLMKVCacheState | null = null;
if (isReady && getKVCacheState) {
try {
kvCacheState = getKVCacheState();
Expand Down
23 changes: 10 additions & 13 deletions apps/nlp/app/privacy-filter/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,7 @@ import {
KeyboardAvoidingView,
Platform,
} from 'react-native';
import {
usePrivacyFilter,
models,
piiSegments,
type PiiEntity,
type PiiSegment,
type PrivacyFilterModel,
} from 'react-native-executorch';
import { usePrivacyFilter, models, nlp, type PrivacyFilterModel } from 'react-native-executorch';
import ScreenWrapper from '../../components/ScreenWrapper';
import { ModelStatus } from '../../components/ModelStatus';
import { Button } from '../../components/Button';
Expand All @@ -33,14 +26,18 @@ Reach her at maria.lopez@example.com or +1 (415) 555-0142. Address: 84 Cedar Hil
/* cspell:enable */

const MODELS: { label: string; value: PrivacyFilterModel; sample: string; iosOnly?: boolean }[] = [
{ label: 'OpenAI (8 types)', value: models.privacyFilter.OPENAI, sample: OPENAI_SAMPLE },
{ label: 'OpenAI (8 types)', value: models.privacyFilter.OPENAI.DEFAULT, sample: OPENAI_SAMPLE },
{
label: 'OpenAI MLX',
value: models.privacyFilter.OPENAI.MLX_INT4,
sample: OPENAI_SAMPLE,
iosOnly: true,
},
{ label: 'Nemotron (55 types)', value: models.privacyFilter.NEMOTRON, sample: NEMOTRON_SAMPLE },
{
label: 'Nemotron (55 types)',
value: models.privacyFilter.NEMOTRON.DEFAULT,
sample: NEMOTRON_SAMPLE,
},
{
label: 'Nemotron MLX',
value: models.privacyFilter.NEMOTRON.MLX_INT8,
Expand All @@ -64,14 +61,14 @@ function PrivacyFilterContent() {
const { isReady, downloadProgress, error, detectPii } = usePrivacyFilter(active.value);

const [text, setText] = useState(active.sample);
const [entities, setEntities] = useState<PiiEntity[] | null>(null);
const [entities, setEntities] = useState<nlp.PiiEntity[] | null>(null);
const [busy, setBusy] = useState(false);
const [runError, setRunError] = useState<string | null>(null);
const [inferenceMs, setInferenceMs] = useState<number | null>(null);

const ready = isReady && !!detectPii;
const segments: PiiSegment[] | null = useMemo(
() => (entities ? piiSegments(text, entities) : null),
const segments: nlp.PiiSegment[] | null = useMemo(
() => (entities ? nlp.piiSegments(text, entities) : null),
[text, entities]
);

Expand Down
22 changes: 14 additions & 8 deletions apps/nlp/app/text-embeddings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,22 @@ const MODELS: {
docPrompt?: string;
iosOnly?: boolean;
}[] = [
{ label: 'MiniLM L6', value: models.textEmbeddings.ALL_MINILM_L6_V2 },
{ label: 'MPNet Base', value: models.textEmbeddings.ALL_MPNET_BASE_V2 },
{ label: 'MultiQA MiniLM', value: models.textEmbeddings.MULTI_QA_MINILM_L6_COS_V1 },
{ label: 'MultiQA MPNet', value: models.textEmbeddings.MULTI_QA_MPNET_BASE_DOT_V1 },
{ label: 'Paraphrase ML', value: models.textEmbeddings.PARAPHRASE_MULTILINGUAL_MINILM_L12_V2 },
{ label: 'DistilUSE ML', value: models.textEmbeddings.DISTILUSE_BASE_MULTILINGUAL_CASED_V2 },
{ label: 'CLIP Text', value: models.textEmbeddings.CLIP_VIT_BASE_PATCH32_TEXT },
{ label: 'MiniLM L6', value: models.textEmbeddings.ALL_MINILM_L6_V2.DEFAULT },
{ label: 'MPNet Base', value: models.textEmbeddings.ALL_MPNET_BASE_V2.DEFAULT },
{ label: 'MultiQA MiniLM', value: models.textEmbeddings.MULTI_QA_MINILM_L6_COS_V1.DEFAULT },
{ label: 'MultiQA MPNet', value: models.textEmbeddings.MULTI_QA_MPNET_BASE_DOT_V1.DEFAULT },
{
label: 'Paraphrase ML',
value: models.textEmbeddings.PARAPHRASE_MULTILINGUAL_MINILM_L12_V2.DEFAULT,
},
{
label: 'DistilUSE ML',
value: models.textEmbeddings.DISTILUSE_BASE_MULTILINGUAL_CASED_V2.DEFAULT,
},
{ label: 'CLIP Text', value: models.textEmbeddings.CLIP_VIT_BASE_PATCH32_TEXT.DEFAULT },
{
label: 'LFM2.5',
value: models.textEmbeddings.LFM2_5_EMBEDDING_350M,
value: models.textEmbeddings.LFM2_5_EMBEDDING_350M.DEFAULT,
docPrompt: 'document: ',
},
{
Expand Down
Loading