@garrix82/reactgenie-dsl
v1.0.4
Published
A natural language parser based on a large language model
Maintainers
Readme
ReactGenieDSL
Decorators, DSL execution, and LLM-backed semantic parsing for ReactGenie-style applications
Fork notice: this package snapshot is maintained as a thesis-project fork by Omkar Mirgal. For the original ReactGenieDSL project, see StanfordHCI/ReactGenieDSL.
Introduction
@omkarfork/reactgenie-dsl is the lower-level engine that powers Genie-based apps.
It provides:
- a decorated object model for app state and actions
- a shared Redux-backed Genie store
- a DSL interpreter for explicit command execution
- an LLM-backed semantic parser that translates natural language into DSL
- structured response generation for spoken and on-screen feedback
- monitoring hooks for parser and response calls
If you need the React integration layer, voice UI, route handling, or screen-aware Current() resolution, use @omkarfork/reactgenie-lib on top of this package.
This README covers installation, quick start, feature overview, and the current public surface. For deeper implementation details and parser/runtime behavior, see DEVELOPER_GUIDE.md.
Feature Overview
ReactGenieDSL currently includes:
- Genie model base classes:
GenieObject,DataClass,HelperClass - decorators:
GenieClass,GenieFunction,GenieProperty,GenieKey - descriptor types:
ClassDescriptor,FuncDescriptor,FieldDescriptor,ParamDescriptor - shared store bootstrap and access:
initGenie,genieDispatch,sharedStore,sharedState,AllGenieObjects - DSL execution with
DslInterpreter - stepwise execution introspection with
interpretSteps(...) - JSON-friendly result shaping with
describe(...)anddescribeSteps(...) - built-in collection operators:
matching(...)contains(...)between(...)equals(...)sort(...)index(...)length()
- natural-language orchestration with
NlInterpreter - parser backends:
NlParserGroqNlParserfor OpenAI-compatible APIs
- prompt generators:
BasicPromptGenDescriptorPromptGenContextAwareDescriptorPromptGen
- parser monitoring with
getLLMMonitor(...) - configurable sampling and provider selection
- structured agent-response generation with normalized fallback handling
Parser Enhancements In The Current Implementation
The current parser stack includes several implementation details beyond the older basic prompt flow:
- context-aware prompt narrowing that selects only relevant class descriptions and examples
- lexical ranking of descriptors/examples without an embeddings dependency
- bounded caching of prompt selections for repeated utterances
- recent-turn memory plus summarized older-turn context
- runtime UI context injection for deictic utterances such as "this", "it", or "current"
- explicit parser rules for:
- named parameters
- array-parameter brackets
- dotted accessor parameters such as
.receivedAt
- structured JSON output for command parsing and agent responses
- lenient-first then strict structured-output retries
- semantic validation of generated commands through a validator interpreter
- automatic repair passes when the generated DSL is semantically invalid
- optional stateful validation retry for the OpenAI Responses path
- normalized response payloads and safe fallback responses when response synthesis fails
- LangSmith-compatible monitoring hooks for prompt, token, latency, and cost tracking
Installation
Install the current package and reflect-metadata:
npm install @omkarfork/reactgenie-dsl reflect-metadataTypeScript and Babel setup
ReactGenieDSL relies on decorator metadata.
TypeScript:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"useDefineForClassFields": false
}
}Babel:
plugins: [
["@babel/plugin-proposal-decorators", { legacy: true }],
["@babel/plugin-transform-class-properties", { loose: true }],
"babel-plugin-parameter-decorator",
"babel-plugin-reactgenie"
]Import reflect-metadata before any decorated Genie classes are evaluated.
Quick Start
1. Define a Genie model
import "reflect-metadata";
import {
DataClass,
GenieClass,
GenieFunction,
GenieKey,
GenieProperty,
int,
} from "@omkarfork/reactgenie-dsl";
@GenieClass("A counter the user can inspect or update")
export class Counter extends DataClass {
@GenieKey
@GenieProperty("Stable counter identifier")
name: string;
@GenieProperty("Current count")
count: int;
static Examples = [
{
user_utterance: "increment the apples counter",
example_parsed: 'Counter.findByName(name: "apples").increment()',
},
{
user_utterance: "what is the apples count",
example_parsed: 'Counter.findByName(name: "apples").count',
},
];
constructor({ name, count = 0 }: { name: string; count?: int }) {
super({ name });
this.name = name;
this.count = count;
}
static setup() {
Counter.CreateObject({ name: "apples", count: 2 });
Counter.CreateObject({ name: "oranges", count: 5 });
}
@GenieFunction("Return the default counter")
static current(): Counter {
return Counter.GetObject({ name: "apples" });
}
@GenieFunction("Find a counter by name")
static findByName({ name }: { name: string }): Counter {
return Counter.GetObject({ name });
}
@GenieFunction("Increase the counter by one")
increment(): this {
this.count += 1;
return this;
}
}Notes:
- use
DataClassfor indexed, retrievable entities - use
HelperClassfor nested value objects - create objects with
CreateObject(...), notnew @GenieFunction()currently expects either no parameters or a single destructured object parameter
2. Initialize Genie
import { initGenie } from "@omkarfork/reactgenie-dsl";
const store = initGenie();initGenie() initializes the shared store, applies registered modifiers, and runs setup() on already-registered classes.
3. Execute explicit DSL
import { AllGenieObjects, DslInterpreter } from "@omkarfork/reactgenie-dsl";
const descriptors = Object.values(AllGenieObjects).map(
(klass: any) => klass.ClassDescriptor
);
const interpreter = new DslInterpreter(descriptors);
await interpreter.interpret('Counter.findByName(name: "apples").increment()');
const value = await interpreter.interpret('Counter.findByName(name: "apples").count');
const described = await interpreter.describe(value);4. Parse natural language into DSL
import {
AllGenieObjects,
ClassDescriptor,
ExampleParse,
GenieObject,
NlInterpreter,
} from "@omkarfork/reactgenie-dsl";
const descriptors = Object.values(AllGenieObjects).map(
(klass: any) => klass.ClassDescriptor as ClassDescriptor<GenieObject>
);
const examples: ExampleParse[] = [
new ExampleParse(
"increment the apples counter",
'Counter.findByName(name: "apples").increment()'
),
new ExampleParse(
"what is the apples count",
'Counter.findByName(name: "apples").count'
),
];
const interpreter = new NlInterpreter(
descriptors,
process.env.LLM_API_KEY!,
undefined,
examples
);
const executionResult = await interpreter.interpret("increment the apples counter");5. Generate a structured response
const response = await interpreter.respond(
"increment the apples counter",
'Counter.findByName(name: "apples").increment()',
JSON.stringify(await interpreter.dslInterpreter.describe(executionResult))
);The response payload shape is:
{
minimalText: string;
fullText: string;
type: "info" | "error" | "success" | "warning";
shouldSpeak: boolean;
}Current DSL Capabilities
ReactGenieDSL currently supports:
- static calls such as
Order.current() - instance calls such as
Order.current().placeOrder() - property access such as
Order.current().status - chained access such as
Order.All().sort(field: .dateTime, ascending: false)[0].restaurant.name - array literals
- negative indexing
- collection filters through
matching,contains,between, andequals - collection sorting through
sort - collection indexing through
index(...)or bracket syntax - collection length via
length()
Important parser rules:
- parameter names must be explicit
- accessor parameters for filters/sort must be dotted accessors such as
.name, not quoted strings - when passing an array expression into a function parameter, the expression must be wrapped in
[...]
Provider Configuration
NlInterpreter supports groq and openai parser providers.
Groq example
const interpreter = new NlInterpreter(
descriptors,
process.env.LLM_API_KEY!,
undefined,
examples,
undefined,
{
parser: {
provider: "groq",
groq: {
model: "llama-3.3-70b-versatile",
baseUrl: "https://api.groq.com/openai/v1",
samplingParams: {
temperature: 0.2,
top_p: 1,
frequency_penalty: 0,
presence_penalty: 0,
},
},
},
}
);OpenAI-compatible example
const interpreter = new NlInterpreter(
descriptors,
process.env.LLM_API_KEY!,
undefined,
examples,
undefined,
{
parser: {
provider: "openai",
openai: {
baseUrl: "https://api.openai.com/v1",
model: "gpt-4o-mini",
statefulValidationRetry: true,
samplingParams: {
temperature: 0.2,
top_p: 1,
frequency_penalty: 0,
presence_penalty: 0,
},
},
},
}
);Provider notes:
- default provider is
groq GENIE_PARSER_PROVIDERcan select the provider if config is omitted- OpenAI mode requires an explicit model
- Groq mode defaults to
llama-3.3-70b-versatile - base URLs are normalized internally to the expected OpenAI-compatible endpoints
Monitoring
The NL stack exposes getLLMMonitor(...) and integrates with LangSmith-style telemetry.
Monitoring supports:
- prompt / completion token counts
- cost metadata when the backend returns it
- latency tracking
- parser/response errors
- optional telemetry bridges for error and message forwarding
Public API At a Glance
Model and decorators
GenieObjectDataClassHelperClassGenieClassGenieFunctionGeniePropertyGenieKeyClassDescriptorFuncDescriptorFieldDescriptorParamDescriptorintfloatLazyType
Store and registry
initGeniegenieDispatchsharedStoresharedStateAllGenieObjects
DSL execution
DslInterpreterInterpreterErrorClassMissingErrorFieldMissingErrorFieldStaticErrorFunctionMissingErrorFunctionStaticErrorInvalidParameterTypeError
NL parsing and prompting
NlInterpreterNlParserNlParserGroqBasicPromptGenDescriptorPromptGenContextAwareDescriptorPromptGenPromptGenExampleParsePromptSelectionConfigPromptRuntimeContextSetterRuntimeUiContextPromptInteractionRecordPromptInteractionRecorderAgentResponsePayloadResponseSeveritySamplingParams
Monitoring
getLLMMonitorLLMMonitorTelemetryBridge
Documentation Split
README.md: install, quick start, feature overview, and public API summaryDEVELOPER_GUIDE.md: deeper package behavior, parser/runtime details, DSL semantics, provider configuration, and troubleshooting
License
Apache-2.0
This package is a thesis-project fork maintained by Omkar Mirgal. For the original ReactGenieDSL project, see StanfordHCI/ReactGenieDSL. See the LICENSE file for the full license text.
