@metta-ts/hyperon 1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MesTTo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,186 @@
1
+ # @metta-ts/hyperon
2
+
3
+ A TypeScript class API for MeTTa atoms, spaces, and a runner, modeled on Hyperon's `hyperon.atoms`
4
+ and `hyperon.base`. Where the Python package wraps a Rust core over FFI, this one wraps the immutable
5
+ terms of [`@metta-ts/core`](../core) in classes. It runs anywhere TypeScript runs, with no native
6
+ addon and no WASM.
7
+
8
+ Hyperon's Python method names are kept as aliases next to the idiomatic TypeScript ones, so code
9
+ ported from `hyperon` reads naturally: `get_name()` sits beside `name()`, `get_children()` beside
10
+ `children()`, `add_atom()` beside `addAtom()`.
11
+
12
+ ## Atoms
13
+
14
+ You build atoms with the short constructors `S`, `V`, `E`, `G`, and `ValueAtom`:
15
+
16
+ ```ts
17
+ import { S, V, E, ValueAtom } from "@metta-ts/hyperon";
18
+
19
+ S("parent"); // a symbol
20
+ V("x"); // a variable, prints as $x
21
+ E(S("parent"), S("tom"), V("c")); // an expression (parent tom $c)
22
+ ValueAtom(42); // a grounded number
23
+ ValueAtom("hi"); // a grounded string, prints as "hi"
24
+ ```
25
+
26
+ Every atom answers `metatype()`, `equals(other)`, `toString()`, `iterate()` (depth-first), and
27
+ `matchAtom(other)`. The kinds are `SymbolAtom`, `VariableAtom`, `ExpressionAtom`, and `GroundedAtom`;
28
+ `SymbolAtom.name()` and `ExpressionAtom.children()` read the parts.
29
+
30
+ ## Matching and bindings
31
+
32
+ `matchAtom` returns a `BindingsSet`, a set of binding frames. An empty set means no match.
33
+
34
+ ```ts
35
+ import { S, V, E, ValueAtom } from "@metta-ts/hyperon";
36
+
37
+ const set = E(S("point"), V("x"), V("y"))
38
+ .matchAtom(E(S("point"), ValueAtom(1), ValueAtom(2)));
39
+
40
+ const frame = set.frames[0];
41
+ frame.resolve(V("x"))?.toString(); // "1"
42
+ frame.resolve(V("y"))?.toString(); // "2"
43
+ ```
44
+
45
+ A `Bindings` frame records associations with `addVarBinding(v, atom)`, reads them with
46
+ `resolve(v)` and `pairs()`, and combines with another frame via `merge`.
47
+
48
+ ## Spaces
49
+
50
+ A `GroundingSpace` holds atoms. You add, query, and substitute:
51
+
52
+ ```ts
53
+ import { GroundingSpace, S, V, E } from "@metta-ts/hyperon";
54
+
55
+ const sp = new GroundingSpace();
56
+ sp.addAtom(E(S("parent"), S("tom"), S("bob")));
57
+ sp.addAtom(E(S("parent"), S("tom"), S("liz")));
58
+
59
+ sp.subst(E(S("parent"), S("tom"), V("c")), V("c"))
60
+ .map((a) => a.toString()); // ["bob", "liz"]
61
+ ```
62
+
63
+ For a Distributed AtomSpace backend, see [`@metta-ts/das-client`](../das-client), whose `DasLiveSpace`
64
+ is the async analogue (a remote query is a network round-trip).
65
+
66
+ ## Running MeTTa
67
+
68
+ The `MeTTa` runner evaluates programs and keeps its knowledge base across `run` calls.
69
+ Non-bang atoms extend the knowledge base; each `!`-query returns its results.
70
+
71
+ ```ts
72
+ import { MeTTa } from "@metta-ts/hyperon";
73
+
74
+ const m = new MeTTa();
75
+ m.run("(= (color) red)\n(= (color) green)");
76
+ m.run("!(color)")[0].map((a) => a.toString()); // ["red", "green"]
77
+ m.run("!(+ 1 2)")[0].map((a) => a.toString()); // ["3"]
78
+ ```
79
+
80
+ `registerOperation(name, fn)` adds a grounded operation callable from
81
+ MeTTa source; the function takes the argument atoms and returns the result atoms:
82
+
83
+ ```ts
84
+ import { MeTTa, ValueAtom, GroundedAtom } from "@metta-ts/hyperon";
85
+
86
+ const m = new MeTTa();
87
+ m.registerOperation("double", (args) => {
88
+ const n = (args[0] as GroundedAtom).object().content as number;
89
+ return [ValueAtom(n * 2)];
90
+ });
91
+ m.run("!(double 21)")[0].map((a) => a.toString()); // ["42"]
92
+ ```
93
+
94
+ `registerToken(regex, constr)` registers a custom token, `space()` exposes the knowledge base, and
95
+ `getAtomTypes(atom)` returns the types the runner infers for an atom.
96
+
97
+ The runner's `space()` is live: an atom added through it reaches the evaluator
98
+ exactly as a non-bang atom in `run` does, querying it sees what the evaluator sees, and removing an
99
+ atom retracts it from evaluation.
100
+
101
+ ```ts
102
+ const m = new MeTTa();
103
+ m.space().addAtom(parseRule("(= (greeting) hello)")); // reaches evaluation
104
+ m.run("!(greeting)")[0].map((a) => a.toString()); // ["hello"]
105
+ ```
106
+
107
+ ## Grounded objects
108
+
109
+ `ValueObject`, `OperationObject`, and `MatchableObject` wrap a JS value, a function, or a
110
+ custom-matching value. `ValueAtom` converts primitives for you (`number` to Number, `string` to
111
+ String, `boolean` to Bool); `G(obj, type?)` wraps any `GroundedObject`, and `GroundedAtom.object()`
112
+ recovers it.
113
+
114
+ Wrapping a non-primitive object registers it in a process-global table (the core's grounded value
115
+ carries only an id, and the object must outlive any single wrapper). A long-running host that creates
116
+ many grounded objects can reclaim that memory with `clearGroundedObjects()` once no grounded `ext`
117
+ atom is still in use.
118
+
119
+ ## Optional modules
120
+
121
+ Two grounded-operation modules from hyperon-experimental ship as opt-in registrations on a runner.
122
+
123
+ The JSON module gives you `dict-space`, `get-keys`, `get-value`, `json-decode`, and `json-encode`:
124
+
125
+ ```ts
126
+ import { MeTTa, registerJsonModule } from "@metta-ts/hyperon";
127
+
128
+ const m = new MeTTa();
129
+ registerJsonModule(m);
130
+ m.run('!(json-decode "[1, 2, 3]")')[0].map((a) => a.toString()); // ["(1 2 3)"]
131
+ m.run('(= (d) (dict-space ((a 1) (b 2))))');
132
+ m.run("!(get-value (d) a)")[0].map((a) => a.toString()); // ["1"]
133
+ ```
134
+
135
+ The module catalog gives you `catalog-clear!`, `catalog-list!`, and `catalog-update!` over a
136
+ `ModuleCatalog` you populate yourself (the dependency-free analogue of Hyperon's remote catalogs):
137
+
138
+ ```ts
139
+ import { MeTTa, ModuleCatalog, registerCatalogModule } from "@metta-ts/hyperon";
140
+
141
+ const m = new MeTTa();
142
+ const catalog = new ModuleCatalog();
143
+ catalog.register("local", ["mod-a", "mod-b"]);
144
+ registerCatalogModule(m, catalog);
145
+ m.run("!(catalog-list! all)"); // returns (); records into catalog.listing
146
+ ```
147
+
148
+ ## JavaScript interop
149
+
150
+ Hyperon's Python binding has `py-atom`/`py-dot` to call Python from MeTTa, bridged over FFI. Here the
151
+ engine is TypeScript, so there is no bridge: a grounded atom can hold a JS function and the interpreter
152
+ runs it directly. `registerJsInterop(m)` exposes that (opt-in, since it can call arbitrary global JS):
153
+
154
+ ```ts
155
+ import { MeTTa, registerJsInterop } from "@metta-ts/hyperon";
156
+
157
+ const m = new MeTTa();
158
+ registerJsInterop(m);
159
+ m.run(`!((js-atom "Math.abs") -5)`)[0]; // 5
160
+ m.run(`!((js-atom "Math.max") 3 7 2)`)[0]; // 7
161
+ m.run(`!((js-dot "hello world" "toUpperCase"))`)[0]; // "HELLO WORLD"
162
+ m.run(`!((js-dot (js-list (5 1 3)) "join") "-")`)[0]; // "5-1-3"
163
+ m.run(`!(js-dot (js-dict (("a" 1) ("b" 2))) "b")`)[0]; // 2
164
+ ```
165
+
166
+ `js-atom` resolves a dotted path from `globalThis` into a grounded atom (an executable one if it is a
167
+ function); `js-dot` reads a property or method (methods come back bound to their object); `js-list` and
168
+ `js-dict` build a JS array or object from MeTTa atoms.
169
+
170
+ An `OperationAtom` that heads an expression is run by the interpreter, so a JS function wrapped as an
171
+ atom is callable in-language. That is also what makes `registerAtom` with an `OperationAtom` work like
172
+ Python's `bind! abs (py-atom ...)`:
173
+
174
+ ```ts
175
+ m.registerAtom("dbl", OperationAtom("dbl", (a) =>
176
+ [ValueAtom((a as GroundedAtom).object().content as number * 2)]));
177
+ m.run("!(dbl 21)")[0]; // 42
178
+ ```
179
+
180
+ A grounded operation that throws surfaces as a MeTTa `(Error ...)` atom (an error the program can
181
+ still inspect) rather than crashing the run. `evaluateAtom(atom)` evaluates a single constructed atom
182
+ (the atom-level counterpart of `run`).
183
+
184
+ ## Docs
185
+
186
+ API docs are generated with TypeDoc from the TSDoc comments: `pnpm --filter @metta-ts/hyperon docs`.
@@ -0,0 +1,436 @@
1
+ import * as core from '@metta-ts/core';
2
+
3
+ /**
4
+ * Variable bindings, modeled on Hyperon's `Bindings` and `BindingsSet`. A {@link Bindings} is one
5
+ * variable-to-atom frame; a {@link BindingsSet} is the set of frames produced by a match. They wrap the
6
+ * core's immutable binding relations behind a small mutable API.
7
+ */
8
+
9
+ /** One frame of variable-to-atom associations. */
10
+ declare class Bindings {
11
+ private rels;
12
+ /** The underlying immutable core relations. Replaced (not mutated) by the mutating methods. */
13
+ constructor(rels?: core.Bindings);
14
+ /** The core relations backing this frame. */
15
+ raw(): core.Bindings;
16
+ /** The atom bound to a variable, if any. */
17
+ resolve(variable: VariableAtom): Atom | undefined;
18
+ /** Bind a variable to an atom; returns `true` (the binding is recorded). */
19
+ addVarBinding(variable: VariableAtom, atom: Atom): boolean;
20
+ /** Python alias of {@link addVarBinding}. */
21
+ add_var_binding(variable: VariableAtom, atom: Atom): boolean;
22
+ /** Assert that two variables are equal (`$a = $b`); returns `true`. */
23
+ addVarEquality(a: VariableAtom, b: VariableAtom): boolean;
24
+ /** Python alias of {@link addVarEquality}. */
25
+ add_var_equality(a: VariableAtom, b: VariableAtom): boolean;
26
+ /** True when this frame has no associations. */
27
+ isEmpty(): boolean;
28
+ /** Python alias of {@link isEmpty}. */
29
+ is_empty(): boolean;
30
+ /** The variable-atom pairs in this frame. */
31
+ pairs(): [VariableAtom, Atom][];
32
+ /** Python alias of {@link pairs}. */
33
+ iterator(): [VariableAtom, Atom][];
34
+ /** Keep only the associations for the given variables. */
35
+ narrowVars(vars: VariableAtom[]): Bindings;
36
+ /** Python alias of {@link narrowVars}. */
37
+ narrow_vars(vars: VariableAtom[]): Bindings;
38
+ /** Merge with another frame, yielding the consistent combinations as a {@link BindingsSet}. */
39
+ merge(other: Bindings): BindingsSet;
40
+ /** A copy of this frame (the core relations are immutable, so the copy is independent). */
41
+ clone(): Bindings;
42
+ equals(other: Bindings): boolean;
43
+ toString(): string;
44
+ }
45
+ /** A set of binding frames; the result of a match. An empty set means no match; a set with one
46
+ * empty frame means a match that binds nothing (variables may take any value). */
47
+ declare class BindingsSet {
48
+ readonly frames: Bindings[];
49
+ constructor(frames?: Bindings[]);
50
+ /** A set with no frames (no valid match). */
51
+ static empty(): BindingsSet;
52
+ /** A set with a single empty frame (a match binding nothing). */
53
+ static single(): BindingsSet;
54
+ /** True when there are no frames. */
55
+ isEmpty(): boolean;
56
+ /** Python alias of {@link isEmpty}. */
57
+ is_empty(): boolean;
58
+ /** True when there is exactly one frame and it binds nothing. */
59
+ isSingle(): boolean;
60
+ /** Python alias of {@link isSingle}. */
61
+ is_single(): boolean;
62
+ /** The frame at an index. */
63
+ get(index: number): Bindings | undefined;
64
+ /** Iterate the frames. */
65
+ iterator(): Bindings[];
66
+ /** Add a frame to the set. */
67
+ push(bindings: Bindings): void;
68
+ /** Bind a variable to an atom in every frame; returns `true`. */
69
+ addVarBinding(variable: VariableAtom, value: Atom): boolean;
70
+ /** Python alias of {@link addVarBinding}. */
71
+ add_var_binding(variable: VariableAtom, value: Atom): boolean;
72
+ /** Assert that two variables are equal in every frame; returns `true`. */
73
+ addVarEquality(a: VariableAtom, b: VariableAtom): boolean;
74
+ /** Python alias of {@link addVarEquality}. */
75
+ add_var_equality(a: VariableAtom, b: VariableAtom): boolean;
76
+ /** Merge another set (or frame) into this one (cartesian merge of frames). */
77
+ mergeInto(input: BindingsSet | Bindings): void;
78
+ /** Python alias of {@link mergeInto}. */
79
+ merge_into(input: BindingsSet | Bindings): void;
80
+ /** A copy of this set. */
81
+ clone(): BindingsSet;
82
+ toString(): string;
83
+ }
84
+
85
+ /**
86
+ * Atom API: a TypeScript class surface over the functional `@metta-ts/core` term model, modeled on
87
+ * Hyperon's `hyperon.atoms`. It wraps immutable core atoms in classes; it does not bridge Python, Rust,
88
+ * or FFI. Python aliases (`get_name`, `get_metatype`, ...) sit beside idiomatic names (`name`,
89
+ * `metatype`, ...) for ported code.
90
+ */
91
+
92
+ /** The kind of an atom: `Symbol`, `Variable`, `Expression`, or `Grounded`. */
93
+ type MetaType = core.MetaType;
94
+ /**
95
+ * Base class for every atom. Wraps one immutable core atom (`catom`) and exposes shared operations:
96
+ * metatype, structural equality, rendering, depth-first iteration, and matching.
97
+ */
98
+ declare abstract class Atom {
99
+ readonly catom: core.Atom;
100
+ protected constructor(catom: core.Atom);
101
+ /** Wrap a core atom in the matching subclass. */
102
+ static fromCAtom(c: core.Atom): Atom;
103
+ /** The metatype (kind) of this atom. */
104
+ metatype(): MetaType;
105
+ /** Python alias of {@link metatype}. */
106
+ get_metatype(): MetaType;
107
+ /** Structural equality with another atom. */
108
+ equals(other: Atom): boolean;
109
+ /** MeTTa source rendering. */
110
+ toString(): string;
111
+ /** This atom and all descendants, depth-first (Hyperon `iterate`). */
112
+ iterate(): Atom[];
113
+ /** Match this atom against another, returning every resulting binding frame. */
114
+ matchAtom(other: Atom): BindingsSet;
115
+ /** Python alias of {@link matchAtom}. */
116
+ match_atom(other: Atom): BindingsSet;
117
+ }
118
+ /** A symbol: a single named concept. Symbols with the same name are the same atom. */
119
+ declare class SymbolAtom extends Atom {
120
+ /** Wrap a core symbol atom. */
121
+ constructor(catom: core.Atom);
122
+ /** The symbol's name. */
123
+ name(): string;
124
+ /** Python alias of {@link name}. */
125
+ get_name(): string;
126
+ }
127
+ /** A variable: a placeholder that can be bound during matching. */
128
+ declare class VariableAtom extends Atom {
129
+ /** Wrap a core variable atom. */
130
+ constructor(catom: core.Atom);
131
+ /** The variable's name (without the leading `$`). */
132
+ name(): string;
133
+ /** Python alias of {@link name}. */
134
+ get_name(): string;
135
+ /** Construct a variable from a name (Hyperon `parse_name`). */
136
+ static parseName(name: string): VariableAtom;
137
+ }
138
+ /** An expression: an ordered tuple of child atoms. */
139
+ declare class ExpressionAtom extends Atom {
140
+ /** Wrap a core expression atom. */
141
+ constructor(catom: core.Atom);
142
+ /** The child atoms, in order. */
143
+ children(): Atom[];
144
+ /** Python alias of {@link children}. */
145
+ get_children(): Atom[];
146
+ }
147
+ /** Wraps arbitrary content inside a grounded atom, optionally with a display id. */
148
+ declare class GroundedObject {
149
+ readonly content: unknown;
150
+ readonly id?: string | undefined;
151
+ constructor(content: unknown, id?: string | undefined);
152
+ toString(): string;
153
+ /** A copy of this object (content is shared). */
154
+ copy(): GroundedObject;
155
+ }
156
+ /** A grounded object compared by the equality of its content. */
157
+ declare class ValueObject extends GroundedObject {
158
+ /** The wrapped value. */
159
+ get value(): unknown;
160
+ equals(other: ValueObject): boolean;
161
+ }
162
+ /** A value object that can define custom matching against an atom (Hyperon `MatchableObject`). */
163
+ declare class MatchableObject extends ValueObject {
164
+ /** Override to define matching behavior. Throws by default. */
165
+ match_(atom: Atom): unknown[];
166
+ }
167
+ /** A grounded operation: a named function callable as a grounded atom. */
168
+ declare class OperationObject extends GroundedObject {
169
+ readonly opName: string;
170
+ readonly op: (...args: Atom[]) => Atom[];
171
+ readonly unwrap: boolean;
172
+ constructor(opName: string, op: (...args: Atom[]) => Atom[], unwrap?: boolean);
173
+ /** Run the operation over the argument atoms. */
174
+ execute(...args: Atom[]): Atom[];
175
+ }
176
+ /** Drop every registered grounded object. Call only when no grounded `ext` atom is still in use;
177
+ * afterwards `GroundedAtom.object()` on a cleared atom degrades to a `ValueObject` over its string id. */
178
+ declare function clearGroundedObjects(): void;
179
+ /** A grounded atom: value, space, or operation content wrapped as an atom. */
180
+ declare class GroundedAtom extends Atom {
181
+ private obj;
182
+ /** Wrap a core grounded atom, optionally remembering the JS object behind it. */
183
+ constructor(catom: core.Atom, obj?: GroundedObject);
184
+ /** The wrapped object: the original `GroundedObject` if known, otherwise a `ValueObject` over the
185
+ * grounded value. The result is cached so repeated calls return the same instance. */
186
+ object(): GroundedObject;
187
+ /** Python alias of {@link object}. */
188
+ get_object(): GroundedObject;
189
+ /** The plain JS value behind this grounded atom, typed as `T`. */
190
+ jsValue<T = unknown>(): T;
191
+ /** The grounded type atom. */
192
+ groundedType(): Atom;
193
+ /** Python alias of {@link groundedType}. */
194
+ get_grounded_type(): Atom;
195
+ }
196
+ /** The plain JS value behind a core ground (numbers, strings, booleans; `undefined` for unit). */
197
+ declare function groundToJs(g: core.Ground): unknown;
198
+ /** Construct a {@link SymbolAtom}. */
199
+ declare const S: (name: string) => SymbolAtom;
200
+ /** Construct a {@link VariableAtom}. */
201
+ declare const V: (name: string) => VariableAtom;
202
+ /** Construct an {@link ExpressionAtom} from child atoms. */
203
+ declare const E: (...children: Atom[]) => ExpressionAtom;
204
+ /** Construct a {@link GroundedAtom} from a grounded object, optionally typed. An `OperationObject`
205
+ * becomes executable: when it heads `(<atom> arg...)`, the interpreter runs its operation. */
206
+ declare function G(obj: GroundedObject, type?: Atom): GroundedAtom;
207
+ /**
208
+ * Wrap a JS value in a grounded atom. Without `typeName`, primitives become MeTTa primitives
209
+ * (`number` -> Number, `string` -> String, `boolean` -> Bool) and anything else is wrapped in a
210
+ * {@link ValueObject}. With `typeName`, the value is always wrapped in a `ValueObject` carrying that
211
+ * type, so the requested type is honored for primitives too.
212
+ */
213
+ declare function ValueAtom(value: unknown, typeName?: string): GroundedAtom;
214
+ /** Construct a grounded operation atom (Hyperon `OperationAtom`). The operation runs over atoms;
215
+ * register it in a {@link MeTTa} runner's tokenizer/grounding to call it from MeTTa source. */
216
+ declare function OperationAtom(name: string, op: (...args: Atom[]) => Atom[], unwrap?: boolean): GroundedAtom;
217
+ /** The built-in type atoms (Hyperon `AtomType`). */
218
+ declare const AtomType: {
219
+ /** `%Undefined%`. */
220
+ readonly UNDEFINED: SymbolAtom;
221
+ /** `Type`. */
222
+ readonly TYPE: SymbolAtom;
223
+ /** `Atom`. */
224
+ readonly ATOM: SymbolAtom;
225
+ /** `Symbol`. */
226
+ readonly SYMBOL: SymbolAtom;
227
+ /** `Variable`. */
228
+ readonly VARIABLE: SymbolAtom;
229
+ /** `Expression`. */
230
+ readonly EXPRESSION: SymbolAtom;
231
+ /** `Grounded`. */
232
+ readonly GROUNDED: SymbolAtom;
233
+ /** `Number`. */
234
+ readonly NUMBER: SymbolAtom;
235
+ /** `Bool`. */
236
+ readonly BOOL: SymbolAtom;
237
+ /** `String`. */
238
+ readonly STRING: SymbolAtom;
239
+ };
240
+ /** Display type name for an atom, for use in error messages (e.g. `Number`, `String`,
241
+ * `Symbol`, `Expression`). Grounded atoms report their value type rather than just `Grounded`. */
242
+ declare function friendlyTypeName(atom: Atom): string;
243
+ /** True when an atom is an `(Error ...)` expression. */
244
+ declare function atomIsError(atom: Atom): boolean;
245
+ /** True when two atoms are alpha-equivalent (equal up to consistent variable renaming). */
246
+ declare function atomsAreEquivalent(first: Atom, second: Atom): boolean;
247
+
248
+ /**
249
+ * Runtime API: spaces, tokenizer, parser, and MeTTa runner, modeled on Hyperon's `hyperon.base` and
250
+ * `hyperon.runner`. TypeScript surface over `@metta-ts/core`.
251
+ */
252
+
253
+ /** A reference to a Space: a store of atoms that can be added to, queried, and substituted over. */
254
+ declare class SpaceRef {
255
+ readonly space: core.Space;
256
+ constructor(space: core.Space);
257
+ /** Add an atom to the space. */
258
+ addAtom(atom: Atom): void;
259
+ /** Python alias of {@link addAtom}. */
260
+ add_atom(atom: Atom): void;
261
+ /** Remove an atom from the space; returns whether one was removed. */
262
+ removeAtom(atom: Atom): boolean;
263
+ /** Python alias of {@link removeAtom}. */
264
+ remove_atom(atom: Atom): boolean;
265
+ /** Every atom in the space. */
266
+ getAtoms(): Atom[];
267
+ /** Python alias of {@link getAtoms}. */
268
+ get_atoms(): Atom[];
269
+ /** The number of atoms in the space. */
270
+ atomCount(): number;
271
+ /** Python alias of {@link atomCount}. */
272
+ atom_count(): number;
273
+ /** Match a pattern against the space, returning the binding frames. */
274
+ query(pattern: Atom): BindingsSet;
275
+ /** Match `pattern`, then instantiate `template` under each resulting binding. */
276
+ subst(pattern: Atom, template: Atom): Atom[];
277
+ }
278
+ /** A space implemented in memory (Hyperon `GroundingSpace`). */
279
+ declare class GroundingSpace extends SpaceRef {
280
+ constructor();
281
+ }
282
+ /** Turns words and string literals into atoms via registered `(regex, constructor)` pairs. */
283
+ declare class Tokenizer {
284
+ readonly ctok: core.Tokenizer;
285
+ constructor(ctok?: core.Tokenizer);
286
+ /** Register a token: text matching `regex` becomes the atom built by `constr`. */
287
+ registerToken(regex: RegExp, constr: (token: string) => Atom): void;
288
+ /** Python alias of {@link registerToken}. */
289
+ register_token(regex: RegExp, constr: (token: string) => Atom): void;
290
+ }
291
+ /** Parses S-expression MeTTa text into atoms, using a {@link Tokenizer} for leaf tokens. */
292
+ declare class SExprParser {
293
+ private readonly text;
294
+ constructor(text: string);
295
+ /** Parse the first atom (Hyperon `parse`). */
296
+ parse(tokenizer: Tokenizer): Atom | undefined;
297
+ /** Parse every top-level atom. */
298
+ parseAll(tokenizer: Tokenizer): Atom[];
299
+ }
300
+ /**
301
+ * MeTTa runner. Evaluates programs while preserving a knowledge base and grounding across calls
302
+ * (REPL-style). Build it, `run` source, register tokens and grounded operations.
303
+ */
304
+ declare class MeTTa {
305
+ private readonly gt;
306
+ private readonly tok;
307
+ private env;
308
+ private st;
309
+ private readonly kb;
310
+ private readonly _space;
311
+ constructor();
312
+ private addToKb;
313
+ private removeFromKb;
314
+ /** Run MeTTa source. Non-bang atoms extend the knowledge base; each `!`-query yields its results.
315
+ * Returns one atom list per `!`-query, in order. */
316
+ run(program: string, fuel?: number): Atom[][];
317
+ /** Run MeTTa source asynchronously, awaiting any async grounded operations (registered with
318
+ * {@link registerAsyncOperation}). Identical to {@link run} for a program with no async ops. */
319
+ runAsync(program: string, fuel?: number): Promise<Atom[][]>;
320
+ /** Register an async grounded operation callable from MeTTa source by `name` (resolved by the async
321
+ * runner). The function receives argument atoms and resolves to result atoms. A rejection becomes a
322
+ * MeTTa `(Error ...)` atom. Use it for I/O: fetch, a DAS query, a timer. */
323
+ registerAsyncOperation(name: string, op: (args: Atom[]) => Promise<Atom[]>): void;
324
+ /** Parse every top-level atom of a program. */
325
+ parseAll(program: string): Atom[];
326
+ /** Parse the first atom of a program. */
327
+ parseSingle(program: string): Atom | undefined;
328
+ /** Evaluate a single atom against the runner's knowledge base (Hyperon `evaluate_atom`); returns its
329
+ * results. Unlike `run`, it takes an atom rather than source text. */
330
+ evaluateAtom(atom: Atom, fuel?: number): Atom[];
331
+ /** Python alias of {@link evaluateAtom}. */
332
+ evaluate_atom(atom: Atom, fuel?: number): Atom[];
333
+ /** Evaluate a single atom, awaiting any async grounded operations reached during evaluation (those
334
+ * registered with {@link registerAsyncOperation}). Identical to {@link evaluateAtom} when no async op
335
+ * is reached. */
336
+ evaluateAtomAsync(atom: Atom, fuel?: number): Promise<Atom[]>;
337
+ /** The runner's top-level space. Atoms added through it reach the evaluator's knowledge base
338
+ * (same as a non-bang atom in `run`), and querying it sees what the evaluator sees. Removing an
339
+ * atom retracts it from evaluation too. */
340
+ space(): SpaceRef;
341
+ /** The runner's tokenizer. */
342
+ tokenizer(): Tokenizer;
343
+ /** Register a custom token (text matching `regex` becomes `constr`'s atom). */
344
+ registerToken(regex: RegExp, constr: (token: string) => Atom): void;
345
+ /** Register a symbol as a token that produces a fixed atom. */
346
+ registerAtom(name: string, atom: Atom): void;
347
+ /** Register a grounded operation callable from MeTTa source by `name`. The function receives argument
348
+ * atoms and returns result atoms. A thrown error becomes a MeTTa `(Error ...)` atom instead of
349
+ * crashing the run. Throw {@link IncorrectArgumentError} to leave the expression unevaluated so other
350
+ * rewrite rules can try (MeTTa's multiple dispatch on a type mismatch). */
351
+ registerOperation(name: string, op: (args: Atom[]) => Atom[]): void;
352
+ /** Every type the runner infers for an atom (Hyperon `get_atom_types`). */
353
+ getAtomTypes(atom: Atom): Atom[];
354
+ /** Python alias of {@link getAtomTypes}. */
355
+ get_atom_types(atom: Atom): Atom[];
356
+ }
357
+ /** Throw this from a {@link MeTTa.registerOperation} handler to signal wrong arguments and leave the
358
+ * expression unevaluated for other rules (the core's `incorrectArgument`) instead of producing a hard
359
+ * `(Error ...)` atom. */
360
+ declare class IncorrectArgumentError extends Error {
361
+ }
362
+ /** The MeTTa standard tokenizer as a wrapped {@link Tokenizer} (integers, floats, `True`/`False`). */
363
+ declare function standardTokenizer(): Tokenizer;
364
+
365
+ /**
366
+ * JSON module, modeled on hyperon-experimental's `hyperon.stdlib` JSON operations. Register it on a
367
+ * {@link MeTTa} runner to make these grounded operations callable from MeTTa source:
368
+ *
369
+ * - `dict-space` `(-> Expression Grounded)`: build a Space of `(key value)` pairs.
370
+ * - `get-keys` `(-> Grounded Atom)`: every key in a dict-space (one result per key).
371
+ * - `get-value` `(-> Grounded Atom %Undefined%)`: the value tied to a key (empty if absent).
372
+ * - `json-decode` `(-> String Atom)`: JSON text to MeTTa (array to expression, object to dict-space,
373
+ * string to String, number to Number, bool to Bool, null to `null`).
374
+ * - `json-encode` `(-> Atom String)`: MeTTa to JSON text (the inverse).
375
+ */
376
+
377
+ /** A grounded value wrapping a Space, so a dict-space round-trips through grounded atoms. */
378
+ declare class SpaceValue extends ValueObject {
379
+ readonly space: GroundingSpace;
380
+ constructor(space: GroundingSpace);
381
+ toString(): string;
382
+ }
383
+ /** Register the JSON module's operations on a runner. */
384
+ declare function registerJsonModule(m: MeTTa): void;
385
+
386
+ /** An in-memory registry of named module catalogs. */
387
+ declare class ModuleCatalog {
388
+ private readonly catalogs;
389
+ /** One line per `catalog-list!` call, so tests and UIs can observe the side effect. */
390
+ readonly listing: string[];
391
+ /** The names of catalogs updated by `catalog-update!`. */
392
+ readonly updated: string[];
393
+ /** Add or replace a named catalog's module list. */
394
+ register(name: string, modules: string[]): void;
395
+ /** The module names in a catalog. */
396
+ modules(name: string): string[];
397
+ /** The catalog names, in insertion order. */
398
+ names(): string[];
399
+ private targets;
400
+ /** Clear one catalog (or `all`). */
401
+ clear(target: string): void;
402
+ /** Record the contents of one catalog (or `all`) into {@link listing}. */
403
+ list(target: string): void;
404
+ /** Mark one catalog (or `all`) updated. */
405
+ update(target: string): void;
406
+ }
407
+ /** Register the catalog operations on a runner, backed by the given catalog. */
408
+ declare function registerCatalogModule(m: MeTTa, catalog: ModuleCatalog): void;
409
+
410
+ /**
411
+ * JavaScript interop, the TypeScript analogue of Hyperon's Python interop (py-atom/py-dot/py-list/
412
+ * py-dict). The MeTTa engine runs in TypeScript, so a grounded atom can hold a JS function and the
413
+ * interpreter executes it directly (see GroundedAtom exec wiring). Register with `registerJsInterop(m)`;
414
+ * opt-in because it can resolve and call arbitrary global JS.
415
+ *
416
+ * - `js-atom` `(js-atom "Math.abs")`: resolve a dotted path from `globalThis` into a grounded atom
417
+ * (an executable one if it is a function), e.g. `((js-atom "Math.abs") -5)` -> 5.
418
+ * - `js-dot` `(js-dot <obj> "prop")`: read a property/method of a wrapped JS object; a method is
419
+ * returned bound to the object so `((js-dot <s> "toUpperCase"))` works.
420
+ * - `js-list` `(js-list (1 2 3))`: a JS array from the expression's elements.
421
+ * - `js-dict` `(js-dict (("a" 1) ("b" 2)))`: a JS object from (key value) pairs.
422
+ */
423
+
424
+ /** Marks a grounded atom that wraps an arbitrary JS value (object/array), for round-tripping. */
425
+ declare class JsValue extends ValueObject {
426
+ }
427
+ /** The plain JS value behind an atom: wrapped JS values unwrap to themselves, grounded primitives to
428
+ * their content, symbols to their name, expressions to arrays; everything else to its text. */
429
+ declare function atomToJs(atom: Atom): unknown;
430
+ /** Wrap a JS value as an atom: functions become executable operation atoms, primitives become grounded
431
+ * primitives, everything else is wrapped in a {@link JsValue} grounded atom. */
432
+ declare function jsToAtom(value: unknown): Atom;
433
+ /** Register the JS interop operations on a runner. */
434
+ declare function registerJsInterop(m: MeTTa): void;
435
+
436
+ export { Atom, AtomType, Bindings, BindingsSet, E, ExpressionAtom, G, GroundedAtom, GroundedObject, GroundingSpace, IncorrectArgumentError, JsValue, MatchableObject, MeTTa, type MetaType, ModuleCatalog, OperationAtom, OperationObject, S, SExprParser, SpaceRef, SpaceValue, SymbolAtom, Tokenizer, V, ValueAtom, ValueObject, VariableAtom, atomIsError, atomToJs, atomsAreEquivalent, clearGroundedObjects, friendlyTypeName, groundToJs, jsToAtom, registerCatalogModule, registerJsInterop, registerJsonModule, standardTokenizer };