@getenki/ai-darwin-arm64 0.2.5 → 0.2.7

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 (2) hide show
  1. package/README.md +440 -2
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,3 +1,441 @@
1
- # `@getenki/ai-darwin-arm64`
1
+ # `@getenki/ai`
2
2
 
3
- This is the **aarch64-apple-darwin** binary for `@getenki/ai`
3
+ Node.js bindings for Enki's Rust agent runtime, published as a native package via `napi-rs`.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @getenki/ai
9
+ ```
10
+
11
+ The package ships prebuilt native binaries for:
12
+
13
+ - Windows x64 and arm64
14
+ - macOS x64 and arm64
15
+ - Linux x64 and arm64 (GNU libc)
16
+
17
+ ## What It Exports
18
+
19
+ The current package surface is intentionally small:
20
+
21
+ - `NativeEnkiAgent`
22
+ - `JsMemoryKind`
23
+ - `JsMemoryModule`
24
+ - `JsMemoryEntry`
25
+
26
+ `NativeEnkiAgent` is the main entrypoint. It can be created in four modes:
27
+
28
+ - `new(...)` for a plain agent
29
+ - `NativeEnkiAgent.withTools(...)`
30
+ - `NativeEnkiAgent.withMemory(...)`
31
+ - `NativeEnkiAgent.withToolsAndMemory(...)`
32
+
33
+ ## Basic Agent
34
+
35
+ Use the constructor when you only need a session-based agent backed by the native runtime.
36
+
37
+ ```js
38
+ const { NativeEnkiAgent } = require('@getenki/ai')
39
+
40
+ async function main() {
41
+ const agent = new NativeEnkiAgent(
42
+ 'Assistant',
43
+ 'Answer clearly and keep responses short.',
44
+ 'ollama::qwen3.5:latest',
45
+ 20,
46
+ process.cwd(),
47
+ )
48
+
49
+ const output = await agent.run('session-1', 'Explain what this project does.')
50
+ console.log(output)
51
+ }
52
+
53
+ main().catch(console.error)
54
+ ```
55
+
56
+ TypeScript version:
57
+
58
+ ```ts
59
+ import { NativeEnkiAgent } from '@getenki/ai'
60
+
61
+ const agent = new NativeEnkiAgent(
62
+ 'Assistant',
63
+ 'Answer clearly and keep responses short.',
64
+ 'ollama::qwen3.5:latest',
65
+ 20,
66
+ process.cwd(),
67
+ )
68
+
69
+ const output = await agent.run('session-1', 'Explain what this project does.')
70
+ console.log(output)
71
+ ```
72
+
73
+ Constructor arguments:
74
+
75
+ - `name?: string`
76
+ - `systemPromptPreamble?: string`
77
+ - `model?: string`
78
+ - `maxIterations?: number`
79
+ - `workspaceHome?: string`
80
+
81
+ If omitted, the runtime falls back to built-in defaults for name, prompt, and max iterations.
82
+
83
+ ## Tools
84
+
85
+ Tools can be attached with `NativeEnkiAgent.withTools(...)`. Each tool object must provide:
86
+
87
+ - `id` or `name`
88
+ - `description`
89
+ - one of `inputSchema`, `inputSchemaJson`, `parameters`, or `parametersJson`
90
+ - either `execute(inputJson, contextJson)` or a shared `toolHandler`
91
+
92
+ Example:
93
+
94
+ ```js
95
+ const { NativeEnkiAgent } = require('@getenki/ai')
96
+
97
+ const tools = [
98
+ {
99
+ id: 'calculate_sum',
100
+ description: 'Add two numbers and return a short text result.',
101
+ inputSchema: {
102
+ type: 'object',
103
+ properties: {
104
+ a: { type: 'number' },
105
+ b: { type: 'number' },
106
+ },
107
+ required: ['a', 'b'],
108
+ },
109
+ execute: (inputJson, contextJson) => {
110
+ const args = inputJson ? JSON.parse(inputJson) : {}
111
+ const ctx = contextJson ? JSON.parse(contextJson) : {}
112
+ const result = Number(args.a) + Number(args.b)
113
+
114
+ return JSON.stringify({
115
+ result,
116
+ workspaceDir: ctx.workspaceDir,
117
+ text: `${args.a} + ${args.b} = ${result}`,
118
+ })
119
+ },
120
+ },
121
+ ]
122
+
123
+ const agent = NativeEnkiAgent.withTools(
124
+ 'Tool Agent',
125
+ 'Use tools when they help.',
126
+ 'ollama::qwen3.5:latest',
127
+ 20,
128
+ process.cwd(),
129
+ tools,
130
+ null,
131
+ )
132
+ ```
133
+
134
+ Per-tool `execute` receives:
135
+
136
+ - `inputJson`: serialized tool arguments
137
+ - `contextJson`: serialized runtime context with `agentDir`, `workspaceDir`, and `sessionsDir`
138
+
139
+ TypeScript tool example:
140
+
141
+ ```ts
142
+ import { NativeEnkiAgent } from '@getenki/ai'
143
+
144
+ type SumArgs = {
145
+ a?: number
146
+ b?: number
147
+ }
148
+
149
+ type ExampleTool = {
150
+ id: string
151
+ description: string
152
+ inputSchema: Record<string, unknown>
153
+ execute: (inputJson: string, contextJson: string) => string
154
+ }
155
+
156
+ const tools: ExampleTool[] = [
157
+ {
158
+ id: 'calculate_sum',
159
+ description: 'Add two numbers and return a short text result.',
160
+ inputSchema: {
161
+ type: 'object',
162
+ properties: {
163
+ a: { type: 'number' },
164
+ b: { type: 'number' },
165
+ },
166
+ required: ['a', 'b'],
167
+ },
168
+ execute: (inputJson: string, contextJson: string): string => {
169
+ const args = inputJson ? (JSON.parse(inputJson) as SumArgs) : {}
170
+ const ctx = contextJson
171
+ ? (JSON.parse(contextJson) as { workspaceDir?: string })
172
+ : {}
173
+ const result = Number(args.a) + Number(args.b)
174
+
175
+ return JSON.stringify({
176
+ result,
177
+ workspaceDir: ctx.workspaceDir,
178
+ text: `${args.a} + ${args.b} = ${result}`,
179
+ })
180
+ },
181
+ },
182
+ ]
183
+
184
+ const agent = NativeEnkiAgent.withTools(
185
+ 'Tool Agent',
186
+ 'Use tools when they help.',
187
+ 'ollama::qwen3.5:latest',
188
+ 20,
189
+ process.cwd(),
190
+ tools,
191
+ null,
192
+ )
193
+ ```
194
+
195
+ Instead of putting `execute` on every tool, you can pass a shared `toolHandler` as the final argument to `withTools(...)` or `withToolsAndMemory(...)`. The shared handler receives:
196
+
197
+ - `toolName`
198
+ - `inputJson`
199
+ - `agentDir`
200
+ - `workspaceDir`
201
+ - `sessionsDir`
202
+
203
+ ## Memory
204
+
205
+ Memory modules are plain objects:
206
+
207
+ ```js
208
+ const memories = [{ name: 'example-memory' }]
209
+ ```
210
+
211
+ When using `withMemory(...)` or `withToolsAndMemory(...)`, you supply four callbacks:
212
+
213
+ - `recordHandler(memoryName, sessionId, userMsg, assistantMsg)`
214
+ - `recallHandler(memoryName, sessionId, query, maxEntries)`
215
+ - `flushHandler(memoryName, sessionId)`
216
+ - `consolidateHandler(memoryName, sessionId)`
217
+
218
+ `recallHandler` must return an array of `JsMemoryEntry` objects:
219
+
220
+ ```ts
221
+ type JsMemoryEntry = {
222
+ key: string
223
+ content: string
224
+ kind: JsMemoryKind
225
+ relevance: number
226
+ timestampNs: string
227
+ }
228
+ ```
229
+
230
+ Supported memory kinds:
231
+
232
+ - `JsMemoryKind.RecentMessage`
233
+ - `JsMemoryKind.Summary`
234
+ - `JsMemoryKind.Entity`
235
+ - `JsMemoryKind.Preference`
236
+
237
+ TypeScript memory typing example:
238
+
239
+ ```ts
240
+ import {
241
+ JsMemoryKind,
242
+ type JsMemoryEntry,
243
+ type JsMemoryModule,
244
+ } from '@getenki/ai'
245
+
246
+ const memories: JsMemoryModule[] = [{ name: 'example-memory' }]
247
+ const memoryStore = new Map<string, JsMemoryEntry[]>()
248
+
249
+ function memoryKey(memoryName: string, sessionId: string): string {
250
+ return `${memoryName}:${sessionId}`
251
+ }
252
+
253
+ function getMemoryEntries(memoryName: string, sessionId: string): JsMemoryEntry[] {
254
+ const key = memoryKey(memoryName, sessionId)
255
+ const existing = memoryStore.get(key)
256
+ if (existing) {
257
+ return existing
258
+ }
259
+
260
+ const empty: JsMemoryEntry[] = []
261
+ memoryStore.set(key, empty)
262
+ return empty
263
+ }
264
+
265
+ const recordHandler = (
266
+ memoryName: string,
267
+ sessionId: string,
268
+ userMsg: string,
269
+ assistantMsg: string,
270
+ ): void => {
271
+ const entries = getMemoryEntries(memoryName, sessionId)
272
+ entries.push({
273
+ key: `entry-${entries.length + 1}`,
274
+ content: `User: ${userMsg}\nAssistant: ${assistantMsg}`,
275
+ kind: JsMemoryKind.RecentMessage,
276
+ relevance: 1,
277
+ timestampNs: `${Date.now() * 1000000}`,
278
+ })
279
+ }
280
+ ```
281
+
282
+ ## Tools And Memory Example
283
+
284
+ The repository examples in [`example/basic-js/index.js`](/I:/projects/enki/core-next/example/basic-js/index.js) and [`example/basic-ts/index.ts`](/I:/projects/enki/core-next/example/basic-ts/index.ts) use `NativeEnkiAgent.withToolsAndMemory(...)` with:
285
+
286
+ - a `calculate_sum` tool
287
+ - a `get_today` tool
288
+ - an in-memory `Map` for session memory storage
289
+
290
+ Minimal JavaScript version:
291
+
292
+ ```js
293
+ const { JsMemoryKind, NativeEnkiAgent } = require('@getenki/ai')
294
+
295
+ const tools = [
296
+ {
297
+ id: 'get_today',
298
+ description: 'Return the current local date in ISO format.',
299
+ inputSchema: { type: 'object', properties: {} },
300
+ execute: () => JSON.stringify({ today: new Date().toISOString().slice(0, 10) }),
301
+ },
302
+ ]
303
+
304
+ const memories = [{ name: 'example-memory' }]
305
+ const memoryStore = new Map()
306
+
307
+ function memoryKey(memoryName, sessionId) {
308
+ return `${memoryName}:${sessionId}`
309
+ }
310
+
311
+ const agent = NativeEnkiAgent.withToolsAndMemory(
312
+ 'Basic JS Agent',
313
+ 'Answer clearly and keep responses short.',
314
+ 'ollama::qwen3.5:latest',
315
+ 20,
316
+ process.cwd(),
317
+ tools,
318
+ null,
319
+ memories,
320
+ (memoryName, sessionId, userMsg, assistantMsg) => {
321
+ const key = memoryKey(memoryName, sessionId)
322
+ const entries = memoryStore.get(key) ?? []
323
+ entries.push({
324
+ key: `entry-${entries.length + 1}`,
325
+ content: `User: ${userMsg}\nAssistant: ${assistantMsg}`,
326
+ kind: JsMemoryKind.RecentMessage,
327
+ relevance: 1,
328
+ timestampNs: `${Date.now() * 1000000}`,
329
+ })
330
+ memoryStore.set(key, entries)
331
+ },
332
+ (memoryName, sessionId, query, maxEntries) => {
333
+ const entries = memoryStore.get(memoryKey(memoryName, sessionId)) ?? []
334
+ return entries.filter((entry) => entry.content.includes(query)).slice(-maxEntries)
335
+ },
336
+ (memoryName, sessionId) => {
337
+ memoryStore.delete(memoryKey(memoryName, sessionId))
338
+ },
339
+ () => {},
340
+ )
341
+ ```
342
+
343
+ Minimal TypeScript version:
344
+
345
+ ```ts
346
+ import {
347
+ JsMemoryKind,
348
+ type JsMemoryEntry,
349
+ type JsMemoryModule,
350
+ NativeEnkiAgent,
351
+ } from '@getenki/ai'
352
+
353
+ type ExampleTool = {
354
+ id: string
355
+ description: string
356
+ inputSchema: Record<string, unknown>
357
+ execute: (inputJson: string, contextJson: string) => string
358
+ }
359
+
360
+ const tools: ExampleTool[] = [
361
+ {
362
+ id: 'get_today',
363
+ description: 'Return the current local date in ISO format.',
364
+ inputSchema: { type: 'object', properties: {} },
365
+ execute: (): string =>
366
+ JSON.stringify({ today: new Date().toISOString().slice(0, 10) }),
367
+ },
368
+ ]
369
+
370
+ const memories: JsMemoryModule[] = [{ name: 'example-memory' }]
371
+ const memoryStore = new Map<string, JsMemoryEntry[]>()
372
+
373
+ const agent = NativeEnkiAgent.withToolsAndMemory(
374
+ 'Basic TS Agent',
375
+ 'Answer clearly and keep responses short.',
376
+ 'ollama::qwen3.5:latest',
377
+ 20,
378
+ process.cwd(),
379
+ tools,
380
+ null,
381
+ memories,
382
+ (memoryName: string, sessionId: string, userMsg: string, assistantMsg: string): void => {
383
+ const key = `${memoryName}:${sessionId}`
384
+ const entries = memoryStore.get(key) ?? []
385
+ entries.push({
386
+ key: `entry-${entries.length + 1}`,
387
+ content: `User: ${userMsg}\nAssistant: ${assistantMsg}`,
388
+ kind: JsMemoryKind.RecentMessage,
389
+ relevance: 1,
390
+ timestampNs: `${Date.now() * 1000000}`,
391
+ })
392
+ memoryStore.set(key, entries)
393
+ },
394
+ (memoryName: string, sessionId: string, query: string, maxEntries: number): JsMemoryEntry[] => {
395
+ const entries = memoryStore.get(`${memoryName}:${sessionId}`) ?? []
396
+ return entries.filter((entry) => entry.content.includes(query)).slice(-maxEntries)
397
+ },
398
+ (memoryName: string, sessionId: string): void => {
399
+ memoryStore.delete(`${memoryName}:${sessionId}`)
400
+ },
401
+ (): void => {},
402
+ )
403
+ ```
404
+
405
+ ## Running The Examples
406
+
407
+ JavaScript example:
408
+
409
+ ```bash
410
+ cd example/basic-js
411
+ npm install
412
+ npm start
413
+ ```
414
+
415
+ TypeScript example:
416
+
417
+ ```bash
418
+ cd example/basic-ts
419
+ npm install
420
+ npm start
421
+ ```
422
+
423
+ The checked-in examples currently hardcode `ollama::qwen3.5:latest` as the model, so make sure that model is available in your local provider before running them.
424
+
425
+ ## Development
426
+
427
+ From [`crates/bindings/enki-js`](/I:/projects/enki/core-next/crates/bindings/enki-js):
428
+
429
+ ```bash
430
+ npm install
431
+ npm run build
432
+ npm test
433
+ ```
434
+
435
+ Useful scripts:
436
+
437
+ - `npm run build`: build the native addon in release mode
438
+ - `npm run build:debug`: build without release optimizations
439
+ - `npm test`: run the AVA test suite
440
+ - `npm run lint`: run `oxlint`
441
+ - `npm run format`: run Prettier, `cargo fmt`, and `taplo format`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getenki/ai-darwin-arm64",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "cpu": [
5
5
  "arm64"
6
6
  ],