@open1s/ezbos 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.
Binary file
package/README.md ADDED
@@ -0,0 +1,468 @@
1
+ # @open1s/ezbos
2
+
3
+ Simple BrainOS - Easy wrapper for [@open1s/jsbos](https://www.npmjs.com/package/@open1s/jsbos). Build AI agents with tools, hooks, plugins, MCP, skills, and messaging.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @open1s/ezbos
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```ts
14
+ import { BrainOS, tool } from '@open1s/ezbos';
15
+
16
+ const brain = new BrainOS();
17
+ await brain.start();
18
+
19
+ const addTool = tool('Add', 'Add two numbers', (args) => String(args.a + args.b));
20
+
21
+ const agent = brain.agent('assistant')
22
+ .with_tools(addTool)
23
+ .with_systemPrompt('You are a helpful assistant.');
24
+
25
+ const started = await agent.start();
26
+ const result = await started.ask('What is 5 + 3?');
27
+ console.log(result);
28
+
29
+ await started.close();
30
+ await brain.stop();
31
+ ```
32
+
33
+ ## Configuration
34
+
35
+ Place a `brainos.json` in your project root:
36
+
37
+ ```json
38
+ {
39
+ "global_model": {
40
+ "model": "nvidia/meta/llama-3.1-8b-instruct",
41
+ "base_url": "https://integrate.api.nvidia.com/v1",
42
+ "api_key": "your-key"
43
+ }
44
+ }
45
+ ```
46
+
47
+ BrainOS auto-discovers this config on `start()`. You can also pass options directly:
48
+
49
+ ```ts
50
+ const brain = new BrainOS({
51
+ model: 'nvidia/meta/llama-3.1-8b-instruct',
52
+ baseUrl: 'https://integrate.api.nvidia.com/v1',
53
+ apiKey: 'nvapi-xxx',
54
+ });
55
+ await brain.start();
56
+ ```
57
+
58
+ ## Agent Builder
59
+
60
+ Fluent builder for creating agents:
61
+
62
+ ```ts
63
+ const agent = brain.agent('name')
64
+ .with_systemPrompt('You are helpful.')
65
+ .with_model('nvidia/meta/llama-3.1-8b-instruct')
66
+ .with_baseUrl('https://integrate.api.nvidia.com/v1')
67
+ .with_apiKey('your-key')
68
+ .with_temperature(0.7)
69
+ .with_timeout(120)
70
+ .with_maxTokens(4096)
71
+ .with_tools(tool1, tool2)
72
+ .with_hooks(hook1, hook2)
73
+ .with_plugins(plugin1)
74
+ .with_mcp_process('fs', 'npx', ['-y', '@modelcontextprotocol/server-filesystem', '/tmp'])
75
+ .with_mcp_http('math', 'http://127.0.0.1:8000/mcp')
76
+ .with_skills_dir('./skills')
77
+ .with_skills({ name: 'Code Review', content: '...' })
78
+ .with_resilience({ circuitBreakerMaxFailures: 3, rateLimitCapacity: 5 });
79
+
80
+ const started = await agent.start();
81
+ ```
82
+
83
+ ### Resilience
84
+
85
+ Configure circuit breaker and rate limiting:
86
+
87
+ ```ts
88
+ agent.with_resilience({
89
+ circuitBreakerMaxFailures: 3, // trip after 3 failures
90
+ circuitBreakerCooldownSecs: 10, // wait 10s before retry
91
+ rateLimitCapacity: 5, // allow 5 requests
92
+ rateLimitWindowSecs: 60, // per 60 seconds
93
+ rateLimitMaxRetries: 3, // retry 3 times when limited
94
+ });
95
+ ```
96
+
97
+ ## Tools
98
+
99
+ Define tools the LLM can call.
100
+
101
+ ### Simple Tool
102
+
103
+ ```ts
104
+ import { tool } from '@open1s/ezbos';
105
+
106
+ const add = tool('Add', 'Add two numbers', (args) => String(args.a + args.b));
107
+ ```
108
+
109
+ ### Tool Builder
110
+
111
+ For tools with schema and optional parameters:
112
+
113
+ ```ts
114
+ import { defineTool, ok, err } from '@open1s/ezbos';
115
+
116
+ const greet = defineTool('Greet', 'Greet someone')
117
+ .required('name', 'string', 'Name to greet')
118
+ .param('language', 'string', 'Language code', 'en')
119
+ .handle((args) => `Hello, ${args.name}!`);
120
+
121
+ const divide = defineTool('Divide', 'Divide two numbers')
122
+ .required('n', 'number', 'Numerator')
123
+ .required('d', 'number', 'Denominator')
124
+ .handle((args) => {
125
+ if (args.d === 0) return err('Division by zero');
126
+ return ok(args.n / args.d);
127
+ });
128
+ ```
129
+
130
+ ### Result Helpers
131
+
132
+ ```ts
133
+ const success = ok({ value: 42 }, { cached: true });
134
+ const failure = err('Not found', { code: 404 });
135
+ ```
136
+
137
+ **Note:** Tool callbacks must be synchronous. The underlying jsbos native layer does not support async tool callbacks.
138
+
139
+ ## Hooks
140
+
141
+ Intercept agent lifecycle events.
142
+
143
+ ```ts
144
+ import { HookEvent, defineHook } from '@open1s/ezbos';
145
+
146
+ const logHook = defineHook(HookEvent.BeforeToolCall, (ctx) => {
147
+ console.log('About to call:', ctx.data?.tool_name);
148
+ return 'continue'; // or 'abort'
149
+ });
150
+
151
+ agent.with_hooks(logHook);
152
+ ```
153
+
154
+ Available events:
155
+
156
+ | Event | Description |
157
+ |-------|-------------|
158
+ | `BeforeToolCall` | Before a tool is invoked |
159
+ | `AfterToolCall` | After a tool returns |
160
+ | `BeforeLlmCall` | Before sending to LLM |
161
+ | `AfterLlmCall` | After receiving from LLM |
162
+ | `OnMessage` | On each message |
163
+ | `OnComplete` | When task completes |
164
+ | `OnError` | On error |
165
+
166
+ ### Merge Hooks
167
+
168
+ ```ts
169
+ import { mergeHooks } from '@open1s/ezbos';
170
+
171
+ const allHooks = mergeHooks(beforeHook, afterHook, beforeLlmHook);
172
+ agent.with_hooks(allHooks);
173
+ ```
174
+
175
+ ## Plugins
176
+
177
+ Register plugins for LLM/tool lifecycle events.
178
+
179
+ ### Plain Plugin
180
+
181
+ ```ts
182
+ import { definePlugin } from '@open1s/ezbos';
183
+
184
+ const loggerPlugin = definePlugin({
185
+ name: 'logger',
186
+ on_llm_request: (req) => { console.log('LLM request:', req.model); return req; },
187
+ on_llm_response: (resp) => { console.log('LLM response'); return resp; },
188
+ on_tool_call: (call) => { console.log('Tool call:', call.name); return call; },
189
+ on_tool_result: (result) => { console.log('Tool result'); return result; },
190
+ });
191
+
192
+ agent.with_plugins(loggerPlugin);
193
+ ```
194
+
195
+ ### Class-based Plugin
196
+
197
+ ```ts
198
+ import { getPluginHandlers } from '@open1s/ezbos';
199
+
200
+ class MyPlugin {
201
+ __pluginName = 'my-plugin';
202
+
203
+ on_llm_request(req: any) { return req; }
204
+ on_llm_response(resp: any) { return resp; }
205
+ on_tool_call(call: any) { return call; }
206
+ on_tool_result(result: any) { return result; }
207
+ }
208
+
209
+ const plugin = new MyPlugin();
210
+ const handlers = getPluginHandlers(plugin);
211
+ agent.with_plugins(plugin);
212
+ ```
213
+
214
+ ### Merge Plugins
215
+
216
+ ```ts
217
+ import { mergePlugins } from '@open1s/ezbos';
218
+
219
+ const merged = mergePlugins(pluginA, pluginB);
220
+ agent.with_plugins(merged);
221
+ ```
222
+
223
+ ## MCP
224
+
225
+ Connect to MCP (Model Context Protocol) servers.
226
+
227
+ ### Process-based
228
+
229
+ ```ts
230
+ import { defineMcpProcess } from '@open1s/ezbos';
231
+
232
+ const config = defineMcpProcess('files', 'npx', [
233
+ '-y', '@modelcontextprotocol/server-filesystem', '/tmp'
234
+ ]);
235
+
236
+ agent.with_mcp_process('files', 'npx', [
237
+ '-y', '@modelcontextprotocol/server-filesystem', '/tmp'
238
+ ]);
239
+ ```
240
+
241
+ ### HTTP-based
242
+
243
+ ```ts
244
+ import { defineMcpHttp } from '@open1s/ezbos';
245
+
246
+ const config = defineMcpHttp('hello-mcp', 'http://127.0.0.1:8000/mcp');
247
+
248
+ agent.with_mcp_http('hello-mcp', 'http://127.0.0.1:8000/mcp');
249
+ ```
250
+
251
+ ### MCP Builder
252
+
253
+ ```ts
254
+ import { McpBuilder } from '@open1s/ezbos';
255
+
256
+ const configs = new McpBuilder()
257
+ .process('files', 'npx', ['-y', '@modelcontextprotocol/server-filesystem', '/tmp'])
258
+ .http('hello-mcp', 'http://127.0.0.1:8000/mcp')
259
+ .build();
260
+ ```
261
+
262
+ ### List MCP Tools
263
+
264
+ ```ts
265
+ const mcpTools = await started.listMcpTools();
266
+ console.log(`MCP tools available: ${mcpTools.length}`);
267
+ ```
268
+
269
+ ## Skills
270
+
271
+ Add domain-specific instructions to the system prompt.
272
+
273
+ ### Define Skill
274
+
275
+ ```ts
276
+ import { defineSkill } from '@open1s/ezbos';
277
+
278
+ const skill = defineSkill('math-expert', 'You are a math expert. Always show your work step by step.');
279
+ ```
280
+
281
+ ### Directory-based
282
+
283
+ Auto-discovers `SKILL.md` files in a directory:
284
+
285
+ ```ts
286
+ agent.with_skills_dir('./skills');
287
+ ```
288
+
289
+ Directory structure:
290
+ ```
291
+ skills/
292
+ code-review/
293
+ SKILL.md
294
+ ```
295
+
296
+ ### Skills Builder
297
+
298
+ ```ts
299
+ import { SkillsBuilder } from '@open1s/ezbos';
300
+
301
+ const built = new SkillsBuilder()
302
+ .from_dir('./skills')
303
+ .add('code-review', 'You are a code reviewer. Be thorough.')
304
+ .add('api-design', 'You are an API designer. Follow REST best practices.')
305
+ .build();
306
+ ```
307
+
308
+ ## Agent (Started)
309
+
310
+ The running agent instance.
311
+
312
+ ### LLM Calls
313
+
314
+ ```ts
315
+ // ReAct loop (tools + reasoning)
316
+ const result = await started.ask('What is 5 + 3?');
317
+
318
+ // ReAct with explicit task
319
+ const result2 = await started.react('Calculate the sum');
320
+
321
+ // Simple LLM call (no tools)
322
+ const result3 = await started.runSimple('Say hello');
323
+ ```
324
+
325
+ ### Streaming
326
+
327
+ ```ts
328
+ // Stream tokens
329
+ await started.stream('Task', (token) => {
330
+ if (token.type === 'Text') process.stdout.write(token.text);
331
+ if (token.type === 'ReasoningContent') process.stdout.write(token.text);
332
+ });
333
+
334
+ // Collect all tokens
335
+ const tokens = await started.streamCollect('Task');
336
+ const text = tokens.filter(t => t.text).map(t => t.text).join('');
337
+ ```
338
+
339
+ ### Session Management
340
+
341
+ ```ts
342
+ // AI-powered compaction (replaces old messages with LLM summary)
343
+ await started.compactSession();
344
+
345
+ // Save/restore
346
+ started.saveSession('./session.json');
347
+ started.restoreSession('./session.json');
348
+
349
+ // Clear
350
+ started.clearSession();
351
+
352
+ // Export/import as JSON
353
+ const json = started.exportSession();
354
+ started.importSession(json);
355
+ ```
356
+
357
+ ### Metrics
358
+
359
+ ```ts
360
+ const metrics = started.metrics;
361
+ console.log(metrics.llmCallCount);
362
+ console.log(metrics.toolInvocationCount);
363
+ console.log(metrics.totalWallTimeUs);
364
+
365
+ started.resetMetrics();
366
+ ```
367
+
368
+ ### Info
369
+
370
+ ```ts
371
+ console.log(started.tools); // ['Add', 'Greet']
372
+ console.log(started.config); // { model, baseUrl, temperature, ... }
373
+ ```
374
+
375
+ ## Messaging
376
+
377
+ Pub/sub, query, and RPC patterns via the message bus.
378
+
379
+ ### Publisher / Subscriber
380
+
381
+ ```ts
382
+ // Publisher
383
+ const pub = await brain.publisher('events');
384
+ await pub.text('Hello');
385
+ await pub.json({ event: 'click', x: 100 });
386
+
387
+ // Subscriber - recv with timeout
388
+ const sub = await brain.subscriber('events');
389
+ const msg = await sub.recv(3000);
390
+
391
+ // Subscriber - continuous processing
392
+ const sub2 = await brain.subscriber('events');
393
+ await sub2.run((msg) => console.log('Received:', msg));
394
+ await sub2.stop();
395
+ ```
396
+
397
+ ### Query / Queryable (request-response)
398
+
399
+ ```ts
400
+ // Server
401
+ const server = await brain.queryable('math', (input) => {
402
+ const n = parseInt(input);
403
+ return String(n * n);
404
+ });
405
+ await server.start();
406
+
407
+ // Client
408
+ const client = await brain.query('math');
409
+ const response = await client.ask('21', 5000); // "441"
410
+ ```
411
+
412
+ ### Caller / Callable (RPC)
413
+
414
+ ```ts
415
+ // Server
416
+ const rpcServer = await brain.callable('add', (input) => {
417
+ const [a, b] = input.split(',').map(Number);
418
+ return String(a + b);
419
+ });
420
+ await rpcServer.start();
421
+
422
+ // Client
423
+ const rpcClient = await brain.caller('add');
424
+ const result = await rpcClient.call('10,20'); // "30"
425
+ ```
426
+
427
+ ## Quick Agent
428
+
429
+ One-liner to create and start an agent:
430
+
431
+ ```ts
432
+ import { BrainOS } from '@open1s/ezbos';
433
+
434
+ const agent = await BrainOS.with('assistant', {
435
+ model: 'nvidia/meta/llama-3.1-8b-instruct',
436
+ apiKey: 'nvapi-xxx',
437
+ });
438
+ const result = await agent.ask('Hello');
439
+ await agent.close();
440
+ ```
441
+
442
+ ## Examples
443
+
444
+ | Example | Description |
445
+ |---------|-------------|
446
+ | `01-tools.ts` | Tool definitions (required/optional params), ok/err results, isErrorResult, error handling |
447
+ | `02-hooks.ts` | All 7 hook events, defineHook, mergeHooks, hook registry |
448
+ | `03-plugins.ts` | Plain plugins, class-based plugins, getPluginHandlers, mergePlugins |
449
+ | `04-mcp.ts` | Process-based MCP, HTTP MCP, McpBuilder, listMcpTools |
450
+ | `05-skills.ts` | defineSkill, SkillsBuilder, skill directories |
451
+ | `06-session.ts` | Multi-turn conversation, compactSession, save/restore, export/import |
452
+ | `07-agent-advanced.ts` | Streaming, streamCollect, metrics, resilience, config |
453
+ | `08-brainos-messaging.ts` | Query/Queryable, Caller/Callable, Publisher/Subscriber (recv + run) |
454
+
455
+ ```bash
456
+ npm run example:tools
457
+ npm run example:hooks
458
+ npm run example:plugins
459
+ npm run example:mcp
460
+ npm run example:skills
461
+ npm run example:session
462
+ npm run example:agent
463
+ npm run example:messaging
464
+ ```
465
+
466
+ ## License
467
+
468
+ MIT
package/bun.lock ADDED
@@ -0,0 +1,89 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "configVersion": 0,
4
+ "workspaces": {
5
+ "": {
6
+ "name": "@open1s/ezbos",
7
+ "dependencies": {
8
+ "@open1s/jsbos": "^2.1.4",
9
+ },
10
+ "devDependencies": {
11
+ "tsx": "^4.22.0",
12
+ "typescript": "^6.0.3",
13
+ },
14
+ },
15
+ },
16
+ "packages": {
17
+ "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.0", "", { "os": "aix", "cpu": "ppc64" }, "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA=="],
18
+
19
+ "@esbuild/android-arm": ["@esbuild/android-arm@0.28.0", "", { "os": "android", "cpu": "arm" }, "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ=="],
20
+
21
+ "@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.0", "", { "os": "android", "cpu": "arm64" }, "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw=="],
22
+
23
+ "@esbuild/android-x64": ["@esbuild/android-x64@0.28.0", "", { "os": "android", "cpu": "x64" }, "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA=="],
24
+
25
+ "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q=="],
26
+
27
+ "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ=="],
28
+
29
+ "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q=="],
30
+
31
+ "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw=="],
32
+
33
+ "@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.0", "", { "os": "linux", "cpu": "arm" }, "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw=="],
34
+
35
+ "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A=="],
36
+
37
+ "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.0", "", { "os": "linux", "cpu": "ia32" }, "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ=="],
38
+
39
+ "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.0", "", { "os": "linux", "cpu": "none" }, "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg=="],
40
+
41
+ "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.0", "", { "os": "linux", "cpu": "none" }, "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w=="],
42
+
43
+ "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg=="],
44
+
45
+ "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.0", "", { "os": "linux", "cpu": "none" }, "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ=="],
46
+
47
+ "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q=="],
48
+
49
+ "@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.0", "", { "os": "linux", "cpu": "x64" }, "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ=="],
50
+
51
+ "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.0", "", { "os": "none", "cpu": "arm64" }, "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw=="],
52
+
53
+ "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.0", "", { "os": "none", "cpu": "x64" }, "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw=="],
54
+
55
+ "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.0", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g=="],
56
+
57
+ "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA=="],
58
+
59
+ "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.0", "", { "os": "none", "cpu": "arm64" }, "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w=="],
60
+
61
+ "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.0", "", { "os": "sunos", "cpu": "x64" }, "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw=="],
62
+
63
+ "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA=="],
64
+
65
+ "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA=="],
66
+
67
+ "@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.0", "", { "os": "win32", "cpu": "x64" }, "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw=="],
68
+
69
+ "@open1s/jsbos": ["@open1s/jsbos@2.1.4", "", { "optionalDependencies": { "@open1s/jsbos-darwin-arm64": "2.1.4", "@open1s/jsbos-linux-arm64-gnu": "2.1.4", "@open1s/jsbos-linux-x64-gnu": "2.1.4", "@open1s/jsbos-win32-arm64-msvc": "2.1.4", "@open1s/jsbos-win32-x64-msvc": "2.1.4" } }, "sha512-G8FCJFJsELMWtBSyqiDyO1BqFMi45wxdS8RVKUc6+B+imjhht2ZBn7L2O46AErhlZOAKoU/yEeVOKu17Ni5RKQ=="],
70
+
71
+ "@open1s/jsbos-darwin-arm64": ["@open1s/jsbos-darwin-arm64@2.1.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-b6N2J37Rdg2i4+pFQLhmPpXSiPu842eYqY8ZfV/hWdwTIiehg9qG/1kcMETK9icmHc4Md9xQzXtN1Ytb3Q0l6g=="],
72
+
73
+ "@open1s/jsbos-linux-arm64-gnu": ["@open1s/jsbos-linux-arm64-gnu@2.1.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-3BrurLQGxHBkfL51T3EFOqmnFIml7cNFm5f5xX1nBqBLJ+u2TyRMMemeGNlPVI4vl0CQDKy3SIQaEsL1pRzvwQ=="],
74
+
75
+ "@open1s/jsbos-linux-x64-gnu": ["@open1s/jsbos-linux-x64-gnu@2.1.4", "", { "os": "linux", "cpu": "x64" }, "sha512-XfLzVZG4fHyyIbX1sV5uADHRIsXLtzNiEKMuJG1oz6ZWA3k4WOZKWhrFw/M3D4ZuyrovQdA4FdfmPI5za9Epcw=="],
76
+
77
+ "@open1s/jsbos-win32-arm64-msvc": ["@open1s/jsbos-win32-arm64-msvc@2.1.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-pelaitUjyLYCtaXkSFvD5N0v6GX7fOs+B8vZ60/WwraTcksrD4ZU9twEwdgRiep/qY1lydIQIv/72ReX5dCDSA=="],
78
+
79
+ "@open1s/jsbos-win32-x64-msvc": ["@open1s/jsbos-win32-x64-msvc@2.1.4", "", { "os": "win32", "cpu": "x64" }, "sha512-tCOtC0pjF9IWwF3WcmBIIdufQTA4pZlnB9OStDBT4jOR++ukTffXLg3i52H77rz5HayJSJBE2Onrmxy2ZXBj6Q=="],
80
+
81
+ "esbuild": ["esbuild@0.28.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.0", "@esbuild/android-arm": "0.28.0", "@esbuild/android-arm64": "0.28.0", "@esbuild/android-x64": "0.28.0", "@esbuild/darwin-arm64": "0.28.0", "@esbuild/darwin-x64": "0.28.0", "@esbuild/freebsd-arm64": "0.28.0", "@esbuild/freebsd-x64": "0.28.0", "@esbuild/linux-arm": "0.28.0", "@esbuild/linux-arm64": "0.28.0", "@esbuild/linux-ia32": "0.28.0", "@esbuild/linux-loong64": "0.28.0", "@esbuild/linux-mips64el": "0.28.0", "@esbuild/linux-ppc64": "0.28.0", "@esbuild/linux-riscv64": "0.28.0", "@esbuild/linux-s390x": "0.28.0", "@esbuild/linux-x64": "0.28.0", "@esbuild/netbsd-arm64": "0.28.0", "@esbuild/netbsd-x64": "0.28.0", "@esbuild/openbsd-arm64": "0.28.0", "@esbuild/openbsd-x64": "0.28.0", "@esbuild/openharmony-arm64": "0.28.0", "@esbuild/sunos-x64": "0.28.0", "@esbuild/win32-arm64": "0.28.0", "@esbuild/win32-ia32": "0.28.0", "@esbuild/win32-x64": "0.28.0" }, "bin": "bin/esbuild" }, "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw=="],
82
+
83
+ "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
84
+
85
+ "tsx": ["tsx@4.22.0", "", { "dependencies": { "esbuild": "~0.28.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": "dist/cli.mjs" }, "sha512-8ccZMPD69s1AbKXx0C5ddTNZfNjwV04iIKgjZmKfKxMynEtSYcK0Lh7iQFh53fI5Yu4pb9usgAiqyPmEONaALg=="],
86
+
87
+ "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="],
88
+ }
89
+ }
@@ -0,0 +1 @@
1
+ console.log('This is a placeholder file for the 00-pr.ts example. Please refer to the other example files for actual code demonstrations of BrainOS features.');
@@ -0,0 +1,85 @@
1
+ import { BrainOS, defineTool, tool, ok, err, isErrorResult, version } from '../src/index.js';
2
+
3
+ import {initTracing} from "@open1s/jsbos";
4
+
5
+ // initTracing();
6
+
7
+ const addTool = defineTool('Add', 'Add two numbers')
8
+ .required('a', 'number', 'First number')
9
+ .required('b', 'number', 'Second number')
10
+ .handle((args: any) => { console.error('Adding numbers:', args.a, args.b); return args.a + args.b; });
11
+
12
+ const multiplyTool = defineTool('Multiply', 'Multiply two numbers')
13
+ .required('x', 'number', 'First number')
14
+ .required('y', 'number', 'Second number')
15
+ .handle((args: any) => { console.error('Multiplying numbers:', args.x, args.y); return args.x * args.y; });
16
+
17
+ const stringConcatTool = defineTool('Concat', 'Concatenate two strings')
18
+ .param('str1', 'string', 'First string')
19
+ .param('str2', 'string', 'Second string')
20
+ .param('separator', 'string', 'Separator', ', ')
21
+ .handle((args: any) => { console.error('Concatenating strings:', args.str1, args.str2, args.separator); return args.str1 + args.separator + args.str2; });
22
+
23
+ const divideTool = defineTool('Divide', 'Divide two numbers')
24
+ .required('n', 'number', 'Numerator')
25
+ .required('d', 'number', 'Denominator')
26
+ .handle((args: any) => {
27
+ console.error('Dividing numbers:', args.n, args.d);
28
+ if (args.d === 0) return err('Division by zero');
29
+ return ok(args.n / args.d);
30
+ });
31
+
32
+ const asyncWeatherTool = defineTool('Weather', 'Get weather for a city')
33
+ .required('city', 'string', 'City name')
34
+ .handle((args: any) => {
35
+ console.error('Fetching weather for city:', args.city);
36
+ return ok({ city: args.city, temp: 22, condition: 'sunny', unit: 'celsius' });
37
+ });
38
+
39
+ const errorTool = tool('Fail', 'Always returns an error', () => {
40
+ throw new Error('Intentional failure from errorTool');
41
+ });
42
+
43
+ async function main() {
44
+ console.log(`\n=== 01-tools.ts - Tool API Demo (v${version()}) ===\n`);
45
+
46
+ const brain = new BrainOS();
47
+ await brain.start();
48
+
49
+ const agent = brain.agent('tools-demo')
50
+ .with_tools(addTool, multiplyTool, stringConcatTool, divideTool, asyncWeatherTool, errorTool);
51
+
52
+ const started = await agent.start();
53
+
54
+ const tests = [
55
+ { q: 'What is 15 + 27?', expect: 42 },
56
+ { q: 'What is 8 times 6?', expect: 48 },
57
+ { q: 'Concatenate "Brain" and "OS" with separator "-"', expect: 'Brain-OS' },
58
+ { q: 'Divide 100 by 4', expect: 25 },
59
+ { q: 'Divide 10 by 0', expect: 'error' },
60
+ { q: 'What is the weather in Tokyo?', expect: 'ok' },
61
+ ];
62
+
63
+ for (const t of tests) {
64
+ console.log(`\nQ: ${t.q}`);
65
+ console.log(` Expected: ${t.expect}`);
66
+ const result = await started.ask(t.q);
67
+ console.log(` A: ${result}`);
68
+ }
69
+
70
+ console.log('\n--- Tool definitions ---');
71
+ console.log('addTool schema:', JSON.stringify((addTool as any).schema, null, 2));
72
+
73
+ console.log('\n--- isErrorResult demo ---');
74
+ const okResult = ok(42);
75
+ const errResult = err('bad');
76
+ console.log('ok(42):', okResult, 'isErrorResult:', isErrorResult(okResult));
77
+ console.log('err("bad"):', errResult, 'isErrorResult:', isErrorResult(errResult));
78
+
79
+ await started.close();
80
+ await brain.stop();
81
+ console.log('\nDone.');
82
+ process.exit(0);
83
+ }
84
+
85
+ main().catch((e) => { console.error(e); process.exit(1); });